summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDon Kjer <don@lindenlab.com>2013-07-11 15:15:04 -0700
committerDon Kjer <don@lindenlab.com>2013-07-11 15:15:04 -0700
commita85fa3b10a406218cabfecc0d592e816f8dfdb53 (patch)
tree403ae646796518c876454da2d46eb08d508fc751
parentd079f0dcdc0d317813cda282496a1edae3feed64 (diff)
Adding support for COPY methods to httpclient. Implementing viewer-side use of AISv3 COPY library folder operation. (SH-4304)
-rwxr-xr-xindra/llmessage/llhttpclient.cpp13
-rwxr-xr-xindra/llmessage/llhttpclient.h18
-rwxr-xr-xindra/llmessage/llhttpconstants.cpp6
-rwxr-xr-xindra/llmessage/llhttpconstants.h1
-rwxr-xr-xindra/llmessage/llurlrequest.cpp10
-rwxr-xr-xindra/newview/llaisapi.cpp588
-rwxr-xr-xindra/newview/llaisapi.h55
-rwxr-xr-xindra/newview/llappearancemgr.cpp76
-rwxr-xr-xindra/newview/llinventorymodel.cpp24
-rwxr-xr-xindra/newview/llviewerinventory.cpp62
-rwxr-xr-xindra/newview/llviewerinventory.h4
-rwxr-xr-xindra/newview/llviewerregion.cpp19
-rwxr-xr-xindra/newview/llviewerregion.h1
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;