llinventorymodel.cpp 147 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449
  1. /**
  2. * @file llinventorymodel.cpp
  3. * @brief Implementation of the inventory model used to track agent inventory.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-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 <sstream>
  34. #include <utility>
  35. #include "llinventorymodel.h"
  36. #include "llcallbacklist.h"
  37. #include "llcorebufferarray.h"
  38. #include "llcorehttputil.h"
  39. #include "hbfastmap.h"
  40. #include "lldir.h"
  41. #include "lldispatcher.h"
  42. #include "llnotifications.h"
  43. #include "llsdserialize.h"
  44. #include "llsdutil.h"
  45. #include "llstreamtools.h" // g[un]zip_file()
  46. #include "llagent.h"
  47. #include "llagentwearables.h"
  48. #include "llaisapi.h"
  49. #include "llappearancemgr.h"
  50. #include "llappviewer.h"
  51. #include "llfloaterinventory.h"
  52. #include "hbfloatereditenvsettings.h"
  53. #include "llgesturemgr.h"
  54. #include "llgridmanager.h" // For gIsInSecondLife
  55. #include "llinventorybridge.h"
  56. #include "llinventorymodelfetch.h"
  57. #include "llmarketplacefunctions.h"
  58. #include "llmutelist.h"
  59. #include "llpreview.h"
  60. //MK
  61. #include "mkrlinterface.h"
  62. //mk
  63. #include "llviewercontrol.h"
  64. #include "llviewerfoldertype.h"
  65. #include "llviewerinventory.h"
  66. #include "llviewermessage.h" // For gGenericDispatcher
  67. #include "llviewerstats.h"
  68. #include "llviewerwindow.h"
  69. #include "llvoavatarself.h"
  70. // Increment this if the inventory contents change in a non-backwards
  71. // compatible way. For viewers with link items support, former caches are
  72. // incorrect.
  73. constexpr S32 INVENTORY_CACHE_VERSION = 2;
  74. constexpr S32 MAX_INDIVIDUAL_ITEM_REQUESTS = 7;
  75. bool LLInventoryModel::sWearNewClothing = false;
  76. LLUUID LLInventoryModel::sWearNewClothingTransactionID;
  77. //----------------------------------------------------------------------------
  78. // Local function declarations, constants, enums, and typedefs
  79. //----------------------------------------------------------------------------
  80. struct InventoryIDPtrLess
  81. {
  82. bool operator()(const LLViewerInventoryCategory* i1,
  83. const LLViewerInventoryCategory* i2) const
  84. {
  85. return i1->getUUID() < i2->getUUID();
  86. }
  87. };
  88. class LLCanCache final : public LLInventoryCollectFunctor
  89. {
  90. public:
  91. LLCanCache(LLInventoryModel* model)
  92. : mModel(model)
  93. {
  94. }
  95. bool operator()(LLInventoryCategory* catp,
  96. LLInventoryItem* itemp) override;
  97. protected:
  98. LLInventoryModel* mModel;
  99. uuid_list_t mCachedCatIDs;
  100. };
  101. bool LLCanCache::operator()(LLInventoryCategory* catp, LLInventoryItem* itemp)
  102. {
  103. if (itemp)
  104. {
  105. return mCachedCatIDs.count(itemp->getParentUUID()) != 0;
  106. }
  107. if (catp)
  108. {
  109. // *HACK: downcast
  110. LLViewerInventoryCategory* vcatp = (LLViewerInventoryCategory*)catp;
  111. if (!vcatp->isVersionUnknown())
  112. {
  113. S32 descendents_server = vcatp->getDescendentCount();
  114. S32 descendents_actual = vcatp->getViewerDescendentCount();
  115. if (descendents_server == descendents_actual)
  116. {
  117. mCachedCatIDs.emplace(vcatp->getUUID());
  118. return true;
  119. }
  120. }
  121. }
  122. return false;
  123. }
  124. struct InventoryCallbackInfo
  125. {
  126. InventoryCallbackInfo(U32 callback, const LLUUID& inv_id)
  127. : mCallback(callback),
  128. mInvID(inv_id)
  129. {
  130. }
  131. LLUUID mInvID;
  132. U32 mCallback;
  133. };
  134. class LLDispatchBulkUpdateInventory final : public LLDispatchHandler
  135. {
  136. protected:
  137. LOG_CLASS(LLDispatchBulkUpdateInventory);
  138. public:
  139. bool operator()(const LLDispatcher*, const std::string& key,
  140. const LLUUID& invoice, const sparam_t& strings) override;
  141. };
  142. static LLDispatchBulkUpdateInventory sBulkUpdateInventory;
  143. bool LLDispatchBulkUpdateInventory::operator()(const LLDispatcher*,
  144. const std::string& key,
  145. const LLUUID& invoice,
  146. const sparam_t& strings)
  147. {
  148. LLSD message;
  149. // Expect single string parameter in the form of a notation serialized LLSD.
  150. sparam_t::const_iterator it = strings.begin();
  151. if (it != strings.end())
  152. {
  153. const std::string& llsd_raw = *it++;
  154. std::istringstream llsd_data(llsd_raw);
  155. if (!LLSDSerialize::deserialize(message, llsd_data, llsd_raw.length()))
  156. {
  157. llwarns << "Attempted to read parameter data into LLSD but failed: "
  158. << llsd_raw << llendl;
  159. }
  160. }
  161. //MK
  162. bool check_rlv_share =
  163. gRLenabled && gRLInterface.getRlvShare() &&
  164. !gSavedSettings.getBool("RestrainedLoveForbidGiveToRLV");
  165. std::vector<LLPointer<LLViewerInventoryCategory> > folders_to_move;
  166. //mk
  167. LLInventoryModel::update_map_t update;
  168. LLInventoryModel::cat_array_t folders;
  169. LLInventoryModel::item_array_t items;
  170. typedef std::list<InventoryCallbackInfo> cblist_t;
  171. cblist_t callback_list;
  172. uuid_vec_t wearable_ids;
  173. const LLSD& item_data = message["item_data"];
  174. if (item_data.isArray())
  175. {
  176. for (LLSD::array_const_iterator it = item_data.beginArray(),
  177. end = item_data.endArray();
  178. it != end; ++it)
  179. {
  180. const LLSD& item_llsd = *it;
  181. // Agent Id probably should be in the root of the message.
  182. if (item_llsd["agent_id"].asUUID() != gAgentID)
  183. {
  184. llwarns << "Got a message for the wrong agent. Ignored."
  185. << llendl;
  186. return false;
  187. }
  188. LLPointer<LLViewerInventoryItem> itemp = new LLViewerInventoryItem;
  189. itemp->unpackMessage(item_llsd);
  190. const LLUUID& item_id = itemp->getUUID();
  191. const LLUUID& parent_id = itemp->getParentUUID();
  192. LL_DEBUGS("Inventory") << "Unpacked item '" << itemp->getName()
  193. << "' (" << item_id << ") in folder Id: "
  194. << parent_id << LL_ENDL;
  195. // Note: the callback_id might be no longer supported...
  196. U32 callback_id = item_llsd["callback_id"].asInteger();
  197. callback_list.emplace_back(callback_id, item_id);
  198. if (item_id.isNull()) // This should not happen...
  199. {
  200. continue;
  201. }
  202. items.push_back(itemp);
  203. if (itemp->getInventoryType() == LLInventoryType::IT_WEARABLE)
  204. {
  205. wearable_ids.push_back(itemp->getUUID());
  206. }
  207. // Examine update for changes.
  208. LLViewerInventoryItem* old_itemp = gInventory.getItem(item_id);
  209. if (old_itemp)
  210. {
  211. const LLUUID& old_parent_id = old_itemp->getParentUUID();
  212. if (parent_id == old_parent_id)
  213. {
  214. update[parent_id];
  215. }
  216. else
  217. {
  218. ++update[parent_id];
  219. --update[old_parent_id];
  220. }
  221. }
  222. else
  223. {
  224. LLViewerInventoryCategory* catp =
  225. gInventory.getCategory(parent_id);
  226. if (catp)
  227. {
  228. ++update[parent_id];
  229. }
  230. }
  231. }
  232. }
  233. const LLSD& folder_data = message["folder_data"];
  234. if (folder_data.isArray())
  235. {
  236. for (LLSD::array_const_iterator it = folder_data.beginArray(),
  237. end = folder_data.endArray();
  238. it != end; ++it)
  239. {
  240. const LLSD& folder_llsd = *it;
  241. LLPointer<LLViewerInventoryCategory> catp =
  242. new LLViewerInventoryCategory(gAgentID);
  243. catp->unpackMessage(folder_llsd);
  244. const LLUUID& cat_id = catp->getUUID();
  245. const LLUUID& parent_id = catp->getParentUUID();
  246. LL_DEBUGS("Inventory") << "Unpacked folder '" << catp->getName()
  247. << "' (" << cat_id << ") in folder Id: "
  248. << parent_id << LL_ENDL;
  249. if (cat_id.isNull()) // This should not happen...
  250. {
  251. continue;
  252. }
  253. // If the folder is a listing or a version folder, all we need to
  254. // do is to update the SLM data
  255. if (LLMarketplace::updateIfListed(cat_id, parent_id))
  256. {
  257. // In that case, there is no item to update so no callback, so
  258. // we skip the rest of the update
  259. continue;
  260. }
  261. folders.push_back(catp);
  262. LLViewerInventoryCategory* old_catp =
  263. gInventory.getCategory(cat_id);
  264. if (old_catp)
  265. {
  266. const LLUUID& old_parent_id = old_catp->getParentUUID();
  267. if (parent_id == old_parent_id)
  268. {
  269. if (parent_id.notNull())
  270. {
  271. update[parent_id];
  272. }
  273. else
  274. {
  275. llwarns << "Null parent Id for folder " << cat_id
  276. << llendl;
  277. }
  278. }
  279. else
  280. {
  281. if (parent_id.notNull())
  282. {
  283. ++update[parent_id];
  284. }
  285. else
  286. {
  287. llwarns << "Null new parent Id for folder " << cat_id
  288. << llendl;
  289. }
  290. if (old_parent_id.notNull())
  291. {
  292. --update[old_parent_id];
  293. }
  294. else
  295. {
  296. llwarns << "Null old parent Id for folder " << cat_id
  297. << llendl;
  298. }
  299. }
  300. //MK
  301. if (check_rlv_share &&
  302. gRLInterface.shouldMoveToSharedSubFolder(catp))
  303. {
  304. folders_to_move.emplace_back(catp);
  305. }
  306. //mk
  307. }
  308. else if (parent_id.notNull())
  309. {
  310. // We could not find the folder, so it is probably new. We
  311. // however still want to attempt accounting for any parent.
  312. LLViewerInventoryCategory* catp =
  313. gInventory.getCategory(parent_id);
  314. if (catp)
  315. {
  316. ++update[parent_id];
  317. }
  318. }
  319. else
  320. {
  321. llwarns << "Null new parent Id for non-found folder " << cat_id
  322. << llendl;
  323. }
  324. }
  325. }
  326. gInventory.accountForUpdate(update);
  327. for (LLInventoryModel::cat_array_t::iterator it = folders.begin(),
  328. end = folders.end();
  329. it != end; ++it)
  330. {
  331. gInventory.updateCategory(*it);
  332. }
  333. for (LLInventoryModel::item_array_t::iterator it = items.begin(),
  334. end = items.end();
  335. it != end; ++it)
  336. {
  337. gInventory.updateItem(*it);
  338. }
  339. gInventory.notifyObservers();
  340. // Transaction Id is missing from this message, so just wear what we got in
  341. // it when wanting to wear incomming wearable items, regardless of that Id.
  342. // Note: it means that should more wearable items arrive for the same
  343. // transaction in other message packets, we would fail to wear them... This
  344. // "feature" is only used by llfloaterbuycontents.cpp: see if we can
  345. // reimplement it properly, without relying on this hacky and fragile
  346. // "sWearNewClothing" trick. HB
  347. if (LLInventoryModel::sWearNewClothing && !wearable_ids.empty())
  348. {
  349. LLInventoryModel::sWearNewClothing = false;
  350. for (S32 i = 0, count = wearable_ids.size(); i < count; ++i)
  351. {
  352. LLViewerInventoryItem* wearablep =
  353. gInventory.getItem(wearable_ids[i]);
  354. if (wearablep)
  355. {
  356. gAppearanceMgr.wearInventoryItemOnAvatar(wearablep, true);
  357. }
  358. }
  359. }
  360. for (cblist_t::const_iterator it = callback_list.begin(),
  361. end = callback_list.end();
  362. it != end; ++it)
  363. {
  364. const InventoryCallbackInfo& cbinfo = *it;
  365. gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
  366. }
  367. //MK
  368. for (U32 i = 0, count = folders_to_move.size(); i < count; ++i)
  369. {
  370. gRLInterface.moveToSharedSubFolder(folders_to_move[i].get());
  371. }
  372. //mk
  373. return true;
  374. }
  375. //----------------------------------------------------------------------------
  376. // Class LLInventoryModel
  377. //----------------------------------------------------------------------------
  378. // Global for the agent inventory.
  379. LLInventoryModel gInventory;
  380. // Default constructor
  381. LLInventoryModel::LLInventoryModel()
  382. : mModifyMask(LLInventoryObserver::ALL),
  383. mModifyMaskBacklog(LLInventoryObserver::NONE),
  384. mLastItem(NULL),
  385. mIsNotifyObservers(false),
  386. mIsAgentInvUsable(false),
  387. mHttpRequestFG(NULL),
  388. mHttpRequestBG(NULL),
  389. mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID)
  390. {
  391. }
  392. // Destroys the object
  393. LLInventoryModel::~LLInventoryModel()
  394. {
  395. cleanupInventory();
  396. }
  397. void LLInventoryModel::cleanupInventory()
  398. {
  399. empty();
  400. // Deleting one observer might erase others from the list, so always pop
  401. // off the front
  402. while (!mObservers.empty())
  403. {
  404. observer_list_t::iterator iter = mObservers.begin();
  405. LLInventoryObserver* observer = *iter;
  406. mObservers.erase(iter);
  407. delete observer;
  408. }
  409. mObservers.clear();
  410. // Run down HTTP transport
  411. mHttpHeaders.reset();
  412. mHttpOptions.reset();
  413. delete mHttpRequestFG;
  414. mHttpRequestFG = NULL;
  415. delete mHttpRequestBG;
  416. mHttpRequestBG = NULL;
  417. }
  418. // This is a convenience method to check if one object has a parent chain up to
  419. // the category specified by UUID.
  420. bool LLInventoryModel::isObjectDescendentOf(const LLUUID& obj_id,
  421. const LLUUID& cat_id) const
  422. {
  423. if (obj_id == cat_id) return true;
  424. const LLInventoryObject* obj = getObject(obj_id);
  425. while (obj)
  426. {
  427. const LLUUID& parent_id = obj->getParentUUID();
  428. if (parent_id.isNull())
  429. {
  430. return false;
  431. }
  432. if (parent_id == cat_id)
  433. {
  434. return true;
  435. }
  436. // Since we are scanning up the parents, we only need to check in the
  437. // category list.
  438. obj = getCategory(parent_id);
  439. }
  440. return false;
  441. }
  442. bool LLInventoryModel::isInCOF(const LLUUID& inv_object_id) const
  443. {
  444. // Note: in OpenSim, we allow to remove the COF, and its UUID may therefore
  445. // change during a viewer session, so we do not cache this UUID. HB
  446. const LLUUID cof_id = LLAppearanceMgr::getCOF();
  447. return cof_id.notNull() && isObjectDescendentOf(inv_object_id, cof_id);
  448. }
  449. bool LLInventoryModel::isInMarketPlace(const LLUUID& inv_object_id) const
  450. {
  451. const LLUUID& mp_id = LLMarketplace::getMPL();
  452. return mp_id.notNull() && isObjectDescendentOf(inv_object_id, mp_id);
  453. }
  454. // Searches up the parent chain until we get to the specified parent, then
  455. // returns the first child category under it.
  456. const LLViewerInventoryCategory* LLInventoryModel::getFirstDescendantOf(const LLUUID& master_parent_id,
  457. const LLUUID& obj_id) const
  458. {
  459. if (master_parent_id == obj_id)
  460. {
  461. return NULL;
  462. }
  463. const LLViewerInventoryCategory* current_cat = getCategory(obj_id);
  464. if (!current_cat)
  465. {
  466. current_cat = getCategory(getObject(obj_id)->getParentUUID());
  467. }
  468. while (current_cat)
  469. {
  470. const LLUUID& current_parent_id = current_cat->getParentUUID();
  471. if (current_parent_id == master_parent_id)
  472. {
  473. return current_cat;
  474. }
  475. current_cat = getCategory(current_parent_id);
  476. }
  477. return NULL;
  478. }
  479. // Get the object by id. Returns NULL if not found.
  480. LLInventoryObject* LLInventoryModel::getObject(const LLUUID& id) const
  481. {
  482. LLViewerInventoryCategory* cat = getCategory(id);
  483. if (cat)
  484. {
  485. return cat;
  486. }
  487. LLViewerInventoryItem* item = getItem(id);
  488. if (item)
  489. {
  490. return item;
  491. }
  492. return NULL;
  493. }
  494. // Get the item by id. Returns NULL if not found.
  495. LLViewerInventoryItem* LLInventoryModel::getItem(const LLUUID& id) const
  496. {
  497. LLViewerInventoryItem* item = NULL;
  498. if (mLastItem.notNull() && mLastItem->getUUID() == id)
  499. {
  500. item = mLastItem;
  501. }
  502. else
  503. {
  504. item_map_t::const_iterator iter = mItemMap.find(id);
  505. if (iter != mItemMap.end())
  506. {
  507. item = iter->second;
  508. mLastItem = item;
  509. }
  510. }
  511. return item;
  512. }
  513. // Get the category by id. Returns NULL if not found
  514. LLViewerInventoryCategory* LLInventoryModel::getCategory(const LLUUID& id) const
  515. {
  516. LLViewerInventoryCategory* catp = NULL;
  517. if (mCategoryMap.size() > 0)
  518. {
  519. cat_map_t::const_iterator iter = mCategoryMap.find(id);
  520. if (iter != mCategoryMap.end())
  521. {
  522. catp = iter->second;
  523. }
  524. }
  525. return catp;
  526. }
  527. S32 LLInventoryModel::getItemCount() const
  528. {
  529. return mItemMap.size();
  530. }
  531. S32 LLInventoryModel::getCategoryCount() const
  532. {
  533. return mCategoryMap.size();
  534. }
  535. // Return the direct descendents of the id provided. The array provided points
  536. // straight into the guts of this object, and should only be used for read
  537. // operations, since modifications may invalidate the internal state of the
  538. // inventory. Set passed in values to NULL if the call fails.
  539. void LLInventoryModel::getDirectDescendentsOf(const LLUUID& cat_id,
  540. cat_array_t*& categories,
  541. item_array_t*& items) const
  542. {
  543. categories = get_ptr_in_map(mParentChildCategoryTree, cat_id);
  544. items = get_ptr_in_map(mParentChildItemTree, cat_id);
  545. }
  546. #if LL_HAS_ASSERT
  547. // SJB: added version to lock the arrays to catch potential logic bugs
  548. void LLInventoryModel::lockDirectDescendentArrays(const LLUUID& cat_id,
  549. cat_array_t*& categories,
  550. item_array_t*& items)
  551. {
  552. getDirectDescendentsOf(cat_id, categories, items);
  553. if (categories)
  554. {
  555. mCategoryLock[cat_id] = true;
  556. }
  557. if (items)
  558. {
  559. mItemLock[cat_id] = true;
  560. }
  561. }
  562. void LLInventoryModel::unlockDirectDescendentArrays(const LLUUID& cat_id)
  563. {
  564. mCategoryLock[cat_id] = mItemLock[cat_id] = false;
  565. }
  566. #endif
  567. void LLInventoryModel::consolidateForType(const LLUUID& main_id,
  568. LLFolderType::EType type,
  569. bool is_root_cat)
  570. {
  571. if (main_id.isNull())
  572. {
  573. llwarns << "Cannot consolidate for type: "
  574. << LLFolderType::lookup(type) << " - Missing system folder."
  575. << llendl;
  576. if (isInventoryUsable())
  577. {
  578. llinfos << "Creating missing system folder for type: "
  579. << LLFolderType::lookup(type) << llendl;
  580. createNewCategory(getRootFolderID(), type, LLStringUtil::null,
  581. NULL);
  582. }
  583. return;
  584. }
  585. // Make a list of folders that are not "main_id" and are of "type"
  586. uuid_vec_t folder_ids;
  587. for (cat_map_t::iterator cit = mCategoryMap.begin(),
  588. end = mCategoryMap.end();
  589. cit != end; ++cit)
  590. {
  591. LLViewerInventoryCategory* cat = cit->second;
  592. if (!cat) continue; // Paranoia
  593. const LLUUID& cat_id = cat->getUUID();
  594. if (cat_id.notNull() && cat_id != main_id &&
  595. cat->getPreferredType() == type)
  596. {
  597. folder_ids.emplace_back(cat_id);
  598. }
  599. }
  600. // Iterate through those folders
  601. for (S32 i = 0, count = folder_ids.size(); i < count; ++i)
  602. {
  603. const LLUUID& folder_id = folder_ids[i];
  604. if (!isObjectDescendentOf(folder_id, gInventory.getRootFolderID()))
  605. {
  606. // Do not consolidate folders contained in the library...
  607. continue;
  608. }
  609. // Get the content of this folder
  610. cat_array_t* cats;
  611. item_array_t* items;
  612. getDirectDescendentsOf(folder_id, cats, items);
  613. // Move all items to the main folder.
  614. // Note : we get the list of UUIDs and iterate on them instead of
  615. // iterating directly on item_array_t elements. This is because moving
  616. // elements modify the maps and, consequently, invalidate iterators on
  617. // them. This "gather and iterate" method is verbose but resilient.
  618. uuid_vec_t list_uuids;
  619. for (item_array_t::const_iterator it = items->begin(),
  620. end = items->end();
  621. it != end; ++it)
  622. {
  623. LLViewerInventoryItem* item = *it;
  624. if (item) // Paranoia
  625. {
  626. list_uuids.emplace_back(item->getUUID());
  627. }
  628. }
  629. for (S32 j = 0, count2 = list_uuids.size(); j < count2; ++j)
  630. {
  631. LLViewerInventoryItem* item = getItem(list_uuids[j]);
  632. changeItemParent(item, main_id, true);
  633. }
  634. // Move all folders to the main folder
  635. list_uuids.clear();
  636. for (cat_array_t::const_iterator it = cats->begin(),
  637. end = cats->end();
  638. it != end; ++it)
  639. {
  640. LLViewerInventoryCategory* cat = *it;
  641. if (cat) // Paranoia
  642. {
  643. list_uuids.emplace_back(cat->getUUID());
  644. }
  645. }
  646. for (S32 j = 0, count2 = list_uuids.size(); j < count2; ++j)
  647. {
  648. LLViewerInventoryCategory* cat = getCategory(list_uuids[j]);
  649. changeCategoryParent(cat, main_id, true);
  650. }
  651. // Purge the emptied folder
  652. removeCategory(folder_id);
  653. remove_inventory_category(folder_id, NULL, false);
  654. notifyObservers();
  655. }
  656. if (is_root_cat)
  657. {
  658. // Make sure this category is parented to the root folder
  659. const LLUUID& root_id = getRootFolderID();
  660. LLViewerInventoryCategory* cat = getCategory(main_id);
  661. if (cat && cat->getParentUUID() != root_id)
  662. {
  663. changeCategoryParent(cat, root_id, true);
  664. }
  665. }
  666. }
  667. // Returns the UUID of the category that specifies 'type' as what it defaults
  668. // to containing. The category is not necessarily only for that type.
  669. // *NOTE: this will create a new inventory category on the fly if one does not
  670. // exist.
  671. LLUUID LLInventoryModel::findCategoryUUIDForType(LLFolderType::EType t,
  672. bool create_folder)
  673. {
  674. LLUUID cat_id = findCatUUID(t);
  675. if (cat_id.isNull() && create_folder)
  676. {
  677. if (!isInventoryUsable())
  678. {
  679. llwarns_once << "Cannot create missing category: "
  680. << LLFolderType::lookup(t)
  681. << " - Inventory not in usable state." << llendl;
  682. }
  683. else
  684. {
  685. llinfos << "Using legacy UDP messaging to create missing category: "
  686. << LLFolderType::lookup(t) << llendl;
  687. cat_id = createCategoryUDP(getRootFolderID(), t,
  688. LLStringUtil::null);
  689. }
  690. }
  691. return cat_id;
  692. }
  693. LLUUID LLInventoryModel::findChoosenCategoryUUIDForType(LLFolderType::EType t)
  694. {
  695. static LLCachedControl<std::string> animation_id(gSavedPerAccountSettings,
  696. "UploadAnimationFolder");
  697. static LLCachedControl<std::string> material_id(gSavedPerAccountSettings,
  698. "UploadMaterialFolder");
  699. static LLCachedControl<std::string> model_id(gSavedPerAccountSettings,
  700. "UploadModelFolder");
  701. static LLCachedControl<std::string> outfits_id(gSavedPerAccountSettings,
  702. "NewOutfitFolder");
  703. static LLCachedControl<std::string> sound_id(gSavedPerAccountSettings,
  704. "UploadSoundFolder");
  705. static LLCachedControl<std::string> texture_id(gSavedPerAccountSettings,
  706. "UploadTextureFolder");
  707. std::string id_str;
  708. switch (t) // Cases are in LLFolderType::EType order. HB
  709. {
  710. case LLFolderType::FT_TEXTURE:
  711. id_str = texture_id;
  712. break;
  713. case LLFolderType::FT_SOUND:
  714. id_str = sound_id;
  715. break;
  716. case LLFolderType::FT_OBJECT:
  717. id_str = model_id;
  718. break;
  719. case LLFolderType::FT_ANIMATION:
  720. id_str = animation_id;
  721. break;
  722. case LLFolderType::FT_MY_OUTFITS:
  723. // FT_MY_OUTFITS becomes FT_CLOTHING on purpose when no user
  724. // preferred folder is set, since it is where v1 viewers always
  725. // create new outfits. HB
  726. t = LLFolderType::FT_CLOTHING;
  727. id_str = outfits_id;
  728. break;
  729. case LLFolderType::FT_MATERIAL:
  730. id_str = material_id;
  731. break;
  732. default:
  733. break;
  734. }
  735. if (!id_str.empty())
  736. {
  737. LLUUID cat_id;
  738. cat_id.set(id_str, false);
  739. if (cat_id.notNull() && getCategory(cat_id))
  740. {
  741. return cat_id;
  742. }
  743. }
  744. return findCategoryUUIDForType(t, true);
  745. }
  746. // Internal method which looks for a category with the specified preferred
  747. // type. Returns LLUUID::null if not found.
  748. LLUUID LLInventoryModel::findCatUUID(LLFolderType::EType type)
  749. {
  750. LLUUID root_id = getRootFolderID();
  751. if (type == LLFolderType::FT_ROOT_INVENTORY)
  752. {
  753. return root_id;
  754. }
  755. if (type == LLFolderType::FT_ROOT_INVENTORY_OS && !gIsInSecondLife)
  756. {
  757. return root_id;
  758. }
  759. if (root_id.notNull())
  760. {
  761. cat_array_t* cats = get_ptr_in_map(mParentChildCategoryTree, root_id);
  762. if (cats)
  763. {
  764. S32 count = cats->size();
  765. for (S32 i = 0; i < count; ++i)
  766. {
  767. LLInventoryCategory* cat = (*cats)[i];
  768. if (cat->getPreferredType() == type)
  769. {
  770. return cat->getUUID();
  771. }
  772. }
  773. }
  774. }
  775. return LLUUID::null;
  776. }
  777. static LLPointer<LLViewerInventoryCategory> create_cat(const LLUUID& cat_id,
  778. const LLUUID& parent_id,
  779. const LLUUID& thumb_id,
  780. LLFolderType::EType type,
  781. const std::string& name)
  782. {
  783. LLPointer<LLViewerInventoryCategory> catp = NULL;
  784. // For when the AIS callback reports a failure: abort the creation then.
  785. if (cat_id.isNull())
  786. {
  787. return catp;
  788. }
  789. // If the category already exists (may be the case with the AIS callback),
  790. // there is nothing to do.
  791. catp = gInventory.getCategory(cat_id);
  792. if (catp.notNull())
  793. {
  794. return catp;
  795. }
  796. // Add the category to the internal representation
  797. catp = new LLViewerInventoryCategory(cat_id, parent_id, type, name,
  798. gAgentID);
  799. // Note: VERSION_INITIAL - 1 because accountForUpdate() will increment it
  800. catp->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1);
  801. catp->setDescendentCount(0);
  802. if (thumb_id.notNull())
  803. {
  804. catp->setThumbnailUUID(thumb_id);
  805. }
  806. LLInventoryModel::LLCategoryUpdate update(catp->getParentUUID(), 1);
  807. gInventory.accountForUpdate(update);
  808. gInventory.updateCategory(catp);
  809. return catp;
  810. }
  811. LLUUID LLInventoryModel::createCategoryUDP(const LLUUID& parent_id,
  812. LLFolderType::EType preferred_type,
  813. const std::string& pname,
  814. const LLUUID& thumbnail_id)
  815. {
  816. if (!isInventoryUsable())
  817. {
  818. llwarns << "Inventory is broken." << llendl;
  819. return LLUUID::null;
  820. }
  821. if (LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())
  822. {
  823. LL_DEBUGS("Inventory") << "Attempt to create unsupported category type: "
  824. << preferred_type << LL_ENDL;
  825. return LLUUID::null;
  826. }
  827. std::string name = pname;
  828. if (pname.empty())
  829. {
  830. name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
  831. }
  832. else
  833. {
  834. name.assign(pname);
  835. }
  836. LLUUID cat_id;
  837. cat_id.generate();
  838. LL_DEBUGS("Inventory") << "Using UDP messaging to create category: "
  839. << name << " (Id: " << cat_id << ")" << LL_ENDL;
  840. LLMessageSystem* msg = gMessageSystemp;
  841. if (!msg) return LLUUID::null; // Paranoia.
  842. // Add the category to the internal representation
  843. LLPointer<LLViewerInventoryCategory> catp = create_cat(cat_id,
  844. parent_id,
  845. thumbnail_id,
  846. preferred_type,
  847. name);
  848. // Create the category with our generated UUID on the server.
  849. msg->newMessage(_PREHASH_CreateInventoryFolder);
  850. msg->nextBlock(_PREHASH_AgentData);
  851. msg->addUUID(_PREHASH_AgentID, gAgentID);
  852. msg->addUUID(_PREHASH_SessionID, gAgentSessionID);
  853. msg->nextBlock(_PREHASH_FolderData);
  854. catp->packMessage(msg);
  855. gAgent.sendReliableMessage();
  856. // Return the UUID of the category we just asked the server to create.
  857. return cat_id;
  858. }
  859. void LLInventoryModel::createNewCategory(const LLUUID& parent_id,
  860. LLFolderType::EType preferred_type,
  861. const std::string& pname,
  862. inventory_func_t callback,
  863. const LLUUID& thumbnail_id)
  864. {
  865. if (!isInventoryUsable())
  866. {
  867. llwarns << "Inventory is broken." << llendl;
  868. if (callback)
  869. {
  870. callback(LLUUID::null);
  871. }
  872. return;
  873. }
  874. if (LLFolderType::lookup(preferred_type) == LLFolderType::badLookup())
  875. {
  876. LL_DEBUGS("Inventory") << "Attempt to create unsupported category type: "
  877. << preferred_type << LL_ENDL;
  878. if (callback)
  879. {
  880. callback(LLUUID::null);
  881. }
  882. return;
  883. }
  884. std::string name = pname;
  885. if (pname.empty())
  886. {
  887. name.assign(LLViewerFolderType::lookupNewCategoryName(preferred_type));
  888. }
  889. else
  890. {
  891. name.assign(pname);
  892. }
  893. if (AISAPI::isAvailable())
  894. {
  895. LL_DEBUGS("Inventory") << "Using AIS to create category: " << name
  896. << LL_ENDL;
  897. LLPointer<LLViewerInventoryCategory> catp =
  898. new LLViewerInventoryCategory(LLUUID::null, parent_id,
  899. preferred_type, name, gAgentID);
  900. if (thumbnail_id.notNull())
  901. {
  902. catp->setThumbnailUUID(thumbnail_id);
  903. }
  904. LLSD cat_sd = catp->asAISCreateCatLLSD();
  905. LLSD new_inventory = LLSD::emptyMap();
  906. new_inventory["categories"] = LLSD::emptyArray();
  907. new_inventory["categories"].append(cat_sd);
  908. AISAPI::createInventory(parent_id, new_inventory,
  909. [callback, parent_id, thumbnail_id,
  910. preferred_type, name](const LLUUID& cat_id)
  911. {
  912. create_cat(cat_id, parent_id, thumbnail_id,
  913. preferred_type, name);
  914. if (callback && !callback.empty())
  915. {
  916. callback(cat_id);
  917. }
  918. });
  919. return;
  920. }
  921. const std::string& url =
  922. gAgent.getRegionCapability("CreateInventoryCategory");
  923. if (!url.empty())
  924. {
  925. // Use the capability.
  926. // Note; currently, in SL, this requested id will *not* be honoured. HB
  927. LLUUID cat_id;
  928. cat_id.generate();
  929. LL_DEBUGS("Inventory") << "Using the capability to create category: "
  930. << name << " (requested Id: " << cat_id << ")"
  931. << LL_ENDL;
  932. LLSD body;
  933. body["folder_id"] = cat_id;
  934. body["parent_id"] = parent_id;
  935. body["type"] = (LLSD::Integer)preferred_type;
  936. body["name"] = name;
  937. gCoros.launch("LLInventoryModel::createNewCategoryCoro",
  938. boost::bind(&LLInventoryModel::createNewCategoryCoro,
  939. this, url, body, thumbnail_id, callback));
  940. return;
  941. }
  942. // Fall back to the old UDP message.
  943. LLUUID cat_id = createCategoryUDP(parent_id, preferred_type, pname,
  944. thumbnail_id);
  945. if (callback)
  946. {
  947. callback(cat_id);
  948. }
  949. }
  950. void LLInventoryModel::createNewCategoryCoro(const std::string& url,
  951. const LLSD& data, LLUUID thumb_id,
  952. inventory_func_t callback)
  953. {
  954. llinfos << "Generic POST for " << url << llendl;
  955. LLCore::HttpOptions::ptr_t options(new LLCore::HttpOptions);
  956. options->setWantHeaders(true);
  957. LLCoreHttpUtil::HttpCoroutineAdapter adapter("createNewCategoryCoro",
  958. mHttpPolicyClass);
  959. LLSD result = adapter.postAndSuspend(url, data, options);
  960. LLCore::HttpStatus status =
  961. LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(result);
  962. if (!status)
  963. {
  964. llwarns << "HTTP failure attempting to create category." << llendl;
  965. if (callback)
  966. {
  967. callback(LLUUID::null);
  968. }
  969. return;
  970. }
  971. if (!result.has("folder_id"))
  972. {
  973. llwarns << "Malformed response contents:\n"
  974. << ll_pretty_print_sd(result) << llendl;
  975. if (callback)
  976. {
  977. callback(LLUUID::null);
  978. }
  979. return;
  980. }
  981. // Get the new category parameters.
  982. LLUUID cat_id = result["folder_id"].asUUID();
  983. LLFolderType::EType type = (LLFolderType::EType)result["type"].asInteger();
  984. LLUUID parent_id = result["parent_id"].asUUID();
  985. std::string name = result["name"].asString();
  986. // Add the category to the internal representation.
  987. LLPointer<LLViewerInventoryCategory> catp =
  988. new LLViewerInventoryCategory(cat_id, parent_id, type, name, gAgentID);
  989. if (thumb_id.notNull())
  990. {
  991. catp->setThumbnailUUID(thumb_id);
  992. }
  993. bool needs_accounting = true;
  994. LLViewerInventoryCategory* folderp = gInventory.getCategory(cat_id);
  995. if (folderp)
  996. {
  997. // Bulk processing was faster than the coroutine (coro request ->
  998. // processBulkUpdateInventory -> coro response): the category already
  999. // exists, but needs an update.
  1000. S32 version = folderp->getVersion();
  1001. S32 descendents = folderp->getDescendentCount();
  1002. if (version != LLViewerInventoryCategory::VERSION_INITIAL ||
  1003. descendents != LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
  1004. {
  1005. LL_DEBUGS("Inventory") << "Inventory desynchronization on folder creation. Folder "
  1006. << folderp->getName() << "("
  1007. << folderp->getUUID() << ").";
  1008. if (descendents != LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN)
  1009. {
  1010. LL_CONT << " Already got descendents: " << descendents << ".";
  1011. }
  1012. if (version != LLViewerInventoryCategory::VERSION_INITIAL)
  1013. {
  1014. LL_CONT << " Already got a version: " << version << ".";
  1015. }
  1016. LL_CONT << LL_ENDL;
  1017. }
  1018. if (folderp->getParentUUID() != parent_id)
  1019. {
  1020. llwarns << "Inventory desynchronization on folder creation. Folder "
  1021. << folderp->getName() << "(" << cat_id
  1022. << ") has wrong parent (" << folderp->getParentUUID()
  1023. << "). Expected parent: " << parent_id << llendl;
  1024. }
  1025. else
  1026. {
  1027. // Do not update parent, parent is already aware of the change.
  1028. // See processBulkUpdateInventory().
  1029. needs_accounting = false;
  1030. }
  1031. }
  1032. catp->setDescendentCount(0);
  1033. if (needs_accounting)
  1034. {
  1035. // Note: VERSION_INITIAL-1 because accountForUpdate() will increment it
  1036. catp->setVersion(LLViewerInventoryCategory::VERSION_INITIAL - 1);
  1037. LLCategoryUpdate update(catp->getParentUUID(), 1);
  1038. accountForUpdate(update);
  1039. }
  1040. else
  1041. {
  1042. catp->setVersionInitial();
  1043. }
  1044. updateCategory(catp);
  1045. if (callback)
  1046. {
  1047. llinfos << "Calling creation callback for category: " << cat_id
  1048. << llendl;
  1049. callback(cat_id);
  1050. }
  1051. }
  1052. // Starting with the object specified, add its descendents to the array
  1053. // provided, but do not add the inventory object specified by id. There is no
  1054. // guaranteed order. Neither array will be erased before adding objects to it.
  1055. // Do not store a copy of the pointers collected - use them, and collect them
  1056. // again later if you need to reference the same objects.
  1057. class LLAlwaysCollect final : public LLInventoryCollectFunctor
  1058. {
  1059. public:
  1060. LL_INLINE bool operator()(LLInventoryCategory*, LLInventoryItem*) override
  1061. {
  1062. return true;
  1063. }
  1064. };
  1065. void LLInventoryModel::collectDescendents(const LLUUID& id,
  1066. cat_array_t& cats,
  1067. item_array_t& items,
  1068. bool include_trash)
  1069. {
  1070. LLAlwaysCollect always;
  1071. collectDescendentsIf(id, cats, items, include_trash, always);
  1072. }
  1073. void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
  1074. cat_array_t& cats,
  1075. item_array_t& items,
  1076. bool include_trash,
  1077. LLInventoryCollectFunctor& add)
  1078. {
  1079. // Start with categories
  1080. if (!include_trash)
  1081. {
  1082. const LLUUID& trash_id = getTrashID();
  1083. if (trash_id.notNull() && trash_id == id)
  1084. {
  1085. return;
  1086. }
  1087. }
  1088. cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id);
  1089. if (cat_array)
  1090. {
  1091. S32 count = cat_array->size();
  1092. for (S32 i = 0; i < count; ++i)
  1093. {
  1094. LLViewerInventoryCategory* cat = (*cat_array)[i];
  1095. if (add(cat, NULL))
  1096. {
  1097. cats.emplace_back(cat);
  1098. }
  1099. collectDescendentsIf(cat->getUUID(), cats, items, include_trash,
  1100. add);
  1101. }
  1102. }
  1103. // Move onto items
  1104. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
  1105. if (item_array)
  1106. {
  1107. S32 count = item_array->size();
  1108. for (S32 i = 0; i < count; ++i)
  1109. {
  1110. LLViewerInventoryItem* item = (*item_array)[i];
  1111. if (add(NULL, item))
  1112. {
  1113. items.emplace_back(item);
  1114. }
  1115. }
  1116. }
  1117. }
  1118. void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id,
  1119. U32 mask)
  1120. {
  1121. const LLInventoryObject* obj = getObject(object_id);
  1122. if (!obj || obj->getIsLinkType())
  1123. {
  1124. return;
  1125. }
  1126. LLInventoryModel::cat_array_t cat_array;
  1127. LLInventoryModel::item_array_t item_array;
  1128. LLLinkedItemIDMatches is_linked_item_match(object_id);
  1129. collectDescendentsIf(getRootFolderID(), cat_array, item_array,
  1130. LLInventoryModel::INCLUDE_TRASH,
  1131. is_linked_item_match);
  1132. if (cat_array.empty() && item_array.empty())
  1133. {
  1134. return;
  1135. }
  1136. for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(),
  1137. cat_end = cat_array.end();
  1138. cat_iter != cat_end; ++cat_iter)
  1139. {
  1140. LLViewerInventoryCategory* linked_cat = *cat_iter;
  1141. addChangedMask(mask, linked_cat->getUUID());
  1142. }
  1143. for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(),
  1144. end = item_array.end();
  1145. iter != end; ++iter)
  1146. {
  1147. LLViewerInventoryItem* linked_item = *iter;
  1148. addChangedMask(mask, linked_item->getUUID());
  1149. }
  1150. }
  1151. const LLUUID& LLInventoryModel::getLinkedItemID(const LLUUID& object_id) const
  1152. {
  1153. const LLInventoryItem* item = getItem(object_id);
  1154. if (!item)
  1155. {
  1156. return object_id;
  1157. }
  1158. // Find the base item in case this a link (if it is not a link, this will
  1159. // just be inv_item_id)
  1160. return item->getLinkedUUID();
  1161. }
  1162. // Generates a string containing the path to the item specified by item_id.
  1163. void LLInventoryModel::appendPath(const LLUUID& id, std::string& path)
  1164. {
  1165. std::string temp;
  1166. LLInventoryObject* obj = getObject(id);
  1167. LLUUID parent_id;
  1168. if (obj) parent_id = obj->getParentUUID();
  1169. std::string forward_slash("/");
  1170. while (obj)
  1171. {
  1172. obj = getCategory(parent_id);
  1173. if (obj)
  1174. {
  1175. temp.assign(forward_slash + obj->getName() + temp);
  1176. parent_id = obj->getParentUUID();
  1177. }
  1178. }
  1179. path.append(temp);
  1180. }
  1181. LLInventoryModel::item_array_t LLInventoryModel::collectLinkedItems(const LLUUID& id,
  1182. const LLUUID& start_folder_id)
  1183. {
  1184. item_array_t items;
  1185. const LLInventoryObject* obj = getObject(id);
  1186. if (!obj || obj->getIsLinkType())
  1187. {
  1188. return items;
  1189. }
  1190. LLInventoryModel::cat_array_t cat_array;
  1191. LLLinkedItemIDMatches is_linked_item_match(id);
  1192. collectDescendentsIf(start_folder_id.isNull() ? getRootFolderID()
  1193. : start_folder_id,
  1194. cat_array, items, LLInventoryModel::INCLUDE_TRASH,
  1195. is_linked_item_match);
  1196. return items;
  1197. }
  1198. bool LLInventoryModel::isInventoryUsable() const
  1199. {
  1200. return getRootFolderID().notNull() && mIsAgentInvUsable;
  1201. }
  1202. // Calling this method with an inventory item will either change an existing
  1203. // item with a matching item_id, or will add the item to the current inventory.
  1204. U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item, U32 mask)
  1205. {
  1206. if (!item || item->getUUID().isNull())
  1207. {
  1208. return mask;
  1209. }
  1210. #if !LL_MESH_ASSET_SUPPORT
  1211. LLAssetType::EType type = item->getType();
  1212. if (type == LLAssetType::AT_MESH || type == LLAssetType::AT_GLTF ||
  1213. type == LLAssetType::AT_GLTF)
  1214. {
  1215. return mask;
  1216. }
  1217. #endif
  1218. if (!isInventoryUsable())
  1219. {
  1220. llwarns_sparse << "Inventory is broken." << llendl;
  1221. return mask;
  1222. }
  1223. const LLUUID& laf = getLostAndFoundID();
  1224. LLPointer<LLViewerInventoryItem> old_item = getItem(item->getUUID());
  1225. if (old_item)
  1226. {
  1227. // We already have an old item, modify its values
  1228. LLUUID old_parent_id = old_item->getParentUUID();
  1229. LLUUID new_parent_id = item->getParentUUID();
  1230. if (old_parent_id != new_parent_id)
  1231. {
  1232. bool null_parent_id = new_parent_id.isNull();
  1233. if (null_parent_id)
  1234. {
  1235. llwarns << "Null parent UUID for item " << item->getUUID()
  1236. << " - " << old_item->getName()
  1237. << ". Moving item to Lost And Found" << llendl;
  1238. new_parent_id = laf;
  1239. }
  1240. // We need to update the parent-child tree
  1241. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree,
  1242. old_parent_id);
  1243. if (item_array)
  1244. {
  1245. vector_replace_with_last(*item_array, old_item);
  1246. }
  1247. item_array = get_ptr_in_map(mParentChildItemTree, new_parent_id);
  1248. if (item_array)
  1249. {
  1250. item_array->emplace_back(old_item);
  1251. }
  1252. mask |= LLInventoryObserver::STRUCTURE;
  1253. if (null_parent_id)
  1254. {
  1255. LLCategoryUpdate update(new_parent_id, 1);
  1256. accountForUpdate(update);
  1257. old_item->setParent(new_parent_id);
  1258. old_item->updateParentOnServer(false);
  1259. }
  1260. }
  1261. if (old_item->getName() != item->getName())
  1262. {
  1263. mask |= LLInventoryObserver::LABEL;
  1264. }
  1265. old_item->copyViewerItem(item);
  1266. mask |= LLInventoryObserver::INTERNAL;
  1267. }
  1268. else
  1269. {
  1270. // Simply add this item
  1271. LLPointer<LLViewerInventoryItem> new_item =
  1272. new LLViewerInventoryItem(item);
  1273. addItem(new_item);
  1274. if (item->getParentUUID().isNull())
  1275. {
  1276. LLFolderType::EType cat_type =
  1277. LLFolderType::assetTypeToFolderType(new_item->getType());
  1278. LLUUID category_id = findCategoryUUIDForType(cat_type);
  1279. new_item->setParent(category_id);
  1280. item_array_t* item_array =
  1281. get_ptr_in_map(mParentChildItemTree, category_id);
  1282. if (item_array)
  1283. {
  1284. LLCategoryUpdate update(category_id, 1);
  1285. accountForUpdate(update);
  1286. // *FIX: bit of a hack to call update server from here...
  1287. new_item->updateParentOnServer(false);
  1288. item_array->emplace_back(new_item);
  1289. }
  1290. else
  1291. {
  1292. llwarns << "Could not find parent-child item tree for "
  1293. << new_item->getName() << llendl;
  1294. }
  1295. }
  1296. else
  1297. {
  1298. // *NOTE: The general scheme is that if every byte of the UUID is
  1299. // null, except for the last one or two, the use the last two bytes
  1300. // of the parent id, and match that up against the type. For now,
  1301. // we are only worried about Lost And Found.
  1302. LLUUID parent_id = item->getParentUUID();
  1303. if (parent_id == CATEGORIZE_LOST_AND_FOUND_ID)
  1304. {
  1305. parent_id = laf;
  1306. new_item->setParent(parent_id);
  1307. update_list_t update;
  1308. update.emplace_back(parent_id, 1);
  1309. accountForUpdate(update);
  1310. }
  1311. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree,
  1312. parent_id);
  1313. if (item_array)
  1314. {
  1315. item_array->emplace_back(new_item);
  1316. }
  1317. else
  1318. {
  1319. // Whoops ! No such parent, make one.
  1320. llinfos << "Lost item: " << new_item->getUUID() << " - "
  1321. << new_item->getName() << llendl;
  1322. parent_id = laf;
  1323. new_item->setParent(parent_id);
  1324. item_array = get_ptr_in_map(mParentChildItemTree, parent_id);
  1325. if (item_array)
  1326. {
  1327. LLCategoryUpdate update(parent_id, 1);
  1328. accountForUpdate(update);
  1329. // *FIX: bit of a hack to call update server from here...
  1330. new_item->updateParentOnServer(false);
  1331. item_array->emplace_back(new_item);
  1332. }
  1333. else
  1334. {
  1335. llwarns << "Lost and found not there !" << llendl;
  1336. }
  1337. }
  1338. }
  1339. mask |= LLInventoryObserver::ADD;
  1340. }
  1341. if (item->getType() == LLAssetType::AT_CALLINGCARD)
  1342. {
  1343. mask |= LLInventoryObserver::CALLING_CARD;
  1344. }
  1345. addChangedMask(mask, item->getUUID());
  1346. return mask;
  1347. }
  1348. LLInventoryModel::cat_array_t* LLInventoryModel::getUnlockedCatArray(const LLUUID& id)
  1349. {
  1350. cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id);
  1351. llassert(cat_array && !mCategoryLock[id]);
  1352. return cat_array;
  1353. }
  1354. LLInventoryModel::item_array_t* LLInventoryModel::getUnlockedItemArray(const LLUUID& id)
  1355. {
  1356. item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
  1357. llassert(item_array && !mItemLock[id]);
  1358. return item_array;
  1359. }
  1360. // Calling this method with an inventory category will either change an
  1361. // existing item with the matching id, or it will add the category.
  1362. void LLInventoryModel::updateCategory(const LLViewerInventoryCategory* cat,
  1363. U32 mask)
  1364. {
  1365. if (!cat)
  1366. {
  1367. return;
  1368. }
  1369. if (!isInventoryUsable())
  1370. {
  1371. llwarns << "Inventory is broken." << llendl;
  1372. return;
  1373. }
  1374. const LLUUID& cat_id = cat->getUUID();
  1375. if (cat_id.isNull())
  1376. {
  1377. return;
  1378. }
  1379. LLPointer<LLViewerInventoryCategory> old_cat = getCategory(cat_id);
  1380. if (old_cat)
  1381. {
  1382. // We already have an old category, modify its values
  1383. LLUUID old_parent_id = old_cat->getParentUUID();
  1384. LLUUID new_parent_id = cat->getParentUUID();
  1385. if (old_parent_id != new_parent_id)
  1386. {
  1387. // Need to update the parent-child tree
  1388. cat_array_t* cat_array = getUnlockedCatArray(old_parent_id);
  1389. if (cat_array)
  1390. {
  1391. vector_replace_with_last(*cat_array, old_cat);
  1392. }
  1393. cat_array = getUnlockedCatArray(new_parent_id);
  1394. if (cat_array)
  1395. {
  1396. cat_array->emplace_back(old_cat);
  1397. }
  1398. mask |= LLInventoryObserver::STRUCTURE;
  1399. }
  1400. if (old_cat->getName() != cat->getName() ||
  1401. // Under marketplace, category labels are quite complex and need
  1402. // an extra update
  1403. LLMarketplace::contains(cat_id))
  1404. {
  1405. mask |= LLInventoryObserver::LABEL;
  1406. }
  1407. old_cat->copyViewerCategory(cat);
  1408. addChangedMask(mask, cat_id);
  1409. }
  1410. else
  1411. {
  1412. // Add this category
  1413. LLPointer<LLViewerInventoryCategory> new_cat =
  1414. new LLViewerInventoryCategory(cat->getOwnerID());
  1415. new_cat->copyViewerCategory(cat);
  1416. addCategory(new_cat);
  1417. // Make sure this category is correctly referenced by its parent.
  1418. cat_array_t* cat_array = getUnlockedCatArray(cat->getParentUUID());
  1419. if (cat_array)
  1420. {
  1421. cat_array->emplace_back(new_cat);
  1422. }
  1423. // Make space in the tree for this category's children.
  1424. llassert(!mCategoryLock[new_cat->getUUID()] &&
  1425. !mItemLock[new_cat->getUUID()]);
  1426. cat_array_t* catsp = new cat_array_t;
  1427. item_array_t* itemsp = new item_array_t;
  1428. mParentChildCategoryTree[new_cat->getUUID()] = catsp;
  1429. mParentChildItemTree[new_cat->getUUID()] = itemsp;
  1430. mask |= LLInventoryObserver::ADD;
  1431. addChangedMask(mask, cat_id);
  1432. }
  1433. }
  1434. void LLInventoryModel::moveObject(const LLUUID& object_id,
  1435. const LLUUID& cat_id)
  1436. {
  1437. if (!isInventoryUsable())
  1438. {
  1439. llwarns << "Inventory is broken." << llendl;
  1440. return;
  1441. }
  1442. if (object_id == cat_id || !mCategoryMap.count(cat_id))
  1443. {
  1444. llwarns << "Could not move inventory object " << object_id << " to "
  1445. << cat_id << llendl;
  1446. return;
  1447. }
  1448. LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id);
  1449. if (cat && cat->getParentUUID() != cat_id)
  1450. {
  1451. cat_array_t* cat_array;
  1452. cat_array = getUnlockedCatArray(cat->getParentUUID());
  1453. if (cat_array)
  1454. {
  1455. vector_replace_with_last(*cat_array, cat);
  1456. }
  1457. cat_array = getUnlockedCatArray(cat_id);
  1458. cat->setParent(cat_id);
  1459. if (cat_array)
  1460. {
  1461. cat_array->emplace_back(cat);
  1462. }
  1463. addChangedMask(LLInventoryObserver::STRUCTURE, object_id);
  1464. return;
  1465. }
  1466. LLPointer<LLViewerInventoryItem> item = getItem(object_id);
  1467. if (item && item->getParentUUID() != cat_id)
  1468. {
  1469. item_array_t* item_array;
  1470. item_array = getUnlockedItemArray(item->getParentUUID());
  1471. if (item_array)
  1472. {
  1473. vector_replace_with_last(*item_array, item);
  1474. }
  1475. item_array = getUnlockedItemArray(cat_id);
  1476. item->setParent(cat_id);
  1477. if (item_array)
  1478. {
  1479. item_array->emplace_back(item);
  1480. }
  1481. addChangedMask(LLInventoryObserver::STRUCTURE, object_id);
  1482. }
  1483. }
  1484. // Migrated from llinventorybridge.cpp
  1485. void LLInventoryModel::changeItemParent(LLViewerInventoryItem* itemp,
  1486. const LLUUID& new_parent_id,
  1487. bool restamp)
  1488. {
  1489. if (itemp && itemp->getParentUUID() != new_parent_id)
  1490. {
  1491. const LLUUID& item_id = itemp->getUUID();
  1492. llinfos << "Moving '" << itemp->getName() << "' (" << item_id
  1493. << ") from category " << itemp->getParentUUID()
  1494. << " to category " << new_parent_id << llendl;
  1495. if (new_parent_id == getTrashID())
  1496. {
  1497. // Hide any preview
  1498. LLPreview::hide(item_id, true);
  1499. if (itemp->getType() == LLAssetType::AT_GESTURE)
  1500. {
  1501. gGestureManager.deactivateGesture(item_id);
  1502. }
  1503. else if (itemp->getType() == LLAssetType::AT_SETTINGS)
  1504. {
  1505. HBFloaterEditEnvSettings::destroy(item_id);
  1506. }
  1507. }
  1508. LLCategoryUpdate old_folder(itemp->getParentUUID(), -1);
  1509. accountForUpdate(old_folder);
  1510. LLCategoryUpdate new_folder(new_parent_id, 1, false);
  1511. accountForUpdate(new_folder);
  1512. LLPointer<LLViewerInventoryItem> new_itemp =
  1513. new LLViewerInventoryItem(itemp);
  1514. new_itemp->setParent(new_parent_id);
  1515. new_itemp->updateParentOnServer(restamp);
  1516. updateItem(new_itemp);
  1517. notifyObservers();
  1518. }
  1519. }
  1520. // Migrated from llinventorybridge.cpp
  1521. void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* catp,
  1522. const LLUUID& new_parent_id,
  1523. bool restamp)
  1524. {
  1525. if (catp && !isObjectDescendentOf(new_parent_id, catp->getUUID()))
  1526. {
  1527. const LLUUID& cat_id = catp->getUUID();
  1528. llinfos << "Moving '" << catp->getName() << "' (" << cat_id
  1529. << ") from category " << catp->getParentUUID()
  1530. << " to category " << new_parent_id << llendl;
  1531. LLCategoryUpdate old_folder(catp->getParentUUID(), -1);
  1532. accountForUpdate(old_folder);
  1533. LLCategoryUpdate new_folder(new_parent_id, 1, false);
  1534. accountForUpdate(new_folder);
  1535. LLPointer<LLViewerInventoryCategory> new_catp =
  1536. new LLViewerInventoryCategory(catp);
  1537. new_catp->setParent(new_parent_id);
  1538. new_catp->updateParentOnServer(restamp);
  1539. updateCategory(new_catp);
  1540. notifyObservers();
  1541. }
  1542. }
  1543. #if 0 // Do not appear to be used currently.
  1544. void LLInventoryModel::onItemUpdated(const LLUUID& item_id,
  1545. const LLSD& updates,
  1546. bool update_parent_version)
  1547. {
  1548. U32 mask = LLInventoryObserver::NONE;
  1549. LLPointer<LLViewerInventoryItem> item = gInventory.getItem(item_id);
  1550. LL_DEBUGS("Inventory") << "item_id: " << item_id << " - name: "
  1551. << (item ? item->getName() : "(NOT FOUND)")
  1552. << LL_ENDL;
  1553. if (item)
  1554. {
  1555. for (LLSD::map_const_iterator it = updates.beginMap();
  1556. it != updates.endMap(); ++it)
  1557. {
  1558. if (it->first == "name")
  1559. {
  1560. llinfos << "Updating name from " << item->getName() << " to "
  1561. << it->second.asString() << llendl;
  1562. item->rename(it->second.asString());
  1563. mask |= LLInventoryObserver::LABEL;
  1564. }
  1565. else if (it->first == "desc")
  1566. {
  1567. llinfos << "Updating description from "
  1568. << item->getActualDescription()
  1569. << " to " << it->second.asString() << llendl;
  1570. item->setDescription(it->second.asString());
  1571. }
  1572. else
  1573. {
  1574. llwarns << "Unhandled updates for field: " << it->first
  1575. << llendl;
  1576. llassert(false);
  1577. }
  1578. }
  1579. mask |= LLInventoryObserver::INTERNAL;
  1580. addChangedMask(mask, item->getUUID());
  1581. if (update_parent_version)
  1582. {
  1583. // Descendent count is unchanged, but folder version incremented.
  1584. LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0);
  1585. accountForUpdate(up);
  1586. }
  1587. // Do we want to be able to make this optional ?
  1588. notifyObservers();
  1589. }
  1590. }
  1591. void LLInventoryModel::onCategoryUpdated(const LLUUID& cat_id,
  1592. const LLSD& updates)
  1593. {
  1594. U32 mask = LLInventoryObserver::NONE;
  1595. LLPointer<LLViewerInventoryCategory> cat = gInventory.getCategory(cat_id);
  1596. LL_DEBUGS("Inventory") << "cat_id: " << cat_id << " - name: "
  1597. << (cat ? cat->getName() : "(NOT FOUND)")
  1598. << LL_ENDL;
  1599. if (cat)
  1600. {
  1601. for (LLSD::map_const_iterator it = updates.beginMap();
  1602. it != updates.endMap(); ++it)
  1603. {
  1604. if (it->first == "name")
  1605. {
  1606. llinfos << "Updating name from " << cat->getName() << " to "
  1607. << it->second.asString() << llendl;
  1608. cat->rename(it->second.asString());
  1609. mask |= LLInventoryObserver::LABEL;
  1610. }
  1611. else
  1612. {
  1613. llwarns << "Unhandled updates for field: " << it->first
  1614. << llendl;
  1615. llassert(false);
  1616. }
  1617. }
  1618. mask |= LLInventoryObserver::INTERNAL;
  1619. addChangedMask(mask, cat->getUUID());
  1620. // Do we want to be able to make this optional ?
  1621. notifyObservers();
  1622. }
  1623. }
  1624. #endif
  1625. // Update model after descendents have been purged.
  1626. void LLInventoryModel::onDescendentsPurgedFromServer(const LLUUID& object_id,
  1627. bool fix_broken_links)
  1628. {
  1629. LLPointer<LLViewerInventoryCategory> cat = getCategory(object_id);
  1630. if (cat.notNull())
  1631. {
  1632. // do the cache accounting
  1633. S32 descendents = cat->getDescendentCount();
  1634. if (descendents > 0)
  1635. {
  1636. LLCategoryUpdate up(object_id, -descendents);
  1637. accountForUpdate(up);
  1638. }
  1639. // We know that descendent count is 0, however since the accounting may
  1640. // actually not do an update, we should force it here.
  1641. cat->setDescendentCount(0);
  1642. // Unceremoniously remove anything we have locally stored.
  1643. cat_array_t categories;
  1644. item_array_t items;
  1645. collectDescendents(object_id, categories, items,
  1646. LLInventoryModel::INCLUDE_TRASH);
  1647. S32 count = items.size();
  1648. LLUUID uu_id;
  1649. for (S32 i = 0; i < count; ++i)
  1650. {
  1651. uu_id = items[i]->getUUID();
  1652. // This check prevents the deletion of a previously deleted item.
  1653. // This is necessary because deletion is not done in a hierarchical
  1654. // order. The current item may have been already deleted as a child
  1655. // of its deleted parent.
  1656. if (getItem(uu_id))
  1657. {
  1658. deleteObject(uu_id, fix_broken_links);
  1659. }
  1660. }
  1661. count = categories.size();
  1662. // Slightly kludgy way to make sure categories are removed only after
  1663. // their child categories have gone away.
  1664. // *FIXME: Would probably make more sense to have this whole
  1665. // descendent-clearing thing be a post-order recursive function to get
  1666. // the leaf-up behavior automatically.
  1667. S32 deleted_count;
  1668. S32 total_deleted_count = 0;
  1669. do
  1670. {
  1671. deleted_count = 0;
  1672. for (S32 i = 0; i < count; ++i)
  1673. {
  1674. uu_id = categories[i]->getUUID();
  1675. if (getCategory(uu_id))
  1676. {
  1677. cat_array_t* cat_list = getUnlockedCatArray(uu_id);
  1678. if (!cat_list || cat_list->size() == 0)
  1679. {
  1680. deleteObject(uu_id, fix_broken_links);
  1681. ++deleted_count;
  1682. }
  1683. }
  1684. }
  1685. total_deleted_count += deleted_count;
  1686. }
  1687. while (deleted_count > 0);
  1688. if (total_deleted_count != count)
  1689. {
  1690. llwarns << "Unexpected count of categories deleted, got "
  1691. << total_deleted_count << " expected " << count << llendl;
  1692. }
  1693. }
  1694. }
  1695. // Update model after an item is confirmed as removed from server. Works for
  1696. // categories or items.
  1697. void LLInventoryModel::onObjectDeletedFromServer(const LLUUID& object_id,
  1698. bool fix_broken_links,
  1699. bool update_parent_version,
  1700. bool do_notify_observers)
  1701. {
  1702. LLPointer<LLInventoryObject> obj = getObject(object_id);
  1703. if (obj)
  1704. {
  1705. if (getCategory(object_id))
  1706. {
  1707. // For category, need to delete/update all children first.
  1708. onDescendentsPurgedFromServer(object_id, fix_broken_links);
  1709. }
  1710. // From item/cat removeFromServer()
  1711. if (update_parent_version)
  1712. {
  1713. LLCategoryUpdate up(obj->getParentUUID(), -1);
  1714. accountForUpdate(up);
  1715. }
  1716. LLPreview::hide(object_id, true);
  1717. HBFloaterEditEnvSettings::destroy(object_id);
  1718. deleteObject(object_id, fix_broken_links, do_notify_observers);
  1719. }
  1720. }
  1721. // Delete a particular inventory object by ID.
  1722. void LLInventoryModel::deleteObject(const LLUUID& id, bool fix_broken_links,
  1723. bool do_notify_observers)
  1724. {
  1725. LLPointer<LLInventoryObject> obj = getObject(id);
  1726. if (!obj)
  1727. {
  1728. llwarns << "Deleting non-existent object (id: " << id << " )"
  1729. << llendl;
  1730. return;
  1731. }
  1732. LL_DEBUGS("Inventory") << "Deleting inventory object " << id << LL_ENDL;
  1733. // Hide any preview
  1734. LLPreview::hide(id, true);
  1735. HBFloaterEditEnvSettings::destroy(id);
  1736. mLastItem = NULL;
  1737. LLUUID parent_id = obj->getParentUUID();
  1738. mCategoryMap.erase(id);
  1739. mItemMap.erase(id);
  1740. #if 0
  1741. mInventory.erase(id);
  1742. #endif
  1743. item_array_t* item_list = getUnlockedItemArray(parent_id);
  1744. if (item_list)
  1745. {
  1746. LLPointer<LLViewerInventoryItem> item =
  1747. (LLViewerInventoryItem*)((LLInventoryObject*)obj);
  1748. vector_replace_with_last(*item_list, item);
  1749. }
  1750. cat_array_t* cat_list = getUnlockedCatArray(parent_id);
  1751. if (cat_list)
  1752. {
  1753. LLPointer<LLViewerInventoryCategory> cat =
  1754. (LLViewerInventoryCategory*)((LLInventoryObject*)obj);
  1755. vector_replace_with_last(*cat_list, cat);
  1756. }
  1757. item_list = getUnlockedItemArray(id);
  1758. if (item_list)
  1759. {
  1760. if (item_list->size())
  1761. {
  1762. llwarns << "Deleting cat " << id
  1763. << " while it still has child items" << llendl;
  1764. }
  1765. delete item_list;
  1766. mParentChildItemTree.erase(id);
  1767. }
  1768. cat_list = getUnlockedCatArray(id);
  1769. if (cat_list)
  1770. {
  1771. if (cat_list->size())
  1772. {
  1773. llwarns << "Deleting cat " << id
  1774. << " while it still has child cats" << llendl;
  1775. }
  1776. delete cat_list;
  1777. mParentChildCategoryTree.erase(id);
  1778. }
  1779. addChangedMask(LLInventoryObserver::REMOVE, id);
  1780. // Cannot have links to links, so there is no need for this update if the
  1781. // item removed is a link. Can also skip if source of the update is
  1782. // getting broken link info separately.
  1783. bool is_link_type = obj->getIsLinkType();
  1784. #if 0 // *TODO ?
  1785. if (is_link_type)
  1786. {
  1787. removeBacklinkInfo(obj->getUUID(), obj->getLinkedUUID());
  1788. }
  1789. #endif
  1790. if (fix_broken_links && !is_link_type)
  1791. {
  1792. updateLinkedObjectsFromPurge(id);
  1793. }
  1794. obj = NULL; // Delete obj
  1795. if (do_notify_observers)
  1796. {
  1797. notifyObservers();
  1798. }
  1799. }
  1800. void LLInventoryModel::updateLinkedObjectsFromPurge(const LLUUID& baseobj_id)
  1801. {
  1802. LLInventoryModel::item_array_t item_array = collectLinkedItems(baseobj_id);
  1803. // REBUILD is expensive, so clear the current change list first else
  1804. // everything else on the changelist will also get rebuilt.
  1805. if (item_array.size() > 0)
  1806. {
  1807. notifyObservers();
  1808. // Icon and label may have changed.
  1809. constexpr S32 CHANGED_MASK = LLInventoryObserver::REBUILD |
  1810. LLInventoryObserver::LABEL;
  1811. for (LLInventoryModel::item_array_t::const_iterator
  1812. iter = item_array.begin(), end = item_array.end();
  1813. iter != end; ++iter)
  1814. {
  1815. const LLViewerInventoryItem* linked_item = *iter;
  1816. const LLUUID& item_id = linked_item->getUUID();
  1817. if (item_id != baseobj_id)
  1818. {
  1819. addChangedMask(CHANGED_MASK, item_id);
  1820. }
  1821. }
  1822. notifyObservers();
  1823. }
  1824. }
  1825. void LLInventoryModel::addObserver(LLInventoryObserver* observer)
  1826. {
  1827. mObservers.insert(observer);
  1828. }
  1829. void LLInventoryModel::removeObserver(LLInventoryObserver* observer)
  1830. {
  1831. mObservers.erase(observer);
  1832. }
  1833. bool LLInventoryModel::containsObserver(LLInventoryObserver* observer)
  1834. {
  1835. return mObservers.find(observer) != mObservers.end();
  1836. }
  1837. void LLInventoryModel::idleNotifyObservers()
  1838. {
  1839. // *FIX: make this conditional or moved elsewhere...
  1840. handleResponses(true);
  1841. if (!mLinksRebuildList.empty())
  1842. {
  1843. // Mark "broken" links corresponding to recently restored valid items
  1844. // for repair (rebuild).
  1845. for (U32 i = 0, count = mLinksRebuildList.size(); i < count; ++i)
  1846. {
  1847. const LLUUID& link_id = mLinksRebuildList[i];
  1848. if (mItemMap.count(link_id)) // Still there ?
  1849. {
  1850. addChangedMask(LLInventoryObserver::REBUILD, link_id);
  1851. LL_DEBUGS("Inventory") << "Repaired broken link: " << link_id
  1852. << LL_ENDL;
  1853. }
  1854. }
  1855. mLinksRebuildList.clear();
  1856. }
  1857. if (mModifyMask != LLInventoryObserver::NONE || mChangedItemIDs.size())
  1858. {
  1859. notifyObservers();
  1860. }
  1861. }
  1862. // Call this method when it is time to update everyone on a new state.
  1863. void LLInventoryModel::notifyObservers()
  1864. {
  1865. if (mIsNotifyObservers)
  1866. {
  1867. // Within notifyObservers, something called notifyObservers again.
  1868. // This type of recursion is unsafe because it causes items to be
  1869. // processed twice, and this can easily lead to infinite loops.
  1870. // Note: the Cool VL Viewer code should have been purged from any such
  1871. // bugs, but letting this in place, just in case... HB
  1872. llwarns << "Recursive call detected; aborting and delaying to next frame."
  1873. << llendl;
  1874. return;
  1875. }
  1876. mIsNotifyObservers = true;
  1877. for (observer_list_t::iterator iter = mObservers.begin();
  1878. iter != mObservers.end(); )
  1879. {
  1880. LLInventoryObserver* observer = *iter;
  1881. observer->changed(mModifyMask);
  1882. // Safe way to increment since changed() may delete a few entries.
  1883. iter = mObservers.upper_bound(observer);
  1884. }
  1885. // If any changes arrived during the calls to the observers, schedule them
  1886. // for the next notifyObservers() call.
  1887. mModifyMask = mModifyMaskBacklog;
  1888. mModifyMaskBacklog = LLInventoryObserver::NONE;
  1889. mChangedItemIDs.clear();
  1890. if (!mChangedItemIDsBacklog.empty())
  1891. {
  1892. // This the fastest method and also clears mChangedItemIDsBacklog. HB
  1893. mChangedItemIDs.swap(mChangedItemIDsBacklog);
  1894. }
  1895. mAddedItemIDs.clear();
  1896. if (!mAddedItemIDsBacklog.empty())
  1897. {
  1898. // This the fastest method and also clears mAddedItemIDsBacklog. HB
  1899. mAddedItemIDs.swap(mAddedItemIDsBacklog);
  1900. }
  1901. mIsNotifyObservers = false;
  1902. }
  1903. // Stores flags for change and Id of object that change applies to
  1904. void LLInventoryModel::addChangedMask(U32 mask, const LLUUID& referent)
  1905. {
  1906. uuid_list_t* changed_items;
  1907. uuid_list_t* added_items;
  1908. if (mIsNotifyObservers)
  1909. {
  1910. // This condition sometimes happen when we update our agent's outfit
  1911. // and receive the wearable data during an idleNotifyObservers() call.
  1912. // There is no way to avoid it, so we must instead track the updated
  1913. // items and the type of updates, so to reinsert them at the end of
  1914. // the notifyObservers() call and get those changes accounted for on
  1915. // next call. HB
  1916. LL_DEBUGS("Inventory") << "Modify mask changed within notify observer for ";
  1917. std::string name = "<unknown>";
  1918. LLViewerInventoryCategory* cat = getCategory(referent);
  1919. if (cat)
  1920. {
  1921. name = "category: " + cat->getName();
  1922. }
  1923. else
  1924. {
  1925. LLViewerInventoryItem* item = getItem(referent);
  1926. if (item)
  1927. {
  1928. name = "item: " + item->getName();
  1929. }
  1930. }
  1931. LL_CONT << name << LL_ENDL;
  1932. mModifyMaskBacklog |= mask;
  1933. changed_items = &mChangedItemIDsBacklog;
  1934. added_items = &mAddedItemIDsBacklog;
  1935. }
  1936. else
  1937. {
  1938. mModifyMask |= mask;
  1939. changed_items = &mChangedItemIDs;
  1940. added_items = &mAddedItemIDs;
  1941. }
  1942. if (referent.notNull() && !changed_items->count(referent))
  1943. {
  1944. changed_items->emplace(referent);
  1945. #if 0 // This is a bogus thing to do here (because updateCategory() would
  1946. // change the modify masks and that change would have all risks to be
  1947. // ignored, simply triggering the warning above), and should not be
  1948. // needed any more now that I fixed the observer code for the
  1949. // marketplace (by moving changes to the inventory structure out of
  1950. // the observer event code and into an idle callback). HB
  1951. if (LLMarketplace::contains(referent))
  1952. {
  1953. LLMarketplace::updateCategory(referent, false);
  1954. }
  1955. #endif
  1956. if (mask & LLInventoryObserver::ADD)
  1957. {
  1958. added_items->emplace(referent);
  1959. }
  1960. // Update all linked items. Starting with just LABEL because I am
  1961. // not sure what else might need to be accounted for this.
  1962. if (mask & LLInventoryObserver::LABEL)
  1963. {
  1964. addChangedMaskForLinks(referent, LLInventoryObserver::LABEL);
  1965. }
  1966. }
  1967. }
  1968. void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
  1969. {
  1970. if (folder_id.isNull())
  1971. {
  1972. llwarns << "Calling fetch descendents on NULL folder id !" << llendl;
  1973. return;
  1974. }
  1975. LLViewerInventoryCategory* cat = getCategory(folder_id);
  1976. if (!cat)
  1977. {
  1978. llwarns_once << "Asked to fetch descendents of non-existent folder: "
  1979. << folder_id << llendl;
  1980. return;
  1981. }
  1982. #if 0
  1983. S32 known_descendents = 0;
  1984. cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree,
  1985. folder_id);
  1986. item_array_t* items = get_ptr_in_map(mParentChildItemTree, folder_id);
  1987. if (categories)
  1988. {
  1989. known_descendents += categories->size();
  1990. }
  1991. if (items)
  1992. {
  1993. known_descendents += items->size();
  1994. }
  1995. llinfos << "Known descendents for " << folder_id << ": "
  1996. << known_descendents << llendl;
  1997. #endif
  1998. if (!cat->fetch())
  1999. {
  2000. LL_DEBUGS("Inventory") << "Not fetching descendents" << LL_ENDL;
  2001. }
  2002. }
  2003. std::string LLInventoryModel::getCacheFileName(const LLUUID& agent_id)
  2004. {
  2005. std::string agent_id_str;
  2006. agent_id.toString(agent_id_str);
  2007. std::string filename = gDirUtil.getFullPath(LL_PATH_CACHE, agent_id_str);
  2008. if (!gIsInSecondLife)
  2009. {
  2010. static std::string grid_label =
  2011. LLDir::getScrubbedFileName(LLGridManager::getInstance()->getGridLabel());
  2012. filename += "_" + grid_label;
  2013. }
  2014. else if (!gIsInSecondLifeProductionGrid)
  2015. {
  2016. filename += "_beta";
  2017. }
  2018. filename += "_inv.llsd";
  2019. return filename;
  2020. }
  2021. void LLInventoryModel::cache(const LLUUID& parent_folder_id,
  2022. const LLUUID& agent_id)
  2023. {
  2024. if (agent_id.isNull())
  2025. {
  2026. LL_DEBUGS("Inventory") << "Null UUID passed as agent Id. Aborting."
  2027. << LL_ENDL;
  2028. return;
  2029. }
  2030. if (parent_folder_id.isNull())
  2031. {
  2032. LL_DEBUGS("Inventory") << "Null UUID passed as folder Id. Aborting."
  2033. << LL_ENDL;
  2034. return;
  2035. }
  2036. LL_DEBUGS("Inventory") << "Caching " << parent_folder_id << " for "
  2037. << agent_id << LL_ENDL;
  2038. LLViewerInventoryCategory* root_cat = getCategory(parent_folder_id);
  2039. if (!root_cat) return;
  2040. cat_array_t categories;
  2041. categories.push_back(root_cat);
  2042. item_array_t items;
  2043. LLCanCache can_cache(this);
  2044. can_cache(root_cat, NULL);
  2045. collectDescendentsIf(parent_folder_id, categories, items, INCLUDE_TRASH,
  2046. can_cache);
  2047. std::string inventory_filename = getCacheFileName(agent_id);
  2048. saveToFile(inventory_filename, categories, items);
  2049. std::string gzip_filename = inventory_filename + ".gz";
  2050. if (!LLFile::gzip(inventory_filename, gzip_filename))
  2051. {
  2052. llwarns << "Unable to compress " << inventory_filename << llendl;
  2053. return;
  2054. }
  2055. LL_DEBUGS("Inventory") << "Successfully compressed "
  2056. << inventory_filename << LL_ENDL;
  2057. LLFile::remove(inventory_filename);
  2058. }
  2059. void LLInventoryModel::addCategory(LLViewerInventoryCategory* category)
  2060. {
  2061. if (category)
  2062. {
  2063. // Insert category uniquely into the map
  2064. // LLPointer will deref and delete the old one
  2065. mCategoryMap[category->getUUID()] = category;
  2066. //mInventory[category->getUUID()] = category;
  2067. }
  2068. }
  2069. void LLInventoryModel::addItem(LLViewerInventoryItem* itemp)
  2070. {
  2071. if (!itemp)
  2072. {
  2073. return;
  2074. }
  2075. if (itemp->getType() == LLAssetType::AT_NONE)
  2076. {
  2077. llwarns << "Got bad asset type for item. Name: " << itemp->getName()
  2078. << " - type: " << itemp->getType() << " inv-type: "
  2079. << itemp->getInventoryType() << ". Ignoring." << llendl;
  2080. return;
  2081. }
  2082. // This can happen if assettype enums from llassettype.h ever change. For
  2083. // example, there is a known backwards compatibility issue in some viewer
  2084. // prototypes prior to when the AT_LINK enum changed from 23 to 24.
  2085. if (LLAssetType::lookup(itemp->getType()) == LLAssetType::badLookup())
  2086. {
  2087. llwarns << "Got unsupported asset type for item. Name: "
  2088. << itemp->getName() << " - Type: " << itemp->getType()
  2089. << " Inventory type: " << itemp->getInventoryType()
  2090. << llendl;
  2091. }
  2092. const LLUUID& item_id = itemp->getUUID();
  2093. // This condition means that we tried to add a link without the baseobj
  2094. // being in memory. The item will show up as a broken link.
  2095. if (itemp->getIsBrokenLink())
  2096. {
  2097. // The UUID of the linked item is stored as the link item's asset UUID.
  2098. const LLUUID& linked_id = itemp->getAssetUUID();
  2099. if (linked_id.notNull())
  2100. {
  2101. // Schedule this link for a recheck as inventory gets loaded.
  2102. mBrokenLinks[linked_id].emplace_back(item_id);
  2103. LL_DEBUGS("Inventory") << "Registering apparently broken link '"
  2104. << itemp->getName()
  2105. << "' with linked item Id: " << linked_id
  2106. << LL_ENDL;
  2107. }
  2108. else
  2109. {
  2110. llinfos << "Adding broken link. Name: " << itemp->getName()
  2111. << " - Item Id: " << itemp->getUUID() << " - Asset Id: "
  2112. << itemp->getAssetUUID() << " - Parent Id: "
  2113. << itemp->getParentUUID() << llendl;
  2114. }
  2115. }
  2116. else if (!mBrokenLinks.empty())
  2117. {
  2118. // Check to see if this item corresponds to broken links.
  2119. broken_links_map_t::iterator it = mBrokenLinks.find(item_id);
  2120. if (it != mBrokenLinks.end())
  2121. {
  2122. const uuid_vec_t& links = it->second;
  2123. for (U32 i = 0, count = links.size(); i < count; ++i)
  2124. {
  2125. mLinksRebuildList.emplace_back(links[i]);
  2126. }
  2127. mBrokenLinks.erase(it);
  2128. }
  2129. }
  2130. mItemMap[item_id] = itemp;
  2131. }
  2132. void LLInventoryModel::rebuildBrokenLinks()
  2133. {
  2134. // Make sure we are not adding a potentially expensive rebuild to anything
  2135. // else.
  2136. notifyObservers();
  2137. bool has_rebuilds = false;
  2138. if (!mBrokenLinks.empty())
  2139. {
  2140. for (broken_links_map_t::iterator it = mBrokenLinks.begin(),
  2141. end = mBrokenLinks.end();
  2142. it != end; ++it)
  2143. {
  2144. if (!mItemMap.count(it->first))
  2145. {
  2146. continue; // Still not in our inventory representation.
  2147. }
  2148. const uuid_vec_t& links = it->second;
  2149. for (U32 i = 0, count = links.size(); i < count; ++i)
  2150. {
  2151. const LLUUID& link_id = links[i];
  2152. if (mItemMap.count(link_id)) // Still there ?
  2153. {
  2154. addChangedMask(LLInventoryObserver::REBUILD, link_id);
  2155. LL_DEBUGS("Inventory") << "Repaired broken link: "
  2156. << link_id << LL_ENDL;
  2157. has_rebuilds = true;
  2158. }
  2159. }
  2160. // We can get away with this one...
  2161. it = mBrokenLinks.erase(it);
  2162. }
  2163. }
  2164. #if 0 // This is done in idleNotifyObservers(). HB
  2165. if (!mLinksRebuildList.empty())
  2166. {
  2167. for (U32 i = 0, count = mLinksRebuildList.size(); i < count; ++i)
  2168. {
  2169. const LLUUID& link_id = mLinksRebuildList[i];
  2170. if (mItemMap.find(link_id)) // Still there ?
  2171. {
  2172. addChangedMask(LLInventoryObserver::REBUILD, link_id);
  2173. LL_DEBUGS("Inventory") << "Repaired broken link: " << link_id
  2174. << LL_ENDL;
  2175. has_rebuilds = true;
  2176. }
  2177. }
  2178. mLinksRebuildList.clear();
  2179. }
  2180. #endif
  2181. if (has_rebuilds)
  2182. {
  2183. notifyObservers();
  2184. }
  2185. }
  2186. // Empty the entire contents
  2187. void LLInventoryModel::empty()
  2188. {
  2189. for (auto it = mParentChildCategoryTree.begin(),
  2190. end = mParentChildCategoryTree.end();
  2191. it != end; ++it)
  2192. {
  2193. delete it->second;
  2194. }
  2195. mParentChildCategoryTree.clear();
  2196. for (auto it = mParentChildItemTree.begin(),
  2197. end = mParentChildItemTree.end();
  2198. it != end; ++it)
  2199. {
  2200. delete it->second;
  2201. }
  2202. mParentChildItemTree.clear();
  2203. mCategoryMap.clear(); // Remove all references (should delete entries)
  2204. mItemMap.clear(); // Remove all references (should delete entries)
  2205. mLastItem = NULL;
  2206. #if 0
  2207. mInventory.clear();
  2208. #endif
  2209. }
  2210. void LLInventoryModel::accountForUpdate(const LLCategoryUpdate& update) const
  2211. {
  2212. if (update.mCategoryID.isNull())
  2213. {
  2214. llwarns << "Got a null category UUID. Ignoring." << llendl;
  2215. return;
  2216. }
  2217. LLViewerInventoryCategory* catp = getCategory(update.mCategoryID);
  2218. if (!catp)
  2219. {
  2220. llwarns << "No category found for update " << update.mCategoryID
  2221. << llendl;
  2222. return;
  2223. }
  2224. S32 version = catp->getVersion();
  2225. if (version == LLViewerInventoryCategory::VERSION_UNKNOWN)
  2226. {
  2227. llwarns << "Accounting failed for '" << catp->getName()
  2228. << "' version: unknown (" << version << ")" << llendl;
  2229. return;
  2230. }
  2231. S32 descendents_server = catp->getDescendentCount();
  2232. S32 descendents_actual = catp->getViewerDescendentCount();
  2233. if (descendents_server != descendents_actual)
  2234. {
  2235. // Error condition, this means that the category did not register that
  2236. // it got new descendents (perhaps because it is still being loaded)
  2237. // which means its descendent count will be wrong.
  2238. llwarns << "No accounting for: '" << catp->getName() << "' version "
  2239. << version
  2240. << " due to mismatched descendents count: server count = "
  2241. << descendents_server << " - viewer count = "
  2242. << descendents_actual << llendl;
  2243. return;
  2244. }
  2245. descendents_actual += update.mDescendentDelta;
  2246. catp->setDescendentCount(descendents_actual);
  2247. if (update.mChangeVersion)
  2248. {
  2249. catp->setVersion(++version);
  2250. }
  2251. LL_DEBUGS("Inventory") << "Accounted: '" << catp->getName() << "' "
  2252. << version << " with " << descendents_actual
  2253. << " descendents." << LL_ENDL;
  2254. }
  2255. void LLInventoryModel::accountForUpdate(const LLInventoryModel::update_list_t& update) const
  2256. {
  2257. for (update_list_t::const_iterator it = update.begin(), end = update.end();
  2258. it != end; ++it)
  2259. {
  2260. accountForUpdate(*it);
  2261. }
  2262. }
  2263. void LLInventoryModel::accountForUpdate(const LLInventoryModel::update_map_t& update) const
  2264. {
  2265. LLCategoryUpdate up;
  2266. for (update_map_t::const_iterator it = update.begin(), end = update.end();
  2267. it != end; ++it)
  2268. {
  2269. up.mCategoryID = it->first;
  2270. up.mDescendentDelta = it->second.mValue;
  2271. accountForUpdate(up);
  2272. }
  2273. }
  2274. LLInventoryModel::EHasChildren LLInventoryModel::categoryHasChildren(const LLUUID& cat_id) const
  2275. {
  2276. LLViewerInventoryCategory* catp = getCategory(cat_id);
  2277. if (!catp)
  2278. {
  2279. return CHILDREN_NO;
  2280. }
  2281. if (catp->getDescendentCount() > 0)
  2282. {
  2283. return CHILDREN_YES;
  2284. }
  2285. if (catp->getDescendentCount() == 0)
  2286. {
  2287. return CHILDREN_NO;
  2288. }
  2289. if (catp->isVersionUnknown() || catp->isDescendentCountUnknown())
  2290. {
  2291. return CHILDREN_MAYBE;
  2292. }
  2293. // Should not have to run this, but who knows ?...
  2294. parent_cat_map_t::const_iterator cat_it =
  2295. mParentChildCategoryTree.find(catp->getUUID());
  2296. if (cat_it != mParentChildCategoryTree.end() &&
  2297. cat_it->second->size() > 0)
  2298. {
  2299. return CHILDREN_YES;
  2300. }
  2301. parent_item_map_t::const_iterator item_it =
  2302. mParentChildItemTree.find(catp->getUUID());
  2303. if (item_it != mParentChildItemTree.end() && item_it->second->size() > 0)
  2304. {
  2305. return CHILDREN_YES;
  2306. }
  2307. return CHILDREN_NO;
  2308. }
  2309. bool LLInventoryModel::isCategoryComplete(const LLUUID& cat_id) const
  2310. {
  2311. LLViewerInventoryCategory* catp = getCategory(cat_id);
  2312. return catp && !catp->isVersionUnknown() &&
  2313. catp->getDescendentCount() == catp->getViewerDescendentCount();
  2314. }
  2315. //static
  2316. void LLInventoryModel::checkSystemFolders(void*)
  2317. {
  2318. llinfos << "Checking system folders..." << llendl;
  2319. llinfos << "Consolidating the Trash..." << llendl;
  2320. gInventory.consolidateForType(gInventory.getTrashID(),
  2321. LLFolderType::FT_TRASH);
  2322. llinfos << "Consolidating Lost And Found..." << llendl;
  2323. gInventory.consolidateForType(gInventory.getLostAndFoundID(),
  2324. LLFolderType::FT_LOST_AND_FOUND);
  2325. LLUUID id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ANIMATION);
  2326. llinfos << "Consolidating Animations..." << llendl;
  2327. gInventory.consolidateForType(id, LLFolderType::FT_ANIMATION);
  2328. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_BODYPART);
  2329. llinfos << "Consolidating Body Parts..." << llendl;
  2330. gInventory.consolidateForType(id, LLFolderType::FT_BODYPART);
  2331. // Note: we do not consolidate calling cards, because the root Calling
  2332. // Cards folder may contain Calling Card sub-folders (this is an exception,
  2333. // stupidely introduced by v2 viewers, to the rule that a special folder
  2334. // should be parented directly to the root of the inventory...
  2335. llinfos << "Ensuring Calling Cards existence..." << llendl;
  2336. gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD);
  2337. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING);
  2338. llinfos << "Consolidating Clothing..." << llendl;
  2339. gInventory.consolidateForType(id, LLFolderType::FT_CLOTHING);
  2340. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LANDMARK);
  2341. llinfos << "Consolidating Landmarks..." << llendl;
  2342. gInventory.consolidateForType(id, LLFolderType::FT_LANDMARK);
  2343. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_NOTECARD);
  2344. llinfos << "Consolidating Notecards..." << llendl;
  2345. gInventory.consolidateForType(id, LLFolderType::FT_NOTECARD);
  2346. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SNAPSHOT_CATEGORY);
  2347. llinfos << "Consolidating Photo Album..." << llendl;
  2348. gInventory.consolidateForType(id, LLFolderType::FT_SNAPSHOT_CATEGORY);
  2349. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
  2350. llinfos << "Consolidating Objects..." << llendl;
  2351. gInventory.consolidateForType(id, LLFolderType::FT_OBJECT);
  2352. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_LSL_TEXT);
  2353. llinfos << "Consolidating Scripts..." << llendl;
  2354. gInventory.consolidateForType(id, LLFolderType::FT_LSL_TEXT);
  2355. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SOUND);
  2356. llinfos << "Consolidating Sounds..." << llendl;
  2357. gInventory.consolidateForType(id, LLFolderType::FT_SOUND);
  2358. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE);
  2359. llinfos << "Consolidating Textures..." << llendl;
  2360. gInventory.consolidateForType(id, LLFolderType::FT_TEXTURE);
  2361. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
  2362. llinfos << "Consolidating Gestures..." << llendl;
  2363. gInventory.consolidateForType(id, LLFolderType::FT_GESTURE);
  2364. // Do not impose an extended environment Settings folder: let the user
  2365. // choose...
  2366. bool create = gSavedSettings.getBool("CreateSettingsFolder") &&
  2367. gAgent.hasInventorySettings();
  2368. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_SETTINGS, create);
  2369. if (id.notNull())
  2370. {
  2371. llinfos << "Consolidating Settings..." << llendl;
  2372. gInventory.consolidateForType(id, LLFolderType::FT_SETTINGS);
  2373. }
  2374. // Do not impose a Materials folder: let the user choose...
  2375. create = gSavedSettings.getBool("CreateMaterialsFolder") &&
  2376. gAgent.hasInventoryMaterial();
  2377. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MATERIAL, create);
  2378. if (id.notNull())
  2379. {
  2380. llinfos << "Consolidating Materials..." << llendl;
  2381. gInventory.consolidateForType(id, LLFolderType::FT_MATERIAL);
  2382. }
  2383. id = LLMarketplace::getMPL();
  2384. if (id.notNull())
  2385. {
  2386. llinfos << "Consolidating the Marketplace Listings..." << llendl;
  2387. gInventory.consolidateForType(id,
  2388. LLFolderType::FT_MARKETPLACE_LISTINGS);
  2389. }
  2390. if (gIsInSecondLife || gSavedSettings.getBool("OSUseCOF"))
  2391. {
  2392. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
  2393. llinfos << "Consolidating the Current Outfit folder..." << llendl;
  2394. gInventory.consolidateForType(id, LLFolderType::FT_CURRENT_OUTFIT);
  2395. }
  2396. if (gIsInSecondLife)
  2397. {
  2398. id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
  2399. llinfos << "Consolidating the Received Items folder..." << llendl;
  2400. gInventory.consolidateForType(id, LLFolderType::FT_INBOX);
  2401. }
  2402. if (gRLenabled && !gRLInterface.getRlvShare())
  2403. {
  2404. llinfos << "Creating the missing #RLV folder..." << llendl;
  2405. gInventory.createNewCategory(gInventory.getRootFolderID(),
  2406. LLFolderType::FT_NONE, RL_SHARED_FOLDER,
  2407. NULL);
  2408. }
  2409. gInventory.notifyObservers();
  2410. }
  2411. bool LLInventoryModel::loadSkeleton(const LLSD& options,
  2412. const LLUUID& owner_id)
  2413. {
  2414. LL_DEBUGS("LoadInventory") << "Importing inventory skeleton for "
  2415. << owner_id << LL_ENDL;
  2416. typedef std::set<LLPointer<LLViewerInventoryCategory>,
  2417. InventoryIDPtrLess> cat_set_t;
  2418. cat_set_t temp_cats;
  2419. bool rv = true;
  2420. for (LLSD::array_const_iterator it = options.beginArray(),
  2421. end = options.endArray();
  2422. it != end; ++it)
  2423. {
  2424. LLSD name = (*it)["name"];
  2425. LLSD folder_id = (*it)["folder_id"];
  2426. LLSD parent_id = (*it)["parent_id"];
  2427. LLSD version = (*it)["version"];
  2428. if (name.isDefined() && folder_id.isDefined() &&
  2429. parent_id.isDefined() && version.isDefined() &&
  2430. // If an Id is null, it locks the viewer.
  2431. folder_id.asUUID().notNull())
  2432. {
  2433. LLPointer<LLViewerInventoryCategory> cat =
  2434. new LLViewerInventoryCategory(owner_id);
  2435. cat->rename(name.asString());
  2436. cat->setUUID(folder_id.asUUID());
  2437. cat->setParent(parent_id.asUUID());
  2438. LLFolderType::EType preferred_type = LLFolderType::FT_NONE;
  2439. LLSD type_default = (*it)["type_default"];
  2440. if (type_default.isDefined())
  2441. {
  2442. preferred_type = (LLFolderType::EType)type_default.asInteger();
  2443. }
  2444. cat->setPreferredType(preferred_type);
  2445. cat->setVersion(version.asInteger());
  2446. temp_cats.emplace(std::move(cat));
  2447. }
  2448. else
  2449. {
  2450. llwarns << "Unable to import near " << name.asString() << llendl;
  2451. rv = false;
  2452. }
  2453. }
  2454. S32 cached_category_count = 0;
  2455. S32 cached_item_count = 0;
  2456. if (!temp_cats.empty())
  2457. {
  2458. update_map_t child_counts;
  2459. item_array_t items;
  2460. cat_array_t categories;
  2461. cat_set_t invalid_categories;
  2462. uuid_list_t cats_to_update;
  2463. std::string inventory_filename = getCacheFileName(owner_id);
  2464. std::string gzip_filename = inventory_filename + ".gz";
  2465. bool remove_inventory_file = false;
  2466. if (LLFile::exists(gzip_filename))
  2467. {
  2468. if (LLFile::gunzip(gzip_filename, inventory_filename))
  2469. {
  2470. // We only want to remove the inventory file if it was
  2471. // gzipped before we loaded, and we successfully gunziped it.
  2472. remove_inventory_file = true;
  2473. }
  2474. else
  2475. {
  2476. llinfos << "Unable to gunzip " << gzip_filename << llendl;
  2477. }
  2478. }
  2479. bool is_cache_obsolete = false;
  2480. if (loadFromFile(inventory_filename, categories, items, cats_to_update,
  2481. is_cache_obsolete))
  2482. {
  2483. // We were able to find a cache of files. So, use what we found to
  2484. // generate a set of categories we should add. We will go through
  2485. // each category loaded and if the version does not match,
  2486. // invalidate the version.
  2487. S32 count = categories.size();
  2488. cat_set_t::iterator not_cached = temp_cats.end();
  2489. std::set<LLUUID> cached_ids;
  2490. for (S32 i = 0; i < count; ++i)
  2491. {
  2492. LLViewerInventoryCategory* cat = categories[i];
  2493. cat_set_t::iterator cit = temp_cats.find(cat);
  2494. if (cit == temp_cats.end())
  2495. {
  2496. // Cache corruption ? Not sure why this happens - SJB
  2497. continue;
  2498. }
  2499. LLViewerInventoryCategory* tcat = *cit;
  2500. // We can safely ignore anything loaded from file, but not sent
  2501. // down in the skeleton.
  2502. if (cit == not_cached)
  2503. {
  2504. if (cats_to_update.count(tcat->getUUID()))
  2505. {
  2506. tcat->setVersionUnknown();
  2507. }
  2508. continue;
  2509. }
  2510. if (cat->getVersion() != tcat->getVersion() ||
  2511. cats_to_update.count(tcat->getUUID()))
  2512. {
  2513. // If the cached version does not match the server version,
  2514. // throw away the version we have so we can fetch the
  2515. // correct contents the next time the viewer opens the
  2516. // folder.
  2517. tcat->setVersionUnknown();
  2518. }
  2519. else if (tcat->getPreferredType() ==
  2520. LLFolderType::FT_MARKETPLACE_STOCK)
  2521. {
  2522. // Do not trust stock folders being updated
  2523. tcat->setVersionUnknown();
  2524. }
  2525. else
  2526. {
  2527. cached_ids.emplace(tcat->getUUID());
  2528. }
  2529. if (cat->getThumbnailUUID().notNull() &&
  2530. tcat->getThumbnailUUID().isNull())
  2531. {
  2532. tcat->setThumbnailUUID(cat->getThumbnailUUID());
  2533. }
  2534. }
  2535. // Go ahead and add the cats returned during the download
  2536. std::set<LLUUID>::const_iterator not_cached_id = cached_ids.end();
  2537. cached_category_count = cached_ids.size();
  2538. for (cat_set_t::iterator it = temp_cats.begin();
  2539. it != temp_cats.end(); ++it)
  2540. {
  2541. LLViewerInventoryCategory* llvic = *it;
  2542. if (cached_ids.find(llvic->getUUID()) == not_cached_id)
  2543. {
  2544. // This check is performed so that we do not mark new
  2545. // folders in the skeleton (and not in cache) as being
  2546. // cached.
  2547. llvic->setVersionUnknown();
  2548. }
  2549. addCategory(llvic);
  2550. ++child_counts[llvic->getParentUUID()];
  2551. }
  2552. // Add all the items loaded which are parented to a category with a
  2553. // correctly cached parent
  2554. cat_map_t::iterator unparented = mCategoryMap.end();
  2555. // First, we add non-link items and links which base objects have
  2556. // been loaded
  2557. for (item_array_t::const_iterator item_iter = items.begin();
  2558. item_iter != items.end();
  2559. ++item_iter)
  2560. {
  2561. LLViewerInventoryItem* item = item_iter->get();
  2562. const cat_map_t::iterator cit =
  2563. mCategoryMap.find(item->getParentUUID());
  2564. if (cit != unparented)
  2565. {
  2566. const LLViewerInventoryCategory* cat = cit->second.get();
  2567. if (!cat->isVersionUnknown() && !item->getIsBrokenLink())
  2568. {
  2569. addItem(item);
  2570. ++cached_item_count;
  2571. ++child_counts[cat->getUUID()];
  2572. }
  2573. }
  2574. }
  2575. // Then we can add the remaining links since their base objects have
  2576. // now all been loaded...
  2577. S32 bad_link_count = 0;
  2578. item_map_t::const_iterator iit;
  2579. for (item_array_t::const_iterator item_iter = items.begin();
  2580. item_iter != items.end();
  2581. ++item_iter)
  2582. {
  2583. LLViewerInventoryItem* item = item_iter->get();
  2584. const cat_map_t::iterator cit =
  2585. mCategoryMap.find(item->getParentUUID());
  2586. if (cit != unparented)
  2587. {
  2588. const LLViewerInventoryCategory* cat = cit->second.get();
  2589. if (!cat->isVersionUnknown())
  2590. {
  2591. iit = mItemMap.find(item->getUUID());
  2592. if (iit == mItemMap.end()) // Not yet added
  2593. {
  2594. // This can happen if the linked object's baseobj is
  2595. // removed from the cache but the linked object is
  2596. // still in the cache.
  2597. if (item->getIsBrokenLink())
  2598. {
  2599. ++bad_link_count;
  2600. LL_DEBUGS("LoadInventory") << "Attempted to add cached link item without baseobj present (name: "
  2601. << item->getName()
  2602. << " - itemID: "
  2603. << item->getUUID()
  2604. << " - assetID: "
  2605. << item->getAssetUUID()
  2606. << "). Ignoring and invalidating: "
  2607. << cat->getName()
  2608. << LL_ENDL;
  2609. invalid_categories.emplace(cit->second);
  2610. continue;
  2611. }
  2612. addItem(item);
  2613. ++cached_item_count;
  2614. ++child_counts[cat->getUUID()];
  2615. }
  2616. }
  2617. }
  2618. }
  2619. if (bad_link_count > 0)
  2620. {
  2621. llinfos << "Attempted to add " << bad_link_count
  2622. << " cached link items without baseobj present. "
  2623. << "The corresponding categories were invalidated."
  2624. << llendl;
  2625. }
  2626. }
  2627. else
  2628. {
  2629. // Go ahead and add everything after stripping the version
  2630. // information.
  2631. for (cat_set_t::iterator it = temp_cats.begin();
  2632. it != temp_cats.end(); ++it)
  2633. {
  2634. LLViewerInventoryCategory* llvic = *it;
  2635. if (llvic)
  2636. {
  2637. llvic->setVersionUnknown();
  2638. addCategory(llvic);
  2639. }
  2640. }
  2641. }
  2642. // Invalidate all categories that failed fetching descendents for
  2643. // whatever reason (e.g. one of the descendents was a broken link).
  2644. for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin();
  2645. invalid_cat_it != invalid_categories.end();
  2646. invalid_cat_it++)
  2647. {
  2648. LLViewerInventoryCategory* cat = invalid_cat_it->get();
  2649. cat->setVersionUnknown();
  2650. llinfos << "Invalidating category name: " << cat->getName()
  2651. << " - UUID: " << cat->getUUID()
  2652. << ", due to invalid descendents cache" << llendl;
  2653. }
  2654. // At this point, we need to set the known descendents for each
  2655. // category which successfully cached so that we do not needlessly
  2656. // fetch descendents for categories which we have.
  2657. update_map_t::const_iterator no_child_counts = child_counts.end();
  2658. for (cat_set_t::iterator it = temp_cats.begin();
  2659. it != temp_cats.end(); ++it)
  2660. {
  2661. LLViewerInventoryCategory* cat = it->get();
  2662. if (!cat->isVersionUnknown())
  2663. {
  2664. update_map_t::const_iterator the_count =
  2665. child_counts.find(cat->getUUID());
  2666. if (the_count != no_child_counts)
  2667. {
  2668. const S32 num_descendents = the_count->second.mValue;
  2669. cat->setDescendentCount(num_descendents);
  2670. }
  2671. else
  2672. {
  2673. cat->setDescendentCount(0);
  2674. }
  2675. }
  2676. }
  2677. if (remove_inventory_file)
  2678. {
  2679. // Clean up the gunzipped file.
  2680. LLFile::remove(inventory_filename);
  2681. }
  2682. if (is_cache_obsolete)
  2683. {
  2684. // If out of date, remove the gzipped file too.
  2685. llwarns << "Inv cache out of date, removing" << llendl;
  2686. LLFile::remove(gzip_filename);
  2687. }
  2688. categories.clear(); // will unref and delete entries
  2689. }
  2690. llinfos << "Successfully loaded " << cached_category_count
  2691. << " categories and " << cached_item_count << " items from cache."
  2692. << llendl;
  2693. return rv;
  2694. }
  2695. // This is a brute force method to rebuild the entire parent-child relations.
  2696. // The overall operation has O(NlogN) performance, which should be sufficient
  2697. // for our needs.
  2698. void LLInventoryModel::buildParentChildMap()
  2699. {
  2700. llinfos << "Building parent child map..." << llendl;
  2701. // *NOTE: I am skipping the logic around folder version synchronization
  2702. // here because it seems if a folder is lost, we might actually want to
  2703. // invalidate it at that point - not attempt to cache. More time &
  2704. // thought is necessary.
  2705. // First the categories. We will copy all of the categories into a
  2706. // temporary container to iterate over (oh for real iterators). While we
  2707. // are at it, we will allocate the arrays in the trees.
  2708. cat_array_t cats;
  2709. cat_array_t* catsp;
  2710. item_array_t* itemsp;
  2711. for (cat_map_t::iterator cit = mCategoryMap.begin();
  2712. cit != mCategoryMap.end(); ++cit)
  2713. {
  2714. LLViewerInventoryCategory* cat = cit->second;
  2715. cats.push_back(cat);
  2716. const LLUUID& cat_id = cat->getUUID();
  2717. if (mParentChildCategoryTree.count(cat_id) == 0)
  2718. {
  2719. llassert(!mCategoryLock[cat_id]);
  2720. catsp = new cat_array_t;
  2721. mParentChildCategoryTree[cat_id] = catsp;
  2722. }
  2723. if (mParentChildItemTree.count(cat_id) == 0)
  2724. {
  2725. llassert(!mItemLock[cat_id]);
  2726. itemsp = new item_array_t;
  2727. mParentChildItemTree[cat_id] = itemsp;
  2728. }
  2729. }
  2730. // Insert a special parent for the root - so that lookups on LLUUID::null
  2731. // as the parent work correctly. This is kind of a blatent wastes of space
  2732. // since we allocate a block of memory for the array, but whatever - it is
  2733. // not that much space.
  2734. if (mParentChildCategoryTree.count(LLUUID::null) == 0)
  2735. {
  2736. catsp = new cat_array_t;
  2737. mParentChildCategoryTree[LLUUID::null] = catsp;
  2738. }
  2739. // Now we have a structure with all of the categories that we can iterate
  2740. // over and insert into the correct place in the child category tree.
  2741. S32 count = cats.size();
  2742. S32 lost = 0;
  2743. cat_array_t lost_cats;
  2744. for (S32 i = 0; i < count; ++i)
  2745. {
  2746. LLViewerInventoryCategory* cat = cats[i];
  2747. catsp = getUnlockedCatArray(cat->getParentUUID());
  2748. LLFolderType::EType type = cat->getPreferredType();
  2749. // *HACK: work-around for bogus OpenSim servers
  2750. if (type == LLFolderType::FT_ROOT_INVENTORY_OS && !gIsInSecondLife)
  2751. {
  2752. llwarns << "Found bad inventory root type (9 instead or 8) for folder "
  2753. << cat->getName() << llendl;
  2754. type = LLFolderType::FT_ROOT_INVENTORY;
  2755. }
  2756. if (catsp &&
  2757. // Only the two root folders should be children of null. Others
  2758. // should go to Lost And Found.
  2759. (cat->getParentUUID().notNull() ||
  2760. type == LLFolderType::FT_ROOT_INVENTORY))
  2761. {
  2762. catsp->push_back(cat);
  2763. }
  2764. else
  2765. {
  2766. // *NOTE: This process could be a lot more efficient if we used the
  2767. // new MoveInventoryFolder message, but we would have to continue
  2768. // to do the update & build here. So, to implement it, we would
  2769. // need a set or map of uuid pairs which would be (folder_id,
  2770. // new_parent_id) to be sent up to the server.
  2771. llinfos << "Lost category: " << cat->getUUID() << " - "
  2772. << cat->getName() << " with parent:"
  2773. << cat->getParentUUID() << llendl;
  2774. ++lost;
  2775. lost_cats.push_back(cat);
  2776. }
  2777. }
  2778. if (lost)
  2779. {
  2780. llwarns << "Found " << lost << " lost categories." << llendl;
  2781. }
  2782. const LLUUID& laf = getLostAndFoundID();
  2783. bool ais_available = AISAPI::isAvailable();
  2784. // Do moves in a separate pass to make sure we have properly filed the
  2785. // FT_LOST_AND_FOUND category before we try to find its UUID.
  2786. for (S32 i = 0, count = lost_cats.size(); i < count; ++i)
  2787. {
  2788. LLViewerInventoryCategory* cat = lost_cats[i];
  2789. if (!cat) continue; // Paranoia
  2790. // Plop it into the Lost And Found.
  2791. LLFolderType::EType pref = cat->getPreferredType();
  2792. // *HACK: work-around for bogus OpenSim servers
  2793. if (pref == LLFolderType::FT_ROOT_INVENTORY_OS && !gIsInSecondLife)
  2794. {
  2795. pref = LLFolderType::FT_ROOT_INVENTORY;
  2796. }
  2797. if (pref == LLFolderType::FT_NONE)
  2798. {
  2799. cat->setParent(laf);
  2800. }
  2801. else if (pref == LLFolderType::FT_ROOT_INVENTORY)
  2802. {
  2803. // It is the root
  2804. cat->setParent(LLUUID::null);
  2805. }
  2806. else
  2807. {
  2808. // It is a protected folder.
  2809. cat->setParent(gInventory.getRootFolderID());
  2810. }
  2811. // UpdateServer() uses AIS, but AIS cat move is not implemented yet.
  2812. if (ais_available)
  2813. {
  2814. cat->updateParentOnServer(false);
  2815. }
  2816. else
  2817. {
  2818. // *FIXME: note that updateServer() fails with protected types, so
  2819. // this will not work as intended in that case.
  2820. cat->updateServer(true);
  2821. }
  2822. catsp = getUnlockedCatArray(cat->getParentUUID());
  2823. if (catsp)
  2824. {
  2825. catsp->push_back(cat);
  2826. }
  2827. else
  2828. {
  2829. llwarns << "Lost and found Not there !" << llendl;
  2830. }
  2831. }
  2832. // Now the items. We allocated in the last step, so now all we have to do
  2833. // is iterate over the items and put them in the right place.
  2834. item_array_t items;
  2835. if (!mItemMap.empty())
  2836. {
  2837. LLPointer<LLViewerInventoryItem> item;
  2838. for (item_map_t::iterator it = mItemMap.begin();
  2839. it != mItemMap.end(); ++it)
  2840. {
  2841. item = it->second;
  2842. items.emplace_back(item);
  2843. }
  2844. }
  2845. count = items.size();
  2846. lost = 0;
  2847. uuid_vec_t lost_item_ids;
  2848. for (S32 i = 0; i < count; ++i)
  2849. {
  2850. LLPointer<LLViewerInventoryItem> item = items[i];
  2851. itemsp = getUnlockedItemArray(item->getParentUUID());
  2852. if (itemsp)
  2853. {
  2854. itemsp->emplace_back(item);
  2855. }
  2856. else
  2857. {
  2858. llinfos << "Lost item: " << item->getUUID() << " - "
  2859. << item->getName() << llendl;
  2860. ++lost;
  2861. // Plop it into the Lost And Found.
  2862. item->setParent(laf);
  2863. #if 0 // Move it later using a special message to move items. If we
  2864. // update server here, the client might crash.
  2865. item->updateServer();
  2866. #endif
  2867. lost_item_ids.emplace_back(item->getUUID());
  2868. itemsp = getUnlockedItemArray(item->getParentUUID());
  2869. if (itemsp)
  2870. {
  2871. itemsp->emplace_back(item);
  2872. }
  2873. else
  2874. {
  2875. llwarns << "Lost and found not there !" << llendl;
  2876. }
  2877. }
  2878. }
  2879. if (lost)
  2880. {
  2881. llwarns << "Found " << lost << " lost items." << llendl;
  2882. LLMessageSystem* msg = gMessageSystemp;
  2883. bool start_new_message = true;
  2884. for (uuid_vec_t::iterator it = lost_item_ids.begin();
  2885. it < lost_item_ids.end(); ++it)
  2886. {
  2887. if (start_new_message)
  2888. {
  2889. start_new_message = false;
  2890. msg->newMessageFast(_PREHASH_MoveInventoryItem);
  2891. msg->nextBlockFast(_PREHASH_AgentData);
  2892. msg->addUUIDFast(_PREHASH_AgentID, gAgentID);
  2893. msg->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
  2894. msg->addBoolFast(_PREHASH_Stamp, false);
  2895. }
  2896. msg->nextBlockFast(_PREHASH_InventoryData);
  2897. msg->addUUIDFast(_PREHASH_ItemID, (*it));
  2898. msg->addUUIDFast(_PREHASH_FolderID, laf);
  2899. msg->addString("NewName", NULL);
  2900. if (msg->isSendFull(NULL))
  2901. {
  2902. start_new_message = true;
  2903. gAgent.sendReliableMessage();
  2904. }
  2905. }
  2906. if (!start_new_message)
  2907. {
  2908. gAgent.sendReliableMessage();
  2909. }
  2910. }
  2911. const LLUUID& agent_inv_root_id = gInventory.getRootFolderID();
  2912. if (agent_inv_root_id.notNull())
  2913. {
  2914. // 'My Inventory', root of the agent's inventory found. The inventory
  2915. // tree is built.
  2916. mIsAgentInvUsable = true;
  2917. llinfos << "Inventory initialized, notifying observers" << llendl;
  2918. addChangedMask(LLInventoryObserver::ALL, LLUUID::null);
  2919. notifyObservers();
  2920. }
  2921. }
  2922. // Would normally do this at construction but that is too early in the process
  2923. // for gInventory. Have the first requestPost() call set things up.
  2924. void LLInventoryModel::initHttpRequest()
  2925. {
  2926. if (!mHttpRequestFG)
  2927. {
  2928. // Have not initialized, get to it
  2929. LLAppCoreHttp& app_core_http = gAppViewerp->getAppCoreHttp();
  2930. mHttpRequestFG = new LLCore::HttpRequest;
  2931. mHttpRequestBG = new LLCore::HttpRequest;
  2932. mHttpOptions = DEFAULT_HTTP_OPTIONS;
  2933. mHttpOptions->setTransferTimeout(300);
  2934. mHttpOptions->setUseRetryAfter(true);
  2935. #if 0 // Enable to do tracing of requests
  2936. mHttpOptions->setTrace(2);
  2937. #endif
  2938. mHttpHeaders = DEFAULT_HTTP_HEADERS;
  2939. mHttpHeaders->append(HTTP_OUT_HEADER_CONTENT_TYPE,
  2940. HTTP_CONTENT_LLSD_XML);
  2941. mHttpHeaders->append(HTTP_OUT_HEADER_ACCEPT,
  2942. HTTP_CONTENT_LLSD_XML);
  2943. mHttpPolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_INVENTORY);
  2944. }
  2945. if (!gGenericDispatcher.isHandlerPresent(_PREHASH_BulkUpdateInventory))
  2946. {
  2947. gGenericDispatcher.addHandler(_PREHASH_BulkUpdateInventory,
  2948. &sBulkUpdateInventory);
  2949. }
  2950. }
  2951. void LLInventoryModel::handleResponses(bool foreground)
  2952. {
  2953. if (foreground && mHttpRequestFG)
  2954. {
  2955. mHttpRequestFG->update(0);
  2956. }
  2957. else if (!foreground && mHttpRequestBG)
  2958. {
  2959. mHttpRequestBG->update(50000L);
  2960. }
  2961. }
  2962. LLCore::HttpHandle LLInventoryModel::requestPost(bool foreground,
  2963. const std::string& url,
  2964. const LLSD& body,
  2965. const LLCore::HttpHandler::ptr_t& handler,
  2966. const char* message)
  2967. {
  2968. if (!mHttpRequestFG)
  2969. {
  2970. // We do the initialization late and lazily as this class is statically
  2971. // constructed and not all the bits are ready at that time.
  2972. initHttpRequest();
  2973. }
  2974. LLCore::HttpRequest* request = foreground ? mHttpRequestFG
  2975. : mHttpRequestBG;
  2976. LLCore::HttpHandle handle =
  2977. LLCoreHttpUtil::requestPostWithLLSD(request, mHttpPolicyClass,
  2978. url, body, mHttpOptions,
  2979. mHttpHeaders, handler);
  2980. if (handle == LLCORE_HTTP_HANDLE_INVALID)
  2981. {
  2982. LLCore::HttpStatus status = request->getStatus();
  2983. llwarns << "HTTP POST request failed for " << message
  2984. << " - Status: " << status.toTerseString() << " - Reason: '"
  2985. << status.toString() << "'" << llendl;
  2986. }
  2987. return handle;
  2988. }
  2989. //static
  2990. bool LLInventoryModel::loadFromFile(const std::string& filename,
  2991. LLInventoryModel::cat_array_t& categories,
  2992. LLInventoryModel::item_array_t& items,
  2993. uuid_list_t& cats_to_update,
  2994. bool& is_cache_obsolete)
  2995. {
  2996. // Cache is considered obsolete until proven current
  2997. is_cache_obsolete = true;
  2998. if (filename.empty())
  2999. {
  3000. llerrs << "Filename is empty !" << llendl;
  3001. return false;
  3002. }
  3003. llinfos << "Loading cached inventory from file: " << filename << llendl;
  3004. llifstream file(filename.c_str());
  3005. if (!file.is_open())
  3006. {
  3007. llinfos << "Unable to load inventory from: " << filename << llendl;
  3008. return false;
  3009. }
  3010. std::string line;
  3011. LLPointer<LLSDParser> parser(new LLSDNotationParser);
  3012. while (std::getline(file, line))
  3013. {
  3014. LLSD s_item;
  3015. std::istringstream iss(line);
  3016. if (parser->parse(iss, s_item,
  3017. line.length()) == LLSDParser::PARSE_FAILURE)
  3018. {
  3019. llwarns << "Parsing inventory cache failed, line:\n" << line
  3020. << llendl;
  3021. continue;
  3022. }
  3023. if (s_item.has("inv_cache_version"))
  3024. {
  3025. S32 version = s_item["inv_cache_version"].asInteger();
  3026. if (version == INVENTORY_CACHE_VERSION)
  3027. {
  3028. // Cache is up to date
  3029. is_cache_obsolete = false;
  3030. continue;
  3031. }
  3032. else
  3033. {
  3034. // Cache is out of date
  3035. llwarns << "Inventory is outdated" << llendl;
  3036. break;
  3037. }
  3038. }
  3039. if (s_item.has("cat_id"))
  3040. {
  3041. LLPointer<LLViewerInventoryCategory> inv_cat =
  3042. new LLViewerInventoryCategory(LLUUID::null);
  3043. if (inv_cat->importLLSD(s_item))
  3044. {
  3045. categories.emplace_back(inv_cat);
  3046. }
  3047. continue;
  3048. }
  3049. if (s_item.has("item_id"))
  3050. {
  3051. LLPointer<LLViewerInventoryItem> inv_item =
  3052. new LLViewerInventoryItem;
  3053. if (inv_item->fromLLSD(s_item))
  3054. {
  3055. if (inv_item->getUUID().isNull())
  3056. {
  3057. llwarns << "Ignoring inventory with null item id: "
  3058. << inv_item->getName() << llendl;
  3059. }
  3060. else if (inv_item->getType() == LLAssetType::AT_NONE)
  3061. {
  3062. cats_to_update.insert(inv_item->getParentUUID());
  3063. }
  3064. else
  3065. {
  3066. items.emplace_back(inv_item);
  3067. }
  3068. }
  3069. }
  3070. }
  3071. file.close();
  3072. return !is_cache_obsolete;
  3073. }
  3074. //static
  3075. bool LLInventoryModel::saveToFile(const std::string& filename,
  3076. const cat_array_t& categories,
  3077. const item_array_t& items)
  3078. {
  3079. if (filename.empty())
  3080. {
  3081. llerrs << "Filename is empty !" << llendl;
  3082. return false;
  3083. }
  3084. llinfos << "Saving cached inventory to file: " << filename << llendl;
  3085. llofstream file(filename.c_str());
  3086. if (!file.is_open())
  3087. {
  3088. llwarns << "Unable to open file: " << filename << llendl;
  3089. return false;
  3090. }
  3091. LLSD cache_ver;
  3092. cache_ver["inv_cache_version"] = INVENTORY_CACHE_VERSION;
  3093. file << LLSDOStreamer<LLSDNotationFormatter>(cache_ver) << std::endl;
  3094. if (file.fail())
  3095. {
  3096. llwarns << "Failed to write cache version to file. Unable to save inventory to: "
  3097. << filename << llendl;
  3098. return false;
  3099. }
  3100. S32 cat_count = 0;
  3101. for (S32 i = 0, count = categories.size(); i < count; ++i)
  3102. {
  3103. LLViewerInventoryCategory* catp = categories[i];
  3104. if (!catp->isVersionUnknown())
  3105. {
  3106. file << LLSDOStreamer<LLSDNotationFormatter>(catp->exportLLSD())
  3107. << std::endl;
  3108. if (file.fail())
  3109. {
  3110. llwarns << "Failed to write a folder to file. Unable to save inventory to: "
  3111. << filename << llendl;
  3112. return false;
  3113. }
  3114. ++cat_count;
  3115. }
  3116. }
  3117. S32 it_count = items.size();
  3118. for (S32 i = 0; i < it_count; ++i)
  3119. {
  3120. file << LLSDOStreamer<LLSDNotationFormatter>(items[i]->asLLSD())
  3121. << std::endl;
  3122. if (file.fail())
  3123. {
  3124. llwarns << "Failed to write an item to file. Unable to save inventory to: "
  3125. << filename << llendl;
  3126. return false;
  3127. }
  3128. }
  3129. file.close();
  3130. llinfos << "Saved " << it_count << " items in " << cat_count
  3131. << " categories." << llendl;
  3132. return true;
  3133. }
  3134. //----------------------------------------------------------------------------
  3135. // Message handling functionality
  3136. //----------------------------------------------------------------------------
  3137. //static
  3138. void LLInventoryModel::registerCallbacks(LLMessageSystem* msg)
  3139. {
  3140. msg->setHandlerFuncFast(_PREHASH_UpdateCreateInventoryItem,
  3141. processUpdateCreateInventoryItem, NULL);
  3142. msg->setHandlerFuncFast(_PREHASH_RemoveInventoryItem,
  3143. processRemoveInventoryItem, NULL);
  3144. msg->setHandlerFuncFast(_PREHASH_RemoveInventoryFolder,
  3145. processRemoveInventoryFolder, NULL);
  3146. msg->setHandlerFuncFast(_PREHASH_RemoveInventoryObjects,
  3147. processRemoveInventoryObjects, NULL);
  3148. msg->setHandlerFuncFast(_PREHASH_SaveAssetIntoInventory,
  3149. processSaveAssetIntoInventory, NULL);
  3150. msg->setHandlerFuncFast(_PREHASH_BulkUpdateInventory,
  3151. processBulkUpdateInventory, NULL);
  3152. msg->setHandlerFunc(_PREHASH_MoveInventoryItem, processMoveInventoryItem);
  3153. #if 1
  3154. // Note: 2023-10: this was removed from LL's viewer. Verify if still in
  3155. // actual use in OpenSim, or when AISv3 is switched off. HB
  3156. msg->setHandlerFuncFast(_PREHASH_UpdateInventoryFolder,
  3157. processUpdateInventoryFolder, NULL);
  3158. // Note: thees were removed a while ago from LL's viewer. Verify if still
  3159. // in actual use in OpenSim. HB
  3160. msg->setHandlerFunc(_PREHASH_FetchInventoryReply,
  3161. processFetchInventoryReply);
  3162. msg->setHandlerFunc(_PREHASH_InventoryDescendents,
  3163. processInventoryDescendents);
  3164. #endif
  3165. }
  3166. //static
  3167. void LLInventoryModel::processUpdateCreateInventoryItem(LLMessageSystem* msg,
  3168. void**)
  3169. {
  3170. // Do accounting and highlight new items if they arrive
  3171. if (gInventory.messageUpdateCore(msg, true, LLInventoryObserver::CREATE))
  3172. {
  3173. U32 callback_id;
  3174. LLUUID item_id;
  3175. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id);
  3176. msg->getU32Fast(_PREHASH_InventoryData, _PREHASH_CallbackID,
  3177. callback_id);
  3178. gInventoryCallbacks.fire(callback_id, item_id);
  3179. if (LLInventoryModelFetch::useAISFetching())
  3180. {
  3181. // *TODO: instead of unpacking message fully, grab only an item_id,
  3182. // then fetch.
  3183. LLInventoryModelFetch::getInstance()->scheduleItemFetch(item_id,
  3184. true);
  3185. }
  3186. }
  3187. }
  3188. bool LLInventoryModel::messageUpdateCore(LLMessageSystem* msg, bool account,
  3189. U32 mask)
  3190. {
  3191. // NOTE: crashes may happen as a result of the stale calling of this method
  3192. // on logout. So test for the logging out or quitting flags, and abort when
  3193. // any is true. HB.
  3194. if (gLogoutInProgress || LLApp::isQuitting())
  3195. {
  3196. llwarns << "Application is quitting: skipping stale inventory message update."
  3197. << llendl;
  3198. return false;
  3199. }
  3200. LLUUID agent_id;
  3201. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3202. if (agent_id != gAgentID)
  3203. {
  3204. llwarns << "Got an inventory update for the wrong agent: " << agent_id
  3205. << llendl;
  3206. return false;
  3207. }
  3208. item_array_t items;
  3209. update_map_t update;
  3210. S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
  3211. // Does this loop ever execute more than once ?
  3212. for (S32 i = 0; i < count; ++i)
  3213. {
  3214. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  3215. titem->unpackMessage(msg, _PREHASH_InventoryData, i);
  3216. const LLUUID& item_id = titem->getUUID();
  3217. if (item_id.isNull())
  3218. {
  3219. llwarns << "Null item Id, skipping..." << llendl;
  3220. continue;
  3221. }
  3222. const LLUUID& parent_id = titem->getParentUUID();
  3223. LL_DEBUGS("Inventory") << "Processing item id: " << item_id
  3224. << " - parent id: " << parent_id << LL_ENDL;
  3225. items.emplace_back(titem);
  3226. // Examine update for changes.
  3227. LLViewerInventoryItem* itemp = getItem(item_id);
  3228. if (itemp)
  3229. {
  3230. const LLUUID& old_parent_id = itemp->getParentUUID();
  3231. if (parent_id == old_parent_id)
  3232. {
  3233. if (parent_id.notNull())
  3234. {
  3235. update[parent_id];
  3236. }
  3237. else
  3238. {
  3239. llwarns << "Null parent Id for item " << item_id << llendl;
  3240. }
  3241. }
  3242. else
  3243. {
  3244. if (parent_id.notNull())
  3245. {
  3246. ++update[parent_id];
  3247. }
  3248. else
  3249. {
  3250. llwarns << "Null new parent id for item " << item_id
  3251. << llendl;
  3252. }
  3253. if (old_parent_id.notNull())
  3254. {
  3255. --update[old_parent_id];
  3256. }
  3257. else
  3258. {
  3259. llwarns << "Null old parent id for item " << item_id
  3260. << llendl;
  3261. }
  3262. }
  3263. }
  3264. else if (parent_id.notNull())
  3265. {
  3266. ++update[parent_id];
  3267. }
  3268. else
  3269. {
  3270. llwarns << "Null new parent id for non-found item " << item_id
  3271. << llendl;
  3272. }
  3273. }
  3274. if (account)
  3275. {
  3276. accountForUpdate(update);
  3277. mask |= LLInventoryObserver::CREATE;
  3278. }
  3279. // As above, this loop never seems to loop more than once per call
  3280. for (item_array_t::iterator it = items.begin(); it != items.end(); ++it)
  3281. {
  3282. updateItem(*it, mask);
  3283. }
  3284. notifyObservers();
  3285. if (gWindowp)
  3286. {
  3287. gWindowp->decBusyCount();
  3288. }
  3289. return true;
  3290. }
  3291. //static
  3292. void LLInventoryModel::removeInventoryItem(LLUUID agent_id,
  3293. LLMessageSystem* msg,
  3294. const char* msg_label)
  3295. {
  3296. LLUUID item_id;
  3297. S32 count = msg->getNumberOfBlocksFast(msg_label);
  3298. LL_DEBUGS("Inventory") << "Message has " << count << " item blocks"
  3299. << LL_ENDL;
  3300. uuid_vec_t item_ids;
  3301. update_map_t update;
  3302. for (S32 i = 0; i < count; ++i)
  3303. {
  3304. msg->getUUIDFast(msg_label, _PREHASH_ItemID, item_id, i);
  3305. LL_DEBUGS("Inventory") << "Checking for item-to-be-removed " << item_id
  3306. << LL_ENDL;
  3307. LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
  3308. if (itemp)
  3309. {
  3310. LL_DEBUGS("Inventory") << "Item will be removed " << item_id
  3311. << LL_ENDL;
  3312. // We only bother with the delete and account if we found the item:
  3313. // this is usually a back-up for permissions, so frequently the
  3314. // item will already be gone.
  3315. const LLUUID& parent_id = itemp->getParentUUID();
  3316. if (parent_id.notNull())
  3317. {
  3318. --update[parent_id];
  3319. }
  3320. else
  3321. {
  3322. llwarns << "Null parent Id for item " << item_id << llendl;
  3323. }
  3324. item_ids.emplace_back(item_id);
  3325. }
  3326. }
  3327. gInventory.accountForUpdate(update);
  3328. for (U32 i = 0, count = item_ids.size(); i < count; ++i)
  3329. {
  3330. const LLUUID& item_id = item_ids[i];
  3331. LL_DEBUGS("Inventory") << "Calling deleteObject " << item_id << LL_ENDL;
  3332. gInventory.deleteObject(item_id);
  3333. }
  3334. }
  3335. //static
  3336. void LLInventoryModel::processRemoveInventoryItem(LLMessageSystem* msg, void**)
  3337. {
  3338. LLUUID agent_id, item_id;
  3339. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3340. if (agent_id != gAgentID)
  3341. {
  3342. llwarns << "Got a RemoveInventoryItem for the wrong agent."
  3343. << llendl;
  3344. return;
  3345. }
  3346. removeInventoryItem(agent_id, msg, _PREHASH_InventoryData);
  3347. gInventory.notifyObservers();
  3348. }
  3349. #if 1 // Note: this was removed from LL's viewer a while ago. Verify if still
  3350. // in actual use in OpenSim. HB
  3351. //static
  3352. void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg,
  3353. void**)
  3354. {
  3355. // Warn once, so that we can notice its continued usage...
  3356. llwarns_once << "This supposedly deprecated callback got called !!!"
  3357. << llendl;
  3358. LLUUID agent_id, folder_id, parent_id;
  3359. //char name[DB_INV_ITEM_NAME_BUF_SIZE];
  3360. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
  3361. if (agent_id != gAgentID)
  3362. {
  3363. llwarns << "Got an UpdateInventoryFolder for the wrong agent."
  3364. << llendl;
  3365. return;
  3366. }
  3367. //MK
  3368. bool check_rlv_share =
  3369. gRLenabled && gRLInterface.getRlvShare() &&
  3370. !gSavedSettings.getBool("RestrainedLoveForbidGiveToRLV");
  3371. std::vector<LLPointer<LLViewerInventoryCategory> > folders_to_move;
  3372. //mk
  3373. LLPointer<LLViewerInventoryCategory> lastfolder; // *HACK part 1
  3374. cat_array_t folders;
  3375. update_map_t update;
  3376. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  3377. for (S32 i = 0; i < count; ++i)
  3378. {
  3379. LLPointer<LLViewerInventoryCategory> tfolder =
  3380. new LLViewerInventoryCategory(gAgentID);
  3381. lastfolder = tfolder;
  3382. tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
  3383. // Make sure it is not a protected folder
  3384. tfolder->setPreferredType(LLFolderType::FT_NONE);
  3385. folders.emplace_back(tfolder);
  3386. const LLUUID& parent_id = tfolder->getParentUUID();
  3387. LLViewerInventoryCategory* folderp = gInventory.getCategory(parent_id);
  3388. const LLUUID& new_folder_id = tfolder->getUUID();
  3389. // Examine update for changes.
  3390. if (folderp)
  3391. {
  3392. const LLUUID& old_parent_id = folderp->getParentUUID();
  3393. if (parent_id == old_parent_id)
  3394. {
  3395. if (parent_id.notNull())
  3396. {
  3397. update[parent_id];
  3398. }
  3399. else
  3400. {
  3401. llwarns << "Null parent Id for folder " << new_folder_id
  3402. << llendl;
  3403. }
  3404. }
  3405. else
  3406. {
  3407. if (parent_id.notNull())
  3408. {
  3409. ++update[parent_id];
  3410. }
  3411. else
  3412. {
  3413. llwarns << "Null new parent Id for folder "
  3414. << new_folder_id << llendl;
  3415. }
  3416. if (old_parent_id.notNull())
  3417. {
  3418. --update[old_parent_id];
  3419. }
  3420. else
  3421. {
  3422. llwarns << "Null old parent Id for folder "
  3423. << new_folder_id << llendl;
  3424. }
  3425. }
  3426. }
  3427. else if (parent_id.notNull())
  3428. {
  3429. ++update[parent_id];
  3430. }
  3431. else
  3432. {
  3433. llwarns << "Null parent Id for non-found folder "
  3434. << new_folder_id << llendl;
  3435. }
  3436. //MK
  3437. if (check_rlv_share &&
  3438. gRLInterface.shouldMoveToSharedSubFolder(tfolder))
  3439. {
  3440. folders_to_move.emplace_back(tfolder);
  3441. }
  3442. //mk
  3443. }
  3444. gInventory.accountForUpdate(update);
  3445. for (cat_array_t::iterator it = folders.begin(); it != folders.end(); ++it)
  3446. {
  3447. gInventory.updateCategory(*it);
  3448. }
  3449. gInventory.notifyObservers();
  3450. //MK
  3451. for (U32 i = 0, count = folders_to_move.size(); i < count; ++i)
  3452. {
  3453. gRLInterface.moveToSharedSubFolder(folders_to_move[i].get());
  3454. }
  3455. //mk
  3456. // *HACK part 2: Do the 'show' logic for a new item in the inventory.
  3457. LLFloaterInventory* inv = LLFloaterInventory::getActiveFloater();
  3458. if (inv)
  3459. {
  3460. inv->getPanel()->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO);
  3461. }
  3462. }
  3463. #endif
  3464. //static
  3465. void LLInventoryModel::removeInventoryFolder(LLUUID agent_id,
  3466. LLMessageSystem* msg)
  3467. {
  3468. LLUUID folder_id;
  3469. uuid_vec_t folder_ids;
  3470. update_map_t update;
  3471. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  3472. for (S32 i = 0; i < count; ++i)
  3473. {
  3474. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, folder_id, i);
  3475. LLViewerInventoryCategory* folderp = gInventory.getCategory(folder_id);
  3476. if (folderp)
  3477. {
  3478. const LLUUID& parent_id = folderp->getParentUUID();
  3479. if (parent_id.notNull())
  3480. {
  3481. --update[parent_id];
  3482. }
  3483. else
  3484. {
  3485. llwarns << "Null parent Id for folder " << folder_id << llendl;
  3486. }
  3487. folder_ids.emplace_back(folder_id);
  3488. }
  3489. }
  3490. gInventory.accountForUpdate(update);
  3491. for (U32 i = 0, count = folder_ids.size(); i < count; ++i)
  3492. {
  3493. const LLUUID& cat_id = folder_ids[i];
  3494. LL_DEBUGS("Inventory") << "Calling deleteObject " << cat_id << LL_ENDL;
  3495. gInventory.deleteObject(cat_id);
  3496. }
  3497. }
  3498. //static
  3499. void LLInventoryModel::processRemoveInventoryFolder(LLMessageSystem* msg,
  3500. void**)
  3501. {
  3502. LLUUID agent_id, folder_id;
  3503. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_AgentID, agent_id);
  3504. if (agent_id != gAgentID)
  3505. {
  3506. llwarns << "Got a RemoveInventoryFolder for the wrong agent."
  3507. << llendl;
  3508. return;
  3509. }
  3510. removeInventoryFolder(agent_id, msg);
  3511. gInventory.notifyObservers();
  3512. }
  3513. //static
  3514. void LLInventoryModel::processRemoveInventoryObjects(LLMessageSystem* msg,
  3515. void**)
  3516. {
  3517. LLUUID agent_id, session_id;
  3518. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3519. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
  3520. LL_DEBUGS("Inventory") << "Remove inventory objects: " << session_id
  3521. << LL_ENDL;
  3522. if (agent_id != gAgentID)
  3523. {
  3524. llwarns << "Got a RemoveInventoryObjects for the wrong agent."
  3525. << llendl;
  3526. return;
  3527. }
  3528. removeInventoryFolder(agent_id, msg);
  3529. removeInventoryItem(agent_id, msg, _PREHASH_ItemData);
  3530. gInventory.notifyObservers();
  3531. }
  3532. //static
  3533. void LLInventoryModel::processSaveAssetIntoInventory(LLMessageSystem* msg,
  3534. void**)
  3535. {
  3536. LLUUID agent_id;
  3537. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3538. if (agent_id != gAgentID)
  3539. {
  3540. llwarns << "Got a SaveAssetIntoInventory message for the wrong agent."
  3541. << llendl;
  3542. return;
  3543. }
  3544. LLUUID item_id;
  3545. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id);
  3546. // The viewer ignores the asset id because this message is only used for
  3547. // attachments/objects, so the asset id is not used in the viewer anyway.
  3548. LL_DEBUGS("Inventory") << "Processing itemID = " << item_id << LL_ENDL;
  3549. LLViewerInventoryItem* item = gInventory.getItem(item_id);
  3550. if (item)
  3551. {
  3552. LLCategoryUpdate up(item->getParentUUID(), 0);
  3553. gInventory.accountForUpdate(up);
  3554. gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
  3555. gInventory.notifyObservers();
  3556. }
  3557. else
  3558. {
  3559. llinfos << "Item not found: " << item_id << llendl;
  3560. }
  3561. if (gViewerWindowp)
  3562. {
  3563. gWindowp->decBusyCount();
  3564. }
  3565. }
  3566. //static
  3567. void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**)
  3568. {
  3569. LLUUID agent_id;
  3570. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3571. if (agent_id != gAgentID)
  3572. {
  3573. llwarns << "Got a BulkUpdateInventory for the wrong agent." << llendl;
  3574. return;
  3575. }
  3576. LLUUID tid;
  3577. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, tid);
  3578. LL_DEBUGS("Inventory") << "Bulk inventory: " << tid << LL_ENDL;
  3579. //MK
  3580. bool check_rlv_share =
  3581. gRLenabled && gRLInterface.getRlvShare() &&
  3582. !gSavedSettings.getBool("RestrainedLoveForbidGiveToRLV");
  3583. std::vector<LLPointer<LLViewerInventoryCategory> > folders_to_move;
  3584. //mk
  3585. update_map_t update;
  3586. cat_array_t folders;
  3587. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  3588. for (S32 i = 0; i < count; ++i)
  3589. {
  3590. LLPointer<LLViewerInventoryCategory> tfolder =
  3591. new LLViewerInventoryCategory(gAgentID);
  3592. tfolder->unpackMessage(msg, _PREHASH_FolderData, i);
  3593. const LLUUID& folder_id = tfolder->getUUID();
  3594. if (folder_id.isNull())
  3595. {
  3596. LL_DEBUGS("Inventory") << "Null folder Id, skipping." << LL_ENDL;
  3597. continue;
  3598. }
  3599. const LLUUID& parent_id = tfolder->getParentUUID();
  3600. LL_DEBUGS("Inventory") << "Unpacked folder '" << tfolder->getName()
  3601. << "' (" << folder_id << ") in " << parent_id
  3602. << LL_ENDL;
  3603. // If the folder is a listing or a version folder, all we need to do is
  3604. // to update the SLM data
  3605. if (LLMarketplace::updateIfListed(folder_id, parent_id))
  3606. {
  3607. // In that case, there is no item to update so no callback, so we
  3608. // skip the rest of the update
  3609. continue;
  3610. }
  3611. LLViewerInventoryCategory* folderp = gInventory.getCategory(parent_id);
  3612. folders.emplace_back(tfolder);
  3613. if (folderp)
  3614. {
  3615. const LLUUID& old_parent_id = folderp->getParentUUID();
  3616. if (folderp->isVersionUnknown())
  3617. {
  3618. folderp->fetch();
  3619. }
  3620. else if (parent_id == old_parent_id)
  3621. {
  3622. if (parent_id.notNull())
  3623. {
  3624. update[parent_id];
  3625. }
  3626. else
  3627. {
  3628. llwarns << "Null parent Id for folder " << folder_id
  3629. << llendl;
  3630. }
  3631. }
  3632. else
  3633. {
  3634. if (parent_id.notNull())
  3635. {
  3636. ++update[parent_id];
  3637. }
  3638. else
  3639. {
  3640. llwarns << "Null new parent Id for folder " << folder_id
  3641. << llendl;
  3642. }
  3643. if (old_parent_id.notNull())
  3644. {
  3645. --update[old_parent_id];
  3646. }
  3647. else
  3648. {
  3649. llwarns << "Null old parent Id for folder " << folder_id
  3650. << llendl;
  3651. }
  3652. }
  3653. }
  3654. else if (parent_id.notNull())
  3655. {
  3656. // We could not find the folder, so it is probably new.
  3657. // However, we only want to attempt accounting for the parent
  3658. // if we can find the parent.
  3659. folderp = gInventory.getCategory(parent_id);
  3660. if (folderp)
  3661. {
  3662. if (folderp->isVersionUnknown())
  3663. {
  3664. folderp->fetch();
  3665. }
  3666. else
  3667. {
  3668. ++update[parent_id];
  3669. }
  3670. }
  3671. }
  3672. else
  3673. {
  3674. llwarns << "Null new parent Id for non-found folder " << folder_id
  3675. << llendl;
  3676. }
  3677. //MK
  3678. if (check_rlv_share &&
  3679. gRLInterface.shouldMoveToSharedSubFolder(tfolder))
  3680. {
  3681. folders_to_move.emplace_back(tfolder);
  3682. }
  3683. //mk
  3684. }
  3685. count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
  3686. uuid_vec_t wearable_ids;
  3687. item_array_t items;
  3688. typedef std::list<InventoryCallbackInfo> cblist_t;
  3689. cblist_t callback_list;
  3690. for (S32 i = 0; i < count; ++i)
  3691. {
  3692. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  3693. titem->unpackMessage(msg, _PREHASH_ItemData, i);
  3694. const LLUUID& item_id = titem->getUUID();
  3695. const LLUUID& parent_id = titem->getParentUUID();
  3696. LL_DEBUGS("Inventory") << "Unpacked item '" << titem->getName()
  3697. << "' in " << parent_id << LL_ENDL;
  3698. U32 callback_id;
  3699. msg->getU32Fast(_PREHASH_ItemData, _PREHASH_CallbackID, callback_id);
  3700. if (item_id.isNull())
  3701. {
  3702. llwarns << "Null item Id, skipping..." << llendl;
  3703. continue;
  3704. }
  3705. items.emplace_back(titem);
  3706. if (titem->getInventoryType() == LLInventoryType::IT_WEARABLE)
  3707. {
  3708. wearable_ids.emplace_back(item_id);
  3709. }
  3710. callback_list.emplace_back(callback_id, item_id);
  3711. // Examine update for changes.
  3712. LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
  3713. if (itemp)
  3714. {
  3715. const LLUUID& old_parent_id = itemp->getParentUUID();
  3716. if (parent_id == old_parent_id)
  3717. {
  3718. if (parent_id.notNull())
  3719. {
  3720. update[parent_id];
  3721. }
  3722. else
  3723. {
  3724. llwarns << "Null parent Id for item " << item_id << llendl;
  3725. }
  3726. }
  3727. else
  3728. {
  3729. if (parent_id.notNull())
  3730. {
  3731. ++update[parent_id];
  3732. }
  3733. else
  3734. {
  3735. llwarns << "Null new parent Id for item " << item_id
  3736. << llendl;
  3737. }
  3738. if (old_parent_id.notNull())
  3739. {
  3740. --update[old_parent_id];
  3741. }
  3742. else
  3743. {
  3744. llwarns << "Null old parent Id for item " << item_id
  3745. << llendl;
  3746. }
  3747. }
  3748. }
  3749. else
  3750. {
  3751. LLViewerInventoryCategory* folderp =
  3752. gInventory.getCategory(parent_id);
  3753. if (folderp)
  3754. {
  3755. ++update[parent_id];
  3756. }
  3757. }
  3758. }
  3759. LLInventoryModelFetch* fetcherp = NULL;
  3760. if (LLInventoryModelFetch::useAISFetching())
  3761. {
  3762. fetcherp = LLInventoryModelFetch::getInstance();
  3763. }
  3764. gInventory.accountForUpdate(update);
  3765. for (cat_array_t::iterator it = folders.begin(), end = folders.end();
  3766. it != end; ++it)
  3767. {
  3768. gInventory.updateCategory(*it);
  3769. if (fetcherp)
  3770. {
  3771. // Temporary workaround: just fetch the item using AIS to get the
  3772. // missing fields. If this works fine we might want to extract Ids
  3773. // only from the message then use AIS as a primary fetcher.
  3774. fetcherp->scheduleFolderFetch((*it)->getUUID(), true);
  3775. }
  3776. }
  3777. for (item_array_t::iterator it = items.begin(), end = items.end();
  3778. it != end; ++it)
  3779. {
  3780. gInventory.updateItem(*it);
  3781. if (fetcherp)
  3782. {
  3783. // Temporary workaround: just fetch the item using AIS to get the
  3784. // missing fields. If this works fine we might want to extract Ids
  3785. // only from the message then use AIS as a primary fetcher.
  3786. fetcherp->scheduleItemFetch((*it)->getUUID(), true);
  3787. }
  3788. }
  3789. gInventory.notifyObservers();
  3790. // The incoming inventory could span more than one BulkInventoryUpdate
  3791. // packet, so record the transaction ID for this purchase, then wear all
  3792. // clothing that comes in as part of that transaction ID. JC
  3793. if (sWearNewClothing)
  3794. {
  3795. sWearNewClothingTransactionID = tid;
  3796. sWearNewClothing = false;
  3797. }
  3798. if (tid.notNull() && tid == sWearNewClothingTransactionID)
  3799. {
  3800. for (S32 i = 0, count = wearable_ids.size(); i < count; ++i)
  3801. {
  3802. LLViewerInventoryItem* wearablep =
  3803. gInventory.getItem(wearable_ids[i]);
  3804. if (wearablep)
  3805. {
  3806. gAppearanceMgr.wearInventoryItemOnAvatar(wearablep, true);
  3807. }
  3808. }
  3809. }
  3810. for (cblist_t::const_iterator it = callback_list.begin(),
  3811. end = callback_list.end();
  3812. it != end; ++it)
  3813. {
  3814. const InventoryCallbackInfo& cbinfo = *it;
  3815. gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID);
  3816. }
  3817. //MK
  3818. for (U32 i = 0, count = folders_to_move.size(); i < count; ++i)
  3819. {
  3820. gRLInterface.moveToSharedSubFolder(folders_to_move[i].get());
  3821. }
  3822. //mk
  3823. }
  3824. #if 1 // Note: this was removed from LL's viewer a while ago. Verify if still
  3825. // in actual use in OpenSim. HB
  3826. //static
  3827. void LLInventoryModel::processFetchInventoryReply(LLMessageSystem* msg, void**)
  3828. {
  3829. llwarns_once << "This supposedly deprecated callback got called !!!"
  3830. << llendl;
  3831. // No accounting
  3832. gInventory.messageUpdateCore(msg, false);
  3833. }
  3834. //static
  3835. void LLInventoryModel::processInventoryDescendents(LLMessageSystem* msg,
  3836. void**)
  3837. {
  3838. if (!msg) return;
  3839. llwarns_once << "This supposedly deprecated callback got called !!!"
  3840. << llendl;
  3841. LLUUID agent_id;
  3842. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3843. if (agent_id != gAgentID)
  3844. {
  3845. llwarns << "Got a UpdateInventoryItem for the wrong agent." << llendl;
  3846. return;
  3847. }
  3848. LLUUID parent_id;
  3849. msg->getUUID(_PREHASH_AgentData, _PREHASH_FolderID, parent_id);
  3850. LLUUID owner_id;
  3851. msg->getUUID(_PREHASH_AgentData, _PREHASH_OwnerID, owner_id);
  3852. S32 version;
  3853. msg->getS32(_PREHASH_AgentData, _PREHASH_Version, version);
  3854. S32 descendents;
  3855. msg->getS32(_PREHASH_AgentData, _PREHASH_Descendents, descendents);
  3856. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  3857. LLPointer<LLViewerInventoryCategory> tcategory =
  3858. new LLViewerInventoryCategory(owner_id);
  3859. for (S32 i = 0; i < count; ++i)
  3860. {
  3861. tcategory->unpackMessage(msg, _PREHASH_FolderData, i);
  3862. gInventory.updateCategory(tcategory);
  3863. }
  3864. count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
  3865. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  3866. for (S32 i = 0; i < count; ++i)
  3867. {
  3868. titem->unpackMessage(msg, _PREHASH_ItemData, i);
  3869. // If the item has already been added (e.g. from link prefetch),
  3870. // then it doesn't need to be re-added.
  3871. if (gInventory.getItem(titem->getUUID()))
  3872. {
  3873. LL_DEBUGS("Inventory") << "Skipping prefetched item [ Name: "
  3874. << titem->getName() << " | Type: "
  3875. << titem->getActualType()
  3876. << " | ItemUUID: " << titem->getUUID()
  3877. << " ] " << LL_ENDL;
  3878. continue;
  3879. }
  3880. gInventory.updateItem(titem);
  3881. }
  3882. // Set version and descendentcount according to message.
  3883. LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
  3884. if (cat)
  3885. {
  3886. cat->setVersion(version);
  3887. cat->setDescendentCount(descendents);
  3888. // Get this UUID on the changed list so that whatever's listening for
  3889. // it will get triggered.
  3890. gInventory.addChangedMask(LLInventoryObserver::INTERNAL,
  3891. cat->getUUID());
  3892. }
  3893. gInventory.notifyObservers();
  3894. }
  3895. #endif
  3896. //static
  3897. void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**)
  3898. {
  3899. if (!msg) return;
  3900. LLUUID agent_id;
  3901. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
  3902. if (agent_id != gAgentID)
  3903. {
  3904. llwarns << "Got a MoveInventoryItem message for the wrong agent."
  3905. << llendl;
  3906. return;
  3907. }
  3908. LLUUID item_id;
  3909. LLUUID folder_id;
  3910. std::string new_name;
  3911. bool anything_changed = false;
  3912. S32 count = msg->getNumberOfBlocksFast(_PREHASH_InventoryData);
  3913. for (S32 i = 0; i < count; ++i)
  3914. {
  3915. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_ItemID, item_id, i);
  3916. LLViewerInventoryItem* item = gInventory.getItem(item_id);
  3917. if (item)
  3918. {
  3919. LLPointer<LLViewerInventoryItem> new_item =
  3920. new LLViewerInventoryItem(item);
  3921. msg->getUUIDFast(_PREHASH_InventoryData, _PREHASH_FolderID,
  3922. folder_id, i);
  3923. msg->getString("InventoryData", "NewName", new_name, i);
  3924. LL_DEBUGS("Inventory") << "moving item " << item_id
  3925. << " to folder " << folder_id << LL_ENDL;
  3926. update_list_t update;
  3927. // Old folder - 1 item
  3928. update.emplace_back(item->getParentUUID(), -1);
  3929. // New folder + 1 item
  3930. update.emplace_back(folder_id, 1);
  3931. gInventory.accountForUpdate(update);
  3932. new_item->setParent(folder_id);
  3933. if (new_name.length() > 0)
  3934. {
  3935. new_item->rename(new_name);
  3936. }
  3937. gInventory.updateItem(new_item);
  3938. anything_changed = true;
  3939. }
  3940. else
  3941. {
  3942. llinfos << "Item not found: " << item_id << llendl;
  3943. }
  3944. }
  3945. if (anything_changed)
  3946. {
  3947. gInventory.notifyObservers();
  3948. }
  3949. }
  3950. //----------------------------------------------------------------------------
  3951. // *NOTE: DEBUG functionality
  3952. void LLInventoryModel::dumpInventory()
  3953. {
  3954. llinfos << "\nBegin Inventory Dump\n**********************:" << llendl;
  3955. llinfos << "mCategroy[] contains " << mCategoryMap.size() << " items."
  3956. << llendl;
  3957. for (cat_map_t::iterator cit = mCategoryMap.begin();
  3958. cit != mCategoryMap.end(); ++cit)
  3959. {
  3960. LLViewerInventoryCategory* cat = cit->second;
  3961. if (cat)
  3962. {
  3963. llinfos << " " << cat->getUUID() << " '"
  3964. << cat->getName() << "' "
  3965. << cat->getVersion() << " "
  3966. << cat->getDescendentCount() << " parent: "
  3967. << cat->getParentUUID() << llendl;
  3968. }
  3969. else
  3970. {
  3971. llinfos << " NULL category !" << llendl;
  3972. }
  3973. }
  3974. llinfos << "mItemMap[] contains " << mItemMap.size() << " items."
  3975. << llendl;
  3976. for (item_map_t::iterator iit = mItemMap.begin(); iit != mItemMap.end();
  3977. ++iit)
  3978. {
  3979. LLViewerInventoryItem* item = iit->second;
  3980. if (item)
  3981. {
  3982. llinfos << " " << item->getUUID() << " " << item->getName()
  3983. << " (asset Id: " << item->getAssetUUID() << ")" << llendl;
  3984. }
  3985. else
  3986. {
  3987. llinfos << " NULL item !" << llendl;
  3988. }
  3989. }
  3990. llinfos << "\n**********************\nEnd Inventory Dump" << llendl;
  3991. }
  3992. void LLInventoryModel::removeItem(const LLUUID& item_id)
  3993. {
  3994. const LLUUID& new_parent = getTrashID();
  3995. LLViewerInventoryItem* item = item_id.notNull() ? getItem(item_id) : NULL;
  3996. if (item && new_parent.notNull())
  3997. {
  3998. changeItemParent(item, new_parent, true);
  3999. }
  4000. }
  4001. void LLInventoryModel::removeCategory(const LLUUID& category_id)
  4002. {
  4003. if (category_id.isNull()) return;
  4004. // Look for previews or gestures and deactivate them
  4005. LLInventoryModel::cat_array_t descendent_categories;
  4006. LLInventoryModel::item_array_t descendent_items;
  4007. gInventory.collectDescendents(category_id, descendent_categories,
  4008. descendent_items, false);
  4009. for (S32 i = 0, count = descendent_items.size(); i < count; ++i)
  4010. {
  4011. LLInventoryItem* item = descendent_items[i];
  4012. if (!item) continue; // Paranoia
  4013. const LLUUID& item_id = item->getUUID();
  4014. // Hide any preview
  4015. LLPreview::hide(item_id, true);
  4016. if (item->getType() == LLAssetType::AT_SETTINGS)
  4017. {
  4018. gGestureManager.deactivateGesture(item_id);
  4019. }
  4020. else if (item->getType() == LLAssetType::AT_GESTURE &&
  4021. gGestureManager.isGestureActive(item_id))
  4022. {
  4023. gGestureManager.deactivateGesture(item_id);
  4024. }
  4025. }
  4026. // Go ahead and remove the category now (i.e. move it to the trash)
  4027. LLViewerInventoryCategory* cat = getCategory(category_id);
  4028. if (cat)
  4029. {
  4030. const LLUUID& trash_id = getTrashID();
  4031. if (trash_id.notNull())
  4032. {
  4033. changeCategoryParent(cat, trash_id, true);
  4034. }
  4035. }
  4036. }
  4037. bool trash_full_callback(const LLSD& notification, const LLSD& response)
  4038. {
  4039. if (LLNotification::getSelectedOption(notification, response) == 0)
  4040. {
  4041. const LLUUID& trash_id = gInventory.getTrashID();
  4042. if (trash_id.notNull())
  4043. {
  4044. purge_descendents_of(trash_id, NULL);
  4045. }
  4046. }
  4047. return false;
  4048. }
  4049. void LLInventoryModel::checkTrashOverflow()
  4050. {
  4051. static LLCachedControl<U32> max_capacity(gSavedSettings,
  4052. "InventoryTrashMaxCapacity");
  4053. static bool warned = false;
  4054. if (warned) return;
  4055. LLInventoryModel::cat_array_t cats;
  4056. LLInventoryModel::item_array_t items;
  4057. collectDescendents(getTrashID(), cats, items,
  4058. LLInventoryModel::INCLUDE_TRASH);
  4059. if (items.size() + cats.size() >= (size_t)max_capacity)
  4060. {
  4061. warned = true; // Do not spam user if they elect not to purge trash
  4062. gNotifications.add("TrashIsFull", LLSD(), LLSD(),
  4063. boost::bind(&trash_full_callback, _1, _2));
  4064. }
  4065. }
  4066. void LLInventoryModel::setRootFolderID(const LLUUID& val)
  4067. {
  4068. mRootFolderID = val;
  4069. }
  4070. void LLInventoryModel::setLibraryRootFolderID(const LLUUID& val)
  4071. {
  4072. mLibraryRootFolderID = val;
  4073. }
  4074. void LLInventoryModel::setLibraryOwnerID(const LLUUID& val)
  4075. {
  4076. mLibraryOwnerID = val;
  4077. }
  4078. const LLUUID& LLInventoryModel::getTrashID()
  4079. {
  4080. if (mTrashID.isNull())
  4081. {
  4082. mTrashID = findCategoryUUIDForType(LLFolderType::FT_TRASH);
  4083. }
  4084. return mTrashID;
  4085. }
  4086. const LLUUID& LLInventoryModel::getLostAndFoundID()
  4087. {
  4088. if (mLostAndFoundID.isNull())
  4089. {
  4090. mLostAndFoundID =
  4091. findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
  4092. }
  4093. return mLostAndFoundID;
  4094. }
  4095. //----------------------------------------------------------------------------
  4096. // LLInventoryCollectFunctor implementations
  4097. //----------------------------------------------------------------------------
  4098. //static
  4099. bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* item)
  4100. {
  4101. if (!item)
  4102. {
  4103. return false;
  4104. }
  4105. switch (item->getType())
  4106. {
  4107. case LLAssetType::AT_OBJECT:
  4108. {
  4109. if (isAgentAvatarValid() &&
  4110. !gAgentAvatarp->isWearingAttachment(item->getUUID()))
  4111. {
  4112. return true;
  4113. }
  4114. break;
  4115. }
  4116. case LLAssetType::AT_BODYPART:
  4117. case LLAssetType::AT_CLOTHING:
  4118. {
  4119. if (!gAgentWearables.isWearingItem(item->getUUID()))
  4120. {
  4121. return true;
  4122. }
  4123. break;
  4124. }
  4125. default:
  4126. break;
  4127. }
  4128. return true;
  4129. }
  4130. bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  4131. {
  4132. if (cat && mType == LLAssetType::AT_CATEGORY)
  4133. {
  4134. return true;
  4135. }
  4136. return item ? item->getType() == mType : false;
  4137. }
  4138. bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
  4139. {
  4140. if (cat && mType == LLAssetType::AT_CATEGORY)
  4141. {
  4142. return false;
  4143. }
  4144. return item ? item->getType() != mType : true;
  4145. }
  4146. bool LLIsTypeWithPermissions::operator()(LLInventoryCategory* cat,
  4147. LLInventoryItem* item)
  4148. {
  4149. if (cat && mType == LLAssetType::AT_CATEGORY)
  4150. {
  4151. return true;
  4152. }
  4153. if (item && item->getType() == mType)
  4154. {
  4155. LLPermissions perm = item->getPermissions();
  4156. if ((perm.getMaskBase() & mPerm) == mPerm)
  4157. {
  4158. return true;
  4159. }
  4160. }
  4161. return false;
  4162. }
  4163. bool LLBuddyCollector::operator()(LLInventoryCategory*,
  4164. LLInventoryItem* item)
  4165. {
  4166. return get_calling_card_buddy_id((LLViewerInventoryItem*)item).notNull();
  4167. }
  4168. bool LLUniqueBuddyCollector::operator()(LLInventoryCategory*,
  4169. LLInventoryItem* item)
  4170. {
  4171. LLUUID buddy_id = get_calling_card_buddy_id((LLViewerInventoryItem*)item);
  4172. if (buddy_id.isNull() || mFoundIds.count(buddy_id))
  4173. {
  4174. return false;
  4175. }
  4176. mFoundIds.emplace(buddy_id);
  4177. return true;
  4178. }
  4179. bool LLParticularBuddyCollector::operator()(LLInventoryCategory*,
  4180. LLInventoryItem* item)
  4181. {
  4182. return item && item->getType() == LLAssetType::AT_CALLINGCARD &&
  4183. (item->getCreatorUUID() == mBuddyID ||
  4184. item->getDescription() == mBuddyID.asString());
  4185. }
  4186. bool LLNameCategoryCollector::operator()(LLInventoryCategory* cat,
  4187. LLInventoryItem* item)
  4188. {
  4189. return cat && !LLStringUtil::compareInsensitive(mName, cat->getName());
  4190. }
  4191. //----------------------------------------------------------------------------
  4192. // LLInventoryCompletionObserver class
  4193. //----------------------------------------------------------------------------
  4194. void LLInventoryCompletionObserver::changed(U32 mask)
  4195. {
  4196. // Scan through the incomplete items and move or erase them as appropriate.
  4197. if (!mIncomplete.empty())
  4198. {
  4199. for (uuid_vec_t::iterator it = mIncomplete.begin();
  4200. it < mIncomplete.end(); )
  4201. {
  4202. LLViewerInventoryItem* item = gInventory.getItem(*it);
  4203. if (!item)
  4204. {
  4205. it = mIncomplete.erase(it);
  4206. continue;
  4207. }
  4208. if (item->isFinished())
  4209. {
  4210. mComplete.emplace_back(*it);
  4211. it = mIncomplete.erase(it);
  4212. continue;
  4213. }
  4214. ++it;
  4215. }
  4216. if (mIncomplete.empty())
  4217. {
  4218. done();
  4219. }
  4220. }
  4221. }
  4222. void LLInventoryCompletionObserver::watchItem(const LLUUID& id)
  4223. {
  4224. if (id.notNull())
  4225. {
  4226. mIncomplete.emplace_back(id);
  4227. }
  4228. }
  4229. //----------------------------------------------------------------------------
  4230. // LLInventoryFetchObserver class
  4231. //----------------------------------------------------------------------------
  4232. void LLInventoryFetchObserver::changed(U32 mask)
  4233. {
  4234. // Scan through the incomplete items and move or erase them as
  4235. // appropriate.
  4236. if (!mIncomplete.empty())
  4237. {
  4238. for (uuid_vec_t::iterator it = mIncomplete.begin();
  4239. it < mIncomplete.end(); )
  4240. {
  4241. LLViewerInventoryItem* itemp = gInventory.getItem(*it);
  4242. if (!itemp)
  4243. {
  4244. // This happens with the LLGestureInventoryFetchObserver that
  4245. // loads gestures at startup. JC
  4246. it = mIncomplete.erase(it);
  4247. continue;
  4248. }
  4249. if (itemp->isFinished())
  4250. {
  4251. mComplete.emplace_back(*it);
  4252. it = mIncomplete.erase(it);
  4253. continue;
  4254. }
  4255. ++it;
  4256. }
  4257. if (mIncomplete.empty())
  4258. {
  4259. done();
  4260. }
  4261. }
  4262. }
  4263. bool LLInventoryFetchObserver::isFinished() const
  4264. {
  4265. return mIncomplete.empty();
  4266. }
  4267. void fetch_items_from_llsd(const LLSD& items_llsd)
  4268. {
  4269. if (!items_llsd.size()) return;
  4270. LLSD body;
  4271. const std::string& url1 = gAgent.getRegionCapability("FetchInventory2");
  4272. if (url1.empty())
  4273. {
  4274. // All grids servers should have this capability now, including current
  4275. // OpenSim servers versions. HB
  4276. llwarns << "Cannot fetch agent inventory items: missing FetchInventory2 capability."
  4277. << llendl;
  4278. }
  4279. const std::string& url2 = gAgent.getRegionCapability("FetchLib2");
  4280. if (url2.empty())
  4281. {
  4282. // I have seen at least one OpenSim grid without such a capability, but
  4283. // it seems to correspond to an empty/unavailable inventory library,
  4284. // since falling back to the deprecated UDP messaging on that grid to
  4285. // fetch the library did not yield any result either. HB
  4286. llwarns_sparse << "Cannot fetch inventory library items: missing FetchLib2 capability."
  4287. << llendl;
  4288. }
  4289. if (url1.empty() && url2.empty())
  4290. {
  4291. return; // Nothing we can do at this point... HB
  4292. }
  4293. body[0]["cap_url"] = url1;
  4294. body[1]["cap_url"] = url2;
  4295. const std::string lib_owner_id = gInventory.getLibraryOwnerID().asString();
  4296. for (size_t i = 0, count = items_llsd.size(); i < count; ++i)
  4297. {
  4298. if (items_llsd[i]["owner_id"].asString() == gAgentID.asString())
  4299. {
  4300. body[0]["items"].append(items_llsd[i]);
  4301. }
  4302. else if (items_llsd[i]["owner_id"].asString() == lib_owner_id)
  4303. {
  4304. body[1]["items"].append(items_llsd[i]);
  4305. }
  4306. }
  4307. static const char* inv_item_str = "inventory item";
  4308. for (size_t i = 0; i < body.size(); ++i)
  4309. {
  4310. if (!body[i].size() || !body[i]["items"].size())
  4311. {
  4312. // Nothing to fetch...
  4313. continue;
  4314. }
  4315. std::string url = body[i]["cap_url"].asString();
  4316. if (url.empty())
  4317. {
  4318. LL_DEBUGS("Inventory") << "No capability to fetch:\n"
  4319. << ll_pretty_print_sd(body[i]["items"])
  4320. << LL_ENDL;
  4321. continue;
  4322. }
  4323. body[i]["agent_id"] = gAgentID;
  4324. LLCore::HttpHandler::ptr_t
  4325. handler(new LLInventoryModel::FetchItemHttpHandler(body[i]));
  4326. gInventory.requestPost(true, url, body[i], handler, inv_item_str);
  4327. }
  4328. }
  4329. void LLInventoryFetchObserver::fetchItems(const uuid_vec_t& ids)
  4330. {
  4331. LLInventoryModelFetch* fetcherp = NULL;
  4332. if (LLInventoryModelFetch::useAISFetching())
  4333. {
  4334. fetcherp = LLInventoryModelFetch::getInstance();
  4335. }
  4336. typedef fast_hmap<LLUUID, uuid_vec_t> requests_by_folders_t;
  4337. requests_by_folders_t requests;
  4338. LLSD items_llsd;
  4339. for (U32 i = 0, count = ids.size(); i < count; ++i)
  4340. {
  4341. const LLUUID& id = ids[i];
  4342. if (id.isNull())
  4343. {
  4344. llwarns_sparse << "Skipping fetch for a null UUID" << llendl;
  4345. continue;
  4346. }
  4347. LLViewerInventoryItem* itemp = gInventory.getItem(id);
  4348. if (itemp)
  4349. {
  4350. if (itemp->isFinished())
  4351. {
  4352. // It is complete, so put it on the complete container.
  4353. mComplete.emplace_back(id);
  4354. continue;
  4355. }
  4356. }
  4357. else if (gInventory.getCategory(id))
  4358. {
  4359. // Ignore categories since they are not items.
  4360. continue;
  4361. }
  4362. // It is incomplete, so put it on the incomplete container, and pack
  4363. // this on the message.
  4364. mIncomplete.emplace_back(id);
  4365. #if 0 // This does not work when using AISv3 for fetches, because with the
  4366. // latter, we cannot fetch an item for which we ignore the parent
  4367. // category (case of inventory offers of individual items by other
  4368. // residents), so when itemp == NULL, the fetch systematically fails...
  4369. // HB
  4370. if (fetcherp)
  4371. {
  4372. if (itemp)
  4373. {
  4374. const LLUUID& parent_id = itemp->getParentUUID();
  4375. requests[parent_id].emplace_back(id);
  4376. }
  4377. else
  4378. {
  4379. fetcherp->scheduleItemFetch(id);
  4380. }
  4381. }
  4382. else
  4383. {
  4384. // Prepare the data to fetch
  4385. LLSD item_entry;
  4386. item_entry["owner_id"] = itemp ? itemp->getPermissions().getOwner()
  4387. // Assume it is agent inventory.
  4388. : gAgentID;
  4389. item_entry["item_id"] = id;
  4390. items_llsd.append(item_entry);
  4391. }
  4392. #else
  4393. // Unconditionnally prepare the data to fetch items via the legacy
  4394. // capabilities, in case we find out later we need to fetch an item we
  4395. // do not now the parent category for... HB
  4396. LLSD item_entry;
  4397. item_entry["owner_id"] = itemp ? itemp->getPermissions().getOwner()
  4398. // Assume it is agent inventory.
  4399. : gAgentID;
  4400. item_entry["item_id"] = id;
  4401. items_llsd.append(item_entry);
  4402. // If we want AISv3 fetches, let's try this too...
  4403. if (fetcherp)
  4404. {
  4405. if (itemp) // This will work fine in this case.
  4406. {
  4407. requests[itemp->getParentUUID()].emplace_back(id);
  4408. }
  4409. else // Forget it, we do need a parent category !
  4410. {
  4411. LL_DEBUGS("Inventory") << "Parent folder unknown for item "
  4412. << id
  4413. << ": falling back to capability fetch."
  4414. << LL_ENDL;
  4415. fetcherp = NULL;
  4416. }
  4417. }
  4418. #endif
  4419. }
  4420. if (!fetcherp)
  4421. {
  4422. fetch_items_from_llsd(items_llsd);
  4423. return;
  4424. }
  4425. for (const auto& folder : requests)
  4426. {
  4427. const LLUUID& cat_id = folder.first;
  4428. S32 count = folder.second.size();
  4429. if (count > MAX_INDIVIDUAL_ITEM_REQUESTS)
  4430. {
  4431. // Requesting one by one would take a while; request the whole
  4432. // folder instead.
  4433. fetcherp->scheduleFolderFetch(cat_id, true);
  4434. continue;
  4435. }
  4436. LLViewerInventoryCategory* catp = gInventory.getCategory(cat_id);
  4437. if (!catp)
  4438. {
  4439. // This should not happen: we should have all folders and if items
  4440. // exist, the folder is supposed to exist as well.
  4441. llwarns << "Missing folder: " << cat_id
  4442. << ". Fetching items individually." << llendl;
  4443. }
  4444. else if (catp->isVersionUnknown())
  4445. {
  4446. // Start fetching the whole folder since it is not ready either
  4447. // way.
  4448. catp->fetch();
  4449. continue;
  4450. }
  4451. else if (count >= catp->getViewerDescendentCount() ||
  4452. count >= catp->getDescendentCount())
  4453. {
  4454. // Start fetching the whole folder since we need all items.
  4455. fetcherp->scheduleFolderFetch(cat_id, true);
  4456. continue;
  4457. }
  4458. // If we got here, then we need to fetch items one by one.
  4459. for (const LLUUID& item_id : folder.second)
  4460. {
  4461. fetcherp->scheduleItemFetch(item_id);
  4462. }
  4463. }
  4464. }
  4465. //----------------------------------------------------------------------------
  4466. // LLInventoryFetchDescendentsObserver class
  4467. //----------------------------------------------------------------------------
  4468. //virtual
  4469. void LLInventoryFetchDescendentsObserver::changed(U32 mask)
  4470. {
  4471. for (uuid_vec_t::iterator it = mIncompleteFolders.begin();
  4472. it < mIncompleteFolders.end(); )
  4473. {
  4474. LLViewerInventoryCategory* catp = gInventory.getCategory(*it);
  4475. if (!catp)
  4476. {
  4477. it = mIncompleteFolders.erase(it);
  4478. continue;
  4479. }
  4480. if (isCategoryComplete(catp))
  4481. {
  4482. mCompleteFolders.emplace_back(*it);
  4483. it = mIncompleteFolders.erase(it);
  4484. continue;
  4485. }
  4486. ++it;
  4487. }
  4488. if (mIncompleteFolders.empty())
  4489. {
  4490. done();
  4491. }
  4492. }
  4493. void LLInventoryFetchDescendentsObserver::fetchDescendents(const uuid_vec_t& ids)
  4494. {
  4495. for (U32 i = 0, count = ids.size(); i < count; ++i)
  4496. {
  4497. const LLUUID& id = ids[i];
  4498. LLViewerInventoryCategory* catp = gInventory.getCategory(id);
  4499. if (!catp) continue;
  4500. if (isCategoryComplete(catp))
  4501. {
  4502. mCompleteFolders.emplace_back(id);
  4503. }
  4504. else
  4505. {
  4506. // Blindly fetch it without seeing if anything else is fetching it.
  4507. catp->fetch();
  4508. // Add to list of things being downloaded for this observer.
  4509. mIncompleteFolders.emplace_back(id);
  4510. }
  4511. }
  4512. }
  4513. bool LLInventoryFetchDescendentsObserver::isFinished() const
  4514. {
  4515. return mIncompleteFolders.empty();
  4516. }
  4517. bool LLInventoryFetchDescendentsObserver::isCategoryComplete(LLViewerInventoryCategory* catp)
  4518. {
  4519. S32 descendents = catp->getDescendentCount();
  4520. if (descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN ||
  4521. catp->isVersionUnknown())
  4522. {
  4523. return false;
  4524. }
  4525. // It might be complete; check known descendents against currently
  4526. // available.
  4527. LLInventoryModel::cat_array_t* cats;
  4528. LLInventoryModel::item_array_t* items;
  4529. gInventory.getDirectDescendentsOf(catp->getUUID(), cats, items);
  4530. if (!cats || !items)
  4531. {
  4532. // Bit of a hack: pretend we are done if they are gone or incomplete.
  4533. // Should never know, but it would suck if this kept tight looping
  4534. // because of incomplete syncing state.
  4535. return true;
  4536. }
  4537. S32 actual_descendents = cats->size() + items->size();
  4538. if (actual_descendents == descendents)
  4539. {
  4540. return true;
  4541. }
  4542. // Error condition, but recoverable. This happens if something was added to
  4543. // the category before it was initialized, so accountForUpdate() did not
  4544. // update descendent count and thus the category thinks it has fewer
  4545. // descendents than it actually has.
  4546. if (actual_descendents > descendents)
  4547. {
  4548. llwarns << "Resyncing descendents count for category "
  4549. << catp->getName() << ": expected " << descendents
  4550. << " descendents but actually got " << actual_descendents
  4551. << "." << llendl;
  4552. catp->setDescendentCount(actual_descendents);
  4553. return true;
  4554. }
  4555. return false;
  4556. }
  4557. //----------------------------------------------------------------------------
  4558. // LLInventoryFetchComboObserver class
  4559. //----------------------------------------------------------------------------
  4560. void LLInventoryFetchComboObserver::changed(U32 mask)
  4561. {
  4562. if (!mIncompleteItems.empty())
  4563. {
  4564. for (uuid_vec_t::iterator it = mIncompleteItems.begin();
  4565. it < mIncompleteItems.end(); )
  4566. {
  4567. LLViewerInventoryItem* item = gInventory.getItem(*it);
  4568. if (!item)
  4569. {
  4570. it = mIncompleteItems.erase(it);
  4571. continue;
  4572. }
  4573. if (item->isFinished())
  4574. {
  4575. mCompleteItems.emplace_back(*it);
  4576. it = mIncompleteItems.erase(it);
  4577. continue;
  4578. }
  4579. ++it;
  4580. }
  4581. }
  4582. if (!mIncompleteFolders.empty())
  4583. {
  4584. for (uuid_vec_t::iterator it = mIncompleteFolders.begin();
  4585. it < mIncompleteFolders.end(); )
  4586. {
  4587. LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
  4588. if (!cat)
  4589. {
  4590. it = mIncompleteFolders.erase(it);
  4591. continue;
  4592. }
  4593. if (gInventory.isCategoryComplete(*it))
  4594. {
  4595. mCompleteFolders.emplace_back(*it);
  4596. it = mIncompleteFolders.erase(it);
  4597. continue;
  4598. }
  4599. ++it;
  4600. }
  4601. }
  4602. if (!mDone && mIncompleteItems.empty() && mIncompleteFolders.empty())
  4603. {
  4604. mDone = true;
  4605. done();
  4606. }
  4607. }
  4608. void LLInventoryFetchComboObserver::fetch(const uuid_vec_t& folder_ids,
  4609. const uuid_vec_t& item_ids)
  4610. {
  4611. for (U32 i = 0, count = folder_ids.size(); i < count; ++i)
  4612. {
  4613. const LLUUID& id = folder_ids[i];
  4614. LLViewerInventoryCategory* cat = gInventory.getCategory(id);
  4615. if (!cat) continue;
  4616. if (!gInventory.isCategoryComplete(id))
  4617. {
  4618. cat->fetch();
  4619. LL_DEBUGS("Inventory") << "Fetching folder " << id << LL_ENDL;
  4620. mIncompleteFolders.emplace_back(id);
  4621. }
  4622. else
  4623. {
  4624. mCompleteFolders.emplace_back(id);
  4625. LL_DEBUGS("Inventory") << "Completing folder " << id << LL_ENDL;
  4626. }
  4627. }
  4628. // Now for the items: we fetch everything which is not a direct descendent
  4629. // of an incomplete folder because the item will show up in an inventory
  4630. // descendents message soon enough so we do not have to fetch it
  4631. // individually.
  4632. LLSD items_llsd;
  4633. LLUUID owner_id;
  4634. for (U32 i = 0, count = item_ids.size(); i < count; ++i)
  4635. {
  4636. const LLUUID& id = item_ids[i];
  4637. LLViewerInventoryItem* item = gInventory.getItem(id);
  4638. if (!item)
  4639. {
  4640. LL_DEBUGS("Inventory") << "Unable to find item " << id
  4641. << LL_ENDL;
  4642. continue;
  4643. }
  4644. if (item->isFinished())
  4645. {
  4646. // It is complete, so put it on the complete container.
  4647. mCompleteItems.emplace_back(id);
  4648. LL_DEBUGS("Inventory") << "Completing item " << id << LL_ENDL;
  4649. continue;
  4650. }
  4651. else
  4652. {
  4653. mIncompleteItems.emplace_back(id);
  4654. owner_id = item->getPermissions().getOwner();
  4655. }
  4656. if (std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(),
  4657. item->getParentUUID()) == mIncompleteFolders.end())
  4658. {
  4659. LLSD item_entry;
  4660. item_entry["owner_id"] = owner_id;
  4661. item_entry["item_id"] = (id);
  4662. items_llsd.append(item_entry);
  4663. }
  4664. else
  4665. {
  4666. LL_DEBUGS("Inventory") << "Not worrying about " << id << LL_ENDL;
  4667. }
  4668. }
  4669. fetch_items_from_llsd(items_llsd);
  4670. }
  4671. //----------------------------------------------------------------------------
  4672. // LLInventoryExistenceObserver class
  4673. //----------------------------------------------------------------------------
  4674. void LLInventoryExistenceObserver::watchItem(const LLUUID& id)
  4675. {
  4676. if (id.notNull())
  4677. {
  4678. mMIA.emplace_back(id);
  4679. }
  4680. }
  4681. void LLInventoryExistenceObserver::changed(U32 mask)
  4682. {
  4683. // Scan through the incomplete items and move or erase them as appropriate.
  4684. if (!mMIA.empty())
  4685. {
  4686. for (uuid_vec_t::iterator it = mMIA.begin(); it < mMIA.end(); )
  4687. {
  4688. LLViewerInventoryItem* item = gInventory.getItem(*it);
  4689. if (!item)
  4690. {
  4691. ++it;
  4692. continue;
  4693. }
  4694. mExist.emplace_back(*it);
  4695. it = mMIA.erase(it);
  4696. }
  4697. if (mMIA.empty())
  4698. {
  4699. done();
  4700. }
  4701. }
  4702. }
  4703. //----------------------------------------------------------------------------
  4704. // LLInventoryAddedObserver class
  4705. //----------------------------------------------------------------------------
  4706. //static
  4707. LLInventoryAddedObserver::hashes_map_t
  4708. LLInventoryAddedObserver::sCopiedItemsHashes;
  4709. //static
  4710. void LLInventoryAddedObserver::registerCopiedItem(const LLUUID& item_id)
  4711. {
  4712. LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
  4713. if (itemp)
  4714. {
  4715. // Keep a hash of what we are going to copy, which will be used below
  4716. // to distinguish items we already had in inventory and just copied,
  4717. // from items we have newly received in our inventory. In the case when
  4718. // we copy several identical items, we need to keep track of their
  4719. // count in excess of their hash.
  4720. LLUUID hash = itemp->hashContents();
  4721. hashes_map_t::iterator it = sCopiedItemsHashes.find(hash);
  4722. if (it == sCopiedItemsHashes.end())
  4723. {
  4724. sCopiedItemsHashes.emplace(hash, 1);
  4725. }
  4726. else
  4727. {
  4728. // Already seen, just add 1 to the count of such items.
  4729. ++(it->second);
  4730. }
  4731. }
  4732. }
  4733. void LLInventoryAddedObserver::changed(U32 mask)
  4734. {
  4735. constexpr U32 OBSERVED_CHANGES = LLInventoryObserver::ADD |
  4736. LLInventoryObserver::CREATE;
  4737. if (!(mask & OBSERVED_CHANGES))
  4738. {
  4739. return;
  4740. }
  4741. for (uuid_list_t::const_iterator it = gInventory.getAddedIDs().begin(),
  4742. end = gInventory.getAddedIDs().end();
  4743. it != end; ++it)
  4744. {
  4745. const LLUUID& id = *it;
  4746. // Do not consider items copied from the inventory as newly added
  4747. // items. HB
  4748. LLViewerInventoryItem* itemp = gInventory.getItem(id);
  4749. if (itemp)
  4750. {
  4751. hashes_map_t::iterator iter =
  4752. sCopiedItemsHashes.find(itemp->hashContents());
  4753. if (iter != sCopiedItemsHashes.end())
  4754. {
  4755. if (--(iter->second) == 0)
  4756. {
  4757. // No more such item's copy expected, erase it from map.
  4758. sCopiedItemsHashes.erase(iter);
  4759. }
  4760. continue;
  4761. }
  4762. }
  4763. // This is indeed a new item: add it.
  4764. mAdded.emplace_back(id);
  4765. }
  4766. if (!mAdded.empty())
  4767. {
  4768. done();
  4769. }
  4770. }
  4771. //----------------------------------------------------------------------------
  4772. // LLInventoryTransactionObserver class
  4773. //----------------------------------------------------------------------------
  4774. void LLInventoryTransactionObserver::changed(U32 mask)
  4775. {
  4776. if (!(mask & LLInventoryObserver::ADD))
  4777. {
  4778. return;
  4779. }
  4780. // This could be it: see if we are processing a bulk update
  4781. LLMessageSystem* msg = gMessageSystemp;
  4782. if (!msg->getMessageName() ||
  4783. strcmp(msg->getMessageName(), "BulkUpdateInventory"))
  4784. {
  4785. return; // Nope... Ignore.
  4786. }
  4787. // We have a match for the message - now check the transaction id.
  4788. LLUUID id;
  4789. msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TransactionID, id);
  4790. if (id == mTransactionID)
  4791. {
  4792. // We found it
  4793. uuid_vec_t folders, items;
  4794. S32 count = msg->getNumberOfBlocksFast(_PREHASH_FolderData);
  4795. for (S32 i = 0; i < count; ++i)
  4796. {
  4797. msg->getUUIDFast(_PREHASH_FolderData, _PREHASH_FolderID, id, i);
  4798. if (id.notNull())
  4799. {
  4800. folders.emplace_back(id);
  4801. }
  4802. }
  4803. count = msg->getNumberOfBlocksFast(_PREHASH_ItemData);
  4804. for (S32 i = 0; i < count; ++i)
  4805. {
  4806. msg->getUUIDFast(_PREHASH_ItemData, _PREHASH_ItemID, id, i);
  4807. if (id.notNull())
  4808. {
  4809. items.emplace_back(id);
  4810. }
  4811. }
  4812. // Call the derived class the implements this method.
  4813. done(folders, items);
  4814. }
  4815. }
  4816. //----------------------------------------------------------------------------
  4817. // LLAssetIDMatches class
  4818. //----------------------------------------------------------------------------
  4819. bool LLAssetIDMatches ::operator()(LLInventoryCategory*, LLInventoryItem* item)
  4820. {
  4821. return item && item->getAssetUUID() == mAssetID;
  4822. }
  4823. //----------------------------------------------------------------------------
  4824. // LLLinkedItemIDMatches class
  4825. //----------------------------------------------------------------------------
  4826. bool LLLinkedItemIDMatches::operator()(LLInventoryCategory*,
  4827. LLInventoryItem* item)
  4828. {
  4829. return item && item->getIsLinkType() &&
  4830. // A linked item's asset Id must be the compared to the item's Id.
  4831. item->getLinkedUUID() == mBaseItemID;
  4832. }
  4833. //----------------------------------------------------------------------------
  4834. // LLInventoryModel::FetchItemHttpHandler class
  4835. //----------------------------------------------------------------------------
  4836. LLInventoryModel::FetchItemHttpHandler::FetchItemHttpHandler(const LLSD& request_sd)
  4837. : LLCore::HttpHandler(),
  4838. mRequestSD(request_sd)
  4839. {
  4840. }
  4841. void LLInventoryModel::FetchItemHttpHandler::onCompleted(LLCore::HttpHandle handle,
  4842. LLCore::HttpResponse* response)
  4843. {
  4844. LLCore::HttpStatus status = response->getStatus();
  4845. if (!status)
  4846. {
  4847. processFailure(status, response);
  4848. return;
  4849. }
  4850. LLCore::BufferArray* body = response->getBody();
  4851. if (!body || !body->size())
  4852. {
  4853. llwarns << "Missing data in inventory item query." << llendl;
  4854. processFailure("HTTP response for inventory item query missing body",
  4855. response);
  4856. return;
  4857. }
  4858. LLSD body_llsd;
  4859. if (!LLCoreHttpUtil::responseToLLSD(response, true, body_llsd))
  4860. {
  4861. // INFOS-level logging will occur on the parsed failure
  4862. processFailure("HTTP response for inventory item query has malformed LLSD",
  4863. response);
  4864. return;
  4865. }
  4866. // Expect top-level structure to be a map
  4867. if (!body_llsd.isMap())
  4868. {
  4869. processFailure("LLSD response for inventory item not a map", response);
  4870. return;
  4871. }
  4872. // Check for 200-with-error failures
  4873. //
  4874. // Original responder-based serivce model did not check for these errors.
  4875. // It may be more robust to ignore this condition. With aggregated
  4876. // requests, an error in one inventory item might take down the entire
  4877. // request. So if this instead broke up the aggregated items into single
  4878. // requests, maybe that would make progress. Or perhaps there is structured
  4879. // information that can tell us what went wrong. Need to dig into this and
  4880. // firm up the API.
  4881. if (body_llsd.has("error"))
  4882. {
  4883. processFailure("Inventory application error (200-with-error)",
  4884. response);
  4885. return;
  4886. }
  4887. processData(body_llsd, response);
  4888. }
  4889. void LLInventoryModel::FetchItemHttpHandler::processData(LLSD& content,
  4890. LLCore::HttpResponse* response)
  4891. {
  4892. LLInventoryModel::item_array_t items;
  4893. LLInventoryModel::update_map_t update;
  4894. LLSD content_items = content["items"];
  4895. S32 count = content_items.size();
  4896. // Does this loop ever execute more than once ?
  4897. for (S32 i = 0; i < count; ++i)
  4898. {
  4899. LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
  4900. titem->unpackMessage(content_items[i]);
  4901. const LLUUID& item_id = titem->getUUID();
  4902. if (item_id.isNull())
  4903. {
  4904. llwarns << "Null item id. Skipping." << llendl;
  4905. continue;
  4906. }
  4907. const LLUUID& parent_id = titem->getParentUUID();
  4908. LL_DEBUGS("Inventory") << "Success for item id: " << item_id
  4909. << " - new parent id: " << parent_id
  4910. << LL_ENDL;
  4911. items.emplace_back(titem);
  4912. // Examine update for changes.
  4913. LLViewerInventoryItem* itemp = gInventory.getItem(item_id);
  4914. if (itemp)
  4915. {
  4916. const LLUUID& old_parent_id = itemp->getParentUUID();
  4917. if (parent_id == old_parent_id)
  4918. {
  4919. if (parent_id.notNull())
  4920. {
  4921. update[parent_id];
  4922. }
  4923. else
  4924. {
  4925. llwarns << "Null parent Id for item " << item_id
  4926. << llendl;
  4927. }
  4928. }
  4929. else
  4930. {
  4931. if (parent_id.notNull())
  4932. {
  4933. ++update[parent_id];
  4934. }
  4935. else
  4936. {
  4937. llwarns << "Null new parent for item " << item_id
  4938. << llendl;
  4939. }
  4940. if (old_parent_id.notNull())
  4941. {
  4942. --update[old_parent_id];
  4943. }
  4944. else
  4945. {
  4946. llwarns << "Null old parent for item " << item_id
  4947. << llendl;
  4948. }
  4949. }
  4950. }
  4951. else if (parent_id.notNull())
  4952. {
  4953. ++update[parent_id];
  4954. }
  4955. else
  4956. {
  4957. llwarns << "Null new parent id for item " << item_id << llendl;
  4958. }
  4959. }
  4960. // As above, this loop never seems to loop more than once per call
  4961. for (LLInventoryModel::item_array_t::iterator it = items.begin(),
  4962. end = items.end();
  4963. it != end; ++it)
  4964. {
  4965. gInventory.updateItem(*it);
  4966. }
  4967. gInventory.notifyObservers();
  4968. if (gWindowp)
  4969. {
  4970. gWindowp->decBusyCount();
  4971. }
  4972. }
  4973. void LLInventoryModel::FetchItemHttpHandler::processFailure(LLCore::HttpStatus status,
  4974. LLCore::HttpResponse* response)
  4975. {
  4976. // Warn once only, because these can get really spammy, when a capability
  4977. // is not found, for example... *TODO: search where to abort failed cap
  4978. // requests.
  4979. llwarns_once << "Inventory item fetch failure - Status: "
  4980. << status.toTerseString() << " - Reason: "
  4981. << status.toString() << " - Content-type: "
  4982. << response->getContentType() << " - Content (abridged): "
  4983. << LLCoreHttpUtil::responseToString(response) << llendl;
  4984. #if 0 // Avoid: "Call was made to notifyObservers within notifyObservers !"
  4985. // Since there was an error, no update happened anyway... HB
  4986. gInventory.notifyObservers();
  4987. #endif
  4988. }
  4989. void LLInventoryModel::FetchItemHttpHandler::processFailure(const char* const reason,
  4990. LLCore::HttpResponse* response)
  4991. {
  4992. llwarns << "Inventory item fetch failure - Status: internal error - Reason: "
  4993. << reason << " - Content (abridged): "
  4994. << LLCoreHttpUtil::responseToString(response) << llendl;
  4995. #if 0 // Avoid: "Call was made to notifyObservers within notifyObservers !"
  4996. // Since there was an error, no update happened anyway... HB
  4997. gInventory.notifyObservers();
  4998. #endif
  4999. }