From 248d61fe0eadd128c7704e37922ba7fdef35d630 Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Wed, 12 Aug 2015 16:32:49 -0700
Subject: [PATCH] MAINT-5500: Finish converting the AIS responders to the new
 coroutine model, Cleaned up dead an unused code. MAINT-4952: Added COPY and
 MOVE methods to Core:Http adapter

---
 indra/llcorehttp/_httpoprequest.cpp |  18 +
 indra/llcorehttp/_httpoprequest.h   |   9 +-
 indra/llcorehttp/httprequest.cpp    |  31 ++
 indra/llcorehttp/httprequest.h      |  27 +-
 indra/llmessage/llcorehttputil.cpp  |  94 +++-
 indra/llmessage/llcorehttputil.h    |  52 ++-
 indra/newview/llaisapi.cpp          | 659 +++++++---------------------
 indra/newview/llaisapi.h            | 146 ++----
 indra/newview/llappearancemgr.cpp   |  24 +-
 indra/newview/llviewerinventory.cpp |  84 +---
 indra/newview/llviewerregion.cpp    |   2 +-
 11 files changed, 441 insertions(+), 705 deletions(-)

diff --git a/indra/llcorehttp/_httpoprequest.cpp b/indra/llcorehttp/_httpoprequest.cpp
index e588ed8a9b1..86110f5b46c 100755
--- a/indra/llcorehttp/_httpoprequest.cpp
+++ b/indra/llcorehttp/_httpoprequest.cpp
@@ -380,6 +380,19 @@ HttpStatus HttpOpRequest::setupCopy(HttpRequest::policy_t policy_id,
 }
 
 
+HttpStatus HttpOpRequest::setupMove(HttpRequest::policy_t policy_id,
+    HttpRequest::priority_t priority,
+    const std::string & url,
+    const HttpOptions::ptr_t & options,
+    const HttpHeaders::ptr_t &headers)
+{
+    setupCommon(policy_id, priority, url, NULL, options, headers);
+    mReqMethod = HOR_MOVE;
+
+    return HttpStatus();
+}
+
+
 void HttpOpRequest::setupCommon(HttpRequest::policy_t policy_id,
 								HttpRequest::priority_t priority,
 								const std::string & url,
@@ -626,6 +639,11 @@ HttpStatus HttpOpRequest::prepareRequest(HttpService * service)
         check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
         break;
 
+    case HOR_MOVE:
+        code = curl_easy_setopt(mCurlHandle, CURLOPT_CUSTOMREQUEST, "MOVE");
+        check_curl_easy_code(code, CURLOPT_CUSTOMREQUEST);
+        break;
+
 	default:
 		LL_ERRS(LOG_CORE) << "Invalid HTTP method in request:  "
 						  << int(mReqMethod)  << ".  Can't recover."
diff --git a/indra/llcorehttp/_httpoprequest.h b/indra/llcorehttp/_httpoprequest.h
index a9083be02b4..1b449a5abcc 100755
--- a/indra/llcorehttp/_httpoprequest.h
+++ b/indra/llcorehttp/_httpoprequest.h
@@ -83,7 +83,8 @@ class HttpOpRequest : public HttpOperation
 		HOR_PUT,
         HOR_DELETE,
         HOR_PATCH,
-        HOR_COPY
+        HOR_COPY,
+        HOR_MOVE
 	};
 	
 	virtual void stageFromRequest(HttpService *);
@@ -148,6 +149,12 @@ class HttpOpRequest : public HttpOperation
                         const HttpOptions::ptr_t & options,
                         const HttpHeaders::ptr_t & headers);
 
+    HttpStatus setupMove(HttpRequest::policy_t policy_id,
+                        HttpRequest::priority_t priority,
+                        const std::string & url,
+                        const HttpOptions::ptr_t & options,
+                        const HttpHeaders::ptr_t & headers);
+
     // Internal method used to setup the libcurl options for a request.
 	// Does all the libcurl handle setup in one place.
 	//
diff --git a/indra/llcorehttp/httprequest.cpp b/indra/llcorehttp/httprequest.cpp
index f0dfde6153c..63233259fb9 100755
--- a/indra/llcorehttp/httprequest.cpp
+++ b/indra/llcorehttp/httprequest.cpp
@@ -419,6 +419,37 @@ HttpHandle HttpRequest::requestCopy(policy_t policy_id,
     return handle;
 }
 
+HttpHandle HttpRequest::requestMove(policy_t policy_id,
+    priority_t priority,
+    const std::string & url,
+    const HttpOptions::ptr_t & options,
+    const HttpHeaders::ptr_t & headers,
+    HttpHandler * user_handler)
+{
+    HttpStatus status;
+    HttpHandle handle(LLCORE_HTTP_HANDLE_INVALID);
+
+    HttpOpRequest * op = new HttpOpRequest();
+    if (!(status = op->setupMove(policy_id, priority, url, options, headers)))
+    {
+        op->release();
+        mLastReqStatus = status;
+        return handle;
+    }
+    op->setReplyPath(mReplyQueue, user_handler);
+    if (!(status = mRequestQueue->addOp(op)))			// transfers refcount
+    {
+        op->release();
+        mLastReqStatus = status;
+        return handle;
+    }
+
+    mLastReqStatus = status;
+    handle = static_cast<HttpHandle>(op);
+
+    return handle;
+}
+
 
 HttpHandle HttpRequest::requestNoOp(HttpHandler * user_handler)
 {
diff --git a/indra/llcorehttp/httprequest.h b/indra/llcorehttp/httprequest.h
index 20a223c4826..6c2449266f5 100755
--- a/indra/llcorehttp/httprequest.h
+++ b/indra/llcorehttp/httprequest.h
@@ -478,7 +478,7 @@ class HttpRequest
 						  HttpHandler * handler);
 
 
-    /// Queue a full HTTP PUT.  Query arguments and body may
+    /// Queue a full HTTP DELETE.  Query arguments and body may
     /// be provided.  Caller is responsible for escaping and
     /// encoding and communicating the content types.
     ///
@@ -497,7 +497,7 @@ class HttpRequest
             const HttpHeaders::ptr_t & headers,
             HttpHandler * user_handler);
 
-    /// Queue a full HTTP PUT.  Query arguments and body may
+    /// Queue a full HTTP PATCH.  Query arguments and body may
     /// be provided.  Caller is responsible for escaping and
     /// encoding and communicating the content types.
     ///
@@ -520,7 +520,7 @@ class HttpRequest
             const HttpHeaders::ptr_t & headers,
             HttpHandler * user_handler);
 
-    /// Queue a full HTTP PUT.  Query arguments and body may
+    /// Queue a full HTTP COPY.  Query arguments and body may
     /// be provided.  Caller is responsible for escaping and
     /// encoding and communicating the content types.
     ///
@@ -538,7 +538,26 @@ class HttpRequest
             const HttpOptions::ptr_t & options,
             const HttpHeaders::ptr_t & headers,
             HttpHandler * user_handler);
