12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438 |
- /**
- * @file llviewerinventory.cpp
- * @brief Implementation of the viewer side inventory objects.
- *
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llviewerinventory.h"
- #include "llcallbacklist.h"
- #include "llcorehttputil.h"
- #include "llnotifications.h"
- #include "llsdutil.h"
- #include "llmessage.h"
- #include "llagent.h"
- #include "llagentwearables.h"
- #include "llaisapi.h"
- #include "llappearancemgr.h"
- #include "llcommandhandler.h"
- #include "llfloaterinventory.h"
- #include "llfolderview.h"
- #include "llgesturemgr.h"
- #include "llgridmanager.h" // For gIsInSecondLife
- #include "llinventorybridge.h"
- #include "llinventorymodel.h"
- #include "llinventorymodelfetch.h"
- #include "llmarketplacefunctions.h"
- //MK
- #include "mkrlinterface.h"
- //mk
- #include "llviewercontrol.h"
- #include "llviewerfoldertype.h"
- #include "llpreviewgesture.h"
- #include "llviewermessage.h" // For open_inventory_offer()
- #include "llviewerobjectlist.h"
- #include "llviewerregion.h"
- #include "llvoavatarself.h"
- constexpr F32 FETCH_TIMER_EXPIRY = 30.f;
- // Keep in sinc with HTTP timeout (also AIS_TIMEOUT) in llaisapi.cpp. HB
- constexpr F32 AIS_TIMEOUT = 180.f;
- // Do-nothing ops for use in callbacks:
- void no_inv_op(const LLUUID&)
- {
- }
- void no_op()
- {
- }
- #if 1 // *TODO: LLInventoryCallback should be deprecated to conform to the
- // new boost::bind/coroutine model. This is temporary/transition code.
- void doInventoryCb(LLPointer<LLInventoryCallback> cb, LLUUID id)
- {
- if (cb.notNull())
- {
- cb->fire(id);
- }
- }
- #endif
- // Command handler
- class LLInventoryHandler final : public LLCommandHandler
- {
- public:
- // Requires a trusted browser and a click to trigger
- LLInventoryHandler()
- : LLCommandHandler("inventory", UNTRUSTED_THROTTLE)
- {
- }
- bool canHandleUntrusted(const LLSD& params, const LLSD&, LLMediaCtrl*,
- const std::string& nav_type) override
- {
- if (!params.size())
- {
- return true; // Do not block here; it will fail in handle().
- }
- // With UNTRUSTED_THROTTLE this will cause "clicked" to pass,
- // "external" to be throttled, and the rest to be blocked.
- return nav_type == "clicked" || nav_type == "external";
- }
- bool handle(const LLSD& params, const LLSD&, LLMediaCtrl*) override
- {
- if (!params.size())
- {
- return false;
- }
- // Support secondlife:///app/inventory/show
- if (params[0].asString() == "show")
- {
- LLFloaterInventory::showAgentInventory();
- return true;
- }
- // Otherwise, we need a UUID and a verb...
- if (params.size() < 2)
- {
- return false;
- }
- LLUUID inventory_id;
- if (!inventory_id.set(params[0], false))
- {
- return false;
- }
- const std::string verb = params[1].asString();
- if (verb == "select")
- {
- uuid_vec_t items_to_open;
- items_to_open.emplace_back(inventory_id);
- // inventory_handler is just a stub, because we don't know from who
- // this offer
- open_inventory_offer(items_to_open, "inventory_handler");
- return true;
- }
- return false;
- }
- };
- LLInventoryHandler gInventoryHandler;
- //----------------------------------------------------------------------------
- /// Class LLViewerInventoryItem
- ///----------------------------------------------------------------------------
- LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& uuid,
- const LLUUID& parent_uuid,
- const LLPermissions& perm,
- const LLUUID& asset_uuid,
- LLAssetType::EType type,
- LLInventoryType::EType inv_type,
- const std::string& name,
- const std::string& desc,
- const LLSaleInfo& sale_info,
- U32 flags,
- time_t creation_date_utc)
- : LLInventoryItem(uuid, parent_uuid, perm, asset_uuid, type, inv_type,
- name, desc, sale_info, flags, creation_date_utc),
- mIsComplete(true)
- {
- }
- LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
- const LLUUID& parent_id,
- const std::string& name,
- LLInventoryType::EType inv_type)
- : LLInventoryItem(),
- mIsComplete(false)
- {
- mUUID = item_id;
- mParentUUID = parent_id;
- mInventoryType = inv_type;
- mName = name;
- }
- LLViewerInventoryItem::LLViewerInventoryItem()
- : LLInventoryItem(),
- mIsComplete(false)
- {
- }
- LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other)
- : LLInventoryItem()
- {
- copyViewerItem(other);
- if (!mIsComplete)
- {
- llwarns << "Copy constructor for incomplete item: " << mUUID << llendl;
- }
- }
- LLViewerInventoryItem::LLViewerInventoryItem(const LLInventoryItem* other)
- : LLInventoryItem(other),
- mIsComplete(true)
- {
- }
- void LLViewerInventoryItem::copyViewerItem(const LLViewerInventoryItem* other)
- {
- LLInventoryItem::copyItem(other);
- mIsComplete = other->mIsComplete;
- mTransactionID = other->mTransactionID;
- }
- //virtual
- void LLViewerInventoryItem::copyItem(const LLInventoryItem* other)
- {
- LLInventoryItem::copyItem(other);
- mIsComplete = true;
- mTransactionID.setNull();
- }
- void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const
- {
- newitem = new LLViewerInventoryItem(this);
- if (newitem.notNull())
- {
- LLUUID item_id;
- item_id.generate();
- newitem->setUUID(item_id);
- }
- }
- void LLViewerInventoryItem::updateServer(bool is_new) const
- {
- if (!mIsComplete)
- {
- llwarns << "Incomplete item" << llendl;
- gNotifications.add("IncompleteInventoryItem");
- return;
- }
- if (gAgentID != mPermissions.getOwner())
- {
- // *FIX: deal with this better.
- llwarns << "Unowned item:\n" << ll_pretty_print_sd(this->asLLSD())
- << llendl;
- return;
- }
- LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
- gInventory.accountForUpdate(up);
- if (AISAPI::isAvailable())
- {
- LL_DEBUGS("Inventory") << "Updating item via AIS: " << mUUID
- << LL_ENDL;
- LLSD updates = asLLSD();
- // Replace asset_id and/or shadow_id with transaction_id (hash_id)
- if (updates.has("asset_id"))
- {
- updates.erase("asset_id");
- if (mTransactionID.notNull())
- {
- updates["hash_id"] = mTransactionID;
- }
- }
- if (updates.has("shadow_id"))
- {
- updates.erase("shadow_id");
- if (mTransactionID.notNull())
- {
- updates["hash_id"] = mTransactionID;
- }
- }
- AISAPI::completion_t cr =
- boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>)NULL,
- _1);
- AISAPI::updateItem(mUUID, updates, cr);
- }
- else
- {
- LL_DEBUGS("Inventory") << "Updating item: " << mUUID << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_UpdateInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_CallbackID, 0);
- packMessage(msg);
- gAgent.sendReliableMessage();
- }
- }
- void LLViewerInventoryItem::fetchFromServer() const
- {
- if (mIsComplete)
- {
- // This should not happen
- llwarns << "Request to fetch complete item " << mUUID << llendl;
- return;
- }
- if (LLInventoryModelFetch::useAISFetching())
- {
- // Scheduling is not enough with AIS3: we need to trigger the fetch on
- // the parent folder as well. HB
- LLInventoryModelFetch::forceFetchItem(this);
- return;
- }
- const std::string& url = mPermissions.getOwner() != gAgentID ?
- gAgent.getRegionCapability("FetchLib2") :
- gAgent.getRegionCapability("FetchInventory2");
- if (url.empty())
- {
- // 2023-10: the old UDP messaging fallback path which used to be called
- // here has been removed from the SL official viewer. I considered
- // keeping it for OpenSim, but all current server versions do provide
- // the FetchLib*2 and FetchInventory*2 (AKA AIS2) capabilities, making
- // the legacy UDP path useless. HB
- llwarns_sparse << "No capability available. Fetch aborted" << llendl;
- return;
- }
- static const char* inv_item_str = "inventory item";
- LLSD body;
- body["agent_id"] = gAgentID;
- body["items"][0]["owner_id"] = mPermissions.getOwner();
- body["items"][0]["item_id"] = mUUID;
- LLCore::HttpHandler::ptr_t
- handler(new LLInventoryModel::FetchItemHttpHandler(body));
- gInventory.requestPost(true, url, body, handler, inv_item_str);
- }
- //virtual
- bool LLViewerInventoryItem::unpackMessage(const LLSD item)
- {
- bool rv = LLInventoryItem::fromLLSD(item);
- mIsComplete = true;
- return rv;
- }
- //virtual
- bool LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg,
- const char* block,
- S32 block_num)
- {
- bool rv = LLInventoryItem::unpackMessage(msg, block, block_num);
- mIsComplete = true;
- return rv;
- }
- void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_id)
- {
- mTransactionID = transaction_id;
- }
- //virtual
- void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
- {
- llinfos << "UDP Rez/UpdateObject of UUID " << mUUID << " - parent = "
- << mParentUUID << " - type = " << mType << " - transaction = "
- << mTransactionID << llendl;
- msg->addUUIDFast(_PREHASH_ItemID, mUUID);
- msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
- mPermissions.packMessage(msg);
- msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
- S8 type = static_cast<S8>(mType);
- msg->addS8Fast(_PREHASH_Type, type);
- type = static_cast<S8>(mInventoryType);
- msg->addS8Fast(_PREHASH_InvType, type);
- msg->addU32Fast(_PREHASH_Flags, mFlags);
- mSaleInfo.packMessage(msg);
- msg->addStringFast(_PREHASH_Name, mName);
- msg->addStringFast(_PREHASH_Description, mDescription);
- msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
- U32 crc = getCRC32();
- msg->addU32Fast(_PREHASH_CRC, crc);
- }
- //virtual
- bool LLViewerInventoryItem::importLegacyStream(std::istream& input_stream)
- {
- bool rv = LLInventoryItem::importLegacyStream(input_stream);
- mIsComplete = true;
- return rv;
- }
- //virtual
- void LLViewerInventoryItem::updateParentOnServer(bool restamp) const
- {
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_MoveInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addBoolFast(_PREHASH_Stamp, restamp);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addUUIDFast(_PREHASH_ItemID, mUUID);
- msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
- msg->addString("NewName", NULL);
- gAgent.sendReliableMessage();
- }
- ///----------------------------------------------------------------------------
- /// Class LLViewerInventoryCategory
- ///----------------------------------------------------------------------------
- LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
- const LLUUID& parent_uuid,
- LLFolderType::EType pref,
- const std::string& name,
- const LLUUID& owner_id)
- : LLInventoryCategory(uuid, parent_uuid, pref, name),
- mOwnerID(owner_id),
- mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
- mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
- mFetching(FETCH_NONE)
- {
- mDescendentsRequested.reset();
- }
- LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& owner_id)
- : mOwnerID(owner_id),
- mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
- mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
- mFetching(FETCH_NONE)
- {
- mDescendentsRequested.reset();
- }
- LLViewerInventoryCategory::LLViewerInventoryCategory(const LLViewerInventoryCategory* other)
- {
- copyViewerCategory(other);
- }
- void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCategory* other)
- {
- copyCategory(other);
- mOwnerID = other->mOwnerID;
- mVersion = other->mVersion;
- mDescendentCount = other->mDescendentCount;
- mDescendentsRequested = other->mDescendentsRequested;
- mFetching = FETCH_NONE;
- }
- void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const
- {
- msg->addUUIDFast(_PREHASH_FolderID, mUUID);
- msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
- S8 type = static_cast<S8>(mPreferredType);
- msg->addS8Fast(_PREHASH_Type, type);
- msg->addStringFast(_PREHASH_Name, mName);
- }
- void LLViewerInventoryCategory::updateParentOnServer(bool restamp) const
- {
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_MoveInventoryFolder);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addBool("Stamp", restamp);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addUUIDFast(_PREHASH_FolderID, mUUID);
- msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
- gAgent.sendReliableMessage();
- }
- // Communicate changes with the server.
- void LLViewerInventoryCategory::updateServer(bool is_new) const
- {
- if (LLFolderType::lookupIsProtectedType(mPreferredType))
- {
- gNotifications.add("CannotModifyProtectedCategories");
- return;
- }
- if (AISAPI::isAvailable())
- {
- LL_DEBUGS("Inventory") << "Updating category via AIS: " << mUUID
- << LL_ENDL;
- LLSD new_llsd = asLLSD();
- AISAPI::completion_t cr = boost::bind(&doInventoryCb,
- (LLPointer<LLInventoryCallback>)NULL,
- _1);
- AISAPI::updateCategory(mUUID, new_llsd, cr);
- }
- else
- {
- LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
- gInventory.accountForUpdate(up);
- LL_DEBUGS("Inventory") << "Updating category: " << mUUID
- << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_FolderData);
- packMessage(gMessageSystemp);
- gAgent.sendReliableMessage();
- }
- }
- bool LLViewerInventoryCategory::fetch()
- {
- if (mVersion == VERSION_UNKNOWN &&
- // Expired check prevents multiple downloads:
- mDescendentsRequested.hasExpired())
- {
- LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName
- << ", UUID: " << mUUID << LL_ENDL;
- mDescendentsRequested.reset();
- mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
- if (gAgent.hasRegionCapability("FetchInventoryDescendents2") ||
- LLInventoryModelFetch::useAISFetching())
- {
- LLInventoryModelFetch::getInstance()->start(mUUID);
- return true;
- }
- // 2023-10: the old UDP messaging fallback path which used to be called
- // here has been removed from the SL official viewer. I considered
- // keeping it for OpenSim, but all current server versions do provide
- // the Fetch*2 (AKA AIS2) capabilities, making the legacy UDP path
- // useless. HB
- llwarns_sparse << "No capability available. Fetch aborted" << llendl;
- }
- return false;
- }
- U32 LLViewerInventoryCategory::getFetching()
- {
- // If the timer has not expired, request was scheduled, but not in progress
- // if mFetching request was actually started.
- if (mDescendentsRequested.hasExpired())
- {
- mFetching = FETCH_NONE;
- }
- return mFetching;
- }
- void LLViewerInventoryCategory::setFetching(U32 fetching)
- {
- if (fetching > mFetching) // Allow a switch from normal to recursive
- {
- if (mFetching == FETCH_NONE || mDescendentsRequested.hasExpired())
- {
- mDescendentsRequested.reset();
- F32 timeout = FETCH_TIMER_EXPIRY;
- if (LLInventoryModelFetch::useAISFetching())
- {
- timeout = AIS_TIMEOUT;
- }
- mDescendentsRequested.setTimerExpirySec(timeout);
- }
- mFetching = fetching;
- }
- else if (fetching == FETCH_NONE)
- {
- mDescendentsRequested.reset(); // Will expire it as well. HB
- mFetching = fetching;
- }
- }
- bool LLViewerInventoryCategory::isProtected() const
- {
- LLFolderType::EType cat_type = getPreferredType();
- // If not a protected type, do not bother !
- if (cat_type == LLFolderType::FT_NONE ||
- !LLFolderType::lookupIsProtectedType(cat_type))
- {
- return false;
- }
- // If the folder does not bear the default name for its preferred type, it
- // is not protected.
- if (getName() != LLViewerFolderType::lookupNewCategoryName(cat_type))
- {
- return false;
- }
- // If the folder is not at the root of the inventory, it is not protected.
- LLViewerInventoryCategory* cat = gInventory.getCategory(getParentUUID());
- if (cat && cat->getUUID() != gInventory.getRootFolderID())
- {
- return false;
- }
- // Folder is indeed protected !
- return true;
- }
- bool LLViewerInventoryCategory::isUnique() const
- {
- LLFolderType::EType cat_type = getPreferredType();
- //MK
- bool maybe_rlv = getName() == RL_SHARED_FOLDER;
- //mk
- // If it has no type and is not #RLV, it is indeed not unique...
- if (cat_type == LLFolderType::FT_NONE && !maybe_rlv)
- {
- return false;
- }
- // If the folder does not bear the default name for its preferred type, it
- // is not unique.
- if (!maybe_rlv &&
- getName() != LLViewerFolderType::lookupNewCategoryName(cat_type))
- {
- return false;
- }
- // If the folder is not at the root of the inventory, it is not unique
- // either.
- LLViewerInventoryCategory* cat = gInventory.getCategory(getParentUUID());
- if (cat && cat->getUUID() != gInventory.getRootFolderID())
- {
- return false;
- }
- // Folder is indeed unique !
- return true;
- }
- S32 LLViewerInventoryCategory::getViewerDescendentCount() const
- {
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(getUUID(), cats, items);
- S32 descendents_actual = 0;
- if (cats && items)
- {
- descendents_actual = cats->size() + items->size();
- }
- return descendents_actual;
- }
- LLSD LLViewerInventoryCategory::exportLLSD() const
- {
- LLSD cat_data;
- cat_data["cat_id"] = mUUID;
- cat_data["parent_id"] = mParentUUID;
- cat_data["type"] = LLAssetType::lookup(mType);
- cat_data["pref_type"] = LLFolderType::lookup(mPreferredType);
- cat_data["name"] = mName;
- if (mThumbnailUUID.notNull())
- {
- cat_data["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
- }
- cat_data["owner_id"] = mOwnerID;
- cat_data["version"] = mVersion;
- return cat_data;
- }
- bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data)
- {
- if (cat_data.has("cat_id"))
- {
- mUUID = cat_data["cat_id"].asUUID();
- }
- if (cat_data.has("parent_id"))
- {
- mParentUUID = cat_data["parent_id"].asUUID();
- }
- if (cat_data.has("type"))
- {
- mType = LLAssetType::lookup(cat_data["type"].asString());
- }
- if (cat_data.has("pref_type"))
- {
- mPreferredType =
- LLFolderType::lookup(cat_data["pref_type"].asString());
- }
- if (cat_data.has("thumbnail"))
- {
- mThumbnailUUID.setNull();
- const LLSD& thumb_data = cat_data["thumbnail"];
- if (cat_data.has("asset_id"))
- {
- mThumbnailUUID = thumb_data["asset_id"].asUUID();
- }
- }
- if (cat_data.has("name"))
- {
- mName = cat_data["name"].asString();
- LLStringUtil::replaceNonstandardASCII(mName, ' ');
- LLStringUtil::replaceChar(mName, '|', ' ');
- }
- if (cat_data.has("owner_id"))
- {
- mOwnerID = cat_data["owner_id"].asUUID();
- }
- if (cat_data.has("version"))
- {
- mVersion = cat_data["version"].asInteger();
- }
- return true;
- }
- bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item)
- {
- if (!inv_item)
- {
- return false;
- }
- // Only stock folders have limitation on which item they will accept
- if (getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK)
- {
- return true;
- }
- // If the item is copyable (i.e. non stock) do not accept the drop in a
- // stock folder
- if (inv_item->getPermissions().allowCopyBy(gAgentID, gAgent.getGroupID()))
- {
- return false;
- }
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(getUUID(), cat_array, item_array);
- // Destination stock folder must be empty OR types incoming and existing
- // items must be identical and have the same permissions.
- if (item_array->empty())
- {
- return true;
- }
- LLInventoryItem* item = (*item_array)[0];
- return item->getInventoryType() == inv_item->getInventoryType() &&
- item->getPermissions().getMaskNextOwner() ==
- inv_item->getPermissions().getMaskNextOwner();
- }
- //virtual
- bool LLViewerInventoryCategory::unpackMessage(const LLSD& category)
- {
- return LLInventoryCategory::fromLLSD(category);
- }
- //virtual
- void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg,
- const char* block, S32 block_num)
- {
- LLInventoryCategory::unpackMessage(msg, block, block_num);
- }
- //-----------------------------------------------------------------------------
- // LLInventoryCallbackManager
- //-----------------------------------------------------------------------------
- LLInventoryCallbackManager* LLInventoryCallbackManager::sInstance = NULL;
- LLInventoryCallbackManager::LLInventoryCallbackManager()
- : mLastCallback(0)
- {
- if (sInstance)
- {
- llwarns << "Unexpected multiple instances" << llendl;
- return;
- }
- sInstance = this;
- }
- LLInventoryCallbackManager::~LLInventoryCallbackManager()
- {
- if (sInstance != this)
- {
- llwarns << "Unexpected multiple instances" << llendl;
- return;
- }
- sInstance = NULL;
- }
- //static
- void LLInventoryCallbackManager::destroyClass()
- {
- if (sInstance)
- {
- for (callback_map_t::iterator it = sInstance->mMap.begin(),
- end = sInstance->mMap.end();
- it != end; ++it)
- {
- // drop LLPointer reference to callback
- it->second = NULL;
- }
- sInstance->mMap.clear();
- }
- }
- U32 LLInventoryCallbackManager::registerCB(LLPointer<LLInventoryCallback> cb)
- {
- if (cb.isNull())
- {
- return 0;
- }
- if (!++mLastCallback)
- {
- ++mLastCallback;
- }
- mMap[mLastCallback] = cb;
- return mLastCallback;
- }
- void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id)
- {
- if (callback_id && item_id.notNull())
- {
- callback_map_t::iterator i = mMap.find(callback_id);
- if (i != mMap.end())
- {
- i->second->fire(item_id);
- mMap.erase(i);
- }
- }
- }
- LLInventoryCallbackManager gInventoryCallbacks;
- //-----------------------------------------------------------------------------
- // Other callbacks
- //-----------------------------------------------------------------------------
- void ActivateGestureCallback::fire(const LLUUID& inv_item)
- {
- if (inv_item.notNull())
- {
- gGestureManager.activateGesture(inv_item);
- }
- }
- class CreateGestureCallback : public LLInventoryCallback
- {
- public:
- void fire(const LLUUID& inv_item);
- };
- void CreateGestureCallback::fire(const LLUUID& inv_item)
- {
- if (inv_item.isNull())
- {
- return;
- }
- gGestureManager.activateGesture(inv_item);
- LLViewerInventoryItem* item = gInventory.getItem(inv_item);
- if (!item) return;
- LLPermissions perm = item->getPermissions();
- perm.setGroupBits(gAgentID, gAgent.getGroupID(),
- gSavedSettings.getBool("ShareWithGroup"),
- PERM_MODIFY | PERM_MOVE | PERM_COPY);
- perm.setEveryoneBits(gAgentID, gAgent.getGroupID(),
- gSavedSettings.getBool("EveryoneCopy"),
- PERM_COPY);
- if (perm != item->getPermissions() && item->isFinished())
- {
- item->setPermissions(perm);
- item->updateServer(false);
- }
- // Item was just created, update even if permissions did not change
- gInventory.updateItem(item);
- gInventory.notifyObservers();
- if (!LLPreview::show(inv_item, false))
- {
- LLPreviewGesture* previewp =
- LLPreviewGesture::show("Gesture: " + item->getName(), inv_item,
- LLUUID::null);
- // Force to be entirely onscreen.
- gFloaterViewp->adjustToFitScreen(previewp);
- }
- }
- class CreateItemCallback : public LLInventoryCallback
- {
- public:
- void fire(const LLUUID& inv_item);
- };
- void CreateItemCallback::fire(const LLUUID& inv_item)
- {
- if (inv_item.isNull())
- {
- return;
- }
- LLViewerInventoryItem* item = gInventory.getItem(inv_item);
- if (!item || item->getIsLinkType())
- {
- return;
- }
- if (item->getInventoryType() != LLInventoryType::IT_CALLINGCARD)
- {
- bool share_with_group = gSavedSettings.getBool("ShareWithGroup") &&
- (item->getType() != LLAssetType::AT_LSL_TEXT ||
- !gSavedSettings.getBool("NoModScripts"));
- bool everyone_copy = gSavedSettings.getBool("EveryoneCopy");
- if (share_with_group || everyone_copy)
- {
- LLPermissions perm = item->getPermissions();
- perm.setGroupBits(gAgentID, gAgent.getGroupID(), share_with_group,
- PERM_MODIFY | PERM_MOVE | PERM_COPY);
- perm.setEveryoneBits(gAgentID, gAgent.getGroupID(), everyone_copy,
- PERM_COPY);
- if (perm != item->getPermissions() && item->isFinished())
- {
- item->setPermissions(perm);
- item->updateServer(false);
- }
- }
- }
- // Item was just created, update even if permissions did not change
- gInventory.updateItem(item);
- gInventory.notifyObservers();
- }
- void create_new_item(const std::string& name, const LLUUID& parent_id,
- LLAssetType::EType asset_type,
- LLInventoryType::EType inv_type,
- U32 next_owner_perm, std::string desc)
- {
- if (desc.empty())
- {
- LLAssetType::generateDescriptionFor(asset_type, desc);
- }
- if (next_owner_perm == 0)
- {
- next_owner_perm = PERM_MOVE | PERM_TRANSFER;
- }
- LLPointer<LLInventoryCallback> cb = NULL;
- if (inv_type == LLInventoryType::IT_GESTURE)
- {
- cb = new CreateGestureCallback();
- }
- else
- {
- cb = new CreateItemCallback();
- }
- create_inventory_item(parent_id, LLTransactionID::tnull, name, desc,
- asset_type, inv_type, NO_INV_SUBTYPE,
- next_owner_perm, cb);
- }
- void create_inventory_item(const LLUUID& parent_id,
- const LLTransactionID& transaction_id,
- const std::string& name, const std::string& desc,
- LLAssetType::EType asset_type,
- LLInventoryType::EType inv_type, U8 sub_type,
- U32 next_owner_perm,
- LLPointer<LLInventoryCallback> cb)
- {
- LL_DEBUGS("Inventory") << "Creating item: " << name << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_CreateInventoryItem);
- msg->nextBlock(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlock(_PREHASH_InventoryBlock);
- msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
- msg->addUUIDFast(_PREHASH_FolderID, parent_id);
- msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
- msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm);
- msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
- msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
- msg->addU8Fast(_PREHASH_WearableType, sub_type);
- msg->addStringFast(_PREHASH_Name, name);
- msg->addStringFast(_PREHASH_Description, desc);
- gAgent.sendReliableMessage();
- }
- void copy_inventory_item(const LLUUID& current_owner, const LLUUID& item_id,
- const LLUUID& parent_id, const std::string& new_name,
- LLPointer<LLInventoryCallback> cb)
- {
- // Remember the hashed contents of the item we are going to copy. HB
- LLInventoryAddedObserver::registerCopiedItem(item_id);
- LL_DEBUGS("Inventory") << "Copying item: " << item_id
- << "- as new item: " << new_name << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_CopyInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
- msg->addUUIDFast(_PREHASH_OldAgentID, current_owner);
- msg->addUUIDFast(_PREHASH_OldItemID, item_id);
- msg->addUUIDFast(_PREHASH_NewFolderID, parent_id);
- msg->addStringFast(_PREHASH_NewName, new_name);
- gAgent.sendReliableMessage();
- }
- // Counts the number of items (not folders) in the descending hierarchy
- S32 count_descendants_items(const LLUUID& cat_id)
- {
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(cat_id, cat_array, item_array);
- S32 count = item_array->size();
- LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
- for (LLInventoryModel::cat_array_t::iterator
- iter = cat_array_copy.begin(), end = cat_array_copy.end();
- iter != end; ++iter)
- {
- LLViewerInventoryCategory* category = *iter;
- if (category)
- {
- count += count_descendants_items(category->getUUID());
- }
- }
- return count;
- }
- void update_folder_cb(const LLUUID& folder_id)
- {
- LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
- if (cat)
- {
- gInventory.updateCategory(cat);
- gInventory.notifyObservers();
- }
- }
- void copy_inventory_category_cb(const LLUUID& new_cat_id,
- LLInventoryModel* modelp,
- LLViewerInventoryCategory* catp,
- const LLUUID& root_copy_id,
- bool move_no_copy_items)
- {
- if (new_cat_id.isNull())
- {
- gNotifications.add("CantCreateRequestedInvFolder");
- return;
- }
- modelp->notifyObservers();
- LLMarketplaceData* marketdatap = NULL;
- if (LLMarketplace::contains(catp->getUUID()))
- {
- marketdatap = LLMarketplaceData::getInstance();
- }
- // We need to exclude the initial root of the copy to avoid recursively
- // copying the copy, etc...
- LLUUID root_id = root_copy_id.isNull() ? new_cat_id : root_copy_id;
- // Get the content of the folder
- LLInventoryModel::cat_array_t* cat_array;
- LLInventoryModel::item_array_t* item_array;
- gInventory.getDirectDescendentsOf(catp->getUUID(), cat_array, item_array);
- // If root_copy_id is null, tell the marketplace model we will be waiting
- // for new items to be copied over for this folder
- if (marketdatap && root_copy_id.isNull())
- {
- S32 count = count_descendants_items(catp->getUUID());
- marketdatap->setValidationWaiting(root_id, count);
- }
- // Copy all the items
- const LLUUID& group_id = gAgent.getGroupID();
- LLInventoryModel::item_array_t item_array_copy = *item_array;
- for (LLInventoryModel::item_array_t::iterator
- iter = item_array_copy.begin(), end = item_array_copy.end();
- iter != end; ++iter)
- {
- LLInventoryItem* itemp = *iter;
- if (!itemp) continue; // Paranoia
- bool is_link = itemp->getIsLinkType();
- if (!is_link &&
- !itemp->getPermissions().allowCopyBy(gAgentID, group_id))
- {
- // If the item is nocopy, we do nothing or, optionally, move it
- if (move_no_copy_items)
- {
- // Reparent the item
- LLViewerInventoryItem* vitemp = (LLViewerInventoryItem*)itemp;
- gInventory.changeItemParent(vitemp, new_cat_id, true);
- }
- if (marketdatap)
- {
- // Decrement the count in root_id since that one item won't be
- // copied over
- marketdatap->decrementValidationWaiting(root_id);
- }
- continue;
- }
- LLPointer<LLInventoryCallback> cb =
- new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb,
- new_cat_id));
- if (is_link)
- {
- link_inventory_object(new_cat_id, itemp->getLinkedUUID(), cb);
- }
- else
- {
- copy_inventory_item(itemp->getPermissions().getOwner(),
- itemp->getUUID(), new_cat_id,
- LLStringUtil::null, cb);
- }
- }
- // Copy all the folders
- LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
- for (LLInventoryModel::cat_array_t::iterator
- iter = cat_array_copy.begin(), end = cat_array_copy.end();
- iter != end; ++iter)
- {
- LLViewerInventoryCategory* categoryp = *iter;
- if (categoryp && categoryp->getUUID() != root_id)
- {
- copy_inventory_category(modelp, categoryp, new_cat_id, root_id,
- move_no_copy_items);
- }
- }
- }
- void copy_inventory_category(LLInventoryModel* modelp,
- LLViewerInventoryCategory* catp,
- const LLUUID& parent_id,
- const LLUUID& root_copy_id,
- bool move_no_copy_items)
- {
- if (!modelp || !catp) return;
- // Create the initial folder, with the actual copy function invoked from
- // the callback.
- inventory_func_t func =
- [modelp, catp, root_copy_id, move_no_copy_items](const LLUUID& new_id)
- {
- copy_inventory_category_cb(new_id, modelp, catp, root_copy_id,
- move_no_copy_items);
- };
- gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE,
- catp->getName(), func,
- catp->getThumbnailUUID());
- }
- void link_inventory_object(const LLUUID& parent_id,
- LLPointer<LLInventoryObject> baseobj,
- LLPointer<LLInventoryCallback> cb)
- {
- if (baseobj)
- {
- LLInventoryObject::object_list_t obj_array;
- obj_array.emplace_back(baseobj);
- link_inventory_array(parent_id, obj_array, cb);
- }
- else
- {
- llwarns << "Attempt to link to non-existent object inside category: "
- << parent_id << llendl;
- }
- }
- void link_inventory_object(const LLUUID& parent_id, const LLUUID& id,
- LLPointer<LLInventoryCallback> cb)
- {
- LLPointer<LLInventoryObject> baseobj = gInventory.getObject(id);
- link_inventory_object(parent_id, baseobj, cb);
- }
- void do_link_objects(const LLUUID& parent_id, LLSD& links,
- LLPointer<LLInventoryCallback> cb)
- {
- LL_DEBUGS("Inventory") << "Creating links in " << parent_id << ":\n"
- << ll_pretty_print_sd(links) << LL_ENDL;
- static LLCachedControl<bool> use_ais(gSavedSettings, "UseAISForLinksInSL");
- if (AISAPI::isAvailable(gIsInSecondLife && use_ais))
- {
- LLSD new_inventory = LLSD::emptyMap();
- new_inventory["links"] = links;
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::createInventory(parent_id, new_inventory, cr);
- }
- else // Note: as of 2023-10 this does not work any more in SL ! HB
- {
- LLMessageSystem* msg = gMessageSystemp;
- for (LLSD::array_iterator iter = links.beginArray(),
- end = links.endArray();
- iter != end; ++iter)
- {
- msg->newMessageFast(_PREHASH_LinkInventoryItem);
- msg->nextBlock(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlock(_PREHASH_InventoryBlock);
- LLSD link = *iter;
- msg->addU32Fast(_PREHASH_CallbackID,
- gInventoryCallbacks.registerCB(cb));
- msg->addUUIDFast(_PREHASH_FolderID, parent_id);
- msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null);
- msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID());
- msg->addS8Fast(_PREHASH_Type, link["type"].asInteger());
- msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger());
- msg->addStringFast(_PREHASH_Name, link["name"].asString());
- msg->addStringFast(_PREHASH_Description, link["desc"].asString());
- gAgent.sendReliableMessage();
- }
- }
- }
- // Create links to all listed inventory objects.
- void link_inventory_array(const LLUUID& parent_id,
- LLInventoryObject::object_list_t& baseobj_array,
- LLPointer<LLInventoryCallback> cb)
- {
- LLSD links = LLSD::emptyArray();
- for (LLInventoryObject::object_list_t::const_iterator
- it = baseobj_array.begin(), end = baseobj_array.end();
- it != end; ++it)
- {
- const LLInventoryObject* baseobj = *it;
- if (!baseobj)
- {
- llwarns << "Attempt to link to unknown object inside category: "
- << parent_id << llendl;
- continue;
- }
- #if 0 // This is actually cared for below... and thus possible !
- if (baseobj->getIsLinkType())
- {
- llwarns << "Attempt to create a link to link object: "
- << baseobj->getUUID() << llendl;
- continue;
- }
- #endif
- if (!LLAssetType::lookupCanLink(baseobj->getType()))
- {
- // Fail if item can be found but is of a type that can't be linked.
- // Arguably should fail if the item can't be found too, but that
- // could be a larger behavioral change.
- llwarns << "Attempt to link an unlinkable object, type = "
- << baseobj->getActualType() << ", id = "
- << baseobj->getUUID() << llendl;
- continue;
- }
- LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
- LLAssetType::EType asset_type = LLAssetType::AT_NONE;
- std::string new_desc;
- LLUUID linkee_id;
- if (baseobj->asInventoryCategory())
- {
- inv_type = LLInventoryType::IT_CATEGORY;
- asset_type = LLAssetType::AT_LINK_FOLDER;
- linkee_id = baseobj->getUUID();
- }
- else
- {
- const LLViewerInventoryItem* baseitem =
- baseobj->asViewerInventoryItem();
- if (baseitem)
- {
- inv_type = baseitem->getInventoryType();
- new_desc = baseitem->getActualDescription();
- switch (baseitem->getActualType())
- {
- case LLAssetType::AT_LINK:
- case LLAssetType::AT_LINK_FOLDER:
- linkee_id = baseobj->getLinkedUUID();
- asset_type = baseitem->getActualType();
- break;
- default:
- linkee_id = baseobj->getUUID();
- asset_type = LLAssetType::AT_LINK;
- }
- }
- else
- {
- llwarns << "Could not convert object into an item or category: "
- << baseobj->getUUID() << llendl;
- continue;
- }
- }
- LLSD link = LLSD::emptyMap();
- link["linked_id"] = linkee_id;
- link["type"] = (S8)asset_type;
- link["inv_type"] = (S8)inv_type;
- link["name"] = baseobj->getName();
- link["desc"] = new_desc;
- links.append(link);
- LL_DEBUGS("Inventory") << "Linking object '" << baseobj->getName()
- << "' (" << baseobj->getUUID()
- << ") into category: " << parent_id << LL_ENDL;
- }
- do_link_objects(parent_id, links, cb);
- }
- void link_inventory_item(const LLUUID& item_id, const LLUUID& parent_id,
- const std::string& new_description,
- const LLAssetType::EType asset_type,
- LLPointer<LLInventoryCallback> cb)
- {
- const LLInventoryObject* baseobj = gInventory.getObject(item_id);
- if (!baseobj)
- {
- llwarns << "attempt to link to unknown item, linked-to-item's itemID "
- << item_id << llendl;
- return;
- }
- if (baseobj->getIsLinkType())
- {
- llwarns << "attempt to create a link to a link, linked-to-item's itemID "
- << item_id << llendl;
- return;
- }
- if (!LLAssetType::lookupCanLink(baseobj->getType()))
- {
- // Fail if item can be found but is of a type that can't be linked.
- // Arguably should fail if the item can't be found too, but that could
- // be a larger behavioral change.
- llwarns << "attempt to link an unlinkable item, type = "
- << baseobj->getActualType() << llendl;
- return;
- }
- LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
- if (baseobj->asInventoryCategory())
- {
- inv_type = LLInventoryType::IT_CATEGORY;
- }
- else
- {
- const LLViewerInventoryItem* baseitem =
- baseobj->asViewerInventoryItem();
- if (baseitem)
- {
- inv_type = baseitem->getInventoryType();
- }
- }
- LLSD link = LLSD::emptyMap();
- link["linked_id"] = item_id;
- link["type"] = (S8)asset_type;
- link["inv_type"] = (S8)inv_type;
- link["name"] = baseobj->getName(); // Links cannot be given arbitrary names
- link["desc"] = new_description;
- LLSD links = LLSD::emptyArray();
- links.append(link);
- do_link_objects(parent_id, links, cb);
- }
- void move_inventory_item(const LLUUID& item_id, const LLUUID& parent_id,
- const std::string& new_name,
- LLPointer<LLInventoryCallback> cb)
- {
- LLViewerInventoryItem* item = gInventory.getItem(item_id);
- if (!item)
- {
- llwarns << "Attempt to move an unknown item: " << item_id << llendl;
- return;
- }
- LLUUID curcat_id = item->getParentUUID();
- std::string cur_name = item->getName();
- LL_DEBUGS("Inventory") << "Moving item: " << item_id << " - name: "
- << cur_name << " - new name: " << new_name
- << " - from category: " << curcat_id
- << " - to category: " << parent_id << LL_ENDL;
- // First step: change the name if needed.
- if (new_name != cur_name)
- {
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_MoveInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addBoolFast(_PREHASH_Stamp, false);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- msg->addUUIDFast(_PREHASH_FolderID, curcat_id);
- msg->addStringFast(_PREHASH_NewName, new_name);
- gAgent.sendReliableMessage();
- }
- // Second step: change the category if needed.
- if (parent_id != curcat_id)
- {
- gInventory.changeItemParent(item, parent_id, false);
- }
- gInventory.notifyObservers();
- if (cb.notNull())
- {
- // *HACK: There is no callback for MoveInventoryItem... Emulate one.
- constexpr F32 CALLBACK_DELAY = 3.f; // In seconds
- U32 callback_id = gInventoryCallbacks.registerCB(cb);
- doAfterInterval(boost::bind(&LLInventoryCallbackManager::fire,
- &gInventoryCallbacks,
- callback_id, item_id),
- CALLBACK_DELAY);
- }
- }
- bool movable_objects_with_same_parent(const uuid_vec_t& inv_items)
- {
- U32 count = inv_items.size();
- if (!count)
- {
- return false;
- }
- const LLUUID& id = inv_items[0];
- LLViewerInventoryItem* item = gInventory.getItem(id);
- LLViewerInventoryCategory* cat = item ? NULL : gInventory.getCategory(id);
- if (!item && !cat)
- {
- return false;
- }
- if (count == 1)
- {
- return item || !cat->isUnique();
- }
- const LLUUID& parent_id = item ? item->getParentUUID()
- : cat->getParentUUID();
- for (U32 i = 1; i < count; ++i)
- {
- const LLUUID& id = inv_items[i];
- LLViewerInventoryItem* item = gInventory.getItem(id);
- if (item)
- {
- if (item->getParentUUID() != parent_id)
- {
- return false;
- }
- continue;
- }
- LLViewerInventoryCategory* cat = gInventory.getCategory(id);
- if (!cat || cat->getParentUUID() != parent_id || cat->isUnique())
- {
- return false;
- }
- }
- return true;
- }
- bool reparent_to_folder(const LLUUID& parent_id, uuid_vec_t inv_items)
- {
- LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
- if (!cat)
- {
- return false;
- }
- bool moved = false;
- for (U32 i = 0, count = inv_items.size(); i < count; ++i)
- {
- const LLUUID& id = inv_items[i];
- LLViewerInventoryItem* item = gInventory.getItem(id);
- if (item)
- {
- gInventory.changeItemParent(item, parent_id, false);
- moved = true;
- }
- else
- {
- LLViewerInventoryCategory* cat = gInventory.getCategory(id);
- if (cat && !cat->isProtected())
- {
- gInventory.changeCategoryParent(cat, parent_id, false);
- moved = true;
- }
- }
- }
- return moved;
- }
- // Should call this with an update_item that has been copied and modified from
- // an original source item, rather than modifying the source item directly.
- void update_inventory_item(LLViewerInventoryItem* update_item,
- LLPointer<LLInventoryCallback> cb)
- {
- if (!update_item)
- {
- llwarns << "NULL update_item parameter passed !" << llendl;
- llassert(false);
- return;
- }
- const LLUUID& item_id = update_item->getUUID();
- LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
- if (obj.notNull())
- {
- if (AISAPI::isAvailable())
- {
- LL_DEBUGS("Inventory") << "Updating item via AIS: " << item_id
- << "- name: "
- << update_item->getName() << LL_ENDL;
- LLSD updates = update_item->asLLSD();
- // Replace asset_id and/or shadow_id with transaction_id (hash_id)
- if (updates.has("asset_id"))
- {
- updates.erase("asset_id");
- if (update_item->getTransactionID().notNull())
- {
- updates["hash_id"] = update_item->getTransactionID();
- }
- }
- if (updates.has("shadow_id"))
- {
- updates.erase("shadow_id");
- if (update_item->getTransactionID().notNull())
- {
- updates["hash_id"] = update_item->getTransactionID();
- }
- }
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::updateItem(item_id, updates, cr);
- }
- else
- {
- LL_DEBUGS("Inventory") << "Updating item: " << item_id
- << "- name: "
- << update_item->getName() << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_UpdateInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addUUIDFast(_PREHASH_TransactionID,
- update_item->getTransactionID());
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_CallbackID, 0);
- update_item->packMessage(msg);
- gAgent.sendReliableMessage();
- LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(),
- 0);
- gInventory.accountForUpdate(up);
- gInventory.updateItem(update_item);
- if (cb)
- {
- cb->fire(item_id);
- }
- }
- }
- else
- {
- llwarns << "Call done for invalid item: " << item_id << llendl;
- }
- }
- // Note this only supports updating an existing item. Goes through AISv3 code
- // path where available. Not all uses of item->updateServer() can easily be
- // switched to this paradigm.
- void update_inventory_item(const LLUUID& item_id, const LLSD& updates,
- LLPointer<LLInventoryCallback> cb)
- {
- LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
- if (obj.notNull())
- {
- if (AISAPI::isAvailable())
- {
- LL_DEBUGS("Inventory") << "Updating item via AIS: " << item_id
- << "- name: " << obj->getName() << LL_ENDL;
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::updateItem(item_id, updates, cr);
- }
- else
- {
- LL_DEBUGS("Inventory") << "Updating item: " << item_id
- << "- name: " << obj->getName() << LL_ENDL;
- LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
- new_item->copyViewerItem(obj);
- new_item->fromLLSD(updates, false);
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_UpdateInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->addUUIDFast(_PREHASH_TransactionID,
- new_item->getTransactionID());
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addU32Fast(_PREHASH_CallbackID, 0);
- new_item->packMessage(msg);
- gAgent.sendReliableMessage();
- LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(),
- 0);
- gInventory.accountForUpdate(up);
- gInventory.updateItem(new_item);
- if (cb)
- {
- cb->fire(item_id);
- }
- }
- }
- else
- {
- llwarns << "Call done for invalid item: " << item_id << llendl;
- }
- }
- void update_inventory_category(const LLUUID& cat_id, const LLSD& updates,
- LLPointer<LLInventoryCallback> cb)
- {
- LLPointer<LLViewerInventoryCategory> objp = gInventory.getCategory(cat_id);
- if (objp.isNull())
- {
- llwarns << "Call done for invalid category: " << cat_id << llendl;
- return;
- }
- if (LLFolderType::lookupIsProtectedType(objp->getPreferredType()))
- {
- gNotifications.add("CannotModifyProtectedCategories");
- return;
- }
- if (AISAPI::isAvailable())
- {
- LL_DEBUGS("Inventory") << "Updating category via AIS: " << cat_id
- << " - name: " << objp->getName() << LL_ENDL;
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::updateCategory(cat_id, updates, cr);
- return;
- }
- LLPointer<LLViewerInventoryCategory> catp =
- new LLViewerInventoryCategory(objp);
- catp->fromLLSD(updates);
- LL_DEBUGS("Inventory") << "Updating category: " << cat_id
- << " - name: " << objp->getName() << LL_ENDL;
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_FolderData);
- catp->packMessage(msg);
- gAgent.sendReliableMessage();
- LLInventoryModel::LLCategoryUpdate up(catp->getParentUUID(), 0);
- gInventory.accountForUpdate(up);
- gInventory.updateCategory(catp);
- if (cb)
- {
- cb->fire(cat_id);
- }
- }
- void rename_category(LLInventoryModel* modelp, const LLUUID& cat_id,
- const std::string& new_name)
- {
- if (modelp)
- {
- LLViewerInventoryCategory* catp = modelp->getCategory(cat_id);
- if (catp && get_is_category_renameable(modelp, cat_id) &&
- catp->getName() != new_name)
- {
- LLSD updates;
- updates["name"] = new_name;
- update_inventory_category(cat_id, updates, NULL);
- }
- }
- }
- bool get_is_category_renameable(const LLInventoryModel* modelp,
- const LLUUID& id)
- {
- if (modelp)
- {
- LLViewerInventoryCategory* catp = modelp->getCategory(id);
- if (catp &&
- !LLFolderType::lookupIsProtectedType(catp->getPreferredType()) &&
- catp->getOwnerID() == gAgentID)
- {
- return true;
- }
- }
- return false;
- }
- void remove_inventory_items(LLInventoryObject::object_list_t& items_to_kill,
- LLPointer<LLInventoryCallback> cb)
- {
- for (LLInventoryObject::object_list_t::iterator it = items_to_kill.begin(),
- end = items_to_kill.end();
- it != end; ++it)
- {
- remove_inventory_item(*it, cb);
- }
- }
- void remove_inventory_item(const LLUUID& item_id,
- LLPointer<LLInventoryCallback> cb)
- {
- LLPointer<LLInventoryObject> obj = gInventory.getItem(item_id);
- if (obj.notNull())
- {
- LL_DEBUGS("Inventory") << " Removing item, id: " << item_id
- << " - name " << obj->getName() << LL_ENDL;
- remove_inventory_item(obj, cb);
- }
- else
- {
- llwarns << "Call done for invalid item: " << item_id << llendl;
- }
- }
- void remove_inventory_item(LLPointer<LLInventoryObject> obj,
- LLPointer<LLInventoryCallback> cb)
- {
- if (obj.notNull())
- {
- const LLUUID& item_id = obj->getUUID();
- LL_DEBUGS("Inventory") << " Removing item, id: " << item_id
- << " - name " << obj->getName() << LL_ENDL;
- // Hide any preview
- LLPreview::hide(item_id, true);
- if (AISAPI::isAvailable())
- {
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::removeItem(item_id, cr);
- }
- else
- {
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_RemoveInventoryItem);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_InventoryData);
- msg->addUUIDFast(_PREHASH_ItemID, item_id);
- gAgent.sendReliableMessage();
- // Update inventory and call callback immediately since the UDP
- // message-based system has no callback mechanism.
- gInventory.onObjectDeletedFromServer(item_id);
- if (cb)
- {
- cb->fire(item_id);
- }
- }
- }
- else
- {
- // *TODO: Clean up callback?
- llwarns << "Call done for invalid or non-existent item." << llendl;
- }
- }
- class LLRemoveCategoryOnDestroy final : public LLInventoryCallback
- {
- public:
- LLRemoveCategoryOnDestroy(const LLUUID& cat_id,
- LLPointer<LLInventoryCallback> cb)
- : mID(cat_id),
- mCB(cb)
- {
- }
- ~LLRemoveCategoryOnDestroy() override
- {
- LLInventoryModel::EHasChildren children;
- children = gInventory.categoryHasChildren(mID);
- if (children != LLInventoryModel::CHILDREN_NO)
- {
- llwarns << "Descendents removal failed; cannot remove category: "
- << mID << llendl;
- }
- else
- {
- remove_inventory_category(mID, mCB);
- }
- }
- void fire(const LLUUID& item_id) override {}
- private:
- LLUUID mID;
- LLPointer<LLInventoryCallback> mCB;
- };
- void remove_inventory_category(const LLUUID& cat_id,
- LLPointer<LLInventoryCallback> cb,
- bool check_protected)
- {
- LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id);
- if (obj.notNull())
- {
- LL_DEBUGS("Inventory") << "Removing category id: " << cat_id
- << " - name " << obj->getName() << LL_ENDL;
- if (!gInventory.isCategoryComplete(cat_id))
- {
- llwarns << "Not purging the incompletely downloaded folder: "
- << cat_id << llendl;
- return;
- }
- if (check_protected && obj->isProtected())
- {
- gNotifications.add("CannotRemoveProtectedCategories");
- return;
- }
- if (AISAPI::isAvailable())
- {
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::removeCategory(cat_id, cr);
- }
- else
- {
- // RemoveInventoryFolder does not remove children, so must clear
- // descendents first.
- LLInventoryModel::EHasChildren children;
- children = gInventory.categoryHasChildren(cat_id);
- if (children != LLInventoryModel::CHILDREN_NO)
- {
- LL_DEBUGS("Inventory") << "Purging descendents first..."
- << LL_ENDL;
- LLPointer<LLInventoryCallback> wrap_cb =
- new LLRemoveCategoryOnDestroy(cat_id, cb);
- purge_descendents_of(cat_id, wrap_cb);
- return;
- }
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessageFast(_PREHASH_RemoveInventoryFolder);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
- msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlockFast(_PREHASH_FolderData);
- msg->addUUIDFast(_PREHASH_FolderID, cat_id);
- gAgent.sendReliableMessage();
- // Update inventory and call callback immediately since the UDP
- // message-based system has no callback mechanism.
- gInventory.onObjectDeletedFromServer(cat_id);
- if (cb)
- {
- cb->fire(cat_id);
- }
- }
- }
- else
- {
- llwarns << "Call done for invalid or non-existent category: " << cat_id
- << llendl;
- }
- }
- void remove_inventory_object(const LLUUID& object_id,
- LLPointer<LLInventoryCallback> cb)
- {
- if (gInventory.getCategory(object_id))
- {
- remove_inventory_category(object_id, cb);
- }
- else
- {
- remove_inventory_item(object_id, cb);
- }
- }
- void remove_folder_contents(const LLUUID& category,
- LLPointer<LLInventoryCallback> cb)
- {
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(category, cats, items,
- LLInventoryModel::EXCLUDE_TRASH);
- for (S32 i = 0, count = items.size(); i < count; ++i)
- {
- LLViewerInventoryItem* item = items[i];
- if (item && item->getIsLinkType())
- {
- remove_inventory_item(item->getUUID(), cb);
- }
- }
- }
- void slam_inventory_folder(const LLUUID& folder_id, const LLSD& contents,
- LLPointer<LLInventoryCallback> cb)
- {
- if (AISAPI::isAvailable())
- {
- LL_DEBUGS("Inventory") << "using AISv3 to slam folder, id: "
- << folder_id << " - New contents: "
- << ll_pretty_print_sd(contents) << LL_ENDL;
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::slamFolder(folder_id, contents, cr);
- }
- else
- {
- LL_DEBUGS("Inventory") << "using item-by-item calls to slam folder, id: "
- << folder_id << " - New contents: "
- << ll_pretty_print_sd(contents) << LL_ENDL;
- remove_folder_contents(folder_id, cb);
- for (LLSD::array_const_iterator it = contents.beginArray(),
- end = contents.endArray();
- it != end; ++it)
- {
- LLViewerInventoryItem* item = new LLViewerInventoryItem;
- if (item) // Paranoia (guard against out of memory)
- {
- const LLSD& item_contents = *it;
- item->fromLLSD(item_contents);
- link_inventory_object(folder_id, item, cb);
- }
- }
- }
- }
- void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
- {
- #if 0 // MAINT-3319: the cached number of descendents is not always reliable
- if (gInventory.categoryHasChildren(id) == LLInventoryModel::CHILDREN_NO)
- {
- LL_DEBUGS("Inventory") << "No descendents to purge for " << id
- << LL_ENDL;
- return;
- }
- #endif
- LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(id);
- if (cat.notNull())
- {
- if (!gInventory.isCategoryComplete(id))
- {
- llwarns << "Not purging the incompletely downloaded folder: "
- << id << llendl;
- return;
- }
- if (AISAPI::isAvailable())
- {
- AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
- AISAPI::purgeDescendents(id, cr);
- }
- else
- {
- // Send it upstream
- LLMessageSystem* msg = gMessageSystemp;
- msg->newMessage(_PREHASH_PurgeInventoryDescendents);
- msg->nextBlock(_PREHASH_AgentData);
- msg->addUUID(_PREHASH_AgentID, gAgentID);
- msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
- msg->nextBlock(_PREHASH_InventoryData);
- msg->addUUID(_PREHASH_FolderID, id);
- gAgent.sendReliableMessage();
- // Update inventory and call callback immediately since the UDP
- // message-based system has no callback mechanism.
- gInventory.onDescendentsPurgedFromServer(id);
- if (cb)
- {
- cb->fire(id);
- }
- }
- }
- }
- void copy_inventory_from_notecard(const LLUUID& object_id,
- const LLUUID& notecard_inv_id,
- const LLInventoryItem* srcp,
- U32 callback_id)
- {
- if (!srcp)
- {
- llwarns << "Null pointer to item was passed for object_id "
- << object_id << " and notecard_inv_id " << notecard_inv_id
- << llendl;
- return;
- }
- LLViewerRegion* regionp = NULL;
- LLViewerObject* objp = NULL;
- if (object_id.notNull() && (objp = gObjectList.findObject(object_id)))
- {
- regionp = objp->getRegion();
- }
- // Fallback to the agents region if for some reason the object is not found
- // in the viewer.
- if (!regionp)
- {
- regionp = gAgent.getRegion();
- }
- if (!regionp)
- {
- llwarns << "Cannot find region from object_id " << object_id
- << " or agent" << llendl;
- return;
- }
- const std::string& url =
- regionp->getCapability("CopyInventoryFromNotecard");
- if (url.empty())
- {
- llwarns << "There is no 'CopyInventoryFromNotecard' capability for region: "
- << regionp->getIdentity() << llendl;
- return;
- }
- LLSD body;
- body["notecard-id"] = notecard_inv_id;
- body["object-id"] = object_id;
- body["item-id"] = srcp->getUUID();
- body["folder-id"] =
- gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(srcp->getType()));
- body["callback-id"] = (LLSD::Integer)callback_id;
- LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
- "Notecard coppied.",
- "Failed to copy notecard");
- }
- //virtual
- LLAssetType::EType LLViewerInventoryItem::getType() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getType();
- }
- if (const LLViewerInventoryCategory* linked_category = getLinkedCategory())
- {
- return linked_category->getType();
- }
- return LLInventoryItem::getType();
- }
- //virtual
- const LLUUID& LLViewerInventoryItem::getAssetUUID() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getAssetUUID();
- }
- return LLInventoryItem::getAssetUUID();
- }
- //virtual
- const std::string& LLViewerInventoryItem::getName() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getName();
- }
- if (const LLViewerInventoryCategory* linked_category = getLinkedCategory())
- {
- return linked_category->getName();
- }
- return LLInventoryItem::getName();
- }
- //virtual
- const LLPermissions& LLViewerInventoryItem::getPermissions() const
- {
- // Use the actual permissions of the symlink, not its parent.
- return LLInventoryItem::getPermissions();
- }
- //virtual
- const LLUUID& LLViewerInventoryItem::getCreatorUUID() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getCreatorUUID();
- }
- return LLInventoryItem::getCreatorUUID();
- }
- //virtual
- const std::string& LLViewerInventoryItem::getDescription() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getDescription();
- }
- return LLInventoryItem::getDescription();
- }
- //virtual
- const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getSaleInfo();
- }
- return LLInventoryItem::getSaleInfo();
- }
- //virtual
- const LLUUID& LLViewerInventoryItem::getThumbnailUUID() const
- {
- if (mThumbnailUUID.notNull())
- {
- return mThumbnailUUID;
- }
- if (mType == LLAssetType::AT_TEXTURE)
- {
- return mAssetUUID;
- }
- if (mType == LLAssetType::AT_LINK)
- {
- LLViewerInventoryItem* itemp = gInventory.getItem(mAssetUUID);
- return itemp ? itemp->getThumbnailUUID() : LLUUID::null;
- }
- if (mType == LLAssetType::AT_LINK_FOLDER)
- {
- LLViewerInventoryCategory* catp = gInventory.getCategory(mAssetUUID);
- return catp ? catp->getThumbnailUUID() : LLUUID::null;
- }
- return LLUUID::null;
- }
- //virtual
- LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getInventoryType();
- }
- // Categories do not have types. If this item is an AT_FOLDER_LINK, treat
- // it as a category.
- if (getLinkedCategory())
- {
- return LLInventoryType::IT_CATEGORY;
- }
- return LLInventoryItem::getInventoryType();
- }
- //virtual
- U32 LLViewerInventoryItem::getFlags() const
- {
- if (const LLViewerInventoryItem* linked_item = getLinkedItem())
- {
- return linked_item->getFlags();
- }
- return LLInventoryItem::getFlags();
- }
- //virtual
- S32 LLViewerInventoryItem::getSubType() const
- {
- return getFlags() & LLInventoryItem::II_FLAGS_SUBTYPE_MASK;
- }
- //virtual
- bool LLViewerInventoryItem::isWearableType() const
- {
- return getInventoryType() == LLInventoryType::IT_WEARABLE;
- }
- //virtual
- LLWearableType::EType LLViewerInventoryItem::getWearableType() const
- {
- if (!isWearableType())
- {
- return LLWearableType::WT_INVALID;
- }
- return LLWearableType::inventoryFlagsToWearableType(getFlags());
- }
- //virtual
- bool LLViewerInventoryItem::isSettingsType() const
- {
- return getInventoryType() == LLInventoryType::IT_SETTINGS;
- }
- //virtual
- LLSettingsType::EType LLViewerInventoryItem::getSettingsType() const
- {
- if (!isSettingsType())
- {
- return LLSettingsType::ST_NONE;
- }
- return LLSettingsType::fromInventoryFlags(getFlags());
- }
- // This returns true if the item that this item points to doesn't exist in
- // memory (i.e. LLInventoryModel). The base item might still be in the database
- // but just not loaded yet.
- bool LLViewerInventoryItem::getIsBrokenLink() const
- {
- // If the item's type resolves to be a link, that means either:
- // A. It was not able to perform indirection, i.e. the baseobj does not
- // exist in memory.
- // B. It is pointing to another link, which is illegal.
- return LLAssetType::lookupIsLinkType(getType());
- }
- LLViewerInventoryItem* LLViewerInventoryItem::getLinkedItem() const
- {
- if (mType == LLAssetType::AT_LINK)
- {
- LLViewerInventoryItem* linked_item = gInventory.getItem(mAssetUUID);
- if (linked_item && linked_item->getIsLinkType())
- {
- llwarns << "Warning: Accessing link to link" << llendl;
- return NULL;
- }
- return linked_item;
- }
- return NULL;
- }
- LLViewerInventoryCategory* LLViewerInventoryItem::getLinkedCategory() const
- {
- if (mType == LLAssetType::AT_LINK_FOLDER)
- {
- return gInventory.getCategory(mAssetUUID);
- }
- return NULL;
- }
- bool get_is_item_worn(const LLUUID& id, bool include_gestures)
- {
- const LLViewerInventoryItem* itemp = gInventory.getItem(id);
- if (!itemp)
- {
- return false;
- }
- switch (itemp->getType())
- {
- case LLAssetType::AT_OBJECT:
- {
- if (isAgentAvatarValid() &&
- gAgentAvatarp->isWearingAttachment(itemp->getLinkedUUID()))
- {
- return true;
- }
- break;
- }
- case LLAssetType::AT_BODYPART:
- case LLAssetType::AT_CLOTHING:
- {
- if (gAgentWearables.isWearingItem(itemp->getLinkedUUID()))
- {
- return true;
- }
- break;
- }
- case LLAssetType::AT_GESTURE:
- {
- if (include_gestures &&
- gGestureManager.isGestureActive(itemp->getLinkedUUID()))
- {
- return true;
- }
- break;
- }
- default:
- break;
- }
- return false;
- }
- S32 get_folder_levels(LLInventoryCategory* catp)
- {
- LLInventoryModel::cat_array_t* cats;
- LLInventoryModel::item_array_t* items;
- gInventory.getDirectDescendentsOf(catp->getUUID(), cats, items);
- S32 max_child_levels = 0;
- for (S32 i = 0, count = cats->size(); i < count; ++i)
- {
- catp = (*cats)[i];
- // Recurse through categories.
- max_child_levels = llmax(max_child_levels, get_folder_levels(catp));
- }
- return max_child_levels + 1;
- }
- S32 get_folder_path_length(const LLUUID& ancestor_id,
- const LLUUID& descendant_id)
- {
- if (ancestor_id == descendant_id)
- {
- return 0;
- }
- S32 depth = 0;
- LLInventoryCategory* category = gInventory.getCategory(descendant_id);
- while (category)
- {
- const LLUUID& parent_id = category->getParentUUID();
- if (parent_id.isNull())
- {
- break;
- }
- ++depth;
- if (parent_id == ancestor_id)
- {
- return depth;
- }
- category = gInventory.getCategory(parent_id);
- }
- llwarns << "Could not trace a path from the descendant to the ancestor"
- << llendl;
- return -1;
- }
- LLUUID get_calling_card_buddy_id(LLViewerInventoryItem* itemp, bool allow_self)
- {
- if (!itemp || itemp->getType() != LLAssetType::AT_CALLINGCARD)
- {
- return LLUUID::null;
- }
- LLUUID buddy_id(itemp->getActualDescription(), false);
- if (buddy_id.isNull())
- {
- buddy_id = itemp->getCreatorUUID();
- }
- return !allow_self && buddy_id == gAgentID ? LLUUID::null : buddy_id;
- }
- class LLItemAddedObserver : public LLInventoryObserver
- {
- public:
- LLItemAddedObserver(const LLUUID& copied_asset_id,
- LLPointer<LLInventoryCallback> cb)
- : mAssetId(copied_asset_id),
- mCallback(cb)
- {
- }
- void changed(U32 mask) override
- {
- if (!(mask & (LLInventoryObserver::ADD)))
- {
- return;
- }
- for (uuid_list_t::const_iterator it = gInventory.getAddedIDs().begin(),
- end = gInventory.getAddedIDs().end();
- it != end; ++it)
- {
- LLViewerInventoryItem* itemp = gInventory.getItem(*it);
- if (itemp && itemp->getAssetUUID() == mAssetId)
- {
- mCallback->fire(*it);
- gInventory.removeObserver(this);
- delete this;
- return;
- }
- }
- }
- private:
- LLUUID mAssetId;
- LLPointer<LLInventoryCallback> mCallback;
- };
- void move_or_copy_item_from_object(const LLUUID& dest_cat_id,
- const LLUUID& object_id,
- const LLUUID& item_id,
- LLPointer<LLInventoryCallback> cb)
- {
- LLViewerObject* objectp = gObjectList.findObject(object_id);
- if (!objectp) return;
- const LLInventoryItem* itemp = objectp->getInventoryItem(item_id);
- if (!itemp) return;
- const LLUUID& asset_id = itemp->getAssetUUID();
- LLItemAddedObserver* observerp = new LLItemAddedObserver(asset_id, cb);
- gInventory.addObserver(observerp);
- objectp->moveInventory(dest_cat_id, item_id);
- }
|