llinventorymodel.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:112k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llinventorymodel.cpp
  3.  * @brief Implementation of the inventory model used to track agent inventory.
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llinventorymodel.h"
  34. #include "llagent.h"
  35. #include "llagentwearables.h"
  36. #include "llinventorypanel.h"
  37. #include "llinventorybridge.h"
  38. #include "llinventoryfunctions.h"
  39. #include "llinventoryobserver.h"
  40. #include "llinventorypanel.h"
  41. #include "llnotificationsutil.h"
  42. #include "llwindow.h"
  43. #include "llviewercontrol.h"
  44. #include "llpreview.h" 
  45. #include "llviewermessage.h"
  46. #include "llviewerfoldertype.h"
  47. #include "llviewerwindow.h"
  48. #include "llappviewer.h"
  49. #include "llviewerregion.h"
  50. #include "llcallbacklist.h"
  51. #include "llvoavatarself.h"
  52. //#define DIFF_INVENTORY_FILES
  53. #ifdef DIFF_INVENTORY_FILES
  54. #include "process.h"
  55. #endif
  56. BOOL LLInventoryModel::sBackgroundFetchActive = FALSE;
  57. BOOL LLInventoryModel::sAllFoldersFetched = FALSE;
  58. BOOL LLInventoryModel::sMyInventoryFetchStarted = FALSE;
  59. BOOL LLInventoryModel::sLibraryFetchStarted = FALSE;
  60. S32  LLInventoryModel::sNumFetchRetries = 0;
  61. F32  LLInventoryModel::sMinTimeBetweenFetches = 0.3f;
  62. F32  LLInventoryModel::sMaxTimeBetweenFetches = 10.f;
  63. BOOL LLInventoryModel::sTimelyFetchPending = FALSE;
  64. LLFrameTimer LLInventoryModel::sFetchTimer;
  65. S16 LLInventoryModel::sBulkFetchCount = 0;
  66. BOOL LLInventoryModel::sFirstTimeInViewer2 = TRUE;
  67. // Increment this if the inventory contents change in a non-backwards-compatible way.
  68. // For viewer 2, the addition of link items makes a pre-viewer-2 cache incorrect.
  69. const S32 LLInventoryModel::sCurrentInvCacheVersion = 2;
  70. // RN: for some reason, using std::queue in the header file confuses the compiler which things it's an xmlrpc_queue
  71. static std::deque<LLUUID> sFetchQueue;
  72. ///----------------------------------------------------------------------------
  73. /// Local function declarations, constants, enums, and typedefs
  74. ///----------------------------------------------------------------------------
  75. //BOOL decompress_file(const char* src_filename, const char* dst_filename);
  76. const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
  77. const S32 MAX_FETCH_RETRIES = 10;
  78. const char CACHE_FORMAT_STRING[] = "%s.inv"; 
  79. struct InventoryIDPtrLess
  80. {
  81. bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const
  82. {
  83. return (i1->getUUID() < i2->getUUID());
  84. }
  85. };
  86. class LLCanCache : public LLInventoryCollectFunctor 
  87. {
  88. public:
  89. LLCanCache(LLInventoryModel* model) : mModel(model) {}
  90. virtual ~LLCanCache() {}
  91. virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
  92. protected:
  93. LLInventoryModel* mModel;
  94. std::set<LLUUID> mCachedCatIDs;
  95. };
  96. bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  97. {
  98. bool rv = false;
  99. if(item)
  100. {
  101. if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end())
  102. {
  103. rv = true;
  104. }
  105. }
  106. else if(cat)
  107. {
  108. // HACK: downcast
  109. LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat;
  110. if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
  111. {
  112. S32 descendents_server = c->getDescendentCount();
  113. LLInventoryModel::cat_array_t* cats;
  114. LLInventoryModel::item_array_t* items;
  115. mModel->getDirectDescendentsOf(
  116. c->getUUID(),
  117. cats,
  118. items);
  119. S32 descendents_actual = 0;
  120. if(cats && items)
  121. {
  122. descendents_actual = cats->count() + items->count();
  123. }
  124. if(descendents_server == descendents_actual)
  125. {
  126. mCachedCatIDs.insert(c->getUUID());
  127. rv = true;
  128. }
  129. }
  130. }
  131. return rv;
  132. }
  133. ///----------------------------------------------------------------------------
  134. /// Class LLInventoryModel
  135. ///----------------------------------------------------------------------------
  136. // global for the agent inventory.
  137. LLInventoryModel gInventory;
  138. // Default constructor
  139. LLInventoryModel::LLInventoryModel()
  140. : mModifyMask(LLInventoryObserver::ALL),
  141. mChangedItemIDs(),
  142. mCategoryMap(),
  143. mItemMap(),
  144. mCategoryLock(),
  145. mItemLock(),
  146. mLastItem(NULL),
  147. mParentChildCategoryTree(),
  148. mParentChildItemTree(),
  149. mObservers(),
  150. mRootFolderID(),
  151. mLibraryRootFolderID(),
  152. mLibraryOwnerID(),
  153. mIsNotifyObservers(FALSE),
  154. mIsAgentInvUsable(false)
  155. {
  156. }
  157. // Destroys the object
  158. LLInventoryModel::~LLInventoryModel()
  159. {
  160. cleanupInventory();
  161. }
  162. void LLInventoryModel::cleanupInventory()
  163. {
  164. empty();
  165. // Deleting one observer might erase others from the list, so always pop off the front
  166. while (!mObservers.empty())
  167. {
  168. observer_list_t::iterator iter = mObservers.begin();
  169. LLInventoryObserver* observer = *iter;
  170. mObservers.erase(iter);
  171. delete observer;
  172. }
  173. mObservers.clear();
  174. }
  175. // This is a convenience function to check if one object has a parent
  176. // chain up to the category specified by UUID.
  177. BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id,
  178. const LLUUID& cat_id) const
  179. {
  180. if (obj_id == cat_id) return TRUE;
  181. const LLInventoryObject* obj = getObject(obj_id);
  182. while(obj)
  183. {
  184. const LLUUID& parent_id = obj->getParentUUID();
  185. if( parent_id.isNull() )
  186. {
  187. return FALSE;
  188. }
  189. if(parent_id == cat_id)
  190. {
  191. return TRUE;
  192. }
  193. // Since we're scanning up the parents, we only need to check
  194. // in the category list.
  195. obj = getCategory(parent_id);
  196. }
  197. return FALSE;
  198. }
  199. const LLViewerInventoryCategory *LLInventoryModel::getFirstNondefaultParent(const LLUUID& obj_id) const
  200. {
  201. const LLInventoryObject* obj = getObject(obj_id);
  202. // Search up the parent chain until we get to root or an acceptable folder.
  203. // This assumes there are no cycles in the tree else we'll get a hang.
  204. LLUUID parent_id = obj->getParentUUID();
  205. while (!parent_id.isNull())
  206. {
  207. const LLViewerInventoryCategory *cat = getCategory(parent_id);
  208. if (!cat) break;
  209. const LLFolderType::EType folder_type = cat->getPreferredType();
  210. if (folder_type != LLFolderType::FT_NONE &&
  211. folder_type != LLFolderType::FT_ROOT_INVENTORY &&
  212. !LLFolderType::lookupIsEnsembleType(folder_type))
  213. {
  214. return cat;
  215. }
  216. parent_id = cat->getParentUUID();
  217. }
  218. return NULL;
  219. }
  220. // Get the object by id. Returns NULL if not found.
  221. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const
  222. {
  223. LLViewerInventoryCategory* cat = getCategory(id);
  224. if (cat)
  225. {
  226. return cat;
  227. }
  228. LLViewerInventoryItem* item = getItem(id);
  229. if (item)
  230. {
  231. return item;
  232. }
  233. return NULL;
  234. }
  235. // Get the item by id. Returns NULL if not found.
  236. LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const
  237. {
  238. LLViewerInventoryItem* item = NULL;
  239. if(mLastItem.notNull() && mLastItem->getUUID() == id)
  240. {
  241. item = mLastItem;
  242. }
  243. else
  244. {
  245. item_map_t::const_iterator iter = mItemMap.find(id);
  246. if (iter != mItemMap.end())
  247. {
  248. item = iter->second;
  249. mLastItem = item;
  250. }
  251. }
  252. return item;
  253. }
  254. // Get the category by id. Returns NULL if not found
  255. LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const
  256. {
  257. LLViewerInventoryCategory* category = NULL;
  258. cat_map_t::const_iterator iter = mCategoryMap.find(id);
  259. if (iter != mCategoryMap.end())
  260. {
  261. category = iter->second;
  262. }
  263. return category;
  264. }
  265. S32 LLInventoryModel::getItemCount() const
  266. {
  267. return mItemMap.size();
  268. }
  269. S32 LLInventoryModel::getCategoryCount() const
  270. {
  271. return mCategoryMap.size();
  272. }
  273. // Return the direct descendents of the id provided. The array
  274. // provided points straight into the guts of this object, and
  275. // should only be used for read operations, since modifications
  276. // may invalidate the internal state of the inventory. Set passed
  277. // in values to NULL if the call fails.
  278. void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id,
  279.   cat_array_t*& categories,
  280.   item_array_t*& items) const
  281. {
  282. categories = get_ptr_in_map(mParentChildCategoryTree, cat_id);
  283. items = get_ptr_in_map(mParentChildItemTree, cat_id);
  284. }
  285. // SJB: Added version to lock the arrays to catch potential logic bugs
  286. void LLInventoryModel::lockDirectDescendentArrays(const LLUUID& cat_id,
  287.   cat_array_t*& categories,
  288.   item_array_t*& items)
  289. {
  290. getDirectDescendentsOf(cat_id, categories, items);
  291. if (categories)
  292. {
  293. mCategoryLock[cat_id] = true;
  294. }
  295. if (items)
  296. {
  297. mItemLock[cat_id] = true;
  298. }
  299. }
  300. void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id)
  301. {
  302. mCategoryLock[cat_id] = false;
  303. mItemLock[cat_id] = false;
  304. }
  305. // findCategoryUUIDForType() returns the uuid of the category that
  306. // specifies 'type' as what it defaults to containing. The category is
  307. // not necessarily only for that type. *NOTE: This will create a new
  308. // inventory category on the fly if one does not exist.
  309. const LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType t, bool create_folder, bool find_in_library)
  310. {
  311. const LLUUID &rv = findCatUUID(t, find_in_library);
  312. if(rv.isNull() && isInventoryUsable() && (create_folder && !find_in_library))
  313. {
  314. const LLUUID &root_id = gInventory.getRootFolderID();
  315. if(root_id.notNull())
  316. {
  317. return createNewCategory(root_id, t, LLStringUtil::null);
  318. }
  319. }
  320. return rv;
  321. }
  322. // Internal method which looks for a category with the specified
  323. // preferred type. Returns LLUUID::null if not found.
  324. const LLUUID &LLInventoryModel::findCatUUID(LLFolderType::EType preferred_type, bool find_in_library) const
  325. {
  326. const LLUUID &root_id = (find_in_library) ? gInventory.getLibraryRootFolderID() : gInventory.getRootFolderID();
  327. if(LLFolderType::FT_ROOT_INVENTORY == preferred_type)
  328. {
  329. return root_id;
  330. }
  331. if(root_id.notNull())
  332. {
  333. cat_array_t* cats = NULL;
  334. cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
  335. if(cats)
  336. {
  337. S32 count = cats->count();
  338. for(S32 i = 0; i < count; ++i)
  339. {
  340. if(cats->get(i)->getPreferredType() == preferred_type)
  341. {
  342. return cats->get(i)->getUUID();
  343. }
  344. }
  345. }
  346. }
  347. return LLUUID::null;
  348. }
  349. // Convenience function to create a new category. You could call
  350. // updateCategory() with a newly generated UUID category, but this
  351. // version will take care of details like what the name should be
  352. // based on preferred type. Returns the UUID of the new category.
  353. LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
  354.    LLFolderType::EType preferred_type,
  355.    const std::string& pname)
  356. {
  357. LLUUID id;
  358. if(!isInventoryUsable())
  359. {
  360. llwarns << "Inventory is broken." << llendl;
  361. return id;
  362. }
  363. if(LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())
  364. {
  365. lldebugs << "Attempt to create undefined category." << llendl;
  366. return id;
  367. }
  368. id.generate();
  369. std::string name = pname;
  370. if(!pname.empty())
  371. {
  372. name.assign(pname);
  373. }
  374. else
  375. {
  376. name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
  377. }
  378. // Add the category to the internal representation
  379. LLPointer<LLViewerInventoryCategory> cat =
  380. new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
  381. cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL);
  382. cat->setDescendentCount(0);
  383. LLCategoryUpdate update(cat->getParentUUID(), 1);
  384. accountForUpdate(update);
  385. updateCategory(cat);
  386. // Create the category on the server. We do this to prevent people
  387. // from munging their protected folders.
  388. LLMessageSystem* msg = gMessageSystem;
  389. msg->newMessage("CreateInventoryFolder");
  390. msg->nextBlock("AgentData");
  391. msg->addUUID("AgentID", gAgent.getID());
  392. msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
  393. msg->nextBlock("FolderData");
  394. cat->packMessage(msg);
  395. gAgent.sendReliableMessage();
  396. // return the folder id of the newly created folder
  397. return id;
  398. }
  399. // Starting with the object specified, add it's descendents to the
  400. // array provided, but do not add the inventory object specified by
  401. // id. There is no guaranteed order. Neither array will be erased
  402. // before adding objects to it. Do not store a copy of the pointers
  403. // collected - use them, and collect them again later if you need to
  404. // reference the same objects.
  405. class LLAlwaysCollect : public LLInventoryCollectFunctor
  406. {
  407. public:
  408. virtual ~LLAlwaysCollect() {}
  409. virtual bool operator()(LLInventoryCategory* cat,
  410. LLInventoryItem* item)
  411. {
  412. return TRUE;
  413. }
  414. };
  415. void LLInventoryModel::collectDescendents(const LLUUID& id,
  416.   cat_array_t& cats,
  417.   item_array_t& items,
  418.   BOOL include_trash)
  419. {
  420. LLAlwaysCollect always;
  421. collectDescendentsIf(id, cats, items, include_trash, always);
  422. }
  423. void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
  424. cat_array_t& cats,
  425. item_array_t& items,
  426. BOOL include_trash,
  427. LLInventoryCollectFunctor& add,
  428. BOOL follow_folder_links)
  429. {
  430. // Start with categories
  431. if(!include_trash)
  432. {
  433. const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH);
  434. if(trash_id.notNull() && (trash_id == id))
  435. return;
  436. }
  437. cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id);
  438. if(cat_array)
  439. {
  440. S32 count = cat_array->count();
  441. for(S32 i = 0; i < count; ++i)
  442. {
  443. LLViewerInventoryCategory* cat = cat_array->get(i);
  444. if(add(cat,NULL))
  445. {
  446. cats.put(cat);
  447. }
  448. collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add);
  449. }
  450. }
  451. LLViewerInventoryItem* item = NULL;
  452. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
  453. // Follow folder links recursively.  Currently never goes more
  454. // than one level deep (for current outfit support)
  455. // Note: if making it fully recursive, need more checking against infinite loops.
  456. if (follow_folder_links && item_array)
  457. {
  458. S32 count = item_array->count();
  459. for(S32 i = 0; i < count; ++i)
  460. {
  461. item = item_array->get(i);
  462. if (item->getActualType() == LLAssetType::AT_LINK_FOLDER)
  463. {
  464. LLViewerInventoryCategory *linked_cat = item->getLinkedCategory();
  465. if (linked_cat && linked_cat->getPreferredType() != LLFolderType::FT_OUTFIT)
  466. // BAP - was 
  467. // LLAssetType::lookupIsEnsembleCategoryType(linked_cat->getPreferredType()))
  468. // Change back once ensemble typing is in place.
  469. {
  470. if(add(linked_cat,NULL))
  471. {
  472. // BAP should this be added here?  May not
  473. // matter if it's only being used in current
  474. // outfit traversal.
  475. cats.put(LLPointer<LLViewerInventoryCategory>(linked_cat));
  476. }
  477. collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE);
  478. }
  479. }
  480. }
  481. }
  482. // Move onto items
  483. if(item_array)
  484. {
  485. S32 count = item_array->count();
  486. for(S32 i = 0; i < count; ++i)
  487. {
  488. item = item_array->get(i);
  489. if(add(NULL, item))
  490. {
  491. items.put(item);
  492. }
  493. }
  494. }
  495. }
  496. void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask)
  497. {
  498. const LLInventoryObject *obj = getObject(object_id);
  499. if (!obj || obj->getIsLinkType())
  500. return;
  501. LLInventoryModel::cat_array_t cat_array;
  502. LLInventoryModel::item_array_t item_array;
  503. LLLinkedItemIDMatches is_linked_item_match(object_id);
  504. collectDescendentsIf(gInventory.getRootFolderID(),
  505.  cat_array,
  506.  item_array,
  507.  LLInventoryModel::INCLUDE_TRASH,
  508.  is_linked_item_match);
  509. if (cat_array.empty() && item_array.empty())
  510. {
  511. return;
  512. }
  513. for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin();
  514.  cat_iter != cat_array.end();
  515.  cat_iter++)
  516. {
  517. LLViewerInventoryCategory *linked_cat = (*cat_iter);
  518. addChangedMask(mask, linked_cat->getUUID());
  519. };
  520. for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();
  521.  iter != item_array.end();
  522.  iter++)
  523. {
  524. LLViewerInventoryItem *linked_item = (*iter);
  525. addChangedMask(mask, linked_item->getUUID());
  526. };
  527. }
  528. const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const
  529. {
  530. const LLInventoryItem *item = gInventory.getItem(object_id);
  531. if (!item)
  532. {
  533. return object_id;
  534. }
  535. // Find the base item in case this a link (if it's not a link,
  536. // this will just be inv_item_id)
  537. return item->getLinkedUUID();
  538. }
  539. LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id,
  540. const LLUUID& start_folder_id)
  541. {
  542. item_array_t items;
  543. LLInventoryModel::cat_array_t cat_array;
  544. LLLinkedItemIDMatches is_linked_item_match(id);
  545. collectDescendentsIf((start_folder_id == LLUUID::null ? gInventory.getRootFolderID() : start_folder_id),
  546.  cat_array,
  547.  items,
  548.  LLInventoryModel::INCLUDE_TRASH,
  549.  is_linked_item_match);
  550. return items;
  551. }
  552. // Generates a string containing the path to the item specified by
  553. // item_id.
  554. void LLInventoryModel::appendPath(const LLUUID& id, std::string& path) const
  555. {
  556. std::string temp;
  557. const LLInventoryObject* obj = getObject(id);
  558. LLUUID parent_id;
  559. if(obj) parent_id = obj->getParentUUID();
  560. std::string forward_slash("/");
  561. while(obj)
  562. {
  563. obj = getCategory(parent_id);
  564. if(obj)
  565. {
  566. temp.assign(forward_slash + obj->getName() + temp);
  567. parent_id = obj->getParentUUID();
  568. }
  569. }
  570. path.append(temp);
  571. }
  572. bool LLInventoryModel::isInventoryUsable() const
  573. {
  574. bool result = false;
  575. if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable)
  576. {
  577. result = true;
  578. }
  579. return result;
  580. }
  581. // Calling this method with an inventory item will either change an
  582. // existing item with a matching item_id, or will add the item to the
  583. // current inventory.
  584. U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item)
  585. {
  586. U32 mask = LLInventoryObserver::NONE;
  587. if(item->getUUID().isNull())
  588. {
  589. return mask;
  590. }
  591. if(!isInventoryUsable())
  592. {
  593. llwarns << "Inventory is broken." << llendl;
  594. return mask;
  595. }
  596. LLViewerInventoryItem* old_item = getItem(item->getUUID());
  597. LLPointer<LLViewerInventoryItem> new_item;
  598. if(old_item)
  599. {
  600. // We already have an old item, modify its values
  601. new_item = old_item;
  602. LLUUID old_parent_id = old_item->getParentUUID();
  603. LLUUID new_parent_id = item->getParentUUID();
  604. if(old_parent_id != new_parent_id)
  605. {
  606. // need to update the parent-child tree
  607. item_array_t* item_array;
  608. item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id);
  609. if(item_array)
  610. {
  611. item_array->removeObj(old_item);
  612. }
  613. item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id);
  614. if(item_array)
  615. {
  616. item_array->put(old_item);
  617. }
  618. mask |= LLInventoryObserver::STRUCTURE;
  619. }
  620. if(old_item->getName() != item->getName())
  621. {
  622. mask |= LLInventoryObserver::LABEL;
  623. }
  624. old_item->copyViewerItem(item);
  625. mask |= LLInventoryObserver::INTERNAL;
  626. }
  627. else
  628. {
  629. // Simply add this item
  630. new_item = new LLViewerInventoryItem(item);
  631. addItem(new_item);
  632. if(item->getParentUUID().isNull())
  633. {
  634. const LLUUID category_id = findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(new_item->getType()));
  635. new_item->setParent(category_id);
  636. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id);
  637. if( item_array )
  638. {
  639. // *FIX: bit of a hack to call update server from here...
  640. new_item->updateServer(TRUE);
  641. item_array->put(new_item);
  642. }
  643. else
  644. {
  645. llwarns << "Couldn't find parent-child item tree for " << new_item->getName() << llendl;
  646. }
  647. }
  648. else
  649. {
  650. // *NOTE: The general scheme is that if every byte of the
  651. // uuid is 0, except for the last one or two,the use the
  652. // last two bytes of the parent id, and match that up
  653. // against the type. For now, we're only worried about
  654. // lost & found.
  655. LLUUID parent_id = item->getParentUUID();
  656. if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID)
  657. {
  658. parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
  659. new_item->setParent(parent_id);
  660. }
  661. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id);
  662. if(item_array)
  663. {
  664. item_array->put(new_item);
  665. }
  666. else
  667. {
  668. // Whoops! No such parent, make one.
  669. llinfos << "Lost item: " << new_item->getUUID() << " - "
  670. << new_item->getName() << llendl;
  671. parent_id = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
  672. new_item->setParent(parent_id);
  673. item_array = get_ptr_in_map(mParentChildItemTree, parent_id);
  674. if(item_array)
  675. {
  676. // *FIX: bit of a hack to call update server from
  677. // here...
  678. new_item->updateServer(TRUE);
  679. item_array->put(new_item);
  680. }
  681. else
  682. {
  683. llwarns << "Lost and found Not there!!" << llendl;
  684. }
  685. }
  686. }
  687. mask |= LLInventoryObserver::ADD;
  688. }
  689. if(new_item->getType() == LLAssetType::AT_CALLINGCARD)
  690. {
  691. mask |= LLInventoryObserver::CALLING_CARD;
  692. // Handle user created calling cards.
  693. // Target ID is stored in the description field of the card.
  694. LLUUID id;
  695. std::string desc = new_item->getDescription();
  696. BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE);
  697. if (isId)
  698. {
  699. // Valid UUID; set the item UUID and rename it
  700. new_item->setCreator(id);
  701. std::string avatar_name;
  702. // Fetch the currect name
  703. gCacheName->get(id, FALSE, boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), _1, _2, _3));
  704. }
  705. }
  706. else if (new_item->getType() == LLAssetType::AT_GESTURE)
  707. {
  708. mask |= LLInventoryObserver::GESTURE;
  709. }
  710. addChangedMask(mask, new_item->getUUID());
  711. return mask;
  712. }
  713. LLInventoryModel::cat_array_t* LLInventoryModel::getUnlockedCatArray(const LLUUID& id)
  714. {
  715. cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id);
  716. if (cat_array)
  717. {
  718. llassert_always(mCategoryLock[id] == false);
  719. }
  720. return cat_array;
  721. }
  722. LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLUUID& id)
  723. {
  724. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
  725. if (item_array)
  726. {
  727. llassert_always(mItemLock[id] == false);
  728. }
  729. return item_array;
  730. }
  731. // Calling this method with an inventory category will either change
  732. // an existing item with the matching id, or it will add the category.
  733. void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat)
  734. {
  735. if(cat->getUUID().isNull())
  736. {
  737. return;
  738. }
  739. if(!isInventoryUsable())
  740. {
  741. llwarns << "Inventory is broken." << llendl;
  742. return;
  743. }
  744. LLViewerInventoryCategory* old_cat = getCategory(cat->getUUID());
  745. if(old_cat)
  746. {
  747. // We already have an old category, modify it's values
  748. U32 mask = LLInventoryObserver::NONE;
  749. LLUUID old_parent_id = old_cat->getParentUUID();
  750. LLUUID new_parent_id = cat->getParentUUID();
  751. if(old_parent_id != new_parent_id)
  752. {
  753. // need to update the parent-child tree
  754. cat_array_t* cat_array;
  755. cat_array = getUnlockedCatArray(old_parent_id);
  756. if(cat_array)
  757. {
  758. cat_array->removeObj(old_cat);
  759. }
  760. cat_array = getUnlockedCatArray(new_parent_id);
  761. if(cat_array)
  762. {
  763. cat_array->put(old_cat);
  764. }
  765. mask |= LLInventoryObserver::STRUCTURE;
  766. }
  767. if(old_cat->getName() != cat->getName())
  768. {
  769. mask |= LLInventoryObserver::LABEL;
  770. }
  771. old_cat->copyViewerCategory(cat);
  772. addChangedMask(mask, cat->getUUID());
  773. }
  774. else
  775. {
  776. // add this category
  777. LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat->getParentUUID());
  778. new_cat->copyViewerCategory(cat);
  779. addCategory(new_cat);
  780. // make sure this category is correctly referenced by it's parent.
  781. cat_array_t* cat_array;
  782. cat_array = getUnlockedCatArray(cat->getParentUUID());
  783. if(cat_array)
  784. {
  785. cat_array->put(new_cat);
  786. }
  787. // make space in the tree for this category's children.
  788. llassert_always(mCategoryLock[new_cat->getUUID()] == false);
  789. llassert_always(mItemLock[new_cat->getUUID()] == false);
  790. cat_array_t* catsp = new cat_array_t;
  791. item_array_t* itemsp = new item_array_t;
  792. mParentChildCategoryTree[new_cat->getUUID()] = catsp;
  793. mParentChildItemTree[new_cat->getUUID()] = itemsp;
  794. addChangedMask(LLInventoryObserver::ADD, cat->getUUID());
  795. }
  796. }
  797. void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id)
  798. {
  799. lldebugs << "LLInventoryModel::moveObject()" << llendl;
  800. if(!isInventoryUsable())
  801. {
  802. llwarns << "Inventory is broken." << llendl;
  803. return;
  804. }
  805. if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id))
  806. {
  807. llwarns << "Could not move inventory object " << object_id << " to "
  808. << cat_id << llendl;
  809. return;
  810. }
  811. LLViewerInventoryCategory* cat = getCategory(object_id);
  812. if(cat && (cat->getParentUUID() != cat_id))
  813. {
  814. cat_array_t* cat_array;
  815. cat_array = getUnlockedCatArray(cat->getParentUUID());
  816. if(cat_array) cat_array->removeObj(cat);
  817. cat_array = getUnlockedCatArray(cat_id);
  818. cat->setParent(cat_id);
  819. if(cat_array) cat_array->put(cat);
  820. addChangedMask(LLInventoryObserver::STRUCTURE, object_id);
  821. return;
  822. }
  823. LLViewerInventoryItem* item = getItem(object_id);
  824. if(item && (item->getParentUUID() != cat_id))
  825. {
  826. item_array_t* item_array;
  827. item_array = getUnlockedItemArray(item->getParentUUID());
  828. if(item_array) item_array->removeObj(item);
  829. item_array = getUnlockedItemArray(cat_id);
  830. item->setParent(cat_id);
  831. if(item_array) item_array->put(item);
  832. addChangedMask(LLInventoryObserver::STRUCTURE, object_id);
  833. return;
  834. }
  835. }
  836. // Delete a particular inventory object by ID.
  837. void LLInventoryModel::deleteObject(const LLUUID& id)
  838. {
  839. lldebugs << "LLInventoryModel::deleteObject()" << llendl;
  840. LLPointer<LLInventoryObject> obj = getObject(id);
  841. if (!obj) 
  842. {
  843. llwarns << "Deleting non-existent object [ id: " << id << " ] " << llendl;
  844. return;
  845. }
  846. lldebugs << "Deleting inventory object " << id << llendl;
  847. mLastItem = NULL;
  848. LLUUID parent_id = obj->getParentUUID();
  849. mCategoryMap.erase(id);
  850. mItemMap.erase(id);
  851. //mInventory.erase(id);
  852. item_array_t* item_list = getUnlockedItemArray(parent_id);
  853. if(item_list)
  854. {
  855. LLViewerInventoryItem* item = (LLViewerInventoryItem*)((LLInventoryObject*)obj);
  856. item_list->removeObj(item);
  857. }
  858. cat_array_t* cat_list = getUnlockedCatArray(parent_id);
  859. if(cat_list)
  860. {
  861. LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj);
  862. cat_list->removeObj(cat);
  863. }
  864. item_list = getUnlockedItemArray(id);
  865. if(item_list)
  866. {
  867. delete item_list;
  868. mParentChildItemTree.erase(id);
  869. }
  870. cat_list = getUnlockedCatArray(id);
  871. if(cat_list)
  872. {
  873. delete cat_list;
  874. mParentChildCategoryTree.erase(id);
  875. }
  876. addChangedMask(LLInventoryObserver::REMOVE, id);
  877. obj = NULL; // delete obj
  878. updateLinkedObjectsFromPurge(id);
  879. gInventory.notifyObservers();
  880. }
  881. // Delete a particular inventory item by ID, and remove it from the server.
  882. void LLInventoryModel::purgeObject(const LLUUID &id)
  883. {
  884. lldebugs << "LLInventoryModel::purgeObject() [ id: " << id << " ] " << llendl;
  885. LLPointer<LLInventoryObject> obj = getObject(id);
  886. if(obj)
  887. {
  888. obj->removeFromServer();
  889. LLPreview::hide(id);
  890. deleteObject(id);
  891. }
  892. }
  893. void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID &baseobj_id)
  894. {
  895. LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id);
  896. // REBUILD is expensive, so clear the current change list first else
  897. // everything else on the changelist will also get rebuilt.
  898. gInventory.notifyObservers();
  899. for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
  900.  iter != item_array.end();
  901.  iter++)
  902. {
  903. const LLViewerInventoryItem *linked_item = (*iter);
  904. const LLUUID &item_id = linked_item->getUUID();
  905. if (item_id == baseobj_id) continue;
  906. addChangedMask(LLInventoryObserver::REBUILD, item_id);
  907. }
  908. gInventory.notifyObservers();
  909. }
  910. // This is a method which collects the descendents of the id
  911. // provided. If the category is not found, no action is
  912. // taken. This method goes through the long winded process of
  913. // cancelling any calling cards, removing server representation of
  914. // folders, items, etc in a fairly efficient manner.
  915. void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
  916. {
  917. EHasChildren children = categoryHasChildren(id);
  918. if(children == CHILDREN_NO)
  919. {
  920. llinfos << "Not purging descendents of " << id << llendl;
  921. return;
  922. }
  923. LLPointer<LLViewerInventoryCategory> cat = getCategory(id);
  924. if(cat.notNull())
  925. {
  926. // do the cache accounting
  927. llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
  928. << llendl;
  929. S32 descendents = cat->getDescendentCount();
  930. if(descendents > 0)
  931. {
  932. LLCategoryUpdate up(id, -descendents);
  933. accountForUpdate(up);
  934. }
  935. // we know that descendent count is 0, aide since the
  936. // accounting may actually not do an update, we should force
  937. // it here.
  938. cat->setDescendentCount(0);
  939. // send it upstream
  940. LLMessageSystem* msg = gMessageSystem;
  941. msg->newMessage("PurgeInventoryDescendents");
  942. msg->nextBlock("AgentData");
  943. msg->addUUID("AgentID", gAgent.getID());
  944. msg->addUUID("SessionID", gAgent.getSessionID());
  945. msg->nextBlock("InventoryData");
  946. msg->addUUID("FolderID", id);
  947. gAgent.sendReliableMessage();
  948. // unceremoniously remove anything we have locally stored.
  949. cat_array_t categories;
  950. item_array_t items;
  951. collectDescendents(id,
  952.    categories,
  953.    items,
  954.    INCLUDE_TRASH);
  955. S32 count = items.count();
  956. S32 i;
  957. for(i = 0; i < count; ++i)
  958. {
  959. deleteObject(items.get(i)->getUUID());
  960. }
  961. count = categories.count();
  962. for(i = 0; i < count; ++i)
  963. {
  964. deleteObject(categories.get(i)->getUUID());
  965. }
  966. }
  967. }
  968. void LLInventoryModel::deleteFromServer(LLDynamicArray<LLUUID>& category_ids,
  969. LLDynamicArray<LLUUID>& item_ids)
  970. {
  971. // Store off tre UUIDS of parents which are being deleted (thus no
  972. // need to increment) and the parents which are being modified. We
  973. // have to increment the version of the parent with each message
  974. // sent upstream since the dataserver will increment each unique
  975. // parent per update message.
  976. std::set<LLUUID> ignore_parents;
  977. update_map_t inc_parents;
  978. S32 i;
  979. S32 count = category_ids.count();
  980. BOOL start_new_message = TRUE;
  981. LLMessageSystem* msg = gMessageSystem;
  982. LLPointer<LLViewerInventoryCategory> cat;
  983. for(i = 0; i < count; i++)
  984. {
  985. if(start_new_message)
  986. {
  987. start_new_message = FALSE;
  988. msg->newMessageFast(_PREHASH_RemoveInventoryObjects);
  989. msg->nextBlockFast(_PREHASH_AgentData);
  990. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  991. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  992. }
  993. LLUUID cat_id = category_ids.get(i);
  994. msg->nextBlockFast(_PREHASH_FolderData);
  995. msg->addUUIDFast(_PREHASH_FolderID, cat_id);
  996. cat = getCategory(cat_id);
  997. ignore_parents.insert(cat_id);
  998. addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, cat_id);
  999. if(cat.notNull() && (ignore_parents.find(cat->getParentUUID())==ignore_parents.end()))
  1000. {
  1001. --inc_parents[cat->getParentUUID()];
  1002. }
  1003. if(msg->isSendFullFast(_PREHASH_FolderData))
  1004. {
  1005. start_new_message = TRUE;
  1006. msg->nextBlockFast(_PREHASH_ItemData);
  1007. msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
  1008. gAgent.sendReliableMessage();
  1009. accountForUpdate(inc_parents);
  1010. inc_parents.clear();
  1011. }
  1012. }
  1013. count = item_ids.count();
  1014. std::set<LLUUID>::iterator not_ignored = ignore_parents.end();
  1015. LLPointer<LLViewerInventoryItem> item;
  1016. if((0 == count) && (!start_new_message))
  1017. {
  1018. msg->nextBlockFast(_PREHASH_ItemData);
  1019. msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
  1020. }
  1021. for(i = 0; i < count; i++)
  1022. {
  1023. if(start_new_message)
  1024. {
  1025. start_new_message = FALSE;
  1026. msg->newMessageFast(_PREHASH_RemoveInventoryObjects);
  1027. msg->nextBlockFast(_PREHASH_AgentData);
  1028. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  1029. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  1030. msg->nextBlockFast(_PREHASH_FolderData);
  1031. msg->addUUIDFast(_PREHASH_FolderID, LLUUID::null);
  1032. }
  1033. LLUUID item_id = item_ids.get(i);
  1034. msg->nextBlockFast(_PREHASH_ItemData);
  1035. msg->addUUIDFast(_PREHASH_ItemID, item_id);
  1036. item = getItem(item_id);
  1037. addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, item_id);
  1038. if(item.notNull() && (ignore_parents.find(item->getParentUUID()) == not_ignored))
  1039. {
  1040. --inc_parents[item->getParentUUID()];
  1041. }
  1042. if(msg->isSendFullFast(_PREHASH_ItemData))
  1043. {
  1044. start_new_message = TRUE;
  1045. gAgent.sendReliableMessage();
  1046. accountForUpdate(inc_parents);
  1047. inc_parents.clear();
  1048. }
  1049. }
  1050. if(!start_new_message)
  1051. {
  1052. gAgent.sendReliableMessage();
  1053. accountForUpdate(inc_parents);
  1054. }
  1055. }
  1056. // Add/remove an observer. If the observer is destroyed, be sure to
  1057. // remove it.
  1058. void LLInventoryModel::addObserver(LLInventoryObserver* observer)
  1059. {
  1060. mObservers.insert(observer);
  1061. }
  1062. void LLInventoryModel::removeObserver(LLInventoryObserver* observer)
  1063. {
  1064. mObservers.erase(observer);
  1065. }
  1066. BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer) const
  1067. {
  1068. return mObservers.find(observer) != mObservers.end();
  1069. }
  1070. void LLInventoryModel::idleNotifyObservers()
  1071. {
  1072. if (mModifyMask == LLInventoryObserver::NONE && (mChangedItemIDs.size() == 0))
  1073. {
  1074. return;
  1075. }
  1076. notifyObservers("");
  1077. }
  1078. // Call this method when it's time to update everyone on a new state.
  1079. // The optional argument 'service_name' is used by Agent Inventory Service [DEV-20328]
  1080. void LLInventoryModel::notifyObservers(const std::string service_name)
  1081. {
  1082. if (mIsNotifyObservers)
  1083. {
  1084. // Within notifyObservers, something called notifyObservers
  1085. // again.  This type of recursion is unsafe because it causes items to be 
  1086. // processed twice, and this can easily lead to infinite loops.
  1087. llwarns << "Call was made to notifyObservers within notifyObservers!" << llendl;
  1088. return;
  1089. }
  1090. mIsNotifyObservers = TRUE;
  1091. for (observer_list_t::iterator iter = mObservers.begin();
  1092.  iter != mObservers.end(); )
  1093. {
  1094. LLInventoryObserver* observer = *iter;
  1095. if (service_name.empty())
  1096. {
  1097. observer->changed(mModifyMask);
  1098. }
  1099. else
  1100. {
  1101. observer->mMessageName = service_name;
  1102. observer->changed(mModifyMask);
  1103. }
  1104. // safe way to increment since changed may delete entries! (@!##%@!@&*!)
  1105. iter = mObservers.upper_bound(observer); 
  1106. }
  1107. mModifyMask = LLInventoryObserver::NONE;
  1108. mChangedItemIDs.clear();
  1109. mIsNotifyObservers = FALSE;
  1110. }
  1111. // store flag for change
  1112. // and id of object change applies to
  1113. void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent) 
  1114. if (mIsNotifyObservers)
  1115. {
  1116. // Something marked an item for change within a call to notifyObservers
  1117. // (which is in the process of processing the list of items marked for change).
  1118. // This means the change may fail to be processed.
  1119. llwarns << "Adding changed mask within notify observers!  Change will likely be lost." << llendl;
  1120. }
  1121. mModifyMask |= mask; 
  1122. if (referent.notNull())
  1123. {
  1124. mChangedItemIDs.insert(referent);
  1125. }
  1126. // Update all linked items.  Starting with just LABEL because I'm
  1127. // not sure what else might need to be accounted for this.
  1128. if (mModifyMask & LLInventoryObserver::LABEL)
  1129. {
  1130. addChangedMaskForLinks(referent, LLInventoryObserver::LABEL);
  1131. }
  1132. }
  1133. // This method to prepares a set of mock inventory which provides
  1134. // minimal functionality before the actual arrival of inventory.
  1135. /*
  1136. void LLInventoryModel::mock(const LLUUID& root_id)
  1137. {
  1138. llinfos << "LLInventoryModel::mock() " << root_id << llendl;
  1139. if(root_id.isNull())
  1140. {
  1141. llwarns << "Not a valid root id" << llendl;
  1142. return;
  1143. }
  1144. LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(
  1145. root_id,
  1146. LLUUID::null,
  1147. LLAssetType::AT_CATEGORY,
  1148. LLFolderType::lookupNewCategoryName(LLFolderType::FT_ROOT_INVENTORY),
  1149. gAgent.getID());
  1150. addCategory(cat);
  1151. gInventory.buildParentChildMap();
  1152. }
  1153. */
  1154. //If we get back a normal response, handle it here
  1155. void  LLInventoryModel::fetchInventoryResponder::result(const LLSD& content)
  1156. {
  1157. start_new_inventory_observer();
  1158. /*LLUUID agent_id;
  1159. agent_id = content["agent_id"].asUUID();
  1160. if(agent_id != gAgent.getID())
  1161. {
  1162. llwarns << "Got a inventory update for the wrong agent: " << agent_id
  1163. << llendl;
  1164. return;
  1165. }*/
  1166. item_array_t items;
  1167. update_map_t update;
  1168. S32 count = content["items"].size();
  1169. bool all_one_folder = true;
  1170. LLUUID folder_id;
  1171. // Does this loop ever execute more than once?
  1172. for(S32 i = 0; i < count; ++i)
  1173. {
  1174. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  1175. titem->unpackMessage(content["items"][i]);
  1176. lldebugs << "LLInventoryModel::messageUpdateCore() item id:"
  1177.  << titem->getUUID() << llendl;
  1178. items.push_back(titem);
  1179. // examine update for changes.
  1180. LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID());
  1181. if(itemp)
  1182. {
  1183. if(titem->getParentUUID() == itemp->getParentUUID())
  1184. {
  1185. update[titem->getParentUUID()];
  1186. }
  1187. else
  1188. {
  1189. ++update[titem->getParentUUID()];
  1190. --update[itemp->getParentUUID()];
  1191. }
  1192. }
  1193. else
  1194. {
  1195. ++update[titem->getParentUUID()];
  1196. }
  1197. if (folder_id.isNull())
  1198. {
  1199. folder_id = titem->getParentUUID();
  1200. }
  1201. else
  1202. {
  1203. all_one_folder = false;
  1204. }
  1205. }
  1206. U32 changes = 0x0;
  1207. //as above, this loop never seems to loop more than once per call
  1208. for (item_array_t::iterator it = items.begin(); it != items.end(); ++it)
  1209. {
  1210. changes |= gInventory.updateItem(*it);
  1211. }
  1212. gInventory.notifyObservers("fetchinventory");
  1213. gViewerWindow->getWindow()->decBusyCount();
  1214. }
  1215. //If we get back an error (not found, etc...), handle it here
  1216. void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::string& reason)
  1217. {
  1218. llinfos << "fetchInventory::error "
  1219. << status << ": " << reason << llendl;
  1220. gInventory.notifyObservers("fetchinventory");
  1221. }
  1222. bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
  1223. {
  1224. if(folder_id.isNull()) 
  1225. {
  1226. llwarns << "Calling fetch descendents on NULL folder id!" << llendl;
  1227. return false;
  1228. }
  1229. LLViewerInventoryCategory* cat = getCategory(folder_id);
  1230. if(!cat)
  1231. {
  1232. llwarns << "Asked to fetch descendents of non-existent folder: "
  1233. << folder_id << llendl;
  1234. return false;
  1235. }
  1236. //S32 known_descendents = 0;
  1237. ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id);
  1238. //item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id);
  1239. //if(categories)
  1240. //{
  1241. // known_descendents += categories->count();
  1242. //}
  1243. //if(items)
  1244. //{
  1245. // known_descendents += items->count();
  1246. //}
  1247. return cat->fetchDescendents();
  1248. }
  1249. //Initialize statics.
  1250. bool LLInventoryModel::isBulkFetchProcessingComplete()
  1251. {
  1252. return sFetchQueue.empty() && sBulkFetchCount<=0;
  1253. }
  1254. class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder
  1255. {
  1256. public:
  1257. LLInventoryModelFetchDescendentsResponder(const LLSD& request_sd) : mRequestSD(request_sd) {};
  1258. //LLInventoryModelFetchDescendentsResponder() {};
  1259. void result(const LLSD& content);
  1260. void error(U32 status, const std::string& reason);
  1261. public:
  1262. typedef std::vector<LLViewerInventoryCategory*> folder_ref_t;
  1263. protected:
  1264. LLSD mRequestSD;
  1265. };
  1266. //If we get back a normal response, handle it here
  1267. void  LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
  1268. {
  1269. if (content.has("folders"))
  1270. {
  1271. for(LLSD::array_const_iterator folder_it = content["folders"].beginArray();
  1272. folder_it != content["folders"].endArray();
  1273. ++folder_it)
  1274. {
  1275. LLSD folder_sd = *folder_it;
  1276. //LLUUID agent_id = folder_sd["agent_id"];
  1277. //if(agent_id != gAgent.getID()) //This should never happen.
  1278. //{
  1279. // llwarns << "Got a UpdateInventoryItem for the wrong agent."
  1280. // << llendl;
  1281. // break;
  1282. //}
  1283. LLUUID parent_id = folder_sd["folder_id"];
  1284. LLUUID owner_id = folder_sd["owner_id"];
  1285. S32    version  = (S32)folder_sd["version"].asInteger();
  1286. S32    descendents = (S32)folder_sd["descendents"].asInteger();
  1287. LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
  1288.             if (parent_id.isNull())
  1289.             {
  1290.     LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  1291.     for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
  1292.     item_it != folder_sd["items"].endArray();
  1293.     ++item_it)
  1294.     {
  1295.                     const LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
  1296.                     if (lost_uuid.notNull())
  1297.                     {
  1298.         LLSD item = *item_it;
  1299.         titem->unpackMessage(item);
  1300.                         LLInventoryModel::update_list_t update;
  1301.                         LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1);
  1302.                         update.push_back(new_folder);
  1303.                         gInventory.accountForUpdate(update);
  1304.                         titem->setParent(lost_uuid);
  1305.                         titem->updateParentOnServer(FALSE);
  1306.                         gInventory.updateItem(titem);
  1307.                         gInventory.notifyObservers("fetchDescendents");
  1308.                         
  1309.                     }
  1310.                 }
  1311.             }
  1312.         LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id);
  1313. if (!pcat)
  1314. {
  1315. continue;
  1316. }
  1317. for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray();
  1318. category_it != folder_sd["categories"].endArray();
  1319. ++category_it)
  1320. {
  1321. LLSD category = *category_it;
  1322. tcategory->fromLLSD(category); 
  1323. if (LLInventoryModel::sMyInventoryFetchStarted ||
  1324. LLInventoryModel::sLibraryFetchStarted)
  1325. {
  1326. sFetchQueue.push_back(tcategory->getUUID());
  1327. }
  1328. else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
  1329. {
  1330. gInventory.updateCategory(tcategory);
  1331. }
  1332. }
  1333. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  1334. for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
  1335. item_it != folder_sd["items"].endArray();
  1336. ++item_it)
  1337. {
  1338. LLSD item = *item_it;
  1339. titem->unpackMessage(item);
  1340. gInventory.updateItem(titem);
  1341. }
  1342. // set version and descendentcount according to message.
  1343. LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
  1344. if(cat)
  1345. {
  1346. cat->setVersion(version);
  1347. cat->setDescendentCount(descendents);
  1348. cat->determineFolderType();
  1349. }
  1350. }
  1351. }
  1352. if (content.has("bad_folders"))
  1353. {
  1354. for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();
  1355. folder_it != content["bad_folders"].endArray();
  1356. ++folder_it)
  1357. {
  1358. LLSD folder_sd = *folder_it;
  1359. //These folders failed on the dataserver.  We probably don't want to retry them.
  1360. llinfos << "Folder " << folder_sd["folder_id"].asString() 
  1361. << "Error: " << folder_sd["error"].asString() << llendl;
  1362. }
  1363. }
  1364. LLInventoryModel::incrBulkFetch(-1);
  1365. if (LLInventoryModel::isBulkFetchProcessingComplete())
  1366. {
  1367. llinfos << "Inventory fetch completed" << llendl;
  1368. LLInventoryModel::setAllFoldersFetched();
  1369. }
  1370. gInventory.notifyObservers("fetchDescendents");
  1371. }
  1372. //If we get back an error (not found, etc...), handle it here
  1373. void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::string& reason)
  1374. {
  1375. llinfos << "LLInventoryModelFetchDescendentsResponder::error "
  1376. << status << ": " << reason << llendl;
  1377. LLInventoryModel::incrBulkFetch(-1);
  1378. if (status==499) //timed out.  Let's be awesome!
  1379. {
  1380. for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();
  1381. folder_it != mRequestSD["folders"].endArray();
  1382. ++folder_it)
  1383. {
  1384. LLSD folder_sd = *folder_it;
  1385. LLUUID folder_id = folder_sd["folder_id"];
  1386. sFetchQueue.push_front(folder_id);
  1387. }
  1388. }
  1389. else
  1390. {
  1391. if (LLInventoryModel::isBulkFetchProcessingComplete())
  1392. {
  1393. LLInventoryModel::setAllFoldersFetched();
  1394. }
  1395. }
  1396. gInventory.notifyObservers("fetchDescendents");
  1397. }
  1398. //static   Bundle up a bunch of requests to send all at once.
  1399. void LLInventoryModel::bulkFetch(std::string url)
  1400. {
  1401. //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped.
  1402. //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was 
  1403. //sent.  If it exceeds our retry time, go ahead and fire off another batch.  
  1404. //Stopbackgroundfetch will be run from the Responder instead of here.  
  1405. S16 max_concurrent_fetches=8;
  1406. F32 new_min_time = 0.5f; //HACK!  Clean this up when old code goes away entirely.
  1407. if (sMinTimeBetweenFetches < new_min_time) sMinTimeBetweenFetches=new_min_time;  //HACK!  See above.
  1408. if(gDisconnected 
  1409. || sBulkFetchCount > max_concurrent_fetches
  1410. || sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches)
  1411. {
  1412. return; // just bail if we are disconnected.
  1413. }
  1414. U32 folder_count=0;
  1415. U32 max_batch_size=5;
  1416. U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1;
  1417. LLSD body;
  1418. LLSD body_lib;
  1419. while( !(sFetchQueue.empty() ) && (folder_count < max_batch_size) )
  1420. {
  1421.         if (sFetchQueue.front().isNull()) //DEV-17797
  1422.         {
  1423. LLSD folder_sd;
  1424. folder_sd["folder_id"] = LLUUID::null.asString();
  1425. folder_sd["owner_id"] = gAgent.getID();
  1426. folder_sd["sort_order"] = (LLSD::Integer)sort_order;
  1427. folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE;
  1428. folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
  1429. body["folders"].append(folder_sd);
  1430.             folder_count++;
  1431.         }
  1432.         else
  1433.         {
  1434.     LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
  1435.     if (cat)
  1436.     {
  1437.     if ( LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
  1438.     {
  1439.     LLSD folder_sd;
  1440.     folder_sd["folder_id"] = cat->getUUID();
  1441.     folder_sd["owner_id"] = cat->getOwnerID();
  1442.     folder_sd["sort_order"] = (LLSD::Integer)sort_order;
  1443.     folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted;
  1444.     folder_sd["fetch_items"] = (LLSD::Boolean)TRUE;
  1445.     
  1446.     if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID())
  1447.     body_lib["folders"].append(folder_sd);
  1448.     else
  1449.     body["folders"].append(folder_sd);
  1450.     folder_count++;
  1451.     }
  1452.     if (sMyInventoryFetchStarted ||
  1453. sLibraryFetchStarted)
  1454.     { //Already have this folder but append child folders to list.
  1455.     // add all children to queue
  1456.     parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
  1457.     if (cat_it != gInventory.mParentChildCategoryTree.end())
  1458.     {
  1459.     cat_array_t* child_categories = cat_it->second;
  1460.     
  1461.     for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
  1462.     {
  1463.     sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
  1464.     }
  1465.     }
  1466.     
  1467.     }
  1468.     }
  1469.         }
  1470. sFetchQueue.pop_front();
  1471. }
  1472. if (folder_count > 0)
  1473. {
  1474. sBulkFetchCount++;
  1475. if (body["folders"].size())
  1476. {
  1477. LLHTTPClient::post(url, body, new LLInventoryModelFetchDescendentsResponder(body),300.0);
  1478. }
  1479. if (body_lib["folders"].size())
  1480. {
  1481. std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents");
  1482. LLHTTPClient::post(url_lib, body_lib, new LLInventoryModelFetchDescendentsResponder(body_lib),300.0);
  1483. }
  1484. sFetchTimer.reset();
  1485. }
  1486. else if (isBulkFetchProcessingComplete())
  1487. {
  1488. setAllFoldersFetched();
  1489. }
  1490. }
  1491. bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id)
  1492. {
  1493. for (std::deque<LLUUID>::iterator it = sFetchQueue.begin();
  1494.  it != sFetchQueue.end(); ++it)
  1495. {
  1496. const LLUUID& fetch_id = *it;
  1497. if (gInventory.isObjectDescendentOf(fetch_id, cat_id))
  1498. return false;
  1499. }
  1500. return true;
  1501. }
  1502. /* static */
  1503. bool LLInventoryModel::libraryFetchStarted()
  1504. {
  1505. return sLibraryFetchStarted;
  1506. }
  1507. /* static */
  1508. bool LLInventoryModel::libraryFetchCompleted()
  1509. {
  1510. return libraryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getLibraryRootFolderID());
  1511. }
  1512. /* static */
  1513. bool LLInventoryModel::libraryFetchInProgress()
  1514. {
  1515. return libraryFetchStarted() && !libraryFetchCompleted();
  1516. }
  1517. /* static */
  1518. bool LLInventoryModel::myInventoryFetchStarted()
  1519. {
  1520. return sMyInventoryFetchStarted;
  1521. }
  1522. /* static */
  1523. bool LLInventoryModel::myInventoryFetchCompleted()
  1524. {
  1525. return myInventoryFetchStarted() && fetchQueueContainsNoDescendentsOf(gInventory.getRootFolderID());
  1526. }
  1527. /* static */
  1528. bool LLInventoryModel::myInventoryFetchInProgress()
  1529. {
  1530. return myInventoryFetchStarted() && !myInventoryFetchCompleted();
  1531. }
  1532. // static
  1533. bool LLInventoryModel::isEverythingFetched()
  1534. {
  1535. return sAllFoldersFetched;
  1536. }
  1537. //static
  1538. BOOL LLInventoryModel::backgroundFetchActive()
  1539. {
  1540. return sBackgroundFetchActive;
  1541. }
  1542. void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id)
  1543. {
  1544. if (!sAllFoldersFetched)
  1545. {
  1546. sBackgroundFetchActive = TRUE;
  1547. if (cat_id.isNull())
  1548. {
  1549. if (!sMyInventoryFetchStarted)
  1550. {
  1551. sMyInventoryFetchStarted = TRUE;
  1552. sFetchQueue.push_back(gInventory.getRootFolderID());
  1553. gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
  1554. }
  1555. if (!sLibraryFetchStarted)
  1556. {
  1557. sLibraryFetchStarted = TRUE;
  1558. sFetchQueue.push_back(gInventory.getLibraryRootFolderID());
  1559. gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
  1560. }
  1561. }
  1562. else
  1563. {
  1564. // specific folder requests go to front of queue
  1565. if (sFetchQueue.empty() || sFetchQueue.front() != cat_id)
  1566. {
  1567. sFetchQueue.push_front(cat_id);
  1568. gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
  1569. }
  1570. if (cat_id == gInventory.getLibraryRootFolderID())
  1571. {
  1572. sLibraryFetchStarted = TRUE;
  1573. }
  1574. if (cat_id == gInventory.getRootFolderID())
  1575. {
  1576. sMyInventoryFetchStarted = TRUE;
  1577. }
  1578. }
  1579. }
  1580. }
  1581. //static
  1582. void LLInventoryModel::findLostItems()
  1583. {
  1584. sBackgroundFetchActive = TRUE;
  1585.     sFetchQueue.push_back(LLUUID::null);
  1586.     gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
  1587. }
  1588. //static
  1589. void LLInventoryModel::stopBackgroundFetch()
  1590. {
  1591. if (sBackgroundFetchActive)
  1592. {
  1593. sBackgroundFetchActive = FALSE;
  1594. gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL);
  1595. sBulkFetchCount=0;
  1596. sMinTimeBetweenFetches=0.0f;
  1597. }
  1598. }
  1599. // static
  1600. void LLInventoryModel::setAllFoldersFetched()
  1601. {
  1602. if (sMyInventoryFetchStarted &&
  1603. sLibraryFetchStarted)
  1604. {
  1605. sAllFoldersFetched = TRUE;
  1606. }
  1607. stopBackgroundFetch();
  1608. }
  1609. //static 
  1610. void LLInventoryModel::backgroundFetch(void*)
  1611. {
  1612. if (sBackgroundFetchActive && gAgent.getRegion())
  1613. {
  1614. //If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
  1615. std::string url = gAgent.getRegion()->getCapability("WebFetchInventoryDescendents");   
  1616. if (!url.empty()) 
  1617. {
  1618. bulkFetch(url);
  1619. return;
  1620. }
  1621. //DEPRECATED OLD CODE FOLLOWS.
  1622. // no more categories to fetch, stop fetch process
  1623. if (sFetchQueue.empty())
  1624. {
  1625. llinfos << "Inventory fetch completed" << llendl;
  1626. setAllFoldersFetched();
  1627. return;
  1628. }
  1629. F32 fast_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.1f);
  1630. F32 slow_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.5f);
  1631. if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() > slow_fetch_time)
  1632. {
  1633. // double timeouts on failure
  1634. sMinTimeBetweenFetches = llmin(sMinTimeBetweenFetches * 2.f, 10.f);
  1635. sMaxTimeBetweenFetches = llmin(sMaxTimeBetweenFetches * 2.f, 120.f);
  1636. llinfos << "Inventory fetch times grown to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl;
  1637. // fetch is no longer considered "timely" although we will wait for full time-out
  1638. sTimelyFetchPending = FALSE;
  1639. }
  1640. while(1)
  1641. {
  1642. if (sFetchQueue.empty())
  1643. {
  1644. break;
  1645. }
  1646. if(gDisconnected)
  1647. {
  1648. // just bail if we are disconnected.
  1649. break;
  1650. }
  1651. LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
  1652. // category has been deleted, remove from queue.
  1653. if (!cat)
  1654. {
  1655. sFetchQueue.pop_front();
  1656. continue;
  1657. }
  1658. if (sFetchTimer.getElapsedTimeF32() > sMinTimeBetweenFetches && 
  1659. LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
  1660. {
  1661. // category exists but has no children yet, fetch the descendants
  1662. // for now, just request every time and rely on retry timer to throttle
  1663. if (cat->fetchDescendents())
  1664. {
  1665. sFetchTimer.reset();
  1666. sTimelyFetchPending = TRUE;
  1667. }
  1668. else
  1669. {
  1670. //  The catagory also tracks if it has expired and here it says it hasn't
  1671. //  yet.  Get out of here because nothing is going to happen until we
  1672. //  update the timers.
  1673. break;
  1674. }
  1675. }
  1676. // do I have all my children?
  1677. else if (gInventory.isCategoryComplete(sFetchQueue.front()))
  1678. {
  1679. // finished with this category, remove from queue
  1680. sFetchQueue.pop_front();
  1681. // add all children to queue
  1682. parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
  1683. if (cat_it != gInventory.mParentChildCategoryTree.end())
  1684. {
  1685. cat_array_t* child_categories = cat_it->second;
  1686. for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
  1687. {
  1688. sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
  1689. }
  1690. }
  1691. // we received a response in less than the fast time
  1692. if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() < fast_fetch_time)
  1693. {
  1694. // shrink timeouts based on success
  1695. sMinTimeBetweenFetches = llmax(sMinTimeBetweenFetches * 0.8f, 0.3f);
  1696. sMaxTimeBetweenFetches = llmax(sMaxTimeBetweenFetches * 0.8f, 10.f);
  1697. //llinfos << "Inventory fetch times shrunk to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl;
  1698. }
  1699. sTimelyFetchPending = FALSE;
  1700. continue;
  1701. }
  1702. else if (sFetchTimer.getElapsedTimeF32() > sMaxTimeBetweenFetches)
  1703. {
  1704. // received first packet, but our num descendants does not match db's num descendants
  1705. // so try again later
  1706. LLUUID fetch_id = sFetchQueue.front();
  1707. sFetchQueue.pop_front();
  1708. if (sNumFetchRetries++ < MAX_FETCH_RETRIES)
  1709. {
  1710. // push on back of queue
  1711. sFetchQueue.push_back(fetch_id);
  1712. }
  1713. sTimelyFetchPending = FALSE;
  1714. sFetchTimer.reset();
  1715. break;
  1716. }
  1717. // not enough time has elapsed to do a new fetch
  1718. break;
  1719. }
  1720. }
  1721. }
  1722. void LLInventoryModel::cache(
  1723. const LLUUID& parent_folder_id,
  1724. const LLUUID& agent_id)
  1725. {
  1726. lldebugs << "Caching " << parent_folder_id << " for " << agent_id
  1727.  << llendl;
  1728. LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id);
  1729. if(!root_cat) return;
  1730. cat_array_t categories;
  1731. categories.put(root_cat);
  1732. item_array_t items;
  1733. LLCanCache can_cache(this);
  1734. can_cache(root_cat, NULL);
  1735. collectDescendentsIf(
  1736. parent_folder_id,
  1737. categories,
  1738. items,
  1739. INCLUDE_TRASH,
  1740. can_cache);
  1741. std::string agent_id_str;
  1742. std::string inventory_filename;
  1743. agent_id.toString(agent_id_str);
  1744. std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, agent_id_str));
  1745. inventory_filename = llformat(CACHE_FORMAT_STRING, path.c_str());
  1746. saveToFile(inventory_filename, categories, items);
  1747. std::string gzip_filename(inventory_filename);
  1748. gzip_filename.append(".gz");
  1749. if(gzip_file(inventory_filename, gzip_filename))
  1750. {
  1751. lldebugs << "Successfully compressed " << inventory_filename << llendl;
  1752. LLFile::remove(inventory_filename);
  1753. }
  1754. else
  1755. {
  1756. llwarns << "Unable to compress " << inventory_filename << llendl;
  1757. }
  1758. }
  1759. void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)
  1760. {
  1761. //llinfos << "LLInventoryModel::addCategory()" << llendl;
  1762. if(category)
  1763. {
  1764. // Insert category uniquely into the map
  1765. mCategoryMap[category->getUUID()] = category; // LLPointer will deref and delete the old one
  1766. //mInventory[category->getUUID()] = category;
  1767. }
  1768. }
  1769. void LLInventoryModel::addItem(LLViewerInventoryItem* item)
  1770. {
  1771. //llinfos << "LLInventoryModel::addItem()" << llendl;
  1772. llassert(item);
  1773. if(item)
  1774. {
  1775. // This can happen if assettype enums from llassettype.h ever change.
  1776. // For example, there is a known backwards compatibility issue in some viewer prototypes prior to when 
  1777. // the AT_LINK enum changed from 23 to 24.
  1778. if ((item->getType() == LLAssetType::AT_NONE)
  1779.     || LLAssetType::lookup(item->getType()) == LLAssetType::badLookup())
  1780. {
  1781. llwarns << "Got bad asset type for item [ name: " << item->getName() << " type: " << item->getType() << " inv-type: " << item->getInventoryType() << " ], ignoring." << llendl;
  1782. return;
  1783. }
  1784. // This condition means that we tried to add a link without the baseobj being in memory.
  1785. // The item will show up as a broken link.
  1786. if (item->getIsBrokenLink())
  1787. {
  1788. llinfos << "Adding broken link [ name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " )  parent: " << item->getParentUUID() << llendl;
  1789. }
  1790. mItemMap[item->getUUID()] = item;
  1791. }
  1792. }
  1793. // Empty the entire contents
  1794. void LLInventoryModel::empty()
  1795. {
  1796. // llinfos << "LLInventoryModel::empty()" << llendl;
  1797. std::for_each(
  1798. mParentChildCategoryTree.begin(),
  1799. mParentChildCategoryTree.end(),
  1800. DeletePairedPointer());
  1801. mParentChildCategoryTree.clear();
  1802. std::for_each(
  1803. mParentChildItemTree.begin(),
  1804. mParentChildItemTree.end(),
  1805. DeletePairedPointer());
  1806. mParentChildItemTree.clear();
  1807. mCategoryMap.clear(); // remove all references (should delete entries)
  1808. mItemMap.clear(); // remove all references (should delete entries)
  1809. mLastItem = NULL;
  1810. //mInventory.clear();
  1811. }
  1812. void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
  1813. {
  1814. LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);
  1815. if(cat)
  1816. {
  1817. bool accounted = false;
  1818. S32 version = cat->getVersion();
  1819. if(version != LLViewerInventoryCategory::VERSION_UNKNOWN)
  1820. {
  1821. S32 descendents_server = cat->getDescendentCount();
  1822. LLInventoryModel::cat_array_t* cats;
  1823. LLInventoryModel::item_array_t* items;
  1824. getDirectDescendentsOf(update.mCategoryID, cats, items);
  1825. S32 descendents_actual = 0;
  1826. if(cats && items)
  1827. {
  1828. descendents_actual = cats->count() + items->count();
  1829. }
  1830. if(descendents_server == descendents_actual)
  1831. {
  1832. accounted = true;
  1833. descendents_actual += update.mDescendentDelta;
  1834. cat->setDescendentCount(descendents_actual);
  1835. cat->setVersion(++version);
  1836. lldebugs << "accounted: '" << cat->getName() << "' "
  1837.  << version << " with " << descendents_actual
  1838.  << " descendents." << llendl;
  1839. }
  1840. }
  1841. if(!accounted)
  1842. {
  1843. // Error condition, this means that the category did not register that
  1844. // it got new descendents (perhaps because it is still being loaded)
  1845. // which means its descendent count will be wrong.
  1846. llwarns << "Accounting failed for '" << cat->getName() << "' version:"
  1847.  << version << llendl;
  1848. }
  1849. }
  1850. else
  1851. {
  1852. llwarns << "No category found for update " << update.mCategoryID << llendl;
  1853. }
  1854. }
  1855. void LLInventoryModel::accountForUpdate(
  1856. const LLInventoryModel::update_list_t& update)
  1857. {
  1858. update_list_t::const_iterator it = update.begin();
  1859. update_list_t::const_iterator end = update.end();
  1860. for(; it != end; ++it)
  1861. {
  1862. accountForUpdate(*it);
  1863. }
  1864. }
  1865. void LLInventoryModel::accountForUpdate(
  1866. const LLInventoryModel::update_map_t& update)
  1867. {
  1868. LLCategoryUpdate up;
  1869. update_map_t::const_iterator it = update.begin();
  1870. update_map_t::const_iterator end = update.end();
  1871. for(; it != end; ++it)
  1872. {
  1873. up.mCategoryID = (*it).first;
  1874. up.mDescendentDelta = (*it).second.mValue;
  1875. accountForUpdate(up);
  1876. }
  1877. }
  1878. /*
  1879. void LLInventoryModel::incrementCategoryVersion(const LLUUID& category_id)
  1880. {
  1881. LLViewerInventoryCategory* cat = getCategory(category_id);
  1882. if(cat)
  1883. {
  1884. S32 version = cat->getVersion();
  1885. if(LLViewerInventoryCategory::VERSION_UNKNOWN != version)
  1886. {
  1887. cat->setVersion(version + 1);
  1888. llinfos << "IncrementVersion: " << cat->getName() << " "
  1889. << cat->getVersion() << llendl;
  1890. }
  1891. else
  1892. {
  1893. llinfos << "Attempt to increment version when unknown: "
  1894. << category_id << llendl;
  1895. }
  1896. }
  1897. else
  1898. {
  1899. llinfos << "Attempt to increment category: " << category_id << llendl;
  1900. }
  1901. }
  1902. void LLInventoryModel::incrementCategorySetVersion(
  1903. const std::set<LLUUID>& categories)
  1904. {
  1905. if(!categories.empty())
  1906. std::set<LLUUID>::const_iterator it = categories.begin();
  1907. std::set<LLUUID>::const_iterator end = categories.end();
  1908. for(; it != end; ++it)
  1909. {
  1910. incrementCategoryVersion(*it);
  1911. }
  1912. }
  1913. }
  1914. */
  1915. LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(
  1916. const LLUUID& cat_id) const
  1917. {
  1918. LLViewerInventoryCategory* cat = getCategory(cat_id);
  1919. if(!cat) return CHILDREN_NO;
  1920. if(cat->getDescendentCount() > 0)
  1921. {
  1922. return CHILDREN_YES;
  1923. }
  1924. if(cat->getDescendentCount() == 0)
  1925. {
  1926. return CHILDREN_NO;
  1927. }
  1928. if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
  1929.    || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN))
  1930. {
  1931. return CHILDREN_MAYBE;
  1932. }
  1933. // Shouldn't have to run this, but who knows.
  1934. parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID());
  1935. if (cat_it != mParentChildCategoryTree.end() && cat_it->second->count() > 0)
  1936. {
  1937. return CHILDREN_YES;
  1938. }
  1939. parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID());
  1940. if (item_it != mParentChildItemTree.end() && item_it->second->count() > 0)
  1941. {
  1942. return CHILDREN_YES;
  1943. }
  1944. return CHILDREN_NO;
  1945. }
  1946. bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const
  1947. {
  1948. LLViewerInventoryCategory* cat = getCategory(cat_id);
  1949. if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN))
  1950. {
  1951. S32 descendents_server = cat->getDescendentCount();
  1952. LLInventoryModel::cat_array_t* cats;
  1953. LLInventoryModel::item_array_t* items;
  1954. getDirectDescendentsOf(cat_id, cats, items);
  1955. S32 descendents_actual = 0;
  1956. if(cats && items)
  1957. {
  1958. descendents_actual = cats->count() + items->count();
  1959. }
  1960. if(descendents_server == descendents_actual)
  1961. {
  1962. return true;
  1963. }
  1964. }
  1965. return false;
  1966. }
  1967. bool LLInventoryModel::loadSkeleton(
  1968. const LLSD& options,
  1969. const LLUUID& owner_id)
  1970. {
  1971. lldebugs << "importing inventory skeleton for " << owner_id << llendl;
  1972. typedef std::set<LLPointer<LLViewerInventoryCategory>, InventoryIDPtrLess> cat_set_t;
  1973. cat_set_t temp_cats;
  1974. bool rv = true;
  1975. for(LLSD::array_const_iterator it = options.beginArray(),
  1976. end = options.endArray(); it != end; ++it)
  1977. {
  1978. LLSD name = (*it)["name"];
  1979. LLSD folder_id = (*it)["folder_id"];
  1980. LLSD parent_id = (*it)["parent_id"];
  1981. LLSD version = (*it)["version"];
  1982. if(name.isDefined()
  1983. && folder_id.isDefined()
  1984. && parent_id.isDefined()
  1985. && version.isDefined()
  1986. && folder_id.asUUID().notNull() // if an id is null, it locks the viewer.
  1987. {
  1988. LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id);
  1989. cat->rename(name.asString());
  1990. cat->setUUID(folder_id.asUUID());
  1991. cat->setParent(parent_id.asUUID());
  1992. LLFolderType::EType preferred_type = LLFolderType::FT_NONE;
  1993. LLSD type_default = (*it)["type_default"];
  1994. if(type_default.isDefined())
  1995.             {
  1996. preferred_type = (LLFolderType::EType)type_default.asInteger();
  1997.             }
  1998.             cat->setPreferredType(preferred_type);
  1999. cat->setVersion(version.asInteger());
  2000.             temp_cats.insert(cat);
  2001. }
  2002. else
  2003. {
  2004. llwarns << "Unable to import near " << name.asString() << llendl;
  2005.             rv = false;
  2006. }
  2007. }
  2008. S32 cached_category_count = 0;
  2009. S32 cached_item_count = 0;
  2010. if(!temp_cats.empty())
  2011. {
  2012. update_map_t child_counts;
  2013. cat_array_t categories;
  2014. item_array_t items;
  2015. cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded.
  2016. std::string owner_id_str;
  2017. owner_id.toString(owner_id_str);
  2018. std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str));
  2019. std::string inventory_filename;
  2020. inventory_filename = llformat(CACHE_FORMAT_STRING, path.c_str());
  2021. const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN;
  2022. std::string gzip_filename(inventory_filename);
  2023. gzip_filename.append(".gz");
  2024. LLFILE* fp = LLFile::fopen(gzip_filename, "rb");
  2025. bool remove_inventory_file = false;
  2026. if(fp)
  2027. {
  2028. fclose(fp);
  2029. fp = NULL;
  2030. if(gunzip_file(gzip_filename, inventory_filename))
  2031. {
  2032. // we only want to remove the inventory file if it was
  2033. // gzipped before we loaded, and we successfully
  2034. // gunziped it.
  2035. remove_inventory_file = true;
  2036. }
  2037. else
  2038. {
  2039. llinfos << "Unable to gunzip " << gzip_filename << llendl;
  2040. }
  2041. }
  2042. bool is_cache_obsolete = false;
  2043. if(loadFromFile(inventory_filename, categories, items, is_cache_obsolete))
  2044. {
  2045. // We were able to find a cache of files. So, use what we
  2046. // found to generate a set of categories we should add. We
  2047. // will go through each category loaded and if the version
  2048. // does not match, invalidate the version.
  2049. S32 count = categories.count();
  2050. cat_set_t::iterator not_cached = temp_cats.end();
  2051. std::set<LLUUID> cached_ids;
  2052. for(S32 i = 0; i < count; ++i)
  2053. {
  2054. LLViewerInventoryCategory* cat = categories[i];
  2055. cat_set_t::iterator cit = temp_cats.find(cat);
  2056. if (cit == temp_cats.end())
  2057. {
  2058. continue; // cache corruption?? not sure why this happens -SJB
  2059. }
  2060. LLViewerInventoryCategory* tcat = *cit;
  2061. // we can safely ignore anything loaded from file, but
  2062. // not sent down in the skeleton.
  2063. if(cit == not_cached)
  2064. {
  2065. continue;
  2066. }
  2067. if(cat->getVersion() != tcat->getVersion())
  2068. {
  2069. // if the cached version does not match the server version,
  2070. // throw away the version we have so we can fetch the
  2071. // correct contents the next time the viewer opens the folder.
  2072. tcat->setVersion(NO_VERSION);
  2073. }
  2074. else
  2075. {
  2076. cached_ids.insert(tcat->getUUID());
  2077. }
  2078. }
  2079. // go ahead and add the cats returned during the download
  2080. std::set<LLUUID>::const_iterator not_cached_id = cached_ids.end();
  2081. cached_category_count = cached_ids.size();
  2082. for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it)
  2083. {
  2084. if(cached_ids.find((*it)->getUUID()) == not_cached_id)
  2085. {
  2086. // this check is performed so that we do not
  2087. // mark new folders in the skeleton (and not in cache)
  2088. // as being cached.
  2089. LLViewerInventoryCategory *llvic = (*it);
  2090. llvic->setVersion(NO_VERSION);
  2091. }
  2092. addCategory(*it);
  2093. ++child_counts[(*it)->getParentUUID()];
  2094. }
  2095. // Add all the items loaded which are parented to a
  2096. // category with a correctly cached parent
  2097. S32 bad_link_count = 0;
  2098. cat_map_t::iterator unparented = mCategoryMap.end();
  2099. for(item_array_t::const_iterator item_iter = items.begin();
  2100. item_iter != items.end();
  2101. ++item_iter)
  2102. {
  2103. LLViewerInventoryItem *item = (*item_iter).get();
  2104. const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID());
  2105. if(cit != unparented)
  2106. {
  2107. const LLViewerInventoryCategory* cat = cit->second.get();
  2108. if(cat->getVersion() != NO_VERSION)
  2109. {
  2110. // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache.
  2111. if (item->getIsBrokenLink())
  2112. {
  2113. bad_link_count++;
  2114. lldebugs << "Attempted to add cached link item without baseobj present ( name: "
  2115.  << item->getName() << " itemID: " << item->getUUID()
  2116.  << " assetID: " << item->getAssetUUID()
  2117.  << " ).  Ignoring and invalidating " << cat->getName() << " . " << llendl;
  2118. invalid_categories.insert(cit->second);
  2119. continue;
  2120. }
  2121. addItem(item);
  2122. cached_item_count += 1;
  2123. ++child_counts[cat->getUUID()];
  2124. }
  2125. }
  2126. }
  2127. if (bad_link_count > 0)
  2128. {
  2129. llinfos << "Attempted to add " << bad_link_count
  2130. << " cached link items without baseobj present. "
  2131. << "The corresponding categories were invalidated." << llendl;
  2132. }
  2133. }
  2134. else
  2135. {
  2136. // go ahead and add everything after stripping the version
  2137. // information.
  2138. for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it)
  2139. {
  2140. LLViewerInventoryCategory *llvic = (*it);
  2141. llvic->setVersion(NO_VERSION);
  2142. addCategory(*it);
  2143. }
  2144. }
  2145. // At this point, we need to set the known descendents for each
  2146. // category which successfully cached so that we do not
  2147. // needlessly fetch descendents for categories which we have.
  2148. update_map_t::const_iterator no_child_counts = child_counts.end();
  2149. for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it)
  2150. {
  2151. LLViewerInventoryCategory* cat = (*it).get();
  2152. if(cat->getVersion() != NO_VERSION)
  2153. {
  2154. update_map_t::const_iterator the_count = child_counts.find(cat->getUUID());
  2155. if(the_count != no_child_counts)
  2156. {
  2157. const S32 num_descendents = (*the_count).second.mValue;
  2158. cat->setDescendentCount(num_descendents);
  2159. }
  2160. else
  2161. {
  2162. cat->setDescendentCount(0);
  2163. }
  2164. }
  2165. }
  2166. // Invalidate all categories that failed fetching descendents for whatever
  2167. // reason (e.g. one of the descendents was a broken link).
  2168. for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin();
  2169.  invalid_cat_it != invalid_categories.end();
  2170.  invalid_cat_it++)
  2171. {
  2172. LLViewerInventoryCategory* cat = (*invalid_cat_it).get();
  2173. cat->setVersion(NO_VERSION);
  2174. llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl;
  2175. }
  2176. if(remove_inventory_file)
  2177. {
  2178. // clean up the gunzipped file.
  2179. LLFile::remove(inventory_filename);
  2180. }
  2181. if(is_cache_obsolete)
  2182. {
  2183. // If out of date, remove the gzipped file too.
  2184. llwarns << "Inv cache out of date, removing" << llendl;
  2185. LLFile::remove(gzip_filename);
  2186. }
  2187. categories.clear(); // will unref and delete entries
  2188. }
  2189. llinfos << "Successfully loaded " << cached_category_count
  2190. << " categories and " << cached_item_count << " items from cache."
  2191. << llendl;
  2192. return rv;
  2193. }
  2194. bool LLInventoryModel::loadMeat(const LLSD& options, const LLUUID& owner_id)
  2195. {
  2196. llinfos << "importing inventory for " << owner_id << llendl;
  2197. bool rv = true;
  2198. for(LLSD::array_const_iterator it = options.beginArray(),
  2199. end = options.endArray(); it != end; ++it)
  2200. {
  2201. LLSD name = (*it)["name"];
  2202. LLSD item_id = (*it)["item_id"];
  2203. LLSD parent_id = (*it)["parent_id"];
  2204. LLSD asset_type = (*it)["type"];
  2205. LLSD data_id = (*it)["data_id"];
  2206. if(name.isDefined() 
  2207. && item_id.isDefined()
  2208. && parent_id.isDefined()
  2209. && asset_type.isDefined()
  2210. && data_id.isDefined())
  2211. {
  2212. LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem;
  2213. item->rename(name.asString());
  2214. item->setUUID(item_id.asUUID());
  2215. item->setParent(parent_id.asUUID());
  2216. LLAssetType::EType type = (LLAssetType::EType)asset_type.asInteger();
  2217.             item->setType(type);
  2218. LLSD llsd_inv_type = (*it)["inv_type"];
  2219. if(llsd_inv_type.isDefined())
  2220.             {
  2221. LLInventoryType::EType inv_type = (LLInventoryType::EType)llsd_inv_type.asInteger();
  2222.                 item->setInventoryType(inv_type);
  2223.             }
  2224.             if(LLAssetType::AT_CALLINGCARD == type)
  2225.             {
  2226.                 LLPermissions perm;
  2227. perm.init(data_id.asUUID(), owner_id, LLUUID::null, LLUUID::null);
  2228.                 item->setPermissions(perm);
  2229.             }
  2230.             else
  2231.             {
  2232. LLPermissions default_perm;
  2233. default_perm.init(LLUUID::null, owner_id, LLUUID::null, LLUUID::null);
  2234. LLSD llsd_perm_mask = (*it)["perm_mask"];
  2235. if(llsd_perm_mask.isDefined())
  2236.                 {
  2237. PermissionMask perm_mask = llsd_perm_mask.asInteger();
  2238. default_perm.initMasks(
  2239. perm_mask, perm_mask, perm_mask, perm_mask, perm_mask);
  2240. }
  2241. else
  2242. {
  2243. default_perm.initMasks(
  2244. PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
  2245. }
  2246. item->setPermissions(default_perm);
  2247. item->setAssetUUID(data_id.asUUID());
  2248.             }
  2249. LLSD flags = (*it)["flags"];
  2250. if(flags.isDefined())
  2251.             {
  2252. // Not sure how well LLSD.asInteger() maps to 
  2253. // unsigned long - using strtoul()
  2254. item->setFlags(strtoul(flags.asString().c_str(), NULL, 0));
  2255.             }
  2256. LLSD time = (*it)["time"];
  2257. if(time.isDefined())
  2258.             {
  2259. item->setCreationDate(time.asInteger());
  2260.             }
  2261.             addItem(item);
  2262. }
  2263. else
  2264. {
  2265. llwarns << "Unable to import near " << name.asString() << llendl;
  2266.             rv = false;
  2267. }
  2268. }
  2269. return rv;
  2270. }
  2271. // This is a brute force method to rebuild the entire parent-child
  2272. // relations. The overall operation has O(NlogN) performance, which
  2273. // should be sufficient for our needs. 
  2274. void LLInventoryModel::buildParentChildMap()
  2275. {
  2276. llinfos << "LLInventoryModel::buildParentChildMap()" << llendl;
  2277. // *NOTE: I am skipping the logic around folder version
  2278. // synchronization here because it seems if a folder is lost, we
  2279. // might actually want to invalidate it at that point - not
  2280. // attempt to cache. More time & thought is necessary.
  2281. // First the categories. We'll copy all of the categories into a
  2282. // temporary container to iterate over (oh for real iterators.)
  2283. // While we're at it, we'll allocate the arrays in the trees.
  2284. cat_array_t cats;
  2285. cat_array_t* catsp;
  2286. item_array_t* itemsp;
  2287. for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
  2288. {
  2289. LLViewerInventoryCategory* cat = cit->second;
  2290. cats.put(cat);
  2291. if (mParentChildCategoryTree.count(cat->getUUID()) == 0)
  2292. {
  2293. llassert_always(mCategoryLock[cat->getUUID()] == false);
  2294. catsp = new cat_array_t;
  2295. mParentChildCategoryTree[cat->getUUID()] = catsp;
  2296. }
  2297. if (mParentChildItemTree.count(cat->getUUID()) == 0)
  2298. {
  2299. llassert_always(mItemLock[cat->getUUID()] == false);
  2300. itemsp = new item_array_t;
  2301. mParentChildItemTree[cat->getUUID()] = itemsp;
  2302. }
  2303. }
  2304. // Insert a special parent for the root - so that lookups on
  2305. // LLUUID::null as the parent work correctly. This is kind of a
  2306. // blatent wastes of space since we allocate a block of memory for
  2307. // the array, but whatever - it's not that much space.
  2308. if (mParentChildCategoryTree.count(LLUUID::null) == 0)
  2309. {
  2310. catsp = new cat_array_t;
  2311. mParentChildCategoryTree[LLUUID::null] = catsp;
  2312. }
  2313. // Now we have a structure with all of the categories that we can
  2314. // iterate over and insert into the correct place in the child
  2315. // category tree. 
  2316. S32 count = cats.count();
  2317. S32 i;
  2318. S32 lost = 0;
  2319. for(i = 0; i < count; ++i)
  2320. {
  2321. LLViewerInventoryCategory* cat = cats.get(i);
  2322. catsp = getUnlockedCatArray(cat->getParentUUID());
  2323. if(catsp)
  2324. {
  2325. catsp->put(cat);
  2326. }
  2327. else
  2328. {
  2329. // *NOTE: This process could be a lot more efficient if we
  2330. // used the new MoveInventoryFolder message, but we would
  2331. // have to continue to do the update & build here. So, to
  2332. // implement it, we would need a set or map of uuid pairs
  2333. // which would be (folder_id, new_parent_id) to be sent up
  2334. // to the server.
  2335. llinfos << "Lost categroy: " << cat->getUUID() << " - "
  2336. << cat->getName() << llendl;
  2337. ++lost;
  2338. // plop it into the lost & found.
  2339. LLFolderType::EType pref = cat->getPreferredType();
  2340. if(LLFolderType::FT_NONE == pref)
  2341. {
  2342. cat->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
  2343. }
  2344. else if(LLFolderType::FT_ROOT_INVENTORY == pref)
  2345. {
  2346. // it's the root
  2347. cat->setParent(LLUUID::null);
  2348. }
  2349. else
  2350. {
  2351. // it's a protected folder.
  2352. cat->setParent(gInventory.getRootFolderID());
  2353. }
  2354. cat->updateServer(TRUE);
  2355. catsp = getUnlockedCatArray(cat->getParentUUID());
  2356. if(catsp)
  2357. {
  2358. catsp->put(cat);
  2359. }
  2360. else
  2361. {
  2362. llwarns << "Lost and found Not there!!" << llendl;
  2363. }
  2364. }
  2365. }
  2366. if(lost)
  2367. {
  2368. llwarns << "Found  " << lost << " lost categories." << llendl;
  2369. }
  2370. const BOOL COF_exists = (findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT, FALSE) != LLUUID::null);
  2371. sFirstTimeInViewer2 = !COF_exists || gAgent.isFirstLogin();
  2372. // Now the items. We allocated in the last step, so now all we
  2373. // have to do is iterate over the items and put them in the right
  2374. // place.
  2375. item_array_t items;
  2376. if(!mItemMap.empty())
  2377. {
  2378. LLPointer<LLViewerInventoryItem> item;
  2379. for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)
  2380. {
  2381. item = (*iit).second;
  2382. items.put(item);
  2383. }
  2384. }
  2385. count = items.count();
  2386. lost = 0;
  2387. std::vector<LLUUID> lost_item_ids;
  2388. for(i = 0; i < count; ++i)
  2389. {
  2390. LLPointer<LLViewerInventoryItem> item;
  2391. item = items.get(i);
  2392. itemsp = getUnlockedItemArray(item->getParentUUID());
  2393. if(itemsp)
  2394. {
  2395. itemsp->put(item);
  2396. }
  2397. else
  2398. {
  2399. llinfos << "Lost item: " << item->getUUID() << " - "
  2400. << item->getName() << llendl;
  2401. ++lost;
  2402. // plop it into the lost & found.
  2403. //
  2404. item->setParent(findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));
  2405. // move it later using a special message to move items. If
  2406. // we update server here, the client might crash.
  2407. //item->updateServer();
  2408. lost_item_ids.push_back(item->getUUID());
  2409. itemsp = getUnlockedItemArray(item->getParentUUID());
  2410. if(itemsp)
  2411. {
  2412. itemsp->put(item);
  2413. }
  2414. else
  2415. {
  2416. llwarns << "Lost and found Not there!!" << llendl;
  2417. }
  2418. }
  2419. }
  2420. if(lost)
  2421. {
  2422. llwarns << "Found " << lost << " lost items." << llendl;
  2423. LLMessageSystem* msg = gMessageSystem;
  2424. BOOL start_new_message = TRUE;
  2425. const LLUUID lnf = findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
  2426. for(std::vector<LLUUID>::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it)
  2427. {
  2428. if(start_new_message)
  2429. {
  2430. start_new_message = FALSE;
  2431. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  2432. msg->nextBlockFast(_PREHASH_AgentData);
  2433. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  2434. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  2435. msg->addBOOLFast(_PREHASH_Stamp, FALSE);
  2436. }
  2437. msg->nextBlockFast(_PREHASH_InventoryData);
  2438. msg->addUUIDFast(_PREHASH_ItemID, (*it));
  2439. msg->addUUIDFast(_PREHASH_FolderID, lnf);
  2440. msg->addString("NewName", NULL);
  2441. if(msg->isSendFull(NULL))
  2442. {
  2443. start_new_message = TRUE;
  2444. gAgent.sendReliableMessage();
  2445. }
  2446. }
  2447. if(!start_new_message)
  2448. {
  2449. gAgent.sendReliableMessage();
  2450. }
  2451. }
  2452. const LLUUID &agent_inv_root_id = gInventory.getRootFolderID();
  2453. if (agent_inv_root_id.notNull())
  2454. {
  2455. cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id);
  2456. if(catsp)
  2457. {
  2458. // *HACK - fix root inventory folder
  2459. // some accounts has pbroken inventory root folders
  2460. std::string name = "My Inventory";
  2461. LLUUID prev_root_id = mRootFolderID;
  2462. for (parent_cat_map_t::const_iterator it = mParentChildCategoryTree.begin(),
  2463.  it_end = mParentChildCategoryTree.end(); it != it_end; ++it)
  2464. {
  2465. cat_array_t* cat_array = it->second;
  2466. for (cat_array_t::const_iterator cat_it = cat_array->begin(),
  2467.  cat_it_end = cat_array->end(); cat_it != cat_it_end; ++cat_it)
  2468. {
  2469. LLPointer<LLViewerInventoryCategory> category = *cat_it;
  2470. if(category && category->getPreferredType() != LLFolderType::FT_ROOT_INVENTORY)
  2471. continue;
  2472. if ( category && 0 == LLStringUtil::compareInsensitive(name, category->getName()) )
  2473. {
  2474. if(category->getUUID()!=mRootFolderID)
  2475. {
  2476. LLUUID& new_inv_root_folder_id = const_cast<LLUUID&>(mRootFolderID);
  2477. new_inv_root_folder_id = category->getUUID();
  2478. }
  2479. }
  2480. }
  2481. }
  2482. // 'My Inventory',
  2483. // root of the agent's inv found.
  2484. // The inv tree is built.
  2485. mIsAgentInvUsable = true;
  2486. llinfos << "Inventory initialized, notifying observers" << llendl;
  2487. addChangedMask(LLInventoryObserver::ALL, LLUUID::null);
  2488. notifyObservers();
  2489. }
  2490. }
  2491. }
  2492. struct LLUUIDAndName
  2493. {
  2494. LLUUIDAndName() {}
  2495. LLUUIDAndName(const LLUUID& id, const std::string& name);
  2496. bool operator==(const LLUUIDAndName& rhs) const;
  2497. bool operator<(const LLUUIDAndName& rhs) const;
  2498. bool operator>(const LLUUIDAndName& rhs) const;
  2499. LLUUID mID;
  2500. std::string mName;
  2501. };
  2502. LLUUIDAndName::LLUUIDAndName(const LLUUID& id, const std::string& name) :
  2503. mID(id), mName(name)
  2504. {
  2505. }
  2506. bool LLUUIDAndName::operator==(const LLUUIDAndName& rhs) const
  2507. {
  2508. return ((mID == rhs.mID) && (mName == rhs.mName));
  2509. }
  2510. bool LLUUIDAndName::operator<(const LLUUIDAndName& rhs) const
  2511. {
  2512. return (mID < rhs.mID);
  2513. }
  2514. bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const
  2515. {
  2516. return (mID > rhs.mID);
  2517. }
  2518. // Given the current state of the inventory items, figure out the
  2519. // clone information. *FIX: This is sub-optimal, since we can insert
  2520. // this information snurgically, but this makes sure the implementation
  2521. // works before we worry about optimization.
  2522. //void LLInventoryModel::recalculateCloneInformation()
  2523. //{
  2524. // //dumpInventory();
  2525. //
  2526. // // This implements a 'multi-map' like structure to keep track of
  2527. // // how many clones we find.
  2528. // typedef LLDynamicArray<LLViewerInventoryItem*> viewer_item_array_t;
  2529. // typedef std::map<LLUUIDAndName, viewer_item_array_t*> clone_map_t;
  2530. // clone_map_t clone_map;
  2531. // LLUUIDAndName id_and_name;
  2532. // viewer_item_array_t* clones = NULL;
  2533. // LLViewerInventoryItem* item = NULL;
  2534. // for(item = (LLViewerInventoryItem*)mItemMap.getFirstData();
  2535. // item != NULL;
  2536. // item = (LLViewerInventoryItem*)mItemMap.getNextData())
  2537. // {
  2538. // if(item->getType() == LLAssetType::AT_CALLINGCARD)
  2539. // {
  2540. // // if it's a calling card, we key off of the creator id, not
  2541. // // the asset id.
  2542. // id_and_name.mID = item->getCreatorUUID();
  2543. // }
  2544. // else
  2545. // {
  2546. // // if it's not a calling card, we key clones from the
  2547. // // asset id.
  2548. // id_and_name.mID = item->getAssetUUID();
  2549. // }
  2550. // if(id_and_name.mID == LLUUID::null)
  2551. // {
  2552. // continue;
  2553. // }
  2554. // id_and_name.mName = item->getName();
  2555. // if(clone_map.checkData(id_and_name))
  2556. // {
  2557. // clones = clone_map.getData(id_and_name);
  2558. // }
  2559. // else
  2560. // {
  2561. // clones = new viewer_item_array_t;
  2562. // clone_map.addData(id_and_name, clones);
  2563. // }
  2564. // clones->put(item);
  2565. // }
  2566. //
  2567. // S32 count = 0;
  2568. // for(clones = clone_map.getFirstData();
  2569. // clones != NULL;
  2570. // clones = clone_map.getNextData())
  2571. // {
  2572. // count = clones->count();
  2573. // for(S32 i = 0; i < count; i++)
  2574. // {
  2575. // item = clones->get(i);
  2576. // item->setCloneCount(count - 1);
  2577. // //clones[i] = NULL;
  2578. // }
  2579. // delete clones;
  2580. // }
  2581. // clone_map.removeAllData();
  2582. // //dumpInventory();
  2583. //}
  2584. // static
  2585. bool LLInventoryModel::loadFromFile(const std::string& filename,
  2586. LLInventoryModel::cat_array_t& categories,
  2587. LLInventoryModel::item_array_t& items,
  2588. bool &is_cache_obsolete)
  2589. {
  2590. if(filename.empty())
  2591. {
  2592. llerrs << "Filename is Null!" << llendl;
  2593. return false;
  2594. }
  2595. llinfos << "LLInventoryModel::loadFromFile(" << filename << ")" << llendl;
  2596. LLFILE* file = LLFile::fopen(filename, "rb"); /*Flawfinder: ignore*/
  2597. if(!file)
  2598. {
  2599. llinfos << "unable to load inventory from: " << filename << llendl;
  2600. return false;
  2601. }
  2602. // *NOTE: This buffer size is hard coded into scanf() below.
  2603. char buffer[MAX_STRING]; /*Flawfinder: ignore*/
  2604. char keyword[MAX_STRING]; /*Flawfinder: ignore*/
  2605. char value[MAX_STRING]; /*Flawfinder: ignore*/
  2606. is_cache_obsolete = true;   // Obsolete until proven current
  2607. while(!feof(file) && fgets(buffer, MAX_STRING, file)) 
  2608. {
  2609. sscanf(buffer, " %126s %126s", keyword, value); /* Flawfinder: ignore */
  2610. if(0 == strcmp("inv_cache_version", keyword))
  2611. {
  2612. S32 version;
  2613. int succ = sscanf(value,"%d",&version);
  2614. if ((1 == succ) && (version == sCurrentInvCacheVersion))
  2615. {
  2616. // Cache is up to date
  2617. is_cache_obsolete = false;
  2618. continue;
  2619. }
  2620. else
  2621. {
  2622. // Cache is out of date
  2623. break;
  2624. }
  2625. }
  2626. else if(0 == strcmp("inv_category", keyword))
  2627. {
  2628. if (is_cache_obsolete)
  2629. break;
  2630. LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
  2631. if(inv_cat->importFileLocal(file))
  2632. {
  2633. categories.put(inv_cat);
  2634. }
  2635. else
  2636. {
  2637. llwarns << "loadInventoryFromFile().  Ignoring invalid inventory category: " << inv_cat->getName() << llendl;
  2638. //delete inv_cat; // automatic when inv_cat is reassigned or destroyed
  2639. }
  2640. }
  2641. else if(0 == strcmp("inv_item", keyword))
  2642. {
  2643. if (is_cache_obsolete)
  2644. break;
  2645. LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
  2646. if( inv_item->importFileLocal(file) )
  2647. {
  2648. // *FIX: Need a better solution, this prevents the
  2649. // application from freezing, but breaks inventory
  2650. // caching.
  2651. if(inv_item->getUUID().isNull())
  2652. {
  2653. //delete inv_item; // automatic when inv_cat is reassigned or destroyed
  2654. llwarns << "Ignoring inventory with null item id: "
  2655. << inv_item->getName() << llendl;
  2656. }
  2657. else
  2658. {
  2659. items.put(inv_item);
  2660. }
  2661. }
  2662. else
  2663. {
  2664. llwarns << "loadInventoryFromFile().  Ignoring invalid inventory item: " << inv_item->getName() << llendl;
  2665. //delete inv_item; // automatic when inv_cat is reassigned or destroyed
  2666. }
  2667. }
  2668. else
  2669. {
  2670. llwarns << "Unknown token in inventory file '" << keyword << "'"
  2671. << llendl;
  2672. }
  2673. }
  2674. fclose(file);
  2675. if (is_cache_obsolete)
  2676. return false;
  2677. return true;
  2678. }
  2679. // static
  2680. bool LLInventoryModel::saveToFile(const std::string& filename,
  2681.   const cat_array_t& categories,
  2682.   const item_array_t& items)
  2683. {
  2684. if(filename.empty())
  2685. {
  2686. llerrs << "Filename is Null!" << llendl;
  2687. return false;
  2688. }
  2689. llinfos << "LLInventoryModel::saveToFile(" << filename << ")" << llendl;
  2690. LLFILE* file = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/
  2691. if(!file)
  2692. {
  2693. llwarns << "unable to save inventory to: " << filename << llendl;
  2694. return false;
  2695. }
  2696. fprintf(file, "tinv_cache_versiont%dn",sCurrentInvCacheVersion);
  2697. S32 count = categories.count();
  2698. S32 i;
  2699. for(i = 0; i < count; ++i)
  2700. {
  2701. LLViewerInventoryCategory* cat = categories[i];
  2702. if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
  2703. {
  2704. cat->exportFileLocal(file);
  2705. }
  2706. }
  2707. count = items.count();
  2708. for(i = 0; i < count; ++i)
  2709. {
  2710. items[i]->exportFile(file);
  2711. }
  2712. fclose(file);
  2713. return true;
  2714. }
  2715. // message handling functionality
  2716. // static
  2717. void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)
  2718. {
  2719. //msg->setHandlerFuncFast(_PREHASH_InventoryUpdate,
  2720. // processInventoryUpdate,
  2721. // NULL);
  2722. //msg->setHandlerFuncFast(_PREHASH_UseCachedInventory,
  2723. // processUseCachedInventory,
  2724. // NULL);
  2725. msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem,
  2726. processUpdateCreateInventoryItem,
  2727. NULL);
  2728. msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem,
  2729. processRemoveInventoryItem,
  2730. NULL);
  2731. msg->setHandlerFuncFast(_PREHASH_UpdateInventoryFolder,
  2732. processUpdateInventoryFolder,
  2733. NULL);
  2734. msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder,
  2735. processRemoveInventoryFolder,
  2736. NULL);
  2737. //msg->setHandlerFuncFast(_PREHASH_ExchangeCallingCard,
  2738. // processExchangeCallingcard,
  2739. // NULL);
  2740. //msg->setHandlerFuncFast(_PREHASH_AddCallingCard,
  2741. // processAddCallingcard,
  2742. // NULL);
  2743. //msg->setHandlerFuncFast(_PREHASH_DeclineCallingCard,
  2744. // processDeclineCallingcard,
  2745. // NULL);
  2746. msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory,
  2747. processSaveAssetIntoInventory,
  2748. NULL);
  2749. msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory,
  2750. processBulkUpdateInventory,
  2751. NULL);
  2752. msg->setHandlerFunc("InventoryDescendents", processInventoryDescendents);
  2753. msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem);
  2754. msg->setHandlerFunc("FetchInventoryReply", processFetchInventoryReply);
  2755. }
  2756. //  static
  2757. void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**)
  2758. {
  2759. // do accounting and highlight new items if they arrive
  2760. if (gInventory.messageUpdateCore(msg, true))
  2761. {
  2762. U32 callback_id;
  2763. LLUUID item_id;
  2764. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id);
  2765. msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id);
  2766. gInventoryCallbacks.fire(callback_id, item_id);
  2767. }
  2768. }
  2769. // static
  2770. void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**)
  2771. {
  2772. // no accounting
  2773. gInventory.messageUpdateCore(msg, false);
  2774. }
  2775. bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account)
  2776. {
  2777. //make sure our added inventory observer is active
  2778. start_new_inventory_observer();
  2779. LLUUID agent_id;
  2780. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  2781. if(agent_id != gAgent.getID())
  2782. {
  2783. llwarns << "Got a inventory update for the wrong agent: " << agent_id
  2784. << llendl;
  2785. return false;
  2786. }
  2787. item_array_t items;
  2788. update_map_t update;
  2789. S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
  2790. bool all_one_folder = true;
  2791. LLUUID folder_id;
  2792. // Does this loop ever execute more than once?
  2793. for(S32 i = 0; i < count; ++i)
  2794. {
  2795. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  2796. titem->unpackMessage(msg, _PREHASH_InventoryData, i);
  2797. lldebugs << "LLInventoryModel::messageUpdateCore() item id:"
  2798.  << titem->getUUID() << llendl;
  2799. items.push_back(titem);
  2800. // examine update for changes.
  2801. LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID());
  2802. if(itemp)
  2803. {
  2804. if(titem->getParentUUID() == itemp->getParentUUID())
  2805. {
  2806. update[titem->getParentUUID()];
  2807. }
  2808. else
  2809. {
  2810. ++update[titem->getParentUUID()];
  2811. --update[itemp->getParentUUID()];
  2812. }
  2813. }
  2814. else
  2815. {
  2816. ++update[titem->getParentUUID()];
  2817. }
  2818. if (folder_id.isNull())
  2819. {
  2820. folder_id = titem->getParentUUID();
  2821. }
  2822. else
  2823. {
  2824. all_one_folder = false;
  2825. }
  2826. }
  2827. if(account)
  2828. {
  2829. gInventory.accountForUpdate(update);
  2830. }
  2831. U32 changes = 0x0;
  2832. //as above, this loop never seems to loop more than once per call
  2833. for (item_array_t::iterator it = items.begin(); it != items.end(); ++it)
  2834. {
  2835. changes |= gInventory.updateItem(*it);
  2836. }
  2837. gInventory.notifyObservers();
  2838. gViewerWindow->getWindow()->decBusyCount();
  2839. return true;
  2840. }
  2841. //  static
  2842. void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**)
  2843. {
  2844. lldebugs << "LLInventoryModel::processRemoveInventoryItem()" << llendl;
  2845. LLUUID agent_id, item_id;
  2846. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  2847. if(agent_id != gAgent.getID())
  2848. {
  2849. llwarns << "Got a RemoveInventoryItem for the wrong agent."
  2850. << llendl;
  2851. return;
  2852. }
  2853. S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
  2854. std::vector<LLUUID> item_ids;
  2855. update_map_t update;
  2856. for(S32 i = 0; i < count; ++i)
  2857. {
  2858. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
  2859. LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
  2860. if(itemp)
  2861. {
  2862. // we only bother with the delete and account if we found
  2863. // the item - this is usually a back-up for permissions,
  2864. // so frequently the item will already be gone.
  2865. --update[itemp->getParentUUID()];
  2866. item_ids.push_back(item_id);
  2867. }
  2868. }
  2869. gInventory.accountForUpdate(update);
  2870. for(std::vector<LLUUID>::iterator it = item_ids.begin(); it != item_ids.end(); ++it)
  2871. {
  2872. gInventory.deleteObject(*it);
  2873. }
  2874. gInventory.notifyObservers();
  2875. }
  2876. //  static
  2877. void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg,
  2878. void**)
  2879. {
  2880. lldebugs << "LLInventoryModel::processUpdateInventoryFolder()" << llendl;
  2881. LLUUID agent_id, folder_id, parent_id;
  2882. //char name[DB_INV_ITEM_NAME_BUF_SIZE];
  2883. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
  2884. if(agent_id != gAgent.getID())
  2885. {
  2886. llwarns << "Got an UpdateInventoryFolder for the wrong agent."
  2887. << llendl;
  2888. return;
  2889. }
  2890. LLPointer<LLViewerInventoryCategory> lastfolder; // hack
  2891. cat_array_t folders;
  2892. update_map_t update;
  2893. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  2894. for(S32 i = 0; i < count; ++i)
  2895. {
  2896. LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
  2897. lastfolder = tfolder;
  2898. tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
  2899. // make sure it's not a protected folder
  2900. tfolder->setPreferredType(LLFolderType::FT_NONE);
  2901. folders.push_back(tfolder);
  2902. // examine update for changes.
  2903. LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
  2904. if(folderp)
  2905. {
  2906. if(tfolder->getParentUUID() == folderp->getParentUUID())
  2907. {
  2908. update[tfolder->getParentUUID()];
  2909. }
  2910. else
  2911. {
  2912. ++update[tfolder->getParentUUID()];
  2913. --update[folderp->getParentUUID()];
  2914. }
  2915. }
  2916. else
  2917. {
  2918. ++update[tfolder->getParentUUID()];
  2919. }
  2920. }
  2921. gInventory.accountForUpdate(update);
  2922. for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it)
  2923. {
  2924. gInventory.updateCategory(*it);
  2925. }
  2926. gInventory.notifyObservers();
  2927. // *HACK: Do the 'show' logic for a new item in the inventory.
  2928. LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
  2929. if (active_panel)
  2930. {
  2931. active_panel->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO);
  2932. }
  2933. }
  2934. //  static
  2935. void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg,
  2936. void**)
  2937. {
  2938. lldebugs << "LLInventoryModel::processRemoveInventoryFolder()" << llendl;
  2939. LLUUID agent_id, folder_id;
  2940. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
  2941. if(agent_id != gAgent.getID())
  2942. {
  2943. llwarns << "Got a RemoveInventoryFolder for the wrong agent."
  2944. << llendl;
  2945. return;
  2946. }
  2947. std::vector<LLUUID> folder_ids;
  2948. update_map_t update;
  2949. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  2950. for(S32 i = 0; i < count; ++i)
  2951. {
  2952. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i);
  2953. LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id);
  2954. if(folderp)
  2955. {
  2956. --update[folderp->getParentUUID()];
  2957. folder_ids.push_back(folder_id);
  2958. }
  2959. }
  2960. gInventory.accountForUpdate(update);
  2961. for(std::vector<LLUUID>::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it)
  2962. {
  2963. gInventory.deleteObject(*it);
  2964. }
  2965. gInventory.notifyObservers();
  2966. }
  2967. //  static
  2968. void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg,
  2969.  void**)
  2970. {
  2971. LLUUID agent_id;
  2972. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  2973. if(agent_id != gAgent.getID())
  2974. {
  2975. llwarns << "Got a SaveAssetIntoInventory message for the wrong agent."
  2976. << llendl;
  2977. return;
  2978. }
  2979. LLUUID item_id;
  2980. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id);
  2981. // The viewer ignores the asset id because this message is only
  2982. // used for attachments/objects, so the asset id is not used in
  2983. // the viewer anyway.
  2984. lldebugs << "LLInventoryModel::processSaveAssetIntoInventory itemID="
  2985. << item_id << llendl;
  2986. LLViewerInventoryItem* item = gInventory.getItem( item_id );
  2987. if( item )
  2988. {
  2989. LLCategoryUpdate up(item->getParentUUID(), 0);
  2990. gInventory.accountForUpdate(up);
  2991. gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id);
  2992. gInventory.notifyObservers();
  2993. }
  2994. else
  2995. {
  2996. llinfos << "LLInventoryModel::processSaveAssetIntoInventory item"
  2997. " not found: " << item_id << llendl;
  2998. }
  2999. if(gViewerWindow)
  3000. {
  3001. gViewerWindow->getWindow()->decBusyCount();
  3002. }
  3003. }
  3004. struct InventoryCallbackInfo
  3005. {
  3006. InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) :
  3007. mCallback(callback), mInvID(inv_id) {}
  3008. U32 mCallback;
  3009. LLUUID mInvID;
  3010. };
  3011. // static
  3012. void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
  3013. {
  3014. LLUUID agent_id;
  3015. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3016. if(agent_id != gAgent.getID())
  3017. {
  3018. llwarns << "Got a BulkUpdateInventory for the wrong agent." << llendl;
  3019. return;
  3020. }
  3021. LLUUID tid;
  3022. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid);
  3023. llinfos << "Bulk inventory: " << tid << llendl;
  3024. update_map_t update;
  3025. cat_array_t folders;
  3026. S32 count;
  3027. S32 i;
  3028. count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  3029. for(i = 0; i < count; ++i)
  3030. {
  3031. LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
  3032. tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
  3033. //llinfos << "unpaked folder '" << tfolder->getName() << "' ("
  3034. // << tfolder->getUUID() << ") in " << tfolder->getParentUUID()
  3035. // << llendl;
  3036. if(tfolder->getUUID().notNull())
  3037. {
  3038. folders.push_back(tfolder);
  3039. LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
  3040. if(folderp)
  3041. {
  3042. if(tfolder->getParentUUID() == folderp->getParentUUID())
  3043. {
  3044. update[tfolder->getParentUUID()];
  3045. }
  3046. else
  3047. {
  3048. ++update[tfolder->getParentUUID()];
  3049. --update[folderp->getParentUUID()];
  3050. }
  3051. }
  3052. else
  3053. {
  3054. // we could not find the folder, so it is probably
  3055. // new. However, we only want to attempt accounting
  3056. // for the parent if we can find the parent.
  3057. folderp = gInventory.getCategory(tfolder->getParentUUID());
  3058. if(folderp)
  3059. {
  3060. ++update[tfolder->getParentUUID()];
  3061. }
  3062. }
  3063. }
  3064. }
  3065. count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
  3066. std::vector<LLUUID> wearable_ids;
  3067. item_array_t items;
  3068. std::list<InventoryCallbackInfo> cblist;
  3069. for(i = 0; i < count; ++i)
  3070. {
  3071. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  3072. titem->unpackMessage(msg, _PREHASH_ItemData, i);
  3073. //llinfos << "unpaked item '" << titem->getName() << "' in "
  3074. // << titem->getParentUUID() << llendl;
  3075. U32 callback_id;
  3076. msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);
  3077. if(titem->getUUID().notNull())
  3078. {
  3079. items.push_back(titem);
  3080. cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID()));
  3081. if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE)
  3082. {
  3083. wearable_ids.push_back(titem->getUUID());
  3084. }
  3085. // examine update for changes.
  3086. LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID());
  3087. if(itemp)
  3088. {
  3089. if(titem->getParentUUID() == itemp->getParentUUID())
  3090. {
  3091. update[titem->getParentUUID()];
  3092. }
  3093. else
  3094. {
  3095. ++update[titem->getParentUUID()];
  3096. --update[itemp->getParentUUID()];
  3097. }
  3098. }
  3099. else
  3100. {
  3101. LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID());
  3102. if(folderp)
  3103. {
  3104. ++update[titem->getParentUUID()];
  3105. }
  3106. }
  3107. }
  3108. else
  3109. {
  3110. cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null));
  3111. }
  3112. }
  3113. gInventory.accountForUpdate(update);
  3114. for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)
  3115. {
  3116. gInventory.updateCategory(*cit);
  3117. }
  3118. for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)
  3119. {
  3120. gInventory.updateItem(*iit);
  3121. }
  3122. gInventory.notifyObservers();
  3123. // The incoming inventory could span more than one BulkInventoryUpdate packet,
  3124. // so record the transaction ID for this purchase, then wear all clothing
  3125. // that comes in as part of that transaction ID.  JC
  3126. if (LLInventoryState::sWearNewClothing)
  3127. {
  3128. LLInventoryState::sWearNewClothingTransactionID = tid;
  3129. LLInventoryState::sWearNewClothing = FALSE;
  3130. }
  3131. if (tid == LLInventoryState::sWearNewClothingTransactionID)
  3132. {
  3133. count = wearable_ids.size();
  3134. for (i = 0; i < count; ++i)
  3135. {
  3136. LLViewerInventoryItem* wearable_item;
  3137. wearable_item = gInventory.getItem(wearable_ids[i]);
  3138. wear_inventory_item_on_avatar(wearable_item);
  3139. }
  3140. }
  3141. std::list<InventoryCallbackInfo>::iterator inv_it;
  3142. for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it)
  3143. {
  3144. InventoryCallbackInfo cbinfo = (*inv_it);
  3145. gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
  3146. }
  3147. // Don't show the inventory.  We used to call showAgentInventory here.
  3148. //LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();
  3149. //if(view)
  3150. //{
  3151. // const BOOL take_keyboard_focus = FALSE;
  3152. // view->setSelection(category.getUUID(), take_keyboard_focus );
  3153. // LLView* focus_view = gFocusMgr.getKeyboardFocus();
  3154. // LLFocusMgr::FocusLostCallback callback = gFocusMgr.getFocusCallback();
  3155. // // HACK to open inventory offers that are accepted.  This information
  3156. // // really needs to flow through the instant messages and inventory
  3157. // // transfer/update messages.
  3158. // if (LLFloaterInventory::sOpenNextNewItem)
  3159. // {
  3160. // view->openSelected();
  3161. // LLFloaterInventory::sOpenNextNewItem = FALSE;
  3162. // }
  3163. //
  3164. // // restore keyboard focus
  3165. // gFocusMgr.setKeyboardFocus(focus_view);
  3166. //}
  3167. }
  3168. // static
  3169. void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**)
  3170. {
  3171. LLUUID agent_id;
  3172. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3173. if(agent_id != gAgent.getID())
  3174. {
  3175. llwarns << "Got a UpdateInventoryItem for the wrong agent." << llendl;
  3176. return;
  3177. }
  3178. LLUUID parent_id;
  3179. msg->getUUID("AgentData", "FolderID", parent_id);
  3180. LLUUID owner_id;
  3181. msg->getUUID("AgentData", "OwnerID", owner_id);
  3182. S32 version;
  3183. msg->getS32("AgentData", "Version", version);
  3184. S32 descendents;
  3185. msg->getS32("AgentData", "Descendents", descendents);
  3186. S32 i;
  3187. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  3188. LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
  3189. for(i = 0; i < count; ++i)
  3190. {
  3191. tcategory->unpackMessage(msg, _PREHASH_FolderData, i);
  3192. gInventory.updateCategory(tcategory);
  3193. }
  3194. count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
  3195. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  3196. for(i = 0; i < count; ++i)
  3197. {
  3198. titem->unpackMessage(msg, _PREHASH_ItemData, i);
  3199. // If the item has already been added (e.g. from link prefetch), then it doesn't need to be re-added.
  3200. if (gInventory.getItem(titem->getUUID()))
  3201. {
  3202. lldebugs << "Skipping prefetched item [ Name: " << titem->getName() << " | Type: " << titem->getActualType() << " | ItemUUID: " << titem->getUUID() << " ] " << llendl;
  3203. continue;
  3204. }
  3205. gInventory.updateItem(titem);
  3206. }
  3207. // set version and descendentcount according to message.
  3208. LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
  3209. if(cat)
  3210. {
  3211. cat->setVersion(version);
  3212. cat->setDescendentCount(descendents);
  3213. // Get this UUID on the changed list so that whatever's listening for it
  3214. // will get triggered.
  3215. gInventory.addChangedMask(LLInventoryObserver::INTERNAL, cat->getUUID());
  3216. }
  3217. gInventory.notifyObservers();
  3218. }
  3219. // static
  3220. void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**)
  3221. {
  3222. lldebugs << "LLInventoryModel::processMoveInventoryItem()" << llendl;
  3223. LLUUID agent_id;
  3224. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3225. if(agent_id != gAgent.getID())
  3226. {
  3227. llwarns << "Got a MoveInventoryItem message for the wrong agent."
  3228. << llendl;
  3229. return;
  3230. }
  3231. LLUUID item_id;
  3232. LLUUID folder_id;
  3233. std::string new_name;
  3234. bool anything_changed = false;
  3235. S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
  3236. for(S32 i = 0; i < count; ++i)
  3237. {
  3238. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
  3239. LLViewerInventoryItem* item = gInventory.getItem(item_id);
  3240. if(item)
  3241. {
  3242. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  3243. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i);
  3244. msg->getString("InventoryData", "NewName", new_name, i);
  3245. lldebugs << "moving item " << item_id << " to folder "
  3246.  << folder_id << llendl;
  3247. update_list_t update;
  3248. LLCategoryUpdate old_folder(item->getParentUUID(), -1);
  3249. update.push_back(old_folder);
  3250. LLCategoryUpdate new_folder(folder_id, 1);
  3251. update.push_back(new_folder);
  3252. gInventory.accountForUpdate(update);
  3253. new_item->setParent(folder_id);
  3254. if (new_name.length() > 0)
  3255. {
  3256. new_item->rename(new_name);
  3257. }
  3258. gInventory.updateItem(new_item);
  3259. anything_changed = true;
  3260. }
  3261. else
  3262. {
  3263. llinfos << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << llendl;
  3264. }
  3265. }
  3266. if(anything_changed)
  3267. {
  3268. gInventory.notifyObservers();
  3269. }
  3270. }
  3271. //----------------------------------------------------------------------------
  3272. // Trash: LLFolderType::FT_TRASH, "ConfirmEmptyTrash"
  3273. // Lost&Found: LLFolderType::FT_LOST_AND_FOUND, "ConfirmEmptyLostAndFound"
  3274. bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLFolderType::EType preferred_type)
  3275. {
  3276. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  3277. if (option == 0) // YES
  3278. {
  3279. const LLUUID folder_id = findCategoryUUIDForType(preferred_type);
  3280. purgeDescendentsOf(folder_id);
  3281. notifyObservers();
  3282. }
  3283. return false;
  3284. }
  3285. void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderType::EType preferred_type)
  3286. {
  3287. if (!notification.empty())
  3288. {
  3289. LLNotificationsUtil::add(notification, LLSD(), LLSD(),
  3290. boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type));
  3291. }
  3292. else
  3293. {
  3294. const LLUUID folder_id = findCategoryUUIDForType(preferred_type);
  3295. purgeDescendentsOf(folder_id);
  3296. notifyObservers();
  3297. }
  3298. }
  3299. //----------------------------------------------------------------------------
  3300. void LLInventoryModel::removeItem(const LLUUID& item_id)
  3301. {
  3302. LLViewerInventoryItem* item = getItem(item_id);
  3303. const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH);
  3304. if (item && item->getParentUUID() != new_parent)
  3305. {
  3306. LLInventoryModel::update_list_t update;
  3307. LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
  3308. update.push_back(old_folder);
  3309. LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1);
  3310. update.push_back(new_folder);
  3311. accountForUpdate(update);
  3312. LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
  3313. new_item->setParent(new_parent);
  3314. new_item->updateParentOnServer(TRUE);
  3315. updateItem(new_item);
  3316. notifyObservers();
  3317. }
  3318. }
  3319. const LLUUID &LLInventoryModel::getRootFolderID() const
  3320. {
  3321. return mRootFolderID;
  3322. }
  3323. void LLInventoryModel::setRootFolderID(const LLUUID& val)
  3324. {
  3325. mRootFolderID = val;
  3326. }
  3327. const LLUUID &LLInventoryModel::getLibraryRootFolderID() const
  3328. {
  3329. return mLibraryRootFolderID;
  3330. }
  3331. void LLInventoryModel::setLibraryRootFolderID(const LLUUID& val)
  3332. {
  3333. mLibraryRootFolderID = val;
  3334. }
  3335. const LLUUID &LLInventoryModel::getLibraryOwnerID() const
  3336. {
  3337. return mLibraryOwnerID;
  3338. }
  3339. void LLInventoryModel::setLibraryOwnerID(const LLUUID& val)
  3340. {
  3341. mLibraryOwnerID = val;
  3342. }
  3343. // static
  3344. BOOL LLInventoryModel::getIsFirstTimeInViewer2()
  3345. {
  3346. // Do not call this before parentchild map is built.
  3347. if (!gInventory.mIsAgentInvUsable)
  3348. {
  3349. llwarns << "Parent Child Map not yet built; guessing as first time in viewer2." << llendl;
  3350. return TRUE;
  3351. }
  3352. return sFirstTimeInViewer2;
  3353. }
  3354. static LLInventoryModel::item_array_t::iterator find_item_iter_by_uuid(LLInventoryModel::item_array_t& items, const LLUUID& id)
  3355. {
  3356. LLInventoryModel::item_array_t::iterator result = items.end();
  3357. for (LLInventoryModel::item_array_t::iterator i = items.begin(); i != items.end(); ++i)
  3358. {
  3359. if ((*i)->getUUID() == id)
  3360. {
  3361. result = i;
  3362. break;
  3363. }
  3364. }
  3365. return result;
  3366. }
  3367. // static
  3368. void LLInventoryModel::updateItemsOrder(LLInventoryModel::item_array_t& items, const LLUUID& src_item_id, const LLUUID& dest_item_id)
  3369. {
  3370. LLInventoryModel::item_array_t::iterator it_src = find_item_iter_by_uuid(items, src_item_id);
  3371. LLInventoryModel::item_array_t::iterator it_dest = find_item_iter_by_uuid(items, dest_item_id);
  3372. if (it_src == items.end() || it_dest == items.end()) return;
  3373. LLViewerInventoryItem* src_item = *it_src;
  3374. items.erase(it_src);
  3375. // target iterator can not be valid because the container was changed, so update it.
  3376. it_dest = find_item_iter_by_uuid(items, dest_item_id);
  3377. items.insert(it_dest, src_item);
  3378. }
  3379. void LLInventoryModel::saveItemsOrder(const LLInventoryModel::item_array_t& items)
  3380. {
  3381. int sortField = 0;
  3382. // current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
  3383. for (item_array_t::const_iterator i = items.begin(); i != items.end(); ++i)
  3384. {
  3385. LLViewerInventoryItem* item = *i;
  3386. item->setSortField(++sortField);
  3387. item->setComplete(TRUE);
  3388. item->updateServer(FALSE);
  3389. updateItem(item);
  3390. // Tell the parent folder to refresh its sort order.
  3391. addChangedMask(LLInventoryObserver::SORT, item->getParentUUID());
  3392. }
  3393. notifyObservers();
  3394. }
  3395. // See also LLInventorySort where landmarks in the Favorites folder are sorted.
  3396. class LLViewerInventoryItemSort
  3397. {
  3398. public:
  3399. bool operator()(const LLPointer<LLViewerInventoryItem>& a, const LLPointer<LLViewerInventoryItem>& b)
  3400. {
  3401. return a->getSortField() < b->getSortField();
  3402. }
  3403. };
  3404. /**
  3405.  * Sorts passed items by LLViewerInventoryItem sort field.
  3406.  *
  3407.  * @param[in, out] items - array of items, not sorted.
  3408.  */
  3409. static void rearrange_item_order_by_sort_field(LLInventoryModel::item_array_t& items)
  3410. {
  3411. static LLViewerInventoryItemSort sort_functor;
  3412. std::sort(items.begin(), items.end(), sort_functor);
  3413. }
  3414. void LLInventoryModel::rearrangeFavoriteLandmarks(const LLUUID& source_item_id, const LLUUID& target_item_id)
  3415. {
  3416. LLInventoryModel::cat_array_t cats;
  3417. LLInventoryModel::item_array_t items;
  3418. LLIsType is_type(LLAssetType::AT_LANDMARK);
  3419. LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE);
  3420. gInventory.collectDescendentsIf(favorites_id, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type);
  3421. // ensure items are sorted properly before changing order. EXT-3498
  3422. rearrange_item_order_by_sort_field(items);
  3423. // update order
  3424. updateItemsOrder(items, source_item_id, target_item_id);
  3425. saveItemsOrder(items);
  3426. }
  3427. //----------------------------------------------------------------------------
  3428. // *NOTE: DEBUG functionality
  3429. void LLInventoryModel::dumpInventory() const
  3430. {
  3431. llinfos << "nBegin Inventory Dumpn**********************:" << llendl;
  3432. llinfos << "mCategory[] contains " << mCategoryMap.size() << " items." << llendl;
  3433. for(cat_map_t::const_iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
  3434. {
  3435. const LLViewerInventoryCategory* cat = cit->second;
  3436. if(cat)
  3437. {
  3438. llinfos << "  " <<  cat->getUUID() << " '" << cat->getName() << "' "
  3439. << cat->getVersion() << " " << cat->getDescendentCount()
  3440. << llendl;
  3441. }
  3442. else
  3443. {
  3444. llinfos << "  NULL!" << llendl;
  3445. }
  3446. }
  3447. llinfos << "mItemMap[] contains " << mItemMap.size() << " items." << llendl;
  3448. for(item_map_t::const_iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)
  3449. {
  3450. const LLViewerInventoryItem* item = iit->second;
  3451. if(item)
  3452. {
  3453. llinfos << "  " << item->getUUID() << " "
  3454. << item->getName() << llendl;
  3455. }
  3456. else
  3457. {
  3458. llinfos << "  NULL!" << llendl;
  3459. }
  3460. }
  3461. llinfos << "n**********************nEnd Inventory Dump" << llendl;
  3462. }
  3463. ///----------------------------------------------------------------------------
  3464. /// LLInventoryCollectFunctor implementations
  3465. ///----------------------------------------------------------------------------
  3466. // static
  3467. bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item)
  3468. {
  3469. if (!item)
  3470. return false;
  3471. bool allowed = false;
  3472. LLVOAvatarSelf* my_avatar = NULL;
  3473. switch(item->getType())
  3474. {
  3475. case LLAssetType::AT_CALLINGCARD:
  3476. // not allowed
  3477. break;
  3478. case LLAssetType::AT_OBJECT:
  3479. my_avatar = gAgent.getAvatarObject();
  3480. if(my_avatar && !my_avatar->isWearingAttachment(item->getUUID()))
  3481. {
  3482. allowed = true;
  3483. }
  3484. break;
  3485. case LLAssetType::AT_BODYPART:
  3486. case LLAssetType::AT_CLOTHING:
  3487. if(!gAgentWearables.isWearingItem(item->getUUID()))
  3488. {
  3489. allowed = true;
  3490. }
  3491. break;
  3492. default:
  3493. allowed = true;
  3494. break;
  3495. }
  3496. return allowed;
  3497. }
  3498. bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  3499. {
  3500. if(mType == LLAssetType::AT_CATEGORY)
  3501. {
  3502. if(cat) return TRUE;
  3503. }
  3504. if(item)
  3505. {
  3506. if(item->getType() == mType) return TRUE;
  3507. }
  3508. return FALSE;
  3509. }
  3510. bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  3511. {
  3512. if(mType == LLAssetType::AT_CATEGORY)
  3513. {
  3514. if(cat) return FALSE;
  3515. }
  3516. if(item)
  3517. {
  3518. if(item->getType() == mType) return FALSE;
  3519. else return TRUE;
  3520. }
  3521. return TRUE;
  3522. }
  3523. bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  3524. {
  3525. if(mType == LLAssetType::AT_CATEGORY)
  3526. {
  3527. if(cat) 
  3528. {
  3529. return TRUE;
  3530. }
  3531. }
  3532. if(item)
  3533. {
  3534. if(item->getType() == mType)
  3535. {
  3536. LLPermissions perm = item->getPermissions();
  3537. if ((perm.getMaskBase() & mPerm) == mPerm)
  3538. {
  3539. return TRUE;
  3540. }
  3541. }
  3542. }
  3543. return FALSE;
  3544. }
  3545. //bool LLIsClone::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  3546. //{
  3547. // if(cat) return FALSE;
  3548. // if(item)
  3549. // {
  3550. // if(mItemMap->getType() == LLAssetType::AT_CALLINGCARD)
  3551. // {
  3552. // if((item->getType() == LLAssetType::AT_CALLINGCARD)
  3553. //    && !(item->getCreatorUUID().isNull())
  3554. //    && (item->getCreatorUUID() == mItemMap->getCreatorUUID()))
  3555. // {
  3556. // return TRUE;
  3557. // }
  3558. // }
  3559. // else
  3560. // {
  3561. // if((item->getType() == mItemMap->getType())
  3562. //    && !(item->getAssetUUID().isNull())
  3563. //    && (item->getAssetUUID() == mItemMap->getAssetUUID())
  3564. //    && (item->getName() == mItemMap->getName()))
  3565. // {
  3566. // return TRUE;
  3567. // }
  3568. // }
  3569. // }
  3570. // return FALSE;
  3571. //}
  3572. bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
  3573.   LLInventoryItem* item)
  3574. {
  3575. if(item)
  3576. {
  3577. if((LLAssetType::AT_CALLINGCARD == item->getType())
  3578.    && (!item->getCreatorUUID().isNull())
  3579.    && (item->getCreatorUUID() != gAgent.getID()))
  3580. {
  3581. return true;
  3582. }
  3583. }
  3584. return false;
  3585. }
  3586. bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat,
  3587. LLInventoryItem* item)
  3588. {
  3589. if(item)
  3590. {
  3591. if((LLAssetType::AT_CALLINGCARD == item->getType())
  3592.      && (item->getCreatorUUID().notNull())
  3593.      && (item->getCreatorUUID() != gAgent.getID()))
  3594. {
  3595. mSeen.insert(item->getCreatorUUID());
  3596. return true;
  3597. }
  3598. }
  3599. return false;
  3600. }
  3601. bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat,
  3602. LLInventoryItem* item)
  3603. {
  3604. if(item)
  3605. {
  3606. if((LLAssetType::AT_CALLINGCARD == item->getType())
  3607.    && (item->getCreatorUUID() == mBuddyID))
  3608. {
  3609. return TRUE;
  3610. }
  3611. }
  3612. return FALSE;
  3613. }
  3614. bool LLNameCategoryCollector::operator()(
  3615. LLInventoryCategory* cat, LLInventoryItem* item)
  3616. {
  3617. if(cat)
  3618. {
  3619. if (!LLStringUtil::compareInsensitive(mName, cat->getName()))
  3620. {
  3621. return true;
  3622. }
  3623. }
  3624. return false;
  3625. }
  3626. ///----------------------------------------------------------------------------
  3627. /// LLAssetIDMatches 
  3628. ///----------------------------------------------------------------------------
  3629. bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  3630. {
  3631. return (item && item->getAssetUUID() == mAssetID);
  3632. }
  3633. ///----------------------------------------------------------------------------
  3634. /// LLLinkedItemIDMatches 
  3635. ///----------------------------------------------------------------------------
  3636. bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  3637. {
  3638. return (item && 
  3639. (item->getIsLinkType()) &&
  3640. (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
  3641. }
  3642. ///----------------------------------------------------------------------------
  3643. /// Local function definitions
  3644. ///----------------------------------------------------------------------------
  3645. /*
  3646. BOOL decompress_file(const char* src_filename, const char* dst_filename)
  3647. {
  3648. BOOL rv = FALSE;
  3649. gzFile src = NULL;
  3650. U8* buffer = NULL;
  3651. LLFILE* dst = NULL;
  3652. S32 bytes = 0;
  3653. const S32 DECOMPRESS_BUFFER_SIZE = 32000;
  3654. // open the files
  3655. src = gzopen(src_filename, "rb");
  3656. if(!src) goto err_decompress;
  3657. dst = LLFile::fopen(dst_filename, "wb");
  3658. if(!dst) goto err_decompress;
  3659. // decompress.
  3660. buffer = new U8[DECOMPRESS_BUFFER_SIZE + 1];
  3661. do
  3662. {
  3663. bytes = gzread(src, buffer, DECOMPRESS_BUFFER_SIZE);
  3664. if (bytes < 0)
  3665. {
  3666. goto err_decompress;
  3667. }
  3668. fwrite(buffer, bytes, 1, dst);
  3669. } while(gzeof(src) == 0);
  3670. // success
  3671. rv = TRUE;
  3672.  err_decompress:
  3673. if(src != NULL) gzclose(src);
  3674. if(buffer != NULL) delete[] buffer;
  3675. if(dst != NULL) fclose(dst);
  3676. return rv;
  3677. }
  3678. */