From ac145cb21f382b8eab9f770cecfa23ea9d58aac6 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 14 Mar 2023 23:21:26 +0200
Subject: SL-18629 WIP Fetch Inventory using AIS caps

---
 indra/newview/llaisapi.cpp                        |  42 ++++-
 indra/newview/llaisapi.h                          |   4 +-
 indra/newview/llinventoryfilter.cpp               |   2 +-
 indra/newview/llinventorymodel.cpp                |  13 --
 indra/newview/llinventorymodel.h                  |   3 -
 indra/newview/llinventorymodelbackgroundfetch.cpp | 214 ++++++++++++++++++----
 indra/newview/llinventorymodelbackgroundfetch.h   |  47 ++---
 indra/newview/llstartup.cpp                       |   1 +
 indra/newview/llviewerinventory.cpp               |   2 +-
 9 files changed, 242 insertions(+), 86 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llaisapi.cpp b/indra/newview/llaisapi.cpp
index afc307278c..87811e9c0b 100644
--- a/indra/newview/llaisapi.cpp
+++ b/indra/newview/llaisapi.cpp
@@ -33,6 +33,8 @@
 #include "llinventorymodel.h"
 #include "llsdutil.h"
 #include "llviewerregion.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
 #include "llinventoryobserver.h"
 #include "llviewercontrol.h"
 
@@ -409,6 +411,7 @@ void AISAPI::FetchCategoryChildren(const LLUUID &catId, ITEM_TYPE type, bool rec
     if (cap.empty())
     {
         LL_WARNS("Inventory") << "Inventory cap not found!" << LL_ENDL;
+        callback(LLUUID::null);
         return;
     }
     std::string url = cap + std::string("/category/") + catId.asString() + "/children";
@@ -565,6 +568,24 @@ void AISAPI::onIdle(void *userdata)
     }
 }
 
+/*static*/
+void AISAPI::onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type)
+{
+    LLTimer timer;
+    if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
+    {
+        dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
+    }
+    bool is_fetch = (type == FETCHITEM)
+        || (type == FETCHCATEGORYCHILDREN)
+        || (type == FETCHCATEGORYCATEGORIES)
+        || (type == FETCHCOF);
+    // parse update llsd into stuff to do or parse received items.
+    AISUpdate ais_update(update, is_fetch);
+    ais_update.doUpdate(); // execute the updates in the appropriate order.
+    LL_INFOS("Inventory") << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL;
+}
+
 /*static*/
 void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter, 
         invokationFn_t invoke, std::string url, 
@@ -659,7 +680,7 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
     }
 
 	LL_DEBUGS("Inventory") << result << LL_ENDL;
