diff options
| author | Aura Linden <aura@lindenlab.com> | 2014-06-18 11:32:53 -0700 | 
|---|---|---|
| committer | Aura Linden <aura@lindenlab.com> | 2014-06-18 11:32:53 -0700 | 
| commit | a4d60d6721c62511ba7a26352e3b5d35cd0dbb94 (patch) | |
| tree | 082fa1927273936fa07b9b500a7a3548833cbb6f | |
| parent | 4bcf2079f15a09d40f1d7aa61b2768cc54dc427a (diff) | |
| parent | 977476171ddcc057d7c28b6c14ae988b8189ed75 (diff) | |
Pulled merge from release.
302 files changed, 9631 insertions, 9117 deletions
@@ -481,3 +481,4 @@ fc066b82343fca51f9c1b8eda0abc6bee9bb4503 3.7.5-release  d029faf69f20a23007f32420a1ac6a3b89a6d441 3.7.6-release  83959480cb986522d07b151a0c778ab7f920d41b 3.7.7-release  bba9b3722eea08949e4ff69591f736bf0f808434 3.7.8-release +a9f2d0cb11f73b06858e6083bb50083becc3f9cd 3.7.9-release diff --git a/autobuild.xml b/autobuild.xml index 1d827cb6c4..dd4c63f474 100755 --- a/autobuild.xml +++ b/autobuild.xml @@ -764,7 +764,7 @@                <key>hash</key>                <string>aff5566e04003de0383941981198e04e</string>                <key>url</key> -          <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>              </map>              <key>name</key>              <string>darwin</string> @@ -776,7 +776,7 @@                <key>hash</key>                <string>52257e5eb166a0b69c9c0c38f6e1920e</string>                <key>url</key> -	         <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>              </map>              <key>name</key>              <string>linux</string> @@ -834,9 +834,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>d2542614df9dd99cbb5ff67e76d4a6c1</string> +              <string>98994d5b0b4b3d43be22aa6a5c36e6fa</string>                <key>url</key> -              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock/rev/274899/arch/CYGWIN/installer/gmock-1.6.0-windows-20130426.tar.bz2</string> +              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock-graham/rev/272961/arch/CYGWIN/installer/gmock-1.6.0-windows-20130327.tar.bz2</string>              </map>              <key>name</key>              <string>windows</string> @@ -1290,9 +1290,9 @@              <key>archive</key>              <map>                <key>hash</key> -              <string>b6d29de20de5c8f31925697b30e8f727</string> +              <string>54e46715e72b7805d9d3f84d45b6b1b7</string>                <key>url</key> -              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-source/rev/283723/arch/Linux/installer/llappearanceutility_source-0.1-linux-20131109.tar.bz2</string> +              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/llappearanceutility-source/rev/290120/arch/Linux/installer/llappearanceutility_source-0.1-linux-20140519.tar.bz2</string>              </map>              <key>name</key>              <string>linux</string> diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake index e4b63dc7cb..e618a988b8 100755 --- a/indra/cmake/BuildVersion.cmake +++ b/indra/cmake/BuildVersion.cmake @@ -42,6 +42,11 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n          message(SEND_ERROR "Cannot get viewer version from '${VIEWER_VERSION_BASE_FILE}'")       endif ( EXISTS ${VIEWER_VERSION_BASE_FILE} ) +    if ("${VIEWER_VERSION_REVISION}" STREQUAL "") +      message("Ultimate fallback, revision was blank or not set: will use 0") +      set(VIEWER_VERSION_REVISION 0) +    endif ("${VIEWER_VERSION_REVISION}" STREQUAL "") +      set(VIEWER_CHANNEL_VERSION_DEFINES          "LL_VIEWER_CHANNEL=\"${VIEWER_CHANNEL}\""          "LL_VIEWER_VERSION_MAJOR=${VIEWER_VERSION_MAJOR}" diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index beeb570496..c63ad74682 100755 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -1,7 +1 @@ -Wed Nov  7 00:25:19 UTC 2012 - - - - - - +2014-02-25 10:34 diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 41fcb6ce4b..6fdf9e2e07 100644..100755 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -498,29 +498,9 @@ void LLAvatarAppearance::computeBodySize()  	mAvatarOffset.mV[VX] = 0.0f;  	mAvatarOffset.mV[VY] = 0.0f; -	// Certain configurations of avatars can force the overall height (with offset) to go negative. -	// Enforce a constraint to make sure we don't go below 0.1 meters. -	// Camera positioning and other things start to break down when your avatar is "walking" while being fully underground -	if (new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] < 0.1f)  -	{ -		mAvatarOffset.mV[VZ] = -(new_body_size.mV[VZ] - 0.11f); // avoid floating point rounding making the above check continue to fail. - -		llassert(new_body_size.mV[VZ] + mAvatarOffset.mV[VZ] >= 0.1f); - -		if (mWearableData && isSelf())  -		{ -			LLWearable* shape = mWearableData->getWearable(LLWearableType::WT_SHAPE, 0); -			if (shape)  -			{ -				shape->setVisualParamWeight(AVATAR_HOVER, mAvatarOffset.mV[VZ], false); -			} -		} -	} -  	if (new_body_size != mBodySize || old_offset != mAvatarOffset.mV[VZ])  	{  		mBodySize = new_body_size; -		bodySizeChanged();  	}  } @@ -1390,14 +1370,14 @@ BOOL LLAvatarAppearance::teToColorParams( ETextureIndex te, U32 *param_name )  	return TRUE;  } -void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color, BOOL upload_bake ) +void LLAvatarAppearance::setClothesColor( ETextureIndex te, const LLColor4& new_color)  {  	U32 param_name[3];  	if( teToColorParams( te, param_name ) )  	{ -		setVisualParamWeight( param_name[0], new_color.mV[VX], upload_bake ); -		setVisualParamWeight( param_name[1], new_color.mV[VY], upload_bake ); -		setVisualParamWeight( param_name[2], new_color.mV[VZ], upload_bake ); +		setVisualParamWeight( param_name[0], new_color.mV[VX]); +		setVisualParamWeight( param_name[1], new_color.mV[VY]); +		setVisualParamWeight( param_name[2], new_color.mV[VZ]);  	}  } diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index bce2540258..1e898026c0 100644..100755 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -107,7 +107,6 @@ public:  public:  	virtual bool 	isSelf() const { return false; } // True if this avatar is for this viewer's agent  	virtual BOOL	isValid() const; -	virtual BOOL	isUsingServerBakes() const = 0;  	virtual BOOL	isUsingLocalAppearance() const = 0;  	virtual BOOL	isEditingAppearance() const = 0; @@ -137,14 +136,13 @@ public:  	typedef std::map<std::string, LLJoint*> joint_map_t;  	joint_map_t			mJointMap; -	void				computeBodySize(); +	void		computeBodySize();  protected:  	static BOOL			parseSkeletonFile(const std::string& filename);  	virtual void		buildCharacter();  	virtual BOOL		loadAvatar(); -	virtual void		bodySizeChanged() = 0;  	BOOL				setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num);  	BOOL				allocateCharacterJoints(U32 num); @@ -225,7 +223,7 @@ public:  	// Composites  	//--------------------------------------------------------------------  public: -	virtual void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result) = 0; +	virtual void	invalidateComposite(LLTexLayerSet* layerset) = 0;  /********************************************************************************   **                                                                            ** @@ -256,7 +254,7 @@ protected:  	// Clothing colors (convenience functions to access visual parameters)  	//--------------------------------------------------------------------  public: -	void			setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color, BOOL upload_bake); +	void			setClothesColor(LLAvatarAppearanceDefines::ETextureIndex te, const LLColor4& new_color);  	LLColor4		getClothesColor(LLAvatarAppearanceDefines::ETextureIndex te);  	static BOOL		teToColorParams(LLAvatarAppearanceDefines::ETextureIndex te, U32 *param_name); @@ -265,7 +263,7 @@ public:  	//--------------------------------------------------------------------  public:  	LLColor4		getGlobalColor(const std::string& color_name ) const; -	virtual void	onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake) = 0; +	virtual void	onGlobalColorChanged(const LLTexGlobalColor* global_color) = 0;  protected:  	LLTexGlobalColor* mTexSkinColor;  	LLTexGlobalColor* mTexHairColor; diff --git a/indra/llappearance/lldriverparam.cpp b/indra/llappearance/lldriverparam.cpp index c66a428374..e630c1118b 100644..100755 --- a/indra/llappearance/lldriverparam.cpp +++ b/indra/llappearance/lldriverparam.cpp @@ -152,19 +152,31 @@ void LLDriverParamInfo::toStream(std::ostream &out)  // LLDriverParam  //----------------------------------------------------------------------------- -LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) : +LLDriverParam::LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable /* = NULL */) +	: LLViewerVisualParam(), +	mDefaultVec(), +	mDriven(),  	mCurrentDistortionParam( NULL ),   	mAvatarAppearance(appearance),   	mWearablep(wearable)  {  	llassert(mAvatarAppearance); -	if (mWearablep) -	{ -		llassert(mAvatarAppearance->isSelf()); -	} +	llassert((mWearablep == NULL) || mAvatarAppearance->isSelf());  	mDefaultVec.clear();  } +LLDriverParam::LLDriverParam(const LLDriverParam& pOther) +	: LLViewerVisualParam(pOther), +	mDefaultVec(pOther.mDefaultVec), +	mDriven(pOther.mDriven), +	mCurrentDistortionParam(pOther.mCurrentDistortionParam), +	mAvatarAppearance(pOther.mAvatarAppearance), +	mWearablep(pOther.mWearablep) +{ +	llassert(mAvatarAppearance); +	llassert((mWearablep == NULL) || mAvatarAppearance->isSelf()); +} +  LLDriverParam::~LLDriverParam()  {  } @@ -178,7 +190,7 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)  	mID = info->mID;  	info->mDriverParam = this; -	setWeight(getDefaultWeight(), FALSE ); +	setWeight(getDefaultWeight());  	return TRUE;  } @@ -186,16 +198,10 @@ BOOL LLDriverParam::setInfo(LLDriverParamInfo *info)  /*virtual*/ LLViewerVisualParam* LLDriverParam::cloneParam(LLWearable* wearable) const  {  	llassert(wearable); -	LLDriverParam *new_param = new LLDriverParam(mAvatarAppearance, wearable); -	// FIXME DRANO this clobbers mWearablep, which means any code -	// currently using mWearablep is wrong, or at least untested. -	*new_param = *this; -	//new_param->mWearablep = wearable; -//	new_param->mDriven.clear(); // clear driven list to avoid overwriting avatar driven params from wearables.  -	return new_param; +	return new LLDriverParam(*this);  } -void LLDriverParam::setWeight(F32 weight, BOOL upload_bake) +void LLDriverParam::setWeight(F32 weight)  {  	F32 min_weight = getMinWeight();  	F32 max_weight = getMaxWeight(); @@ -254,7 +260,7 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)  					driven_weight = driven_min;  				} -				setDrivenWeight(driven,driven_weight,upload_bake); +				setDrivenWeight(driven,driven_weight);  				continue;  			}  			else  @@ -278,13 +284,13 @@ void LLDriverParam::setWeight(F32 weight, BOOL upload_bake)  					driven_weight = driven_min;  				} -				setDrivenWeight(driven,driven_weight,upload_bake); +				setDrivenWeight(driven,driven_weight);  				continue;  			}  		}  		driven_weight = getDrivenWeight(driven, mCurWeight); -		setDrivenWeight(driven,driven_weight,upload_bake); +		setDrivenWeight(driven,driven_weight);  	}  } @@ -430,9 +436,9 @@ const LLViewerVisualParam* LLDriverParam::getDrivenParam(S32 index) const  //-----------------------------------------------------------------------------  // setAnimationTarget()  //----------------------------------------------------------------------------- -void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake ) +void LLDriverParam::setAnimationTarget( F32 target_value)  { -	LLVisualParam::setAnimationTarget(target_value, upload_bake); +	LLVisualParam::setAnimationTarget(target_value);  	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )  	{ @@ -441,16 +447,16 @@ void LLDriverParam::setAnimationTarget( F32 target_value, BOOL upload_bake )  		// this isn't normally necessary, as driver params handle interpolation of their driven params  		// but texture params need to know to assume their final value at beginning of interpolation -		driven->mParam->setAnimationTarget(driven_weight, upload_bake); +		driven->mParam->setAnimationTarget(driven_weight);  	}  }  //-----------------------------------------------------------------------------  // stopAnimating()  //----------------------------------------------------------------------------- -void LLDriverParam::stopAnimating(BOOL upload_bake) +void LLDriverParam::stopAnimating()  { -	LLVisualParam::stopAnimating(upload_bake); +	LLVisualParam::stopAnimating();  	for( entry_list_t::iterator iter = mDriven.begin(); iter != mDriven.end(); iter++ )  	{ @@ -530,7 +536,7 @@ void LLDriverParam::updateCrossDrivenParams(LLWearableType::EType driven_type)  		LLWearable *wearable = mAvatarAppearance->getWearableData()->getTopWearable(driver_type);  		if (wearable)  		{ -			wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID), false); +			wearable->setVisualParamWeight(mID, wearable->getVisualParamWeight(mID));  		}  	}  } @@ -593,7 +599,7 @@ F32 LLDriverParam::getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight  	return driven_weight;  } -void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake) +void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight)  {  	bool use_self = false;  	if(mWearablep && @@ -610,10 +616,10 @@ void LLDriverParam::setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bo  	if (use_self)  	{  		// call setWeight through LLVOAvatarSelf so other wearables can be updated with the correct values -		mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight, upload_bake ); +		mAvatarAppearance->setVisualParamWeight( (LLVisualParam*)driven->mParam, driven_weight);  	}  	else  	{ -		driven->mParam->setWeight( driven_weight, upload_bake ); +		driven->mParam->setWeight( driven_weight);  	}  } diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h index 2420db76e7..f71c930e5e 100644..100755 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -111,9 +111,9 @@ public:  	// LLVisualParam Virtual functions  	/*virtual*/ void				apply( ESex sex ) {} // apply is called separately for each driven param. -	/*virtual*/ void				setWeight(F32 weight, BOOL upload_bake); -	/*virtual*/ void				setAnimationTarget( F32 target_value, BOOL upload_bake ); -	/*virtual*/ void				stopAnimating(BOOL upload_bake); +	/*virtual*/ void				setWeight(F32 weight); +	/*virtual*/ void				setAnimationTarget( F32 target_value); +	/*virtual*/ void				stopAnimating();  	/*virtual*/ BOOL				linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);  	/*virtual*/ void				resetDrivenParams(); @@ -129,8 +129,9 @@ public:  	const LLViewerVisualParam*		getDrivenParam(S32 index) const;  protected: +	LLDriverParam(const LLDriverParam& pOther);  	F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); -	void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake); +	void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight);  	LL_ALIGN_16(LLVector4a	mDefaultVec); // temp holder diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index ce8a0b0b76..e3992a080e 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -315,10 +315,27 @@ BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)  // LLPolyMorphTarget()  //-----------------------------------------------------------------------------  LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh) -	: mMorphData(NULL), mMesh(poly_mesh), -	  mVertMask(NULL), -	  mLastSex(SEX_FEMALE), -	  mNumMorphMasksPending(0) +	: LLViewerVisualParam(), +	mMorphData(NULL), +	mMesh(poly_mesh), +	mVertMask(NULL), +	mLastSex(SEX_FEMALE), +	mNumMorphMasksPending(0), +	mVolumeMorphs() +{ +} + +//----------------------------------------------------------------------------- +// LLPolyMorphTarget() +//----------------------------------------------------------------------------- +LLPolyMorphTarget::LLPolyMorphTarget(const LLPolyMorphTarget& pOther) +	: LLViewerVisualParam(pOther), +	mMorphData(pOther.mMorphData), +	mMesh(pOther.mMesh), +	mVertMask(pOther.mVertMask == NULL ? NULL : new LLPolyVertexMask(*pOther.mVertMask)), +	mLastSex(pOther.mLastSex), +	mNumMorphMasksPending(pOther.mNumMorphMasksPending), +	mVolumeMorphs(pOther.mVolumeMorphs)  {  } @@ -327,10 +344,8 @@ LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)  //-----------------------------------------------------------------------------  LLPolyMorphTarget::~LLPolyMorphTarget()  { -	if (mVertMask) -	{ -		delete mVertMask; -	} +	delete mVertMask; +	mVertMask = NULL;  }  //----------------------------------------------------------------------------- @@ -343,7 +358,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)  		return FALSE;  	mInfo = info;  	mID = info->mID; -	setWeight(getDefaultWeight(), FALSE ); +	setWeight(getDefaultWeight());  	LLAvatarAppearance* avatarp = mMesh->getAvatar();  	LLPolyMorphTargetInfo::volume_info_list_t::iterator iter; @@ -385,9 +400,7 @@ BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)  /*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const  { -	LLPolyMorphTarget *new_param = new LLPolyMorphTarget(mMesh); -	*new_param = *this; -	return new_param; +	return new LLPolyMorphTarget(*this);  }  #if 0 // obsolete @@ -722,10 +735,25 @@ void	LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3  // LLPolyVertexMask()  //-----------------------------------------------------------------------------  LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data) +	: mWeights(new F32[morph_data->mNumIndices]), +	mMorphData(morph_data), +	mWeightsGenerated(FALSE) +{ +	llassert(mMorphData != NULL); +	llassert(mMorphData->mNumIndices > 0); +} + +//----------------------------------------------------------------------------- +// LLPolyVertexMask() +//----------------------------------------------------------------------------- +LLPolyVertexMask::LLPolyVertexMask(const LLPolyVertexMask& pOther) +	: mWeights(new F32[pOther.mMorphData->mNumIndices]), +	mMorphData(pOther.mMorphData), +	mWeightsGenerated(pOther.mWeightsGenerated)  { -	mWeights = new F32[morph_data->mNumIndices]; -	mMorphData = morph_data; -	mWeightsGenerated = FALSE; +	llassert(mMorphData != NULL); +	llassert(mMorphData->mNumIndices > 0); +	memcpy(mWeights, pOther.mWeights, sizeof(F32) * mMorphData->mNumIndices);  }  //----------------------------------------------------------------------------- @@ -733,7 +761,8 @@ LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)  //-----------------------------------------------------------------------------  LLPolyVertexMask::~LLPolyVertexMask()  { -	delete[] mWeights; +	delete [] mWeights; +	mWeights = NULL;  }  //----------------------------------------------------------------------------- diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index ee380ae7c3..7e712f9e94 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -91,6 +91,7 @@ class LLPolyVertexMask  {  public:  	LLPolyVertexMask(LLPolyMorphData* morph_data); +	LLPolyVertexMask(const LLPolyVertexMask& pOther);  	~LLPolyVertexMask();  	void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights); @@ -182,6 +183,8 @@ public:  	void	addPendingMorphMask() { mNumMorphMasksPending++; }  protected: +	LLPolyMorphTarget(const LLPolyMorphTarget& pOther); +  	LLPolyMorphData*				mMorphData;  	LLPolyMesh*						mMesh;  	LLPolyVertexMask *				mVertMask; diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index a72b446ace..ea29cbd451 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -104,9 +104,25 @@ BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)  // LLPolySkeletalDistortion()  //-----------------------------------------------------------------------------  LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp) +	: LLViewerVisualParam(), +	mDefaultVec(), +	mJointScales(), +	mJointOffsets(), +	mAvatar(avatarp) +{ +	mDefaultVec.splat(0.001f); +} + +//----------------------------------------------------------------------------- +// LLPolySkeletalDistortion() +//----------------------------------------------------------------------------- +LLPolySkeletalDistortion::LLPolySkeletalDistortion(const LLPolySkeletalDistortion &pOther) +	: LLViewerVisualParam(pOther), +	mDefaultVec(pOther.mDefaultVec), +	mJointScales(pOther.mJointScales), +	mJointOffsets(pOther.mJointOffsets), +	mAvatar(pOther.mAvatar)  { -        mAvatar = avatarp; -        mDefaultVec.splat(0.001f);  }  //----------------------------------------------------------------------------- @@ -123,7 +139,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)                  return FALSE;          mInfo = info;          mID = info->mID; -        setWeight(getDefaultWeight(), FALSE ); +        setWeight(getDefaultWeight());          LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;          for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) @@ -171,9 +187,7 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)  /*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const  { -        LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar); -        *new_param = *this; -        return new_param; +	return new LLPolySkeletalDistortion(*this);  }  //----------------------------------------------------------------------------- @@ -185,7 +199,7 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )  {  	LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); -        F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); +	F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();          LLJoint* joint;          joint_vec_map_t::iterator iter; @@ -197,8 +211,10 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )                  joint = iter->first;                  LLVector3 newScale = joint->getScale();                  LLVector3 scaleDelta = iter->second; -                newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); -                joint->setScale(newScale); +                newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);				                 +				//An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached +				joint->storeScaleForReset( newScale );				 +				joint->setScale(newScale);          }          for (iter = mJointOffsets.begin(); @@ -207,8 +223,8 @@ void LLPolySkeletalDistortion::apply( ESex avatar_sex )          {                  joint = iter->first;                  LLVector3 newPosition = joint->getPosition(); -                LLVector3 positionDelta = iter->second; -                newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); +                LLVector3 positionDelta = iter->second;				 +                newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);		                  joint->setPosition(newPosition);          } diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h index 24c9e9ae48..ea2adb8a87 100644 --- a/indra/llappearance/llpolyskeletaldistortion.h +++ b/indra/llappearance/llpolyskeletaldistortion.h @@ -118,6 +118,8 @@ public:  	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};  protected: +	LLPolySkeletalDistortion(const LLPolySkeletalDistortion& pOther); +  	LL_ALIGN_16(LLVector4a mDefaultVec);  	typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;  	joint_vec_map_t mJointScales; diff --git a/indra/llappearance/lltexglobalcolor.cpp b/indra/llappearance/lltexglobalcolor.cpp index 186c537659..3df2254b14 100644..100755 --- a/indra/llappearance/lltexglobalcolor.cpp +++ b/indra/llappearance/lltexglobalcolor.cpp @@ -90,22 +90,36 @@ const std::string& LLTexGlobalColor::getName() const  //-----------------------------------------------------------------------------  // LLTexParamGlobalColor  //----------------------------------------------------------------------------- -LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) : -	LLTexLayerParamColor(tex_global_color->getAvatarAppearance()), +LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) +	: LLTexLayerParamColor(tex_global_color->getAvatarAppearance()),  	mTexGlobalColor(tex_global_color)  {  } +//----------------------------------------------------------------------------- +// LLTexParamGlobalColor +//----------------------------------------------------------------------------- +LLTexParamGlobalColor::LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther) +	: LLTexLayerParamColor(pOther), +	mTexGlobalColor(pOther.mTexGlobalColor) +{ +} + +//----------------------------------------------------------------------------- +// ~LLTexParamGlobalColor +//----------------------------------------------------------------------------- +LLTexParamGlobalColor::~LLTexParamGlobalColor() +{ +} +  /*virtual*/ LLViewerVisualParam* LLTexParamGlobalColor::cloneParam(LLWearable* wearable) const  { -	LLTexParamGlobalColor *new_param = new LLTexParamGlobalColor(mTexGlobalColor); -	*new_param = *this; -	return new_param; +	return new LLTexParamGlobalColor(*this);  } -void LLTexParamGlobalColor::onGlobalColorChanged(bool upload_bake) +void LLTexParamGlobalColor::onGlobalColorChanged()  { -	mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor, upload_bake); +	mAvatarAppearance->onGlobalColorChanged(mTexGlobalColor);  }  //----------------------------------------------------------------------------- diff --git a/indra/llappearance/lltexglobalcolor.h b/indra/llappearance/lltexglobalcolor.h index 2867479876..3b426053de 100644..100755 --- a/indra/llappearance/lltexglobalcolor.h +++ b/indra/llappearance/lltexglobalcolor.h @@ -73,9 +73,11 @@ class LLTexParamGlobalColor : public LLTexLayerParamColor  {  public:  	LLTexParamGlobalColor(LLTexGlobalColor *tex_color); +	virtual ~LLTexParamGlobalColor();  	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;  protected: -	/*virtual*/ void onGlobalColorChanged(bool upload_bake); +	LLTexParamGlobalColor(const LLTexParamGlobalColor& pOther); +	/*virtual*/ void onGlobalColorChanged();  private:  	LLTexGlobalColor*		mTexGlobalColor;  }; diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index f6abaa5eb3..2cf86bb4fe 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -1560,10 +1560,13 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC  		}  		U32 cache_index = alpha_mask_crc.getCRC(); -		U8* alpha_data = get_if_there(mAlphaCache,cache_index,(U8*)NULL); -		if (!alpha_data) +		U8* alpha_data = NULL;  +                // We believe we need to generate morph masks, do not assume that the cached version is accurate. +                // We can get bad morph masks during login, on minimize, and occasional gl errors. +                // We should only be doing this when we believe something has changed with respect to the user's appearance.  		{ -			// clear out a slot if we have filled our cache +                       LL_DEBUGS("Avatar") << "gl alpha cache of morph mask not found, doing readback: " << getName() << LL_ENDL; +                        // clear out a slot if we have filled our cache  			S32 max_cache_entries = getTexLayerSet()->getAvatarAppearance()->isSelf() ? 4 : 1;  			while ((S32)mAlphaCache.size() >= max_cache_entries)  			{ @@ -1783,13 +1786,11 @@ LLTexLayer* LLTexLayerTemplate::getLayer(U32 i) const  /*virtual*/ void LLTexLayerTemplate::gatherAlphaMasks(U8 *data, S32 originX, S32 originY, S32 width, S32 height)  {  	U32 num_wearables = updateWearableCache(); -	for (U32 i = 0; i < num_wearables; i++) +	U32 i = num_wearables - 1; // For rendering morph masks, we only want to use the top wearable +	LLTexLayer *layer = getLayer(i); +	if (layer)  	{ -		LLTexLayer *layer = getLayer(i); -		if (layer) -		{ -			layer->addAlphaMask(data, originX, originY, width, height); -		} +		layer->addAlphaMask(data, originX, originY, width, height);  	}  } diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index f1f7d07fa9..ff682d6906 100644..100755 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -40,7 +40,8 @@  //-----------------------------------------------------------------------------  // LLTexLayerParam  //----------------------------------------------------------------------------- -LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) : +LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) +	: LLViewerVisualParam(),  	mTexLayer(layer),  	mAvatarAppearance(NULL)  { @@ -54,12 +55,19 @@ LLTexLayerParam::LLTexLayerParam(LLTexLayerInterface *layer) :  	}  } -LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) : +LLTexLayerParam::LLTexLayerParam(LLAvatarAppearance *appearance) +	: LLViewerVisualParam(),  	mTexLayer(NULL),  	mAvatarAppearance(appearance)  {  } +LLTexLayerParam::LLTexLayerParam(const LLTexLayerParam& pOther) +	: LLViewerVisualParam(pOther), +	mTexLayer(pOther.mTexLayer), +	mAvatarAppearance(pOther.mAvatarAppearance) +{ +}  BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info, BOOL add_to_appearance)  { @@ -112,9 +120,11 @@ void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes)  	}  } -LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) : -	LLTexLayerParam(layer), +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) +	: LLTexLayerParam(layer),  	mCachedProcessedTexture(NULL), +	mStaticImageTGA(), +	mStaticImageRaw(),  	mNeedsCreateTexture(FALSE),  	mStaticImageInvalid(FALSE),  	mAvgDistortionVec(1.f, 1.f, 1.f), @@ -123,9 +133,11 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayerInterface* layer) :  	sInstances.push_front(this);  } -LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) : -	LLTexLayerParam(appearance), +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) +	: LLTexLayerParam(appearance),  	mCachedProcessedTexture(NULL), +	mStaticImageTGA(), +	mStaticImageRaw(),  	mNeedsCreateTexture(FALSE),  	mStaticImageInvalid(FALSE),  	mAvgDistortionVec(1.f, 1.f, 1.f), @@ -134,6 +146,18 @@ LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLAvatarAppearance* appearance) :  	sInstances.push_front(this);  } +LLTexLayerParamAlpha::LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther) +	: LLTexLayerParam(pOther), +	mCachedProcessedTexture(pOther.mCachedProcessedTexture), +	mStaticImageTGA(pOther.mStaticImageTGA), +	mStaticImageRaw(pOther.mStaticImageRaw), +	mNeedsCreateTexture(pOther.mNeedsCreateTexture), +	mStaticImageInvalid(pOther.mStaticImageInvalid), +	mAvgDistortionVec(pOther.mAvgDistortionVec), +	mCachedEffectiveWeight(pOther.mCachedEffectiveWeight) +{ +	sInstances.push_front(this); +}  LLTexLayerParamAlpha::~LLTexLayerParamAlpha()  { @@ -143,9 +167,7 @@ LLTexLayerParamAlpha::~LLTexLayerParamAlpha()  /*virtual*/ LLViewerVisualParam* LLTexLayerParamAlpha::cloneParam(LLWearable* wearable) const  { -	LLTexLayerParamAlpha *new_param = new LLTexLayerParamAlpha(mTexLayer); -	*new_param = *this; -	return new_param; +	return new LLTexLayerParamAlpha(*this);  }  void LLTexLayerParamAlpha::deleteCaches() @@ -161,7 +183,7 @@ BOOL LLTexLayerParamAlpha::getMultiplyBlend() const  	return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend; 	  } -void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake) +void LLTexLayerParamAlpha::setWeight(F32 weight)  {  	if (mIsAnimating || mTexLayer == NULL)  	{ @@ -179,35 +201,35 @@ void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL upload_bake)  		if ((mAvatarAppearance->getSex() & getSex()) &&  			(mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.  		{ -			mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake); +			mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());  			mTexLayer->invalidateMorphMasks();  		}  	}  } -void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL upload_bake) +void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value)  {   	// do not animate dummy parameters  	if (mIsDummy)  	{ -		setWeight(target_value, upload_bake); +		setWeight(target_value);  		return;  	}  	mTargetWeight = target_value;  -	setWeight(target_value, upload_bake);  +	setWeight(target_value);   	mIsAnimating = TRUE;  	if (mNext)  	{ -		mNext->setAnimationTarget(target_value, upload_bake); +		mNext->setAnimationTarget(target_value);  	}  } -void LLTexLayerParamAlpha::animate(F32 delta, BOOL upload_bake) +void LLTexLayerParamAlpha::animate(F32 delta)  {  	if (mNext)  	{ -		mNext->animate(delta, upload_bake); +		mNext->animate(delta);  	}  } @@ -399,27 +421,31 @@ BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node) -LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer) : -	LLTexLayerParam(layer), +LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayerInterface* layer) +	: LLTexLayerParam(layer),  	mAvgDistortionVec(1.f, 1.f, 1.f)  {  } -LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance) : -	LLTexLayerParam(appearance), +LLTexLayerParamColor::LLTexLayerParamColor(LLAvatarAppearance *appearance) +	: LLTexLayerParam(appearance),  	mAvgDistortionVec(1.f, 1.f, 1.f)  {  } +LLTexLayerParamColor::LLTexLayerParamColor(const LLTexLayerParamColor& pOther) +	: LLTexLayerParam(pOther), +	mAvgDistortionVec(pOther.mAvgDistortionVec) +{ +} +  LLTexLayerParamColor::~LLTexLayerParamColor()  {  }  /*virtual*/ LLViewerVisualParam* LLTexLayerParamColor::cloneParam(LLWearable* wearable) const  { -	LLTexLayerParamColor *new_param = new LLTexLayerParamColor(mTexLayer); -	*new_param = *this; -	return new_param; +	return new LLTexLayerParamColor(*this);  }  LLColor4 LLTexLayerParamColor::getNetColor() const @@ -450,14 +476,14 @@ LLColor4 LLTexLayerParamColor::getNetColor() const  	}  } -void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake) + +void LLTexLayerParamColor::setWeight(F32 weight)  {  	if (mIsAnimating)  	{  		return;  	} -	const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo();  	F32 min_weight = getMinWeight();  	F32 max_weight = getMaxWeight();  	F32 new_weight = llclamp(weight, min_weight, max_weight); @@ -467,6 +493,8 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)  	{  		mCurWeight = new_weight; +                const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); +  		if (info->mNumColors <= 0)  		{  			// This will happen when we set the default weight the first time. @@ -475,10 +503,10 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)  		if ((mAvatarAppearance->getSex() & getSex()) && (mAvatarAppearance->isSelf() && !mIsDummy)) // only trigger a baked texture update if we're changing a wearable's visual param.  		{ -			onGlobalColorChanged(upload_bake); +			onGlobalColorChanged();  			if (mTexLayer)  			{ -				mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet(), upload_bake); +				mAvatarAppearance->invalidateComposite(mTexLayer->getTexLayerSet());  			}  		} @@ -486,23 +514,23 @@ void LLTexLayerParamColor::setWeight(F32 weight, BOOL upload_bake)  	}  } -void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL upload_bake) +void LLTexLayerParamColor::setAnimationTarget(F32 target_value)  {   	// set value first then set interpolating flag to ignore further updates  	mTargetWeight = target_value;  -	setWeight(target_value, upload_bake); +	setWeight(target_value);  	mIsAnimating = TRUE;  	if (mNext)  	{ -		mNext->setAnimationTarget(target_value, upload_bake); +		mNext->setAnimationTarget(target_value);  	}  } -void LLTexLayerParamColor::animate(F32 delta, BOOL upload_bake) +void LLTexLayerParamColor::animate(F32 delta)  {  	if (mNext)  	{ -		mNext->animate(delta, upload_bake); +		mNext->animate(delta);  	}  } diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h index b38d28d3eb..0cb2dedbff 100644..100755 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -52,6 +52,8 @@ public:  	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const = 0;  protected: +	LLTexLayerParam(const LLTexLayerParam& pOther); +  	LLTexLayerInterface*	mTexLayer;  	LLAvatarAppearance*		mAvatarAppearance;  }; @@ -83,9 +85,9 @@ public:  	// LLVisualParam Virtual functions  	///*virtual*/ BOOL		parseData(LLXmlTreeNode* node);  	/*virtual*/ void		apply( ESex avatar_sex ) {} -	/*virtual*/ void		setWeight(F32 weight, BOOL upload_bake); -	/*virtual*/ void		setAnimationTarget(F32 target_value, BOOL upload_bake);  -	/*virtual*/ void		animate(F32 delta, BOOL upload_bake); +	/*virtual*/ void		setWeight(F32 weight); +	/*virtual*/ void		setAnimationTarget(F32 target_value);  +	/*virtual*/ void		animate(F32 delta);  	// LLViewerVisualParam Virtual functions  	/*virtual*/ F32					getTotalDistortion()									{ return 1.f; } @@ -102,6 +104,8 @@ public:  	BOOL					getMultiplyBlend() const;  private: +	LLTexLayerParamAlpha(const LLTexLayerParamAlpha& pOther); +  	LLPointer<LLGLTexture>	mCachedProcessedTexture;  	LLPointer<LLImageTGA>	mStaticImageTGA;  	LLPointer<LLImageRaw>	mStaticImageRaw; @@ -174,9 +178,9 @@ public:  	// LLVisualParam Virtual functions  	///*virtual*/ BOOL			parseData(LLXmlTreeNode* node);  	/*virtual*/ void			apply( ESex avatar_sex ) {} -	/*virtual*/ void			setWeight(F32 weight, BOOL upload_bake); -	/*virtual*/ void			setAnimationTarget(F32 target_value, BOOL upload_bake); -	/*virtual*/ void			animate(F32 delta, BOOL upload_bake); +	/*virtual*/ void			setWeight(F32 weight); +	/*virtual*/ void			setAnimationTarget(F32 target_value); +	/*virtual*/ void			animate(F32 delta);  	// LLViewerVisualParam Virtual functions @@ -190,7 +194,9 @@ public:  	// New functions  	LLColor4				getNetColor() const;  protected: -	virtual void onGlobalColorChanged(bool upload_bake) {} +	LLTexLayerParamColor(const LLTexLayerParamColor& pOther); + +	virtual void onGlobalColorChanged() {}  private:  	LL_ALIGN_16(LLVector4a				mAvgDistortionVec);  } LL_ALIGN_POSTFIX(16); diff --git a/indra/llappearance/llviewervisualparam.cpp b/indra/llappearance/llviewervisualparam.cpp index cc81bcf118..af8394b60c 100644 --- a/indra/llappearance/llviewervisualparam.cpp +++ b/indra/llappearance/llviewervisualparam.cpp @@ -123,6 +123,22 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node)  // LLViewerVisualParam()  //-----------------------------------------------------------------------------  LLViewerVisualParam::LLViewerVisualParam() +	: LLVisualParam() +{ +} + +//----------------------------------------------------------------------------- +// LLViewerVisualParam() +//----------------------------------------------------------------------------- +LLViewerVisualParam::LLViewerVisualParam(const LLViewerVisualParam& pOther) +	: LLVisualParam(pOther) +{ +} + +//----------------------------------------------------------------------------- +// ~LLViewerVisualParam() +//----------------------------------------------------------------------------- +LLViewerVisualParam::~LLViewerVisualParam()  {  } @@ -137,7 +153,7 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)  		return FALSE;  	mInfo = info;  	mID = info->mID; -	setWeight(getDefaultWeight(), FALSE ); +	setWeight(getDefaultWeight());  	return TRUE;  } diff --git a/indra/llappearance/llviewervisualparam.h b/indra/llappearance/llviewervisualparam.h index 2826e6c316..1a710c0ca6 100644 --- a/indra/llappearance/llviewervisualparam.h +++ b/indra/llappearance/llviewervisualparam.h @@ -70,7 +70,7 @@ class LLViewerVisualParam : public LLVisualParam  {  public:  	LLViewerVisualParam(); -	/*virtual*/ ~LLViewerVisualParam(){}; +	virtual ~LLViewerVisualParam();  	// Special: These functions are overridden by child classes  	LLViewerVisualParamInfo 	*getInfo() const { return (LLViewerVisualParamInfo*)mInfo; }; @@ -105,6 +105,8 @@ public:  	BOOL				getCrossWearable() const 	{ return getInfo()->mCrossWearable; } +protected: +	LLViewerVisualParam(const LLViewerVisualParam& pOther);  } LL_ALIGN_POSTFIX(16);  #endif // LL_LLViewerVisualParam_H diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp index 389505fa34..4bce3f99ed 100644..100755 --- a/indra/llappearance/llwearable.cpp +++ b/indra/llappearance/llwearable.cpp @@ -43,9 +43,32 @@ S32 LLWearable::sCurrentDefinitionVersion = 1;  // Private local functions  static std::string terse_F32_to_string(F32 f); +LLWearable::LLWearable() +	: mDefinitionVersion(-1), +	mName(), +	mDescription(), +	mPermissions(), +	mSaleInfo(), +	mType(LLWearableType::WT_NONE), +	mSavedVisualParamMap(), +	mVisualParamIndexMap(), +	mTEMap(), +	mSavedTEMap() +{ +} +  // virtual  LLWearable::~LLWearable()  { +	for (visual_param_index_map_t::iterator vpIter = mVisualParamIndexMap.begin(); vpIter != mVisualParamIndexMap.end(); ++vpIter) +	{ +		LLVisualParam* vp = vpIter->second; +		vp->clearNextParam(); +		delete vp; +		vpIter->second = NULL; +	} + +	destroyTextures();  }  const std::string& LLWearable::getTypeLabel() const @@ -525,7 +548,7 @@ void LLWearable::revertValues()  		LLVisualParam *param = getVisualParam(id);  		if(param &&  !dynamic_cast<LLDriverParam*>(param) )  		{ -			setVisualParamWeight(id, value, TRUE); +			setVisualParamWeight(id, value);  		}  	} @@ -537,7 +560,7 @@ void LLWearable::revertValues()  		LLVisualParam *param = getVisualParam(id);  		if(param &&  dynamic_cast<LLDriverParam*>(param) )  		{ -			setVisualParamWeight(id, value, TRUE); +			setVisualParamWeight(id, value);  		}  	} @@ -620,17 +643,10 @@ void LLWearable::syncImages(te_map_t &src, te_map_t &dst)  void LLWearable::destroyTextures()  { -	for( te_map_t::iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter ) -	{ -		LLLocalTextureObject *lto = iter->second; -		delete lto; -	} +	std::for_each(mTEMap.begin(), mTEMap.end(), DeletePairedPointer());  	mTEMap.clear(); -	for( te_map_t::iterator iter = mSavedTEMap.begin(); iter != mSavedTEMap.end(); ++iter ) -	{ -		LLLocalTextureObject *lto = iter->second; -		delete lto; -	} + +	std::for_each(mSavedTEMap.begin(), mSavedTEMap.end(), DeletePairedPointer());  	mSavedTEMap.clear();  } @@ -647,12 +663,12 @@ void LLWearable::addVisualParam(LLVisualParam *param)  } -void LLWearable::setVisualParamWeight(S32 param_index, F32 value, BOOL upload_bake) +void LLWearable::setVisualParamWeight(S32 param_index, F32 value)  {  	if( is_in_map(mVisualParamIndexMap, param_index ) )  	{  		LLVisualParam *wearable_param = mVisualParamIndexMap[param_index]; -		wearable_param->setWeight(value, upload_bake); +		wearable_param->setWeight(value);  	}  	else  	{ @@ -693,14 +709,14 @@ void LLWearable::getVisualParams(visual_param_vec_t &list)  	}  } -void LLWearable::animateParams(F32 delta, BOOL upload_bake) +void LLWearable::animateParams(F32 delta)  {  	for(visual_param_index_map_t::iterator iter = mVisualParamIndexMap.begin();  		 iter != mVisualParamIndexMap.end();  		 ++iter)  	{  		LLVisualParam *param = (LLVisualParam*) iter->second; -		param->animate(delta, upload_bake); +		param->animate(delta);  	}  } @@ -718,14 +734,14 @@ LLColor4 LLWearable::getClothesColor(S32 te) const  	return color;  } -void LLWearable::setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ) +void LLWearable::setClothesColor( S32 te, const LLColor4& new_color)  {  	U32 param_name[3];  	if( LLAvatarAppearance::teToColorParams( (LLAvatarAppearanceDefines::ETextureIndex)te, param_name ) )  	{  		for( U8 index = 0; index < 3; index++ )  		{ -			setVisualParamWeight(param_name[index], new_color.mV[index], upload_bake); +			setVisualParamWeight(param_name[index], new_color.mV[index]);  		}  	}  } @@ -744,7 +760,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)  			S32 param_id = param->getID();  			F32 weight = getVisualParamWeight(param_id); -			avatarp->setVisualParamWeight( param_id, weight, FALSE ); +			avatarp->setVisualParamWeight( param_id, weight);  		}  	}  } diff --git a/indra/llappearance/llwearable.h b/indra/llappearance/llwearable.h index 132c153bcd..406fc7e883 100644..100755 --- a/indra/llappearance/llwearable.h +++ b/indra/llappearance/llwearable.h @@ -46,6 +46,7 @@ class LLWearable  	// Constructors and destructors  	//--------------------------------------------------------------------  public: +	LLWearable();  	virtual ~LLWearable();  	//-------------------------------------------------------------------- @@ -94,14 +95,14 @@ public:  	void				setLocalTextureObject(S32 index, LLLocalTextureObject <o);  	void				addVisualParam(LLVisualParam *param); -	void 				setVisualParamWeight(S32 index, F32 value, BOOL upload_bake); +	void 				setVisualParamWeight(S32 index, F32 value);  	F32					getVisualParamWeight(S32 index) const;  	LLVisualParam*		getVisualParam(S32 index) const;  	void				getVisualParams(visual_param_vec_t &list); -	void				animateParams(F32 delta, BOOL upload_bake); +	void				animateParams(F32 delta);  	LLColor4			getClothesColor(S32 te) const; -	void 				setClothesColor( S32 te, const LLColor4& new_color, BOOL upload_bake ); +	void 				setClothesColor( S32 te, const LLColor4& new_color);  	virtual void		revertValues();  	virtual void		saveValues(); diff --git a/indra/llappearance/llwearabledata.cpp b/indra/llappearance/llwearabledata.cpp index 089370dbc4..cf1ee435a8 100644..100755 --- a/indra/llappearance/llwearabledata.cpp +++ b/indra/llappearance/llwearabledata.cpp @@ -119,13 +119,6 @@ U32 LLWearableData::pushWearable(const LLWearableType::EType type,  void LLWearableData::wearableUpdated(LLWearable *wearable, BOOL removed)  {  	wearable->setUpdated(); -	// FIXME DRANO avoid updating params via wearables when rendering server-baked appearance. -#if 0 -	if (mAvatarAppearance->isUsingServerBakes() && !mAvatarAppearance->isUsingLocalAppearance()) -	{ -		return; -	} -#endif  	if (!removed)  	{  		pullCrossWearableValues(wearable->getType()); diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 82ddfa01ec..4df975ecc5 100755 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -287,13 +287,13 @@ void LLCharacter::removeAnimationData(std::string name)  //-----------------------------------------------------------------------------  // setVisualParamWeight()  //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight, BOOL upload_bake) +BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 weight)  {  	S32 index = which_param->getID();  	visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);  	if (index_iter != mVisualParamIndexMap.end())  	{ -		index_iter->second->setWeight(weight, upload_bake); +		index_iter->second->setWeight(weight);  		return TRUE;  	}  	return FALSE; @@ -302,7 +302,7 @@ BOOL LLCharacter::setVisualParamWeight(const LLVisualParam* which_param, F32 wei  //-----------------------------------------------------------------------------  // setVisualParamWeight()  //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake) +BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight)  {  	std::string tname(param_name);  	LLStringUtil::toLower(tname); @@ -310,7 +310,7 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL  	visual_param_name_map_t::iterator name_iter = mVisualParamNameMap.find(tableptr);  	if (name_iter != mVisualParamNameMap.end())  	{ -		name_iter->second->setWeight(weight, upload_bake); +		name_iter->second->setWeight(weight);  		return TRUE;  	}  	LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter: " << param_name << LL_ENDL; @@ -320,12 +320,12 @@ BOOL LLCharacter::setVisualParamWeight(const char* param_name, F32 weight, BOOL  //-----------------------------------------------------------------------------  // setVisualParamWeight()  //----------------------------------------------------------------------------- -BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake) +BOOL LLCharacter::setVisualParamWeight(S32 index, F32 weight)  {  	visual_param_index_map_t::iterator index_iter = mVisualParamIndexMap.find(index);  	if (index_iter != mVisualParamIndexMap.end())  	{ -		index_iter->second->setWeight(weight, upload_bake); +		index_iter->second->setWeight(weight);  		return TRUE;  	}  	LL_WARNS() << "LLCharacter::setVisualParamWeight() Invalid visual parameter index: " << index << LL_ENDL; @@ -395,7 +395,7 @@ void LLCharacter::clearVisualParamWeights()  	{  		if (param->isTweakable())  		{ -			param->setWeight( param->getDefaultWeight(), FALSE ); +			param->setWeight( param->getDefaultWeight());  		}  	}  } diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index b10a8a5f34..d4e3b76386 100755 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -190,9 +190,9 @@ public:  	void addVisualParam(LLVisualParam *param);  	void addSharedVisualParam(LLVisualParam *param); -	virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); -	virtual BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); -	virtual BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); +	virtual BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight); +	virtual BOOL setVisualParamWeight(const char* param_name, F32 weight); +	virtual BOOL setVisualParamWeight(S32 index, F32 weight);  	// get visual param weight by param or name  	F32 getVisualParamWeight(LLVisualParam *distortion); diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index 1492cc172c..dbd6d48a95 100755 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -48,8 +48,11 @@ void LLJoint::init()  	mParent = NULL;  	mXform.setScaleChildOffset(TRUE);  	mXform.setScale(LLVector3(1.0f, 1.0f, 1.0f)); +	mOldXform.setScaleChildOffset(TRUE); +	mOldXform.setScale(LLVector3(1.0f, 1.0f, 1.0f));  	mDirtyFlags = MATRIX_DIRTY | ROTATION_DIRTY | POSITION_DIRTY;  	mUpdateXform = TRUE; +	mResetAfterRestoreOldXform = false;	  }  LLJoint::LLJoint() : @@ -57,7 +60,6 @@ LLJoint::LLJoint() :  {  	init();  	touch(); -	mResetAfterRestoreOldXform = false;  }  LLJoint::LLJoint(S32 joint_num) : @@ -65,7 +67,6 @@ LLJoint::LLJoint(S32 joint_num) :  {  	init();  	touch(); -	mResetAfterRestoreOldXform = false;  } @@ -78,7 +79,6 @@ LLJoint::LLJoint(const std::string &name, LLJoint *parent) :  {  	init();  	mUpdateXform = FALSE; -	// *TODO: mResetAfterRestoreOldXform is not initialized!!!  	setName(name);  	if (parent) @@ -239,11 +239,8 @@ const LLVector3& LLJoint::getPosition()  //--------------------------------------------------------------------  void LLJoint::setPosition( const LLVector3& pos )  { -//	if (mXform.getPosition() != pos) -	{ -		mXform.setPosition(pos); -		touch(MATRIX_DIRTY | POSITION_DIRTY); -	} +	mXform.setPosition(pos); +	touch(MATRIX_DIRTY | POSITION_DIRTY);  } @@ -251,38 +248,37 @@ void LLJoint::setPosition( const LLVector3& pos )  // setPosition()  //--------------------------------------------------------------------  void LLJoint::setDefaultFromCurrentXform( void ) -{ +{		  	mDefaultXform = mXform; -	touch(MATRIX_DIRTY | POSITION_DIRTY); -	  }  //--------------------------------------------------------------------  // storeCurrentXform()  //--------------------------------------------------------------------  void LLJoint::storeCurrentXform( const LLVector3& pos ) -{ +{	  	mOldXform = mXform; -	mResetAfterRestoreOldXform = true; +	mResetAfterRestoreOldXform = true;	  	setPosition( pos ); +	touch(ALL_DIRTY);	  } +  //-------------------------------------------------------------------- -// restoreOldXform() +// storeScaleForReset()  //-------------------------------------------------------------------- -void LLJoint::restoreOldXform( void ) +void LLJoint::storeScaleForReset( const LLVector3& scale )  { -	mResetAfterRestoreOldXform = false; -	mXform = mOldXform; +	mOldXform.setScale( scale );  }  //--------------------------------------------------------------------  // restoreOldXform()  //-------------------------------------------------------------------- -void LLJoint::restoreToDefaultXform( void ) +void LLJoint::restoreOldXform( void )  {	  	mXform = mDefaultXform; -	setPosition( mXform.getPosition() );	 +	mResetAfterRestoreOldXform = false; +	mDirtyFlags = ALL_DIRTY;	  } -  //--------------------------------------------------------------------  // getWorldPosition()  //-------------------------------------------------------------------- @@ -299,8 +295,6 @@ LLVector3 LLJoint::getLastWorldPosition()  {  	return mXform.getWorldPosition();  } - -  //--------------------------------------------------------------------  // setWorldPosition()  //-------------------------------------------------------------------- @@ -404,7 +398,7 @@ void LLJoint::setWorldRotation( const LLQuaternion& rot )  //--------------------------------------------------------------------  const LLVector3& LLJoint::getScale()  { -	return mXform.getScale(); +	return mXform.getScale();	  }  //-------------------------------------------------------------------- @@ -413,7 +407,7 @@ const LLVector3& LLJoint::getScale()  void LLJoint::setScale( const LLVector3& scale )  {  //	if (mXform.getScale() != scale) -	{ +	{	  		mXform.setScale(scale);  		touch();  	} diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 6efa13aeb5..b65d6979d4 100755 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -83,6 +83,7 @@ protected:  	LLXformMatrix		mDefaultXform;  	LLUUID				mId; +  public:  	U32				mDirtyFlags;  	BOOL			mUpdateXform; @@ -159,7 +160,7 @@ public:  	// get/set local scale  	const LLVector3& getScale();  	void setScale( const LLVector3& scale ); - +	void storeScaleForReset( const LLVector3& scale );  	// get/set world matrix  	const LLMatrix4 &getWorldMatrix();  	void setWorldMatrix( const LLMatrix4& mat ); @@ -184,7 +185,6 @@ public:  	S32 getJointNum() const { return mJointNum; }  	void restoreOldXform( void ); -	void restoreToDefaultXform( void );  	void setDefaultFromCurrentXform( void );  	void storeCurrentXform( const LLVector3& pos ); @@ -195,8 +195,8 @@ public:  	//If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it  	const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; } -	//Setter for joint reset flag -	void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; } +	void setJointResetFlag( bool val ) { mResetAfterRestoreOldXform = val; } +	  };  #endif // LL_LLJOINT_H diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 50ccfd75fb..e02b139608 100755 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -172,6 +172,13 @@ void LLMotionController::deleteAllMotions()  	for_each(mAllMotions.begin(), mAllMotions.end(), DeletePairedPointer());  	mAllMotions.clear(); + +	// stinson 05/12/20014 : Ownership of the LLMotion pointers is transferred from +	// mAllMotions to mDeprecatedMotions in method +	// LLMotionController::deprecateMotionInstance().  Thus, we should also clean +	// up the mDeprecatedMotions list as well. +	for_each(mDeprecatedMotions.begin(), mDeprecatedMotions.end(), DeletePointer()); +	mDeprecatedMotions.clear();  }  //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llvisualparam.cpp b/indra/llcharacter/llvisualparam.cpp index 0df7fb2bc3..2235496ac5 100755 --- a/indra/llcharacter/llvisualparam.cpp +++ b/indra/llcharacter/llvisualparam.cpp @@ -159,26 +159,42 @@ void LLVisualParamInfo::toStream(std::ostream &out)  //-----------------------------------------------------------------------------  // LLVisualParam()  //----------------------------------------------------------------------------- -LLVisualParam::LLVisualParam()	 -	: -	mCurWeight( 0.f ), +LLVisualParam::LLVisualParam() +	: mCurWeight( 0.f ),  	mLastWeight( 0.f ),  	mNext( NULL ),  	mTargetWeight( 0.f ),  	mIsAnimating( FALSE ), +	mIsDummy(FALSE),  	mID( -1 ),  	mInfo( 0 ), -	mIsDummy(FALSE),  	mParamLocation(LOC_UNKNOWN)  {  }  //----------------------------------------------------------------------------- +// LLVisualParam() +//----------------------------------------------------------------------------- +LLVisualParam::LLVisualParam(const LLVisualParam& pOther) +	: mCurWeight(pOther.mCurWeight), +	mLastWeight(pOther.mLastWeight), +	mNext(pOther.mNext), +	mTargetWeight(pOther.mTargetWeight), +	mIsAnimating(pOther.mIsAnimating), +	mIsDummy(pOther.mIsDummy), +	mID(pOther.mID), +	mInfo(pOther.mInfo), +	mParamLocation(pOther.mParamLocation) +{ +} + +//-----------------------------------------------------------------------------  // ~LLVisualParam()  //-----------------------------------------------------------------------------  LLVisualParam::~LLVisualParam()  {  	delete mNext; +	mNext = NULL;  }  /* @@ -220,7 +236,7 @@ BOOL LLVisualParam::parseData(LLXmlTreeNode *node)  //-----------------------------------------------------------------------------  // setWeight()  //----------------------------------------------------------------------------- -void LLVisualParam::setWeight(F32 weight, BOOL upload_bake) +void LLVisualParam::setWeight(F32 weight)  {  	if (mIsAnimating)  	{ @@ -238,19 +254,19 @@ void LLVisualParam::setWeight(F32 weight, BOOL upload_bake)  	if (mNext)  	{ -		mNext->setWeight(weight, upload_bake); +		mNext->setWeight(weight);  	}  }  //-----------------------------------------------------------------------------  // setAnimationTarget()  //----------------------------------------------------------------------------- -void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake) +void LLVisualParam::setAnimationTarget(F32 target_value)  {  	// don't animate dummy parameters  	if (mIsDummy)  	{ -		setWeight(target_value, upload_bake); +		setWeight(target_value);  		mTargetWeight = mCurWeight;  		return;  	} @@ -270,7 +286,7 @@ void LLVisualParam::setAnimationTarget(F32 target_value, BOOL upload_bake)  	if (mNext)  	{ -		mNext->setAnimationTarget(target_value, upload_bake); +		mNext->setAnimationTarget(target_value);  	}  } @@ -285,26 +301,34 @@ void LLVisualParam::setNextParam( LLVisualParam *next )  }  //----------------------------------------------------------------------------- +// clearNextParam() +//----------------------------------------------------------------------------- +void LLVisualParam::clearNextParam() +{ +	mNext = NULL; +} + +//-----------------------------------------------------------------------------  // animate()  //----------------------------------------------------------------------------- -void LLVisualParam::animate( F32 delta, BOOL upload_bake ) +void LLVisualParam::animate( F32 delta)  {  	if (mIsAnimating)  	{  		F32 new_weight = ((mTargetWeight - mCurWeight) * delta) + mCurWeight; -		setWeight(new_weight, upload_bake); +		setWeight(new_weight);  	}  }  //-----------------------------------------------------------------------------  // stopAnimating()  //----------------------------------------------------------------------------- -void LLVisualParam::stopAnimating(BOOL upload_bake) +void LLVisualParam::stopAnimating()  {   	if (mIsAnimating && isTweakable())  	{  		mIsAnimating = FALSE;  -		setWeight(mTargetWeight, upload_bake); +		setWeight(mTargetWeight);  	}  } diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index a4d9f93e56..c6b97d7e8b 100755 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -120,10 +120,10 @@ public:  	//virtual BOOL			parseData( LLXmlTreeNode *node ) = 0;  	virtual void			apply( ESex avatar_sex ) = 0;  	//  Default functions -	virtual void			setWeight(F32 weight, BOOL upload_bake); -	virtual void			setAnimationTarget( F32 target_value, BOOL upload_bake ); -	virtual void			animate(F32 delta, BOOL upload_bake); -	virtual void			stopAnimating(BOOL upload_bake); +	virtual void			setWeight(F32 weight); +	virtual void			setAnimationTarget( F32 target_value); +	virtual void			animate(F32 delta); +	virtual void			stopAnimating();  	virtual BOOL			linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);  	virtual void			resetDrivenParams(); @@ -155,6 +155,7 @@ public:  	LLVisualParam*			getNextParam()		{ return mNext; }  	void					setNextParam( LLVisualParam *next ); +	void					clearNextParam();  	virtual void			setAnimating(BOOL is_animating) { mIsAnimating = is_animating && !mIsDummy; }  	BOOL					getAnimating() const { return mIsAnimating; } @@ -165,6 +166,8 @@ public:  	EParamLocation			getParamLocation() const { return mParamLocation; }  protected: +	LLVisualParam(const LLVisualParam& pOther); +  	F32					mCurWeight;			// current weight  	F32					mLastWeight;		// last weight  	LLVisualParam*		mNext;				// next param in a shared chain diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 5856e06b67..8eeb186936 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -158,7 +158,6 @@ set(llcommon_HEADER_FILES      llhandle.h      llhash.h      llheartbeat.h -    llhttpstatuscodes.h      llindexedvector.h      llinitparam.h      llinstancetracker.h diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index a7963174ad..22cd861c72 100755 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -47,6 +47,7 @@  #include "lllivefile.h"  #include "llsd.h"  #include "llsdserialize.h" +#include "llsingleton.h"  #include "llstl.h"  #include "lltimer.h" @@ -356,30 +357,31 @@ namespace  	typedef std::map<std::string, LLError::ELevel> LevelMap; -	typedef std::vector<LLError::Recorder*> Recorders; +	typedef std::vector<LLError::RecorderPtr> Recorders;  	typedef std::vector<LLError::CallSite*> CallSiteVector; -	class Globals +	class Globals : public LLSingleton<Globals>  	{  	public: +		Globals(); +  		std::ostringstream messageStream;  		bool messageStreamInUse;  		void addCallSite(LLError::CallSite&);  		void invalidateCallSites(); -		 -		static Globals& get(); -			// return the one instance of the globals  	private:  		CallSiteVector callSites; - -		Globals() -			:	messageStreamInUse(false) -			{ } -		  	}; +	Globals::Globals() +		: messageStream(), +		messageStreamInUse(false), +		callSites() +	{ +	} +  	void Globals::addCallSite(LLError::CallSite& site)  	{  		callSites.push_back(&site); @@ -396,25 +398,17 @@ namespace  		callSites.clear();  	} - -	Globals& Globals::get() -	{ -		/* This pattern, of returning a reference to a static function -		   variable, is to ensure that this global is constructed before -		   it is used, no matter what the global initialization sequence -		   is. -		   See C++ FAQ Lite, sections 10.12 through 10.14 -		*/ -		static Globals* globals = new Globals;		 -		return *globals; -	}  }  namespace LLError  { -	class Settings +	class SettingsConfig : public LLRefCount  	{ +		friend class Settings; +  	public: +		virtual ~SettingsConfig(); +  		bool                                mPrintLocation;  		LLError::ELevel                     mDefaultLevel; @@ -429,81 +423,86 @@ namespace LLError  		LLError::TimeFunction               mTimeFunction;  		Recorders                           mRecorders; -		Recorder*                           mFileRecorder; -		Recorder*                           mFixedBufferRecorder; +		RecorderPtr                         mFileRecorder; +		RecorderPtr                         mFixedBufferRecorder;  		std::string                         mFileRecorderFileName;  		int									mShouldLogCallCounter; -		static Settings& get(); +	private: +		SettingsConfig(); +	}; + +	typedef LLPointer<SettingsConfig> SettingsConfigPtr; + +	class Settings : public LLSingleton<Settings> +	{ +	public: +		Settings(); + +		SettingsConfigPtr getSettingsConfig(); -		static void reset(); -		static Settings* saveAndReset(); -		static void restore(Settings*); +		void reset(); +		SettingsStoragePtr saveAndReset(); +		void restore(SettingsStoragePtr pSettingsStorage);  	private: -		Settings() -		:	mPrintLocation(false), -			mDefaultLevel(LLError::LEVEL_DEBUG), -			mCrashFunction(), -			mTimeFunction(NULL), -			mFileRecorder(NULL), -			mFixedBufferRecorder(NULL), -			mShouldLogCallCounter(0) -			{ } -		 -		~Settings() -		{ -			for_each(mRecorders.begin(), mRecorders.end(), DeletePointer()); -			mRecorders.clear(); -		} -		 -		static Settings*& getPtr(); +		SettingsConfigPtr mSettingsConfig;  	}; -	Settings& Settings::get() +	SettingsConfig::SettingsConfig() +		: LLRefCount(), +		mPrintLocation(false), +		mDefaultLevel(LLError::LEVEL_DEBUG), +		mFunctionLevelMap(), +		mClassLevelMap(), +		mFileLevelMap(), +		mTagLevelMap(), +		mUniqueLogMessages(), +		mCrashFunction(NULL), +		mTimeFunction(NULL), +		mRecorders(), +		mFileRecorder(), +		mFixedBufferRecorder(), +		mFileRecorderFileName(), +		mShouldLogCallCounter(0)  	{ -		Settings* p = getPtr(); -		if (!p) -		{ -			reset(); -			p = getPtr(); -		} -		return *p;  	} -	 -	void Settings::reset() + +	SettingsConfig::~SettingsConfig()  	{ -		Globals::get().invalidateCallSites(); -		 -		Settings*& p = getPtr(); -		delete p; -		p = new Settings(); +		mRecorders.clear(); +	} + +	Settings::Settings() +		: LLSingleton<Settings>(), +		mSettingsConfig(new SettingsConfig()) +	{ +	} + +	SettingsConfigPtr Settings::getSettingsConfig() +	{ +		return mSettingsConfig;  	} -	Settings* Settings::saveAndReset() +	void Settings::reset()  	{ -		Globals::get().invalidateCallSites(); -		 -		Settings*& p = getPtr(); -		Settings* originalSettings = p; -		p = new Settings(); -		return originalSettings; +		Globals::getInstance()->invalidateCallSites(); +		mSettingsConfig = new SettingsConfig();  	} -	void Settings::restore(Settings* originalSettings) +	SettingsStoragePtr Settings::saveAndReset()  	{ -		Globals::get().invalidateCallSites(); -		 -		Settings*& p = getPtr(); -		delete p; -		p = originalSettings; +		SettingsStoragePtr oldSettingsConfig(mSettingsConfig.get()); +		reset(); +		return oldSettingsConfig;  	} -	Settings*& Settings::getPtr() +	void Settings::restore(SettingsStoragePtr pSettingsStorage)  	{ -		static Settings* currentSettings = NULL; -		return currentSettings; +		Globals::getInstance()->invalidateCallSites(); +		SettingsConfigPtr newSettingsConfig(dynamic_cast<SettingsConfig *>(pSettingsStorage.get())); +		mSettingsConfig = newSettingsConfig;  	}  } @@ -604,7 +603,7 @@ namespace  	void commonInit(const std::string& dir, bool log_to_stderr = true)  	{ -		LLError::Settings::reset(); +		LLError::Settings::getInstance()->reset();  		LLError::setDefaultLevel(LLError::LEVEL_INFO);  		LLError::setFatalFunction(LLError::crashAndLoop); @@ -613,11 +612,13 @@ namespace  		// log_to_stderr is only false in the unit and integration tests to keep builds quieter  		if (log_to_stderr && shouldLogToStderr())  		{ -			LLError::addRecorder(new RecordToStderr(stderrLogWantsTime())); +			LLError::RecorderPtr recordToStdErr(new RecordToStderr(stderrLogWantsTime())); +			LLError::addRecorder(recordToStdErr);  		}  #if LL_WINDOWS -		LLError::addRecorder(new RecordToWinDebug); +		LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); +		LLError::addRecorder(recordToWinDebug);  #endif  		LogControlFile& e = LogControlFile::fromDirectory(dir); @@ -645,7 +646,8 @@ namespace LLError  		}  		commonInit(dir);  #if !LL_WINDOWS -		addRecorder(new RecordToSyslog(identity)); +		LLError::RecorderPtr recordToSyslog(new RecordToSyslog(identity)); +		addRecorder(recordToSyslog);  #endif  	} @@ -656,72 +658,67 @@ namespace LLError  	void setPrintLocation(bool print)  	{ -		Settings& s = Settings::get(); -		s.mPrintLocation = print; +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mPrintLocation = print;  	}  	void setFatalFunction(const FatalFunction& f)  	{ -		Settings& s = Settings::get(); -		s.mCrashFunction = f; +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mCrashFunction = f;  	}      FatalFunction getFatalFunction()      { -        Settings& s = Settings::get(); -        return s.mCrashFunction; +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +        return s->mCrashFunction;      }  	void setTimeFunction(TimeFunction f)  	{ -		Settings& s = Settings::get(); -		s.mTimeFunction = f; +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mTimeFunction = f;  	}  	void setDefaultLevel(ELevel level)  	{ -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); -		g.invalidateCallSites(); -		s.mDefaultLevel = level; +		Globals::getInstance()->invalidateCallSites(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mDefaultLevel = level;  	}  	ELevel getDefaultLevel()  	{ -		Settings& s = Settings::get(); -		return s.mDefaultLevel; +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		return s->mDefaultLevel;  	}  	void setFunctionLevel(const std::string& function_name, ELevel level)  	{ -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); -		g.invalidateCallSites(); -		s.mFunctionLevelMap[function_name] = level; +		Globals::getInstance()->invalidateCallSites(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mFunctionLevelMap[function_name] = level;  	}  	void setClassLevel(const std::string& class_name, ELevel level)  	{ -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); -		g.invalidateCallSites(); -		s.mClassLevelMap[class_name] = level; +		Globals::getInstance()->invalidateCallSites(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mClassLevelMap[class_name] = level;  	}  	void setFileLevel(const std::string& file_name, ELevel level)  	{ -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); -		g.invalidateCallSites(); -		s.mFileLevelMap[file_name] = level; +		Globals::getInstance()->invalidateCallSites(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mFileLevelMap[file_name] = level;  	}  	void setTagLevel(const std::string& tag_name, ELevel level)  	{ -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); -		g.invalidateCallSites(); -		s.mTagLevelMap[tag_name] = level; +		Globals::getInstance()->invalidateCallSites(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mTagLevelMap[tag_name] = level;  	}  	LLError::ELevel decodeLevel(std::string name) @@ -765,15 +762,14 @@ namespace LLError  {  	void configure(const LLSD& config)  	{ -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); +		Globals::getInstance()->invalidateCallSites(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); -		g.invalidateCallSites(); -		s.mFunctionLevelMap.clear(); -		s.mClassLevelMap.clear(); -		s.mFileLevelMap.clear(); -		s.mTagLevelMap.clear(); -		s.mUniqueLogMessages.clear(); +		s->mFunctionLevelMap.clear(); +		s->mClassLevelMap.clear(); +		s->mFileLevelMap.clear(); +		s->mTagLevelMap.clear(); +		s->mUniqueLogMessages.clear();  		setPrintLocation(config["print-location"]);  		setDefaultLevel(decodeLevel(config["default-level"])); @@ -786,10 +782,10 @@ namespace LLError  			ELevel level = decodeLevel(entry["level"]); -			setLevels(s.mFunctionLevelMap,	entry["functions"],	level); -			setLevels(s.mClassLevelMap,		entry["classes"],	level); -			setLevels(s.mFileLevelMap,		entry["files"],		level); -			setLevels(s.mTagLevelMap,		entry["tags"],		level); +			setLevels(s->mFunctionLevelMap,	entry["functions"],	level); +			setLevels(s->mClassLevelMap,	entry["classes"],	level); +			setLevels(s->mFileLevelMap,		entry["files"],		level); +			setLevels(s->mTagLevelMap,		entry["tags"],		level);  		}  	}  } @@ -803,10 +799,12 @@ namespace LLError  		mWantsLevel(true),  		mWantsLocation(false),  		mWantsFunctionName(true) -	{} +	{ +	}  	Recorder::~Recorder() -		{ } +	{ +	}  	bool Recorder::wantsTime()  	{  @@ -837,25 +835,25 @@ namespace LLError  		return mWantsFunctionName;  	} -	void addRecorder(Recorder* recorder) +	void addRecorder(RecorderPtr recorder)  	{ -		if (recorder == NULL) +		if (!recorder)  		{  			return;  		} -		Settings& s = Settings::get(); -		s.mRecorders.push_back(recorder); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mRecorders.push_back(recorder);  	} -	void removeRecorder(Recorder* recorder) +	void removeRecorder(RecorderPtr recorder)  	{ -		if (recorder == NULL) +		if (!recorder)  		{  			return;  		} -		Settings& s = Settings::get(); -		s.mRecorders.erase(std::remove(s.mRecorders.begin(), s.mRecorders.end(), recorder), -							s.mRecorders.end()); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), +							s->mRecorders.end());  	}  } @@ -863,51 +861,47 @@ namespace LLError  {  	void logToFile(const std::string& file_name)  	{ -		LLError::Settings& s = LLError::Settings::get(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); -		removeRecorder(s.mFileRecorder); -		delete s.mFileRecorder; -		s.mFileRecorder = NULL; -		s.mFileRecorderFileName.clear(); +		removeRecorder(s->mFileRecorder); +		s->mFileRecorder.reset(); +		s->mFileRecorderFileName.clear();  		if (file_name.empty())  		{  			return;  		} -		RecordToFile* f = new RecordToFile(file_name); -		if (!f->okay()) +		RecorderPtr recordToFile(new RecordToFile(file_name)); +		if (boost::dynamic_pointer_cast<RecordToFile>(recordToFile)->okay())  		{ -			delete f; -			return; +			s->mFileRecorderFileName = file_name; +			s->mFileRecorder = recordToFile; +			addRecorder(recordToFile);  		} - -		s.mFileRecorderFileName = file_name; -		s.mFileRecorder = f; -		addRecorder(f);  	}  	void logToFixedBuffer(LLLineBuffer* fixedBuffer)  	{ -		LLError::Settings& s = LLError::Settings::get(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); -		removeRecorder(s.mFixedBufferRecorder); -		delete s.mFixedBufferRecorder; -		s.mFixedBufferRecorder = NULL; +		removeRecorder(s->mFixedBufferRecorder); +		s->mFixedBufferRecorder.reset();  		if (!fixedBuffer)  		{  			return;  		} -		s.mFixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); -		addRecorder(s.mFixedBufferRecorder); +		RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); +		s->mFixedBufferRecorder = recordToFixedBuffer; +		addRecorder(recordToFixedBuffer);  	}  	std::string logFileName()  	{ -		LLError::Settings& s = LLError::Settings::get(); -		return s.mFileRecorderFileName; +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		return s->mFileRecorderFileName;  	}  } @@ -916,24 +910,24 @@ namespace  	void writeToRecorders(const LLError::CallSite& site, const std::string& message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true)  	{  		LLError::ELevel level = site.mLevel; -		LLError::Settings& s = LLError::Settings::get(); +		LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig(); -		for (Recorders::const_iterator i = s.mRecorders.begin(); -			i != s.mRecorders.end(); +		for (Recorders::const_iterator i = s->mRecorders.begin(); +			i != s->mRecorders.end();  			++i)  		{ -			LLError::Recorder* r = *i; +			LLError::RecorderPtr r = *i;  			std::ostringstream message_stream; -			if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s.mPrintLocation)) +			if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s->mPrintLocation))  			{  				message_stream << site.mLocationString << " ";  			} -			if (show_time && r->wantsTime() && s.mTimeFunction != NULL) +			if (show_time && r->wantsTime() && s->mTimeFunction != NULL)  			{ -				message_stream << s.mTimeFunction() << " "; +				message_stream << s->mTimeFunction() << " ";  			}  			if (show_level && r->wantsLevel()) @@ -1060,10 +1054,9 @@ namespace LLError  			return false;  		} -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); -		s.mShouldLogCallCounter++; +		s->mShouldLogCallCounter++;  		const std::string& class_name = className(site.mClassInfo);  		std::string function_name = functionName(site.mFunction); @@ -1077,21 +1070,21 @@ namespace LLError  			function_name = class_name + "::" + function_name;  		} -		ELevel compareLevel = s.mDefaultLevel; +		ELevel compareLevel = s->mDefaultLevel;  		// The most specific match found will be used as the log level,  		// since the computation short circuits.  		// So, in increasing order of importance:  		// Default < Tags < File < Class < Function -		checkLevelMap(s.mFunctionLevelMap, function_name, compareLevel) -		|| checkLevelMap(s.mClassLevelMap, class_name, compareLevel) -		|| checkLevelMap(s.mFileLevelMap, abbreviateFile(site.mFile), compareLevel) +		checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) +		|| checkLevelMap(s->mClassLevelMap, class_name, compareLevel) +		|| checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel)  		|| (site.mTagCount > 0 -			? checkLevelMap(s.mTagLevelMap, site.mTags, site.mTagCount, compareLevel)  +			? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel)   			: false);  		site.mCached = true; -		g.addCallSite(site); +		Globals::getInstance()->addCallSite(site);  		return site.mShouldLog = site.mLevel >= compareLevel;  	} @@ -1101,12 +1094,12 @@ namespace LLError  		LogLock lock;  		if (lock.ok())  		{ -			Globals& g = Globals::get(); +			Globals* g = Globals::getInstance(); -			if (!g.messageStreamInUse) +			if (!g->messageStreamInUse)  			{ -				g.messageStreamInUse = true; -				return &g.messageStream; +				g->messageStreamInUse = true; +				return &g->messageStream;  			}  		} @@ -1131,13 +1124,12 @@ namespace LLError  		   message[127] = '\0' ;  	   } -	   Globals& g = Globals::get(); - -       if (out == &g.messageStream) +	   Globals* g = Globals::getInstance(); +       if (out == &g->messageStream)         { -           g.messageStream.clear(); -           g.messageStream.str(""); -           g.messageStreamInUse = false; +           g->messageStream.clear(); +           g->messageStream.str(""); +           g->messageStreamInUse = false;         }         else         { @@ -1154,15 +1146,15 @@ namespace LLError  			return;  		} -		Globals& g = Globals::get(); -		Settings& s = Settings::get(); +		Globals* g = Globals::getInstance(); +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig();  		std::string message = out->str(); -		if (out == &g.messageStream) +		if (out == &g->messageStream)  		{ -			g.messageStream.clear(); -			g.messageStream.str(""); -			g.messageStreamInUse = false; +			g->messageStream.clear(); +			g->messageStream.str(""); +			g->messageStreamInUse = false;  		}  		else  		{ @@ -1178,8 +1170,8 @@ namespace LLError  		if (site.mPrintOnce)  		{ -			std::map<std::string, unsigned int>::iterator messageIter = s.mUniqueLogMessages.find(message); -			if (messageIter != s.mUniqueLogMessages.end()) +			std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message); +			if (messageIter != s->mUniqueLogMessages.end())  			{  				messageIter->second++;  				unsigned int num_messages = messageIter->second; @@ -1195,7 +1187,7 @@ namespace LLError  			else   			{  				message_stream << "ONCE: "; -				s.mUniqueLogMessages[message] = 1; +				s->mUniqueLogMessages[message] = 1;  			}  		} @@ -1203,23 +1195,23 @@ namespace LLError  		writeToRecorders(site, message_stream.str()); -		if (site.mLevel == LEVEL_ERROR  &&  s.mCrashFunction) +		if (site.mLevel == LEVEL_ERROR  &&  s->mCrashFunction)  		{ -			s.mCrashFunction(message_stream.str()); +			s->mCrashFunction(message_stream.str());  		}  	}  }  namespace LLError  { -	Settings* saveAndResetSettings() +	SettingsStoragePtr saveAndResetSettings()  	{ -		return Settings::saveAndReset(); +		return Settings::getInstance()->saveAndReset();  	} -	void restoreSettings(Settings* s) +	void restoreSettings(SettingsStoragePtr pSettingsStorage)  	{ -		return Settings::restore(s); +		return Settings::getInstance()->restore(pSettingsStorage);  	}  	std::string removePrefix(std::string& s, const std::string& p) @@ -1265,8 +1257,8 @@ namespace LLError  	int shouldLogCallCount()  	{ -		Settings& s = Settings::get(); -		return s.mShouldLogCallCounter; +		SettingsConfigPtr s = Settings::getInstance()->getSettingsConfig(); +		return s->mShouldLogCallCounter;  	}  #if LL_WINDOWS @@ -1375,15 +1367,9 @@ namespace LLError  #endif  	//static -   void LLCallStacks::push(const char* function, const int line) +   void LLCallStacks::allocateStackBuffer()     { -	   CallStacksLogLock lock; -       if (!lock.ok()) -       { -           return; -       } - -	   if(!sBuffer) +	   if(sBuffer == NULL)  	   {  		   sBuffer = new char*[512] ;  		   sBuffer[0] = new char[512 * 128] ; @@ -1393,6 +1379,31 @@ namespace LLError  		   }  		   sIndex = 0 ;  	   } +   } + +   void LLCallStacks::freeStackBuffer() +   { +	   if(sBuffer != NULL) +	   { +		   delete [] sBuffer[0] ; +		   delete [] sBuffer ; +		   sBuffer = NULL ; +	   } +   } + +   //static +   void LLCallStacks::push(const char* function, const int line) +   { +	   CallStacksLogLock lock; +       if (!lock.ok()) +       { +           return; +       } + +	   if(sBuffer == NULL) +	   { +		   allocateStackBuffer(); +	   }  	   if(sIndex > 511)  	   { @@ -1424,15 +1435,9 @@ namespace LLError             return;         } -	   if(!sBuffer) +	   if(sBuffer == NULL)  	   { -		   sBuffer = new char*[512] ; -		   sBuffer[0] = new char[512 * 128] ; -		   for(S32 i = 1 ; i < 512 ; i++) -		   { -			   sBuffer[i] = sBuffer[i-1] + 128 ; -		   } -		   sIndex = 0 ; +		   allocateStackBuffer();  	   }  	   if(sIndex > 511) @@ -1463,11 +1468,9 @@ namespace LLError             LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL;         } -	   if(sBuffer) +	   if(sBuffer != NULL)  	   { -		   delete[] sBuffer[0] ; -		   delete[] sBuffer ; -		   sBuffer = NULL ; +		   freeStackBuffer();  	   }     } @@ -1477,5 +1480,10 @@ namespace LLError         sIndex = 0 ;     } +   //static +   void LLCallStacks::cleanup() +   { +	   freeStackBuffer(); +   }  } diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index bc80e64423..63040e1772 100755 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -261,6 +261,9 @@ namespace LLError     private:         static char**  sBuffer ;  	   static S32     sIndex ; + +	   static void allocateStackBuffer(); +	   static void freeStackBuffer();     public:     	   static void push(const char* function, const int line) ; @@ -268,6 +271,7 @@ namespace LLError         static void print() ;         static void clear() ;  	   static void end(std::ostringstream* _out) ; +	   static void cleanup();     };   } diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index aab695094c..56ac52e5de 100755 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -29,7 +29,10 @@  #define LL_LLERRORCONTROL_H  #include "llerror.h" +#include "llpointer.h" +#include "llrefcount.h"  #include "boost/function.hpp" +#include "boost/shared_ptr.hpp"  #include <string>  class LLSD; @@ -156,16 +159,14 @@ namespace LLError  				mWantsFunctionName;  	}; +	typedef boost::shared_ptr<Recorder> RecorderPtr; +  	/** -	 * @NOTE: addRecorder() conveys ownership to the underlying Settings -	 * object -- when destroyed, it will @em delete the passed Recorder*! -	 */ -	LL_COMMON_API void addRecorder(Recorder*); -	/** -	 * @NOTE: removeRecorder() reclaims ownership of the Recorder*: its -	 * lifespan becomes the caller's problem. +	 * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership +	 * while still ensuring that the allocated memory is eventually freed  	 */ -	LL_COMMON_API void removeRecorder(Recorder*); +	LL_COMMON_API void addRecorder(RecorderPtr); +	LL_COMMON_API void removeRecorder(RecorderPtr);  		// each error message is passed to each recorder via recordMessage()  	LL_COMMON_API void logToFile(const std::string& filename); @@ -182,9 +183,9 @@ namespace LLError  		Utilities for use by the unit tests of LLError itself.  	*/ -	class Settings; -	LL_COMMON_API Settings* saveAndResetSettings(); -	LL_COMMON_API void restoreSettings(Settings *); +	typedef LLPointer<LLRefCount> SettingsStoragePtr; +	LL_COMMON_API SettingsStoragePtr saveAndResetSettings(); +	LL_COMMON_API void restoreSettings(SettingsStoragePtr pSettingsStorage);  	LL_COMMON_API std::string abbreviateFile(const std::string& filePath);  	LL_COMMON_API int shouldLogCallCount(); diff --git a/indra/llcommon/llhttpstatuscodes.h b/indra/llcommon/llhttpstatuscodes.h deleted file mode 100755 index 0173461dad..0000000000 --- a/indra/llcommon/llhttpstatuscodes.h +++ /dev/null @@ -1,89 +0,0 @@ -/**  - * @file llhttpstatuscodes.h - * @brief Constants for HTTP status codes - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_HTTP_STATUS_CODES_H -#define LL_HTTP_STATUS_CODES_H - -#include "stdtypes.h" - -// Standard errors from HTTP spec: -// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1 -const S32 HTTP_CONTINUE = 100; -const S32 HTTP_SWITCHING_PROTOCOLS = 101; - -// Success -const S32 HTTP_OK = 200; -const S32 HTTP_CREATED = 201; -const S32 HTTP_ACCEPTED = 202; -const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203; -const S32 HTTP_NO_CONTENT = 204; -const S32 HTTP_RESET_CONTENT = 205; -const S32 HTTP_PARTIAL_CONTENT = 206; - -// Redirection -const S32 HTTP_MULTIPLE_CHOICES = 300; -const S32 HTTP_MOVED_PERMANENTLY = 301; -const S32 HTTP_FOUND = 302; -const S32 HTTP_SEE_OTHER = 303; -const S32 HTTP_NOT_MODIFIED = 304; -const S32 HTTP_USE_PROXY = 305; -const S32 HTTP_TEMPORARY_REDIRECT = 307; - -// Client Error -const S32 HTTP_BAD_REQUEST = 400; -const S32 HTTP_UNAUTHORIZED = 401; -const S32 HTTP_PAYMENT_REQUIRED = 402; -const S32 HTTP_FORBIDDEN = 403; -const S32 HTTP_NOT_FOUND = 404; -const S32 HTTP_METHOD_NOT_ALLOWED = 405; -const S32 HTTP_NOT_ACCEPTABLE = 406; -const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; -const S32 HTTP_REQUEST_TIME_OUT = 408; -const S32 HTTP_CONFLICT = 409; -const S32 HTTP_GONE = 410; -const S32 HTTP_LENGTH_REQUIRED = 411; -const S32 HTTP_PRECONDITION_FAILED = 412; -const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413; -const S32 HTTP_REQUEST_URI_TOO_LARGE = 414; -const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415; -const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; -const S32 HTTP_EXPECTATION_FAILED = 417; - -// Server Error -const S32 HTTP_INTERNAL_SERVER_ERROR = 500; -const S32 HTTP_NOT_IMPLEMENTED = 501; -const S32 HTTP_BAD_GATEWAY = 502; -const S32 HTTP_SERVICE_UNAVAILABLE = 503; -const S32 HTTP_GATEWAY_TIME_OUT = 504; -const S32 HTTP_VERSION_NOT_SUPPORTED = 505; - -// We combine internal process errors with status codes -// These status codes should not be sent over the wire -//   and indicate something went wrong internally. -// If you get these they are not normal. -const S32 HTTP_INTERNAL_ERROR = 499; - -#endif diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 2532566319..7aa87fcd0e 100755 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -31,6 +31,7 @@  #include <vector>  #include <list>  #include <boost/function.hpp> +#include <boost/shared_ptr.hpp>  #include <boost/type_traits/is_convertible.hpp>  #include <boost/type_traits/is_enum.hpp>  #include <boost/unordered_map.hpp> @@ -629,7 +630,7 @@ namespace LLInitParam  		UserData*			mUserData;  	}; -	typedef ParamDescriptor* ParamDescriptorPtr; +	typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;  	// each derived Block class keeps a static data structure maintaining offsets to various params  	class LL_COMMON_API BlockDescriptor diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index c9ebc70d19..9a6453ea48 100755 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -166,6 +166,132 @@ protected:  	Type*	mPointer;  }; +template <class Type> class LLConstPointer +{ +public: +	LLConstPointer() :  +		mPointer(NULL) +	{ +	} + +	LLConstPointer(const Type* ptr) :  +		mPointer(ptr) +	{ +		ref(); +	} + +	LLConstPointer(const LLConstPointer<Type>& ptr) :  +		mPointer(ptr.mPointer) +	{ +		ref(); +	} + +	// support conversion up the type hierarchy.  See Item 45 in Effective C++, 3rd Ed. +	template<typename Subclass> +	LLConstPointer(const LLConstPointer<Subclass>& ptr) :  +		mPointer(ptr.get()) +	{ +		ref(); +	} + +	~LLConstPointer() +	{ +		unref(); +	} + +	const Type*	get() const						{ return mPointer; } +	const Type*	operator->() const				{ return mPointer; } +	const Type&	operator*() const				{ return *mPointer; } + +	operator BOOL()  const						{ return (mPointer != NULL); } +	operator bool()  const						{ return (mPointer != NULL); } +	bool operator!() const						{ return (mPointer == NULL); } +	bool isNull() const							{ return (mPointer == NULL); } +	bool notNull() const						{ return (mPointer != NULL); } + +	operator const Type*()       const			{ return mPointer; } +	bool operator !=(const Type* ptr) const     { return (mPointer != ptr); 	} +	bool operator ==(const Type* ptr) const     { return (mPointer == ptr); 	} +	bool operator ==(const LLConstPointer<Type>& ptr) const           { return (mPointer == ptr.mPointer); 	} +	bool operator < (const LLConstPointer<Type>& ptr) const           { return (mPointer < ptr.mPointer); 	} +	bool operator > (const LLConstPointer<Type>& ptr) const           { return (mPointer > ptr.mPointer); 	} + +	LLConstPointer<Type>& operator =(const Type* ptr)                    +	{ +		if( mPointer != ptr ) +		{ +			unref();  +			mPointer = ptr;  +			ref(); +		} + +		return *this;  +	} + +	LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr)   +	{  +		if( mPointer != ptr.mPointer ) +		{ +			unref();  +			mPointer = ptr.mPointer; +			ref(); +		} +		return *this;  +	} + +	// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. +	template<typename Subclass> +	LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr)   +	{  +		if( mPointer != ptr.get() ) +		{ +			unref();  +			mPointer = ptr.get(); +			ref(); +		} +		return *this;  +	} +	 +	// Just exchange the pointers, which will not change the reference counts. +	static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b) +	{ +		const Type* temp = a.mPointer; +		a.mPointer = b.mPointer; +		b.mPointer = temp; +	} + +protected: +#ifdef LL_LIBRARY_INCLUDE +	void ref();                              +	void unref(); +#else +	void ref()                              +	{  +		if (mPointer) +		{ +			mPointer->ref(); +		} +	} + +	void unref() +	{ +		if (mPointer) +		{ +			const Type *tempp = mPointer; +			mPointer = NULL; +			tempp->unref(); +			if (mPointer != NULL) +			{ +				LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; +				unref(); +			} +		} +	} +#endif +protected: +	const Type*	mPointer; +}; +  template<typename Type>  class LLCopyOnWritePointer : public LLPointer<Type>  { diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index f962485284..d8bbb3a74f 100755 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -126,7 +126,9 @@ public:  	virtual UUID	asUUID() const				{ return LLUUID(); }  	virtual Date	asDate() const				{ return LLDate(); }  	virtual URI		asURI() const				{ return LLURI(); } -	virtual Binary	asBinary() const			{ return std::vector<U8>(); } +	virtual const Binary&	asBinary() const	{ static const std::vector<U8> empty; return empty; } + +	virtual const String& asStringRef() const { static const std::string empty; return empty; }   	virtual bool has(const String&) const		{ return false; }  	virtual LLSD get(const String&) const		{ return LLSD(); } @@ -270,6 +272,7 @@ namespace  		virtual LLSD::Date		asDate() const	{ return LLDate(mValue); }  		virtual LLSD::URI		asURI() const	{ return LLURI(mValue); }  		virtual int				size() const	{ return mValue.size(); } +		virtual const LLSD::String&	asStringRef() const { return mValue; }  	};  	LLSD::Integer	ImplString::asInteger() const @@ -348,7 +351,7 @@ namespace  	public:  		ImplBinary(const LLSD::Binary& v) : Base(v) { } -		virtual LLSD::Binary	asBinary() const{ return mValue; } +		virtual const LLSD::Binary&	asBinary() const{ return mValue; }  	}; @@ -840,7 +843,9 @@ LLSD::String	LLSD::asString() const	{ return safe(impl).asString(); }  LLSD::UUID		LLSD::asUUID() const	{ return safe(impl).asUUID(); }  LLSD::Date		LLSD::asDate() const	{ return safe(impl).asDate(); }  LLSD::URI		LLSD::asURI() const		{ return safe(impl).asURI(); } -LLSD::Binary	LLSD::asBinary() const	{ return safe(impl).asBinary(); } +const LLSD::Binary&	LLSD::asBinary() const	{ return safe(impl).asBinary(); } + +const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); }  // const char * helpers  LLSD::LLSD(const char* v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index deb87d7497..7b9b1285f5 100755 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -249,7 +249,10 @@ public:  		UUID	asUUID() const;  		Date	asDate() const;  		URI		asURI() const; -		Binary	asBinary() const; +		const Binary&	asBinary() const; + +		// asStringRef on any non-string type will return a ref to an empty string. +		const String&	asStringRef() const;  		operator Boolean() const	{ return asBoolean(); }  		operator Integer() const	{ return asInteger(); } diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 04d7a6ed56..b2add301f9 100755 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -873,7 +873,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const  {  /**   * Undefined: '!'<br> - * Boolean: 't' for true 'f' for false<br> + * Boolean: '1' for true '0' for false<br>   * Integer: 'i' + 4 bytes network byte order<br>   * Real: 'r' + 8 bytes IEEE double<br>   * UUID: 'u' + 16 byte unsigned integer<br> @@ -1261,12 +1261,37 @@ std::string LLSDNotationFormatter::escapeString(const std::string& in)  // virtual  S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 options) const  { +	S32 rv = format_impl(data, ostr, options, 0); +	return rv; +} + +S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const +{  	S32 format_count = 1; +	std::string pre; +	std::string post; + +	if (options & LLSDFormatter::OPTIONS_PRETTY) +	{ +		for (U32 i = 0; i < level; i++) +		{ +			pre += "    "; +		} +		post = "\n"; +	} +  	switch(data.type())  	{  	case LLSD::TypeMap:  	{ +		if (0 != level) ostr << post << pre;  		ostr << "{"; +		std::string inner_pre; +		if (options & LLSDFormatter::OPTIONS_PRETTY) +		{ +			inner_pre = pre + "    "; +		} +  		bool need_comma = false;  		LLSD::map_const_iterator iter = data.beginMap();  		LLSD::map_const_iterator end = data.endMap(); @@ -1274,18 +1299,18 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti  		{  			if(need_comma) ostr << ",";  			need_comma = true; -			ostr << '\''; +			ostr << post << inner_pre << '\'';  			serialize_string((*iter).first, ostr);  			ostr << "':"; -			format_count += format((*iter).second, ostr); +			format_count += format_impl((*iter).second, ostr, options, level + 2);  		} -		ostr << "}"; +		ostr << post << pre << "}";  		break;  	}  	case LLSD::TypeArray:  	{ -		ostr << "["; +		ostr << post << pre << "[";  		bool need_comma = false;  		LLSD::array_const_iterator iter = data.beginArray();  		LLSD::array_const_iterator end = data.endArray(); @@ -1293,7 +1318,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti  		{  			if(need_comma) ostr << ",";  			need_comma = true; -			format_count += format(*iter, ostr); +			format_count += format_impl(*iter, ostr, options, level + 1);  		}  		ostr << "]";  		break; @@ -1343,7 +1368,7 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti  	case LLSD::TypeString:  		ostr << '\''; -		serialize_string(data.asString(), ostr); +		serialize_string(data.asStringRef(), ostr);  		ostr << '\'';  		break; @@ -1360,9 +1385,26 @@ S32 LLSDNotationFormatter::format(const LLSD& data, std::ostream& ostr, U32 opti  	case LLSD::TypeBinary:  	{  		// *FIX: memory inefficient. -		std::vector<U8> buffer = data.asBinary(); +		const std::vector<U8>& buffer = data.asBinary();  		ostr << "b(" << buffer.size() << ")\""; -		if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); +		if(buffer.size()) +		{ +			if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) +			{ +				std::ios_base::fmtflags old_flags = ostr.flags(); +				ostr.setf( std::ios::hex, std::ios::basefield ); +				ostr << "0x"; +				for (int i = 0; i < buffer.size(); i++) +				{ +					ostr << (int) buffer[i]; +				} +				ostr.flags(old_flags); +			} +			else +			{ +				ostr.write((const char*)&buffer[0], buffer.size()); +			} +		}  		ostr << "\"";  		break;  	} @@ -1460,7 +1502,7 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option  	case LLSD::TypeString:  		ostr.put('s'); -		formatString(data.asString(), ostr); +		formatString(data.asStringRef(), ostr);  		break;  	case LLSD::TypeDate: @@ -1478,9 +1520,8 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option  	case LLSD::TypeBinary:  	{ -		// *FIX: memory inefficient.  		ostr.put('b'); -		std::vector<U8> buffer = data.asBinary(); +		const std::vector<U8>& buffer = data.asBinary();  		U32 size_nbo = htonl(buffer.size());  		ostr.write((const char*)(&size_nbo), sizeof(U32));  		if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index e7a5507385..23a0c8cfb1 100755 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -416,7 +416,8 @@ public:  	typedef enum e_formatter_options_type  	{  		OPTIONS_NONE = 0, -		OPTIONS_PRETTY = 1 +		OPTIONS_PRETTY = 1, +		OPTIONS_PRETTY_BINARY = 2  	} EFormatterOptions;  	/**  @@ -507,6 +508,17 @@ public:  	 * @return Returns The number of LLSD objects fomatted out  	 */  	virtual S32 format(const LLSD& data, std::ostream& ostr, U32 options = LLSDFormatter::OPTIONS_NONE) const; + +protected: + +	/**  +	 * @brief Implementation to format the data. This is called recursively. +	 * +	 * @param data The data to write. +	 * @param ostr The destination stream for the data. +	 * @return Returns The number of LLSD objects fomatted out +	 */ +	S32 format_impl(const LLSD& data, std::ostream& ostr, U32 options, U32 level) const;  }; @@ -634,7 +646,7 @@ protected:   *  </code>   *   * *NOTE - formerly this class inherited from its template parameter Formatter, - * but all insnatiations passed in LLRefCount subclasses.  This conflicted with + * but all instantiations passed in LLRefCount subclasses.  This conflicted with   * the auto allocation intended for this class template (demonstrated in the   * example above).  -brad   */ @@ -720,6 +732,18 @@ public:  		LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter;  		return f->format(sd, str, LLSDFormatter::OPTIONS_NONE);  	} +	static S32 toPrettyNotation(const LLSD& sd, std::ostream& str) +	{ +		LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; +		return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); +	} +	static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) +	{ +		LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; +		return f->format(sd, str,  +				LLSDFormatter::OPTIONS_PRETTY |  +				LLSDFormatter::OPTIONS_PRETTY_BINARY); +	}  	static S32 fromNotation(LLSD& sd, std::istream& str, S32 max_bytes)  	{  		LLPointer<LLSDNotationParser> p = new LLSDNotationParser; diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 4e2af0e589..e1a91f1367 100755 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -168,8 +168,8 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti  		break;  	case LLSD::TypeString: -		if(data.asString().empty()) ostr << pre << "<string />" << post; -		else ostr << pre << "<string>" << escapeString(data.asString()) <<"</string>" << post; +		if(data.asStringRef().empty()) ostr << pre << "<string />" << post; +		else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post;  		break;  	case LLSD::TypeDate: @@ -182,7 +182,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti  	case LLSD::TypeBinary:  	{ -		LLSD::Binary buffer = data.asBinary(); +		const LLSD::Binary& buffer = data.asBinary();  		if(buffer.empty())  		{  			ostr << pre << "<binary />" << post; @@ -375,13 +375,10 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)  		{  			break;  		} +		count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); +		if (!count)  		{ -		 -			count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); -			if (!count) -			{ -				break; -			} +			break;  		}  		status = XML_ParseBuffer(mParser, count, false); diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 803417d368..562fd26658 100755 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -182,7 +182,7 @@ char* ll_pretty_print_sd_ptr(const LLSD* sd)  char* ll_pretty_print_sd(const LLSD& sd)  { -	const U32 bufferSize = 10 * 1024; +	const U32 bufferSize = 100 * 1024;  	static char buffer[bufferSize];  	std::ostringstream stream;  	//stream.rdbuf()->pubsetbuf(buffer, bufferSize); diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 0699dcda83..dd8660a3c8 100755 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -132,10 +132,14 @@ public:  };  typedef std::vector<LLUUID> uuid_vec_t; - - -// Helper structure for ordering lluuids in stl containers. -// eg: 	std::map<LLUUID, LLWidget*, lluuid_less> widget_map; +typedef std::set<LLUUID> uuid_set_t; + +// Helper structure for ordering lluuids in stl containers.  eg: +// std::map<LLUUID, LLWidget*, lluuid_less> widget_map; +// +// (isn't this the default behavior anyway? I think we could +// everywhere replace these with uuid_set_t, but someone should +// verify.)  struct lluuid_less  {  	bool operator()(const LLUUID& lhs, const LLUUID& rhs) const @@ -145,7 +149,6 @@ struct lluuid_less  };  typedef std::set<LLUUID, lluuid_less> uuid_list_t; -  /*   * Sub-classes for keeping transaction IDs and asset IDs   * straight. diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index b28c5ba4b3..a5aaff10c5 100755 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -56,9 +56,9 @@ namespace tut  	{  	public:  		TestRecorder() { mWantsTime = false; } -		~TestRecorder() { LLError::removeRecorder(this); } +		virtual ~TestRecorder() {  } -		void recordMessage(LLError::ELevel level, +		virtual void recordMessage(LLError::ELevel level,  						   const std::string& message)  		{  			mMessages.push_back(message); @@ -85,15 +85,11 @@ namespace tut  	struct ErrorTestData  	{ -		// addRecorder() expects to be able to later delete the passed -		// Recorder*. Even though removeRecorder() reclaims ownership, passing -		// a pointer to a data member rather than a heap Recorder subclass -		// instance would just be Wrong. -		TestRecorder* mRecorder; -		LLError::Settings* mPriorErrorSettings; +		LLError::RecorderPtr mRecorder; +		LLError::SettingsStoragePtr mPriorErrorSettings;  		ErrorTestData(): -			mRecorder(new TestRecorder) +			mRecorder(new TestRecorder())  		{  			fatalWasCalled = false; @@ -106,13 +102,32 @@ namespace tut  		~ErrorTestData()  		{  			LLError::removeRecorder(mRecorder); -			delete mRecorder;  			LLError::restoreSettings(mPriorErrorSettings);  		} +		int countMessages() +		{ +			return boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->countMessages(); +		} + +		void clearMessages() +		{ +			boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->clearMessages(); +		} + +		void setWantsTime(bool t) +		{ +			boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->setWantsTime(t); +		} + +		std::string message(int n) +		{ +			return boost::dynamic_pointer_cast<TestRecorder>(mRecorder)->message(n); +		} +  		void ensure_message_count(int expectedCount)  		{ -			ensure_equals("message count", mRecorder->countMessages(), expectedCount); +			ensure_equals("message count", countMessages(), expectedCount);  		}  		void ensure_message_contains(int n, const std::string& expectedText) @@ -120,7 +135,7 @@ namespace tut  			std::ostringstream test_name;  			test_name << "testing message " << n; -			ensure_contains(test_name.str(), mRecorder->message(n), expectedText); +			ensure_contains(test_name.str(), message(n), expectedText);  		}  		void ensure_message_does_not_contain(int n, const std::string& expectedText) @@ -128,7 +143,7 @@ namespace tut  			std::ostringstream test_name;  			test_name << "testing message " << n; -			ensure_does_not_contain(test_name.str(), mRecorder->message(n), expectedText); +			ensure_does_not_contain(test_name.str(), message(n), expectedText);  		}  	}; @@ -385,15 +400,15 @@ namespace  	}  	typedef std::string (*LogFromFunction)(bool); -	void testLogName(tut::TestRecorder* recorder, LogFromFunction f, +	void testLogName(LLError::RecorderPtr recorder, LogFromFunction f,  		const std::string& class_name = "")  	{ -		recorder->clearMessages(); +		boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->clearMessages();  		std::string name = f(false);  		f(true); -		std::string messageWithoutName = recorder->message(0); -		std::string messageWithName = recorder->message(1); +		std::string messageWithoutName = boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(0); +		std::string messageWithName = boost::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(1);  		ensure_has(name + " logged without name",  			messageWithoutName, name); @@ -528,12 +543,12 @@ namespace tut  	{  		LLError::setTimeFunction(roswell); -		mRecorder->setWantsTime(false); +		setWantsTime(false);  		ufoSighting();  		ensure_message_contains(0, "ufo");  		ensure_message_does_not_contain(0, roswell()); -		mRecorder->setWantsTime(true); +		setWantsTime(true);  		ufoSighting();  		ensure_message_contains(1, "ufo");  		ensure_message_contains(1, roswell()); @@ -545,13 +560,13 @@ namespace tut  	{  		LLError::setPrintLocation(true);  		LLError::setTimeFunction(roswell); -		mRecorder->setWantsTime(true); +		setWantsTime(true);  		std::string location,  					function;  		writeReturningLocationAndFunction(location, function);  		ensure_equals("order is location time type function message", -			mRecorder->message(0), +			message(0),  			location + roswell() + " INFO: " + function + ": apple");  	} @@ -559,19 +574,19 @@ namespace tut  		// multiple recorders  	void ErrorTestObject::test<11>()  	{ -		TestRecorder* altRecorder(new TestRecorder); +		LLError::RecorderPtr altRecorder(new TestRecorder());  		LLError::addRecorder(altRecorder);  		LL_INFOS() << "boo" << LL_ENDL;  		ensure_message_contains(0, "boo"); -		ensure_equals("alt recorder count", altRecorder->countMessages(), 1); -		ensure_contains("alt recorder message 0", altRecorder->message(0), "boo"); +		ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1); +		ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo");  		LLError::setTimeFunction(roswell); -		TestRecorder* anotherRecorder(new TestRecorder); -		anotherRecorder->setWantsTime(true); +		LLError::RecorderPtr anotherRecorder(new TestRecorder()); +		boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->setWantsTime(true);  		LLError::addRecorder(anotherRecorder);  		LL_INFOS() << "baz" << LL_ENDL; @@ -579,10 +594,13 @@ namespace tut  		std::string when = roswell();  		ensure_message_does_not_contain(1, when); -		ensure_equals("alt recorder count", altRecorder->countMessages(), 2); -		ensure_does_not_contain("alt recorder message 1", altRecorder->message(1), when); -		ensure_equals("another recorder count", anotherRecorder->countMessages(), 1); -		ensure_contains("another recorder message 0", anotherRecorder->message(0), when); +		ensure_equals("alt recorder count", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 2); +		ensure_does_not_contain("alt recorder message 1", boost::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(1), when); +		ensure_equals("another recorder count", boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->countMessages(), 1); +		ensure_contains("another recorder message 0", boost::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->message(0), when); + +		LLError::removeRecorder(altRecorder); +		LLError::removeRecorder(anotherRecorder);  	}  } diff --git a/indra/llcommon/tests/stringize_test.cpp b/indra/llcommon/tests/stringize_test.cpp index 3e4ca548e5..2a4ed44a67 100755 --- a/indra/llcommon/tests/stringize_test.cpp +++ b/indra/llcommon/tests/stringize_test.cpp @@ -95,7 +95,7 @@ namespace tut          ensure_equals(stringize(f),    "3.14159");          ensure_equals(stringize(d),    "3.14159");          ensure_equals(stringize(abc),  "abc def"); -        ensure_equals(stringize(def),  "def ghi"); //Will generate llwarns due to narrowing. +        ensure_equals(stringize(def),  "def ghi"); //Will generate LL_WARNS() due to narrowing.          ensure_equals(stringize(llsd), "{'abc':'abc def','d':r3.14159,'i':i34}");      } diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 3137bd8fea..785197ba11 100755 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -38,6 +38,7 @@  #include "stringize.h"  #include <boost/bind.hpp>  #include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp>  #include <list>  #include <string>  #include <stdexcept> @@ -81,72 +82,29 @@ struct WrapLLErrs      }      std::string error; -    LLError::Settings* mPriorErrorSettings; +    LLError::SettingsStoragePtr mPriorErrorSettings;      LLError::FatalFunction mPriorFatal;  };  /** - * LLError::addRecorder() accepts ownership of the passed Recorder* -- it - * expects to be able to delete it later. CaptureLog isa Recorder whose - * pointer we want to be able to pass without any ownership implications. - * For such cases, instantiate a new RecorderProxy(yourRecorder) and pass - * that. Your heap RecorderProxy might later be deleted, but not yourRecorder. - */ -class RecorderProxy: public LLError::Recorder -{ -public: -    RecorderProxy(LLError::Recorder* recorder): -        mRecorder(recorder) -    {} - -    virtual void recordMessage(LLError::ELevel level, const std::string& message) -    { -        mRecorder->recordMessage(level, message); -    } - -    virtual bool wantsTime() -    { -        return mRecorder->wantsTime(); -    } - -private: -    LLError::Recorder* mRecorder; -}; - -/**   * Capture log messages. This is adapted (simplified) from the one in   * llerror_test.cpp.   */ -class CaptureLog : public LLError::Recorder, public boost::noncopyable +class CaptureLogRecorder : public LLError::Recorder, public boost::noncopyable  {  public: -    CaptureLog(LLError::ELevel level=LLError::LEVEL_DEBUG): -        // Mostly what we're trying to accomplish by saving and resetting -        // LLError::Settings is to bypass the default RecordToStderr and -        // RecordToWinDebug Recorders. As these are visible only inside -        // llerror.cpp, we can't just call LLError::removeRecorder() with -        // each. For certain tests we need to produce, capture and examine -        // DEBUG log messages -- but we don't want to spam the user's console -        // with that output. If it turns out that saveAndResetSettings() has -        // some bad effect, give up and just let the DEBUG level log messages -        // display. -        mOldSettings(LLError::saveAndResetSettings()), -        mProxy(new RecorderProxy(this)) +    CaptureLogRecorder() +		: LLError::Recorder(), +		boost::noncopyable(), +		mMessages()      { -        LLError::setFatalFunction(wouldHaveCrashed); -        LLError::setDefaultLevel(level); -        LLError::addRecorder(mProxy);      } -    ~CaptureLog() +    virtual ~CaptureLogRecorder()      { -        LLError::removeRecorder(mProxy); -        delete mProxy; -        LLError::restoreSettings(mOldSettings);      } -    void recordMessage(LLError::ELevel level, -                       const std::string& message) +    virtual void recordMessage(LLError::ELevel level, const std::string& message)      {          mMessages.push_back(message);      } @@ -154,7 +112,7 @@ public:      /// Don't assume the message we want is necessarily the LAST log message      /// emitted by the underlying code; search backwards through all messages      /// for the sought string. -    std::string messageWith(const std::string& search, bool required=true) +    std::string messageWith(const std::string& search, bool required)      {          for (MessageList::const_reverse_iterator rmi(mMessages.rbegin()), rmend(mMessages.rend());               rmi != rmend; ++rmi) @@ -187,14 +145,63 @@ public:          return out;      } +private:      typedef std::list<std::string> MessageList;      MessageList mMessages; -    LLError::Settings* mOldSettings; -    LLError::Recorder* mProxy; +}; + +/** + * Capture log messages. This is adapted (simplified) from the one in + * llerror_test.cpp. + */ +class CaptureLog : public boost::noncopyable +{ +public: +    CaptureLog(LLError::ELevel level=LLError::LEVEL_DEBUG) +        // Mostly what we're trying to accomplish by saving and resetting +        // LLError::Settings is to bypass the default RecordToStderr and +        // RecordToWinDebug Recorders. As these are visible only inside +        // llerror.cpp, we can't just call LLError::removeRecorder() with +        // each. For certain tests we need to produce, capture and examine +        // DEBUG log messages -- but we don't want to spam the user's console +        // with that output. If it turns out that saveAndResetSettings() has +        // some bad effect, give up and just let the DEBUG level log messages +        // display. +		: boost::noncopyable(), +        mOldSettings(LLError::saveAndResetSettings()), +		mRecorder(new CaptureLogRecorder()) +    { +        LLError::setFatalFunction(wouldHaveCrashed); +        LLError::setDefaultLevel(level); +        LLError::addRecorder(mRecorder); +    } + +    ~CaptureLog() +    { +        LLError::removeRecorder(mRecorder); +        LLError::restoreSettings(mOldSettings); +    } + +    /// Don't assume the message we want is necessarily the LAST log message +    /// emitted by the underlying code; search backwards through all messages +    /// for the sought string. +    std::string messageWith(const std::string& search, bool required=true) +    { +		return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->messageWith(search, required); +    } + +    std::ostream& streamto(std::ostream& out) const +    { +		return boost::dynamic_pointer_cast<CaptureLogRecorder>(mRecorder)->streamto(out); +    } + +private: +    LLError::SettingsStoragePtr mOldSettings; +	LLError::RecorderPtr mRecorder;  };  inline -std::ostream& operator<<(std::ostream& out, const CaptureLog& log) +std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log)  {      return log.streamto(out);  } diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp index fc257fb0c1..e56bc84174 100755 --- a/indra/llcorehttp/_httplibcurl.cpp +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -31,7 +31,7 @@  #include "_httpoprequest.h"  #include "_httppolicy.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  namespace LLCore diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp index 926031501e..43dd069bc6 100755 --- a/indra/llcorehttp/_httpoprequest.cpp +++ b/indra/llcorehttp/_httpoprequest.cpp @@ -44,7 +44,7 @@  #include "_httplibcurl.h"  #include "_httpinternal.h" -#include "llhttpstatuscodes.h" +#include "llhttpconstants.h"  #include "llproxy.h"  namespace @@ -531,6 +531,7 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)  			code = curl_easy_setopt(mCurlHandle, CURLOPT_POSTFIELDS, (void *) NULL);  			check_curl_easy_code(code, CURLOPT_POSTFIELDS);  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Expect:"); +			// *TODO: Should this be 'Keep-Alive' ?  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Connection: keep-alive");  			mCurlHeaders = curl_slist_append(mCurlHeaders, "Keep-alive: 300");  		} diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index c40deb2b72..7a97c16ea7 100755 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -52,17 +52,20 @@ BOOL gSent = false;  class LLCrashLoggerResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLCrashLoggerResponder);  public:  	LLCrashLoggerResponder()   	{  	} -	virtual void error(U32 status, const std::string& reason) +protected: +	virtual void httpFailure()  	{ +		LL_WARNS() << dumpResponse() << LL_ENDL;  		gBreak = true;  	} -	virtual void result(const LLSD& content) +	virtual void httpSuccess()  	{  		gBreak = true;  		gSent = true; diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 7fb2a801b2..11647c5518 100755 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -51,6 +51,7 @@ static const std::string INV_DESC_LABEL("desc");  static const std::string INV_PERMISSIONS_LABEL("permissions");  static const std::string INV_SHADOW_ID_LABEL("shadow_id");  static const std::string INV_ASSET_ID_LABEL("asset_id"); +static const std::string INV_LINKED_ID_LABEL("linked_id");  static const std::string INV_SALE_INFO_LABEL("sale_info");  static const std::string INV_FLAGS_LABEL("flags");  static const std::string INV_CREATION_DATE_LABEL("created_at"); @@ -257,13 +258,6 @@ BOOL LLInventoryObject::exportLegacyStream(std::ostream& output_stream, BOOL) co  	return TRUE;  } - -void LLInventoryObject::removeFromServer() -{ -	// don't do nothin' -	LL_WARNS() << "LLInventoryObject::removeFromServer() called.  Doesn't do anything." << LL_ENDL; -} -  void LLInventoryObject::updateParentOnServer(BOOL) const  {  	// don't do nothin' @@ -276,7 +270,7 @@ void LLInventoryObject::updateServer(BOOL) const  	LL_WARNS() << "LLInventoryObject::updateServer() called.  Doesn't do anything." << LL_ENDL;  } -inline +// static  void LLInventoryObject::correctInventoryName(std::string& name)  {  	LLStringUtil::replaceNonstandardASCII(name, ' '); @@ -435,12 +429,17 @@ U32 LLInventoryItem::getCRC32() const  	return crc;  } +// static +void LLInventoryItem::correctInventoryDescription(std::string& desc) +{ +	LLStringUtil::replaceNonstandardASCII(desc, ' '); +	LLStringUtil::replaceChar(desc, '|', ' '); +}  void LLInventoryItem::setDescription(const std::string& d)  {  	std::string new_desc(d); -	LLStringUtil::replaceNonstandardASCII(new_desc, ' '); -	LLStringUtil::replaceChar(new_desc, '|', ' '); +	LLInventoryItem::correctInventoryDescription(new_desc);  	if( new_desc != mDescription )  	{  		disclaimMem(mDescription); @@ -1068,11 +1067,16 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const  LLTrace::BlockTimerStatHandle FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize"); -bool LLInventoryItem::fromLLSD(const LLSD& sd) +bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new)  {  	LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SD_DESERIALIZE); -	mInventoryType = LLInventoryType::IT_NONE; -	mAssetUUID.setNull(); +	if (is_new) +	{ +		// If we're adding LLSD to an existing object, need avoid +		// clobbering these fields. +		mInventoryType = LLInventoryType::IT_NONE; +		mAssetUUID.setNull(); +	}  	std::string w;  	w = INV_ITEM_ID_LABEL; @@ -1129,6 +1133,11 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)  	{  		mAssetUUID = sd[w];  	} +	w = INV_LINKED_ID_LABEL; +	if (sd.has(w)) +	{ +		mAssetUUID = sd[w]; +	}  	w = INV_ASSET_TYPE_LABEL;  	if (sd.has(w))  	{ diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index aa0b4cc24c..70b200e139 100755 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -48,6 +48,7 @@ class LLInventoryObject : public LLRefCount, public LLTrace::MemTrackable<LLInve  {  public:  	typedef std::list<LLPointer<LLInventoryObject> > object_list_t; +	typedef std::list<LLConstPointer<LLInventoryObject> > const_object_list_t;  	//--------------------------------------------------------------------  	// Initialization @@ -86,22 +87,19 @@ public:  	void setType(LLAssetType::EType type);  	virtual void setCreationDate(time_t creation_date_utc); // only stored for items -private:  	// in place correction for inventory name string -	void correctInventoryName(std::string& name); +	static void correctInventoryName(std::string& name);  	//--------------------------------------------------------------------  	// File Support  	//   Implemented here so that a minimal information set can be transmitted  	//   between simulator and viewer.  	//-------------------------------------------------------------------- -public:  	// virtual BOOL importFile(LLFILE* fp);  	virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const;  	virtual BOOL importLegacyStream(std::istream& input_stream);  	virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const; -	virtual void removeFromServer();  	virtual void updateParentOnServer(BOOL) const;  	virtual void updateServer(BOOL) const; @@ -174,6 +172,7 @@ public:  	//--------------------------------------------------------------------  public:  	void setAssetUUID(const LLUUID& asset_id); +	static void correctInventoryDescription(std::string& name);  	void setDescription(const std::string& new_desc);  	void setSaleInfo(const LLSaleInfo& sale_info);  	void setPermissions(const LLPermissions& perm); @@ -212,7 +211,7 @@ public:  	void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);  	LLSD asLLSD() const;  	void asLLSD( LLSD& sd ) const; -	bool fromLLSD(const LLSD& sd); +	bool fromLLSD(const LLSD& sd, bool is_new = true);  	//--------------------------------------------------------------------  	// Member Variables diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index ca48e613d2..8bd134dc84 100755 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -44,6 +44,7 @@ set(llmessage_SOURCE_FILES      llhttpassetstorage.cpp      llhttpclient.cpp      llhttpclientadapter.cpp +    llhttpconstants.cpp      llhttpnode.cpp      llhttpsender.cpp      llinstantmessage.cpp @@ -59,7 +60,6 @@ set(llmessage_SOURCE_FILES      llmessagetemplate.cpp      llmessagetemplateparser.cpp      llmessagethrottle.cpp -    llmime.cpp      llnamevalue.cpp      llnullcipher.cpp      llpacketack.cpp @@ -68,7 +68,6 @@ set(llmessage_SOURCE_FILES      llpartdata.cpp      llproxy.cpp      llpumpio.cpp -    llregionpresenceverifier.cpp      llsdappservices.cpp      llsdhttpserver.cpp      llsdmessage.cpp @@ -138,6 +137,7 @@ set(llmessage_HEADER_FILES      llhttpclient.h      llhttpclientinterface.h      llhttpclientadapter.h +    llhttpconstants.h      llhttpnode.h      llhttpnodeadapter.h      llhttpsender.h @@ -156,7 +156,6 @@ set(llmessage_HEADER_FILES      llmessagetemplate.h      llmessagetemplateparser.h      llmessagethrottle.h -    llmime.h      llmsgvariabletype.h      llnamevalue.h      llnullcipher.h @@ -169,7 +168,6 @@ set(llmessage_HEADER_FILES      llqueryflags.h      llregionflags.h      llregionhandle.h -    llregionpresenceverifier.h      llsdappservices.h      llsdhttpserver.h      llsdmessage.h @@ -233,17 +231,15 @@ target_link_libraries(  # tests  if (LL_TESTS)    SET(llmessage_TEST_SOURCE_FILES -    # llhttpclientadapter.cpp -    llmime.cpp      llnamevalue.cpp      lltrustedmessageservice.cpp      lltemplatemessagedispatcher.cpp -      llregionpresenceverifier.cpp      )    LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}")    #    set(TEST_DEBUG on)    set(test_libs +    ${CURL_LIBRARIES}      ${LLMESSAGE_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES} @@ -270,6 +266,7 @@ if (LL_TESTS)    LL_ADD_INTEGRATION_TEST(llavatarnamecache "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llhost "" "${test_libs}") +  LL_ADD_INTEGRATION_TEST(llhttpclientadapter "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llpartdata "" "${test_libs}")    LL_ADD_INTEGRATION_TEST(llxfer_file "" "${test_libs}")  endif (LL_TESTS) diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp index 81e28121fd..9f90ae1544 100755 --- a/indra/llmessage/llares.cpp +++ b/indra/llmessage/llares.cpp @@ -610,6 +610,15 @@ LLAres *ll_init_ares()  	return gAres;  } +void ll_cleanup_ares() +{ +	if (gAres != NULL) +	{ +		delete gAres; +		gAres = NULL; +	} +} +  LLDnsRecord::LLDnsRecord(LLResType type, const std::string &name,  						 unsigned ttl)  	: LLRefCount(), diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h index 800781ee88..0b5d49e322 100755 --- a/indra/llmessage/llares.h +++ b/indra/llmessage/llares.h @@ -578,5 +578,6 @@ extern LLAres *gAres;   * thread safe.   */  extern LLAres *ll_init_ares(); +extern void ll_cleanup_ares();  #endif // LL_LLARES_H diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index 31dd264021..d02a60b7b2 100755 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -121,7 +121,7 @@ namespace LLAvatarNameCache  	// Erase expired names from cache  	void eraseUnrefreshed(); -	bool expirationFromCacheControl(LLSD headers, F64 *expires); +	bool expirationFromCacheControl(const LLSD& headers, F64 *expires);  }  /* Sample response: @@ -165,33 +165,31 @@ namespace LLAvatarNameCache  class LLAvatarNameResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLAvatarNameResponder);  private:  	// need to store agent ids that are part of this request in case of  	// an error, so we can flag them as unavailable  	std::vector<LLUUID> mAgentIDs; -	// Need the headers to look up Expires: and Retry-After: -	LLSD mHeaders; -	  public:  	LLAvatarNameResponder(const std::vector<LLUUID>& agent_ids) -	:	mAgentIDs(agent_ids), -		mHeaders() +	:	mAgentIDs(agent_ids)  	{ } -	/*virtual*/ void completedHeader(U32 status, const std::string& reason,  -		const LLSD& headers) -	{ -		mHeaders = headers; -	} - -	/*virtual*/ void result(const LLSD& content) +protected: +	/*virtual*/ void httpSuccess()  	{ +		const LLSD& content = getContent(); +		if (!content.isMap()) +		{ +			failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +			return; +		}  		// Pull expiration out of headers if available -		F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(mHeaders); +		F64 expires = LLAvatarNameCache::nameExpirationFromHeaders(getResponseHeaders());  		F64 now = LLFrameTimer::getTotalSeconds(); -		LLSD agents = content["agents"]; +		const LLSD& agents = content["agents"];  		LLSD::array_const_iterator it = agents.beginArray();  		for ( ; it != agents.endArray(); ++it)  		{ @@ -212,7 +210,7 @@ public:  		}  		// Same logic as error response case -		LLSD unresolved_agents = content["bad_ids"]; +		const LLSD& unresolved_agents = content["bad_ids"];  		S32  num_unresolved = unresolved_agents.size();  		if (num_unresolved > 0)  		{ @@ -236,14 +234,13 @@ public:                                   << LL_ENDL;      } -	/*virtual*/ void error(U32 status, const std::string& reason) +	/*virtual*/ void httpFailure()  	{  		// If there's an error, it might be caused by PeopleApi,  		// or when loading textures on startup and using a very slow   		// network, this query may time out.  		// What we should do depends on whether or not we have a cached name -		LL_WARNS("AvNameCache") << "LLAvatarNameResponder::error " << status << " " << reason -								<< LL_ENDL; +		LL_WARNS("AvNameCache") << dumpResponse() << LL_ENDL;  		// Add dummy records for any agent IDs in this request that we do not have cached already  		std::vector<LLUUID>::const_iterator it = mAgentIDs.begin(); @@ -700,7 +697,7 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na  	sCache[agent_id] = av_name;  } -F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers) +F64 LLAvatarNameCache::nameExpirationFromHeaders(const LLSD& headers)  {  	F64 expires = 0.0;  	if (expirationFromCacheControl(headers, &expires)) @@ -716,17 +713,21 @@ F64 LLAvatarNameCache::nameExpirationFromHeaders(LLSD headers)  	}  } -bool LLAvatarNameCache::expirationFromCacheControl(LLSD headers, F64 *expires) +bool LLAvatarNameCache::expirationFromCacheControl(const LLSD& headers, F64 *expires)  {  	bool fromCacheControl = false;  	F64 now = LLFrameTimer::getTotalSeconds();  	// Allow the header to override the default -	LLSD cache_control_header = headers["cache-control"]; -	if (cache_control_header.isDefined()) +	std::string cache_control; +	if (headers.has(HTTP_IN_HEADER_CACHE_CONTROL)) +	{ +		cache_control = headers[HTTP_IN_HEADER_CACHE_CONTROL].asString(); +	} + +	if (!cache_control.empty())  	{  		S32 max_age = 0; -		std::string cache_control = cache_control_header.asString();  		if (max_age_from_cache_control(cache_control, &max_age))  		{  			*expires = now + (F64)max_age; diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 3a19cee3ed..ea016b3125 100755 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -90,7 +90,7 @@ namespace LLAvatarNameCache  	// Compute name expiration time from HTTP Cache-Control header,  	// or return default value, in seconds from epoch. -	F64 nameExpirationFromHeaders(LLSD headers); +	F64 nameExpirationFromHeaders(const LLSD& headers);  	void addUseDisplayNamesCallback(const use_display_name_signal_t::slot_type& cb);  } diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 147940c983..73df47b933 100755 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -49,6 +49,7 @@  #include "llproxy.h"  #include "llsdserialize.h"  #include "llstl.h" +#include "llstring.h"  #include "llthread.h"  #include "lltimer.h" @@ -100,7 +101,7 @@ void check_curl_code(CURLcode code)  	{  		// linux appears to throw a curl error once per session for a bad initialization  		// at a pretty random time (when enabling cookies). -		LL_INFOS() << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL; +		LL_WARNS("curl") << "curl error detected: " << curl_easy_strerror(code) << LL_ENDL;  	}  } @@ -110,7 +111,7 @@ void check_curl_multi_code(CURLMcode code)  	{  		// linux appears to throw a curl error once per session for a bad initialization  		// at a pretty random time (when enabling cookies). -		LL_INFOS() << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL; +		LL_WARNS("curl") << "curl multi error detected: " << curl_multi_strerror(code) << LL_ENDL;  	}  } @@ -135,6 +136,7 @@ std::string LLCurl::getVersionString()  //////////////////////////////////////////////////////////////////////////////  LLCurl::Responder::Responder() +	: mHTTPMethod(HTTP_INVALID), mStatus(HTTP_INTERNAL_ERROR)  {  } @@ -144,22 +146,30 @@ LLCurl::Responder::~Responder()  }  // virtual -void LLCurl::Responder::errorWithContent( -	U32 status, -	const std::string& reason, -	const LLSD&) +void LLCurl::Responder::httpFailure()  { -	error(status, reason); +	LL_WARNS("curl") << dumpResponse() << LL_ENDL;  } -// virtual -void LLCurl::Responder::error(U32 status, const std::string& reason) +std::string LLCurl::Responder::dumpResponse() const   { -	LL_INFOS() << mURL << " [" << status << "]: " << reason << LL_ENDL; +	std::ostringstream s; +	s << "[" << httpMethodAsVerb(mHTTPMethod) << ":" << mURL << "] " +	  << "[status:" << mStatus << "] " +	  << "[reason:" << mReason << "] "; + +	if (mResponseHeaders.has(HTTP_IN_HEADER_CONTENT_TYPE)) +	{ +		s << "[content-type:" << mResponseHeaders[HTTP_IN_HEADER_CONTENT_TYPE] << "] "; +	} + +	s << "[content:" << mContent << "]"; + +	return s.str();  }  // virtual -void LLCurl::Responder::result(const LLSD& content) +void LLCurl::Responder::httpSuccess()  {  } @@ -168,44 +178,109 @@ void LLCurl::Responder::setURL(const std::string& url)  	mURL = url;  } +void LLCurl::Responder::successResult(const LLSD& content) +{ +	setResult(HTTP_OK, "", content); +	httpSuccess(); +} + +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ +	setResult(status, reason, content); +	httpFailure(); +} + +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ +	setResult(status, reason, content); +	httpCompleted(); +} + +void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */) +{ +	mStatus = status; +	mReason = reason; +	mContent = content; +} + +void LLCurl::Responder::setHTTPMethod(EHTTPMethod method) +{ +	mHTTPMethod = method; +} + +void LLCurl::Responder::setResponseHeader(const std::string& header, const std::string& value) +{ +	mResponseHeaders[header] = value; +} + +const std::string& LLCurl::Responder::getResponseHeader(const std::string& header) const +{ +	if (mResponseHeaders.has(header)) +	{ +		return mResponseHeaders[header].asStringRef(); +	} +	static const std::string empty; +	return empty; +} + +bool LLCurl::Responder::hasResponseHeader(const std::string& header) const +{ +	if (mResponseHeaders.has(header)) return true; +	return false; +} +  // virtual  void LLCurl::Responder::completedRaw( -	U32 status, -	const std::string& reason,  	const LLChannelDescriptors& channels,  	const LLIOPipe::buffer_ptr_t& buffer)  { -	LLSD content;  	LLBufferStream istr(channels, buffer.get()); -	const bool emit_errors = false; -	if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(content, istr, emit_errors)) +	const bool emit_parse_errors = false; + +	std::string debug_body("(empty)"); +	bool parsed=true; +	if (EOF == istr.peek()) +	{ +		parsed=false; +	} +	// Try to parse body as llsd, no matter what 'content-type' says. +	else if (LLSDParser::PARSE_FAILURE == LLSDSerialize::fromXML(mContent, istr, emit_parse_errors)) +	{ +		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/llsd+xml' +	if (!parsed && (HTTP_CONTENT_LLSD_XML == getResponseHeader(HTTP_IN_HEADER_CONTENT_TYPE)))  	{ -		LL_INFOS() << "Failed to deserialize LLSD. " << mURL << " [" << status << "]: " << reason << LL_ENDL; -		content["reason"] = reason; +		LL_WARNS() << "Failed to deserialize . " << mURL << " [status:" << mStatus << "] "  +			<< "(" << mReason << ") body: " << debug_body << LL_ENDL;  	} -	completed(status, reason, content); +	httpCompleted();  }  // virtual -void LLCurl::Responder::completed(U32 status, const std::string& reason, const LLSD& content) +void LLCurl::Responder::httpCompleted()  { -	if (isGoodStatus(status)) +	if (isGoodStatus())  	{ -		result(content); +		httpSuccess();  	}  	else  	{ -		errorWithContent(status, reason, content); +		httpFailure();  	}  } -//virtual -void LLCurl::Responder::completedHeader(U32 status, const std::string& reason, const LLSD& content) -{ - -} -  //////////////////////////////////////////////////////////////////////////////  std::set<CURL*> LLCurl::Easy::sFreeHandles; @@ -274,6 +349,36 @@ void LLCurl::Easy::releaseEasyHandle(CURL* handle)  	}  } +//static +void LLCurl::Easy::deleteAllActiveHandles() +{ +	LLMutexLock lock(sHandleMutexp) ; +	LL_CHECK_MEMORY +	for (std::set<CURL*>::iterator activeHandle = sActiveHandles.begin(); activeHandle != sActiveHandles.end(); ++activeHandle) +	{ +		CURL* curlHandle = *activeHandle; +		LLCurl::deleteEasyHandle(curlHandle); +		LL_CHECK_MEMORY +	} + +	sFreeHandles.clear(); +} + +//static +void LLCurl::Easy::deleteAllFreeHandles() +{ +	LLMutexLock lock(sHandleMutexp) ; +	LL_CHECK_MEMORY +	for (std::set<CURL*>::iterator freeHandle = sFreeHandles.begin(); freeHandle != sFreeHandles.end(); ++freeHandle) +	{ +		CURL* curlHandle = *freeHandle; +		LLCurl::deleteEasyHandle(curlHandle); +		LL_CHECK_MEMORY +	} + +	sFreeHandles.clear(); +} +  LLCurl::Easy::Easy()  	: mHeaders(NULL),  	  mCurlEasyHandle(NULL) @@ -289,7 +394,8 @@ LLCurl::Easy* LLCurl::Easy::getEasy()  	if (!easy->mCurlEasyHandle)  	{  		// this can happen if we have too many open files (fails in c-ares/ares_init.c) -		LL_WARNS() << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL; +		LL_WARNS("curl") << "allocEasyHandle() returned NULL! Easy handles: "  +			<< gCurlEasyCount << " Multi handles: " << gCurlMultiCount << LL_ENDL;  		delete easy;  		return NULL;  	} @@ -317,10 +423,14 @@ LLCurl::Easy::~Easy()  	for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());  	LL_CHECK_MEMORY  	if (mResponder && LLCurl::sNotQuitting) //aborted -	{	 -		std::string reason("Request timeout, aborted.") ; -		mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort -			reason, mChannels, mOutput);		 +	{ +		// HTTP_REQUEST_TIME_OUT, timeout, abort +		// *TODO: This looks like improper use of the 408 status code. +		// See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9 +		// This status code should be returned by the *server* when: +		// "The client did not produce a request within the time that the server was prepared to wait." +		mResponder->setResult(HTTP_REQUEST_TIME_OUT, "Request timeout, aborted."); +		mResponder->completedRaw(mChannels, mOutput);  		LL_CHECK_MEMORY  	}  	mResponder = NULL; @@ -384,9 +494,9 @@ void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)  	check_curl_code(curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload));  } -U32 LLCurl::Easy::report(CURLcode code) +S32 LLCurl::Easy::report(CURLcode code)  { -	U32 responseCode = 0;	 +	S32 responseCode = 0;  	std::string responseReason;  	if (code == CURLE_OK) @@ -396,14 +506,15 @@ U32 LLCurl::Easy::report(CURLcode code)  	}  	else  	{ -		responseCode = 499; +		responseCode = HTTP_INTERNAL_ERROR;  		responseReason = strerror(code) + " : " + mErrorBuffer;  		setopt(CURLOPT_FRESH_CONNECT, TRUE);  	}  	if (mResponder)  	{	 -		mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput); +		mResponder->setResult(responseCode, responseReason); +		mResponder->completedRaw(mChannels, mOutput);  		mResponder = NULL;  	} @@ -440,9 +551,31 @@ void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)  	check_curl_code(result);  } +void LLCurl::Easy::slist_append(const std::string& header, const std::string& value) +{ +	std::string pair(header); +	if (value.empty()) +	{ +		pair += ":"; +	} +	else +	{ +		pair += ": "; +		pair += value; +	} +	slist_append(pair.c_str()); +} +  void LLCurl::Easy::slist_append(const char* str)  { -	mHeaders = curl_slist_append(mHeaders, str); +	if (str) +	{ +		mHeaders = curl_slist_append(mHeaders, str); +		if (!mHeaders) +		{ +			LL_WARNS() << "curl_slist_append() call returned NULL appending " << str << LL_ENDL; +		} +	}  }  size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data) @@ -530,8 +663,9 @@ void LLCurl::Easy::prepRequest(const std::string& url,  	if (!post)  	{ -		slist_append("Connection: keep-alive"); -		slist_append("Keep-alive: 300"); +		// *TODO: Should this be set to 'Keep-Alive' ? +		slist_append(HTTP_OUT_HEADER_CONNECTION, "keep-alive"); +		slist_append(HTTP_OUT_HEADER_KEEP_ALIVE, "300");  		// Accept and other headers  		for (std::vector<std::string>::const_iterator iter = headers.begin();  			 iter != headers.end(); ++iter) @@ -810,7 +944,7 @@ S32 LLCurl::Multi::process()  		++processed;  		if (msg->msg == CURLMSG_DONE)  		{ -			U32 response = 0; +			S32 response = 0;  			Easy* easy = NULL ;  			{ @@ -829,7 +963,7 @@ S32 LLCurl::Multi::process()  			}  			else  			{ -				response = 499; +				response = HTTP_INTERNAL_ERROR;  				//*TODO: change to LL_WARNS()  				LL_ERRS() << "cleaned up curl request completed!" << LL_ENDL;  			} @@ -1128,13 +1262,13 @@ bool LLCurlRequest::getByteRange(const std::string& url,  	easy->setopt(CURLOPT_HTTPGET, 1);  	if (length > 0)  	{ -		std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1); -		easy->slist_append(range.c_str()); +		std::string range = llformat("bytes=%d-%d", offset,offset+length-1); +		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);  	}  	else if (offset > 0)  	{ -		std::string range = llformat("Range: bytes=%d-", offset); -		easy->slist_append(range.c_str()); +		std::string range = llformat("bytes=%d-", offset); +		easy->slist_append(HTTP_OUT_HEADER_RANGE, range);  	}  	easy->setHeaders();  	bool res = addEasy(easy); @@ -1161,7 +1295,7 @@ bool LLCurlRequest::post(const std::string& url,  	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);  	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); -	easy->slist_append("Content-Type: application/llsd+xml"); +	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_LLSD_XML);  	easy->setHeaders();  	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; @@ -1189,7 +1323,7 @@ bool LLCurlRequest::post(const std::string& url,  	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);  	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes); -	easy->slist_append("Content-Type: application/octet-stream"); +	easy->slist_append(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_OCTET_STREAM);  	easy->setHeaders();  	LL_DEBUGS() << "POSTING: " << bytes << " bytes." << LL_ENDL; @@ -1561,6 +1695,14 @@ void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void*  	}  } +void LLCurlEasyRequest::slist_append(const std::string& header, const std::string& value) +{ +	if (isValid() && mEasy) +	{ +		mEasy->slist_append(header, value); +	} +} +  void LLCurlEasyRequest::slist_append(const char* str)  {  	if (isValid() && mEasy) @@ -1745,17 +1887,14 @@ void LLCurl::cleanupClass()  #endif  	LL_CHECK_MEMORY - -	for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter) -	{ -		CURL* curl = *iter; -		LLCurl::deleteEasyHandle(curl); -	} -	 +	Easy::deleteAllFreeHandles(); +	LL_CHECK_MEMORY +	Easy::deleteAllActiveHandles();  	LL_CHECK_MEMORY -	Easy::sFreeHandles.clear(); - +	// Free the template easy handle +	curl_easy_cleanup(sCurlTemplateStandardHandle); +	sCurlTemplateStandardHandle = NULL;  	LL_CHECK_MEMORY  	delete Easy::sHandleMutexp ; diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index fc9761ff9f..385d9fffa8 100755 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -39,6 +39,7 @@  #include <curl/curl.h> // TODO: remove dependency  #include "llbuffer.h" +#include "llhttpconstants.h"  #include "lliopipe.h"  #include "llsd.h"  #include "llqueuedthread.h" @@ -76,59 +77,92 @@ public:  		Responder();  		virtual ~Responder(); -		/** -		 * @brief return true if the status code indicates success. -		 */ -		static bool isGoodStatus(U32 status) +		virtual bool followRedir()   		{ -			return((200 <= status) && (status < 300)); +			return false;  		} -		 -		virtual void errorWithContent( -			U32 status, -			const std::string& reason, -			const LLSD& content); -			//< called by completed() on bad status  - -		virtual void error(U32 status, const std::string& reason); -			//< called by default error(status, reason, content) -		 -		virtual void result(const LLSD& content); -			//< called by completed for good status codes. +		/** +		 * @brief return true if the status code indicates success. +		 */ +		bool isGoodStatus() const { return isHttpGoodStatus(mStatus); } + +		S32 getStatus() const { return mStatus; } +		const std::string& getReason() const { return mReason; } +		const LLSD& getContent() const { return mContent; } +		bool hasResponseHeader(const std::string& header) const; +		const std::string& getResponseHeader(const std::string& header) const; +		const LLSD& getResponseHeaders() const { return mResponseHeaders; } +		const std::string& getURL() const { return mURL; } +		EHTTPMethod getHTTPMethod() const { return mHTTPMethod; } + +		// This formats response information for use in log spam.  Includes content spam. +		std::string dumpResponse() const; + +		// Allows direct triggering of success/error with different results. +		void completeResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); +		void successResult(const LLSD& content); +		void failureResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); + +		// The default implementation will try to parse body content as an LLSD, however +		// it should not spam about parsing failures unless the server sent a +		// Content-Type: application/llsd+xml header.  		virtual void completedRaw( -			U32 status, -			const std::string& reason,  			const LLChannelDescriptors& channels,  			const LLIOPipe::buffer_ptr_t& buffer);  			/**< Override point for clients that may want to use this  			   class when the response is some other format besides LLSD  			*/ +			 + +		// The http* methods are not public since these should be triggered internally +		// after status, reason, content, etc have been set. +		// If you need to trigger a completion method, use the *Result methods, above. +	protected: +		// These methods are the preferred way to process final results. +		// By default, when one of these is called the following information will be resolved: +		// * HTTP status code - getStatus() +		// * Reason string - getReason() +		// * Content - getContent() +		// * Response Headers - getResponseHeaders() + +		// By default, httpSuccess is triggered whenever httpCompleted is called with a 2xx status code. +		virtual void httpSuccess(); +			//< called by completed for good status codes. + +		// By default, httpFailure is triggered whenever httpCompleted is called with a non-2xx status code. +		virtual void httpFailure(); +			//< called by httpCompleted() on bad status  -		virtual void completed( -			U32 status, -			const std::string& reason, -			const LLSD& content); -			/**< The default implemetnation calls +		// httpCompleted does not generally need to be overridden, unless +		// you don't care about the status code (which determine httpFailure or httpSuccess) +		// or if you want to re-interpret what a 'good' vs' bad' status code is. +		virtual void httpCompleted(); +			/**< The default implementation calls  				either: -				* result(), or -				* error()  +				* httpSuccess(), or +				* httpFailure()   			*/ -			 -			// Override to handle parsing of the header only.  Note: this is the only place where the contents -			// of the header can be parsed.  In the ::completed call above only the body is contained in the LLSD. -			virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content); - -			// Used internally to set the url for debugging later. -			void setURL(const std::string& url); -			virtual bool followRedir()  -			{ -				return false; -			} +	public: +		void setHTTPMethod(EHTTPMethod method); +		void setURL(const std::string& url); +		void setResult(S32 status, const std::string& reason, const LLSD& content = LLSD()); +		void setResponseHeader(const std::string& header, const std::string& value);  	private: +		// These can be accessed by the get* methods.  Treated as 'read-only' during completion handlers. +		EHTTPMethod mHTTPMethod;  		std::string mURL; +		LLSD mResponseHeaders; + +	protected: +		// These should also generally be treated as 'read-only' during completion handlers +		// and should be accessed by the get* methods.  The exception to this rule would +		// be when overriding the completedRaw method in preparation for calling httpCompleted(). +		S32 mStatus; +		std::string mReason; +		LLSD mContent;  	};  	typedef LLPointer<Responder>	ResponderPtr; @@ -227,10 +261,11 @@ public:  	// Copies the string so that it is guaranteed to stick around  	void setoptString(CURLoption option, const std::string& value); +	void slist_append(const std::string& header, const std::string& value);  	void slist_append(const char* str);  	void setHeaders(); -	U32 report(CURLcode); +	S32 report(CURLcode);  	void getTransferInfo(LLCurl::TransferInfo* info);  	void prepRequest(const std::string& url, const std::vector<std::string>& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false); @@ -269,6 +304,9 @@ private:  	static std::set<CURL*> sFreeHandles;  	static std::set<CURL*> sActiveHandles;  	static LLMutex*        sHandleMutexp ; + +	static void deleteAllActiveHandles(); +	static void deleteAllFreeHandles();  };  class LLCurl::Multi @@ -486,6 +524,7 @@ public:  	void setWriteCallback(curl_write_callback callback, void* userdata);  	void setReadCallback(curl_read_callback callback, void* userdata);  	void setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata); +	void slist_append(const std::string& header, const std::string& value);  	void slist_append(const char* str);  	void sendRequest(const std::string& url);  	void requestComplete(); diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp index 095da6f0f9..f168ac4ec6 100755 --- a/indra/llmessage/llhttpassetstorage.cpp +++ b/indra/llmessage/llhttpassetstorage.cpp @@ -54,13 +54,6 @@ const F32 GET_URL_TO_FILE_TIMEOUT = 1800.0f;  const S32 COMPRESSED_INPUT_BUFFER_SIZE = 4096; -const S32 HTTP_OK = 200; -const S32 HTTP_PUT_OK = 201; -const S32 HTTP_NO_CONTENT = 204; -const S32 HTTP_MISSING = 404; -const S32 HTTP_SERVER_BAD_GATEWAY = 502; -const S32 HTTP_SERVER_TEMP_UNAVAILABLE = 503; -  /////////////////////////////////////////////////////////////////////////////////  // LLTempAssetData  // An asset not stored on central asset store, but on a simulator node somewhere. @@ -955,7 +948,7 @@ void LLHTTPAssetStorage::checkForTimeouts()  			{  				if (curl_msg->data.result == CURLE_OK &&   					(   curl_result == HTTP_OK  -					 || curl_result == HTTP_PUT_OK  +					 || curl_result == HTTP_CREATED  					 || curl_result == HTTP_NO_CONTENT))  				{  					LL_INFOS() << "Success uploading " << req->getUUID() << " to " << req->mURLBuffer << LL_ENDL; @@ -966,8 +959,8 @@ void LLHTTPAssetStorage::checkForTimeouts()  				}  				else if (curl_msg->data.result == CURLE_COULDNT_CONNECT ||  						curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || -						curl_result == HTTP_SERVER_BAD_GATEWAY || -						curl_result == HTTP_SERVER_TEMP_UNAVAILABLE) +						curl_result == HTTP_BAD_GATEWAY || +						curl_result == HTTP_SERVICE_UNAVAILABLE)  				{  					LL_WARNS() << "Re-requesting upload for " << req->getUUID() << ".  Received upload error to " << req->mURLBuffer <<  						" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL; @@ -988,8 +981,8 @@ void LLHTTPAssetStorage::checkForTimeouts()  				if (!(curl_msg->data.result == CURLE_COULDNT_CONNECT ||  						curl_msg->data.result == CURLE_OPERATION_TIMEOUTED || -						curl_result == HTTP_SERVER_BAD_GATEWAY || -						curl_result == HTTP_SERVER_TEMP_UNAVAILABLE)) +						curl_result == HTTP_BAD_GATEWAY || +						curl_result == HTTP_SERVICE_UNAVAILABLE))  				{  					// shared upload finished callback  					// in the base class, this is called from processUploadComplete @@ -1021,7 +1014,7 @@ void LLHTTPAssetStorage::checkForTimeouts()  					LL_WARNS() << "Failure downloading " << req->mURLBuffer <<   						" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL; -					xfer_result = (curl_result == HTTP_MISSING) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; +					xfer_result = (curl_result == HTTP_NOT_FOUND) ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;  					if (req->mVFile)  					{ @@ -1243,7 +1236,7 @@ S32 LLHTTPAssetStorage::getURLToFile(const LLUUID& uuid, LLAssetType::EType asse  		}  		else  		{ -			xfer_result = curl_result == HTTP_MISSING ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED; +			xfer_result = curl_result == HTTP_NOT_FOUND ? LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE : LL_ERR_ASSET_REQUEST_FAILED;  			LL_INFOS() << "Failure downloading " << req.mURLBuffer <<   				" with result " << curl_easy_strerror(curl_msg->data.result) << ", http result " << curl_result << LL_ENDL;  		} diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 31a499b370..200116337d 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -54,7 +54,7 @@ namespace  	{  	public:  		LLHTTPClientURLAdaptor(LLCurl::ResponderPtr responder) -			: LLURLRequestComplete(), mResponder(responder), mStatus(499), +			: LLURLRequestComplete(), mResponder(responder), mStatus(HTTP_INTERNAL_ERROR),  			  mReason("LLURLRequest complete w/no status")  		{  		} @@ -63,7 +63,7 @@ namespace  		{  		} -		virtual void httpStatus(U32 status, const std::string& reason) +		virtual void httpStatus(S32 status, const std::string& reason)  		{  			LLURLRequestComplete::httpStatus(status,reason); @@ -74,30 +74,33 @@ namespace  		virtual void complete(const LLChannelDescriptors& channels,  							  const buffer_ptr_t& buffer)  		{ +			// *TODO: Re-interpret mRequestStatus codes? +			//        Would like to detect curl errors, such as +			//        connection errors, write erros, etc.  			if (mResponder.get())  			{ -				// Allow clients to parse headers before we attempt to parse -				// the body and provide completed/result/error calls. -				mResponder->completedHeader(mStatus, mReason, mHeaderOutput); -				mResponder->completedRaw(mStatus, mReason, channels, buffer); +				mResponder->setResult(mStatus, mReason); +				mResponder->completedRaw(channels, buffer);  			}  		}  		virtual void header(const std::string& header, const std::string& value)  		{ -			mHeaderOutput[header] = value; +			if (mResponder.get()) +			{ +				mResponder->setResponseHeader(header, value); +			}  		}  	private:  		LLCurl::ResponderPtr mResponder; -		U32 mStatus; +		S32 mStatus;  		std::string mReason; -		LLSD mHeaderOutput;  	};  	class Injector : public LLIOPipe  	{  	public: -		virtual const char* contentType() = 0; +		virtual const std::string& contentType() = 0;  	};  	class LLSDInjector : public Injector @@ -106,7 +109,7 @@ namespace  		LLSDInjector(const LLSD& sd) : mSD(sd) {}  		virtual ~LLSDInjector() {} -		const char* contentType() { return "application/llsd+xml"; } +		const std::string& contentType() { return HTTP_CONTENT_LLSD_XML; }  		virtual EStatus process_impl(const LLChannelDescriptors& channels,  			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -124,9 +127,9 @@ namespace  	{  	public:  		RawInjector(const U8* data, S32 size) : mData(data), mSize(size) {} -		virtual ~RawInjector() {delete mData;} +		virtual ~RawInjector() {delete [] mData;} -		const char* contentType() { return "application/octet-stream"; } +		const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }  		virtual EStatus process_impl(const LLChannelDescriptors& channels,  			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -147,7 +150,7 @@ namespace  		FileInjector(const std::string& filename) : mFilename(filename) {}  		virtual ~FileInjector() {} -		const char* contentType() { return "application/octet-stream"; } +		const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }  		virtual EStatus process_impl(const LLChannelDescriptors& channels,  			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -180,7 +183,7 @@ namespace  		VFileInjector(const LLUUID& uuid, LLAssetType::EType asset_type) : mUUID(uuid), mAssetType(asset_type) {}  		virtual ~VFileInjector() {} -		const char* contentType() { return "application/octet-stream"; } +		const std::string& contentType() { return HTTP_CONTENT_OCTET_STREAM; }  		virtual EStatus process_impl(const LLChannelDescriptors& channels,  			buffer_ptr_t& buffer, bool& eos, LLSD& context, LLPumpIO* pump) @@ -213,7 +216,7 @@ void LLHTTPClient::setCertVerifyCallback(LLURLRequest::SSLCertVerifyCallback cal  static void request(  	const std::string& url, -	LLURLRequest::ERequestAction method, +	EHTTPMethod method,  	Injector* body_injector,  	LLCurl::ResponderPtr responder,  	const F32 timeout = HTTP_REQUEST_EXPIRY_SECS, @@ -225,7 +228,7 @@ static void request(  	{  		if (responder)  		{ -		responder->completed(U32_MAX, "No pump", LLSD()); +			responder->completeResult(HTTP_INTERNAL_ERROR, "No pump");  		}  		delete body_injector;  		return; @@ -237,90 +240,82 @@ static void request(  	{  		if (responder)  		{ -			responder->completed(498, "Internal Error - curl failure", LLSD()); +			responder->completeResult(HTTP_INTERNAL_CURL_ERROR, "Internal Error - curl failure");  		} -		delete req ; +		delete req;  		delete body_injector; -		return ; +		return;  	}  	req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req); -	 -	LL_DEBUGS() << LLURLRequest::actionAsVerb(method) << " " << url << " " -		<< headers << LL_ENDL; +	LL_DEBUGS("LLHTTPClient") << httpMethodAsVerb(method) << " " << url << " " << headers << LL_ENDL;  	// Insert custom headers if the caller sent any  	if (headers.isMap())  	{ -		if (headers.has("Cookie")) +		if (headers.has(HTTP_OUT_HEADER_COOKIE))  		{  			req->allowCookies();  		} -        LLSD::map_const_iterator iter = headers.beginMap(); -        LLSD::map_const_iterator end  = headers.endMap(); - -        for (; iter != end; ++iter) -        { -            std::ostringstream header; -            //if the header is "Pragma" with no value -            //the caller intends to force libcurl to drop -            //the Pragma header it so gratuitously inserts -            //Before inserting the header, force libcurl -            //to not use the proxy (read: llurlrequest.cpp) -			static const std::string PRAGMA("Pragma"); -			if ((iter->first == PRAGMA) && (iter->second.asString().empty())) -            { -                req->useProxy(false); -            } -            header << iter->first << ": " << iter->second.asString() ; -            LL_DEBUGS() << "header = " << header.str() << LL_ENDL; -            req->addHeader(header.str().c_str()); -        } -    } +		LLSD::map_const_iterator iter = headers.beginMap(); +		LLSD::map_const_iterator end  = headers.endMap(); + +		for (; iter != end; ++iter) +		{ +			//if the header is "Pragma" with no value +			//the caller intends to force libcurl to drop +			//the Pragma header it so gratuitously inserts +			//Before inserting the header, force libcurl +			//to not use the proxy (read: llurlrequest.cpp) +			if ((iter->first == HTTP_OUT_HEADER_PRAGMA) && (iter->second.asString().empty())) +			{ +				req->useProxy(false); +			} +			LL_DEBUGS("LLHTTPClient") << "header = " << iter->first  +				<< ": " << iter->second.asString() << LL_ENDL; +			req->addHeader(iter->first, iter->second.asString()); +		} +	}  	// Check to see if we have already set Accept or not. If no one  	// set it, set it to application/llsd+xml since that's what we  	// almost always want. -	if( method != LLURLRequest::HTTP_PUT && method != LLURLRequest::HTTP_POST ) +	if( method != HTTP_PUT && method != HTTP_POST )  	{ -		static const std::string ACCEPT("Accept"); -		if(!headers.has(ACCEPT)) +		if(!headers.has(HTTP_OUT_HEADER_ACCEPT))  		{ -			req->addHeader("Accept: application/llsd+xml"); +			req->addHeader(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_LLSD_XML);  		}  	}  	if (responder)  	{  		responder->setURL(url); +		responder->setHTTPMethod(method);  	}  	req->setCallback(new LLHTTPClientURLAdaptor(responder)); -	if (method == LLURLRequest::HTTP_POST  &&  gMessageSystem) +	if (method == HTTP_POST  &&  gMessageSystem)  	{ -		req->addHeader(llformat("X-SecondLife-UDP-Listen-Port: %d", -								gMessageSystem->mPort).c_str()); -   	} +		req->addHeader("X-SecondLife-UDP-Listen-Port", llformat("%d", +					gMessageSystem->mPort)); +	} -	if (method == LLURLRequest::HTTP_PUT || method == LLURLRequest::HTTP_POST) +	if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH)  	{ -		static const std::string CONTENT_TYPE("Content-Type"); -		if(!headers.has(CONTENT_TYPE)) +		if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE))  		{  			// If the Content-Type header was passed in, it has  			// already been added as a header through req->addHeader  			// in the loop above. We defer to the caller's wisdom, but  			// if they did not specify a Content-Type, then ask the  			// injector. -			req->addHeader( -				llformat( -					"Content-Type: %s", -					body_injector->contentType()).c_str()); +			req->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, body_injector->contentType());  		} -   		chain.push_back(LLIOPipe::ptr_t(body_injector)); +		chain.push_back(LLIOPipe::ptr_t(body_injector));  	}  	chain.push_back(LLIOPipe::ptr_t(req)); @@ -342,9 +337,9 @@ void LLHTTPClient::getByteRange(  	if(offset > 0 || bytes > 0)  	{  		std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1); -		headers["Range"] = range; +		headers[HTTP_OUT_HEADER_RANGE] = range;  	} -    request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects); +    request(url,HTTP_GET, NULL, responder, timeout, headers, follow_redirects);  }  void LLHTTPClient::head( @@ -354,18 +349,18 @@ void LLHTTPClient::head(  	const F32 timeout,  	bool follow_redirects /* = true */)  { -	request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects); +	request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);  }  void LLHTTPClient::get(const std::string& url, ResponderPtr responder, const LLSD& headers, const F32 timeout,  					   bool follow_redirects /* = true */)  { -	request(url, LLURLRequest::HTTP_GET, NULL, responder, timeout, headers, follow_redirects); +	request(url, HTTP_GET, NULL, responder, timeout, headers, follow_redirects);  }  void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const LLSD& headers,  								 const F32 timeout, bool follow_redirects /* = true */)  { -	request(url, LLURLRequest::HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects); +	request(url, HTTP_HEAD, NULL, responder, timeout, headers, follow_redirects);  }  void LLHTTPClient::getHeaderOnly(const std::string& url, ResponderPtr responder, const F32 timeout,  								 bool follow_redirects /* = true */) @@ -408,7 +403,7 @@ public:  		return content;  	} -	std::string asString() +	const std::string& asString()  	{  		return mBuffer;  	} @@ -437,7 +432,7 @@ private:    */  static LLSD blocking_request(  	const std::string& url, -	LLURLRequest::ERequestAction method, +	EHTTPMethod method,  	const LLSD& body,  	const LLSD& headers = LLSD(),  	const F32 timeout = 5 @@ -480,11 +475,11 @@ static LLSD blocking_request(  	}  	// * Setup specific method / "verb" for the URI (currently only GET and POST supported + poppy) -	if (method == LLURLRequest::HTTP_GET) +	if (method == HTTP_GET)  	{  		curl_easy_setopt(curlp, CURLOPT_HTTPGET, 1);  	} -	else if (method == LLURLRequest::HTTP_POST) +	else if (method == HTTP_POST)  	{  		curl_easy_setopt(curlp, CURLOPT_POST, 1);  		//serialize to ostr then copy to str - need to because ostr ptr is unstable :( @@ -493,18 +488,20 @@ static LLSD blocking_request(  		body_str = ostr.str();  		curl_easy_setopt(curlp, CURLOPT_POSTFIELDS, body_str.c_str());  		//copied from PHP libs, correct? -		headers_list = curl_slist_append(headers_list, "Content-Type: application/llsd+xml"); +		headers_list = curl_slist_append(headers_list,  +				llformat("%s: %s", HTTP_OUT_HEADER_CONTENT_TYPE.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());  		// copied from llurlrequest.cpp  		// it appears that apache2.2.3 or django in etch is busted. If  		// we do not clear the expect header, we get a 500. May be  		// limited to django/mod_wsgi. -		headers_list = curl_slist_append(headers_list, "Expect:"); +		headers_list = curl_slist_append(headers_list, llformat("%s:", HTTP_OUT_HEADER_EXPECT.c_str()).c_str());  	}  	// * Do the action using curl, handle results  	LL_DEBUGS() << "HTTP body: " << body_str << LL_ENDL; -	headers_list = curl_slist_append(headers_list, "Accept: application/llsd+xml"); +	headers_list = curl_slist_append(headers_list, +				llformat("%s: %s", HTTP_OUT_HEADER_ACCEPT.c_str(), HTTP_CONTENT_LLSD_XML.c_str()).c_str());  	CURLcode curl_result = curl_easy_setopt(curlp, CURLOPT_HTTPHEADER, headers_list);  	if ( curl_result != CURLE_OK )  	{ @@ -513,11 +510,11 @@ static LLSD blocking_request(  	LLSD response = LLSD::emptyMap();  	S32 curl_success = curl_easy_perform(curlp); -	S32 http_status = 499; +	S32 http_status = HTTP_INTERNAL_ERROR;  	curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &http_status);  	response["status"] = http_status;  	// if we get a non-404 and it's not a 200 OR maybe it is but you have error bits, -	if ( http_status != 404 && (http_status != 200 || curl_success != 0) ) +	if ( http_status != HTTP_NOT_FOUND && (http_status != HTTP_OK || curl_success != 0) )  	{  		// We expect 404s, don't spam for them.  		LL_WARNS() << "CURL REQ URL: " << url << LL_ENDL; @@ -547,12 +544,12 @@ static LLSD blocking_request(  LLSD LLHTTPClient::blockingGet(const std::string& url)  { -	return blocking_request(url, LLURLRequest::HTTP_GET, LLSD()); +	return blocking_request(url, HTTP_GET, LLSD());  }  LLSD LLHTTPClient::blockingPost(const std::string& url, const LLSD& body)  { -	return blocking_request(url, LLURLRequest::HTTP_POST, body); +	return blocking_request(url, HTTP_POST, body);  }  void LLHTTPClient::put( @@ -562,7 +559,17 @@ void LLHTTPClient::put(  	const LLSD& headers,  	const F32 timeout)  { -	request(url, LLURLRequest::HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); +	request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers); +} + +void LLHTTPClient::patch( +	const std::string& url, +	const LLSD& body, +	ResponderPtr responder, +	const LLSD& headers, +	const F32 timeout) +{ +	request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers);  }  void LLHTTPClient::post( @@ -572,7 +579,7 @@ void LLHTTPClient::post(  	const LLSD& headers,  	const F32 timeout)  { -	request(url, LLURLRequest::HTTP_POST, new LLSDInjector(body), responder, timeout, headers); +	request(url, HTTP_POST, new LLSDInjector(body), responder, timeout, headers);  }  void LLHTTPClient::postRaw( @@ -583,7 +590,7 @@ void LLHTTPClient::postRaw(  	const LLSD& headers,  	const F32 timeout)  { -	request(url, LLURLRequest::HTTP_POST, new RawInjector(data, size), responder, timeout, headers); +	request(url, HTTP_POST, new RawInjector(data, size), responder, timeout, headers);  }  void LLHTTPClient::postFile( @@ -593,7 +600,7 @@ void LLHTTPClient::postFile(  	const LLSD& headers,  	const F32 timeout)  { -	request(url, LLURLRequest::HTTP_POST, new FileInjector(filename), responder, timeout, headers); +	request(url, HTTP_POST, new FileInjector(filename), responder, timeout, headers);  }  void LLHTTPClient::postFile( @@ -604,7 +611,7 @@ void LLHTTPClient::postFile(  	const LLSD& headers,  	const F32 timeout)  { -	request(url, LLURLRequest::HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers); +	request(url, HTTP_POST, new VFileInjector(uuid, asset_type), responder, timeout, headers);  }  // static @@ -614,7 +621,7 @@ void LLHTTPClient::del(  	const LLSD& headers,  	const F32 timeout)  { -	request(url, LLURLRequest::HTTP_DELETE, NULL, responder, timeout, headers); +	request(url, HTTP_DELETE, NULL, responder, timeout, headers);  }  // static @@ -626,8 +633,21 @@ void LLHTTPClient::move(  	const F32 timeout)  {  	LLSD headers = hdrs; -	headers["Destination"] = destination; -	request(url, LLURLRequest::HTTP_MOVE, NULL, responder, timeout, headers); +	headers[HTTP_OUT_HEADER_DESTINATION] = destination; +	request(url, HTTP_MOVE, NULL, responder, timeout, headers); +} + +// static +void LLHTTPClient::copy( +	const std::string& url, +	const std::string& destination, +	ResponderPtr responder, +	const LLSD& hdrs, +	const F32 timeout) +{ +	LLSD headers = hdrs; +	headers[HTTP_OUT_HEADER_DESTINATION] = destination; +	request(url, HTTP_COPY, NULL, responder, timeout, headers);  } diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 5de257a4f6..b18258fd7b 100755 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -79,6 +79,14 @@ public:  		ResponderPtr,  		const LLSD& headers = LLSD(),  		const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); + +	static void patch( +		const std::string& url, +		const LLSD& body, +		ResponderPtr, +		const LLSD& headers = LLSD(), +		const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); +  	static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS,  							  bool follow_redirects = true);  	static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, @@ -118,7 +126,7 @@ public:  		const LLSD& headers = LLSD(),  		const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);  		///< sends a DELETE method, but we can't call it delete in c++ -	 +  	/**  	 * @brief Send a MOVE webdav method  	 * @@ -135,6 +143,22 @@ public:  		const LLSD& headers = LLSD(),  		const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); +	/** +	 * @brief Send a COPY webdav method +	 * +	 * @param url The complete serialized (and escaped) url to get. +	 * @param destination The complete serialized destination url. +	 * @param responder The responder that will handle the result. +	 * @param headers A map of key:value headers to pass to the request +	 * @param timeout The number of seconds to give the server to respond. +	 */ +	static void copy( +		const std::string& url, +		const std::string& destination, +		ResponderPtr responder, +		const LLSD& headers = LLSD(), +		const F32 timeout=HTTP_REQUEST_EXPIRY_SECS); +  	//@}  	/** diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index dcd2d79d67..b56a804f94 100755 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -35,18 +35,18 @@ void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr respo  {  	LLSD empty_pragma_header;  	// Pragma is required to stop curl adding "no-cache" -	// Space is required to stop llurlrequest from turnning off proxying -	empty_pragma_header["Pragma"] = " ";  +	// Space is required to stop llurlrequest from turning off proxying +	empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";   	LLHTTPClient::get(url, responder, empty_pragma_header);  }  void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers)   {  	LLSD empty_pragma_header = headers; -	if (!empty_pragma_header.has("Pragma")) +	if (!empty_pragma_header.has(HTTP_OUT_HEADER_PRAGMA))  	{ -	// as above -	empty_pragma_header["Pragma"] = " "; +		// as above +		empty_pragma_header[HTTP_OUT_HEADER_PRAGMA] = " ";  	}  	LLHTTPClient::get(url, responder, empty_pragma_header);  } @@ -56,3 +56,18 @@ void LLHTTPClientAdapter::put(const std::string& url, const LLSD& body, LLCurl::  	LLHTTPClient::put(url, body, responder);  } +void LLHTTPClientAdapter::put( +		const std::string& url, +		const LLSD& body, +		LLCurl::ResponderPtr responder, +		const LLSD& headers) +{ +	LLHTTPClient::put(url, body, responder, headers); +} + +void LLHTTPClientAdapter::del( +	const std::string& url, +	LLCurl::ResponderPtr responder) +{ +	LLHTTPClient::del(url, responder); +} diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h index aae6426a59..270282c66f 100755 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -37,6 +37,14 @@ public:  	virtual void get(const std::string& url, LLCurl::ResponderPtr responder);  	virtual void get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers);  	virtual void put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder); +	virtual void put( +		const std::string& url, +		const LLSD& body, +		LLCurl::ResponderPtr responder, +		const LLSD& headers); +	virtual void del( +		const std::string& url, +		LLCurl::ResponderPtr responder);  };  #endif diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp new file mode 100755 index 0000000000..01f4a080b0 --- /dev/null +++ b/indra/llmessage/llhttpconstants.cpp @@ -0,0 +1,228 @@ +/**  + * @file llhttpconstants.cpp + * @brief Implementation of the HTTP request / response constant lookups + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + *  + * Copyright (c) 2013, Linden Research, Inc. + *  + * 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 "linden_common.h" +#include "llhttpconstants.h" +#include "lltimer.h" + +// for curl_getdate() (apparently parsing RFC 1123 dates is hard) +#include <curl/curl.h> + +// Outgoing headers. Do *not* use these to check incoming headers. +// For incoming headers, use the lower-case headers, below. +const std::string HTTP_OUT_HEADER_ACCEPT("Accept"); +const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET("Accept-Charset"); +const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING("Accept-Encoding"); +const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE("Accept-Language"); +const std::string HTTP_OUT_HEADER_ACCEPT_RANGES("Accept-Ranges"); +const std::string HTTP_OUT_HEADER_AGE("Age"); +const std::string HTTP_OUT_HEADER_ALLOW("Allow"); +const std::string HTTP_OUT_HEADER_AUTHORIZATION("Authorization"); +const std::string HTTP_OUT_HEADER_CACHE_CONTROL("Cache-Control"); +const std::string HTTP_OUT_HEADER_CONNECTION("Connection"); +const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION("Content-Description"); +const std::string HTTP_OUT_HEADER_CONTENT_ENCODING("Content-Encoding"); +const std::string HTTP_OUT_HEADER_CONTENT_ID("Content-ID"); +const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE("Content-Language"); +const std::string HTTP_OUT_HEADER_CONTENT_LENGTH("Content-Length"); +const std::string HTTP_OUT_HEADER_CONTENT_LOCATION("Content-Location"); +const std::string HTTP_OUT_HEADER_CONTENT_MD5("Content-MD5"); +const std::string HTTP_OUT_HEADER_CONTENT_RANGE("Content-Range"); +const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding"); +const std::string HTTP_OUT_HEADER_CONTENT_TYPE("Content-Type"); +const std::string HTTP_OUT_HEADER_COOKIE("Cookie"); +const std::string HTTP_OUT_HEADER_DATE("Date"); +const std::string HTTP_OUT_HEADER_DESTINATION("Destination"); +const std::string HTTP_OUT_HEADER_ETAG("ETag"); +const std::string HTTP_OUT_HEADER_EXPECT("Expect"); +const std::string HTTP_OUT_HEADER_EXPIRES("Expires"); +const std::string HTTP_OUT_HEADER_FROM("From"); +const std::string HTTP_OUT_HEADER_HOST("Host"); +const std::string HTTP_OUT_HEADER_IF_MATCH("If-Match"); +const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE("If-Modified-Since"); +const std::string HTTP_OUT_HEADER_IF_NONE_MATCH("If-None-Match"); +const std::string HTTP_OUT_HEADER_IF_RANGE("If-Range"); +const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since"); +const std::string HTTP_OUT_HEADER_KEEP_ALIVE("Keep-Alive"); +const std::string HTTP_OUT_HEADER_LAST_MODIFIED("Last-Modified"); +const std::string HTTP_OUT_HEADER_LOCATION("Location"); +const std::string HTTP_OUT_HEADER_MAX_FORWARDS("Max-Forwards"); +const std::string HTTP_OUT_HEADER_MIME_VERSION("MIME-Version"); +const std::string HTTP_OUT_HEADER_PRAGMA("Pragma"); +const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate"); +const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization"); +const std::string HTTP_OUT_HEADER_RANGE("Range"); +const std::string HTTP_OUT_HEADER_REFERER("Referer"); +const std::string HTTP_OUT_HEADER_RETRY_AFTER("Retry-After"); +const std::string HTTP_OUT_HEADER_SERVER("Server"); +const std::string HTTP_OUT_HEADER_SET_COOKIE("Set-Cookie"); +const std::string HTTP_OUT_HEADER_TE("TE"); +const std::string HTTP_OUT_HEADER_TRAILER("Trailer"); +const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING("Transfer-Encoding"); +const std::string HTTP_OUT_HEADER_UPGRADE("Upgrade"); +const std::string HTTP_OUT_HEADER_USER_AGENT("User-Agent"); +const std::string HTTP_OUT_HEADER_VARY("Vary"); +const std::string HTTP_OUT_HEADER_VIA("Via"); +const std::string HTTP_OUT_HEADER_WARNING("Warning"); +const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE("WWW-Authenticate"); + +// Incoming headers are normalized to lower-case. +const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE("accept-language"); +const std::string HTTP_IN_HEADER_CACHE_CONTROL("cache-control"); +const std::string HTTP_IN_HEADER_CONTENT_LENGTH("content-length"); +const std::string HTTP_IN_HEADER_CONTENT_LOCATION("content-location"); +const std::string HTTP_IN_HEADER_CONTENT_TYPE("content-type"); +const std::string HTTP_IN_HEADER_HOST("host"); +const std::string HTTP_IN_HEADER_LOCATION("location"); +const std::string HTTP_IN_HEADER_RETRY_AFTER("retry-after"); +const std::string HTTP_IN_HEADER_SET_COOKIE("set-cookie"); +const std::string HTTP_IN_HEADER_USER_AGENT("user-agent"); +const std::string HTTP_IN_HEADER_X_FORWARDED_FOR("x-forwarded-for"); + +const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml"); +const std::string HTTP_CONTENT_OCTET_STREAM("application/octet-stream"); +const std::string HTTP_CONTENT_XML("application/xml"); +const std::string HTTP_CONTENT_JSON("application/json"); +const std::string HTTP_CONTENT_TEXT_HTML("text/html"); +const std::string HTTP_CONTENT_TEXT_HTML_UTF8("text/html; charset=utf-8"); +const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8("text/plain; charset=utf-8"); +const std::string HTTP_CONTENT_TEXT_LLSD("text/llsd"); +const std::string HTTP_CONTENT_TEXT_XML("text/xml"); +const std::string HTTP_CONTENT_TEXT_LSL("text/lsl"); +const std::string HTTP_CONTENT_TEXT_PLAIN("text/plain"); +const std::string HTTP_CONTENT_IMAGE_X_J2C("image/x-j2c"); +const std::string HTTP_CONTENT_IMAGE_J2C("image/j2c"); +const std::string HTTP_CONTENT_IMAGE_JPEG("image/jpeg"); +const std::string HTTP_CONTENT_IMAGE_PNG("image/png"); +const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp"); + +const std::string HTTP_NO_CACHE("no-cache"); +const std::string HTTP_NO_CACHE_CONTROL("no-cache, max-age=0"); + +const std::string HTTP_VERB_INVALID("(invalid)"); +const std::string HTTP_VERB_HEAD("HEAD"); +const std::string HTTP_VERB_GET("GET"); +const std::string HTTP_VERB_PUT("PUT"); +const std::string HTTP_VERB_POST("POST"); +const std::string HTTP_VERB_DELETE("DELETE"); +const std::string HTTP_VERB_MOVE("MOVE"); +const std::string HTTP_VERB_OPTIONS("OPTIONS"); +const std::string HTTP_VERB_PATCH("PATCH"); +const std::string HTTP_VERB_COPY("COPY"); + +const std::string& httpMethodAsVerb(EHTTPMethod method) +{ +	static const std::string VERBS[] = +	{ +		HTTP_VERB_INVALID, +		HTTP_VERB_HEAD, +		HTTP_VERB_GET, +		HTTP_VERB_PUT, +		HTTP_VERB_POST, +		HTTP_VERB_DELETE, +		HTTP_VERB_MOVE, +		HTTP_VERB_OPTIONS, +		HTTP_VERB_PATCH, +		HTTP_VERB_COPY +	}; +	if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT)) +	{ +		return VERBS[0]; +	} +	return VERBS[method]; +} + +bool isHttpInformationalStatus(S32 status) +{ +	// Check for status 1xx. +	return((100 <= status) && (status < 200)); +} + +bool isHttpGoodStatus(S32 status) +{ +	// Check for status 2xx. +	return((200 <= status) && (status < 300)); +} + +bool isHttpRedirectStatus(S32 status) +{ +	// Check for status 3xx. +	return((300 <= status) && (status < 400)); +} + +bool isHttpClientErrorStatus(S32 status) +{ +	// Status 499 is sometimes used for re-interpreted status 2xx errors +	// based on body content.  Treat these as potentially retryable 'server' status errors, +	// since we do not have enough context to know if this will always fail. +	if (HTTP_INTERNAL_ERROR == status) return false; + +	// Check for status 5xx. +	return((400 <= status) && (status < 500)); +} + +bool isHttpServerErrorStatus(S32 status) +{ +	// Status 499 is sometimes used for re-interpreted status 2xx errors. +	// Allow retry of these, since we don't have enough information in this +	// context to know if this will always fail. +	if (HTTP_INTERNAL_ERROR == status) return true; + +	// Check for status 5xx. +	return((500 <= status) && (status < 600)); +} + +// Parses 'Retry-After' header contents and returns seconds until retry should occur. +bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait) +{ +	// *TODO:  This needs testing!   Not in use yet. +	// Examples of Retry-After headers: +	// Retry-After: Fri, 31 Dec 1999 23:59:59 GMT +	// Retry-After: 120 + +	// Check for number of seconds version, first: +	char* end = 0; +	// Parse as double +	double seconds = std::strtod(retry_after.c_str(), &end); +	if ( end != 0 && *end == 0 ) +	{ +		// Successful parse +		seconds_to_wait = (F32) seconds; +		return true; +	} + +	// Parse rfc1123 date. +	time_t date = curl_getdate(retry_after.c_str(), NULL ); +	if (-1 == date) return false; + +	seconds_to_wait = (F64)date - LLTimer::getTotalSeconds(); + +	return true; +} + diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h new file mode 100755 index 0000000000..4aa3cc6394 --- /dev/null +++ b/indra/llmessage/llhttpconstants.h @@ -0,0 +1,225 @@ +/**  + * @file llhttpconstants.h + * @brief Constants for HTTP requests and responses + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2001-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_HTTP_CONSTANTS_H +#define LL_HTTP_CONSTANTS_H + +#include "stdtypes.h" + +/////// HTTP STATUS CODES /////// + +// Standard errors from HTTP spec: +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1 +const S32 HTTP_CONTINUE = 100; +const S32 HTTP_SWITCHING_PROTOCOLS = 101; + +// Success +const S32 HTTP_OK = 200; +const S32 HTTP_CREATED = 201; +const S32 HTTP_ACCEPTED = 202; +const S32 HTTP_NON_AUTHORITATIVE_INFORMATION = 203; +const S32 HTTP_NO_CONTENT = 204; +const S32 HTTP_RESET_CONTENT = 205; +const S32 HTTP_PARTIAL_CONTENT = 206; + +// Redirection +const S32 HTTP_MULTIPLE_CHOICES = 300; +const S32 HTTP_MOVED_PERMANENTLY = 301; +const S32 HTTP_FOUND = 302; +const S32 HTTP_SEE_OTHER = 303; +const S32 HTTP_NOT_MODIFIED = 304; +const S32 HTTP_USE_PROXY = 305; +const S32 HTTP_TEMPORARY_REDIRECT = 307; + +// Client Error +const S32 HTTP_BAD_REQUEST = 400; +const S32 HTTP_UNAUTHORIZED = 401; +const S32 HTTP_PAYMENT_REQUIRED = 402; +const S32 HTTP_FORBIDDEN = 403; +const S32 HTTP_NOT_FOUND = 404; +const S32 HTTP_METHOD_NOT_ALLOWED = 405; +const S32 HTTP_NOT_ACCEPTABLE = 406; +const S32 HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; +const S32 HTTP_REQUEST_TIME_OUT = 408; +const S32 HTTP_CONFLICT = 409; +const S32 HTTP_GONE = 410; +const S32 HTTP_LENGTH_REQUIRED = 411; +const S32 HTTP_PRECONDITION_FAILED = 412; +const S32 HTTP_REQUEST_ENTITY_TOO_LARGE = 413; +const S32 HTTP_REQUEST_URI_TOO_LARGE = 414; +const S32 HTTP_UNSUPPORTED_MEDIA_TYPE = 415; +const S32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; +const S32 HTTP_EXPECTATION_FAILED = 417; + +// Server Error +const S32 HTTP_INTERNAL_SERVER_ERROR = 500; +const S32 HTTP_NOT_IMPLEMENTED = 501; +const S32 HTTP_BAD_GATEWAY = 502; +const S32 HTTP_SERVICE_UNAVAILABLE = 503; +const S32 HTTP_GATEWAY_TIME_OUT = 504; +const S32 HTTP_VERSION_NOT_SUPPORTED = 505; + +// We combine internal process errors with status codes +// These status codes should not be sent over the wire +//   and indicate something went wrong internally. +// If you get these they are not normal. +const S32 HTTP_INTERNAL_CURL_ERROR = 498; +const S32 HTTP_INTERNAL_ERROR = 499; + + +////// HTTP Methods ////// + +extern const std::string HTTP_VERB_INVALID; +extern const std::string HTTP_VERB_HEAD; +extern const std::string HTTP_VERB_GET; +extern const std::string HTTP_VERB_PUT; +extern const std::string HTTP_VERB_POST; +extern const std::string HTTP_VERB_DELETE; +extern const std::string HTTP_VERB_MOVE; +extern const std::string HTTP_VERB_OPTIONS; + +enum EHTTPMethod +{ +	HTTP_INVALID = 0, +	HTTP_HEAD, +	HTTP_GET, +	HTTP_PUT, +	HTTP_POST, +	HTTP_DELETE, +	HTTP_MOVE, // Caller will need to set 'Destination' header +	HTTP_OPTIONS, +	HTTP_PATCH, +	HTTP_COPY, +	HTTP_METHOD_COUNT +}; + +const std::string& httpMethodAsVerb(EHTTPMethod method); +bool isHttpInformationalStatus(S32 status); +bool isHttpGoodStatus(S32 status); +bool isHttpRedirectStatus(S32 status); +bool isHttpClientErrorStatus(S32 status); +bool isHttpServerErrorStatus(S32 status); + +// Parses 'Retry-After' header contents and returns seconds until retry should occur. +bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait); + +//// HTTP Headers ///// + +// Outgoing headers. Do *not* use these to check incoming headers. +// For incoming headers, use the lower-case headers, below. +extern const std::string HTTP_OUT_HEADER_ACCEPT; +extern const std::string HTTP_OUT_HEADER_ACCEPT_CHARSET; +extern const std::string HTTP_OUT_HEADER_ACCEPT_ENCODING; +extern const std::string HTTP_OUT_HEADER_ACCEPT_LANGUAGE; +extern const std::string HTTP_OUT_HEADER_ACCEPT_RANGES; +extern const std::string HTTP_OUT_HEADER_AGE; +extern const std::string HTTP_OUT_HEADER_ALLOW; +extern const std::string HTTP_OUT_HEADER_AUTHORIZATION; +extern const std::string HTTP_OUT_HEADER_CACHE_CONTROL; +extern const std::string HTTP_OUT_HEADER_CONNECTION; +extern const std::string HTTP_OUT_HEADER_CONTENT_DESCRIPTION; +extern const std::string HTTP_OUT_HEADER_CONTENT_ENCODING; +extern const std::string HTTP_OUT_HEADER_CONTENT_ID; +extern const std::string HTTP_OUT_HEADER_CONTENT_LANGUAGE; +extern const std::string HTTP_OUT_HEADER_CONTENT_LENGTH; +extern const std::string HTTP_OUT_HEADER_CONTENT_LOCATION; +extern const std::string HTTP_OUT_HEADER_CONTENT_MD5; +extern const std::string HTTP_OUT_HEADER_CONTENT_RANGE; +extern const std::string HTTP_OUT_HEADER_CONTENT_TRANSFER_ENCODING; +extern const std::string HTTP_OUT_HEADER_CONTENT_TYPE; +extern const std::string HTTP_OUT_HEADER_COOKIE; +extern const std::string HTTP_OUT_HEADER_DATE; +extern const std::string HTTP_OUT_HEADER_DESTINATION; +extern const std::string HTTP_OUT_HEADER_ETAG; +extern const std::string HTTP_OUT_HEADER_EXPECT; +extern const std::string HTTP_OUT_HEADER_EXPIRES; +extern const std::string HTTP_OUT_HEADER_FROM; +extern const std::string HTTP_OUT_HEADER_HOST; +extern const std::string HTTP_OUT_HEADER_IF_MATCH; +extern const std::string HTTP_OUT_HEADER_IF_MODIFIED_SINCE; +extern const std::string HTTP_OUT_HEADER_IF_NONE_MATCH; +extern const std::string HTTP_OUT_HEADER_IF_RANGE; +extern const std::string HTTP_OUT_HEADER_IF_UNMODIFIED_SINCE; +extern const std::string HTTP_OUT_HEADER_KEEP_ALIVE; +extern const std::string HTTP_OUT_HEADER_LAST_MODIFIED; +extern const std::string HTTP_OUT_HEADER_LOCATION; +extern const std::string HTTP_OUT_HEADER_MAX_FORWARDS; +extern const std::string HTTP_OUT_HEADER_MIME_VERSION; +extern const std::string HTTP_OUT_HEADER_PRAGMA; +extern const std::string HTTP_OUT_HEADER_PROXY_AUTHENTICATE; +extern const std::string HTTP_OUT_HEADER_PROXY_AUTHORIZATION; +extern const std::string HTTP_OUT_HEADER_RANGE; +extern const std::string HTTP_OUT_HEADER_REFERER; +extern const std::string HTTP_OUT_HEADER_RETRY_AFTER; +extern const std::string HTTP_OUT_HEADER_SERVER; +extern const std::string HTTP_OUT_HEADER_SET_COOKIE; +extern const std::string HTTP_OUT_HEADER_TE; +extern const std::string HTTP_OUT_HEADER_TRAILER; +extern const std::string HTTP_OUT_HEADER_TRANSFER_ENCODING; +extern const std::string HTTP_OUT_HEADER_UPGRADE; +extern const std::string HTTP_OUT_HEADER_USER_AGENT; +extern const std::string HTTP_OUT_HEADER_VARY; +extern const std::string HTTP_OUT_HEADER_VIA; +extern const std::string HTTP_OUT_HEADER_WARNING; +extern const std::string HTTP_OUT_HEADER_WWW_AUTHENTICATE; + +// Incoming headers are normalized to lower-case. +extern const std::string HTTP_IN_HEADER_ACCEPT_LANGUAGE; +extern const std::string HTTP_IN_HEADER_CACHE_CONTROL; +extern const std::string HTTP_IN_HEADER_CONTENT_LENGTH; +extern const std::string HTTP_IN_HEADER_CONTENT_LOCATION; +extern const std::string HTTP_IN_HEADER_CONTENT_TYPE; +extern const std::string HTTP_IN_HEADER_HOST; +extern const std::string HTTP_IN_HEADER_LOCATION; +extern const std::string HTTP_IN_HEADER_RETRY_AFTER; +extern const std::string HTTP_IN_HEADER_SET_COOKIE; +extern const std::string HTTP_IN_HEADER_USER_AGENT; +extern const std::string HTTP_IN_HEADER_X_FORWARDED_FOR; + +//// HTTP Content Types //// + +extern const std::string HTTP_CONTENT_LLSD_XML; +extern const std::string HTTP_CONTENT_OCTET_STREAM; +extern const std::string HTTP_CONTENT_XML; +extern const std::string HTTP_CONTENT_JSON; +extern const std::string HTTP_CONTENT_TEXT_HTML; +extern const std::string HTTP_CONTENT_TEXT_HTML_UTF8; +extern const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8; +extern const std::string HTTP_CONTENT_TEXT_LLSD; +extern const std::string HTTP_CONTENT_TEXT_XML; +extern const std::string HTTP_CONTENT_TEXT_LSL; +extern const std::string HTTP_CONTENT_TEXT_PLAIN; +extern const std::string HTTP_CONTENT_IMAGE_X_J2C; +extern const std::string HTTP_CONTENT_IMAGE_J2C; +extern const std::string HTTP_CONTENT_IMAGE_JPEG; +extern const std::string HTTP_CONTENT_IMAGE_PNG; +extern const std::string HTTP_CONTENT_IMAGE_BMP; + +//// HTTP Cache Settings //// +extern const std::string HTTP_NO_CACHE; +extern const std::string HTTP_NO_CACHE_CONTROL; + +#endif diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index f1f4a95005..f235965879 100755 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -30,9 +30,15 @@  #include <boost/tokenizer.hpp>  #include "llstl.h" -#include "lliohttpserver.h" // for string constants +#include "llhttpconstants.h" -static const std::string CONTEXT_WILDCARD("wildcard"); +const std::string CONTEXT_HEADERS("headers"); +const std::string CONTEXT_PATH("path"); +const std::string CONTEXT_QUERY_STRING("query-string"); +const std::string CONTEXT_REQUEST("request"); +const std::string CONTEXT_RESPONSE("response"); +const std::string CONTEXT_VERB("verb"); +const std::string CONTEXT_WILDCARD("wildcard");  /**   * LLHTTPNode @@ -173,21 +179,23 @@ LLSD LLHTTPNode::simpleDel(const LLSD&) const  void  LLHTTPNode::options(ResponsePtr response, const LLSD& context) const  {  	//LL_INFOS() << "options context: " << context << LL_ENDL; +	LL_DEBUGS("LLHTTPNode") << "context: " << context << LL_ENDL;  	// default implementation constructs an url to the documentation. +	// *TODO: Check for 'Host' header instead of 'host' header?  	std::string host( -		context[CONTEXT_REQUEST][CONTEXT_HEADERS]["host"].asString()); +		context[CONTEXT_REQUEST][CONTEXT_HEADERS][HTTP_IN_HEADER_HOST].asString());  	if(host.empty())  	{ -		response->status(400, "Bad Request -- need Host header"); +		response->status(HTTP_BAD_REQUEST, "Bad Request -- need Host header");  		return;  	}  	std::ostringstream ostr;  	ostr << "http://" << host << "/web/server/api"; -	ostr << context[CONTEXT_REQUEST]["path"].asString(); +	ostr << context[CONTEXT_REQUEST][CONTEXT_PATH].asString();  	static const std::string DOC_HEADER("X-Documentation-URL");  	response->addHeader(DOC_HEADER, ostr.str()); -	response->status(200, "OK"); +	response->status(HTTP_OK, "OK");  } @@ -389,17 +397,17 @@ void LLHTTPNode::Response::statusUnknownError(S32 code)  void LLHTTPNode::Response::notFound(const std::string& message)  { -	status(404, message); +	status(HTTP_NOT_FOUND, message);  }  void LLHTTPNode::Response::notFound()  { -	status(404, "Not Found"); +	status(HTTP_NOT_FOUND, "Not Found");  }  void LLHTTPNode::Response::methodNotAllowed()  { -	status(405, "Method Not Allowed"); +	status(HTTP_METHOD_NOT_ALLOWED, "Method Not Allowed");  }  void LLHTTPNode::Response::addHeader( @@ -467,7 +475,7 @@ LLSimpleResponse::~LLSimpleResponse()  void LLSimpleResponse::result(const LLSD& result)  { -	status(200, "OK"); +	status(HTTP_OK, "OK");  }  void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const LLSD& headers) @@ -475,6 +483,11 @@ void LLSimpleResponse::extendedResult(S32 code, const std::string& body, const L  	status(code,body);  } +void LLSimpleResponse::extendedResult(S32 code, const LLSD& r, const LLSD& headers) +{ +	status(code,"(LLSD)"); +} +  void LLSimpleResponse::status(S32 code, const std::string& message)  {  	mCode = code; diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h index 148647ddde..1144d88be1 100755 --- a/indra/llmessage/llhttpnode.h +++ b/indra/llmessage/llhttpnode.h @@ -31,6 +31,17 @@  #include "llrefcount.h"  #include "llsd.h" +// common strings use for populating the context. basically 'request', +// 'wildcard', and 'headers'. +extern const std::string CONTEXT_HEADERS; +extern const std::string CONTEXT_PATH; +extern const std::string CONTEXT_QUERY_STRING; +extern const std::string CONTEXT_REQUEST; +extern const std::string CONTEXT_RESPONSE; +extern const std::string CONTEXT_VERB; +extern const std::string CONTEXT_WILDCARD; + +  class LLChainIOFactory;  /** @@ -60,6 +71,8 @@ class LLChainIOFactory;   */  class LLHTTPNode  { +protected: +    LOG_CLASS(LLHTTPNode);  public:  	LLHTTPNode();  	virtual ~LLHTTPNode(); @@ -100,7 +113,12 @@ public:  		/**  		 * @brief return status code and message with headers.  		 */ -		virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) = 0; +		virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers = LLSD()) = 0; + +		/** +		 * @brief return status code and LLSD result with headers. +		 */ +		virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers = LLSD()) = 0;  		/**  		 * @brief return status code and reason string on http header, @@ -118,7 +136,7 @@ public:  		virtual void methodNotAllowed();  		/** -		* @breif Add a name: value http header. +		* @brief Add a name: value http header.  		*  		* No effort is made to ensure the response is a valid http  		* header. @@ -187,15 +205,15 @@ public:  			 name, and return true if the name will construct to a valid url.  			 For convenience, the <code>getChild()</code> method above will  			 automatically insert the name in -			 context["request"]["wildcard"][key] if this method returns true. +			 context[CONTEXT_REQUEST][CONTEXT_WILDCARD][key] if this method returns true.  			 For example, the node "agent/<agent_id>/detail" will set -			 context["request"]["wildcard"]["agent_id"] eqaul to the value  +			 context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["agent_id"] eqaul to the value   			 found during traversal.  		*/  	const LLHTTPNode* traverse(const std::string& path, LLSD& context) const;  		/**< find a node, if any, that can service this path -			 set up context["request"] information  +			 set up context[CONTEXT_REQUEST] information    		*/   	//@} @@ -287,7 +305,7 @@ public:  	void result(const LLSD& result);  	void extendedResult(S32 code, const std::string& body, const LLSD& headers); -	 +	void extendedResult(S32 code, const LLSD& result, const LLSD& headers);  	void status(S32 code, const std::string& message);  	void print(std::ostream& out) const; diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 23813c6edb..d9042fa8b0 100755 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -33,6 +33,7 @@  #include "llapr.h"  #include "llbuffer.h"  #include "llbufferstream.h" +#include "llhttpconstants.h"  #include "llfasttimer.h"  #include "llhttpnode.h"  #include "lliopipe.h" @@ -50,15 +51,6 @@  #include <boost/tokenizer.hpp>  static const char HTTP_VERSION_STR[] = "HTTP/1.0"; -const std::string CONTEXT_REQUEST("request"); -const std::string CONTEXT_RESPONSE("response"); -const std::string CONTEXT_VERB("verb"); -const std::string CONTEXT_HEADERS("headers"); -const std::string HTTP_VERB_GET("GET"); -const std::string HTTP_VERB_PUT("PUT"); -const std::string HTTP_VERB_POST("POST"); -const std::string HTTP_VERB_DELETE("DELETE"); -const std::string HTTP_VERB_OPTIONS("OPTIONS");  static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;  static void* sTimingCallbackData = NULL; @@ -103,7 +95,7 @@ private:  		// from LLHTTPNode::Response  		virtual void result(const LLSD&);  		virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers); -		 +		virtual void extendedResult(S32 code, const LLSD& body, const LLSD& headers);  		virtual void status(S32 code, const std::string& message);  		void nullPipe(); @@ -123,7 +115,8 @@ private:  		STATE_LOCKED,  		STATE_GOOD_RESULT,  		STATE_STATUS_RESULT, -		STATE_EXTENDED_RESULT +		STATE_EXTENDED_RESULT, +		STATE_EXTENDED_LLSD_RESULT  	};  	State mState; @@ -133,7 +126,7 @@ private:  	void lockChain(LLPumpIO*);  	void unlockChain(); -	LLSD mGoodResult; +	LLSD mResult;  	S32 mStatusCode;  	std::string mStatusMessage;	  	LLSD mHeaders; @@ -194,7 +187,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  			}  			else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)  			{ -				std::stringstream strstrm; +				std::ostringstream strstrm;  				strstrm << istr.rdbuf();  				input = strstrm.str();  			} @@ -210,7 +203,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  			}  			else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)  			{ -				std::stringstream strstrm; +				std::ostringstream strstrm;  				strstrm << istr.rdbuf();  				input = strstrm.str();  			} @@ -245,12 +238,12 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		// Log all HTTP transactions.  		// TODO: Add a way to log these to their own file instead of indra.log  		// It is just too spammy to be in indra.log. -		LL_DEBUGS() << verb << " " << context[CONTEXT_REQUEST]["path"].asString() +		LL_DEBUGS() << verb << " " << context[CONTEXT_REQUEST][CONTEXT_PATH].asString()  			<< " " << mStatusCode << " " <<  mStatusMessage << " " << delta  			<< "s" << LL_ENDL;  		// Log Internal Server Errors -		//if(mStatusCode == 500) +		//if(mStatusCode == HTTP_INTERNAL_SERVER_ERROR)  		//{  		//	LL_WARNS() << "LLHTTPPipe::process_impl:500:Internal Server Error"   		//			<< LL_ENDL; @@ -272,10 +265,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		case STATE_GOOD_RESULT:  		{  			LLSD headers = mHeaders; -			headers["Content-Type"] = "application/llsd+xml"; +			headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML;  			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;  			LLBufferStream ostr(channels, buffer.get()); -			LLSDSerialize::toXML(mGoodResult, ostr); +			LLSDSerialize::toXML(mResult, ostr);  			return STATUS_DONE;  		} @@ -283,7 +276,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  		case STATE_STATUS_RESULT:  		{  			LLSD headers = mHeaders; -			headers["Content-Type"] = "text/plain"; +			headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_TEXT_PLAIN;  			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;  			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;  			context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage; @@ -301,6 +294,17 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(  			return STATUS_DONE;  		} +		case STATE_EXTENDED_LLSD_RESULT: +		{ +			LLSD headers = mHeaders; +			headers[HTTP_OUT_HEADER_CONTENT_TYPE] = HTTP_CONTENT_LLSD_XML; +			context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers; +			context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode; +			LLBufferStream ostr(channels, buffer.get()); +			LLSDSerialize::toXML(mResult, ostr); + +			return STATUS_DONE; +		}  		default:  			LL_WARNS() << "LLHTTPPipe::process_impl: unexpected state "  				<< mState << LL_ENDL; @@ -336,12 +340,28 @@ void LLHTTPPipe::Response::result(const LLSD& r)  		return;  	} -	mPipe->mStatusCode = 200; +	mPipe->mStatusCode = HTTP_OK;  	mPipe->mStatusMessage = "OK"; -	mPipe->mGoodResult = r; +	mPipe->mResult = r;  	mPipe->mState = STATE_GOOD_RESULT;  	mPipe->mHeaders = mHeaders; -	mPipe->unlockChain();	 +	mPipe->unlockChain(); +} + +void LLHTTPPipe::Response::extendedResult(S32 code, const LLSD& r, const LLSD& headers) +{ +	if(! mPipe) +	{ +		LL_WARNS() << "LLHTTPPipe::Response::extendedResult: NULL pipe" << LL_ENDL; +		return; +	} + +	mPipe->mStatusCode = code; +	mPipe->mStatusMessage = "(LLSD)"; +	mPipe->mResult = r; +	mPipe->mHeaders = headers; +	mPipe->mState = STATE_EXTENDED_LLSD_RESULT; +	mPipe->unlockChain();  }  void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, const LLSD& headers) @@ -455,9 +475,9 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(  		std::string message = context[CONTEXT_RESPONSE]["statusMessage"];  		int code = context[CONTEXT_RESPONSE]["statusCode"]; -		if (code < 200) +		if (code < HTTP_OK)  		{ -			code = 200; +			code = HTTP_OK;  			message = "OK";  		} @@ -466,7 +486,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(  		S32 content_length = buffer->countAfter(channels.in(), NULL);  		if(0 < content_length)  		{ -			ostr << "Content-Length: " << content_length << "\r\n"; +			ostr << HTTP_OUT_HEADER_CONTENT_LENGTH << ": " << content_length << "\r\n";  		}  		// *NOTE: This guard can go away once the LLSD static map  		// iterator is available. Phoenix. 2008-05-09 @@ -772,7 +792,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  					std::string name(buf, pos_colon - buf);  					std::string value(pos_colon + 2);  					LLStringUtil::toLower(name); -					if("content-length" == name) +					if(HTTP_IN_HEADER_CONTENT_LENGTH == name)  					{  						LL_DEBUGS() << "Content-Length: " << value << LL_ENDL;  						mContentLength = atoi(value.c_str()); @@ -847,12 +867,12 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(  			// HTTP headers.  			LLPumpIO::chain_t chain;  			chain.push_back(LLIOPipe::ptr_t(new LLIOFlush)); -			context[CONTEXT_REQUEST]["path"] = mPath; -			context[CONTEXT_REQUEST]["query-string"] = mQuery; -			context[CONTEXT_REQUEST]["remote-host"] -				= mBuildContext["remote-host"]; -			context[CONTEXT_REQUEST]["remote-port"] -				= mBuildContext["remote-port"]; +			context[CONTEXT_REQUEST][CONTEXT_PATH] = mPath; +			context[CONTEXT_REQUEST][CONTEXT_QUERY_STRING] = mQuery; +			context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST] +				= mBuildContext[CONTEXT_REMOTE_HOST]; +			context[CONTEXT_REQUEST][CONTEXT_REMOTE_PORT] +				= mBuildContext[CONTEXT_REMOTE_PORT];  			context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders;  			const LLChainIOFactory* protocolHandler diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h index 5c1b0531ff..a23eafe58a 100755 --- a/indra/llmessage/lliohttpserver.h +++ b/indra/llmessage/lliohttpserver.h @@ -33,18 +33,6 @@  class LLPumpIO; -// common strings use for populating the context. bascally 'request', -// 'wildcard', and 'headers'. -extern const std::string CONTEXT_REQUEST; -extern const std::string CONTEXT_RESPONSE; -extern const std::string CONTEXT_VERB; -extern const std::string CONTEXT_HEADERS; -extern const std::string HTTP_VERB_GET; -extern const std::string HTTP_VERB_PUT; -extern const std::string HTTP_VERB_POST; -extern const std::string HTTP_VERB_DELETE; -extern const std::string HTTP_VERB_OPTIONS; -  class LLIOHTTPServer  {  public: diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index 4b8d1b44f6..b7460df508 100755 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -40,6 +40,9 @@  // constants  // +const std::string CONTEXT_REMOTE_HOST("remote-host"); +const std::string CONTEXT_REMOTE_PORT("remote-port"); +  static const S32 LL_DEFAULT_LISTEN_BACKLOG = 10;  static const S32 LL_SEND_BUFFER_SIZE = 40000;  static const S32 LL_RECV_BUFFER_SIZE = 40000; @@ -620,8 +623,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(  		apr_sockaddr_ip_get(&remote_host_string, remote_addr);  		LLSD context; -		context["remote-host"] = remote_host_string; -		context["remote-port"] = remote_addr->port; +		context[CONTEXT_REMOTE_HOST] = remote_host_string; +		context[CONTEXT_REMOTE_PORT] = remote_addr->port;  		LLPumpIO::chain_t chain;  		chain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(llsocket))); diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index ec998552d0..f840f0275c 100755 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -43,6 +43,9 @@  #include "apr_network_io.h"  #include "llchainio.h" +extern const std::string CONTEXT_REMOTE_HOST; +extern const std::string CONTEXT_REMOTE_PORT; +  class LLHost;  /**  diff --git a/indra/llmessage/llmime.cpp b/indra/llmessage/llmime.cpp deleted file mode 100755 index 9d9c4ebd68..0000000000 --- a/indra/llmessage/llmime.cpp +++ /dev/null @@ -1,629 +0,0 @@ -/**  - * @file llmime.cpp - * @author Phoenix - * @date 2006-12-20 - * @brief Implementation of mime tools. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llmime.h" - -#include <vector> - -#include "llmemorystream.h" - -/** - * Useful constants. - */ -// Headers specified in rfc-2045 will be canonicalized below. -static const std::string CONTENT_LENGTH("Content-Length"); -static const std::string CONTENT_TYPE("Content-Type"); -static const S32 KNOWN_HEADER_COUNT = 6; -static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] = -{ -	CONTENT_LENGTH, -	CONTENT_TYPE, -	std::string("MIME-Version"), -	std::string("Content-Transfer-Encoding"), -	std::string("Content-ID"), -	std::string("Content-Description"), -}; - -// parser helpers -static const std::string MULTIPART("multipart"); -static const std::string BOUNDARY("boundary"); -static const std::string END_OF_CONTENT_PARAMETER("\r\n ;\t"); -static const std::string SEPARATOR_PREFIX("--"); -//static const std::string SEPARATOR_SUFFIX("\r\n"); - -/* -Content-Type: multipart/mixed; boundary="segment" -Content-Length: 24832 - ---segment -Content-Type: image/j2c -Content-Length: 23715 - -<data> - ---segment -Content-Type: text/xml; charset=UTF-8 - -<meta data> -EOF - -*/ - -/** - * LLMimeIndex - */ - -/**  - * @class LLMimeIndex::Impl - * @brief Implementation details of the mime index class. - * @see LLMimeIndex - */ -class LLMimeIndex::Impl -{ -public: -	Impl() : mOffset(-1), mUseCount(1) -	{} -	Impl(LLSD headers, S32 offset) : -		mHeaders(headers), mOffset(offset), mUseCount(1) -	{} -public: -	LLSD mHeaders; -	S32 mOffset; -	S32 mUseCount; - -	typedef std::vector<LLMimeIndex> sub_part_t; -	sub_part_t mAttachments; -}; - -LLSD LLMimeIndex::headers() const -{ -	return mImpl->mHeaders; -} - -S32 LLMimeIndex::offset() const -{ -	return mImpl->mOffset; -} - -S32 LLMimeIndex::contentLength() const -{ -	// Find the content length in the headers. -	S32 length = -1; -	LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH]; -	if(content_length.isDefined()) -	{ -		length = content_length.asInteger(); -	} -	return length; -} - -std::string LLMimeIndex::contentType() const -{ -	std::string type; -	LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; -	if(content_type.isDefined()) -	{ -		type = content_type.asString(); -	} -	return type; -} - -bool LLMimeIndex::isMultipart() const -{ -	bool multipart = false; -	LLSD content_type = mImpl->mHeaders[CONTENT_TYPE]; -	if(content_type.isDefined()) -	{ -		std::string type = content_type.asString(); -		int comp = type.compare(0, MULTIPART.size(), MULTIPART); -		if(0 == comp) -		{ -			multipart = true; -		} -	} -	return multipart; -} - -S32 LLMimeIndex::subPartCount() const -{ -	return mImpl->mAttachments.size(); -} - -LLMimeIndex LLMimeIndex::subPart(S32 index) const -{ -	LLMimeIndex part; -	if((index >= 0) && (index < (S32)mImpl->mAttachments.size())) -	{ -		part = mImpl->mAttachments[index]; -	} -	return part; -} - -LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl) -{ -} - -LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) : -	mImpl(new LLMimeIndex::Impl(headers, content_offset)) -{ -} - -LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) : -	mImpl(mime.mImpl) -{ -	++mImpl->mUseCount; -} - -LLMimeIndex::~LLMimeIndex() -{ -	if(0 == --mImpl->mUseCount) -	{ -		delete mImpl; -	} -} - -LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime) -{ -	// Increment use count first so that we handle self assignment -	// automatically. -	++mime.mImpl->mUseCount; -	if(0 == --mImpl->mUseCount) -	{ -		delete mImpl; -	} -	mImpl = mime.mImpl; -	return *this; -} - -bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part) -{ -	// *FIX: Should we check for multi-part? -	if(mImpl->mAttachments.size() < S32_MAX) -	{ -		mImpl->mAttachments.push_back(sub_part); -		return true; -	} -	return false; -} - -/** - * LLMimeParser - */ -/**  - * @class LLMimeParser::Impl - * @brief Implementation details of the mime parser class. - * @see LLMimeParser - */ -class LLMimeParser::Impl -{ -public: -	// @brief Constructor. -	Impl(); - -	// @brief Reset this for a new parse. -	void reset(); - -	/**  -	 * @brief Parse a mime entity to find the index information. -	 * -	 * This method will scan the istr until a single complete mime -	 * entity is read, an EOF, or limit bytes have been scanned. The -	 * istr will be modified by this parsing, so pass in a temporary -	 * stream or rewind/reset the stream after this call. -	 * @param istr An istream which contains a mime entity. -	 * @param limit The maximum number of bytes to scan. -	 * @param separator The multipart separator if it is known. -	 * @param is_subpart Set true if parsing a multipart sub part. -	 * @param index[out] The parsed output. -	 * @return Returns true if an index was parsed and no errors occurred. -	 */ -	bool parseIndex( -		std::istream& istr, -		S32 limit, -		const std::string& separator, -		bool is_subpart, -		LLMimeIndex& index); - -protected: -	/** -	 * @brief parse the headers. -	 * -	 * At the end of a successful parse, mScanCount will be at the -	 * start of the content. -	 * @param istr The input stream. -	 * @param limit maximum number of bytes to process -	 * @param headers[out] A map of the headers found. -	 * @return Returns true if the parse was successful. -	 */ -	bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers); - -	/** -	 * @brief Figure out the separator string from a content type header. -	 *  -	 * @param multipart_content_type The content type value from the headers. -	 * @return Returns the separator string. -	 */ -	std::string findSeparator(std::string multipart_content_type); - -	/** -	 * @brief Scan through istr past the separator. -	 * -	 * @param istr The input stream. -	 * @param limit Maximum number of bytes to scan. -	 * @param separator The multipart separator. -	 */ -	void scanPastSeparator( -		std::istream& istr, -		S32 limit, -		const std::string& separator); - -	/** -	 * @brief Scan through istr past the content of the current mime part. -	 * -	 * @param istr The input stream. -	 * @param limit Maximum number of bytes to scan. -	 * @param headers The headers for this mime part. -	 * @param separator The multipart separator if known. -	 */ -	void scanPastContent( -		std::istream& istr, -		S32 limit, -		LLSD headers, -		const std::string separator); - -	/** -	 * @brief Eat CRLF. -	 * -	 * This method has no concept of the limit, so ensure you have at -	 * least 2 characters left to eat before hitting the limit. This -	 * method will increment mScanCount as it goes. -	 * @param istr The input stream. -	 * @return Returns true if CRLF was found and consumed off of istr. -	 */ -	bool eatCRLF(std::istream& istr); - -	// @brief Returns true if parsing should continue. -	bool continueParse() const { return (!mError && mContinue); } - -	// @brief anonymous enumeration for parse buffer size. -	enum -	{ -		LINE_BUFFER_LENGTH = 1024 -	}; - -protected: -	S32 mScanCount; -	bool mContinue; -	bool mError; -	char mBuffer[LINE_BUFFER_LENGTH]; -}; - -LLMimeParser::Impl::Impl() -{ -	reset(); -} - -void LLMimeParser::Impl::reset() -{ -	mScanCount = 0; -	mContinue = true; -	mError = false; -	mBuffer[0] = '\0'; -} - -bool LLMimeParser::Impl::parseIndex( -	std::istream& istr, -	S32 limit, -	const std::string& separator, -	bool is_subpart, -	LLMimeIndex& index) -{ -	LLSD headers; -	bool parsed_something = false; -	if(parseHeaders(istr, limit, headers)) -	{ -		parsed_something = true; -		LLMimeIndex mime(headers, mScanCount); -		index = mime; -		if(index.isMultipart()) -		{ -			// Figure out the separator, scan past it, and recurse. -			std::string ct = headers[CONTENT_TYPE].asString(); -			std::string sep = findSeparator(ct); -			scanPastSeparator(istr, limit, sep); -			while(continueParse() && parseIndex(istr, limit, sep, true, mime)) -			{ -				index.attachSubPart(mime); -			} -		} -		else -		{ -			// Scan to the end of content. -			scanPastContent(istr, limit, headers, separator); -			if(is_subpart) -			{ -				scanPastSeparator(istr, limit, separator); -			} -		} -	} -	if(mError) return false; -	return parsed_something; -} - -bool LLMimeParser::Impl::parseHeaders( -	std::istream& istr, -	S32 limit, -	LLSD& headers) -{ -	while(continueParse()) -	{ -		// Get the next line. -		// We subtract 1 from the limit so that we make sure -		// not to read past limit when we get() the newline. -		S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); -		istr.getline(mBuffer, max_get, '\r'); -		mScanCount += (S32)istr.gcount(); -		int c = istr.get(); -		if(EOF == c) -		{ -			mContinue = false; -			return false; -		} -		++mScanCount; -		if(c != '\n') -		{ -			mError = true; -			return false; -		} -		if(mScanCount >= limit) -		{ -			mContinue = false; -		} - -		// Check if that's the end of headers. -		if('\0' == mBuffer[0]) -		{ -			break; -		} - -		// Split out the name and value. -		// *NOTE: The use of strchr() here is safe since mBuffer is -		// guaranteed to be NULL terminated from the call to getline() -		// above. -		char* colon = strchr(mBuffer, ':'); -		if(!colon) -		{ -			mError = true; -			return false; -		} - -		// Cononicalize the name part, and store the name: value in -		// the headers structure. We do this by iterating through -		// 'known' headers and replacing the value found with the -		// correct one. -		// *NOTE: Not so efficient, but iterating through a small -		// subset should not be too much of an issue. -		std::string name(mBuffer, colon++ - mBuffer); -		while(isspace(*colon)) ++colon; -		std::string value(colon); -		for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii) -		{ -			if(0 == LLStringUtil::compareInsensitive(name, KNOWN_HEADER[ii])) -			{ -				name = KNOWN_HEADER[ii]; -				break; -			} -		} -		headers[name] = value; -	} -	if(headers.isUndefined()) return false; -	return true; -} - -std::string LLMimeParser::Impl::findSeparator(std::string header) -{ -	//                               01234567890 -	//Content-Type: multipart/mixed; boundary="segment" -	std::string separator; -	std::string::size_type pos = header.find(BOUNDARY); -	if(std::string::npos == pos) return separator; -	pos += BOUNDARY.size() + 1; -	std::string::size_type end; -	if(header[pos] == '"') -	{ -		// the boundary is quoted, find the end from pos, and take the -		// substring. -		end = header.find('"', ++pos); -		if(std::string::npos == end) -		{ -			// poorly formed boundary. -			mError = true; -		} -	} -	else -	{ -		// otherwise, it's every character until a whitespace, end of -		// line, or another parameter begins. -		end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos); -		if(std::string::npos == end) -		{ -			// it goes to the end of the string. -			end = header.size(); -		} -	} -	if(!mError) separator = header.substr(pos, end - pos); -	return separator; -} - -void LLMimeParser::Impl::scanPastSeparator( -	std::istream& istr, -	S32 limit, -	const std::string& sep) -{ -	std::ostringstream ostr; -	ostr << SEPARATOR_PREFIX << sep; -	std::string separator = ostr.str(); -	bool found_separator = false; -	while(!found_separator && continueParse()) -	{ -		// Subtract 1 from the limit so that we make sure not to read -		// past limit when we get() the newline. -		S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1); -		istr.getline(mBuffer, max_get, '\r'); -		mScanCount += (S32)istr.gcount(); -		if(istr.gcount() >= LINE_BUFFER_LENGTH - 1) -		{ -			// that's way too long to be a separator, so ignore it. -			continue; -		} -		int c = istr.get(); -		if(EOF == c) -		{ -			mContinue = false; -			return; -		} -		++mScanCount; -		if(c != '\n') -		{ -			mError = true; -			return; -		} -		if(mScanCount >= limit) -		{ -			mContinue = false; -		} -		if(0 == LLStringUtil::compareStrings(std::string(mBuffer), separator)) -		{ -			found_separator = true; -		} -	} -} - -void LLMimeParser::Impl::scanPastContent( -	std::istream& istr, -	S32 limit, -	LLSD headers, -	const std::string separator) -{ -	if(headers.has(CONTENT_LENGTH)) -	{ -		S32 content_length = headers[CONTENT_LENGTH].asInteger(); -		// Subtract 2 here for the \r\n after the content. -		S32 max_skip = llmin(content_length, limit - mScanCount - 2); -		istr.ignore(max_skip); -		mScanCount += max_skip; - -		// *NOTE: Check for hitting the limit and eof here before -		// checking for the trailing EOF, because our mime parser has -		// to gracefully handle incomplete mime entites. -		if((mScanCount >= limit) || istr.eof()) -		{ -			mContinue = false; -		} -		else if(!eatCRLF(istr)) -		{ -			mError = true; -			return; -		} -	} -} - -bool LLMimeParser::Impl::eatCRLF(std::istream& istr) -{ -	int c = istr.get(); -	++mScanCount; -	if(c != '\r') -	{ -		return false; -	} -	c = istr.get(); -	++mScanCount; -	if(c != '\n') -	{ -		return false; -	} -	return true; -} -	 - -LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl) -{ -} - -LLMimeParser::~LLMimeParser() -{ -	delete & mImpl; -} - -void LLMimeParser::reset() -{ -	mImpl.reset(); -} - -bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index) -{ -	std::string separator; -	return mImpl.parseIndex(istr, S32_MAX, separator, false, index); -} - -bool LLMimeParser::parseIndex( -	const std::vector<U8>& buffer, -	LLMimeIndex& index) -{ -	LLMemoryStream mstr(&buffer[0], buffer.size()); -	return parseIndex(mstr, buffer.size() + 1, index); -} - -bool LLMimeParser::parseIndex( -	std::istream& istr, -	S32 limit, -	LLMimeIndex& index) -{ -	std::string separator; -	return mImpl.parseIndex(istr, limit, separator, false, index); -} - -bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index) -{ -	LLMemoryStream mstr(buffer, length); -	return parseIndex(mstr, length + 1, index); -} - -/* -bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const -{ -	return false; -} - -bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const -{ -	LLMemoryStream mstr(buffer, length); -	return verify(mstr, index); -} -*/ diff --git a/indra/llmessage/llmime.h b/indra/llmessage/llmime.h deleted file mode 100755 index e6617fb503..0000000000 --- a/indra/llmessage/llmime.h +++ /dev/null @@ -1,292 +0,0 @@ -/**  - * @file llmime.h - * @author Phoenix - * @date 2006-12-20 - * @brief Declaration of mime tools. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLMIME_H -#define LL_LLMIME_H - -#include <string> -#include "llsd.h" - -/** - * This file declares various tools for parsing and creating MIME - * objects as described in RFCs 2045, 2046, 2047, 2048, and 2049. - */ - -/**  - * @class LLMimeIndex - * @brief Skeletal information useful for handling mime packages. - * @see LLMimeParser - * - * An instance of this class is the parsed output from a LLMimeParser - * which then allows for easy access into a data stream to find and - * get what you want out of it. - * - * This class meant as a tool to quickly find what you seek in a - * parsed mime entity. As such, it does not have useful support for - * modification of a mime entity and specializes the interface toward - * querying data from a fixed mime entity. Modifying an instance of - * LLMimeIndx does not alter a mime entity and changes to a mime - * entity itself are not propogated into an instance of a LLMimeIndex. - * - * Usage:<br> - *  LLMimeIndex mime_index;<br> - *  std::ifstream fstr("package.mime", ios::binary);<br> - *  LLMimeParser parser;<br> - *  if(parser.parseIndex(fstr, mime_index))<br> - *  {<br> - *    std::vector<U8> content;<br> - *    content.resize(mime_index.contentLength());<br> - *    fstr.seekg(mime_index.offset(), ios::beg);<br> - *    // ...do work on fstr and content<br> - *  }<br> - */ -class LLMimeIndex -{ -public: -	/* @name Client interface. -	 */ -	//@{ -	/**  -	 * @brief Get the full parsed headers for this. -	 * -	 * If there are any headers, it will be a map of header name to -	 * the value found on the line. The name is everything before the -	 * colon, and the value is the string found after the colon to the -	 * end of the line after trimming leading whitespace. So, for -	 * example: -	 * Content-Type:  text/plain -	 * would become an entry in the headers of: -	 * headers["Content-Type"] == "text/plain" -	 * -	 * If this instance of an index was generated by the -	 * LLMimeParser::parseIndex() call, all header names in rfc2045 -	 * will be capitalized as in rfc, eg Content-Length and -	 * MIME-Version, not content-length and mime-version. -	 * @return Returns an LLSD map of header name to value. Returns -	 * undef if there are no headers. -	 */ -	LLSD headers() const; - -	/**  -	 * @brief Get the content offset. -	 * -	 * @return Returns the number of bytes to the start of the data -	 * segment from the start of serialized mime entity. Returns -1 if -	 * offset is not known. -	 */ -	S32 offset() const; - -	/**  -	 * @brief Get the length of the data segment for this mime part. -	 * -	 * @return Returns the content length in bytes. Returns -1 if -	 * length is not known. -	 */ -	S32 contentLength() const; - -	/**  -	 * @brief Get the mime type associated with this node. -	 * -	 * @return Returns the mimetype. -	 */ -	std::string contentType() const; - -	/**  -	 * @brief Helper method which simplifies parsing the return from type() -	 * -	 * @return Returns true if this is a multipart mime, and therefore -	 * getting subparts will succeed. -	 */ -	bool isMultipart() const; - -	/**  -	 * @brief Get the number of atachments. -	 * -	 * @return Returns the number of sub-parts for this. -	 */ -	S32 subPartCount() const; - -	/**  -	 * @brief Get the indicated attachment. -	 * -	 * @param index Value from 0 to (subPartCount() - 1). -	 * @return Returns the indicated sub-part, or an invalid mime -	 * index on failure. -	 */ -	LLMimeIndex subPart(S32 index) const; -	//@} - -	/* @name Interface for building, testing, and helpers for typical use. -	 */ -	//@{ -	/** -	 * @brief Default constructor - creates a useless LLMimeIndex. -	 */ -	LLMimeIndex(); - -	/** -	 * @brief Full constructor. -	 * -	 * @param headers The complete headers. -	 * @param content_offset The number of bytes to the start of the -	 * data segment of this mime entity from the start of the stream -	 * or buffer. -	 */ -	LLMimeIndex(LLSD headers, S32 content_offset); - -	/** -	 * @brief Copy constructor. -	 * -	 * @param mime The other mime object. -	 */ -	LLMimeIndex(const LLMimeIndex& mime); - -	// @brief Destructor. -	~LLMimeIndex(); - -	/* -	 * @breif Assignment operator. -	 * -	 * @param mime The other mime object. -	 * @return Returns this after assignment. -	 */ -	LLMimeIndex& operator=(const LLMimeIndex& mime); - -	/**  -	 * @brief Add attachment information as a sub-part to a multipart mime. -	 * -	 * @param sub_part the part to attach. -	 * @return Returns true on success, false on failure. -	 */ -	bool attachSubPart(LLMimeIndex sub_part); -	//@} - -protected: -	// Implementation. -	class Impl; -	Impl* mImpl; -}; - - -/**  - * @class LLMimeParser - * @brief This class implements a MIME parser and verifier. - * - * THOROUGH_DESCRIPTION - */ -class LLMimeParser -{ -public: -	// @brief Make a new mime parser. -	LLMimeParser(); -	 -	// @brief Mime parser Destructor. -	~LLMimeParser(); - -	// @brief Reset internal state of this parser. -	void reset(); - -	 -	/* @name Index generation interface. -	 */ -	//@{ -	/**  -	 * @brief Parse a stream to find the mime index information. -	 * -	 * This method will scan the istr until a single complete mime -	 * entity is read or EOF. The istr will be modified by this -	 * parsing, so pass in a temporary stream or rewind/reset the -	 * stream after this call. -	 * @param istr An istream which contains a mime entity. -	 * @param index[out] The parsed output. -	 * @return Returns true if an index was parsed and no errors occurred. -	 */ -	bool parseIndex(std::istream& istr, LLMimeIndex& index); - -	/**  -	 * @brief Parse a vector to find the mime index information. -	 * -	 * @param buffer A vector with data to parse. -	 * @param index[out] The parsed output. -	 * @return Returns true if an index was parsed and no errors occurred. -	 */ -	bool parseIndex(const std::vector<U8>& buffer, LLMimeIndex& index); - -	/**  -	 * @brief Parse a stream to find the mime index information. -	 * -	 * This method will scan the istr until a single complete mime -	 * entity is read, an EOF, or limit bytes have been scanned. The -	 * istr will be modified by this parsing, so pass in a temporary -	 * stream or rewind/reset the stream after this call. -	 * @param istr An istream which contains a mime entity. -	 * @param limit The maximum number of bytes to scan. -	 * @param index[out] The parsed output. -	 * @return Returns true if an index was parsed and no errors occurred. -	 */ -	bool parseIndex(std::istream& istr, S32 limit, LLMimeIndex& index); - -	/**  -	 * @brief Parse a memory bufffer to find the mime index information. -	 * -	 * @param buffer The start of the buffer to parse. -	 * @param buffer_length The length of the buffer. -	 * @param index[out] The parsed output. -	 * @return Returns true if an index was parsed and no errors occurred. -	 */ -	bool parseIndex(const U8* buffer, S32 buffer_length, LLMimeIndex& index); -	//@} - -	/**  -	 * @brief  -	 * -	 * @return -	 */ -	//bool verify(std::istream& istr, LLMimeIndex& index) const; - -	/**  -	 * @brief  -	 * -	 * @return -	 */ -	//bool verify(U8* buffer, S32 buffer_length, LLMimeIndex& index) const; - -protected: -	// Implementation. -	class Impl; -	Impl& mImpl; - -private: -	// @brief Not implemneted to prevent copy consturction. -	LLMimeParser(const LLMimeParser& parser); - -	// @brief Not implemneted to prevent assignment. -	LLMimeParser& operator=(const LLMimeParser& mime); -}; - -#endif // LL_LLMIME_H diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp deleted file mode 100755 index e6ed37028a..0000000000 --- a/indra/llmessage/llregionpresenceverifier.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/**  - * @file llregionpresenceverifier.cpp - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llregionpresenceverifier.h" -#include "llhttpclientinterface.h" -#include <sstream> -#include "net.h" -#include "message.h" - -namespace boost -{ -	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p) -	{ -		++p->mReferenceCount; -	} -	 -	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p) -	{ -		if(p && 0 == --p->mReferenceCount) -		{ -			delete p; -		} -	} -}; - -LLRegionPresenceVerifier::Response::~Response() -{ -} - -LLRegionPresenceVerifier::RegionResponder::RegionResponder(const std::string& -														   uri, -														   ResponsePtr data, -														   S32 retry_count) : -	mUri(uri), -	mSharedData(data), -	mRetryCount(retry_count) -{ -} - -//virtual -LLRegionPresenceVerifier::RegionResponder::~RegionResponder() -{ -} - -void LLRegionPresenceVerifier::RegionResponder::result(const LLSD& content) -{ -	std::string host = content["private_host"].asString(); -	U32 port = content["private_port"].asInteger(); -	LLHost destination(host, port); -	LLUUID id = content["region_id"]; - -	LL_DEBUGS() << "Verifying " << destination.getString() << " is region " << id << LL_ENDL; - -	std::stringstream uri; -	uri << "http://" << destination.getString() << "/state/basic/"; -	mSharedData->getHttpClient().get( -		uri.str(), -		new VerifiedDestinationResponder(mUri, mSharedData, content, mRetryCount)); -} - -void LLRegionPresenceVerifier::RegionResponder::error(U32 status, -													 const std::string& reason) -{ -	// TODO: babbage: distinguish between region presence service and -	// region verification errors? -	mSharedData->onRegionVerificationFailed(); -} - -LLRegionPresenceVerifier::VerifiedDestinationResponder::VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, const LLSD& content, -	S32 retry_count): -	mUri(uri), -	mSharedData(data), -	mContent(content), -	mRetryCount(retry_count)  -{ -} - -//virtual -LLRegionPresenceVerifier::VerifiedDestinationResponder::~VerifiedDestinationResponder() -{ -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::result(const LLSD& content) -{ -	LLUUID actual_region_id = content["region_id"]; -	LLUUID expected_region_id = mContent["region_id"]; - -	LL_DEBUGS() << "Actual region: " << content << LL_ENDL; -	LL_DEBUGS() << "Expected region: " << mContent << LL_ENDL; - -	if (mSharedData->checkValidity(content) && -		(actual_region_id == expected_region_id)) -	{ -		mSharedData->onRegionVerified(mContent); -	} -	else if (mRetryCount > 0) -	{ -		retry(); -	} -	else -	{ -		LL_WARNS() << "Simulator verification failed. Region: " << mUri << LL_ENDL; -		mSharedData->onRegionVerificationFailed(); -	} -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::retry() -{ -	LLSD headers; -	headers["Cache-Control"] = "no-cache, max-age=0"; -	LL_INFOS() << "Requesting region information, get uncached for region " -			<< mUri << LL_ENDL; -	--mRetryCount; -	mSharedData->getHttpClient().get(mUri, new RegionResponder(mUri, mSharedData, mRetryCount), headers); -} - -void LLRegionPresenceVerifier::VerifiedDestinationResponder::error(U32 status, const std::string& reason) -{ -	if(mRetryCount > 0) -	{ -		retry(); -	} -	else -	{ -		LL_WARNS() << "Failed to contact simulator for verification. Region: " << mUri << LL_ENDL; -		mSharedData->onRegionVerificationFailed(); -	} -} diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h deleted file mode 100755 index 5e8251e519..0000000000 --- a/indra/llmessage/llregionpresenceverifier.h +++ /dev/null @@ -1,98 +0,0 @@ -/**  - * @file llregionpresenceverifier.cpp - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -/* Macro Definitions */ -#ifndef LL_LLREGIONPRESENCEVERIFIER_H -#define LL_LLREGIONPRESENCEVERIFIER_H - -#include "llhttpclient.h" -#include <string> -#include "llsd.h" -#include <boost/intrusive_ptr.hpp> - -class LLHTTPClientInterface; - -class LLRegionPresenceVerifier -{ -public: -	class Response -	{ -	public: -		virtual ~Response() = 0; - -		virtual bool checkValidity(const LLSD& content) const = 0; -		virtual void onRegionVerified(const LLSD& region_details) = 0; -		virtual void onRegionVerificationFailed() = 0; - -		virtual LLHTTPClientInterface& getHttpClient() = 0; - -	public: /* but not really -- don't touch this */ -		U32 mReferenceCount;		 -	}; - -	typedef boost::intrusive_ptr<Response> ResponsePtr; - -	class RegionResponder : public LLHTTPClient::Responder -	{ -	public: -		RegionResponder(const std::string& uri, ResponsePtr data, -						S32 retry_count); -		virtual ~RegionResponder();  -		virtual void result(const LLSD& content); -		virtual void error(U32 status, const std::string& reason); - -	private: -		ResponsePtr mSharedData; -		std::string mUri; -		S32 mRetryCount; -	}; - -	class VerifiedDestinationResponder : public LLHTTPClient::Responder -	{ -	public: -		VerifiedDestinationResponder(const std::string& uri, ResponsePtr data, -									 const LLSD& content, S32 retry_count); -		virtual ~VerifiedDestinationResponder(); -		virtual void result(const LLSD& content); -		 -		virtual void error(U32 status, const std::string& reason); -		 -	private: -		void retry(); -		ResponsePtr mSharedData; -		LLSD mContent; -		std::string mUri; -		S32 mRetryCount; -	}; -}; - -namespace boost -{ -	void intrusive_ptr_add_ref(LLRegionPresenceVerifier::Response* p); -	void intrusive_ptr_release(LLRegionPresenceVerifier::Response* p); -}; - -#endif //LL_LLREGIONPRESENCEVERIFIER_H diff --git a/indra/llmessage/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp index 4103ece33a..4ca45267bd 100755 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -121,7 +121,7 @@ public:  	{  		//LL_INFOS() << "validate: " << name << ", "  		//	<< LLSDOStreamer<LLSDNotationFormatter>(context) << LL_ENDL; -		if((std::string("PUT") == context["request"]["verb"].asString()) && !name.empty()) +		if((std::string("PUT") == context[CONTEXT_REQUEST][CONTEXT_VERB].asString()) && !name.empty())  		{  			return true;  		} @@ -139,7 +139,7 @@ public:  		LLHTTPNode::ResponsePtr response,  		const LLSD& context) const  	{ -		std::string name = context["request"]["wildcard"]["option-name"]; +		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];  		LLSD options = LLApp::instance()->getOptionData(  			LLApp::PRIORITY_RUNTIME_OVERRIDE);  		response->result(options[name]); @@ -150,7 +150,7 @@ public:  		const LLSD& context,  		const LLSD& input) const  	{ -		std::string name = context["request"]["wildcard"]["option-name"]; +		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];  		LLSD options = LLApp::instance()->getOptionData(  			LLApp::PRIORITY_RUNTIME_OVERRIDE);  		options[name] = input; @@ -164,7 +164,7 @@ public:  		LLHTTPNode::ResponsePtr response,  		const LLSD& context) const  	{ -		std::string name = context["request"]["wildcard"]["option-name"]; +		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];  		LLSD options = LLApp::instance()->getOptionData(  			LLApp::PRIORITY_RUNTIME_OVERRIDE);  		options.erase(name); @@ -268,7 +268,7 @@ public:  		LLHTTPNode::ResponsePtr response,  		const LLSD& context) const  	{ -		std::string name = context["request"]["wildcard"]["option-name"]; +		std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["option-name"];  		response->result(LLApp::instance()->getOption(name));  	}  }; diff --git a/indra/llmessage/llsdhttpserver.cpp b/indra/llmessage/llsdhttpserver.cpp index 5c8fc7b2bb..8ac6b3cb12 100755 --- a/indra/llmessage/llsdhttpserver.cpp +++ b/indra/llmessage/llsdhttpserver.cpp @@ -109,7 +109,7 @@ public:      virtual void get(ResponsePtr response, const LLSD& context) const  	{ -		const LLSD& remainder = context["request"]["remainder"]; +		const LLSD& remainder = context[CONTEXT_REQUEST]["remainder"];  		if (remainder.size() > 0)  		{ diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index 1d0904e3f1..61fcc5dd2f 100755 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -92,14 +92,14 @@ bool LLSDMessage::httpListener(const LLSD& request)      return false;  } -void LLSDMessage::EventResponder::result(const LLSD& data) +void LLSDMessage::EventResponder::httpSuccess()  {      // If our caller passed an empty replyPump name, they're not      // listening: this is a fire-and-forget message. Don't bother posting      // to the pump whose name is "".      if (! mReplyPump.empty())      { -        LLSD response(data); +        LLSD response(getContent());          mReqID.stamp(response);          mPumps.obtain(mReplyPump).post(response);      } @@ -111,7 +111,7 @@ void LLSDMessage::EventResponder::result(const LLSD& data)      }  } -void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLSDMessage::EventResponder::httpFailure()  {      // If our caller passed an empty errorPump name, they're not      // listening: "default error handling is acceptable." Only post to an @@ -121,9 +121,9 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string          LLSD info(mReqID.makeResponse());          info["target"]  = mTarget;          info["message"] = mMessage; -        info["status"]  = LLSD::Integer(status); -        info["reason"]  = reason; -        info["content"] = content; +        info["status"]  = getStatus(); +        info["reason"]  = getReason(); +        info["content"] = getContent();          mPumps.obtain(mErrorPump).post(info);      }      else                        // default error handling @@ -131,9 +131,7 @@ void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string          // convention seems to be to use LL_INFOS(), but that seems a bit casual?          LL_WARNS("LLSDMessage::EventResponder")              << "'" << mMessage << "' to '" << mTarget -            << "' failed with code " << status << ": " << reason << '\n' -            << ll_pretty_print_sd(content) -            << LL_ENDL; +            << "' failed " << dumpResponse() << LL_ENDL;      }  } @@ -151,11 +149,11 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success)  {      if (success)      { -        mResponder->result(payload); +        mResponder->successResult(payload);      }      else      { -        mResponder->errorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]); +        mResponder->failureResult(payload["status"].asInteger(), payload["reason"], payload["content"]);      }      /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 0d34847ff2..e5d532d6a4 100755 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -123,6 +123,7 @@ private:      /// LLCapabilityListener. Others should use higher-level APIs.      class EventResponder: public LLHTTPClient::Responder      { +        LOG_CLASS(EventResponder);      public:          /**           * LLHTTPClient::Responder that dispatches via named LLEventPump instances. @@ -149,8 +150,9 @@ private:              mErrorPump(errorPump)          {} -        virtual void result(const LLSD& data); -        virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); +    protected: +        virtual void httpSuccess(); +        virtual void httpFailure();      private:          LLEventPumps& mPumps; diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h index 8eb7a08620..c4e0333ca3 100755 --- a/indra/llmessage/llsdrpcclient.h +++ b/indra/llmessage/llsdrpcclient.h @@ -240,7 +240,7 @@ public:  	virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const  	{  		LL_DEBUGS() << "LLSDRPCClientFactory::build" << LL_ENDL; -		LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST)); +		LLURLRequest* http(new LLURLRequest(HTTP_POST));  		if(!http->isValid())  		{  			LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ; @@ -251,7 +251,7 @@ public:  		LLIOPipe::ptr_t service(new Client);  		chain.push_back(service);		  		LLIOPipe::ptr_t http_pipe(http); -		http->addHeader("Content-Type: text/llsd"); +		http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_LLSD);  		if(mURL.empty())  		{  			chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); @@ -291,7 +291,7 @@ public:  	{  		LL_DEBUGS() << "LLXMLSDRPCClientFactory::build" << LL_ENDL; -		LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST)); +		LLURLRequest* http(new LLURLRequest(HTTP_POST));  		if(!http->isValid())  		{  			LL_WARNS() << "Creating LLURLRequest failed." << LL_ENDL ; @@ -301,7 +301,7 @@ public:  		LLIOPipe::ptr_t service(new Client);  		chain.push_back(service);		  		LLIOPipe::ptr_t http_pipe(http); -		http->addHeader("Content-Type: text/xml"); +		http->addHeader(HTTP_OUT_HEADER_CONTENT_TYPE, HTTP_CONTENT_TEXT_XML);  		if(mURL.empty())  		{  			chain.push_back(LLIOPipe::ptr_t(new LLContextURLExtractor(http))); diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp index 151d02a156..5bd1112cfe 100755 --- a/indra/llmessage/lltrustedmessageservice.cpp +++ b/indra/llmessage/lltrustedmessageservice.cpp @@ -42,9 +42,9 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response,  								   const LLSD& context,  								   const LLSD& input) const  { -	std::string name = context["request"]["wildcard"]["message-name"]; -	std::string senderIP = context["request"]["remote-host"]; -	std::string senderPort = context["request"]["headers"] +	std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"]; +	std::string senderIP = context[CONTEXT_REQUEST][CONTEXT_REMOTE_HOST]; +	std::string senderPort = context[CONTEXT_REQUEST][CONTEXT_HEADERS]  		["x-secondlife-udp-listen-port"];  	LLSD message_data; @@ -64,7 +64,7 @@ void LLTrustedMessageService::post(LLHTTPNode::ResponsePtr response,  		LL_WARNS("Messaging") << "trusted message POST to /trusted-message/"   				<< name << " from unknown or untrusted sender "  				<< sender << LL_ENDL; -		response->status(403, "Unknown or untrusted sender"); +		response->status(HTTP_FORBIDDEN, "Unknown or untrusted sender");  	}  	else  	{ diff --git a/indra/llmessage/lltrustedmessageservice.h b/indra/llmessage/lltrustedmessageservice.h index 688937ac2c..12a37bb535 100755 --- a/indra/llmessage/lltrustedmessageservice.h +++ b/indra/llmessage/lltrustedmessageservice.h @@ -30,6 +30,10 @@  #include "linden_common.h"  #include "llhttpnode.h" +// These are defined in lliosocket.h/lliosocket.cpp   +extern const std::string CONTEXT_REMOTE_HOST; +extern const std::string CONTEXT_REMOTE_PORT; +  class LLSD;  class LLTrustedMessageService diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index 8e4ee85c17..1294379eca 100755 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -41,7 +41,6 @@  #include "llstring.h"  #include "apr_env.h"  #include "llapr.h" -static const U32 HTTP_STATUS_PIPE_ERROR = 499;  /**   * String constants @@ -49,11 +48,12 @@ static const U32 HTTP_STATUS_PIPE_ERROR = 499;  const std::string CONTEXT_DEST_URI_SD_LABEL("dest_uri");  const std::string CONTEXT_TRANSFERED_BYTES("transfered_bytes"); +// These are defined in llhttpnode.h/llhttpnode.cpp +extern const std::string CONTEXT_REQUEST; +extern const std::string CONTEXT_RESPONSE;  static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user); - -  /**   * class LLURLRequestDetail   */ @@ -131,27 +131,8 @@ CURLcode LLURLRequest::_sslCtxCallback(CURL * curl, void *sslctx, void *param)   * class LLURLRequest   */ -// static -std::string LLURLRequest::actionAsVerb(LLURLRequest::ERequestAction action) -{ -	static const std::string VERBS[] = -	{ -		"(invalid)", -		"HEAD", -		"GET", -		"PUT", -		"POST", -		"DELETE", -		"MOVE" -	}; -	if(((S32)action <=0) || ((S32)action >= REQUEST_ACTION_COUNT)) -	{ -		return VERBS[0]; -	} -	return VERBS[action]; -} -LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redirects /* = true */) : +LLURLRequest::LLURLRequest(EHTTPMethod action, bool follow_redirects /* = true */) :  	mAction(action),  	mFollowRedirects(follow_redirects)  { @@ -159,7 +140,7 @@ LLURLRequest::LLURLRequest(LLURLRequest::ERequestAction action, bool follow_redi  }  LLURLRequest::LLURLRequest( -	LLURLRequest::ERequestAction action, +	EHTTPMethod action,  	const std::string& url,  	bool follow_redirects /* = true */) :  	mAction(action), @@ -184,12 +165,17 @@ void LLURLRequest::setURL(const std::string& url)  	}  } -std::string LLURLRequest::getURL() const +const std::string& LLURLRequest::getURL() const  {  	return mDetail->mURL;  } -void LLURLRequest::addHeader(const char* header) +void LLURLRequest::addHeader(const std::string& header, const std::string& value /* = "" */) +{ +	mDetail->mCurlRequest->slist_append(header, value); +} + +void LLURLRequest::addHeaderRaw(const char* header)  {  	mDetail->mCurlRequest->slist_append(header);  } @@ -276,7 +262,7 @@ LLIOPipe::EStatus LLURLRequest::handleError(  		LLURLRequestComplete* complete = NULL;  		complete = (LLURLRequestComplete*)mCompletionCallback.get();  		complete->httpStatus( -			HTTP_STATUS_PIPE_ERROR, +			HTTP_INTERNAL_ERROR,  			LLIOPipe::lookupStatusString(status));  		complete->responseStatus(status);  		pump->respond(complete); @@ -504,21 +490,32 @@ bool LLURLRequest::configure()  	case HTTP_PUT:  		// Disable the expect http 1.1 extension. POST and PUT default  		// to turning this on, and I am not too sure what it means. -		addHeader("Expect:"); +		addHeader(HTTP_OUT_HEADER_EXPECT); + +		mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1); +		mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); +		rv = true; +		break; + +	case HTTP_PATCH: +		// Disable the expect http 1.1 extension. POST and PUT default +		// to turning this on, and I am not too sure what it means. +		addHeader(HTTP_OUT_HEADER_EXPECT);  		mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);  		mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes); +		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH");  		rv = true;  		break;  	case HTTP_POST:  		// Disable the expect http 1.1 extension. POST and PUT default  		// to turning this on, and I am not too sure what it means. -		addHeader("Expect:"); +		addHeader(HTTP_OUT_HEADER_EXPECT);  		// Disable the content type http header.  		// *FIX: what should it be? -		addHeader("Content-Type:"); +		addHeader(HTTP_OUT_HEADER_CONTENT_TYPE);  		// Set the handle for an http post  		mDetail->mCurlRequest->setPost(NULL, bytes); @@ -529,13 +526,19 @@ bool LLURLRequest::configure()  		break;  	case HTTP_DELETE: -		// Set the handle for an http post +		// Set the handle for an http delete  		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "DELETE");  		rv = true;  		break; +	case HTTP_COPY: +		// Set the handle for an http copy +		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "COPY"); +		rv = true; +		break; +  	case HTTP_MOVE: -		// Set the handle for an http post +		// Set the handle for an http move  		mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "MOVE");  		// *NOTE: should we check for the Destination header?  		rv = true; @@ -648,7 +651,7 @@ static size_t headerCallback(void* data, size_t size, size_t nmemb, void* user)  		S32 status_code = atoi(status.c_str());  		if (status_code > 0)  		{ -			complete->httpStatus((U32)status_code, reason); +			complete->httpStatus(status_code, reason);  			return header_len;  		}  	} diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h index 20d6e30d17..88fccd4bf6 100755 --- a/indra/llmessage/llurlrequest.h +++ b/indra/llmessage/llurlrequest.h @@ -42,9 +42,10 @@  #include "llcurl.h" -extern const std::string CONTEXT_REQUEST; +/** + * External constants + */  extern const std::string CONTEXT_DEST_URI_SD_LABEL; -extern const std::string CONTEXT_RESPONSE;  extern const std::string CONTEXT_TRANSFERED_BYTES;  class LLURLRequestDetail; @@ -68,42 +69,22 @@ class LLURLRequest : public LLIOPipe  {  	LOG_CLASS(LLURLRequest);  public: -  	typedef int (* SSLCertVerifyCallback)(X509_STORE_CTX *ctx, void *param); -	/**  -	 * @brief This enumeration is for specifying the type of request. -	 */ -	enum ERequestAction -	{ -		INVALID, -		HTTP_HEAD, -		HTTP_GET, -		HTTP_PUT, -		HTTP_POST, -		HTTP_DELETE, -		HTTP_MOVE, // Caller will need to set 'Destination' header -		REQUEST_ACTION_COUNT -	}; - -	/** -	 * @brief Turn the requst action into an http verb. -	 */ -	static std::string actionAsVerb(ERequestAction action);  	/**   	 * @brief Constructor.  	 * -	 * @param action One of the ERequestAction enumerations. +	 * @param action One of the EHTTPMethod enumerations.  	 */ -	LLURLRequest(ERequestAction action, bool follow_redirects = true); +	LLURLRequest(EHTTPMethod action, bool follow_redirects = true);  	/**   	 * @brief Constructor.  	 * -	 * @param action One of the ERequestAction enumerations. +	 * @param action One of the EHTTPMethod enumerations.  	 * @param url The url of the request. It should already be encoded.  	 */ -	LLURLRequest(ERequestAction action, const std::string& url, bool follow_redirects = true); +	LLURLRequest(EHTTPMethod action, const std::string& url, bool follow_redirects = true);  	/**   	 * @brief Destructor. @@ -123,17 +104,17 @@ public:  	 *   	 */  	void setURL(const std::string& url); -	std::string getURL() const; +	const std::string& getURL() const;  	/**   	 * @brief Add a header to the http post.  	 * -	 * The header must be correctly formatted for HTTP requests. This -	 * provides a raw interface if you know what kind of request you +	 * This provides a raw interface if you know what kind of request you  	 * will be making during construction of this instance. All  	 * required headers will be automatically constructed, so this is  	 * usually useful for encoding parameters.  	 */ -	void addHeader(const char* header); +	void addHeader(const std::string& header, const std::string& value = ""); +	void addHeaderRaw(const char* header);  	/**  	 * @brief Check remote server certificate signed by a known root CA. @@ -218,7 +199,7 @@ protected:  		STATE_HAVE_RESPONSE,  	};  	EState mState; -	ERequestAction mAction; +	EHTTPMethod mAction;  	bool mFollowRedirects;  	LLURLRequestDetail* mDetail;  	LLIOPipe::ptr_t mCompletionCallback; @@ -316,7 +297,7 @@ public:  	// May be called more than once, particularly for redirects and proxy madness.  	// Ex. a 200 for a connection to https through a proxy, followed by the "real" status  	//     a 3xx for a redirect followed by a "real" status, or more redirects. -	virtual void httpStatus(U32 status, const std::string& reason) { } +	virtual void httpStatus(S32 status, const std::string& reason) { }  	virtual void complete(  		const LLChannelDescriptors& channels, @@ -369,15 +350,8 @@ protected:  	//@}  	// value to note if we actually got the response. This value -	// depends on correct useage from the LLURLRequest instance. +	// depends on correct usage from the LLURLRequest instance.  	EStatus mRequestStatus;  }; - - -/** - * External constants - */ -extern const std::string CONTEXT_DEST_URI_SD_LABEL; -  #endif // LL_LLURLREQUEST_H diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 4e4dcc1d81..cc2d5d66ad 100755 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -110,20 +110,20 @@ namespace  		{  		} -		virtual void error(U32 status, const std::string& reason) +	protected: +		virtual void httpFailure()  		{  			// don't spam when agent communication disconnected already -			if (status != 410) +			if (HTTP_GONE != getStatus())  			{ -				LL_WARNS("Messaging") << "error status " << status -						<< " for message " << mMessageName -						<< " reason " << reason << LL_ENDL; +				LL_WARNS("Messaging") << "error for message " << mMessageName +									  << " " << dumpResponse() << LL_ENDL;  			}  			// TODO: Map status in to useful error code.  			if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_TCP_TIMEOUT);  		} -		virtual void result(const LLSD& content) +		virtual void httpSuccess()  		{  			if(NULL != mCallback) mCallback(mCallbackData, LL_ERR_NOERR);  		} @@ -149,7 +149,7 @@ class LLMessageHandlerBridge : public LLHTTPNode  void LLMessageHandlerBridge::post(LLHTTPNode::ResponsePtr response,   							const LLSD& context, const LLSD& input) const  { -	std::string name = context["request"]["wildcard"]["message-name"]; +	std::string name = context[CONTEXT_REQUEST][CONTEXT_WILDCARD]["message-name"];  	char* namePtr = LLMessageStringTable::getInstance()->getString(name.c_str());  	LL_DEBUGS() << "Setting mLastSender " << input["sender"].asString() << LL_ENDL; diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp index 9b298d0c04..b7fdf4f437 100755 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -24,55 +24,76 @@   * $/LicenseInfo$   */ +#ifndef LL_CURL_STUB_CPP +#define LL_CURL_STUB_CPP + +  #include "linden_common.h"  #include "llcurl.h" +#include "llhttpconstants.cpp"  LLCurl::Responder::Responder()  {  } -void LLCurl::Responder::completed(U32 status, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const &reason, -								  LLSD const& mContent) +void LLCurl::Responder::httpCompleted()  { -	if (isGoodStatus(status)) +	if (isGoodStatus())  	{ -		result(mContent); +		httpSuccess();  	}  	else  	{ -		errorWithContent(status, reason, mContent); +		httpFailure();  	}  } -void LLCurl::Responder::completedHeader(unsigned, -										std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, -										LLSD const&) +void LLCurl::Responder::completedRaw(LLChannelDescriptors const&, +									 boost::shared_ptr<LLBufferArray> const&)  {  } -void LLCurl::Responder::completedRaw(unsigned, -									 std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, -									 LLChannelDescriptors const&, -									 boost::shared_ptr<LLBufferArray> const&) +void LLCurl::Responder::httpFailure()  {  } -void LLCurl::Responder::errorWithContent(unsigned, -							  std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, -							  LLSD const&) +LLCurl::Responder::~Responder ()  {  } -LLCurl::Responder::~Responder () +void LLCurl::Responder::httpSuccess() +{ +} + +std::string LLCurl::Responder::dumpResponse() const +{ +	return "dumpResponse()"; +} + +void LLCurl::Responder::successResult(const LLSD& content)  { +	setResult(HTTP_OK, "", content); +	httpSuccess();  } -void LLCurl::Responder::error(unsigned, -							  std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) +void LLCurl::Responder::failureResult(S32 status, const std::string& reason, const LLSD& content) +{ +	setResult(status, reason, content); +	httpFailure(); +} + + +void LLCurl::Responder::completeResult(S32 status, const std::string& reason, const LLSD& content)  { +	setResult(status, reason, content); +	httpCompleted();  } -void LLCurl::Responder::result(LLSD const&) +void LLCurl::Responder::setResult(S32 status, const std::string& reason, const LLSD& content /* = LLSD() */)  { +	mStatus = status; +	mReason = reason; +	mContent = content;  } +#endif diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp index 559001d079..a32bfa59ce 100755 --- a/indra/llmessage/tests/llhttpclient_test.cpp +++ b/indra/llmessage/tests/llhttpclient_test.cpp @@ -40,8 +40,6 @@  #include "llproxy.h"  #include "llpumpio.h" -#include "llsdhttpserver.h" -#include "lliohttpserver.h"  #include "lliosocket.h"  #include "stringize.h" @@ -101,7 +99,7 @@ namespace tut  			if (mSawError)  			{  				std::string msg = -					llformat("error() called when not expected, status %d", +					llformat("httpFailure() called when not expected, status %d",  						mStatus);  				fail(msg);  			} @@ -111,7 +109,7 @@ namespace tut  		{  			if (!mSawError)  			{ -				fail("error() wasn't called"); +				fail("httpFailure() wasn't called");  			}  		} @@ -153,33 +151,26 @@ namespace tut  				mClient.mResultDeleted = true;  			} -			virtual void error(U32 status, const std::string& reason) +		protected: +			virtual void httpFailure()  			{  				mClient.mSawError = true; -				mClient.mStatus = status; -				mClient.mReason = reason; +				mClient.mStatus = getStatus(); +				mClient.mReason = getReason();  			} -			virtual void result(const LLSD& content) +			virtual void httpSuccess()  			{ -				mClient.mResult = content; +				mClient.mResult = getContent();  			} -			virtual void completed( -							U32 status, const std::string& reason, -							const LLSD& content) +			virtual void httpCompleted()  			{ -				LLHTTPClient::Responder::completed(status, reason, content); - +				LLHTTPClient::Responder::httpCompleted(); +				  				mClient.mSawCompleted = true; -			} - -			virtual void completedHeader( -				U32 status, const std::string& reason, -				const LLSD& content) -			{ -				mClient.mHeader = content;  				mClient.mSawCompletedHeader = true; +				mClient.mHeader = getResponseHeaders();  			}  		private: diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp index 13ce0a0edd..e9ce116bb3 100755 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp @@ -1,6 +1,6 @@  /**  - * @file  - * @brief  + * @file llhttpclientadapter_test.cpp + * @brief Tests for LLHTTPClientAdapter   *   * $LicenseInfo:firstyear=2008&license=viewerlgpl$   * Second Life Viewer Source Code @@ -33,8 +33,8 @@  float const HTTP_REQUEST_EXPIRY_SECS = 1.0F;  std::vector<std::string> get_urls; -std::vector<boost::intrusive_ptr<LLCurl::Responder> > get_responders; -void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout) +std::vector< LLCurl::ResponderPtr > get_responders; +void LLHTTPClient::get(const std::string& url, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout, bool follow_redirects)  {  	get_urls.push_back(url);  	get_responders.push_back(responder); @@ -42,16 +42,30 @@ void LLHTTPClient::get(const std::string& url, boost::intrusive_ptr<LLCurl::Resp  std::vector<std::string> put_urls;  std::vector<LLSD> put_body; -std::vector<boost::intrusive_ptr<LLCurl::Responder> > put_responders; +std::vector<LLSD> put_headers; +std::vector<LLCurl::ResponderPtr> put_responders; -void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout) +void LLHTTPClient::put(const std::string& url, const LLSD& body, LLCurl::ResponderPtr responder, const LLSD& headers, const F32 timeout)  {  	put_urls.push_back(url);  	put_responders.push_back(responder);  	put_body.push_back(body); +	put_headers.push_back(headers);  } +std::vector<std::string> delete_urls; +std::vector<LLCurl::ResponderPtr> delete_responders; + +void LLHTTPClient::del( +	const std::string& url, +	LLCurl::ResponderPtr responder, +	const LLSD& headers, +	const F32 timeout) +{ +	delete_urls.push_back(url); +	delete_responders.push_back(responder); +}  namespace tut  { @@ -64,6 +78,9 @@ namespace tut  			put_urls.clear();  			put_responders.clear();  			put_body.clear(); +			put_headers.clear(); +			delete_urls.clear(); +			delete_responders.clear();  		}  	}; @@ -73,7 +90,7 @@ namespace tut  namespace  { -	tut::factory tf("LLHTTPClientAdapterData test"); +	tut::factory tf("LLHTTPClientAdapterData");  }  namespace tut @@ -91,7 +108,7 @@ namespace tut  	{  		LLHTTPClientAdapter adapter; -		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder(); +		LLCurl::ResponderPtr responder = new LLCurl::Responder();  		adapter.get("Made up URL", responder);  		ensure_equals(get_urls.size(), 1); @@ -103,7 +120,7 @@ namespace tut  	void object::test<3>()  	{  		LLHTTPClientAdapter adapter; -		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder(); +		LLCurl::ResponderPtr responder = new LLCurl::Responder();  		adapter.get("Made up URL", responder); @@ -117,7 +134,7 @@ namespace tut  	{  		LLHTTPClientAdapter adapter; -		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder(); +		LLCurl::ResponderPtr responder = new LLCurl::Responder();  		LLSD body;  		body["TestBody"] = "Foobar"; @@ -133,7 +150,7 @@ namespace tut  	{  		LLHTTPClientAdapter adapter; -		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder(); +		LLCurl::ResponderPtr responder = new LLCurl::Responder();  		LLSD body;  		body["TestBody"] = "Foobar"; @@ -150,7 +167,7 @@ namespace tut  	{  		LLHTTPClientAdapter adapter; -		boost::intrusive_ptr<LLCurl::Responder> responder = new LLCurl::Responder(); +		LLCurl::ResponderPtr responder = new LLCurl::Responder();  		LLSD body;  		body["TestBody"] = "Foobar"; @@ -160,5 +177,45 @@ namespace tut  		ensure_equals(put_body.size(), 1);  		ensure_equals(put_body[0]["TestBody"].asString(), "Foobar");  	} + +	// Ensure that headers are passed through put properly +	template<> template<> +	void object::test<7>() +	{ +		LLHTTPClientAdapter adapter; + +		LLCurl::ResponderPtr responder = new LLCurl::Responder(); + +		LLSD body = LLSD::emptyMap(); +		body["TestBody"] = "Foobar"; + +		LLSD headers = LLSD::emptyMap(); +		headers["booger"] = "omg"; + +		adapter.put("Made up URL", body, responder, headers); + +		ensure_equals("Header count", put_headers.size(), 1); +		ensure_equals( +			"First header", +			put_headers[0]["booger"].asString(), +			"omg"); +	} + +	// Ensure that del() passes appropriate arguments to the LLHTTPClient +	template<> template<> +	void object::test<8>() +	{ +		LLHTTPClientAdapter adapter; + +		LLCurl::ResponderPtr responder = new LLCurl::Responder(); + +		adapter.del("Made up URL", responder); + +		ensure_equals("URL count", delete_urls.size(), 1); +		ensure_equals("Received URL", delete_urls[0], "Made up URL"); + +		ensure_equals("Responder count", delete_responders.size(), 1); +		//ensure_equals("Responder", delete_responders[0], responder); +	}  } diff --git a/indra/llmessage/tests/llhttpnode_stub.cpp b/indra/llmessage/tests/llhttpnode_stub.cpp new file mode 100755 index 0000000000..479a256bdd --- /dev/null +++ b/indra/llmessage/tests/llhttpnode_stub.cpp @@ -0,0 +1,107 @@ +/**  + * @file llhttpnode_stub.cpp + * @brief STUB Implementation of classes for generic HTTP/LSL/REST handling. + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + *  + * Second Life Viewer Source Code + * Copyright (c) 2006-2009, Linden Research, Inc. + *  + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + *  + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + *  + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + *  + * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llhttpnode.h" + +const std::string CONTEXT_VERB("verb"); +const std::string CONTEXT_REQUEST("request"); +const std::string CONTEXT_WILDCARD("wildcard"); +const std::string CONTEXT_PATH("path"); +const std::string CONTEXT_QUERY_STRING("query-string"); +const std::string CONTEXT_REMOTE_HOST("remote-host"); +const std::string CONTEXT_REMOTE_PORT("remote-port"); +const std::string CONTEXT_HEADERS("headers"); +const std::string CONTEXT_RESPONSE("response"); + +/** + * LLHTTPNode + */ +class LLHTTPNode::Impl +{ +    // dummy +}; + +LLHTTPNode::LLHTTPNode(): impl(*new Impl) {} +LLHTTPNode::~LLHTTPNode() {} +LLSD LLHTTPNode::simpleGet() const { return LLSD(); } +LLSD LLHTTPNode::simplePut(const LLSD& input) const { return LLSD(); } +LLSD LLHTTPNode::simplePost(const LLSD& input) const { return LLSD(); } +LLSD LLHTTPNode::simpleDel(const LLSD&) const { return LLSD(); } +void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const {} +void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {} +void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const {} +void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const {} +void  LLHTTPNode::options(ResponsePtr response, const LLSD& context) const {} +LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const { return NULL; } +bool LLHTTPNode::handles(const LLSD& remainder, LLSD& context) const { return false; } +bool LLHTTPNode::validate(const std::string& name, LLSD& context) const { return false; } +const LLHTTPNode* LLHTTPNode::traverse(const std::string& path, LLSD& context) const { return NULL; } +void LLHTTPNode::addNode(const std::string& path, LLHTTPNode* nodeToAdd) { } +LLSD LLHTTPNode::allNodePaths() const { return LLSD(); } +const LLHTTPNode* LLHTTPNode::rootNode() const { return NULL; } +const LLHTTPNode* LLHTTPNode::findNode(const std::string& name) const { return NULL; } + +LLHTTPNode::Response::~Response(){} +void LLHTTPNode::Response::notFound(const std::string& message) +{ +	status(404, message); +} +void LLHTTPNode::Response::notFound() +{ +	status(404, "Not Found"); +} +void LLHTTPNode::Response::methodNotAllowed() +{ +	status(405, "Method Not Allowed"); +} +void LLHTTPNode::Response::statusUnknownError(S32 code) +{ +	status(code, "Unknown Error"); +} + +void LLHTTPNode::Response::status(S32 code, const std::string& message) +{ +} + +void LLHTTPNode::Response::addHeader(const std::string& name,const std::string& value)  +{ +	mHeaders[name] = value; +} +void LLHTTPNode::describe(Description& desc) const { } + + +const LLChainIOFactory* LLHTTPNode::getProtocolHandler() const { return NULL; } + + +LLHTTPRegistrar::NodeFactory::~NodeFactory() { } + +void LLHTTPRegistrar::registerFactory( +    const std::string& path, NodeFactory& factory) {} +void LLHTTPRegistrar::buildAllServices(LLHTTPNode& root) {} + + diff --git a/indra/llmessage/tests/llmime_test.cpp b/indra/llmessage/tests/llmime_test.cpp deleted file mode 100755 index ea48561ae9..0000000000 --- a/indra/llmessage/tests/llmime_test.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/**  - * @file llmime_test.cpp - * @author Phoenix - * @date 2006-12-24 - * @brief BRIEF_DESC of llmime_test.cpp - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llsdserialize.h" - -#include "../llmime.h" - -#include "../test/lltut.h" - -namespace tut -{ -	struct mime_index -	{ -	}; -	typedef test_group<mime_index> mime_index_t; -	typedef mime_index_t::object mime_index_object_t; -	tut::mime_index_t tut_mime_index("LLMime"); - -	template<> template<> -	void mime_index_object_t::test<1>() -	{ -		LLMimeIndex mime; -		ensure("no headers", mime.headers().isUndefined()); -		ensure_equals("invalid offset", mime.offset(), -1); -		ensure_equals("invalid content length", mime.contentLength(), -1); -		ensure("no content type", mime.contentType().empty()); -		ensure("not multipart", !mime.isMultipart()); -		ensure_equals("no attachments", mime.subPartCount(), 0); -	} - -	template<> template<> -	void mime_index_object_t::test<2>() -	{ -		const S32 CONTENT_LENGTH = 6000; -		const S32 CONTENT_OFFSET = 100; -		const std::string CONTENT_TYPE = std::string("image/j2c"); -		LLSD headers; -		headers["Content-Length"] = CONTENT_LENGTH; -		headers["Content-Type"] = CONTENT_TYPE; -		LLMimeIndex mime(headers, CONTENT_OFFSET); -		ensure("headers are map", mime.headers().isMap()); -		ensure_equals("offset", mime.offset(), CONTENT_OFFSET); -		ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH); -		ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE); -		ensure("not multipart", !mime.isMultipart()); -		ensure_equals("no attachments", mime.subPartCount(), 0); -	} - -	template<> template<> -	void mime_index_object_t::test<3>() -	{ -		const S32 MULTI_CONTENT_LENGTH = 8000; -		const S32 MULTI_CONTENT_OFFSET = 100; -		const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed"); -		LLSD headers; -		headers["Content-Length"] = MULTI_CONTENT_LENGTH; -		headers["Content-Type"] = MULTI_CONTENT_TYPE; -		LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET); -		LL_INFOS() << "headers: " << LLSDOStreamer<LLSDNotationFormatter>(headers) -			<< LL_ENDL; - - -		const S32 META_CONTENT_LENGTH = 700; -		const S32 META_CONTENT_OFFSET = 69; -		const std::string META_CONTENT_TYPE = std::string( -			"text/llsd+xml"); -		headers = LLSD::emptyMap(); -		headers["Content-Length"] = META_CONTENT_LENGTH; -		headers["Content-Type"] = META_CONTENT_TYPE; -		LLMimeIndex meta(headers, META_CONTENT_OFFSET); -		mime.attachSubPart(meta); - -		const S32 IMAGE_CONTENT_LENGTH = 6000; -		const S32 IMAGE_CONTENT_OFFSET = 200; -		const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c"); -		headers = LLSD::emptyMap(); -		headers["Content-Length"] = IMAGE_CONTENT_LENGTH; -		headers["Content-Type"] = IMAGE_CONTENT_TYPE; -		LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET); -		mime.attachSubPart(image); - -		// make sure we have a valid multi-part -		ensure("is multipart", mime.isMultipart()); -		ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET); -		ensure_equals( -			"multi content length", -			mime.contentLength(), -			MULTI_CONTENT_LENGTH); -		ensure_equals("two attachments", mime.subPartCount(), 2); - -		// make sure ranged gets do the right thing with out of bounds -		// sub-parts. -		LLMimeIndex invalid_child(mime.subPart(-1)); -		ensure("no headers", invalid_child.headers().isUndefined()); -		ensure_equals("invalid offset", invalid_child.offset(), -1); -		ensure_equals( -			"invalid content length", invalid_child.contentLength(), -1); -		ensure("no content type", invalid_child.contentType().empty()); -		ensure("not multipart", !invalid_child.isMultipart()); -		ensure_equals("no attachments", invalid_child.subPartCount(), 0); - -		invalid_child = mime.subPart(2); -		ensure("no headers", invalid_child.headers().isUndefined()); -		ensure_equals("invalid offset", invalid_child.offset(), -1); -		ensure_equals( -			"invalid content length", invalid_child.contentLength(), -1); -		ensure("no content type", invalid_child.contentType().empty()); -		ensure("not multipart", !invalid_child.isMultipart()); -		ensure_equals("no attachments", invalid_child.subPartCount(), 0); -	} - -	template<> template<> -	void mime_index_object_t::test<4>() -	{ -		const S32 MULTI_CONTENT_LENGTH = 8000; -		const S32 MULTI_CONTENT_OFFSET = 100; -		const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed"); -		LLSD headers; -		headers["Content-Length"] = MULTI_CONTENT_LENGTH; -		headers["Content-Type"] = MULTI_CONTENT_TYPE; -		LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET); - -		const S32 META_CONTENT_LENGTH = 700; -		const S32 META_CONTENT_OFFSET = 69; -		const std::string META_CONTENT_TYPE = std::string( -			"application/llsd+xml"); -		headers = LLSD::emptyMap(); -		headers["Content-Length"] = META_CONTENT_LENGTH; -		headers["Content-Type"] = META_CONTENT_TYPE; -		LLMimeIndex meta(headers, META_CONTENT_OFFSET); -		mime.attachSubPart(meta); - -		const S32 IMAGE_CONTENT_LENGTH = 6000; -		const S32 IMAGE_CONTENT_OFFSET = 200; -		const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c"); -		headers = LLSD::emptyMap(); -		headers["Content-Length"] = IMAGE_CONTENT_LENGTH; -		headers["Content-Type"] = IMAGE_CONTENT_TYPE; -		LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET); -		mime.attachSubPart(image); - -		// check what we have -		ensure("is multipart", mime.isMultipart()); -		ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET); -		ensure_equals( -			"multi content length", -			mime.contentLength(), -			MULTI_CONTENT_LENGTH); -		ensure_equals("two attachments", mime.subPartCount(), 2); - -		LLMimeIndex actual_meta = mime.subPart(0); -		ensure_equals( -			"meta type", actual_meta.contentType(), META_CONTENT_TYPE); -		ensure_equals( -			"meta offset", actual_meta.offset(), META_CONTENT_OFFSET); -		ensure_equals( -			"meta content length", -			actual_meta.contentLength(), -			META_CONTENT_LENGTH); - -		LLMimeIndex actual_image = mime.subPart(1); -		ensure_equals( -			"image type", actual_image.contentType(), IMAGE_CONTENT_TYPE); -		ensure_equals( -			"image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET); -		ensure_equals( -			"image content length", -			actual_image.contentLength(), -			IMAGE_CONTENT_LENGTH); -	} - -/* -	template<> template<> -	void mime_index_object_t::test<5>() -	{ -	} -	template<> template<> -	void mime_index_object_t::test<6>() -	{ -	} -	template<> template<> -	void mime_index_object_t::test<7>() -	{ -	} -	template<> template<> -	void mime_index_object_t::test<8>() -	{ -	} -	template<> template<> -	void mime_index_object_t::test<>() -	{ -	} -*/ -} - - -namespace tut -{ -	struct mime_parse -	{ -	}; -	typedef test_group<mime_parse> mime_parse_t; -	typedef mime_parse_t::object mime_parse_object_t; -	tut::mime_parse_t tut_mime_parse("LLMimeParse"); - -	template<> template<> -	void mime_parse_object_t::test<1>() -	{ -		// parse one mime object -		const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n"); -		std::stringstream istr; -		istr.str(SERIALIZED_MIME); -		LLMimeIndex mime; -		LLMimeParser parser; -		bool ok = parser.parseIndex(istr, mime); -		ensure("Parse successful.", ok); -		ensure_equals("content type", mime.contentType(), "text/plain"); -		ensure_equals("content length", mime.contentLength(), 200); -		ensure_equals("offset", mime.offset(), 49); - 	} - -	template<> template<> -	void mime_parse_object_t::test<2>() -	{ -		// make sure we only parse one. -		const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n"); -		std::stringstream istr; -		istr.str(SERIALIZED_MIME); -		LLMimeIndex mime; -		LLMimeParser parser; -		bool ok = parser.parseIndex(istr, mime); -		ensure("Parse successful.", ok); -		ensure("not multipart.", !mime.isMultipart()); -		ensure_equals("content type", mime.contentType(), "text/plain"); -		ensure_equals("content length", mime.contentLength(), 200); -		ensure_equals("offset", mime.offset(), 49); -	} - -	template<> template<> -	void mime_parse_object_t::test<3>() -	{ -		// test multi-part and lack of content length for some of it. -		/* -Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn -		 */ -		const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n"); -		std::stringstream istr; -		istr.str(SERIALIZED_MIME); -		LLMimeIndex mime; -		LLMimeParser parser; -		bool ok = parser.parseIndex(istr, mime); -		ensure("Parse successful.", ok); -		ensure("is multipart.", mime.isMultipart()); -		ensure_equals("sub-part count", mime.subPartCount(), 2); -		ensure_equals("content length", mime.contentLength(), 150); -		ensure_equals("data offset for multipart", mime.offset(), 74); - -		LLMimeIndex mime_plain(mime.subPart(0)); -		ensure_equals( -			"first part type", -			mime_plain.contentType(), -			"text/plain"); -		ensure_equals( -			"first part content length not known.", -			mime_plain.contentLength(), -			-1); -		ensure_equals("first part offset", mime_plain.offset(), 113); - -		LLMimeIndex mime_xml(mime.subPart(1)); -		ensure_equals( -			"second part type", -			mime_xml.contentType(), -			"text/xml; charset=UTF-8"); -		ensure_equals( -			"second part content length", -			mime_xml.contentLength(), -			22); -		ensure_equals("second part offset", mime_xml.offset(), 198); -	} - -	template<> template<> -	void mime_parse_object_t::test<4>() -	{ -		// test multi-part, unquoted separator, and premature eof conditions -		/* -Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn		 */ -		const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n"); -		std::stringstream istr; -		istr.str(SERIALIZED_MIME); -		LLMimeIndex mime; -		LLMimeParser parser; -		bool ok = parser.parseIndex(istr, mime); -		ensure("Parse successful.", ok); -		ensure("is multipart.", mime.isMultipart()); -		ensure_equals("sub-part count", mime.subPartCount(), 2); -		ensure_equals("content length", mime.contentLength(), 220); -		ensure_equals("data offset for multipart", mime.offset(), 72); - -		LLMimeIndex mime_plain(mime.subPart(0)); -		ensure_equals( -			"first part type", -			mime_plain.contentType(), -			"text/plain"); -		ensure_equals( -			"first part content length", -			mime_plain.contentLength(), -			55); -		ensure_equals("first part offset", mime_plain.offset(), 131); - -		LLMimeIndex mime_xml(mime.subPart(1)); -		ensure_equals( -			"second part type", -			mime_xml.contentType(), -			"text/xml; charset=UTF-8"); -		ensure_equals( -			"second part content length", -			mime_xml.contentLength(), -			22); -		ensure_equals("second part offset", mime_xml.offset(), 262); -	} - -	template<> template<> -	void mime_parse_object_t::test<5>() -	{ -		// test multi-part with multiple params -		const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n"); -		std::stringstream istr; -		istr.str(SERIALIZED_MIME); -		LLMimeIndex mime; -		LLMimeParser parser; -		bool ok = parser.parseIndex(istr, mime); -		ensure("Parse successful.", ok); -		ensure("is multipart.", mime.isMultipart()); -		ensure_equals("sub-part count", mime.subPartCount(), 2); -		ensure_equals("content length", mime.contentLength(), 220); - -		LLMimeIndex mime_plain(mime.subPart(0)); -		ensure_equals( -			"first part type", -			mime_plain.contentType(), -			"text/plain"); -		ensure_equals( -			"first part content length", -			mime_plain.contentLength(), -			55); - -		LLMimeIndex mime_xml(mime.subPart(1)); -		ensure_equals( -			"second part type", -			mime_xml.contentType(), -			"text/xml; charset=UTF-8"); -		ensure_equals( -			"second part content length", -			mime_xml.contentLength(), -			22); -	} - -	template<> template<> -	void mime_parse_object_t::test<6>() -	{ -		// test multi-part with no specified boundary and eof -/* -Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn -*/ -		const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n"); -		std::stringstream istr; -		istr.str(SERIALIZED_MIME); -		LLMimeIndex mime; -		LLMimeParser parser; -		bool ok = parser.parseIndex(istr, mime); -		ensure("Parse successful.", ok); -		ensure("is multipart.", mime.isMultipart()); -		ensure_equals("sub-part count", mime.subPartCount(), 2); -		ensure_equals("content length", mime.contentLength(), 500); -		ensure_equals("data offset for multipart", mime.offset(), 56); - -		LLMimeIndex mime_plain(mime.subPart(0)); -		ensure_equals( -			"first part type", -			mime_plain.contentType(), -			"text/plain"); -		ensure_equals( -			"first part content length", -			mime_plain.contentLength(), -			55); -		ensure_equals("first part offset", mime_plain.offset(), 108); - -		LLMimeIndex mime_xml(mime.subPart(1)); -		ensure_equals( -			"second part type", -			mime_xml.contentType(), -			"text/xml; charset=UTF-8"); -		ensure_equals( -			"second part content length", -			mime_xml.contentLength(), -			22); -		ensure_equals("second part offset", mime_xml.offset(), 232); -	} - -/* -	template<> template<> -	void mime_parse_object_t::test<>() -	{ -	} -	template<> template<> -	void mime_parse_object_t::test<>() -	{ -	} -	template<> template<> -	void mime_parse_object_t::test<>() -	{ -	} -	template<> template<> -	void mime_parse_object_t::test<>() -	{ -	} -*/ -} diff --git a/indra/llmessage/tests/llregionpresenceverifier_test.cpp b/indra/llmessage/tests/llregionpresenceverifier_test.cpp deleted file mode 100755 index 5b89f2a8c6..0000000000 --- a/indra/llmessage/tests/llregionpresenceverifier_test.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/**  - * @file  - * @brief  - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "../test/lltut.h" -#include "llregionpresenceverifier.h" -#include "llcurl_stub.cpp" -#include "llhost.cpp" -#include "net.cpp" -#include "lltesthttpclientadapter.cpp" - -class LLTestResponse : public LLRegionPresenceVerifier::Response -{ -public: - -	virtual bool checkValidity(const LLSD& content) const -	{ -		return true; -	} - -	virtual void onRegionVerified(const LLSD& region_details) -	{ -	} - -	virtual void onRegionVerificationFailed() -	{ -	} -	 -	virtual LLHTTPClientInterface& getHttpClient() -	{ -		return mHttpInterface; -	} - -	LLTestHTTPClientAdapter mHttpInterface; -}; - -namespace tut -{ -	struct LLRegionPresenceVerifierData -	{ -		LLRegionPresenceVerifierData() : -			mResponse(new LLTestResponse()), -			mResponder("", LLRegionPresenceVerifier::ResponsePtr(mResponse), -					   LLSD(), 3) -		{ -		} -		 -		LLTestResponse* mResponse; -		LLRegionPresenceVerifier::VerifiedDestinationResponder mResponder; -	}; - -	typedef test_group<LLRegionPresenceVerifierData> factory; -	typedef factory::object object; -} - -namespace -{ -	tut::factory tf("LLRegionPresenceVerifier"); -} - -namespace tut -{ -	// Test that VerifiedDestinationResponder does retry -    // on error when shouldRetry returns true. -	template<> template<> -	void object::test<1>() -	{ -		mResponder.error(500, "Internal server error"); -		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 1); -	} - -	// Test that VerifiedDestinationResponder only retries -	// on error until shouldRetry returns false. -	template<> template<> -	void object::test<2>() -	{ -		mResponder.error(500, "Internal server error"); -		mResponder.error(500, "Internal server error"); -		mResponder.error(500, "Internal server error"); -		mResponder.error(500, "Internal server error"); -		ensure_equals(mResponse->mHttpInterface.mGetUrl.size(), 3); -	} -} - diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp index b287a29841..55748ad27e 100755 --- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp +++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -32,6 +32,7 @@  #include "message.h"  #include "llmessageconfig.h" +#include "llhttpnode_stub.cpp"  LLMessageSystem* gMessageSystem = NULL; diff --git a/indra/llplugin/llplugincookiestore.cpp b/indra/llplugin/llplugincookiestore.cpp index f64b264222..a5d717389d 100755 --- a/indra/llplugin/llplugincookiestore.cpp +++ b/indra/llplugin/llplugincookiestore.cpp @@ -27,6 +27,7 @@   */  #include "linden_common.h" +#include "llstl.h"  #include "indra_constants.h"  #include "llplugincookiestore.h" @@ -654,12 +655,8 @@ void LLPluginCookieStore::setOneCookie(const std::string &s, std::string::size_t  void LLPluginCookieStore::clearCookies()  { -	while(!mCookies.empty()) -	{ -		cookie_map_t::iterator iter = mCookies.begin(); -		delete iter->second; -		mCookies.erase(iter); -	} +	std::for_each(mCookies.begin(), mCookies.end(), DeletePairedPointer()); +	mCookies.clear();  }  void LLPluginCookieStore::removeCookie(const std::string &key) diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index ea0d2b81f1..b5a2588e1e 100755 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -131,6 +131,8 @@ LLPluginProcessParent::~LLPluginProcessParent()  	{  		// destroy the shared memory region  		iter->second->destroy(); +		delete iter->second; +		iter->second = NULL;  		// and remove it from our map  		mSharedMemoryRegions.erase(iter); @@ -960,6 +962,8 @@ void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)  			{  				// destroy the shared memory region  				iter->second->destroy(); +				delete iter->second; +				iter->second = NULL;  				// and remove it from our map  				mSharedMemoryRegions.erase(iter); diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 44e6b97b31..e24d3bb5ba 100755 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -610,6 +610,7 @@ bool LLGLManager::initGL()  	if (mGLVendor.substr(0,4) == "ATI ")  	{  		mGLVendorShort = "ATI"; +		// *TODO: Fix this?  		mIsATI = TRUE;  #if LL_WINDOWS && !LL_MESA_HEADLESS diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index ddf38c6745..ebed454271 100755 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -390,9 +390,7 @@ LLImageGL::~LLImageGL()  {  	LLImageGL::cleanup();  	sImageList.erase(this); -	disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); -	delete [] mPickMask; -	mPickMask = NULL; +	freePickMask();  	sCount--;  } @@ -461,6 +459,8 @@ void LLImageGL::cleanup()  	{  		destroyGLTexture();  	} +	freePickMask(); +  	mSaveData = NULL; // deletes data  } @@ -504,10 +504,7 @@ void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve  		}  		// pickmask validity depends on old image size, delete it -		disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); -		delete [] mPickMask; -		mPickMask = NULL; -		mPickMaskWidth = mPickMaskHeight = 0; +		freePickMask();  		mWidth = width;  		mHeight = height; @@ -1886,6 +1883,37 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)  }  //---------------------------------------------------------------------------- +U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) +{ +	U32 pick_width = pWidth/2 + 1; +	U32 pick_height = pHeight/2 + 1; + +	U32 size = pick_width * pick_height; +	size = (size + 7) / 8; // pixelcount-to-bits +	mPickMask = new U8[size]; +	claimMem(size); +	mPickMaskWidth = pick_width - 1; +	mPickMaskHeight = pick_height - 1; + +	memset(mPickMask, 0, sizeof(U8) * size); + +	return size; +} + +//---------------------------------------------------------------------------- +void LLImageGL::freePickMask() +{ +	// pickmask validity depends on old image size, delete it +	if (mPickMask != NULL) +	{ +		disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); +		delete [] mPickMask; +	} +	mPickMask = NULL; +	mPickMaskWidth = mPickMaskHeight = 0; +} + +//----------------------------------------------------------------------------  void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)  {  	if(!mNeedsAlphaAndPickMask) @@ -1893,10 +1921,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)  		return ;  	} -	disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); -	delete [] mPickMask; -	mPickMask = NULL; -	mPickMaskWidth = mPickMaskHeight = 0; +	freePickMask();  	if (mFormatType != GL_UNSIGNED_BYTE ||  	    mFormatPrimary != GL_RGBA) @@ -1905,17 +1930,11 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)  		return;  	} -	U32 pick_width = width/2 + 1; -	U32 pick_height = height/2 + 1; - -	U32 size = pick_width * pick_height; -	size = (size + 7) / 8; // pixelcount-to-bits -	mPickMask = new U8[size]; -	claimMem(size); -	mPickMaskWidth = pick_width - 1; -	mPickMaskHeight = pick_height - 1; - -	memset(mPickMask, 0, sizeof(U8) * size); +#ifdef SHOW_ASSERT +	const U32 pickSize = createPickMask(width, height); +#else // SHOW_ASSERT +	createPickMask(width, height); +#endif // SHOW_ASSERT  	U32 pick_bit = 0; @@ -1929,7 +1948,7 @@ void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in)  			{  				U32 pick_idx = pick_bit/8;  				U32 pick_offset = pick_bit%8; -				llassert(pick_idx < size); +				llassert(pick_idx < pickSize);  				mPickMask[pick_idx] |= 1 << pick_offset;  			} diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 6ca814af6f..21982eab1d 100755 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -186,6 +186,9 @@ public:  	mutable F32  mLastBindTime;	// last time this was bound, by discard level  private: +	U32 createPickMask(S32 pWidth, S32 pHeight); +	void freePickMask(); +  	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL  	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel  	U16 mPickMaskWidth; diff --git a/indra/llui/llbadgeowner.cpp b/indra/llui/llbadgeowner.cpp index 1860a05edd..55e64bb940 100755 --- a/indra/llui/llbadgeowner.cpp +++ b/indra/llui/llbadgeowner.cpp @@ -35,8 +35,9 @@  //  LLBadgeOwner::LLBadgeOwner(LLHandle< LLView > viewHandle) -	: mBadge(NULL) -	, mBadgeOwnerView(viewHandle) +	: mHasBadgeHolderParent(false), +	mBadge(NULL), +	mBadgeOwnerView(viewHandle)  {  } @@ -45,31 +46,12 @@ void LLBadgeOwner::initBadgeParams(const LLBadge::Params& p)  	if (!p.equals(LLUICtrlFactory::getDefaultParams<LLBadge>()))  	{  		mBadge = createBadge(p); -	} -} - -void LLBadgeOwner::setBadgeLabel(const LLStringExplicit& label) -{ -	if (mBadge == NULL) -	{ -		mBadge = createBadge(LLUICtrlFactory::getDefaultParams<LLBadge>()); - -		addBadgeToParentPanel(); -	} - -	if (mBadge) -	{ -		mBadge->setLabel(label); - -		// -		// Push the badge to the front so it renders on top -		// - -		LLView * parent = mBadge->getParent(); +		mHasBadgeHolderParent = false; -		if (parent) +		LLView * owner_view = mBadgeOwnerView.get(); +		if (owner_view)  		{ -			parent->sendChildToFront(mBadge); +			mBadge->addToView(owner_view);  		}  	}  } @@ -82,10 +64,8 @@ void LLBadgeOwner::setBadgeVisibility(bool visible)  	}  } -bool LLBadgeOwner::addBadgeToParentPanel() +void LLBadgeOwner::addBadgeToParentHolder()  { -	bool badge_added = false; -  	LLView * owner_view = mBadgeOwnerView.get();  	if (mBadge && owner_view) @@ -110,16 +90,9 @@ bool LLBadgeOwner::addBadgeToParentPanel()  		if (badge_holder)  		{ -			badge_added = badge_holder->addBadge(mBadge); -		} -		else -		{ -			// Badge parent is fallback badge owner if no valid holder exists in the hierarchy -			badge_added = mBadge->addToView(owner_view); +			mHasBadgeHolderParent = badge_holder->addBadge(mBadge);  		}  	} - -	return badge_added;  }  LLBadge* LLBadgeOwner::createBadge(const LLBadge::Params& p) diff --git a/indra/llui/llbadgeowner.h b/indra/llui/llbadgeowner.h index 8d03e30645..53c2de95c8 100755 --- a/indra/llui/llbadgeowner.h +++ b/indra/llui/llbadgeowner.h @@ -41,11 +41,9 @@ public:  	LLBadgeOwner(LLHandle< LLView > viewHandle);  	void initBadgeParams(const LLBadge::Params& p); -	bool addBadgeToParentPanel(); +	void addBadgeToParentHolder(); -	bool badgeHasParent() const { return (mBadge && mBadge->getParent()); } - -	void setBadgeLabel(const LLStringExplicit& label); +	bool hasBadgeHolderParent() const { return mHasBadgeHolderParent; };  	void setBadgeVisibility(bool visible);  private: @@ -53,7 +51,7 @@ private:  	LLBadge* createBadge(const LLBadge::Params& p);  private: - +	bool				mHasBadgeHolderParent;  	LLBadge*			mBadge;  	LLHandle< LLView >	mBadgeOwnerView;  }; diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 093d91d44d..ce8383857c 100755 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -384,7 +384,7 @@ BOOL LLButton::postBuild()  {  	autoResize(); -	addBadgeToParentPanel(); +	addBadgeToParentHolder();  	return LLUICtrl::postBuild();  } diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 62c923f6f0..3dbc9a5902 100755 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -1634,7 +1634,7 @@ void LLFloater::bringToFront( S32 x, S32 y )  // virtual -void LLFloater::setVisibleAndFrontmost(BOOL take_focus, const LLSD& key) +void LLFloater::setVisibleAndFrontmost(BOOL take_focus,const LLSD& key)  {  	LLMultiFloater* hostp = getHost();  	if (hostp) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 199db85747..ef7c6180d2 100755 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -311,7 +311,7 @@ public:  	/*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override  	void			setFrontmost(BOOL take_focus = TRUE); -    virtual void	setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());     +     virtual void	setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());  	// Defaults to false.  	virtual BOOL	canSaveAs() const { return FALSE; } diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index b92e298348..bc2388dd28 100755 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -227,10 +227,11 @@ LLFolderView::LLFolderView(const Params& p)  	mStatusTextBox = LLUICtrlFactory::create<LLTextBox> (text_p);  	mStatusTextBox->setFollowsLeft();  	mStatusTextBox->setFollowsTop(); -	//addChild(mStatusTextBox); +	addChild(mStatusTextBox);  	// make the popup menu available +	llassert(LLMenuGL::sMenuContainer != NULL);  	LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>(p.options_menu, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());  	if (!menu)  	{ @@ -703,8 +704,9 @@ void LLFolderView::finishRenamingItem( void )  	closeRenamer(); +	// This is moved to an inventory observer in llinventorybridge.cpp, to handle updating after operation completed in AISv3 (SH-4611).  	// List is re-sorted alphabetically, so scroll to make sure the selected item is visible. -	scrollToShowSelection(); +	//scrollToShowSelection();  }  void LLFolderView::closeRenamer( void ) diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index d410a2de33..b09c927782 100755 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -192,6 +192,7 @@ LLLineEditor::LLLineEditor(const LLLineEditor::Params& p)  	setPrevalidateInput(p.prevalidate_input_callback());  	setPrevalidate(p.prevalidate_callback()); +	llassert(LLMenuGL::sMenuContainer != NULL);  	LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>  		("menu_text_editor.xml",  		 LLMenuGL::sMenuContainer, diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 0609cd8b42..303afcda15 100755 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -93,6 +93,7 @@ void LLMenuButton::setMenu(const std::string& menu_filename, EMenuPosition posit  		return;  	} +	llassert(LLMenuGL::sMenuContainer != NULL);  	LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(menu_filename, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());  	if (!menu)  	{ diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp index 7383a8c307..604dc92789 100755 --- a/indra/llui/llmenugl.cpp +++ b/indra/llui/llmenugl.cpp @@ -63,6 +63,7 @@  // static  LLMenuHolderGL *LLMenuGL::sMenuContainer = NULL; +view_listener_t::listener_map_t view_listener_t::sListeners;  S32 MENU_BAR_HEIGHT = 0;  S32 MENU_BAR_WIDTH = 0; diff --git a/indra/llui/llmenugl.h b/indra/llui/llmenugl.h index feafaab199..ae9b169691 100755 --- a/indra/llui/llmenugl.h +++ b/indra/llui/llmenugl.h @@ -895,7 +895,8 @@ class view_listener_t : public boost::signals2::trackable  {  public:  	virtual bool handleEvent(const LLSD& userdata) = 0; -	virtual ~view_listener_t() {} +	view_listener_t() { sListeners.insert(this); } +	virtual ~view_listener_t() { sListeners.erase(this); }  	static void addEnable(view_listener_t* listener, const std::string& name)  	{ @@ -913,6 +914,20 @@ public:  		addEnable(listener, name);  		addCommit(listener, name);  	} + +	static void cleanup() +	{ +		listener_vector_t listeners(sListeners.begin(), sListeners.end()); +		sListeners.clear(); + +		std::for_each(listeners.begin(), listeners.end(), DeletePointer()); +		listeners.clear(); +	} + +private: +	typedef std::set<view_listener_t*> listener_map_t; +	typedef std::vector<view_listener_t*> listener_vector_t; +	static listener_map_t sListeners;  };  #endif // LL_LLMENUGL_H diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index 3708071e11..5f72ee3ac6 100755 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -1815,6 +1815,7 @@ BOOL LLScrollListCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask)  			// create the context menu from the XUI file and display it  			std::string menu_name = is_group ? "menu_url_group.xml" : "menu_url_agent.xml";  			delete mPopupMenu; +			llassert(LLMenuGL::sMenuContainer != NULL);  			mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(  				menu_name, LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());  			if (mPopupMenu) diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index ebc6183b8b..6f858cdeb3 100755 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -1140,6 +1140,17 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  			addChild( btn, 0 );  		}  	} +	else +	{ +		if (textbox) +		{ +			LLUICtrl::addChild(textbox, 0); +		} +		if (btn) +		{ +			LLUICtrl::addChild(btn, 0); +		} +	}  	if (child)  	{ @@ -1636,16 +1647,26 @@ void LLTabContainer::setTabImage(LLPanel* child, LLIconCtrl* icon)  {  	LLTabTuple* tuple = getTabByPanel(child);  	LLCustomButtonIconCtrl* button; +	bool hasButton = false;  	if(tuple)  	{  		button = dynamic_cast<LLCustomButtonIconCtrl*>(tuple->mButton);  		if(button)  		{ +			hasButton = true;  			button->setIcon(icon);  			reshapeTuple(tuple);  		}  	} + +	if (!hasButton && (icon != NULL)) +	{ +		// It was assumed that the tab's button would take ownership of the icon pointer. +		// But since the tab did not have a button, kill the icon to prevent the memory +		// leak. +		icon->die(); +	}  }  void LLTabContainer::reshapeTuple(LLTabTuple* tuple) diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 62edbadb07..8906a6e736 100755 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1955,6 +1955,7 @@ void LLTextBase::createUrlContextMenu(S32 x, S32 y, const std::string &in_url)  	// create and return the context menu from the XUI file  	delete mPopupMenu; +	llassert(LLMenuGL::sMenuContainer != NULL);  	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(xui_file, LLMenuGL::sMenuContainer,  																		 LLMenuHolderGL::child_registry_t::instance());	  	if (mIsFriendSignal) @@ -2037,7 +2038,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  		LLUrlMatch match;  		std::string text = new_text;  		while ( LLUrlRegistry::instance().findUrl(text, match, -				boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3)) ) +				boost::bind(&LLTextBase::replaceUrl, this, _1, _2, _3),isContentTrusted()))  		{  			start = match.getStart();  			end = match.getEnd()+1; @@ -2074,7 +2075,7 @@ void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Para  					}  			} -			LLTextUtil::processUrlMatch(&match,this); +			LLTextUtil::processUrlMatch(&match,this,isContentTrusted());  			// move on to the rest of the text after the Url  			if (end < (S32)text.length())  diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index d1f66b6cfe..ecbfdaf84c 100755 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -367,7 +367,9 @@ public:  	bool					getWordWrap() { return mWordWrap; }  	bool					getUseEllipses() { return mUseEllipses; }  	bool					truncate(); // returns true of truncation occurred +  	bool					isContentTrusted() {return mTrustedContent;} +	void					setContentTrusted(bool trusted_content) { mTrustedContent = trusted_content; }  	// TODO: move into LLTextSegment?  	void					createUrlContextMenu(S32 x, S32 y, const std::string &url); // create a popup context menu for the given Url diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index c797b6acc5..b4ebed0849 100755 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2031,6 +2031,7 @@ void LLTextEditor::showContextMenu(S32 x, S32 y)  {  	if (!mContextMenu)  	{ +		llassert(LLMenuGL::sMenuContainer != NULL);  		mContextMenu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_text_editor.xml",   																				LLMenuGL::sMenuContainer,   																				LLMenuHolderGL::child_registry_t::instance()); diff --git a/indra/llui/lltextutil.cpp b/indra/llui/lltextutil.cpp index 4df2c3363f..fff04b34f2 100755 --- a/indra/llui/lltextutil.cpp +++ b/indra/llui/lltextutil.cpp @@ -72,7 +72,7 @@ const std::string& LLTextUtil::formatPhoneNumber(const std::string& phone_str)  	return formatted_phone_str;  } -bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base) +bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted)  {  	if (match == 0 || text_base == 0)  		return false; @@ -85,7 +85,7 @@ bool LLTextUtil::processUrlMatch(LLUrlMatch* match,LLTextBase* text_base)  	}  	// output an optional icon before the Url -	if (!match->getIcon().empty() ) +	if (is_content_trusted && !match->getIcon().empty() )  	{  		LLUIImagePtr image = LLUI::getUIImage(match->getIcon());  		if (image) diff --git a/indra/llui/lltextutil.h b/indra/llui/lltextutil.h index bf7dbb58ce..798f14d086 100755 --- a/indra/llui/lltextutil.h +++ b/indra/llui/lltextutil.h @@ -64,7 +64,7 @@ namespace LLTextUtil  	 */  	const std::string& formatPhoneNumber(const std::string& phone_str); -	bool processUrlMatch(LLUrlMatch* match,LLTextBase* text_base); +	bool processUrlMatch(LLUrlMatch* match,LLTextBase* text_base, bool is_content_trusted);  	class TextHelpers  	{ diff --git a/indra/llui/lltoolbar.cpp b/indra/llui/lltoolbar.cpp index f9bdd87087..abc2b6e9ca 100755 --- a/indra/llui/lltoolbar.cpp +++ b/indra/llui/lltoolbar.cpp @@ -148,6 +148,7 @@ void LLToolBar::createContextMenu()  		enable_reg.add("Toolbars.CheckSetting", boost::bind(&LLToolBar::isSettingChecked, this, _2));  		// Create the context menu +		llassert(LLMenuGL::sMenuContainer != NULL);  		LLContextMenu* menu = LLUICtrlFactory::instance().createFromFile<LLContextMenu>("menu_toolbars.xml", LLMenuGL::sMenuContainer, LLMenuHolderGL::child_registry_t::instance());  		if (menu) diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 523ee5d78c..bccc646821 100755 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -41,7 +41,8 @@ LLUrlRegistry::LLUrlRegistry()  	// Urls are matched in the order that they were registered  	registerUrl(new LLUrlEntryNoLink()); -	registerUrl(new LLUrlEntryIcon()); +	mUrlEntryIcon = new LLUrlEntryIcon(); +	registerUrl(mUrlEntryIcon);  	registerUrl(new LLUrlEntrySLURL());  	registerUrl(new LLUrlEntryHTTP());  	registerUrl(new LLUrlEntryHTTPLabel()); @@ -145,7 +146,7 @@ static bool stringHasUrl(const std::string &text)  			text.find("<icon") != std::string::npos);  } -bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb) +bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LLUrlLabelCallback &cb, bool is_content_trusted)  {  	// avoid costly regexes if there is clearly no URL in the text  	if (! stringHasUrl(text)) @@ -160,6 +161,12 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL  	std::vector<LLUrlEntryBase *>::iterator it;  	for (it = mUrlEntry.begin(); it != mUrlEntry.end(); ++it)  	{ +		//Skip for url entry icon if content is not trusted +		if(!is_content_trusted && (mUrlEntryIcon == *it)) +		{ +			continue; +		} +  		LLUrlEntryBase *url_entry = *it;  		U32 start = 0, end = 0; diff --git a/indra/llui/llurlregistry.h b/indra/llui/llurlregistry.h index da16171a97..6270df1bbb 100755 --- a/indra/llui/llurlregistry.h +++ b/indra/llui/llurlregistry.h @@ -73,7 +73,8 @@ public:  	/// get the next Url in an input string, starting at a given character offset  	/// your callback is invoked if the matched Url's label changes in the future  	bool findUrl(const std::string &text, LLUrlMatch &match, -				 const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback); +				 const LLUrlLabelCallback &cb = &LLUrlRegistryNullCallback, +				 bool is_content_trusted = false);  	/// a slightly less efficient version of findUrl for wide strings  	bool findUrl(const LLWString &text, LLUrlMatch &match, @@ -92,6 +93,7 @@ private:  	friend class LLSingleton<LLUrlRegistry>;  	std::vector<LLUrlEntryBase *> mUrlEntry; +	LLUrlEntryBase*	mUrlEntryIcon;  };  #endif diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 0637572f67..19961d5759 100755 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -657,7 +657,7 @@ LLWindowWin32::~LLWindowWin32()  	delete [] mSupportedResolutions;  	mSupportedResolutions = NULL; -	delete mWindowClassName; +	delete [] mWindowClassName;  	mWindowClassName = NULL;  } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c94969435b..812850f6ff 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 @@ -109,7 +110,6 @@ set(viewer_SOURCE_FILES      llagentpilot.cpp      llagentui.cpp      llagentwearables.cpp -    llagentwearablesfetch.cpp      llanimstatelabels.cpp      llappcorehttp.cpp      llappearancemgr.cpp @@ -313,6 +313,7 @@ set(viewer_SOURCE_FILES      llhasheduniqueid.cpp      llhints.cpp      llhomelocationresponder.cpp +    llhttpretrypolicy.cpp      llhudeffect.cpp      llhudeffectbeam.cpp      llhudeffectlookat.cpp @@ -689,6 +690,7 @@ set(viewer_HEADER_FILES      groupchatlistener.h      llaccountingcost.h      llaccountingcostmanager.h +    llaisapi.h      llagent.h      llagentaccess.h      llagentcamera.h @@ -699,7 +701,6 @@ set(viewer_HEADER_FILES      llagentpilot.h      llagentui.h      llagentwearables.h -    llagentwearablesfetch.h      llanimstatelabels.h      llappcorehttp.h      llappearance.h @@ -905,6 +906,7 @@ set(viewer_HEADER_FILES      llgroupmgr.h      llhasheduniqueid.h      llhints.h +    llhttpretrypolicy.h      llhomelocationresponder.h      llhudeffect.h      llhudeffectbeam.h @@ -2166,10 +2168,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( @@ -2250,6 +2263,7 @@ if (LL_TESTS)    set(test_libs      ${LLMESSAGE_LIBRARIES} +    ${LLCOREHTTP_LIBRARIES}      ${WINDOWS_LIBRARIES}      ${LLVFS_LIBRARIES}      ${LLMATH_LIBRARIES} @@ -2290,6 +2304,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/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index c77a7de85c..f06fb9e915 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -3.7.9 +3.7.10 diff --git a/indra/newview/app_settings/logcontrol.xml b/indra/newview/app_settings/logcontrol.xml index 7da047aed5..15cb5bc0eb 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>SceneLoadTiming</string>  						     <string>Avatar</string>  						     <string>Voice</string>		 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b0b683aef9..8d3a7327b9 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11748,6 +11748,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 6de5b18c3c..9ec6428ee6 100755 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -4480,7 +4480,7 @@       group="1"       sex="female"       name="Breast_Physics_UpDown_Driven" -     wearable="shape" +     wearable="physics"       edit_group="driven"       value_default="0"       value_min="-3" @@ -4502,7 +4502,7 @@       group="1"       sex="female"       name="Breast_Physics_InOut_Driven" -     wearable="shape" +     wearable="physics"       edit_group="driven"       value_default="0"       value_min="-1.25" @@ -4524,7 +4524,6 @@       group="1"       name="Belly_Physics_Torso_UpDown_Driven"       wearable="physics" -     cross_wearable="true"       edit_group="driven"       value_default="0"       value_min="-1" @@ -4542,7 +4541,6 @@       group="1"       name="Breast_Physics_LeftRight_Driven"       wearable="physics" -     cross_wearable="true"       edit_group="driven"       value_default="0"       value_min="-2" @@ -7716,7 +7714,7 @@ render_pass="bump">        <param         id="868" -       group="0" +       group="3"         wearable="shirt"         edit_group="shirt"         edit_group_order="8" @@ -8839,7 +8837,7 @@ render_pass="bump">        <param         id="869" -       group="0" +       group="3"         wearable="pants"         edit_group="pants"         edit_group_order="6" @@ -9760,7 +9758,7 @@ render_pass="bump">      <param       id="163" -     group="0" +     group="3"       wearable="skin"       edit_group="skin_facedetail"       edit_group_order="3" @@ -11819,7 +11817,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 150b97baa5..a42286a9e4 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()  	{ -		LL_WARNS() << "Transport error [status:" << statusNum << "]: " << content <<LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		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") )  		{ -			LL_WARNS()	<< "Error on fetched data"<< LL_ENDL; +			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 eb9ca542a3..aa8e0bad76 100755 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -406,7 +406,7 @@ LLAgent::LLAgent() :  	mNextFidgetTime(0.f),  	mCurrentFidget(0),  	mFirstLogin(FALSE), -	mGenderChosen(FALSE), +	mOutfitChosen(FALSE),  	mVoiceConnected(false), @@ -809,30 +809,6 @@ void LLAgent::standUp()  	setControlFlags(AGENT_CONTROL_STAND_UP);  } - -void LLAgent::handleServerBakeRegionTransition(const LLUUID& region_id) -{ -	LL_INFOS() << "called" << LL_ENDL; - - -	// Old-style appearance entering a server-bake region. -	if (isAgentAvatarValid() && -		!gAgentAvatarp->isUsingServerBakes() && -		(mRegionp->getCentralBakeVersion()>0)) -	{ -		LL_INFOS() << "update requested due to region transition" << LL_ENDL; -		LLAppearanceMgr::instance().requestServerAppearanceUpdate(); -	} -	// new-style appearance entering a non-bake region, -	// need to check for existence of the baking service. -	else if (isAgentAvatarValid() && -			 gAgentAvatarp->isUsingServerBakes() && -			 mRegionp->getCentralBakeVersion()==0) -	{ -		gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); -	} -} -  void LLAgent::changeParcels()  {  	LL_DEBUGS("AgentLocation") << "Calling ParcelChanged callbacks" << LL_ENDL; @@ -934,19 +910,6 @@ void LLAgent::setRegion(LLViewerRegion *regionp)  	LLFloaterMove::sUpdateFlyingStatus(); -	// If the newly entered region is using server bakes, and our -	// current appearance is non-baked, request appearance update from -	// server. -	if (mRegionp->capabilitiesReceived()) -	{ -		handleServerBakeRegionTransition(mRegionp->getRegionID()); -	} -	else -	{ -		// Need to handle via callback after caps arrive. -		mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::handleServerBakeRegionTransition,this,_1)); -	} -  	if (notifyRegionChange)  	{  		LL_DEBUGS("AgentLocation") << "Calling RegionChanged callbacks" << LL_ENDL; @@ -1917,7 +1880,7 @@ BOOL LLAgent::needsRenderAvatar()  		return FALSE;  	} -	return mShowAvatar && mGenderChosen; +	return mShowAvatar && mOutfitChosen;  }  // TRUE if we need to render your own avatar's head. @@ -2565,17 +2528,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; @@ -2594,39 +2559,43 @@ LLMaturityPreferencesResponder::~LLMaturityPreferencesResponder()  {  } -void LLMaturityPreferencesResponder::result(const LLSD &pContent) +void LLMaturityPreferencesResponder::httpSuccess()  { -	U8 actualMaturity = parseMaturityFromServerResponse(pContent); +	U8 actualMaturity = parseMaturityFromServerResponse(getContent());  	if (actualMaturity != mPreferredMaturity)  	{ -		LL_WARNS() << "while attempting to change maturity preference from '" << LLViewerRegion::accessToString(mPreviousMaturity) -			<< "' to '" << LLViewerRegion::accessToString(mPreferredMaturity) << "', the server responded with '" -			<< LLViewerRegion::accessToString(actualMaturity) << "' [value:" << static_cast<U32>(actualMaturity) << ", llsd:" -			<< pContent << "]" << LL_ENDL; +		LL_WARNS() << "while attempting to change maturity preference from '" +				   << LLViewerRegion::accessToString(mPreviousMaturity) +				   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  +				   << "', the server responded with '" +				   << LLViewerRegion::accessToString(actualMaturity)  +				   << "' [value:" << static_cast<U32>(actualMaturity)  +				   << "], " << dumpResponse() << LL_ENDL;  	}  	mAgent->handlePreferredMaturityResult(actualMaturity);  } -void LLMaturityPreferencesResponder::errorWithContent(U32 pStatus, const std::string& pReason, const LLSD& pContent) +void LLMaturityPreferencesResponder::httpFailure()  { -	LL_WARNS() << "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)) << LL_ENDL; +	LL_WARNS() << "while attempting to change maturity preference from '"  +			   << LLViewerRegion::accessToString(mPreviousMaturity) +			   << "' to '" << LLViewerRegion::accessToString(mPreferredMaturity)  +			<< "', " << dumpResponse() << LL_ENDL;  	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())  	{ @@ -2772,7 +2741,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  		{ @@ -2782,7 +2751,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 @@ -3330,8 +3299,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"]; @@ -3400,8 +3368,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"));  		}  	}  }; @@ -3683,82 +3650,6 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **)  }  */ -//static -void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data) -{ -	gAgentQueryManager.mNumPendingQueries--; -	if (gAgentQueryManager.mNumPendingQueries == 0) -	{ -		selfStopPhase("fetch_texture_cache_entries"); -	} - -	if (!isAgentAvatarValid() || gAgentAvatarp->isDead()) -	{ -		LL_WARNS() << "No avatar for user in cached texture update!" << LL_ENDL; -		return; -	} - -	if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) -	{ -		// ignore baked textures when in customize mode -		return; -	} - -	S32 query_id; -	mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id); - -	S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData); - - -	S32 num_results = 0; -	for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++) -	{ -		LLUUID texture_id; -		U8 texture_index; - -		mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block); -		mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block); - - -		if ((S32)texture_index < TEX_NUM_INDICES ) -		{	 -			const LLAvatarAppearanceDictionary::TextureEntry *texture_entry = LLAvatarAppearanceDictionary::instance().getTexture((ETextureIndex)texture_index); -			if (texture_entry) -			{ -				EBakedTextureIndex baked_index = texture_entry->mBakedTextureIndex; - -				if (gAgentQueryManager.mActiveCacheQueries[baked_index] == query_id) -				{ -					if (texture_id.notNull()) -					{ -						//LL_INFOS() << "Received cached texture " << (U32)texture_index << ": " << texture_id << LL_ENDL; -						gAgentAvatarp->setCachedBakedTexture((ETextureIndex)texture_index, texture_id); -						//gAgentAvatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id ); -						gAgentQueryManager.mActiveCacheQueries[baked_index] = 0; -						num_results++; -					} -					else -					{ -						// no cache of this bake. request upload. -						gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE); -					} -				} -			} -		} -	} -	LL_INFOS() << "Received cached texture response for " << num_results << " textures." << LL_ENDL; -	gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them"); - -	gAgentAvatarp->updateMeshTextures(); - -	if (gAgentQueryManager.mNumPendingQueries == 0) -	{ -		// RN: not sure why composites are disabled at this point -		gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); -		gAgent.sendAgentSetAppearance(); -	} -} -  BOOL LLAgent::anyControlGrabbed() const  {  	for (U32 i = 0; i < TOTAL_CONTROLS; i++) @@ -4351,192 +4242,6 @@ void LLAgent::requestLeaveGodMode()  	sendReliableMessage();  } -// For debugging, trace agent state at times appearance message are sent out. -void LLAgent::dumpSentAppearance(const std::string& dump_prefix) -{ -	std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml"); - -	LLAPRFile outfile; -	std::string fullpath = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,outfilename); -	outfile.open(fullpath, LL_APR_WB ); -	apr_file_t* file = outfile.getFileHandle(); -	if (!file) -	{ -		return; -	} -	else -	{ -		LL_DEBUGS("Avatar") << "dumping sent appearance message to " << fullpath << LL_ENDL; -	} - -	LLVisualParam* appearance_version_param = gAgentAvatarp->getVisualParam(11000); -	if (appearance_version_param) -	{ -		F32 value = appearance_version_param->getWeight(); -		dump_visual_param(file, appearance_version_param, value); -	} -	for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); -		 iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); -		 ++iter) -	{ -		const ETextureIndex index = iter->first; -		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; -		if (texture_dict->mIsBakedTexture) -		{ -			LLTextureEntry* entry = gAgentAvatarp->getTE((U8) index); -			const LLUUID& uuid = entry->getID(); -			apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", index, uuid.asString().c_str()); -		} -	} -} - -//----------------------------------------------------------------------------- -// sendAgentSetAppearance() -//----------------------------------------------------------------------------- -void LLAgent::sendAgentSetAppearance() -{ -	if (gAgentQueryManager.mNumPendingQueries > 0)  -	{ -		return; -	} - -	if (!isAgentAvatarValid() || (getRegion() && getRegion()->getCentralBakeVersion())) return; - -	// At this point we have a complete appearance to send and are in a non-baking region. -	// DRANO FIXME -	//gAgentAvatarp->setIsUsingServerBakes(FALSE); -	S32 sb_count, host_count, both_count, neither_count; -	gAgentAvatarp->bakedTextureOriginCounts(sb_count, host_count, both_count, neither_count); -	if (both_count != 0 || neither_count != 0) -	{ -		LL_WARNS() << "bad bake texture state " << sb_count << "," << host_count << "," << both_count << "," << neither_count << LL_ENDL; -	} -	if (sb_count != 0 && host_count == 0) -	{ -		gAgentAvatarp->setIsUsingServerBakes(true); -	} -	else if (sb_count == 0 && host_count != 0) -	{ -		gAgentAvatarp->setIsUsingServerBakes(false); -	} -	else if (sb_count + host_count > 0) -	{ -		LL_WARNS() << "unclear baked texture state, not sending appearance" << LL_ENDL; -		return; -	} -	 -	 -	LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL; -	//dumpAvatarTEs( "sendAgentSetAppearance()" ); - -	LLMessageSystem* msg = gMessageSystem; -	msg->newMessageFast(_PREHASH_AgentSetAppearance); -	msg->nextBlockFast(_PREHASH_AgentData); -	msg->addUUIDFast(_PREHASH_AgentID, getID()); -	msg->addUUIDFast(_PREHASH_SessionID, getSessionID()); - -	// correct for the collision tolerance (to make it look like the  -	// agent is actually walking on the ground/object) -	// NOTE -- when we start correcting all of the other Havok geometry  -	// 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);	 - -	// 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" -	mAppearanceSerialNum++; -	msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum ); - -	// is texture data current relative to wearables? -	// KLW - TAT this will probably need to check the local queue. -	BOOL textures_current = gAgentAvatarp->areTexturesCurrent(); - -	for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) -	{ -		const ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - -		// if we're not wearing a skirt, we don't need the texture to be baked -		if (texture_index == TEX_SKIRT_BAKED && !gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT)) -		{ -			continue; -		} - -		// IMG_DEFAULT_AVATAR means not baked. 0 index should be ignored for baked textures -		if (!gAgentAvatarp->isTextureDefined(texture_index, 0)) -		{ -			LL_DEBUGS("Avatar") << "texture not current for baked " << (S32)baked_index << " local " << (S32)texture_index << LL_ENDL; -			textures_current = FALSE; -			break; -		} -	} - -	// only update cache entries if we have all our baked textures - -	// FIXME DRANO need additional check for not in appearance editing -	// mode, if still using local composites need to set using local -	// composites to false, and update mesh textures. -	if (textures_current) -	{ -		bool enable_verbose_dumps = gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"); -		std::string dump_prefix = gAgentAvatarp->getFullname() + "_sent_appearance"; -		if (enable_verbose_dumps) -		{ -			dumpSentAppearance(dump_prefix); -		} -		LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL; -		for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) -		{ -			BOOL generate_valid_hash = TRUE; -			if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLAvatarAppearanceDefines::EBakedTextureIndex)baked_index)) -			{ -				generate_valid_hash = FALSE; -				LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL; -			} - -			const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); -			if (hash.notNull()) -			{ -				ETextureIndex texture_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex) baked_index); -				msg->nextBlockFast(_PREHASH_WearableData); -				msg->addUUIDFast(_PREHASH_CacheID, hash); -				msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index); -			} -		} -		msg->nextBlockFast(_PREHASH_ObjectData); -		gAgentAvatarp->sendAppearanceMessage( gMessageSystem ); -	} -	else -	{ -		// If the textures aren't baked, send NULL for texture IDs -		// This means the baked texture IDs on the server will be untouched. -		// Once all textures are baked, another AvatarAppearance message will be sent to update the TEs -		msg->nextBlockFast(_PREHASH_ObjectData); -		gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0); -	} - - -	S32 transmitted_params = 0; -	for (LLViewerVisualParam* param = (LLViewerVisualParam*)gAgentAvatarp->getFirstVisualParam(); -		 param; -		 param = (LLViewerVisualParam*)gAgentAvatarp->getNextVisualParam()) -	{ -		if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) // do not transmit params of group VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT -		{ -			msg->nextBlockFast(_PREHASH_VisualParam ); -			 -			// We don't send the param ids.  Instead, we assume that the receiver has the same params in the same sequence. -			const F32 param_value = param->getWeight(); -			const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight()); -			msg->addU8Fast(_PREHASH_ParamValue, new_weight ); -			transmitted_params++; -		} -	} - -	//LL_INFOS() << "Avatar XML num VisualParams transmitted = " << transmitted_params << LL_ENDL; -	sendReliableMessage(); -} -  void LLAgent::sendAgentDataUpdateRequest()  {  	gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest); @@ -4679,23 +4384,6 @@ void LLAgent::renderAutoPilotTarget()  /********************************************************************************/ -LLAgentQueryManager gAgentQueryManager; - -LLAgentQueryManager::LLAgentQueryManager() : -	mWearablesCacheQueryID(0), -	mNumPendingQueries(0), -	mUpdateSerialNum(0) -{ -	for (U32 i = 0; i < BAKED_NUM_INDICES; i++) -	{ -		mActiveCacheQueries[i] = 0; -	} -} - -LLAgentQueryManager::~LLAgentQueryManager() -{ -} -  //-----------------------------------------------------------------------------  // LLTeleportRequest  //----------------------------------------------------------------------------- diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 1a573d32ce..a2e9cedd88 100755 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -161,12 +161,13 @@ public:  	// Gender  	//--------------------------------------------------------------------  public: -	// On the very first login, gender isn't chosen until the user clicks -	// in a dialog.  We don't render the avatar until they choose. -	BOOL 			isGenderChosen() const 	{ return mGenderChosen; } -	void			setGenderChosen(BOOL b)	{ mGenderChosen = b; } +	// On the very first login, outfit needs to be chosen by some +	// mechanism, usually by loading the requested initial outfit.  We +	// don't render the avatar until the choice is made. +	BOOL 			isOutfitChosen() const 	{ return mOutfitChosen; } +	void			setOutfitChosen(BOOL b)	{ mOutfitChosen = b; }  private: -	BOOL			mGenderChosen; +	BOOL			mOutfitChosen;  /**                    Identity   **                                                                            ** @@ -652,7 +653,6 @@ private:  	void            handleTeleportFinished();  	void            handleTeleportFailed(); -	void			handleServerBakeRegionTransition(const LLUUID& region_id);  	//--------------------------------------------------------------------  	// Teleport State @@ -888,8 +888,6 @@ private:  public:  	void			sendMessage(); // Send message to this agent's region  	void			sendReliableMessage(); -	void 			dumpSentAppearance(const std::string& dump_prefix); -	void			sendAgentSetAppearance();  	void 			sendAgentDataUpdateRequest();  	void 			sendAgentUserInfoRequest();  	// IM to Email and Online visibility @@ -903,7 +901,6 @@ public:  	static void		processAgentGroupDataUpdate(LLMessageSystem *msg, void **);  	static void		processAgentDropGroup(LLMessageSystem *msg, void **);  	static void		processScriptControlChange(LLMessageSystem *msg, void **); -	static void		processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data);  /**                    Messaging   **                                                                            ** @@ -932,24 +929,4 @@ inline bool operator==(const LLGroupData &a, const LLGroupData &b)  	return (a.mID == b.mID);  } -class LLAgentQueryManager -{ -	friend class LLAgent; -	friend class LLAgentWearables; -	 -public: -	LLAgentQueryManager(); -	virtual ~LLAgentQueryManager(); -	 -	BOOL 			hasNoPendingQueries() const 	{ return getNumPendingQueries() == 0; } -	S32 			getNumPendingQueries() const 	{ return mNumPendingQueries; } -private: -	S32				mNumPendingQueries; -	S32				mWearablesCacheQueryID; -	U32				mUpdateSerialNum; -	S32		    	mActiveCacheQueries[LLAvatarAppearanceDefines::BAKED_NUM_INDICES]; -}; - -extern LLAgentQueryManager gAgentQueryManager; -  #endif diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 58981d0e06..26626ad894 100755 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -30,7 +30,6 @@  #include "llaccordionctrltab.h"  #include "llagent.h"  #include "llagentcamera.h" -#include "llagentwearablesfetch.h"  #include "llappearancemgr.h"  #include "llcallbacklist.h"  #include "llfloatersidepanelcontainer.h" @@ -70,7 +69,7 @@ void wear_and_edit_cb(const LLUUID& inv_item)  	gAgentWearables.requestEditingWearable(inv_item);  	// Wear it. -	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item); +	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item,true);  }  /////////////////////////////////////////////////////////////////////////////// @@ -127,13 +126,6 @@ void LLAgentWearables::dump()  		}  	} -	LL_INFOS() << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << LL_ENDL; -	for (std::set<LLUUID>::iterator it = mItemsAwaitingWearableUpdate.begin(); -		 it != mItemsAwaitingWearableUpdate.end(); -		 ++it) -	{ -		LL_INFOS() << (*it).asString() << LL_ENDL; -	}  }  struct LLAgentDumper @@ -183,23 +175,9 @@ void LLAgentWearables::initClass()  void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)  {  	llassert(avatar); -	avatar->outputRezTiming("Sending wearables request"); -	sendAgentWearablesRequest();  	setAvatarAppearance(avatar);  } -// wearables -LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() -{ -	LL_INFOS() << "destructor - all done?" << LL_ENDL; -	gAgentWearables.createStandardWearablesAllDone(); -} - -LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback() -{ -	gAgentWearables.sendAgentWearablesUpdate(); -} -  /**   * @brief Construct a callback for dealing with the wearables.   * @@ -210,7 +188,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),	 @@ -222,42 +200,24 @@ LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInvento  	LL_INFOS() << "constructor" << LL_ENDL;  } -void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) +void LLAgentWearables::AddWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)  { -	if (mTodo & CALL_CREATESTANDARDDONE) -	{ -		LL_INFOS() << "callback fired, inv_item " << inv_item.asString() << LL_ENDL; -	} -  	if (inv_item.isNull())  		return;  	gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); -	if (mTodo & CALL_UPDATE) -	{ -		gAgentWearables.sendAgentWearablesUpdate(); -	} -	if (mTodo & CALL_RECOVERDONE) -	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); -		gAgentWearables.recoverMissingWearableDone(); -	}  	/*  	 * Do this for every one in the loop  	 */ -	if (mTodo & CALL_CREATESTANDARDDONE) -	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item,false); -		gAgentWearables.createStandardWearablesDone(mType, mIndex); -	}  	if (mTodo & CALL_MAKENEWOUTFITDONE)  	{  		gAgentWearables.makeNewOutfitDone(mType, mIndex);  	}  	if (mTodo & CALL_WEARITEM)  	{ -		LLAppearanceMgr::instance().addCOFItemLink(inv_item, true, NULL, mDescription); +		LLAppearanceMgr::instance().addCOFItemLink(inv_item,  +			new LLUpdateAppearanceAndEditWearableOnDestroy(inv_item), mDescription);  	}  } @@ -304,81 +264,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy  	gInventory.notifyObservers();  } -void LLAgentWearables::sendAgentWearablesUpdate() -{ -	// First make sure that we have inventory items for each wearable -	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) -	{ -		for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index) -		{ -			LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type,index); -			if (wearable) -			{ -				if (wearable->getItemID().isNull()) -				{ -					LLPointer<LLInventoryCallback> cb = -						new addWearableToAgentInventoryCallback( -							LLPointer<LLRefCount>(NULL), -							(LLWearableType::EType)type, -							index, -							wearable, -							addWearableToAgentInventoryCallback::CALL_NONE); -					addWearableToAgentInventory(cb, wearable); -				} -				else -				{ -					gInventory.addChangedMask(LLInventoryObserver::LABEL, -											  wearable->getItemID()); -				} -			} -		} -	} - -	// Then make sure the inventory is in sync with the avatar. -	gInventory.notifyObservers(); - -	// Send the AgentIsNowWearing  -	gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); - -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - -	LL_DEBUGS() << "sendAgentWearablesUpdate()" << LL_ENDL; -	// MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables. -	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type) -	{ -		gMessageSystem->nextBlockFast(_PREHASH_WearableData); - -		U8 type_u8 = (U8)type; -		gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8); - -		LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)type, 0); -		if (wearable) -		{ -			//LL_INFOS() << "Sending wearable " << wearable->getName() << LL_ENDL; -			LLUUID item_id = wearable->getItemID(); -			const LLViewerInventoryItem *item = gInventory.getItem(item_id); -			if (item && item->getIsLinkType()) -			{ -				// Get the itemID that this item points to.  i.e. make sure -				// we are storing baseitems, not their links, in the database. -				item_id = item->getLinkedUUID(); -			} -			gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);			 -		} -		else -		{ -			//LL_INFOS() << "Not wearing wearable type " << LLWearableType::getTypeName((LLWearableType::EType)i) << LL_ENDL; -			gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); -		} - -		LL_DEBUGS() << "       " << LLWearableType::getTypeLabel((LLWearableType::EType)type) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << LL_ENDL; -	} -	gAgent.sendReliableMessage(); -} - -void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update, +void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 index,  									const std::string new_name)  {  	LLViewerWearable* old_wearable = getViewerWearable(type, index); @@ -419,23 +305,14 @@ 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; -			if (send_update) -			{ -				todo |= addWearableToAgentInventoryCallback::CALL_UPDATE; -			} +			U32 todo = AddWearableToAgentInventoryCallback::CALL_NONE;  			LLPointer<LLInventoryCallback> cb = -				new addWearableToAgentInventoryCallback( +				new AddWearableToAgentInventoryCallback(  					LLPointer<LLRefCount>(NULL),  					type,  					index, @@ -445,12 +322,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32  			return;  		} -		gAgentAvatarp->wearableUpdated( type, TRUE ); - -		if (send_update) -		{ -			sendAgentWearablesUpdate(); -		} +		gAgentAvatarp->wearableUpdated(type);  	}  } @@ -484,12 +356,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; @@ -526,8 +398,6 @@ void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U3  	{  		wearable->revertValues();  	} - -	gAgent.sendAgentSetAppearance();  }  void LLAgentWearables::saveAllWearables() @@ -540,9 +410,8 @@ void LLAgentWearables::saveAllWearables()  	for (S32 i=0; i < LLWearableType::WT_COUNT; i++)  	{  		for (U32 j=0; j < getWearableCount((LLWearableType::EType)i); j++) -			saveWearable((LLWearableType::EType)i, j, FALSE); +			saveWearable((LLWearableType::EType)i, j);  	} -	sendAgentWearablesUpdate();  }  // Called when the user changes the name of a wearable inventory item that is currently being worn. @@ -571,7 +440,6 @@ void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string&  				old_wearable->setName(old_name);  				setWearable((LLWearableType::EType)i,j,new_wearable); -				sendAgentWearablesUpdate();  				break;  			}  		} @@ -692,15 +560,6 @@ LLViewerWearable*	LLAgentWearables::getWearableFromAssetID(const LLUUID& asset_i  	return NULL;  } -void LLAgentWearables::sendAgentWearablesRequest() -{ -	gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	gAgent.sendReliableMessage(); -} -  LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/)  {  	return dynamic_cast<LLViewerWearable*> (getWearable(type, index)); @@ -722,8 +581,7 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)  {  	if (isAgentAvatarValid())  	{ -		const BOOL upload_result = removed; -		gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result); +		gAgentAvatarp->wearableUpdated(wearable->getType());  	}  	LLWearableData::wearableUpdated(wearable, removed); @@ -743,23 +601,13 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)  			wearable->setDefinitionVersion(22);  			U32 index = getWearableIndex(wearable);  			LL_INFOS() << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << LL_ENDL; -			saveWearable(wearable->getType(),index,TRUE); +			saveWearable(wearable->getType(),index);  		}  		checkWearableAgainstInventory(viewer_wearable);  	}  } -BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const -{ -	return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end(); -} - -U32 LLAgentWearables::itemUpdatePendingCount() const -{ -	return mItemsAwaitingWearableUpdate.size(); -} -  const LLUUID LLAgentWearables::getWearableItemID(LLWearableType::EType type, U32 index) const  {  	const LLViewerWearable *wearable = getViewerWearable(type,index); @@ -783,157 +631,6 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const  	return getWearableFromItemID(item_id) != NULL;  } -// MULTI-WEARABLE: DEPRECATED (see backwards compatibility) -// static -// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume -// that viewers have a Current Outfit Folder and won't need this message, and thus -// we can remove/ignore this whole function. EXCEPT gAgentWearables.notifyLoadingStarted -void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) -{ -	// We should only receive this message a single time.  Ignore subsequent AgentWearablesUpdates -	// that may result from AgentWearablesRequest having been sent more than once. -	if (mInitialWearablesUpdateReceived) -		return; - -	if (isAgentAvatarValid()) -	{ -		gAgentAvatarp->startPhase("process_initial_wearables_update"); -		gAgentAvatarp->outputRezTiming("Received initial wearables update"); -	} - -	// notify subscribers that wearables started loading. See EXT-7777 -	// *TODO: find more proper place to not be called from deprecated method. -	// Seems such place is found: LLInitialWearablesFetch::processContents() -	gAgentWearables.notifyLoadingStarted(); - -	mInitialWearablesUpdateReceived = true; - -	LLUUID agent_id; -	gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - -	if (isAgentAvatarValid() && (agent_id == gAgentAvatarp->getID())) -	{ -		gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum); -		 -		const S32 NUM_BODY_PARTS = 4; -		S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); -		if (num_wearables < NUM_BODY_PARTS) -		{ -			// Transitional state.  Avatars should always have at least their body parts (hair, eyes, shape and skin). -			// The fact that they don't have any here (only a dummy is sent) implies that either: -			// 1. This account existed before we had wearables -			// 2. The database has gotten messed up -			// 3. This is the account's first login (i.e. the wearables haven't been generated yet). -			return; -		} - -		// Get the UUID of the current outfit folder (will be created if it doesn't exist) -		const LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT); -		LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(current_outfit_id); -		 -		//LL_DEBUGS() << "processAgentInitialWearablesUpdate()" << LL_ENDL; -		// Add wearables -		// MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future. -		gAgentWearables.mItemsAwaitingWearableUpdate.clear(); -		for (S32 i=0; i < num_wearables; i++) -		{ -			// Parse initial wearables data from message system -			U8 type_u8 = 0; -			gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i); -			if (type_u8 >= LLWearableType::WT_COUNT) -			{ -				continue; -			} -			const LLWearableType::EType type = (LLWearableType::EType) type_u8; -			 -			LLUUID item_id; -			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i); -			 -			LLUUID asset_id; -			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i); -			if (asset_id.isNull()) -			{ -				LLViewerWearable::removeFromAvatar(type, FALSE); -			} -			else -			{ -				LLAssetType::EType asset_type = LLWearableType::getAssetType(type); -				if (asset_type == LLAssetType::AT_NONE) -				{ -					continue; -				} -				 -				// MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions -				 -				// Store initial wearables data until we know whether we have the current outfit folder or need to use the data. -				LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); -				outfit->add(wearable_data); -			} -			 -			LL_DEBUGS() << "       " << LLWearableType::getTypeLabel(type) << LL_ENDL; -		} -		 -		// Get the complete information on the items in the inventory and set up an observer -		// that will trigger when the complete information is fetched. -		outfit->startFetch(); -		if(outfit->isFinished()) -		{ -			// everything is already here - call done. -			outfit->done(); -		} -		else -		{ -			// it's all on it's way - add an observer, and the inventory -			// will call done for us when everything is here. -			gInventory.addObserver(outfit); -		} -		 -	} -} - -// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the -// database.  If for some reason, we can't load one of those assets, we can try to reconstruct it so that -// the user isn't left without a shape, for example.  (We can do that only after the inventory has loaded.) -void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type, U32 index) -{ -	// Try to recover by replacing missing wearable with a new one. -	LLNotificationsUtil::add("ReplacedMissingWearable"); -	LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL; -	LLViewerWearable* new_wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp); - -	setWearable(type,index,new_wearable); -	//new_wearable->writeToAvatar(TRUE); - -	// Add a new one in the lost and found folder. -	// (We used to overwrite the "not found" one, but that could potentially -	// destory content.) JC -	const LLUUID lost_and_found_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND); -	LLPointer<LLInventoryCallback> cb = -		new addWearableToAgentInventoryCallback( -			LLPointer<LLRefCount>(NULL), -			type, -			index, -			new_wearable, -			addWearableToAgentInventoryCallback::CALL_RECOVERDONE); -	addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE); -} - -void LLAgentWearables::recoverMissingWearableDone() -{ -	// Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? -	updateWearablesLoaded(); -	if (areWearablesLoaded()) -	{ -		// Make sure that the server's idea of the avatar's wearables actually match the wearables. -		gAgent.sendAgentSetAppearance(); -	} -	else -	{ -		gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null); -		gInventory.notifyObservers(); -	} -} -  void LLAgentWearables::addLocalTextureObject(const LLWearableType::EType wearable_type, const LLAvatarAppearanceDefines::ETextureIndex texture_type, U32 wearable_index)  {  	LLViewerWearable* wearable = getViewerWearable((LLWearableType::EType)wearable_type, wearable_index); @@ -957,7 +654,7 @@ public:  	/* virtual */ void fire(const LLUUID& inv_item)  	{  		LL_INFOS() << "One item created " << inv_item.asString() << LL_ENDL; -		LLViewerInventoryItem *item = gInventory.getItem(inv_item); +		LLConstPointer<LLInventoryObject> item = gInventory.getItem(inv_item);  		mItemsToLink.push_back(item);  		updatePendingWearable(inv_item);  	} @@ -965,9 +662,9 @@ public:  	{  		LL_INFOS() << "All items created" << LL_ENDL;  		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)  	{ @@ -1016,7 +713,7 @@ public:  	}  private: -	LLInventoryModel::item_array_t mItemsToLink; +	LLInventoryObject::const_object_list_t mItemsToLink;  	std::vector<LLViewerWearable*> mWearablesAwaitingItems;  }; @@ -1068,28 +765,38 @@ void LLAgentWearables::createStandardWearables()  	}  } -void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) +// We no longer need this message in the current viewer, but send +// it for now to maintain compatibility with release viewers. Can +// remove this function once the SH-3455 changesets are universally deployed. +void LLAgentWearables::sendDummyAgentWearablesUpdate()  { -	LL_INFOS() << "type " << type << " index " << index << LL_ENDL; +	LL_DEBUGS("Avatar") << "sendAgentWearablesUpdate()" << LL_ENDL; -	if (!isAgentAvatarValid()) return; -	gAgentAvatarp->updateVisualParams(); -} +	// Send the AgentIsNowWearing  +	gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); +	 +	gMessageSystem->nextBlockFast(_PREHASH_AgentData); +	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); +	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -void LLAgentWearables::createStandardWearablesAllDone() -{ -	// ... because sendAgentWearablesUpdate will notify inventory -	// observers. -	LL_INFOS() << "all done?" << LL_ENDL; +	// Send 4 standardized nonsense item ids (same as returned by the modified sim, not that it especially matters). +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(1)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("db5a4e5f-9da3-44c8-992d-1181c5795498"));			 -	mWearablesLoaded = TRUE;  -	checkWearablesLoaded(); -	notifyLoadingFinished(); -	 -	updateServer(); +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(2)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("6969c7cc-f72f-4a76-a19b-c293cce8ce4f"));			 + +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(3)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("7999702b-b291-48f9-8903-c91dfb828408"));			 -	// Treat this as the first texture entry message, if none received yet -	gAgentAvatarp->onFirstTEMessageReceived(); +	gMessageSystem->nextBlockFast(_PREHASH_WearableData); +	gMessageSystem->addU8Fast(_PREHASH_WearableType, U8(4)); +	gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID("566cb59e-ef60-41d7-bfa6-e0f293fbea40"));			 + +	gAgent.sendReliableMessage();  }  void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) @@ -1205,11 +912,10 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo  		for (S32 i=max_entry; i>=0; i--)  		{  			LLViewerWearable* old_wearable = getViewerWearable(type,i); -			//queryWearableCache(); // moved below  			if (old_wearable)  			{  				popWearable(old_wearable); -				old_wearable->removeFromAvatar(TRUE); +				old_wearable->removeFromAvatar();  			}  		}  		clearWearableType(type); @@ -1217,48 +923,99 @@ void LLAgentWearables::removeWearableFinal(const LLWearableType::EType type, boo  	else  	{  		LLViewerWearable* old_wearable = getViewerWearable(type, index); -		//queryWearableCache(); // moved below  		if (old_wearable)  		{  			popWearable(old_wearable); -			old_wearable->removeFromAvatar(TRUE); +			old_wearable->removeFromAvatar();  		}  	} -	queryWearableCache(); - -	// Update the server -	updateServer();  	gInventory.notifyObservers();  }  // Assumes existing wearables are not dirty.  void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items, -										 const std::vector< LLViewerWearable* >& wearables, -										 BOOL remove) +										 const std::vector< LLViewerWearable* >& wearables)  {  	LL_INFOS() << "setWearableOutfit() start" << LL_ENDL; +	S32 count = wearables.size(); +	llassert(items.size() == 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) +		{ +			LL_WARNS() << "invalid type " << type << LL_ENDL; +			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")  << LL_ENDL; +			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() +								<< LL_ENDL; +			mismatched++; +			continue; +		} +		// If we got here, everything matches. +		matched++; +	} +	LL_DEBUGS("Avatar") << "matched " << matched << " mismatched " << mismatched << LL_ENDL; +	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] << LL_ENDL;  +			mismatched++; +		} +	} +	if (mismatched == 0) +	{ +		LL_DEBUGS("Avatar") << "no changes, bailing out" << LL_ENDL; +		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.size(); -	llassert(items.size() == 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]; @@ -1305,14 +1062,12 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it  	// Start rendering & update the server  	mWearablesLoaded = TRUE;  -	checkWearablesLoaded(); +  	notifyLoadingFinished(); -	queryWearableCache(); -	updateServer();  	gAgentAvatarp->dumpAvatarTEs("setWearableOutfit"); -	LL_DEBUGS() << "setWearableOutfit() end" << LL_ENDL; +	LL_DEBUGS("Avatar") << "setWearableOutfit() end" << LL_ENDL;  } @@ -1429,79 +1184,6 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLViewerWeara  		LL_INFOS() << "Replaced current element 0 for type " << type  				<< " size is now " << getWearableCount(type) << LL_ENDL;  	} - -	//LL_INFOS() << "LLVOAvatar::setWearableItem()" << LL_ENDL; -	queryWearableCache(); -	//new_wearable->writeToAvatar(TRUE); - -	updateServer(); -} - -void LLAgentWearables::queryWearableCache() -{ -	if (!areWearablesLoaded() || (gAgent.getRegion() && gAgent.getRegion()->getCentralBakeVersion())) -	{ -		return; -	} - -	// Look up affected baked textures. -	// If they exist: -	//		disallow updates for affected layersets (until dataserver responds with cache request.) -	//		If cache miss, turn updates back on and invalidate composite. -	//		If cache hit, modify baked texture entries. -	// -	// Cache requests contain list of hashes for each baked texture entry. -	// Response is list of valid baked texture assets. (same message) - -	gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture); -	gMessageSystem->nextBlockFast(_PREHASH_AgentData); -	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); -	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); -	gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID); - -	S32 num_queries = 0; -	for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) -	{ -		LLUUID hash_id = computeBakedTextureHash((EBakedTextureIndex) baked_index); -		if (hash_id.notNull()) -		{ -			num_queries++; -			// *NOTE: make sure at least one request gets packed - -			ETextureIndex te_index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); - -			//LL_INFOS() << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << LL_ENDL; -			gMessageSystem->nextBlockFast(_PREHASH_WearableData); -			gMessageSystem->addUUIDFast(_PREHASH_ID, hash_id); -			gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)te_index); -		} - -		gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID; -	} -	//VWR-22113: gAgent.getRegion() can return null if invalid, seen here on logout -	if(gAgent.getRegion()) -	{ -		if (isAgentAvatarValid()) -		{ -			selfStartPhase("fetch_texture_cache_entries"); -			gAgentAvatarp->outputRezTiming("Fetching textures from cache"); -		} - -		LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL; -		gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); -		gAgentQueryManager.mNumPendingQueries++; -		gAgentQueryManager.mWearablesCacheQueryID++; -	} -} - -// 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); -	}  }  // User has picked "remove from avatar" from a menu. @@ -1687,17 +1369,6 @@ void LLAgentWearables::userAttachMultipleAttachments(LLInventoryModel::item_arra  	}  } -void LLAgentWearables::checkWearablesLoaded() const -{ -#ifdef SHOW_ASSERT -	U32 item_pend_count = itemUpdatePendingCount(); -	if (mWearablesLoaded) -	{ -		llassert(item_pend_count==0); -	} -#endif -} -  // Returns false if the given wearable is already topmost/bottommost  // (depending on closer_to_body parameter).  bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_body) const @@ -1714,20 +1385,9 @@ bool LLAgentWearables::canMoveWearable(const LLUUID& item_id, bool closer_to_bod  BOOL LLAgentWearables::areWearablesLoaded() const  { -	checkWearablesLoaded();  	return mWearablesLoaded;  } -// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate -void LLAgentWearables::updateWearablesLoaded() -{ -	mWearablesLoaded = (itemUpdatePendingCount()==0); -	if (mWearablesLoaded) -	{ -		notifyLoadingFinished(); -	} -} -  bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) const  {  	if (!wearable) return false; @@ -1737,7 +1397,7 @@ bool LLAgentWearables::canWearableBeRemoved(const LLViewerWearable* wearable) co  	return !(((type == LLWearableType::WT_SHAPE) || (type == LLWearableType::WT_SKIN) || (type == LLWearableType::WT_HAIR) || (type == LLWearableType::WT_EYES))  			 && (getWearableCount(type) <= 1) );		    } -void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake) +void LLAgentWearables::animateAllWearableParams(F32 delta)  {  	for( S32 type = 0; type < LLWearableType::WT_COUNT; ++type )  	{ @@ -1747,7 +1407,7 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)  			llassert(wearable);  			if (wearable)  			{ -				wearable->animateParams(delta, upload_bake); +				wearable->animateParams(delta);  			}  		}  	} @@ -1870,30 +1530,6 @@ void LLAgentWearables::editWearableIfRequested(const LLUUID& item_id)  	}  } -void LLAgentWearables::updateServer() -{ -	sendAgentWearablesUpdate(); -	gAgent.sendAgentSetAppearance(); -} - -void LLAgentWearables::populateMyOutfitsFolder(void) -{	 -	LL_INFOS() << "starting outfit population" << LL_ENDL; - -	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); @@ -1912,6 +1548,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 02d24892b5..cdb1bdbe05 100755 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -42,7 +42,6 @@  class LLInventoryItem;  class LLVOAvatarSelf;  class LLViewerWearable; -class LLInitialWearablesFetch;  class LLViewerObject;  class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearableData @@ -51,7 +50,6 @@ class LLAgentWearables : public LLInitClass<LLAgentWearables>, public LLWearable  	// Constructors / destructors / Initializers  	//--------------------------------------------------------------------  public: -	friend class LLInitialWearablesFetch;  	LLAgentWearables();  	virtual ~LLAgentWearables(); @@ -62,9 +60,6 @@ public:  	// LLInitClass interface  	static void initClass(); -protected: -	void			createStandardWearablesDone(S32 type, U32 index/* = 0*/); -	void			createStandardWearablesAllDone();  	//--------------------------------------------------------------------  	// Queries @@ -77,6 +72,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; @@ -84,7 +80,7 @@ public:  	// Note: False for shape, skin, eyes, and hair, unless you have MORE than 1.  	bool			canWearableBeRemoved(const LLViewerWearable* wearable) const; -	void			animateAllWearableParams(F32 delta, BOOL upload_bake); +	void			animateAllWearableParams(F32 delta);  	//--------------------------------------------------------------------  	// Accessors @@ -107,7 +103,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 std::vector< LLViewerWearable* >& wearables, BOOL remove); +	void			setWearableOutfit(const LLInventoryItem::item_array_t& items, const std::vector< 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); @@ -151,31 +147,10 @@ private:  	void			removeWearableFinal(const LLWearableType::EType type, bool do_remove_all /*= false*/, U32 index /*= 0*/);  protected:  	static bool		onRemoveWearableDialog(const LLSD& notification, const LLSD& response); -	 -	//-------------------------------------------------------------------- -	// Server Communication -	//-------------------------------------------------------------------- -public: -	// Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant) -	static void		processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); - -protected: -	/*virtual*/ void	invalidateBakedTextureHash(LLMD5& hash) const; -	void			sendAgentWearablesUpdate(); -	void			sendAgentWearablesRequest(); -	void			queryWearableCache(); -	void 			updateServer(); -	static void		onInitialWearableAssetArrived(LLViewerWearable* wearable, void* userdata);  	//--------------------------------------------------------------------  	// 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);  @@ -184,11 +159,16 @@ private:  	//--------------------------------------------------------------------  public:	  	void			saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, const std::string& description, BOOL save_in_lost_and_found); -	void			saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, +	void			saveWearable(const LLWearableType::EType type, const U32 index,  								 const std::string new_name = "");  	void			saveAllWearables();  	void			revertWearable(const LLWearableType::EType type, const U32 index); +	// We no longer need this message in the current viewer, but send +	// it for now to maintain compatibility with release viewers. Can +	// remove this function once the SH-3455 changesets are universally deployed. +	void			sendDummyAgentWearablesUpdate(); +  	//--------------------------------------------------------------------  	// Static UI hooks  	//-------------------------------------------------------------------- @@ -202,9 +182,6 @@ public:  	static void		userRemoveMultipleAttachments(llvo_vec_t& llvo_array);  	static void		userAttachMultipleAttachments(LLInventoryModel::item_array_t& obj_item_array); -	BOOL			itemUpdatePending(const LLUUID& item_id) const; -	U32				itemUpdatePendingCount() const; -  	//--------------------------------------------------------------------  	// Signals  	//-------------------------------------------------------------------- @@ -231,29 +208,18 @@ private:  private:  	static BOOL		mInitialWearablesUpdateReceived;  	BOOL			mWearablesLoaded; -	std::set<LLUUID>	mItemsAwaitingWearableUpdate;  	/**  	 * True if agent's outfit is being changed now.  	 */  	BOOL			mCOFChangeInProgress; +	LLTimer			mCOFChangeTimer;  	//--------------------------------------------------------------------------------  	// Support classes  	//--------------------------------------------------------------------------------  private: -	class createStandardWearablesAllDoneCallback : public LLRefCount -	{ -	protected: -		~createStandardWearablesAllDoneCallback(); -	}; -	class sendAgentWearablesUpdateCallback : public LLRefCount -	{ -	protected: -		~sendAgentWearablesUpdateCallback(); -	}; - -	class addWearableToAgentInventoryCallback : public LLInventoryCallback +	class AddWearableToAgentInventoryCallback : public LLInventoryCallback  	{  	public:  		enum ETodo @@ -266,7 +232,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 deleted file mode 100755 index af0f02861d..0000000000 --- a/indra/newview/llagentwearablesfetch.cpp +++ /dev/null @@ -1,600 +0,0 @@ -/**  - * @file llagentwearablesfetch.cpp - * @brief LLAgentWearblesFetch class implementation - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llagentwearablesfetch.h" - -#include "llagent.h" -#include "llagentwearables.h" -#include "llappearancemgr.h" -#include "llinventoryfunctions.h" -#include "llstartup.h" -#include "llvoavatarself.h" - - -void order_my_outfits_cb() -	{ -		if (!LLApp::isRunning()) -		{ -			LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; -			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) -		{ -			LL_WARNS() << "My Outfits category was not populated properly" << LL_ENDL; -			return; -		} - -		LL_INFOS() << "Starting updating My Outfits with wearables ordering information" << LL_ENDL; - -		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); -		} - -		LL_INFOS() << "Finished updating My Outfits with wearables ordering information" << LL_ENDL; -	} - -LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) : -	LLInventoryFetchDescendentsObserver(cof_id) -{ -	if (isAgentAvatarValid()) -	{ -		gAgentAvatarp->startPhase("initial_wearables_fetch"); -		gAgentAvatarp->outputRezTiming("Initial wearables fetch started"); -	} -} - -LLInitialWearablesFetch::~LLInitialWearablesFetch() -{ -} - -// virtual -void LLInitialWearablesFetch::done() -{ -	// Delay processing the actual results of this so it's not handled within -	// gInventory.notifyObservers.  The results will be handled in the next -	// idle tick instead. -	gInventory.removeObserver(this); -	doOnIdleOneTime(boost::bind(&LLInitialWearablesFetch::processContents,this)); -	if (isAgentAvatarValid()) -	{ -		gAgentAvatarp->stopPhase("initial_wearables_fetch"); -		gAgentAvatarp->outputRezTiming("Initial wearables fetch done"); -	} -} - -void LLInitialWearablesFetch::add(InitialWearableData &data) - -{ -	mAgentInitialWearables.push_back(data); -} - -void LLInitialWearablesFetch::processContents() -{ -	if(!gAgentAvatarp) //no need to process wearables if the agent avatar is deleted. -	{ -		delete this; -		return ; -	} - -	// Fetch the wearable items from the Current Outfit Folder -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t wearable_array; -	LLFindWearables is_wearable; -	llassert_always(mComplete.size() != 0); -	gInventory.collectDescendentsIf(mComplete.front(), cat_array, wearable_array,  -									LLInventoryModel::EXCLUDE_TRASH, is_wearable); - -	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); -	if (wearable_array.size() > 0) -	{ -		gAgentWearables.notifyLoadingStarted(); -		LLAppearanceMgr::instance().updateAppearanceFromCOF(); -	} -	else -	{ -		// if we're constructing the COF from the wearables message, we don't have a proper outfit link -		LLAppearanceMgr::instance().setOutfitDirty(true); -		processWearablesMessage(); -	} -	delete this; -} - -class LLFetchAndLinkObserver: public LLInventoryFetchItemsObserver -{ -public: -	LLFetchAndLinkObserver(uuid_vec_t& ids): -		LLInventoryFetchItemsObserver(ids) -	{ -	} -	~LLFetchAndLinkObserver() -	{ -	} -	virtual void done() -	{ -		gInventory.removeObserver(this); - -		// Link to all fetched items in COF. -		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy; -		for (uuid_vec_t::iterator it = mIDs.begin(); -			 it != mIDs.end(); -			 ++it) -		{ -			LLUUID id = *it; -			LLViewerInventoryItem *item = gInventory.getItem(*it); -			if (!item) -			{ -				LL_WARNS() << "fetch failed!" << LL_ENDL; -				continue; -			} - -			link_inventory_item(gAgent.getID(), -								item->getLinkedUUID(), -								LLAppearanceMgr::instance().getCOF(), -								item->getName(), -								item->getDescription(), -								LLAssetType::AT_LINK, -								link_waiter); -		} -	} -}; - -void LLInitialWearablesFetch::processWearablesMessage() -{ -	if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. -	{ -		const LLUUID current_outfit_id = LLAppearanceMgr::instance().getCOF(); -		uuid_vec_t ids; -		for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) -		{ -			// Populate the current outfit folder with links to the wearables passed in the message -			InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. -			 -			if (wearable_data->mAssetID.notNull()) -			{ -				ids.push_back(wearable_data->mItemID); -			} -			else -			{ -				LL_INFOS() << "Invalid wearable, type " << wearable_data->mType << " itemID " -				<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << LL_ENDL; -				delete wearable_data; -			} -		} - -		// Add all current attachments to the requested items as well. -		if (isAgentAvatarValid()) -		{ -			for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();  -				 iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter) -			{ -				LLViewerJointAttachment* attachment = iter->second; -				if (!attachment) continue; -				for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); -					 attachment_iter != attachment->mAttachedObjects.end(); -					 ++attachment_iter) -				{ -					LLViewerObject* attached_object = (*attachment_iter); -					if (!attached_object) continue; -					const LLUUID& item_id = attached_object->getAttachmentItemID(); -					if (item_id.isNull()) continue; -					ids.push_back(item_id); -				} -			} -		} - -		// Need to fetch the inventory items for ids, then create links to them after they arrive. -		LLFetchAndLinkObserver *fetcher = new LLFetchAndLinkObserver(ids); -		fetcher->startFetch(); -		// If no items to be fetched, done will never be triggered. -		// TODO: Change LLInventoryFetchItemsObserver::fetchItems to trigger done() on this condition. -		if (fetcher->isFinished()) -		{ -			fetcher->done(); -		} -		else -		{ -			gInventory.addObserver(fetcher); -		} -	} -	else -	{ -		LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; -	} -} - -LLLibraryOutfitsFetch::LLLibraryOutfitsFetch(const LLUUID& my_outfits_id) :  -	LLInventoryFetchDescendentsObserver(my_outfits_id), -	mCurrFetchStep(LOFS_FOLDER),  -	mOutfitsPopulated(false)  -{ -	LL_INFOS() << "created" << LL_ENDL; - -	mMyOutfitsID = LLUUID::null; -	mClothingID = LLUUID::null; -	mLibraryClothingID = LLUUID::null; -	mImportedClothingID = LLUUID::null; -	mImportedClothingName = "Imported Library Clothing"; -} - -LLLibraryOutfitsFetch::~LLLibraryOutfitsFetch() -{ -	LL_INFOS() << "destroyed" << LL_ENDL; -} - -void LLLibraryOutfitsFetch::done() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	// 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() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	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: -			LL_WARNS() << "Got invalid state for outfit fetch: " << mCurrFetchStep << LL_ENDL; -			mOutfitsPopulated = TRUE; -			break; -	} - -	// We're completely done.  Cleanup. -	if (mOutfitsPopulated) -	{ -		gInventory.removeObserver(this); -		delete this; -		return; -	} -} - -void LLLibraryOutfitsFetch::folderDone() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	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.size() > 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.size() > 0) -	{ -		const LLViewerInventoryCategory *cat = cat_array.at(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() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	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.size() > 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.at(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() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	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) -		{ -			LL_WARNS() << "Library folder import for uuid:" << src_folder_id << " failed to find folder." << LL_ENDL; -			continue; -		} -		 -		if (!LLAppearanceMgr::getInstance()->getCanMakeFolderIntoOutfit(src_folder_id)) -		{ -			LL_INFOS() << "Skipping non-outfit folder name:" << cat->getName() << LL_ENDL; -			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() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	// 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() -{ -	LL_INFOS() << "start" << LL_ENDL; - -	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() -{		 -	LL_INFOS() << "start" << LL_ENDL; - -	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) -		{ -			LL_WARNS() << "Library folder import for uuid:" << folder_id << " failed to find folder." << LL_ENDL; -			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 deleted file mode 100755 index bedc445c0e..0000000000 --- a/indra/newview/llagentwearablesfetch.h +++ /dev/null @@ -1,114 +0,0 @@ -/**  - * @file llagentwearablesinitialfetch.h - * @brief LLAgentWearablesInitialFetch class header file - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLAGENTWEARABLESINITIALFETCH_H -#define LL_LLAGENTWEARABLESINITIALFETCH_H - -#include "llinventoryobserver.h" -#include "llwearabletype.h" -#include "lluuid.h" - -//-------------------------------------------------------------------- -// InitialWearablesFetch -//  -// This grabs contents from the COF and processes them. -// The processing is handled in idle(), i.e. outside of done(), -// to avoid gInventory.notifyObservers recursion. -//-------------------------------------------------------------------- -class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver -{ -	LOG_CLASS(LLInitialWearablesFetch); - -public: -	LLInitialWearablesFetch(const LLUUID& cof_id); -	~LLInitialWearablesFetch(); -	virtual void done(); - -	struct InitialWearableData -	{ -		LLWearableType::EType mType; -		LLUUID mItemID; -		LLUUID mAssetID; -		InitialWearableData(LLWearableType::EType type, LLUUID& itemID, LLUUID& assetID) : -			mType(type), -			mItemID(itemID), -			mAssetID(assetID) -		{} -	}; - -	void add(InitialWearableData &data); - -protected: -	void processWearablesMessage(); -	void processContents(); - -private: -	typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; -	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..da66ea357a --- /dev/null +++ b/indra/newview/llaisapi.cpp @@ -0,0 +1,867 @@ +/**  + * @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" +#include "llinventoryobserver.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)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		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)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		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)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		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)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		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& cat_id, +											 const LLSD& updates, +											 LLPointer<LLInventoryCallback> callback): +	mUpdates(updates), +	AISCommand(callback) +{ +	std::string cap; +	if (!getInvCap(cap)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	std::string url = cap + std::string("/category/") + cat_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)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		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)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		return; +	} +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString(); +	LL_INFOS() << 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::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)) +	{ +		LL_WARNS() << "No cap found" << LL_ENDL; +		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(); +	LL_INFOS() << url << LL_ENDL; +	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? +		LL_ERRS() << "unpack failed" << LL_ENDL; +	} +} + +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? +		LL_ERRS() << "unpack failed" << LL_ENDL; +	} +} + + +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? +		LL_ERRS() << "unpack failed" << LL_ENDL; +	} + +	// 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("categories") && +		embedded.has("links") && +		embedded.has("items")) +	{ +		mCatDescendentsKnown[category_id]  = embedded["categories"].size(); +		mCatDescendentsKnown[category_id] += embedded["links"].size(); +		mCatDescendentsKnown[category_id] += embedded["items"].size(); +	} +} + +void AISUpdate::parseEmbedded(const LLSD& embedded) +{ +	if (embedded.has("links")) // _embedded in a category +	{ +		parseEmbeddedLinks(embedded["links"]); +	} +	if (embedded.has("items")) // _embedded in a category +	{ +		parseEmbeddedItems(embedded["items"]); +	} +	if (embedded.has("item")) // _embedded in a link +	{ +		parseEmbeddedItem(embedded["item"]); +	} +	if (embedded.has("categories")) // _embedded in a category +	{ +		parseEmbeddedCategories(embedded["categories"]); +	} +	if (embedded.has("category")) // _embedded in a link +	{ +		parseEmbeddedCategory(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::parseEmbeddedItem(const LLSD& item) +{ +	// a single item (_embedded in a link) +	if (item.has("item_id")) +	{ +		if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID())) +		{ +			parseItem(item); +		} +	} +} + +void AISUpdate::parseEmbeddedItems(const LLSD& items) +{ +	// a map of items (_embedded in a category) +	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::parseEmbeddedCategory(const LLSD& category) +{ +	// a single category (_embedded in a link) +	if (category.has("category_id")) +	{ +		if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID())) +		{ +			parseCategory(category); +		} +	} +} + +void AISUpdate::parseEmbeddedCategories(const LLSD& categories) +{ +	// a map of categories (_embedded in a category) +	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 << LL_ENDL; + +		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, LLInventoryObserver::CREATE); +		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, LLInventoryObserver::CREATE); +	} +	 +	// 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() << LL_ENDL; +		if (cat->getVersion() != version) +		{ +			LL_WARNS() << "Possible version mismatch for category " << cat->getName() +					<< ", viewer version " << cat->getVersion() +					<< " server version " << version << LL_ENDL; +		} +	} + +	gInventory.notifyObservers(); +} + diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h new file mode 100755 index 0000000000..5a2ec94af9 --- /dev/null +++ b/indra/newview/llaisapi.h @@ -0,0 +1,183 @@ +/**  + * @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& cat_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& items); +	void parseEmbeddedCategories(const LLSD& categories); +	void parseEmbeddedItem(const LLSD& item); +	void parseEmbeddedCategory(const LLSD& category); +	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 81f713502f..a4c430bada 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,22 @@ 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 << LL_ENDL; -  		if (!requestOperation(item_id))  		{  			LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << LL_ENDL;  			return; -	} +		}  		mPendingRequests++;  		// On a re-request, this will reset the timer.  		mWaitTimes[item_id] = LLTimer();  		if (mRetryCounts.find(item_id) == mRetryCounts.end()) -	{ +		{  			mRetryCounts[item_id] = 0;  		}  		else @@ -242,7 +243,7 @@ public:  	void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp)  	{  		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate")) -	{ +		{  			LL_WARNS() << "Simulating late operation by punting handling to later" << LL_ENDL;  			doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp),  							mRetryAfter); @@ -265,12 +266,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 +289,7 @@ public:  			onFailure();  		}  	} -		 +  	void onFailure()  	{  		LL_INFOS() << "failed" << LL_ENDL; @@ -300,7 +301,7 @@ public:  		LL_INFOS() << "done" << LL_ENDL;  		mOnCompletionFunc();  	} - +	  	// virtual  	// Will be deleted after returning true - only safe to do this if all callbacks have fired.  	BOOL tick() @@ -313,7 +314,7 @@ public:  		// been serviced, since it will result in this object being  		// deleted.  		bool all_done = (mPendingRequests==0); -		 +  		if (!mWaitTimes.empty())  		{  			LL_WARNS() << "still waiting on " << mWaitTimes.size() << " items" << LL_ENDL; @@ -323,20 +324,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" << LL_ENDL;  						mRetryCount++;  						addItem(curr_it->first); -		} -		else -		{ +					} +					else +					{  						LL_WARNS() << "Giving up on " << curr_it->first << " after too many retries" << LL_ENDL;  						mWaitTimes.erase(curr_it);  						mFailCount++; @@ -347,8 +348,8 @@ public:  					onCompletionOrFailure();  				} +			}  		} -	}  		return all_done;  	} @@ -360,7 +361,7 @@ public:  		LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << LL_ENDL;  		LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << LL_ENDL;  	} - +	  	virtual ~LLCallAfterInventoryBatchMgr()  	{  		LL_DEBUGS("Avatar") << "deleting" << LL_ENDL; @@ -396,10 +397,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 << LL_ENDL; @@ -418,95 +425,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 << LL_ENDL; -				return false; -			} -			LL_DEBUGS("Avatar") << "linking item " << item_id << " name " << item->getName() << " to " << mDstCatID << LL_ENDL; -			// create an inventory item link. -			if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate")) -			{ -				LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << LL_ENDL; -				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) -			{ -				LL_WARNS() << "link request failed, id not found as inventory item or category " << item_id << LL_ENDL; -				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 << LL_ENDL; -					return true; -				} -				LL_DEBUGS("Avatar") << "linking folder " << item_id << " name " << catp->getName() << " to cof " << cof << LL_ENDL; -				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 +514,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 +617,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 +632,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,13 +648,13 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():  	mIsMostRecent(true),  	mIsAllComplete(false)  { -	if (sActiveHoldingPatterns.size()>0) +	if (countActive()>0)  	{  		LL_INFOS() << "Creating LLWearableHoldingPattern when " -				<< sActiveHoldingPatterns.size() -				<< " other attempts are active." -				<< " Flagging others as invalid." -				<< LL_ENDL; +				   << countActive() +				   << " other attempts are active." +				   << " Flagging others as invalid." +				   << LL_ENDL;  		for (type_set_hp::iterator it = sActiveHoldingPatterns.begin();  			 it != sActiveHoldingPatterns.end();  			 ++it) @@ -634,7 +663,9 @@ LLWearableHoldingPattern::LLWearableHoldingPattern():  		}  	} +	mIndex = sNextIndex++;  	sActiveHoldingPatterns.insert(this); +	LL_DEBUGS("Avatar") << "HP " << index() << " created" << LL_ENDL;  	selfStartPhase("holding_pattern");  } @@ -645,6 +676,7 @@ LLWearableHoldingPattern::~LLWearableHoldingPattern()  	{  		selfStopPhase("holding_pattern");  	} +	LL_DEBUGS("Avatar") << "HP " << index() << " deleted" << LL_ENDL;  }  bool LLWearableHoldingPattern::isMostRecent() @@ -733,7 +765,10 @@ void LLWearableHoldingPattern::checkMissingWearables()  	resetTime(60.0F); -	selfStartPhase("get_missing_wearables"); +	if (isMostRecent()) +	{ +		selfStartPhase("get_missing_wearables_2"); +	}  	if (!pollMissingWearables())  	{  		doOnIdleRepeating(boost::bind(&LLWearableHoldingPattern::pollMissingWearables,this)); @@ -773,8 +808,8 @@ 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()) @@ -797,7 +832,10 @@ void LLWearableHoldingPattern::onAllComplete()  void LLWearableHoldingPattern::onFetchCompletion()  { -	selfStopPhase("get_wearables"); +	if (isMostRecent()) +	{ +		selfStopPhase("get_wearables_2"); +	}  	if (!isMostRecent())  	{ @@ -823,7 +861,7 @@ 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; @@ -841,69 +879,64 @@ bool LLWearableHoldingPattern::pollFetchCompletion()  void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)  {  	if (!holder->isMostRecent()) -		{ -			LL_WARNS() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -			// runway skip here? -		} +	{ +		LL_WARNS() << "HP " << holder->index() << " skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; +		// runway skip here? +	} -	LL_INFOS() << "Recovered item link for type " << type << LL_ENDL; +	LL_INFOS() << "HP " << holder->index() << " recovered item link for type " << type << LL_ENDL;  	holder->eraseTypeToLink(type); -		// Add wearable to FoundData for actual wearing -		LLViewerInventoryItem *item = gInventory.getItem(item_id); -		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL; +	// 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 -			{ -				LL_WARNS() << self_av_string() << "inventory item not found for recovered wearable" << LL_ENDL; -			}  		}  		else  		{  			LL_WARNS() << self_av_string() << "inventory link not found for recovered wearable" << LL_ENDL;  		}  	} +	else +	{ +		LL_WARNS() << self_av_string() << "HP " << holder->index() << " inventory link not found for recovered wearable" << LL_ENDL; +	} +}  void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)  {  	if (!holder->isMostRecent()) -		{ -			// runway skip here? -			LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; -		} +	{ +		// runway skip here? +		LL_WARNS() << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << LL_ENDL; +	}  	LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL; -		LLViewerInventoryItem *itemp = gInventory.getItem(item_id); +	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)  { @@ -916,7 +949,7 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type  		// Try to recover by replacing missing wearable with a new one.  	LLNotificationsUtil::add("ReplacedMissingWearable");  	LL_DEBUGS() << "Wearable " << LLWearableType::getTypeLabel(type) -			 << " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL; +				<< " could not be downloaded.  Replaced inventory item with default wearable." << LL_ENDL;  	LLViewerWearable* wearable = LLWearableList::instance().createNewWearable(type, gAgentAvatarp);  	// Add a new one in the lost and found folder. @@ -949,7 +982,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);  		}  	} @@ -969,7 +1002,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 +1011,10 @@ bool LLWearableHoldingPattern::pollMissingWearables()  	if (done)  	{ -		selfStopPhase("get_missing_wearables"); +		if (isMostRecent()) +		{ +			selfStopPhase("get_missing_wearables_2"); +		}  		gAgentAvatarp->debugWearablesLoaded(); @@ -1016,7 +1052,7 @@ void LLWearableHoldingPattern::handleLateArrivals()  		LL_WARNS() << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << LL_ENDL;  	} -	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 +1115,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) @@ -1096,7 +1132,7 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLViewerWearable *wearable)  	}  	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)  	{  		LL_WARNS() << self_av_string() << "no wearable found" << LL_ENDL; @@ -1203,8 +1239,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 +1305,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 +1329,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 +1349,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 +1373,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 +1506,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); +	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; +	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin(); +		 iter != items->end(); +		 ++iter) +	{ +		const LLViewerInventoryItem* item = (*iter); +		switch (item->getActualType()) +		{ +			case LLAssetType::AT_LINK: +			{ +				LL_DEBUGS("Avatar") << "linking inventory item " << item->getName() << LL_ENDL; +				//getActualDescription() is used for a new description  +				//to propagate ordering information saved in descriptions of links +				LLSD item_contents; +				item_contents["name"] = item->getName(); +				item_contents["desc"] = item->getActualDescription(); +				item_contents["linked_id"] = item->getLinkedUUID(); +				item_contents["type"] = LLAssetType::AT_LINK;  +				contents.append(item_contents); +				break; +			} +			case LLAssetType::AT_LINK_FOLDER: +			{ +				LLViewerInventoryCategory *catp = item->getLinkedCategory(); +				if (catp && include_folder_links) +				{ +					LL_DEBUGS("Avatar") << "linking inventory folder " << item->getName() << LL_ENDL; +					LLSD base_contents; +					base_contents["name"] = catp->getName(); +					base_contents["desc"] = ""; // categories don't have descriptions. +					base_contents["linked_id"] = catp->getLinkedUUID(); +					base_contents["type"] = LLAssetType::AT_LINK_FOLDER;  +					contents.append(base_contents); +				} +				break; +			} +			default: +			{ +				// Linux refuses to compile unless all possible enums are handled. Really, Linux? +				break; +			} +		} +	} +	slam_inventory_folder(dst_id, contents, cb); +}  // Copy contents of src_id to dst_id.  void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LLUUID& dst_id,  													  LLPointer<LLInventoryCallback> cb) @@ -1465,6 +1566,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  	LLInventoryModel::item_array_t* items;  	gInventory.getDirectDescendentsOf(src_id, cats, items);  	LL_INFOS() << "copying " << items->size() << " items" << LL_ENDL; +	LLInventoryObject::const_object_list_t link_array;  	for (LLInventoryModel::item_array_t::const_iterator iter = items->begin();  		 iter != items->end();  		 ++iter) @@ -1474,14 +1576,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() << LL_ENDL; +				link_array.push_back(LLConstPointer<LLInventoryObject>(item));  				break;  			}  			case LLAssetType::AT_LINK_FOLDER: @@ -1490,12 +1586,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() << LL_ENDL; +					link_array.push_back(LLConstPointer<LLInventoryObject>(item));  				}  				break;  			} @@ -1504,7 +1596,7 @@ void LLAppearanceMgr::shallowCopyCategoryContents(const LLUUID& src_id, const LL  			case LLAssetType::AT_BODYPART:  			case LLAssetType::AT_GESTURE:  			{ -				LL_INFOS() << "copying inventory item " << item->getName() << LL_ENDL; +				LL_DEBUGS("Avatar") << "copying inventory item " << item->getName() << LL_ENDL;  				copy_inventory_item(gAgent.getID(),  									item->getPermissions().getOwner(),  									item->getUUID(), @@ -1518,6 +1610,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 +1678,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 +1695,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 +1714,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 +1729,14 @@ void LLAppearanceMgr::purgeBaseOutfitLink(const LLUUID& category)  		LLViewerInventoryItem *item = items.at(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.size(); ++i) -	{ -		LLViewerInventoryItem *item = items.at(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) -			{ -				LL_INFOS() << "preserved item" << LL_ENDL; -			} -			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 +1761,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.size(); i++) -	{ -		const LLInventoryItem* item = items.at(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) +	{ +		LL_WARNS() << "no category found for id " << category << LL_ENDL; +		return; +	}  	LL_INFOS("Avatar") << self_av_string() << "starting, cat '" << (pcat ? pcat->getName() : "[UNKNOWN]") << "'" << LL_ENDL;  	const LLUUID cof = getCOF(); @@ -1748,7 +1777,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.size(); ++i)  		{  			LLViewerInventoryItem *gest_item = gest_items.at(i); @@ -1765,8 +1794,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 +1805,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 +1814,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 +1832,56 @@ void LLAppearanceMgr::updateCOF(const LLUUID& category, bool append)  	std::copy(obj_items.begin(), obj_items.end(), std::back_inserter(all_items));  	std::copy(gest_items.begin(), gest_items.end(), std::back_inserter(all_items)); +	// Find any wearables that need description set to enforce ordering. +	desc_map_t desc_map; +	getWearableOrderingDescUpdates(wear_items, desc_map); +  	// Will link all the above items. -	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() << ")" << LL_ENDL; +		} +		else +		{ +			desc = item->getActualDescription(); +		} + +		item_contents["name"] = item->getName(); +		item_contents["desc"] = desc; +		item_contents["linked_id"] = item->getLinkedUUID(); +		item_contents["type"] = LLAssetType::AT_LINK;  +		contents.append(item_contents); +	} +	const LLUUID& base_id = append ? getBaseOutfitUUID() : category; +	LLViewerInventoryCategory *base_cat = gInventory.getCategory(base_id); +	if (base_cat) +	{ +		LLSD base_contents; +		base_contents["name"] = base_cat->getName(); +		base_contents["desc"] = ""; +		base_contents["linked_id"] = base_cat->getLinkedUUID(); +		base_contents["type"] = LLAssetType::AT_LINK_FOLDER;  +		contents.append(base_contents); +	} +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +	{ +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_slam_request", contents); +	} +	slam_inventory_folder(getCOF(), contents, link_waiter);  	LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL;  } @@ -1840,21 +1902,20 @@ 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)  { -	LL_DEBUGS() << "updateAgentWearables()" << LL_ENDL; +	LL_DEBUGS("Avatar") << "updateAgentWearables()" << LL_ENDL;  	LLInventoryItem::item_array_t items;  	std::vector< LLViewerWearable* > wearables;  	wearables.reserve(32); @@ -1881,10 +1942,15 @@ void LLAppearanceMgr::updateAgentWearables(LLWearableHoldingPattern* holder, boo  	if(wearables.size() > 0)  	{ -		gAgentWearables.setWearableOutfit(items, wearables, !append); +		gAgentWearables.setWearableOutfit(items, wearables);  	}  } +S32 LLAppearanceMgr::countActiveHoldingPatterns() +{ +	return LLWearableHoldingPattern::countActive(); +} +  static void remove_non_link_items(LLInventoryModel::item_array_t &items)  {  	LLInventoryModel::item_array_t pruned_items; @@ -1933,12 +1999,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) @@ -1951,40 +2017,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)  	{ @@ -1992,19 +2057,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()) +	{ +		LL_WARNS() << "Clothing ordering error" << LL_ENDL; +	} + +	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(); @@ -2014,13 +2103,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. @@ -2028,7 +2111,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); @@ -2037,6 +2120,13 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	dumpItemArray(wear_items,"asset_dump: wear_item");  	dumpItemArray(obj_items,"asset_dump: obj_item"); +	LLViewerInventoryCategory *cof = gInventory.getCategory(current_outfit_id); +	if (!gInventory.isCategoryComplete(current_outfit_id)) +	{ +		LL_WARNS() << "COF info is not complete. Version " << cof->getVersion() +				<< " descendent_count " << cof->getDescendentCount() +				<< " viewer desc count " << cof->getViewerDescendentCount() << LL_ENDL; +	}  	if(!wear_items.size())  	{  		LLNotificationsUtil::add("CouldNotPutOnOutfit"); @@ -2047,6 +2137,8 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering)  	sortItemsByActualDescription(wear_items); +	LL_DEBUGS("Avatar") << "HP block starts" << LL_ENDL; +	LLTimer hp_block_timer;  	LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;  	holder->setObjItems(obj_items); @@ -2096,7 +2188,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) @@ -2120,12 +2212,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() << LL_ENDL;  }  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); @@ -2133,15 +2227,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; @@ -2149,8 +2241,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 ); @@ -2158,8 +2249,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; @@ -2168,8 +2258,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) @@ -2184,10 +2273,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) @@ -2268,7 +2383,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() )  	{ @@ -2288,6 +2403,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; @@ -2341,9 +2457,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)  	{ @@ -2359,14 +2474,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;  }; @@ -2374,42 +2488,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)  	{ @@ -2449,43 +2547,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 (do_update) -		{	 -			LLAppearanceMgr::updateAppearanceFromCOF(); -		} -		return; -	} -	else +	if (!linked_already)  	{ -		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) @@ -2515,6 +2593,12 @@ LLInventoryModel::item_array_t LLAppearanceMgr::findCOFItemLinks(const LLUUID& i  	return result;  } +bool LLAppearanceMgr::isLinkedInCOF(const LLUUID& item_id) +{ +	LLInventoryModel::item_array_t links = LLAppearanceMgr::instance().findCOFItemLinks(item_id); +	return links.size() > 0; +} +  void LLAppearanceMgr::removeAllClothesFromAvatar()  {  	// Fetch worn clothes (i.e. the ones in COF). @@ -2525,8 +2609,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) @@ -2570,7 +2653,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); @@ -2585,12 +2668,12 @@ void LLAppearanceMgr::removeCOFItemLinks(const LLUUID& item_id)  		const LLInventoryItem* item = item_array.at(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; @@ -2603,7 +2686,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);  		}  	}  } @@ -2642,7 +2725,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; @@ -2656,6 +2739,7 @@ void LLAppearanceMgr::updateIsDirty()  		if(outfit_items.size() != cof_items.size())  		{ +			LL_DEBUGS("Avatar") << "item count different - base " << outfit_items.size() << " cof " << cof_items.size() << LL_ENDL;  			// Current outfit folder should have one more item than the outfit folder.  			// this one item is the link back to the outfit folder itself.  			mOutfitIsDirty = true; @@ -2675,11 +2759,30 @@ void LLAppearanceMgr::updateIsDirty()  				item1->getName() != item2->getName() ||  				item1->getActualDescription() != item2->getActualDescription())  			{ +				if (item1->getLinkedUUID() != item2->getLinkedUUID()) +				{ +					LL_DEBUGS("Avatar") << "link id different " << LL_ENDL; +				} +				else +				{ +					if (item1->getName() != item2->getName()) +					{ +						LL_DEBUGS("Avatar") << "name different " << item1->getName() << " " << item2->getName() << LL_ENDL; +					} +					if (item1->getActualDescription() != item2->getActualDescription()) +					{ +						LL_DEBUGS("Avatar") << "desc different " << item1->getActualDescription() +											<< " " << item2->getActualDescription()  +											<< " names " << item1->getName() << " " << item2->getName() << LL_ENDL; +					} +				}  				mOutfitIsDirty = true;  				return;  			}  		}  	} +	llassert(!mOutfitIsDirty); +	LL_DEBUGS("Avatar") << "clean" << LL_ENDL;  }  // *HACK: Must match name in Library or agent inventory @@ -2761,23 +2864,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()  { @@ -2785,10 +2871,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()) { @@ -2803,9 +2885,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()) @@ -2814,23 +2914,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 << LL_ENDL; -	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;  } @@ -2878,12 +2975,6 @@ struct WearablesOrderComparator  	bool operator()(const LLInventoryItem* item1, const LLInventoryItem* item2)  	{ -		if (!item1 || !item2) -		{ -			LL_WARNS() << "either item1 or item2 is NULL" << LL_ENDL; -			return true; -		} -		  		const std::string& desc1 = item1->getActualDescription();  		const std::string& desc2 = item2->getActualDescription(); @@ -2897,260 +2988,373 @@ 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); +		LL_WARNS() << "Order validation fails: " << item->getName() +				<< " needs to update desc to: " << new_order_str +				<< " (from: " << item->getActualDescription() << ")" << LL_ENDL;  	} -}; +	 +	return desc_map.size() == 0; +} -// 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() << ")" << LL_ENDL; +		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 << LL_ENDL; +	if ((mInFlightCounter>0) && (mInFlightTimer.hasExpired()))  	{ -		mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10); +		LL_WARNS("Avatar") << "in flight timer expired, resetting " << LL_ENDL; +		mInFlightCounter = 0; +	} +	if (cof_version < last_rcv) +	{ +		LL_DEBUGS("Avatar") << "Have already received update for cof version " << last_rcv +							<< " will not request for " << cof_version << LL_ENDL; +		return; +	} +	if (mInFlightCounter>0 && last_req >= cof_version) +	{ +		LL_DEBUGS("Avatar") << "Request already in flight for cof version " << last_req  +							<< " will not request for " << cof_version << LL_ENDL; +		return;  	} -	virtual ~RequestAgentUpdateAppearanceResponder() +	// Actually send the request. +	LL_DEBUGS("Avatar") << "Will send request for cof_version " << cof_version << LL_ENDL; +	mRetryPolicy->reset(); +	sendRequest(); +} +	 +void RequestAgentUpdateAppearanceResponder::sendRequest() +{ +	if (gAgentAvatarp->isEditingAppearance())   	{ +		// don't send out appearance updates if in appearance editing mode +		return;  	} -	// Successful completion. -	/* virtual */ void result(const LLSD& content) +	if (!gAgent.getRegion())  	{ -		LL_DEBUGS("Avatar") << "content: " << ll_pretty_print_sd(content) << LL_ENDL; -		if (content["success"].asBoolean()) +		LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; +		return; +	} +	if (gAgent.getRegion()->getCentralBakeVersion()==0) +	{ +		LL_WARNS() << "Region does not support baking" << LL_ENDL; +	} +	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 +	if (url.empty()) +	{ +		LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; +		return; +	} +	 +	LLSD body; +	S32 cof_version = LLAppearanceMgr::instance().getCOFVersion(); +	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate")) +	{ +		body = LLAppearanceMgr::instance().dumpCOF(); +	} +	else +	{ +		body["cof_version"] = cof_version; +		if (gSavedSettings.getBOOL("DebugForceAppearanceRequestFailure"))  		{ -			LL_DEBUGS("Avatar") << "OK" << LL_ENDL; -			if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +			body["cof_version"] = cof_version+999; +		} +	} +	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << LL_ENDL; + +	mInFlightCounter++; +	mInFlightTimer.setTimerExpirySec(60.0); +	LLHTTPClient::post(url, body, this); +	llassert(cof_version >= gAgentAvatarp->mLastUpdateRequestCOFVersion); +	gAgentAvatarp->mLastUpdateRequestCOFVersion = cof_version; +} + +void RequestAgentUpdateAppearanceResponder::debugCOF(const LLSD& content) +{ +	LL_INFOS("Avatar") << "AIS COF, version received: " << content["expected"].asInteger() +					   << " ================================= " << LL_ENDL; +	std::set<LLUUID> ais_items, local_items; +	const LLSD& cof_raw = content["cof_raw"]; +	for (LLSD::array_const_iterator it = cof_raw.beginArray(); +		 it != cof_raw.endArray(); ++it) +	{ +		const LLSD& item = *it; +		if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) +		{ +			ais_items.insert(item["item_id"].asUUID()); +			if (item["type"].asInteger() == 24) // link +			{ +				LL_INFOS("Avatar") << "AIS Link: item_id: " << item["item_id"].asUUID() +								   << " linked_item_id: " << item["asset_id"].asUUID() +								   << " name: " << item["name"].asString() +								   << LL_ENDL;  +			} +			else if (item["type"].asInteger() == 25) // folder link +			{ +				LL_INFOS("Avatar") << "AIS Folder link: item_id: " << item["item_id"].asUUID() +								   << " linked_item_id: " << item["asset_id"].asUUID() +								   << " name: " << item["name"].asString() +								   << LL_ENDL;  +			} +			else  			{ -				dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_ok", content); +				LL_INFOS("Avatar") << "AIS Other: item_id: " << item["item_id"].asUUID() +								   << " linked_item_id: " << item["asset_id"].asUUID() +								   << " name: " << item["name"].asString() +								   << " type: " << item["type"].asInteger() +								   << LL_ENDL;   			}  		} -		else +	} +	LL_INFOS("Avatar") << LL_ENDL; +	LL_INFOS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger()  +					   << " ================================= " << LL_ENDL; +	LLInventoryModel::cat_array_t cat_array; +	LLInventoryModel::item_array_t item_array; +	gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), +								  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); +	for (S32 i=0; i<item_array.size(); i++) +	{ +		const LLViewerInventoryItem* inv_item = item_array.at(i).get(); +		local_items.insert(inv_item->getUUID()); +		LL_INFOS("Avatar") << "LOCAL: item_id: " << inv_item->getUUID() +						   << " linked_item_id: " << inv_item->getLinkedUUID() +						   << " name: " << inv_item->getName() +						   << " parent: " << inv_item->getParentUUID() +						   << LL_ENDL; +	} +	LL_INFOS("Avatar") << " ================================= " << LL_ENDL; +	S32 local_only = 0, ais_only = 0; +	for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) +	{ +		if (ais_items.find(*it) == ais_items.end())  		{ -			onFailure(200); +			LL_INFOS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; +			local_only++;  		}  	} - -	// Error -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it)  	{ -		LL_WARNS() << "appearance update request failed, status: " << status << " reason: " << reason << " code: " << content["code"].asInteger() << " error: \"" << content["error"].asString() << "\"" << LL_ENDL; -		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage")) +		if (local_items.find(*it) == local_items.end())  		{ -			dumpContents(gAgentAvatarp->getFullname() + "_appearance_request_error", content); -			debugCOF(content); -		 +			LL_INFOS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; +			ais_only++;  		} -		onFailure(status); -	}	 +	} +	if (local_only==0 && ais_only==0) +	{ +		LL_INFOS("Avatar") << "COF contents identical, only version numbers differ (req " +						   << content["observed"].asInteger() +						   << " rcv " << content["expected"].asInteger() +						   << ")" << LL_ENDL; +	} +} -	void onFailure(U32 status) +/* virtual */ void RequestAgentUpdateAppearanceResponder::httpSuccess() +{ +	const LLSD& content = getContent(); +	if (!content.isMap())  	{ -		F32 seconds_to_wait; -		if (mRetryPolicy->shouldRetry(status,seconds_to_wait)) -		{ -			LL_INFOS() << "retrying" << LL_ENDL; -			doAfterInterval(boost::bind(&LLAppearanceMgr::requestServerAppearanceUpdate, -										LLAppearanceMgr::getInstance(), -										LLCurl::ResponderPtr(this)), -							seconds_to_wait); -		} -		else +		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content); +		return; +	} +	if (content["success"].asBoolean()) +	{ +		LL_DEBUGS("Avatar") << "succeeded" << LL_ENDL; +		if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))  		{ -			LL_WARNS() << "giving up after too many retries" << LL_ENDL; +			dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_ok", content);  		} -	}	 -	void dumpContents(const std::string outprefix, const LLSD& content) +		onSuccess(); +	} +	else  	{ -		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; +		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; -	void debugCOF(const LLSD& content) +	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))  	{ -		LL_DEBUGS("Avatar") << "AIS COF, version found: " << content["expected"].asInteger() << LL_ENDL; -		std::set<LLUUID> ais_items, local_items; -		const LLSD& cof_raw = content["cof_raw"]; -		for (LLSD::array_const_iterator it = cof_raw.beginArray(); -			 it != cof_raw.endArray(); ++it) -		{ -			const LLSD& item = *it; -			if (item["parent_id"].asUUID() == LLAppearanceMgr::instance().getCOF()) -			{ -				ais_items.insert(item["item_id"].asUUID()); -				if (item["type"].asInteger() == 24) // link -				{ -					LL_DEBUGS("Avatar") << "Link: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< LL_ENDL;  -				} -				else if (item["type"].asInteger() == 25) // folder link -				{ -					LL_DEBUGS("Avatar") << "Folder link: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< LL_ENDL;  -					 -				} -				else -				{ -					LL_DEBUGS("Avatar") << "Other: item_id: " << item["item_id"].asUUID() -										<< " linked_item_id: " << item["asset_id"].asUUID() -										<< " name: " << item["name"].asString() -										<< LL_ENDL;  -				} -			} -		} -		LL_DEBUGS("Avatar") << LL_ENDL; -		LL_DEBUGS("Avatar") << "Local COF, version requested: " << content["observed"].asInteger() << LL_ENDL; -		LLInventoryModel::cat_array_t cat_array; -		LLInventoryModel::item_array_t item_array; -		gInventory.collectDescendents(LLAppearanceMgr::instance().getCOF(), -									  cat_array,item_array,LLInventoryModel::EXCLUDE_TRASH); -		for (S32 i=0; i<item_array.size(); i++) -		{ -			const LLViewerInventoryItem* inv_item = item_array.at(i).get(); -			local_items.insert(inv_item->getUUID()); -			LL_DEBUGS("Avatar") << "item_id: " << inv_item->getUUID() -								<< " linked_item_id: " << inv_item->getLinkedUUID() -								<< " name: " << inv_item->getName() -								<< LL_ENDL; -		} -		LL_DEBUGS("Avatar") << LL_ENDL; -		for (std::set<LLUUID>::iterator it = local_items.begin(); it != local_items.end(); ++it) -		{ -			if (ais_items.find(*it) == ais_items.end()) -			{ -				LL_DEBUGS("Avatar") << "LOCAL ONLY: " << *it << LL_ENDL; -			} -		} -		for (std::set<LLUUID>::iterator it = ais_items.begin(); it != ais_items.end(); ++it) -		{ -			if (local_items.find(*it) == local_items.end()) -			{ -				LL_DEBUGS("Avatar") << "AIS ONLY: " << *it << LL_ENDL; -			} -		} +		const LLSD& content = getContent(); +		dump_sequential_xml(gAgentAvatarp->getFullname() + "_appearance_request_error", content); +		debugCOF(content);  	} +	onFailure(); +} + +void RequestAgentUpdateAppearanceResponder::onFailure() +{ +	mInFlightCounter = llmax(mInFlightCounter-1,0); + +	F32 seconds_to_wait; +	mRetryPolicy->onFailure(getStatus(), getResponseHeaders()); +	if (mRetryPolicy->shouldRetry(seconds_to_wait)) +	{ +		LL_INFOS() << "retrying" << LL_ENDL; +		doAfterInterval(boost::bind(&RequestAgentUpdateAppearanceResponder::sendRequest,this), +						seconds_to_wait); +	} +	else +	{ +		LL_WARNS() << "giving up after too many retries" << LL_ENDL; +	} +}	 -	LLPointer<LLHTTPRetryPolicy> mRetryPolicy; -};  LLSD LLAppearanceMgr::dumpCOF() const  { @@ -3215,58 +3419,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()) -	{ -		LL_WARNS() << "Region not set, cannot request server appearance update" << LL_ENDL; -		return; -	} -	if (gAgent.getRegion()->getCentralBakeVersion()==0) -	{ -		LL_WARNS() << "Region does not support baking" << LL_ENDL; -	} -	std::string url = gAgent.getRegion()->getCapability("UpdateAvatarAppearance");	 -	if (url.empty()) -	{ -		LL_WARNS() << "No cap for UpdateAvatarAppearance." << LL_ENDL; -		return; -	} - -	LLSD body; -	S32 cof_version = 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 << LL_ENDL; - -	//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()  	{ @@ -3277,22 +3437,31 @@ public:  	{  	} -	virtual void result(const LLSD &pContent) +protected: +	virtual void httpSuccess()  	{  		LL_INFOS() << "Successfully incremented agent's COF." << LL_ENDL; -		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()  	{ -		LL_WARNS() << "While attempting to increment the agent's cof we got an error with [status:" -				<< pStatus << "]: " << content << LL_ENDL; +		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))  		{  			LL_INFOS() << "retrying" << LL_ENDL;  			doAfterInterval(boost::bind(&LLAppearanceMgr::incrementCofVersion, @@ -3306,6 +3475,7 @@ public:  		}  	} +private:  	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;  }; @@ -3338,6 +3508,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()) @@ -3348,57 +3527,91 @@ std::string LLAppearanceMgr::getAppearanceServiceURL() const  }  void show_created_outfit(LLUUID& folder_id, bool show_panel = true) +{ +	if (!LLApp::isRunning())  	{ -		if (!LLApp::isRunning()) -		{ -			LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; -			return; -		} - -		LLSD key; -		 +		LL_WARNS() << "called during shutdown, skipping" << LL_ENDL; +		return; +	} +	 +	LL_DEBUGS("Avatar") << "called" << LL_ENDL; +	LLSD key; +	  	//EXT-7727. For new accounts inventory callback is created during login process  	// and may be processed after login process is finished  	if (show_panel) -		{ -			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" << LL_ENDL; +		LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key); +		 +	} +	LLOutfitsList *outfits_list = +		dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab")); +	if (outfits_list) +	{  		outfits_list->setSelectedOutfitByUUID(folder_id); -		} - -		LLAppearanceMgr::getInstance()->updateIsDirty(); -		gAgentWearables.notifyLoadingFinished(); // New outfit is saved. -		LLAppearanceMgr::getInstance()->updatePanelOutfitName("");  	} +	 +	LLAppearanceMgr::getInstance()->updateIsDirty(); +	gAgentWearables.notifyLoadingFinished(); // New outfit is saved. +	LLAppearanceMgr::getInstance()->updatePanelOutfitName(""); + +	// For SSB, need to update appearance after we add a base outfit +	// link, since, the COF version has changed. There is a race +	// condition in initial outfit setup which can lead to rez +	// failures - SH-3860. +	LL_DEBUGS("Avatar") << "requesting appearance update after createBaseOutfitLink" << LL_ENDL; +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +	LLAppearanceMgr::getInstance()->createBaseOutfitLink(folder_id, cb); +} -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" << LL_ENDL; -	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() @@ -3414,23 +3627,24 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)  	if (ids_to_remove.empty())  	{  		LL_WARNS() << "called with empty list, nothing to do" << LL_ENDL; +		return;  	} +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy;  	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)  	{  		const LLUUID& id_to_remove = *it;  		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove); -		removeCOFItemLinks(linked_item_id); +		removeCOFItemLinks(linked_item_id, cb);  		addDoomedTempAttachment(linked_item_id);  	} -	updateAppearanceFromCOF();  }  void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)  {  	LLUUID linked_item_id = gInventory.getLinkedItemID(id_to_remove); -	removeCOFItemLinks(linked_item_id); +	LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy; +	removeCOFItemLinks(linked_item_id, cb);  	addDoomedTempAttachment(linked_item_id); -	updateAppearanceFromCOF();  } @@ -3490,7 +3704,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()) << LL_ENDL; +	// FIXME switch to use AISv3 where supported.  	//items need to be updated on a dataserver  	item->setComplete(TRUE);  	item->updateServer(FALSE); @@ -3504,7 +3723,7 @@ bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_b  	bool result = false;  	if (result = gAgentWearables.moveWearable(item, closer_to_body))  	{ -		gAgentAvatarp->wearableUpdated(item->getWearableType(), FALSE); +		gAgentAvatarp->wearableUpdated(item->getWearableType());  	}  	setOutfitDirty(true); @@ -3566,7 +3785,8 @@ LLAppearanceMgr::LLAppearanceMgr():  	mAttachmentInvLinkEnabled(false),  	mOutfitIsDirty(false),  	mOutfitLocked(false), -	mIsInUpdateAppearanceFromCOF(false) +	mIsInUpdateAppearanceFromCOF(false), +	mAppearanceResponder(new RequestAgentUpdateAppearanceResponder)  {  	LLOutfitObserver& outfit_observer = LLOutfitObserver::instance(); @@ -3616,7 +3836,11 @@ 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. +		   if (!isLinkedInCOF(item_id)) +		   { +			   LLPointer<LLInventoryCallback> cb = new LLUpdateAppearanceOnDestroy(); +			   LLAppearanceMgr::addCOFItemLink(item_id, cb);  // Add COF link for item. +		   }  	   }  	   else  	   { @@ -3640,22 +3864,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 @@ -3672,18 +3895,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 @@ -3824,7 +4035,7 @@ public:  			LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);  			// *TODOw: This may not be necessary if initial outfit is chosen already -- josh -			gAgent.setGenderChosen(TRUE); +			gAgent.setOutfitChosen(TRUE);  		}  		// release avatar picker keyboard focus diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index b5ef0bd935..7742a19c07 100755 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -39,6 +39,7 @@  class LLWearableHoldingPattern;  class LLInventoryCallback;  class LLOutfitUnLockTimer; +class RequestAgentUpdateAppearanceResponder;  class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>  { @@ -50,7 +51,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); @@ -65,9 +68,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); @@ -106,15 +118,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); @@ -125,21 +140,17 @@ 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); +	bool isLinkedInCOF(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(); @@ -156,12 +167,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(); @@ -176,7 +186,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); @@ -185,18 +198,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(); @@ -217,24 +239,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. @@ -266,17 +285,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/llappviewer.cpp b/indra/newview/llappviewer.cpp index f98ec69732..f52e6625c1 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2019,6 +2019,9 @@ bool LLAppViewer::cleanup()  	// Non-LLCurl libcurl library  	mAppCoreHttp.cleanup(); +	// NOTE The following call is not thread safe.  +	ll_cleanup_ares(); +  	LLFilePickerThread::cleanupClass();  	//MUST happen AFTER LLCurl::cleanupClass @@ -2114,6 +2117,8 @@ bool LLAppViewer::cleanup()  	ll_close_fail_log(); +	LLError::LLCallStacks::cleanup(); +  	removeMarkerFiles();      LL_INFOS() << "Goodbye!" << LL_ENDL; diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 06f081e920..57fb84bbf1 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -438,7 +438,7 @@ void LLAppViewerWin32::disableWinErrorReporting()  const S32 MAX_CONSOLE_LINES = 500; -void create_console() +static bool create_console()  {  	int h_con_handle;  	long l_std_handle; @@ -447,7 +447,7 @@ void create_console()  	FILE *fp;  	// allocate a console for this app -	AllocConsole(); +	const bool isConsoleAllocated = AllocConsole();  	// set the screen buffer to be big enough to let us scroll text  	GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); @@ -495,10 +495,13 @@ void create_console()  		*stderr = *fp;  		setvbuf( stderr, NULL, _IONBF, 0 );  	} + +    return isConsoleAllocated;  }  LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) : -    mCmdLine(cmd_line) +	mCmdLine(cmd_line), +	mIsConsoleAllocated(false)  {  } @@ -542,6 +545,16 @@ bool LLAppViewerWin32::cleanup()  	gDXHardware.cleanup(); +#ifndef LL_RELEASE_FOR_DOWNLOAD +	LLWinDebug::instance().cleanup(); +#endif + +	if (mIsConsoleAllocated) +	{ +		FreeConsole(); +		mIsConsoleAllocated = false; +	} +  	return result;  } @@ -553,7 +566,7 @@ void LLAppViewerWin32::initLoggingAndGetLastDuration()  void LLAppViewerWin32::initConsole()  {  	// pop up debug console -	create_console(); +	mIsConsoleAllocated = create_console();  	return LLAppViewer::initConsole();  } diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index fb37df1a2f..59d1ddaa3d 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -61,7 +61,8 @@ protected:  private:  	void disableWinErrorReporting(); -    std::string mCmdLine; +	std::string mCmdLine; +	bool mIsConsoleAllocated;  };  #endif // LL_LLAPPVIEWERWIN32_H diff --git a/indra/newview/llassetuploadqueue.cpp b/indra/newview/llassetuploadqueue.cpp index 2b428aec4b..8833c57948 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) -   	{ -		LL_WARNS() << "LLAssetUploadChainResponder Error [status:"  -				<< statusNum << "]: " << content << LL_ENDL; -		LLUpdateTaskInventoryResponder::errorWithContent(statusNum, reason, content); -   		LLAssetUploadQueue *queue = mSupplier->get(); -   		if (queue) +protected: +	virtual void httpFailure() +	{ +		// Parent class will spam the failure. +		//LL_WARNS() << dumpResponse() << LL_ENDL; +		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 d86e63589f..a98ff64d0a 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()  { -	LL_INFOS() << "LLAssetUploadResponder::error [status:"  -			<< statusNum << "]: " << content << LL_ENDL; +	// *TODO: Add adaptive retry policy? +	LL_WARNS() << dumpResponse() << LL_ENDL;  	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; +	}  	LL_DEBUGS() << "LLAssetUploadResponder::result from capabilities" << LL_ENDL; -	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)  { +	LL_WARNS() << dumpResponse() << LL_ENDL;  	// 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);  } @@ -445,58 +450,6 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)  	//LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);  } -LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, -												 const LLUUID& vfile_id, -												 LLAssetType::EType asset_type, -												 LLBakedUploadData * baked_upload_data) :  -	LLAssetUploadResponder(post_data, vfile_id, asset_type), -	mBakedUploadData(baked_upload_data) -{ -} - -LLSendTexLayerResponder::~LLSendTexLayerResponder() -{ -	// mBakedUploadData is normally deleted by calls to LLViewerTexLayerSetBuffer::onTextureUploadComplete() below -	if (mBakedUploadData) -	{	// ...but delete it in the case where uploadComplete() is never called -		delete mBakedUploadData; -		mBakedUploadData = NULL; -	} -} - - -// Baked texture upload completed -void LLSendTexLayerResponder::uploadComplete(const LLSD& content) -{ -	LLUUID item_id = mPostData["item_id"]; - -	std::string result = content["state"]; -	LLUUID new_id = content["new_asset"]; - -	LL_INFOS() << "result: " << result << " new_id: " << new_id << LL_ENDL; -	if (result == "complete" -		&& mBakedUploadData != NULL) -	{	// Invoke  -		LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, 0, LL_EXSTAT_NONE); -		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete() -	} -	else -	{	// Invoke the original callback with an error result -		LLViewerTexLayerSetBuffer::onTextureUploadComplete(new_id, (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); -		mBakedUploadData = NULL;	// deleted in onTextureUploadComplete() -	} -} - -void LLSendTexLayerResponder::errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) -{ -	LL_INFOS() << "LLSendTexLayerResponder error [status:" -			<< statusNum << "]: " << content << LL_ENDL; -	 -	// Invoke the original callback with an error result -	LLViewerTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE); -	mBakedUploadData = NULL;	// deleted in onTextureUploadComplete() -} -  LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(  	const LLSD& post_data,  	const LLUUID& vfile_id, @@ -1009,19 +962,14 @@ LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResp  	delete mImpl;  } -void LLNewAgentInventoryVariablePriceResponder::errorWithContent( -	U32 statusNum, -	const std::string& reason, -	const LLSD& content) +void LLNewAgentInventoryVariablePriceResponder::httpFailure()  { -	LL_DEBUGS()  -		<< "LLNewAgentInventoryVariablePrice::error " << statusNum  -		<< " reason: " << reason << LL_ENDL; +	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 +978,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 +1001,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 +1045,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..7fbebc7481 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( @@ -109,24 +116,6 @@ private:  	Impl* mImpl;  }; -struct LLBakedUploadData; -class LLSendTexLayerResponder : public LLAssetUploadResponder -{ -	LOG_CLASS(LLSendTexLayerResponder); -public: -	LLSendTexLayerResponder(const LLSD& post_data, -							const LLUUID& vfile_id, -							LLAssetType::EType asset_type, -							LLBakedUploadData * baked_upload_data); - -	~LLSendTexLayerResponder(); - -	virtual void uploadComplete(const LLSD& content); -	virtual void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content); - -	LLBakedUploadData * mBakedUploadData; -}; -  class LLUpdateAgentInventoryResponder : public LLAssetUploadResponder  {  public: diff --git a/indra/newview/llbreastmotion.cpp b/indra/newview/llbreastmotion.cpp index 9a8cd5ceae..3a88bab3b3 100755 --- a/indra/newview/llbreastmotion.cpp +++ b/indra/newview/llbreastmotion.cpp @@ -340,8 +340,7 @@ BOOL LLBreastMotion::onUpdate(F32 time, U8* joint_mask)  		if (mBreastParamsDriven[i])  		{  			mCharacter->setVisualParamWeight(mBreastParamsDriven[i], -											 new_local_pt[i], -											 FALSE); +											 new_local_pt[i]);  		}  	} diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 05c4181714..84b9ac756a 100755 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -107,6 +107,7 @@ class LLChatHistoryHeader: public LLPanel  public:  	LLChatHistoryHeader()  	:	LLPanel(), +		mInfoCtrl(NULL),  		mPopupMenuHandleAvatar(),  		mPopupMenuHandleObject(),  		mAvatarID(), @@ -129,9 +130,6 @@ public:  	~LLChatHistoryHeader()  	{ -		// Detach the info button so that it doesn't get destroyed (EXT-8463). -		hideInfoCtrl(); -  		if (mAvatarNameCacheConnection.connected())  		{  			mAvatarNameCacheConnection.disconnect(); @@ -292,6 +290,11 @@ public:  		mUserNameTextBox = getChild<LLTextBox>("user_name");  		mTimeBoxTextBox = getChild<LLTextBox>("time_box"); +		mInfoCtrl = LLUICtrlFactory::getInstance()->createFromFile<LLUICtrl>("inspector_info_ctrl.xml", this, LLPanel::child_registry_t::instance()); +		llassert(mInfoCtrl != NULL); +		mInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, mInfoCtrl)); +		mInfoCtrl->setVisible(FALSE); +  		return LLPanel::postBuild();  	} @@ -589,39 +592,19 @@ protected:  	void showInfoCtrl()  	{ -		if (mAvatarID.isNull() || mFrom.empty() || CHAT_SOURCE_SYSTEM == mSourceType) return; -				 -		if (!sInfoCtrl) -		{ -			// *TODO: Delete the button at exit. -			sInfoCtrl = LLUICtrlFactory::createFromFile<LLUICtrl>("inspector_info_ctrl.xml", NULL, LLPanel::child_registry_t::instance()); -			if (sInfoCtrl) -			{ -				sInfoCtrl->setCommitCallback(boost::bind(&LLChatHistoryHeader::onClickInfoCtrl, sInfoCtrl)); -			} -		} - -		if (!sInfoCtrl) +		const bool isVisible = !mAvatarID.isNull() && !mFrom.empty() && CHAT_SOURCE_SYSTEM != mSourceType; +		if (isVisible)  		{ -			llassert(sInfoCtrl != NULL); -			return; +			const LLRect sticky_rect = mUserNameTextBox->getRect(); +			S32 icon_x = llmin(sticky_rect.mLeft + mUserNameTextBox->getTextBoundingRect().getWidth() + 7, sticky_rect.mRight - 3); +			mInfoCtrl->setOrigin(icon_x, sticky_rect.getCenterY() - mInfoCtrl->getRect().getHeight() / 2 ) ;  		} - -		LLTextBox* name = getChild<LLTextBox>("user_name"); -		LLRect sticky_rect = name->getRect(); -		S32 icon_x = llmin(sticky_rect.mLeft + name->getTextBoundingRect().getWidth() + 7, sticky_rect.mRight - 3); -		sInfoCtrl->setOrigin(icon_x, sticky_rect.getCenterY() - sInfoCtrl->getRect().getHeight() / 2 ) ; -		addChild(sInfoCtrl); +		mInfoCtrl->setVisible(isVisible);  	}  	void hideInfoCtrl()  	{ -		if (!sInfoCtrl) return; - -		if (sInfoCtrl->getParent() == this) -		{ -			removeChild(sInfoCtrl); -		} +		mInfoCtrl->setVisible(FALSE);  	}  private: @@ -692,7 +675,7 @@ protected:  	LLHandle<LLView>	mPopupMenuHandleAvatar;  	LLHandle<LLView>	mPopupMenuHandleObject; -	static LLUICtrl*	sInfoCtrl; +	LLUICtrl*			mInfoCtrl;  	LLUUID			    mAvatarID;  	LLSD				mObjectData; @@ -709,8 +692,6 @@ private:  	boost::signals2::connection mAvatarNameCacheConnection;  }; -LLUICtrl* LLChatHistoryHeader::sInfoCtrl = NULL; -  LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)  :	LLUICtrl(p),  	mMessageHeaderFilename(p.message_header), diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index bb6d4fb59c..44736a0489 100755 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -93,14 +93,15 @@ class LLChatHistory : public LLUICtrl  		 * @return pointer to LLView separator object.  		 */  		LLView* getSeparator(); + +		void onClickMoreText(); + +	private:  		/**  		 * Builds a message header.  		 * @return pointer to LLView header object.  		 */  		LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args); - -		void onClickMoreText(); -  	public:  		~LLChatHistory();  		LLSD getValue() const;    diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp index fd4f17b694..cfc62c07b6 100755 --- a/indra/newview/llchatitemscontainerctrl.cpp +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -29,7 +29,6 @@  #include "llchatitemscontainerctrl.h"  #include "lltextbox.h" -#include "llchatmsgbox.h"  #include "llavatariconctrl.h"  #include "llcommandhandler.h"  #include "llfloaterreg.h" @@ -130,7 +129,6 @@ void LLFloaterIMNearbyChatToastPanel::addMessage(LLSD& notification)  {  	std::string		messageText = notification["message"].asString();		// UTF-8 line of text -	LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false);  	std::string color_name = notification["text_color"].asString(); @@ -171,7 +169,7 @@ void LLFloaterIMNearbyChatToastPanel::addMessage(LLSD& notification)  		{  			style_params.font.style = "ITALIC";  		} -		msg_text->appendText(messageText, TRUE, style_params); +		mMsgText->appendText(messageText, TRUE, style_params);  	}  	snapToMessageHeight(); @@ -204,9 +202,10 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)  		case 2:	messageFont = LLFontGL::getFontSansSerifBig();	break;  	} -	LLChatMsgBox* msg_text = getChild<LLChatMsgBox>("msg_text", false); +	mMsgText = getChild<LLChatMsgBox>("msg_text", false); +	mMsgText->setContentTrusted(false); -	msg_text->setText(std::string("")); +	mMsgText->setText(std::string(""));  	if ( notification["chat_style"].asInteger() != CHAT_STYLE_IRC )  	{ @@ -232,12 +231,12 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)  			style_params_name.link_href = notification["sender_slurl"].asString();  			style_params_name.is_link = true; -			msg_text->appendText(str_sender, FALSE, style_params_name); +			mMsgText->appendText(str_sender, FALSE, style_params_name);  		}  		else  		{ -			msg_text->appendText(str_sender, false); +			mMsgText->appendText(str_sender, false);  		}  	} @@ -264,7 +263,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)  		{  			style_params.font.style = "ITALIC";  		} -		msg_text->appendText(messageText, FALSE, style_params); +		mMsgText->appendText(messageText, FALSE, style_params);  	} @@ -275,8 +274,7 @@ void LLFloaterIMNearbyChatToastPanel::init(LLSD& notification)  void	LLFloaterIMNearbyChatToastPanel::snapToMessageHeight	()  { -	LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); -	S32 new_height = llmax (text_box->getTextPixelHeight() + 2*text_box->getVPad() + 2*msg_height_pad, 25); +	S32 new_height = llmax (mMsgText->getTextPixelHeight() + 2*mMsgText->getVPad() + 2*msg_height_pad, 25);  	LLRect panel_rect = getRect(); @@ -312,14 +310,13 @@ BOOL	LLFloaterIMNearbyChatToastPanel::handleMouseUp	(S32 x, S32 y, MASK mask)  		return LLPanel::handleMouseUp(x,y,mask);      */ -	LLChatMsgBox* text_box = getChild<LLChatMsgBox>("msg_text", false); -	S32 local_x = x - text_box->getRect().mLeft; -	S32 local_y = y - text_box->getRect().mBottom; +	S32 local_x = x - mMsgText->getRect().mLeft; +	S32 local_y = y - mMsgText->getRect().mBottom;  	//if text_box process mouse up (ussually this is click on url) - we didn't show nearby_chat. -	if (text_box->pointInView(local_x, local_y) ) +	if (mMsgText->pointInView(local_x, local_y) )  	{ -		if (text_box->handleMouseUp(local_x,local_y,mask) == TRUE) +		if (mMsgText->handleMouseUp(local_x,local_y,mask) == TRUE)  			return TRUE;  		else  		{ diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h index 54b6499d52..f66670ec8c 100755 --- a/indra/newview/llchatitemscontainerctrl.h +++ b/indra/newview/llchatitemscontainerctrl.h @@ -28,6 +28,7 @@  #define LL_LLCHATITEMSCONTAINERCTRL_H_  #include "llchat.h" +#include "llchatmsgbox.h"  #include "llpanel.h"  #include "llscrollbar.h"  #include "llviewerchat.h" @@ -85,6 +86,7 @@ private:  	LLUUID			mFromID;	// agent id or object id  	std::string		mFromName;  	EChatSourceType	mSourceType; +	LLChatMsgBox* 	mMsgText; diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp index b1dce42dfd..c0823182c0 100755 --- a/indra/newview/llchiclet.cpp +++ b/indra/newview/llchiclet.cpp @@ -204,6 +204,7 @@ void LLNotificationChiclet::createMenu()  	enable_registrar.add("NotificationWellChicletMenu.EnableItem",  		boost::bind(&LLNotificationChiclet::enableMenuItem, this, _2)); +	llassert(LLMenuGL::sMenuContainer != NULL);  	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>  		("menu_notification_well_button.xml",  		 LLMenuGL::sMenuContainer, diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index bc7815fba2..f1ef8e9a03 100755 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -42,8 +42,14 @@ LLClassifiedStatsResponder::LLClassifiedStatsResponder(LLUUID 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(); @@ -59,7 +65,8 @@ void LLClassifiedStatsResponder::result(const LLSD& content)  }  /*virtual*/ -void LLClassifiedStatsResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) +void LLClassifiedStatsResponder::httpFailure()  { -	LL_INFOS() << "LLClassifiedStatsResponder::error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } + 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/llemote.cpp b/indra/newview/llemote.cpp index 510ff69acf..b9ef297c00 100755 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -79,13 +79,13 @@ BOOL LLEmote::onActivate()  	LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );  	if( default_param )  	{ -		default_param->setWeight( default_param->getMaxWeight(), FALSE ); +		default_param->setWeight( default_param->getMaxWeight());  	}  	mParam = mCharacter->getVisualParam(mName.c_str());  	if (mParam)  	{ -		mParam->setWeight(0.f, FALSE); +		mParam->setWeight(0.f);  		mCharacter->updateVisualParams();  	} @@ -101,7 +101,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)  	if( mParam )  	{  		F32 weight = mParam->getMinWeight() + mPose.getWeight() * (mParam->getMaxWeight() - mParam->getMinWeight()); -		mParam->setWeight(weight, FALSE); +		mParam->setWeight(weight);  		// Cross fade against the default parameter  		LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" ); @@ -110,7 +110,7 @@ BOOL LLEmote::onUpdate(F32 time, U8* joint_mask)  			F32 default_param_weight = default_param->getMinWeight() +   				(1.f - mPose.getWeight()) * ( default_param->getMaxWeight() - default_param->getMinWeight() ); -			default_param->setWeight( default_param_weight, FALSE ); +			default_param->setWeight( default_param_weight);  		}  		mCharacter->updateVisualParams(); @@ -127,13 +127,13 @@ void LLEmote::onDeactivate()  {  	if( mParam )  	{ -		mParam->setWeight( mParam->getDefaultWeight(), FALSE ); +		mParam->setWeight( mParam->getDefaultWeight());  	}  	LLVisualParam* default_param = mCharacter->getVisualParam( "Express_Closed_Mouth" );  	if( default_param )  	{ -		default_param->setWeight( default_param->getMaxWeight(), FALSE ); +		default_param->setWeight( default_param->getMaxWeight());  	}  	mCharacter->updateVisualParams(); diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp index 761adc5942..78d619a315 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()  	{  		LL_INFOS() << "Committed estate info" << LL_ENDL;  		LLEstateInfoModel::instance().notifyCommit();  	}  	// if we get an error response -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	virtual void httpFailure()  	{ -		LL_WARNS() << "Failed to commit estate info [status:" << status << "]: " << content << LL_ENDL; +		LL_WARNS() << "Failed to commit estate info " << dumpResponse() << LL_ENDL;  	}  }; diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index fbd9466afe..4de6ad4d2f 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); -			LL_WARNS() << "LLEventPollResponder error [status:" << status << "]: " << content << LL_ENDL; +			LL_WARNS() << dumpResponse() << LL_ENDL;  		}  		else  		{ -			LL_WARNS() << "LLEventPollResponder error <" << mCount  -					<< "> [status:" << status << "]: " << content -					<<	(mDone ? " -- done"	: "") << LL_ENDL; +			LL_WARNS() << dumpResponse() +					   << " [count:" << mCount << "] " +					   << (mDone ? " -- done" : "") << LL_ENDL;  			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()  	{  		LL_DEBUGS() <<	"LLEventPollResponder::result <" << mCount	<< ">"  				 <<	(mDone ? " -- done"	: "") << LL_ENDL; @@ -243,10 +242,12 @@ namespace  		mErrorCount = 0; -		if (!content.get("events") || +		const LLSD& content = getContent(); +		if (!content.isMap() || +			!content.get("events") ||  			!content.get("id"))  		{ -			LL_WARNS() << "received event poll with no events or id key" << LL_ENDL; +			LL_WARNS() << "received event poll with no events or id key: " << dumpResponse() << LL_ENDL;  			makeRequest();  			return;  		} @@ -260,8 +261,8 @@ namespace  		}  		// was LL_INFOS() but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG -		LL_DEBUGS()  << "LLEventPollResponder::completed <" <<	mCount << "> " << events.size() << "events (id " -				 <<	LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL; +		LL_DEBUGS()  << "LLEventPollResponder::httpSuccess <" <<	mCount << "> " << events.size() << "events (id " +					 <<	LLSDXMLStreamer(mAcknowledge) << ")" << LL_ENDL;  		LLSD::array_const_iterator i = events.beginArray();  		LLSD::array_const_iterator end = events.endArray(); diff --git a/indra/newview/llfacebookconnect.cpp b/indra/newview/llfacebookconnect.cpp index 514aac46fc..e2fa117453 100644..100755 --- a/indra/newview/llfacebookconnect.cpp +++ b/indra/newview/llfacebookconnect.cpp @@ -110,28 +110,36 @@ public:          LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);      } -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -		if (isGoodStatus(status)) +		LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +	} + +	/* virtual */ void httpFailure() +	{ +		if ( HTTP_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; -			 -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (location.empty()) +			{ +				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() +							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +			} +			else +			{ +				LLFacebookConnect::instance().openFacebookWeb(location); +			}  		} -		else if (status != 302) +		else  		{ -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); -            log_facebook_connect_error("Connect", status, reason, content.get("error_code"), content.get("error_description")); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Connect", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} -     -    void completedHeader(U32 status, const std::string& reason, const LLSD& content) -    { -        if (status == 302) -        { -            LLFacebookConnect::instance().openFacebookWeb(content["location"]); -        } -    }  };  /////////////////////////////////////////////////////////////////////////////// @@ -145,34 +153,42 @@ public:  	{  		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTING);  	} -	 -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) + +	/* virtual */ void httpSuccess() +	{ +		toast_user_for_success(); +		LL_DEBUGS("FacebookConnect") << "Post successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); +	} + +	/* virtual */ void httpFailure()  	{ -		if (isGoodStatus(status)) +		if ( HTTP_FOUND == getStatus() )  		{ -            toast_user_for_success(); -			LL_DEBUGS("FacebookConnect") << "Post successful. content: " << content << LL_ENDL; -			 -			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POSTED); +			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (location.empty()) +			{ +				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() +							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +			} +			else +			{ +				LLFacebookConnect::instance().openFacebookWeb(location); +			}  		} -		else if (status == 404) +		else if ( HTTP_NOT_FOUND == getStatus() )  		{  			LLFacebookConnect::instance().connectToFacebook();  		}  		else  		{ -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); -            log_facebook_connect_error("Share", status, reason, content.get("error_code"), content.get("error_description")); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_POST_FAILED); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Share", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} -     -    void completedHeader(U32 status, const std::string& reason, const LLSD& content) -    { -        if (status == 302) -        { -            LLFacebookConnect::instance().openFacebookWeb(content["location"]); -        } -    }  };  /////////////////////////////////////////////////////////////////////////////// @@ -196,24 +212,27 @@ public:  		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED);  	} -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpSuccess()  	{ -		if (isGoodStatus(status))  -		{ -			LL_DEBUGS("FacebookConnect") << "Disconnect successful. content: " << content << LL_ENDL; -			setUserDisconnected(); +		LL_DEBUGS("FacebookConnect") << "Disconnect successful. " << dumpResponse() << LL_ENDL; +		setUserDisconnected(); +	} -		} +	/* virtual */ void httpFailure() +	{  		//User not found so already disconnected -		else if(status == 404) +		if ( HTTP_NOT_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Already disconnected. content: " << content << LL_ENDL; +			LL_DEBUGS("FacebookConnect") << "Already disconnected. " << dumpResponse() << LL_ENDL;  			setUserDisconnected();  		}  		else  		{ +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL;  			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); -            log_facebook_connect_error("Disconnect", status, reason, content.get("error_code"), content.get("error_description")); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Disconnect", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	}  }; @@ -229,34 +248,35 @@ public:      {  		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_IN_PROGRESS);      } -     -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) + +	/* virtual */ void httpSuccess()  	{ -		if (isGoodStatus(status)) +		LL_DEBUGS("FacebookConnect") << "Connect successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +	} + +	/* virtual */ void httpFailure() +	{ +		// show the facebook login page if not connected yet +		if ( HTTP_NOT_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Connect successful. content: " << content << LL_ENDL; -             -            LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTED); +			LL_DEBUGS("FacebookConnect") << "Not connected. " << dumpResponse() << LL_ENDL; +			if (mAutoConnect) +			{ +				LLFacebookConnect::instance().connectToFacebook(); +			} +			else +			{ +				LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); +			}  		}  		else  		{ -			// show the facebook login page if not connected yet -			if (status == 404) -			{ -				if (mAutoConnect) -				{ -					LLFacebookConnect::instance().connectToFacebook(); -				} -				else -				{ -					LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_NOT_CONNECTED); -				} -			} -            else -            { -                LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_CONNECTION_FAILED); -				log_facebook_connect_error("Connected", status, reason, content.get("error_code"), content.get("error_description")); -            } +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			LLFacebookConnect::instance().setConnectionState(LLFacebookConnect::FB_DISCONNECT_FAILED); +			const LLSD& content = getContent(); +			log_facebook_connect_error("Connected", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} @@ -271,25 +291,27 @@ class LLFacebookInfoResponder : public LLHTTPClient::Responder  	LOG_CLASS(LLFacebookInfoResponder);  public: -	virtual void completed(U32 status, const std::string& reason, const LLSD& info) +	/* virtual */ void httpSuccess() +	{ +		LL_INFOS("FacebookConnect") << "Facebook: Info received" << LL_ENDL; +		LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().storeInfo(getContent()); +	} + +	/* virtual */ void httpFailure()  	{ -		if (isGoodStatus(status)) +		if ( HTTP_FOUND == getStatus() )  		{  			LL_INFOS() << "Facebook: Info received" << LL_ENDL; -			LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << info << LL_ENDL; -			LLFacebookConnect::instance().storeInfo(info); +			LL_DEBUGS("FacebookConnect") << "Getting Facebook info successful. info: " << getContent() << LL_ENDL; +			LLFacebookConnect::instance().storeInfo(getContent());  		}  		else  		{ -			log_facebook_connect_error("Info", status, reason, info.get("error_code"), info.get("error_description")); -		} -	} - -	void completedHeader(U32 status, const std::string& reason, const LLSD& content) -	{ -		if (status == 302) -		{ -			LLFacebookConnect::instance().openFacebookWeb(content["location"]); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			const LLSD& content = getContent(); +			log_facebook_connect_error("Info", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	}  }; @@ -300,27 +322,36 @@ class LLFacebookFriendsResponder : public LLHTTPClient::Responder  {  	LOG_CLASS(LLFacebookFriendsResponder);  public: +     +	/* virtual */ void httpSuccess() +	{ +		LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. " << dumpResponse() << LL_ENDL; +		LLFacebookConnect::instance().storeContent(getContent()); +	} -	virtual void completed(U32 status, const std::string& reason, const LLSD& content) +	/* virtual */ void httpFailure()  	{ -		if (isGoodStatus(status)) +		if ( HTTP_FOUND == getStatus() )  		{ -			LL_DEBUGS("FacebookConnect") << "Getting Facebook friends successful. content: " << content << LL_ENDL; -			LLFacebookConnect::instance().storeContent(content); +			const std::string& location = getResponseHeader(HTTP_IN_HEADER_LOCATION); +			if (location.empty()) +			{ +				LL_WARNS("FacebookConnect") << "Missing Location header " << dumpResponse() +							 << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +			} +			else +			{ +				LLFacebookConnect::instance().openFacebookWeb(location); +			}  		}  		else  		{ -            log_facebook_connect_error("Friends", status, reason, content.get("error_code"), content.get("error_description")); +			LL_WARNS("FacebookConnect") << dumpResponse() << LL_ENDL; +			const LLSD& content = getContent(); +			log_facebook_connect_error("Friends", getStatus(), getReason(), +									   content.get("error_code"), content.get("error_description"));  		}  	} - -    void completedHeader(U32 status, const std::string& reason, const LLSD& content) -    { -        if (status == 302) -        { -            LLFacebookConnect::instance().openFacebookWeb(content["location"]); -        } -    }  };  /////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 8c3a4bb5c0..d0555477ea 100755 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -39,6 +39,7 @@  #include "llgl.h"  #include "llappviewer.h" +#include "llbufferstream.h"  #include "llhttpclient.h"  #include "llnotificationsutil.h"  #include "llviewercontrol.h" @@ -609,6 +610,7 @@ bool LLFeatureManager::parseGPUTable(std::string filename)  // responder saves table into file  class LLHTTPFeatureTableResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLHTTPFeatureTableResponder);  public:  	LLHTTPFeatureTableResponder(std::string filename) : @@ -617,11 +619,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 @@ -640,7 +641,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; +			} +			LL_WARNS() << dumpResponse() << LL_ENDL; +		}  	}  private: diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 8402148a46..a7f5cd9dac 100755 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -1105,9 +1105,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; @@ -1115,13 +1115,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)");  } @@ -1177,7 +1177,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_PNG: @@ -1211,6 +1211,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 efaba1d7a4..15b94034bb 100755 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -76,14 +76,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();  };  ///---------------------------------------------------------------------------- @@ -303,16 +298,15 @@ void LLServerReleaseNotesURLFetcher::startFetch()  }  // virtual -void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::string& reason, const LLSD& content) +void LLServerReleaseNotesURLFetcher::httpCompleted()  { -	LL_DEBUGS() << "Status: " << status << LL_ENDL; -	LL_DEBUGS() << "Reason: " << reason << LL_ENDL; -	LL_DEBUGS() << "Headers: " << content << LL_ENDL; +	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(); +		std::string location = getResponseHeader(HTTP_IN_HEADER_LOCATION);  		if (location.empty())  		{  			location = LLTrans::getString("ErrorFetchingServerReleaseNotesURL"); @@ -321,14 +315,3 @@ void LLServerReleaseNotesURLFetcher::completedHeader(U32 status, const std::stri  	}  } -// 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 c1e6673406..3e032d0e4a 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  		{ -			LL_WARNS() << "avatar picker failed [status:" << status << "]: " << content << LL_ENDL; -			 +			LL_WARNS() << "avatar picker failed " << dumpResponse() << LL_ENDL;  		}  	}  }; diff --git a/indra/newview/llfloaterbuycurrencyhtml.cpp b/indra/newview/llfloaterbuycurrencyhtml.cpp index 0c408f556d..a69aa8d227 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()  	LL_INFOS() << "Buy currency HTML parsed URL is " << buy_currency_url << LL_ENDL;  	// 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 1452d53265..9797b5c062 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 f61359f87a..7852a1f7b3 100644..100755 --- a/indra/newview/llfloaterimsession.cpp +++ b/indra/newview/llfloaterimsession.cpp @@ -1181,16 +1181,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()  	{ -		LL_WARNS() << "Error inviting all agents to session [status:"  -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL;  		//throw something back to the viewer here?  	} diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 12c1a68ccd..b17ce97a2e 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -5861,7 +5861,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)  {  	LL_WARNS() << "LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(" << status << " : " << reason << ")" << LL_ENDL;  	doOnIdleOneTime(boost::bind(&LLFloaterModelPreview::toggleCalculateButton, this, true)); @@ -5937,7 +5937,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)  {  	LL_WARNS() << "LLFloaterModelPreview::setPermissonsErrorStatus(" << status << " : " << reason << ")" << LL_ENDL; 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 2ad2d32652..22a8ac4705 100755 --- a/indra/newview/llfloatermodeluploadbase.cpp +++ b/indra/newview/llfloatermodeluploadbase.cpp @@ -44,8 +44,10 @@ void LLFloaterModelUploadBase::requestAgentUploadPermissions()  	if (!url.empty())  	{ -		LL_INFOS()<< typeid(*this).name() <<"::requestAgentUploadPermissions() requesting for upload model permissions from: "<< url <<LL_ENDL; -		LLHTTPClient::get(url, new LLUploadModelPremissionsResponder(getPermObserverHandle())); +		LL_INFOS()<< typeid(*this).name() +				  << "::requestAgentUploadPermissions() requesting for upload model permissions from: " +				  << url << LL_ENDL; +		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 94bf8974bb..feaeef4ad0 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 bed34abee8..40757a4d04 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 d67089ff85..5e9b25b474 100755 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -759,12 +759,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()  	{ -		LL_WARNS() << "ConsoleRequestResponder error requesting mesh_rez_enabled [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS() << "error requesting mesh_rez_enabled " << dumpResponse() << LL_ENDL;  	}  }; @@ -772,12 +772,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()  	{ -		LL_WARNS() << "ConsoleRequestResponder error updating mesh enabled region setting [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS() << "error updating mesh enabled region setting " << dumpResponse() << LL_ENDL;  	}  }; @@ -2244,14 +2244,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" << LL_ENDL; @@ -2262,10 +2264,9 @@ public:  	}  	// if we get an error response -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) +	virtual void httpFailure()  	{ -		LL_INFOS() << "LLEstateChangeInfoResponder::error [status:" -			<< status << "]: " << content << LL_ENDL; +		LL_WARNS("Windlight") << dumpResponse() << LL_ENDL;  	}  private:  	LLHandle<LLPanel> mpPanel; diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 825159703c..a3b9713e3e 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 2ed7bb842d..5fbdd75e97 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()  { -	LL_WARNS() << "fetchScriptLimitsRegionInfoResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } -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()  { -	LL_WARNS() << "fetchScriptLimitsRegionSummaryResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } -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()  { -	LL_WARNS() << "fetchScriptLimitsRegionDetailsResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  } -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()  { -	LL_WARNS() << "fetchScriptLimitsAttachmentInfoResponder error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  }  ///---------------------------------------------------------------------------- @@ -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)  {  	LL_WARNS() << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<LL_ENDL;  } 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 a3a78b5d8b..f72adbb880 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 "llfacebookconnect.h"  #include "lllayoutstack.h"  #include "llpluginclassmedia.h" @@ -240,9 +241,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); @@ -489,7 +490,7 @@ void LLFloaterWebContent::onEnterAddress()      LLStringUtil::trim(url);  	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 6566ef5dca..307e259006 100755 --- a/indra/newview/llfriendcard.cpp +++ b/indra/newview/llfriendcard.cpp @@ -38,6 +38,7 @@  #include "llcallingcard.h" // for LLAvatarTracker  #include "llviewerinventory.h"  #include "llinventorymodel.h" +#include "llcallbacklist.h"  // Constants; @@ -86,7 +87,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; @@ -154,7 +155,7 @@ void LLInitialFriendCardsFetch::done()  	// This observer is no longer needed.  	gInventory.removeObserver(this); -	mCheckFolderCallback(); +	doOnIdleOneTime(mCheckFolderCallback);  	delete this;  } diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index ffddeeb129..b15556d73d 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 b2ad737a1d..d5b817ce76 100755 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -1851,23 +1851,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 eefa8bd42a..d0492bcdb4 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    {      LL_INFOS() << "setting home position" << LL_ENDL; -		 +      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()  { -	LL_WARNS() << "LLHomeLocationResponder error [status:" << status << "]: " << content << LL_ENDL; +  LL_WARNS() << dumpResponse() << LL_ENDL;  } 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..2d4ce6c883 --- /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) +	{ +		LL_INFOS() << "keep on failing" << LL_ENDL; +		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) +	{ +		LL_INFOS() << "Too many retries " << mRetryCount << ", will not retry" << LL_ENDL; +		mShouldRetry = false; +	} +	if (!mRetryOn4xx && !isHttpServerErrorStatus(status)) +	{ +		LL_INFOS() << "Non-server error " << status << ", will not retry" << LL_ENDL; +		mShouldRetry = false; +	} +	if (mShouldRetry) +	{ +		LL_INFOS() << "Retry count " << mRetryCount << " should retry after " << wait_time << LL_ENDL; +		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 ? (F32) 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 34ccab0302..c194dc05b0 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()  	{ -		LL_WARNS() << "Error inviting all agents to session [status:"  -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << "Error inviting all agents to session " << dumpResponse() << LL_ENDL;  		//throw something back to the viewer here?  	} diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index af93778c10..8917c07759 100755 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1460,6 +1460,7 @@ void start_deprecated_conference_chat(  class LLStartConferenceChatResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(LLStartConferenceChatResponder);  public:  	LLStartConferenceChatResponder(  		const LLUUID& temp_session_id, @@ -1473,10 +1474,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, @@ -1485,8 +1488,7 @@ public:  				mAgents);  		} -		LL_WARNS() << "LLStartConferenceChatResponder error [status:" -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		//else throw an error back to the client?  		//in theory we should have just have these error strings @@ -1578,6 +1580,7 @@ bool LLIMModel::sendStartSession(  class LLViewerChatterBoxInvitationAcceptResponder :  	public LLHTTPClient::Responder  { +	LOG_CLASS(LLViewerChatterBoxInvitationAcceptResponder);  public:  	LLViewerChatterBoxInvitationAcceptResponder(  		const LLUUID& session_id, @@ -1587,8 +1590,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); @@ -1633,19 +1643,17 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +	void httpFailure()  	{ -		LL_WARNS() << "LLViewerChatterBoxInvitationAcceptResponder error [status:" -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		//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 b75140238e..1e15dc832c 100755 --- a/indra/newview/llinspectavatar.cpp +++ b/indra/newview/llinspectavatar.cpp @@ -292,11 +292,6 @@ void LLInspectAvatar::processAvatarData(LLAvatarData* data)  	delete mPropertiesRequest;  	mPropertiesRequest = NULL;  } -/* -prep# -			virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -				LL_WARNS() << "MuteVoiceResponder error [status:" << status << "]: " << content << LL_ENDL; -	*/  void LLInspectAvatar::updateVolumeSlider()  { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c538fb6c68..5df28ccb73 100755 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -202,6 +202,7 @@ const std::string& LLInvFVBridge::getDisplayName() const  	{  		buildDisplayName();  	} +  	return mDisplayName;  } @@ -1161,17 +1162,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);  	}  } @@ -1607,18 +1601,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  { @@ -1732,13 +1726,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. @@ -1774,16 +1764,8 @@ BOOL LLItemBridge::removeItem()  	{  		if (!item->getIsLinkType())  		{ -			LLInventoryModel::cat_array_t cat_array; -			LLInventoryModel::item_array_t item_array; -			LLLinkedItemIDMatches is_linked_item_match(mUUID); -			gInventory.collectDescendentsIf(gInventory.getRootFolderID(), -											cat_array, -											item_array, -											LLInventoryModel::INCLUDE_TRASH, -											is_linked_item_match); - -			const U32 num_links = cat_array.size() + item_array.size(); +			LLInventoryModel::item_array_t item_array = gInventory.collectLinksTo(mUUID); +			const U32 num_links = item_array.size();  			if (num_links > 0)  			{  				// Warn if the user is will break any links when deleting this item. @@ -1935,49 +1917,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();  	}  } @@ -2490,49 +2442,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)  			{ @@ -2924,17 +2840,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); @@ -3097,9 +3002,20 @@ LLUIImagePtr LLFolderBridge::getIconOverlay() const  	return NULL;  } +std::string LLFolderBridge::getLabelSuffix() const +{ +	static LLCachedControl<F32> folder_loading_message_delay(gSavedSettings, "FolderLoadingMessageWaitTime", 0.5f); +	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)  { + +	LLScrollOnRenameObserver *observer = new LLScrollOnRenameObserver(mUUID, mRoot); +	gInventory.addObserver(observer); +  	rename_category(getInventoryModel(), mUUID, new_name);  	// return FALSE because we either notified observers (& therefore @@ -3337,28 +3253,9 @@ void LLFolderBridge::pasteLinkFromClipboard()  					dropToOutfit(item, move_is_into_current_outfit);  				}  			} -			else if (LLInventoryCategory *cat = model->getCategory(object_id)) +			else if (LLConstPointer<LLInventoryObject> obj = model->getObject(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)) -			{ -				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 @@ -3449,16 +3346,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 @@ -3620,6 +3507,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"));  	}  } @@ -3950,14 +3841,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 bc875e8f37..02134c7cc5 100755 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -252,7 +252,7 @@ public:  	LLFolderBridge(LLInventoryPanel* inventory,   				   LLFolderView* root,  				   const LLUUID& uuid)  -        :       LLInvFVBridge(inventory, root, uuid), +	:	LLInvFVBridge(inventory, root, uuid),  		mCallingCards(FALSE),  		mWearables(FALSE),  		mIsLoading(false) @@ -276,6 +276,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 f16b9330be..1e7825a13e 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 7db1f29797..14ca0095ae 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 @@ -103,17 +105,7 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  		if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)  		{  			S32 descendents_server = c->getDescendentCount(); -			LLInventoryModel::cat_array_t* cats; -			LLInventoryModel::item_array_t* items; -			mModel->getDirectDescendentsOf( -				c->getUUID(), -				cats, -				items); -			S32 descendents_actual = 0; -			if(cats && items) -			{ -				descendents_actual = cats->size() + items->size(); -			} +			S32 descendents_actual = c->getViewerDescendentCount();  			if(descendents_server == descendents_actual)  			{  				mCachedCatIDs.insert(c->getUUID()); @@ -135,6 +127,7 @@ LLInventoryModel gInventory;  LLInventoryModel::LLInventoryModel()  :	mModifyMask(LLInventoryObserver::ALL),  	mChangedItemIDs(), +	mBacklinkMMap(),  	mCategoryMap(),  	mItemMap(),  	mCategoryLock(), @@ -252,6 +245,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) +		{ +			LL_WARNS() << "unable to trace topmost ancestor, missing item for uuid " << object->getParentUUID() << LL_ENDL; +			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  { @@ -429,15 +439,12 @@ void LLInventoryModel::consolidateForType(const LLUUID& main_id, LLFolderType::E  	}  } -// 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; @@ -453,14 +460,17 @@ const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType prefe  			{  				if(cats->at(i)->getPreferredType() == preferred_type)  				{ -					rv = cats->at(i)->getUUID(); -					break; +					const LLUUID& folder_id = cats->at(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())  		{ @@ -470,68 +480,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->size(); -			for(S32 i = 0; i < count; ++i) -			{ -				if(cats->at(i)->getPreferredType() == preferred_type) -				{ -					rv = cats->at(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) << LL_ENDL;  		// Add the category to the internal representation  		LLPointer<LLViewerInventoryCategory> cat =  		new LLViewerInventoryCategory( category_id,  @@ -544,17 +535,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;  }; @@ -565,8 +554,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; @@ -593,33 +581,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) << LL_ENDL; +		//		viewer_region->getCapAPI().post(request); +		LLHTTPClient::post( +			url, +			body, +			new LLCreateInventoryCategoryResponder(this, callback) ); + +		return LLUUID::null;  	}  	// Add the category to the internal representation @@ -646,6 +633,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 its 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 @@ -677,8 +698,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) @@ -705,36 +725,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->size(); -		for(S32 i = 0; i < count; ++i) -		{ -			item = item_array->at(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.push_back(LLPointer<LLViewerInventoryCategory>(linked_cat)); -					} -					collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); -				} -			} -		} -	} -	  	// Move onto items  	if(item_array)  	{ @@ -756,26 +746,7 @@ void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask)  	if (!obj || obj->getIsLinkType())  		return; -	LLInventoryModel::cat_array_t cat_array; -	LLInventoryModel::item_array_t item_array; -	LLLinkedItemIDMatches is_linked_item_match(object_id); -	collectDescendentsIf(gInventory.getRootFolderID(), -						 cat_array, -						 item_array, -						 LLInventoryModel::INCLUDE_TRASH, -						 is_linked_item_match); -	if (cat_array.empty() && item_array.empty()) -	{ -		return; -	} -	for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); -		 cat_iter != cat_array.end(); -		 cat_iter++) -	{ -		LLViewerInventoryCategory *linked_cat = (*cat_iter); -		addChangedMask(mask, linked_cat->getUUID()); -	}; - +	LLInventoryModel::item_array_t item_array = collectLinksTo(object_id);  	for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();  		 iter != item_array.end();  		 iter++) @@ -803,17 +774,27 @@ LLViewerInventoryItem* LLInventoryModel::getLinkedItem(const LLUUID& object_id)  	return object_id.notNull() ? getItem(getLinkedItemID(object_id)) : NULL;  } -LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id, -																	const LLUUID& start_folder_id) +LLInventoryModel::item_array_t LLInventoryModel::collectLinksTo(const LLUUID& id)  { +	// Get item list via collectDescendents (slow!)  	item_array_t items; -	LLInventoryModel::cat_array_t cat_array; -	LLLinkedItemIDMatches is_linked_item_match(id); -	collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id), -						 cat_array, -						 items, -						 LLInventoryModel::INCLUDE_TRASH, -						 is_linked_item_match); +	const LLInventoryObject *obj = getObject(id); +	// FIXME - should be as in next line, but this is causing a +	// stack-smashing crash of cause TBD... check in the REBUILD code. +	//if (obj && obj->getIsLinkType()) +	if (!obj || obj->getIsLinkType()) +		return items; +	 +	std::pair<backlink_mmap_t::iterator, backlink_mmap_t::iterator> range = mBacklinkMMap.equal_range(id); +	for (backlink_mmap_t::iterator it = range.first; it != range.second; ++it) +	{ +		LLViewerInventoryItem *item = getItem(it->second); +		if (item) +		{ +			items.push_back(item); +		} +	} +  	return items;  } @@ -830,9 +811,8 @@ bool LLInventoryModel::isInventoryUsable() const  // Calling this method with an inventory item will either change an  // existing item with a matching item_id, or will add the item to the  // current inventory. -U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) +U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask)  { -	U32 mask = LLInventoryObserver::NONE;  	if(item->getUUID().isNull())  	{  		return mask; @@ -1011,7 +991,7 @@ LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLU  // Calling this method with an inventory category will either change  // an existing item with the matching id, or it will add the category. -void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat) +void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat, U32 mask)  {  	if(cat->getUUID().isNull())  	{ @@ -1028,7 +1008,6 @@ void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat)  	if(old_cat)  	{  		// We already have an old category, modify it's values -		U32 mask = LLInventoryObserver::NONE;  		LLUUID old_parent_id = old_cat->getParentUUID();  		LLUUID new_parent_id = cat->getParentUUID();  		if(old_parent_id != new_parent_id) @@ -1182,8 +1161,199 @@ 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. +	LL_INFOS() << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL; +} + +// Does not appear to be used currently. +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)") << LL_ENDL; +	if(item) +	{ +		for (LLSD::map_const_iterator it = updates.beginMap(); +			 it != updates.endMap(); ++it) +		{ +			if (it->first == "name") +			{ +				LL_INFOS() << "Updating name from " << item->getName() << " to " << it->second.asString() << LL_ENDL; +				item->rename(it->second.asString()); +				mask |= LLInventoryObserver::LABEL; +			} +			else if (it->first == "desc") +			{ +				LL_INFOS() << "Updating description from " << item->getActualDescription() +						<< " to " << it->second.asString() << LL_ENDL; +				item->setDescription(it->second.asString()); +			} +			else +			{ +				LL_ERRS() << "unhandled updates for field: " << it->first << LL_ENDL; +			} +		} +		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? +	} +} + +// Not used? +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)") << LL_ENDL; +	if(cat) +	{ +		for (LLSD::map_const_iterator it = updates.beginMap(); +			 it != updates.endMap(); ++it) +		{ +			if (it->first == "name") +			{ +				LL_INFOS() << "Updating name from " << cat->getName() << " to " << it->second.asString() << LL_ENDL; +				cat->rename(it->second.asString()); +				mask |= LLInventoryObserver::LABEL; +			} +			else +			{ +				LL_ERRS() << "unhandled updates for field: " << it->first << LL_ENDL; +			} +		} +		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.size(); + +		LLUUID uu_id; +		for(S32 i = 0; i < count; ++i) +		{ +			uu_id = items.at(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.size(); +		// 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.at(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) +		{ +			LL_WARNS() << "Unexpected count of categories deleted, got " +					<< total_deleted_count << " expected " << count << LL_ENDL; +		} +		//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)  {  	LL_DEBUGS() << "LLInventoryModel::deleteObject()" << LL_ENDL;  	LLPointer<LLInventoryObject> obj = getObject(id); @@ -1214,157 +1384,64 @@ void LLInventoryModel::deleteObject(const LLUUID& id)  	item_list = getUnlockedItemArray(id);  	if(item_list)  	{ +		if (item_list->size()) +		{ +			LL_WARNS() << "Deleting cat " << id << " while it still has child items" << LL_ENDL; +		}  		delete item_list;  		mParentChildItemTree.erase(id);  	}  	cat_list = getUnlockedCatArray(id);  	if(cat_list)  	{ +		if (cat_list->size()) +		{ +			LL_WARNS() << "Deleting cat " << id << " while it still has child cats" << LL_ENDL; +		}  		delete cat_list;  		mParentChildCategoryTree.erase(id);  	}  	addChangedMask(LLInventoryObserver::REMOVE, id); -	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) -{ -	LL_DEBUGS() << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << LL_ENDL; -	LLPointer<LLInventoryObject> obj = getObject(id); -	if(obj) +	bool is_link_type = obj->getIsLinkType(); +	if (is_link_type) +	{ +		removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID()); +	} + +	// 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. +	obj = NULL; // delete obj +	if (fix_broken_links && !is_link_type) +	{ +		updateLinkedObjectsFromPurge(id); +	} +	if (do_notify_observers)  	{ -		obj->removeFromServer(); -		LLPreview::hide(id); -		deleteObject(id); +		notifyObservers();  	}  }  void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)  { -	LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id); +	LLInventoryModel::item_array_t item_array = collectLinksTo(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++) +	if (item_array.size() > 0)  	{ -		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) -{ -	LLPointer<LLViewerInventoryCategory> cat = 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_INFOS() << "LLInventoryModel::purgeDescendentsOf " << cat->getName() -			<< " iterate and purge non hidden items" << LL_ENDL; -			cat_array_t* categories; -			item_array_t* items; -			// Get the list of direct descendants in that category 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 +		gInventory.notifyObservers(); +		for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); +			iter != item_array.end(); +			iter++)  		{ -			// Fast purge -			// do the cache accounting -			LL_INFOS() << "LLInventoryModel::purgeDescendentsOf " << cat->getName() -				<< LL_ENDL; -			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.size(); - -			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.at(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.size(); -			for(S32 i = 0; i < count; ++i) -			{ -				uu_id = categories.at(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();  	}  } @@ -1419,6 +1496,7 @@ void LLInventoryModel::notifyObservers()  	mModifyMask = LLInventoryObserver::NONE;  	mChangedItemIDs.clear(); +	mAddedItemIDs.clear();  	mIsNotifyObservers = FALSE;  } @@ -1432,25 +1510,49 @@ void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)  		// (which is in the process of processing the list of items marked for change).  		// This means the change may fail to be processed.  		LL_WARNS() << "Adding changed mask within notify observers!  Change will likely be lost." << LL_ENDL; +		LLViewerInventoryItem *item = getItem(referent); +		if (item) +		{ +			LL_WARNS() << "Item " << item->getName() << LL_ENDL; +		} +		else +		{ +			LLViewerInventoryCategory *cat = getCategory(referent); +			if (cat) +			{ +				LL_WARNS() << "Category " << cat->getName() << LL_ENDL; +			} +		}  	}  	mModifyMask |= mask;   	if (referent.notNull())  	{  		mChangedItemIDs.insert(referent); -	} + +		if (mask & LLInventoryObserver::ADD) +		{ +			mAddedItemIDs.insert(referent); +		} -	// Update all linked items.  Starting with just LABEL because I'm -	// not sure what else might need to be accounted for this. -	if (mModifyMask & LLInventoryObserver::LABEL) -	{ -		addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); +		// Update all linked items.  Starting with just LABEL because I'm +		// not sure what else might need to be accounted for this. +		if (mask & LLInventoryObserver::LABEL) +		{ +			addChangedMaskForLinks(referent, LLInventoryObserver::LABEL); +		}  	}  }  // 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; @@ -1471,8 +1573,8 @@ void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)  		LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;  		titem->unpackMessage(content["items"][i]); -		LL_DEBUGS() << "LLInventoryModel::messageUpdateCore() item id:" -				 << titem->getUUID() << LL_ENDL; +		LL_DEBUGS() << "LLInventoryModel::fetchInventoryResponder item id: " +					<< titem->getUUID() << LL_ENDL;  		items.push_back(titem);  		// examine update for changes.  		LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID()); @@ -1509,9 +1611,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()  { -	LL_WARNS() << "fetchInventory error [status:" << status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	gInventory.notifyObservers();  } @@ -1603,6 +1705,47 @@ void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)  	}  } +bool LLInventoryModel::hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const +{ +	std::pair <backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range; +	range = mBacklinkMMap.equal_range(target_id); +	for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) +	{ +		if (it->second == link_id) +		{ +			return true; +		} +	} +	return false; +} + +void LLInventoryModel::addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ +	if (!hasBacklinkInfo(link_id, target_id)) +	{ +		mBacklinkMMap.insert(std::make_pair(target_id, link_id)); +	} +} + +void LLInventoryModel::removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) +{ +	std::pair <backlink_mmap_t::iterator, backlink_mmap_t::iterator> range; +	range = mBacklinkMMap.equal_range(target_id); +	for (backlink_mmap_t::iterator it = range.first; it != range.second; ) +	{ +		if (it->second == link_id) +		{ +			backlink_mmap_t::iterator delete_it = it; // iterator will be invalidated by erase. +			++it; +			mBacklinkMMap.erase(delete_it); +		} +		else +		{ +			++it; +		} +	} +} +  void LLInventoryModel::addItem(LLViewerInventoryItem* item)  {  	llassert(item); @@ -1624,7 +1767,13 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item)  		{  			LL_INFOS() << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " )  parent: " << item->getParentUUID() << LL_ENDL;  		} - +		if (item->getIsLinkType()) +		{ +			// Add back-link from linked-to UUID. +			const LLUUID& link_id = item->getUUID(); +			const LLUUID& target_id = item->getLinkedUUID(); +			addBacklinkInfo(link_id, target_id); +		}  		mItemMap[item->getUUID()] = item;  	}  } @@ -1643,6 +1792,7 @@ void LLInventoryModel::empty()  		mParentChildItemTree.end(),  		DeletePairedPointer());  	mParentChildItemTree.clear(); +	mBacklinkMMap.clear(); // forget all backlink information.  	mCategoryMap.clear(); // remove all references (should delete entries)  	mItemMap.clear(); // remove all references (should delete entries)  	mLastItem = NULL; @@ -1654,37 +1804,34 @@ 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)  		{  			S32 descendents_server = cat->getDescendentCount(); -			LLInventoryModel::cat_array_t* cats; -			LLInventoryModel::item_array_t* items; -			getDirectDescendentsOf(update.mCategoryID, cats, items); -			S32 descendents_actual = 0; -			if(cats && items) -			{ -				descendents_actual = cats->size() + items->size(); -			} +			S32 descendents_actual = cat->getViewerDescendentCount();  			if(descendents_server == descendents_actual)  			{ -				accounted = true;  				descendents_actual += update.mDescendentDelta;  				cat->setDescendentCount(descendents_actual);  				cat->setVersion(++version); -				LL_DEBUGS() << "accounted: '" << cat->getName() << "' " -						 << version << " with " << descendents_actual -						 << " descendents." << LL_ENDL; +				LL_DEBUGS("Inventory") << "accounted: '" << cat->getName() << "' " +									   << version << " with " << descendents_actual +									   << " 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. +				LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version:" +						   << version << " due to mismatched descendent count:  server == " +						   << descendents_server << ", viewer == " << descendents_actual << LL_ENDL;  			}  		} -		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. -			LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version:" -					 << version << LL_ENDL; +			LL_WARNS() << "Accounting failed for '" << cat->getName() << "' version: unknown ("  +					   << version << ")" << LL_ENDL;  		}  	}  	else @@ -1718,47 +1865,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); -			LL_INFOS() << "IncrementVersion: " << cat->getName() << " " -					<< cat->getVersion() << LL_ENDL; -		} -		else -		{ -			LL_INFOS() << "Attempt to increment version when unknown: " -					<< category_id << LL_ENDL; -		} -	} -	else -	{ -		LL_INFOS() << "Attempt to increment category: " << category_id << LL_ENDL; -	} -} -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  { @@ -1799,14 +1905,7 @@ bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const  	if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN))  	{  		S32 descendents_server = cat->getDescendentCount(); -		LLInventoryModel::cat_array_t* cats; -		LLInventoryModel::item_array_t* items; -		getDirectDescendentsOf(cat_id, cats, items); -		S32 descendents_actual = 0; -		if(cats && items) -		{ -			descendents_actual = cats->size() + items->size(); -		} +		S32 descendents_actual = cat->getViewerDescendentCount();  		if(descendents_server == descendents_actual)  		{  			return true; @@ -2144,11 +2243,16 @@ void LLInventoryModel::buildParentChildMap()  	S32 count = cats.size();  	S32 i;  	S32 lost = 0; +	cat_array_t lost_cats;  	for(i = 0; i < count; ++i)  	{  		LLViewerInventoryCategory* cat = cats.at(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->push_back(cat);  		} @@ -2160,35 +2264,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. -			LL_INFOS() << "Lost categroy: " << cat->getUUID() << " - " -					<< cat->getName() << LL_ENDL; +			LL_INFOS() << "Lost category: " << cat->getUUID() << " - " +					   << cat->getName() << LL_ENDL;  			++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->push_back(cat); -			} -			else -			{		 -				LL_WARNS() << "Lost and found Not there!!" << LL_ENDL; -			} +			lost_cats.push_back(cat);  		}  	}  	if(lost) @@ -2196,6 +2275,42 @@ void LLInventoryModel::buildParentChildMap()  		LL_WARNS() << "Found  " << lost << " lost categories." << LL_ENDL;  	} +	// 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.size(); ++i) +	{ +		LLViewerInventoryCategory *cat = lost_cats.at(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->push_back(cat); +		} +		else +		{		 +			LL_WARNS() << "Lost and found Not there!!" << LL_ENDL; +		} +	} +  	const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null);  	sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin(); @@ -2228,7 +2343,7 @@ void LLInventoryModel::buildParentChildMap()  		else  		{  			LL_INFOS() << "Lost item: " << item->getUUID() << " - " -					<< item->getName() << LL_ENDL; +					   << item->getName() << LL_ENDL;  			++lost;  			// plop it into the lost & found.  			// @@ -2319,11 +2434,25 @@ void LLInventoryModel::buildParentChildMap()  			// The inv tree is built.  			mIsAgentInvUsable = true; -			LL_INFOS() << "Inventory initialized, notifying observers" << LL_ENDL; -			addChangedMask(LLInventoryObserver::ALL, LLUUID::null); -			notifyObservers(); +			// notifyObservers() has been moved to +			// llstartup/idle_startup() after this func completes. +			// Allows some system categories to be created before +			// observers start firing.  		}  	} + +	if (!gInventory.validate()) +	{ +	 	LL_WARNS() << "model failed validity check!" << LL_ENDL; +	} +} + +void LLInventoryModel::createCommonSystemCategories() +{ +	gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH,true); +	gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true); +	gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD,true); +	gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS,true);  }  struct LLUUIDAndName @@ -2547,7 +2676,7 @@ void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)  void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**)  {  	// do accounting and highlight new items if they arrive -	if (gInventory.messageUpdateCore(msg, true)) +	if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::UPDATE_CREATE))  	{  		U32 callback_id;  		LLUUID item_id; @@ -2567,7 +2696,7 @@ void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**)  } -bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account) +bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account, U32 mask)  {  	//make sure our added inventory observer is active  	start_new_inventory_observer(); @@ -2621,10 +2750,14 @@ bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account)  	}  	U32 changes = 0x0; +	if (account) +	{ +		mask |= LLInventoryObserver::CREATE; +	}  	//as above, this loop never seems to loop more than once per call  	for (item_array_t::iterator it = items.begin(); it != items.end(); ++it)  	{ -		changes |= gInventory.updateItem(*it); +		changes |= gInventory.updateItem(*it, mask);  	}  	gInventory.notifyObservers();  	gViewerWindow->getWindow()->decBusyCount(); @@ -2862,7 +2995,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	LLUUID tid;  	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid);  #ifndef LL_RELEASE_FOR_DOWNLOAD -	LL_INFOS() << "Bulk inventory: " << tid << LL_ENDL; +	LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL;  #endif  	update_map_t update; @@ -2874,9 +3007,9 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	{  		LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());  		tfolder->unpackMessage(msg, _PREHASH_FolderData, i); -		LL_INFOS() << "unpacked folder '" << tfolder->getName() << "' (" -				<< tfolder->getUUID() << ") in " << tfolder->getParentUUID() -				<< LL_ENDL; +		LL_DEBUGS("Inventory") << "unpacked folder '" << tfolder->getName() << "' (" +							   << tfolder->getUUID() << ") in " << tfolder->getParentUUID() +							   << LL_ENDL;  		if(tfolder->getUUID().notNull())  		{  			folders.push_back(tfolder); @@ -2916,8 +3049,8 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)  	{  		LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;  		titem->unpackMessage(msg, _PREHASH_ItemData, i); -		LL_INFOS() << "unpacked item '" << titem->getName() << "' in " -				<< titem->getParentUUID() << LL_ENDL; +		LL_DEBUGS("Inventory") << "unpacked item '" << titem->getName() << "' in " +							   << titem->getParentUUID() << LL_ENDL;  		U32 callback_id;  		msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);  		if(titem->getUUID().notNull() ) // && callback_id.notNull() ) @@ -2994,6 +3127,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) @@ -3052,7 +3188,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()))  		{ -			LL_DEBUGS() << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL; +			LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: " << titem->getName() +								   << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << LL_ENDL;  			continue;  		}  		gInventory.updateItem(titem); @@ -3138,8 +3275,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;  } @@ -3154,8 +3290,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);  	}  } @@ -3442,6 +3577,305 @@ void LLInventoryModel::dumpInventory() const  	LL_INFOS() << "\n**********************\nEnd Inventory Dump" << LL_ENDL;  } +// 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()) +	{ +		LL_WARNS() << "no root folder id" << LL_ENDL; +		valid = false; +	} +	if (getLibraryRootFolderID().isNull()) +	{ +		LL_WARNS() << "no root folder id" << LL_ENDL; +		valid = false; +	} + +	if (mCategoryMap.size() + 1 != mParentChildCategoryTree.size()) +	{ +		// ParentChild should be one larger because of the special entry for null uuid. +		LL_INFOS() << "unexpected sizes: cat map size " << mCategoryMap.size() +				<< " parent/child " << mParentChildCategoryTree.size() << LL_ENDL; +		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) +		{ +			LL_WARNS() << "invalid cat" << LL_ENDL; +			valid = false; +			continue; +		} +		if (cat_id != cat->getUUID()) +		{ +			LL_WARNS() << "cat id/index mismatch " << cat_id << " " << cat->getUUID() << LL_ENDL; +			valid = false; +		} + +		if (cat->getParentUUID().isNull()) +		{ +			if (cat_id != getRootFolderID() && cat_id != getLibraryRootFolderID()) +			{ +				LL_WARNS() << "cat " << cat_id << " has no parent, but is not root (" +						<< getRootFolderID() << ") or library root (" +						<< getLibraryRootFolderID() << ")" << LL_ENDL; +			} +		} +		cat_array_t* cats; +		item_array_t* items; +		getDirectDescendentsOf(cat_id,cats,items); +		if (!cats || !items) +		{ +			LL_WARNS() << "invalid direct descendents for " << cat_id << LL_ENDL; +			valid = false; +			continue; +		} +		if (cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN) +		{ +			desc_unknown_count++; +		} +		else if (cats->size() + items->size() != cat->getDescendentCount()) +		{ +			LL_WARNS() << "invalid desc count for " << cat_id << " name [" << cat->getName() +					<< "] parent " << cat->getParentUUID() +					<< " cached " << cat->getDescendentCount() +					<< " expected " << cats->size() << "+" << items->size() +					<< "=" << cats->size() +items->size() << LL_ENDL; +			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->at(i); + +			if (!item) +			{ +				LL_WARNS() << "null item at index " << i << " for cat " << cat_id << LL_ENDL; +				valid = false; +				continue; +			} + +			const LLUUID& item_id = item->getUUID(); +			 +			if (item->getParentUUID() != cat_id) +			{ +				LL_WARNS() << "wrong parent for " << item_id << " found " +						<< item->getParentUUID() << " expected " << cat_id +						<< LL_ENDL; +				valid = false; +			} + + +			// Entries in items and mItemMap should correspond. +			item_map_t::const_iterator it = mItemMap.find(item_id); +			if (it == mItemMap.end()) +			{ +				LL_WARNS() << "item " << item_id << " found as child of " +						<< cat_id << " but not in top level mItemMap" << LL_ENDL; +				valid = false; +			} +			else +			{ +				LLViewerInventoryItem *top_item = it->second; +				if (top_item != item) +				{ +					LL_WARNS() << "item mismatch, item_id " << item_id +							<< " top level entry is different, uuid " << top_item->getUUID() << LL_ENDL; +				} +			} + +			// Topmost ancestor should be root or library. +			LLUUID topmost_ancestor_id; +			bool found = getObjectTopmostAncestor(item_id, topmost_ancestor_id); +			if (!found) +			{ +				LL_WARNS() << "unable to find topmost ancestor for " << item_id << LL_ENDL; +				valid = false; +			} +			else +			{ +				if (topmost_ancestor_id != getRootFolderID() && +					topmost_ancestor_id != getLibraryRootFolderID()) +				{ +					LL_WARNS() << "unrecognized top level ancestor for " << item_id +							<< " got " << topmost_ancestor_id +							<< " expected " << getRootFolderID() +							<< " or " << getLibraryRootFolderID() << LL_ENDL; +					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) +			{ +				LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() +						<< "] orphaned - no child cat array for alleged parent " << parent_id << LL_ENDL; +				valid = false; +			} +			else +			{ +				bool found = false; +				for (S32 i = 0; i<cats->size(); i++) +				{ +					LLViewerInventoryCategory *kid_cat = cats->at(i); +					if (kid_cat == cat) +					{ +						found = true; +						break; +					} +				} +				if (!found) +				{ +					LL_WARNS() << "cat " << cat_id << " name [" << cat->getName() +							<< "] orphaned - not found in child cat array of alleged parent " << parent_id << LL_ENDL; +				} +			} +		} +	} + +	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) +		{ +			LL_WARNS() << "item_id " << item_id << " does not match " << item->getUUID() << LL_ENDL; +			valid = false; +		} + +		const LLUUID& parent_id = item->getParentUUID(); +		if (parent_id.isNull()) +		{ +			LL_WARNS() << "item " << item_id << " name [" << item->getName() << "] has null parent id!" << LL_ENDL; +		} +		else +		{ +			cat_array_t* cats; +			item_array_t* items; +			getDirectDescendentsOf(parent_id,cats,items); +			if (!items) +			{ +				LL_WARNS() << "item " << item_id << " name [" << item->getName() +						<< "] orphaned - alleged parent has no child items list " << parent_id << LL_ENDL; +			} +			else +			{ +				bool found = false; +				for (S32 i=0; i<items->size(); ++i) +				{ +					if (items->at(i) == item)  +					{ +						found = true; +						break; +					} +				} +				if (!found) +				{ +					LL_WARNS() << "item " << item_id << " name [" << item->getName() +							<< "] orphaned - not found as child of alleged parent " << parent_id << LL_ENDL; +				} +			} +				 +		} +		// Link checking +		if (item->getIsLinkType()) +		{ +			const LLUUID& link_id = item->getUUID(); +			const LLUUID& target_id = item->getLinkedUUID(); +			LLViewerInventoryItem *target_item = getItem(target_id); +			LLViewerInventoryCategory *target_cat = getCategory(target_id); +			// Linked-to UUID should have back reference to this link. +			if (!hasBacklinkInfo(link_id, target_id)) +			{ +				LL_WARNS() << "link " << item->getUUID() << " type " << item->getActualType() +						<< " missing backlink info at target_id " << target_id +						<< LL_ENDL; +			} +			// Links should have referents. +			if (item->getActualType() == LLAssetType::AT_LINK && !target_item) +			{ +				LL_WARNS() << "broken item link " << item->getName() << " id " << item->getUUID() << LL_ENDL; +			} +			else if (item->getActualType() == LLAssetType::AT_LINK_FOLDER && !target_cat) +			{ +				LL_WARNS() << "broken folder link " << item->getName() << " id " << item->getUUID() << LL_ENDL; +			} +			if (target_item && target_item->getIsLinkType()) +			{ +				LL_WARNS() << "link " << item->getName() << " references a link item " +						<< target_item->getName() << " " << target_item->getUUID() << LL_ENDL; +			} + +			// Links should not have backlinks. +			std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(link_id); +			if (range.first != range.second) +			{ +				LL_WARNS() << "Link item " << item->getName() << " has backlinks!" << LL_ENDL; +			} +		} +		else +		{ +			// Check the backlinks of a non-link item. +			const LLUUID& target_id = item->getUUID(); +			std::pair<backlink_mmap_t::const_iterator, backlink_mmap_t::const_iterator> range = mBacklinkMMap.equal_range(target_id); +			for (backlink_mmap_t::const_iterator it = range.first; it != range.second; ++it) +			{ +				const LLUUID& link_id = it->second; +				LLViewerInventoryItem *link_item = getItem(link_id); +				if (!link_item || !link_item->getIsLinkType()) +				{ +					LL_WARNS() << "invalid backlink from target " << item->getName() << " to " << link_id << LL_ENDL; +				} +			} +		} +	} +	 +	if (cat_lock > 0 || item_lock > 0) +	{ +		LL_INFOS() << "Found locks on some categories: sub-cat arrays " +				<< cat_lock << ", item arrays " << item_lock << LL_ENDL; +	} +	if (desc_unknown_count != 0) +	{ +		LL_INFOS() << "Found " << desc_unknown_count << " cats with unknown descendent count" << LL_ENDL;  +	} +	if (version_unknown_count != 0) +	{ +		LL_INFOS() << "Found " << version_unknown_count << " cats with unknown version" << LL_ENDL; +	} + +	LL_INFOS() << "Validate done, valid = " << (U32) valid << LL_ENDL; + +	return valid; +} +  ///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 7dd7ac8e9a..2e957809be 100755 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -33,6 +33,7 @@  #include "llcurl.h"  #include "lluuid.h"  #include "llpermissionsflags.h" +#include "llviewerinventory.h"  #include "llstring.h"  #include "llmd5.h"  #include <map> @@ -44,14 +45,9 @@ class LLInventoryObserver;  class LLInventoryObject;  class LLInventoryItem;  class LLInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory; -class LLViewerInventoryItem; -class LLViewerInventoryCategory;  class LLMessageSystem;  class LLInventoryCollectFunctor; -  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // LLInventoryModel  // @@ -80,11 +76,12 @@ public:  	class fetchInventoryResponder : public LLCurl::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;  	}; @@ -137,6 +134,8 @@ public:  	// during authentication. Returns true if everything parsed.  	bool loadSkeleton(const LLSD& options, const LLUUID& owner_id);  	void buildParentChildMap(); // brute force method to rebuild the entire parent-child relations +	void createCommonSystemCategories(); +	  	// Call on logout to save a terse representation.  	void cache(const LLUUID& parent_folder_id, const LLUUID& agent_id);  private: @@ -155,6 +154,15 @@ private:  	parent_cat_map_t mParentChildCategoryTree;  	parent_item_map_t mParentChildItemTree; +	// Track links to items and categories. We do not store item or +	// category pointers here, because broken links are also supported. +	typedef std::multimap<LLUUID, LLUUID> backlink_mmap_t; +	backlink_mmap_t mBacklinkMMap; // key = target_id: ID of item, values = link_ids: IDs of item or folder links referencing it. +	// For internal use only +	bool hasBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id) const; +	void addBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); +	void removeBacklinkInfo(const LLUUID& link_id, const LLUUID& target_id); +	  	//--------------------------------------------------------------------  	// Login  	//-------------------------------------------------------------------- @@ -203,6 +211,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, @@ -211,22 +222,27 @@ 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. -	item_array_t collectLinkedItems(const LLUUID& item_id, -									const LLUUID& start_folder_id = LLUUID::null); -	 +	item_array_t collectLinksTo(const LLUUID& item_id);  	// 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  @@ -296,7 +312,7 @@ public:  	//    NOTE: In usage, you will want to perform cache accounting  	//    operations in LLInventoryModel::accountForUpdate() or  	//    LLViewerInventoryItem::updateServer() before calling this method. -	U32 updateItem(const LLViewerInventoryItem* item); +	U32 updateItem(const LLViewerInventoryItem* item, U32 mask = 0);  	// Change an existing item with the matching id or add  	// the category. No notifcation will be sent to observers. This @@ -305,7 +321,7 @@ public:  	//    NOTE: In usage, you will want to perform cache accounting  	//    operations in accountForUpdate() or LLViewerInventoryCategory::  	//    updateServer() before calling this method. -	void updateCategory(const LLViewerInventoryCategory* cat); +	void updateCategory(const LLViewerInventoryCategory* cat, U32 mask = 0);  	// Move the specified object id to the specified category and  	// update the internal structures. No cache accounting, @@ -326,11 +342,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 @@ -338,17 +374,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); @@ -383,8 +408,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 @@ -461,7 +485,9 @@ public:  	// been changed 'under the hood', but outside the control of the  	// inventory. The next notify will include that notification.  	void addChangedMask(U32 mask, const LLUUID& referent); +	  	const changed_items_t& getChangedIDs() const { return mChangedItemIDs; } +	const changed_items_t& getAddedIDs() const { return mAddedItemIDs; }  protected:  	// Updates all linked items pointing to this id.  	void addChangedMaskForLinks(const LLUUID& object_id, U32 mask); @@ -472,6 +498,8 @@ private:  	// Variables used to track what has changed since the last notify.  	U32 mModifyMask;  	changed_items_t mChangedItemIDs; +	changed_items_t mAddedItemIDs; +	  	//--------------------------------------------------------------------  	// Observers @@ -533,7 +561,7 @@ public:  	static void processMoveInventoryItem(LLMessageSystem* msg, void**);  	static void processFetchInventoryReply(LLMessageSystem* msg, void**);  protected: -	bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting); +	bool messageUpdateCore(LLMessageSystem* msg, bool do_accounting, U32 mask = 0x0);  	//--------------------------------------------------------------------  	// Locks @@ -555,6 +583,7 @@ private:  	//--------------------------------------------------------------------  public:  	void dumpInventory() const; +	bool validate() const;  /**                    Miscellaneous   **                                                                            ** diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index a8fda4fcf8..2de37b0790 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; +		//LL_INFOS() << "All folders fetched, validating" << LL_ENDL; +		//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. -			LL_INFOS() << "Folder " << folder_sd["folder_id"].asString()  -					<< "Error: " << folder_sd["error"].asString() << LL_ENDL; +			LL_WARNS() << "Folder " << folder_sd["folder_id"].asString()  +					   << "Error: " << folder_sd["error"].asString() << LL_ENDL;  		}  	} - -	fetcher->incrFetchCount(-1);  	if (fetcher->isBulkFetchProcessingComplete())  	{ @@ -529,21 +542,21 @@ 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()  { +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance(); -	LL_INFOS() << "LLInventoryModelFetchDescendentsResponder::error [status:" -			<< status << "]: " << content << LL_ENDL; +	LL_INFOS() << dumpResponse() << LL_ENDL;  	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 +599,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()  		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))  	{  		return; // just bail if we are disconnected -	}	 +	}  	U32 item_count=0;  	U32 folder_count=0; @@ -686,63 +699,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/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index 2cbf9bb8b6..2dd8dce42f 100755 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -465,41 +465,13 @@ void LLInventoryFetchComboObserver::startFetch()  	mFetchDescendents->startFetch();  } -void LLInventoryExistenceObserver::watchItem(const LLUUID& id) -{ -	if (id.notNull()) -	{ -		mMIA.push_back(id); -	} -} - -void LLInventoryExistenceObserver::changed(U32 mask) -{ -	// scan through the incomplete items and move or erase them as -	// appropriate. -	if (!mMIA.empty()) -	{ -		for (uuid_vec_t::iterator it = mMIA.begin(); it < mMIA.end(); ) -		{ -			LLViewerInventoryItem* item = gInventory.getItem(*it); -			if (!item) -			{ -				++it; -				continue; -			} -			mExist.push_back(*it); -			it = mMIA.erase(it); -		} -		if (mMIA.empty()) -		{ -			done(); -		} -	} -} - +// See comment preceding LLInventoryAddedObserver::changed() for some +// concerns that also apply to this observer.  void LLInventoryAddItemByAssetObserver::changed(U32 mask)  { -	if(!(mask & LLInventoryObserver::ADD)) +	if(!(mask & LLInventoryObserver::ADD) || +	   !(mask & LLInventoryObserver::CREATE) || +	   !(mask & LLInventoryObserver::UPDATE_CREATE))  	{  		return;  	} @@ -510,20 +482,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask)  		return;  	} -	LLMessageSystem* msg = gMessageSystem; -	if (!(msg->getMessageName() && (0 == strcmp(msg->getMessageName(), "UpdateCreateInventoryItem")))) +	const uuid_set_t& added = gInventory.getAddedIDs(); +	for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it)  	{ -		// this is not our message -		return; // to prevent a crash. EXT-7921; -	} - -	LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem; -	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); -	for(S32 i = 0; i < num_blocks; ++i) -	{ -		item->unpackMessage(msg, _PREHASH_InventoryData, i); +		LLInventoryItem *item = gInventory.getItem(*it);  		const LLUUID& asset_uuid = item->getAssetUUID(); -		if (item->getUUID().notNull() && asset_uuid.notNull()) +		if (item && item->getUUID().notNull() && asset_uuid.notNull())  		{  			if (isAssetWatched(asset_uuid))  			{ @@ -532,11 +496,11 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask)  			}  		}  	} - +	  	if (mAddedItems.size() == mWatchedAssets.size())  	{ -		done();  		LL_DEBUGS("Inventory_Move") << "All watched items are added & processed." << LL_ENDL; +		done();  		mAddedItems.clear();  		// Unable to clean watched items here due to somebody can require to check them in current frame. @@ -566,41 +530,28 @@ bool LLInventoryAddItemByAssetObserver::isAssetWatched( const LLUUID& asset_id )  	return std::find(mWatchedAssets.begin(), mWatchedAssets.end(), asset_id) != mWatchedAssets.end();  } +// This observer used to explicitly check for whether it was being +// called as a result of an UpdateCreateInventoryItem message. It has +// now been decoupled enough that it's not actually checking the +// message system, but now we have the special UPDATE_CREATE flag +// being used for the same purpose. Fixing this, as we would need to +// do to get rid of the message, is somewhat subtle because there's no +// particular obvious criterion for when creating a new item should +// trigger this observer and when it shouldn't. For example, creating +// a new notecard with new->notecard causes a preview window to pop up +// via the derived class LLOpenTaskOffer, but creating a new notecard +// by copy and paste does not, solely because one goes through +// UpdateCreateInventoryItem and the other doesn't.  void LLInventoryAddedObserver::changed(U32 mask)  { -	if (!(mask & LLInventoryObserver::ADD)) +	if (!(mask & LLInventoryObserver::ADD) || +		!(mask & LLInventoryObserver::CREATE) || +		!(mask & LLInventoryObserver::UPDATE_CREATE))  	{  		return;  	} -	// *HACK: If this was in response to a packet off -	// the network, figure out which item was updated. -	LLMessageSystem* msg = gMessageSystem; - -	std::string msg_name = msg->getMessageName(); -	if (msg_name.empty()) -	{ -		return; -	} -	 -	// We only want newly created inventory items. JC -	if ( msg_name != "UpdateCreateInventoryItem") -	{ -		return; -	} - -	LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem; -	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData); -	for (S32 i = 0; i < num_blocks; ++i) -	{ -		titem->unpackMessage(msg, _PREHASH_InventoryData, i); -		if (!(titem->getUUID().isNull())) -		{ -			//we don't do anything with null keys -			mAdded.push_back(titem->getUUID()); -		} -	} -	if (!mAdded.empty()) +	if (!gInventory.getAddedIDs().empty())  	{  		done();  	} @@ -613,9 +564,9 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask)  		return;  	} -	const LLInventoryModel::changed_items_t& changed_ids = gInventory.getChangedIDs(); +	const LLInventoryModel::changed_items_t& added_ids = gInventory.getAddedIDs(); -	for (LLInventoryModel::changed_items_t::const_iterator cit = changed_ids.begin(); cit != changed_ids.end(); ++cit) +	for (LLInventoryModel::changed_items_t::const_iterator cit = added_ids.begin(); cit != added_ids.end(); ++cit)  	{  		LLViewerInventoryCategory* cat = gInventory.getCategory(*cit); @@ -633,58 +584,6 @@ void LLInventoryCategoryAddedObserver::changed(U32 mask)  	}  } - -LLInventoryTransactionObserver::LLInventoryTransactionObserver(const LLTransactionID& transaction_id) : -	mTransactionID(transaction_id) -{ -} - -void LLInventoryTransactionObserver::changed(U32 mask) -{ -	if (mask & LLInventoryObserver::ADD) -	{ -		// This could be it - see if we are processing a bulk update -		LLMessageSystem* msg = gMessageSystem; -		if (msg->getMessageName() -		   && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory"))) -		{ -			// we have a match for the message - now check the -			// transaction id. -			LLUUID id; -			msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id); -			if (id == mTransactionID) -			{ -				// woo hoo, we found it -				uuid_vec_t folders; -				uuid_vec_t items; -				S32 count; -				count = msg->getNumberOfBlocksFast(_PREHASH_FolderData); -				S32 i; -				for (i = 0; i < count; ++i) -				{ -					msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i); -					if (id.notNull()) -					{ -						folders.push_back(id); -					} -				} -				count = msg->getNumberOfBlocksFast(_PREHASH_ItemData); -				for (i = 0; i < count; ++i) -				{ -					msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i); -					if (id.notNull()) -					{ -						items.push_back(id); -					} -				} - -				// call the derived class the implements this method. -				done(folders, items); -			} -		} -	} -} -  void LLInventoryCategoriesObserver::changed(U32 mask)  {  	if (!mCategoryMap.size()) @@ -702,7 +601,7 @@ void LLInventoryCategoriesObserver::changed(U32 mask)  		LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);  		if (!category)          { -            llwarns << "Category : Category id = " << cat_id << " disappeared" << llendl; +            LL_WARNS() << "Category : Category id = " << cat_id << " disappeared" << LL_ENDL;  			cat_data.mCallback();              // Keep track of those deleted categories so we can remove them              deleted_categories_ids.push_back(cat_id); @@ -833,3 +732,23 @@ LLInventoryCategoriesObserver::LLCategoryData::LLCategoryData(  {  	mItemNameHash.finalize();  } + +void LLScrollOnRenameObserver::changed(U32 mask) +{ +	if (mask & LLInventoryObserver::LABEL) +	{ +		const uuid_set_t& changed_item_ids = gInventory.getChangedIDs(); +		for (uuid_set_t::const_iterator it = changed_item_ids.begin(); it != changed_item_ids.end(); ++it) +		{ +			const LLUUID& id = *it; +			if (id == mUUID) +			{ +				mView->scrollToShowSelection(); +					 +				gInventory.removeObserver(this); +				delete this; +				return; +			} +		} +	} +} diff --git a/indra/newview/llinventoryobserver.h b/indra/newview/llinventoryobserver.h index aa1eae84d7..8cf6a6bdab 100755 --- a/indra/newview/llinventoryobserver.h +++ b/indra/newview/llinventoryobserver.h @@ -58,6 +58,9 @@ public:  		GESTURE 		= 64,  		REBUILD 		= 128, 	// Item UI changed (e.g. item type different)  		SORT 			= 256, 	// Folder needs to be resorted. +		CREATE			= 512,  // With ADD, item has just been created. +		// unfortunately a particular message is still associated with some unique semantics. +		UPDATE_CREATE	= 1024,  // With ADD, item added via UpdateCreateInventoryItem  		ALL 			= 0xffffffff  	};  	LLInventoryObserver(); @@ -152,25 +155,6 @@ protected:  };  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryExistenceObserver -// -//   Used as a base class for doing something when all the -//   observed item ids exist in the inventory somewhere. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryExistenceObserver : public LLInventoryObserver -{ -public: -	LLInventoryExistenceObserver() {} -	/*virtual*/ void changed(U32 mask); - -	void watchItem(const LLUUID& id); -protected: -	virtual void done() = 0; -	uuid_vec_t mExist; -	uuid_vec_t mMIA; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLInventoryMovedObserver  //  // This class is used as a base class for doing something when all the @@ -209,13 +193,11 @@ private:  class LLInventoryAddedObserver : public LLInventoryObserver  {  public: -	LLInventoryAddedObserver() : mAdded() {} +	LLInventoryAddedObserver() {}  	/*virtual*/ void changed(U32 mask);  protected:  	virtual void done() = 0; - -	uuid_vec_t mAdded;  };  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -241,25 +223,6 @@ protected:  };  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLInventoryTransactionObserver -// -//   Base class for doing something when an inventory transaction completes. -//   NOTE: This class is not quite complete. Avoid using unless you fix up its -//   functionality gaps. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryTransactionObserver : public LLInventoryObserver -{ -public: -	LLInventoryTransactionObserver(const LLTransactionID& transaction_id); -	/*virtual*/ void changed(U32 mask); - -protected: -	virtual void done(const uuid_vec_t& folders, const uuid_vec_t& items) = 0; - -	LLTransactionID mTransactionID; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLInventoryCompletionObserver  //  //   Base class for doing something when when all observed items are locally  @@ -326,4 +289,22 @@ protected:  	category_map_t				mCategoryMap;  }; +class LLFolderView; + +// Force a FolderView to scroll after an item in the corresponding view has been renamed. +class LLScrollOnRenameObserver: public LLInventoryObserver +{ +public: +	LLFolderView *mView; +	LLUUID mUUID; +	 +	LLScrollOnRenameObserver(const LLUUID& uuid, LLFolderView *view): +		mUUID(uuid), +		mView(view) +	{ +	} +	/* virtual */ void changed(U32 mask); +}; + +  #endif // LL_LLINVENTORYOBSERVERS_H diff --git a/indra/newview/lllistcontextmenu.cpp b/indra/newview/lllistcontextmenu.cpp index a624c9fb87..6bda8b1d0d 100755 --- a/indra/newview/lllistcontextmenu.cpp +++ b/indra/newview/lllistcontextmenu.cpp @@ -110,6 +110,7 @@ void LLListContextMenu::handleMultiple(functor_t functor, const uuid_vec_t& ids)  // static  LLContextMenu* LLListContextMenu::createFromFile(const std::string& filename)  { +	llassert(LLMenuGL::sMenuContainer != NULL);  	return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(  		filename, LLContextMenu::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());  } diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 1948475530..8e4950f5c2 100755 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -541,7 +541,7 @@ void LLLocalBitmap::updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableTyp  					{  						U32 index = gAgentWearables.getWearableIndex(wearable);  						gAgentAvatarp->setLocalTexture(reg_texind, gTextureList.getImage(new_id), FALSE, index); -						gAgentAvatarp->wearableUpdated(type, FALSE); +						gAgentAvatarp->wearableUpdated(type);  						/* telling the manager to rebake once update cycle is fully done */  						LLLocalBitmapMgr::setNeedsRebake(); diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index af194aaa1d..8d21fda8f9 100755 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -107,8 +107,8 @@ public:  private:  	/*virtual*/ void done()  	{ -		uuid_vec_t::const_iterator it = mAdded.begin(), end = mAdded.end(); -		for(; it != end; ++it) +		const uuid_set_t& added = gInventory.getAddedIDs(); +		for (uuid_set_t::const_iterator it = added.begin(); it != added.end(); ++it)  		{  			LLInventoryItem* item = gInventory.getItem(*it);  			if (!item || item->getType() != LLAssetType::AT_LANDMARK) @@ -124,8 +124,6 @@ private:  				mInput->onLandmarkLoaded(lm);  			}  		} - -		mAdded.clear();  	}  	LLLocationInputCtrl* mInput; @@ -142,7 +140,11 @@ public:  private:  	/*virtual*/ void changed(U32 mask)  	{ -		if (mask & (~(LLInventoryObserver::LABEL|LLInventoryObserver::INTERNAL|LLInventoryObserver::ADD))) +		if (mask & (~(LLInventoryObserver::LABEL| +					  LLInventoryObserver::INTERNAL| +					  LLInventoryObserver::ADD| +					  LLInventoryObserver::CREATE| +					  LLInventoryObserver::UPDATE_CREATE)))  		{  			mInput->updateAddLandmarkButton();  		} diff --git a/indra/newview/llmarketplacefunctions.cpp b/indra/newview/llmarketplacefunctions.cpp index 7907e700c4..4a7a4e268d 100755 --- a/indra/newview/llmarketplacefunctions.cpp +++ b/indra/newview/llmarketplacefunctions.cpp @@ -100,7 +100,7 @@ namespace LLMarketplaceImport  	bool hasSessionCookie();  	bool inProgress();  	bool resultPending(); -	U32 getResultStatus(); +	S32 getResultStatus();  	const LLSD& getResults();  	bool establishMarketplaceSessionCookie(); @@ -114,7 +114,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; @@ -124,23 +124,26 @@ 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"))  			{ -				LL_INFOS() << " SLM POST status: " << status << LL_ENDL; -				LL_INFOS() << " SLM POST reason: " << reason << LL_ENDL; -				LL_INFOS() << " SLM POST content: " << content.asString() << LL_ENDL; -				LL_INFOS() << " SLM POST timer: " << slmPostTimer.getElapsedTimeF32() << LL_ENDL; +				LL_INFOS() << " SLM [timer:" << slmPostTimer.getElapsedTimeF32() << "] " +						   << dumpResponse() << LL_ENDL;  			} -			// MAINT-2301 : we determined we can safely ignore that error in that context -			if (status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT) +			S32 status = getStatus(); +			if ((status == MarketplaceErrorCodes::IMPORT_REDIRECT) || +				(status == MarketplaceErrorCodes::IMPORT_AUTHENTICATION_ERROR) || +				// MAINT-2301 : we determined we can safely ignore that error in that context +				(status == MarketplaceErrorCodes::IMPORT_JOB_TIMEOUT))  			{  				if (gSavedSettings.getBOOL("InventoryOutboxLogging"))  				{ @@ -161,39 +164,37 @@ 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"))  			{ -				LL_INFOS() << " SLM GET status: " << status << LL_ENDL; -				LL_INFOS() << " SLM GET reason: " << reason << LL_ENDL; -				LL_INFOS() << " SLM GET content: " << content.asString() << LL_ENDL; -				LL_INFOS() << " SLM GET timer: " << slmGetTimer.getElapsedTimeF32() << LL_ENDL; +				LL_INFOS() << " SLM [timer:" << slmGetTimer.getElapsedTimeF32() << "] " +						   << dumpResponse() << LL_ENDL;  			}              // MAINT-2452 : Do not clear the cookie on IMPORT_DONE_WITH_ERRORS : Happens when trying to import objects with wrong permissions              // ACME-1221 : Do not clear the cookie on IMPORT_NOT_FOUND : Happens for newly created Merchant accounts that are initally empty +			S32 status = getStatus();  			if ((status >= MarketplaceErrorCodes::IMPORT_BAD_REQUEST) &&                  (status != MarketplaceErrorCodes::IMPORT_DONE_WITH_ERRORS) &&                  (status != MarketplaceErrorCodes::IMPORT_NOT_FOUND)) @@ -212,7 +213,7 @@ namespace LLMarketplaceImport  			sImportInProgress = (status == MarketplaceErrorCodes::IMPORT_PROCESSING);  			sImportGetPending = false;  			sImportResultStatus = status; -			sImportResults = content; +			sImportResults = getContent();  		}  	}; @@ -233,7 +234,7 @@ namespace LLMarketplaceImport  		return (sImportPostPending || sImportGetPending);  	} -	U32 getResultStatus() +	S32 getResultStatus()  	{  		return sImportResultStatus;  	} @@ -297,10 +298,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"))  		{ @@ -334,11 +336,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/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index df6a42db4d..a1f6a01aa0 100644..100755 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -71,8 +71,8 @@ public:  	LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback);  	virtual ~LLMaterialsResponder(); -	virtual void result(const LLSD& pContent); -	virtual void error(U32 pStatus, const std::string& pReason); +	virtual void httpSuccess(); +	virtual void httpFailure();  private:  	std::string      mMethod; @@ -92,14 +92,19 @@ LLMaterialsResponder::~LLMaterialsResponder()  {  } -void LLMaterialsResponder::result(const LLSD& pContent) +void LLMaterialsResponder::httpSuccess()  { +	const LLSD& pContent = getContent(); +  	LL_DEBUGS("Materials") << LL_ENDL;  	mCallback(true, pContent);  } -void LLMaterialsResponder::error(U32 pStatus, const std::string& pReason) +void LLMaterialsResponder::httpFailure()  { +	U32 pStatus = (U32) getStatus(); +	const std::string& pReason = getReason(); +	  	LL_WARNS("Materials")  		<< "\n--------------------------------------------------------------------------\n"  		<< mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp index 323445afa6..0178512cb5 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" @@ -390,8 +391,12 @@ BOOL LLMediaCtrl::postBuild ()  	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar;  	registar.add("Open.WebInspector", boost::bind(&LLMediaCtrl::onOpenWebInspector, this)); +	// stinson 05/05/2014 : use this as the parent of the context menu if the static menu +	// container has yet to be created +	LLPanel* menuParent = (LLMenuGL::sMenuContainer != NULL) ? dynamic_cast<LLPanel*>(LLMenuGL::sMenuContainer) : dynamic_cast<LLPanel*>(this); +	llassert(menuParent != NULL);  	mContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>( -		"menu_media_ctrl.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); +		"menu_media_ctrl.xml", menuParent, LLViewerMenuHolderGL::child_registry_t::instance());  	setVisibleCallback(boost::bind(&LLMediaCtrl::onVisibilityChanged, this, _2));  	return TRUE; @@ -576,7 +581,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 +953,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; @@ -1117,3 +1122,8 @@ void LLMediaCtrl::setTrustedContent(bool trusted)  		mMediaSource->setTrustedBrowser(trusted);  	}  } + +void LLMediaCtrl::updateContextMenuParent(LLView* pNewParent) +{ +	mContextMenu->updateParent(pNewParent); +} diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h index 5978a7a344..b07eb356ae 100755 --- a/indra/newview/llmediactrl.h +++ b/indra/newview/llmediactrl.h @@ -168,6 +168,8 @@ public:  		LLUUID getTextureID() {return mMediaTextureID;} +		void updateContextMenuParent(LLView* pNewParent); +  	protected:  		void convertInputCoords(S32& x, S32& y); 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 08d2d03b9b..80a427c0b8 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -27,8 +27,10 @@  #include "llviewerprecompiledheaders.h" +#include "apr_pools.h" +#include "apr_dso.h" +#include "llhttpconstants.h"  #include "llapr.h" -#include "llhttpstatuscodes.h"  #include "llmeshrepository.h"  #include "llagent.h" @@ -515,6 +517,7 @@ S32 LLMeshRepoThread::sRequestWaterLevel = 0;  class LLMeshHandlerBase : public LLCore::HttpHandler  {  public: +	LOG_CLASS(LLMeshHandlerBase);  	LLMeshHandlerBase()  		: LLCore::HttpHandler(),  		  mMeshParams(), @@ -547,6 +550,7 @@ public:  class LLMeshHeaderHandler : public LLMeshHandlerBase  {  public: +	LOG_CLASS(LLMeshHeaderHandler);  	LLMeshHeaderHandler(const LLVolumeParams & mesh_params)  		: LLMeshHandlerBase()  	{ @@ -603,6 +607,7 @@ public:  class LLMeshSkinInfoHandler : public LLMeshHandlerBase  	{  public: +	LOG_CLASS(LLMeshSkinInfoHandler);  	LLMeshSkinInfoHandler(const LLUUID& id, U32 offset, U32 size)  		: LLMeshHandlerBase(),  		  mMeshID(id), @@ -632,6 +637,7 @@ public:  class LLMeshDecompositionHandler : public LLMeshHandlerBase  	{  public: +	LOG_CLASS(LLMeshDecompositionHandler);  	LLMeshDecompositionHandler(const LLUUID& id, U32 offset, U32 size)  		: LLMeshHandlerBase(),  		  mMeshID(id), @@ -661,6 +667,7 @@ public:  class LLMeshPhysicsShapeHandler : public LLMeshHandlerBase  	{  public: +	LOG_CLASS(LLMeshPhysicsShapeHandler);  	LLMeshPhysicsShapeHandler(const LLUUID& id, U32 offset, U32 size)  		: LLMeshHandlerBase(),  		  mMeshID(id), @@ -736,7 +743,6 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,  	}  } -  LLMeshRepoThread::LLMeshRepoThread()  : LLThread("mesh repo"),    mHttpRequest(NULL), diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 62966e3a4e..3cd39d7c7e 100755 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -96,15 +96,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()  	{ -		LL_WARNS() << "Sending click message failed (" << status << "): [" << reason << "]" << LL_ENDL; -		LL_WARNS() << "Content: [" << content << "]" << LL_ENDL; +		LL_WARNS() << "Sending click message failed " << dumpResponse() << LL_ENDL;  	}  }; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index daa7df682b..ac00c5d986 100755 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -944,11 +944,11 @@ void LLPanelEditWearable::onCommitSexChange()          LLViewerWearable*     wearable = gAgentWearables.getViewerWearable(type, index);          if (wearable)          { -                wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); +                wearable->setVisualParamWeight(param->getID(), is_new_sex_male);          } -        param->setWeight( is_new_sex_male, FALSE ); +        param->setWeight( is_new_sex_male); -        gAgentAvatarp->updateSexDependentLayerSets( FALSE ); +        gAgentAvatarp->updateSexDependentLayerSets();          gAgentAvatarp->updateVisualParams(); @@ -983,7 +983,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl)                                  U32 index = gAgentWearables.getWearableIndex(getWearable());                                  gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index);                                  LLVisualParamHint::requestHintUpdates(); -                                gAgentAvatarp->wearableUpdated(type, FALSE); +                                gAgentAvatarp->wearableUpdated(type);                          }                  }                  else @@ -1007,9 +1007,9 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* ctrl)                          const LLColor4& new_color = LLColor4(ctrl->getValue());                          if( old_color != new_color )                          { -                                getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); +                                getWearable()->setClothesColor(entry->mTextureIndex, new_color);                                  LLVisualParamHint::requestHintUpdates(); -                                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); +                                gAgentAvatarp->wearableUpdated(getWearable()->getType());                          }                  }                  else @@ -1080,10 +1080,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          { @@ -1093,17 +1093,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() << LL_ENDL; + +				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, new_name);          } @@ -1121,7 +1123,7 @@ void LLPanelEditWearable::revertChanges()          mNameEditor->setText(mWearableItem->getName());          updatePanelPickerControls(mWearablePtr->getType());          updateTypeSpecificControls(mWearablePtr->getType()); -        gAgentAvatarp->wearableUpdated(mWearablePtr->getType(), FALSE); +        gAgentAvatarp->wearableUpdated(mWearablePtr->getType());  }  void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BOOL disable_camera_switch) @@ -1583,7 +1585,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL                  LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE );                  U32 index = gAgentWearables.getWearableIndex(getWearable());                  gAgentAvatarp->setLocalTexture(te, image, FALSE, index); -                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); +                gAgentAvatarp->wearableUpdated(getWearable()->getType());          }          else          { @@ -1600,7 +1602,7 @@ void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LL                  U32 index = gAgentWearables.getWearableIndex(getWearable());                  gAgentAvatarp->setLocalTexture(te, image, FALSE, index); -                gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); +                gAgentAvatarp->wearableUpdated(getWearable()->getType());          }          updatePanelPickerControls(getWearable()->getType()); diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 343f2b413f..67cbc91332 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)  {  	LL_WARNS() << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<<LL_ENDL;  } diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 80310d1524..c11cbe05ae 100755 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -108,7 +108,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 e2b4d098e9..088eaa8e0d 100755 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -421,7 +421,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);  	} @@ -785,7 +785,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/llpanelmarketplaceinboxinventory.cpp b/indra/newview/llpanelmarketplaceinboxinventory.cpp index 2f65bedc2b..f7c2f629ec 100755 --- a/indra/newview/llpanelmarketplaceinboxinventory.cpp +++ b/indra/newview/llpanelmarketplaceinboxinventory.cpp @@ -129,11 +129,11 @@ void LLInboxFolderViewFolder::addItem(LLFolderViewItem* item)  // virtual  void LLInboxFolderViewFolder::draw()  { -	if (!badgeHasParent()) +	if (!hasBadgeHolderParent())  	{ -		addBadgeToParentPanel(); +		addBadgeToParentHolder();  	} -	 +  	setBadgeVisibility(mFresh);  	LLFolderViewFolder::draw(); @@ -214,9 +214,9 @@ BOOL LLInboxFolderViewItem::handleDoubleClick(S32 x, S32 y, MASK mask)  // virtual  void LLInboxFolderViewItem::draw()  { -	if (!badgeHasParent()) +	if (!hasBadgeHolderParent())  	{ -		addBadgeToParentPanel(); +		addBadgeToParentHolder();  	}  	setBadgeVisibility(mFresh); diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp index e48aa88937..496168229d 100755 --- a/indra/newview/llpaneloutfitedit.cpp +++ b/indra/newview/llpaneloutfitedit.cpp @@ -159,6 +159,7 @@ public:  		registrar.add("Wearable.Create", boost::bind(onCreate, _2)); +		llassert(LLMenuGL::sMenuContainer != NULL);  		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(  			"menu_cof_gear.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());  		llassert(menu); @@ -228,6 +229,7 @@ public:  		enable_registrar.add("AddWearable.Gear.Check", boost::bind(onCheck, flat_list_handle, inventory_panel_handle, _2));  		enable_registrar.add("AddWearable.Gear.Visible", boost::bind(onVisible, inventory_panel_handle, _2)); +		llassert(LLMenuGL::sMenuContainer != NULL);  		LLToggleableMenu* menu = LLUICtrlFactory::getInstance()->createFromFile<LLToggleableMenu>(  			"menu_add_wearable_gear.xml",  			LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); @@ -1184,12 +1186,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 3c72607678..1e1f59055f 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 c05b379fd8..2be96b9b78 100755 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -168,8 +168,7 @@ public:  protected:  	/*virtual*/ void done()  	{ -		mPlaces->showAddedLandmarkInfo(mAdded); -		mAdded.clear(); +		mPlaces->showAddedLandmarkInfo(gInventory.getAddedIDs());  	}  private: @@ -217,7 +216,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)  	{  		LL_ERRS() << "Can't complete remote parcel request. Http Status: "  			   << status << ". Reason : " << reason << LL_ENDL; @@ -1100,9 +1099,9 @@ void LLPanelPlaces::changedGlobalPos(const LLVector3d &global_pos)  	updateVerbs();  } -void LLPanelPlaces::showAddedLandmarkInfo(const uuid_vec_t& items) +void LLPanelPlaces::showAddedLandmarkInfo(const uuid_set_t& items)  { -	for (uuid_vec_t::const_iterator item_iter = items.begin(); +	for (uuid_set_t::const_iterator item_iter = items.begin();  		 item_iter != items.end();  		 ++item_iter)  	{ diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h index b6019ca32e..c3d1b9bc53 100755 --- a/indra/newview/llpanelplaces.h +++ b/indra/newview/llpanelplaces.h @@ -69,7 +69,7 @@ public:  	void changedGlobalPos(const LLVector3d &global_pos);  	// Opens landmark info panel when agent creates or receives landmark. -	void showAddedLandmarkInfo(const uuid_vec_t& items); +	void showAddedLandmarkInfo(const uuid_set_t& items);  	void setItem(LLInventoryItem* item); diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp index 8fddd9523f..652d2be6f6 100755 --- a/indra/newview/llpanelteleporthistory.cpp +++ b/indra/newview/llpanelteleporthistory.cpp @@ -341,6 +341,7 @@ LLContextMenu* LLTeleportHistoryPanel::ContextMenu::createMenu()  	registrar.add("TeleportHistory.CopyToClipboard",boost::bind(&LLTeleportHistoryPanel::ContextMenu::onCopyToClipboard, this));  	// create the context menu from the XUI +	llassert(LLMenuGL::sMenuContainer != NULL);  	return LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(  		"menu_teleport_history_item.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance());  } @@ -935,6 +936,7 @@ void LLTeleportHistoryPanel::onAccordionTabRightClick(LLView *view, S32 x, S32 y  	registrar.add("TeleportHistory.TabClose",	boost::bind(&LLTeleportHistoryPanel::onAccordionTabClose, this, tab));  	// create the context menu from the XUI +	llassert(LLMenuGL::sMenuContainer != NULL);  	mAccordionTabMenu = LLUICtrlFactory::getInstance()->createFromFile<LLContextMenu>(  		"menu_teleport_history_tab.xml", LLMenuGL::sMenuContainer, LLViewerMenuHolderGL::child_registry_t::instance()); diff --git a/indra/newview/llpathfindingmanager.cpp b/indra/newview/llpathfindingmanager.cpp index ae5b3b4e76..4977a72dc6 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()  { -	LL_WARNS() << "NavMeshStatusResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	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); +	LL_WARNS() << dumpResponse() << LL_ENDL; +	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()  { -	LL_WARNS() << "AgentStateResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	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()  { -	LL_WARNS() << "NavMeshRebakeResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	mRebakeNavMeshCallback(false);  } @@ -918,11 +905,9 @@ 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()  { -	LL_WARNS() << "LinksetsResponder object linksets error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << "LinksetsResponder object linksets error" << LL_ENDL;  	mObjectMessagingState = kReceivedError;  	if (mTerrainMessagingState != kWaiting)  	{ @@ -941,11 +926,9 @@ 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()  { -	LL_WARNS() << "LinksetsResponder terrain linksets error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << "LinksetsResponder terrain linksets error" << LL_ENDL;  	mTerrainMessagingState = kReceivedError;  	if (mObjectMessagingState != kWaiting)  	{ @@ -979,9 +962,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 +972,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); +	LL_WARNS() << dumpResponse() << LL_ENDL; +	mLinksetsResponsderPtr->handleObjectLinksetsError();  }  //---------------------------------------------------------------------------  // TerrainLinksetsResponder  //--------------------------------------------------------------------------- -TerrainLinksetsResponder::TerrainLinksetsResponder(const std::string &pCapabilityURL, LinksetsResponderPtr pLinksetsResponsderPtr) +TerrainLinksetsResponder::TerrainLinksetsResponder(LinksetsResponderPtr pLinksetsResponsderPtr)  	: LLHTTPClient::Responder(), -	mCapabilityURL(pCapabilityURL),  	mLinksetsResponsderPtr(pLinksetsResponsderPtr)  {  } @@ -1015,23 +997,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); +	LL_WARNS() << dumpResponse() << LL_ENDL; +	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 +1023,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()  { -	LL_WARNS() << "CharactersResponder error [status:" << pStatus << "]: " << pContent << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	LLPathfindingObjectListPtr characterListPtr =  LLPathfindingObjectListPtr(new LLPathfindingCharacterList());  	mCharactersCallback(mRequestId, LLPathfindingManager::kRequestError, characterListPtr); diff --git a/indra/newview/llpathfindingnavmesh.cpp b/indra/newview/llpathfindingnavmesh.cpp index 40f5d8c23e..0287c07f96 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)  { -	LL_WARNS() << "LLPathfindingNavMesh error with request to URL '" << pURL << "' [status:" -			<< pStatus << "]: " << pContent << LL_ENDL;  	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/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index 05ef436bd9..ea10d03264 100755 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -668,9 +668,7 @@ BOOL LLPhysicsMotion::onUpdate(F32 time)  			if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) &&  			    (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT))  			{ -				mCharacter->setVisualParamWeight(driver_param, -								 0, -								 FALSE); +				mCharacter->setVisualParamWeight(driver_param, 0);  			}  			S32 num_driven = driver_param->getDrivenParamsCount();  			for (S32 i = 0; i < num_driven; ++i) @@ -770,7 +768,5 @@ void LLPhysicsMotion::setParamValue(const LLViewerVisualParam *param,  	// Scale from [0,1] to [value_min_local,value_max_local]          const F32 new_value_local = value_min_local + (value_max_local-value_min_local) * new_value_rescaled; -        mCharacter->setVisualParamWeight(param, -                                         new_value_local, -                                         FALSE); +        mCharacter->setVisualParamWeight(param, new_value_local);  } diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index b379ef7bdb..6d032ad3d3 100755 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -400,13 +400,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 e85194d173..e92bf4590d 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()  	{ -		LL_WARNS() << "LLProductInfoRequest error [status:" -				<< status << ":] " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  	}  }; diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 13120fdf45..29dcc12f9e 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()  { -	LL_WARNS() << "LLRemoteParcelRequest error [status:" -			<< status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	// 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 e4b8791f7c..35348b69ff 100755 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -38,16 +38,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;  }; @@ -79,7 +80,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/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 6a840f3f40..8708fb87ee 100755 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -273,6 +273,14 @@ void LLScreenChannel::addToast(const LLToast::Params& p)  			// only cancel notification if it isn't being used in IM session  			LLNotifications::instance().cancel(notification);  		} + +		// It was assumed that the toast would take ownership of the panel pointer. +		// But since we have decided not to display the toast, kill the panel to +		// prevent the memory leak. +		if (p.panel != NULL) +		{ +			p.panel()->die(); +		}  		return;  	} diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index a7e24b86b1..bfa453a0ae 100755 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -266,7 +266,7 @@ void LLScrollingPanelParam::onHintHeldDown( LLVisualParamHint* hint )  			if (slider->getMinValue() < new_percent  				&& new_percent < slider->getMaxValue())  			{ -				mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight, FALSE); +				mWearable->setVisualParamWeight( hint->getVisualParam()->getID(), new_weight);  				mWearable->writeToAvatar(gAgentAvatarp);  				gAgentAvatarp->updateVisualParams(); @@ -299,7 +299,7 @@ void LLScrollingPanelParam::onHintMinMouseUp( void* userdata )  			if (slider->getMinValue() < new_percent  				&& new_percent < slider->getMaxValue())  			{ -				self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); +				self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);  				self->mWearable->writeToAvatar(gAgentAvatarp);  				slider->setValue( self->weightToPercent( new_weight ) );  			} @@ -333,7 +333,7 @@ void LLScrollingPanelParam::onHintMaxMouseUp( void* userdata )  				if (slider->getMinValue() < new_percent  					&& new_percent < slider->getMaxValue())  				{ -					self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight, FALSE); +					self->mWearable->setVisualParamWeight(hint->getVisualParam()->getID(), new_weight);  					self->mWearable->writeToAvatar(gAgentAvatarp);  					slider->setValue( self->weightToPercent( new_weight ) );  				} diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index 8e083ddb6c..fe7a362723 100755 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -93,7 +93,7 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl, void* userdata)  	F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() );  	if (current_weight != new_weight )  	{ -		self->mWearable->setVisualParamWeight( param->getID(), new_weight, FALSE ); +		self->mWearable->setVisualParamWeight( param->getID(), new_weight);  		self->mWearable->writeToAvatar(gAgentAvatarp);  		gAgentAvatarp->updateVisualParams();  	} diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp index c938a478f7..64f24cd291 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/llspatialpartition.h b/indra/newview/llspatialpartition.h index a7b99a0f6b..08a4d00d0f 100755 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -640,12 +640,26 @@ class LLVolumeGeometryManager: public LLGeometryManager  		DISTANCE_SORT  	} eSortType; -	virtual ~LLVolumeGeometryManager() { } +	LLVolumeGeometryManager(); +	virtual ~LLVolumeGeometryManager();  	virtual void rebuildGeom(LLSpatialGroup* group);  	virtual void rebuildMesh(LLSpatialGroup* group);  	virtual void getGeometry(LLSpatialGroup* group);  	void genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL no_materials = FALSE);  	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type); + +private: +	void allocateFaces(U32 pMaxFaceCount); +	void freeFaces(); + +	static int32_t sInstanceCount; +	static LLFace** sFullbrightFaces; +	static LLFace** sBumpFaces; +	static LLFace** sSimpleFaces; +	static LLFace** sNormFaces; +	static LLFace** sSpecFaces; +	static LLFace** sNormSpecFaces; +	static LLFace** sAlphaFaces;  };  //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp) diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index f25076d47e..89302c3c64 100755 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -270,21 +270,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()  	{ -		LL_WARNS() << status << ": " << reason << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		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", @@ -855,10 +857,7 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update)  		}  	}  } -/*prep# -	virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -		LL_WARNS() << "ModerationResponder error [status:" << status << "]: " << content << LL_ENDL; -		*/ +  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 a76b4bbe09..56fac3b092 100755 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -311,6 +311,12 @@ void update_texture_fetch()  	gTextureList.updateImages(0.10f);  } +void set_flags_and_update_appearance() +{ +	LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); +	LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); +} +  // Returns false to skip other idle processing. Should only return  // true when all initialization done.  bool idle_startup() @@ -1287,6 +1293,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(); @@ -1771,6 +1779,15 @@ bool idle_startup()  		// This method MUST be called before gInventory.findCategoryUUIDForType because of   		// gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.  		gInventory.buildParentChildMap(); +		gInventory.createCommonSystemCategories(); + +		// It's debatable whether this flag is a good idea - sets all +		// bits, and in general it isn't true that inventory +		// initialization generates all types of changes. Maybe add an +		// INITIALIZE mask bit instead? +		gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); +		gInventory.notifyObservers(); +		  		display_startup();  		//all categories loaded. lets create "My Favorites" category @@ -2018,7 +2035,7 @@ bool idle_startup()  	{  		display_startup();  		F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY; - +		  		// We now have an inventory skeleton, so if this is a user's first  		// login, we can start setting up their clothing and avatar   		// appearance.  This helps to avoid the generic "Ruth" avatar in @@ -2027,18 +2044,38 @@ bool idle_startup()  			&& !sInitialOutfit.empty()    // registration set up an outfit  			&& !sInitialOutfitGender.empty() // and a gender  			&& isAgentAvatarValid()	  // can't wear clothes without object -			&& !gAgent.isGenderChosen() ) // nothing already loading +			&& !gAgent.isOutfitChosen()) // nothing already loading  		{  			// Start loading the wearables, textures, gestures  			LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender );  		} +		// If not first login, we need to fetch COF contents and +		// compute appearance from that. +		if (isAgentAvatarValid() && !gAgent.isFirstLogin() && !gAgent.isOutfitChosen()) +		{ +			gAgentWearables.notifyLoadingStarted(); +			gAgent.setOutfitChosen(TRUE); +			gAgentWearables.sendDummyAgentWearablesUpdate(); +			callAfterCategoryFetch(LLAppearanceMgr::instance().getCOF(), set_flags_and_update_appearance); +		}  		display_startup();  		// wait precache-delay and for agent's avatar or a lot longer. -		if(((timeout_frac > 1.f) && isAgentAvatarValid()) -		   || (timeout_frac > 3.f)) +		if ((timeout_frac > 1.f) && isAgentAvatarValid()) +		{ +			LLStartUp::setStartupState( STATE_WEARABLES_WAIT ); +		} +		else if (timeout_frac > 10.f)   		{ +			// If we exceed the wait above while isAgentAvatarValid is +			// not true yet, we will change startup state and +			// eventually (once avatar does get created) wind up at +			// the gender chooser. This should occur only in very +			// unusual circumstances, so set the timeout fairly high +			// to minimize mistaken hits here. +			LL_WARNS() << "Wait for valid avatar state exceeded "  +					<< timeout.getElapsedTimeF32() << " will invoke gender chooser" << LL_ENDL;   			LLStartUp::setStartupState( STATE_WEARABLES_WAIT );  		}  		else @@ -2060,12 +2097,11 @@ bool idle_startup()  		const F32 wearables_time = wearables_timer.getElapsedTimeF32();  		static LLCachedControl<F32> max_wearables_time(gSavedSettings, "ClothingLoadingDelay"); -		display_startup(); -		if (!gAgent.isGenderChosen() && isAgentAvatarValid()) +		if (!gAgent.isOutfitChosen() && isAgentAvatarValid())  		{ -			// No point in waiting for clothing, we don't even -			// know what gender we are.  Pop a dialog to ask and -			// proceed to draw the world. JC +			// No point in waiting for clothing, we don't even know +			// what outfit we want.  Pop up a gender chooser dialog to +			// ask and proceed to draw the world. JC  			//  			// *NOTE: We might hit this case even if we have an  			// initial outfit, but if the load hasn't started @@ -2075,7 +2111,10 @@ bool idle_startup()  				callback_choose_gender);  			LLStartUp::setStartupState( STATE_CLEANUP );  		} -		else if (wearables_time >= max_wearables_time()) +		 +		display_startup(); + +		if (gAgent.isOutfitChosen() && (wearables_time > max_wearables_time))  		{  			LLNotificationsUtil::add("ClothingLoading");  			record(LLStatViewer::LOADING_WEARABLES_LONG_DELAY, wearables_time); @@ -2086,25 +2125,24 @@ bool idle_startup()  				&& gAgentAvatarp->isFullyLoaded())  		{  			// wait for avatar to be completely loaded -			//LL_INFOS() << "avatar fully loaded" << LL_ENDL; -			LLStartUp::setStartupState( STATE_CLEANUP ); -		} -		// OK to just get the wearables -		else if (!gAgent.isFirstLogin() && gAgentWearables.areWearablesLoaded() ) -		{ -			// We have our clothing, proceed. -			//LL_INFOS() << "wearables loaded" << LL_ENDL; -			LLStartUp::setStartupState( STATE_CLEANUP ); +			if (isAgentAvatarValid() +				&& gAgentAvatarp->isFullyLoaded()) +			{ +				LL_DEBUGS("Avatar") << "avatar fully loaded" << LL_ENDL; +				LLStartUp::setStartupState( STATE_CLEANUP ); +				return TRUE; +			}  		}  		else  		{ -			display_startup(); -			update_texture_fetch(); -			display_startup(); -			set_startup_status(0.9f + 0.1f * wearables_time / max_wearables_time(), -				LLTrans::getString("LoginDownloadingClothing").c_str(), -				gAgent.mMOTD.c_str()); -			display_startup(); +			// OK to just get the wearables +			if ( gAgentWearables.areWearablesLoaded() ) +			{ +				// We have our clothing, proceed. +				LL_DEBUGS("Avatar") << "wearables loaded" << LL_ENDL; +				LLStartUp::setStartupState( STATE_CLEANUP ); +				return TRUE; +			}  		}  		//fall through this frame to STATE_CLEANUP  	} @@ -2351,8 +2389,6 @@ void register_viewer_callbacks(LLMessageSystem* msg)  	msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair,	process_remove_name_value);  	msg->setHandlerFuncFast(_PREHASH_AvatarAnimation,		process_avatar_animation);  	msg->setHandlerFuncFast(_PREHASH_AvatarAppearance,		process_avatar_appearance); -	msg->setHandlerFunc("AgentCachedTextureResponse",	LLAgent::processAgentCachedTextureResponse); -	msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);  	msg->setHandlerFuncFast(_PREHASH_CameraConstraint,		process_camera_constraint);  	msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse,		process_avatar_sit_response);  	msg->setHandlerFunc("SetFollowCamProperties",			process_set_follow_cam_properties); @@ -2426,9 +2462,6 @@ void register_viewer_callbacks(LLMessageSystem* msg)  	// msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply,  	//					LLFloaterRate::processReputationIndividualReply); -	msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, -						LLAgentWearables::processAgentInitialWearablesUpdate ); -  	msg->setHandlerFunc("ScriptControlChange",  						LLAgent::processScriptControlChange ); @@ -2585,9 +2618,8 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,  		LL_DEBUGS() << "initial outfit category id: " << cat_id << LL_ENDL;  	} -	// This is really misnamed -- it means we have started loading -	// an outfit/shape that will give the avatar a gender eventually. JC -	gAgent.setGenderChosen(TRUE); +	gAgent.setOutfitChosen(TRUE); +	gAgentWearables.sendDummyAgentWearablesUpdate();  }  //static @@ -2600,10 +2632,10 @@ void LLStartUp::saveInitialOutfit()  	if (sWearablesLoadedCon.connected())  	{ -		LL_DEBUGS() << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL; +		LL_DEBUGS("Avatar") << "sWearablesLoadedCon is connected, disconnecting" << LL_ENDL;  		sWearablesLoadedCon.disconnect();  	} -	LL_DEBUGS() << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL; +	LL_DEBUGS("Avatar") << "calling makeNewOutfitLinks( \"" << sInitialOutfit << "\" )" << LL_ENDL;  	LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);  } @@ -3348,7 +3380,11 @@ bool process_login_success_response()  		flag = login_flags["gendered"].asString();  		if(flag == "Y")  		{ -			gAgent.setGenderChosen(TRUE); +			// We don't care about this flag anymore; now base whether +			// outfit is chosen on COF contents, initial outfit +			// requested and available, etc. + +			//gAgent.setGenderChosen(TRUE);  		}  		bool pacific_daylight_time = false; diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 2acd38b753..14a42dd8dc 100755 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -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" @@ -64,6 +64,8 @@  #include "bufferarray.h"  #include "bufferstream.h" +#include "llhttpretrypolicy.h" +  bool LLTextureFetchDebugger::sDebuggerEnabled = false ;  LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > LLTextureFetch::sCacheHitRate("texture_cache_hits");  LLTrace::EventStatHandle<F64Milliseconds > LLTextureFetch::sCacheReadLatency("texture_cache_read_latency"); @@ -245,6 +247,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  { @@ -383,12 +404,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, @@ -549,6 +572,8 @@ private:  	S32 mActiveCount;  	LLCore::HttpStatus mGetStatus;  	std::string mGetReason; +	LLAdaptiveRetryPolicy mFetchRetryPolicy; +  	// Work Data  	LLMutex mWorkMutex; @@ -894,7 +919,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() ; @@ -1153,6 +1179,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  	} @@ -1183,9 +1210,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  																		  offset, size, responder);  				mCacheReadTimer.reset();  			} -/* SH-3980 - disabling caching of server bakes until we can fix the blurring problems */ -/*			else if ((mUrl.empty()||mFTType==FTT_SERVER_BAKE) && mFetcher->canLoadFromCache()) */ -			else if (mUrl.empty() && mFetcher->canLoadFromCache()) +			else if ((mUrl.empty() || mFTType==FTT_SERVER_BAKE) && mFetcher->canLoadFromCache())  			{  				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it @@ -1275,6 +1300,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) +			{ +				LL_INFOS() << mID << " retrying now" << LL_ENDL; +			} +			else +			{ +				//LL_INFOS() << mID << " waiting to retry for " << wait_seconds << " seconds" << LL_ENDL; +				return false; +			} +		} +  		static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP", true);  // 		if (mHost != LLHost::invalid) get_url = false; @@ -1291,7 +1331,11 @@ bool LLTextureFetchWorker::doWork(S32 param)  				std::string http_url = region->getHttpUrl() ;  				if (!http_url.empty())  				{ -					mUrl = http_url + "/?texture_id=" + mID.asString().c_str(); +					if (mFTType != FTT_DEFAULT) +					{ +						LL_WARNS() << "trying to seek a non-default texture on the sim. Bad!" << LL_ENDL; +					} +					setUrl(http_url + "/?texture_id=" + mID.asString().c_str());  					mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.  				}  				else @@ -1306,12 +1350,11 @@ bool LLTextureFetchWorker::doWork(S32 param)  				mCanUseHTTP = false;  			}  		} -#if 0 /* SH-3980 - disabling caching of server bakes until we can fix the blurring problems */ -		if (mFTType == FTT_SERVER_BAKE) +		else if (mFTType == FTT_SERVER_BAKE)  		{  			mWriteToCacheState = CAN_WRITE;  		} -#endif +  		if (mCanUseHTTP && !mUrl.empty())  		{  			setState(WAIT_HTTP_RESOURCE); @@ -1345,7 +1388,6 @@ bool LLTextureFetchWorker::doWork(S32 param)  			//recordTextureStart(false);  			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); -			LL_DEBUGS("Texture") << mID << " does this happen?" << LL_ENDL;  			return false;  		}  	} @@ -1487,12 +1529,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);  		} @@ -1524,16 +1568,22 @@ bool LLTextureFetchWorker::doWork(S32 param)  			{  				if (http_not_found == mGetStatus)  				{ -					if(mWriteToCacheState == NOT_WRITE) //map tiles +					if (mFTType != FTT_MAP_TILE) +					{ +						LL_WARNS() << "Texture missing from server (404): " << mUrl << LL_ENDL; +					} + +					if(mWriteToCacheState == NOT_WRITE) //map tiles or server bakes  					{  						setState(DONE);  						releaseHttpSemaphore(); -						LL_DEBUGS("Texture") << mID << " abort: WAIT_HTTP_REQ not found" << LL_ENDL; -						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" << LL_ENDL; +						} +						return true;   					} -					LL_WARNS() << "Texture missing from server (404): " << mUrl << LL_ENDL; -  					// roll back to try UDP  					if (mCanUseNET)  					{ @@ -1548,6 +1598,10 @@ bool LLTextureFetchWorker::doWork(S32 param)  				else if (http_service_unavail == mGetStatus)  				{  					LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL; +					LL_INFOS() << "503: HTTP GET failed for: " << mUrl +							<< " Status: " << mGetStatus.toHex() +							<< " Reason: '" << mGetReason << "'" +							<< LL_ENDL;  				}  				else if (http_not_sat == mGetStatus)  				{ @@ -1562,7 +1616,10 @@ bool LLTextureFetchWorker::doWork(S32 param)  							<< LL_ENDL;  				} -				mUrl.clear(); +				if (mFTType != FTT_SERVER_BAKE) +				{ +					mUrl.clear(); +				}  				if (cur_size > 0)  				{  					// Use available data @@ -1589,7 +1646,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  			// Clear the url since we're done with the fetch  			// Note: mUrl is used to check is fetching is required so failure to clear it will force an http fetch  			// next time the texture is requested, even if the data have already been fetched. -			if(mWriteToCacheState != NOT_WRITE) +			if(mWriteToCacheState != NOT_WRITE && mFTType != FTT_SERVER_BAKE)  			{  				// Why do we want to keep url if NOT_WRITE - is this a proxy for map tiles?  				mUrl.clear(); @@ -1768,7 +1825,7 @@ bool LLTextureFetchWorker::doWork(S32 param)  				if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0)  				{  					// Cache file should be deleted, try again -// 					LL_WARNS() << mID << ": Decode of cached file failed (removed), retrying" << LL_ENDL; + 					LL_WARNS() << mID << ": Decode of cached file failed (removed), retrying" << LL_ENDL;  					llassert_always(mDecodeHandle == 0);  					mFormattedImage = NULL;  					++mRetryAttempt; @@ -1895,14 +1952,48 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe  		mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, LLTimer::getTotalTime());  	} +	static LLCachedControl<F32> fake_failure_rate(gSavedSettings, "TextureFetchFakeFailureRate", 0.0f); +	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)) +	{ +		LL_WARNS() << mID << " for debugging, setting fake failure status for texture " << mID +				<< " (rand was " << rand_val << "/" << rate << ")" << LL_ENDL; +		response->setStatus(LLCore::HttpStatus(503)); +	}  	bool success = true;  	bool partial = false;  	LLCore::HttpStatus status(response->getStatus()); +	if (!status && (mFTType == FTT_SERVER_BAKE)) +	{ +		LL_INFOS() << mID << " state " << e_state_name[mState] << LL_ENDL; +		mFetchRetryPolicy.onFailure(response); +		F32 retry_after; +		if (mFetchRetryPolicy.shouldRetry(retry_after)) +		{ +			LL_INFOS() << mID << " will retry after " << retry_after << " seconds, resetting state to LOAD_FROM_NETWORK" << LL_ENDL; +			mFetcher->removeFromHTTPQueue(mID, S32Bytes(0)); +			std::string reason(status.toString()); +			setGetStatus(status, reason); +			releaseHttpSemaphore(); +			setState(LOAD_FROM_NETWORK); +			return; +		} +		else +		{ +			LL_INFOS() << mID << " will not retry" << LL_ENDL; +		} +	} +	else +	{ +		mFetchRetryPolicy.onSuccess(); +	}  	LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID -			 << " status: " << status.toTerseString() -			 << " '" << status.toString() << "'" +						 << " status: " << status.toTerseString() +						 << " '" << status.toString() << "'"  						 << LL_ENDL; +  //	unsigned int offset(0), length(0), full_length(0);  //	response->getRange(&offset, &length, &full_length);  // 	LL_WARNS() << "HTTP COMPLETE: " << mID << " handle: " << handle @@ -1911,13 +2002,18 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe  // 			<< " offset: " << offset << " length: " << length  // 			<< LL_ENDL; +	std::string reason(status.toString()); +	setGetStatus(status, reason);  	if (! status)  	{  		success = false; -		std::string reason(status.toString()); -		setGetStatus(status, reason); -		LL_WARNS() << "CURL GET FAILED, status: " << status.toTerseString() -				<< " reason: " << reason << LL_ENDL; +		if (mFTType != FTT_MAP_TILE) // missing map tiles are normal, don't complain about them. +		{ +			std::string reason(status.toString()); +			setGetStatus(status, reason); +			LL_WARNS() << "CURL GET FAILED, status: " << status.toTerseString() +					<< " reason: " << reason << LL_ENDL; +		}  	}  	else  	{ @@ -2477,7 +2573,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 << " type " << f_type << LL_ENDL; +	}  	LLTextureFetchWorker* worker = getWorker(id) ;  	if (worker)  	{ @@ -2493,7 +2593,18 @@ bool LLTextureFetch::createRequest(FTType f_type, const std::string& url, const  	S32 desired_size;  	std::string exten = gDirUtilp->getExtension(url); -	if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)) +	if (f_type == FTT_SERVER_BAKE) +	{ +		// SH-4030: This case should be redundant with the following one, just +		// breaking it out here to clarify that it's intended behavior. +		llassert(!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C)); + +		// Do full requests for baked textures to reduce interim blurring. +		LL_DEBUGS("Texture") << "full request for " << id << " texture is FTT_SERVER_BAKE" << LL_ENDL; +		desired_size = MAX_IMAGE_DATA_SIZE; +		desired_discard = 0; +	} +	else if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))  	{  		LL_DEBUGS("Texture") << "full request for " << id << " exten is not J2C: " << exten << LL_ENDL;  		// Only do partial requests for J2C at the moment @@ -2535,7 +2646,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); @@ -2562,7 +2674,8 @@ 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 << LL_ENDL; + 	LL_DEBUGS("Texture") << "REQUESTED: " << id << " f_type " << fttype_to_string(f_type) +						 << " Discard: " << desired_discard << " size " << desired_size << LL_ENDL;  	return true;  } @@ -2741,7 +2854,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); @@ -2763,6 +2877,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; @@ -3233,25 +3348,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] << LL_ENDL; +	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] << LL_ENDL; +	}  	mState = new_state;  } @@ -4016,7 +4120,7 @@ LLTextureFetchDebugger::~LLTextureFetchDebugger()  void LLTextureFetchDebugger::init()  { -	mState = IDLE; +	setDebuggerState(IDLE);  	mCacheReadTime = -1.f;  	mCacheWriteTime = -1.f; @@ -4113,7 +4217,7 @@ void LLTextureFetchDebugger::startDebug()  	//clear the current fetching queue  	gTextureList.clearFetchingRequests(); -	mState = START_DEBUG; +	setDebuggerState(START_DEBUG);  }  bool LLTextureFetchDebugger::processStartDebug(F32 max_time) @@ -4188,7 +4292,7 @@ void LLTextureFetchDebugger::tryToStopDebug()  	//clear the current debug work  	S32 size = mFetchingHistory.size(); -	switch(mState) +	switch(mDebuggerState)  	{  	case READ_CACHE:		  		for(S32 i = 0 ; i < size; i++) @@ -4261,7 +4365,7 @@ void LLTextureFetchDebugger::addHistoryEntry(LLTextureFetchWorker* worker)  	if(mFreezeHistory)  	{ -		if(mState == REFETCH_VIS_CACHE || mState == REFETCH_VIS_HTTP) +		if(mDebuggerState == REFETCH_VIS_CACHE || mDebuggerState == REFETCH_VIS_HTTP)  		{  			mRefetchedVisPixels += worker->mRawImage->getWidth() * worker->mRawImage->getHeight();  			mRefetchedVisData += worker->mFormattedImage->getDataSize(); @@ -4306,9 +4410,9 @@ void LLTextureFetchDebugger::unlockCache()  void LLTextureFetchDebugger::debugCacheRead()  {  	lockCache(); -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	mTimer.reset(); -	mState = READ_CACHE; +	setDebuggerState(READ_CACHE);  	mCacheReadTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4342,9 +4446,9 @@ void LLTextureFetchDebugger::debugCacheWrite()  	clearCache();  	lockCache(); -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	mTimer.reset(); -	mState = WRITE_CACHE; +	setDebuggerState(WRITE_CACHE);  	mCacheWriteTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4371,9 +4475,9 @@ void LLTextureFetchDebugger::unlockDecoder()  void LLTextureFetchDebugger::debugDecoder()  {  	lockDecoder(); -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	mTimer.reset(); -	mState = DECODING; +	setDebuggerState(DECODING);  	mDecodingTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4392,7 +4496,7 @@ void LLTextureFetchDebugger::debugDecoder()  void LLTextureFetchDebugger::debugHTTP()  { -	llassert_always(mState == IDLE); +	llassert_always(mDebuggerState == IDLE);  	LLViewerRegion* region = gAgent.getRegion();  	if (!region) @@ -4409,7 +4513,7 @@ void LLTextureFetchDebugger::debugHTTP()  	}  	mTimer.reset(); -	mState = HTTP_FETCHING; +	setDebuggerState(HTTP_FETCHING);  	mHTTPTime = -1.f;  	S32 size = mFetchingHistory.size(); @@ -4489,8 +4593,8 @@ S32 LLTextureFetchDebugger::fillCurlQueue()  void LLTextureFetchDebugger::debugGLTextureCreation()  { -	llassert_always(mState == IDLE); -	mState = GL_TEX; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(GL_TEX);  	mTempTexList.clear();  	S32 size = mFetchingHistory.size(); @@ -4611,8 +4715,8 @@ void LLTextureFetchDebugger::scanRefetchList()  void LLTextureFetchDebugger::debugRefetchVisibleFromCache()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_VIS_CACHE; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_VIS_CACHE);  	clearTextures();  	mFetcher->setLoadSource(LLTextureFetch::FROM_ALL); @@ -4626,8 +4730,8 @@ void LLTextureFetchDebugger::debugRefetchVisibleFromCache()  void LLTextureFetchDebugger::debugRefetchVisibleFromHTTP()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_VIS_HTTP; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_VIS_HTTP);  	clearTextures();  	mFetcher->setLoadSource(LLTextureFetch::FROM_HTTP_ONLY); @@ -4641,8 +4745,8 @@ void LLTextureFetchDebugger::debugRefetchVisibleFromHTTP()  void LLTextureFetchDebugger::debugRefetchAllFromCache()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_ALL_CACHE; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_ALL_CACHE);  	clearTextures();  	makeRefetchList(); @@ -4658,8 +4762,8 @@ void LLTextureFetchDebugger::debugRefetchAllFromCache()  void LLTextureFetchDebugger::debugRefetchAllFromHTTP()  { -	llassert_always(mState == IDLE); -	mState = REFETCH_ALL_HTTP; +	llassert_always(mDebuggerState == IDLE); +	setDebuggerState(REFETCH_ALL_HTTP);  	clearTextures();  	makeRefetchList(); @@ -4675,19 +4779,19 @@ void LLTextureFetchDebugger::debugRefetchAllFromHTTP()  bool LLTextureFetchDebugger::update(F32 max_time)  { -	switch(mState) +	switch(mDebuggerState)  	{  	case START_DEBUG:  		if(processStartDebug(max_time))  		{ -			mState = IDLE; +			setDebuggerState(IDLE);  		}  		break;  	case READ_CACHE:  		if(!mTextureCache->update(1))  		{  			mCacheReadTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			unlockCache();  		}  		break; @@ -4695,7 +4799,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if(!mTextureCache->update(1))  		{  			mCacheWriteTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			unlockCache();  		}  		break; @@ -4703,7 +4807,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if(!mImageDecodeThread->update(1))  		{  			mDecodingTime =  mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			unlockDecoder();  		}  		break; @@ -4713,13 +4817,13 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (!fillCurlQueue() && mNbCurlCompleted == mFetchingHistory.size())  		{  			mHTTPTime =  mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  		}  		break;  	case GL_TEX:  		if(processGLCreation(max_time))  		{ -			mState = IDLE; +			setDebuggerState(IDLE);  			mTempTexList.clear();  		}  		break; @@ -4727,7 +4831,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)  		{  			mRefetchVisCacheTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  		} @@ -4736,7 +4840,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)  		{  			mRefetchVisHTTPTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  		} @@ -4753,7 +4857,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  			}  			mRefetchAllCacheTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE;  +			setDebuggerState(IDLE);   			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  			mRefetchList.clear(); @@ -4765,7 +4869,7 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		if (LLAppViewer::getTextureFetch()->getNumRequests() == 0)  		{  			mRefetchAllHTTPTime = mTimer.getElapsedTimeF32() ; -			mState = IDLE; +			setDebuggerState(IDLE);  			mFetcher->lockFetcher(true);  			mFetcher->resetLoadSource();  			mRefetchList.clear(); @@ -4773,11 +4877,11 @@ bool LLTextureFetchDebugger::update(F32 max_time)  		}  		break;  	default: -		mState = IDLE; +		setDebuggerState(IDLE);  		break;  	} -	return mState == IDLE; +	return mDebuggerState == IDLE;  }  void LLTextureFetchDebugger::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index d7fb2b4356..c4da2e8685 100755 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -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); @@ -396,6 +397,9 @@ private:  	e_tex_source mFetchSource;  	e_tex_source mOriginFetchSource; +	// Retry logic +	//LLAdaptiveRetryPolicy mFetchRetryPolicy; +	  public:  	//debug use  	LLTextureFetchDebugger* getFetchDebugger() { return mFetchDebugger;} @@ -475,8 +479,9 @@ private:  	typedef std::map<LLCore::HttpHandle, S32> handle_fetch_map_t;  	handle_fetch_map_t mHandleToFetchIndex; -	 -	e_debug_state mState; + +	void setDebuggerState(e_debug_state new_state) { mDebuggerState = new_state; } +	e_debug_state mDebuggerState;  	F32 mCacheReadTime;  	F32 mCacheWriteTime; @@ -549,7 +554,7 @@ public:  	void callbackDecoded(S32 id, bool success, LLImageRaw* raw, LLImageRaw* aux);  	void callbackHTTP(FetchEntry & fetch, LLCore::HttpResponse * response); -	e_debug_state getState()             {return mState;} +	e_debug_state getState()             {return mDebuggerState;}  	S32  getNumFetchedTextures()         {return mNumFetchedTextures;}  	S32  getNumFetchingRequests()        {return mFetchingHistory.size();}  	S32  getNumCacheHits()               {return mNumCacheHits;} diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 8ee83b5df0..aa1f680a1e 100755 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -434,15 +434,7 @@ void LLAvatarTexBar::draw()  		if (!layerset_buffer) continue;  		LLColor4 text_color = LLColor4::white; -		 -		if (layerset_buffer->uploadNeeded()) -		{ -			text_color = LLColor4::red; -		} - 		if (layerset_buffer->uploadInProgress()) -		{ -			text_color = LLColor4::magenta; -		} +  		std::string text = layerset_buffer->dumpTextureInfo();  		LLFontGL::getFontMonospace()->renderUTF8(text, 0, l_offset, v_offset + line_height*line_num,  												 text_color, LLFontGL::LEFT, LLFontGL::TOP); //, LLFontGL::BOLD, LLFontGL::DROP_SHADOW_SOFT); diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp index a27105e22d..39adfb3431 100755 --- a/indra/newview/lltoastimpanel.cpp +++ b/indra/newview/lltoastimpanel.cpp @@ -54,6 +54,7 @@ LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) :	LLToastPanel(p.notif  	mAvatarName = getChild<LLTextBox>("user_name");  	mTime = getChild<LLTextBox>("time_box");  	mMessage = getChild<LLTextBox>("message"); +	mMessage->setContentTrusted(false);  	LLStyle::Params style_params;  	LLFontGL* fontp = LLViewerChat::getChatFont(); diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp index 51935dc03b..907baf0661 100755 --- a/indra/newview/lltoastnotifypanel.cpp +++ b/indra/newview/lltoastnotifypanel.cpp @@ -270,8 +270,12 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )      // customize panel's attributes      // is it intended for displaying a tip?      mIsTip = mNotification->getType() == "notifytip"; + +    std::string notif_name = mNotification->getName();      // is it a script dialog? -    mIsScriptDialog = (mNotification->getName() == "ScriptDialog" || mNotification->getName() == "ScriptDialogGroup"); +    mIsScriptDialog = (notif_name == "ScriptDialog" || notif_name == "ScriptDialogGroup"); + +    bool is_content_trusted = (notif_name != "LoadWebPage");      // is it a caution?      //      // caution flag can be set explicitly by specifying it in the notification payload, or it can be set implicitly if the @@ -314,6 +318,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )      mTextBox->setMaxTextLength(MAX_LENGTH);      mTextBox->setVisible(TRUE);      mTextBox->setPlainText(!show_images); +    mTextBox->setContentTrusted(is_content_trusted);      mTextBox->setValue(mNotification->getMessage());  	mTextBox->setIsFriendCallback(LLAvatarActions::isFriend); diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 148e5a015b..2d458db36b 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); +	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight); +	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight);  	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(); @@ -238,7 +246,13 @@ BOOL LLVisualParamHint::render()  		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);  	}  	gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); -	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); +	mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); +	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 7e80d72dec..c0ba0a1f39 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 248f1bf1d5..69b9b1f9f1 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()  { -	LL_WARNS() << "LLUploadModelPremissionsResponder error [status:" -			<< status << "]: " << content << LL_ENDL; +	LL_WARNS() << dumpResponse() << LL_ENDL;  	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 3d794f0d91..e390e8776d 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()  	{ -		LL_WARNS() << "LLSetDisplayNameResponder error [status:" -				<< status << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		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 4237ffd295..2c196ece51 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -143,14 +143,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 a4773646ef..b236bba3b7 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() -{ -	LL_DEBUGS() << "Removing inventory item " << mUUID << " from server." -			 << LL_ENDL; - -	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,8 +361,9 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const  	if(gAgent.getID() != mPermissions.getOwner())  	{  		// *FIX: deal with this better. -		LL_WARNS() << "LLViewerInventoryItem::updateServer() - for unowned item" -				<< LL_ENDL; +		LL_WARNS() << "LLViewerInventoryItem::updateServer() - for unowned item " +				   << ll_pretty_print_sd(this->asLLSD()) +				   << LL_ENDL;  		return;  	}  	LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0); @@ -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 ) -{ -	LL_INFOS() << "Removing inventory category " << mUUID << " from server." -			<< LL_ENDL; -	// 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; @@ -729,6 +701,19 @@ bool LLViewerInventoryCategory::fetch()  	return false;  } +S32 LLViewerInventoryCategory::getViewerDescendentCount() const +{ +	LLInventoryModel::cat_array_t* cats; +	LLInventoryModel::item_array_t* items; +	gInventory.getDirectDescendentsOf(getUUID(), cats, items); +	S32 descendents_actual = 0; +	if(cats && items) +	{ +		descendents_actual = cats->size() + items->size(); +	} +	return descendents_actual; +} +  bool LLViewerInventoryCategory::importFileLocal(LLFILE* fp)  {  	// *NOTE: This buffer size is hard coded into scanf() below. @@ -894,6 +879,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,75 +1087,148 @@ 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)  	{ -		LL_WARNS() << "attempt to link to unknown item, linked-to-item's itemID " << item_id << LL_ENDL; -		return; -	} -	if (baseobj && baseobj->getIsLinkType()) -	{ -		LL_WARNS() << "attempt to create a link to a link, linked-to-item's itemID " << item_id << LL_ENDL; +		LL_WARNS() << "Attempt to link to non-existent object" << LL_ENDL;  		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. -		LL_WARNS() << "attempt to link an unlinkable item, type = " << baseobj->getActualType() << LL_ENDL; -		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(); +			LL_WARNS() << "attempt to link to unknown object" << LL_ENDL; +			continue;  		} -	} -#if 1 // debugging stuff -	LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id); -	LL_DEBUGS() << "cat: " << cat << LL_ENDL; -	 +		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. +			LL_WARNS() << "attempt to link an unlinkable object, type = " << baseobj->getActualType() << LL_ENDL; +			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 +			{ +				LL_WARNS() << "could not convert object into an item or category: " << baseobj->getUUID() << LL_ENDL; +				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( @@ -1179,6 +1252,392 @@ 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(); +		// Replace asset_id and/or shadow_id with transaction_id (hash_id) +		if (updates.has("asset_id")) +		{ +			updates.erase("asset_id"); +			updates["hash_id"] = update_item->getTransactionID(); +		} +		if (updates.has("shadow_id")) +		{ +			updates.erase("shadow_id"); +			updates["hash_id"] = update_item->getTransactionID(); +		} +		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)") << LL_ENDL; +		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)") << LL_ENDL; +		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)") << LL_ENDL; +	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)" << LL_ENDL; +	} +} + +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() << LL_ENDL; +		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? +		LL_WARNS() << "remove_inventory_item called for invalid or nonexistent item." << LL_ENDL; +	} +} + +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) +		{ +			LL_WARNS() << "remove descendents failed, cannot remove category " << LL_ENDL; +		} +		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 << "] " << LL_ENDL; +	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 << LL_ENDL; +				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 +	{ +		LL_WARNS() << "remove_inventory_category called for invalid or nonexistent item " << cat_id << LL_ENDL; +	} +} + +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 << LL_ENDL; +		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" << LL_ENDL; +			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() << LL_ENDL; + +				// 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 +1737,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) << LL_ENDL; +		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) << LL_ENDL; +		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.size(); ++i) +	{ +		LLViewerInventoryItem *item = items.at(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 +2219,5 @@ BOOL LLViewerInventoryItem::regenerateLink()  	gInventory.notifyObservers();  	return TRUE;  } + + diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index a10eda947d..c284c703d4 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 @@ -218,6 +217,8 @@ public:  	enum { DESCENDENT_COUNT_UNKNOWN = -1 };  	S32 getDescendentCount() const { return mDescendentCount; }  	void setDescendentCount(S32 descendents) { mDescendentCount = descendents; } +	// How many descendents do we currently have information for in the InventoryModel? +	S32 getViewerDescendentCount() const;  	// file handling on the viewer. These are not meant for anything  	// other than caching. @@ -225,6 +226,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 +267,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 +279,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 +353,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 +372,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 +424,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 a4e3c8cdbd..ed26842035 100755 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -157,7 +157,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), @@ -176,13 +176,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()) +		{ +			LL_WARNS() << dumpResponse() +					<< " [headers:" << getResponseHeaders() << "]" << LL_ENDL; +		} +		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); -		LL_DEBUGS() << "status is " << status << ", media type \"" << media_type << "\"" << LL_ENDL; +		LL_DEBUGS() << "status is " << getStatus() << ", media type \"" << media_type << "\"" << LL_ENDL;  		// 2xx status codes indicate success.  		// Most 4xx status codes are successful enough for our purposes. @@ -199,32 +205,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"; -			} -			 -			completeAny(status, mime_type); -		} -		else -		{ -			LL_WARNS() << "responder failed with status " << status << ", reason " << reason << LL_ENDL; -		 -			if(mMediaImpl) -			{ -				mMediaImpl->mMediaSourceFailed = true; +				mime_type = HTTP_CONTENT_TEXT_HTML;  			}  		} +		//else +		//{ +		//	LL_WARNS() << "responder failed with status " << dumpResponse() << LL_ENDL; +		// +		//	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; @@ -240,6 +241,7 @@ public:  		}  	} +public:  	void cancelRequest()  	{  		disconnectOwner(); @@ -268,7 +270,7 @@ public:  class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder  { -LOG_CLASS(LLViewerMediaOpenIDResponder); +	LOG_CLASS(LLViewerMediaOpenIDResponder);  public:  	LLViewerMediaOpenIDResponder( )  	{ @@ -278,23 +280,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);  	}  }; @@ -312,17 +308,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. @@ -330,16 +332,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;  }; @@ -1386,10 +1378,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;  } @@ -1427,9 +1421,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() ); @@ -1459,9 +1453,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(); @@ -1533,7 +1527,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);  	}  } @@ -1599,6 +1593,17 @@ void LLViewerMedia::cleanupClass()  {  	gIdleCallbacks.deleteFunction(LLViewerMedia::updateMedia, NULL);  	sTeleportFinishConnection.disconnect(); +	if (sSpareBrowserMediaSource != NULL) +	{ +		delete sSpareBrowserMediaSource; +		sSpareBrowserMediaSource = NULL; +	} + +	if (sCookieStore != NULL) +	{ +		delete sCookieStore; +		sCookieStore = NULL; +	}  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -2644,16 +2649,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/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 9c08ec7e77..b23e23f32e 100755 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -7839,6 +7839,7 @@ void handle_buy_currency_test(void*)  	LLFloaterReg::showInstance("buy_currency_html", LLSD(url));  } +// SUNSHINE CLEANUP - is only the request update at the end needed now?  void handle_rebake_textures(void*)  {  	if (!isAgentAvatarValid()) return; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 00d28a4307..0d1ffd2b51 100755 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -1010,7 +1010,12 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver  protected:  	/*virtual*/ void done()  	{ -		for (uuid_vec_t::iterator it = mAdded.begin(); it != mAdded.end();) +		uuid_vec_t added; +		for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) +		{ +			added.push_back(*it); +		} +		for (uuid_vec_t::iterator it = added.begin(); it != added.end();)  		{  			const LLUUID& item_uuid = *it;  			bool was_moved = false; @@ -1032,13 +1037,12 @@ protected:  			if (was_moved)  			{ -				it = mAdded.erase(it); +				it = added.erase(it);  			}  			else ++it;  		} -		open_inventory_offer(mAdded, ""); -		mAdded.clear(); +		open_inventory_offer(added, "");  	}   }; @@ -1047,8 +1051,12 @@ class LLOpenTaskGroupOffer : public LLInventoryAddedObserver  protected:  	/*virtual*/ void done()  	{ -		open_inventory_offer(mAdded, "group_offer"); -		mAdded.clear(); +		uuid_vec_t added; +		for(uuid_set_t::const_iterator it = gInventory.getAddedIDs().begin(); it != gInventory.getAddedIDs().end(); ++it) +		{ +			added.push_back(*it); +		} +		open_inventory_offer(added, "group_offer");  		gInventory.removeObserver(this);  		delete this;  	} @@ -4001,6 +4009,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 @@ -4116,10 +4126,6 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**)  		gAgent.setTeleportState( LLAgent::TELEPORT_START_ARRIVAL ); -		// set the appearance on teleport since the new sim does not -		// know what you look like. -		gAgent.sendAgentSetAppearance(); -  		if (isAgentAvatarValid())  		{  			// Set the new position @@ -4243,6 +4249,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 1dabe07942..7c60be7046 100755 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -56,6 +56,7 @@  #include "llaudiosourcevo.h"  #include "llagent.h"  #include "llagentcamera.h" +#include "llagentwearables.h"  #include "llbbox.h"  #include "llbox.h"  #include "llcylinder.h" @@ -152,6 +153,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco  			{  				gAgentAvatarp = new LLVOAvatarSelf(id, pcode, regionp);  				gAgentAvatarp->initInstance(); +				gAgentWearables.setAvatarObject(gAgentAvatarp);  			}  			else   			{ @@ -5502,6 +5504,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 d92c00a6b2..bab107cc57 100755 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -415,6 +415,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 0e40db8504..7f5d2ac125 100755 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -796,6 +796,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)  class LLObjectCostResponder : public LLCurl::Responder  { +	LOG_CLASS(LLObjectCostResponder);  public:  	LLObjectCostResponder(const LLSD& object_ids)  		: mObjectIDs(object_ids) @@ -816,20 +817,19 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{ -		LL_WARNS() -			<< "Transport error requesting object cost " -			<< "[status: " << statusNum << "]: " -			<< content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		// 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, @@ -885,6 +885,7 @@ private:  class LLPhysicsFlagsResponder : public LLCurl::Responder  { +	LOG_CLASS(LLPhysicsFlagsResponder);  public:  	LLPhysicsFlagsResponder(const LLSD& object_ids)  		: mObjectIDs(object_ids) @@ -905,20 +906,19 @@ public:  		}  	} -	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content) +private: +	/* virtual */ void httpFailure()  	{ -		LL_WARNS() -			<< "Transport error requesting object physics flags " -			<< "[status: " << statusNum << "]: " -			<< content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  		// 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 b55154f889..37b249dddd 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 1932f4e8ce..fd5df9b774 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" @@ -80,6 +81,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. @@ -97,6 +103,8 @@ S32  LLViewerRegion::sNewObjectCreationThrottle = -1;  typedef std::map<std::string, std::string> CapabilityMap; +static void log_capabilities(const CapabilityMap &capmap); +  class LLViewerRegionImpl {  public:  	LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) @@ -164,7 +172,7 @@ public:  	CapabilityMap mCapabilities;  	CapabilityMap mSecondCapabilitiesTracker;  -	 +  	LLEventPoll* mEventPoll;  	S32 mSeedCapMaxAttempts; @@ -228,24 +236,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_WARNS("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_WARNS("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  		{ @@ -259,12 +273,19 @@ 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_DEBUGS("AppInit", "Capabilities") << "got capability for " << iter->first << LL_ENDL; + +			LL_DEBUGS("AppInit", "Capabilities") << "got capability for "  +				<< iter->first << LL_ENDL;  			/* HACK we're waiting for the ServerReleaseNotes */  			if (iter->first == "ServerReleaseNotes" && regionp->getReleaseNotesRequested()) @@ -281,11 +302,6 @@ public:  		}  	} -    static BaseCapabilitiesComplete* build( U64 region_handle, S32 id ) -    { -		return new BaseCapabilitiesComplete(region_handle, id); -    } -  private:  	U64 mRegionHandle;  	S32 mID; @@ -302,19 +318,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()  	{ -		LL_WARNS() << "BaseCapabilitiesCompleteTracker error [status:" -				<< statusNum << "]: " << content << LL_ENDL; +		LL_WARNS() << dumpResponse() << LL_ENDL;  	} -	void result(const LLSD& content) +	/* virtual */ void httpSuccess()  	{  		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);  		if( !regionp )   		{ +			LL_WARNS("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)  		{ @@ -324,32 +353,46 @@ public:  		if ( regionp->getRegionImpl()->mCapabilities.size() != regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() )  		{ -			LL_INFOS() << "BaseCapabilitiesCompleteTracker " << "sim " << regionp->getName() -				<< " sent duplicate seed caps that differs in size - most likely content. "  -				<< (S32) regionp->getRegionImpl()->mCapabilities.size() << " vs " << regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() -				<< LL_ENDL;			 -			 -			//todo#add cap debug versus original check? -			/* -			CapabilityMap::const_iterator iter = regionp->getRegionImpl()->mCapabilities.begin(); -			while (iter!=regionp->getRegionImpl()->mCapabilities.end() ) +			LL_WARNS("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_WARNS("AppInit", "Capabilities") +				<< "Initial Base capabilities: " << LL_ENDL; + +			log_capabilities(regionp->getRegionImpl()->mCapabilities); + +			LL_WARNS("AppInit", "Capabilities") +							<< "Latest base capabilities: " << LL_ENDL; + +			log_capabilities(regionp->getRegionImpl()->mSecondCapabilitiesTracker); + +#endif + +			if (regionp->getRegionImpl()->mSecondCapabilitiesTracker.size() > regionp->getRegionImpl()->mCapabilities.size() )  			{ -				LL_INFOS() << "BaseCapabilitiesCompleteTracker Original " << iter->first << " " << iter->second<<LL_ENDL; -				++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;  }; @@ -369,7 +412,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,  	mSimAccess( SIM_ACCESS_MIN ),  	mBillableFactor(1.0),  	mMaxTasks(DEFAULT_MAX_REGION_WIDE_PRIM_COUNT), -	mCentralBakeVersion(0), +	mCentralBakeVersion(1),  	mClassID(0),  	mCPURatio(0),  	mColoName("unknown"), @@ -2584,6 +2627,8 @@ void LLViewerRegion::unpackRegionHandshake()  	msg->nextBlock("RegionInfo");  	U32 flags = 0; +	flags |= REGION_HANDSHAKE_SUPPORTS_SELF_APPEARANCE; +  	if(sVOCacheCullingEnabled)  	{  		flags |= 0x00000001; //set the bit 0 to be 1 to ask sim to send all cacheable objects.		 @@ -2616,12 +2661,13 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	//capabilityNames.append("FacebookRedirect");  	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"); @@ -2636,7 +2682,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"); @@ -2677,7 +2723,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  	capabilityNames.append("ViewerMetrics");  	capabilityNames.append("ViewerStartAuction");  	capabilityNames.append("ViewerStats"); -	 +  	// Please add new capabilities alphabetically to reduce  	// merge conflicts.  } @@ -2685,8 +2731,11 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  void LLViewerRegion::setSeedCapability(const std::string& url)  {  	if (getCapability("Seed") == url) -    { -		//LL_WARNS() << "Ignoring duplicate seed capability" << LL_ENDL; +    {	 +		setCapabilityDebug("Seed", url); +		LL_DEBUGS("CrossingCaps") <<  "Received duplicate seed capability, posting to seed " << +				url	<< LL_ENDL; +  		//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(); @@ -2759,31 +2808,36 @@ class SimulatorFeaturesReceived : public LLHTTPClient::Responder  {  	LOG_CLASS(SimulatorFeaturesReceived);  public: -    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_WARNS("AppInit", "SimulatorFeatures") << "[status:" << statusNum << "]: " << content << LL_ENDL; +	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) +	{ } + +	/* virtual */ void httpFailure() +	{ +		LL_WARNS("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_WARNS("AppInit", "SimulatorFeatures") << "Received results for region that no longer exists!" << LL_ENDL; +			LL_WARNS("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) @@ -2793,7 +2847,7 @@ private:  			LLHTTPClient::get(mRetryURL, new SimulatorFeaturesReceived(*this), LLSD(), CAP_REQUEST_TIMEOUT);  		}  	} -	 +  	std::string mRetryURL;  	U64 mRegionHandle;  	S32 mAttempt; @@ -2830,7 +2884,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) @@ -2842,7 +2905,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const  {  	if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia")))  	{ -		LL_WARNS() << "getCapability called before caps received" << LL_ENDL; +		LL_WARNS() << "getCapability called before caps received for " << name << LL_ENDL;  	}  	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); @@ -2854,6 +2917,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"))) +	{ +		LL_WARNS() << "isCapabilityAvailable called before caps received for " << name << LL_ENDL; +	} +	 +	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); +	if(iter == mImpl->mCapabilities.end()) +	{ +		return false; +	} + +	return true; +} +  bool LLViewerRegion::capabilitiesReceived() const  {  	return mCapabilitiesReceived; @@ -2881,16 +2960,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()) -		{ -			LL_INFOS() << iter->first << " URL is " << iter->second << LL_ENDL; -		} -	} -	LL_INFOS() << "Dumped " << count << " entries." << LL_ENDL; +	log_capabilities(mImpl->mCapabilities);  }  LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) @@ -2982,7 +3052,21 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const  	return ( mSimulatorFeatures.has("DynamicPathfindingEnabled") &&  			 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()) +		{ +			LL_INFOS() << "log_capabilities: " << iter->first << " URL is " << iter->second << LL_ENDL; +		} +	} +	LL_INFOS() << "log_capabilities: Dumped " << count << " entries." << LL_ENDL; +}  void LLViewerRegion::resetMaterialsCapThrottle()  {  	F32 requests_per_sec = 	1.0f; // original default; @@ -3027,3 +3111,4 @@ U32 LLViewerRegion::getMaxMaterialsPerTransaction() const  } + diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 00d3900a88..1e225553b8 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -48,6 +48,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; @@ -255,6 +257,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/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 9d2a4a50e1..dafe2cafec 100755 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -355,6 +355,16 @@ LLViewerShaderMgr * LLViewerShaderMgr::instance()  	return static_cast<LLViewerShaderMgr*>(sInstance);  } +// static +void LLViewerShaderMgr::releaseInstance() +{ +	if (sInstance != NULL) +	{ +		delete sInstance; +		sInstance = NULL; +	} +} +  void LLViewerShaderMgr::initAttribsAndUniforms(void)  {  	if (mReservedAttribs.empty()) diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 42147fdd29..923aa522ad 100755 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -43,6 +43,7 @@ public:  	// singleton pattern implementation  	static LLViewerShaderMgr * instance(); +	static void releaseInstance();  	void initAttribsAndUniforms(void);  	void setShaders(); diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index d5ae2d1030..f60829e9e8 100755 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -412,18 +412,19 @@ void update_statistics()  class ViewerStatsResponder : public LLHTTPClient::Responder  { +	LOG_CLASS(ViewerStatsResponder);  public: -    ViewerStatsResponder() { } +	ViewerStatsResponder() { } -    void error(U32 statusNum, const std::string& reason) -    { -		LL_INFOS() << "ViewerStatsResponder::error " << statusNum << " " -				<< reason << LL_ENDL; -    } +private: +	/* virtual */ void httpFailure() +	{ +		LL_WARNS() << dumpResponse() << LL_ENDL; +	} -    void result(const LLSD& content) -    { -		LL_INFOS() << "ViewerStatsResponder::result" << LL_ENDL; +	/* virtual */ void httpSuccess() +	{ +		LL_INFOS() << "OK" << LL_ENDL;  	}  }; @@ -622,44 +623,28 @@ void send_stats()  	LLViewerStats::instance().getRecording().resume();  } -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); -	LL_DEBUGS() << "startPhase " << phase_name << LL_ENDL; -	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()); -		} -		LL_DEBUGS() << "stopPhase (all) " << phase_name << LL_ENDL; -		iter->second.pause(); -	} +	LLTimer& timer = getPhaseTimer(phase_name); +	timer.start(); +	//LL_DEBUGS("Avatar") << "startPhase " << phase_name << LL_ENDL;  }  void LLViewerStats::PhaseMap::clearPhases()  { -	LL_DEBUGS() << "clearPhases" << LL_ENDL; +	//LL_DEBUGS("Avatar") << "clearPhases" << LL_ENDL;  	mPhaseMap.clear();  } @@ -684,7 +669,6 @@ LLViewerStats::PhaseMap::PhaseMap()  {  } -  void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)  {  	phase_map_t::iterator iter = mPhaseMap.find(phase_name); @@ -697,6 +681,7 @@ void LLViewerStats::PhaseMap::stopPhase(const std::string& phase_name)  		}  	}  } +  // static  LLViewerStats::StatsAccumulator& LLViewerStats::PhaseMap::getPhaseStats(const std::string& phase_name)  { @@ -720,14 +705,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) << LL_ENDL;  	}  	else  	{ -		return false; +		//LL_DEBUGS("Avatar") << " phase_name " << phase_name << " NOT FOUND"  << LL_ENDL;  	} + +	return found;  } diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 0d959ed034..7843652589 100755 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -342,7 +342,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  	{ @@ -351,11 +351,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			asLLSD();  		static StatsAccumulator& getPhaseStats(const std::string& phase_name); diff --git a/indra/newview/llviewertexlayer.cpp b/indra/newview/llviewertexlayer.cpp index 62e8da81ec..65ba3fb6e5 100755 --- a/indra/newview/llviewertexlayer.cpp +++ b/indra/newview/llviewertexlayer.cpp @@ -37,7 +37,6 @@  #include "llglslshader.h"  #include "llvoavatarself.h"  #include "pipeline.h" -#include "llassetuploadresponders.h"  #include "llviewercontrol.h"  static const S32 BAKE_UPLOAD_ATTEMPTS = 7; @@ -46,22 +45,6 @@ static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power o  // runway consolidate  extern std::string self_av_string(); - -//----------------------------------------------------------------------------- -// LLBakedUploadData() -//----------------------------------------------------------------------------- -LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar, -									 LLViewerTexLayerSet* layerset, -									 const LLUUID& id, -									 bool highest_res) : -	mAvatar(avatar), -	mTexLayerSet(layerset), -	mID(id), -	mStartTime(LLFrameTimer::getTotalTime()),		// Record starting time -	mIsHighestRes(highest_res) -{  -} -  //-----------------------------------------------------------------------------  // LLViewerTexLayerSetBuffer  // The composite image that a LLViewerTexLayerSet writes to.  Each LLViewerTexLayerSet has one. @@ -75,15 +58,10 @@ LLViewerTexLayerSetBuffer::LLViewerTexLayerSetBuffer(LLTexLayerSet* const owner,  	// ORDER_LAST => must render these after the hints are created.  	LLTexLayerSetBuffer(owner),  	LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ),  -	mUploadPending(FALSE), // Not used for any logic here, just to sync sending of updates -	mNeedsUpload(FALSE), -	mNumLowresUploads(0), -	mUploadFailCount(0),  	mNeedsUpdate(TRUE),  	mNumLowresUpdates(0)  {  	LLViewerTexLayerSetBuffer::sGLByteCount += getSize(); -	mNeedsUploadTimer.start();  	mNeedsUpdateTimer.start();  } @@ -126,33 +104,6 @@ void LLViewerTexLayerSetBuffer::requestUpdate()  	restartUpdateTimer();  	mNeedsUpdate = TRUE;  	mNumLowresUpdates = 0; -	// If we're in the middle of uploading a baked texture, we don't care about it any more. -	// When it's downloaded, ignore it. -	mUploadID.setNull(); -} - -void LLViewerTexLayerSetBuffer::requestUpload() -{ -	conditionalRestartUploadTimer(); -	mNeedsUpload = TRUE; -	mNumLowresUploads = 0; -	mUploadPending = TRUE; -} - -void LLViewerTexLayerSetBuffer::conditionalRestartUploadTimer() -{ -	// If we requested a new upload but haven't even uploaded -	// a low res version of our last upload request, then -	// keep the timer ticking instead of resetting it. -	if (mNeedsUpload && (mNumLowresUploads == 0)) -	{ -		mNeedsUploadTimer.unpause(); -	} -	else -	{ -		mNeedsUploadTimer.reset(); -		mNeedsUploadTimer.start(); -	}  }  void LLViewerTexLayerSetBuffer::restartUpdateTimer() @@ -161,25 +112,16 @@ void LLViewerTexLayerSetBuffer::restartUpdateTimer()  	mNeedsUpdateTimer.start();  } -void LLViewerTexLayerSetBuffer::cancelUpload() -{ -	mNeedsUpload = FALSE; -	mUploadPending = FALSE; -	mNeedsUploadTimer.pause(); -	mUploadRetryTimer.reset(); -} -  // virtual  BOOL LLViewerTexLayerSetBuffer::needsRender()  {  	llassert(mTexLayerSet->getAvatarAppearance() == gAgentAvatarp);  	if (!isAgentAvatarValid()) return FALSE; -	const BOOL upload_now = mNeedsUpload && isReadyToUpload();  	const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); -	// Don't render if we don't want to (or aren't ready to) upload or update. -	if (!(update_now || upload_now)) +	// Don't render if we don't want to (or aren't ready to) update. +	if (!update_now)  	{  		return FALSE;  	} @@ -190,11 +132,10 @@ BOOL LLViewerTexLayerSetBuffer::needsRender()  		return FALSE;  	} -	// Don't render if we are trying to create a shirt texture but aren't wearing a skirt. +	// Don't render if we are trying to create a skirt texture but aren't wearing a skirt.  	if (gAgentAvatarp->getBakedTE(getViewerTexLayerSet()) == LLAvatarAppearanceDefines::TEX_SKIRT_BAKED &&   		!gAgentAvatarp->isWearingWearableType(LLWearableType::WT_SKIRT))  	{ -		cancelUpload();  		return FALSE;  	} @@ -222,36 +163,7 @@ void LLViewerTexLayerSetBuffer::postRenderTexLayerSet(BOOL success)  // virtual  void LLViewerTexLayerSetBuffer::midRenderTexLayerSet(BOOL success)  { -	// do we need to upload, and do we have sufficient data to create an uploadable composite? -	// TODO: When do we upload the texture if gAgent.mNumPendingQueries is non-zero? -	const BOOL upload_now = mNeedsUpload && isReadyToUpload();  	const BOOL update_now = mNeedsUpdate && isReadyToUpdate(); - -	if(upload_now) -	{ -		if (!success) -		{ -			LL_INFOS() << "Failed attempt to bake " << mTexLayerSet->getBodyRegionName() << LL_ENDL; -			mUploadPending = FALSE; -		} -		else -		{ -			LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); -			if (layer_set->isVisible()) -			{ -				layer_set->getAvatar()->debugBakedTextureUpload(layer_set->getBakedTexIndex(), FALSE); // FALSE for start of upload, TRUE for finish. -				doUpload(); -			} -			else -			{ -				mUploadPending = FALSE; -				mNeedsUpload = FALSE; -				mNeedsUploadTimer.pause(); -				layer_set->getAvatar()->setNewBakedTexture(layer_set->getBakedTexIndex(),IMG_INVISIBLE); -			} -		} -	} -	  	if (update_now)  	{  		doUpdate(); @@ -267,60 +179,6 @@ BOOL LLViewerTexLayerSetBuffer::isInitialized(void) const  	return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated();  } -BOOL LLViewerTexLayerSetBuffer::uploadPending() const -{ -	return mUploadPending; -} - -BOOL LLViewerTexLayerSetBuffer::uploadNeeded() const -{ -	return mNeedsUpload; -} - -BOOL LLViewerTexLayerSetBuffer::uploadInProgress() const -{ -	return !mUploadID.isNull(); -} - -BOOL LLViewerTexLayerSetBuffer::isReadyToUpload() const -{ -	if (!gAgentQueryManager.hasNoPendingQueries()) return FALSE; // Can't upload if there are pending queries. -	if (isAgentAvatarValid() && gAgentAvatarp->isEditingAppearance()) return FALSE; // Don't upload if avatar is being edited. - -	BOOL ready = FALSE; -	if (getViewerTexLayerSet()->isLocalTextureDataFinal()) -	{ -		// If we requested an upload and have the final LOD ready, upload (or wait a while if this is a retry) -		if (mUploadFailCount == 0) -		{ -			ready = TRUE; -		} -		else -		{ -			ready = mUploadRetryTimer.getElapsedTimeF32() >= BAKE_UPLOAD_RETRY_DELAY * (1 << (mUploadFailCount - 1)); -		} -	} -	else -	{ -		// Upload if we've hit a timeout.  Upload is a pretty expensive process so we need to make sure -		// we aren't doing uploads too frequently. -		const U32 texture_timeout = gSavedSettings.getU32("AvatarBakedTextureUploadTimeout"); -		if (texture_timeout != 0) -		{ -			// The timeout period increases exponentially between every lowres upload in order to prevent -			// spamming the server with frequent uploads. -			const U32 texture_timeout_threshold = texture_timeout*(1 << mNumLowresUploads); - -			// If we hit our timeout and have textures available at even lower resolution, then upload. -			const BOOL is_upload_textures_timeout = mNeedsUploadTimer.getElapsedTimeF32() >= texture_timeout_threshold; -			const BOOL has_lower_lod = getViewerTexLayerSet()->isLocalTextureDataAvailable(); -			ready = has_lower_lod && is_upload_textures_timeout; -		} -	} - -	return ready; -} -  BOOL LLViewerTexLayerSetBuffer::isReadyToUpdate() const  {  	// If we requested an update and have the final LOD ready, then update. @@ -358,159 +216,6 @@ BOOL LLViewerTexLayerSetBuffer::requestUpdateImmediate()  	return result;  } -// Create the baked texture, send it out to the server, then wait for it to come -// back so we can switch to using it. -void LLViewerTexLayerSetBuffer::doUpload() -{ -	LLViewerTexLayerSet* layer_set = getViewerTexLayerSet(); -	LL_DEBUGS("Avatar") << "Uploading baked " << layer_set->getBodyRegionName() << LL_ENDL; -	add(LLStatViewer::TEX_BAKES, 1); - -	// Don't need caches since we're baked now.  (note: we won't *really* be baked  -	// until this image is sent to the server and the Avatar Appearance message is received.) -	layer_set->deleteCaches(); - -	// Get the COLOR information from our texture -	U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ]; -	glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); -	stop_glerror(); - -	// Get the MASK information from our texture -	LLGLSUIDefault gls_ui; -	LLPointer<LLImageRaw> baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 ); -	U8* baked_mask_data = baked_mask_image->getData();  -	layer_set->gatherMorphMaskAlpha(baked_mask_data, -									mOrigin.mX, mOrigin.mY, -									mFullWidth, mFullHeight); - - -	// Create the baked image from our color and mask information -	const S32 baked_image_components = 5; // red green blue [bump] clothing -	LLPointer<LLImageRaw> baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components ); -	U8* baked_image_data = baked_image->getData(); -	S32 i = 0; -	for (S32 u=0; u < mFullWidth; u++) -	{ -		for (S32 v=0; v < mFullHeight; v++) -		{ -			baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; -			baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; -			baked_image_data[5*i + 2] = baked_color_data[4*i + 2]; -			baked_image_data[5*i + 3] = baked_color_data[4*i + 3]; // alpha should be correct for eyelashes. -			baked_image_data[5*i + 4] = baked_mask_data[i]; -			i++; -		} -	} -	 -	LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C; -	const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) -	if (compressedImage->encode(baked_image, comment_text)) -	{ -		LLTransactionID tid; -		tid.generate(); -		const LLAssetID asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); -		if (LLVFile::writeFile(compressedImage->getData(), compressedImage->getDataSize(), -							   gVFS, asset_id, LLAssetType::AT_TEXTURE)) -		{ -			// Read back the file and validate. -			BOOL valid = FALSE; -			LLPointer<LLImageJ2C> integrity_test = new LLImageJ2C; -			S32 file_size = 0; -			LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE); -			file_size = file.getSize(); -			U8* data = integrity_test->allocateData(file_size); -			file.read(data, file_size); -			if (data) -			{ -				valid = integrity_test->validate(data, file_size); // integrity_test will delete 'data' -			} -			else -			{ -				integrity_test->setLastError("Unable to read entire file"); -			} -			 -			if (valid) -			{ -				const bool highest_lod = layer_set->isLocalTextureDataFinal(); -				// Baked_upload_data is owned by the responder and deleted after the request completes. -				LLBakedUploadData* baked_upload_data = new LLBakedUploadData(gAgentAvatarp,  -																			 layer_set,  -																			 asset_id, -																			 highest_lod); -				// upload ID is used to avoid overlaps, e.g. when the user rapidly makes two changes outside of Face Edit. -				mUploadID = asset_id; - -				// Upload the image -				const std::string url = gAgent.getRegion()->getCapability("UploadBakedTexture"); -				if(!url.empty() -					&& !LLPipeline::sForceOldBakedUpload // toggle debug setting UploadBakedTexOld to change between the new caps method and old method -					&& (mUploadFailCount < (BAKE_UPLOAD_ATTEMPTS - 1))) // Try last ditch attempt via asset store if cap upload is failing. -				{ -					LLSD body = LLSD::emptyMap(); -					// The responder will call LLViewerTexLayerSetBuffer::onTextureUploadComplete() -					LLHTTPClient::post(url, body, new LLSendTexLayerResponder(body, mUploadID, LLAssetType::AT_TEXTURE, baked_upload_data)); -					LL_INFOS() << "Baked texture upload via capability of " << mUploadID << " to " << url << LL_ENDL; -				}  -				else -				{ -					gAssetStorage->storeAssetData(tid, -												  LLAssetType::AT_TEXTURE, -												  LLViewerTexLayerSetBuffer::onTextureUploadComplete, -												  baked_upload_data, -												  TRUE,		// temp_file -												  TRUE,		// is_priority -												  TRUE);	// store_local -					LL_INFOS() << "Baked texture upload via Asset Store." <<  LL_ENDL; -				} - -				if (highest_lod) -				{ -					// Sending the final LOD for the baked texture.  All done, pause  -					// the upload timer so we know how long it took. -					mNeedsUpload = FALSE; -					mNeedsUploadTimer.pause(); -				} -				else -				{ -					// Sending a lower level LOD for the baked texture.  Restart the upload timer. -					mNumLowresUploads++; -					mNeedsUploadTimer.unpause(); -					mNeedsUploadTimer.reset(); -				} - -				// Print out notification that we uploaded this texture. -				if (gSavedSettings.getBOOL("DebugAvatarRezTime")) -				{ -					const std::string lod_str = highest_lod ? "HighRes" : "LowRes"; -					LLSD args; -					args["EXISTENCE"] = llformat("%d",(U32)layer_set->getAvatar()->debugGetExistenceTimeElapsedF32()); -					args["TIME"] = llformat("%d",(U32)mNeedsUploadTimer.getElapsedTimeF32()); -					args["BODYREGION"] = layer_set->getBodyRegionName(); -					args["RESOLUTION"] = lod_str; -					LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args); -					LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << layer_set->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL; -				} -			} -			else -			{ -				// The read back and validate operation failed.  Remove the uploaded file. -				mUploadPending = FALSE; -				LLVFile file(gVFS, asset_id, LLAssetType::AT_TEXTURE, LLVFile::WRITE); -				file.remove(); -				LL_INFOS() << "Unable to create baked upload file (reason: corrupted)." << LL_ENDL; -			} -		} -	} -	else -	{ -		// The VFS write file operation failed. -		mUploadPending = FALSE; -		LL_INFOS() << "Unable to create baked upload file (reason: failed to write file)" << LL_ENDL; -	} - -	delete [] baked_color_data; -} -  // Mostly bookkeeping; don't need to actually "do" anything since  // render() will actually do the update.  void LLViewerTexLayerSetBuffer::doUpdate() @@ -547,82 +252,6 @@ void LLViewerTexLayerSetBuffer::doUpdate()  	}  } -// static -void LLViewerTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, -												  void* userdata, -												  S32 result, -												  LLExtStat ext_status) // StoreAssetData callback (not fixed) -{ -	LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata; - -	if (isAgentAvatarValid() && -		!gAgentAvatarp->isDead() && -		(baked_upload_data->mAvatar == gAgentAvatarp) && // Sanity check: only the user's avatar should be uploading textures. -		(baked_upload_data->mTexLayerSet->hasComposite())) -	{ -		LLViewerTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getViewerComposite(); -		S32 failures = layerset_buffer->mUploadFailCount; -		layerset_buffer->mUploadFailCount = 0; - -		if (layerset_buffer->mUploadID.isNull()) -		{ -			// The upload got canceled, we should be in the -			// process of baking a new texture so request an -			// upload with the new data - -			// BAP: does this really belong in this callback, as -			// opposed to where the cancellation takes place? -			// suspect this does nothing. -			layerset_buffer->requestUpload(); -		} -		else if (baked_upload_data->mID == layerset_buffer->mUploadID) -		{ -			// This is the upload we're currently waiting for. -			layerset_buffer->mUploadID.setNull(); -			const std::string name(baked_upload_data->mTexLayerSet->getBodyRegionName()); -			const std::string resolution = baked_upload_data->mIsHighestRes ? " full res " : " low res "; -			if (result >= 0) -			{ -				layerset_buffer->mUploadPending = FALSE; // Allows sending of AgentSetAppearance later -				LLAvatarAppearanceDefines::ETextureIndex baked_te = gAgentAvatarp->getBakedTE(layerset_buffer->getViewerTexLayerSet()); -				// Update baked texture info with the new UUID -				U64 now = LLFrameTimer::getTotalTime();		// Record starting time -				LL_INFOS() << "Baked" << resolution << "texture upload for " << name << " took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << LL_ENDL; -				gAgentAvatarp->setNewBakedTexture(baked_te, uuid); -			} -			else -			{	 -				++failures; -				S32 max_attempts = baked_upload_data->mIsHighestRes ? BAKE_UPLOAD_ATTEMPTS : 1; // only retry final bakes -				LL_WARNS() << "Baked" << resolution << "texture upload for " << name << " failed (attempt " << failures << "/" << max_attempts << ")" << LL_ENDL; -				if (failures < max_attempts) -				{ -					layerset_buffer->mUploadFailCount = failures; -					layerset_buffer->mUploadRetryTimer.start(); -					layerset_buffer->requestUpload(); -				} -			} -		} -		else -		{ -			LL_INFOS() << "Received baked texture out of date, ignored." << LL_ENDL; -		} - -		gAgentAvatarp->dirtyMesh(); -	} -	else -	{ -		// Baked texture failed to upload (in which case since we -		// didn't set the new baked texture, it means that they'll try -		// and rebake it at some point in the future (after login?)), -		// or this response to upload is out of date, in which case a -		// current response should be on the way or already processed. -		LL_WARNS() << "Baked upload failed" << LL_ENDL; -	} - -	delete baked_upload_data; -} -  //-----------------------------------------------------------------------------  // LLViewerTexLayerSet  // An ordered set of texture layers that get composited into a single texture. @@ -664,20 +293,6 @@ void LLViewerTexLayerSet::requestUpdate()  	}  } -void LLViewerTexLayerSet::requestUpload() -{ -	createComposite(); -	getViewerComposite()->requestUpload(); -} - -void LLViewerTexLayerSet::cancelUpload() -{ -	if(mComposite) -	{ -		getViewerComposite()->cancelUpload(); -	} -} -  void LLViewerTexLayerSet::updateComposite()  {  	createComposite(); @@ -730,19 +345,12 @@ const std::string LLViewerTexLayerSetBuffer::dumpTextureInfo() const  {  	if (!isAgentAvatarValid()) return ""; -	const BOOL is_high_res = !mNeedsUpload; -	const U32 num_low_res = mNumLowresUploads; -	const U32 upload_time = (U32)mNeedsUploadTimer.getElapsedTimeF32(); +	const BOOL is_high_res = TRUE;  +	const U32 num_low_res = 0;  	const std::string local_texture_info = gAgentAvatarp->debugDumpLocalTextureDataInfo(getViewerTexLayerSet()); -	std::string status 				= "CREATING "; -	if (!uploadNeeded()) status 	= "DONE     "; -	if (uploadInProgress()) status 	= "UPLOADING"; - -	std::string text = llformat("[%s] [HiRes:%d LoRes:%d] [Elapsed:%d] %s", -								status.c_str(), +	std::string text = llformat("[HiRes:%d LoRes:%d] %s",  								is_high_res, num_low_res, -								upload_time,   								local_texture_info.c_str());  	return text;  } diff --git a/indra/newview/llviewertexlayer.h b/indra/newview/llviewertexlayer.h index 959c883da8..027ae255ec 100644..100755 --- a/indra/newview/llviewertexlayer.h +++ b/indra/newview/llviewertexlayer.h @@ -47,8 +47,6 @@ public:  	virtual ~LLViewerTexLayerSet();  	/*virtual*/void				requestUpdate(); -	void						requestUpload(); -	void						cancelUpload();  	BOOL						isLocalTextureDataAvailable() const;  	BOOL						isLocalTextureDataFinal() const;  	void						updateComposite(); @@ -116,31 +114,6 @@ protected:  	virtual BOOL			render() { return renderTexLayerSet(); }  	//-------------------------------------------------------------------- -	// Uploads -	//-------------------------------------------------------------------- -public: -	void					requestUpload(); -	void					cancelUpload(); -	BOOL					uploadNeeded() const; 			// We need to upload a new texture -	BOOL					uploadInProgress() const; 		// We have started uploading a new texture and are awaiting the result -	BOOL					uploadPending() const; 			// We are expecting a new texture to be uploaded at some point -	static void				onTextureUploadComplete(const LLUUID& uuid, -													void* userdata, -													S32 result, LLExtStat ext_status); -protected: -	BOOL					isReadyToUpload() const; -	void					doUpload(); 					// Does a read back and upload. -	void					conditionalRestartUploadTimer(); -private: -	BOOL					mNeedsUpload; 					// Whether we need to send our baked textures to the server -	U32						mNumLowresUploads; 				// Number of times we've sent a lowres version of our baked textures to the server -	BOOL					mUploadPending; 				// Whether we have received back the new baked textures -	LLUUID					mUploadID; 						// The current upload process (null if none). -	LLFrameTimer    		mNeedsUploadTimer; 				// Tracks time since upload was requested and performed. -	S32						mUploadFailCount;				// Number of consecutive upload failures -	LLFrameTimer    		mUploadRetryTimer; 				// Tracks time since last upload failure. - -	//--------------------------------------------------------------------  	// Updates  	//--------------------------------------------------------------------  public: @@ -156,25 +129,5 @@ private:  	LLFrameTimer    		mNeedsUpdateTimer; 				// Tracks time since update was requested and performed.  }; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// LLBakedUploadData -// -// Used by LLTexLayerSetBuffer for a callback. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -struct LLBakedUploadData -{ -	LLBakedUploadData(const LLVOAvatarSelf* avatar, -					  LLViewerTexLayerSet* layerset,  -					  const LLUUID& id, -					  bool highest_res); -	~LLBakedUploadData() {} -	const LLUUID				mID; -	const LLVOAvatarSelf*		mAvatar; // note: backlink only; don't LLPointer  -	LLViewerTexLayerSet*		mTexLayerSet; -   	const U64					mStartTime;	// for measuring baked texture upload time -   	const bool					mIsHighestRes; // whether this is a "final" bake, or intermediate low res -}; -  #endif  // LL_VIEWER_TEXLAYER_H diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 3be82a5531..ba89aafc84 100755 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -961,6 +961,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  //---------------------------------------------------------------------------------------------- @@ -973,7 +994,7 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, FTType f_type,  	mFTType = f_type;  	if (mFTType == FTT_HOST_BAKE)  	{ -		mCanUseHTTP = false; +		LL_WARNS() << "Unsupported fetch type " << mFTType << LL_ENDL;  	}  	generateGLTexture();  } @@ -998,6 +1019,7 @@ void LLViewerFetchedTexture::init(bool firstinit)  {  	mOrigWidth = 0;  	mOrigHeight = 0; +	mHasAux = FALSE;  	mNeedsAux = FALSE;  	mRequestedDiscardLevel = -1;  	mRequestedDownloadPriority = 0.f; @@ -1054,7 +1076,7 @@ void LLViewerFetchedTexture::init(bool firstinit)  	mLastReferencedSavedRawImageTime = 0.0f;  	mKeptSavedRawImageTime = 0.f;  	mLastCallBackActiveTime = 0.f; - +	mForceCallbackFetch = FALSE;  	mInDebug = FALSE;  	mFTType = FTT_UNKNOWN; @@ -1836,9 +1858,14 @@ 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 (mAuxRawImage.notNull()) +		{ +			mHasAux = TRUE; +			sAuxCount++; +		}  		if (finished)  		{  			mIsFetching = FALSE; @@ -1899,20 +1926,34 @@ bool LLViewerFetchedTexture::updateFetch()  			if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL))  			{  				// We finished but received no data -				if (current_discard < 0) +				if (getDiscardLevel() < 0)  				{ -					LL_WARNS() << "!mIsFetching, setting as missing, decode_priority " << decode_priority -							<< " mRawDiscardLevel " << mRawDiscardLevel -							<< " current_discard " << current_discard -							<< LL_ENDL; +					if (getFTType() != FTT_MAP_TILE) +					{ +						LL_WARNS() << mID +								<< " Fetch failure, setting as missing, decode_priority " << decode_priority +								<< " mRawDiscardLevel " << mRawDiscardLevel +								<< " current_discard " << current_discard +								<< " stats " << mLastHttpGetStatus.toHex() +								<< LL_ENDL; +					}  					setIsMissingAsset();  					desired_discard = -1;  				}  				else  				{  					//LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL; -					mMinDiscardLevel = current_discard; -					desired_discard = current_discard; +					if(current_discard >= 0) +					{ +						mMinDiscardLevel = current_discard; +						desired_discard = current_discard; +					} +					else +					{ +						S32 dis_level = getDiscardLevel(); +						mMinDiscardLevel = dis_level; +						desired_discard = dis_level; +					}  				}  				destroyRawImage();  			} @@ -2083,29 +2124,43 @@ void LLViewerFetchedTexture::forceToDeleteRequest()  	mDesiredDiscardLevel = getMaxDiscardLevel() + 1;  } -void LLViewerFetchedTexture::setIsMissingAsset() +void LLViewerFetchedTexture::setIsMissingAsset(BOOL is_missing)  { -	if (mUrl.empty()) +	if (is_missing == mIsMissingAsset)  	{ -		LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; +		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. -		LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; +		if (mUrl.empty()) +		{ +			LL_WARNS() << mID << ": Marking image as missing" << LL_ENDL; +		} +		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) +			{ +				LL_WARNS() << mUrl << ": Marking image as missing" << LL_ENDL; +			} +		} +		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; +		LL_INFOS() << mID << ": un-flagging missing asset" << LL_ENDL;  	} -	mIsMissingAsset = TRUE; +	mIsMissingAsset = is_missing;  }  void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, @@ -2148,10 +2203,19 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call  	}  	if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0)  	{ -		// We need aux data, but we've already loaded the image, and it didn't have any -		LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; +		if(mHasAux) +		{ +			//trigger a refetch +			forceToRefetchTexture(); +		} +		else +		{ +			// We need aux data, but we've already loaded the image, and it didn't have any +			LL_WARNS() << "No aux data available for callback for image:" << getID() << LL_ENDL; +		}  	} -	mLastCallBackActiveTime = sCurrentTime; +	mLastCallBackActiveTime = sCurrentTime ; +        mLastReferencedSavedRawImageTime = sCurrentTime;  }  void LLViewerFetchedTexture::clearCallbackEntryList() @@ -2262,8 +2326,9 @@ void LLViewerFetchedTexture::unpauseLoadedCallbacks(const LLLoadedCallbackEntry:  			}  		}  	} -	mPauseLoadedCallBacks = FALSE; -	mLastCallBackActiveTime = sCurrentTime; +	mPauseLoadedCallBacks = FALSE ; +	mLastCallBackActiveTime = sCurrentTime ; +	mForceCallbackFetch = TRUE;  	if(need_raw)  	{  		mSaveRawImage = TRUE; @@ -2303,7 +2368,8 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s  bool LLViewerFetchedTexture::doLoadedCallbacks()  { -	static const F32 MAX_INACTIVE_TIME = 900.f; //seconds +	static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds +	static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds  	if (mNeedsCreateTexture)  	{ @@ -2316,14 +2382,30 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()  	}	  	if(sCurrentTime - mLastCallBackActiveTime > MAX_INACTIVE_TIME && !mIsFetching)  	{ -		clearCallbackEntryList(); //remove all callbacks. -		return false; +		if (mFTType == FTT_SERVER_BAKE) +		{ +			//output some debug info +			LL_INFOS() << "baked texture: " << mID << "clears all call backs due to inactivity." << LL_ENDL; +			LL_INFOS() << mUrl << LL_ENDL; +			LL_INFOS() << "current discard: " << getDiscardLevel() << " current discard for fetch: " << getCurrentDiscardLevelForFetching() << +				" Desired discard: " << getDesiredDiscardLevel() << "decode Pri: " << getDecodePriority() << LL_ENDL; +		} + +		clearCallbackEntryList() ; //remove all callbacks. +		return false ;  	}  	bool res = false;  	if (isMissingAsset())  	{ +		if (mFTType == FTT_SERVER_BAKE) +		{ +			//output some debug info +			LL_INFOS() << "baked texture: " << mID << "is missing." << LL_ENDL; +			LL_INFOS() << mUrl << LL_ENDL; +		} +  		for(callback_list_t::iterator iter = mLoadedCallbackList.begin();  			iter != mLoadedCallbackList.end(); )  		{ @@ -2508,6 +2590,9 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()  		}  	} +	// Done with any raw image data at this point (will be re-created if we still have callbacks) +	destroyRawImage(); +  	//  	// If we have no callbacks, take us off of the image callback list.  	// @@ -2515,10 +2600,13 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()  	{  		gTextureList.mCallbackList.erase(this);  	} +	else if(!res && mForceCallbackFetch && sCurrentTime - mLastCallBackActiveTime > MAX_IDLE_WAIT_TIME && !mIsFetching) +	{ +		//wait for long enough but no fetching request issued, force one. +		forceToRefetchTexture(mLoadedCallbackDesiredDiscardLevel, 5.f); +		mForceCallbackFetch = FALSE; //fire once. +	} -	// Done with any raw image data at this point (will be re-created if we still have callbacks) -	destroyRawImage(); -	  	return res;  } @@ -2600,7 +2688,7 @@ bool LLViewerFetchedTexture::needsToSaveRawImage()  void LLViewerFetchedTexture::destroyRawImage()  {	 -	if (mAuxRawImage.notNull()) +	if (mAuxRawImage.notNull() && !needsToSaveRawImage())  	{  		sAuxCount--;  		mAuxRawImage = NULL; @@ -2756,6 +2844,24 @@ void LLViewerFetchedTexture::saveRawImage()  	mLastReferencedSavedRawImageTime = sCurrentTime;  } +//force to refetch the texture to the discard level  +void LLViewerFetchedTexture::forceToRefetchTexture(S32 desired_discard, F32 kept_time) +{ +	if(mForceToSaveRawImage) +	{ +		desired_discard = llmin(desired_discard, mDesiredSavedRawDiscardLevel); +		kept_time = llmax(kept_time, mKeptSavedRawImageTime); +	} + +	//trigger a new fetch. +	mForceToSaveRawImage = TRUE ; +	mDesiredSavedRawDiscardLevel = desired_discard ; +	mKeptSavedRawImageTime = kept_time ; +	mLastReferencedSavedRawImageTime = sCurrentTime ; +	mSavedRawImage = NULL ; +	mSavedRawDiscardLevel = -1 ; +} +  void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, F32 kept_time)   {   	mKeptSavedRawImageTime = kept_time; @@ -2796,13 +2902,19 @@ void LLViewerFetchedTexture::destroySavedRawImage()  	clearCallbackEntryList(); -	mSavedRawImage = NULL; -	mForceToSaveRawImage  = FALSE; -	mSaveRawImage = FALSE; -	mSavedRawDiscardLevel = -1; -	mDesiredSavedRawDiscardLevel = -1; -	mLastReferencedSavedRawImageTime = 0.0f; -	mKeptSavedRawImageTime = 0.f; +	mSavedRawImage = NULL ; +	mForceToSaveRawImage  = FALSE ; +	mSaveRawImage = FALSE ; +	mSavedRawDiscardLevel = -1 ; +	mDesiredSavedRawDiscardLevel = -1 ; +	mLastReferencedSavedRawImageTime = 0.0f ; +	mKeptSavedRawImageTime = 0.f ; +	 +	if(mAuxRawImage.notNull()) +	{ +		sAuxCount--; +		mAuxRawImage = NULL; +	}  }  LLImageRaw* LLViewerFetchedTexture::getSavedRawImage()  diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index b12b988513..307204da60 100755 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -34,6 +34,7 @@  #include "llgltypes.h"  #include "llrender.h"  #include "llmetricperformancetester.h" +#include "httpcommon.h"  #include <map>  #include <list> @@ -41,6 +42,7 @@  extern const S32Megabytes gMinVideoRam;  extern const S32Megabytes gMaxVideoRam; +class LLFace;  class LLImageGL ;  class LLImageRaw;  class LLViewerObject; @@ -97,6 +99,7 @@ public:  		DYNAMIC_TEXTURE,  		FETCHED_TEXTURE,  		LOD_TEXTURE, +		ATLAS_TEXTURE,  		INVALID_TEXTURE_TYPE  	}; @@ -118,7 +121,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 LL_INFOS()  	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ; @@ -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 @@ -383,6 +388,7 @@ public:  	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}  	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	  	void        forceToSaveRawImage(S32 desired_discard = 0, F32 kept_time = 0.f) ; +	void        forceToRefetchTexture(S32 desired_discard = 0, F32 kept_time = 60.f);  	/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;  	void        destroySavedRawImage() ;  	LLImageRaw* getSavedRawImage() ; @@ -411,10 +417,16 @@ private:  	void saveRawImage() ;  	void setCachedRawImage() ; +	//for atlas +	void resetFaceAtlas() ; +	void invalidateAtlas(BOOL rebuild_geom) ; +	BOOL insertToAtlas() ; +  private:  	BOOL  mFullyLoaded;  	BOOL  mInDebug;  	BOOL  mInFastCacheList; +	BOOL  mForceCallbackFetch;  protected:		  	std::string mLocalFileName; @@ -442,11 +454,13 @@ protected:  	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have  	S8  mNeedsAux;					// We need to decode the auxiliary channels +	S8  mHasAux;                    // We have aux channels  	S8  mDecodingAux;				// Are we decoding high components  	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 a544cc81da..7de82a4710 100644..100755 --- a/indra/newview/llviewerwearable.cpp +++ b/indra/newview/llviewerwearable.cpp @@ -73,14 +73,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(); @@ -265,7 +267,7 @@ void LLViewerWearable::setParamsToDefaults()  	{  		if( (((LLViewerVisualParam*)param)->getWearableType() == mType ) && (param->isTweakable() ) )  		{ -			setVisualParamWeight(param->getID(),param->getDefaultWeight(), FALSE); +			setVisualParamWeight(param->getID(),param->getDefaultWeight());  		}  	}  } @@ -321,16 +323,6 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)  	if (!viewer_avatar->isValid()) return; -#if 0 -	// FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. -	// Ideally would avoid calling this func in the first place. -	if (viewer_avatar->isUsingServerBakes() && -		!viewer_avatar->isUsingLocalAppearance()) -	{ -		return; -	} -#endif -  	ESex old_sex = avatarp->getSex();  	LLWearable::writeToAvatar(avatarp); @@ -360,19 +352,14 @@ void LLViewerWearable::writeToAvatar(LLAvatarAppearance *avatarp)  	ESex new_sex = avatarp->getSex();  	if( old_sex != new_sex )  	{ -		viewer_avatar->updateSexDependentLayerSets( FALSE ); +		viewer_avatar->updateSexDependentLayerSets();  	}	 -	 -//	if( upload_bake ) -//	{ -//		gAgent.sendAgentSetAppearance(); -//	}  }  // Updates the user's avatar's appearance, replacing this wearables' parameters and textures with default values.  // static  -void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake ) +void LLViewerWearable::removeFromAvatar( LLWearableType::EType type)  {  	if (!isAgentAvatarValid()) return; @@ -391,7 +378,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload  		if( (((LLViewerVisualParam*)param)->getWearableType() == type) && (param->isTweakable() ) )  		{  			S32 param_id = param->getID(); -			gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight(), upload_bake ); +			gAgentAvatarp->setVisualParamWeight( param_id, param->getDefaultWeight());  		}  	} @@ -401,12 +388,7 @@ void LLViewerWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload  	}  	gAgentAvatarp->updateVisualParams(); -	gAgentAvatarp->wearableUpdated(type, FALSE); - -//	if( upload_bake ) -//	{ -//		gAgent.sendAgentSetAppearance(); -//	} +	gAgentAvatarp->wearableUpdated(type);  }  // Does not copy mAssetID. @@ -479,13 +461,6 @@ void LLViewerWearable::setItemID(const LLUUID& item_id)  void LLViewerWearable::revertValues()  { -#if 0 -	// DRANO avoid overwrite when not in local appearance -	if (isAgentAvatarValid() && gAgentAvatarp->isUsingServerBakes() && !gAgentAvatarp->isUsingLocalAppearance()) -	{ -		return; -	} -#endif  	LLWearable::revertValues(); @@ -523,13 +498,6 @@ void LLViewerWearable::refreshName()  	}  } -// virtual -void LLViewerWearable::addToBakedTextureHash(LLMD5& hash) const -{ -	LLUUID asset_id = getAssetID(); -	hash.update((const unsigned char*)asset_id.mData, UUID_BYTES); -} -  struct LLWearableSaveData  {  	LLWearableType::EType mType; diff --git a/indra/newview/llviewerwearable.h b/indra/newview/llviewerwearable.h index 8f49e3c4e2..62cd5e21ad 100644..100755 --- a/indra/newview/llviewerwearable.h +++ b/indra/newview/llviewerwearable.h @@ -62,13 +62,15 @@ public:  	BOOL				isOldVersion() const;  	/*virtual*/ void	writeToAvatar(LLAvatarAppearance *avatarp); -	void				removeFromAvatar( BOOL upload_bake )	{ LLViewerWearable::removeFromAvatar( mType, upload_bake ); } -	static void			removeFromAvatar( LLWearableType::EType type, BOOL upload_bake );  +	void				removeFromAvatar()	{ LLViewerWearable::removeFromAvatar( mType); } +	static void			removeFromAvatar( LLWearableType::EType type);   	/*virtual*/ EImportResult	importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );  	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; @@ -89,14 +91,14 @@ public:  	// the wearable was worn. make sure the name of the wearable object matches the LLViewerInventoryItem,  	// not the wearable asset itself.  	void				refreshName(); - -	// Update the baked texture hash. -	/*virtual*/void		addToBakedTextureHash(LLMD5& hash) const; +	/*virtual*/void		addToBakedTextureHash(LLMD5& hash) const {}  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 ec794e527d..d052906bee 100755 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -261,7 +261,7 @@ std::string	LLViewerWindow::sMovieBaseName;  LLTrace::SampleStatHandle<> LLViewerWindow::sMouseVelocityStat("Mouse Velocity"); -class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole> +class RecordToChatConsoleRecorder : public LLError::Recorder  {  public:  	virtual void recordMessage(LLError::ELevel level, @@ -285,6 +285,22 @@ public:  	}  }; +class RecordToChatConsole : public LLSingleton<RecordToChatConsole> +{ +public: +	RecordToChatConsole() +		: LLSingleton<RecordToChatConsole>(), +		mRecorder(new RecordToChatConsoleRecorder()) +	{ +	} + +	void startRecorder() { LLError::addRecorder(mRecorder); } +	void stopRecorder() { LLError::removeRecorder(mRecorder); } + +private: +	LLError::RecorderPtr mRecorder; +}; +  ////////////////////////////////////////////////////////////////////////////  //  // LLDebugText @@ -1886,11 +1902,11 @@ void LLViewerWindow::initBase()  	// optionally forward warnings to chat console/chat floater  	// for qa runs and dev builds  #if  !LL_RELEASE_FOR_DOWNLOAD -	LLError::addRecorder(RecordToChatConsole::getInstance()); +	RecordToChatConsole::getInstance()->startRecorder();  #else  	if(gSavedSettings.getBOOL("QAMode"))  	{ -		LLError::addRecorder(RecordToChatConsole::getInstance()); +		RecordToChatConsole::getInstance()->startRecorder();  	}  #endif @@ -1907,9 +1923,7 @@ void LLViewerWindow::initBase()  	setProgressCancelButtonVisible(FALSE);  	gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder"); -  	LLMenuGL::sMenuContainer = gMenuHolder; -  }  void LLViewerWindow::initWorldUI() @@ -2023,7 +2037,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) @@ -2031,7 +2045,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);  	}  } @@ -2039,8 +2053,7 @@ void LLViewerWindow::initWorldUI()  void LLViewerWindow::shutdownViews()  {  	// clean up warning logger -	LLError::removeRecorder(RecordToChatConsole::getInstance()); - +	RecordToChatConsole::getInstance()->stopRecorder();  	LL_INFOS() << "Warning logger is cleaned." << LL_ENDL ;  	delete mDebugText; @@ -2075,6 +2088,9 @@ void LLViewerWindow::shutdownViews()  	// access to gMenuHolder  	cleanup_menus();  	LL_INFOS() << "menus destroyed." << LL_ENDL ; + +	view_listener_t::cleanup(); +	LL_INFOS() << "view listeners destroyed." << LL_ENDL ;  	// Delete all child views.  	delete mRootView; @@ -2150,6 +2166,12 @@ LLViewerWindow::~LLViewerWindow()  	delete mDebugText;  	mDebugText = NULL; + +	if (LLViewerShaderMgr::sInitialized) +	{ +		LLViewerShaderMgr::releaseInstance(); +		LLViewerShaderMgr::sInitialized = FALSE; +	}  } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 04f64a4997..9f42776d78 100755 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -109,7 +109,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 @@ -713,7 +713,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mLastRezzedStatus(-1),  	mIsEditingAppearance(FALSE),  	mUseLocalAppearance(FALSE), -	mUseServerBakes(FALSE), // FIXME DRANO consider using boost::optional, defaulting to unknown.  	mLastUpdateRequestCOFVersion(-1),  	mLastUpdateReceivedCOFVersion(-1)  { @@ -723,7 +722,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job  	mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); -	LL_DEBUGS() << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL; +	LL_DEBUGS("Avatar") << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << LL_ENDL;  	mPelvisp = NULL; @@ -830,8 +829,8 @@ LLVOAvatar::~LLVOAvatar()  		}  	logPendingPhases(); - -	LL_DEBUGS() << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL; +	 +	LL_DEBUGS("Avatar") << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL;  	std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());  	mAttachmentPoints.clear(); @@ -1085,7 +1084,7 @@ void LLVOAvatar::restoreGL()  	gAgentAvatarp->setCompositeUpdatesEnabled(TRUE);  	for (U32 i = 0; i < gAgentAvatarp->mBakedTextureDatas.size(); i++)  	{ -		gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i), FALSE); +		gAgentAvatarp->invalidateComposite(gAgentAvatarp->getTexLayerSet(i));  	}  	gAgentAvatarp->updateMeshTextures();  } @@ -1252,6 +1251,7 @@ LLTexLayerSet* LLVOAvatar::createTexLayerSet()  const LLVector3 LLVOAvatar::getRenderPosition() const  { +  	if (mDrawable.isNull() || mDrawable->getGeneration() < 0)  	{  		return getPositionAgent(); @@ -1274,6 +1274,8 @@ const LLVector3 LLVOAvatar::getRenderPosition() const  	{  		return getPosition() * mDrawable->getParent()->getRenderMatrix();  	} +	 +	  }  void LLVOAvatar::updateDrawable(BOOL force_damped) @@ -1309,6 +1311,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) @@ -1986,24 +1990,23 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU  		// Should already exist, don't need to find it on sim or baked-texture host.  		result = gTextureList.findImage(uuid);  	} -  	if (!result)  {  		const std::string url = getImageURL(te,uuid); -		if (!url.empty()) -	{ -			LL_DEBUGS("Avatar") << avString() << "from URL " << url << LL_ENDL; -			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 << LL_ENDL; -			LLHost host = getObjectHost(); -			result = LLViewerTextureManager::getFetchedTexture( -				uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); + +		if (url.empty()) +		{ +			LL_WARNS() << "unable to determine URL for te " << te << " uuid " << uuid << LL_ENDL; +			return NULL; +		} +		LL_DEBUGS("Avatar") << avString() << "get server-bake image from URL " << url << LL_ENDL; +		result = LLViewerTextureManager::getFetchedTextureFromUrl( +			url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid); +		if (result->isMissingAsset()) +		{ +			result->setIsMissingAsset(false); +		}  	} -}  	return result;  } @@ -2231,8 +2234,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)  				if ( mLipSyncActive )  				{ -					if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight(), FALSE); -					if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight(), FALSE); +					if( mOohMorph ) mOohMorph->setWeight(mOohMorph->getMinWeight()); +					if( mAahMorph ) mAahMorph->setWeight(mAahMorph->getMinWeight());  					mLipSyncActive = false;  					LLCharacter::updateVisualParams(); @@ -2255,7 +2258,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 ) @@ -2395,14 +2398,10 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()  			{  				if (param->isTweakable())  				{ -					param->stopAnimating(FALSE); +					param->stopAnimating();  				}  			}  			updateVisualParams(); -			if (isSelf()) -			{ -				gAgent.sendAgentSetAppearance(); -			}  		}  		else  		{ @@ -2418,7 +2417,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()  				{  					if (param->isTweakable())  					{ -						param->animate(morph_amt, FALSE); +						param->animate(morph_amt);  					}  				}  			} @@ -2471,7 +2470,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)  			F32 ooh_weight = mOohMorph->getMinWeight()  				+ ooh_morph_amount * (mOohMorph->getMaxWeight() - mOohMorph->getMinWeight()); -			mOohMorph->setWeight( ooh_weight, FALSE ); +			mOohMorph->setWeight( ooh_weight);  		}  		if( mAahMorph ) @@ -2479,7 +2478,7 @@ void LLVOAvatar::idleUpdateLipSync(bool voice_enabled)  			F32 aah_weight = mAahMorph->getMinWeight()  				+ aah_morph_amount * (mAahMorph->getMaxWeight() - mAahMorph->getMinWeight()); -			mAahMorph->setWeight( aah_weight, FALSE ); +			mAahMorph->setWeight( aah_weight);  		}  		mLipSyncActive = true; @@ -2996,6 +2995,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); @@ -3175,7 +3176,10 @@ void	LLVOAvatar::forceUpdateVisualMuteSettings()  // called on both your avatar and other avatars  //------------------------------------------------------------------------  BOOL LLVOAvatar::updateCharacter(LLAgent &agent) -{ +{	 +	// clear debug text +	mDebugText.clear(); +  	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))  	{  		S32 central_bake_version = -1; @@ -3189,7 +3193,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  										  isSelf() ? (all_local_downloaded ? "L" : "l") : "-",  										  all_baked_downloaded ? "B" : "b",  										  mUseLocalAppearance, mIsEditingAppearance, -										  mUseServerBakes, central_bake_version); +										  1, central_bake_version);  		std::string origin_string = bakedTextureOriginInfo();  		debug_line += " [" + origin_string + "]";  		S32 curr_cof_version = LLAppearanceMgr::instance().getCOFVersion(); @@ -3689,6 +3693,9 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)  	//mesh vertices need to be reskinned  	mNeedsSkin = TRUE; + +		 +	  	return TRUE;  }  //----------------------------------------------------------------------------- @@ -3722,9 +3729,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; @@ -3734,18 +3741,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;	 @@ -4285,34 +4290,6 @@ bool LLVOAvatar::allBakedTexturesCompletelyDownloaded() const  	return allTexturesCompletelyDownloaded(baked_ids);  } -void LLVOAvatar::bakedTextureOriginCounts(S32 &sb_count, // server-bake, has origin URL. -										  S32 &host_count, // host-based bake, has host. -										  S32 &both_count, // error - both host and URL set. -										  S32 &neither_count) // error - neither set. -{ -	sb_count = host_count = both_count = neither_count = 0; -	 -	std::set<LLUUID> baked_ids; -	collectBakedTextureUUIDs(baked_ids); -	for (std::set<LLUUID>::const_iterator it = baked_ids.begin(); it != baked_ids.end(); ++it) -	{ -		LLViewerFetchedTexture *imagep = gTextureList.findImage(*it); -		bool has_url = false, has_host = false; -		if (!imagep->getUrl().empty()) -		{ -			has_url = true; -		} -		if (imagep->getTargetHost().isOk()) -		{ -			has_host = true; -		} -		if (has_url && !has_host) sb_count++; -		else if (has_host && !has_url) host_count++; -		else if (has_host && has_url) both_count++; -		else if (!has_host && !has_url) neither_count++; -	} -} -  std::string LLVOAvatar::bakedTextureOriginInfo()  {  	std::string result; @@ -4553,19 +4530,6 @@ void LLVOAvatar::updateTextures()  		{  			const S32 boost_level = getAvatarBakedBoostLevel();  			imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE); -			// Spam if this is a baked texture, not set to default image, without valid host info -			if (isIndexBakedTexture((ETextureIndex)texture_index) -				&& imagep->getID() != IMG_DEFAULT_AVATAR -				&& imagep->getID() != IMG_INVISIBLE -				&& !isUsingServerBakes()  -				&& !imagep->getTargetHost().isOk()) -			{ -				LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " -										 << imagep->getID() << " for avatar " -										 << (isSelf() ? "<myself>" : getID().asString())  -										 << " on host " << getRegion()->getHost() << LL_ENDL; -			} -  			addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );			  		}  	} @@ -4585,7 +4549,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 @@ -4648,11 +4612,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); @@ -4697,22 +4661,19 @@ const std::string LLVOAvatar::getImageURL(const U8 te, const LLUUID &uuid)  {  	llassert(isIndexBakedTexture(ETextureIndex(te)));  	std::string url = ""; -	if (isUsingServerBakes()) +	const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); +	if (appearance_service_url.empty())  	{ -		const std::string& appearance_service_url = LLAppearanceMgr::instance().getAppearanceServiceURL(); -		if (appearance_service_url.empty()) -		{ -			// Probably a server-side issue if we get here: -			LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; -			return url; -		} +		// Probably a server-side issue if we get here: +		LL_WARNS() << "AgentAppearanceServiceURL not set - Baked texture requests will fail" << LL_ENDL; +		return url; +	} -		const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); -		if (texture_entry != NULL) -		{ -			url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); -			//LL_INFOS() << "baked texture url: " << url << LL_ENDL; -		} +	const LLAvatarAppearanceDictionary::TextureEntry* texture_entry = LLAvatarAppearanceDictionary::getInstance()->getTexture((ETextureIndex)te); +	if (texture_entry != NULL) +	{ +		url = appearance_service_url + "texture/" + getID().asString() + "/" + texture_entry->mDefaultImageName + "/" + uuid.asString(); +		//LL_INFOS() << "baked texture url: " << url << LL_ENDL;  	}  	return url;  } @@ -5096,70 +5057,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 -	{ -		LL_INFOS()<<"Did not find "<< name.c_str()<<LL_ENDL; -	} -}  //-----------------------------------------------------------------------------  // 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() @@ -5314,7 +5244,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()  			{  				attachment->setOriginalPosition(info->mPosition);  			} - +			  			if (info->mHasRotation)  			{  				LLQuaternion rotation; @@ -5384,7 +5314,6 @@ void LLVOAvatar::updateVisualParams()  	dirtyMesh();  	updateHeadOffset();  } -  //-----------------------------------------------------------------------------  // isActive()  //----------------------------------------------------------------------------- @@ -5541,11 +5470,11 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)  //-----------------------------------------------------------------------------  // updateSexDependentLayerSets()  //----------------------------------------------------------------------------- -void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake ) +void LLVOAvatar::updateSexDependentLayerSets()  { -	invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); -	invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); -	invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); +	invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); +	invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); +	invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);  }  //----------------------------------------------------------------------------- @@ -5761,6 +5690,7 @@ void LLVOAvatar::lazyAttach()  void LLVOAvatar::resetHUDAttachments()  { +  	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end();  		 ++iter) @@ -5813,10 +5743,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() ) @@ -5835,6 +5765,7 @@ void LLVOAvatar::cleanupAttachedMesh( LLViewerObject* pVO )  //-----------------------------------------------------------------------------  BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  { +  	for (attachment_map_t::iterator iter = mAttachmentPoints.begin();   		 iter != mAttachmentPoints.end();  		 ++iter) @@ -5845,6 +5776,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)  		{  			mVisualComplexityStale = TRUE;  			cleanupAttachedMesh( viewer_object ); +		  			attachment->removeObject(viewer_object);  			LL_DEBUGS() << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << LL_ENDL;  			return TRUE; @@ -6058,8 +5990,6 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const  	return FALSE;  } - -  LLViewerObject *	LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) const  {  	for(attachment_map_t::const_iterator attachment_points_iter = mAttachmentPoints.begin(); @@ -6083,9 +6013,8 @@ LLViewerObject *	LLVOAvatar::findAttachmentByID( const LLUUID & target_id ) cons  	return NULL;  } -  // virtual -void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset)  {  } @@ -6094,18 +6023,18 @@ void LLVOAvatar::invalidateAll()  }  // virtual -void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake ) +void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color)  {  	if (global_color == mTexSkinColor)  	{ -		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); -		invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, upload_bake ); -		invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, upload_bake ); +		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); +		invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet); +		invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet);  	}  	else if (global_color == mTexHairColor)  	{ -		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, upload_bake ); -		invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, upload_bake ); +		invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet); +		invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet);  		// ! BACKWARDS COMPATIBILITY !  		// Fix for dealing with avatars from viewers that don't bake hair. @@ -6127,7 +6056,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL  	else if (global_color == mTexEyeColor)  	{  //		LL_INFOS() << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << LL_ENDL;  -		invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet,  upload_bake ); +		invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet);  	}  	updateMeshTextures();  } @@ -6218,9 +6147,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 << LL_ENDL; +	if (found)  	{  		if (!completed)  		{ @@ -6233,9 +6165,9 @@ void LLVOAvatar::startPhase(const std::string& phase_name)  }  void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check) -		{ -	F32 elapsed; -	bool completed; +{ +	F32 elapsed = 0.0; +	bool completed = false;  	if (getPhases().getPhaseValues(phase_name, elapsed, completed))  	{  		if (!completed) @@ -6321,7 +6253,7 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse  		}  	record["grid_x"] = LLSD::Integer(grid_x);  	record["grid_y"] = LLSD::Integer(grid_y); -	record["is_using_server_bakes"] = ((bool) isUsingServerBakes()); +	record["is_using_server_bakes"] = true;  	record["is_self"] = isSelf();  	if (isAgentAvatarValid()) @@ -6566,6 +6498,8 @@ void LLVOAvatar::updateMeshTextures()  				// we'll consider it loaded and use it (rather than  				// doing compositing).  				useBakedTexture( baked_img->getID() ); +                                mLoadedCallbacksPaused |= !isVisible(); +                                checkTextureLoading();  			}  			else  			{ @@ -6578,6 +6512,10 @@ 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;  +                               checkTextureLoading();  			}  		}  		else if (layerset && isUsingLocalAppearance()) @@ -6724,8 +6662,6 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com  	}  } - -  // returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise  BOOL LLVOAvatar::morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index)  { @@ -6936,6 +6872,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;   			}  		} @@ -7008,7 +6947,7 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)  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; @@ -7035,7 +6974,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();  		} @@ -7089,7 +7029,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();  				} @@ -7110,7 +7051,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() << LL_ENDL; @@ -7157,13 +7099,13 @@ bool resolve_appearance_version(const LLAppearanceMessageContents& contents, S32  	{  		appearance_version = contents.mParamAppearanceVersion;  	} -	if (contents.mAppearanceVersion >= 0) +	else if (contents.mAppearanceVersion > 0)  	{  		appearance_version = contents.mAppearanceVersion;  	} -	if (appearance_version < 0) // still not set, go with 0. +	else // still not set, go with 1.  	{ -		appearance_version = 0; +		appearance_version = 1;  	}  	LL_DEBUGS("Avatar") << "appearance version info - field " << contents.mAppearanceVersion  						<< " param: " << contents.mParamAppearanceVersion @@ -7201,24 +7143,21 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		LL_WARNS() << "bad appearance version info, discarding" << LL_ENDL;  		return;  	} +	llassert(appearance_version > 0); +	if (appearance_version > 1) +	{ +		LL_WARNS() << "unsupported appearance version " << appearance_version << ", discarding appearance message" << LL_ENDL; +		return; +	} +  	S32 this_update_cof_version = contents.mCOFVersion;  	S32 last_update_request_cof_version = mLastUpdateRequestCOFVersion; -	// Only now that we have result of appearance_version can we decide whether to bail out.  	if( isSelf() )  	{  		LL_DEBUGS("Avatar") << "this_update_cof_version " << this_update_cof_version  				<< " last_update_request_cof_version " << last_update_request_cof_version  				<<  " my_cof_version " << LLAppearanceMgr::instance().getCOFVersion() << LL_ENDL; - -		if (getRegion() && (getRegion()->getCentralBakeVersion()==0)) -		{ -			LL_WARNS() << avString() << "Received AvatarAppearance message for self in non-server-bake region" << LL_ENDL; -		} -		if( mFirstTEMessageReceived && (appearance_version == 0)) -		{ -			return; -		}  	}  	else  	{ @@ -7227,7 +7166,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  	// Check for stale update.  	if (isSelf() -		&& (appearance_version>0)  		&& (this_update_cof_version < last_update_request_cof_version))  	{  		LL_WARNS() << "Stale appearance update, wanted version " << last_update_request_cof_version @@ -7241,6 +7179,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		return;  	} +	// SUNSHINE CLEANUP - is this case OK now?  	S32 num_params = contents.mParamWeights.size();  	if (num_params <= 1)  	{ @@ -7252,10 +7191,14 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  		return;  	} +	// No backsies zone - if we get here, the message should be valid and usable, will be processed. + +	// Note: +	// RequestAgentUpdateAppearanceResponder::onRequestRequested() +	// assumes that cof version is only updated with server-bake +	// appearance messages.  	mLastUpdateReceivedCOFVersion = this_update_cof_version; -	setIsUsingServerBakes(appearance_version > 0); -  	applyParsedTEMessage(contents.mTEContents);  	// prevent the overwriting of valid baked textures with invalid baked textures @@ -7265,9 +7208,15 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  			&& mBakedTextureDatas[baked_index].mLastTextureID != IMG_DEFAULT  			&& baked_index != BAKED_SKIRT)  		{ +			LL_DEBUGS("Avatar") << avString() << " baked_index " << (S32) baked_index << " using mLastTextureID " << mBakedTextureDatas[baked_index].mLastTextureID << LL_ENDL;  			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() << " baked_index " << (S32) baked_index << " using texture id " +								<< getTE(mBakedTextureDatas[baked_index].mTextureIndex)->getID() << LL_ENDL; +		}  	}  	// runway - was @@ -7293,32 +7242,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 << LL_ENDL; +					param->setWeight(newWeight);  				} +				else +				{ +					interp_params = TRUE; +					param->setAnimationTarget(newWeight); +				} +			}  		} -		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() << LL_ENDL;  		} +		LL_DEBUGS("Avatar") << "Changed " << params_changed_count << " params" << LL_ENDL;  		if (params_changed)  		{  			if (interp_params) @@ -7330,7 +7285,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  			ESex new_sex = getSex();  			if( old_sex != new_sex )  			{ -				updateSexDependentLayerSets( FALSE ); +				updateSexDependentLayerSets();  			}	  		} @@ -7368,7 +7323,6 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )  	}  	updateMeshTextures(); -  	//if (enable_verbose_dumps) dumpArchetypeXML(dump_prefix + "process_end");  } @@ -7553,7 +7507,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; @@ -7626,6 +7580,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); @@ -7634,10 +7597,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");  	} @@ -7704,6 +7663,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 ) @@ -7715,6 +7675,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" ); @@ -7837,41 +7798,6 @@ void LLVOAvatar::startAppearanceAnimation()  }  // 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 -{ -#if 1 -	// Sanity check - visual param for appearance version should match mUseServerBakes -	LLVisualParam* appearance_version_param = getVisualParam(11000); -	llassert(appearance_version_param); -	F32 wt = appearance_version_param->getWeight(); -	F32 expect_wt = mUseServerBakes ? 1.0 : 0.0; -	if (!is_approx_equal(wt,expect_wt)) -{ -		LL_WARNS() << "wt " << wt << " differs from expected " << expect_wt << LL_ENDL; -	} -#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()  			{  } diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 9d0391b42c..42ff7bff92 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 @@ -442,7 +440,7 @@ public:  	// Global colors  	//--------------------------------------------------------------------  public: -	/*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL upload_bake); +	/*virtual*/void onGlobalColorChanged(const LLTexGlobalColor* global_color);  	//--------------------------------------------------------------------  	// Visibility @@ -602,7 +600,7 @@ protected:  	// Composites  	//--------------------------------------------------------------------  public: -	virtual void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); +	virtual void	invalidateComposite(LLTexLayerSet* layerset);  	virtual void	invalidateAll();  	virtual void	setCompositeUpdatesEnabled(bool b) {}  	virtual void 	setCompositeUpdatesEnabled(U32 index, bool b) {} @@ -639,7 +637,7 @@ private:  public:  	void			debugColorizeSubMeshes(U32 i, const LLColor4& color);  	virtual void 	updateMeshTextures(); -	void 			updateSexDependentLayerSets(BOOL upload_bake); +	void 			updateSexDependentLayerSets();  	virtual void	dirtyMesh(); // Dirty the avatar mesh  	void 			updateMeshData();  protected: @@ -672,7 +670,6 @@ public:  	void 			processAvatarAppearance(LLMessageSystem* mesgsys);  	void 			hideSkirt();  	void			startAppearanceAnimation(); -	/*virtual*/ void bodySizeChanged();  	//--------------------------------------------------------------------  	// Appearance morphing @@ -685,12 +682,6 @@ public:  	// editing or when waiting for a subsequent server rebake.  	/*virtual*/ BOOL	isUsingLocalAppearance() const { return mUseLocalAppearance; } -	// True if this avatar should fetch its baked textures via the new -	// appearance mechanism. -	BOOL				isUsingServerBakes() const; -	void 				setIsUsingServerBakes(BOOL newval); - -  	// True if we are currently in appearance editing mode. Often but  	// not always the same as isUsingLocalAppearance().  	/*virtual*/ BOOL	isEditingAppearance() const { return mIsEditingAppearance; } @@ -703,7 +694,6 @@ private:  	F32				mLastAppearanceBlendTime;  	BOOL			mIsEditingAppearance; // flag for if we're actively in appearance editing mode  	BOOL			mUseLocalAppearance; // flag for if we're using a local composite -	BOOL			mUseServerBakes; // flag for if baked textures should be fetched from baking service (false if they're temporary uploads)  	//--------------------------------------------------------------------  	// Visibility @@ -1031,10 +1021,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 319da1abb5..42a7c2e576 100755 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -161,8 +161,6 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,  	mRegionCrossingCount(0),  	mInitialBakesLoaded(false)  { -	gAgentWearables.setAvatarObject(this); -  	mMotionController.mIsSelf = TRUE;  	LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL; @@ -188,15 +186,6 @@ bool update_avatar_rez_metrics()  	return false;  } -bool check_for_unsupported_baked_appearance() -{ -	if (!isAgentAvatarValid()) -		return true; - -	gAgentAvatarp->checkForUnsupportedServerBakeAppearance(); -	return false; -} -  void LLVOAvatarSelf::initInstance()  {  	BOOL status = TRUE; @@ -233,7 +222,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" << LL_ENDL; +		F32 change_time = gAgentWearables.getCOFChangeTime(); +		LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << LL_ENDL; +		S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns(); +		LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << LL_ENDL; +		S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations(); +		LL_DEBUGS("Avatar") << "active copy operations " << active_copies << LL_ENDL; + +		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 @@ -644,55 +659,42 @@ 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 ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight)  {  	if (!which_param)  	{  		return FALSE;  	}  	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID()); -	return setParamWeight(param,weight,upload_bake); +	return setParamWeight(param,weight);  }  // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight)  {  	if (!param_name)  	{  		return FALSE;  	}  	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name); -	return setParamWeight(param,weight,upload_bake); +	return setParamWeight(param,weight);  }  // virtual -BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight)  {  	LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index); -	return setParamWeight(param,weight,upload_bake); +	return setParamWeight(param,weight);  } -BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake ) +BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight)  {  	if (!param)  	{  		return FALSE;  	} -#if 0 -	// FIXME DRANO - kludgy way to avoid overwriting avatar state from wearables. -	if (isUsingServerBakes() && !isUsingLocalAppearance()) -	{ -		return FALSE; -	} -#endif -  	if (param->getCrossWearable())  	{  		LLWearableType::EType type = (LLWearableType::EType)param->getWearableType(); @@ -702,12 +704,12 @@ BOOL LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight  			LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count);  			if (wearable)  			{ -				wearable->setVisualParamWeight(param->getID(), weight, upload_bake); +				wearable->setVisualParamWeight(param->getID(), weight);  			}  		}  	} -	return LLCharacter::setVisualParamWeight(param,weight,upload_bake); +	return LLCharacter::setVisualParamWeight(param,weight);  }  /*virtual*/  @@ -720,7 +722,7 @@ void LLVOAvatarSelf::updateVisualParams()  void LLVOAvatarSelf::idleUpdateAppearanceAnimation()  {  	// Animate all top-level wearable visual parameters -	gAgentWearables.animateAllWearableParams(calcMorphAmount(), FALSE); +	gAgentWearables.animateAllWearableParams(calcMorphAmount());  	// apply wearable visual params to avatar  	for (U32 type = 0; type < LLWearableType::WT_COUNT; type++) @@ -762,57 +764,6 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id)  	}  } -//virtual -U32  LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys, -													 void **user_data, -													 U32 block_num, -													 const EObjectUpdateType update_type, -													 LLDataPacker *dp) -{ -	U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp); - -#if 0 -	// DRANO - it's not clear this does anything useful. If we wait -	// until an appearance message has been received, we already have -	// the texture ids. If we don't wait, we don't yet know where to -	// look for baked textures, because we haven't received the -	// appearance version data from the appearance message. This looks -	// like an old optimization that's incompatible with server-side -	// texture baking. -	 -	// FIXME DRANO - skipping in the case of !mFirstAppearanceMessageReceived prevents us from trying to -	// load textures before we know where they come from (ie, from baking service or not); -	// unknown impact on performance. -	if (mInitialBakesLoaded == false && retval == 0x0 && mFirstAppearanceMessageReceived) -	{ -		// call update textures to force the images to be created -		updateMeshTextures(); - -		// unpack the texture UUIDs to the texture slots -		if(mesgsys != NULL) -		{ -		retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, (S32) block_num); -		} - -		// need to trigger a few operations to get the avatar to use the new bakes -		for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -		{ -			const LLAvatarAppearanceDefines::ETextureIndex te = mBakedTextureDatas[i].mTextureIndex; -			LLUUID texture_id = getTEImage(te)->getID(); -			setNewBakedTexture(te, texture_id); -			mInitialBakeIDs[i] = texture_id; -		} - -		onFirstTEMessageReceived(); - -		mInitialBakesLoaded = true; -	} -#endif - -	return retval; -} - -  void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index)  {  	if (te >= TEX_NUM_INDICES) @@ -864,13 +815,9 @@ void LLVOAvatarSelf::removeMissingBakedTextures()  		{  			LLViewerTexLayerSet *layerset = getTexLayerSet(i);  			layerset->setUpdatesEnabled(TRUE); -			invalidateComposite(layerset, FALSE); -		} -		updateMeshTextures();	// may call back into this function -		if (getRegion() && !getRegion()->getCentralBakeVersion()) -		{ -			requestLayerSetUploads(); +			invalidateComposite(layerset);  		} +		updateMeshTextures();  	}  } @@ -1039,7 +986,7 @@ void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)  // forces an update to any baked textures relevant to type.  // will force an upload of the resulting bake if the second parameter is TRUE  //----------------------------------------------------------------------------- -void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_result ) +void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type)  {  	for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().begin();  		 baked_iter != LLAvatarAppearanceDictionary::getInstance()->getBakedTextures().end(); @@ -1061,20 +1008,13 @@ void LLVOAvatarSelf::wearableUpdated( LLWearableType::EType type, BOOL upload_re  					if (layerset)  					{  						layerset->setUpdatesEnabled(true); -						invalidateComposite(layerset, upload_result); +						invalidateComposite(layerset);  					}  					break;  				}  			}  		}  	} -	 -	// Physics type has no associated baked textures, but change of params needs to be sent to -	// other avatars. -	if (type == LLWearableType::WT_PHYSICS) -	  { -	    gAgent.sendAgentSetAppearance(); -	  }  }  //----------------------------------------------------------------------------- @@ -1486,15 +1426,6 @@ BOOL LLVOAvatarSelf::isAllLocalTextureDataFinal() const  	return TRUE;  } -BOOL LLVOAvatarSelf::isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const -{ -	const LLViewerTexLayerSet *layerset = getLayerSet(index); -	if (!layerset) return FALSE; -	const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite(); -	if (!layerset_buffer) return FALSE; -	return !layerset_buffer->uploadNeeded(); -} -  BOOL LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const  {  	LLUUID id; @@ -1552,49 +1483,12 @@ BOOL LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex t  	return isTextureVisible(type,index);  } - -//----------------------------------------------------------------------------- -// requestLayerSetUploads() -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::requestLayerSetUploads() -{ -	for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -	{ -		requestLayerSetUpload((EBakedTextureIndex)i); -	} -} - -void LLVOAvatarSelf::requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i) -{ -	ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex; -	const BOOL layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index)); -	LLViewerTexLayerSet *layerset = getLayerSet(i); -	if (!layer_baked && layerset) -	{ -		layerset->requestUpload(); -	} -} -  bool LLVOAvatarSelf::areTexturesCurrent() const  { -	return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded(); +	return gAgentWearables.areWearablesLoaded();  } -// virtual -bool LLVOAvatarSelf::hasPendingBakedUploads() const -{ -	for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -	{ -		LLViewerTexLayerSet* layerset = getTexLayerSet(i); -		if (layerset && layerset->getViewerComposite() && layerset->getViewerComposite()->uploadPending()) -		{ -			return true; -		} -	} -	return false; -} - -void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result ) +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset)  {  	LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset);  	if( !layer_set || !layer_set->getUpdatesEnabled() ) @@ -1605,16 +1499,6 @@ void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_r  	layer_set->requestUpdate();  	layer_set->invalidateMorphMasks(); - -	if( upload_result  && (getRegion() && !getRegion()->getCentralBakeVersion())) -	{ -		llassert(isSelf()); - -		ETextureIndex baked_te = getBakedTE( layer_set ); -		setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) ); -		layer_set->requestUpload(); -		updateMeshTextures(); -	}  }  void LLVOAvatarSelf::invalidateAll() @@ -1622,7 +1506,7 @@ void LLVOAvatarSelf::invalidateAll()  	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)  	{  		LLViewerTexLayerSet *layerset = getTexLayerSet(i); -		invalidateComposite(layerset, TRUE); +		invalidateComposite(layerset);  	}  	//mDebugSelfLoadTimer.reset();  } @@ -2033,7 +1917,10 @@ BOOL LLVOAvatarSelf::getIsCloud() const  /*static*/  void LLVOAvatarSelf::debugOnTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata)  { -	gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); +	if (gAgentAvatarp.notNull()) +	{ +		gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); +	}  }  void LLVOAvatarSelf::debugTimingLocalTexLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) @@ -2217,27 +2104,9 @@ const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const  	return text;  } - -#if 0 -// Dump avatar metrics data. -LLSD LLVOAvatarSelf::metricsData() -{ -	// runway - add region info -	LLSD result; -	result["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); -	result["timers"]["debug_existence"] = mDebugExistenceTimer.getElapsedTimeF32(); -	result["timers"]["ruth_debug"] = mRuthDebugTimer.getElapsedTimeF32(); -	result["timers"]["ruth"] = mRuthTimer.getElapsedTimeF32(); -	result["timers"]["invisible"] = mInvisibleTimer.getElapsedTimeF32(); -	result["timers"]["fully_loaded"] = mFullyLoadedTimer.getElapsedTimeF32(); -	result["startup"] = LLStartUp::getPhases().asLLSD(); -	 -	return result; -} -#endif -  class ViewerAppearanceChangeMetricsResponder: public LLCurl::Responder  { +	LOG_CLASS(ViewerAppearanceChangeMetricsResponder);  public:  	ViewerAppearanceChangeMetricsResponder( S32 expected_sequence,  											volatile const S32 & live_sequence, @@ -2248,32 +2117,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; @@ -2356,11 +2218,10 @@ LLSD summarize_by_buckets(std::vector<LLSD> in_records,  void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  { -	// gAgentAvatarp->stopAllPhases();  	static volatile bool reporting_started(false);  	static volatile S32 report_sequence(0); -	LLSD msg; // = metricsData(); +	LLSD msg;  	msg["message"] = "ViewerAppearanceChangeMetrics";  	msg["session_id"] = gAgentSessionID;  	msg["agent_id"] = gAgentID; @@ -2420,63 +2281,6 @@ void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()  	}  } -class CheckAgentAppearanceServiceResponder: public LLHTTPClient::Responder -{ -public: -	CheckAgentAppearanceServiceResponder() -	{ -	} -	 -	virtual ~CheckAgentAppearanceServiceResponder() -	{ -	} - -	/* virtual */ void result(const LLSD& content) -	{ -		LL_DEBUGS("Avatar") << "status OK" << LL_ENDL; -	} - -	// Error -	/*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content) -	{ -		if (isAgentAvatarValid()) -		{ -			LL_DEBUGS("Avatar") << "failed, will rebake [status:" -					<< status << "]: " << content << LL_ENDL; -			forceAppearanceUpdate(); -		} -	}	 - -	static void forceAppearanceUpdate() -	{ -		// Trying to rebake immediately after crossing region boundary -		// seems to be failure prone; adding a delay factor. Yes, this -		// fix is ad-hoc and not guaranteed to work in all cases. -		doAfterInterval(boost::bind(&LLVOAvatarSelf::forceBakeAllTextures, -									gAgentAvatarp.get(), true), 5.0); -	} -}; - -void LLVOAvatarSelf::checkForUnsupportedServerBakeAppearance() -{ -	// Need to check only if we have a server baked appearance and are -	// in a non-baking region. -	if (!gAgentAvatarp->isUsingServerBakes()) -		return; -	if (!gAgent.getRegion() || gAgent.getRegion()->getCentralBakeVersion()!=0) -		return; - -	// if baked image service is unknown, need to refresh. -	if (LLAppearanceMgr::instance().getAppearanceServiceURL().empty()) -	{ -		CheckAgentAppearanceServiceResponder::forceAppearanceUpdate(); -	} -	// query baked image service to check status. -	std::string image_url = gAgentAvatarp->getImageURL(TEX_HEAD_BAKED, -													   getTE(TEX_HEAD_BAKED)->getID()); -	LLHTTPClient::head(image_url, new CheckAgentAppearanceServiceResponder); -} -  const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const  {  	if (canGrabBakedTexture(baked_index)) @@ -2587,7 +2391,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe  				imagep->setBoostLevel(getAvatarBoostLevel());  				imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;  				imagep->resetTextureStats(); -				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL); +				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);  				imagep->addTextureStats( desired_pixels / texel_area_ratio );  				imagep->forceUpdateBindStats() ;  				if (imagep->getDiscardLevel() < 0) @@ -2633,82 +2437,6 @@ ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset )  	return TEX_HEAD_BAKED;  } - -void LLVOAvatarSelf::setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid) -{ -	ETextureIndex index = LLAvatarAppearanceDictionary::bakedToLocalTextureIndex(i); -	setNewBakedTexture(index, uuid); -} - - -//----------------------------------------------------------------------------- -// setNewBakedTexture() -// A new baked texture has been successfully uploaded and we can start using it now. -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ -	// Baked textures live on other sims. -	LLHost target_host = getObjectHost();	 -	setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, FTT_HOST_BAKE, target_host ) ); -	updateMeshTextures(); -	dirtyMesh(); - -	LLVOAvatar::cullAvatarsByPixelArea(); - -	/* switch(te) -		case TEX_HEAD_BAKED: -			LL_INFOS() << "New baked texture: HEAD" << LL_ENDL; */ -	const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(te); -	if (texture_dict->mIsBakedTexture) -	{ -		debugBakedTextureUpload(texture_dict->mBakedTextureIndex, TRUE); // FALSE for start of upload, TRUE for finish. -		LL_INFOS() << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <<LL_ENDL; -	} -	else -	{ -		LL_WARNS() << "New baked texture: unknown te " << te << LL_ENDL; -	} -	 -	//	dumpAvatarTEs( "setNewBakedTexture() send" ); -	// RN: throttle uploads -	if (!hasPendingBakedUploads()) -	{ -		gAgent.sendAgentSetAppearance(); - -		if (gSavedSettings.getBOOL("DebugAvatarRezTime")) -		{ -			LLSD args; -			args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); -			args["TIME"] = llformat("%d",(U32)mDebugSelfLoadTimer.getElapsedTimeF32()); -			if (isAllLocalTextureDataFinal()) -			{ -				LLNotificationsUtil::add("AvatarRezSelfBakedDoneNotification",args); -				LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() -						<< "sec ]" -						<< avString()  -						<< "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() -						<< " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() -						<< " Notification " << "AvatarRezSelfBakedDoneNotification" -						<< LL_ENDL; -			} -			else -			{ -				args["STATUS"] = debugDumpAllLocalTextureDataInfo(); -				LLNotificationsUtil::add("AvatarRezSelfBakedUpdateNotification",args); -				LL_DEBUGS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() -						<< "sec ]" -						<< avString()  -						<< "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() -						<< " SelfLoadTimer " << (U32)mDebugSelfLoadTimer.getElapsedTimeF32() -						<< " Notification " << "AvatarRezSelfBakedUpdateNotification" -						<< LL_ENDL; -			} -		} - -		outputRezDiagnostics(); -	} -} -  // FIXME: This is not called consistently. Something may be broken.  void LLVOAvatarSelf::outputRezDiagnostics() const  { @@ -2784,89 +2512,7 @@ void LLVOAvatarSelf::reportAvatarRezTime() const  	// TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow.  } -//----------------------------------------------------------------------------- -// setCachedBakedTexture() -// A baked texture id was received from a cache query, make it active -//----------------------------------------------------------------------------- -void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ -	setTETexture( te, uuid ); - -	/* switch(te) -		case TEX_HEAD_BAKED: -			if( mHeadLayerSet ) -				mHeadLayerSet->cancelUpload(); */ -	for (U32 i = 0; i < mBakedTextureDatas.size(); i++) -	{ -		LLViewerTexLayerSet *layerset = getTexLayerSet(i); -		if ( mBakedTextureDatas[i].mTextureIndex == te && layerset) -		{ -			if (mInitialBakeIDs[i] != LLUUID::null) -			{ -				if (mInitialBakeIDs[i] == uuid) -				{ -					LL_INFOS() << "baked texture correctly loaded at login! " << i << LL_ENDL; -				} -				else -				{ -					LL_WARNS() << "baked texture does not match id loaded at login!" << i << LL_ENDL; -				} -				mInitialBakeIDs[i] = LLUUID::null; -			} -			layerset->cancelUpload(); -		} -	} -} - -// static -void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) -{ -	LLUUID texture_id; -	msg->getUUID("TextureData", "TextureID", texture_id); -	if (!isAgentAvatarValid()) return; - -	// If this is a texture corresponding to one of our baked entries,  -	// just rebake that layer set. -	BOOL found = FALSE; - -	/* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = -			TEX_HEAD_BAKED, -			TEX_UPPER_BAKED, */ -	for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getTextures().begin(); -		 iter != LLAvatarAppearanceDictionary::getInstance()->getTextures().end(); -		 ++iter) -	{ -		const ETextureIndex index = iter->first; -		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; -		if (texture_dict->mIsBakedTexture) -		{ -			if (texture_id == gAgentAvatarp->getTEImage(index)->getID()) -			{ -				LLViewerTexLayerSet* layer_set = gAgentAvatarp->getLayerSet(index); -				if (layer_set) -				{ -					LL_INFOS() << "TAT: rebake - matched entry " << (S32)index << LL_ENDL; -					gAgentAvatarp->invalidateComposite(layer_set, TRUE); -					found = TRUE; -					add(LLStatViewer::TEX_REBAKES, 1); -				} -			} -		} -	} - -	// If texture not found, rebake all entries. -	if (!found) -	{ -		gAgentAvatarp->forceBakeAllTextures(); -	} -	else -	{ -		// Not sure if this is necessary, but forceBakeAllTextures() does it. -		gAgentAvatarp->updateMeshTextures(); -	} -} - - +// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures()  void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)  {  	LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL; @@ -2880,10 +2526,9 @@ void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)  			if (slam_for_debug)  			{  				layer_set->setUpdatesEnabled(TRUE); -				layer_set->cancelUpload();  			} -			invalidateComposite(layer_set, TRUE); +			invalidateComposite(layer_set);  			add(LLStatViewer::TEX_REBAKES, 1);  		}  		else @@ -2952,6 +2597,11 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)  {  	if (isAgentAvatarValid())  	{ +		if (!gAgentAvatarp->mEndCustomizeCallback.get()) +		{ +			gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy; +		} +		  		gAgentAvatarp->mIsEditingAppearance = true;  		gAgentAvatarp->mUseLocalAppearance = true; @@ -2978,12 +2628,6 @@ void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)  	if (isAgentAvatarValid())  	{  		gAgentAvatarp->mIsEditingAppearance = false; -		if (gAgentAvatarp->getRegion() && !gAgentAvatarp->getRegion()->getCentralBakeVersion()) -		{ -			// FIXME DRANO - move to sendAgentSetAppearance, make conditional on upload complete. -			gAgentAvatarp->mUseLocalAppearance = false; -		} -  		gAgentAvatarp->invalidateAll();  		if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch) @@ -2991,8 +2635,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 444175b62e..e03de9fa0b 100755 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -33,6 +33,7 @@  #include <map>  struct LocalTextureData; +class LLInventoryCallback;  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -87,21 +88,15 @@ public:  				void		resetJointPositions( void ); -	/*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight, BOOL upload_bake = FALSE ); -	/*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight, BOOL upload_bake = FALSE ); -	/*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight, BOOL upload_bake = FALSE ); +	/*virtual*/ BOOL setVisualParamWeight(const LLVisualParam *which_param, F32 weight); +	/*virtual*/ BOOL setVisualParamWeight(const char* param_name, F32 weight); +	/*virtual*/ BOOL setVisualParamWeight(S32 index, F32 weight);  	/*virtual*/ void updateVisualParams();  	/*virtual*/ void idleUpdateAppearanceAnimation(); -	/*virtual*/ U32  processUpdateMessage(LLMessageSystem *mesgsys, -													 void **user_data, -													 U32 block_num, -													 const EObjectUpdateType update_type, -													 LLDataPacker *dp); -  private:  	// helper function. Passed in param is assumed to be in avatar's parameter list. -	BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE ); +	BOOL setParamWeight(const LLViewerVisualParam *param, F32 weight); @@ -129,6 +124,7 @@ public:  public:  	/*virtual*/ BOOL 	updateCharacter(LLAgent &agent);  	/*virtual*/ void 	idleUpdateTractorBeam(); +	bool				checkStuckAppearance();  	//--------------------------------------------------------------------  	// Loading state @@ -185,12 +181,10 @@ public:  	// Loading status  	//--------------------------------------------------------------------  public: -	/*virtual*/ bool	hasPendingBakedUploads() const;  	S32					getLocalDiscardLevel(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;  	bool				areTexturesCurrent() const;  	BOOL				isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const;  	BOOL				isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const; -	BOOL				isBakedTextureFinal(const LLAvatarAppearanceDefines::EBakedTextureIndex index) const;  	// If you want to check all textures of a given type, pass gAgentWearables.getWearableCount() for index  	/*virtual*/ BOOL    isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const;  	/*virtual*/ BOOL	isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index = 0) const; @@ -225,11 +219,8 @@ private:  	//--------------------------------------------------------------------  public:  	LLAvatarAppearanceDefines::ETextureIndex getBakedTE(const LLViewerTexLayerSet* layerset ) const; -	void				setNewBakedTexture(LLAvatarAppearanceDefines::EBakedTextureIndex i, const LLUUID &uuid); -	void				setNewBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); -	void				setCachedBakedTexture(LLAvatarAppearanceDefines::ETextureIndex i, const LLUUID& uuid); +	// SUNSHINE CLEANUP - dead? or update to just call request appearance update?  	void				forceBakeAllTextures(bool slam_for_debug = false); -	static void			processRebakeAvatarTextures(LLMessageSystem* msg, void**);  protected:  	/*virtual*/ void	removeMissingBakedTextures(); @@ -237,8 +228,6 @@ protected:  	// Layers  	//--------------------------------------------------------------------  public: -	void 				requestLayerSetUploads(); -	void				requestLayerSetUpload(LLAvatarAppearanceDefines::EBakedTextureIndex i);  	void				requestLayerSetUpdate(LLAvatarAppearanceDefines::ETextureIndex i);  	LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::EBakedTextureIndex baked_index) const;  	LLViewerTexLayerSet* getLayerSet(LLAvatarAppearanceDefines::ETextureIndex index) const; @@ -248,7 +237,7 @@ public:  	// Composites  	//--------------------------------------------------------------------  public: -	/* virtual */ void	invalidateComposite(LLTexLayerSet* layerset, BOOL upload_result); +	/* virtual */ void	invalidateComposite(LLTexLayerSet* layerset);  	/* virtual */ void	invalidateAll();  	/* virtual */ void	setCompositeUpdatesEnabled(bool b); // only works for self  	/* virtual */ void  setCompositeUpdatesEnabled(U32 index, bool b); @@ -290,7 +279,7 @@ protected:   **/  public: -	void				wearableUpdated(LLWearableType::EType type, BOOL upload_result); +	void				wearableUpdated(LLWearableType::EType type);  protected:  	U32 getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const; @@ -331,6 +320,7 @@ private:  public:  	static void		onCustomizeStart(bool disable_camera_switch = false);  	static void		onCustomizeEnd(bool disable_camera_switch = false); +	LLPointer<LLInventoryCallback> mEndCustomizeCallback;  	//--------------------------------------------------------------------  	// Visibility @@ -392,7 +382,6 @@ public:  	const std::string		debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const; // Lists out state of this particular baked texture layer  	const std::string		debugDumpAllLocalTextureDataInfo() const; // Lists out which baked textures are at highest LOD  	void					sendViewerAppearanceChangeMetrics(); // send data associated with completing a change. -	void 					checkForUnsupportedServerBakeAppearance();  private:  	LLFrameTimer    		mDebugSelfLoadTimer;  	F32						mDebugTimeWearablesLoaded; diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 312842a70f..3c3dc33772 100755 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -55,26 +55,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( @@ -91,12 +92,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 09a2003ef8..9937a1c42a 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"]; @@ -2651,7 +2658,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; @@ -3153,7 +3160,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; @@ -3426,7 +3433,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; @@ -5393,9 +5400,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 d1108020ff..945d3711f0 100755 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -82,7 +82,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; @@ -4059,7 +4059,8 @@ U32 LLVOVolume::getPartitionType() const  }  LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp) -: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB, regionp) +: LLSpatialPartition(LLVOVolume::VERTEX_DATA_MASK, TRUE, GL_DYNAMIC_DRAW_ARB, regionp), +LLVolumeGeometryManager()  {  	mLODPeriod = 32;  	mDepthMask = FALSE; @@ -4070,7 +4071,8 @@ LLVolumePartition::LLVolumePartition(LLViewerRegion* regionp)  }  LLVolumeBridge::LLVolumeBridge(LLDrawable* drawablep, LLViewerRegion* regionp) -: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK, regionp) +: LLSpatialBridge(drawablep, TRUE, LLVOVolume::VERTEX_DATA_MASK, regionp), +LLVolumeGeometryManager()  {  	mDepthMask = FALSE;  	mLODPeriod = 32; @@ -4107,6 +4109,70 @@ bool can_batch_texture(LLFace* facep)  	return true;  } +const static U32 MAX_FACE_COUNT = 4096U; +int32_t LLVolumeGeometryManager::sInstanceCount = 0; +LLFace** LLVolumeGeometryManager::sFullbrightFaces = NULL; +LLFace** LLVolumeGeometryManager::sBumpFaces = NULL; +LLFace** LLVolumeGeometryManager::sSimpleFaces = NULL; +LLFace** LLVolumeGeometryManager::sNormFaces = NULL; +LLFace** LLVolumeGeometryManager::sSpecFaces = NULL; +LLFace** LLVolumeGeometryManager::sNormSpecFaces = NULL; +LLFace** LLVolumeGeometryManager::sAlphaFaces = NULL; + +LLVolumeGeometryManager::LLVolumeGeometryManager() +	: LLGeometryManager() +{ +	llassert(sInstanceCount >= 0); +	if (sInstanceCount == 0) +	{ +		allocateFaces(MAX_FACE_COUNT); +	} + +	++sInstanceCount; +} + +LLVolumeGeometryManager::~LLVolumeGeometryManager() +{ +	llassert(sInstanceCount > 0); +	--sInstanceCount; + +	if (sInstanceCount <= 0) +	{ +		freeFaces(); +		sInstanceCount = 0; +	} +} + +void LLVolumeGeometryManager::allocateFaces(U32 pMaxFaceCount) +{ +	sFullbrightFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +	sBumpFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +	sSimpleFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +	sNormFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +	sSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +	sNormSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +	sAlphaFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); +} + +void LLVolumeGeometryManager::freeFaces() +{ +	ll_aligned_free<64>(sFullbrightFaces); +	ll_aligned_free<64>(sBumpFaces); +	ll_aligned_free<64>(sSimpleFaces); +	ll_aligned_free<64>(sNormFaces); +	ll_aligned_free<64>(sSpecFaces); +	ll_aligned_free<64>(sNormSpecFaces); +	ll_aligned_free<64>(sAlphaFaces); + +	sFullbrightFaces = NULL; +	sBumpFaces = NULL; +	sSimpleFaces = NULL; +	sNormFaces = NULL; +	sSpecFaces = NULL; +	sNormSpecFaces = NULL; +	sAlphaFaces = NULL; +} +  static LLTrace::BlockTimerStatHandle FTM_REGISTER_FACE("Register Face");  void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) @@ -4429,16 +4495,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  	mFaceList.clear(); -	const U32 MAX_FACE_COUNT = 4096; -	 -	static LLFace** fullbright_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); -	static LLFace** bump_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); -	static LLFace** simple_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); -	static LLFace** norm_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); -	static LLFace** spec_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); -	static LLFace** normspec_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); -	static LLFace** alpha_faces = (LLFace**) ll_aligned_malloc<64>(MAX_FACE_COUNT*sizeof(LLFace*)); -	  	U32 fullbright_count = 0;  	U32 bump_count = 0;  	U32 simple_count = 0; @@ -4458,7 +4514,10 @@ 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;  	{  		LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST); @@ -4541,18 +4600,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();								 @@ -4560,43 +4613,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(); -										//LL_INFOS()<<"joint name "<<lookingForJoint.c_str()<<LL_ENDL;  										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)  					{ @@ -4820,7 +4872,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  						{ //can be treated as alpha mask  							if (simple_count < MAX_FACE_COUNT)  							{ -								simple_faces[simple_count++] = facep; +								sSimpleFaces[simple_count++] = facep;  							}  						}  						else @@ -4831,7 +4883,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  							}  							if (alpha_count < MAX_FACE_COUNT)  							{ -								alpha_faces[alpha_count++] = facep; +								sAlphaFaces[alpha_count++] = facep;  							}  						}  					} @@ -4854,14 +4906,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  									{ //has normal and specular maps (needs texcoord1, texcoord2, and tangent)  										if (normspec_count < MAX_FACE_COUNT)  										{ -											normspec_faces[normspec_count++] = facep; +											sNormSpecFaces[normspec_count++] = facep;  										}  									}  									else  									{ //has normal map (needs texcoord1 and tangent)  										if (norm_count < MAX_FACE_COUNT)  										{ -											norm_faces[norm_count++] = facep; +											sNormFaces[norm_count++] = facep;  										}  									}  								} @@ -4869,14 +4921,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  								{ //has specular map but no normal map, needs texcoord2  									if (spec_count < MAX_FACE_COUNT)  									{ -										spec_faces[spec_count++] = facep; +										sSpecFaces[spec_count++] = facep;  									}  								}  								else  								{ //has neither specular map nor normal map, only needs texcoord0  									if (simple_count < MAX_FACE_COUNT)  									{ -										simple_faces[simple_count++] = facep; +										sSimpleFaces[simple_count++] = facep;  									}  								}									  							} @@ -4884,14 +4936,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  							{ //needs normal + tangent  								if (bump_count < MAX_FACE_COUNT)  								{ -									bump_faces[bump_count++] = facep; +									sBumpFaces[bump_count++] = facep;  								}  							}  							else if (te->getShiny() || !te->getFullbright())  							{ //needs normal  								if (simple_count < MAX_FACE_COUNT)  								{ -									simple_faces[simple_count++] = facep; +									sSimpleFaces[simple_count++] = facep;  								}  							}  							else  @@ -4899,7 +4951,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  								facep->setState(LLFace::FULLBRIGHT);  								if (fullbright_count < MAX_FACE_COUNT)  								{ -									fullbright_faces[fullbright_count++] = facep; +									sFullbrightFaces[fullbright_count++] = facep;  								}  							}  						} @@ -4909,7 +4961,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  							{ //needs normal + tangent  								if (bump_count < MAX_FACE_COUNT)  								{ -									bump_faces[bump_count++] = facep; +									sBumpFaces[bump_count++] = facep;  								}  							}  							else if ((te->getShiny() && LLPipeline::sRenderBump) || @@ -4917,7 +4969,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  							{ //needs normal  								if (simple_count < MAX_FACE_COUNT)  								{ -									simple_faces[simple_count++] = facep; +									sSimpleFaces[simple_count++] = facep;  								}  							}  							else  @@ -4925,7 +4977,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  								facep->setState(LLFace::FULLBRIGHT);  								if (fullbright_count < MAX_FACE_COUNT)  								{ -									fullbright_faces[fullbright_count++] = facep; +									sFullbrightFaces[fullbright_count++] = facep;  								}  							}  						} @@ -4952,7 +5004,16 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  			{  				drawablep->clearState(LLDrawable::RIGGED);  			} +			  		} + +		 +		 +			 +		 +					 + +		  	}  	group->mBufferUsage = useage; @@ -4988,13 +5049,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)  		fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX;  	} -	genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, simple_count, FALSE, batch_textures, FALSE); -	genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, fullbright_count, FALSE, batch_textures); -	genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, alpha_count, TRUE, batch_textures); -	genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, bump_count, FALSE, FALSE); -	genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, norm_faces, norm_count, FALSE, FALSE); -	genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, spec_faces, spec_count, FALSE, FALSE); -	genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, normspec_faces, normspec_count, FALSE, FALSE); +	genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSimpleFaces, simple_count, FALSE, batch_textures, FALSE); +	genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sFullbrightFaces, fullbright_count, FALSE, batch_textures); +	genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sAlphaFaces, alpha_count, TRUE, batch_textures); +	genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sBumpFaces, bump_count, FALSE, FALSE); +	genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormFaces, norm_count, FALSE, FALSE); +	genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSpecFaces, spec_count, FALSE, FALSE); +	genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormSpecFaces, normspec_count, FALSE, FALSE);  	if (!LLPipeline::sDelayVBUpdate)  	{ diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 6085893129..b61fbbd073 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" << LL_ENDL;  		asset_arrived_callback( instance, userdata );  	}  	else diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 0cf0e7b9c0..ddb7f7bfce 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)  		{ -			LL_WARNS() << "Failed to get upload config (" << status << ")" << LL_ENDL; +			LL_WARNS() << "Failed to get upload config " << dumpResponse() << LL_ENDL;  			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)  		{ -			LL_WARNS() << "Failed to upload image: " << status << " " << reason << LL_ENDL; +			LL_WARNS() << "Failed to upload image " << dumpResponse() << LL_ENDL;  			LLWebProfile::reportImageUploadStatus(false);  			return;  		} @@ -158,33 +155,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 << LL_ENDL; -			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()) +			{ +				LL_WARNS() << "Received empty redirection URL " << dumpResponse() << LL_ENDL; +				LL_DEBUGS("Snapshots") << "[headers:" << getResponseHeaders() << "]" << LL_ENDL; +				LLWebProfile::reportImageUploadStatus(false); +			} +			else +			{ +				LL_DEBUGS("Snapshots") << "Got redirection URL: " << redir_url << LL_ENDL; +				LLHTTPClient::get(redir_url, new LLWebProfileResponders::PostImageRedirectResponder, headers); +			}  		}  		else  		{ -			LL_WARNS() << "Unexpected POST status: " << status << " " << reason << LL_ENDL; -			LL_DEBUGS("Snapshots") << "headers: [" << content << "]" << LL_ENDL; +			LL_WARNS() << "Unexpected POST response " << dumpResponse() << LL_ENDL; +			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) -	{ -	}  };  /////////////////////////////////////////////////////////////////////////////// @@ -203,7 +203,7 @@ void LLWebProfile::uploadImage(LLPointer<LLImageFormatted> image, const std::str  	LL_DEBUGS("Snapshots") << "Requesting " << config_url << LL_ENDL;  	LLSD headers = LLViewerMedia::getHeaders(); -	headers["Cookie"] = getAuthCookie(); +	headers[HTTP_OUT_HEADER_COOKIE] = getAuthCookie();  	LLHTTPClient::get(config_url, new LLWebProfileResponders::ConfigResponder(image), headers);  } @@ -227,8 +227,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/llwindebug.cpp b/indra/newview/llwindebug.cpp index 551d0be8d7..eff70ca0b2 100755 --- a/indra/newview/llwindebug.cpp +++ b/indra/newview/llwindebug.cpp @@ -45,7 +45,7 @@ public:  	~LLMemoryReserve();  	void reserve();  	void release(); -protected: +private:  	unsigned char *mReserve;  	static const size_t MEMORY_RESERVATION_SIZE;  }; @@ -53,7 +53,7 @@ protected:  LLMemoryReserve::LLMemoryReserve() :  	mReserve(NULL)  { -}; +}  LLMemoryReserve::~LLMemoryReserve()  { @@ -66,14 +66,19 @@ const size_t LLMemoryReserve::MEMORY_RESERVATION_SIZE = 5 * 1024 * 1024;  void LLMemoryReserve::reserve()  {  	if(NULL == mReserve) +	{  		mReserve = new unsigned char[MEMORY_RESERVATION_SIZE]; -}; +	} +}  void LLMemoryReserve::release()  { -	delete [] mReserve; +	if (NULL != mReserve) +	{ +		delete [] mReserve; +	}  	mReserve = NULL; -}; +}  static LLMemoryReserve gEmergencyMemoryReserve; @@ -130,6 +135,11 @@ void  LLWinDebug::init()  	}  } +void LLWinDebug::cleanup () +{ +	gEmergencyMemoryReserve.release(); +} +  void LLWinDebug::writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename)  {  	// Temporary fix to switch out the code that writes the DMP file. diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index 6f274c6f16..a3cbf6dc03 100755 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -37,6 +37,7 @@ class LLWinDebug:  public:  	static void init();  	static void generateMinidump(struct _EXCEPTION_POINTERS *pExceptionInfo = NULL); +	static void cleanup();  private:  	static void writeDumpToFile(MINIDUMP_TYPE type, MINIDUMP_EXCEPTION_INFORMATION *ExInfop, const std::string& filename);  }; 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 1ef2cfff8a..b4e8114a5f 100755 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1149,6 +1149,8 @@ public:  					<< sim << LL_ENDL;  			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 8e164337b6..c12c2cc24c 100755 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -333,7 +333,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/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 8ce56326d8..5e73dbb981 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, bool) {} diff --git a/indra/test/llassetuploadqueue_tut.cpp b/indra/test/llassetuploadqueue_tut.cpp index ec952e0058..25efe63d3f 100755 --- a/indra/test/llassetuploadqueue_tut.cpp +++ b/indra/test/llassetuploadqueue_tut.cpp @@ -45,11 +45,11 @@ LLAssetUploadResponder::~LLAssetUploadResponder()  {  } -void LLAssetUploadResponder::error(U32 statusNum, const std::string& reason) +void LLAssetUploadResponder::httpFailure()  {  } -void LLAssetUploadResponder::result(const LLSD& content) +void LLAssetUploadResponder::httpSuccess()  {  } diff --git a/indra/test/llblowfish_tut.cpp b/indra/test/llblowfish_tut.cpp index 96e30f4e1e..18eb01363f 100755 --- a/indra/test/llblowfish_tut.cpp +++ b/indra/test/llblowfish_tut.cpp @@ -65,7 +65,7 @@ namespace tut  			}  			if (!fp)  			{ -				LL_WARNS() << "unabled to open " << filename << LL_ENDL; +				LL_WARNS() << "unable to open " << filename << LL_ENDL;  				return false;  			} diff --git a/indra/test/llhttpnode_tut.cpp b/indra/test/llhttpnode_tut.cpp index 216c59d766..c528a34129 100755 --- a/indra/test/llhttpnode_tut.cpp +++ b/indra/test/llhttpnode_tut.cpp @@ -44,7 +44,7 @@ namespace tut  			std::ostringstream pathOutput;  			bool addSlash = false; -			LLSD& remainder = mContext["request"]["remainder"]; +			LLSD& remainder = mContext[CONTEXT_REQUEST]["remainder"];  			for (LLSD::array_const_iterator i = remainder.beginArray();  				i != remainder.endArray();  				++i) @@ -81,6 +81,7 @@ namespace tut  			void result(const LLSD& result) { mResult = result; }  			void status(S32 code, const std::string& message) { }  			void extendedResult(S32 code, const std::string& message, const LLSD& headers) { } +			void extendedResult(S32 code, const LLSD& result, const LLSD& headers) { }  		private:  			Response() {;} // Must be accessed through LLPointer. diff --git a/indra/test/llsd_new_tut.cpp b/indra/test/llsd_new_tut.cpp index f928a1bad0..03df1d339b 100755 --- a/indra/test/llsd_new_tut.cpp +++ b/indra/test/llsd_new_tut.cpp @@ -93,6 +93,18 @@ namespace tut  			ensure(			s + " type",	traits.checkType(actual));  			ensure_equals(	s + " value",	traits.get(actual), expectedValue);  		} + +		template<class T> +		static void ensureTypeAndRefValue(const char* msg, const LLSD& actual, +			const T& expectedValue) +		{ +			LLSDTraits<const T&> traits; +			 +			std::string s(msg); +			 +			ensure(			s + " type",	traits.checkType(actual)); +			ensure_equals(	s + " value",	traits.get(actual), expectedValue); +		}  	};  	typedef test_group<SDTestData>	SDTestGroup; @@ -162,7 +174,7 @@ namespace tut  		std::vector<U8> data;  		copy(&source[0], &source[sizeof(source)], back_inserter(data)); -		v = data;		ensureTypeAndValue("set to data", v, data); +		v = data;		ensureTypeAndRefValue("set to data", v, data);  		v.clear();  		ensure("reset to undefined", v.type() == LLSD::TypeUndefined); @@ -213,8 +225,8 @@ namespace tut  		const char source[] = "once in a blue moon";  		std::vector<U8> data;  		copy(&source[0], &source[sizeof(source)], back_inserter(data)); -		LLSD x1(data);	ensureTypeAndValue("construct vector<U8>", x1, data); -		LLSD x2 = data;	ensureTypeAndValue("initialize vector<U8>", x2, data); +		LLSD x1(data);	ensureTypeAndRefValue("construct vector<U8>", x1, data); +		LLSD x2 = data;	ensureTypeAndRefValue("initialize vector<U8>", x2, data);  	}  	void checkConversions(const char* msg, const LLSD& v, @@ -757,42 +769,6 @@ namespace tut  		{  			SDAllocationCheck check("shared values test for threaded work", 9); -			//U32 start_llsd_count = llsd::outstandingCount(); - -			LLSD m = LLSD::emptyMap(); - -			m["one"] = 1; -			m["two"] = 2; -			m["one_copy"] = m["one"];			// 3 (m, "one" and "two") - -			m["undef_one"] = LLSD(); -			m["undef_two"] = LLSD(); -			m["undef_one_copy"] = m["undef_one"]; - -			{	// Ensure first_array gets freed to avoid counting it -				LLSD first_array = LLSD::emptyArray(); -				first_array.append(1.0f); -				first_array.append(2.0f);			 -				first_array.append(3.0f);			// 7 - -				m["array"] = first_array; -				m["array_clone"] = first_array; -				m["array_copy"] = m["array"];		// 7 -			} - -			m["string_one"] = "string one value"; -			m["string_two"] = "string two value"; -			m["string_one_copy"] = m["string_one"];		// 9 - -			//U32 llsd_object_count = llsd::outstandingCount(); -			//std::cout << "Using " << (llsd_object_count - start_llsd_count) << " LLSD objects" << std::endl; - -			//m.dumpStats(); -		} - -		{ -			SDAllocationCheck check("shared values test for threaded work", 9); -  			//U32 start_llsd_count = LLSD::outstandingCount();  			LLSD m = LLSD::emptyMap(); @@ -852,3 +828,4 @@ namespace tut  		test serializations  	*/  } + diff --git a/indra/test/llsdtraits.h b/indra/test/llsdtraits.h index 8144aaee94..07f6193ce2 100755 --- a/indra/test/llsdtraits.h +++ b/indra/test/llsdtraits.h @@ -93,7 +93,7 @@ LLSDTraits<LLSD::URI>::LLSDTraits()  { }  template<> inline -LLSDTraits<LLSD::Binary>::LLSDTraits() +LLSDTraits<const LLSD::Binary&>::LLSDTraits()  	: type(LLSD::TypeBinary), getter(&LLSD::asBinary)  { } diff --git a/indra/test/lltut.h b/indra/test/lltut.h index 55d84bcaca..243e869be7 100755 --- a/indra/test/lltut.h +++ b/indra/test/lltut.h @@ -65,6 +65,16 @@ namespace tut  		ensure_approximately_equals(NULL, actual, expected, frac_bits);  	} +	inline void ensure_approximately_equals_range(const char *msg, F32 actual, F32 expected, F32 delta) +	{ +		if (fabs(actual-expected)>delta) +		{ +			std::stringstream ss; +			ss << (msg?msg:"") << (msg?": ":"") << "not equal actual: " << actual << " expected: " << expected << " tolerance: " << delta; +			throw tut::failure(ss.str().c_str()); +		} +	} +  	inline void ensure_memory_matches(const char* msg,const void* actual, U32 actual_len, const void* expected,U32 expected_len)  	{  		if((expected_len != actual_len) ||  diff --git a/indra/test/message_tut.cpp b/indra/test/message_tut.cpp index 4c0463c65c..57e423e550 100755 --- a/indra/test/message_tut.cpp +++ b/indra/test/message_tut.cpp @@ -45,6 +45,7 @@ namespace  			mStatus = code;  		}  		virtual void extendedResult(S32 code, const std::string& message, const LLSD& headers) { } +		virtual void extendedResult(S32 code, const LLSD& result, const LLSD& headers) { }  		S32 mStatus;  	};  } @@ -141,7 +142,7 @@ namespace tut  		const LLSD message;  		const LLPointer<Response> response = new Response();  		gMessageSystem->dispatch(name, message, response); -		ensure_equals(response->mStatus, 404); +		ensure_equals(response->mStatus, HTTP_NOT_FOUND);  	}  } diff --git a/indra/test/mock_http_client.cpp b/indra/test/mock_http_client.cpp index d7ef407d52..e72902bfc2 100755 --- a/indra/test/mock_http_client.cpp +++ b/indra/test/mock_http_client.cpp @@ -25,8 +25,7 @@   */  #include "linden_common.h" -#include "llsdhttpserver.h" -#include "lliohttpserver.h" +#include "llhttpnode.h"  namespace tut  { diff --git a/indra/test/mock_http_client.h b/indra/test/mock_http_client.h index 7668a43fdf..a2b9b435fb 100755 --- a/indra/test/mock_http_client.h +++ b/indra/test/mock_http_client.h @@ -98,7 +98,7 @@ namespace tut  			if (mSawError)  			{  				std::string msg = -					llformat("error() called when not expected, status %d", +					llformat("httpFailure() called when not expected, status %d",  						mStatus);   				fail(msg);  			} @@ -108,7 +108,7 @@ namespace tut  		{  			if (!mSawError)  			{ -				fail("error() wasn't called"); +				fail("httpFailure() wasn't called");  			}  		} @@ -119,7 +119,7 @@ namespace tut  	protected:  		bool mSawError; -		U32 mStatus; +		S32 mStatus;  		std::string mReason;  		bool mSawCompleted;  		LLSD mResult; @@ -144,23 +144,22 @@ namespace tut  				mClient.mResultDeleted = true;  			} -			virtual void error(U32 status, const std::string& reason) +		protected: +			virtual void httpFailure()  			{  				mClient.mSawError = true; -				mClient.mStatus = status; -				mClient.mReason = reason; +				mClient.mStatus = getStatus(); +				mClient.mReason = getReason();  			} -			virtual void result(const LLSD& content) +			virtual void httpSuccess()  			{ -				mClient.mResult = content; +				mClient.mResult = getContent();  			} -			virtual void completed( -							U32 status, const std::string& reason, -							const LLSD& content) +			virtual void httpCompleted()  			{ -				LLHTTPClient::Responder::completed(status, reason, content); +				LLHTTPClient::Responder::httpCompleted();  				mClient.mSawCompleted = true;  			} diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 10f71a2843..e42374d56b 100755 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -95,25 +95,20 @@ public:  	virtual void replay(std::ostream&) {}  }; -class LLReplayLogReal: public LLReplayLog, public LLError::Recorder, public boost::noncopyable +class RecordToTempFile : public LLError::Recorder, public boost::noncopyable  {  public: -	LLReplayLogReal(LLError::ELevel level, apr_pool_t* pool): -		mOldSettings(LLError::saveAndResetSettings()), -		mProxy(new RecorderProxy(this)), -		mTempFile("log", "", pool),		// create file -		mFile(mTempFile.getName().c_str()) // open it +	RecordToTempFile(apr_pool_t* pPool) +		: LLError::Recorder(), +		boost::noncopyable(), +		mTempFile("log", "", pPool), +		mFile(mTempFile.getName().c_str())  	{ -		LLError::setFatalFunction(wouldHaveCrashed); -		LLError::setDefaultLevel(level); -		LLError::addRecorder(mProxy);  	} -	virtual ~LLReplayLogReal() +	virtual ~RecordToTempFile()  	{ -		LLError::removeRecorder(mProxy); -		delete mProxy; -		LLError::restoreSettings(mOldSettings); +		mFile.close();  	}  	virtual void recordMessage(LLError::ELevel level, const std::string& message) @@ -121,13 +116,13 @@ public:  		mFile << message << std::endl;  	} -	virtual void reset() +	void reset()  	{  		mFile.close();  		mFile.open(mTempFile.getName().c_str());  	} -	virtual void replay(std::ostream& out) +	void replay(std::ostream& out)  	{  		mFile.close();  		std::ifstream inf(mTempFile.getName().c_str()); @@ -139,12 +134,45 @@ public:  	}  private: -	LLError::Settings* mOldSettings; -	LLError::Recorder* mProxy;  	NamedTempFile mTempFile;  	std::ofstream mFile;  }; +class LLReplayLogReal: public LLReplayLog, public boost::noncopyable +{ +public: +	LLReplayLogReal(LLError::ELevel level, apr_pool_t* pool) +		: LLReplayLog(), +		boost::noncopyable(), +		mOldSettings(LLError::saveAndResetSettings()), +		mRecorder(new RecordToTempFile(pool)) +	{ +		LLError::setFatalFunction(wouldHaveCrashed); +		LLError::setDefaultLevel(level); +		LLError::addRecorder(mRecorder); +	} + +	virtual ~LLReplayLogReal() +	{ +		LLError::removeRecorder(mRecorder); +		LLError::restoreSettings(mOldSettings); +	} + +	virtual void reset() +	{ +		boost::dynamic_pointer_cast<RecordToTempFile>(mRecorder)->reset(); +	} + +	virtual void replay(std::ostream& out) +	{ +		boost::dynamic_pointer_cast<RecordToTempFile>(mRecorder)->replay(out); +	} + +private: +	LLError::SettingsStoragePtr mOldSettings; +	LLError::RecorderPtr mRecorder; +}; +  class LLTestCallback : public tut::callback  {  public: diff --git a/indra/viewer_components/updater/llupdatechecker.cpp b/indra/viewer_components/updater/llupdatechecker.cpp index dc8ff2f644..8da4f88905 100755 --- a/indra/viewer_components/updater/llupdatechecker.cpp +++ b/indra/viewer_components/updater/llupdatechecker.cpp @@ -130,12 +130,13 @@ void LLUpdateChecker::Implementation::checkVersion(std::string const & urlBase,  	}  } -void LLUpdateChecker::Implementation::completed(U32 status, -												const std::string & reason, -												const LLSD & content) +void LLUpdateChecker::Implementation::httpCompleted()  {  	mInProgress = false;	 -	 + +	S32 status = getStatus(); +	const LLSD& content = getContent(); +	const std::string& reason = getReason();  	if(status != 200)  	{  		std::string server_error; @@ -162,8 +163,9 @@ void LLUpdateChecker::Implementation::completed(U32 status,  } -void LLUpdateChecker::Implementation::error(U32 status, const std::string & reason) +void LLUpdateChecker::Implementation::httpFailure()  { +	const std::string& reason = getReason();  	mInProgress = false;  	LL_WARNS("UpdaterService") << "update check failed; " << reason << LL_ENDL;  	mClient.error(reason); diff --git a/indra/viewer_components/updater/llupdatechecker.h b/indra/viewer_components/updater/llupdatechecker.h index 4244007340..3163a6d53c 100755 --- a/indra/viewer_components/updater/llupdatechecker.h +++ b/indra/viewer_components/updater/llupdatechecker.h @@ -52,11 +52,10 @@ public:  						  bool                willing_to_test  						  ); +    protected:  		// Responder: -		virtual void completed(U32 status, -							   const std::string & reason, -							   const LLSD& content); -		virtual void error(U32 status, const std::string & reason); +		virtual void httpCompleted(); +		virtual void httpFailure();  	private:	  		static const char * sLegacyProtocolVersion;  | 