-       
+
+    /// Queue a full HTTP MOVE.  Query arguments and body may
+    /// be provided.  Caller is responsible for escaping and
+    /// encoding and communicating the content types.
+    ///
+    /// @param	policy_id		@see requestGet()
+    /// @param	priority		"
+    /// @param	url				"
+    /// @param	options			@see requestGet()K(optional)
+    /// @param	headers			"
+    /// @param	handler			"
+    /// @return					"
+    ///
+    HttpHandle requestMove(policy_t policy_id,
+            priority_t priority,
+            const std::string & url,
+            const HttpOptions::ptr_t & options,
+            const HttpHeaders::ptr_t & headers,
+            HttpHandler * user_handler);
+
     /// Queue a NoOp request.
 	/// The request is queued and serviced by the working thread which
 	/// immediately processes it and returns the request to the reply
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index 50c866f3702..d342888255d 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -700,7 +700,6 @@ LLSD HttpCoroutineAdapter::postAndYield_(LLCore::HttpRequest::ptr_t &request,
     LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
     cleanState();
 
-    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
     return results;
 }
 
@@ -737,7 +736,7 @@ LLSD HttpCoroutineAdapter::putAndYield_(LLCore::HttpRequest::ptr_t &request,
     saveState(hhandle, request, handler);
     LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
     cleanState();
-    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
+
     return results;
 }
 
@@ -792,7 +791,7 @@ LLSD HttpCoroutineAdapter::getAndYield_(LLCore::HttpRequest::ptr_t &request,
     saveState(hhandle, request, handler);
     LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
     cleanState();
-    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
+
     return results;
 }
 
@@ -827,7 +826,7 @@ LLSD HttpCoroutineAdapter::deleteAndYield_(LLCore::HttpRequest::ptr_t &request,
     saveState(hhandle, request, handler);
     LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
     cleanState();
-    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
+
     return results;
 }
 
@@ -865,10 +864,95 @@ LLSD HttpCoroutineAdapter::patchAndYield_(LLCore::HttpRequest::ptr_t &request,
     saveState(hhandle, request, handler);
     LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
     cleanState();
-    //LL_INFOS() << "Results for transaction " << transactionId << LL_ENDL;
+
+    return results;
+}
+
+LLSD HttpCoroutineAdapter::copyAndYield(LLCore::HttpRequest::ptr_t request,
+    const std::string & url, const std::string dest,
+    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+    LLEventStream  replyPump(mAdapterName + "Reply", true);
+    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+
+    if (!headers)
+        headers.reset(new LLCore::HttpHeaders);
+    headers->append(HTTP_OUT_HEADER_DESTINATION, dest);
+
+    return copyAndYield_(request, url, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::copyAndYield_(LLCore::HttpRequest::ptr_t &request,
+    const std::string & url, 
+    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+    HttpCoroHandler::ptr_t &handler)
+{
+    HttpRequestPumper pumper(request);
+
+    checkDefaultHeaders(headers);
+
+    // The HTTPCoroHandler does not self delete, so retrieval of a the contained 
+    // pointer from the smart pointer is safe in this case.
+    // 
+    LLCore::HttpHandle hhandle = request->requestCopy(mPolicyId, mPriority, url,
+        options, headers, handler.get());
+
+    if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+    {
+        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+    }
+
+    saveState(hhandle, request, handler);
+    LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+    cleanState();
+
+    return results;
+}
+
+LLSD HttpCoroutineAdapter::moveAndYield(LLCore::HttpRequest::ptr_t request,
+    const std::string & url, const std::string dest,
+    LLCore::HttpOptions::ptr_t options, LLCore::HttpHeaders::ptr_t headers)
+{
+    LLEventStream  replyPump(mAdapterName + "Reply", true);
+    HttpCoroHandler::ptr_t httpHandler = HttpCoroHandler::ptr_t(new HttpCoroLLSDHandler(replyPump));
+
+    if (!headers)
+        headers.reset(new LLCore::HttpHeaders);
+    headers->append(HTTP_OUT_HEADER_DESTINATION, dest);
+
+    return moveAndYield_(request, url, options, headers, httpHandler);
+}
+
+
+LLSD HttpCoroutineAdapter::moveAndYield_(LLCore::HttpRequest::ptr_t &request,
+    const std::string & url,
+    LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+    HttpCoroHandler::ptr_t &handler)
+{
+    HttpRequestPumper pumper(request);
+
+    checkDefaultHeaders(headers);
+
+    // The HTTPCoroHandler does not self delete, so retrieval of a the contained 
+    // pointer from the smart pointer is safe in this case.
+    // 
+    LLCore::HttpHandle hhandle = request->requestMove(mPolicyId, mPriority, url,
+        options, headers, handler.get());
+
+    if (hhandle == LLCORE_HTTP_HANDLE_INVALID)
+    {
+        return HttpCoroutineAdapter::buildImmediateErrorResult(request, url);
+    }
+
+    saveState(hhandle, request, handler);
+    LLSD results = llcoro::waitForEventOn(handler->getReplyPump());
+    cleanState();
+
     return results;
 }
 
+
 void HttpCoroutineAdapter::checkDefaultHeaders(LLCore::HttpHeaders::ptr_t &headers)
 {
     if (!headers)
diff --git a/indra/llmessage/llcorehttputil.h b/indra/llmessage/llcorehttputil.h
index 8fe2354d6b7..31a73bb9009 100644
--- a/indra/llmessage/llcorehttputil.h
+++ b/indra/llmessage/llcorehttputil.h
@@ -457,7 +457,7 @@ class HttpCoroutineAdapter
         LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
 
 
-    /// Execute a Post transaction on the supplied URL and yield execution of 
+    /// Execute a PATCH transaction on the supplied URL and yield execution of 
     /// the coroutine until a result is available. 
     /// 
     /// @Note: the request's smart pointer is passed by value so that it will
@@ -474,6 +474,46 @@ class HttpCoroutineAdapter
             LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
     }
 
+    /// Execute a COPY transaction on the supplied URL and yield execution of 
+    /// the coroutine until a result is available. 
+    /// 
+    /// @Note: The destination is passed through the HTTP pipe as a header
+    /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination");
+    /// 
+    /// @Note: the request's smart pointer is passed by value so that it will
+    /// not be deallocated during the yield.
+    LLSD copyAndYield(LLCore::HttpRequest::ptr_t request,
+        const std::string & url, const std::string dest,
+        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+    LLSD copyAndYield(LLCore::HttpRequest::ptr_t &request,
+        const std::string & url, const std::string & dest,
+        LLCore::HttpHeaders::ptr_t &headers)
+    {
+        return copyAndYield(request, url, dest,
+            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+    }
+
+    /// Execute a MOVE transaction on the supplied URL and yield execution of 
+    /// the coroutine until a result is available. 
+    /// 
+    /// @Note: The destination is passed through the HTTP pipe in the headers.
+    /// The header used is defined as: HTTP_OUT_HEADER_DESTINATION("Destination");
+    /// 
+    /// @Note: the request's smart pointer is passed by value so that it will
+    /// not be deallocated during the yield.
+    LLSD moveAndYield(LLCore::HttpRequest::ptr_t request,
+        const std::string & url, const std::string dest,
+        LLCore::HttpOptions::ptr_t options = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()),
+        LLCore::HttpHeaders::ptr_t headers = LLCore::HttpHeaders::ptr_t(new LLCore::HttpHeaders()));
+    LLSD moveAndYield(LLCore::HttpRequest::ptr_t &request,
+        const std::string & url, const std::string & dest,
+        LLCore::HttpHeaders::ptr_t &headers)
+    {
+        return moveAndYield(request, url, dest,
+            LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions()), headers);
+    }
+
     ///
     void cancelYieldingOperation();
 
@@ -541,6 +581,16 @@ class HttpCoroutineAdapter
         LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
         HttpCoroHandler::ptr_t &handler);
 
+    LLSD copyAndYield_(LLCore::HttpRequest::ptr_t &request,
+        const std::string & url, 
+        LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+        HttpCoroHandler::ptr_t &handler);
+
+    LLSD moveAndYield_(LLCore::HttpRequest::ptr_t &request,
+        const std::string & url,
+        LLCore::HttpOptions::ptr_t &options, LLCore::HttpHeaders::ptr_t &headers,
+        HttpCoroHandler::ptr_t &handler);
+
     static void trivialGetCoro(std::string url, LLCore::HttpRequest::policy_t policyId, completionCallback_t success, completionCallback_t failure);
     static void trivialPostCoro(std::string url, LLCore::HttpRequest::policy_t policyId, LLSD postData, completionCallback_t success, completionCallback_t failure);
 
diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index 3565c046091..23ea692a16f 100755
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -37,11 +37,54 @@
 #include "llviewercontrol.h"
 
 ///----------------------------------------------------------------------------
-#if 1
+/// Classes for AISv3 support.
+///----------------------------------------------------------------------------
+
+//=========================================================================
+const std::string AISAPI::INVENTORY_CAP_NAME("InventoryAPIv3");
+const std::string AISAPI::LIBRARY_CAP_NAME("LibraryAPIv3");
+
+//-------------------------------------------------------------------------
+/*static*/
+bool AISAPI::isAvailable()
+{
+    if (gAgent.getRegion())
+    {
+        return gAgent.getRegion()->isCapabilityAvailable(INVENTORY_CAP_NAME);
+    }
+    return false;
+}
+
+/*static*/
+void AISAPI::getCapNames(LLSD& capNames)
+{
+    capNames.append(INVENTORY_CAP_NAME);
+    capNames.append(LIBRARY_CAP_NAME);
+}
+
+/*static*/
+std::string AISAPI::getInvCap()
+{
+    if (gAgent.getRegion())
+    {
+        return gAgent.getRegion()->getCapability(INVENTORY_CAP_NAME);
+    }
+    return std::string();
+}
+
+/*static*/
+std::string AISAPI::getLibCap()
+{
+    if (gAgent.getRegion())
+    {
+        return gAgent.getRegion()->getCapability(LIBRARY_CAP_NAME);
+    }
+    return std::string();
+}
+
 /*static*/ 
-void AISAPI::CreateInventoryCommand(const LLUUID& parentId, const LLSD& newInventory, completion_t callback)
+void AISAPI::CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback)
 {
-#if 1
     std::string cap = getInvCap();
     if (cap.empty())
     {
@@ -68,23 +111,22 @@ void AISAPI::CreateInventoryCommand(const LLUUID& parentId, const LLSD& newInven
         // Humans ignore next line.  It is just a cast.
         static_cast<LLSD (LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
         //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
         (&LLCoreHttpUtil::HttpCoroutineAdapter::postAndYield), _1, _2, _3, _4, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, postFn, url, parentId, newInventory, callback));
-#else
-    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::CreateInventoryCommandCoro, 
-        _1, parentId, newInventory, callback));
-
-#endif
+        _1, postFn, url, parentId, newInventory, callback, COPYINVENTORY));
     EnqueueAISCommand("CreateInventory", proc);