-    gInventory.onAISUpdateReceived("AISCommand", result);
+    onUpdateReceived("AISCommand", result, type);
 
     if (callback && !callback.empty())
     {
@@ -708,7 +729,8 @@ void AISAPI::InvokeAISCommandCoro(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t ht
 }
 
 //-------------------------------------------------------------------------
-AISUpdate::AISUpdate(const LLSD& update)
+AISUpdate::AISUpdate(const LLSD& update, bool fetch)
+: mFetch(fetch)
 {
 	parseUpdate(update);
 }
@@ -849,7 +871,7 @@ void AISUpdate::parseItem(const LLSD& item_map)
 	BOOL rv = new_item->unpackMessage(item_map);
 	if (rv)
 	{
-		if (curr_item)
+		if (!mFetch && curr_item)
 		{
 			mItemsUpdated[item_id] = new_item;
 			// This statement is here to cause a new entry with 0
@@ -884,7 +906,7 @@ void AISUpdate::parseLink(const LLSD& link_map)
 	if (rv)
 	{
 		const LLUUID& parent_id = new_link->getParentUUID();
-		if (curr_link)
+		if (!mFetch && curr_link)
 		{
 			mItemsUpdated[item_id] = new_link;
 			// This statement is here to cause a new entry with 0
@@ -951,7 +973,7 @@ void AISUpdate::parseCategory(const LLSD& category_map)
 	//}
 	if (rv)
 	{
-		if (curr_cat)
+		if (curr_cat && !mFetch)
 		{
 			mCategoriesUpdated[category_id] = new_cat;
 			// This statement is here to cause a new entry with 0
@@ -1054,7 +1076,7 @@ void AISUpdate::parseEmbeddedLinks(const LLSD& links)
 	{
 		const LLUUID link_id((*linkit).first);
 		const LLSD& link_map = (*linkit).second;
-		if (mItemIds.end() == mItemIds.find(link_id))
+		if (!mFetch && mItemIds.end() == mItemIds.find(link_id))
 		{
 			LL_DEBUGS("Inventory") << "Ignoring link not in items list " << link_id << LL_ENDL;
 		}
@@ -1070,7 +1092,7 @@ void AISUpdate::parseEmbeddedItem(const LLSD& item)
 	// a single item (_embedded in a link)
 	if (item.has("item_id"))
 	{
-		if (mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
+		if (mFetch || mItemIds.end() != mItemIds.find(item["item_id"].asUUID()))
 		{
 			parseItem(item);
 		}
@@ -1086,7 +1108,7 @@ void AISUpdate::parseEmbeddedItems(const LLSD& items)
 	{
 		const LLUUID item_id((*itemit).first);
 		const LLSD& item_map = (*itemit).second;
-		if (mItemIds.end() == mItemIds.find(item_id))
+		if (!mFetch && mItemIds.end() == mItemIds.find(item_id))
 		{
 			LL_DEBUGS("Inventory") << "Ignoring item not in items list " << item_id << LL_ENDL;
 		}
@@ -1102,7 +1124,7 @@ void AISUpdate::parseEmbeddedCategory(const LLSD& category)
 	// a single category (_embedded in a link)
 	if (category.has("category_id"))
 	{
-		if (mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
+		if (mFetch || mCategoryIds.end() != mCategoryIds.find(category["category_id"].asUUID()))
 		{
 			parseCategory(category);
 		}
@@ -1118,7 +1140,7 @@ void AISUpdate::parseEmbeddedCategories(const LLSD& categories)
 	{
 		const LLUUID category_id((*categoryit).first);
 		const LLSD& category_map = (*categoryit).second;
-		if (mCategoryIds.end() == mCategoryIds.find(category_id))
+		if (!mFetch && mCategoryIds.end() == mCategoryIds.find(category_id))
 		{
 			LL_DEBUGS("Inventory") << "Ignoring category not in categories list " << category_id << LL_ENDL;
 		}
diff --git a/indra/newview/llaisapi.h b/indra/newview/llaisapi.h
index b21edb9f33..3de3366a0e 100644
--- a/indra/newview/llaisapi.h
+++ b/indra/newview/llaisapi.h
@@ -86,6 +86,7 @@ private:
 
     static void EnqueueAISCommand(const std::string &procName, LLCoprocedureManager::CoProcedure_t proc);
     static void onIdle(void *userdata); // launches postponed AIS commands
+    static void onUpdateReceived(const std::string& context, const LLSD& update, COMMAND_TYPE type);
 
     static std::string getInvCap();
     static std::string getLibCap();
@@ -101,7 +102,7 @@ private:
 class AISUpdate
 {
 public:
-	AISUpdate(const LLSD& update);
+	AISUpdate(const LLSD& update, bool fetch);
 	void parseUpdate(const LLSD& update);
 	void parseMeta(const LLSD& update);
 	void parseContent(const LLSD& update);
@@ -137,6 +138,7 @@ private:
 	uuid_list_t mObjectsDeletedIds;
 	uuid_list_t mItemIds;
 	uuid_list_t mCategoryIds;
+    bool mFetch;
 };
 
 #endif
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index d6110b3cd5..6e09161473 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -202,7 +202,7 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
         {
             // At the moment background fetch only cares about VERSION_UNKNOWN,
             // so do not check isCategoryComplete that compares descendant count
-            LLInventoryModelBackgroundFetch::instance().start(folder_id);
+            LLInventoryModelBackgroundFetch::instance().start(folder_id, false);
         }
 	}
 
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index ee0dd2422a..65690228e7 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -1754,19 +1754,6 @@ void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat,
 	notifyObservers();
 }
 
-void LLInventoryModel::onAISUpdateReceived(const std::string& context, const LLSD& update)
-{
-	LLTimer timer;
-	if (gSavedSettings.getBOOL("DebugAvatarAppearanceMessage"))
-	{
-		dump_sequential_xml(gAgentAvatarp->getFullname() + "_ais_update", update);
-	}
-
-	AISUpdate ais_update(update); // parse update llsd into stuff to do.
-	ais_update.doUpdate(); // execute the updates in the appropriate order.
-	LL_INFOS(LOG_INV) << "elapsed: " << timer.getElapsedTimeF32() << LL_ENDL;
-}
-
 // Does not appear to be used currently.
 void LLInventoryModel::onItemUpdated(const LLUUID& item_id, const LLSD& updates, bool update_parent_version)
 {
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index 3fbf8924b5..5e4319bb12 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -411,9 +411,6 @@ public:
 	// Delete
 	//--------------------------------------------------------------------
 public:
-
-	// Update model after an AISv3 update received for any operation.
-	void onAISUpdateReceived(const std::string& context, const LLSD& update);
 		
 	// Update model after an item is confirmed as removed from
 	// server. Works for categories or items.
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 406c8b89d0..1905a9c9a4 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -27,6 +27,7 @@
 #include "llviewerprecompiledheaders.h"
 #include "llinventorymodelbackgroundfetch.h"
 
+#include "llaisapi.h"
 #include "llagent.h"
 #include "llappviewer.h"
 #include "llcallbacklist.h"
@@ -184,12 +185,12 @@ const char * const LOG_INV("Inventory");
 ///----------------------------------------------------------------------------
 
 LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch():
-	mBackgroundFetchActive(FALSE),
+	mBackgroundFetchActive(false),
 	mFolderFetchActive(false),
 	mFetchCount(0),
-	mAllFoldersFetched(FALSE),
-	mRecursiveInventoryFetchStarted(FALSE),
-	mRecursiveLibraryFetchStarted(FALSE),
+	mAllFoldersFetched(false),
+	mRecursiveInventoryFetchStarted(false),
+	mRecursiveLibraryFetchStarted(false),
 	mMinTimeBetweenFetches(0.3f)
 {}
 
@@ -241,17 +242,17 @@ BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const
 	return mFolderFetchActive;
 }
 
-void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category)
+void LLInventoryModelBackgroundFetch::addRequestAtFront(const LLUUID & id, bool recursive, bool is_category)
 {
 	mFetchQueue.push_front(FetchQueueInfo(id, recursive, is_category));
 }
 
-void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category)
+void LLInventoryModelBackgroundFetch::addRequestAtBack(const LLUUID & id, bool recursive, bool is_category)
 {
 	mFetchQueue.push_back(FetchQueueInfo(id, recursive, is_category));
 }
 
-void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
+void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive)
 {
 	LLViewerInventoryCategory * cat(gInventory.getCategory(id));
 
@@ -260,31 +261,57 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
 		// it's a folder, do a bulk fetch
 		LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL;
 
-		mBackgroundFetchActive = TRUE;
+		mBackgroundFetchActive = true;
 		mFolderFetchActive = true;
 		if (id.isNull())
 		{
 			if (! mRecursiveInventoryFetchStarted)
 			{
 				mRecursiveInventoryFetchStarted |= recursive;
-				mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
+                if (recursive && AISAPI::isAvailable())
+                {
+                    mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
+                }
+                else
+                {
+                    mFetchQueue.push_back(FetchQueueInfo(gInventory.getRootFolderID(), recursive));
+                }
 				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
 			}
 			if (! mRecursiveLibraryFetchStarted)
 			{
 				mRecursiveLibraryFetchStarted |= recursive;
-				mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
+                if (recursive && AISAPI::isAvailable())
+                {
+                    mRecursiveFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
+                }
+                else
+                {
+                    mFetchQueue.push_back(FetchQueueInfo(gInventory.getLibraryRootFolderID(), recursive));
+                }
 				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
 			}
 		}
 		else
 		{
-			// Specific folder requests go to front of queue.
-			if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)
-			{
-				mFetchQueue.push_front(FetchQueueInfo(id, recursive));
-				gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
-			}
+            if (recursive && AISAPI::isAvailable())
+            {
+                // AIS does depth requests, recursive requests will need to be prioritizes
+                if (mRecursiveFetchQueue.empty() || mRecursiveFetchQueue.back().mUUID != id)
+                {
+                    mRecursiveFetchQueue.push_back(FetchQueueInfo(id, recursive));
+                    gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+                }
+            }
+            else
+            {
+                // Specific folder requests go to front of queue.
+                if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)
+                {
+                    mFetchQueue.push_front(FetchQueueInfo(id, recursive));
+                    gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
+                }
+            }
 			if (id == gInventory.getLibraryRootFolderID())
 			{
 				mRecursiveLibraryFetchStarted |= recursive;
@@ -299,7 +326,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
 	{
 		if (! itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id))
 		{
-			mBackgroundFetchActive = TRUE;
+			mBackgroundFetchActive = true;
 
 			mFetchQueue.push_front(FetchQueueInfo(id, false, false));
 			gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
@@ -309,9 +336,9 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive)
 
 void LLInventoryModelBackgroundFetch::findLostItems()
 {
-	mBackgroundFetchActive = TRUE;
+	mBackgroundFetchActive = true;
 	mFolderFetchActive = true;
-    mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE));
+    mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, true));
     gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL);
 }
 
@@ -320,7 +347,7 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched()
 	if (mRecursiveInventoryFetchStarted &&
 		mRecursiveLibraryFetchStarted)
 	{
-		mAllFoldersFetched = TRUE;
+		mAllFoldersFetched = true;
 		//LL_INFOS(LOG_INV) << "All folders fetched, validating" << LL_ENDL;
 		//gInventory.validate();
 	}
@@ -338,8 +365,15 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
 {
 	if (mBackgroundFetchActive && gAgent.getRegion() && gAgent.getRegion()->capabilitiesReceived())
 	{
-		// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
-		bulkFetch();
+        if (AISAPI::isAvailable())
+        {
+            bulkFetchViaAis();
+        }
+        else
+        {
+            // If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
+            bulkFetch();
+        }
 	}
 }
 
@@ -352,9 +386,118 @@ void LLInventoryModelBackgroundFetch::incrFetchCount(S32 fetching)
 		mFetchCount = 0; 
 	}
 }
+void ais_callback(const LLUUID& inv_id)
+{
+    LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1);
+}
 
 static LLTrace::BlockTimerStatHandle FTM_BULK_FETCH("Bulk Fetch");
 
+void LLInventoryModelBackgroundFetch::bulkFetchViaAis()
+{
+    LL_RECORD_BLOCK_TIME(FTM_BULK_FETCH);
+    //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
+    if (gDisconnected)
+    {
+        return;
+    }
+
+    static const S32 max_concurrent_fetches(12);
+
+    if (mFetchCount >= max_concurrent_fetches)
+    {
+        return;
+    }
+
+    // Start with recursive queue since it can get multiple categories
+    // in a single request and might contain what other requests want
+    while (!mRecursiveFetchQueue.empty() && mFetchCount < max_concurrent_fetches)
+    {
+        const FetchQueueInfo & fetch_info(mRecursiveFetchQueue.front());
+        bulkFetchViaAis(fetch_info);
+        mRecursiveFetchQueue.pop_front();
+    }
+
+    while (!mFetchQueue.empty() && mFetchCount < max_concurrent_fetches)
+    {
+        const FetchQueueInfo & fetch_info(mFetchQueue.front());
+        bulkFetchViaAis(fetch_info);
+        mFetchQueue.pop_front();
+    }
+    
+    if (isBulkFetchProcessingComplete())
+    {
+        setAllFoldersFetched();
+    }
+}
+
+void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetch_info)
+{
+    if (fetch_info.mIsCategory)
+    {
+        const LLUUID & cat_id(fetch_info.mUUID);
+        if (cat_id.isNull()) // Lost and found
+        {
+            AISAPI::FetchCategoryChildren(LLUUID::null, AISAPI::INVENTORY, false, ais_callback);
+            mFetchCount++;
+        }
+        else
+        {
+            const LLViewerInventoryCategory * cat(gInventory.getCategory(cat_id));
+
+            if (cat)
+            {
+                if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
+                {
+                    if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
+                    {
+                        AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::LIBRARY, fetch_info.mRecursive, ais_callback);
+                    }
+                    else
+                    {
+                        AISAPI::FetchCategoryChildren(cat->getUUID(), AISAPI::INVENTORY, fetch_info.mRecursive, ais_callback);
+                    }
+                    mFetchCount++;
+                }
+                else
+                {
+                    // Already fetched, check if anything inside needs fetching
+                    if (fetch_info.mRecursive)
+                    {
+                        LLInventoryModel::cat_array_t * categories(NULL);
+                        LLInventoryModel::item_array_t * items(NULL);
+                        gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
+                        for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
+                            it != categories->end();
+                            ++it)
+                        {
+                            mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive));
+                        }
+                    }
+                }
+            }
+            // else???
+        }
+    }
+    else
+    {
+        LLViewerInventoryItem * itemp(gInventory.getItem(fetch_info.mUUID));
+
+        if (itemp)
+        {
+            if (itemp->getPermissions().getOwner() == gAgent.getID())
+            {
+                AISAPI::FetchItem(itemp->getUUID(), AISAPI::INVENTORY, ais_callback);
+            }
+            else
+            {
+                AISAPI::FetchItem(itemp->getUUID(), AISAPI::LIBRARY, ais_callback);
+            }
+            mFetchCount++;
+        }
+    }
+}
+
 // Bundle up a bunch of requests to send all at once.
 void LLInventoryModelBackgroundFetch::bulkFetch()
 {
@@ -374,13 +517,6 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 	// inventory more quickly.
 	static const U32 max_batch_size(10);
 	static const S32 max_concurrent_fetches(12);		// Outstanding requests, not connections
-	static const F32 new_min_time(0.05f);		// *HACK:  Clean this up when old code goes away entirely.
-	
-	mMinTimeBetweenFetches = new_min_time;
-	if (mMinTimeBetweenFetches < new_min_time) 
-	{
-		mMinTimeBetweenFetches = new_min_time;  // *HACK:  See above.
-	}
 
 	if (mFetchCount)
 	{
@@ -394,8 +530,7 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 		gInventory.notifyObservers();
 	}
 	
-	if ((mFetchCount > max_concurrent_fetches) ||
-		(mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches))
+	if (mFetchCount > max_concurrent_fetches)
 	{
 		return;
 	}
@@ -414,6 +549,13 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 	LLSD item_request_body;
 	LLSD item_request_body_lib;
 
+    if (!mRecursiveFetchQueue.empty())
+    {
+        LL_DEBUGS(LOG_INV) << "Request was sheduled for AIS, using legacy" << LL_ENDL;
+        mFetchQueue.insert(mFetchQueue.begin(), mRecursiveFetchQueue.begin(), mRecursiveFetchQueue.end());
+        mRecursiveFetchQueue.clear();
+    }
+
 	while (! mFetchQueue.empty() 
 			&& (item_count + folder_count) < max_batch_size)
 	{
@@ -421,14 +563,14 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 		if (fetch_info.mIsCategory)
 		{
 			const LLUUID & cat_id(fetch_info.mUUID);
-			if (cat_id.isNull()) //DEV-17797
+			if (cat_id.isNull()) //DEV-17797 Lost and found
 			{
 				LLSD folder_sd;
 				folder_sd["folder_id"]		= LLUUID::null.asString();
 				folder_sd["owner_id"]		= gAgent.getID();
 				folder_sd["sort_order"]		= LLSD::Integer(sort_order);
-				folder_sd["fetch_folders"]	= LLSD::Boolean(FALSE);
-				folder_sd["fetch_items"]	= LLSD::Boolean(TRUE);
+				folder_sd["fetch_folders"]	= LLSD::Boolean(false);
+				folder_sd["fetch_items"]	= LLSD::Boolean(true);
 				folder_request_body["folders"].append(folder_sd);
 				folder_count++;
 			}
@@ -444,8 +586,8 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 						folder_sd["folder_id"]		= cat->getUUID();
 						folder_sd["owner_id"]		= cat->getOwnerID();
 						folder_sd["sort_order"]		= LLSD::Integer(sort_order);
-						folder_sd["fetch_folders"]	= LLSD::Boolean(TRUE); //(LLSD::Boolean)sFullFetchStarted;
-						folder_sd["fetch_items"]	= LLSD::Boolean(TRUE);
+						folder_sd["fetch_folders"]	= LLSD::Boolean(true); //(LLSD::Boolean)sFullFetchStarted;
+						folder_sd["fetch_items"]	= LLSD::Boolean(true);
 				    
 						if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
 						{
diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h
index 00d2908c1b..ac1c42e0d7 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.h
+++ b/indra/newview/llinventorymodelbackgroundfetch.h
@@ -49,7 +49,7 @@ public:
 
 	// Start and stop background breadth-first fetching of inventory contents.
 	// This gets triggered when performing a filter-search.
-	void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE);
+	void start(const LLUUID& cat_id = LLUUID::null, bool recursive = true);
 
 	BOOL folderFetchActive() const;
 	bool isEverythingFetched() const; // completing the fetch once per session should be sufficient
@@ -68,10 +68,27 @@ public:
 	bool isBulkFetchProcessingComplete() const;
 	void setAllFoldersFetched();
 
-	void addRequestAtFront(const LLUUID & id, BOOL recursive, bool is_category);
-	void addRequestAtBack(const LLUUID & id, BOOL recursive, bool is_category);
+	void addRequestAtFront(const LLUUID & id, bool recursive, bool is_category);
+	void addRequestAtBack(const LLUUID & id, bool recursive, bool is_category);
 
 protected:
+
+    struct FetchQueueInfo
+    {
+        FetchQueueInfo(const LLUUID& id, bool recursive, bool is_category = true)
+            : mUUID(id),
+            mIsCategory(is_category),
+            mRecursive(recursive)
+        {}
+
+        LLUUID mUUID;
+        bool mIsCategory;
+        bool mRecursive;
+    };
+    typedef std::deque<FetchQueueInfo> fetch_queue_t;
+
+    void bulkFetchViaAis();
+    void bulkFetchViaAis(const FetchQueueInfo& fetch_info);
 	void bulkFetch();
 
 	void backgroundFetch();
@@ -80,31 +97,19 @@ protected:
 	bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const;
 
 private:
- 	BOOL mRecursiveInventoryFetchStarted;
-	BOOL mRecursiveLibraryFetchStarted;
-	BOOL mAllFoldersFetched;
+ 	bool mRecursiveInventoryFetchStarted;
+	bool mRecursiveLibraryFetchStarted;
+	bool mAllFoldersFetched;
 
-	BOOL mBackgroundFetchActive;
+    bool mBackgroundFetchActive;
 	bool mFolderFetchActive;
 	S32 mFetchCount;
 
 	LLFrameTimer mFetchTimer;
 	F32 mMinTimeBetweenFetches;
-
-	struct FetchQueueInfo
-	{
-		FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true)
-			: mUUID(id),
-			  mIsCategory(is_category),
-			  mRecursive(recursive)
-		{}
-		
-		LLUUID mUUID;
-		bool mIsCategory;
-		BOOL mRecursive;
-	};
-	typedef std::deque<FetchQueueInfo> fetch_queue_t;
 	fetch_queue_t mFetchQueue;
+    fetch_queue_t mRecursiveFetchQueue;
+
 };
 
 #endif // LL_LLINVENTORYMODELBACKGROUNDFETCH_H
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 776b9f8279..842192a62b 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1897,6 +1897,7 @@ bool idle_startup()
 			LLNotificationsUtil::add("InventoryUnusable");
 		}
 		
+        LLInventoryModelBackgroundFetch::instance().start();
 		gInventory.createCommonSystemCategories();
 
 		// It's debatable whether this flag is a good idea - sets all
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index 6f7c5d96f5..61123e65d7 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -667,7 +667,7 @@ bool LLViewerInventoryCategory::fetch()
 		{
 			LL_WARNS(LOG_INV) << "agent region is null" << LL_ENDL;
 		}
-		if (!url.empty()) //Capability found.  Build up LLSD and use it.
+		if (!url.empty() || AISAPI::isAvailable())
 		{
 			LLInventoryModelBackgroundFetch::instance().start(mUUID, false);			
 		}
-- 
cgit v1.2.3