summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/llinventory/llinventory.cpp2
-rwxr-xr-xindra/llinventory/llinventory.h4
-rwxr-xr-xindra/llmessage/llhttpclient.cpp12
-rwxr-xr-xindra/llmessage/llhttpclient.h8
-rwxr-xr-x[-rw-r--r--]indra/llmessage/llhttpconstants.h37
-rwxr-xr-xindra/llmessage/llurlrequest.cpp11
-rwxr-xr-xindra/newview/llappearancemgr.cpp4
-rwxr-xr-xindra/newview/llinventorybridge.cpp10
-rwxr-xr-xindra/newview/llinventoryfunctions.cpp9
-rwxr-xr-xindra/newview/llinventorymodel.cpp93
-rwxr-xr-xindra/newview/llinventorymodel.h6
-rwxr-xr-xindra/newview/llviewerinventory.cpp510
-rwxr-xr-xindra/newview/llviewerinventory.h14
13 files changed, 523 insertions, 197 deletions
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index a4cd8333cf..641532ec29 100755
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -261,7 +261,7 @@ void LLInventoryObject::updateServer(BOOL) const
llwarns << "LLInventoryObject::updateServer() called. Doesn't do anything." << llendl;
}
-inline
+// static
void LLInventoryObject::correctInventoryName(std::string& name)
{
LLStringUtil::replaceNonstandardASCII(name, ' ');
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 8b865f044d..17421b3f5e 100755
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -86,16 +86,14 @@ public:
void setType(LLAssetType::EType type);
virtual void setCreationDate(time_t creation_date_utc); // only stored for items
-private:
// in place correction for inventory name string
- void correctInventoryName(std::string& name);
+ static void correctInventoryName(std::string& name);
//--------------------------------------------------------------------
// File Support
// Implemented here so that a minimal information set can be transmitted
// between simulator and viewer.
//--------------------------------------------------------------------
-public:
// virtual BOOL importFile(LLFILE* fp);
virtual BOOL exportFile(LLFILE* fp, BOOL include_asset_key = TRUE) const;
virtual BOOL importLegacyStream(std::istream& input_stream);
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 5830a5eca0..53cef54559 100755
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -304,7 +304,7 @@ static void request(
gMessageSystem->mPort));
}
- if (method == HTTP_PUT || method == HTTP_POST)
+ if (method == HTTP_PUT || method == HTTP_POST || method == HTTP_PATCH)
{
if(!headers.has(HTTP_OUT_HEADER_CONTENT_TYPE))
{
@@ -556,6 +556,16 @@ void LLHTTPClient::put(
request(url, HTTP_PUT, new LLSDInjector(body), responder, timeout, headers);
}
+void LLHTTPClient::patch(
+ const std::string& url,
+ const LLSD& body,
+ ResponderPtr responder,
+ const LLSD& headers,
+ const F32 timeout)
+{
+ request(url, HTTP_PATCH, new LLSDInjector(body), responder, timeout, headers);
+}
+
void LLHTTPClient::post(
const std::string& url,
const LLSD& body,
diff --git a/indra/llmessage/llhttpclient.h b/indra/llmessage/llhttpclient.h
index a7236ba169..4e7495495f 100755
--- a/indra/llmessage/llhttpclient.h
+++ b/indra/llmessage/llhttpclient.h
@@ -74,6 +74,14 @@ public:
ResponderPtr,
const LLSD& headers = LLSD(),
const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+
+ static void patch(
+ const std::string& url,
+ const LLSD& body,
+ ResponderPtr,
+ const LLSD& headers = LLSD(),
+ const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
+
static void getHeaderOnly(const std::string& url, ResponderPtr, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
static void getHeaderOnly(const std::string& url, ResponderPtr, const LLSD& headers, const F32 timeout=HTTP_REQUEST_EXPIRY_SECS);
diff --git a/indra/llmessage/llhttpconstants.h b/indra/llmessage/llhttpconstants.h
index 8cc3459654..aa947af414 100644..100755
--- a/indra/llmessage/llhttpconstants.h
+++ b/indra/llmessage/llhttpconstants.h
@@ -2,31 +2,25 @@
* @file llhttpconstants.h
* @brief Constants for HTTP requests and responses
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2013, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2001-2013, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -117,6 +111,7 @@ enum EHTTPMethod
HTTP_DELETE,
HTTP_MOVE, // Caller will need to set 'Destination' header
HTTP_OPTIONS,
+ HTTP_PATCH,
HTTP_METHOD_COUNT
};
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 49cfef2771..cadff49cb8 100755
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -487,6 +487,17 @@ bool LLURLRequest::configure()
rv = true;
break;
+ case HTTP_PATCH:
+ // Disable the expect http 1.1 extension. POST and PUT default
+ // to turning this on, and I am not too sure what it means.
+ addHeader(HTTP_OUT_HEADER_EXPECT);
+
+ mDetail->mCurlRequest->setopt(CURLOPT_UPLOAD, 1);
+ mDetail->mCurlRequest->setopt(CURLOPT_INFILESIZE, bytes);
+ mDetail->mCurlRequest->setoptString(CURLOPT_CUSTOMREQUEST, "PATCH");
+ rv = true;
+ break;
+
case HTTP_POST:
// Disable the expect http 1.1 extension. POST and PUT default
// to turning this on, and I am not too sure what it means.
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index cfe9055aab..14eed6e1df 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2812,8 +2812,10 @@ struct WearablesOrderComparator
//items with ordering information but not for the associated wearables type
if (!item1_valid && item2_valid)
return false;
+ else if (item1_valid && !item2_valid)
+ return true;
- return true;
+ return item1->getName() < item2->getName();
}
U32 mControlSize;
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index c32abe507e..89c56ab82c 100755
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -1692,13 +1692,9 @@ BOOL LLItemBridge::renameItem(const std::string& new_name)
LLViewerInventoryItem* item = getItem();
if(item && (item->getName() != new_name))
{
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
- new_item->rename(new_name);
- new_item->updateServer(FALSE);
- model->updateItem(new_item);
-
- model->notifyObservers();
- buildDisplayName();
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_item(item->getUUID(),updates, NULL);
}
// return FALSE because we either notified observers (& therefore
// rebuilt) or we didn't update.
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index f1a4889f5a..b5fb226872 100755
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -123,12 +123,9 @@ void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::s
return;
}
- LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
- new_cat->rename(new_name);
- new_cat->updateServer(FALSE);
- model->updateCategory(new_cat);
-
- model->notifyObservers();
+ LLSD updates;
+ updates["name"] = new_name;
+ update_inventory_category(cat_id, updates, NULL);
}
void copy_inventory_category(LLInventoryModel* model,
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index 73ef3e60da..06c614aeaa 100755
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -1196,6 +1196,36 @@ void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLS
onObjectDeletedFromServer(*it, false);
}
+ if (update.has("item_id"))
+ {
+ // item has been modified or possibly created (would be better if we could distinguish these cases directly)
+ LLUUID item_id = update["item_id"].asUUID();
+ LLViewerInventoryItem *item = gInventory.getItem(item_id);
+ LLViewerInventoryCategory *cat = gInventory.getCategory(item_id);
+ if (item)
+ {
+ LLSD changes;
+ if (update.has("name") && update["name"] != item->getName())
+ {
+ changes["name"] = update["name"];
+ }
+ if (update.has("desc") && update["desc"] != item->getActualDescription())
+ {
+ changes["desc"] = update["desc"];
+ }
+ onItemUpdated(item_id,changes);
+ }
+ else if (cat)
+ {
+ llerrs << "don't handle cat update yet" << llendl;
+ }
+ else
+ {
+ llerrs << "don't handle creation case yet" << llendl;
+ }
+
+ }
+
// 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.
@@ -1212,10 +1242,71 @@ void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLS
}
}
#endif
-
}
+void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates)
+{
+ U32 mask = LLInventoryObserver::NONE;
+
+ LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id);
+ LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (item ? item->getName() : "(NOT FOUND)") << llendl;
+ if(item)
+ {
+ for (LLSD::map_const_iterator it = updates.beginMap();
+ it != updates.endMap(); ++it)
+ {
+ if (it->first == "name")
+ {
+ llinfos << "Updating name from " << item->getName() << " to " << it->second.asString() << llendl;
+ item->rename(it->second.asString());
+ mask |= LLInventoryObserver::LABEL;
+ }
+ else if (it->first == "desc")
+ {
+ llinfos << "Updating description from " << item->getActualDescription()
+ << " to " << it->second.asString() << llendl;
+ item->setDescription(it->second.asString());
+ }
+ else
+ {
+ llerrs << "unhandled updates for field: " << it->first << llendl;
+ }
+ }
+ mask |= LLInventoryObserver::INTERNAL;
+ addChangedMask(mask, item->getUUID());
+ gInventory.notifyObservers(); // do we want to be able to make this optional?
+ }
+}
+
+void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates)
+{
+ U32 mask = LLInventoryObserver::NONE;
+
+ LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id);
+ LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (cat ? cat->getName() : "(NOT FOUND)") << llendl;
+ if(cat)
+ {
+ for (LLSD::map_const_iterator it = updates.beginMap();
+ it != updates.endMap(); ++it)
+ {
+ if (it->first == "name")
+ {
+ llinfos << "Updating name from " << cat->getName() << " to " << it->second.asString() << llendl;
+ cat->rename(it->second.asString());
+ mask |= LLInventoryObserver::LABEL;
+ }
+ else
+ {
+ llerrs << "unhandled updates for field: " << it->first << llendl;
+ }
+ }
+ mask |= LLInventoryObserver::INTERNAL;
+ addChangedMask(mask, cat->getUUID());
+ gInventory.notifyObservers(); // do we want to be able to make this optional?
+ }
+}
+
// Update model after descendents have been purged.
void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links)
{
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 696d0a9163..515c99c0b4 100755
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -339,6 +339,12 @@ public:
// Update model after all descendents removed from server.
void onDescendentsPurgedFromServer(const LLUUID& object_id, bool fix_broken_links = true);
+ // Update model after an existing item gets updated on server.
+ void onItemUpdated(const LLUUID& item_id, const LLSD& updates);
+
+ // Update model after an existing category gets updated on server.
+ void onCategoryUpdated(const LLUUID& cat_id, const LLSD& updates);
+
// Delete a particular inventory object by ID. Will purge one
// object from the internal data structures, maintaining a
// consistent internal state. No cache accounting, observer
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 50d67463c7..90fef3b5ed 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -260,6 +260,240 @@ LLInventoryHandler gInventoryHandler;
///----------------------------------------------------------------------------
+/// Classes for AISv3 support.
+///----------------------------------------------------------------------------
+class AISCommand: public LLHTTPClient::Responder
+{
+public:
+ typedef boost::function<void()> command_func_type;
+
+ AISCommand(LLPointer<LLInventoryCallback> callback):
+ mCallback(callback)
+ {
+ mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
+ }
+
+ virtual ~AISCommand()
+ {
+ }
+
+ void run_command()
+ {
+ mCommandFunc();
+ }
+
+ void setCommandFunc(command_func_type command_func)
+ {
+ mCommandFunc = command_func;
+ }
+
+ // Need to do command-specific parsing to get an id here. May or
+ // may not need to bother, since most LLInventoryCallbacks do
+ // their work in the destructor.
+ virtual bool getResponseUUID(const LLSD& content, LLUUID& id)
+ {
+ return false;
+ }
+
+ /* virtual */ void httpSuccess()
+ {
+ // Command func holds a reference to self, need to release it
+ // after a success or final failure.
+ setCommandFunc(no_op);
+
+ const LLSD& content = getContent();
+ if (!content.isMap())
+ {
+ failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
+ return;
+ }
+ mRetryPolicy->onSuccess();
+
+ gInventory.onAISUpdateReceived("AISCommand", content);
+
+ if (mCallback)
+ {
+ LLUUID item_id; // will default to null if parse fails.
+ getResponseUUID(content,item_id);
+ mCallback->fire(item_id);
+ }
+ }
+
+ /*virtual*/ void httpFailure()
+ {
+ const LLSD& content = getContent();
+ S32 status = getStatus();
+ const std::string& reason = getReason();
+ const LLSD& headers = getResponseHeaders();
+ if (!content.isMap())
+ {
+ LL_DEBUGS("Inventory") << "Malformed response contents " << content
+ << " status " << status << " reason " << reason << llendl;
+ }
+ else
+ {
+ LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content)
+ << " status " << status << " reason " << reason << llendl;
+ }
+ mRetryPolicy->onFailure(status, headers);
+ F32 seconds_to_wait;
+ if (mRetryPolicy->shouldRetry(seconds_to_wait))
+ {
+ doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait);
+ }
+ else
+ {
+ // Command func holds a reference to self, need to release it
+ // after a success or final failure.
+ setCommandFunc(no_op);
+ }
+ }
+
+ static bool getCap(std::string& cap)
+ {
+ if (gAgent.getRegion())
+ {
+ cap = gAgent.getRegion()->getCapability("InventoryAPIv3");
+ }
+ if (!cap.empty())
+ {
+ return true;
+ }
+ return false;
+ }
+
+private:
+ command_func_type mCommandFunc;
+ LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
+ LLPointer<LLInventoryCallback> mCallback;
+};
+
+class RemoveItemCommand: public AISCommand
+{
+public:
+ RemoveItemCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback):
+ AISCommand(callback)
+ {
+ std::string cap;
+ if (!getCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/item/") + item_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << llendl;
+ LLHTTPClient::ResponderPtr responder = this;
+ LLSD headers;
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+ setCommandFunc(cmd);
+ }
+};
+
+class RemoveCategoryCommand: public AISCommand
+{
+public:
+ RemoveCategoryCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback):
+ AISCommand(callback)
+ {
+ std::string cap;
+ if (!getCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + item_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << llendl;
+ LLHTTPClient::ResponderPtr responder = this;
+ LLSD headers;
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+ setCommandFunc(cmd);
+ }
+};
+
+class PurgeDescendentsCommand: public AISCommand
+{
+public:
+ PurgeDescendentsCommand(const LLUUID& item_id,
+ LLPointer<LLInventoryCallback> callback):
+ AISCommand(callback)
+ {
+ std::string cap;
+ if (!getCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + item_id.asString() + "/children";
+ LL_DEBUGS("Inventory") << "url: " << url << llendl;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
+ setCommandFunc(cmd);
+ }
+};
+
+class UpdateItemCommand: public AISCommand
+{
+public:
+ UpdateItemCommand(const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> callback):
+ mUpdates(updates),
+ AISCommand(callback)
+ {
+ std::string cap;
+ if (!getCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/item/") + item_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << llendl;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ headers["Content-Type"] = "application/llsd+xml";
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
+ setCommandFunc(cmd);
+ }
+private:
+ LLSD mUpdates;
+};
+
+class UpdateCategoryCommand: public AISCommand
+{
+public:
+ UpdateCategoryCommand(const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> callback):
+ mUpdates(updates),
+ AISCommand(callback)
+ {
+ std::string cap;
+ if (!getCap(cap))
+ {
+ llwarns << "No cap found" << llendl;
+ return;
+ }
+ std::string url = cap + std::string("/category/") + item_id.asString();
+ LL_DEBUGS("Inventory") << "url: " << url << llendl;
+ LLCurl::ResponderPtr responder = this;
+ LLSD headers;
+ headers["Content-Type"] = "application/llsd+xml";
+ F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
+ command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
+ setCommandFunc(cmd);
+ }
+private:
+ LLSD mUpdates;
+};
+
+///----------------------------------------------------------------------------
/// Class LLViewerInventoryItem
///----------------------------------------------------------------------------
@@ -456,6 +690,20 @@ void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_
// virtual
void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
{
+ static const LLSD updates;
+ packUpdateMessage(msg,updates);
+}
+
+void LLViewerInventoryItem::packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const
+{
+ for (LLSD::map_const_iterator it = updates.beginMap(); it != updates.endMap(); ++it)
+ {
+ if ((it->first != "desc") && (it->first != "name"))
+ {
+ llerrs << "unhandled field: " << it->first << llendl;
+ }
+ }
+
msg->addUUIDFast(_PREHASH_ItemID, mUUID);
msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
mPermissions.packMessage(msg);
@@ -466,12 +714,29 @@ void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
msg->addS8Fast(_PREHASH_InvType, type);
msg->addU32Fast(_PREHASH_Flags, mFlags);
mSaleInfo.packMessage(msg);
- msg->addStringFast(_PREHASH_Name, mName);
- msg->addStringFast(_PREHASH_Description, mDescription);
+ if (updates.has("name"))
+ {
+ std::string new_name = updates["name"].asString();
+ LLInventoryObject::correctInventoryName(new_name);
+ msg->addStringFast(_PREHASH_Name, new_name);
+ }
+ else
+ {
+ msg->addStringFast(_PREHASH_Name, mName);
+ }
+ if (updates.has("desc"))
+ {
+ msg->addStringFast(_PREHASH_Description, updates["desc"].asString());
+ }
+ else
+ {
+ msg->addStringFast(_PREHASH_Description, mDescription);
+ }
msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
U32 crc = getCRC32();
msg->addU32Fast(_PREHASH_CRC, crc);
}
+
// virtual
BOOL LLViewerInventoryItem::importFile(LLFILE* fp)
{
@@ -583,6 +848,32 @@ void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCatego
}
+void LLViewerInventoryCategory::packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const
+{
+ for (LLSD::map_const_iterator it = updates.beginMap(); it != updates.endMap(); ++it)
+ {
+ if (it->first != "name")
+ {
+ llerrs << "unhandled field: " << it->first << llendl;
+ }
+ }
+
+ msg->addUUIDFast(_PREHASH_FolderID, mUUID);
+ msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
+ S8 type = static_cast<S8>(mPreferredType);
+ msg->addS8Fast(_PREHASH_Type, type);
+ if (updates.has("name"))
+ {
+ std::string new_name = updates["name"].asString();
+ LLInventoryObject::correctInventoryName(new_name);
+ msg->addStringFast(_PREHASH_Name, new_name);
+ }
+ else
+ {
+ msg->addStringFast(_PREHASH_Name, mName);
+ }
+}
+
void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const
{
LLMessageSystem* msg = gMessageSystem;
@@ -1139,180 +1430,87 @@ void move_inventory_item(
gAgent.sendReliableMessage();
}
-class AISCommand: public LLHTTPClient::Responder
+// Note this only supports updating an existing item. Goes through AISv3
+// code path where available. Not all uses of item->updateServer() can
+// easily be switched to this paradigm.
+void update_inventory_item(
+ const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb)
{
-public:
- typedef boost::function<void()> command_func_type;
-
- AISCommand(LLPointer<LLInventoryCallback> callback):
- mCallback(callback)
- {
- mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
- }
-
- virtual ~AISCommand()
- {
- }
-
- void run_command()
- {
- mCommandFunc();
- }
-
- void setCommandFunc(command_func_type command_func)
- {
- mCommandFunc = command_func;
- }
-
- // Need to do command-specific parsing to get an id here. May or
- // may not need to bother, since most LLInventoryCallbacks do
- // their work in the destructor.
- virtual bool getResponseUUID(const LLSD& content, LLUUID& id)
- {
- return false;
- }
-
- /* virtual */ void httpSuccess()
- {
- // Command func holds a reference to self, need to release it
- // after a success or final failure.
- setCommandFunc(no_op);
-
- const LLSD& content = getContent();
- if (!content.isMap())
- {
- failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
- return;
- }
- mRetryPolicy->onSuccess();
-
- gInventory.onAISUpdateReceived("AISCommand", content);
-
- if (mCallback)
- {
- LLUUID item_id; // will default to null if parse fails.
- getResponseUUID(content,item_id);
- mCallback->fire(item_id);
- }
- }
-
- /*virtual*/ void httpFailure()
+ LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
+ LL_DEBUGS("Inventory") << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
+ if(obj)
{
- const LLSD& content = getContent();
- S32 status = getStatus();
- const std::string& reason = getReason();
- const LLSD& headers = getResponseHeaders();
- if (!content.isMap())
- {
- LL_DEBUGS("Inventory") << "Malformed response contents " << content
- << " status " << status << " reason " << reason << llendl;
- }
- else
- {
- LL_DEBUGS("Inventory") << "failed with content: " << ll_pretty_print_sd(content)
- << " status " << status << " reason " << reason << llendl;
- }
- mRetryPolicy->onFailure(status, headers);
- F32 seconds_to_wait;
- if (mRetryPolicy->shouldRetry(seconds_to_wait))
+ std::string cap;
+ if (AISCommand::getCap(cap))
{
- doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait);
+ LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb);
+ cmd_ptr->run_command();
}
- else
+ else // no cap
{
- // Command func holds a reference to self, need to release it
- // after a success or final failure.
- setCommandFunc(no_op);
- }
- }
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_UpdateInventoryItem);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_TransactionID, obj->getTransactionID());
+ msg->nextBlockFast(_PREHASH_InventoryData);
+ msg->addU32Fast(_PREHASH_CallbackID, 0);
+ obj->packUpdateMessage(msg, updates);
+ gAgent.sendReliableMessage();
- static bool getCap(std::string& cap)
- {
- if (gAgent.getRegion())
- {
- cap = gAgent.getRegion()->getCapability("InventoryAPIv3");
- }
- if (!cap.empty())
- {
- return true;
+ gInventory.onItemUpdated(item_id, updates);
+ if (cb)
+ {
+ cb->fire(item_id);
+ }
}
- return false;
}
+}
-private:
- command_func_type mCommandFunc;
- LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
- LLPointer<LLInventoryCallback> mCallback;
-};
-
-class RemoveItemCommand: public AISCommand
+void update_inventory_category(
+ const LLUUID& cat_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb)
{
-public:
- RemoveItemCommand(const LLUUID& item_id,
- LLPointer<LLInventoryCallback> callback):
- AISCommand(callback)
+ LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id);
+ LL_DEBUGS("Inventory") << "cat_id: [" << cat_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << llendl;
+ if(obj)
{
- std::string cap;
- if (!getCap(cap))
+ if (LLFolderType::lookupIsProtectedType(obj->getPreferredType()))
{
- llwarns << "No cap found" << llendl;
+ LLNotificationsUtil::add("CannotModifyProtectedCategories");
return;
}
- std::string url = cap + std::string("/item/") + item_id.asString();
- LL_DEBUGS("Inventory") << "url: " << url << llendl;
- LLHTTPClient::ResponderPtr responder = this;
- LLSD headers;
- F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
- setCommandFunc(cmd);
- }
-};
-class RemoveCategoryCommand: public AISCommand
-{
-public:
- RemoveCategoryCommand(const LLUUID& item_id,
- LLPointer<LLInventoryCallback> callback):
- AISCommand(callback)
- {
- std::string cap;
- if (!getCap(cap))
+ //std::string cap;
+ // FIXME - restore this once the back-end work has been done.
+ if (0) // if (AISCommand::getCap(cap))
{
- llwarns << "No cap found" << llendl;
- return;
+ LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, updates, cb);
+ cmd_ptr->run_command();
}
- std::string url = cap + std::string("/category/") + item_id.asString();
- LL_DEBUGS("Inventory") << "url: " << url << llendl;
- LLHTTPClient::ResponderPtr responder = this;
- LLSD headers;
- F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
- setCommandFunc(cmd);
- }
-};
-
-class PurgeDescendentsCommand: public AISCommand
-{
-public:
- PurgeDescendentsCommand(const LLUUID& item_id,
- LLPointer<LLInventoryCallback> callback):
- AISCommand(callback)
- {
- std::string cap;
- if (!getCap(cap))
+ else // no cap
{
- llwarns << "No cap found" << llendl;
- return;
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_FolderData);
+ obj->packUpdateMessage(msg, updates);
+ gAgent.sendReliableMessage();
+
+ gInventory.onCategoryUpdated(cat_id, updates);
+ if (cb)
+ {
+ cb->fire(cat_id);
+ }
}
- std::string url = cap + std::string("/category/") + item_id.asString() + "/children";
- LL_DEBUGS("Inventory") << "url: " << url << llendl;
- LLCurl::ResponderPtr responder = this;
- LLSD headers;
- F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
- command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
- setCommandFunc(cmd);
}
-};
+}
void remove_inventory_item(
const LLUUID& item_id,
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 4e24dc87d1..c52b0c2d9d 100755
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -139,6 +139,8 @@ public:
//void updateAssetOnServer() const;
virtual void packMessage(LLMessageSystem* msg) const;
+ // Contents of updates will take precedence over fields of item where they differ.
+ void packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const;
virtual void setTransactionID(const LLTransactionID& transaction_id);
struct comparePointers
{
@@ -224,6 +226,8 @@ public:
void determineFolderType();
void changeType(LLFolderType::EType new_folder_type);
+ void packUpdateMessage(LLMessageSystem* msg, const LLSD& updates) const;
+
private:
friend class LLInventoryModel;
void localizeName(); // intended to be called from the LLInventoryModel
@@ -363,6 +367,16 @@ void move_inventory_item(
const std::string& new_name,
LLPointer<LLInventoryCallback> cb);
+void update_inventory_item(
+ const LLUUID& item_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb);
+
+void update_inventory_category(
+ const LLUUID& cat_id,
+ const LLSD& updates,
+ LLPointer<LLInventoryCallback> cb);
+
void remove_inventory_item(
const LLUUID& item_id,
LLPointer<LLInventoryCallback> cb);