-
 }
 
 /*static*/ 
-void AISAPI::SlamFolderCommand(const LLUUID& folderId, const LLSD& newInventory, completion_t callback)
+void AISAPI::SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback)
 {
-#if 1
     std::string cap = getInvCap();
     if (cap.empty())
     {
@@ -99,23 +141,24 @@ void AISAPI::SlamFolderCommand(const LLUUID& folderId, const LLSD& newInventory,
 
     // see comment above in CreateInventoryCommand
     invokationFn_t putFn = boost::bind(
-        // Humans ignore next line.  It is just a cast.
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
         static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
         //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
         (&LLCoreHttpUtil::HttpCoroutineAdapter::putAndYield), _1, _2, _3, _4, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, putFn, url, folderId, newInventory, callback));
-
-#else
-    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::SlamFolderCommandCoro,
-        _1, folderId, newInventory, callback));
-#endif
+        _1, putFn, url, folderId, newInventory, callback, SLAMFOLDER));
 
     EnqueueAISCommand("SlamFolder", proc);
 }
 
-void AISAPI::RemoveCategoryCommand(const LLUUID &categoryId, completion_t callback)
+void AISAPI::RemoveCategory(const LLUUID &categoryId, completion_t callback)
 {
     std::string cap;
 
@@ -130,21 +173,26 @@ void AISAPI::RemoveCategoryCommand(const LLUUID &categoryId, completion_t callba
     LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
 
     invokationFn_t delFn = boost::bind(
-        // Humans ignore next line.  It is just a cast.
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
         static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
         //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
         (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndYield), _1, _2, _3, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, delFn, url, categoryId, LLSD(), callback));
+        _1, delFn, url, categoryId, LLSD(), callback, REMOVECATEGORY));
 
     EnqueueAISCommand("RemoveCategory", proc);
 }
 
 /*static*/ 
-void AISAPI::RemoveItemCommand(const LLUUID &itemId, completion_t callback)
+void AISAPI::RemoveItem(const LLUUID &itemId, completion_t callback)
 {
-#if 1
     std::string cap;
 
     cap = getInvCap();
@@ -158,25 +206,64 @@ void AISAPI::RemoveItemCommand(const LLUUID &itemId, completion_t callback)
     LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
 
     invokationFn_t delFn = boost::bind(
-        // Humans ignore next line.  It is just a cast.
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
         static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
         //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
         (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndYield), _1, _2, _3, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, delFn, url, itemId, LLSD(), callback));
-
-#else
-    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::RemoveItemCommandCoro,
-        _1, itemId, callback));
-#endif
+        _1, delFn, url, itemId, LLSD(), callback, REMOVEITEM));
 
     EnqueueAISCommand("RemoveItem", proc);
 }
 
