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