00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llinventorymodel.h"
00035
00036 #include "llassetstorage.h"
00037 #include "llcrc.h"
00038 #include "lldir.h"
00039 #include "llsys.h"
00040 #include "llxfermanager.h"
00041 #include "message.h"
00042
00043 #include "llagent.h"
00044 #include "llfloater.h"
00045 #include "llfocusmgr.h"
00046 #include "llinventoryview.h"
00047 #include "llviewerinventory.h"
00048 #include "llviewermessage.h"
00049 #include "llviewerwindow.h"
00050 #include "llviewerregion.h"
00051 #include "llappviewer.h"
00052 #include "lldbstrings.h"
00053 #include "llviewerstats.h"
00054 #include "llmutelist.h"
00055 #include "llnotify.h"
00056 #include "llcallbacklist.h"
00057 #include "llpreview.h"
00058 #include "llviewercontrol.h"
00059 #include "llsdutil.h"
00060 #include <deque>
00061
00062
00063 #ifdef DIFF_INVENTORY_FILES
00064 #include "process.h"
00065 #endif
00066
00067 BOOL LLInventoryModel::sBackgroundFetchActive = FALSE;
00068 BOOL LLInventoryModel::sAllFoldersFetched = FALSE;
00069 BOOL LLInventoryModel::sFullFetchStarted = FALSE;
00070 S32 LLInventoryModel::sNumFetchRetries = 0;
00071 F32 LLInventoryModel::sMinTimeBetweenFetches = 0.3f;
00072 F32 LLInventoryModel::sMaxTimeBetweenFetches = 10.f;
00073 BOOL LLInventoryModel::sTimelyFetchPending = FALSE;
00074 LLFrameTimer LLInventoryModel::sFetchTimer;
00075 LLInventoryModel::cat_map_t LLInventoryModel::sBulkFetchMap;
00076 S16 LLInventoryModel::sBulkFetchCount = 0;
00077
00078
00079 static std::deque<LLUUID> sFetchQueue;
00080
00084
00085
00086 const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f;
00087 const S32 MAX_FETCH_RETRIES = 5;
00088 const char CACHE_FORMAT_STRING[] = "%s.inv";
00089 const char* NEW_CATEGORY_NAME = "New Folder";
00090 const char* NEW_CATEGORY_NAMES[LLAssetType::AT_COUNT] =
00091 {
00092 "Textures",
00093 "Sounds",
00094 "Calling Cards",
00095 "Landmarks",
00096 "Scripts",
00097 "Clothing",
00098 "Objects",
00099 "Notecards",
00100 "New Folder",
00101 "Inventory",
00102 "Scripts",
00103 "Scripts",
00104 "Uncompressed Images",
00105 "Body Parts",
00106 "Trash",
00107 "Photo Album",
00108 "Lost And Found",
00109 "Uncompressed Sounds",
00110 "Uncompressed Images",
00111 "Uncompressed Images",
00112 "Animations",
00113 "Gestures",
00114 };
00115
00116 struct InventoryIDPtrLess
00117 {
00118 bool operator()(const LLViewerInventoryCategory* i1, const LLViewerInventoryCategory* i2) const
00119 {
00120 return (i1->getUUID() < i2->getUUID());
00121 }
00122 };
00123
00124 class LLCanCache : public LLInventoryCollectFunctor
00125 {
00126 public:
00127 LLCanCache(LLInventoryModel* model) : mModel(model) {}
00128 virtual ~LLCanCache() {}
00129 virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item);
00130 protected:
00131 LLInventoryModel* mModel;
00132 std::set<LLUUID> mCachedCatIDs;
00133 };
00134
00135 bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
00136 {
00137 bool rv = false;
00138 if(item)
00139 {
00140 if(mCachedCatIDs.find(item->getParentUUID()) != mCachedCatIDs.end())
00141 {
00142 rv = true;
00143 }
00144 }
00145 else if(cat)
00146 {
00147
00148 LLViewerInventoryCategory* c = (LLViewerInventoryCategory*)cat;
00149 if(c->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
00150 {
00151 S32 descendents_server = c->getDescendentCount();
00152 LLInventoryModel::cat_array_t* cats;
00153 LLInventoryModel::item_array_t* items;
00154 mModel->getDirectDescendentsOf(
00155 c->getUUID(),
00156 cats,
00157 items);
00158 S32 descendents_actual = 0;
00159 if(cats && items)
00160 {
00161 descendents_actual = cats->count() + items->count();
00162 }
00163 if(descendents_server == descendents_actual)
00164 {
00165 mCachedCatIDs.insert(c->getUUID());
00166 rv = true;
00167 }
00168 }
00169 }
00170 return rv;
00171 }
00172
00176
00177
00178 LLInventoryModel gInventory;
00179
00180
00181 LLInventoryModel::LLInventoryModel() :
00182 mModifyMask(LLInventoryObserver::ALL),
00183 mLastItem(NULL),
00184 mIsAgentInvUsable(false)
00185 {
00186 }
00187
00188
00189 LLInventoryModel::~LLInventoryModel()
00190 {
00191 empty();
00192 for (observer_list_t::iterator iter = mObservers.begin();
00193 iter != mObservers.end(); ++iter)
00194 {
00195 delete *iter;
00196 }
00197 }
00198
00199
00200
00201 BOOL LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id,
00202 const LLUUID& cat_id)
00203 {
00204 LLInventoryObject* obj = getObject(obj_id);
00205 while(obj)
00206 {
00207 const LLUUID& parent_id = obj->getParentUUID();
00208 if( parent_id.isNull() )
00209 {
00210 return FALSE;
00211 }
00212 if(parent_id == cat_id)
00213 {
00214 return TRUE;
00215 }
00216
00217
00218 obj = getCategory(parent_id);
00219 }
00220 return FALSE;
00221 }
00222
00223
00224 LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const
00225 {
00226 LLViewerInventoryCategory* cat = getCategory(id);
00227 if (cat)
00228 {
00229 return cat;
00230 }
00231 LLViewerInventoryItem* item = getItem(id);
00232 if (item)
00233 {
00234 return item;
00235 }
00236 return NULL;
00237 }
00238
00239
00240 LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const
00241 {
00242 LLViewerInventoryItem* item = NULL;
00243 if(mLastItem.notNull() && mLastItem->getUUID() == id)
00244 {
00245 item = mLastItem;
00246 }
00247 else
00248 {
00249 item_map_t::const_iterator iter = mItemMap.find(id);
00250 if (iter != mItemMap.end())
00251 {
00252 item = iter->second;
00253 mLastItem = item;
00254 }
00255 }
00256 return item;
00257 }
00258
00259
00260 LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const
00261 {
00262 LLViewerInventoryCategory* category = NULL;
00263 cat_map_t::const_iterator iter = mCategoryMap.find(id);
00264 if (iter != mCategoryMap.end())
00265 {
00266 category = iter->second;
00267 }
00268 return category;
00269 }
00270
00271 S32 LLInventoryModel::getItemCount() const
00272 {
00273 return mItemMap.size();
00274 }
00275
00276 S32 LLInventoryModel::getCategoryCount() const
00277 {
00278 return mCategoryMap.size();
00279 }
00280
00281
00282
00283
00284
00285
00286 void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id,
00287 cat_array_t*& categories,
00288 item_array_t*& items) const
00289 {
00290 categories = get_ptr_in_map(mParentChildCategoryTree, cat_id);
00291 items = get_ptr_in_map(mParentChildItemTree, cat_id);
00292 }
00293
00294
00295
00296
00297
00298 LLUUID LLInventoryModel::findCategoryUUIDForType(LLAssetType::EType t, bool create_folder)
00299 {
00300 LLUUID rv = findCatUUID(t);
00301 if(rv.isNull() && isInventoryUsable() && create_folder)
00302 {
00303 LLUUID root_id = gAgent.getInventoryRootID();
00304 if(root_id.notNull())
00305 {
00306 rv = createNewCategory(root_id, t, NULL);
00307 }
00308 }
00309 return rv;
00310 }
00311
00312
00313
00314 LLUUID LLInventoryModel::findCatUUID(LLAssetType::EType preferred_type)
00315 {
00316 LLUUID root_id = gAgent.getInventoryRootID();
00317 if(LLAssetType::AT_CATEGORY == preferred_type)
00318 {
00319 return root_id;
00320 }
00321 if(root_id.notNull())
00322 {
00323 cat_array_t* cats = NULL;
00324 cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
00325 if(cats)
00326 {
00327 S32 count = cats->count();
00328 for(S32 i = 0; i < count; ++i)
00329 {
00330 if(cats->get(i)->getPreferredType() == preferred_type)
00331 {
00332 return cats->get(i)->getUUID();
00333 }
00334 }
00335 }
00336 }
00337 return LLUUID::null;
00338 }
00339
00340
00341
00342
00343
00344 LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id,
00345 LLAssetType::EType preferred_type,
00346 const LLString& pname)
00347 {
00348 LLUUID id;
00349 if(!isInventoryUsable())
00350 {
00351 llwarns << "Inventory is broken." << llendl;
00352 return id;
00353 }
00354
00355 id.generate();
00356 LLString name = pname;
00357 if(!pname.empty())
00358 {
00359 name.assign(pname);
00360 }
00361 else if((preferred_type >= LLAssetType::AT_TEXTURE) &&
00362 (preferred_type < LLAssetType::AT_COUNT))
00363 {
00364 name.assign(NEW_CATEGORY_NAMES[preferred_type]);
00365 }
00366 else
00367 {
00368 name.assign(NEW_CATEGORY_NAME);
00369 }
00370
00371
00372 LLPointer<LLViewerInventoryCategory> cat =
00373 new LLViewerInventoryCategory(id, parent_id, preferred_type, name, gAgent.getID());
00374 cat->setVersion(LLViewerInventoryCategory::VERSION_INITIAL);
00375 cat->setDescendentCount(0);
00376 LLCategoryUpdate update(cat->getParentUUID(), 1);
00377 accountForUpdate(update);
00378 updateCategory(cat);
00379
00380
00381
00382 LLMessageSystem* msg = gMessageSystem;
00383 msg->newMessage("CreateInventoryFolder");
00384 msg->nextBlock("AgentData");
00385 msg->addUUID("AgentID", gAgent.getID());
00386 msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID());
00387 msg->nextBlock("FolderData");
00388 cat->packMessage(msg);
00389 gAgent.sendReliableMessage();
00390
00391
00392 return id;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402 class LLAlwaysCollect : public LLInventoryCollectFunctor
00403 {
00404 public:
00405 virtual ~LLAlwaysCollect() {}
00406 virtual bool operator()(LLInventoryCategory* cat,
00407 LLInventoryItem* item)
00408 {
00409 return TRUE;
00410 }
00411 };
00412
00413 void LLInventoryModel::collectDescendents(const LLUUID& id,
00414 cat_array_t& cats,
00415 item_array_t& items,
00416 BOOL include_trash)
00417 {
00418 LLAlwaysCollect always;
00419 collectDescendentsIf(id, cats, items, include_trash, always);
00420 }
00421
00422 void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
00423 cat_array_t& cats,
00424 item_array_t& items,
00425 BOOL include_trash,
00426 LLInventoryCollectFunctor& add)
00427 {
00428
00429 if(!include_trash)
00430 {
00431 LLUUID trash_id(findCatUUID(LLAssetType::AT_TRASH));
00432 if(trash_id.notNull() && (trash_id == id))
00433 return;
00434 }
00435 cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id);
00436 if(cat_array)
00437 {
00438 S32 count = cat_array->count();
00439 for(S32 i = 0; i < count; ++i)
00440 {
00441 LLViewerInventoryCategory* cat = cat_array->get(i);
00442 if(add(cat,NULL))
00443 {
00444 cats.put(cat);
00445 }
00446 collectDescendentsIf(cat->getUUID(), cats, items, include_trash, add);
00447 }
00448 }
00449
00450
00451 LLViewerInventoryItem* item = NULL;
00452 item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
00453 if(item_array)
00454 {
00455 S32 count = item_array->count();
00456 for(S32 i = 0; i < count; ++i)
00457 {
00458 item = item_array->get(i);
00459 if(add(NULL, item))
00460 {
00461 items.put(item);
00462 }
00463 }
00464 }
00465 }
00466
00467
00468
00469 void LLInventoryModel::appendPath(const LLUUID& id, LLString& path)
00470 {
00471 LLString temp;
00472 LLInventoryObject* obj = getObject(id);
00473 LLUUID parent_id;
00474 if(obj) parent_id = obj->getParentUUID();
00475 LLString forward_slash("/");
00476 while(obj)
00477 {
00478 obj = getCategory(parent_id);
00479 if(obj)
00480 {
00481 temp.assign(forward_slash + obj->getName() + temp);
00482 parent_id = obj->getParentUUID();
00483 }
00484 }
00485 path.append(temp);
00486 }
00487
00488 bool LLInventoryModel::isInventoryUsable()
00489 {
00490 bool result = false;
00491 if(gAgent.getInventoryRootID().notNull() && mIsAgentInvUsable)
00492 {
00493 result = true;
00494 }
00495 return result;
00496 }
00497
00498
00499
00500
00501 U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item)
00502 {
00503 U32 mask = LLInventoryObserver::NONE;
00504 if(item->getUUID().isNull())
00505 {
00506 return mask;
00507 }
00508
00509 if(!isInventoryUsable())
00510 {
00511 llwarns << "Inventory is broken." << llendl;
00512 return mask;
00513 }
00514
00515 LLViewerInventoryItem* old_item = getItem(item->getUUID());
00516 if(old_item)
00517 {
00518
00519 LLUUID old_parent_id = old_item->getParentUUID();
00520 LLUUID new_parent_id = item->getParentUUID();
00521 if(old_parent_id != new_parent_id)
00522 {
00523
00524 item_array_t* item_array;
00525 item_array = get_ptr_in_map(mParentChildItemTree, old_parent_id);
00526 if(item_array)
00527 {
00528 item_array->removeObj(old_item);
00529 }
00530 item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id);
00531 if(item_array)
00532 {
00533 item_array->put(old_item);
00534 }
00535 mask |= LLInventoryObserver::STRUCTURE;
00536 }
00537 if(old_item->getName() != item->getName())
00538 {
00539 mask |= LLInventoryObserver::LABEL;
00540 }
00541 old_item->copyViewerItem(item);
00542 mask |= LLInventoryObserver::INTERNAL;
00543 }
00544 else
00545 {
00546
00547 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
00548 addItem(new_item);
00549
00550 if(item->getParentUUID().isNull())
00551 {
00552 LLUUID category_id = findCategoryUUIDForType(new_item->getType());
00553 new_item->setParent(category_id);
00554 item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, category_id);
00555 if( item_array )
00556 {
00557
00558 new_item->updateServer(TRUE);
00559 item_array->put(new_item);
00560 }
00561 else
00562 {
00563 llwarns << "Couldn't find parent-child item tree for " << new_item->getName() << llendl;
00564 }
00565 }
00566 else
00567 {
00568
00569
00570
00571
00572
00573 LLUUID parent_id = item->getParentUUID();
00574 if(parent_id == CATEGORIZE_LOST_AND_FOUND_ID)
00575 {
00576 parent_id = findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
00577 new_item->setParent(parent_id);
00578 }
00579 item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, parent_id);
00580 if(item_array)
00581 {
00582 item_array->put(new_item);
00583 }
00584 else
00585 {
00586
00587 llinfos << "Lost item: " << new_item->getUUID() << " - "
00588 << new_item->getName() << llendl;
00589 parent_id = findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
00590 new_item->setParent(parent_id);
00591 item_array = get_ptr_in_map(mParentChildItemTree, parent_id);
00592 if(item_array)
00593 {
00594
00595
00596 new_item->updateServer(TRUE);
00597 item_array->put(new_item);
00598 }
00599 else
00600 {
00601 llwarns << "Lost and found Not there!!" << llendl;
00602 }
00603 }
00604 }
00605 mask |= LLInventoryObserver::ADD;
00606 }
00607 if(item->getType() == LLAssetType::AT_CALLINGCARD)
00608 {
00609 mask |= LLInventoryObserver::CALLING_CARD;
00610 }
00611 addChangedMask(mask, item->getUUID());
00612 return mask;
00613 }
00614
00615
00616
00617 void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat)
00618 {
00619 if(cat->getUUID().isNull())
00620 {
00621 return;
00622 }
00623
00624 if(!isInventoryUsable())
00625 {
00626 llwarns << "Inventory is broken." << llendl;
00627 return;
00628 }
00629
00630 LLViewerInventoryCategory* old_cat = getCategory(cat->getUUID());
00631 if(old_cat)
00632 {
00633
00634 U32 mask = LLInventoryObserver::NONE;
00635 LLUUID old_parent_id = old_cat->getParentUUID();
00636 LLUUID new_parent_id = cat->getParentUUID();
00637 if(old_parent_id != new_parent_id)
00638 {
00639
00640 cat_array_t* cat_array;
00641 cat_array = get_ptr_in_map(mParentChildCategoryTree, old_parent_id);
00642 if(cat_array)
00643 {
00644 cat_array->removeObj(old_cat);
00645 }
00646 cat_array = get_ptr_in_map(mParentChildCategoryTree, new_parent_id);
00647 if(cat_array)
00648 {
00649 cat_array->put(old_cat);
00650 }
00651 mask |= LLInventoryObserver::STRUCTURE;
00652 }
00653 if(old_cat->getName() != cat->getName())
00654 {
00655 mask |= LLInventoryObserver::LABEL;
00656 }
00657 old_cat->copyViewerCategory(cat);
00658 addChangedMask(mask, cat->getUUID());
00659 }
00660 else
00661 {
00662
00663 LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat->getParentUUID());
00664 new_cat->copyViewerCategory(cat);
00665 addCategory(new_cat);
00666
00667
00668 cat_array_t* cat_array;
00669 cat_array = get_ptr_in_map(mParentChildCategoryTree, cat->getParentUUID());
00670 if(cat_array)
00671 {
00672 cat_array->put(new_cat);
00673 }
00674
00675
00676 cat_array_t* catsp = new cat_array_t;
00677 item_array_t* itemsp = new item_array_t;
00678 mParentChildCategoryTree[new_cat->getUUID()] = catsp;
00679 mParentChildItemTree[new_cat->getUUID()] = itemsp;
00680 addChangedMask(LLInventoryObserver::ADD, cat->getUUID());
00681 }
00682 }
00683
00684 void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id)
00685 {
00686 lldebugs << "LLInventoryModel::moveObject()" << llendl;
00687 if(!isInventoryUsable())
00688 {
00689 llwarns << "Inventory is broken." << llendl;
00690 return;
00691 }
00692
00693 if((object_id == cat_id) || !is_in_map(mCategoryMap, cat_id))
00694 {
00695 llwarns << "Could not move inventory object " << object_id << " to "
00696 << cat_id << llendl;
00697 return;
00698 }
00699 LLViewerInventoryCategory* cat = getCategory(object_id);
00700 if(cat && (cat->getParentUUID() != cat_id))
00701 {
00702 cat_array_t* cat_array;
00703 cat_array = get_ptr_in_map(mParentChildCategoryTree, cat->getParentUUID());
00704 if(cat_array) cat_array->removeObj(cat);
00705 cat_array = get_ptr_in_map(mParentChildCategoryTree, cat_id);
00706 cat->setParent(cat_id);
00707 if(cat_array) cat_array->put(cat);
00708 addChangedMask(LLInventoryObserver::STRUCTURE, object_id);
00709 return;
00710 }
00711 LLViewerInventoryItem* item = getItem(object_id);
00712 if(item && (item->getParentUUID() != cat_id))
00713 {
00714 item_array_t* item_array;
00715 item_array = get_ptr_in_map(mParentChildItemTree, item->getParentUUID());
00716 if(item_array) item_array->removeObj(item);
00717 item_array = get_ptr_in_map(mParentChildItemTree, cat_id);
00718 item->setParent(cat_id);
00719 if(item_array) item_array->put(item);
00720 addChangedMask(LLInventoryObserver::STRUCTURE, object_id);
00721 return;
00722 }
00723 }
00724
00725
00726 void LLInventoryModel::deleteObject(const LLUUID& id)
00727 {
00728 lldebugs << "LLInventoryModel::deleteObject()" << llendl;
00729 LLPointer<LLInventoryObject> obj = getObject(id);
00730 if(obj)
00731 {
00732 lldebugs << "Deleting inventory object " << id << llendl;
00733 mLastItem = NULL;
00734 LLUUID parent_id = obj->getParentUUID();
00735 mCategoryMap.erase(id);
00736 mItemMap.erase(id);
00737
00738 item_array_t* item_list = get_ptr_in_map(mParentChildItemTree, parent_id);
00739 if(item_list)
00740 {
00741 LLViewerInventoryItem* item = (LLViewerInventoryItem*)((LLInventoryObject*)obj);
00742 item_list->removeObj(item);
00743 }
00744 cat_array_t* cat_list = get_ptr_in_map(mParentChildCategoryTree, parent_id);
00745 if(cat_list)
00746 {
00747 LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)((LLInventoryObject*)obj);
00748 cat_list->removeObj(cat);
00749 }
00750 item_list = get_ptr_in_map(mParentChildItemTree, id);
00751 if(item_list)
00752 {
00753 delete item_list;
00754 mParentChildItemTree.erase(id);
00755 }
00756 cat_list = get_ptr_in_map(mParentChildCategoryTree, id);
00757 if(cat_list)
00758 {
00759 delete cat_list;
00760 mParentChildCategoryTree.erase(id);
00761 }
00762 addChangedMask(LLInventoryObserver::REMOVE, id);
00763 obj = NULL;
00764 }
00765 }
00766
00767
00768
00769
00770
00771
00772 void LLInventoryModel::purgeDescendentsOf(const LLUUID& id)
00773 {
00774 EHasChildren children = categoryHasChildren(id);
00775 if(children == CHILDREN_NO)
00776 {
00777 llinfos << "Not purging descendents of " << id << llendl;
00778 return;
00779 }
00780 LLPointer<LLViewerInventoryCategory> cat = getCategory(id);
00781 if(cat.notNull())
00782 {
00783
00784 llinfos << "LLInventoryModel::purgeDescendentsOf " << cat->getName()
00785 << llendl;
00786 S32 descendents = cat->getDescendentCount();
00787 if(descendents > 0)
00788 {
00789 LLCategoryUpdate up(id, -descendents);
00790 accountForUpdate(up);
00791 }
00792
00793
00794
00795
00796 cat->setDescendentCount(0);
00797
00798
00799 LLMessageSystem* msg = gMessageSystem;
00800 msg->newMessage("PurgeInventoryDescendents");
00801 msg->nextBlock("AgentData");
00802 msg->addUUID("AgentID", gAgent.getID());
00803 msg->addUUID("SessionID", gAgent.getSessionID());
00804 msg->nextBlock("InventoryData");
00805 msg->addUUID("FolderID", id);
00806 gAgent.sendReliableMessage();
00807
00808
00809 cat_array_t categories;
00810 item_array_t items;
00811 collectDescendents(id,
00812 categories,
00813 items,
00814 INCLUDE_TRASH);
00815 S32 count = items.count();
00816 S32 i;
00817 for(i = 0; i < count; ++i)
00818 {
00819 deleteObject(items.get(i)->getUUID());
00820 }
00821 count = categories.count();
00822 for(i = 0; i < count; ++i)
00823 {
00824 deleteObject(categories.get(i)->getUUID());
00825 }
00826 }
00827 }
00828
00829 void LLInventoryModel::deleteFromServer(LLDynamicArray<LLUUID>& category_ids,
00830 LLDynamicArray<LLUUID>& item_ids)
00831 {
00832
00833
00834
00835
00836
00837 std::set<LLUUID> ignore_parents;
00838 update_map_t inc_parents;
00839
00840 S32 i;
00841 S32 count = category_ids.count();
00842 BOOL start_new_message = TRUE;
00843 LLMessageSystem* msg = gMessageSystem;
00844 LLPointer<LLViewerInventoryCategory> cat;
00845 for(i = 0; i < count; i++)
00846 {
00847 if(start_new_message)
00848 {
00849 start_new_message = FALSE;
00850 msg->newMessageFast(_PREHASH_RemoveInventoryObjects);
00851 msg->nextBlockFast(_PREHASH_AgentData);
00852 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00853 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00854 }
00855 LLUUID cat_id = category_ids.get(i);
00856
00857 msg->nextBlockFast(_PREHASH_FolderData);
00858 msg->addUUIDFast(_PREHASH_FolderID, cat_id);
00859 cat = getCategory(cat_id);
00860 ignore_parents.insert(cat_id);
00861 addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, cat_id);
00862 if(cat.notNull() && (ignore_parents.find(cat->getParentUUID())==ignore_parents.end()))
00863 {
00864 --inc_parents[cat->getParentUUID()];
00865 }
00866 if(msg->isSendFullFast(_PREHASH_FolderData))
00867 {
00868 start_new_message = TRUE;
00869 msg->nextBlockFast(_PREHASH_ItemData);
00870 msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
00871 gAgent.sendReliableMessage();
00872 accountForUpdate(inc_parents);
00873 inc_parents.clear();
00874 }
00875 }
00876
00877 count = item_ids.count();
00878 std::set<LLUUID>::iterator not_ignored = ignore_parents.end();
00879 LLPointer<LLViewerInventoryItem> item;
00880 if((0 == count) && (!start_new_message))
00881 {
00882 msg->nextBlockFast(_PREHASH_ItemData);
00883 msg->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
00884 }
00885 for(i = 0; i < count; i++)
00886 {
00887 if(start_new_message)
00888 {
00889 start_new_message = FALSE;
00890 msg->newMessageFast(_PREHASH_RemoveInventoryObjects);
00891 msg->nextBlockFast(_PREHASH_AgentData);
00892 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00893 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00894 msg->nextBlockFast(_PREHASH_FolderData);
00895 msg->addUUIDFast(_PREHASH_FolderID, LLUUID::null);
00896 }
00897 LLUUID item_id = item_ids.get(i);
00898 msg->nextBlockFast(_PREHASH_ItemData);
00899 msg->addUUIDFast(_PREHASH_ItemID, item_id);
00900 item = getItem(item_id);
00901 addChangedMask(LLInventoryObserver::REMOVE | LLInventoryObserver::STRUCTURE, item_id);
00902 if(item.notNull() && (ignore_parents.find(item->getParentUUID()) == not_ignored))
00903 {
00904 --inc_parents[item->getParentUUID()];
00905 }
00906 if(msg->isSendFullFast(_PREHASH_ItemData))
00907 {
00908 start_new_message = TRUE;
00909 gAgent.sendReliableMessage();
00910 accountForUpdate(inc_parents);
00911 inc_parents.clear();
00912 }
00913 }
00914 if(!start_new_message)
00915 {
00916 gAgent.sendReliableMessage();
00917 accountForUpdate(inc_parents);
00918 }
00919 }
00920
00921
00922
00923 void LLInventoryModel::addObserver(LLInventoryObserver* observer)
00924 {
00925 mObservers.insert(observer);
00926 }
00927
00928 void LLInventoryModel::removeObserver(LLInventoryObserver* observer)
00929 {
00930 mObservers.erase(observer);
00931 }
00932
00933 BOOL LLInventoryModel::containsObserver(LLInventoryObserver* observer)
00934 {
00935 return mObservers.find(observer) != mObservers.end();
00936 }
00937
00938
00939
00940
00941 void LLInventoryModel::notifyObservers()
00942 {
00943 for (observer_list_t::iterator iter = mObservers.begin();
00944 iter != mObservers.end(); )
00945 {
00946 LLInventoryObserver* observer = *iter;
00947 observer->changed(mModifyMask);
00948
00949 iter = mObservers.upper_bound(observer);
00950 }
00951
00952 mModifyMask = LLInventoryObserver::NONE;
00953 mChangedItemIDs.clear();
00954 }
00955
00956
00957
00958 void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)
00959 {
00960 mModifyMask |= mask;
00961 if (referent.notNull())
00962 {
00963 mChangedItemIDs.insert(referent);
00964 }
00965 }
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989 void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
00990 {
00991 LLViewerInventoryCategory* cat = getCategory(folder_id);
00992 if(!cat)
00993 {
00994 llwarns << "Asked to fetch descendents of non-existent folder: "
00995 << folder_id << llendl;
00996 return;
00997 }
00998
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009 if(!cat->fetchDescendents())
01010 {
01011
01012 }
01013 }
01014
01015
01016 LLAlertDialog* LLInventoryModel::fetchDescendentsResponder::sRetryDialog=NULL;
01017 LLSD LLInventoryModel::fetchDescendentsResponder::sRetrySD;
01018
01019 bool LLInventoryModel::isBulkFetchProcessingComplete()
01020 {
01021 return ( (sFetchQueue.empty()
01022 && sBulkFetchMap.empty()
01023 && sBulkFetchCount==0) ? TRUE : FALSE ) ;
01024 }
01025
01026
01027 void LLInventoryModel::fetchDescendentsResponder::result(const LLSD& content)
01028 {
01029 if (content.has("folders"))
01030 {
01031 for(LLSD::array_const_iterator folder_it = content["folders"].beginArray();
01032 folder_it != content["folders"].endArray();
01033 ++folder_it)
01034 {
01035 LLSD folder_sd = *folder_it;
01036
01037
01038 LLUUID agent_id = folder_sd["agent-id"];
01039
01040 if(agent_id != gAgent.getID())
01041 {
01042 llwarns << "Got a UpdateInventoryItem for the wrong agent."
01043 << llendl;
01044 break;
01045 }
01046 LLUUID parent_id = folder_sd["folder-id"];
01047 LLUUID owner_id = folder_sd["owner-id"];
01048 S32 version = (S32)folder_sd["version"].asInteger();
01049 S32 descendents = (S32)folder_sd["descendents"].asInteger();
01050 LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
01051 for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray();
01052 category_it != folder_sd["categories"].endArray();
01053 ++category_it)
01054 {
01055 LLSD category = *category_it;
01056 tcategory->fromLLSD(category);
01057
01058 if (sFullFetchStarted)
01059 {
01060 sFetchQueue.push_back(tcategory->getUUID());
01061 }
01062 else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
01063 {
01064 gInventory.updateCategory(tcategory);
01065 }
01066
01067 }
01068 LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
01069 for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
01070 item_it != folder_sd["items"].endArray();
01071 ++item_it)
01072 {
01073 LLSD item = *item_it;
01074 titem->unpackMessage(item);
01075
01076 gInventory.updateItem(titem);
01077 }
01078
01079
01080 LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
01081 if(cat)
01082 {
01083 cat->setVersion(version);
01084 cat->setDescendentCount(descendents);
01085 }
01086
01087 }
01088 }
01089
01090 if (content.has("bad-folders"))
01091 {
01092 for(LLSD::array_const_iterator folder_it = content["bad-folders"].beginArray();
01093 folder_it != content["bad-folders"].endArray();
01094 ++folder_it)
01095 {
01096 LLSD folder_sd = *folder_it;
01097
01098
01099 llinfos << "Folder " << folder_sd["folder-id"].asString()
01100 << "Error: " << folder_sd["error"].asString() << llendl;
01101 }
01102 }
01103
01104 LLInventoryModel::incrBulkFetch(-1);
01105
01106 if (isBulkFetchProcessingComplete())
01107 {
01108 llinfos << "Inventory fetch completed" << llendl;
01109 if (sFullFetchStarted)
01110 {
01111 sAllFoldersFetched = TRUE;
01112 }
01113 stopBackgroundFetch();
01114 }
01115
01116 gInventory.notifyObservers();
01117 }
01118
01119
01120 void LLInventoryModel::fetchDescendentsResponder::error(U32 status, const std::string& reason)
01121 {
01122 llinfos << "fetchDescendentsResponder::error "
01123 << status << ": " << reason << llendl;
01124
01125 LLInventoryModel::incrBulkFetch(-1);
01126
01127 if (status==499)
01128 {
01129 for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray();
01130 folder_it != mRequestSD["folders"].endArray();
01131 ++folder_it)
01132 {
01133 LLSD folder_sd = *folder_it;
01134 sRetrySD["folders"].append(folder_sd);
01135 }
01136 sMinTimeBetweenFetches = 10.0f;
01137
01138 if (!sRetryDialog)
01139 {
01140 sRetryDialog = gViewerWindow->alertXml("RetryFetchInventoryDescendents", onClickRetry, this);
01141 }
01142 }
01143 else
01144 {
01145 if (isBulkFetchProcessingComplete())
01146 {
01147 if (sFullFetchStarted)
01148 {
01149 sAllFoldersFetched = TRUE;
01150 }
01151 stopBackgroundFetch();
01152 }
01153 }
01154 gInventory.notifyObservers();
01155 }
01156
01157 void LLInventoryModel::fetchDescendentsResponder::onClickRetry(S32 option, void* userdata)
01158 {
01159 if (option == 0)
01160 {
01161 std::string url;
01162
01163 LLViewerRegion * agent_region = gAgent.getRegion();
01164 if (agent_region)
01165 {
01166 url = agent_region->getCapability("FetchInventoryDescendents");
01167 }
01168
01169 if (!url.empty())
01170 {
01171 LLSD body = sRetrySD;
01172 LLInventoryModel::incrBulkFetch(1);
01173 LLHTTPClient::post(url, body, new LLInventoryModel::fetchDescendentsResponder(body),300);
01174 }
01175 }
01176 else
01177 {
01178 if (isBulkFetchProcessingComplete())
01179 {
01180 if (sFullFetchStarted)
01181 {
01182 sAllFoldersFetched = TRUE;
01183 }
01184 stopBackgroundFetch();
01185 }
01186 }
01187 sRetryDialog=NULL;
01188 sRetrySD.clear();
01189 }
01190
01191
01192 void LLInventoryModel::bulkFetch(std::string url)
01193 {
01194
01195
01196
01197
01198
01199 S16 max_concurrent_fetches=8;
01200 F32 new_min_time = 0.5f;
01201 if (sMinTimeBetweenFetches <= new_min_time) sMinTimeBetweenFetches=new_min_time;
01202
01203 if(gDisconnected
01204 || sBulkFetchCount > max_concurrent_fetches
01205 || sFetchTimer.getElapsedTimeF32() < sMinTimeBetweenFetches)
01206 {
01207 return;
01208 }
01209
01210
01211
01212
01213 U32 folder_count=0;
01214 U32 max_batch_size=10;
01215 while( !(sFetchQueue.empty() ) )
01216 {
01217 LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
01218
01219 if (cat)
01220 {
01221 if ( !gInventory.isCategoryComplete(cat->getUUID()) )
01222 {
01223 sBulkFetchMap[(cat->getUUID())] = cat;
01224 }
01225 else if (sFullFetchStarted)
01226 {
01227
01228 parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
01229 if (cat_it != gInventory.mParentChildCategoryTree.end())
01230 {
01231 cat_array_t* child_categories = cat_it->second;
01232
01233 for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
01234 {
01235 sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
01236 }
01237 }
01238
01239 }
01240 }
01241 sFetchQueue.pop_front();
01242 }
01243
01244
01245 if (!sBulkFetchMap.empty())
01246 {
01247 U32 sort_order = gSavedSettings.getU32("InventorySortOrder") & 0x1;
01248
01249 LLSD body;
01250
01251 cat_map_t::iterator iter=sBulkFetchMap.begin();
01252 while( iter!=sBulkFetchMap.end() && (folder_count < max_batch_size) )
01253 {
01254 LLViewerInventoryCategory* cat = iter->second;
01255
01256 if (cat && !gInventory.isCategoryComplete(cat->getUUID()) )
01257 {
01258 BOOL fetchItems=TRUE;
01259 if ( sFullFetchStarted
01260 && gInventory.isCategoryComplete(cat->getUUID()) )
01261 {
01262 fetchItems=FALSE;
01263 }
01264
01265 LLSD folder_sd;
01266 folder_sd["folder-id"] = cat->getUUID();
01267 folder_sd["owner-id"] = cat->getOwnerID();
01268 folder_sd["sort-order"] = (LLSD::Integer)sort_order;
01269 folder_sd["fetch-folders"] = (LLSD::Boolean)sFullFetchStarted;
01270 folder_sd["fetch-items"] = (LLSD::Boolean)fetchItems;
01271 body["folders"].append(folder_sd);
01272
01273 folder_count++;
01274 }
01275 sBulkFetchMap.erase(iter);
01276 iter=sBulkFetchMap.begin();
01277 }
01278
01279 if (iter == sBulkFetchMap.end()) sBulkFetchMap.clear();
01280
01281 if (folder_count > 0)
01282 {
01283 sBulkFetchCount++;
01284
01285 LLHTTPClient::post(url, body, new LLInventoryModel::fetchDescendentsResponder(body));
01286 sFetchTimer.reset();
01287 }
01288
01289 }
01290
01291 if (isBulkFetchProcessingComplete())
01292 {
01293 if (sFullFetchStarted)
01294 {
01295 sAllFoldersFetched = TRUE;
01296 }
01297 stopBackgroundFetch();
01298 }
01299 }
01300
01301
01302 bool LLInventoryModel::isEverythingFetched()
01303 {
01304 return (sAllFoldersFetched ? true : false);
01305 }
01306
01307
01308 BOOL LLInventoryModel::backgroundFetchActive()
01309 {
01310 return sBackgroundFetchActive;
01311 }
01312
01313
01314 void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id)
01315 {
01316 if (!sAllFoldersFetched)
01317 {
01318 sBackgroundFetchActive = TRUE;
01319 if (cat_id.isNull())
01320 {
01321 if (!sFullFetchStarted)
01322 {
01323 sFullFetchStarted = TRUE;
01324 sFetchQueue.push_back(gInventoryLibraryRoot);
01325 sFetchQueue.push_back(gAgent.getInventoryRootID());
01326 gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
01327 }
01328 }
01329 else
01330 {
01331
01332 if (sFetchQueue.empty() || sFetchQueue.front() != cat_id)
01333 {
01334 sFetchQueue.push_front(cat_id);
01335 gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL);
01336 }
01337 }
01338 }
01339 }
01340
01341
01342 void LLInventoryModel::stopBackgroundFetch()
01343 {
01344 if (sBackgroundFetchActive)
01345 {
01346 sBackgroundFetchActive = FALSE;
01347 gIdleCallbacks.deleteFunction(&LLInventoryModel::backgroundFetch, NULL);
01348 sBulkFetchCount=0;
01349 sMinTimeBetweenFetches=0.0f;
01350
01351 }
01352 }
01353
01354
01355 void LLInventoryModel::backgroundFetch(void*)
01356 {
01357 if (sBackgroundFetchActive)
01358 {
01359
01360 std::string url;
01361
01362 LLViewerRegion * agent_region = gAgent.getRegion();
01363 if (agent_region)
01364 {
01365 url = agent_region->getCapability("FetchInventoryDescendents");
01366 }
01367
01368 if (!url.empty())
01369 {
01370 bulkFetch(url);
01371 return;
01372 }
01373
01374
01375
01376 if (sFetchQueue.empty())
01377 {
01378 llinfos << "Inventory fetch completed" << llendl;
01379 if (sFullFetchStarted)
01380 {
01381 sAllFoldersFetched = TRUE;
01382 }
01383 stopBackgroundFetch();
01384 return;
01385 }
01386
01387 F32 fast_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.1f);
01388 F32 slow_fetch_time = lerp(sMinTimeBetweenFetches, sMaxTimeBetweenFetches, 0.5f);
01389 if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() > slow_fetch_time)
01390 {
01391
01392 sMinTimeBetweenFetches = llmin(sMinTimeBetweenFetches * 2.f, 10.f);
01393 sMaxTimeBetweenFetches = llmin(sMaxTimeBetweenFetches * 2.f, 120.f);
01394 llinfos << "Inventory fetch times grown to (" << sMinTimeBetweenFetches << ", " << sMaxTimeBetweenFetches << ")" << llendl;
01395
01396 sTimelyFetchPending = FALSE;
01397 }
01398
01399 while(1)
01400 {
01401 if (sFetchQueue.empty())
01402 {
01403 break;
01404 }
01405
01406 if(gDisconnected)
01407 {
01408
01409 break;
01410 }
01411
01412 LLViewerInventoryCategory* cat = gInventory.getCategory(sFetchQueue.front());
01413
01414
01415 if (!cat)
01416 {
01417 sFetchQueue.pop_front();
01418 continue;
01419 }
01420
01421 if (sFetchTimer.getElapsedTimeF32() > sMinTimeBetweenFetches &&
01422 LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
01423 {
01424
01425
01426 if (cat->fetchDescendents())
01427 {
01428 sFetchTimer.reset();
01429 sTimelyFetchPending = TRUE;
01430 }
01431 else
01432 {
01433
01434
01435
01436 break;
01437 }
01438 }
01439
01440 else if (gInventory.isCategoryComplete(sFetchQueue.front()))
01441 {
01442
01443 sFetchQueue.pop_front();
01444
01445
01446 parent_cat_map_t::iterator cat_it = gInventory.mParentChildCategoryTree.find(cat->getUUID());
01447 if (cat_it != gInventory.mParentChildCategoryTree.end())
01448 {
01449 cat_array_t* child_categories = cat_it->second;
01450
01451 for (S32 child_num = 0; child_num < child_categories->count(); child_num++)
01452 {
01453 sFetchQueue.push_back(child_categories->get(child_num)->getUUID());
01454 }
01455 }
01456
01457
01458 if (sTimelyFetchPending && sFetchTimer.getElapsedTimeF32() < fast_fetch_time)
01459 {
01460
01461 sMinTimeBetweenFetches = llmax(sMinTimeBetweenFetches * 0.8f, 0.3f);
01462 sMaxTimeBetweenFetches = llmax(sMaxTimeBetweenFetches * 0.8f, 10.f);
01463
01464 }
01465
01466 sTimelyFetchPending = FALSE;
01467 continue;
01468 }
01469 else if (sFetchTimer.getElapsedTimeF32() > sMaxTimeBetweenFetches)
01470 {
01471
01472
01473 LLUUID fetch_id = sFetchQueue.front();
01474 sFetchQueue.pop_front();
01475
01476 if (sNumFetchRetries++ < MAX_FETCH_RETRIES)
01477 {
01478
01479 sFetchQueue.push_back(fetch_id);
01480 }
01481 sTimelyFetchPending = FALSE;
01482 sFetchTimer.reset();
01483 break;
01484 }
01485
01486
01487 break;
01488 }
01489 }
01490 }
01491
01492 void LLInventoryModel::cache(
01493 const LLUUID& parent_folder_id,
01494 const LLUUID& agent_id)
01495 {
01496 lldebugs << "Caching " << parent_folder_id << " for " << agent_id
01497 << llendl;
01498 LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id);
01499 if(!root_cat) return;
01500 cat_array_t categories;
01501 categories.put(root_cat);
01502 item_array_t items;
01503
01504 LLCanCache can_cache(this);
01505 can_cache(root_cat, NULL);
01506 collectDescendentsIf(
01507 parent_folder_id,
01508 categories,
01509 items,
01510 INCLUDE_TRASH,
01511 can_cache);
01512 char agent_id_str[UUID_STR_LENGTH];
01513 char inventory_filename[LL_MAX_PATH];
01514 agent_id.toString(agent_id_str);
01515 std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, agent_id_str));
01516 snprintf(
01517 inventory_filename,
01518 LL_MAX_PATH,
01519 CACHE_FORMAT_STRING,
01520 path.c_str());
01521 saveToFile(inventory_filename, categories, items);
01522 std::string gzip_filename(inventory_filename);
01523 gzip_filename.append(".gz");
01524 if(gzip_file(inventory_filename, gzip_filename.c_str()))
01525 {
01526 lldebugs << "Successfully compressed " << inventory_filename << llendl;
01527 LLFile::remove(inventory_filename);
01528 }
01529 else
01530 {
01531 llwarns << "Unable to compress " << inventory_filename << llendl;
01532 }
01533 }
01534
01535
01536 void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)
01537 {
01538
01539 if(category)
01540 {
01541
01542 mCategoryMap[category->getUUID()] = category;
01543
01544 }
01545 }
01546
01547 void LLInventoryModel::addItem(LLViewerInventoryItem* item)
01548 {
01549
01550 if(item)
01551 {
01552 mItemMap[item->getUUID()] = item;
01553
01554 }
01555 }
01556
01557
01558 void LLInventoryModel::empty()
01559 {
01560
01561 std::for_each(
01562 mParentChildCategoryTree.begin(),
01563 mParentChildCategoryTree.end(),
01564 DeletePairedPointer());
01565 mParentChildCategoryTree.clear();
01566 std::for_each(
01567 mParentChildItemTree.begin(),
01568 mParentChildItemTree.end(),
01569 DeletePairedPointer());
01570 mParentChildItemTree.clear();
01571 mCategoryMap.clear();
01572 mItemMap.clear();
01573 mLastItem = NULL;
01574
01575 }
01576
01577 void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update)
01578 {
01579 LLViewerInventoryCategory* cat = getCategory(update.mCategoryID);
01580 if(cat)
01581 {
01582 bool accounted = false;
01583 S32 version = cat->getVersion();
01584 if(version != LLViewerInventoryCategory::VERSION_UNKNOWN)
01585 {
01586 S32 descendents_server = cat->getDescendentCount();
01587 LLInventoryModel::cat_array_t* cats;
01588 LLInventoryModel::item_array_t* items;
01589 getDirectDescendentsOf(update.mCategoryID, cats, items);
01590 S32 descendents_actual = 0;
01591 if(cats && items)
01592 {
01593 descendents_actual = cats->count() + items->count();
01594 }
01595 if(descendents_server == descendents_actual)
01596 {
01597 accounted = true;
01598 descendents_actual += update.mDescendentDelta;
01599 cat->setDescendentCount(descendents_actual);
01600 cat->setVersion(++version);
01601 llinfos << "accounted: '" << cat->getName() << "' "
01602 << version << " with " << descendents_actual
01603 << " descendents." << llendl;
01604 }
01605 }
01606 if(!accounted)
01607 {
01608 lldebugs << "No accounting for: '" << cat->getName() << "' "
01609 << version << llendl;
01610 }
01611 }
01612 else
01613 {
01614 llwarns << "No category found for update " << update.mCategoryID
01615 << llendl;
01616 }
01617 }
01618
01619 void LLInventoryModel::accountForUpdate(
01620 const LLInventoryModel::update_list_t& update)
01621 {
01622 update_list_t::const_iterator it = update.begin();
01623 update_list_t::const_iterator end = update.end();
01624 for(; it != end; ++it)
01625 {
01626 accountForUpdate(*it);
01627 }
01628 }
01629
01630 void LLInventoryModel::accountForUpdate(
01631 const LLInventoryModel::update_map_t& update)
01632 {
01633 LLCategoryUpdate up;
01634 update_map_t::const_iterator it = update.begin();
01635 update_map_t::const_iterator end = update.end();
01636 for(; it != end; ++it)
01637 {
01638 up.mCategoryID = (*it).first;
01639 up.mDescendentDelta = (*it).second.mValue;
01640 accountForUpdate(up);
01641 }
01642 }
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685 LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(
01686 const LLUUID& cat_id) const
01687 {
01688 LLViewerInventoryCategory* cat = getCategory(cat_id);
01689 if(!cat) return CHILDREN_NO;
01690 if(cat->getDescendentCount() > 0)
01691 {
01692 return CHILDREN_YES;
01693 }
01694 if(cat->getDescendentCount() == 0)
01695 {
01696 return CHILDREN_NO;
01697 }
01698 if((cat->getDescendentCount() == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
01699 || (cat->getVersion() == LLViewerInventoryCategory::VERSION_UNKNOWN))
01700 {
01701 return CHILDREN_MAYBE;
01702 }
01703
01704
01705 parent_cat_map_t::const_iterator cat_it = mParentChildCategoryTree.find(cat->getUUID());
01706 if (cat_it != mParentChildCategoryTree.end() && cat_it->second->count() > 0)
01707 {
01708 return CHILDREN_YES;
01709 }
01710 parent_item_map_t::const_iterator item_it = mParentChildItemTree.find(cat->getUUID());
01711 if (item_it != mParentChildItemTree.end() && item_it->second->count() > 0)
01712 {
01713 return CHILDREN_YES;
01714 }
01715
01716 return CHILDREN_NO;
01717 }
01718
01719 bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const
01720 {
01721 LLViewerInventoryCategory* cat = getCategory(cat_id);
01722 if(cat && (cat->getVersion()!=LLViewerInventoryCategory::VERSION_UNKNOWN))
01723 {
01724 S32 descendents_server = cat->getDescendentCount();
01725 LLInventoryModel::cat_array_t* cats;
01726 LLInventoryModel::item_array_t* items;
01727 getDirectDescendentsOf(cat_id, cats, items);
01728 S32 descendents_actual = 0;
01729 if(cats && items)
01730 {
01731 descendents_actual = cats->count() + items->count();
01732 }
01733 if(descendents_server == descendents_actual)
01734 {
01735 return true;
01736 }
01737 }
01738 return false;
01739 }
01740
01741 bool LLInventoryModel::loadSkeleton(
01742 const LLInventoryModel::options_t& options,
01743 const LLUUID& owner_id)
01744 {
01745 lldebugs << "importing inventory skeleton for " << owner_id << llendl;
01746
01747 typedef std::set<LLPointer<LLViewerInventoryCategory>, InventoryIDPtrLess> cat_set_t;
01748 cat_set_t temp_cats;
01749
01750 update_map_t child_counts;
01751
01752 LLUUID id;
01753 LLAssetType::EType preferred_type;
01754 bool rv = true;
01755 for(options_t::const_iterator it = options.begin(); it < options.end(); ++it)
01756 {
01757 LLPointer<LLViewerInventoryCategory> cat = new LLViewerInventoryCategory(owner_id);
01758 response_t::const_iterator no_response = (*it).end();
01759 response_t::const_iterator skel;
01760 skel = (*it).find("name");
01761 if(skel == no_response) goto clean_cat;
01762 cat->rename(LLString((*skel).second.c_str()));
01763 skel = (*it).find("folder_id");
01764 if(skel == no_response) goto clean_cat;
01765 id.set((*skel).second.c_str());
01766
01767 if(id.isNull()) goto clean_cat;
01768 cat->setUUID(id);
01769 skel = (*it).find("parent_id");
01770 if(skel == no_response) goto clean_cat;
01771 id.set((*skel).second.c_str());
01772 cat->setParent(id);
01773 skel = (*it).find("type_default");
01774 if(skel == no_response)
01775 {
01776 preferred_type = LLAssetType::AT_NONE;
01777 }
01778 else
01779 {
01780 S32 t = atoi((*skel).second.c_str());
01781 preferred_type = (LLAssetType::EType)t;
01782 }
01783 cat->setPreferredType(preferred_type);
01784 skel = (*it).find("version");
01785 if(skel == no_response) goto clean_cat;
01786 cat->setVersion(atoi((*skel).second.c_str()));
01787 temp_cats.insert(cat);
01788 continue;
01789 clean_cat:
01790 llwarns << "Unable to import near " << cat->getName() << llendl;
01791 rv = false;
01792
01793 }
01794
01795 S32 cached_category_count = 0;
01796 S32 cached_item_count = 0;
01797 if(!temp_cats.empty())
01798 {
01799 cat_array_t categories;
01800 item_array_t items;
01801 char owner_id_str[UUID_STR_LENGTH];
01802 owner_id.toString(owner_id_str);
01803 std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str));
01804 char inventory_filename[LL_MAX_PATH];
01805 snprintf(
01806 inventory_filename,
01807 LL_MAX_PATH,
01808 CACHE_FORMAT_STRING,
01809 path.c_str());
01810 const S32 NO_VERSION = LLViewerInventoryCategory::VERSION_UNKNOWN;
01811 std::string gzip_filename(inventory_filename);
01812 gzip_filename.append(".gz");
01813 LLFILE* fp = LLFile::fopen(gzip_filename.c_str(), "rb");
01814 bool remove_inventory_file = false;
01815 if(fp)
01816 {
01817 fclose(fp);
01818 fp = NULL;
01819 if(gunzip_file(gzip_filename.c_str(), inventory_filename))
01820 {
01821
01822
01823
01824 remove_inventory_file = true;
01825 }
01826 else
01827 {
01828 llinfos << "Unable to gunzip " << gzip_filename << llendl;
01829 }
01830 }
01831 if(loadFromFile(inventory_filename, categories, items))
01832 {
01833
01834
01835
01836
01837 S32 count = categories.count();
01838 cat_set_t::iterator not_cached = temp_cats.end();
01839 std::set<LLUUID> cached_ids;
01840 for(S32 i = 0; i < count; ++i)
01841 {
01842 LLViewerInventoryCategory* cat = categories[i];
01843 cat_set_t::iterator cit = temp_cats.find(cat);
01844 if (cit == temp_cats.end())
01845 {
01846 continue;
01847 }
01848 LLViewerInventoryCategory* tcat = *cit;
01849
01850
01851
01852 if(cit == not_cached)
01853 {
01854 continue;
01855 }
01856 if(cat->getVersion() != tcat->getVersion())
01857 {
01858
01859
01860
01861 tcat->setVersion(NO_VERSION);
01862 }
01863 else
01864 {
01865 cached_ids.insert(tcat->getUUID());
01866 }
01867 }
01868
01869
01870 std::set<LLUUID>::iterator not_cached_id = cached_ids.end();
01871 cached_category_count = cached_ids.size();
01872 for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it)
01873 {
01874 if(cached_ids.find((*it)->getUUID()) == not_cached_id)
01875 {
01876
01877
01878
01879 LLViewerInventoryCategory *llvic = (*it);
01880 llvic->setVersion(NO_VERSION);
01881 }
01882 addCategory(*it);
01883 ++child_counts[(*it)->getParentUUID()];
01884 }
01885
01886
01887
01888 count = items.count();
01889 cat_map_t::iterator unparented = mCategoryMap.end();
01890 for(int i = 0; i < count; ++i)
01891 {
01892 cat_map_t::iterator cit = mCategoryMap.find(items[i]->getParentUUID());
01893
01894 if(cit != unparented)
01895 {
01896 LLViewerInventoryCategory* cat = cit->second;
01897 if(cat->getVersion() != NO_VERSION)
01898 {
01899 addItem(items[i]);
01900 cached_item_count += 1;
01901 ++child_counts[cat->getUUID()];
01902 }
01903 }
01904 }
01905 }
01906 else
01907 {
01908
01909
01910 for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it)
01911 {
01912 LLViewerInventoryCategory *llvic = (*it);
01913 llvic->setVersion(NO_VERSION);
01914 addCategory(*it);
01915 }
01916 }
01917
01918
01919
01920
01921 update_map_t::iterator no_child_counts = child_counts.end();
01922 update_map_t::iterator the_count;
01923 for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it)
01924 {
01925 LLViewerInventoryCategory* cat = (*it);
01926 if(cat->getVersion() != NO_VERSION)
01927 {
01928 the_count = child_counts.find(cat->getUUID());
01929 if(the_count != no_child_counts)
01930 {
01931 cat->setDescendentCount((*the_count).second.mValue);
01932 }
01933 else
01934 {
01935 cat->setDescendentCount(0);
01936 }
01937 }
01938 }
01939
01940 if(remove_inventory_file)
01941 {
01942
01943 LLFile::remove(inventory_filename);
01944 }
01945 categories.clear();
01946 }
01947
01948 llinfos << "Successfully loaded " << cached_category_count
01949 << " categories and " << cached_item_count << " items from cache."
01950 << llendl;
01951
01952 return rv;
01953 }
01954
01955 bool LLInventoryModel::loadMeat(
01956 const LLInventoryModel::options_t& options, const LLUUID& owner_id)
01957 {
01958 llinfos << "importing inventory for " << owner_id << llendl;
01959 LLPermissions default_perm;
01960 default_perm.init(LLUUID::null, owner_id, LLUUID::null, LLUUID::null);
01961 LLPointer<LLViewerInventoryItem> item;
01962 LLUUID id;
01963 LLAssetType::EType type;
01964 LLInventoryType::EType inv_type;
01965 bool rv = true;
01966 for(options_t::const_iterator it = options.begin(); it < options.end(); ++it)
01967 {
01968 item = new LLViewerInventoryItem;
01969 response_t::const_iterator no_response = (*it).end();
01970 response_t::const_iterator meat;
01971 meat = (*it).find("name");
01972 if(meat == no_response) goto clean_item;
01973 item->rename(LLString((*meat).second.c_str()));
01974 meat = (*it).find("item_id");
01975 if(meat == no_response) goto clean_item;
01976 id.set((*meat).second.c_str());
01977 item->setUUID(id);
01978 meat = (*it).find("parent_id");
01979 if(meat == no_response) goto clean_item;
01980 id.set((*meat).second.c_str());
01981 item->setParent(id);
01982 meat = (*it).find("type");
01983 if(meat == no_response) goto clean_item;
01984 type = (LLAssetType::EType)atoi((*meat).second.c_str());
01985 item->setType(type);
01986 meat = (*it).find("inv_type");
01987 if(meat != no_response)
01988 {
01989 inv_type = (LLInventoryType::EType)atoi((*meat).second.c_str());
01990 item->setInventoryType(inv_type);
01991 }
01992 meat = (*it).find("data_id");
01993 if(meat == no_response) goto clean_item;
01994 id.set((*meat).second.c_str());
01995 if(LLAssetType::AT_CALLINGCARD == type)
01996 {
01997 LLPermissions perm;
01998 perm.init(id, owner_id, LLUUID::null, LLUUID::null);
01999 item->setPermissions(perm);
02000 }
02001 else
02002 {
02003 meat = (*it).find("perm_mask");
02004 if(meat != no_response)
02005 {
02006 PermissionMask perm_mask = atoi((*meat).second.c_str());
02007 default_perm.initMasks(
02008 perm_mask, perm_mask, perm_mask, perm_mask, perm_mask);
02009 }
02010 else
02011 {
02012 default_perm.initMasks(
02013 PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE, PERM_NONE);
02014 }
02015 item->setPermissions(default_perm);
02016 item->setAssetUUID(id);
02017 }
02018 meat = (*it).find("flags");
02019 if(meat != no_response)
02020 {
02021 item->setFlags(strtoul((*meat).second.c_str(), NULL, 0));
02022 }
02023 meat = (*it).find("time");
02024 if(meat != no_response)
02025 {
02026 item->setCreationDate(atoi((*meat).second.c_str()));
02027 }
02028 addItem(item);
02029 continue;
02030 clean_item:
02031 llwarns << "Unable to import near " << item->getName() << llendl;
02032 rv = false;
02033
02034 }
02035 return rv;
02036 }
02037
02038
02039
02040
02041 void LLInventoryModel::buildParentChildMap()
02042 {
02043 llinfos << "LLInventoryModel::buildParentChildMap()" << llendl;
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053 cat_array_t cats;
02054 cat_array_t* catsp;
02055 item_array_t* itemsp;
02056
02057 for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
02058 {
02059 LLViewerInventoryCategory* cat = cit->second;
02060 cats.put(cat);
02061 if (mParentChildCategoryTree.count(cat->getUUID()) == 0)
02062 {
02063 catsp = new cat_array_t;
02064 mParentChildCategoryTree[cat->getUUID()] = catsp;
02065 }
02066 if (mParentChildItemTree.count(cat->getUUID()) == 0)
02067 {
02068 itemsp = new item_array_t;
02069 mParentChildItemTree[cat->getUUID()] = itemsp;
02070 }
02071 }
02072
02073
02074
02075
02076
02077 if (mParentChildCategoryTree.count(LLUUID::null) == 0)
02078 {
02079 catsp = new cat_array_t;
02080 mParentChildCategoryTree[LLUUID::null] = catsp;
02081 }
02082
02083
02084
02085
02086 S32 count = cats.count();
02087 S32 i;
02088 S32 lost = 0;
02089 for(i = 0; i < count; ++i)
02090 {
02091 LLViewerInventoryCategory* cat = cats.get(i);
02092 catsp = get_ptr_in_map(mParentChildCategoryTree, cat->getParentUUID());
02093 if(catsp)
02094 {
02095 catsp->put(cat);
02096 }
02097 else
02098 {
02099
02100
02101
02102
02103
02104
02105 llinfos << "Lost categroy: " << cat->getUUID() << " - "
02106 << cat->getName() << llendl;
02107 ++lost;
02108
02109 LLAssetType::EType pref = cat->getPreferredType();
02110 if(LLAssetType::AT_NONE == pref)
02111 {
02112 cat->setParent(findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND));
02113 }
02114 else if(LLAssetType::AT_CATEGORY == pref)
02115 {
02116
02117 cat->setParent(LLUUID::null);
02118 }
02119 else
02120 {
02121
02122 cat->setParent(gAgent.getInventoryRootID());
02123 }
02124 cat->updateServer(TRUE);
02125 catsp = get_ptr_in_map(mParentChildCategoryTree, cat->getParentUUID());
02126 if(catsp)
02127 {
02128 catsp->put(cat);
02129 }
02130 else
02131 {
02132 llwarns << "Lost and found Not there!!" << llendl;
02133 }
02134 }
02135 }
02136 if(lost)
02137 {
02138 llwarns << "Found " << lost << " lost categories." << llendl;
02139 }
02140
02141
02142
02143
02144 item_array_t items;
02145 if(!mItemMap.empty())
02146 {
02147 LLPointer<LLViewerInventoryItem> item;
02148 for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)
02149 {
02150 item = (*iit).second;
02151 items.put(item);
02152 }
02153 }
02154 count = items.count();
02155 lost = 0;
02156 std::vector<LLUUID> lost_item_ids;
02157 for(i = 0; i < count; ++i)
02158 {
02159 LLPointer<LLViewerInventoryItem> item;
02160 item = items.get(i);
02161 itemsp = get_ptr_in_map(mParentChildItemTree, item->getParentUUID());
02162 if(itemsp)
02163 {
02164 itemsp->put(item);
02165 }
02166 else
02167 {
02168 llinfos << "Lost item: " << item->getUUID() << " - "
02169 << item->getName() << llendl;
02170 ++lost;
02171
02172
02173 item->setParent(findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND));
02174
02175
02176
02177 lost_item_ids.push_back(item->getUUID());
02178 itemsp = get_ptr_in_map(mParentChildItemTree, item->getParentUUID());
02179 if(itemsp)
02180 {
02181 itemsp->put(item);
02182 }
02183 else
02184 {
02185 llwarns << "Lost and found Not there!!" << llendl;
02186 }
02187 }
02188 }
02189 if(lost)
02190 {
02191 llwarns << "Found " << lost << " lost items." << llendl;
02192 LLMessageSystem* msg = gMessageSystem;
02193 BOOL start_new_message = TRUE;
02194 LLUUID lnf = findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
02195 for(std::vector<LLUUID>::iterator it = lost_item_ids.begin() ; it < lost_item_ids.end(); ++it)
02196 {
02197 if(start_new_message)
02198 {
02199 start_new_message = FALSE;
02200 msg->newMessageFast(_PREHASH_MoveInventoryItem);
02201 msg->nextBlockFast(_PREHASH_AgentData);
02202 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
02203 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
02204 msg->addBOOLFast(_PREHASH_Stamp, FALSE);
02205 }
02206 msg->nextBlockFast(_PREHASH_InventoryData);
02207 msg->addUUIDFast(_PREHASH_ItemID, (*it));
02208 msg->addUUIDFast(_PREHASH_FolderID, lnf);
02209 msg->addString("NewName", NULL);
02210 if(msg->isSendFull(NULL))
02211 {
02212 start_new_message = TRUE;
02213 gAgent.sendReliableMessage();
02214 }
02215 }
02216 if(!start_new_message)
02217 {
02218 gAgent.sendReliableMessage();
02219 }
02220 }
02221
02222 const LLUUID& agent_inv_root_id = gAgent.getInventoryRootID();
02223 if (agent_inv_root_id.notNull())
02224 {
02225 cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id);
02226 if(catsp)
02227 {
02228
02229
02230
02231 mIsAgentInvUsable = true;
02232 }
02233 }
02234 }
02235
02236 struct LLUUIDAndName
02237 {
02238 LLUUIDAndName() {}
02239 LLUUIDAndName(const LLUUID& id, const LLString& name);
02240 bool operator==(const LLUUIDAndName& rhs) const;
02241 bool operator<(const LLUUIDAndName& rhs) const;
02242 bool operator>(const LLUUIDAndName& rhs) const;
02243
02244 LLUUID mID;
02245 LLString mName;
02246 };
02247
02248 LLUUIDAndName::LLUUIDAndName(const LLUUID& id, const LLString& name) :
02249 mID(id), mName(name)
02250 {
02251 }
02252
02253 bool LLUUIDAndName::operator==(const LLUUIDAndName& rhs) const
02254 {
02255 return ((mID == rhs.mID) && (mName == rhs.mName));
02256 }
02257
02258 bool LLUUIDAndName::operator<(const LLUUIDAndName& rhs) const
02259 {
02260 return (mID < rhs.mID);
02261 }
02262
02263 bool LLUUIDAndName::operator>(const LLUUIDAndName& rhs) const
02264 {
02265 return (mID > rhs.mID);
02266 }
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335
02336 bool LLInventoryModel::loadFromFile(
02337 const char* filename,
02338 LLInventoryModel::cat_array_t& categories,
02339 LLInventoryModel::item_array_t& items)
02340 {
02341 if(!filename)
02342 {
02343 llerrs << "Filename is Null!" << llendl;
02344 return false;
02345 }
02346 llinfos << "LLInventoryModel::loadFromFile(" << filename << ")" << llendl;
02347 LLFILE* file = LLFile::fopen(filename, "rb");
02348 if(!file)
02349 {
02350 llinfos << "unable to load inventory from: " << filename << llendl;
02351 return false;
02352 }
02353
02354 char buffer[MAX_STRING];
02355 char keyword[MAX_STRING];
02356 while(!feof(file) && fgets(buffer, MAX_STRING, file))
02357 {
02358 sscanf(buffer, " %254s", keyword);
02359 if(0 == strcmp("inv_category", keyword))
02360 {
02361 LLPointer<LLViewerInventoryCategory> inv_cat = new LLViewerInventoryCategory(LLUUID::null);
02362 if(inv_cat->importFileLocal(file))
02363 {
02364 categories.put(inv_cat);
02365 }
02366 else
02367 {
02368 llwarns << "loadInventoryFromFile(). Ignoring invalid inventory category: " << inv_cat->getName() << llendl;
02369
02370 }
02371 }
02372 else if(0 == strcmp("inv_item", keyword))
02373 {
02374 LLPointer<LLViewerInventoryItem> inv_item = new LLViewerInventoryItem;
02375 if( inv_item->importFileLocal(file) )
02376 {
02377
02378
02379
02380 if(inv_item->getUUID().isNull())
02381 {
02382
02383 llwarns << "Ignoring inventory with null item id: "
02384 << inv_item->getName() << llendl;
02385
02386 }
02387 else
02388 {
02389 items.put(inv_item);
02390 }
02391 }
02392 else
02393 {
02394 llwarns << "loadInventoryFromFile(). Ignoring invalid inventory item: " << inv_item->getName() << llendl;
02395
02396 }
02397 }
02398 else
02399 {
02400 llwarns << "Unknown token in inventory file '" << keyword << "'"
02401 << llendl;
02402 }
02403 }
02404 fclose(file);
02405 return true;
02406 }
02407
02408
02409 bool LLInventoryModel::saveToFile(
02410 const char* filename,
02411 const cat_array_t& categories,
02412 const item_array_t& items)
02413 {
02414 if(!filename)
02415 {
02416 llerrs << "Filename is Null!" << llendl;
02417 return false;
02418 }
02419 llinfos << "LLInventoryModel::saveToFile(" << filename << ")" << llendl;
02420 LLFILE* file = LLFile::fopen(filename, "wb");
02421 if(!file)
02422 {
02423 llwarns << "unable to save inventory to: " << filename << llendl;
02424 return false;
02425 }
02426
02427 S32 count = categories.count();
02428 S32 i;
02429 for(i = 0; i < count; ++i)
02430 {
02431 LLViewerInventoryCategory* cat = categories[i];
02432 if(cat->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN)
02433 {
02434 cat->exportFileLocal(file);
02435 }
02436 }
02437
02438 count = items.count();
02439 for(i = 0; i < count; ++i)
02440 {
02441 items[i]->exportFile(file);
02442 }
02443
02444 fclose(file);
02445 return true;
02446 }
02447
02448
02449
02450 void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)
02451 {
02452
02453
02454
02455
02456
02457
02458 msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem,
02459 processUpdateCreateInventoryItem,
02460 NULL);
02461 msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem,
02462 processRemoveInventoryItem,
02463 NULL);
02464 msg->setHandlerFuncFast(_PREHASH_UpdateInventoryFolder,
02465 processUpdateInventoryFolder,
02466 NULL);
02467 msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder,
02468 processRemoveInventoryFolder,
02469 NULL);
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479 msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory,
02480 processSaveAssetIntoInventory,
02481 NULL);
02482 msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory,
02483 processBulkUpdateInventory,
02484 NULL);
02485 msg->setHandlerFunc("InventoryDescendents", processInventoryDescendents);
02486 msg->setHandlerFunc("MoveInventoryItem", processMoveInventoryItem);
02487 msg->setHandlerFunc("FetchInventoryReply", processFetchInventoryReply);
02488 }
02489
02490
02491
02492 void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg, void**)
02493 {
02494
02495 if (gInventory.messageUpdateCore(msg, true))
02496 {
02497 U32 callback_id;
02498 LLUUID item_id;
02499 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id);
02500 msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID, callback_id);
02501
02502 gInventoryCallbacks.fire(callback_id, item_id);
02503 }
02504
02505 }
02506
02507
02508 void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**)
02509 {
02510
02511 gInventory.messageUpdateCore(msg, false);
02512 }
02513
02514
02515 bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account)
02516 {
02517
02518 start_new_inventory_observer();
02519
02520 LLUUID agent_id;
02521 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02522 if(agent_id != gAgent.getID())
02523 {
02524 llwarns << "Got a inventory update for the wrong agent: " << agent_id
02525 << llendl;
02526 return false;
02527 }
02528 item_array_t items;
02529 update_map_t update;
02530 S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
02531 bool all_one_folder = true;
02532 LLUUID folder_id;
02533
02534 for(S32 i = 0; i < count; ++i)
02535 {
02536 LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
02537 titem->unpackMessage(msg, _PREHASH_InventoryData, i);
02538 lldebugs << "LLInventoryModel::messageUpdateCore() item id:"
02539 << titem->getUUID() << llendl;
02540 items.push_back(titem);
02541
02542 LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID());
02543 if(itemp)
02544 {
02545 if(titem->getParentUUID() == itemp->getParentUUID())
02546 {
02547 update[titem->getParentUUID()];
02548 }
02549 else
02550 {
02551 ++update[titem->getParentUUID()];
02552 --update[itemp->getParentUUID()];
02553 }
02554 }
02555 else
02556 {
02557 ++update[titem->getParentUUID()];
02558 }
02559 if (folder_id.isNull())
02560 {
02561 folder_id = titem->getParentUUID();
02562 }
02563 else
02564 {
02565 all_one_folder = false;
02566 }
02567 }
02568 if(account)
02569 {
02570 gInventory.accountForUpdate(update);
02571 }
02572
02573 U32 changes = 0x0;
02574
02575 for (item_array_t::iterator it = items.begin(); it != items.end(); ++it)
02576 {
02577 changes |= gInventory.updateItem(*it);
02578 }
02579 gInventory.notifyObservers();
02580 gViewerWindow->getWindow()->decBusyCount();
02581
02582 return true;
02583 }
02584
02585
02586 void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**)
02587 {
02588 lldebugs << "LLInventoryModel::processRemoveInventoryItem()" << llendl;
02589 LLUUID agent_id, item_id;
02590 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02591 if(agent_id != gAgent.getID())
02592 {
02593 llwarns << "Got a RemoveInventoryItem for the wrong agent."
02594 << llendl;
02595 return;
02596 }
02597 S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
02598 std::vector<LLUUID> item_ids;
02599 update_map_t update;
02600 for(S32 i = 0; i < count; ++i)
02601 {
02602 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
02603 LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
02604 if(itemp)
02605 {
02606
02607
02608
02609 --update[itemp->getParentUUID()];
02610 item_ids.push_back(item_id);
02611 }
02612 }
02613 gInventory.accountForUpdate(update);
02614 for(std::vector<LLUUID>::iterator it = item_ids.begin(); it != item_ids.end(); ++it)
02615 {
02616 gInventory.deleteObject(*it);
02617 }
02618 gInventory.notifyObservers();
02619 }
02620
02621
02622 void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg,
02623 void**)
02624 {
02625 lldebugs << "LLInventoryModel::processUpdateInventoryFolder()" << llendl;
02626 LLUUID agent_id, folder_id, parent_id;
02627
02628 msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
02629 if(agent_id != gAgent.getID())
02630 {
02631 llwarns << "Got an UpdateInventoryFolder for the wrong agent."
02632 << llendl;
02633 return;
02634 }
02635 LLPointer<LLViewerInventoryCategory> lastfolder;
02636 cat_array_t folders;
02637 update_map_t update;
02638 S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
02639 for(S32 i = 0; i < count; ++i)
02640 {
02641 LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
02642 lastfolder = tfolder;
02643 tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
02644
02645 tfolder->setPreferredType(LLAssetType::AT_NONE);
02646 folders.push_back(tfolder);
02647
02648 LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
02649 if(folderp)
02650 {
02651 if(tfolder->getParentUUID() == folderp->getParentUUID())
02652 {
02653 update[tfolder->getParentUUID()];
02654 }
02655 else
02656 {
02657 ++update[tfolder->getParentUUID()];
02658 --update[folderp->getParentUUID()];
02659 }
02660 }
02661 else
02662 {
02663 ++update[tfolder->getParentUUID()];
02664 }
02665 }
02666 gInventory.accountForUpdate(update);
02667 for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it)
02668 {
02669 gInventory.updateCategory(*it);
02670 }
02671 gInventory.notifyObservers();
02672
02673
02674 LLInventoryView* view = LLInventoryView::getActiveInventory();
02675 if(view)
02676 {
02677 view->getPanel()->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO);
02678 }
02679 }
02680
02681
02682 void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg,
02683 void**)
02684 {
02685 lldebugs << "LLInventoryModel::processRemoveInventoryFolder()" << llendl;
02686 LLUUID agent_id, folder_id;
02687 msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
02688 if(agent_id != gAgent.getID())
02689 {
02690 llwarns << "Got a RemoveInventoryFolder for the wrong agent."
02691 << llendl;
02692 return;
02693 }
02694 std::vector<LLUUID> folder_ids;
02695 update_map_t update;
02696 S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
02697 for(S32 i = 0; i < count; ++i)
02698 {
02699 msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i);
02700 LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id);
02701 if(folderp)
02702 {
02703 --update[folderp->getParentUUID()];
02704 folder_ids.push_back(folder_id);
02705 }
02706 }
02707 gInventory.accountForUpdate(update);
02708 for(std::vector<LLUUID>::iterator it = folder_ids.begin(); it != folder_ids.end(); ++it)
02709 {
02710 gInventory.deleteObject(*it);
02711 }
02712 gInventory.notifyObservers();
02713 }
02714
02715
02716 void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg,
02717 void**)
02718 {
02719 LLUUID agent_id;
02720 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02721 if(agent_id != gAgent.getID())
02722 {
02723 llwarns << "Got a SaveAssetIntoInventory message for the wrong agent."
02724 << llendl;
02725 return;
02726 }
02727
02728 LLUUID item_id;
02729 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id);
02730
02731
02732
02733
02734 lldebugs << "LLInventoryModel::processSaveAssetIntoInventory itemID="
02735 << item_id << llendl;
02736 LLViewerInventoryItem* item = gInventory.getItem( item_id );
02737 if( item )
02738 {
02739 LLCategoryUpdate up(item->getParentUUID(), 0);
02740 gInventory.accountForUpdate(up);
02741 gInventory.addChangedMask( LLInventoryObserver::INTERNAL, item_id);
02742 gInventory.notifyObservers();
02743 }
02744 else
02745 {
02746 llinfos << "LLInventoryModel::processSaveAssetIntoInventory item"
02747 " not found: " << item_id << llendl;
02748 }
02749 if(gViewerWindow)
02750 {
02751 gViewerWindow->getWindow()->decBusyCount();
02752 }
02753 }
02754
02755 struct InventoryCallbackInfo
02756 {
02757 InventoryCallbackInfo(U32 callback, const LLUUID& inv_id) :
02758 mCallback(callback), mInvID(inv_id) {}
02759 U32 mCallback;
02760 LLUUID mInvID;
02761 };
02762
02763
02764 void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
02765 {
02766 LLUUID agent_id;
02767 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02768 if(agent_id != gAgent.getID())
02769 {
02770 llwarns << "Got a BulkUpdateInventory for the wrong agent." << llendl;
02771 return;
02772 }
02773 LLUUID tid;
02774 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid);
02775 llinfos << "Bulk inventory: " << tid << llendl;
02776
02777 update_map_t update;
02778 cat_array_t folders;
02779 S32 count;
02780 S32 i;
02781 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
02782 for(i = 0; i < count; ++i)
02783 {
02784 LLPointer<LLViewerInventoryCategory> tfolder = new LLViewerInventoryCategory(gAgent.getID());
02785 tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
02786
02787
02788
02789 if(tfolder->getUUID().notNull())
02790 {
02791 folders.push_back(tfolder);
02792 LLViewerInventoryCategory* folderp = gInventory.getCategory(tfolder->getUUID());
02793 if(folderp)
02794 {
02795 if(tfolder->getParentUUID() == folderp->getParentUUID())
02796 {
02797 update[tfolder->getParentUUID()];
02798 }
02799 else
02800 {
02801 ++update[tfolder->getParentUUID()];
02802 --update[folderp->getParentUUID()];
02803 }
02804 }
02805 else
02806 {
02807
02808
02809
02810 folderp = gInventory.getCategory(tfolder->getParentUUID());
02811 if(folderp)
02812 {
02813 ++update[tfolder->getParentUUID()];
02814 }
02815 }
02816 }
02817 }
02818
02819
02820 count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
02821 std::vector<LLUUID> wearable_ids;
02822 item_array_t items;
02823 std::list<InventoryCallbackInfo> cblist;
02824 for(i = 0; i < count; ++i)
02825 {
02826 LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
02827 titem->unpackMessage(msg, _PREHASH_ItemData, i);
02828
02829
02830 U32 callback_id;
02831 msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);
02832 if(titem->getUUID().notNull())
02833 {
02834 items.push_back(titem);
02835 cblist.push_back(InventoryCallbackInfo(callback_id, titem->getUUID()));
02836 if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE)
02837 {
02838 wearable_ids.push_back(titem->getUUID());
02839 }
02840
02841 LLViewerInventoryItem* itemp = gInventory.getItem(titem->getUUID());
02842 if(itemp)
02843 {
02844 if(titem->getParentUUID() == itemp->getParentUUID())
02845 {
02846 update[titem->getParentUUID()];
02847 }
02848 else
02849 {
02850 ++update[titem->getParentUUID()];
02851 --update[itemp->getParentUUID()];
02852 }
02853 }
02854 else
02855 {
02856 LLViewerInventoryCategory* folderp = gInventory.getCategory(titem->getParentUUID());
02857 if(folderp)
02858 {
02859 ++update[titem->getParentUUID()];
02860 }
02861 }
02862 }
02863 else
02864 {
02865 cblist.push_back(InventoryCallbackInfo(callback_id, LLUUID::null));
02866 }
02867 }
02868 gInventory.accountForUpdate(update);
02869
02870 for (cat_array_t::iterator cit = folders.begin(); cit != folders.end(); ++cit)
02871 {
02872 gInventory.updateCategory(*cit);
02873 }
02874 for (item_array_t::iterator iit = items.begin(); iit != items.end(); ++iit)
02875 {
02876 gInventory.updateItem(*iit);
02877 }
02878 gInventory.notifyObservers();
02879
02880
02881
02882
02883 if (LLInventoryView::sWearNewClothing)
02884 {
02885 LLInventoryView::sWearNewClothingTransactionID = tid;
02886 LLInventoryView::sWearNewClothing = FALSE;
02887 }
02888
02889 if (tid == LLInventoryView::sWearNewClothingTransactionID)
02890 {
02891 count = wearable_ids.size();
02892 for (i = 0; i < count; ++i)
02893 {
02894 LLViewerInventoryItem* wearable_item;
02895 wearable_item = gInventory.getItem(wearable_ids[i]);
02896 wear_inventory_item_on_avatar(wearable_item);
02897 }
02898 }
02899
02900 std::list<InventoryCallbackInfo>::iterator inv_it;
02901 for (inv_it = cblist.begin(); inv_it != cblist.end(); ++inv_it)
02902 {
02903 InventoryCallbackInfo cbinfo = (*inv_it);
02904 gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
02905 }
02906
02907
02908
02909
02910
02911
02912
02913
02914
02915
02916
02917
02918
02919
02920
02921
02922
02923
02924
02925
02926 }
02927
02928
02929 void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,void**)
02930 {
02931 LLUUID agent_id;
02932 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02933 if(agent_id != gAgent.getID())
02934 {
02935 llwarns << "Got a UpdateInventoryItem for the wrong agent."
02936 << llendl;
02937 return;
02938 }
02939 LLUUID parent_id;
02940 msg->getUUID("AgentData", "FolderID", parent_id);
02941 LLUUID owner_id;
02942 msg->getUUID("AgentData", "OwnerID", owner_id);
02943 S32 version;
02944 msg->getS32("AgentData", "Version", version);
02945 S32 descendents;
02946 msg->getS32("AgentData", "Descendents", descendents);
02947 S32 i;
02948 S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
02949 LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);
02950 for(i = 0; i < count; ++i)
02951 {
02952 tcategory->unpackMessage(msg, _PREHASH_FolderData, i);
02953 gInventory.updateCategory(tcategory);
02954 }
02955
02956 count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
02957 LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
02958 for(i = 0; i < count; ++i)
02959 {
02960 titem->unpackMessage(msg, _PREHASH_ItemData, i);
02961 gInventory.updateItem(titem);
02962 }
02963
02964
02965 LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
02966 if(cat)
02967 {
02968 cat->setVersion(version);
02969 cat->setDescendentCount(descendents);
02970 }
02971 gInventory.notifyObservers();
02972 }
02973
02974
02975 void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**)
02976 {
02977 lldebugs << "LLInventoryModel::processMoveInventoryItem()" << llendl;
02978 LLUUID agent_id;
02979 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
02980 if(agent_id != gAgent.getID())
02981 {
02982 llwarns << "Got a MoveInventoryItem message for the wrong agent."
02983 << llendl;
02984 return;
02985 }
02986
02987 LLUUID item_id;
02988 LLUUID folder_id;
02989 char new_name[MAX_STRING];
02990 bool anything_changed = false;
02991 S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
02992 for(S32 i = 0; i < count; ++i)
02993 {
02994 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
02995 LLViewerInventoryItem* item = gInventory.getItem(item_id);
02996 if(item)
02997 {
02998 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
02999 msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID, folder_id, i);
03000 msg->getString("InventoryData", "NewName", MAX_STRING, new_name, i);
03001
03002 lldebugs << "moving item " << item_id << " to folder "
03003 << folder_id << llendl;
03004 update_list_t update;
03005 LLCategoryUpdate old_folder(item->getParentUUID(), -1);
03006 update.push_back(old_folder);
03007 LLCategoryUpdate new_folder(folder_id, 1);
03008 update.push_back(new_folder);
03009 gInventory.accountForUpdate(update);
03010
03011 new_item->setParent(folder_id);
03012 if(strlen(new_name) > 0)
03013 {
03014 new_item->rename(new_name);
03015 }
03016 gInventory.updateItem(new_item);
03017 anything_changed = true;
03018 }
03019 else
03020 {
03021 llinfos << "LLInventoryModel::processMoveInventoryItem item not found: " << item_id << llendl;
03022 }
03023 }
03024 if(anything_changed)
03025 {
03026 gInventory.notifyObservers();
03027 }
03028 }
03029
03030
03031 void LLInventoryModel::dumpInventory()
03032 {
03033 llinfos << "\nBegin Inventory Dump\n**********************:" << llendl;
03034 llinfos << "mCategroy[] contains " << mCategoryMap.size() << " items." << llendl;
03035 for(cat_map_t::iterator cit = mCategoryMap.begin(); cit != mCategoryMap.end(); ++cit)
03036 {
03037 LLViewerInventoryCategory* cat = cit->second;
03038 if(cat)
03039 {
03040 llinfos << " " << cat->getUUID() << " '" << cat->getName() << "' "
03041 << cat->getVersion() << " " << cat->getDescendentCount()
03042 << llendl;
03043 }
03044 else
03045 {
03046 llinfos << " NULL!" << llendl;
03047 }
03048 }
03049 llinfos << "mItemMap[] contains " << mItemMap.size() << " items." << llendl;
03050 for(item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end(); ++iit)
03051 {
03052 LLViewerInventoryItem* item = iit->second;
03053 if(item)
03054 {
03055 llinfos << " " << item->getUUID() << " "
03056 << item->getName() << llendl;
03057 }
03058 else
03059 {
03060 llinfos << " NULL!" << llendl;
03061 }
03062 }
03063 llinfos << "\n**********************\nEnd Inventory Dump" << llendl;
03064 }
03065
03069
03070 bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
03071 {
03072 if(mType == LLAssetType::AT_CATEGORY)
03073 {
03074 if(cat) return TRUE;
03075 }
03076 if(item)
03077 {
03078 if(item->getType() == mType) return TRUE;
03079 }
03080 return FALSE;
03081 }
03082
03083 bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
03084 {
03085 if(mType == LLAssetType::AT_CATEGORY)
03086 {
03087 if(cat) return FALSE;
03088 }
03089 if(item)
03090 {
03091 if(item->getType() == mType) return FALSE;
03092 else return TRUE;
03093 }
03094 return TRUE;
03095 }
03096
03097 bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
03098 {
03099 if(mType == LLAssetType::AT_CATEGORY)
03100 {
03101 if(cat)
03102 {
03103 return TRUE;
03104 }
03105 }
03106 if(item)
03107 {
03108 if(item->getType() == mType)
03109 {
03110 LLPermissions perm = item->getPermissions();
03111 if ((perm.getMaskBase() & mPerm) == mPerm)
03112 {
03113 return TRUE;
03114 }
03115 }
03116 }
03117 return FALSE;
03118 }
03119
03120
03121
03122
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149 bool LLBuddyCollector::operator()(LLInventoryCategory* cat,
03150 LLInventoryItem* item)
03151 {
03152 if(item)
03153 {
03154 if((LLAssetType::AT_CALLINGCARD == item->getType())
03155 && (!item->getCreatorUUID().isNull())
03156 && (item->getCreatorUUID() != gAgent.getID()))
03157 {
03158 return true;
03159 }
03160 }
03161 return false;
03162 }
03163
03164
03165 bool LLUniqueBuddyCollector::operator()(LLInventoryCategory* cat,
03166 LLInventoryItem* item)
03167 {
03168 if(item)
03169 {
03170 if((LLAssetType::AT_CALLINGCARD == item->getType())
03171 && (item->getCreatorUUID().notNull())
03172 && (item->getCreatorUUID() != gAgent.getID()))
03173 {
03174 mSeen.insert(item->getCreatorUUID());
03175 return true;
03176 }
03177 }
03178 return false;
03179 }
03180
03181
03182 bool LLParticularBuddyCollector::operator()(LLInventoryCategory* cat,
03183 LLInventoryItem* item)
03184 {
03185 if(item)
03186 {
03187 if((LLAssetType::AT_CALLINGCARD == item->getType())
03188 && (item->getCreatorUUID() == mBuddyID))
03189 {
03190 return TRUE;
03191 }
03192 }
03193 return FALSE;
03194 }
03195
03196
03197 bool LLNameCategoryCollector::operator()(
03198 LLInventoryCategory* cat, LLInventoryItem* item)
03199 {
03200 if(cat)
03201 {
03202 if (!LLString::compareInsensitive(mName.c_str(), cat->getName().c_str()))
03203 {
03204 return true;
03205 }
03206 }
03207 return false;
03208 }
03209
03210
03211
03215
03216 void LLInventoryCompletionObserver::changed(U32 mask)
03217 {
03218
03219
03220 if(!mIncomplete.empty())
03221 {
03222 for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); )
03223 {
03224 LLViewerInventoryItem* item = gInventory.getItem(*it);
03225 if(!item)
03226 {
03227 it = mIncomplete.erase(it);
03228 continue;
03229 }
03230 if(item->isComplete())
03231 {
03232 mComplete.push_back(*it);
03233 it = mIncomplete.erase(it);
03234 continue;
03235 }
03236 ++it;
03237 }
03238 if(mIncomplete.empty())
03239 {
03240 done();
03241 }
03242 }
03243 }
03244
03245 void LLInventoryCompletionObserver::watchItem(const LLUUID& id)
03246 {
03247 if(id.notNull())
03248 {
03249 mIncomplete.push_back(id);
03250 }
03251 }
03252
03253
03254 void LLInventoryFetchObserver::changed(U32 mask)
03255 {
03256
03257
03258 if(!mIncomplete.empty())
03259 {
03260 for(item_ref_t::iterator it = mIncomplete.begin(); it < mIncomplete.end(); )
03261 {
03262 LLViewerInventoryItem* item = gInventory.getItem(*it);
03263 if(!item)
03264 {
03265
03266
03267
03268 it = mIncomplete.erase(it);
03269 continue;
03270 }
03271 if(item->isComplete())
03272 {
03273 mComplete.push_back(*it);
03274 it = mIncomplete.erase(it);
03275 continue;
03276 }
03277 ++it;
03278 }
03279 if(mIncomplete.empty())
03280 {
03281 done();
03282 }
03283 }
03284
03285
03286 }
03287
03288 bool LLInventoryFetchObserver::isEverythingComplete() const
03289 {
03290 return mIncomplete.empty();
03291 }
03292
03293 void LLInventoryFetchObserver::fetchItems(
03294 const LLInventoryFetchObserver::item_ref_t& ids)
03295 {
03296 LLMessageSystem* msg = gMessageSystem;
03297 BOOL start_new_message = TRUE;
03298 LLUUID owner_id;
03299 for(item_ref_t::const_iterator it = ids.begin(); it < ids.end(); ++it)
03300 {
03301 LLViewerInventoryItem* item = gInventory.getItem(*it);
03302 if(item)
03303 {
03304 if(item->isComplete())
03305 {
03306
03307 mComplete.push_back(*it);
03308 continue;
03309 }
03310 else
03311 {
03312 owner_id = item->getPermissions().getOwner();
03313 }
03314 }
03315 else
03316 {
03317
03318 owner_id = gAgent.getID();
03319 }
03320
03321
03322
03323 mIncomplete.push_back(*it);
03324 if(start_new_message)
03325 {
03326 start_new_message = FALSE;
03327 msg->newMessageFast(_PREHASH_FetchInventory);
03328 msg->nextBlockFast(_PREHASH_AgentData);
03329 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
03330 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03331 }
03332 msg->nextBlockFast(_PREHASH_InventoryData);
03333 msg->addUUIDFast(_PREHASH_OwnerID, owner_id);
03334 msg->addUUIDFast(_PREHASH_ItemID, (*it));
03335 if(msg->isSendFull(NULL))
03336 {
03337 start_new_message = TRUE;
03338 gAgent.sendReliableMessage();
03339 }
03340 }
03341 if(!start_new_message)
03342 {
03343 gAgent.sendReliableMessage();
03344 }
03345 }
03346
03347
03348 void LLInventoryFetchDescendentsObserver::changed(U32 mask)
03349 {
03350 for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();)
03351 {
03352 LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
03353 if(!cat)
03354 {
03355 it = mIncompleteFolders.erase(it);
03356 continue;
03357 }
03358 if(isComplete(cat))
03359 {
03360 mCompleteFolders.push_back(*it);
03361 it = mIncompleteFolders.erase(it);
03362 continue;
03363 }
03364 ++it;
03365 }
03366 if(mIncompleteFolders.empty())
03367 {
03368 done();
03369 }
03370 }
03371
03372 void LLInventoryFetchDescendentsObserver::fetchDescendents(
03373 const folder_ref_t& ids)
03374 {
03375 for(folder_ref_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
03376 {
03377 LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
03378 if(!cat) continue;
03379 if(!isComplete(cat))
03380 {
03381 cat->fetchDescendents();
03382 mIncompleteFolders.push_back(*it);
03383 }
03384 else
03385 {
03386 mCompleteFolders.push_back(*it);
03387 }
03388 }
03389 }
03390
03391 bool LLInventoryFetchDescendentsObserver::isEverythingComplete() const
03392 {
03393 return mIncompleteFolders.empty();
03394 }
03395
03396 bool LLInventoryFetchDescendentsObserver::isComplete(LLViewerInventoryCategory* cat)
03397 {
03398 S32 version = cat->getVersion();
03399 S32 descendents = cat->getDescendentCount();
03400 if((LLViewerInventoryCategory::VERSION_UNKNOWN == version)
03401 || (LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN == descendents))
03402 {
03403 return false;
03404 }
03405
03406
03407 LLInventoryModel::cat_array_t* cats;
03408 LLInventoryModel::item_array_t* items;
03409 gInventory.getDirectDescendentsOf(cat->getUUID(), cats, items);
03410 if(!cats || !items)
03411 {
03412
03413
03414
03415 return true;
03416 }
03417 S32 known = cats->count() + items->count();
03418 if(descendents == known)
03419 {
03420
03421 return true;
03422 }
03423 return false;
03424 }
03425
03426 void LLInventoryFetchComboObserver::changed(U32 mask)
03427 {
03428 if(!mIncompleteItems.empty())
03429 {
03430 for(item_ref_t::iterator it = mIncompleteItems.begin(); it < mIncompleteItems.end(); )
03431 {
03432 LLViewerInventoryItem* item = gInventory.getItem(*it);
03433 if(!item)
03434 {
03435 it = mIncompleteItems.erase(it);
03436 continue;
03437 }
03438 if(item->isComplete())
03439 {
03440 mCompleteItems.push_back(*it);
03441 it = mIncompleteItems.erase(it);
03442 continue;
03443 }
03444 ++it;
03445 }
03446 }
03447 if(!mIncompleteFolders.empty())
03448 {
03449 for(folder_ref_t::iterator it = mIncompleteFolders.begin(); it < mIncompleteFolders.end();)
03450 {
03451 LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
03452 if(!cat)
03453 {
03454 it = mIncompleteFolders.erase(it);
03455 continue;
03456 }
03457 if(gInventory.isCategoryComplete(*it))
03458 {
03459 mCompleteFolders.push_back(*it);
03460 it = mIncompleteFolders.erase(it);
03461 continue;
03462 }
03463 ++it;
03464 }
03465 }
03466 if(!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty())
03467 {
03468 mDone = true;
03469 done();
03470 }
03471 }
03472
03473 void LLInventoryFetchComboObserver::fetch(
03474 const folder_ref_t& folder_ids,
03475 const item_ref_t& item_ids)
03476 {
03477 lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl;
03478 for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit)
03479 {
03480 LLViewerInventoryCategory* cat = gInventory.getCategory(*fit);
03481 if(!cat) continue;
03482 if(!gInventory.isCategoryComplete(*fit))
03483 {
03484 cat->fetchDescendents();
03485 lldebugs << "fetching folder " << *fit <<llendl;
03486 mIncompleteFolders.push_back(*fit);
03487 }
03488 else
03489 {
03490 mCompleteFolders.push_back(*fit);
03491 lldebugs << "completing folder " << *fit <<llendl;
03492 }
03493 }
03494
03495
03496
03497
03498
03499 LLUUID owner_id;
03500 LLMessageSystem* msg = gMessageSystem;
03501 bool start_new_message = true;
03502 for(item_ref_t::const_iterator iit = item_ids.begin(); iit != item_ids.end(); ++iit)
03503 {
03504 LLViewerInventoryItem* item = gInventory.getItem(*iit);
03505 if(!item)
03506 {
03507 lldebugs << "uanble to find item " << *iit << llendl;
03508 continue;
03509 }
03510 if(item->isComplete())
03511 {
03512
03513 mCompleteItems.push_back(*iit);
03514 lldebugs << "completing item " << *iit << llendl;
03515 continue;
03516 }
03517 else
03518 {
03519 mIncompleteItems.push_back(*iit);
03520 owner_id = item->getPermissions().getOwner();
03521 }
03522 if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end())
03523 {
03524 lldebugs << "fetching item " << *iit << llendl;
03525 if(start_new_message)
03526 {
03527 start_new_message = false;
03528 msg->newMessageFast(_PREHASH_FetchInventory);
03529 msg->nextBlockFast(_PREHASH_AgentData);
03530 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
03531 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03532 }
03533 msg->nextBlockFast(_PREHASH_InventoryData);
03534 msg->addUUIDFast(_PREHASH_OwnerID, owner_id);
03535 msg->addUUIDFast(_PREHASH_ItemID, (*iit));
03536 if(msg->isSendFullFast(_PREHASH_InventoryData))
03537 {
03538 start_new_message = true;
03539 gAgent.sendReliableMessage();
03540 }
03541 }
03542 else
03543 {
03544 lldebugs << "not worrying about " << *iit << llendl;
03545 }
03546 }
03547 if(!start_new_message)
03548 {
03549 gAgent.sendReliableMessage();
03550 }
03551 }
03552
03553 void LLInventoryExistenceObserver::watchItem(const LLUUID& id)
03554 {
03555 if(id.notNull())
03556 {
03557 mMIA.push_back(id);
03558 }
03559 }
03560
03561 void LLInventoryExistenceObserver::changed(U32 mask)
03562 {
03563
03564
03565 if(!mMIA.empty())
03566 {
03567 for(item_ref_t::iterator it = mMIA.begin(); it < mMIA.end(); )
03568 {
03569 LLViewerInventoryItem* item = gInventory.getItem(*it);
03570 if(!item)
03571 {
03572 ++it;
03573 continue;
03574 }
03575 mExist.push_back(*it);
03576 it = mMIA.erase(it);
03577 }
03578 if(mMIA.empty())
03579 {
03580 done();
03581 }
03582 }
03583 }
03584
03585 void LLInventoryAddedObserver::changed(U32 mask)
03586 {
03587 if(!(mask & LLInventoryObserver::ADD))
03588 {
03589 return;
03590 }
03591
03592
03593
03594
03595 LLMessageSystem* msg = gMessageSystem;
03596 const char* msg_name = msg->getMessageName();
03597 if (!msg_name) return;
03598
03599
03600 if ( strcmp(msg_name, "UpdateCreateInventoryItem") )
03601 {
03602 return;
03603 }
03604
03605 LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
03606 S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
03607 for(S32 i = 0; i < num_blocks; ++i)
03608 {
03609 titem->unpackMessage(msg, _PREHASH_InventoryData, i);
03610 if (!(titem->getUUID().isNull()))
03611 {
03612
03613 mAdded.push_back(titem->getUUID());
03614 }
03615 }
03616 if (!mAdded.empty())
03617 {
03618 done();
03619 }
03620 }
03621
03622 LLInventoryTransactionObserver::LLInventoryTransactionObserver(
03623 const LLTransactionID& transaction_id) :
03624 mTransactionID(transaction_id)
03625 {
03626 }
03627
03628 void LLInventoryTransactionObserver::changed(U32 mask)
03629 {
03630 if(mask & LLInventoryObserver::ADD)
03631 {
03632
03633 LLMessageSystem* msg = gMessageSystem;
03634 if(msg->getMessageName()
03635 && (0 == strcmp(msg->getMessageName(), "BulkUpdateInventory")))
03636 {
03637
03638
03639 LLUUID id;
03640 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id);
03641 if(id == mTransactionID)
03642 {
03643
03644 folder_ref_t folders;
03645 item_ref_t items;
03646 S32 count;
03647 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
03648 S32 i;
03649 for(i = 0; i < count; ++i)
03650 {
03651 msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i);
03652 if(id.notNull())
03653 {
03654 folders.push_back(id);
03655 }
03656 }
03657 count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
03658 for(i = 0; i < count; ++i)
03659 {
03660 msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i);
03661 if(id.notNull())
03662 {
03663 items.push_back(id);
03664 }
03665 }
03666
03667
03668 done(folders, items);
03669 }
03670 }
03671 }
03672 }
03673
03674
03678 bool LLAssetIDMatches ::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
03679 {
03680 return (item && item->getAssetUUID() == mAssetID);
03681 }
03682
03683
03687
03688
03689
03690
03691
03692
03693
03694
03695
03696
03697
03698
03699
03700
03701
03702
03703
03704
03705
03706
03707
03708
03709
03710
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720
03721
03722
03723
03724
03725
03726
03727
03728