+void AISAPI::CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, completion_t callback)
+{
+    std::string cap;
+
+    cap = getLibCap();
+    if (cap.empty())
+    {
+        LL_WARNS("Inventory") << "Library cap not found!" << LL_ENDL;
+        return;
+    }
+
+    LL_DEBUGS("Inventory") << "Copying library category: " << sourceId << " => " << destId << LL_ENDL;
+
+    LLUUID tid;
+    tid.generate();
+
+    std::string url = cap + std::string("/category/") + sourceId.asString() + "?tid=" + tid.asString();
+    LL_INFOS() << url << LL_ENDL;
+
+    std::string destination = destId.asString();
+
+    invokationFn_t copyFn = boost::bind(
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
+        static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const std::string, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
+        //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
+        (&LLCoreHttpUtil::HttpCoroutineAdapter::copyAndYield), _1, _2, _3, destination, _5, _6);
+         
+    LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
+        _1, copyFn, url, destId, LLSD(), callback, COPYLIBRARYCATEGORY));
+
+    EnqueueAISCommand("CopyLibraryCategory", proc);
+}
 
 /*static*/ 
-void AISAPI::PurgeDescendentsCommand(const LLUUID &categoryId, completion_t callback)
+void AISAPI::PurgeDescendents(const LLUUID &categoryId, completion_t callback)
 {
     std::string cap;
 
@@ -191,20 +278,26 @@ void AISAPI::PurgeDescendentsCommand(const LLUUID &categoryId, completion_t call
     LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
 
     invokationFn_t delFn = boost::bind(
-        // Humans ignore next line.  It is just a cast.
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
         static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
         //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
         (&LLCoreHttpUtil::HttpCoroutineAdapter::deleteAndYield), _1, _2, _3, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, delFn, url, categoryId, LLSD(), callback));
+        _1, delFn, url, categoryId, LLSD(), callback, PURGEDESCENDENTS));
 
     EnqueueAISCommand("PurgeDescendents", proc);
 }
 
 
 /*static*/
-void AISAPI::UpdateCategoryCommand(const LLUUID &categoryId, const LLSD &updates, completion_t callback)
+void AISAPI::UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback)
 {
     std::string cap;
 
@@ -217,19 +310,25 @@ void AISAPI::UpdateCategoryCommand(const LLUUID &categoryId, const LLSD &updates
     std::string url = cap + std::string("/category/") + categoryId.asString();
 
     invokationFn_t patchFn = boost::bind(
-        // Humans ignore next line.  It is just a cast.
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
         static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
         //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
         (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndYield), _1, _2, _3, _4, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, patchFn, url, categoryId, updates, callback));
+        _1, patchFn, url, categoryId, updates, callback, UPDATECATEGORY));
 
     EnqueueAISCommand("UpdateCategory", proc);
 }
 
 /*static*/
-void AISAPI::UpdateItemCommand(const LLUUID &itemId, const LLSD &updates, completion_t callback)
+void AISAPI::UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback)
 {
 
     std::string cap;
@@ -243,13 +342,19 @@ void AISAPI::UpdateItemCommand(const LLUUID &itemId, const LLSD &updates, comple
     std::string url = cap + std::string("/item/") + itemId.asString();
 
     invokationFn_t patchFn = boost::bind(
-        // Humans ignore next line.  It is just a cast.
+        // Humans ignore next line.  It is just a cast to specify which LLCoreHttpUtil::HttpCoroutineAdapter routine overload.
         static_cast<LLSD(LLCoreHttpUtil::HttpCoroutineAdapter::*)(LLCore::HttpRequest::ptr_t, const std::string &, const LLSD &, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t)>
         //----
+        // _1 -> httpAdapter
+        // _2 -> httpRequest
+        // _3 -> url
+        // _4 -> body 
+        // _5 -> httpOptions
+        // _6 -> httpHeaders
         (&LLCoreHttpUtil::HttpCoroutineAdapter::patchAndYield), _1, _2, _3, _4, _5, _6);
 
     LLCoprocedureManager::CoProcedure_t proc(boost::bind(&AISAPI::InvokeAISCommandCoro,
-        _1, patchFn, url, itemId, updates, callback));
+        _1, patchFn, url, itemId, updates, callback, UPDATEITEM));
 
     EnqueueAISCommand("UpdateItem", proc);
 }
@@ -262,31 +367,10 @@ void AISAPI::EnqueueAISCommand(const std::string &procName, LLCoprocedureManager
 
 }
 
-/*static*/ 
-std::string AISAPI::getInvCap()
-{
-    if (gAgent.getRegion())
-    {
-        return gAgent.getRegion()->getCapability("InventoryAPIv3");
-    }
-
-    return std::string();
-}
-
-/*static*/ 
-std::string AISAPI::getLibCap()
-{
-    if (gAgent.getRegion())
-    {
-        return gAgent.getRegion()->getCapability("LibraryAPIv3");
-    }
-    return std::string();
-}
-
 /*static*/
 void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, 
         invokationFn_t invoke, std::string url, 
