llviewerinventory.cpp 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438
  1. /**
  2. * @file llviewerinventory.cpp
  3. * @brief Implementation of the viewer side inventory objects.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llviewerinventory.h"
  34. #include "llcallbacklist.h"
  35. #include "llcorehttputil.h"
  36. #include "llnotifications.h"
  37. #include "llsdutil.h"
  38. #include "llmessage.h"
  39. #include "llagent.h"
  40. #include "llagentwearables.h"
  41. #include "llaisapi.h"
  42. #include "llappearancemgr.h"
  43. #include "llcommandhandler.h"
  44. #include "llfloaterinventory.h"
  45. #include "llfolderview.h"
  46. #include "llgesturemgr.h"
  47. #include "llgridmanager.h" // For gIsInSecondLife
  48. #include "llinventorybridge.h"
  49. #include "llinventorymodel.h"
  50. #include "llinventorymodelfetch.h"
  51. #include "llmarketplacefunctions.h"
  52. //MK
  53. #include "mkrlinterface.h"
  54. //mk
  55. #include "llviewercontrol.h"
  56. #include "llviewerfoldertype.h"
  57. #include "llpreviewgesture.h"
  58. #include "llviewermessage.h" // For open_inventory_offer()
  59. #include "llviewerobjectlist.h"
  60. #include "llviewerregion.h"
  61. #include "llvoavatarself.h"
  62. constexpr F32 FETCH_TIMER_EXPIRY = 30.f;
  63. // Keep in sinc with HTTP timeout (also AIS_TIMEOUT) in llaisapi.cpp. HB
  64. constexpr F32 AIS_TIMEOUT = 180.f;
  65. // Do-nothing ops for use in callbacks:
  66. void no_inv_op(const LLUUID&)
  67. {
  68. }
  69. void no_op()
  70. {
  71. }
  72. #if 1 // *TODO: LLInventoryCallback should be deprecated to conform to the
  73. // new boost::bind/coroutine model. This is temporary/transition code.
  74. void doInventoryCb(LLPointer<LLInventoryCallback> cb, LLUUID id)
  75. {
  76. if (cb.notNull())
  77. {
  78. cb->fire(id);
  79. }
  80. }
  81. #endif
  82. // Command handler
  83. class LLInventoryHandler final : public LLCommandHandler
  84. {
  85. public:
  86. // Requires a trusted browser and a click to trigger
  87. LLInventoryHandler()
  88. : LLCommandHandler("inventory", UNTRUSTED_THROTTLE)
  89. {
  90. }
  91. bool canHandleUntrusted(const LLSD& params, const LLSD&, LLMediaCtrl*,
  92. const std::string& nav_type) override
  93. {
  94. if (!params.size())
  95. {
  96. return true; // Do not block here; it will fail in handle().
  97. }
  98. // With UNTRUSTED_THROTTLE this will cause "clicked" to pass,
  99. // "external" to be throttled, and the rest to be blocked.
  100. return nav_type == "clicked" || nav_type == "external";
  101. }
  102. bool handle(const LLSD& params, const LLSD&, LLMediaCtrl*) override
  103. {
  104. if (!params.size())
  105. {
  106. return false;
  107. }
  108. // Support secondlife:///app/inventory/show
  109. if (params[0].asString() == "show")
  110. {
  111. LLFloaterInventory::showAgentInventory();
  112. return true;
  113. }
  114. // Otherwise, we need a UUID and a verb...
  115. if (params.size() < 2)
  116. {
  117. return false;
  118. }
  119. LLUUID inventory_id;
  120. if (!inventory_id.set(params[0], false))
  121. {
  122. return false;
  123. }
  124. const std::string verb = params[1].asString();
  125. if (verb == "select")
  126. {
  127. uuid_vec_t items_to_open;
  128. items_to_open.emplace_back(inventory_id);
  129. // inventory_handler is just a stub, because we don't know from who
  130. // this offer
  131. open_inventory_offer(items_to_open, "inventory_handler");
  132. return true;
  133. }
  134. return false;
  135. }
  136. };
  137. LLInventoryHandler gInventoryHandler;
  138. //----------------------------------------------------------------------------
  139. /// Class LLViewerInventoryItem
  140. ///----------------------------------------------------------------------------
  141. LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& uuid,
  142. const LLUUID& parent_uuid,
  143. const LLPermissions& perm,
  144. const LLUUID& asset_uuid,
  145. LLAssetType::EType type,
  146. LLInventoryType::EType inv_type,
  147. const std::string& name,
  148. const std::string& desc,
  149. const LLSaleInfo& sale_info,
  150. U32 flags,
  151. time_t creation_date_utc)
  152. : LLInventoryItem(uuid, parent_uuid, perm, asset_uuid, type, inv_type,
  153. name, desc, sale_info, flags, creation_date_utc),
  154. mIsComplete(true)
  155. {
  156. }
  157. LLViewerInventoryItem::LLViewerInventoryItem(const LLUUID& item_id,
  158. const LLUUID& parent_id,
  159. const std::string& name,
  160. LLInventoryType::EType inv_type)
  161. : LLInventoryItem(),
  162. mIsComplete(false)
  163. {
  164. mUUID = item_id;
  165. mParentUUID = parent_id;
  166. mInventoryType = inv_type;
  167. mName = name;
  168. }
  169. LLViewerInventoryItem::LLViewerInventoryItem()
  170. : LLInventoryItem(),
  171. mIsComplete(false)
  172. {
  173. }
  174. LLViewerInventoryItem::LLViewerInventoryItem(const LLViewerInventoryItem* other)
  175. : LLInventoryItem()
  176. {
  177. copyViewerItem(other);
  178. if (!mIsComplete)
  179. {
  180. llwarns << "Copy constructor for incomplete item: " << mUUID << llendl;
  181. }
  182. }
  183. LLViewerInventoryItem::LLViewerInventoryItem(const LLInventoryItem* other)
  184. : LLInventoryItem(other),
  185. mIsComplete(true)
  186. {
  187. }
  188. void LLViewerInventoryItem::copyViewerItem(const LLViewerInventoryItem* other)
  189. {
  190. LLInventoryItem::copyItem(other);
  191. mIsComplete = other->mIsComplete;
  192. mTransactionID = other->mTransactionID;
  193. }
  194. //virtual
  195. void LLViewerInventoryItem::copyItem(const LLInventoryItem* other)
  196. {
  197. LLInventoryItem::copyItem(other);
  198. mIsComplete = true;
  199. mTransactionID.setNull();
  200. }
  201. void LLViewerInventoryItem::cloneViewerItem(LLPointer<LLViewerInventoryItem>& newitem) const
  202. {
  203. newitem = new LLViewerInventoryItem(this);
  204. if (newitem.notNull())
  205. {
  206. LLUUID item_id;
  207. item_id.generate();
  208. newitem->setUUID(item_id);
  209. }
  210. }
  211. void LLViewerInventoryItem::updateServer(bool is_new) const
  212. {
  213. if (!mIsComplete)
  214. {
  215. llwarns << "Incomplete item" << llendl;
  216. gNotifications.add("IncompleteInventoryItem");
  217. return;
  218. }
  219. if (gAgentID != mPermissions.getOwner())
  220. {
  221. // *FIX: deal with this better.
  222. llwarns << "Unowned item:\n" << ll_pretty_print_sd(this->asLLSD())
  223. << llendl;
  224. return;
  225. }
  226. LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
  227. gInventory.accountForUpdate(up);
  228. if (AISAPI::isAvailable())
  229. {
  230. LL_DEBUGS("Inventory") << "Updating item via AIS: " << mUUID
  231. << LL_ENDL;
  232. LLSD updates = asLLSD();
  233. // Replace asset_id and/or shadow_id with transaction_id (hash_id)
  234. if (updates.has("asset_id"))
  235. {
  236. updates.erase("asset_id");
  237. if (mTransactionID.notNull())
  238. {
  239. updates["hash_id"] = mTransactionID;
  240. }
  241. }
  242. if (updates.has("shadow_id"))
  243. {
  244. updates.erase("shadow_id");
  245. if (mTransactionID.notNull())
  246. {
  247. updates["hash_id"] = mTransactionID;
  248. }
  249. }
  250. AISAPI::completion_t cr =
  251. boost::bind(&doInventoryCb, (LLPointer<LLInventoryCallback>)NULL,
  252. _1);
  253. AISAPI::updateItem(mUUID, updates, cr);
  254. }
  255. else
  256. {
  257. LL_DEBUGS("Inventory") << "Updating item: " << mUUID << LL_ENDL;
  258. LLMessageSystem* msg = gMessageSystemp;
  259. msg->newMessageFast(_PREHASH_UpdateInventoryItem);
  260. msg->nextBlockFast(_PREHASH_AgentData);
  261. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  262. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  263. msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
  264. msg->nextBlockFast(_PREHASH_InventoryData);
  265. msg->addU32Fast(_PREHASH_CallbackID, 0);
  266. packMessage(msg);
  267. gAgent.sendReliableMessage();
  268. }
  269. }
  270. void LLViewerInventoryItem::fetchFromServer() const
  271. {
  272. if (mIsComplete)
  273. {
  274. // This should not happen
  275. llwarns << "Request to fetch complete item " << mUUID << llendl;
  276. return;
  277. }
  278. if (LLInventoryModelFetch::useAISFetching())
  279. {
  280. // Scheduling is not enough with AIS3: we need to trigger the fetch on
  281. // the parent folder as well. HB
  282. LLInventoryModelFetch::forceFetchItem(this);
  283. return;
  284. }
  285. const std::string& url = mPermissions.getOwner() != gAgentID ?
  286. gAgent.getRegionCapability("FetchLib2") :
  287. gAgent.getRegionCapability("FetchInventory2");
  288. if (url.empty())
  289. {
  290. // 2023-10: the old UDP messaging fallback path which used to be called
  291. // here has been removed from the SL official viewer. I considered
  292. // keeping it for OpenSim, but all current server versions do provide
  293. // the FetchLib*2 and FetchInventory*2 (AKA AIS2) capabilities, making
  294. // the legacy UDP path useless. HB
  295. llwarns_sparse << "No capability available. Fetch aborted" << llendl;
  296. return;
  297. }
  298. static const char* inv_item_str = "inventory item";
  299. LLSD body;
  300. body["agent_id"] = gAgentID;
  301. body["items"][0]["owner_id"] = mPermissions.getOwner();
  302. body["items"][0]["item_id"] = mUUID;
  303. LLCore::HttpHandler::ptr_t
  304. handler(new LLInventoryModel::FetchItemHttpHandler(body));
  305. gInventory.requestPost(true, url, body, handler, inv_item_str);
  306. }
  307. //virtual
  308. bool LLViewerInventoryItem::unpackMessage(const LLSD item)
  309. {
  310. bool rv = LLInventoryItem::fromLLSD(item);
  311. mIsComplete = true;
  312. return rv;
  313. }
  314. //virtual
  315. bool LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg,
  316. const char* block,
  317. S32 block_num)
  318. {
  319. bool rv = LLInventoryItem::unpackMessage(msg, block, block_num);
  320. mIsComplete = true;
  321. return rv;
  322. }
  323. void LLViewerInventoryItem::setTransactionID(const LLTransactionID& transaction_id)
  324. {
  325. mTransactionID = transaction_id;
  326. }
  327. //virtual
  328. void LLViewerInventoryItem::packMessage(LLMessageSystem* msg) const
  329. {
  330. llinfos << "UDP Rez/UpdateObject of UUID " << mUUID << " - parent = "
  331. << mParentUUID << " - type = " << mType << " - transaction = "
  332. << mTransactionID << llendl;
  333. msg->addUUIDFast(_PREHASH_ItemID, mUUID);
  334. msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
  335. mPermissions.packMessage(msg);
  336. msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
  337. S8 type = static_cast<S8>(mType);
  338. msg->addS8Fast(_PREHASH_Type, type);
  339. type = static_cast<S8>(mInventoryType);
  340. msg->addS8Fast(_PREHASH_InvType, type);
  341. msg->addU32Fast(_PREHASH_Flags, mFlags);
  342. mSaleInfo.packMessage(msg);
  343. msg->addStringFast(_PREHASH_Name, mName);
  344. msg->addStringFast(_PREHASH_Description, mDescription);
  345. msg->addS32Fast(_PREHASH_CreationDate, mCreationDate);
  346. U32 crc = getCRC32();
  347. msg->addU32Fast(_PREHASH_CRC, crc);
  348. }
  349. //virtual
  350. bool LLViewerInventoryItem::importLegacyStream(std::istream& input_stream)
  351. {
  352. bool rv = LLInventoryItem::importLegacyStream(input_stream);
  353. mIsComplete = true;
  354. return rv;
  355. }
  356. //virtual
  357. void LLViewerInventoryItem::updateParentOnServer(bool restamp) const
  358. {
  359. LLMessageSystem* msg = gMessageSystemp;
  360. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  361. msg->nextBlockFast(_PREHASH_AgentData);
  362. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  363. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  364. msg->addBoolFast(_PREHASH_Stamp, restamp);
  365. msg->nextBlockFast(_PREHASH_InventoryData);
  366. msg->addUUIDFast(_PREHASH_ItemID, mUUID);
  367. msg->addUUIDFast(_PREHASH_FolderID, mParentUUID);
  368. msg->addString("NewName", NULL);
  369. gAgent.sendReliableMessage();
  370. }
  371. ///----------------------------------------------------------------------------
  372. /// Class LLViewerInventoryCategory
  373. ///----------------------------------------------------------------------------
  374. LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& uuid,
  375. const LLUUID& parent_uuid,
  376. LLFolderType::EType pref,
  377. const std::string& name,
  378. const LLUUID& owner_id)
  379. : LLInventoryCategory(uuid, parent_uuid, pref, name),
  380. mOwnerID(owner_id),
  381. mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
  382. mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
  383. mFetching(FETCH_NONE)
  384. {
  385. mDescendentsRequested.reset();
  386. }
  387. LLViewerInventoryCategory::LLViewerInventoryCategory(const LLUUID& owner_id)
  388. : mOwnerID(owner_id),
  389. mVersion(LLViewerInventoryCategory::VERSION_UNKNOWN),
  390. mDescendentCount(LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN),
  391. mFetching(FETCH_NONE)
  392. {
  393. mDescendentsRequested.reset();
  394. }
  395. LLViewerInventoryCategory::LLViewerInventoryCategory(const LLViewerInventoryCategory* other)
  396. {
  397. copyViewerCategory(other);
  398. }
  399. void LLViewerInventoryCategory::copyViewerCategory(const LLViewerInventoryCategory* other)
  400. {
  401. copyCategory(other);
  402. mOwnerID = other->mOwnerID;
  403. mVersion = other->mVersion;
  404. mDescendentCount = other->mDescendentCount;
  405. mDescendentsRequested = other->mDescendentsRequested;
  406. mFetching = FETCH_NONE;
  407. }
  408. void LLViewerInventoryCategory::packMessage(LLMessageSystem* msg) const
  409. {
  410. msg->addUUIDFast(_PREHASH_FolderID, mUUID);
  411. msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
  412. S8 type = static_cast<S8>(mPreferredType);
  413. msg->addS8Fast(_PREHASH_Type, type);
  414. msg->addStringFast(_PREHASH_Name, mName);
  415. }
  416. void LLViewerInventoryCategory::updateParentOnServer(bool restamp) const
  417. {
  418. LLMessageSystem* msg = gMessageSystemp;
  419. msg->newMessageFast(_PREHASH_MoveInventoryFolder);
  420. msg->nextBlockFast(_PREHASH_AgentData);
  421. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  422. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  423. msg->addBool("Stamp", restamp);
  424. msg->nextBlockFast(_PREHASH_InventoryData);
  425. msg->addUUIDFast(_PREHASH_FolderID, mUUID);
  426. msg->addUUIDFast(_PREHASH_ParentID, mParentUUID);
  427. gAgent.sendReliableMessage();
  428. }
  429. // Communicate changes with the server.
  430. void LLViewerInventoryCategory::updateServer(bool is_new) const
  431. {
  432. if (LLFolderType::lookupIsProtectedType(mPreferredType))
  433. {
  434. gNotifications.add("CannotModifyProtectedCategories");
  435. return;
  436. }
  437. if (AISAPI::isAvailable())
  438. {
  439. LL_DEBUGS("Inventory") << "Updating category via AIS: " << mUUID
  440. << LL_ENDL;
  441. LLSD new_llsd = asLLSD();
  442. AISAPI::completion_t cr = boost::bind(&doInventoryCb,
  443. (LLPointer<LLInventoryCallback>)NULL,
  444. _1);
  445. AISAPI::updateCategory(mUUID, new_llsd, cr);
  446. }
  447. else
  448. {
  449. LLInventoryModel::LLCategoryUpdate up(mParentUUID, is_new ? 1 : 0);
  450. gInventory.accountForUpdate(up);
  451. LL_DEBUGS("Inventory") << "Updating category: " << mUUID
  452. << LL_ENDL;
  453. LLMessageSystem* msg = gMessageSystemp;
  454. msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
  455. msg->nextBlockFast(_PREHASH_AgentData);
  456. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  457. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  458. msg->nextBlockFast(_PREHASH_FolderData);
  459. packMessage(gMessageSystemp);
  460. gAgent.sendReliableMessage();
  461. }
  462. }
  463. bool LLViewerInventoryCategory::fetch()
  464. {
  465. if (mVersion == VERSION_UNKNOWN &&
  466. // Expired check prevents multiple downloads:
  467. mDescendentsRequested.hasExpired())
  468. {
  469. LL_DEBUGS("InventoryFetch") << "Fetching category children: " << mName
  470. << ", UUID: " << mUUID << LL_ENDL;
  471. mDescendentsRequested.reset();
  472. mDescendentsRequested.setTimerExpirySec(FETCH_TIMER_EXPIRY);
  473. if (gAgent.hasRegionCapability("FetchInventoryDescendents2") ||
  474. LLInventoryModelFetch::useAISFetching())
  475. {
  476. LLInventoryModelFetch::getInstance()->start(mUUID);
  477. return true;
  478. }
  479. // 2023-10: the old UDP messaging fallback path which used to be called
  480. // here has been removed from the SL official viewer. I considered
  481. // keeping it for OpenSim, but all current server versions do provide
  482. // the Fetch*2 (AKA AIS2) capabilities, making the legacy UDP path
  483. // useless. HB
  484. llwarns_sparse << "No capability available. Fetch aborted" << llendl;
  485. }
  486. return false;
  487. }
  488. U32 LLViewerInventoryCategory::getFetching()
  489. {
  490. // If the timer has not expired, request was scheduled, but not in progress
  491. // if mFetching request was actually started.
  492. if (mDescendentsRequested.hasExpired())
  493. {
  494. mFetching = FETCH_NONE;
  495. }
  496. return mFetching;
  497. }
  498. void LLViewerInventoryCategory::setFetching(U32 fetching)
  499. {
  500. if (fetching > mFetching) // Allow a switch from normal to recursive
  501. {
  502. if (mFetching == FETCH_NONE || mDescendentsRequested.hasExpired())
  503. {
  504. mDescendentsRequested.reset();
  505. F32 timeout = FETCH_TIMER_EXPIRY;
  506. if (LLInventoryModelFetch::useAISFetching())
  507. {
  508. timeout = AIS_TIMEOUT;
  509. }
  510. mDescendentsRequested.setTimerExpirySec(timeout);
  511. }
  512. mFetching = fetching;
  513. }
  514. else if (fetching == FETCH_NONE)
  515. {
  516. mDescendentsRequested.reset(); // Will expire it as well. HB
  517. mFetching = fetching;
  518. }
  519. }
  520. bool LLViewerInventoryCategory::isProtected() const
  521. {
  522. LLFolderType::EType cat_type = getPreferredType();
  523. // If not a protected type, do not bother !
  524. if (cat_type == LLFolderType::FT_NONE ||
  525. !LLFolderType::lookupIsProtectedType(cat_type))
  526. {
  527. return false;
  528. }
  529. // If the folder does not bear the default name for its preferred type, it
  530. // is not protected.
  531. if (getName() != LLViewerFolderType::lookupNewCategoryName(cat_type))
  532. {
  533. return false;
  534. }
  535. // If the folder is not at the root of the inventory, it is not protected.
  536. LLViewerInventoryCategory* cat = gInventory.getCategory(getParentUUID());
  537. if (cat && cat->getUUID() != gInventory.getRootFolderID())
  538. {
  539. return false;
  540. }
  541. // Folder is indeed protected !
  542. return true;
  543. }
  544. bool LLViewerInventoryCategory::isUnique() const
  545. {
  546. LLFolderType::EType cat_type = getPreferredType();
  547. //MK
  548. bool maybe_rlv = getName() == RL_SHARED_FOLDER;
  549. //mk
  550. // If it has no type and is not #RLV, it is indeed not unique...
  551. if (cat_type == LLFolderType::FT_NONE && !maybe_rlv)
  552. {
  553. return false;
  554. }
  555. // If the folder does not bear the default name for its preferred type, it
  556. // is not unique.
  557. if (!maybe_rlv &&
  558. getName() != LLViewerFolderType::lookupNewCategoryName(cat_type))
  559. {
  560. return false;
  561. }
  562. // If the folder is not at the root of the inventory, it is not unique
  563. // either.
  564. LLViewerInventoryCategory* cat = gInventory.getCategory(getParentUUID());
  565. if (cat && cat->getUUID() != gInventory.getRootFolderID())
  566. {
  567. return false;
  568. }
  569. // Folder is indeed unique !
  570. return true;
  571. }
  572. S32 LLViewerInventoryCategory::getViewerDescendentCount() const
  573. {
  574. LLInventoryModel::cat_array_t* cats;
  575. LLInventoryModel::item_array_t* items;
  576. gInventory.getDirectDescendentsOf(getUUID(), cats, items);
  577. S32 descendents_actual = 0;
  578. if (cats && items)
  579. {
  580. descendents_actual = cats->size() + items->size();
  581. }
  582. return descendents_actual;
  583. }
  584. LLSD LLViewerInventoryCategory::exportLLSD() const
  585. {
  586. LLSD cat_data;
  587. cat_data["cat_id"] = mUUID;
  588. cat_data["parent_id"] = mParentUUID;
  589. cat_data["type"] = LLAssetType::lookup(mType);
  590. cat_data["pref_type"] = LLFolderType::lookup(mPreferredType);
  591. cat_data["name"] = mName;
  592. if (mThumbnailUUID.notNull())
  593. {
  594. cat_data["thumbnail"] = LLSD().with("asset_id", mThumbnailUUID);
  595. }
  596. cat_data["owner_id"] = mOwnerID;
  597. cat_data["version"] = mVersion;
  598. return cat_data;
  599. }
  600. bool LLViewerInventoryCategory::importLLSD(const LLSD& cat_data)
  601. {
  602. if (cat_data.has("cat_id"))
  603. {
  604. mUUID = cat_data["cat_id"].asUUID();
  605. }
  606. if (cat_data.has("parent_id"))
  607. {
  608. mParentUUID = cat_data["parent_id"].asUUID();
  609. }
  610. if (cat_data.has("type"))
  611. {
  612. mType = LLAssetType::lookup(cat_data["type"].asString());
  613. }
  614. if (cat_data.has("pref_type"))
  615. {
  616. mPreferredType =
  617. LLFolderType::lookup(cat_data["pref_type"].asString());
  618. }
  619. if (cat_data.has("thumbnail"))
  620. {
  621. mThumbnailUUID.setNull();
  622. const LLSD& thumb_data = cat_data["thumbnail"];
  623. if (cat_data.has("asset_id"))
  624. {
  625. mThumbnailUUID = thumb_data["asset_id"].asUUID();
  626. }
  627. }
  628. if (cat_data.has("name"))
  629. {
  630. mName = cat_data["name"].asString();
  631. LLStringUtil::replaceNonstandardASCII(mName, ' ');
  632. LLStringUtil::replaceChar(mName, '|', ' ');
  633. }
  634. if (cat_data.has("owner_id"))
  635. {
  636. mOwnerID = cat_data["owner_id"].asUUID();
  637. }
  638. if (cat_data.has("version"))
  639. {
  640. mVersion = cat_data["version"].asInteger();
  641. }
  642. return true;
  643. }
  644. bool LLViewerInventoryCategory::acceptItem(LLInventoryItem* inv_item)
  645. {
  646. if (!inv_item)
  647. {
  648. return false;
  649. }
  650. // Only stock folders have limitation on which item they will accept
  651. if (getPreferredType() != LLFolderType::FT_MARKETPLACE_STOCK)
  652. {
  653. return true;
  654. }
  655. // If the item is copyable (i.e. non stock) do not accept the drop in a
  656. // stock folder
  657. if (inv_item->getPermissions().allowCopyBy(gAgentID, gAgent.getGroupID()))
  658. {
  659. return false;
  660. }
  661. LLInventoryModel::cat_array_t* cat_array;
  662. LLInventoryModel::item_array_t* item_array;
  663. gInventory.getDirectDescendentsOf(getUUID(), cat_array, item_array);
  664. // Destination stock folder must be empty OR types incoming and existing
  665. // items must be identical and have the same permissions.
  666. if (item_array->empty())
  667. {
  668. return true;
  669. }
  670. LLInventoryItem* item = (*item_array)[0];
  671. return item->getInventoryType() == inv_item->getInventoryType() &&
  672. item->getPermissions().getMaskNextOwner() ==
  673. inv_item->getPermissions().getMaskNextOwner();
  674. }
  675. //virtual
  676. bool LLViewerInventoryCategory::unpackMessage(const LLSD& category)
  677. {
  678. return LLInventoryCategory::fromLLSD(category);
  679. }
  680. //virtual
  681. void LLViewerInventoryCategory::unpackMessage(LLMessageSystem* msg,
  682. const char* block, S32 block_num)
  683. {
  684. LLInventoryCategory::unpackMessage(msg, block, block_num);
  685. }
  686. //-----------------------------------------------------------------------------
  687. // LLInventoryCallbackManager
  688. //-----------------------------------------------------------------------------
  689. LLInventoryCallbackManager* LLInventoryCallbackManager::sInstance = NULL;
  690. LLInventoryCallbackManager::LLInventoryCallbackManager()
  691. : mLastCallback(0)
  692. {
  693. if (sInstance)
  694. {
  695. llwarns << "Unexpected multiple instances" << llendl;
  696. return;
  697. }
  698. sInstance = this;
  699. }
  700. LLInventoryCallbackManager::~LLInventoryCallbackManager()
  701. {
  702. if (sInstance != this)
  703. {
  704. llwarns << "Unexpected multiple instances" << llendl;
  705. return;
  706. }
  707. sInstance = NULL;
  708. }
  709. //static
  710. void LLInventoryCallbackManager::destroyClass()
  711. {
  712. if (sInstance)
  713. {
  714. for (callback_map_t::iterator it = sInstance->mMap.begin(),
  715. end = sInstance->mMap.end();
  716. it != end; ++it)
  717. {
  718. // drop LLPointer reference to callback
  719. it->second = NULL;
  720. }
  721. sInstance->mMap.clear();
  722. }
  723. }
  724. U32 LLInventoryCallbackManager::registerCB(LLPointer<LLInventoryCallback> cb)
  725. {
  726. if (cb.isNull())
  727. {
  728. return 0;
  729. }
  730. if (!++mLastCallback)
  731. {
  732. ++mLastCallback;
  733. }
  734. mMap[mLastCallback] = cb;
  735. return mLastCallback;
  736. }
  737. void LLInventoryCallbackManager::fire(U32 callback_id, const LLUUID& item_id)
  738. {
  739. if (callback_id && item_id.notNull())
  740. {
  741. callback_map_t::iterator i = mMap.find(callback_id);
  742. if (i != mMap.end())
  743. {
  744. i->second->fire(item_id);
  745. mMap.erase(i);
  746. }
  747. }
  748. }
  749. LLInventoryCallbackManager gInventoryCallbacks;
  750. //-----------------------------------------------------------------------------
  751. // Other callbacks
  752. //-----------------------------------------------------------------------------
  753. void ActivateGestureCallback::fire(const LLUUID& inv_item)
  754. {
  755. if (inv_item.notNull())
  756. {
  757. gGestureManager.activateGesture(inv_item);
  758. }
  759. }
  760. class CreateGestureCallback : public LLInventoryCallback
  761. {
  762. public:
  763. void fire(const LLUUID& inv_item);
  764. };
  765. void CreateGestureCallback::fire(const LLUUID& inv_item)
  766. {
  767. if (inv_item.isNull())
  768. {
  769. return;
  770. }
  771. gGestureManager.activateGesture(inv_item);
  772. LLViewerInventoryItem* item = gInventory.getItem(inv_item);
  773. if (!item) return;
  774. LLPermissions perm = item->getPermissions();
  775. perm.setGroupBits(gAgentID, gAgent.getGroupID(),
  776. gSavedSettings.getBool("ShareWithGroup"),
  777. PERM_MODIFY | PERM_MOVE | PERM_COPY);
  778. perm.setEveryoneBits(gAgentID, gAgent.getGroupID(),
  779. gSavedSettings.getBool("EveryoneCopy"),
  780. PERM_COPY);
  781. if (perm != item->getPermissions() && item->isFinished())
  782. {
  783. item->setPermissions(perm);
  784. item->updateServer(false);
  785. }
  786. // Item was just created, update even if permissions did not change
  787. gInventory.updateItem(item);
  788. gInventory.notifyObservers();
  789. if (!LLPreview::show(inv_item, false))
  790. {
  791. LLPreviewGesture* previewp =
  792. LLPreviewGesture::show("Gesture: " + item->getName(), inv_item,
  793. LLUUID::null);
  794. // Force to be entirely onscreen.
  795. gFloaterViewp->adjustToFitScreen(previewp);
  796. }
  797. }
  798. class CreateItemCallback : public LLInventoryCallback
  799. {
  800. public:
  801. void fire(const LLUUID& inv_item);
  802. };
  803. void CreateItemCallback::fire(const LLUUID& inv_item)
  804. {
  805. if (inv_item.isNull())
  806. {
  807. return;
  808. }
  809. LLViewerInventoryItem* item = gInventory.getItem(inv_item);
  810. if (!item || item->getIsLinkType())
  811. {
  812. return;
  813. }
  814. if (item->getInventoryType() != LLInventoryType::IT_CALLINGCARD)
  815. {
  816. bool share_with_group = gSavedSettings.getBool("ShareWithGroup") &&
  817. (item->getType() != LLAssetType::AT_LSL_TEXT ||
  818. !gSavedSettings.getBool("NoModScripts"));
  819. bool everyone_copy = gSavedSettings.getBool("EveryoneCopy");
  820. if (share_with_group || everyone_copy)
  821. {
  822. LLPermissions perm = item->getPermissions();
  823. perm.setGroupBits(gAgentID, gAgent.getGroupID(), share_with_group,
  824. PERM_MODIFY | PERM_MOVE | PERM_COPY);
  825. perm.setEveryoneBits(gAgentID, gAgent.getGroupID(), everyone_copy,
  826. PERM_COPY);
  827. if (perm != item->getPermissions() && item->isFinished())
  828. {
  829. item->setPermissions(perm);
  830. item->updateServer(false);
  831. }
  832. }
  833. }
  834. // Item was just created, update even if permissions did not change
  835. gInventory.updateItem(item);
  836. gInventory.notifyObservers();
  837. }
  838. void create_new_item(const std::string& name, const LLUUID& parent_id,
  839. LLAssetType::EType asset_type,
  840. LLInventoryType::EType inv_type,
  841. U32 next_owner_perm, std::string desc)
  842. {
  843. if (desc.empty())
  844. {
  845. LLAssetType::generateDescriptionFor(asset_type, desc);
  846. }
  847. if (next_owner_perm == 0)
  848. {
  849. next_owner_perm = PERM_MOVE | PERM_TRANSFER;
  850. }
  851. LLPointer<LLInventoryCallback> cb = NULL;
  852. if (inv_type == LLInventoryType::IT_GESTURE)
  853. {
  854. cb = new CreateGestureCallback();
  855. }
  856. else
  857. {
  858. cb = new CreateItemCallback();
  859. }
  860. create_inventory_item(parent_id, LLTransactionID::tnull, name, desc,
  861. asset_type, inv_type, NO_INV_SUBTYPE,
  862. next_owner_perm, cb);
  863. }
  864. void create_inventory_item(const LLUUID& parent_id,
  865. const LLTransactionID& transaction_id,
  866. const std::string& name, const std::string& desc,
  867. LLAssetType::EType asset_type,
  868. LLInventoryType::EType inv_type, U8 sub_type,
  869. U32 next_owner_perm,
  870. LLPointer<LLInventoryCallback> cb)
  871. {
  872. LL_DEBUGS("Inventory") << "Creating item: " << name << LL_ENDL;
  873. LLMessageSystem* msg = gMessageSystemp;
  874. msg->newMessageFast(_PREHASH_CreateInventoryItem);
  875. msg->nextBlock(_PREHASH_AgentData);
  876. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  877. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  878. msg->nextBlock(_PREHASH_InventoryBlock);
  879. msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
  880. msg->addUUIDFast(_PREHASH_FolderID, parent_id);
  881. msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
  882. msg->addU32Fast(_PREHASH_NextOwnerMask, next_owner_perm);
  883. msg->addS8Fast(_PREHASH_Type, (S8)asset_type);
  884. msg->addS8Fast(_PREHASH_InvType, (S8)inv_type);
  885. msg->addU8Fast(_PREHASH_WearableType, sub_type);
  886. msg->addStringFast(_PREHASH_Name, name);
  887. msg->addStringFast(_PREHASH_Description, desc);
  888. gAgent.sendReliableMessage();
  889. }
  890. void copy_inventory_item(const LLUUID& current_owner, const LLUUID& item_id,
  891. const LLUUID& parent_id, const std::string& new_name,
  892. LLPointer<LLInventoryCallback> cb)
  893. {
  894. // Remember the hashed contents of the item we are going to copy. HB
  895. LLInventoryAddedObserver::registerCopiedItem(item_id);
  896. LL_DEBUGS("Inventory") << "Copying item: " << item_id
  897. << "- as new item: " << new_name << LL_ENDL;
  898. LLMessageSystem* msg = gMessageSystemp;
  899. msg->newMessageFast(_PREHASH_CopyInventoryItem);
  900. msg->nextBlockFast(_PREHASH_AgentData);
  901. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  902. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  903. msg->nextBlockFast(_PREHASH_InventoryData);
  904. msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb));
  905. msg->addUUIDFast(_PREHASH_OldAgentID, current_owner);
  906. msg->addUUIDFast(_PREHASH_OldItemID, item_id);
  907. msg->addUUIDFast(_PREHASH_NewFolderID, parent_id);
  908. msg->addStringFast(_PREHASH_NewName, new_name);
  909. gAgent.sendReliableMessage();
  910. }
  911. // Counts the number of items (not folders) in the descending hierarchy
  912. S32 count_descendants_items(const LLUUID& cat_id)
  913. {
  914. LLInventoryModel::cat_array_t* cat_array;
  915. LLInventoryModel::item_array_t* item_array;
  916. gInventory.getDirectDescendentsOf(cat_id, cat_array, item_array);
  917. S32 count = item_array->size();
  918. LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
  919. for (LLInventoryModel::cat_array_t::iterator
  920. iter = cat_array_copy.begin(), end = cat_array_copy.end();
  921. iter != end; ++iter)
  922. {
  923. LLViewerInventoryCategory* category = *iter;
  924. if (category)
  925. {
  926. count += count_descendants_items(category->getUUID());
  927. }
  928. }
  929. return count;
  930. }
  931. void update_folder_cb(const LLUUID& folder_id)
  932. {
  933. LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id);
  934. if (cat)
  935. {
  936. gInventory.updateCategory(cat);
  937. gInventory.notifyObservers();
  938. }
  939. }
  940. void copy_inventory_category_cb(const LLUUID& new_cat_id,
  941. LLInventoryModel* modelp,
  942. LLViewerInventoryCategory* catp,
  943. const LLUUID& root_copy_id,
  944. bool move_no_copy_items)
  945. {
  946. if (new_cat_id.isNull())
  947. {
  948. gNotifications.add("CantCreateRequestedInvFolder");
  949. return;
  950. }
  951. modelp->notifyObservers();
  952. LLMarketplaceData* marketdatap = NULL;
  953. if (LLMarketplace::contains(catp->getUUID()))
  954. {
  955. marketdatap = LLMarketplaceData::getInstance();
  956. }
  957. // We need to exclude the initial root of the copy to avoid recursively
  958. // copying the copy, etc...
  959. LLUUID root_id = root_copy_id.isNull() ? new_cat_id : root_copy_id;
  960. // Get the content of the folder
  961. LLInventoryModel::cat_array_t* cat_array;
  962. LLInventoryModel::item_array_t* item_array;
  963. gInventory.getDirectDescendentsOf(catp->getUUID(), cat_array, item_array);
  964. // If root_copy_id is null, tell the marketplace model we will be waiting
  965. // for new items to be copied over for this folder
  966. if (marketdatap && root_copy_id.isNull())
  967. {
  968. S32 count = count_descendants_items(catp->getUUID());
  969. marketdatap->setValidationWaiting(root_id, count);
  970. }
  971. // Copy all the items
  972. const LLUUID& group_id = gAgent.getGroupID();
  973. LLInventoryModel::item_array_t item_array_copy = *item_array;
  974. for (LLInventoryModel::item_array_t::iterator
  975. iter = item_array_copy.begin(), end = item_array_copy.end();
  976. iter != end; ++iter)
  977. {
  978. LLInventoryItem* itemp = *iter;
  979. if (!itemp) continue; // Paranoia
  980. bool is_link = itemp->getIsLinkType();
  981. if (!is_link &&
  982. !itemp->getPermissions().allowCopyBy(gAgentID, group_id))
  983. {
  984. // If the item is nocopy, we do nothing or, optionally, move it
  985. if (move_no_copy_items)
  986. {
  987. // Reparent the item
  988. LLViewerInventoryItem* vitemp = (LLViewerInventoryItem*)itemp;
  989. gInventory.changeItemParent(vitemp, new_cat_id, true);
  990. }
  991. if (marketdatap)
  992. {
  993. // Decrement the count in root_id since that one item won't be
  994. // copied over
  995. marketdatap->decrementValidationWaiting(root_id);
  996. }
  997. continue;
  998. }
  999. LLPointer<LLInventoryCallback> cb =
  1000. new LLBoostFuncInventoryCallback(boost::bind(update_folder_cb,
  1001. new_cat_id));
  1002. if (is_link)
  1003. {
  1004. link_inventory_object(new_cat_id, itemp->getLinkedUUID(), cb);
  1005. }
  1006. else
  1007. {
  1008. copy_inventory_item(itemp->getPermissions().getOwner(),
  1009. itemp->getUUID(), new_cat_id,
  1010. LLStringUtil::null, cb);
  1011. }
  1012. }
  1013. // Copy all the folders
  1014. LLInventoryModel::cat_array_t cat_array_copy = *cat_array;
  1015. for (LLInventoryModel::cat_array_t::iterator
  1016. iter = cat_array_copy.begin(), end = cat_array_copy.end();
  1017. iter != end; ++iter)
  1018. {
  1019. LLViewerInventoryCategory* categoryp = *iter;
  1020. if (categoryp && categoryp->getUUID() != root_id)
  1021. {
  1022. copy_inventory_category(modelp, categoryp, new_cat_id, root_id,
  1023. move_no_copy_items);
  1024. }
  1025. }
  1026. }
  1027. void copy_inventory_category(LLInventoryModel* modelp,
  1028. LLViewerInventoryCategory* catp,
  1029. const LLUUID& parent_id,
  1030. const LLUUID& root_copy_id,
  1031. bool move_no_copy_items)
  1032. {
  1033. if (!modelp || !catp) return;
  1034. // Create the initial folder, with the actual copy function invoked from
  1035. // the callback.
  1036. inventory_func_t func =
  1037. [modelp, catp, root_copy_id, move_no_copy_items](const LLUUID& new_id)
  1038. {
  1039. copy_inventory_category_cb(new_id, modelp, catp, root_copy_id,
  1040. move_no_copy_items);
  1041. };
  1042. gInventory.createNewCategory(parent_id, LLFolderType::FT_NONE,
  1043. catp->getName(), func,
  1044. catp->getThumbnailUUID());
  1045. }
  1046. void link_inventory_object(const LLUUID& parent_id,
  1047. LLPointer<LLInventoryObject> baseobj,
  1048. LLPointer<LLInventoryCallback> cb)
  1049. {
  1050. if (baseobj)
  1051. {
  1052. LLInventoryObject::object_list_t obj_array;
  1053. obj_array.emplace_back(baseobj);
  1054. link_inventory_array(parent_id, obj_array, cb);
  1055. }
  1056. else
  1057. {
  1058. llwarns << "Attempt to link to non-existent object inside category: "
  1059. << parent_id << llendl;
  1060. }
  1061. }
  1062. void link_inventory_object(const LLUUID& parent_id, const LLUUID& id,
  1063. LLPointer<LLInventoryCallback> cb)
  1064. {
  1065. LLPointer<LLInventoryObject> baseobj = gInventory.getObject(id);
  1066. link_inventory_object(parent_id, baseobj, cb);
  1067. }
  1068. void do_link_objects(const LLUUID& parent_id, LLSD& links,
  1069. LLPointer<LLInventoryCallback> cb)
  1070. {
  1071. LL_DEBUGS("Inventory") << "Creating links in " << parent_id << ":\n"
  1072. << ll_pretty_print_sd(links) << LL_ENDL;
  1073. static LLCachedControl<bool> use_ais(gSavedSettings, "UseAISForLinksInSL");
  1074. if (AISAPI::isAvailable(gIsInSecondLife && use_ais))
  1075. {
  1076. LLSD new_inventory = LLSD::emptyMap();
  1077. new_inventory["links"] = links;
  1078. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1079. AISAPI::createInventory(parent_id, new_inventory, cr);
  1080. }
  1081. else // Note: as of 2023-10 this does not work any more in SL ! HB
  1082. {
  1083. LLMessageSystem* msg = gMessageSystemp;
  1084. for (LLSD::array_iterator iter = links.beginArray(),
  1085. end = links.endArray();
  1086. iter != end; ++iter)
  1087. {
  1088. msg->newMessageFast(_PREHASH_LinkInventoryItem);
  1089. msg->nextBlock(_PREHASH_AgentData);
  1090. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1091. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1092. msg->nextBlock(_PREHASH_InventoryBlock);
  1093. LLSD link = *iter;
  1094. msg->addU32Fast(_PREHASH_CallbackID,
  1095. gInventoryCallbacks.registerCB(cb));
  1096. msg->addUUIDFast(_PREHASH_FolderID, parent_id);
  1097. msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null);
  1098. msg->addUUIDFast(_PREHASH_OldItemID, link["linked_id"].asUUID());
  1099. msg->addS8Fast(_PREHASH_Type, link["type"].asInteger());
  1100. msg->addS8Fast(_PREHASH_InvType, link["inv_type"].asInteger());
  1101. msg->addStringFast(_PREHASH_Name, link["name"].asString());
  1102. msg->addStringFast(_PREHASH_Description, link["desc"].asString());
  1103. gAgent.sendReliableMessage();
  1104. }
  1105. }
  1106. }
  1107. // Create links to all listed inventory objects.
  1108. void link_inventory_array(const LLUUID& parent_id,
  1109. LLInventoryObject::object_list_t& baseobj_array,
  1110. LLPointer<LLInventoryCallback> cb)
  1111. {
  1112. LLSD links = LLSD::emptyArray();
  1113. for (LLInventoryObject::object_list_t::const_iterator
  1114. it = baseobj_array.begin(), end = baseobj_array.end();
  1115. it != end; ++it)
  1116. {
  1117. const LLInventoryObject* baseobj = *it;
  1118. if (!baseobj)
  1119. {
  1120. llwarns << "Attempt to link to unknown object inside category: "
  1121. << parent_id << llendl;
  1122. continue;
  1123. }
  1124. #if 0 // This is actually cared for below... and thus possible !
  1125. if (baseobj->getIsLinkType())
  1126. {
  1127. llwarns << "Attempt to create a link to link object: "
  1128. << baseobj->getUUID() << llendl;
  1129. continue;
  1130. }
  1131. #endif
  1132. if (!LLAssetType::lookupCanLink(baseobj->getType()))
  1133. {
  1134. // Fail if item can be found but is of a type that can't be linked.
  1135. // Arguably should fail if the item can't be found too, but that
  1136. // could be a larger behavioral change.
  1137. llwarns << "Attempt to link an unlinkable object, type = "
  1138. << baseobj->getActualType() << ", id = "
  1139. << baseobj->getUUID() << llendl;
  1140. continue;
  1141. }
  1142. LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
  1143. LLAssetType::EType asset_type = LLAssetType::AT_NONE;
  1144. std::string new_desc;
  1145. LLUUID linkee_id;
  1146. if (baseobj->asInventoryCategory())
  1147. {
  1148. inv_type = LLInventoryType::IT_CATEGORY;
  1149. asset_type = LLAssetType::AT_LINK_FOLDER;
  1150. linkee_id = baseobj->getUUID();
  1151. }
  1152. else
  1153. {
  1154. const LLViewerInventoryItem* baseitem =
  1155. baseobj->asViewerInventoryItem();
  1156. if (baseitem)
  1157. {
  1158. inv_type = baseitem->getInventoryType();
  1159. new_desc = baseitem->getActualDescription();
  1160. switch (baseitem->getActualType())
  1161. {
  1162. case LLAssetType::AT_LINK:
  1163. case LLAssetType::AT_LINK_FOLDER:
  1164. linkee_id = baseobj->getLinkedUUID();
  1165. asset_type = baseitem->getActualType();
  1166. break;
  1167. default:
  1168. linkee_id = baseobj->getUUID();
  1169. asset_type = LLAssetType::AT_LINK;
  1170. }
  1171. }
  1172. else
  1173. {
  1174. llwarns << "Could not convert object into an item or category: "
  1175. << baseobj->getUUID() << llendl;
  1176. continue;
  1177. }
  1178. }
  1179. LLSD link = LLSD::emptyMap();
  1180. link["linked_id"] = linkee_id;
  1181. link["type"] = (S8)asset_type;
  1182. link["inv_type"] = (S8)inv_type;
  1183. link["name"] = baseobj->getName();
  1184. link["desc"] = new_desc;
  1185. links.append(link);
  1186. LL_DEBUGS("Inventory") << "Linking object '" << baseobj->getName()
  1187. << "' (" << baseobj->getUUID()
  1188. << ") into category: " << parent_id << LL_ENDL;
  1189. }
  1190. do_link_objects(parent_id, links, cb);
  1191. }
  1192. void link_inventory_item(const LLUUID& item_id, const LLUUID& parent_id,
  1193. const std::string& new_description,
  1194. const LLAssetType::EType asset_type,
  1195. LLPointer<LLInventoryCallback> cb)
  1196. {
  1197. const LLInventoryObject* baseobj = gInventory.getObject(item_id);
  1198. if (!baseobj)
  1199. {
  1200. llwarns << "attempt to link to unknown item, linked-to-item's itemID "
  1201. << item_id << llendl;
  1202. return;
  1203. }
  1204. if (baseobj->getIsLinkType())
  1205. {
  1206. llwarns << "attempt to create a link to a link, linked-to-item's itemID "
  1207. << item_id << llendl;
  1208. return;
  1209. }
  1210. if (!LLAssetType::lookupCanLink(baseobj->getType()))
  1211. {
  1212. // Fail if item can be found but is of a type that can't be linked.
  1213. // Arguably should fail if the item can't be found too, but that could
  1214. // be a larger behavioral change.
  1215. llwarns << "attempt to link an unlinkable item, type = "
  1216. << baseobj->getActualType() << llendl;
  1217. return;
  1218. }
  1219. LLInventoryType::EType inv_type = LLInventoryType::IT_NONE;
  1220. if (baseobj->asInventoryCategory())
  1221. {
  1222. inv_type = LLInventoryType::IT_CATEGORY;
  1223. }
  1224. else
  1225. {
  1226. const LLViewerInventoryItem* baseitem =
  1227. baseobj->asViewerInventoryItem();
  1228. if (baseitem)
  1229. {
  1230. inv_type = baseitem->getInventoryType();
  1231. }
  1232. }
  1233. LLSD link = LLSD::emptyMap();
  1234. link["linked_id"] = item_id;
  1235. link["type"] = (S8)asset_type;
  1236. link["inv_type"] = (S8)inv_type;
  1237. link["name"] = baseobj->getName(); // Links cannot be given arbitrary names
  1238. link["desc"] = new_description;
  1239. LLSD links = LLSD::emptyArray();
  1240. links.append(link);
  1241. do_link_objects(parent_id, links, cb);
  1242. }
  1243. void move_inventory_item(const LLUUID& item_id, const LLUUID& parent_id,
  1244. const std::string& new_name,
  1245. LLPointer<LLInventoryCallback> cb)
  1246. {
  1247. LLViewerInventoryItem* item = gInventory.getItem(item_id);
  1248. if (!item)
  1249. {
  1250. llwarns << "Attempt to move an unknown item: " << item_id << llendl;
  1251. return;
  1252. }
  1253. LLUUID curcat_id = item->getParentUUID();
  1254. std::string cur_name = item->getName();
  1255. LL_DEBUGS("Inventory") << "Moving item: " << item_id << " - name: "
  1256. << cur_name << " - new name: " << new_name
  1257. << " - from category: " << curcat_id
  1258. << " - to category: " << parent_id << LL_ENDL;
  1259. // First step: change the name if needed.
  1260. if (new_name != cur_name)
  1261. {
  1262. LLMessageSystem* msg = gMessageSystemp;
  1263. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  1264. msg->nextBlockFast(_PREHASH_AgentData);
  1265. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1266. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1267. msg->addBoolFast(_PREHASH_Stamp, false);
  1268. msg->nextBlockFast(_PREHASH_InventoryData);
  1269. msg->addUUIDFast(_PREHASH_ItemID, item_id);
  1270. msg->addUUIDFast(_PREHASH_FolderID, curcat_id);
  1271. msg->addStringFast(_PREHASH_NewName, new_name);
  1272. gAgent.sendReliableMessage();
  1273. }
  1274. // Second step: change the category if needed.
  1275. if (parent_id != curcat_id)
  1276. {
  1277. gInventory.changeItemParent(item, parent_id, false);
  1278. }
  1279. gInventory.notifyObservers();
  1280. if (cb.notNull())
  1281. {
  1282. // *HACK: There is no callback for MoveInventoryItem... Emulate one.
  1283. constexpr F32 CALLBACK_DELAY = 3.f; // In seconds
  1284. U32 callback_id = gInventoryCallbacks.registerCB(cb);
  1285. doAfterInterval(boost::bind(&LLInventoryCallbackManager::fire,
  1286. &gInventoryCallbacks,
  1287. callback_id, item_id),
  1288. CALLBACK_DELAY);
  1289. }
  1290. }
  1291. bool movable_objects_with_same_parent(const uuid_vec_t& inv_items)
  1292. {
  1293. U32 count = inv_items.size();
  1294. if (!count)
  1295. {
  1296. return false;
  1297. }
  1298. const LLUUID& id = inv_items[0];
  1299. LLViewerInventoryItem* item = gInventory.getItem(id);
  1300. LLViewerInventoryCategory* cat = item ? NULL : gInventory.getCategory(id);
  1301. if (!item && !cat)
  1302. {
  1303. return false;
  1304. }
  1305. if (count == 1)
  1306. {
  1307. return item || !cat->isUnique();
  1308. }
  1309. const LLUUID& parent_id = item ? item->getParentUUID()
  1310. : cat->getParentUUID();
  1311. for (U32 i = 1; i < count; ++i)
  1312. {
  1313. const LLUUID& id = inv_items[i];
  1314. LLViewerInventoryItem* item = gInventory.getItem(id);
  1315. if (item)
  1316. {
  1317. if (item->getParentUUID() != parent_id)
  1318. {
  1319. return false;
  1320. }
  1321. continue;
  1322. }
  1323. LLViewerInventoryCategory* cat = gInventory.getCategory(id);
  1324. if (!cat || cat->getParentUUID() != parent_id || cat->isUnique())
  1325. {
  1326. return false;
  1327. }
  1328. }
  1329. return true;
  1330. }
  1331. bool reparent_to_folder(const LLUUID& parent_id, uuid_vec_t inv_items)
  1332. {
  1333. LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
  1334. if (!cat)
  1335. {
  1336. return false;
  1337. }
  1338. bool moved = false;
  1339. for (U32 i = 0, count = inv_items.size(); i < count; ++i)
  1340. {
  1341. const LLUUID& id = inv_items[i];
  1342. LLViewerInventoryItem* item = gInventory.getItem(id);
  1343. if (item)
  1344. {
  1345. gInventory.changeItemParent(item, parent_id, false);
  1346. moved = true;
  1347. }
  1348. else
  1349. {
  1350. LLViewerInventoryCategory* cat = gInventory.getCategory(id);
  1351. if (cat && !cat->isProtected())
  1352. {
  1353. gInventory.changeCategoryParent(cat, parent_id, false);
  1354. moved = true;
  1355. }
  1356. }
  1357. }
  1358. return moved;
  1359. }
  1360. // Should call this with an update_item that has been copied and modified from
  1361. // an original source item, rather than modifying the source item directly.
  1362. void update_inventory_item(LLViewerInventoryItem* update_item,
  1363. LLPointer<LLInventoryCallback> cb)
  1364. {
  1365. if (!update_item)
  1366. {
  1367. llwarns << "NULL update_item parameter passed !" << llendl;
  1368. llassert(false);
  1369. return;
  1370. }
  1371. const LLUUID& item_id = update_item->getUUID();
  1372. LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
  1373. if (obj.notNull())
  1374. {
  1375. if (AISAPI::isAvailable())
  1376. {
  1377. LL_DEBUGS("Inventory") << "Updating item via AIS: " << item_id
  1378. << "- name: "
  1379. << update_item->getName() << LL_ENDL;
  1380. LLSD updates = update_item->asLLSD();
  1381. // Replace asset_id and/or shadow_id with transaction_id (hash_id)
  1382. if (updates.has("asset_id"))
  1383. {
  1384. updates.erase("asset_id");
  1385. if (update_item->getTransactionID().notNull())
  1386. {
  1387. updates["hash_id"] = update_item->getTransactionID();
  1388. }
  1389. }
  1390. if (updates.has("shadow_id"))
  1391. {
  1392. updates.erase("shadow_id");
  1393. if (update_item->getTransactionID().notNull())
  1394. {
  1395. updates["hash_id"] = update_item->getTransactionID();
  1396. }
  1397. }
  1398. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1399. AISAPI::updateItem(item_id, updates, cr);
  1400. }
  1401. else
  1402. {
  1403. LL_DEBUGS("Inventory") << "Updating item: " << item_id
  1404. << "- name: "
  1405. << update_item->getName() << LL_ENDL;
  1406. LLMessageSystem* msg = gMessageSystemp;
  1407. msg->newMessageFast(_PREHASH_UpdateInventoryItem);
  1408. msg->nextBlockFast(_PREHASH_AgentData);
  1409. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1410. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1411. msg->addUUIDFast(_PREHASH_TransactionID,
  1412. update_item->getTransactionID());
  1413. msg->nextBlockFast(_PREHASH_InventoryData);
  1414. msg->addU32Fast(_PREHASH_CallbackID, 0);
  1415. update_item->packMessage(msg);
  1416. gAgent.sendReliableMessage();
  1417. LLInventoryModel::LLCategoryUpdate up(update_item->getParentUUID(),
  1418. 0);
  1419. gInventory.accountForUpdate(up);
  1420. gInventory.updateItem(update_item);
  1421. if (cb)
  1422. {
  1423. cb->fire(item_id);
  1424. }
  1425. }
  1426. }
  1427. else
  1428. {
  1429. llwarns << "Call done for invalid item: " << item_id << llendl;
  1430. }
  1431. }
  1432. // Note this only supports updating an existing item. Goes through AISv3 code
  1433. // path where available. Not all uses of item->updateServer() can easily be
  1434. // switched to this paradigm.
  1435. void update_inventory_item(const LLUUID& item_id, const LLSD& updates,
  1436. LLPointer<LLInventoryCallback> cb)
  1437. {
  1438. LLPointer<LLViewerInventoryItem> obj = gInventory.getItem(item_id);
  1439. if (obj.notNull())
  1440. {
  1441. if (AISAPI::isAvailable())
  1442. {
  1443. LL_DEBUGS("Inventory") << "Updating item via AIS: " << item_id
  1444. << "- name: " << obj->getName() << LL_ENDL;
  1445. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1446. AISAPI::updateItem(item_id, updates, cr);
  1447. }
  1448. else
  1449. {
  1450. LL_DEBUGS("Inventory") << "Updating item: " << item_id
  1451. << "- name: " << obj->getName() << LL_ENDL;
  1452. LLPointer<LLViewerInventoryItem> new_item(new LLViewerInventoryItem);
  1453. new_item->copyViewerItem(obj);
  1454. new_item->fromLLSD(updates, false);
  1455. LLMessageSystem* msg = gMessageSystemp;
  1456. msg->newMessageFast(_PREHASH_UpdateInventoryItem);
  1457. msg->nextBlockFast(_PREHASH_AgentData);
  1458. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1459. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1460. msg->addUUIDFast(_PREHASH_TransactionID,
  1461. new_item->getTransactionID());
  1462. msg->nextBlockFast(_PREHASH_InventoryData);
  1463. msg->addU32Fast(_PREHASH_CallbackID, 0);
  1464. new_item->packMessage(msg);
  1465. gAgent.sendReliableMessage();
  1466. LLInventoryModel::LLCategoryUpdate up(new_item->getParentUUID(),
  1467. 0);
  1468. gInventory.accountForUpdate(up);
  1469. gInventory.updateItem(new_item);
  1470. if (cb)
  1471. {
  1472. cb->fire(item_id);
  1473. }
  1474. }
  1475. }
  1476. else
  1477. {
  1478. llwarns << "Call done for invalid item: " << item_id << llendl;
  1479. }
  1480. }
  1481. void update_inventory_category(const LLUUID& cat_id, const LLSD& updates,
  1482. LLPointer<LLInventoryCallback> cb)
  1483. {
  1484. LLPointer<LLViewerInventoryCategory> objp = gInventory.getCategory(cat_id);
  1485. if (objp.isNull())
  1486. {
  1487. llwarns << "Call done for invalid category: " << cat_id << llendl;
  1488. return;
  1489. }
  1490. if (LLFolderType::lookupIsProtectedType(objp->getPreferredType()))
  1491. {
  1492. gNotifications.add("CannotModifyProtectedCategories");
  1493. return;
  1494. }
  1495. if (AISAPI::isAvailable())
  1496. {
  1497. LL_DEBUGS("Inventory") << "Updating category via AIS: " << cat_id
  1498. << " - name: " << objp->getName() << LL_ENDL;
  1499. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1500. AISAPI::updateCategory(cat_id, updates, cr);
  1501. return;
  1502. }
  1503. LLPointer<LLViewerInventoryCategory> catp =
  1504. new LLViewerInventoryCategory(objp);
  1505. catp->fromLLSD(updates);
  1506. LL_DEBUGS("Inventory") << "Updating category: " << cat_id
  1507. << " - name: " << objp->getName() << LL_ENDL;
  1508. LLMessageSystem* msg = gMessageSystemp;
  1509. msg->newMessageFast(_PREHASH_UpdateInventoryFolder);
  1510. msg->nextBlockFast(_PREHASH_AgentData);
  1511. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1512. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1513. msg->nextBlockFast(_PREHASH_FolderData);
  1514. catp->packMessage(msg);
  1515. gAgent.sendReliableMessage();
  1516. LLInventoryModel::LLCategoryUpdate up(catp->getParentUUID(), 0);
  1517. gInventory.accountForUpdate(up);
  1518. gInventory.updateCategory(catp);
  1519. if (cb)
  1520. {
  1521. cb->fire(cat_id);
  1522. }
  1523. }
  1524. void rename_category(LLInventoryModel* modelp, const LLUUID& cat_id,
  1525. const std::string& new_name)
  1526. {
  1527. if (modelp)
  1528. {
  1529. LLViewerInventoryCategory* catp = modelp->getCategory(cat_id);
  1530. if (catp && get_is_category_renameable(modelp, cat_id) &&
  1531. catp->getName() != new_name)
  1532. {
  1533. LLSD updates;
  1534. updates["name"] = new_name;
  1535. update_inventory_category(cat_id, updates, NULL);
  1536. }
  1537. }
  1538. }
  1539. bool get_is_category_renameable(const LLInventoryModel* modelp,
  1540. const LLUUID& id)
  1541. {
  1542. if (modelp)
  1543. {
  1544. LLViewerInventoryCategory* catp = modelp->getCategory(id);
  1545. if (catp &&
  1546. !LLFolderType::lookupIsProtectedType(catp->getPreferredType()) &&
  1547. catp->getOwnerID() == gAgentID)
  1548. {
  1549. return true;
  1550. }
  1551. }
  1552. return false;
  1553. }
  1554. void remove_inventory_items(LLInventoryObject::object_list_t& items_to_kill,
  1555. LLPointer<LLInventoryCallback> cb)
  1556. {
  1557. for (LLInventoryObject::object_list_t::iterator it = items_to_kill.begin(),
  1558. end = items_to_kill.end();
  1559. it != end; ++it)
  1560. {
  1561. remove_inventory_item(*it, cb);
  1562. }
  1563. }
  1564. void remove_inventory_item(const LLUUID& item_id,
  1565. LLPointer<LLInventoryCallback> cb)
  1566. {
  1567. LLPointer<LLInventoryObject> obj = gInventory.getItem(item_id);
  1568. if (obj.notNull())
  1569. {
  1570. LL_DEBUGS("Inventory") << " Removing item, id: " << item_id
  1571. << " - name " << obj->getName() << LL_ENDL;
  1572. remove_inventory_item(obj, cb);
  1573. }
  1574. else
  1575. {
  1576. llwarns << "Call done for invalid item: " << item_id << llendl;
  1577. }
  1578. }
  1579. void remove_inventory_item(LLPointer<LLInventoryObject> obj,
  1580. LLPointer<LLInventoryCallback> cb)
  1581. {
  1582. if (obj.notNull())
  1583. {
  1584. const LLUUID& item_id = obj->getUUID();
  1585. LL_DEBUGS("Inventory") << " Removing item, id: " << item_id
  1586. << " - name " << obj->getName() << LL_ENDL;
  1587. // Hide any preview
  1588. LLPreview::hide(item_id, true);
  1589. if (AISAPI::isAvailable())
  1590. {
  1591. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1592. AISAPI::removeItem(item_id, cr);
  1593. }
  1594. else
  1595. {
  1596. LLMessageSystem* msg = gMessageSystemp;
  1597. msg->newMessageFast(_PREHASH_RemoveInventoryItem);
  1598. msg->nextBlockFast(_PREHASH_AgentData);
  1599. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1600. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1601. msg->nextBlockFast(_PREHASH_InventoryData);
  1602. msg->addUUIDFast(_PREHASH_ItemID, item_id);
  1603. gAgent.sendReliableMessage();
  1604. // Update inventory and call callback immediately since the UDP
  1605. // message-based system has no callback mechanism.
  1606. gInventory.onObjectDeletedFromServer(item_id);
  1607. if (cb)
  1608. {
  1609. cb->fire(item_id);
  1610. }
  1611. }
  1612. }
  1613. else
  1614. {
  1615. // *TODO: Clean up callback?
  1616. llwarns << "Call done for invalid or non-existent item." << llendl;
  1617. }
  1618. }
  1619. class LLRemoveCategoryOnDestroy final : public LLInventoryCallback
  1620. {
  1621. public:
  1622. LLRemoveCategoryOnDestroy(const LLUUID& cat_id,
  1623. LLPointer<LLInventoryCallback> cb)
  1624. : mID(cat_id),
  1625. mCB(cb)
  1626. {
  1627. }
  1628. ~LLRemoveCategoryOnDestroy() override
  1629. {
  1630. LLInventoryModel::EHasChildren children;
  1631. children = gInventory.categoryHasChildren(mID);
  1632. if (children != LLInventoryModel::CHILDREN_NO)
  1633. {
  1634. llwarns << "Descendents removal failed; cannot remove category: "
  1635. << mID << llendl;
  1636. }
  1637. else
  1638. {
  1639. remove_inventory_category(mID, mCB);
  1640. }
  1641. }
  1642. void fire(const LLUUID& item_id) override {}
  1643. private:
  1644. LLUUID mID;
  1645. LLPointer<LLInventoryCallback> mCB;
  1646. };
  1647. void remove_inventory_category(const LLUUID& cat_id,
  1648. LLPointer<LLInventoryCallback> cb,
  1649. bool check_protected)
  1650. {
  1651. LLPointer<LLViewerInventoryCategory> obj = gInventory.getCategory(cat_id);
  1652. if (obj.notNull())
  1653. {
  1654. LL_DEBUGS("Inventory") << "Removing category id: " << cat_id
  1655. << " - name " << obj->getName() << LL_ENDL;
  1656. if (!gInventory.isCategoryComplete(cat_id))
  1657. {
  1658. llwarns << "Not purging the incompletely downloaded folder: "
  1659. << cat_id << llendl;
  1660. return;
  1661. }
  1662. if (check_protected && obj->isProtected())
  1663. {
  1664. gNotifications.add("CannotRemoveProtectedCategories");
  1665. return;
  1666. }
  1667. if (AISAPI::isAvailable())
  1668. {
  1669. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1670. AISAPI::removeCategory(cat_id, cr);
  1671. }
  1672. else
  1673. {
  1674. // RemoveInventoryFolder does not remove children, so must clear
  1675. // descendents first.
  1676. LLInventoryModel::EHasChildren children;
  1677. children = gInventory.categoryHasChildren(cat_id);
  1678. if (children != LLInventoryModel::CHILDREN_NO)
  1679. {
  1680. LL_DEBUGS("Inventory") << "Purging descendents first..."
  1681. << LL_ENDL;
  1682. LLPointer<LLInventoryCallback> wrap_cb =
  1683. new LLRemoveCategoryOnDestroy(cat_id, cb);
  1684. purge_descendents_of(cat_id, wrap_cb);
  1685. return;
  1686. }
  1687. LLMessageSystem* msg = gMessageSystemp;
  1688. msg->newMessageFast(_PREHASH_RemoveInventoryFolder);
  1689. msg->nextBlockFast(_PREHASH_AgentData);
  1690. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  1691. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  1692. msg->nextBlockFast(_PREHASH_FolderData);
  1693. msg->addUUIDFast(_PREHASH_FolderID, cat_id);
  1694. gAgent.sendReliableMessage();
  1695. // Update inventory and call callback immediately since the UDP
  1696. // message-based system has no callback mechanism.
  1697. gInventory.onObjectDeletedFromServer(cat_id);
  1698. if (cb)
  1699. {
  1700. cb->fire(cat_id);
  1701. }
  1702. }
  1703. }
  1704. else
  1705. {
  1706. llwarns << "Call done for invalid or non-existent category: " << cat_id
  1707. << llendl;
  1708. }
  1709. }
  1710. void remove_inventory_object(const LLUUID& object_id,
  1711. LLPointer<LLInventoryCallback> cb)
  1712. {
  1713. if (gInventory.getCategory(object_id))
  1714. {
  1715. remove_inventory_category(object_id, cb);
  1716. }
  1717. else
  1718. {
  1719. remove_inventory_item(object_id, cb);
  1720. }
  1721. }
  1722. void remove_folder_contents(const LLUUID& category,
  1723. LLPointer<LLInventoryCallback> cb)
  1724. {
  1725. LLInventoryModel::cat_array_t cats;
  1726. LLInventoryModel::item_array_t items;
  1727. gInventory.collectDescendents(category, cats, items,
  1728. LLInventoryModel::EXCLUDE_TRASH);
  1729. for (S32 i = 0, count = items.size(); i < count; ++i)
  1730. {
  1731. LLViewerInventoryItem* item = items[i];
  1732. if (item && item->getIsLinkType())
  1733. {
  1734. remove_inventory_item(item->getUUID(), cb);
  1735. }
  1736. }
  1737. }
  1738. void slam_inventory_folder(const LLUUID& folder_id, const LLSD& contents,
  1739. LLPointer<LLInventoryCallback> cb)
  1740. {
  1741. if (AISAPI::isAvailable())
  1742. {
  1743. LL_DEBUGS("Inventory") << "using AISv3 to slam folder, id: "
  1744. << folder_id << " - New contents: "
  1745. << ll_pretty_print_sd(contents) << LL_ENDL;
  1746. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1747. AISAPI::slamFolder(folder_id, contents, cr);
  1748. }
  1749. else
  1750. {
  1751. LL_DEBUGS("Inventory") << "using item-by-item calls to slam folder, id: "
  1752. << folder_id << " - New contents: "
  1753. << ll_pretty_print_sd(contents) << LL_ENDL;
  1754. remove_folder_contents(folder_id, cb);
  1755. for (LLSD::array_const_iterator it = contents.beginArray(),
  1756. end = contents.endArray();
  1757. it != end; ++it)
  1758. {
  1759. LLViewerInventoryItem* item = new LLViewerInventoryItem;
  1760. if (item) // Paranoia (guard against out of memory)
  1761. {
  1762. const LLSD& item_contents = *it;
  1763. item->fromLLSD(item_contents);
  1764. link_inventory_object(folder_id, item, cb);
  1765. }
  1766. }
  1767. }
  1768. }
  1769. void purge_descendents_of(const LLUUID& id, LLPointer<LLInventoryCallback> cb)
  1770. {
  1771. #if 0 // MAINT-3319: the cached number of descendents is not always reliable
  1772. if (gInventory.categoryHasChildren(id) == LLInventoryModel::CHILDREN_NO)
  1773. {
  1774. LL_DEBUGS("Inventory") << "No descendents to purge for " << id
  1775. << LL_ENDL;
  1776. return;
  1777. }
  1778. #endif
  1779. LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(id);
  1780. if (cat.notNull())
  1781. {
  1782. if (!gInventory.isCategoryComplete(id))
  1783. {
  1784. llwarns << "Not purging the incompletely downloaded folder: "
  1785. << id << llendl;
  1786. return;
  1787. }
  1788. if (AISAPI::isAvailable())
  1789. {
  1790. AISAPI::completion_t cr = boost::bind(&doInventoryCb, cb, _1);
  1791. AISAPI::purgeDescendents(id, cr);
  1792. }
  1793. else
  1794. {
  1795. // Send it upstream
  1796. LLMessageSystem* msg = gMessageSystemp;
  1797. msg->newMessage(_PREHASH_PurgeInventoryDescendents);
  1798. msg->nextBlock(_PREHASH_AgentData);
  1799. msg->addUUID(_PREHASH_AgentID, gAgentID);
  1800. msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
  1801. msg->nextBlock(_PREHASH_InventoryData);
  1802. msg->addUUID(_PREHASH_FolderID, id);
  1803. gAgent.sendReliableMessage();
  1804. // Update inventory and call callback immediately since the UDP
  1805. // message-based system has no callback mechanism.
  1806. gInventory.onDescendentsPurgedFromServer(id);
  1807. if (cb)
  1808. {
  1809. cb->fire(id);
  1810. }
  1811. }
  1812. }
  1813. }
  1814. void copy_inventory_from_notecard(const LLUUID& object_id,
  1815. const LLUUID& notecard_inv_id,
  1816. const LLInventoryItem* srcp,
  1817. U32 callback_id)
  1818. {
  1819. if (!srcp)
  1820. {
  1821. llwarns << "Null pointer to item was passed for object_id "
  1822. << object_id << " and notecard_inv_id " << notecard_inv_id
  1823. << llendl;
  1824. return;
  1825. }
  1826. LLViewerRegion* regionp = NULL;
  1827. LLViewerObject* objp = NULL;
  1828. if (object_id.notNull() && (objp = gObjectList.findObject(object_id)))
  1829. {
  1830. regionp = objp->getRegion();
  1831. }
  1832. // Fallback to the agents region if for some reason the object is not found
  1833. // in the viewer.
  1834. if (!regionp)
  1835. {
  1836. regionp = gAgent.getRegion();
  1837. }
  1838. if (!regionp)
  1839. {
  1840. llwarns << "Cannot find region from object_id " << object_id
  1841. << " or agent" << llendl;
  1842. return;
  1843. }
  1844. const std::string& url =
  1845. regionp->getCapability("CopyInventoryFromNotecard");
  1846. if (url.empty())
  1847. {
  1848. llwarns << "There is no 'CopyInventoryFromNotecard' capability for region: "
  1849. << regionp->getIdentity() << llendl;
  1850. return;
  1851. }
  1852. LLSD body;
  1853. body["notecard-id"] = notecard_inv_id;
  1854. body["object-id"] = object_id;
  1855. body["item-id"] = srcp->getUUID();
  1856. body["folder-id"] =
  1857. gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(srcp->getType()));
  1858. body["callback-id"] = (LLSD::Integer)callback_id;
  1859. LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body,
  1860. "Notecard coppied.",
  1861. "Failed to copy notecard");
  1862. }
  1863. //virtual
  1864. LLAssetType::EType LLViewerInventoryItem::getType() const
  1865. {
  1866. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1867. {
  1868. return linked_item->getType();
  1869. }
  1870. if (const LLViewerInventoryCategory* linked_category = getLinkedCategory())
  1871. {
  1872. return linked_category->getType();
  1873. }
  1874. return LLInventoryItem::getType();
  1875. }
  1876. //virtual
  1877. const LLUUID& LLViewerInventoryItem::getAssetUUID() const
  1878. {
  1879. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1880. {
  1881. return linked_item->getAssetUUID();
  1882. }
  1883. return LLInventoryItem::getAssetUUID();
  1884. }
  1885. //virtual
  1886. const std::string& LLViewerInventoryItem::getName() const
  1887. {
  1888. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1889. {
  1890. return linked_item->getName();
  1891. }
  1892. if (const LLViewerInventoryCategory* linked_category = getLinkedCategory())
  1893. {
  1894. return linked_category->getName();
  1895. }
  1896. return LLInventoryItem::getName();
  1897. }
  1898. //virtual
  1899. const LLPermissions& LLViewerInventoryItem::getPermissions() const
  1900. {
  1901. // Use the actual permissions of the symlink, not its parent.
  1902. return LLInventoryItem::getPermissions();
  1903. }
  1904. //virtual
  1905. const LLUUID& LLViewerInventoryItem::getCreatorUUID() const
  1906. {
  1907. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1908. {
  1909. return linked_item->getCreatorUUID();
  1910. }
  1911. return LLInventoryItem::getCreatorUUID();
  1912. }
  1913. //virtual
  1914. const std::string& LLViewerInventoryItem::getDescription() const
  1915. {
  1916. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1917. {
  1918. return linked_item->getDescription();
  1919. }
  1920. return LLInventoryItem::getDescription();
  1921. }
  1922. //virtual
  1923. const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const
  1924. {
  1925. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1926. {
  1927. return linked_item->getSaleInfo();
  1928. }
  1929. return LLInventoryItem::getSaleInfo();
  1930. }
  1931. //virtual
  1932. const LLUUID& LLViewerInventoryItem::getThumbnailUUID() const
  1933. {
  1934. if (mThumbnailUUID.notNull())
  1935. {
  1936. return mThumbnailUUID;
  1937. }
  1938. if (mType == LLAssetType::AT_TEXTURE)
  1939. {
  1940. return mAssetUUID;
  1941. }
  1942. if (mType == LLAssetType::AT_LINK)
  1943. {
  1944. LLViewerInventoryItem* itemp = gInventory.getItem(mAssetUUID);
  1945. return itemp ? itemp->getThumbnailUUID() : LLUUID::null;
  1946. }
  1947. if (mType == LLAssetType::AT_LINK_FOLDER)
  1948. {
  1949. LLViewerInventoryCategory* catp = gInventory.getCategory(mAssetUUID);
  1950. return catp ? catp->getThumbnailUUID() : LLUUID::null;
  1951. }
  1952. return LLUUID::null;
  1953. }
  1954. //virtual
  1955. LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
  1956. {
  1957. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1958. {
  1959. return linked_item->getInventoryType();
  1960. }
  1961. // Categories do not have types. If this item is an AT_FOLDER_LINK, treat
  1962. // it as a category.
  1963. if (getLinkedCategory())
  1964. {
  1965. return LLInventoryType::IT_CATEGORY;
  1966. }
  1967. return LLInventoryItem::getInventoryType();
  1968. }
  1969. //virtual
  1970. U32 LLViewerInventoryItem::getFlags() const
  1971. {
  1972. if (const LLViewerInventoryItem* linked_item = getLinkedItem())
  1973. {
  1974. return linked_item->getFlags();
  1975. }
  1976. return LLInventoryItem::getFlags();
  1977. }
  1978. //virtual
  1979. S32 LLViewerInventoryItem::getSubType() const
  1980. {
  1981. return getFlags() & LLInventoryItem::II_FLAGS_SUBTYPE_MASK;
  1982. }
  1983. //virtual
  1984. bool LLViewerInventoryItem::isWearableType() const
  1985. {
  1986. return getInventoryType() == LLInventoryType::IT_WEARABLE;
  1987. }
  1988. //virtual
  1989. LLWearableType::EType LLViewerInventoryItem::getWearableType() const
  1990. {
  1991. if (!isWearableType())
  1992. {
  1993. return LLWearableType::WT_INVALID;
  1994. }
  1995. return LLWearableType::inventoryFlagsToWearableType(getFlags());
  1996. }
  1997. //virtual
  1998. bool LLViewerInventoryItem::isSettingsType() const
  1999. {
  2000. return getInventoryType() == LLInventoryType::IT_SETTINGS;
  2001. }
  2002. //virtual
  2003. LLSettingsType::EType LLViewerInventoryItem::getSettingsType() const
  2004. {
  2005. if (!isSettingsType())
  2006. {
  2007. return LLSettingsType::ST_NONE;
  2008. }
  2009. return LLSettingsType::fromInventoryFlags(getFlags());
  2010. }
  2011. // This returns true if the item that this item points to doesn't exist in
  2012. // memory (i.e. LLInventoryModel). The base item might still be in the database
  2013. // but just not loaded yet.
  2014. bool LLViewerInventoryItem::getIsBrokenLink() const
  2015. {
  2016. // If the item's type resolves to be a link, that means either:
  2017. // A. It was not able to perform indirection, i.e. the baseobj does not
  2018. // exist in memory.
  2019. // B. It is pointing to another link, which is illegal.
  2020. return LLAssetType::lookupIsLinkType(getType());
  2021. }
  2022. LLViewerInventoryItem* LLViewerInventoryItem::getLinkedItem() const
  2023. {
  2024. if (mType == LLAssetType::AT_LINK)
  2025. {
  2026. LLViewerInventoryItem* linked_item = gInventory.getItem(mAssetUUID);
  2027. if (linked_item && linked_item->getIsLinkType())
  2028. {
  2029. llwarns << "Warning: Accessing link to link" << llendl;
  2030. return NULL;
  2031. }
  2032. return linked_item;
  2033. }
  2034. return NULL;
  2035. }
  2036. LLViewerInventoryCategory* LLViewerInventoryItem::getLinkedCategory() const
  2037. {
  2038. if (mType == LLAssetType::AT_LINK_FOLDER)
  2039. {
  2040. return gInventory.getCategory(mAssetUUID);
  2041. }
  2042. return NULL;
  2043. }
  2044. bool get_is_item_worn(const LLUUID& id, bool include_gestures)
  2045. {
  2046. const LLViewerInventoryItem* itemp = gInventory.getItem(id);
  2047. if (!itemp)
  2048. {
  2049. return false;
  2050. }
  2051. switch (itemp->getType())
  2052. {
  2053. case LLAssetType::AT_OBJECT:
  2054. {
  2055. if (isAgentAvatarValid() &&
  2056. gAgentAvatarp->isWearingAttachment(itemp->getLinkedUUID()))
  2057. {
  2058. return true;
  2059. }
  2060. break;
  2061. }
  2062. case LLAssetType::AT_BODYPART:
  2063. case LLAssetType::AT_CLOTHING:
  2064. {
  2065. if (gAgentWearables.isWearingItem(itemp->getLinkedUUID()))
  2066. {
  2067. return true;
  2068. }
  2069. break;
  2070. }
  2071. case LLAssetType::AT_GESTURE:
  2072. {
  2073. if (include_gestures &&
  2074. gGestureManager.isGestureActive(itemp->getLinkedUUID()))
  2075. {
  2076. return true;
  2077. }
  2078. break;
  2079. }
  2080. default:
  2081. break;
  2082. }
  2083. return false;
  2084. }
  2085. S32 get_folder_levels(LLInventoryCategory* catp)
  2086. {
  2087. LLInventoryModel::cat_array_t* cats;
  2088. LLInventoryModel::item_array_t* items;
  2089. gInventory.getDirectDescendentsOf(catp->getUUID(), cats, items);
  2090. S32 max_child_levels = 0;
  2091. for (S32 i = 0, count = cats->size(); i < count; ++i)
  2092. {
  2093. catp = (*cats)[i];
  2094. // Recurse through categories.
  2095. max_child_levels = llmax(max_child_levels, get_folder_levels(catp));
  2096. }
  2097. return max_child_levels + 1;
  2098. }
  2099. S32 get_folder_path_length(const LLUUID& ancestor_id,
  2100. const LLUUID& descendant_id)
  2101. {
  2102. if (ancestor_id == descendant_id)
  2103. {
  2104. return 0;
  2105. }
  2106. S32 depth = 0;
  2107. LLInventoryCategory* category = gInventory.getCategory(descendant_id);
  2108. while (category)
  2109. {
  2110. const LLUUID& parent_id = category->getParentUUID();
  2111. if (parent_id.isNull())
  2112. {
  2113. break;
  2114. }
  2115. ++depth;
  2116. if (parent_id == ancestor_id)
  2117. {
  2118. return depth;
  2119. }
  2120. category = gInventory.getCategory(parent_id);
  2121. }
  2122. llwarns << "Could not trace a path from the descendant to the ancestor"
  2123. << llendl;
  2124. return -1;
  2125. }
  2126. LLUUID get_calling_card_buddy_id(LLViewerInventoryItem* itemp, bool allow_self)
  2127. {
  2128. if (!itemp || itemp->getType() != LLAssetType::AT_CALLINGCARD)
  2129. {
  2130. return LLUUID::null;
  2131. }
  2132. LLUUID buddy_id(itemp->getActualDescription(), false);
  2133. if (buddy_id.isNull())
  2134. {
  2135. buddy_id = itemp->getCreatorUUID();
  2136. }
  2137. return !allow_self && buddy_id == gAgentID ? LLUUID::null : buddy_id;
  2138. }
  2139. class LLItemAddedObserver : public LLInventoryObserver
  2140. {
  2141. public:
  2142. LLItemAddedObserver(const LLUUID& copied_asset_id,
  2143. LLPointer<LLInventoryCallback> cb)
  2144. : mAssetId(copied_asset_id),
  2145. mCallback(cb)
  2146. {
  2147. }
  2148. void changed(U32 mask) override
  2149. {
  2150. if (!(mask & (LLInventoryObserver::ADD)))
  2151. {
  2152. return;
  2153. }
  2154. for (uuid_list_t::const_iterator it = gInventory.getAddedIDs().begin(),
  2155. end = gInventory.getAddedIDs().end();
  2156. it != end; ++it)
  2157. {
  2158. LLViewerInventoryItem* itemp = gInventory.getItem(*it);
  2159. if (itemp && itemp->getAssetUUID() == mAssetId)
  2160. {
  2161. mCallback->fire(*it);
  2162. gInventory.removeObserver(this);
  2163. delete this;
  2164. return;
  2165. }
  2166. }
  2167. }
  2168. private:
  2169. LLUUID mAssetId;
  2170. LLPointer<LLInventoryCallback> mCallback;
  2171. };
  2172. void move_or_copy_item_from_object(const LLUUID& dest_cat_id,
  2173. const LLUUID& object_id,
  2174. const LLUUID& item_id,
  2175. LLPointer<LLInventoryCallback> cb)
  2176. {
  2177. LLViewerObject* objectp = gObjectList.findObject(object_id);
  2178. if (!objectp) return;
  2179. const LLInventoryItem* itemp = objectp->getInventoryItem(item_id);
  2180. if (!itemp) return;
  2181. const LLUUID& asset_id = itemp->getAssetUUID();
  2182. LLItemAddedObserver* observerp = new LLItemAddedObserver(asset_id, cb);
  2183. gInventory.addObserver(observerp);
  2184. objectp->moveInventory(dest_cat_id, item_id);
  2185. }