Scene.Inventory.cs 131 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Collections;
  30. using System.Reflection;
  31. using System.Text;
  32. using System.Xml;
  33. using OpenMetaverse;
  34. using log4net;
  35. using OpenSim.Framework;
  36. using OpenSim.Framework.Serialization.External;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes.Serialization;
  39. using PermissionMask = OpenSim.Framework.PermissionMask;
  40. namespace OpenSim.Region.Framework.Scenes
  41. {
  42. public partial class Scene
  43. {
  44. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  45. //private static readonly string LogHeader = "[SCENE INVENTORY]";
  46. /// <summary>
  47. /// Allows asynchronous derezzing of objects from the scene into a client's inventory.
  48. /// </summary>
  49. protected AsyncSceneObjectGroupDeleter m_asyncSceneObjectDeleter;
  50. /// <summary>
  51. /// Allows inventory details to be sent to clients asynchronously
  52. /// </summary>
  53. protected AsyncInventorySender m_asyncInventorySender;
  54. /// <summary>
  55. /// Creates all the scripts in the scene which should be started.
  56. /// </summary>
  57. /// <returns>
  58. /// Number of scripts that were valid for starting. This does not guarantee that all these scripts
  59. /// were actually started, but just that the start could be attempt (e.g. the asset data for the script could be found)
  60. /// </returns>
  61. public int CreateScriptInstances()
  62. {
  63. m_log.InfoFormat("[SCENE]: Initializing script instances in {0}", RegionInfo.RegionName);
  64. int scriptsValidForStarting = 0;
  65. EntityBase[] entities = Entities.GetEntities();
  66. foreach (EntityBase group in entities)
  67. {
  68. if (group is SceneObjectGroup sog)
  69. {
  70. scriptsValidForStarting += sog.CreateScriptInstances(0, false, DefaultScriptEngine, 0);
  71. sog.ResumeScripts();
  72. }
  73. }
  74. m_log.InfoFormat(
  75. "[SCENE]: Initialized {0} script instances in {1}",
  76. scriptsValidForStarting, RegionInfo.RegionName);
  77. return scriptsValidForStarting;
  78. }
  79. /// <summary>
  80. /// Lets the script engines start processing scripts.
  81. /// </summary>
  82. public void StartScripts()
  83. {
  84. //m_log.InfoFormat("[SCENE]: Starting scripts in {0}, please wait.", RegionInfo.RegionName);
  85. IScriptModule[] engines = RequestModuleInterfaces<IScriptModule>();
  86. foreach (IScriptModule engine in engines)
  87. engine.StartProcessing();
  88. }
  89. public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item, uint cost)
  90. {
  91. IMoneyModule money = RequestModuleInterface<IMoneyModule>();
  92. money?.ApplyUploadCharge(agentID, (int)cost, "Asset upload");
  93. AddInventoryItem(item);
  94. }
  95. public bool AddInventoryItemReturned(UUID AgentId, InventoryItemBase item)
  96. {
  97. if (AddInventoryItem(item))
  98. return true;
  99. else
  100. {
  101. m_log.WarnFormat(
  102. "[AGENT INVENTORY]: Unable to add item {1} to agent {2} inventory", item.Name, AgentId);
  103. return false;
  104. }
  105. }
  106. public bool AddInventoryItem(InventoryItemBase item)
  107. {
  108. return AddInventoryItem(item, true);
  109. }
  110. /// <summary>
  111. /// Add the given inventory item to a user's inventory.
  112. /// </summary>
  113. /// <param name="item"></param>
  114. public bool AddInventoryItem(InventoryItemBase item, bool trigger)
  115. {
  116. if (item.Folder.IsNotZero() && InventoryService.AddItem(item))
  117. {
  118. int userlevel = Permissions.IsGod(item.Owner) ? 1 : 0;
  119. if (trigger)
  120. EventManager.TriggerOnNewInventoryItemUploadComplete(item, userlevel);
  121. return true;
  122. }
  123. // OK so either the viewer didn't send a folderID or AddItem failed
  124. UUID originalFolder = item.Folder;
  125. InventoryFolderBase f = null;
  126. if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType))
  127. f = InventoryService.GetFolderForType(item.Owner, (FolderType)item.AssetType);
  128. if (f is not null)
  129. {
  130. m_log.DebugFormat(
  131. "[AGENT INVENTORY]: Found folder {0} type {1} for item {2}",
  132. f.Name, (AssetType)f.Type, item.Name);
  133. item.Folder = f.ID;
  134. }
  135. else
  136. {
  137. f = InventoryService.GetRootFolder(item.Owner);
  138. if (f is not null)
  139. {
  140. item.Folder = f.ID;
  141. }
  142. else
  143. {
  144. m_log.WarnFormat(
  145. "[AGENT INVENTORY]: Could not find root folder for {0} when trying to add item {1} with no parent folder specified",
  146. item.Owner, item.Name);
  147. return false;
  148. }
  149. }
  150. if (InventoryService.AddItem(item))
  151. {
  152. int userlevel = Permissions.IsGod(item.Owner) ? 1 : 0;
  153. if (trigger)
  154. EventManager.TriggerOnNewInventoryItemUploadComplete(item, userlevel);
  155. if (originalFolder.IsNotZero())
  156. {
  157. // Tell the viewer that the item didn't go there
  158. ChangePlacement(item, f);
  159. }
  160. return true;
  161. }
  162. else
  163. {
  164. m_log.WarnFormat(
  165. "[AGENT INVENTORY]: Agent {0} could not add item {1} {2}",
  166. item.Owner, item.Name, item.ID);
  167. return false;
  168. }
  169. }
  170. private void ChangePlacement(InventoryItemBase item, InventoryFolderBase f)
  171. {
  172. ScenePresence sp = GetScenePresence(item.Owner);
  173. if (sp is not null && sp.ControllingClient is not null && sp.ControllingClient.IsActive)
  174. {
  175. IClientAPI cli = sp.ControllingClient;
  176. InventoryFolderBase parent = InventoryService.GetFolder(f.Owner, f.ParentID);
  177. cli.SendRemoveInventoryItems(new UUID[] { item.ID });
  178. cli.SendBulkUpdateInventory(Array.Empty<InventoryFolderBase>(), new InventoryItemBase[] { item });
  179. string message = "The item was placed in folder " + f.Name;
  180. if (parent is not null)
  181. message += " under " + parent.Name;
  182. cli.SendAgentAlertMessage(message, false);
  183. }
  184. }
  185. /// <summary>
  186. /// Add the given inventory item to a user's inventory.
  187. /// </summary>
  188. /// <param name="AgentID">
  189. /// A <see cref="UUID"/>
  190. /// </param>
  191. /// <param name="item">
  192. /// A <see cref="InventoryItemBase"/>
  193. /// </param>
  194. [Obsolete("Use AddInventoryItem(InventoryItemBase item) instead. This was deprecated in OpenSim 0.7.1")]
  195. public void AddInventoryItem(UUID AgentID, InventoryItemBase item)
  196. {
  197. AddInventoryItem(item);
  198. }
  199. /// <summary>
  200. /// Add an inventory item to an avatar's inventory.
  201. /// </summary>
  202. /// <param name="remoteClient">The remote client controlling the avatar</param>
  203. /// <param name="item">The item. This structure contains all the item metadata, including the folder
  204. /// in which the item is to be placed.</param>
  205. public void AddInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
  206. {
  207. AddInventoryItem(item);
  208. remoteClient.SendInventoryItemCreateUpdate(item, 0);
  209. }
  210. /// <summary>
  211. /// <see>CapsUpdatedInventoryItemAsset(IClientAPI, UUID, byte[])</see>
  212. /// </summary>
  213. public UUID CapsUpdateItemAsset(UUID avatarId, UUID itemID, UUID objectID, byte[] data)
  214. {
  215. if (!TryGetScenePresence(avatarId, out ScenePresence avatar))
  216. {
  217. m_log.ErrorFormat("[CapsUpdateItemAsset]: Avatar {0} cannot be found to update item asset", avatarId);
  218. return UUID.Zero;
  219. }
  220. if (objectID.IsZero())
  221. {
  222. IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
  223. return invAccess is not null ? invAccess.CapsUpdateInventoryItemAsset(avatar.ControllingClient, itemID, data) : UUID.Zero;
  224. }
  225. SceneObjectPart sop = GetSceneObjectPart(objectID);
  226. if(sop is null || sop.ParentGroup.IsDeleted)
  227. {
  228. m_log.ErrorFormat("[CapsUpdateItemAsset]: Object {0} cannot be found to update item asset", objectID);
  229. return UUID.Zero;
  230. }
  231. TaskInventoryItem item = sop.Inventory.GetInventoryItem(itemID);
  232. if (item is null)
  233. {
  234. m_log.ErrorFormat("[CapsUpdateItemAsset]: Could not find item {0} for asset update", itemID);
  235. return UUID.Zero;
  236. }
  237. if (!Permissions.CanEditObjectInventory(objectID, avatarId))
  238. return UUID.Zero;
  239. InventoryType itemType = (InventoryType)item.InvType;
  240. switch (itemType)
  241. {
  242. case InventoryType.Notecard:
  243. {
  244. if (!Permissions.CanEditNotecard(itemID, objectID, avatarId))
  245. {
  246. avatar.ControllingClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false);
  247. return UUID.Zero;
  248. }
  249. avatar.ControllingClient.SendAlertMessage("Notecard updated");
  250. break;
  251. }
  252. case (InventoryType)CustomInventoryType.AnimationSet:
  253. {
  254. AnimationSet animSet = new(data);
  255. uint res = animSet.Validate(x => {
  256. const int required = (int)(PermissionMask.Transfer | PermissionMask.Copy);
  257. int perms = InventoryService.GetAssetPermissions(avatarId, x);
  258. // enforce previus perm rule
  259. if ((perms & required) != required)
  260. return 0;
  261. return (uint)perms;
  262. });
  263. if (res == 0)
  264. {
  265. avatar.ControllingClient.SendAgentAlertMessage("Not enought permissions on asset(s) referenced by animation set '{0}', update failed", false);
  266. return UUID.Zero;
  267. }
  268. break;
  269. }
  270. case InventoryType.Gesture:
  271. {
  272. if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
  273. {
  274. avatar.ControllingClient.SendAgentAlertMessage("Insufficient permissions to edit gesture", false);
  275. return UUID.Zero;
  276. }
  277. avatar.ControllingClient.SendAlertMessage("Gesture updated");
  278. break;
  279. }
  280. case InventoryType.Settings:
  281. {
  282. if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
  283. {
  284. avatar.ControllingClient.SendAgentAlertMessage("Insufficient permissions to edit setting", false);
  285. return UUID.Zero;
  286. }
  287. avatar.ControllingClient.SendAlertMessage("Setting updated");
  288. break;
  289. }
  290. case InventoryType.Material:
  291. {
  292. if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
  293. {
  294. avatar.ControllingClient.SendAgentAlertMessage("Insufficient permissions to edit setting", false);
  295. return UUID.Zero;
  296. }
  297. break;
  298. }
  299. }
  300. AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)item.Type, data, avatarId);
  301. item.AssetID = asset.FullID;
  302. AssetService.Store(asset);
  303. sop.Inventory.UpdateInventoryItem(item);
  304. // remoteClient.SendInventoryItemCreateUpdate(item);
  305. return asset.FullID;
  306. }
  307. /// <summary>
  308. /// Capability originating call to update the asset of a script in a prim's (task's) inventory
  309. /// </summary>
  310. /// <param name="remoteClient"></param>
  311. /// <param name="itemID"></param>
  312. /// <param name="primID">The prim which contains the item to update</param>
  313. /// <param name="isScriptRunning">Indicates whether the script to update is currently running</param>
  314. /// <param name="data"></param>
  315. public ArrayList CapsUpdateTaskInventoryScriptAsset(IClientAPI remoteClient, UUID itemId,
  316. UUID primId, bool isScriptRunning, byte[] data)
  317. {
  318. if (!Permissions.CanEditScript(itemId, primId, remoteClient.AgentId))
  319. {
  320. remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false);
  321. return new ArrayList();
  322. }
  323. // Retrieve group
  324. SceneObjectPart part = GetSceneObjectPart(primId);
  325. if (part is null)
  326. return new ArrayList();
  327. SceneObjectGroup group = part.ParentGroup;
  328. // Retrieve item
  329. TaskInventoryItem item = group.GetInventoryItem(part.LocalId, itemId);
  330. if (item is null)
  331. {
  332. m_log.ErrorFormat(
  333. "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for caps script update "
  334. + " but the item does not exist in this inventory",
  335. itemId, part.Name, part.UUID);
  336. return new ArrayList();
  337. }
  338. item.ScriptRunning = isScriptRunning;
  339. AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)AssetType.LSLText, data, remoteClient.AgentId);
  340. AssetService.Store(asset);
  341. //m_log.DebugFormat(
  342. // "[PRIM INVENTORY]: Stored asset {0} when updating item {1} in prim {2} for {3}",
  343. // asset.ID, item.Name, part.Name, remoteClient.Name);
  344. part.Inventory.RemoveScriptInstance(item.ItemID, false);
  345. // Update item with new asset
  346. item.AssetID = asset.FullID;
  347. group.UpdateInventoryItem(item);
  348. group.InvalidateEffectivePerms();
  349. part.SendPropertiesToClient(remoteClient);
  350. // Trigger rerunning of script (use TriggerRezScript event, see RezScript)
  351. // Needs to determine which engine was running it and use that
  352. ArrayList errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 1);
  353. // Tell anyone managing scripts that a script has been reloaded/changed
  354. EventManager.TriggerUpdateScript(remoteClient.AgentId, itemId, primId, isScriptRunning, item.AssetID);
  355. part.ParentGroup.ResumeScripts();
  356. return errors;
  357. }
  358. /// <summary>
  359. /// <see>CapsUpdateTaskInventoryScriptAsset(IClientAPI, UUID, UUID, bool, byte[])</see>
  360. /// </summary>
  361. public ArrayList CapsUpdateTaskInventoryScriptAsset(UUID avatarId, UUID itemId,
  362. UUID primId, bool isScriptRunning, byte[] data)
  363. {
  364. if (TryGetScenePresence(avatarId, out ScenePresence avatar))
  365. {
  366. return CapsUpdateTaskInventoryScriptAsset(
  367. avatar.ControllingClient, itemId, primId, isScriptRunning, data);
  368. }
  369. else
  370. {
  371. m_log.ErrorFormat("[PRIM INVENTORY]: Avatar {0} cannot be found to update its prim item asset", avatarId);
  372. return new ArrayList();
  373. }
  374. }
  375. /// <summary>
  376. /// Update an item which is either already in the client's inventory or is within
  377. /// a transaction
  378. /// </summary>
  379. /// <param name="remoteClient"></param>
  380. /// <param name="transactionID">The transaction ID. If this is UUID.Zero we will
  381. /// assume that we are not in a transaction</param>
  382. /// <param name="itemID">The ID of the updated item</param>
  383. /// <param name="name">The name of the updated item</param>
  384. /// <param name="description">The description of the updated item</param>
  385. /// <param name="nextOwnerMask">The permissions of the updated item</param>
  386. /* public void UpdateInventoryItemAsset(IClientAPI remoteClient, UUID transactionID,
  387. UUID itemID, string name, string description,
  388. uint nextOwnerMask)*/
  389. public void UpdateInventoryItem(IClientAPI remoteClient, UUID transactionID,
  390. UUID itemID, InventoryItemBase itemUpd)
  391. {
  392. //m_log.DebugFormat(
  393. // "[USER INVENTORY]: Updating asset for item {0} {1}, transaction ID {2} for {3}",
  394. // itemID, itemUpd.Name, transactionID, remoteClient.Name);
  395. // This one will let people set next perms on items in agent
  396. // inventory. Rut-Roh. Whatever. Make this secure. Yeah.
  397. //
  398. // Passing something to another avatar or a an object will already
  399. InventoryItemBase item = InventoryService.GetItem(remoteClient.AgentId, itemID);
  400. if (item is not null)
  401. {
  402. if (item.Owner.NotEqual(remoteClient.AgentId))
  403. return;
  404. bool sendUpdate = false;
  405. item.Flags = (item.Flags & ~(uint)255) | (itemUpd.Flags & (uint)255);
  406. if(item.AssetType == (int)AssetType.Landmark)
  407. {
  408. if(item.Name.StartsWith("HG ") && !itemUpd.Name.StartsWith("HG "))
  409. {
  410. itemUpd.Name = "HG " + itemUpd.Name;
  411. sendUpdate = true;
  412. }
  413. int origIndx = item.Description.LastIndexOf("@ htt");
  414. if(origIndx >= 0)
  415. {
  416. if(itemUpd.Description.LastIndexOf('@') < 0)
  417. {
  418. itemUpd.Description += string.Concat(" ", item.Description.AsSpan(origIndx));
  419. sendUpdate = true;
  420. }
  421. }
  422. }
  423. item.Name = itemUpd.Name;
  424. item.Description = itemUpd.Description;
  425. //m_log.DebugFormat(
  426. // "[USER INVENTORY]: itemUpd {0} {1} {2} {3}, item {4} {5} {6} {7}",
  427. // itemUpd.NextPermissions, itemUpd.GroupPermissions, itemUpd.EveryOnePermissions, item.Flags,
  428. // item.NextPermissions, item.GroupPermissions, item.EveryOnePermissions, item.CurrentPermissions);
  429. if (itemUpd.NextPermissions != 0) // Use this to determine validity. Can never be 0 if valid
  430. {
  431. // Create a set of base permissions that will not include export if the user
  432. // is not allowed to change the export flag.
  433. bool denyExportChange = false;
  434. //m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions);
  435. // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export
  436. if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner)
  437. denyExportChange = true;
  438. //m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange);
  439. // If it is already set, force it set and also force full perm
  440. // else prevent setting it. It can and should never be set unless
  441. // set in base, so the condition above is valid
  442. if (denyExportChange)
  443. {
  444. // If we are not allowed to change it, then force it to the
  445. // original item's setting and if it was on, also force full perm
  446. if ((item.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
  447. {
  448. itemUpd.NextPermissions = (uint)(PermissionMask.All);
  449. itemUpd.EveryOnePermissions |= (uint)PermissionMask.Export;
  450. }
  451. else
  452. {
  453. itemUpd.EveryOnePermissions &= ~(uint)PermissionMask.Export;
  454. }
  455. }
  456. else
  457. {
  458. // If the new state is exportable, force full perm
  459. if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0)
  460. {
  461. //m_log.DebugFormat("[XXX]: Force full perm");
  462. itemUpd.NextPermissions = (uint)(PermissionMask.All);
  463. }
  464. }
  465. if (item.NextPermissions != (itemUpd.NextPermissions & item.BasePermissions))
  466. item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
  467. item.NextPermissions = itemUpd.NextPermissions & item.BasePermissions;
  468. if (item.EveryOnePermissions != (itemUpd.EveryOnePermissions & item.BasePermissions))
  469. item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
  470. item.EveryOnePermissions = itemUpd.EveryOnePermissions & item.BasePermissions;
  471. if (item.GroupPermissions != (itemUpd.GroupPermissions & item.BasePermissions))
  472. item.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
  473. item.GroupPermissions = itemUpd.GroupPermissions & item.BasePermissions;
  474. item.GroupID = itemUpd.GroupID;
  475. item.GroupOwned = itemUpd.GroupOwned;
  476. item.CreationDate = itemUpd.CreationDate;
  477. // The client sends zero if its newly created?
  478. if (itemUpd.CreationDate == 0)
  479. item.CreationDate = Util.UnixTimeSinceEpoch();
  480. else
  481. item.CreationDate = itemUpd.CreationDate;
  482. // TODO: Check if folder changed and move item
  483. //item.NextPermissions = itemUpd.Folder;
  484. item.InvType = itemUpd.InvType;
  485. if (item.SalePrice != itemUpd.SalePrice ||
  486. item.SaleType != itemUpd.SaleType)
  487. item.Flags |= (uint)InventoryItemFlags.ObjectSlamSale;
  488. item.SalePrice = itemUpd.SalePrice;
  489. item.SaleType = itemUpd.SaleType;
  490. if (item.InvType == (int)InventoryType.Wearable && (item.Flags & 0xf) == 0 && (itemUpd.Flags & 0xf) != 0)
  491. {
  492. item.Flags = (item.Flags & 0xfffffff0) | (itemUpd.Flags & 0xf);
  493. sendUpdate = true;
  494. }
  495. InventoryService.UpdateItem(item);
  496. }
  497. if (transactionID.IsNotZero())
  498. {
  499. AgentTransactionsModule?.HandleItemUpdateFromTransaction(remoteClient, transactionID, item);
  500. }
  501. else
  502. {
  503. // This MAY be problematic, if it is, another solution
  504. // needs to be found. If inventory item flags are updated
  505. // the viewer's notion of the item needs to be refreshed.
  506. //
  507. // In other situations we cannot send out a bulk update here, since this will cause editing of clothing to start
  508. // failing frequently. Possibly this is a race with a separate transaction that uploads the asset.
  509. if (sendUpdate)
  510. remoteClient.SendBulkUpdateInventory(item);
  511. }
  512. }
  513. else
  514. {
  515. m_log.ErrorFormat(
  516. "[AGENTINVENTORY]: Item id {0} not found for an inventory item update for {1}.",
  517. itemID, remoteClient.Name);
  518. }
  519. }
  520. /// <summary>
  521. /// Give an inventory item from one user to another
  522. /// </summary>
  523. /// <param name="recipientClient"></param>
  524. /// <param name="senderId">ID of the sender of the item</param>
  525. /// <param name="itemId"></param>
  526. public virtual void GiveInventoryItem(IClientAPI recipientClient, UUID senderId, UUID itemId, out string message)
  527. {
  528. InventoryItemBase itemCopy = GiveInventoryItem(recipientClient.AgentId, senderId, itemId, out message);
  529. if (itemCopy is not null)
  530. recipientClient.SendBulkUpdateInventory(itemCopy);
  531. }
  532. /// <summary>
  533. /// Give an inventory item from one user to another
  534. /// </summary>
  535. /// <param name="recipient"></param>
  536. /// <param name="senderId">ID of the sender of the item</param>
  537. /// <param name="itemId"></param>
  538. /// <returns>The inventory item copy given, null if the give was unsuccessful</returns>
  539. public virtual InventoryItemBase GiveInventoryItem(UUID recipient, UUID senderId, UUID itemId, out string message)
  540. {
  541. return GiveInventoryItem(recipient, senderId, itemId, UUID.Zero, out message);
  542. }
  543. /// <summary>
  544. /// Give an inventory item from one user to another
  545. /// </summary>
  546. /// <param name="recipient"></param>
  547. /// <param name="senderId">ID of the sender of the item</param>
  548. /// <param name="itemId"></param>
  549. /// <param name="recipientFolderId">
  550. /// The id of the folder in which the copy item should go. If UUID.Zero then the item is placed in the most
  551. /// appropriate default folder.
  552. /// </param>
  553. /// <returns>
  554. /// The inventory item copy given, null if the give was unsuccessful
  555. /// </returns>
  556. public virtual InventoryItemBase GiveInventoryItem(
  557. UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId, out string message)
  558. {
  559. //Console.WriteLine("Scene.Inventory.cs: GiveInventoryItem");
  560. if (!Permissions.CanTransferUserInventory(itemId, senderId, recipient))
  561. {
  562. message = "Not allowed to transfer this item.";
  563. return null;
  564. }
  565. InventoryItemBase item = InventoryService.GetItem(senderId, itemId);
  566. if (item is null)
  567. {
  568. m_log.WarnFormat(
  569. "[AGENT INVENTORY]: Failed to find item {0} sent by {1} to {2}", itemId, senderId, recipient);
  570. message = string.Format("Item not found: {0}.", itemId);
  571. return null;
  572. }
  573. if (item.AssetType == (int)AssetType.Link || item.AssetType == (int)AssetType.LinkFolder)
  574. {
  575. message = "inventory links not supported.";
  576. return null;
  577. }
  578. if (item.Owner.NotEqual(senderId))
  579. {
  580. m_log.WarnFormat(
  581. "[AGENT INVENTORY]: Attempt to send item {0} {1} to {2} failed because sender {3} did not match item owner {4}",
  582. item.Name, item.ID, recipient, senderId, item.Owner);
  583. message = "Sender did not match item owner.";
  584. return null;
  585. }
  586. IUserManagement uman = RequestModuleInterface<IUserManagement>();
  587. uman?.AddCreatorUser(item.CreatorIdAsUuid, item.CreatorData);
  588. if (!Permissions.BypassPermissions())
  589. {
  590. if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
  591. {
  592. message = "Item doesn't have the Transfer permission.";
  593. return null;
  594. }
  595. }
  596. // Insert a copy of the item into the recipient
  597. InventoryItemBase itemCopy = new()
  598. {
  599. Owner = recipient,
  600. CreatorId = item.CreatorId,
  601. CreatorData = item.CreatorData,
  602. ID = UUID.Random(),
  603. AssetID = item.AssetID,
  604. Description = item.Description,
  605. Name = item.Name,
  606. AssetType = item.AssetType,
  607. InvType = item.InvType,
  608. Folder = recipientFolderId,
  609. Flags = item.Flags
  610. };
  611. if (Permissions.PropagatePermissions() && recipient != senderId)
  612. {
  613. // Trying to do this right this time. This is evil. If
  614. // you believe in Good, go elsewhere. Vampires and other
  615. // evil creatores only beyond this point. You have been
  616. // warned.
  617. // We're going to mask a lot of things by the next perms
  618. // Tweak the next perms to be nicer to our data
  619. //
  620. // In this mask, all the bits we do NOT want to mess
  621. // with are set. These are:
  622. //
  623. // Transfer
  624. // Copy
  625. // Modify
  626. uint permsMask = ~ ((uint)PermissionMask.Copy |
  627. (uint)PermissionMask.Transfer |
  628. (uint)PermissionMask.Modify |
  629. (uint)PermissionMask.Export);
  630. // Now, reduce the next perms to the mask bits
  631. // relevant to the operation
  632. uint nextPerms = permsMask | (item.NextPermissions &
  633. ((uint)PermissionMask.Copy |
  634. (uint)PermissionMask.Transfer |
  635. (uint)PermissionMask.Modify));
  636. // nextPerms now has all bits set, except for the actual
  637. // next permission bits.
  638. // This checks for no mod, no copy, no trans.
  639. // This indicates an error or messed up item. Do it like
  640. // SL and assume trans
  641. if (nextPerms == permsMask)
  642. nextPerms |= (uint)PermissionMask.Transfer;
  643. // Inventory owner perms are the logical AND of the
  644. // folded perms and the root prim perms, however, if
  645. // the root prim is mod, the inventory perms will be
  646. // mod. This happens on "take" and is of little concern
  647. // here, save for preventing escalation
  648. // This hack ensures that items previously permalocked
  649. // get unlocked when they're passed or rezzed
  650. uint basePerms = item.BasePermissions |
  651. (uint)PermissionMask.Move;
  652. uint ownerPerms = item.CurrentPermissions;
  653. // These will be applied to the root prim at next rez.
  654. // The legacy slam bit (bit 3) and folded permission (bits 0-2)
  655. // are preserved due to the above mangling
  656. //ownerPerms &= nextPerms;
  657. // Mask the base permissions. This is a conservative
  658. // approach altering only the three main perms
  659. //basePerms &= nextPerms;
  660. // Mask out the folded portion of the base mask.
  661. // While the owner mask carries the actual folded
  662. // permissions, the base mask carries the original
  663. // base mask, before masking with the folded perms.
  664. // We need this later for rezzing.
  665. //basePerms &= ~(uint)PermissionMask.FoldedMask;
  666. //basePerms |= ((basePerms >> 13) & 7) | (((basePerms & (uint)PermissionMask.Export) != 0) ? (uint)PermissionMask.FoldedExport : 0);
  667. // If this is an object, root prim perms may be more
  668. // permissive than folded perms. Use folded perms as
  669. // a mask
  670. uint foldedPerms = (item.CurrentPermissions & (uint)PermissionMask.FoldedMask) << (int)PermissionMask.FoldingShift;
  671. if (foldedPerms != 0 && item.InvType == (int)InventoryType.Object)
  672. {
  673. foldedPerms |= permsMask;
  674. bool isRootMod = (item.CurrentPermissions & (uint)PermissionMask.Modify) != 0;
  675. // Mask the owner perms to the folded perms
  676. // Note that this is only to satisfy the viewer.
  677. // The effect of this will be reversed on rez.
  678. ownerPerms &= foldedPerms;
  679. basePerms &= foldedPerms;
  680. // If the root was mod, let the mask reflect that
  681. // We also need to adjust the base here, because
  682. // we should be able to edit in-inventory perms
  683. // for the root prim, if it's mod.
  684. if (isRootMod)
  685. {
  686. ownerPerms |= (uint)PermissionMask.Modify;
  687. basePerms |= (uint)PermissionMask.Modify;
  688. }
  689. }
  690. // move here so nextperms are mandatory
  691. ownerPerms &= nextPerms;
  692. basePerms &= nextPerms;
  693. basePerms &= ~(uint)PermissionMask.FoldedMask;
  694. basePerms |= ((basePerms >> 13) & 7) | (((basePerms & (uint)PermissionMask.Export) != 0) ? (uint)PermissionMask.FoldedExport : 0);
  695. // Assign to the actual item. Make sure the slam bit is
  696. // set, if it wasn't set before.
  697. itemCopy.BasePermissions = basePerms;
  698. itemCopy.CurrentPermissions = ownerPerms;
  699. itemCopy.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
  700. // Need to clear the other inventory slam options.
  701. // That is so we can handle the case where the recipient
  702. // changes the bits in inventory before rezzing
  703. itemCopy.Flags &= ~(uint)(InventoryItemFlags.ObjectOverwriteBase | InventoryItemFlags.ObjectOverwriteOwner | InventoryItemFlags.ObjectOverwriteGroup | InventoryItemFlags.ObjectOverwriteEveryone | InventoryItemFlags.ObjectOverwriteNextOwner);
  704. itemCopy.NextPermissions = item.NextPermissions;
  705. // This preserves "everyone can move"
  706. itemCopy.EveryOnePermissions = item.EveryOnePermissions &
  707. nextPerms;
  708. // Intentionally killing "share with group" here, as
  709. // the recipient will not have the group this is
  710. // set to
  711. itemCopy.GroupPermissions = 0;
  712. }
  713. else
  714. {
  715. itemCopy.CurrentPermissions = item.CurrentPermissions;
  716. itemCopy.NextPermissions = item.NextPermissions;
  717. itemCopy.EveryOnePermissions = item.EveryOnePermissions & item.NextPermissions;
  718. itemCopy.GroupPermissions = item.GroupPermissions & item.NextPermissions;
  719. itemCopy.BasePermissions = item.BasePermissions;
  720. }
  721. if (itemCopy.Folder.IsZero())
  722. {
  723. InventoryFolderBase folder = null;
  724. if (Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType))
  725. folder = InventoryService.GetFolderForType(recipient, (FolderType)itemCopy.AssetType);
  726. if (folder is not null)
  727. {
  728. itemCopy.Folder = folder.ID;
  729. }
  730. else
  731. {
  732. InventoryFolderBase root = InventoryService.GetRootFolder(recipient);
  733. if (root is not null)
  734. {
  735. itemCopy.Folder = root.ID;
  736. }
  737. else
  738. {
  739. message = "Can't find a folder to add the item to.";
  740. return null;
  741. }
  742. }
  743. }
  744. itemCopy.GroupID = UUID.Zero;
  745. itemCopy.GroupOwned = false;
  746. itemCopy.SalePrice = 0; //item.SalePrice;
  747. itemCopy.SaleType = 0; //item.SaleType;
  748. IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
  749. invAccess?.TransferInventoryAssets(itemCopy, senderId, recipient);
  750. AddInventoryItem(itemCopy, false);
  751. if (!Permissions.BypassPermissions())
  752. {
  753. if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  754. {
  755. List<UUID> items = new() { itemId };
  756. InventoryService.DeleteItems(senderId, items);
  757. }
  758. }
  759. message = null;
  760. return itemCopy;
  761. }
  762. private readonly HashSet<short> denyGiveFolderTypes = new()
  763. {
  764. (short)FolderType.Trash,
  765. (short)FolderType.LostAndFound,
  766. (short)FolderType.CurrentOutfit,
  767. (short)FolderType.Inbox,
  768. (short)FolderType.Outbox,
  769. (short)FolderType.Suitcase,
  770. (short)FolderType.Root
  771. };
  772. /// <summary>
  773. /// Give an entire inventory folder from one user to another. The entire contents (including all descendent
  774. /// folders) is given.
  775. /// </summary>
  776. /// <param name="recipientId"></param>
  777. /// <param name="senderId">ID of the sender of the item</param>
  778. /// <param name="folderId"></param>
  779. /// <param name="recipientParentFolderId">
  780. /// The id of the receipient folder in which the send folder should be placed. If UUID.Zero then the
  781. /// recipient folder is the root folder
  782. /// </param>
  783. /// <returns>
  784. /// The inventory folder copy given, null if the copy was unsuccessful
  785. /// </returns>
  786. public virtual InventoryFolderBase GiveInventoryFolder(IClientAPI client,
  787. UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId)
  788. {
  789. //// Retrieve the folder from the sender
  790. InventoryFolderBase folder = InventoryService.GetFolder(senderId, folderId);
  791. if (folder is null)
  792. {
  793. m_log.ErrorFormat("[AGENT INVENTORY]: Could not find inventory folder {0} to give", folderId);
  794. return null;
  795. }
  796. if (denyGiveFolderTypes.Contains(folder.Type))
  797. {
  798. m_log.ErrorFormat("[AGENT INVENTORY]: can not give inventory folder {0}", folderId);
  799. return null;
  800. }
  801. if (recipientParentFolderId.IsZero())
  802. {
  803. InventoryFolderBase recipientRootFolder = InventoryService.GetRootFolder(recipientId);
  804. if (recipientRootFolder != null)
  805. recipientParentFolderId = recipientRootFolder.ID;
  806. else
  807. {
  808. m_log.WarnFormat("[AGENT INVENTORY]: Unable to find root folder for receiving agent");
  809. return null;
  810. }
  811. }
  812. UUID newFolderId = UUID.Random();
  813. InventoryFolderBase newFolder = new(
  814. newFolderId, folder.Name, recipientId, folder.Type, recipientParentFolderId, folder.Version);
  815. InventoryService.AddFolder(newFolder);
  816. // Give all the subfolders
  817. InventoryCollection contents = InventoryService.GetFolderContent(senderId, folderId);
  818. // Give all the items (first, this is recursive call)
  819. foreach (InventoryItemBase item in contents.Items)
  820. {
  821. if (GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID, out string message) is null)
  822. {
  823. client?.SendAgentAlertMessage(message, false);
  824. }
  825. }
  826. contents.Items = null;
  827. foreach (InventoryFolderBase childFolder in contents.Folders)
  828. {
  829. GiveInventoryFolder(client, recipientId, senderId, childFolder.ID, newFolder.ID);
  830. }
  831. return newFolder;
  832. }
  833. public virtual InventoryFolderBase GiveInventoryFolder(IClientAPI client,
  834. UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId, Dictionary<UUID, AssetType> ids)
  835. {
  836. //// Retrieve the folder from the sender
  837. InventoryFolderBase folder = InventoryService.GetFolder(senderId, folderId);
  838. if (folder is null)
  839. {
  840. m_log.ErrorFormat("[AGENT INVENTORY]: Could not find inventory folder {0} to give", folderId);
  841. return null;
  842. }
  843. if(!ids.Remove(folder.ID))
  844. return null;
  845. if (denyGiveFolderTypes.Contains(folder.Type))
  846. {
  847. m_log.ErrorFormat("[AGENT INVENTORY]: can not give inventory folder {0}", folderId);
  848. return null;
  849. }
  850. if (recipientParentFolderId.IsZero())
  851. {
  852. InventoryFolderBase recipientRootFolder = InventoryService.GetRootFolder(recipientId);
  853. if (recipientRootFolder is not null)
  854. recipientParentFolderId = recipientRootFolder.ID;
  855. else
  856. {
  857. m_log.WarnFormat("[AGENT INVENTORY]: Unable to find root folder for receiving agent");
  858. return null;
  859. }
  860. }
  861. UUID newFolderId = UUID.Random();
  862. InventoryFolderBase newFolder = new(
  863. newFolderId, folder.Name, recipientId, folder.Type, recipientParentFolderId, folder.Version);
  864. InventoryService.AddFolder(newFolder);
  865. InventoryCollection contents = InventoryService.GetFolderContent(senderId, folderId);
  866. if(client is null)
  867. {
  868. foreach (InventoryItemBase item in contents.Items)
  869. {
  870. if (ids.Remove(item.ID))
  871. GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID, out string _);
  872. }
  873. }
  874. else
  875. {
  876. foreach (InventoryItemBase item in contents.Items)
  877. {
  878. if (ids.Remove(item.ID))
  879. {
  880. if (GiveInventoryItem(recipientId, senderId, item.ID, newFolder.ID, out string message) == null)
  881. client.SendAgentAlertMessage(message, false);
  882. }
  883. }
  884. }
  885. contents.Items = null;
  886. foreach (InventoryFolderBase childFolder in contents.Folders)
  887. {
  888. GiveInventoryFolder(client, recipientId, senderId, childFolder.ID, newFolder.ID);
  889. }
  890. return newFolder;
  891. }
  892. public void CopyInventoryItem(IClientAPI remoteClient, uint callbackID, UUID oldAgentID, UUID oldItemID,
  893. UUID newFolderID, string newName)
  894. {
  895. m_log.DebugFormat(
  896. "[AGENT INVENTORY]: CopyInventoryItem received by {0} with oldAgentID {1}, oldItemID {2}, new FolderID {3}, newName {4}",
  897. remoteClient.AgentId, oldAgentID, oldItemID, newFolderID, newName);
  898. InventoryItemBase item = null;
  899. if (LibraryService is not null && LibraryService.LibraryRootFolder is not null)
  900. item = LibraryService.LibraryRootFolder.FindItem(oldItemID);
  901. if (item is null)
  902. {
  903. item = InventoryService.GetItem(remoteClient.AgentId, oldItemID);
  904. if (item is null)
  905. {
  906. m_log.Error("[AGENT INVENTORY]: Failed to find item " + oldItemID.ToString());
  907. return;
  908. }
  909. if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  910. return;
  911. }
  912. if (string.IsNullOrEmpty(newName))
  913. newName = item.Name;
  914. if (remoteClient.AgentId.Equals(oldAgentID)
  915. || (LibraryService is not null
  916. && LibraryService.LibraryRootFolder is not null
  917. && oldAgentID.Equals(LibraryService.LibraryRootFolder.Owner)))
  918. {
  919. CreateNewInventoryItem(
  920. remoteClient, item.CreatorId, item.CreatorData, newFolderID,
  921. newName, item.Description, item.Flags, callbackID, item.AssetID, (sbyte)item.AssetType, (sbyte)item.InvType,
  922. item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions,
  923. item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
  924. }
  925. else
  926. {
  927. // If item is transfer or permissions are off or calling agent is allowed to copy item owner's inventory item.
  928. if (((item.CurrentPermissions & (uint)PermissionMask.Transfer) != 0)
  929. && (m_permissions.BypassPermissions()
  930. || m_permissions.CanCopyUserInventory(remoteClient.AgentId, oldItemID)))
  931. {
  932. CreateNewInventoryItem(
  933. remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Description, item.Flags, callbackID,
  934. item.AssetID, (sbyte)item.AssetType, (sbyte)item.InvType,
  935. item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions,
  936. item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
  937. }
  938. }
  939. }
  940. /// <summary>
  941. /// Create a new asset data structure.
  942. /// </summary>
  943. public AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data, UUID creatorID)
  944. {
  945. return new AssetBase(UUID.Random(), name, assetType, creatorID.ToString())
  946. {
  947. Description = description,
  948. Data = data ?? (new byte[1])
  949. };
  950. }
  951. /// <summary>
  952. /// Move an item within the agent's inventory, and leave a copy (used in making a new outfit)
  953. /// </summary>
  954. public void MoveInventoryItemsLeaveCopy(IClientAPI remoteClient, List<InventoryItemBase> items, UUID destfolder)
  955. {
  956. List<InventoryItemBase> moveitems = new();
  957. foreach (InventoryItemBase b in items)
  958. {
  959. CopyInventoryItem(remoteClient, 0, remoteClient.AgentId, b.ID, b.Folder, null);
  960. InventoryItemBase n = InventoryService.GetItem(b.Owner, b.ID);
  961. n.Folder = destfolder;
  962. moveitems.Add(n);
  963. remoteClient.SendInventoryItemCreateUpdate(n, 0);
  964. }
  965. MoveInventoryItem(remoteClient, moveitems);
  966. }
  967. /// <summary>
  968. /// Move an item within the agent's inventory.
  969. /// </summary>
  970. /// <param name="remoteClient"></param>
  971. /// <param name="folderID"></param>
  972. /// <param name="itemID"></param>
  973. /// <param name="length"></param>
  974. /// <param name="newName"></param>
  975. public void MoveInventoryItem(IClientAPI remoteClient, List<InventoryItemBase> items)
  976. {
  977. UUID agentId = remoteClient.AgentId;
  978. m_log.DebugFormat(
  979. "[AGENT INVENTORY]: Moving {0} items for user {1}", items.Count, agentId);
  980. if (!InventoryService.MoveItems(agentId, items))
  981. m_log.Warn("[AGENT INVENTORY]: Failed to move items for user " + agentId);
  982. foreach (InventoryItemBase it in items)
  983. {
  984. InventoryItemBase n = InventoryService.GetItem(agentId, it.ID);
  985. if(n is not null)
  986. remoteClient.SendBulkUpdateInventory(n);
  987. }
  988. }
  989. /// <summary>
  990. /// Create a new Inventory Item
  991. /// </summary>
  992. /// <param name="remoteClient">Client creating this inventory item.</param>
  993. /// <param name="creatorID"></param>
  994. /// <param name="creatorData"></param>
  995. /// <param name="folderID">UUID of folder in which this item should be placed.</param>
  996. /// <param name="name">Item name.</para>
  997. /// <param name="description">Item description.</param>
  998. /// <param name="flags">Item flags</param>
  999. /// <param name="callbackID">Generated by the client.</para>
  1000. /// <param name="asset">Asset to which this item refers.</param>
  1001. /// <param name="invType">Type of inventory item.</param>
  1002. /// <param name="baseMask">Base permissions mask.</param>
  1003. /// <param name="currentMask">Current permissions mask.</param>
  1004. /// <param name="everyoneMask">Everyone permissions mask.</param>
  1005. /// <param name="nextOwnerMask">Next owner pemrissions mask.</param>
  1006. /// <param name="groupMask">Group permissions mask.</param>
  1007. /// <param name="creationDate">Unix timestamp at which this item was created.</param>
  1008. public void CreateNewInventoryItem(
  1009. IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
  1010. string name, string description, uint flags, uint callbackID, UUID assetID, sbyte assetType, sbyte invType,
  1011. uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate,
  1012. bool assetUpload)
  1013. {
  1014. CreateNewInventoryItem(
  1015. remoteClient, creatorID, creatorData, folderID,
  1016. name, description, flags, callbackID, assetID, assetType, invType,
  1017. baseMask, currentMask, everyoneMask, nextOwnerMask, groupMask, creationDate);
  1018. }
  1019. public void CreateNewInventoryItem(
  1020. IClientAPI remoteClient, string creatorID, string creatorData, UUID folderID,
  1021. string name, string description, uint flags, uint callbackID, UUID assetID, sbyte assetType, sbyte invType,
  1022. uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate)
  1023. {
  1024. InventoryItemBase item = new()
  1025. {
  1026. Owner = remoteClient.AgentId,
  1027. CreatorId = creatorID,
  1028. CreatorData = creatorData,
  1029. ID = UUID.Random(),
  1030. AssetID = assetID,
  1031. Name = name,
  1032. Description = description,
  1033. Flags = flags,
  1034. AssetType = assetType,
  1035. InvType = invType,
  1036. Folder = folderID,
  1037. CurrentPermissions = currentMask,
  1038. NextPermissions = nextOwnerMask,
  1039. EveryOnePermissions = everyoneMask,
  1040. GroupPermissions = groupMask,
  1041. BasePermissions = baseMask,
  1042. CreationDate = creationDate
  1043. };
  1044. // special AnimationSet case
  1045. if (item.InvType == (int)CustomInventoryType.AnimationSet)
  1046. AnimationSet.enforceItemPermitions(item,true);
  1047. if (AddInventoryItem(item))
  1048. {
  1049. remoteClient.SendInventoryItemCreateUpdate(item, callbackID);
  1050. }
  1051. else
  1052. {
  1053. m_dialogModule.SendAlertToUser(remoteClient, "Failed to create item");
  1054. m_log.WarnFormat(
  1055. "Failed to add item for {0} in CreateNewInventoryItem!",
  1056. remoteClient.Name);
  1057. }
  1058. }
  1059. /// <summary>
  1060. /// Link an inventory item to an existing item.
  1061. /// </summary>
  1062. /// <remarks>
  1063. /// The linkee item id is placed in the asset id slot. This appears to be what the viewer expects when
  1064. /// it receives inventory information.
  1065. /// </remarks>
  1066. /// <param name="remoteClient"></param>
  1067. /// <param name="transActionID"></param>
  1068. /// <param name="folderID"></param>
  1069. /// <param name="callbackID"></param>
  1070. /// <param name="description"></param>
  1071. /// <param name="name"></param>
  1072. /// <param name="invType"></param>
  1073. /// <param name="type">/param>
  1074. /// <param name="olditemID"></param>
  1075. private void HandleLinkInventoryItem(IClientAPI remoteClient, UUID transActionID, UUID folderID,
  1076. uint callbackID, string description, string name,
  1077. sbyte invType, sbyte type, UUID olditemID)
  1078. {
  1079. //m_log.DebugFormat(
  1080. // "[AGENT INVENTORY]: Received request from {0} to create inventory item link {1} in folder {2} pointing to {3}, assetType {4}, inventoryType {5}",
  1081. // remoteClient.Name, name, folderID, olditemID, (AssetType)type, (InventoryType)invType);
  1082. if (!Permissions.CanCreateUserInventory(invType, remoteClient.AgentId))
  1083. return;
  1084. if (TryGetScenePresence(remoteClient.AgentId, out ScenePresence _))
  1085. {
  1086. // Disabled the check for duplicate links.
  1087. //
  1088. // When outfits are being adjusted, the viewer rapidly sends delete link messages followed by
  1089. // create links. However, since these are handled asynchronously, the deletes do not complete before
  1090. // the creates are handled. Therefore, we cannot enforce a duplicate link check.
  1091. // InventoryItemBase existingLink = null;
  1092. // List<InventoryItemBase> existingItems = InventoryService.GetFolderItems(remoteClient.AgentId, folderID);
  1093. // foreach (InventoryItemBase item in existingItems)
  1094. // if (item.AssetID == olditemID)
  1095. // existingLink = item;
  1096. //
  1097. // if (existingLink != null)
  1098. // {
  1099. // m_log.WarnFormat(
  1100. // "[AGENT INVENTORY]: Ignoring request from {0} to create item link {1} in folder {2} pointing to {3} since a link named {4} with id {5} already exists",
  1101. // remoteClient.Name, name, folderID, olditemID, existingLink.Name, existingLink.ID);
  1102. //
  1103. // return;
  1104. // }
  1105. CreateNewInventoryItem(
  1106. remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID,
  1107. name, description, 0, callbackID, olditemID, type, invType,
  1108. (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All,
  1109. (uint)PermissionMask.All | (uint)PermissionMask.Export, (uint)PermissionMask.All | (uint)PermissionMask.Export, Util.UnixTimeSinceEpoch(),
  1110. false);
  1111. }
  1112. else
  1113. {
  1114. m_log.ErrorFormat(
  1115. "ScenePresence for agent uuid {0} unexpectedly not found in HandleLinkInventoryItem",
  1116. remoteClient.AgentId);
  1117. }
  1118. }
  1119. /// <summary>
  1120. /// Remove an inventory item for the client's inventory
  1121. /// </summary>
  1122. /// <param name="remoteClient"></param>
  1123. /// <param name="itemID"></param>
  1124. private void RemoveInventoryItem(IClientAPI remoteClient, List<UUID> itemIDs)
  1125. {
  1126. //m_log.DebugFormat(
  1127. // "[AGENT INVENTORY]: Removing inventory items {0} for {1}",
  1128. // string.Join(",", itemIDs.ConvertAll<string>(uuid => uuid.ToString()).ToArray()),
  1129. // remoteClient.Name);
  1130. InventoryService.DeleteItems(remoteClient.AgentId, itemIDs);
  1131. }
  1132. /// <summary>
  1133. /// Removes an inventory folder. This packet is sent when the user
  1134. /// right-clicks a folder that's already in trash and chooses "purge"
  1135. /// </summary>
  1136. /// <param name="remoteClient"></param>
  1137. /// <param name="folderID"></param>
  1138. private void RemoveInventoryFolder(IClientAPI remoteClient, List<UUID> folderIDs)
  1139. {
  1140. m_log.DebugFormat("[SCENE INVENTORY]: RemoveInventoryFolders count {0}", folderIDs.Count);
  1141. InventoryService.DeleteFolders(remoteClient.AgentId, folderIDs);
  1142. }
  1143. /// <summary>
  1144. /// Send the details of a prim's inventory to the client.
  1145. /// </summary>
  1146. /// <param name="remoteClient"></param>
  1147. /// <param name="primLocalID"></param>
  1148. public void RequestTaskInventory(IClientAPI remoteClient, uint primLocalID)
  1149. {
  1150. SceneObjectPart part = GetSceneObjectPart(primLocalID);
  1151. if (part is null)
  1152. return;
  1153. if (XferManager is not null)
  1154. part.Inventory.RequestInventoryFile(remoteClient, XferManager);
  1155. }
  1156. /// <summary>
  1157. /// Remove an item from a prim (task) inventory
  1158. /// </summary>
  1159. /// <param name="remoteClient">Unused at the moment but retained since the avatar ID might
  1160. /// be necessary for a permissions check at some stage.</param>
  1161. /// <param name="itemID"></param>
  1162. /// <param name="localID"></param>
  1163. public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID)
  1164. {
  1165. SceneObjectPart part = GetSceneObjectPart(localID);
  1166. if (part is null)
  1167. return;
  1168. SceneObjectGroup group = part.ParentGroup;
  1169. if(group is null)
  1170. return;
  1171. if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
  1172. return;
  1173. TaskInventoryItem item = group.GetInventoryItem(localID, itemID);
  1174. if (item is null)
  1175. return;
  1176. InventoryFolderBase destFolder = InventoryService.GetFolderForType(remoteClient.AgentId, FolderType.Trash);
  1177. // Move the item to trash. If this is a copyable item, only
  1178. // a copy will be moved and we will still need to delete
  1179. // the item from the prim. If it was no copy, it will be
  1180. // deleted by this method.
  1181. InventoryItemBase item2 = MoveTaskInventoryItem(remoteClient, destFolder.ID, part, itemID, out string message);
  1182. if (item2 is null)
  1183. {
  1184. m_log.WarnFormat("[SCENE INVENTORY]: RemoveTaskInventory of item {0} failed: {1}", itemID, message);
  1185. remoteClient.SendAgentAlertMessage(message, false);
  1186. return;
  1187. }
  1188. if (group.GetInventoryItem(localID, itemID) is not null)
  1189. {
  1190. if (item.Type == (int)InventoryType.LSL)
  1191. {
  1192. part.RemoveScriptEvents(itemID);
  1193. part.ParentGroup.AddActiveScriptCount(-1);
  1194. }
  1195. group.RemoveInventoryItem(localID, itemID);
  1196. group.InvalidateEffectivePerms();
  1197. }
  1198. part.SendPropertiesToClient(remoteClient);
  1199. }
  1200. /// <summary>
  1201. /// Creates (in memory only) a user inventory item that will contain a copy of a task inventory item.
  1202. /// </summary>
  1203. private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId, out string message)
  1204. {
  1205. TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
  1206. if (taskItem is null)
  1207. {
  1208. m_log.ErrorFormat(
  1209. "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for creating an avatar"
  1210. + " inventory item from a prim's inventory item "
  1211. + " but the required item does not exist in the prim's inventory",
  1212. itemId, part.Name, part.UUID);
  1213. message = "Item not found: " + itemId;
  1214. return null;
  1215. }
  1216. if ((destAgent != taskItem.OwnerID) && ((taskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
  1217. {
  1218. message = "Item doesn't have the Transfer permission.";
  1219. return null;
  1220. }
  1221. InventoryItemBase agentItem = new()
  1222. {
  1223. ID = UUID.Random(),
  1224. CreatorId = taskItem.CreatorID.ToString(),
  1225. CreatorData = taskItem.CreatorData,
  1226. Owner = destAgent,
  1227. AssetID = taskItem.AssetID,
  1228. Description = taskItem.Description,
  1229. Name = taskItem.Name,
  1230. AssetType = taskItem.Type,
  1231. InvType = taskItem.InvType,
  1232. Flags = taskItem.Flags
  1233. };
  1234. // The code below isn't OK. It doesn't account for flags being changed
  1235. // in the object inventory, so it will break when you do it. That
  1236. // is the previous behaviour, so no matter at this moment. However, there is a lot
  1237. // TODO: Fix this after the inventory fixer exists and has beenr run
  1238. if (part.OwnerID.NotEqual(destAgent) && Permissions.PropagatePermissions())
  1239. {
  1240. uint perms = taskItem.BasePermissions & taskItem.NextPermissions;
  1241. if (taskItem.InvType == (int)InventoryType.Object)
  1242. {
  1243. PermissionsUtil.ApplyFoldedPermissions(taskItem.CurrentPermissions, ref perms );
  1244. perms = PermissionsUtil.FixAndFoldPermissions(perms);
  1245. }
  1246. else
  1247. perms &= taskItem.CurrentPermissions;
  1248. // always unlock
  1249. perms |= (uint)PermissionMask.Move;
  1250. agentItem.BasePermissions = perms;
  1251. agentItem.CurrentPermissions = perms;
  1252. agentItem.NextPermissions = perms & taskItem.NextPermissions;
  1253. agentItem.EveryOnePermissions = perms & taskItem.EveryonePermissions;
  1254. agentItem.GroupPermissions = perms & taskItem.GroupPermissions;
  1255. agentItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
  1256. agentItem.Flags &= ~(uint)(InventoryItemFlags.ObjectOverwriteBase | InventoryItemFlags.ObjectOverwriteOwner | InventoryItemFlags.ObjectOverwriteGroup | InventoryItemFlags.ObjectOverwriteEveryone | InventoryItemFlags.ObjectOverwriteNextOwner);
  1257. }
  1258. else
  1259. {
  1260. agentItem.BasePermissions = taskItem.BasePermissions;
  1261. agentItem.CurrentPermissions = taskItem.CurrentPermissions;
  1262. agentItem.NextPermissions = taskItem.NextPermissions;
  1263. agentItem.EveryOnePermissions = taskItem.EveryonePermissions;
  1264. agentItem.GroupPermissions = taskItem.GroupPermissions;
  1265. }
  1266. message = null;
  1267. return agentItem;
  1268. }
  1269. /// <summary>
  1270. /// If the task item is not-copyable then remove it from the prim.
  1271. /// </summary>
  1272. private void RemoveNonCopyTaskItemFromPrim(SceneObjectPart part, UUID itemId)
  1273. {
  1274. TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
  1275. if (taskItem is null)
  1276. return;
  1277. if (!Permissions.BypassPermissions())
  1278. {
  1279. if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  1280. {
  1281. if (taskItem.Type == (int)AssetType.LSLText)
  1282. {
  1283. part.RemoveScriptEvents(itemId);
  1284. part.ParentGroup.AddActiveScriptCount(-1);
  1285. }
  1286. part.Inventory.RemoveInventoryItem(itemId);
  1287. }
  1288. }
  1289. }
  1290. /// <summary>
  1291. /// Move the given item in the given prim to a folder in the client's inventory
  1292. /// </summary>
  1293. /// <param name="remoteClient"></param>
  1294. /// <param name="folderID"></param>
  1295. /// <param name="part"></param>
  1296. /// <param name="itemID"></param>
  1297. public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId, out string message)
  1298. {
  1299. m_log.DebugFormat(
  1300. "[PRIM INVENTORY]: Adding item {0} from {1} to folder {2} for {3}",
  1301. itemId, part.Name, folderId, remoteClient.Name);
  1302. InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId, out message);
  1303. if (agentItem is null)
  1304. return null;
  1305. agentItem.Folder = folderId;
  1306. AddInventoryItem(remoteClient, agentItem);
  1307. RemoveNonCopyTaskItemFromPrim(part, itemId);
  1308. message = null;
  1309. return agentItem;
  1310. }
  1311. /// <summary>
  1312. /// <see>ClientMoveTaskInventoryItem</see>
  1313. /// </summary>
  1314. /// <param name="remoteClient"></param>
  1315. /// <param name="folderID"></param>
  1316. /// <param name="primLocalID"></param>
  1317. /// <param name="itemID"></param>
  1318. public void ClientMoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, uint primLocalId, UUID itemId)
  1319. {
  1320. // Can't move a null item
  1321. if (itemId.IsZero())
  1322. return;
  1323. SceneObjectPart part = GetSceneObjectPart(primLocalId);
  1324. if (part is null)
  1325. {
  1326. m_log.WarnFormat(
  1327. "[PRIM INVENTORY]: " +
  1328. "Move of inventory item {0} from prim with local id {1} failed because the prim could not be found",
  1329. itemId, primLocalId);
  1330. return;
  1331. }
  1332. TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
  1333. if (taskItem is null)
  1334. {
  1335. m_log.WarnFormat("[PRIM INVENTORY]: Move of inventory item {0} from prim with local id {1} failed"
  1336. + " because the inventory item could not be found",
  1337. itemId, primLocalId);
  1338. return;
  1339. }
  1340. if (!Permissions.CanCopyObjectInventory(itemId, part.UUID, remoteClient.AgentId))
  1341. return;
  1342. InventoryItemBase item = MoveTaskInventoryItem(remoteClient, folderId, part, itemId, out string message);
  1343. if (item is null)
  1344. remoteClient.SendAgentAlertMessage(message, false);
  1345. }
  1346. /// <summary>
  1347. /// <see>MoveTaskInventoryItem</see>
  1348. /// </summary>
  1349. /// <param name="remoteClient"></param>
  1350. /// <param name="folderID">
  1351. /// The user inventory folder to move (or copy) the item to. If null, then the most
  1352. /// suitable system folder is used (e.g. the Objects folder for objects). If there is no suitable folder, then
  1353. /// the item is placed in the user's root inventory folder
  1354. /// </param>
  1355. /// <param name="part"></param>
  1356. /// <param name="itemID"></param>
  1357. public InventoryItemBase MoveTaskInventoryItem(UUID avatarId, UUID folderId, SceneObjectPart part, UUID itemId, out string message)
  1358. {
  1359. if (TryGetScenePresence(avatarId, out ScenePresence avatar))
  1360. {
  1361. return MoveTaskInventoryItem(avatar.ControllingClient, folderId, part, itemId, out message);
  1362. }
  1363. else
  1364. {
  1365. InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(avatarId, part, itemId, out message);
  1366. if (agentItem is null)
  1367. return null;
  1368. agentItem.Folder = folderId;
  1369. AddInventoryItem(agentItem);
  1370. RemoveNonCopyTaskItemFromPrim(part, itemId);
  1371. return agentItem;
  1372. }
  1373. }
  1374. /// <summary>
  1375. /// Copy a task (prim) inventory item to another task (prim)
  1376. /// </summary>
  1377. /// <param name="destId">ID of destination part</param>
  1378. /// <param name="part">Source part</param>
  1379. /// <param name="itemId">Source item id to transfer</param>
  1380. public void MoveTaskInventoryItem(UUID destId, SceneObjectPart part, UUID itemId)
  1381. {
  1382. TaskInventoryItem srcTaskItem = part.Inventory.GetInventoryItem(itemId);
  1383. if (srcTaskItem is null)
  1384. {
  1385. m_log.ErrorFormat(
  1386. "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for moving"
  1387. + " but the item does not exist in this inventory",
  1388. itemId, part.Name, part.UUID);
  1389. return;
  1390. }
  1391. SceneObjectPart destPart = GetSceneObjectPart(destId);
  1392. if (destPart is null)
  1393. {
  1394. m_log.ErrorFormat(
  1395. "[PRIM INVENTORY]: " +
  1396. "Could not find prim for ID {0}",
  1397. destId);
  1398. return;
  1399. }
  1400. if(!Permissions.CanDoObjectInvToObjectInv(srcTaskItem, part, destPart))
  1401. return;
  1402. TaskInventoryItem destTaskItem = new()
  1403. {
  1404. ItemID = UUID.Random(),
  1405. CreatorID = srcTaskItem.CreatorID,
  1406. CreatorData = srcTaskItem.CreatorData,
  1407. AssetID = srcTaskItem.AssetID,
  1408. GroupID = destPart.GroupID,
  1409. OwnerID = destPart.OwnerID,
  1410. ParentID = destPart.UUID,
  1411. ParentPartID = destPart.UUID,
  1412. BasePermissions = srcTaskItem.BasePermissions,
  1413. EveryonePermissions = srcTaskItem.EveryonePermissions,
  1414. GroupPermissions = srcTaskItem.GroupPermissions,
  1415. CurrentPermissions = srcTaskItem.CurrentPermissions,
  1416. NextPermissions = srcTaskItem.NextPermissions,
  1417. Flags = srcTaskItem.Flags
  1418. };
  1419. if (destPart.OwnerID.NotEqual(part.OwnerID))
  1420. {
  1421. if (Permissions.PropagatePermissions())
  1422. {
  1423. destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions &
  1424. (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
  1425. destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions &
  1426. (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
  1427. destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions &
  1428. (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
  1429. destTaskItem.BasePermissions = srcTaskItem.BasePermissions &
  1430. (srcTaskItem.NextPermissions | (uint)PermissionMask.Move);
  1431. destTaskItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
  1432. }
  1433. }
  1434. destTaskItem.Description = srcTaskItem.Description;
  1435. destTaskItem.Name = srcTaskItem.Name;
  1436. destTaskItem.InvType = srcTaskItem.InvType;
  1437. destTaskItem.Type = srcTaskItem.Type;
  1438. destPart.Inventory.AddInventoryItem(destTaskItem, part.OwnerID != destPart.OwnerID);
  1439. if ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  1440. {
  1441. part.Inventory.RemoveInventoryItem(itemId);
  1442. }
  1443. if (TryGetScenePresence(srcTaskItem.OwnerID, out ScenePresence avatar))
  1444. {
  1445. destPart.SendPropertiesToClient(avatar.ControllingClient);
  1446. }
  1447. }
  1448. public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items, bool sendUpdates = true)
  1449. {
  1450. IClientAPI remoteClient = null;
  1451. if (TryGetScenePresence(destID, out ScenePresence avatar))
  1452. remoteClient = avatar.ControllingClient;
  1453. SceneObjectPart destPart = GetSceneObjectPart(destID);
  1454. if (destPart is not null) // Move into a prim
  1455. {
  1456. foreach(UUID itemID in items)
  1457. MoveTaskInventoryItem(destID, host, itemID);
  1458. return destID; // Prim folder ID == prim ID
  1459. }
  1460. // move to a avatar inventory
  1461. if(remoteClient is null)
  1462. return UUID.Zero;
  1463. InventoryFolderBase rootFolder = InventoryService.GetRootFolder(destID);
  1464. if(rootFolder is null)
  1465. return UUID.Zero;
  1466. UUID newFolderID = UUID.Random();
  1467. InventoryFolderBase newFolder = new(newFolderID, category, destID, -1, rootFolder.ID, rootFolder.Version);
  1468. InventoryService.AddFolder(newFolder);
  1469. foreach (UUID itemID in items)
  1470. {
  1471. InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(destID, host, itemID, out string message);
  1472. if (agentItem is not null)
  1473. {
  1474. agentItem.Folder = newFolderID;
  1475. AddInventoryItem(agentItem);
  1476. RemoveNonCopyTaskItemFromPrim(host, itemID);
  1477. }
  1478. else
  1479. {
  1480. remoteClient.SendAgentAlertMessage(message, false);
  1481. }
  1482. }
  1483. if(sendUpdates)
  1484. {
  1485. SendInventoryUpdate(remoteClient, rootFolder, true, false);
  1486. SendInventoryUpdate(remoteClient, newFolder, false, true);
  1487. }
  1488. return newFolderID;
  1489. }
  1490. public void SendInventoryUpdate(IClientAPI client, InventoryFolderBase folder, bool fetchFolders, bool fetchItems)
  1491. {
  1492. if (folder is null)
  1493. return;
  1494. // TODO: This code for looking in the folder for the library should be folded somewhere else
  1495. // so that this class doesn't have to know the details (and so that multiple libraries, etc.
  1496. // can be handled transparently).
  1497. InventoryFolderImpl fold;
  1498. if (LibraryService is not null && LibraryService.LibraryRootFolder is not null)
  1499. {
  1500. if ((fold = LibraryService.LibraryRootFolder.FindFolder(folder.ID)) is not null)
  1501. {
  1502. List<InventoryItemBase> its = fold.RequestListOfItems();
  1503. List<InventoryFolderBase> fds = fold.RequestListOfFolders();
  1504. client.SendInventoryFolderDetails(
  1505. fold.Owner, folder.ID, its, fds,
  1506. fold.Version, its.Count + fds.Count, fetchFolders, fetchItems);
  1507. return;
  1508. }
  1509. }
  1510. // Fetch the folder contents
  1511. InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID);
  1512. // Fetch the folder itself to get its current version
  1513. InventoryFolderBase containingFolder = InventoryService.GetFolder(client.AgentId, folder.ID);
  1514. //m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}",
  1515. // contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName);
  1516. if (containingFolder is not null )
  1517. {
  1518. int descendents = contents.Folders.Count + contents.Items.Count;
  1519. if(fetchItems && contents.Items.Count > 0)
  1520. {
  1521. var linksIDs = new HashSet<UUID>();
  1522. var links = new List<InventoryItemBase>();
  1523. for (int i = 0; i < contents.Items.Count; ++i)
  1524. {
  1525. InventoryItemBase item = contents.Items[i];
  1526. if (item.AssetType == (int)AssetType.Link)
  1527. {
  1528. if(linksIDs.Contains(item.AssetID))
  1529. continue;
  1530. InventoryItemBase linkedItem = InventoryService.GetItem(item.Owner, item.AssetID);
  1531. if (linkedItem is not null && linkedItem.AssetType != (int)AssetType.Link &&
  1532. linkedItem.AssetType != (int)AssetType.LinkFolder)
  1533. {
  1534. links.Add(linkedItem);
  1535. linksIDs.Add(linkedItem.ID);
  1536. }
  1537. }
  1538. }
  1539. if(links.Count > 0)
  1540. {
  1541. links.AddRange(contents.Items);
  1542. contents.Items = links;
  1543. }
  1544. }
  1545. client.SendInventoryFolderDetails(
  1546. client.AgentId, folder.ID, contents.Items, contents.Folders,
  1547. containingFolder.Version, descendents, fetchFolders, fetchItems);
  1548. }
  1549. }
  1550. /// <summary>
  1551. /// Update an item in a prim (task) inventory.
  1552. /// This method does not handle scripts, <see>RezScript(IClientAPI, UUID, unit)</see>
  1553. /// </summary>
  1554. /// <param name="remoteClient"></param>
  1555. /// <param name="transactionID"></param>
  1556. /// <param name="itemInfo"></param>
  1557. /// <param name="primLocalID"></param>
  1558. public void UpdateTaskInventory(IClientAPI remoteClient, UUID transactionID, TaskInventoryItem itemInfo,
  1559. uint primLocalID)
  1560. {
  1561. UUID itemID = itemInfo.ItemID;
  1562. if (itemID.IsZero())
  1563. {
  1564. m_log.ErrorFormat(
  1565. "[PRIM INVENTORY]: UpdateTaskInventory called with item ID Zero on update for {1}!",
  1566. remoteClient.Name);
  1567. return;
  1568. }
  1569. // Find the prim we're dealing with
  1570. SceneObjectPart part = GetSceneObjectPart(primLocalID);
  1571. if(part is null)
  1572. {
  1573. m_log.WarnFormat(
  1574. "[PRIM INVENTORY]: " +
  1575. "Update with item {0} requested of prim {1} for {2} but this prim does not exist",
  1576. itemID, primLocalID, remoteClient.Name);
  1577. return;
  1578. }
  1579. TaskInventoryItem currentItem = part.Inventory.GetInventoryItem(itemID);
  1580. if (currentItem == null)
  1581. {
  1582. InventoryItemBase item = InventoryService.GetItem(remoteClient.AgentId, itemID);
  1583. // if not found Try library
  1584. if (item is null && LibraryService is not null && LibraryService.LibraryRootFolder is not null)
  1585. item = LibraryService.LibraryRootFolder.FindItem(itemID);
  1586. if(item is null)
  1587. {
  1588. m_log.ErrorFormat(
  1589. "[PRIM INVENTORY]: Could not find inventory item {0} to update for {1}!",
  1590. itemID, remoteClient.Name);
  1591. return;
  1592. }
  1593. if (!Permissions.CanDropInObjectInv(item, remoteClient, part))
  1594. return;
  1595. UUID copyID = UUID.Random();
  1596. bool modrights = Permissions.CanEditObject(part.ParentGroup, remoteClient);
  1597. part.ParentGroup.AddInventoryItem(remoteClient.AgentId, primLocalID, item, copyID, modrights);
  1598. m_log.InfoFormat(
  1599. "[PRIM INVENTORY]: Update with item {0} requested of prim {1} for {2}",
  1600. item.Name, primLocalID, remoteClient.Name);
  1601. part.SendPropertiesToClient(remoteClient);
  1602. if (!Permissions.BypassPermissions())
  1603. {
  1604. if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  1605. {
  1606. List<UUID> uuids = new() { itemID };
  1607. RemoveInventoryItem(remoteClient, uuids);
  1608. }
  1609. }
  1610. }
  1611. else // Updating existing item with new perms etc
  1612. {
  1613. //m_log.DebugFormat(
  1614. // "[PRIM INVENTORY]: Updating item {0} in {1} for UpdateTaskInventory()",
  1615. // currentItem.Name, part.Name);
  1616. if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
  1617. return;
  1618. // Only look for an uploaded updated asset if we are passed a transaction ID. This is only the
  1619. // case for updates uploded through UDP. Updates uploaded via a capability (e.g. a script update)
  1620. // will not pass in a transaction ID in the update message.
  1621. if (transactionID.IsNotZero() && AgentTransactionsModule is not null)
  1622. {
  1623. AgentTransactionsModule.HandleTaskItemUpdateFromTransaction(
  1624. remoteClient, part, transactionID, currentItem);
  1625. //if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
  1626. // remoteClient.SendAgentAlertMessage("Notecard saved", false);
  1627. //else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
  1628. // remoteClient.SendAgentAlertMessage("Script saved", false);
  1629. //else
  1630. // remoteClient.SendAgentAlertMessage("Item saved", false);
  1631. }
  1632. // Base ALWAYS has move
  1633. currentItem.BasePermissions |= (uint)PermissionMask.Move;
  1634. itemInfo.Flags = currentItem.Flags;
  1635. // Check if we're allowed to mess with permissions
  1636. if (!Permissions.IsGod(remoteClient.AgentId)) // Not a god
  1637. {
  1638. bool noChange;
  1639. if (remoteClient.AgentId.NotEqual(part.OwnerID)) // Not owner
  1640. {
  1641. noChange = true;
  1642. if(itemInfo.OwnerID.IsZero() && itemInfo.GroupID.IsNotZero())
  1643. {
  1644. if(remoteClient.IsGroupMember(itemInfo.GroupID))
  1645. {
  1646. ulong powers = remoteClient.GetGroupPowers(itemInfo.GroupID);
  1647. if((powers & (ulong)GroupPowers.ObjectManipulate) != 0)
  1648. noChange = false;
  1649. }
  1650. }
  1651. }
  1652. else
  1653. noChange = false;
  1654. if(noChange)
  1655. {
  1656. // Friends and group members can't change any perms
  1657. itemInfo.BasePermissions = currentItem.BasePermissions;
  1658. itemInfo.EveryonePermissions = currentItem.EveryonePermissions;
  1659. itemInfo.GroupPermissions = currentItem.GroupPermissions;
  1660. itemInfo.NextPermissions = currentItem.NextPermissions;
  1661. itemInfo.CurrentPermissions = currentItem.CurrentPermissions;
  1662. }
  1663. else
  1664. {
  1665. // Owner can't change base, and can change other
  1666. // only up to base
  1667. itemInfo.BasePermissions = currentItem.BasePermissions;
  1668. if (itemInfo.EveryonePermissions != currentItem.EveryonePermissions)
  1669. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
  1670. if (itemInfo.GroupPermissions != currentItem.GroupPermissions)
  1671. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
  1672. if (itemInfo.CurrentPermissions != currentItem.CurrentPermissions)
  1673. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteOwner;
  1674. if (itemInfo.NextPermissions != currentItem.NextPermissions)
  1675. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
  1676. itemInfo.EveryonePermissions &= currentItem.BasePermissions;
  1677. itemInfo.GroupPermissions &= currentItem.BasePermissions;
  1678. itemInfo.CurrentPermissions &= currentItem.BasePermissions;
  1679. itemInfo.NextPermissions &= currentItem.BasePermissions;
  1680. }
  1681. }
  1682. else
  1683. {
  1684. if (itemInfo.BasePermissions != currentItem.BasePermissions)
  1685. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteBase;
  1686. if (itemInfo.EveryonePermissions != currentItem.EveryonePermissions)
  1687. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteEveryone;
  1688. if (itemInfo.GroupPermissions != currentItem.GroupPermissions)
  1689. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteGroup;
  1690. if (itemInfo.CurrentPermissions != currentItem.CurrentPermissions)
  1691. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteOwner;
  1692. if (itemInfo.NextPermissions != currentItem.NextPermissions)
  1693. itemInfo.Flags |= (uint)InventoryItemFlags.ObjectOverwriteNextOwner;
  1694. }
  1695. // Next ALWAYS has move
  1696. itemInfo.NextPermissions |= (uint)PermissionMask.Move;
  1697. if (part.Inventory.UpdateInventoryItem(itemInfo))
  1698. {
  1699. part.SendPropertiesToClient(remoteClient);
  1700. }
  1701. }
  1702. }
  1703. /// <summary>
  1704. /// Rez a script into a prim's inventory, either ex nihilo or from an existing avatar inventory
  1705. /// </summary>
  1706. /// <param name="remoteClient"></param>
  1707. /// <param name="itemBase"> </param>
  1708. /// <param name="transactionID"></param>
  1709. /// <param name="localID"></param>
  1710. public void RezScript(IClientAPI remoteClient, InventoryItemBase itemBase, UUID transactionID, uint localID)
  1711. {
  1712. SceneObjectPart partWhereRezzed;
  1713. if (itemBase.ID.IsZero())
  1714. partWhereRezzed = RezNewScript(remoteClient.AgentId, itemBase);
  1715. else
  1716. partWhereRezzed = RezScriptFromAgentInventory(remoteClient.AgentId, itemBase.ID, localID);
  1717. partWhereRezzed?.SendPropertiesToClient(remoteClient);
  1718. }
  1719. /// <summary>
  1720. /// Rez a script into a prim from an agent inventory.
  1721. /// </summary>
  1722. /// <param name="agentID"></param>
  1723. /// <param name="fromItemID"></param>
  1724. /// <param name="localID"></param>
  1725. /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
  1726. public SceneObjectPart RezScriptFromAgentInventory(UUID agentID, UUID fromItemID, uint localID)
  1727. {
  1728. UUID copyID = UUID.Random();
  1729. InventoryItemBase item = InventoryService.GetItem(agentID, fromItemID);
  1730. // Try library
  1731. // XXX clumsy, possibly should be one call
  1732. if (item is null && LibraryService is not null && LibraryService.LibraryRootFolder is not null)
  1733. {
  1734. item = LibraryService.LibraryRootFolder.FindItem(fromItemID);
  1735. }
  1736. if (item is not null)
  1737. {
  1738. SceneObjectPart part = GetSceneObjectPart(localID);
  1739. if (part is not null)
  1740. {
  1741. if (!Permissions.CanEditObjectInventory(part.UUID, agentID))
  1742. return null;
  1743. part.ParentGroup.AddInventoryItem(agentID, localID, item, copyID);
  1744. // TODO: switch to posting on_rez here when scripts
  1745. // have state in inventory
  1746. part.Inventory.CreateScriptInstance(copyID, 0, false, DefaultScriptEngine, 0);
  1747. // tell anyone watching that there is a new script in town
  1748. EventManager.TriggerNewScript(agentID, part, copyID);
  1749. //m_log.InfoFormat("[PRIMINVENTORY]: " +
  1750. // "Rezzed script {0} into prim local ID {1} for user {2}",
  1751. // item.inventoryName, localID, remoteClient.Name);
  1752. part.ParentGroup.ResumeScripts();
  1753. return part;
  1754. }
  1755. else
  1756. {
  1757. m_log.ErrorFormat(
  1758. "[PRIM INVENTORY]: " +
  1759. "Could not rez script {0} into prim local ID {1} for user {2}"
  1760. + " because the prim could not be found in the region!",
  1761. item.Name, localID, agentID);
  1762. }
  1763. }
  1764. else
  1765. {
  1766. m_log.ErrorFormat(
  1767. "[PRIM INVENTORY]: Could not find script inventory item {0} to rez for {1}!",
  1768. fromItemID, agentID);
  1769. }
  1770. return null;
  1771. }
  1772. /// <summary>
  1773. /// Rez a new script from nothing.
  1774. /// </summary>
  1775. /// <param name="remoteClient"></param>
  1776. /// <param name="itemBase"></param>
  1777. /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
  1778. public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
  1779. {
  1780. return RezNewScript(agentID, itemBase, null);
  1781. }
  1782. /// <summary>
  1783. /// Rez a new script from nothing with given script text.
  1784. /// </summary>
  1785. /// <param name="remoteClient"></param>
  1786. /// <param name="itemBase">Template item.</param>
  1787. /// <param name="scriptText"></param>
  1788. /// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
  1789. public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase, string scriptText)
  1790. {
  1791. // The part ID is the folder ID!
  1792. SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
  1793. if (part is null)
  1794. {
  1795. //m_log.DebugFormat(
  1796. // "[SCENE INVENTORY]: Could not find part with id {0} for {1} to rez new script",
  1797. // itemBase.Folder, agentID);
  1798. return null;
  1799. }
  1800. if (!Permissions.CanCreateObjectInventory(itemBase.InvType, part.UUID, agentID))
  1801. {
  1802. //m_log.DebugFormat(
  1803. // "[SCENE INVENTORY]: No permission to create new script in {0} for {1}", part.Name, agentID);
  1804. return null;
  1805. }
  1806. UUID assetID;
  1807. if (scriptText is null)
  1808. assetID = Constants.DefaultScriptID;
  1809. else
  1810. {
  1811. AssetBase asset = CreateAsset(
  1812. itemBase.Name, itemBase.Description,
  1813. (sbyte)AssetType.LSLText,
  1814. Encoding.ASCII.GetBytes(scriptText),
  1815. agentID);
  1816. AssetService.Store(asset);
  1817. assetID = asset.FullID;
  1818. }
  1819. TaskInventoryItem taskItem = new()
  1820. {
  1821. ItemID = UUID.Random(),
  1822. OldItemID = UUID.Zero,
  1823. ParentPartID = itemBase.Folder,
  1824. ParentID = itemBase.Folder,
  1825. CreationDate = (uint)itemBase.CreationDate,
  1826. Name = itemBase.Name,
  1827. Description = itemBase.Description,
  1828. Type = itemBase.AssetType,
  1829. InvType = itemBase.InvType,
  1830. OwnerID = itemBase.Owner,
  1831. CreatorID = itemBase.CreatorIdAsUuid,
  1832. BasePermissions = itemBase.BasePermissions,
  1833. CurrentPermissions = itemBase.CurrentPermissions,
  1834. EveryonePermissions = itemBase.EveryOnePermissions,
  1835. //GroupPermissions = itemBase.GroupPermissions,
  1836. GroupPermissions = 0,
  1837. NextPermissions = itemBase.NextPermissions,
  1838. GroupID = itemBase.GroupID,
  1839. Flags = itemBase.Flags,
  1840. PermsGranter = UUID.Zero,
  1841. PermsMask = 0,
  1842. AssetID = assetID
  1843. };
  1844. part.Inventory.AddInventoryItem(taskItem, false);
  1845. part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 1);
  1846. part.ParentGroup.InvalidateEffectivePerms();
  1847. // tell anyone managing scripts that a new script exists
  1848. EventManager.TriggerNewScript(agentID, part, taskItem.ItemID);
  1849. part.ParentGroup.ResumeScripts();
  1850. return part;
  1851. }
  1852. /// <summary>
  1853. /// Rez a script into a prim's inventory from another prim
  1854. /// </summary>
  1855. /// <param name="remoteClient"></param>
  1856. /// <param name="srcPart"> </param>
  1857. /// <param name="destId"> </param>
  1858. /// <param name="pin"></param>
  1859. /// <param name="running"></param>
  1860. /// <param name="start_param"></param>
  1861. public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
  1862. {
  1863. TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
  1864. if (srcTaskItem is null)
  1865. {
  1866. m_log.ErrorFormat(
  1867. "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for rezzing a script but the "
  1868. + " item does not exist in this inventory",
  1869. srcId, srcPart.Name, srcPart.UUID);
  1870. return;
  1871. }
  1872. SceneObjectPart destPart = GetSceneObjectPart(destId);
  1873. if (destPart is null)
  1874. {
  1875. m_log.ErrorFormat(
  1876. "[PRIM INVENTORY]: Could not find part {0} to insert script item {1} from {2} {3} in {4}",
  1877. destId, srcId, srcPart.Name, srcPart.UUID, Name);
  1878. return;
  1879. }
  1880. // Must own the object, and have modify rights
  1881. if (srcPart.OwnerID.NotEqual(destPart.OwnerID))
  1882. {
  1883. // Group permissions
  1884. if ((destPart.GroupID.IsZero()) || (destPart.GroupID.NotEqual(srcPart.GroupID)) ||
  1885. ((destPart.GroupMask & (uint)PermissionMask.Modify) == 0))
  1886. return;
  1887. if((srcPart.OwnerMask & (uint)PermissionMask.Transfer) == 0)
  1888. return;
  1889. }
  1890. else
  1891. {
  1892. if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
  1893. return;
  1894. }
  1895. if (destPart.ScriptAccessPin == 0 || destPart.ScriptAccessPin != pin)
  1896. {
  1897. m_log.WarnFormat(
  1898. "[PRIM INVENTORY]: " +
  1899. "Script in object {0} : {1}, attempted to load script {2} : {3} into object {4} : {5} with invalid pin {6}",
  1900. srcPart.Name, srcId, srcTaskItem.Name, srcTaskItem.ItemID, destPart.Name, destId, pin);
  1901. // the LSL Wiki says we are supposed to shout on the DEBUG_CHANNEL -
  1902. // "Object: Task Object trying to illegally load script onto task Other_Object!"
  1903. // How do we shout from in here?
  1904. return;
  1905. }
  1906. TaskInventoryItem destTaskItem = new()
  1907. {
  1908. ItemID = UUID.Random(),
  1909. CreatorID = srcTaskItem.CreatorID,
  1910. CreatorData = srcTaskItem.CreatorData,
  1911. AssetID = srcTaskItem.AssetID,
  1912. GroupID = destPart.GroupID,
  1913. OwnerID = destPart.OwnerID,
  1914. ParentID = destPart.UUID,
  1915. ParentPartID = destPart.UUID,
  1916. BasePermissions = srcTaskItem.BasePermissions,
  1917. EveryonePermissions = srcTaskItem.EveryonePermissions,
  1918. GroupPermissions = srcTaskItem.GroupPermissions,
  1919. CurrentPermissions = srcTaskItem.CurrentPermissions,
  1920. NextPermissions = srcTaskItem.NextPermissions,
  1921. Flags = srcTaskItem.Flags
  1922. };
  1923. if (destPart.OwnerID.NotEqual(srcPart.OwnerID))
  1924. {
  1925. if (Permissions.PropagatePermissions())
  1926. {
  1927. destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions &
  1928. srcTaskItem.NextPermissions;
  1929. destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions &
  1930. srcTaskItem.NextPermissions;
  1931. destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions &
  1932. srcTaskItem.NextPermissions;
  1933. destTaskItem.BasePermissions = srcTaskItem.BasePermissions &
  1934. srcTaskItem.NextPermissions;
  1935. destTaskItem.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm;
  1936. }
  1937. }
  1938. destTaskItem.Description = srcTaskItem.Description;
  1939. destTaskItem.Name = srcTaskItem.Name;
  1940. destTaskItem.InvType = srcTaskItem.InvType;
  1941. destTaskItem.Type = srcTaskItem.Type;
  1942. destTaskItem.ScriptRunning = running != 0;
  1943. destPart.Inventory.AddInventoryItemExclusive(destTaskItem, false);
  1944. destPart.Inventory.CreateScriptInstance(destTaskItem, start_param, false, DefaultScriptEngine, 1);
  1945. destPart.ParentGroup.ResumeScripts();
  1946. if (TryGetScenePresence(srcTaskItem.OwnerID, out ScenePresence avatar))
  1947. {
  1948. destPart.SendPropertiesToClient(avatar.ControllingClient);
  1949. }
  1950. }
  1951. /// <summary>
  1952. /// Derez one or more objects from the scene.
  1953. /// </summary>
  1954. /// <remarks>
  1955. /// Won't actually remove the scene object in the case where the object is being copied to a user inventory.
  1956. /// </remarks>
  1957. /// <param name='remoteClient'>Client requesting derez</param>
  1958. /// <param name='localIDs'>Local ids of root parts of objects to delete.</param>
  1959. /// <param name='groupID'>Not currently used. Here because the client passes this to us.</param>
  1960. /// <param name='action'>DeRezAction</param>
  1961. /// <param name='destinationID'>User folder ID to place derezzed object</param>
  1962. public virtual void DeRezObjects(
  1963. IClientAPI remoteClient, List<uint> localIDs, UUID groupID, DeRezAction action, UUID destinationID, bool AddToReturns = true)
  1964. {
  1965. // First, see of we can perform the requested action and
  1966. // build a list of eligible objects
  1967. List<uint> deleteIDs = new();
  1968. List<SceneObjectGroup> deleteGroups = new();
  1969. List<SceneObjectGroup> takeCopyGroups = new();
  1970. List<SceneObjectGroup> takeDeleteGroups = new();
  1971. List<SceneObjectGroup> noPermtakeCopyGroups = new();
  1972. ScenePresence sp = null;
  1973. if(remoteClient is not null)
  1974. sp = remoteClient.SceneAgent as ScenePresence;
  1975. else if(action != DeRezAction.Return)
  1976. return; // only Return can be called without a client
  1977. // this is not as 0.8x code
  1978. // 0.8x did refuse all operation if not allowed on all objects
  1979. // this will do it on allowed objects
  1980. // current viewers only ask if all allowed
  1981. foreach (uint localID in localIDs)
  1982. {
  1983. // Invalid id
  1984. SceneObjectPart part = GetSceneObjectPart(localID);
  1985. if (part is null)
  1986. {
  1987. //Client still thinks the object exists, kill it
  1988. deleteIDs.Add(localID);
  1989. continue;
  1990. }
  1991. SceneObjectGroup grp = part.ParentGroup;
  1992. if (grp is null || grp.IsDeleted)
  1993. {
  1994. //Client still thinks the object exists, kill it
  1995. deleteIDs.Add(localID);
  1996. continue;
  1997. }
  1998. // Can't delete child prims
  1999. if (part != grp.RootPart)
  2000. continue;
  2001. if (grp.IsAttachment)
  2002. {
  2003. if(!sp.IsGod || action != DeRezAction.Return || action != DeRezAction.Delete)
  2004. continue;
  2005. // this may break the attachment, but its a security action
  2006. // viewers don't allow it anyways
  2007. }
  2008. // If child prims have invalid perms, fix them
  2009. grp.AdjustChildPrimPermissions(false);
  2010. switch (action)
  2011. {
  2012. case DeRezAction.SaveToExistingUserInventoryItem:
  2013. {
  2014. if (Permissions.CanTakeCopyObject(grp, sp))
  2015. takeCopyGroups.Add(grp);
  2016. break;
  2017. }
  2018. case DeRezAction.TakeCopy:
  2019. {
  2020. if (Permissions.CanTakeCopyObject(grp, sp))
  2021. takeCopyGroups.Add(grp);
  2022. else
  2023. noPermtakeCopyGroups.Add(grp);
  2024. break;
  2025. }
  2026. case DeRezAction.Take:
  2027. {
  2028. if (Permissions.CanTakeObject(grp, sp))
  2029. takeDeleteGroups.Add(grp);
  2030. break;
  2031. }
  2032. case DeRezAction.GodTakeCopy:
  2033. {
  2034. if((remoteClient is not null) && Permissions.IsGod(remoteClient.AgentId))
  2035. takeCopyGroups.Add(grp);
  2036. break;
  2037. }
  2038. case DeRezAction.Delete:
  2039. {
  2040. if (Permissions.CanDeleteObject(grp, remoteClient))
  2041. {
  2042. if(m_useTrashOnDelete || (sp.IsGod && grp.OwnerID.NotEqual(sp.UUID)))
  2043. takeDeleteGroups.Add(grp);
  2044. else
  2045. deleteGroups.Add(grp);
  2046. }
  2047. break;
  2048. }
  2049. case DeRezAction.Return:
  2050. {
  2051. if (remoteClient is not null)
  2052. {
  2053. if (Permissions.CanReturnObjects( null, remoteClient, new List<SceneObjectGroup>() {grp}))
  2054. {
  2055. takeDeleteGroups.Add(grp);
  2056. if (AddToReturns)
  2057. AddReturn(grp.OwnerID.Equals(grp.GroupID) ? grp.LastOwnerID : grp.OwnerID, grp.Name, grp.AbsolutePosition,
  2058. "parcel owner return");
  2059. }
  2060. }
  2061. else // Auto return passes through here with null agent
  2062. {
  2063. takeDeleteGroups.Add(grp);
  2064. }
  2065. break;
  2066. }
  2067. default:
  2068. break;
  2069. }
  2070. }
  2071. if(deleteIDs.Count > 0)
  2072. SendKillObject(deleteIDs);
  2073. if (noPermtakeCopyGroups.Count > 0 && remoteClient is not null)
  2074. {
  2075. if(noPermtakeCopyGroups.Count == 1)
  2076. remoteClient.SendAlertMessage("No permission to take copy object " + noPermtakeCopyGroups[0].Name);
  2077. else
  2078. {
  2079. StringBuilder sb = new(1024);
  2080. sb.Append("No permission to take copy object ");
  2081. int i = 0;
  2082. while(i < noPermtakeCopyGroups.Count - 1)
  2083. {
  2084. sb.Append(noPermtakeCopyGroups[i++].Name);
  2085. sb.Append(", ");
  2086. }
  2087. sb.Append(noPermtakeCopyGroups[i].Name);
  2088. remoteClient.SendAlertMessage(sb.ToString());
  2089. }
  2090. }
  2091. if (takeDeleteGroups.Count > 0)
  2092. {
  2093. m_asyncSceneObjectDeleter.DeleteToInventory(action, destinationID, takeDeleteGroups,
  2094. remoteClient, true);
  2095. }
  2096. if (takeCopyGroups.Count > 0)
  2097. {
  2098. m_asyncSceneObjectDeleter.DeleteToInventory(action, destinationID, takeCopyGroups,
  2099. remoteClient, false);
  2100. }
  2101. if (deleteGroups.Count > 0)
  2102. {
  2103. foreach (SceneObjectGroup g in deleteGroups)
  2104. DeleteSceneObject(g, false);
  2105. }
  2106. }
  2107. public UUID attachObjectAssetStore(IClientAPI remoteClient, SceneObjectGroup grp, UUID AgentId, out UUID itemID)
  2108. {
  2109. itemID = UUID.Zero;
  2110. if (grp is not null)
  2111. {
  2112. Vector3 inventoryStoredPosition = new(
  2113. Math.Min(grp.AbsolutePosition.X, RegionInfo.RegionSizeX - 6),
  2114. Math.Min(grp.AbsolutePosition.Y, RegionInfo.RegionSizeY - 6),
  2115. grp.AbsolutePosition.Z);
  2116. Vector3 originalPosition = grp.AbsolutePosition;
  2117. grp.AbsolutePosition = inventoryStoredPosition;
  2118. string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
  2119. grp.AbsolutePosition = originalPosition;
  2120. SceneObjectPart grpRootPart = grp.RootPart;
  2121. AssetBase asset = CreateAsset(
  2122. grpRootPart.Name,
  2123. grpRootPart.Description,
  2124. (sbyte)AssetType.Object,
  2125. Utils.StringToBytes(sceneObjectXml),
  2126. remoteClient.AgentId);
  2127. AssetService.Store(asset);
  2128. InventoryItemBase item = new()
  2129. {
  2130. CreatorId = grpRootPart.CreatorID.ToString(),
  2131. CreatorData = grpRootPart.CreatorData,
  2132. Owner = remoteClient.AgentId,
  2133. ID = UUID.Random(),
  2134. AssetID = asset.FullID,
  2135. Description = grpRootPart.Description,
  2136. Name = grpRootPart.Name,
  2137. AssetType = asset.Type,
  2138. InvType = (int)InventoryType.Object
  2139. };
  2140. InventoryFolderBase folder = InventoryService.GetFolderForType(remoteClient.AgentId, FolderType.Object);
  2141. if (folder is not null)
  2142. item.Folder = folder.ID;
  2143. else // oopsies
  2144. item.Folder = UUID.Zero;
  2145. // Set up base perms properly
  2146. uint permsBase = (uint)(PermissionMask.Move | PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify);
  2147. permsBase &= grpRootPart.BaseMask;
  2148. permsBase |= (uint)PermissionMask.Move;
  2149. // Make sure we don't lock it
  2150. grpRootPart.NextOwnerMask |= (uint)PermissionMask.Move;
  2151. if (remoteClient.AgentId.NotEqual(grpRootPart.OwnerID) && Permissions.PropagatePermissions())
  2152. {
  2153. item.BasePermissions = permsBase & grpRootPart.NextOwnerMask;
  2154. item.CurrentPermissions = permsBase & grpRootPart.NextOwnerMask;
  2155. item.NextPermissions = permsBase & grpRootPart.NextOwnerMask;
  2156. item.EveryOnePermissions = permsBase & grpRootPart.EveryoneMask & grpRootPart.NextOwnerMask;
  2157. item.GroupPermissions = permsBase & grpRootPart.GroupMask & grpRootPart.NextOwnerMask;
  2158. }
  2159. else
  2160. {
  2161. item.BasePermissions = permsBase;
  2162. item.CurrentPermissions = permsBase & grpRootPart.OwnerMask;
  2163. item.NextPermissions = permsBase & grpRootPart.NextOwnerMask;
  2164. item.EveryOnePermissions = permsBase & grpRootPart.EveryoneMask;
  2165. item.GroupPermissions = permsBase & grpRootPart.GroupMask;
  2166. }
  2167. item.CreationDate = Util.UnixTimeSinceEpoch();
  2168. // sets itemID so client can show item as 'attached' in inventory
  2169. grp.FromItemID = item.ID;
  2170. if (AddInventoryItem(item))
  2171. remoteClient.SendInventoryItemCreateUpdate(item, 0);
  2172. else
  2173. m_dialogModule.SendAlertToUser(remoteClient, "Operation failed");
  2174. itemID = item.ID;
  2175. return item.AssetID;
  2176. }
  2177. return UUID.Zero;
  2178. }
  2179. /// <summary>
  2180. /// Returns the list of Scene Objects in an asset.
  2181. /// </summary>
  2182. /// <remarks>
  2183. /// Returns one object if the asset is a regular object, and multiple objects for a coalesced object.
  2184. /// </remarks>
  2185. /// <param name="assetData">Asset data</param>
  2186. /// <param name="isAttachment">True if the object is an attachment.</param>
  2187. /// <param name="objlist">The objects included in the asset</param>
  2188. /// <param name="veclist">Relative positions of the objects</param>
  2189. /// <param name="bbox">Bounding box of all the objects</param>
  2190. /// <param name="offsetHeight">Offset in the Z axis from the centre of the bounding box
  2191. /// to the centre of the root prim (relevant only when returning a single object)</param>
  2192. /// <returns>
  2193. /// true if returning a single object or deserialization fails, false if returning the coalesced
  2194. /// list of objects
  2195. /// </returns>
  2196. public bool GetObjectsToRez(
  2197. byte[] assetData, bool isAttachment, out List<SceneObjectGroup> objlist, out List<Vector3> veclist,
  2198. out Vector3 bbox, out float offsetHeight)
  2199. {
  2200. objlist = new List<SceneObjectGroup>();
  2201. veclist = new List<Vector3>();
  2202. bbox = Vector3.Zero;
  2203. offsetHeight = 0;
  2204. string xmlData = ExternalRepresentationUtils.SanitizeXml(Utils.BytesToString(assetData));
  2205. try
  2206. {
  2207. using (XmlTextReader wrappedReader = new(xmlData, XmlNodeType.Element, null))
  2208. {
  2209. using (XmlReader reader = XmlReader.Create(wrappedReader, Util.SharedXmlReaderSettings))
  2210. {
  2211. reader.Read();
  2212. bool isSingleObject = reader.Name != "CoalescedObject";
  2213. if (isSingleObject || isAttachment)
  2214. {
  2215. SceneObjectGroup g;
  2216. try
  2217. {
  2218. g = SceneObjectSerializer.FromOriginalXmlFormat(reader);
  2219. }
  2220. catch (Exception e)
  2221. {
  2222. m_log.Error("[AGENT INVENTORY]: Deserialization of xml failed ", e);
  2223. Util.LogFailedXML("[AGENT INVENTORY]:", xmlData);
  2224. g = null;
  2225. }
  2226. if (g is not null)
  2227. {
  2228. objlist.Add(g);
  2229. veclist.Add(Vector3.Zero);
  2230. bbox = g.GetAxisAlignedBoundingBox(out offsetHeight);
  2231. }
  2232. return true;
  2233. }
  2234. else
  2235. {
  2236. XmlDocument doc = new();
  2237. doc.LoadXml(xmlData);
  2238. XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
  2239. XmlElement coll = (XmlElement)e;
  2240. float bx = Convert.ToSingle(coll.GetAttribute("x"));
  2241. float by = Convert.ToSingle(coll.GetAttribute("y"));
  2242. float bz = Convert.ToSingle(coll.GetAttribute("z"));
  2243. bbox = new Vector3(bx, by, bz);
  2244. offsetHeight = 0;
  2245. XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
  2246. foreach (XmlNode n in groups)
  2247. {
  2248. SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
  2249. if (g is not null)
  2250. {
  2251. objlist.Add(g);
  2252. XmlElement el = (XmlElement)n;
  2253. string rawX = el.GetAttribute("offsetx");
  2254. string rawY = el.GetAttribute("offsety");
  2255. string rawZ = el.GetAttribute("offsetz");
  2256. float x = Convert.ToSingle(rawX);
  2257. float y = Convert.ToSingle(rawY);
  2258. float z = Convert.ToSingle(rawZ);
  2259. veclist.Add(new Vector3(x, y, z));
  2260. }
  2261. }
  2262. return false;
  2263. }
  2264. }
  2265. }
  2266. }
  2267. catch (Exception e)
  2268. {
  2269. m_log.Error("[AGENT INVENTORY]: Deserialization of xml failed when looking for CoalescedObject tag ", e);
  2270. Util.LogFailedXML("[AGENT INVENTORY]:", xmlData);
  2271. }
  2272. return true;
  2273. }
  2274. /// <summary>
  2275. /// Event Handler Rez an object into a scene
  2276. /// Calls the non-void event handler
  2277. /// </summary>
  2278. /// <param name="remoteClient"></param>
  2279. /// <param name="itemID"></param>
  2280. /// <param name="rezGroupID"></param>
  2281. /// <param name="RayEnd"></param>
  2282. /// <param name="RayStart"></param>
  2283. /// <param name="RayTargetID"></param>
  2284. /// <param name="BypassRayCast"></param>
  2285. /// <param name="RayEndIsIntersection"></param>
  2286. /// <param name="EveryoneMask"></param>
  2287. /// <param name="GroupMask"></param>
  2288. /// <param name="RezSelected"></param>
  2289. /// <param name="RemoveItem"></param>
  2290. /// <param name="fromTaskID"></param>
  2291. public virtual void RezObject(IClientAPI remoteClient, UUID itemID, UUID rezGroupID,
  2292. Vector3 RayEnd, Vector3 RayStart,
  2293. UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
  2294. bool RezSelected, bool RemoveItem, UUID fromTaskID)
  2295. {
  2296. //m_log.DebugFormat(
  2297. // "[PRIM INVENTORY]: RezObject from {0} for item {1} from task id {2}",
  2298. // remoteClient.Name, itemID, fromTaskID);
  2299. if (fromTaskID.IsZero())
  2300. {
  2301. // rez from user inventory
  2302. IInventoryAccessModule invAccess = RequestModuleInterface<IInventoryAccessModule>();
  2303. invAccess?.RezObject(
  2304. remoteClient, itemID, rezGroupID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
  2305. RezSelected, RemoveItem, fromTaskID, false);
  2306. return;
  2307. }
  2308. // rez from a prim inventory
  2309. SceneObjectPart part = GetSceneObjectPart(fromTaskID);
  2310. if (part is null)
  2311. {
  2312. m_log.ErrorFormat(
  2313. "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such scene object",
  2314. remoteClient.Name, itemID, fromTaskID);
  2315. return;
  2316. }
  2317. TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
  2318. if (item is null)
  2319. {
  2320. m_log.ErrorFormat(
  2321. "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but there is no such item",
  2322. remoteClient.Name, itemID, fromTaskID);
  2323. return;
  2324. }
  2325. if(item.InvType != (int)InventoryType.Object)
  2326. {
  2327. m_log.ErrorFormat(
  2328. "[TASK INVENTORY]: {0} tried to rez item id {1} from object id {2} but item is not a object",
  2329. remoteClient.Name, itemID, fromTaskID);
  2330. return;
  2331. }
  2332. byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0);
  2333. Vector3 scale = new(0.5f, 0.5f, 0.5f);
  2334. Vector3 pos = GetNewRezLocation(
  2335. RayStart, RayEnd, RayTargetID, Quaternion.Identity,
  2336. BypassRayCast, bRayEndIsIntersection, true, scale, false);
  2337. RezObject(part, item, remoteClient.AgentId, rezGroupID, pos, null, Vector3.Zero, 0, false, true, true);
  2338. }
  2339. /// <summary>
  2340. /// Rez an object into the scene from a prim's inventory.
  2341. /// </summary>
  2342. /// <param name="sourcePart"></param>
  2343. /// <param name="item"></param>
  2344. /// <param name="pos">The position of the rezzed object.</param>
  2345. /// <param name="rot">The rotation of the rezzed object. If null, then the rotation stored with the object
  2346. /// will be used if it exists.</param>
  2347. /// <param name="vel">The velocity of the rezzed object.</param>
  2348. /// <param name="param"></param>
  2349. /// <returns>The SceneObjectGroup(s) rezzed, or null if rez was unsuccessful</returns>
  2350. public virtual List<SceneObjectGroup> RezObject(SceneObjectPart sourcePart, TaskInventoryItem item,
  2351. Vector3 pos, Quaternion? rot, Vector3 vel, int param, bool atRoot, bool rezSelected = false)
  2352. {
  2353. return RezObject(sourcePart, item, item.OwnerID, sourcePart.GroupID,
  2354. pos, rot, vel, param, atRoot, rezSelected, false);
  2355. }
  2356. public virtual List<SceneObjectGroup> RezObject(SceneObjectPart sourcePart, TaskInventoryItem item,
  2357. UUID newowner, UUID newgroup,
  2358. Vector3 pos, Quaternion? rot, Vector3 vel, int param, bool atRoot, bool rezSelected, bool humanRez)
  2359. {
  2360. if (item is null)
  2361. return null;
  2362. bool success = sourcePart.Inventory.GetRezReadySceneObjects(item, newowner, newgroup,
  2363. out List<SceneObjectGroup> objlist, out List<Vector3> veclist,
  2364. out Vector3 bbox, out float _);
  2365. if (!success)
  2366. return null;
  2367. int totalPrims = 0;
  2368. foreach (SceneObjectGroup group in objlist)
  2369. totalPrims += group.PrimCount;
  2370. if (!Permissions.CanRezObject(totalPrims, newowner, pos))
  2371. return null;
  2372. if (!Permissions.BypassPermissions())
  2373. {
  2374. if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  2375. sourcePart.Inventory.RemoveInventoryItem(item.ItemID);
  2376. }
  2377. SceneObjectGroup sog;
  2378. bool fixrot = false;
  2379. Quaternion netRot = Quaternion.Identity;
  2380. // position adjust
  2381. if (totalPrims > 1) // nothing to do on a single prim
  2382. {
  2383. if (objlist.Count == 1)
  2384. {
  2385. // current object position is root position
  2386. if(!atRoot)
  2387. {
  2388. sog = objlist[0];
  2389. Quaternion orot = rot ?? sog.RootPart.GetWorldRotation();
  2390. // possible should be bbox, but geometric center looks better
  2391. Vector3 off = sog.GetGeometricCenter();
  2392. //Vector3 off = bbox * 0.5f;
  2393. off *= orot;
  2394. pos -= off;
  2395. }
  2396. }
  2397. else
  2398. {
  2399. //veclist[] are relative to bbox corner with min X,Y and Z
  2400. // rez at root, and rot will be referenced to first object in list
  2401. if (rot is null)
  2402. {
  2403. // use original rotations
  2404. if (atRoot)
  2405. pos -= veclist[0];
  2406. else
  2407. pos -= bbox / 2;
  2408. }
  2409. else
  2410. {
  2411. fixrot = true;
  2412. sog = objlist[0];
  2413. netRot = Quaternion.Conjugate(sog.RootPart.GetWorldRotation());
  2414. netRot *= rot.Value;
  2415. Vector3 off;
  2416. if (atRoot)
  2417. off = veclist[0];
  2418. else
  2419. off = bbox / 2;
  2420. off *= netRot;
  2421. pos -= off;
  2422. }
  2423. }
  2424. }
  2425. UUID rezzerID;
  2426. if(humanRez)
  2427. rezzerID = newowner;
  2428. else
  2429. rezzerID = sourcePart.UUID;
  2430. for (int i = 0; i < objlist.Count; i++)
  2431. {
  2432. SceneObjectGroup group = objlist[i];
  2433. Vector3 curpos;
  2434. if(fixrot)
  2435. curpos = pos + veclist[i] * netRot;
  2436. else
  2437. curpos = pos + veclist[i];
  2438. if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
  2439. {
  2440. group.RootPart.AttachedPos = group.AbsolutePosition;
  2441. group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
  2442. }
  2443. group.RezzerID = rezzerID;
  2444. if (rezSelected)
  2445. {
  2446. group.IsSelected = true;
  2447. group.RootPart.CreateSelected = true;
  2448. }
  2449. if ( i == 0)
  2450. AddNewSceneObject(group, true, curpos, rot, vel);
  2451. else
  2452. {
  2453. Quaternion crot = objlist[i].RootPart.GetWorldRotation();
  2454. if (fixrot)
  2455. {
  2456. crot *= netRot;
  2457. }
  2458. AddNewSceneObject(group, true, curpos, crot, vel);
  2459. }
  2460. // We can only call this after adding the scene object, since the scene object references the scene
  2461. // to find out if scripts should be activated at all.
  2462. group.InvalidateEffectivePerms();
  2463. group.CreateScriptInstances(param, true, DefaultScriptEngine, 3);
  2464. if(humanRez)
  2465. group.ResumeScripts();
  2466. group.ScheduleGroupForUpdate(PrimUpdateFlags.FullUpdatewithAnimMatOvr);
  2467. }
  2468. return objlist;
  2469. }
  2470. public virtual bool returnObjects(SceneObjectGroup[] returnobjects,
  2471. IClientAPI client)
  2472. {
  2473. List<uint> localIDs = new();
  2474. foreach (SceneObjectGroup grp in returnobjects)
  2475. {
  2476. AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition,
  2477. "parcel owner return");
  2478. localIDs.Add(grp.RootPart.LocalId);
  2479. }
  2480. DeRezObjects(client, localIDs, UUID.Zero, DeRezAction.Return,
  2481. UUID.Zero, false);
  2482. return true;
  2483. }
  2484. public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running)
  2485. {
  2486. if (!Permissions.CanEditScript(itemID, objectID, controllingClient.AgentId))
  2487. return;
  2488. SceneObjectPart part = GetSceneObjectPart(objectID);
  2489. if (part is null)
  2490. return;
  2491. if (running)
  2492. EventManager.TriggerStartScript(part.LocalId, itemID);
  2493. else
  2494. EventManager.TriggerStopScript(part.LocalId, itemID);
  2495. }
  2496. public void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
  2497. {
  2498. EventManager.TriggerGetScriptRunning(controllingClient, objectID, itemID);
  2499. }
  2500. void ObjectOwner(IClientAPI remoteClient, UUID ownerID, UUID groupID, List<uint> localIDs)
  2501. {
  2502. if (!Permissions.IsGod(remoteClient.AgentId))
  2503. {
  2504. if (ownerID.IsNotZero())
  2505. return;
  2506. }
  2507. List<SceneObjectGroup> groups = new();
  2508. foreach (uint localID in localIDs)
  2509. {
  2510. SceneObjectPart part = GetSceneObjectPart(localID);
  2511. if (part is null)
  2512. continue;
  2513. if (!groups.Contains(part.ParentGroup))
  2514. groups.Add(part.ParentGroup);
  2515. }
  2516. foreach (SceneObjectGroup sog in groups)
  2517. {
  2518. if (ownerID.IsNotZero())
  2519. {
  2520. sog.SetOwnerId(ownerID);
  2521. sog.SetGroup(groupID, remoteClient);
  2522. sog.ScheduleGroupForFullUpdate();
  2523. SceneObjectPart[] partList = sog.Parts;
  2524. foreach (SceneObjectPart child in partList)
  2525. {
  2526. child.Inventory.ChangeInventoryOwner(ownerID);
  2527. child.TriggerScriptChangedEvent(Changed.OWNER);
  2528. }
  2529. }
  2530. else // The object deeded to the group
  2531. {
  2532. if (!Permissions.CanDeedObject(remoteClient, sog, groupID))
  2533. continue;
  2534. sog.SetOwnerId(groupID);
  2535. // this is wrong, GroupMask is used for group sharing, still possible to set
  2536. // this whould give owner rights to users that are member of group but don't have role powers to edit
  2537. //sog.RootPart.GroupMask = sog.RootPart.OwnerMask;
  2538. // we should keep all permissions on deed to group
  2539. // and with this comented code, if user does not set next permissions on the object
  2540. // and on ALL contents of ALL prims, he may loose rights, making the object useless
  2541. sog.ApplyNextOwnerPermissions();
  2542. sog.InvalidateEffectivePerms();
  2543. sog.ScheduleGroupForFullUpdate();
  2544. SceneObjectPart[] partList = sog.Parts;
  2545. foreach (SceneObjectPart child in partList)
  2546. {
  2547. child.Inventory.ChangeInventoryOwner(groupID);
  2548. child.TriggerScriptChangedEvent(Changed.OWNER);
  2549. }
  2550. }
  2551. }
  2552. foreach (uint localID in localIDs)
  2553. {
  2554. SceneObjectPart part = GetSceneObjectPart(localID);
  2555. if (part is null)
  2556. continue;
  2557. part.SendPropertiesToClient(remoteClient);
  2558. }
  2559. }
  2560. public void DelinkObjects(List<uint> primIds, IClientAPI client)
  2561. {
  2562. List<SceneObjectPart> parts = new();
  2563. foreach (uint localID in primIds)
  2564. {
  2565. SceneObjectPart part = GetSceneObjectPart(localID);
  2566. if (part is null)
  2567. continue;
  2568. if (Permissions.CanDelinkObject(client.AgentId, part.ParentGroup.RootPart.UUID))
  2569. parts.Add(part);
  2570. }
  2571. m_sceneGraph.DelinkObjects(parts);
  2572. }
  2573. /// <summary>
  2574. /// Link the scene objects containing the indicated parts to a root object.
  2575. /// </summary>
  2576. /// <param name="client"></param>
  2577. /// <param name="parentPrimId">A root prim id of the object which will be the root prim of the resulting linkset.</param>
  2578. /// <param name="childPrimIds">A list of child prims for the objects that should be linked in.</param>
  2579. public void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds)
  2580. {
  2581. LinkObjects(client.AgentId, parentPrimId, childPrimIds);
  2582. }
  2583. /// <summary>
  2584. /// Link the scene objects containing the indicated parts to a root object.
  2585. /// </summary>
  2586. /// <param name="agentId">The ID of the user linking.</param>
  2587. /// <param name="parentPrimId">A root prim id of the object which will be the root prim of the resulting linkset.</param>
  2588. /// <param name="childPrimIds">A list of child prims for the objects that should be linked in.</param>
  2589. public void LinkObjects(UUID agentId, uint parentPrimId, List<uint> childPrimIds)
  2590. {
  2591. List<UUID> owners = new();
  2592. List<SceneObjectPart> children = new();
  2593. SceneObjectPart root = GetSceneObjectPart(parentPrimId);
  2594. if (root is null)
  2595. {
  2596. m_log.DebugFormat("[LINK]: Can't find linkset root prim {0}", parentPrimId);
  2597. return;
  2598. }
  2599. if (!Permissions.CanLinkObject(agentId, root.ParentGroup.RootPart.UUID))
  2600. {
  2601. m_log.DebugFormat("[LINK]: Refusing link. No permissions on root prim");
  2602. return;
  2603. }
  2604. foreach (uint localID in childPrimIds)
  2605. {
  2606. SceneObjectPart part = GetSceneObjectPart(localID);
  2607. if (part is null)
  2608. continue;
  2609. if (!owners.Contains(part.OwnerID))
  2610. owners.Add(part.OwnerID);
  2611. if (Permissions.CanLinkObject(agentId, part.ParentGroup.RootPart.UUID))
  2612. children.Add(part);
  2613. }
  2614. // Must be all one owner
  2615. //
  2616. if (owners.Count > 1)
  2617. {
  2618. m_log.DebugFormat("[LINK]: Refusing link. Too many owners");
  2619. return;
  2620. }
  2621. if (children.Count == 0)
  2622. {
  2623. m_log.DebugFormat("[LINK]: Refusing link. No permissions to link any of the children");
  2624. return;
  2625. }
  2626. bool oldUsePhysics = (root.Flags & PrimFlags.Physics) != 0;
  2627. m_sceneGraph.LinkObjects(root, children);
  2628. if (TryGetScenePresence(agentId, out ScenePresence sp))
  2629. {
  2630. root.SendPropertiesToClient(sp.ControllingClient);
  2631. if (oldUsePhysics && (root.Flags & PrimFlags.Physics) == 0)
  2632. {
  2633. sp.ControllingClient.SendAlertMessage("Object physics cancelled");
  2634. }
  2635. }
  2636. }
  2637. private string PermissionString(uint permissions)
  2638. {
  2639. PermissionMask perms = (PermissionMask)permissions &
  2640. (PermissionMask.Move |
  2641. PermissionMask.Copy |
  2642. PermissionMask.Transfer |
  2643. PermissionMask.Modify);
  2644. return perms.ToString();
  2645. }
  2646. }
  2647. }