-        LLUUID targetId, LLSD body, completion_t callback)
+        LLUUID targetId, LLSD body, completion_t callback, COMMAND_TYPE type)
 {
     LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
     LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
@@ -313,455 +397,20 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
     gInventory.onAISUpdateReceived("AISCommand", result);
 
     if (callback)
-    {   // UUID always null
-        callback(LLUUID::null);
-    }
-
-}
-
-#if 0
-/*static*/
-void AISAPI::CreateInventoryCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, LLUUID parentId, LLSD newInventory, completion_t callback)
-{
-    std::string cap;
-    LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
-    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
-
-    httpOptions->setTimeout(HTTP_REQUEST_EXPIRY_SECS);
-
-    cap = getInvCap();
-    if (cap.empty())
-    {
-        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
-        return;
-    }
-
-    LLUUID tid;
-    tid.generate();
+    {   
+        LLUUID id(LLUUID::null);
 
-    std::string url = cap + std::string("/category/") + parentId.asString() + "?tid=" + tid.asString();
-    LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
+        if (result.has("category_id") && (type == COPYLIBRARYCATEGORY))
+	    {
+		    id = result["category_id"];
+	    }
 
-    LLSD result = httpAdapter->postAndYield(httpRequest, url, newInventory, httpOptions);
-    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
-    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
-    if (!status || !result.isMap())
-    {
-        if (!result.isMap())
-        {
-            status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents");
-        }
-        LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
-        LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
+        callback(id);
     }
 
-    gInventory.onAISUpdateReceived("AISCommand", result);
-
-    if (callback)
-    {   // UUID always null
-        callback(LLUUID::null);
-    }
-
-}
-
-/*static*/
-void AISAPI::SlamFolderCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, LLUUID folderId, LLSD newInventory, completion_t callback)
-{
-    std::string cap;
-    LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
-    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
-
-    httpOptions->setTimeout(HTTP_REQUEST_EXPIRY_SECS);
-
-    cap = getInvCap();
-    if (cap.empty())
-    {
-        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
-        return;
-    }
-
-    LLUUID tid;
-    tid.generate();
-
-    std::string url = cap + std::string("/category/") + folderId.asString() + "/links?tid=" + tid.asString();
-
-    LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-
-    LLSD result = httpAdapter->putAndYield(httpRequest, url, newInventory, httpOptions);
-    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
-    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
-    if (!status || !result.isMap())
-    {
-        if (!result.isMap())
-        {
-            status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents");
-        }
-        LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
-        LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
-    }
-
-    gInventory.onAISUpdateReceived("AISCommand", result);
-
-    if (callback)
-    {   // UUID always null
-        callback(LLUUID::null);
-    }
-
-}
-
-void AISAPI::RemoveItemCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, LLUUID itemId, completion_t callback)
-{
-    std::string cap;
-    LLCore::HttpOptions::ptr_t httpOptions(new LLCore::HttpOptions);
-    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest());
-
-    httpOptions->setTimeout(HTTP_REQUEST_EXPIRY_SECS);
-
-    cap = getInvCap();
-    if (cap.empty())
-    {
-        LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
-        return;
-    }
-
-    std::string url = cap + std::string("/item/") + itemId.asString();
-    LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-
-    LLSD result = httpAdapter->deleteAndYield(httpRequest, url, httpOptions);
-    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
-    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
-    if (!status || !result.isMap())
-    {
-        if (!result.isMap())
-        {
-            status = LLCore::HttpStatus(HTTP_INTERNAL_ERROR, "Malformed response contents");
-        }
-        LL_WARNS("Inventory") << "Inventory error: " << status.toString() << LL_ENDL;
-        LL_WARNS("Inventory") << ll_pretty_print_sd(result) << LL_ENDL;
-    }
-
-    gInventory.onAISUpdateReceived("AISCommand", result);
-
-    if (callback)
-    {   // UUID always null
-        callback(LLUUID::null);
-    }
-}
-#endif
-#endif
-///----------------------------------------------------------------------------
-/// Classes for AISv3 support.
-///----------------------------------------------------------------------------
-
-// AISCommand - base class for retry-able HTTP requests using the AISv3 cap.
-AISCommand::AISCommand(LLPointer<LLInventoryCallback> callback):
-	mCommandFunc(NULL),
-	mCallback(callback)
-{
-	mRetryPolicy = new LLAdaptiveRetryPolicy(1.0, 32.0, 2.0, 10);
-}
-
-bool AISCommand::run_command()
-{
-	if (NULL == mCommandFunc)
-	{
-		// This may happen if a command failed to initiate itself.
-		LL_WARNS("Inventory") << "AIS command attempted with null command function" << LL_ENDL;
-		return false;
-	}
-	else
-	{
-		mCommandFunc();
-		return true;
-	}
-}
-
-void AISCommand::setCommandFunc(command_func_type command_func)
-{
-	mCommandFunc = command_func;
-}
-	
-// virtual
-bool AISCommand::getResponseUUID(const LLSD& content, LLUUID& id)
-{
-	return false;
-}
-	
-/* virtual */
-void AISCommand::httpSuccess()
-{
-	// Command func holds a reference to self, need to release it
-	// after a success or final failure.
-	setCommandFunc(no_op);
-		
-	const LLSD& content = getContent();
-	if (!content.isMap())
-	{
-		failureResult(HTTP_INTERNAL_ERROR, "Malformed response contents", content);
-		return;
-	}
-	mRetryPolicy->onSuccess();
-		
-	gInventory.onAISUpdateReceived("AISCommand", content);
-
-	if (mCallback)
-	{
-		LLUUID id; // will default to null if parse fails.
-		getResponseUUID(content,id);
-		mCallback->fire(id);
-	}
-}
-
-/*virtual*/
-void AISCommand::httpFailure()
-{
-	LL_WARNS("Inventory") << dumpResponse() << LL_ENDL;
-	S32 status = getStatus();
-	const LLSD& headers = getResponseHeaders();
-	mRetryPolicy->onFailure(status, headers);
-	F32 seconds_to_wait;
-	if (mRetryPolicy->shouldRetry(seconds_to_wait))
-	{
-		doAfterInterval(boost::bind(&AISCommand::run_command,this),seconds_to_wait);
-	}
-	else
-	{
-		// Command func holds a reference to self, need to release it
-		// after a success or final failure.
-		// *TODO: Notify user?  This seems bad.
-		setCommandFunc(no_op);
-	}
-}
-
-//static
-bool AISCommand::isAPIAvailable()
-{
-	if (gAgent.getRegion())
-	{
-		return gAgent.getRegion()->isCapabilityAvailable("InventoryAPIv3");
-	}
-	return false;
-}
-
-//static
-bool AISCommand::getInvCap(std::string& cap)
-{
-	if (gAgent.getRegion())
-	{
-		cap = gAgent.getRegion()->getCapability("InventoryAPIv3");
-	}
-	if (!cap.empty())
-	{
-		return true;
-	}
-	return false;
-}
-
-//static
-bool AISCommand::getLibCap(std::string& cap)
-{
-	if (gAgent.getRegion())
-	{
-		cap = gAgent.getRegion()->getCapability("LibraryAPIv3");
-	}
-	if (!cap.empty())
-	{
-		return true;
-	}
-	return false;
-}
-
-//static
-void AISCommand::getCapabilityNames(LLSD& capabilityNames)
-{
-	capabilityNames.append("InventoryAPIv3");
-	capabilityNames.append("LibraryAPIv3");
-}
-
-// RemoveItemCommand::RemoveItemCommand(const LLUUID& item_id,
-// 									 LLPointer<LLInventoryCallback> callback):
-// 	AISCommand(callback)
-// {
-// 	std::string cap;
-// 	if (!getInvCap(cap))
-// 	{
-// 		LL_WARNS() << "No cap found" << LL_ENDL;
-// 		return;
-// 	}
-// 	std::string url = cap + std::string("/item/") + item_id.asString();
-// 	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-// 	LLHTTPClient::ResponderPtr responder = this;
-// 	LLSD headers;
-// 	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-// 	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
-// 	setCommandFunc(cmd);
-// }
-
-// RemoveCategoryCommand::RemoveCategoryCommand(const LLUUID& item_id,
-// 											 LLPointer<LLInventoryCallback> callback):
-// 	AISCommand(callback)
-// {
-// 	std::string cap;
-// 	if (!getInvCap(cap))
-// 	{
-// 		LL_WARNS() << "No cap found" << LL_ENDL;
-// 		return;
-// 	}
-// 	std::string url = cap + std::string("/category/") + item_id.asString();
-// 	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-// 	LLHTTPClient::ResponderPtr responder = this;
-// 	LLSD headers;
-// 	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-// 	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
-// 	setCommandFunc(cmd);
-// }
-
-// PurgeDescendentsCommand::PurgeDescendentsCommand(const LLUUID& item_id,
-// 												 LLPointer<LLInventoryCallback> callback):
-// 	AISCommand(callback)
-// {
-// 	std::string cap;
-// 	if (!getInvCap(cap))
-// 	{
-// 		LL_WARNS() << "No cap found" << LL_ENDL;
-// 		return;
-// 	}
-// 	std::string url = cap + std::string("/category/") + item_id.asString() + "/children";
-// 	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-// 	LLCurl::ResponderPtr responder = this;
-// 	LLSD headers;
-// 	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-// 	command_func_type cmd = boost::bind(&LLHTTPClient::del, url, responder, headers, timeout);
-// 	setCommandFunc(cmd);
-// }
-
-// UpdateItemCommand::UpdateItemCommand(const LLUUID& item_id,
-// 									 const LLSD& updates,
-// 									 LLPointer<LLInventoryCallback> callback):
-// 	mUpdates(updates),
-// 	AISCommand(callback)
-// {
-// 	std::string cap;
-// 	if (!getInvCap(cap))
-// 	{
-// 		LL_WARNS() << "No cap found" << LL_ENDL;
-// 		return;
-// 	}
-// 	std::string url = cap + std::string("/item/") + item_id.asString();
-// 	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-// 	LL_DEBUGS("Inventory") << "request: " << ll_pretty_print_sd(mUpdates) << LL_ENDL;
-// 	LLCurl::ResponderPtr responder = this;
-// 	LLSD headers;
-// 	headers["Content-Type"] = "application/llsd+xml";
-// 	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-// 	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
-// 	setCommandFunc(cmd);
-// }
-
-// UpdateCategoryCommand::UpdateCategoryCommand(const LLUUID& cat_id,
-// 											 const LLSD& updates,
-// 											 LLPointer<LLInventoryCallback> callback):
-// 	mUpdates(updates),
-// 	AISCommand(callback)
-// {
-// 	std::string cap;
-// 	if (!getInvCap(cap))
-// 	{
-// 		LL_WARNS() << "No cap found" << LL_ENDL;
-// 		return;
-// 	}
-// 	std::string url = cap + std::string("/category/") + cat_id.asString();
-// 	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-// 	LLCurl::ResponderPtr responder = this;
-// 	LLSD headers;
-// 	headers["Content-Type"] = "application/llsd+xml";
-// 	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-// 	command_func_type cmd = boost::bind(&LLHTTPClient::patch, url, mUpdates, responder, headers, timeout);
-// 	setCommandFunc(cmd);
-// }
-
-// CreateInventoryCommand::CreateInventoryCommand(const LLUUID& parent_id,
-// 							 				   const LLSD& new_inventory,
-// 							 				   LLPointer<LLInventoryCallback> callback):
-// 	mNewInventory(new_inventory),
-// 	AISCommand(callback)
-// {
-// 	std::string cap;
-// 	if (!getInvCap(cap))
-// 	{
-// 		LL_WARNS() << "No cap found" << LL_ENDL;
-// 		return;
-// 	}
-// 	LLUUID tid;
-// 	tid.generate();
-// 	std::string url = cap + std::string("/category/") + parent_id.asString() + "?tid=" + tid.asString();
-// 	LL_DEBUGS("Inventory") << "url: " << url << LL_ENDL;
-// 	LLCurl::ResponderPtr responder = this;
-// 	LLSD headers;
-// 	headers["Content-Type"] = "application/llsd+xml";
-// 	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-// 	command_func_type cmd = boost::bind(&LLHTTPClient::post, url, mNewInventory, responder, headers, timeout);
-// 	setCommandFunc(cmd);
-// }
-
-// SlamFolderCommand::SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback):
-// 	mContents(contents),
-// 	AISCommand(callback)
-// {
-// 	std::string cap;
-// 	if (!getInvCap(cap))
-// 	{
-// 		LL_WARNS() << "No cap found" << LL_ENDL;
-// 		return;
-// 	}
-// 	LLUUID tid;
-// 	tid.generate();
-// 	std::string url = cap + std::string("/category/") + folder_id.asString() + "/links?tid=" + tid.asString();
-// 	LL_INFOS() << url << LL_ENDL;
-// 	LLCurl::ResponderPtr responder = this;
-// 	LLSD headers;
-// 	headers["Content-Type"] = "application/llsd+xml";
-// 	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-// 	command_func_type cmd = boost::bind(&LLHTTPClient::put, url, mContents, responder, headers, timeout);
-// 	setCommandFunc(cmd);
-// }
-
-CopyLibraryCategoryCommand::CopyLibraryCategoryCommand(const LLUUID& source_id,
-													   const LLUUID& dest_id,
-													   LLPointer<LLInventoryCallback> callback):
-	AISCommand(callback)
-{
-	std::string cap;
-	if (!getLibCap(cap))
-	{
-		LL_WARNS() << "No cap found" << LL_ENDL;
-		return;
-	}
-	LL_DEBUGS("Inventory") << "Copying library category: " << source_id << " => " << dest_id << LL_ENDL;
-	LLUUID tid;
-	tid.generate();
-	std::string url = cap + std::string("/category/") + source_id.asString() + "?tid=" + tid.asString();
-	LL_INFOS() << url << LL_ENDL;
-	LLCurl::ResponderPtr responder = this;
-	LLSD headers;
-	F32 timeout = HTTP_REQUEST_EXPIRY_SECS;
-	command_func_type cmd = boost::bind(&LLHTTPClient::copy, url, dest_id.asString(), responder, headers, timeout);
-	setCommandFunc(cmd);
-}
-
-bool CopyLibraryCategoryCommand::getResponseUUID(const LLSD& content, LLUUID& id)
-{
-	if (content.has("category_id"))
-	{
-		id = content["category_id"];
-		return true;
-	}
-	return false;
 }
 
