diff options
Diffstat (limited to 'indra')
| -rwxr-xr-x | indra/llmessage/llhttpclient.cpp | 13 | ||||
| -rwxr-xr-x | indra/llmessage/llhttpclient.h | 18 | ||||
| -rwxr-xr-x | indra/llmessage/llhttpconstants.cpp | 6 | ||||
| -rwxr-xr-x | indra/llmessage/llhttpconstants.h | 1 | ||||
| -rwxr-xr-x | indra/llmessage/llurlrequest.cpp | 10 | ||||
| -rwxr-xr-x | indra/newview/llaisapi.cpp | 588 | ||||
| -rwxr-xr-x | indra/newview/llaisapi.h | 55 | ||||
| -rwxr-xr-x | indra/newview/llappearancemgr.cpp | 76 | ||||
| -rwxr-xr-x | indra/newview/llinventorymodel.cpp | 24 | ||||
| -rwxr-xr-x | indra/newview/llviewerinventory.cpp | 62 | ||||
| -rwxr-xr-x | indra/newview/llviewerinventory.h | 4 | ||||
| -rwxr-xr-x | indra/newview/llviewerregion.cpp | 19 | ||||
| -rwxr-xr-x | indra/newview/llviewerregion.h | 1 | 
13 files changed, 689 insertions, 188 deletions
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp index 53cef54559..70c890a8de 100755 --- a/indra/llmessage/llhttpclient.cpp +++ b/indra/llmessage/llhttpclient.cpp @@ -631,6 +631,19 @@ void LLHTTPClient::move(  	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); +} +  void LLHTTPClient::setPump(LLPumpIO& pump)  { diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h index 4e7495495f..5ace2d74c9 100755 --- a/indra/llmessage/llhttpclient.h +++ b/indra/llmessage/llhttpclient.h @@ -119,7 +119,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  	 * @@ -136,6 +136,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/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp index 016f1f1970..01f4a080b0 100755 --- a/indra/llmessage/llhttpconstants.cpp +++ b/indra/llmessage/llhttpconstants.cpp @@ -133,6 +133,8 @@ 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)  { @@ -145,7 +147,9 @@ const std::string& httpMethodAsVerb(EHTTPMethod method)  		HTTP_VERB_POST,  		HTTP_VERB_DELETE,  		HTTP_VERB_MOVE, -		HTTP_VERB_OPTIONS +		HTTP_VERB_OPTIONS, +		HTTP_VERB_PATCH, +		HTTP_VERB_COPY  	};  	if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT))  	{ diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h index aa947af414..4aa3cc6394 100755 --- a/indra/llmessage/llhttpconstants.h +++ b/indra/llmessage/llhttpconstants.h @@ -112,6 +112,7 @@ enum EHTTPMethod  	HTTP_MOVE, // Caller will need to set 'Destination' header  	HTTP_OPTIONS,  	HTTP_PATCH, +	HTTP_COPY,  	HTTP_METHOD_COUNT  }; diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp index cadff49cb8..7bf930aeb0 100755 --- a/indra/llmessage/llurlrequest.cpp +++ b/indra/llmessage/llurlrequest.cpp @@ -516,13 +516,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; diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp index 6d5f1951f9..cb8700865a 100755 --- a/indra/newview/llaisapi.cpp +++ b/indra/newview/llaisapi.cpp @@ -40,14 +40,25 @@  // 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);  } -void AISCommand::run_command() +bool AISCommand::run_command()  { -	mCommandFunc(); +	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) @@ -80,9 +91,9 @@ void AISCommand::httpSuccess()  	if (mCallback)  	{ -		LLUUID item_id; // will default to null if parse fails. -		getResponseUUID(content,item_id); -		mCallback->fire(item_id); +		LLUUID id; // will default to null if parse fails. +		getResponseUUID(content,id); +		mCallback->fire(id);  	}  } @@ -96,12 +107,12 @@ void AISCommand::httpFailure()  	if (!content.isMap())  	{  		LL_DEBUGS("Inventory") << "Malformed response contents " << content -							   << " status " << status << " reason " << reason << llendl; +							   << " status " << status << " reason " << reason << LL_ENDL;  	}  	else  	{  		LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content) -							   << " status " << status << " reason " << reason << llendl; +							   << " status " << status << " reason " << reason << LL_ENDL;  	}  	mRetryPolicy->onFailure(status, headers);  	F32 seconds_to_wait; @@ -113,12 +124,23 @@ void AISCommand::httpFailure()  	{  		// 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::getCap(std::string& cap) +bool AISCommand::isAPIAvailable() +{ +	if (gAgent.getRegion()) +	{ +		return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3"); +	} +	return false; +} + +//static +bool AISCommand::getInvCap(std::string& cap)  {  	if (gAgent.getRegion())  	{ @@ -131,18 +153,39 @@ bool AISCommand::getCap(std::string& cap)  	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 (!getCap(cap)) +	if (!getInvCap(cap))  	{  		llwarns << "No cap found" << llendl;  		return;  	}  	std::string url = cap + std::string("/item/") + item_id.asString(); -	LL_DEBUGS("Inventory") << "url: " << url << llendl; +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;  	LLHTTPClient::ResponderPtr responder = this;  	LLSD headers;  	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; @@ -155,13 +198,13 @@ RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id,  	AISCommand(callback)  {  	std::string cap; -	if (!getCap(cap)) +	if (!getInvCap(cap))  	{  		llwarns << "No cap found" << llendl;  		return;  	}  	std::string url = cap + std::string("/category/") + item_id.asString(); -	LL_DEBUGS("Inventory") << "url: " << url << llendl; +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;  	LLHTTPClient::ResponderPtr responder = this;  	LLSD headers;  	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; @@ -174,13 +217,13 @@ PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id,  	AISCommand(callback)  {  	std::string cap; -	if (!getCap(cap)) +	if (!getInvCap(cap))  	{  		llwarns << "No cap found" << llendl;  		return;  	}  	std::string url = cap + std::string("/category/") + item_id.asString() + "/children"; -	LL_DEBUGS("Inventory") << "url: " << url << llendl; +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;  	LLCurl::ResponderPtr responder = this;  	LLSD headers;  	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; @@ -195,14 +238,14 @@ UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id,  	AISCommand(callback)  {  	std::string cap; -	if (!getCap(cap)) +	if (!getInvCap(cap))  	{  		llwarns << "No cap found" << llendl;  		return;  	}  	std::string url = cap + std::string("/item/") + item_id.asString(); -	LL_DEBUGS("Inventory") << "url: " << url << llendl; -	LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << llendl; +	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"; @@ -218,13 +261,13 @@ UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& item_id,  	AISCommand(callback)  {  	std::string cap; -	if (!getCap(cap)) +	if (!getInvCap(cap))  	{  		llwarns << "No cap found" << llendl;  		return;  	}  	std::string url = cap + std::string("/category/") + item_id.asString(); -	LL_DEBUGS("Inventory") << "url: " << url << llendl; +	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;  	LLCurl::ResponderPtr responder = this;  	LLSD headers;  	headers["Content-Type"] = "application/llsd+xml"; @@ -238,7 +281,7 @@ SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& conten  	AISCommand(callback)  {  	std::string cap; -	if (!getCap(cap)) +	if (!getInvCap(cap))  	{  		llwarns << "No cap found" << llendl;  		return; @@ -255,146 +298,335 @@ SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& conten  	setCommandFunc(cmd);  } +CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id, +													   const LLUUID& dest_id, +													   LLPointer<LLInventoryCallback> callback): +	AISCommand(callback) +{ +	std::string cap; +	if (!getLibCap(cap)) +	{ +		llwarns << "No cap found" << llendl; +		return; +	} +	LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL; +	LLUUID tid; +	tid.generate(); +	std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString(); +	llinfos << url << llendl; +	LLCurl::ResponderPtr responder = this; +	LLSD headers; +	F32 timeout = HTTP_REQUEST_EXPIRY_SECS; +	command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout); +	setCommandFunc(cmd); +} + +bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id) +{ +	if (content.has("category_id")) +	{ +		id = content["category_id"]; +		return true; +	} +	return false; +} +  AISUpdate::AISUpdate(const LLSD& update)  {  	parseUpdate(update);  } +void AISUpdate::clearParseResults() +{ +	mCatDescendentDeltas.clear(); +	mCatDescendentsKnown.clear(); +	mCatVersionsUpdated.clear(); +	mItemsCreated.clear(); +	mItemsUpdated.clear(); +	mCategoriesCreated.clear(); +	mCategoriesUpdated.clear(); +	mObjectsDeletedIds.clear(); +	mItemIds.clear(); +	mCategoryIds.clear(); +} +  void AISUpdate::parseUpdate(const LLSD& update)  { -	// parse _categories_removed -> mObjectsDeleted -	uuid_vec_t cat_ids; +	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_vec_t::const_iterator it = cat_ids.begin(); +	for (uuid_list_t::const_iterator it = cat_ids.begin();  		 it != cat_ids.end(); ++it)  	{  		LLViewerInventoryCategory *cat = gInventory.getCategory(*it); -		mCatDeltas[cat->getParentUUID()]--; -		mObjectsDeleted.insert(*it); +		mCatDescendentDeltas[cat->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it);  	} -	// parse _categories_items_removed -> mObjectsDeleted -	uuid_vec_t item_ids; +	// parse _categories_items_removed -> mObjectsDeletedIds +	uuid_list_t item_ids;  	parseUUIDArray(update,"_category_items_removed",item_ids); -	for (uuid_vec_t::const_iterator it = item_ids.begin(); +	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); -		mCatDeltas[item->getParentUUID()]--; -		mObjectsDeleted.insert(*it); +		mCatDescendentDeltas[item->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it);  	} -	// parse _broken_links_removed -> mObjectsDeleted -	uuid_vec_t broken_link_ids; +	// parse _broken_links_removed -> mObjectsDeletedIds +	uuid_list_t broken_link_ids;  	parseUUIDArray(update,"_broken_links_removed",broken_link_ids); -	for (uuid_vec_t::const_iterator it = broken_link_ids.begin(); +	for (uuid_list_t::const_iterator it = broken_link_ids.begin();  		 it != broken_link_ids.end(); ++it)  	{  		LLViewerInventoryItem *item = gInventory.getItem(*it); -		mCatDeltas[item->getParentUUID()]--; -		mObjectsDeleted.insert(*it); +		mCatDescendentDeltas[item->getParentUUID()]--; +		mObjectsDeletedIds.insert(*it);  	}  	// parse _created_items -	parseUUIDArray(update,"_created_items",mItemsCreatedIds); +	parseUUIDArray(update,"_created_items",mItemIds); + +	// parse _created_categories +	parseUUIDArray(update,"_created_categories",mCategoryIds); -	if (update.has("_embedded")) +	// Parse updated category versions. +	const std::string& ucv = "_updated_category_versions"; +	if (update.has(ucv))  	{ -		const LLSD& embedded = update["_embedded"]; -		for(LLSD::map_const_iterator it = embedded.beginMap(), -				end = embedded.endMap(); -				it != end; ++it) +		for(LLSD::map_const_iterator it = update[ucv].beginMap(), +				end = update[ucv].endMap(); +			it != end; ++it)  		{ -			const std::string& field = (*it).first; -			 -			// parse created links -			if (field == "link") -			{ -				const LLSD& links = embedded["link"]; -				parseCreatedLinks(links); -			} +			const LLUUID id((*it).first); +			S32 version = (*it).second.asInteger(); +			mCatVersionsUpdated[id] = version;  		}  	} +} -	// Parse item update at the top level. -	if (update.has("item_id")) +void AISUpdate::parseContent(const LLSD& update) +{ +	if (update.has("linked_id"))  	{ -		LLUUID item_id = update["item_id"].asUUID(); -		LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); -		LLViewerInventoryItem *curr_item = gInventory.getItem(item_id); -		if (curr_item) +		parseLink(update); +	} +	else if (update.has("item_id")) +	{ +		parseItem(update); +	} + +	if (update.has("category_id")) +	{ +		parseCategory(update); +	} +	else +	{ +		if (update.has("_embedded"))  		{ -			// Default to current values where not provided. -			new_item->copyViewerItem(curr_item); +			parseEmbedded(update["_embedded"]);  		} -		BOOL rv = new_item->unpackMessage(update); -		if (rv) +	} +} + +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. -			mCatDeltas[new_item->getParentUUID()]; +			mCatDescendentDeltas[new_item->getParentUUID()];  		}  		else  		{ -			llerrs << "unpack failed" << llendl; +			mItemsCreated[item_id] = new_item; +			mCatDescendentDeltas[new_item->getParentUUID()]++;  		}  	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		llerrs << "unpack failed" << llendl; +	} +} -	// Parse updated category versions. -	const std::string& ucv = "_updated_category_versions"; -	if (update.has(ucv)) +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)  	{ -		for(LLSD::map_const_iterator it = update[ucv].beginMap(), -				end = update[ucv].endMap(); -			it != end; ++it) +		// 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)  		{ -			const LLUUID id((*it).first); -			S32 version = (*it).second.asInteger(); -			mCatVersions[id] = version; +			mItemsUpdated[item_id] = new_link; +			// This statement is here to cause a new entry with 0 +			// delta to be created if it does not already exist; +			// otherwise has no effect. +			mCatDescendentDeltas[parent_id]; +		} +		else +		{ +			LLPermissions default_perms; +			default_perms.init(gAgent.getID(),gAgent.getID(),LLUUID::null,LLUUID::null); +			default_perms.initMasks(PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE,PERM_NONE); +			new_link->setPermissions(default_perms); +			LLSaleInfo default_sale_info; +			new_link->setSaleInfo(default_sale_info); +			//LL_DEBUGS("Inventory") << "creating link from llsd: " << ll_pretty_print_sd(link_map) << LL_ENDL; +			mItemsCreated[item_id] = new_link; +			mCatDescendentDeltas[parent_id]++;  		}  	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		llerrs << "unpack failed" << llendl; +	}  } -void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_vec_t& ids) + +void AISUpdate::parseCategory(const LLSD& category_map)  { -	ids.clear(); -	if (content.has(name)) +	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"))  	{ -		for(LLSD::array_const_iterator it = content[name].beginArray(), -				end = content[name].endArray(); -				it != end; ++it) +		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()]; +		} +		else  		{ -			ids.push_back((*it).asUUID()); +			// Set version/descendents for newly created categories. +			if (category_map.has("version")) +			{ +				S32 version = category_map["version"].asInteger(); +				LL_DEBUGS("Inventory") << "Setting version to " << version +									   << " for new category " << category_id << LL_ENDL; +				new_cat->setVersion(version); +			} +			uuid_int_map_t::const_iterator lookup_it = mCatDescendentsKnown.find(category_id); +			if (mCatDescendentsKnown.end() != lookup_it) +			{ +				S32 descendent_count = lookup_it->second; +				LL_DEBUGS("Inventory") << "Setting descendents count to " << descendent_count  +									   << " for new category " << category_id << LL_ENDL; +				new_cat->setDescendentCount(descendent_count); +			} +			mCategoriesCreated[category_id] = new_cat; +			mCatDescendentDeltas[new_cat->getParentUUID()]++;  		}  	} +	else +	{ +		// *TODO: Wow, harsh.  Should we just complain and get out? +		llerrs << "unpack failed" << llendl; +	} + +	// Check for more embedded content. +	if (category_map.has("_embedded")) +	{ +		parseEmbedded(category_map["_embedded"]); +	}  } -void AISUpdate::parseLink(const LLUUID& link_id, const LLSD& link_map) +void AISUpdate::parseDescendentCount(const LLUUID& category_id, const LLSD& embedded)  { -	LLPointer<LLViewerInventoryItem> new_link(new LLViewerInventoryItem); -	BOOL rv = new_link->unpackMessage(link_map); -	if (rv) +	// We can only determine true descendent count if this contains all descendent types. +	if (embedded.has("category") && +		embedded.has("link") && +		embedded.has("item"))  	{ -		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) << llendl; -		mItemsCreated[link_id] = new_link; -		const LLUUID& parent_id = new_link->getParentUUID(); -		mCatDeltas[parent_id]++; +		mCatDescendentsKnown[category_id]  = embedded["category"].size(); +		mCatDescendentsKnown[category_id] += embedded["link"].size(); +		mCatDescendentsKnown[category_id] += embedded["item"].size();  	} -	else +} + +void AISUpdate::parseEmbedded(const LLSD& embedded) +{ +	if (embedded.has("link")) +	{ +		parseEmbeddedLinks(embedded["link"]); +	} +	if (embedded.has("item")) +	{ +		parseEmbeddedItems(embedded["item"]); +	} +	if (embedded.has("category"))  	{ -		llwarns << "failed to parse" << llendl; +		parseEmbeddedCategories(embedded["category"]); +	} +} + +void AISUpdate::parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids) +{ +	if (content.has(name)) +	{ +		for(LLSD::array_const_iterator it = content[name].beginArray(), +				end = content[name].endArray(); +				it != end; ++it) +		{ +			ids.insert((*it).asUUID()); +		}  	}  } -void AISUpdate::parseCreatedLinks(const LLSD& links) +void AISUpdate::parseEmbeddedLinks(const LLSD& links)  {  	for(LLSD::map_const_iterator linkit = links.beginMap(),  			linkend = links.endMap(); @@ -402,47 +634,134 @@ void AISUpdate::parseCreatedLinks(const LLSD& links)  	{  		const LLUUID link_id((*linkit).first);  		const LLSD& link_map = (*linkit).second; -		uuid_vec_t::const_iterator pos = -			std::find(mItemsCreatedIds.begin(), -					  mItemsCreatedIds.end(),link_id); -		if (pos != mItemsCreatedIds.end()) +		if (mItemIds.end() == mItemIds.find(link_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL; +		} +		else +		{ +			parseLink(link_map); +		} +	} +} + +void AISUpdate::parseEmbeddedItems(const LLSD& items) +{ +	// Special case: this may be a single item (_embedded in a link) +	if (items.has("item_id")) +	{ +		if (mItemIds.end() != mItemIds.find(items["item_id"].asUUID())) +		{ +			parseContent(items); +		} +		return; +	} + +	for(LLSD::map_const_iterator itemit = items.beginMap(), +			itemend = items.endMap(); +		itemit != itemend; ++itemit) +	{ +		const LLUUID item_id((*itemit).first); +		const LLSD& item_map = (*itemit).second; +		if (mItemIds.end() == mItemIds.find(item_id)) +		{ +			LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL; +		} +		else +		{ +			parseItem(item_map); +		} +	} +} + +void AISUpdate::parseEmbeddedCategories(const LLSD& categories) +{ +	for(LLSD::map_const_iterator categoryit = categories.beginMap(), +			categoryend = categories.endMap(); +		categoryit != categoryend; ++categoryit) +	{ +		const LLUUID category_id((*categoryit).first); +		const LLSD& category_map = (*categoryit).second; +		if (mCategoryIds.end() == mCategoryIds.find(category_id))  		{ -			parseLink(link_id,link_map); +			LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;  		}  		else  		{ -			LL_DEBUGS("Inventory") << "Ignoring link not in created items list " << link_id << llendl; +			parseCategory(category_map);  		}  	}  }  void AISUpdate::doUpdate()  { -	// Do descendent/version accounting. -	// Can remove this if/when we use the version info directly. -	for (std::map<LLUUID,S32>::const_iterator catit = mCatDeltas.begin(); -		 catit != mCatDeltas.end(); ++catit) +	// Do version/descendent accounting. +	for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin(); +		 catit != mCatDescendentDeltas.end(); ++catit)  	{  		const LLUUID cat_id(catit->first); -		S32 delta = catit->second; -		LLInventoryModel::LLCategoryUpdate up(cat_id, delta); -		gInventory.accountForUpdate(up); +		// 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_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; +		}  	} -	 -	// 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 = mCatVersions.begin(); -		 ucv_it != mCatVersions.end(); ++ucv_it) + +	// CREATE CATEGORIES +	for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin(); +		 create_it != mCategoriesCreated.end(); ++create_it)  	{ -		const LLUUID id = ucv_it->first; -		S32 version = ucv_it->second; -		LLViewerInventoryCategory *cat = gInventory.getCategory(id); -		if (cat->getVersion() != version) +		LLUUID category_id(create_it->first); +		LLPointer<LLViewerInventoryCategory> new_category = create_it->second; + +		gInventory.updateCategory(new_category); +		LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL; +	} + +	// UPDATE CATEGORIES +	for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin(); +		 update_it != mCategoriesUpdated.end(); ++update_it) +	{ +		LLUUID category_id(update_it->first); +		LLPointer<LLViewerInventoryCategory> new_category = update_it->second; +		// Since this is a copy of the category *before* the accounting update, above, +		// we need to transfer back the updated version/descendent count. +		LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID()); +		if (NULL == curr_cat)  		{ -			llwarns << "Possible version mismatch for category " << cat->getName() -					<< ", viewer version " << cat->getVersion() -					<< " server version " << version << llendl; +			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 " << category_id << LL_ENDL;  		}  	} @@ -456,7 +775,7 @@ void AISUpdate::doUpdate()  		// 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 << llendl; +		LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL;  		gInventory.updateItem(new_item);  	} @@ -469,19 +788,36 @@ void AISUpdate::doUpdate()  		// 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 << llendl; -		//LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << llendl; +		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 (std::set<LLUUID>::const_iterator del_it = mObjectsDeleted.begin(); -		 del_it != mObjectsDeleted.end(); ++del_it) +	for (std::set<LLUUID>::const_iterator del_it = mObjectsDeletedIds.begin(); +		 del_it != mObjectsDeletedIds.end(); ++del_it)  	{ -		LL_DEBUGS("Inventory") << "deleted item " << *del_it << llendl; +		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); +		if (cat->getVersion() != version) +		{ +			llwarns << "Possible version mismatch for category " << cat->getName() +					<< ", viewer version " << cat->getVersion() +					<< " server version " << version << llendl; +		} +	} +  	gInventory.notifyObservers();  } diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h index 1f9555f004..f4e219e9e6 100755 --- a/indra/newview/llaisapi.h +++ b/indra/newview/llaisapi.h @@ -31,7 +31,6 @@  #include <map>  #include <set>  #include <string> -#include <vector>  #include "llcurl.h"  #include "llhttpclient.h"  #include "llhttpretrypolicy.h" @@ -46,7 +45,7 @@ public:  	virtual ~AISCommand() {} -	void run_command(); +	bool run_command();  	void setCommandFunc(command_func_type command_func); @@ -54,13 +53,17 @@ public:  	// LLInventoryCallback::fire().  May or may not need to bother,  	// since most LLInventoryCallbacks do their work in the  	// destructor. -	virtual bool getResponseUUID(const LLSD& content, LLUUID& id);  	/* virtual */ void httpSuccess(); +	/* virtual */ void httpFailure(); -	/*virtual*/ void httpFailure(); +	static bool isAPIAvailable(); +	static bool getInvCap(std::string& cap); +	static bool getLibCap(std::string& cap); +	static void getCapabilityNames(LLSD& capabilityNames); -	static bool getCap(std::string& cap); +protected: +	virtual bool getResponseUUID(const LLSD& content, LLUUID& id);  private:  	command_func_type mCommandFunc; @@ -118,26 +121,52 @@ 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 AISUpdate  {  public:  	AISUpdate(const LLSD& update);  	void parseUpdate(const LLSD& update); -	void parseUUIDArray(const LLSD& content, const std::string& name, uuid_vec_t& ids); -	void parseLink(const LLUUID& link_id, const LLSD& link_map); -	void parseCreatedLinks(const LLSD& links); +	void parseMeta(const LLSD& update); +	void parseContent(const LLSD& update); +	void parseUUIDArray(const LLSD& content, const std::string& name, uuid_list_t& ids); +	void parseLink(const LLSD& link_map); +	void parseItem(const LLSD& link_map); +	void parseCategory(const LLSD& link_map); +	void parseDescendentCount(const LLUUID& category_id, const LLSD& embedded); +	void parseEmbedded(const LLSD& embedded); +	void parseEmbeddedLinks(const LLSD& links); +	void parseEmbeddedItems(const LLSD& links); +	void parseEmbeddedCategories(const LLSD& links);  	void doUpdate();  private: +	void clearParseResults(); +  	typedef std::map<LLUUID,S32> uuid_int_map_t; -	uuid_int_map_t mCatDeltas; -	uuid_int_map_t mCatVersions; +	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; - -	std::set<LLUUID> mObjectsDeleted; -	uuid_vec_t mItemsCreatedIds; +	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 a0f8cbe911..fc07932860 100755 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -435,6 +435,50 @@ private:  S32 LLCallAfterInventoryCopyMgr::sInstanceCount = 0; +class LLWearCategoryAfterCopy: public LLInventoryCallback +{ +public: +	LLWearCategoryAfterCopy(bool append): +		mAppend(append) +	{} + +	// virtual +	void fire(const LLUUID& id) +	{ +		// Wear the inventory category. +		LLInventoryCategory* cat = gInventory.getCategory(id); +		LLAppearanceMgr::instance().wearInventoryCategoryOnAvatar(cat, mAppend); +	} + +private: +	bool mAppend; +}; + +class LLTrackPhaseWrapper : public LLInventoryCallback +{ +public: +	LLTrackPhaseWrapper(const std::string& phase_name, LLPointer<LLInventoryCallback> cb = NULL): +		mTrackingPhase(phase_name), +		mCB(cb) +	{ +		selfStartPhase(mTrackingPhase); +	} + +	// virtual +	void fire(const LLUUID& id) +	{ +		selfStopPhase(mTrackingPhase); +		if (mCB) +		{ +			mCB->fire(id); +		} +	} + +protected: +	std::string mTrackingPhase; +	LLPointer<LLInventoryCallback> mCB; +}; +  LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool enforce_item_restrictions,  														 bool enforce_ordering,  														 nullary_func_t post_update_func  @@ -2244,10 +2288,31 @@ 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 @@ -3544,8 +3609,7 @@ void LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, boo  	// First, make a folder in the My Outfits directory.  	const LLUUID parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); -	std::string cap; -	if (AISCommand::getCap(cap)) +	if (AISCommand::isAPIAvailable())  	{  		// cap-based category creation was buggy until recently. use  		// existence of AIS as an indicator the fix is present. Does diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e1fd2e02fa..0d99bea3fc 100755 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1718,7 +1718,6 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const  	LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);  	if(cat)  	{ -		bool accounted = false;  		S32 version = cat->getVersion();  		if(version != LLViewerInventoryCategory::VERSION_UNKNOWN)  		{ @@ -1733,22 +1732,27 @@ void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const  			}  			if(descendents_server == descendents_actual)  			{ -				accounted = true;  				descendents_actual += update.mDescendentDelta;  				cat->setDescendentCount(descendents_actual);  				cat->setVersion(++version); -				lldebugs << "accounted: '" << cat->getName() << "' " +				LL_DEBUGS("Inventory") << "accounted: '" << cat->getName() << "' "  						 << version << " with " << descendents_actual -						 << " descendents." << llendl; +						 << " descendents." << LL_ENDL; +			} +			else +			{ +				// Error condition, this means that the category did not register that +				// it got new descendents (perhaps because it is still being loaded) +				// which means its descendent count will be wrong. +				llwarns << "Accounting failed for '" << cat->getName() << "' version:" +						 << version << " due to mismatched descendent count:  server == " +						 << descendents_server << ", viewer == " << descendents_actual << llendl;  			}  		} -		if(!accounted) +		else  		{ -			// Error condition, this means that the category did not register that -			// it got new descendents (perhaps because it is still being loaded) -			// which means its descendent count will be wrong. -			llwarns << "Accounting failed for '" << cat->getName() << "' version:" -					 << version << llendl; +			llwarns << "Accounting failed for '" << cat->getName() << "' version: unknown ("  +					<< version << ")" << llendl;  		}  	}  	else diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index c934dd991b..5beae8ec24 100755 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -430,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); @@ -866,6 +866,21 @@ void LLViewerInventoryCategory::localizeName()  	LLLocalizedInventoryItemsDictionary::getInstance()->localizeInventoryObjectName(mName);  } +// virtual +BOOL LLViewerInventoryCategory::unpackMessage(const LLSD& category) +{ +	BOOL rv = LLInventoryCategory::fromLLSD(category); +	localizeName(); +	return rv; +} + +// virtual +void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) +{ +	LLInventoryCategory::unpackMessage(msg, block, block_num); +	localizeName(); +} +  ///----------------------------------------------------------------------------  /// Local function definitions  ///---------------------------------------------------------------------------- @@ -1159,24 +1174,22 @@ void update_inventory_item(  	const LLSD& updates,  	LLPointer<LLInventoryCallback> cb)  { -	LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); -	LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl; -	if(obj) +	bool ais_ran = false; +	if (AISCommand::isAPIAvailable())  	{ -		LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); -		new_item->copyViewerItem(obj);	 -		new_item->fromLLSD(updates,false); -		 -		std::string cap; -		if (AISCommand::getCap(cap)) -		{ -			LLSD new_llsd; -			new_item->asLLSD(new_llsd); -			LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, new_llsd, cb); -			cmd_ptr->run_command(); -		} -		else // no cap +		LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb); +		ais_ran = cmd_ptr->run_command(); +	} +	if (!ais_ran) +	{ +		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id); +		LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl; +		if(obj)  		{ +			LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem); +			new_item->copyViewerItem(obj); +			new_item->fromLLSD(updates,false); +  			LLMessageSystem* msg = gMessageSystem;  			msg->newMessageFast(_PREHASH_UpdateInventoryItem);  			msg->nextBlockFast(_PREHASH_AgentData); @@ -1216,9 +1229,8 @@ void update_inventory_category(  		LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj);  		new_cat->fromLLSD(updates); -		//std::string cap;  		// FIXME - restore this once the back-end work has been done. -		if (0) // if (AISCommand::getCap(cap)) +		if (0) // if (AISCommand::isAPIAvailable())  		{  			LLSD new_llsd = new_cat->asLLSD();  			LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb); @@ -1254,8 +1266,7 @@ void remove_inventory_item(  	LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;  	if(obj)  	{ -		std::string cap; -		if (AISCommand::getCap(cap)) +		if (AISCommand::isAPIAvailable())  		{  			LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb);  			cmd_ptr->run_command(); @@ -1325,8 +1336,7 @@ void remove_inventory_category(  			LLNotificationsUtil::add("CannotRemoveProtectedCategories");  			return;  		} -		std::string cap; -		if (AISCommand::getCap(cap)) +		if (AISCommand::isAPIAvailable())  		{  			LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb);  			cmd_ptr->run_command(); @@ -1429,8 +1439,7 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)  		}  		else  		{ -			std::string cap; -			if (AISCommand::getCap(cap)) +			if (AISCommand::isAPIAvailable())  			{  				LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb);  				cmd_ptr->run_command(); @@ -1564,8 +1573,7 @@ void slam_inventory_folder(const LLUUID& folder_id,  						   const LLSD& contents,  						   LLPointer<LLInventoryCallback> cb)  { -	std::string cap; -	if (AISCommand::getCap(cap)) +	if (AISCommand::isAPIAvailable())  	{  		LL_DEBUGS("Avatar") << "using AISv3 to slam folder, id " << folder_id  							<< " new contents: " << ll_pretty_print_sd(contents) << llendl; diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index de1f3daa1e..0d4ffaa575 100755 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -124,7 +124,7 @@ public:  	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); @@ -224,6 +224,8 @@ public:  	bool importFileLocal(LLFILE* fp);  	void determineFolderType();  	void changeType(LLFolderType::EType new_folder_type); +	virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0); +	virtual BOOL unpackMessage(const LLSD& category);  private:  	friend class LLInventoryModel; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index dca1a5b542..ad046accd0 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" @@ -1645,7 +1646,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)  		capabilityNames.append("FetchInventory2");  		capabilityNames.append("FetchInventoryDescendents2");  		capabilityNames.append("IncrementCOFVersion"); -		capabilityNames.append("InventoryAPIv3"); +		AISCommand::getCapabilityNames(capabilityNames);  	}  	capabilityNames.append("GetDisplayNames"); @@ -1893,6 +1894,22 @@ std::string LLViewerRegion::getCapability(const std::string& name) const  	return iter->second;  } +bool LLViewerRegion::isCapabilityAvailable(const std::string& name) const +{ +	if (!capabilitiesReceived() && (name!=std::string("Seed")) && (name!=std::string("ObjectMedia"))) +	{ +		llwarns << "isCapabilityAvailable called before caps received for " << name << llendl; +	} +	 +	CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); +	if(iter == mImpl->mCapabilities.end()) +	{ +		return false; +	} + +	return true; +} +  bool LLViewerRegion::capabilitiesReceived() const  {  	return mCapabilitiesReceived; diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 5ac2a83aaf..4fb1b7402c 100755 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -244,6 +244,7 @@ public:  	S32 getNumSeedCapRetries();  	void setCapability(const std::string& name, const std::string& url);  	void setCapabilityDebug(const std::string& name, const std::string& url); +	bool isCapabilityAvailable(const std::string& name) const;  	// implements LLCapabilityProvider      virtual std::string getCapability(const std::string& name) const;  | 