+//-------------------------------------------------------------------------
 AISUpdate::AISUpdate(const LLSD& update)
 {
 	parseUpdate(update);
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index ebb952a3eca..fc2bedc9ece 100755
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -38,21 +38,38 @@
 #include "llcorehttputil.h"
 #include "llcoproceduremanager.h"
 
-#if 1
 class AISAPI
 {
 public:
     typedef boost::function<void(const LLUUID &invItem)>    completion_t;
 
-    static void CreateInventoryCommand(const LLUUID& parentId, const LLSD& newInventory, completion_t callback);
-    static void SlamFolderCommand(const LLUUID& folderId, const LLSD& newInventory, completion_t callback);
-    static void RemoveCategoryCommand(const LLUUID &categoryId, completion_t callback);
-    static void RemoveItemCommand(const LLUUID &itemId, completion_t callback);
-    static void PurgeDescendentsCommand(const LLUUID &categoryId, completion_t callback);
-    static void UpdateCategoryCommand(const LLUUID &categoryId, const LLSD &updates, completion_t callback);
-    static void UpdateItemCommand(const LLUUID &itemId, const LLSD &updates, completion_t callback);
+    static bool isAvailable();
+    static void getCapNames(LLSD& capNames);
+
+    static void CreateInventory(const LLUUID& parentId, const LLSD& newInventory, completion_t callback);
+    static void SlamFolder(const LLUUID& folderId, const LLSD& newInventory, completion_t callback);
+    static void RemoveCategory(const LLUUID &categoryId, completion_t callback);
+    static void RemoveItem(const LLUUID &itemId, completion_t callback);
+    static void PurgeDescendents(const LLUUID &categoryId, completion_t callback);
+    static void UpdateCategory(const LLUUID &categoryId, const LLSD &updates, completion_t callback);
+    static void UpdateItem(const LLUUID &itemId, const LLSD &updates, completion_t callback);
+    static void CopyLibraryCategory(const LLUUID& sourceId, const LLUUID& destId, completion_t callback);
 
 private:
+    typedef enum {
+        COPYINVENTORY,
+        SLAMFOLDER,
+        REMOVECATEGORY,
+        REMOVEITEM,
+        PURGEDESCENDENTS,
+        UPDATECATEGORY,
+        UPDATEITEM,
+        COPYLIBRARYCATEGORY
+    } COMMAND_TYPE;
+
+    static const std::string INVENTORY_CAP_NAME;
+    static const std::string LIBRARY_CAP_NAME;
+
     typedef boost::function < LLSD (LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t, LLCore::HttpRequest::ptr_t,
         const std::string, LLSD, LLCore::HttpOptions::ptr_t, LLCore::HttpHeaders::ptr_t) > invokationFn_t;
 
@@ -61,118 +78,11 @@ class AISAPI
     static std::string getInvCap();
     static std::string getLibCap();
 
-    static void InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, invokationFn_t invoke, std::string url, LLUUID targetId, LLSD body, completion_t callback);
+    static void InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, 
+        invokationFn_t invoke, std::string url, LLUUID targetId, LLSD body, 
+        completion_t callback, COMMAND_TYPE type);
 
-#if 0
-    static void CreateInventoryCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t adapter, LLUUID parentId, LLSD newInventory, completion_t callback);
-    static void SlamFolderCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, LLUUID folderId, LLSD newInventory, completion_t callback);
-    static void RemoveItemCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, LLUUID itemId, completion_t callback);
-#endif
 };
-#endif 
-
-class AISCommand: public LLHTTPClient::Responder
-{
-public:
-	typedef boost::function<void()> command_func_type;
-
-	AISCommand(LLPointer<LLInventoryCallback> callback);
-
-	virtual ~AISCommand() {}
-
-	bool run_command();
-
-	void setCommandFunc(command_func_type command_func);
-	
-	// Need to do command-specific parsing to get an id here, for
-	// LLInventoryCallback::fire().  May or may not need to bother,
-	// since most LLInventoryCallbacks do their work in the
-	// destructor.
-	
-	/* virtual */ void httpSuccess();
-	/* virtual */ void httpFailure();
-
-	static bool isAPIAvailable();
-	static bool getInvCap(std::string& cap);
-	static bool getLibCap(std::string& cap);
-	static void getCapabilityNames(LLSD& capabilityNames);
-
-protected:
-	virtual bool getResponseUUID(const LLSD& content, LLUUID& id);
-
-private:
-	command_func_type mCommandFunc;
-	LLPointer<LLHTTPRetryPolicy> mRetryPolicy;
-	LLPointer<LLInventoryCallback> mCallback;
-};
-
-// class RemoveItemCommand: public AISCommand
-// {
-// public:
-// 	RemoveItemCommand(const LLUUID& item_id,
-// 					  LLPointer<LLInventoryCallback> callback);
-// };
-
-// class RemoveCategoryCommand: public AISCommand
-// {
-// public:
-// 	RemoveCategoryCommand(const LLUUID& item_id,
-// 						  LLPointer<LLInventoryCallback> callback);
-// };
-
-// class PurgeDescendentsCommand: public AISCommand
-// {
-// public:
-// 	PurgeDescendentsCommand(const LLUUID& item_id,
-// 							LLPointer<LLInventoryCallback> callback);
-// };
-
-// class UpdateItemCommand: public AISCommand
-// {
-// public:
-// 	UpdateItemCommand(const LLUUID& item_id,
-// 					  const LLSD& updates,
-// 					  LLPointer<LLInventoryCallback> callback);
-// private:
-// 	LLSD mUpdates;
-// };
-
-// class UpdateCategoryCommand: public AISCommand
-// {
-// public:
-// 	UpdateCategoryCommand(const LLUUID& cat_id,
-// 						  const LLSD& updates,
-// 						  LLPointer<LLInventoryCallback> callback);
-// private:
-// 	LLSD mUpdates;
-// };
-
-// class SlamFolderCommand: public AISCommand
-// {
-// public:
-// 	SlamFolderCommand(const LLUUID& folder_id, const LLSD& contents, LLPointer<LLInventoryCallback> callback);
-// 	
-// private:
-// 	LLSD mContents;
-// };
-
-class CopyLibraryCategoryCommand: public AISCommand
-{
-public:
-	CopyLibraryCategoryCommand(const LLUUID& source_id, const LLUUID& dest_id, LLPointer<LLInventoryCallback> callback);
-
-protected:
-	/* virtual */ bool getResponseUUID(const LLSD& content, LLUUID& id);
-};
-
-// class CreateInventoryCommand: public AISCommand
-// {
-// public:
-// 	CreateInventoryCommand(const LLUUID& parent_id, const LLSD& new_inventory, LLPointer<LLInventoryCallback> callback);
-// 
-// private:
-// 	LLSD mNewInventory;
-// };
 
 class AISUpdate
 {
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index ff420a36003..2883886fa1d 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -63,6 +63,17 @@
 #pragma warning (disable:4702)
 #endif
 
+#if 1
+// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model.
+// temp code in transition
+void doAppearanceCb(LLPointer<LLInventoryCallback> cb, LLUUID id)
+{
+    if (cb.notNull())
+        cb->fire(id);
+}
+#endif
+
+
 std::string self_av_string()
 {
 	// On logout gAgentAvatarp can already be invalid
@@ -2457,8 +2468,7 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
 			 << " )" << LL_ENDL;
 
 	// If we are copying from library, attempt to use AIS to copy the category.
-	bool ais_ran=false;
-	if (copy && AISCommand::isAPIAvailable())
+    if (copy && AISAPI::isAvailable())
 	{
 		LLUUID parent_id;
 		parent_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
@@ -2470,11 +2480,11 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool
 		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)
+        AISAPI::completion_t cr = boost::bind(&doAppearanceCb, track_cb, _1);
+        AISAPI::CopyLibraryCategory(category->getUUID(), parent_id, cr);
+	}
+    else
 	{
 		selfStartPhase("wear_inventory_category_fetch");
 		callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal,
@@ -3602,7 +3612,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);
-	if (AISCommand::isAPIAvailable())
+    if (AISAPI::isAvailable())
 	{
 		// 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/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 729af3c8edc..ac19d84a5e5 100755
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -80,6 +80,7 @@ static const char * const LOG_LOCAL("InventoryLocalize");
 static const char * const LOG_NOTECARD("copy_inventory_from_notecard");
 
 #if 1
+// *TODO$: LLInventoryCallback should be deprecated to conform to the new boost::bind/coroutine model.
 // temp code in transition
 void doInventoryCb(LLPointer<LLInventoryCallback> cb, LLUUID id)
 {
@@ -1289,21 +1290,14 @@ void link_inventory_array(const LLUUID& category,
 #endif
 	}
 
-	bool ais_ran = false;
-	if (AISCommand::isAPIAvailable())
+    if (AISAPI::isAvailable())
 	{
 		LLSD new_inventory = LLSD::emptyMap();
 		new_inventory["links"] = links;
-#if 1
         AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-        AISAPI::CreateInventoryCommand(category, new_inventory, cr);
-#else
- 		LLPointer<AISCommand> cmd_ptr = new CreateInventoryCommand(category, new_inventory, cb);
- 		ais_ran = cmd_ptr->run_command();
-#endif
+        AISAPI::CreateInventory(category, new_inventory, cr);
 	}
-
-	if (!ais_ran)
+    else
 	{
 		LLMessageSystem* msg = gMessageSystem;
 		for (LLSD::array_iterator iter = links.beginArray(); iter != links.endArray(); ++iter )
@@ -1360,8 +1354,7 @@ void update_inventory_item(
 	LLPointer<LLInventoryCallback> cb)
 {
 	const LLUUID& item_id = update_item->getUUID();
-	bool ais_ran = false;
-	if (AISCommand::isAPIAvailable())
+    if (AISAPI::isAvailable())
 	{
 		LLSD updates = update_item->asLLSD();
 		// Replace asset_id and/or shadow_id with transaction_id (hash_id)
@@ -1375,15 +1368,10 @@ void update_inventory_item(
 			updates.erase("shadow_id");
 			updates["hash_id"] = update_item->getTransactionID();
 		}
-#if 1
         AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-        AISAPI::UpdateItemCommand(item_id, updates, cr);
-#else
-		LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb);
-		ais_ran = cmd_ptr->run_command();
-#endif
+        AISAPI::UpdateItem(item_id, updates, cr);
 	}
-	if (!ais_ran)
+    else
 	{
 		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
 		LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (update_item ? update_item->getName() : "(NOT FOUND)") << LL_ENDL;
@@ -1419,18 +1407,12 @@ void update_inventory_item(
 	const LLSD& updates,
 	LLPointer<LLInventoryCallback> cb)
 {
-	bool ais_ran = false;
-	if (AISCommand::isAPIAvailable())
+    if (AISAPI::isAvailable())
 	{
-#if 1
         AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-        AISAPI::UpdateItemCommand(item_id, updates, cr);
-#else
-		LLPointer<AISCommand> cmd_ptr = new UpdateItemCommand(item_id, updates, cb);
-		ais_ran = cmd_ptr->run_command();
-#endif
+        AISAPI::UpdateItem(item_id, updates, cr);
 	}
-	if (!ais_ran)
+    else
 	{
 		LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
 		LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << (obj ? obj->getName() : "(NOT FOUND)") << LL_ENDL;
@@ -1480,16 +1462,11 @@ void update_inventory_category(
 		LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(obj);
 		new_cat->fromLLSD(updates);
 		// FIXME - restore this once the back-end work has been done.
-		if (AISCommand::isAPIAvailable())
+        if (AISAPI::isAvailable())
 		{
 			LLSD new_llsd = new_cat->asLLSD();
-#if 1
             AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-            AISAPI::UpdateCategoryCommand(cat_id, new_llsd, cr);
-#else
-			LLPointer<AISCommand> cmd_ptr = new UpdateCategoryCommand(cat_id, new_llsd, cb);
-			cmd_ptr->run_command();
-#endif
+            AISAPI::UpdateCategory(cat_id, new_llsd, cr);
 		}
 		else // no cap
 		{
@@ -1551,15 +1528,10 @@ void remove_inventory_item(
 	{
 		const LLUUID item_id(obj->getUUID());
 		LL_DEBUGS(LOG_INV) << "item_id: [" << item_id << "] name " << obj->getName() << LL_ENDL;
-		if (AISCommand::isAPIAvailable())
+        if (AISAPI::isAvailable())
 		{
-#if 1
             AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-            AISAPI::RemoveItemCommand(item_id, cr);
-#else
-			LLPointer<AISCommand> cmd_ptr = new RemoveItemCommand(item_id, cb);
-			cmd_ptr->run_command();
-#endif
+            AISAPI::RemoveItem(item_id, cr);
 
 			if (immediate_delete)
 			{
@@ -1632,15 +1604,10 @@ void remove_inventory_category(
 			LLNotificationsUtil::add("CannotRemoveProtectedCategories");
 			return;
 		}
-		if (AISCommand::isAPIAvailable())
+        if (AISAPI::isAvailable())
 		{
-#if 1
             AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-            AISAPI::RemoveCategoryCommand(cat_id, cr);
-#else
-			LLPointer<AISCommand> cmd_ptr = new RemoveCategoryCommand(cat_id, cb);
-			cmd_ptr->run_command();
-#endif
+            AISAPI::RemoveCategory(cat_id, cr);
 		}
 		else // no cap
 		{
@@ -1740,15 +1707,10 @@ void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
 		}
 		else
 		{
-			if (AISCommand::isAPIAvailable())
+            if (AISAPI::isAvailable())
 			{
-#if 1
                 AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-                AISAPI::PurgeDescendentsCommand(id, cr);
-#else
-                LLPointer<AISCommand> cmd_ptr = new PurgeDescendentsCommand(id, cb);
-				cmd_ptr->run_command();
-#endif
+                AISAPI::PurgeDescendents(id, cr);
 			}
 			else // no cap
 			{
@@ -1895,17 +1857,13 @@ void slam_inventory_folder(const LLUUID& folder_id,
 						   const LLSD& contents,
 						   LLPointer<LLInventoryCallback> cb)
 {
-	if (AISCommand::isAPIAvailable())
+    if (AISAPI::isAvailable())
 	{
 		LL_DEBUGS(LOG_INV) << "using AISv3 to slam folder, id " << folder_id
 						   << " new contents: " << ll_pretty_print_sd(contents) << LL_ENDL;
-#if 1
+
         AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
-        AISAPI::SlamFolderCommand(folder_id, contents, cr);
-#else
-		LLPointer<AISCommand> cmd_ptr = new SlamFolderCommand(folder_id, contents, cb);
-		cmd_ptr->run_command();
-#endif
+        AISAPI::SlamFolder(folder_id, contents, cr);
 	}
 	else // no cap
 	{
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 5c7071c63de..32b57dae259 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2822,7 +2822,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("FetchInventory2");
 	capabilityNames.append("FetchInventoryDescendents2");
 	capabilityNames.append("IncrementCOFVersion");
-	AISCommand::getCapabilityNames(capabilityNames);
+	AISAPI::getCapNames(capabilityNames);
 
 	capabilityNames.append("GetDisplayNames");
 	capabilityNames.append("GetExperiences");
-- 
GitLab