1
0

SceneObjectPartInventory.cs 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  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.Xml;
  29. using System.IO;
  30. using System.Collections.Generic;
  31. using System.Collections;
  32. using System.Reflection;
  33. using System.Threading;
  34. using OpenMetaverse;
  35. using log4net;
  36. using OpenSim.Framework;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes.Scripting;
  39. using OpenSim.Region.Framework.Scenes.Serialization;
  40. namespace OpenSim.Region.Framework.Scenes
  41. {
  42. public class SceneObjectPartInventory : IEntityInventory
  43. {
  44. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  45. private string m_inventoryFileName = String.Empty;
  46. private byte[] m_inventoryFileData = new byte[0];
  47. private uint m_inventoryFileNameSerial = 0;
  48. /// <value>
  49. /// The part to which the inventory belongs.
  50. /// </value>
  51. private SceneObjectPart m_part;
  52. /// <summary>
  53. /// Serial count for inventory file , used to tell if inventory has changed
  54. /// no need for this to be part of Database backup
  55. /// </summary>
  56. protected uint m_inventorySerial = 0;
  57. /// <summary>
  58. /// Holds in memory prim inventory
  59. /// </summary>
  60. protected TaskInventoryDictionary m_items = new TaskInventoryDictionary();
  61. /// <summary>
  62. /// Tracks whether inventory has changed since the last persistent backup
  63. /// </summary>
  64. internal bool HasInventoryChanged;
  65. /// <value>
  66. /// Inventory serial number
  67. /// </value>
  68. protected internal uint Serial
  69. {
  70. get { return m_inventorySerial; }
  71. set { m_inventorySerial = value; }
  72. }
  73. /// <value>
  74. /// Raw inventory data
  75. /// </value>
  76. protected internal TaskInventoryDictionary Items
  77. {
  78. get { return m_items; }
  79. set
  80. {
  81. m_items = value;
  82. m_inventorySerial++;
  83. }
  84. }
  85. /// <summary>
  86. /// Constructor
  87. /// </summary>
  88. /// <param name="part">
  89. /// A <see cref="SceneObjectPart"/>
  90. /// </param>
  91. public SceneObjectPartInventory(SceneObjectPart part)
  92. {
  93. m_part = part;
  94. }
  95. /// <summary>
  96. /// Force the task inventory of this prim to persist at the next update sweep
  97. /// </summary>
  98. public void ForceInventoryPersistence()
  99. {
  100. HasInventoryChanged = true;
  101. }
  102. /// <summary>
  103. /// Reset UUIDs for all the items in the prim's inventory.
  104. /// </summary>
  105. /// <remarks>
  106. /// This involves either generating
  107. /// new ones or setting existing UUIDs to the correct parent UUIDs.
  108. ///
  109. /// If this method is called and there are inventory items, then we regard the inventory as having changed.
  110. /// </remarks>
  111. public void ResetInventoryIDs()
  112. {
  113. if (null == m_part)
  114. return;
  115. lock (m_items)
  116. {
  117. if (0 == m_items.Count)
  118. return;
  119. IList<TaskInventoryItem> items = GetInventoryItems();
  120. m_items.Clear();
  121. foreach (TaskInventoryItem item in items)
  122. {
  123. item.ResetIDs(m_part.UUID);
  124. m_items.Add(item.ItemID, item);
  125. }
  126. }
  127. }
  128. public void ResetObjectID()
  129. {
  130. lock (Items)
  131. {
  132. IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
  133. Items.Clear();
  134. foreach (TaskInventoryItem item in items)
  135. {
  136. item.ParentPartID = m_part.UUID;
  137. item.ParentID = m_part.UUID;
  138. Items.Add(item.ItemID, item);
  139. }
  140. }
  141. }
  142. /// <summary>
  143. /// Change every item in this inventory to a new owner.
  144. /// </summary>
  145. /// <param name="ownerId"></param>
  146. public void ChangeInventoryOwner(UUID ownerId)
  147. {
  148. lock (Items)
  149. {
  150. if (0 == Items.Count)
  151. {
  152. return;
  153. }
  154. }
  155. HasInventoryChanged = true;
  156. m_part.ParentGroup.HasGroupChanged = true;
  157. List<TaskInventoryItem> items = GetInventoryItems();
  158. foreach (TaskInventoryItem item in items)
  159. {
  160. if (ownerId != item.OwnerID)
  161. item.LastOwnerID = item.OwnerID;
  162. item.OwnerID = ownerId;
  163. item.PermsMask = 0;
  164. item.PermsGranter = UUID.Zero;
  165. item.OwnerChanged = true;
  166. }
  167. }
  168. /// <summary>
  169. /// Change every item in this inventory to a new group.
  170. /// </summary>
  171. /// <param name="groupID"></param>
  172. public void ChangeInventoryGroup(UUID groupID)
  173. {
  174. lock (Items)
  175. {
  176. if (0 == Items.Count)
  177. {
  178. return;
  179. }
  180. }
  181. // Don't let this set the HasGroupChanged flag for attachments
  182. // as this happens during rez and we don't want a new asset
  183. // for each attachment each time
  184. if (!m_part.ParentGroup.IsAttachment)
  185. {
  186. HasInventoryChanged = true;
  187. m_part.ParentGroup.HasGroupChanged = true;
  188. }
  189. List<TaskInventoryItem> items = GetInventoryItems();
  190. foreach (TaskInventoryItem item in items)
  191. {
  192. if (groupID != item.GroupID)
  193. item.GroupID = groupID;
  194. }
  195. }
  196. /// <summary>
  197. /// Start all the scripts contained in this prim's inventory
  198. /// </summary>
  199. public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
  200. {
  201. List<TaskInventoryItem> scripts = GetInventoryScripts();
  202. foreach (TaskInventoryItem item in scripts)
  203. CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
  204. }
  205. public ArrayList GetScriptErrors(UUID itemID)
  206. {
  207. ArrayList ret = new ArrayList();
  208. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  209. if (engines == null) // No engine at all
  210. return ret;
  211. foreach (IScriptModule e in engines)
  212. {
  213. if (e != null)
  214. {
  215. ArrayList errors = e.GetScriptErrors(itemID);
  216. foreach (Object line in errors)
  217. ret.Add(line);
  218. }
  219. }
  220. return ret;
  221. }
  222. /// <summary>
  223. /// Stop all the scripts in this prim.
  224. /// </summary>
  225. /// <param name="sceneObjectBeingDeleted">
  226. /// Should be true if these scripts are being removed because the scene
  227. /// object is being deleted. This will prevent spurious updates to the client.
  228. /// </param>
  229. public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
  230. {
  231. List<TaskInventoryItem> scripts = GetInventoryScripts();
  232. foreach (TaskInventoryItem item in scripts)
  233. RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
  234. }
  235. /// <summary>
  236. /// Start a script which is in this prim's inventory.
  237. /// </summary>
  238. /// <param name="item"></param>
  239. /// <returns></returns>
  240. public void CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource)
  241. {
  242. // m_log.InfoFormat(
  243. // "[PRIM INVENTORY]: " +
  244. // "Starting script {0}, {1} in prim {2}, {3}",
  245. // item.Name, item.ItemID, Name, UUID);
  246. if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
  247. return;
  248. m_part.AddFlag(PrimFlags.Scripted);
  249. if (!m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts)
  250. {
  251. if (stateSource == 2 && // Prim crossing
  252. m_part.ParentGroup.Scene.m_trustBinaries)
  253. {
  254. lock (m_items)
  255. {
  256. m_items[item.ItemID].PermsMask = 0;
  257. m_items[item.ItemID].PermsGranter = UUID.Zero;
  258. }
  259. m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
  260. m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
  261. m_part.ParentGroup.AddActiveScriptCount(1);
  262. m_part.ScheduleFullUpdate();
  263. return;
  264. }
  265. AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
  266. if (null == asset)
  267. {
  268. m_log.ErrorFormat(
  269. "[PRIM INVENTORY]: " +
  270. "Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
  271. item.Name, item.ItemID, m_part.AbsolutePosition,
  272. m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID);
  273. }
  274. else
  275. {
  276. if (m_part.ParentGroup.m_savedScriptState != null)
  277. RestoreSavedScriptState(item.OldItemID, item.ItemID);
  278. lock (m_items)
  279. {
  280. m_items[item.ItemID].PermsMask = 0;
  281. m_items[item.ItemID].PermsGranter = UUID.Zero;
  282. }
  283. string script = Utils.BytesToString(asset.Data);
  284. m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
  285. m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
  286. m_part.ParentGroup.AddActiveScriptCount(1);
  287. m_part.ScheduleFullUpdate();
  288. }
  289. }
  290. }
  291. private void RestoreSavedScriptState(UUID oldID, UUID newID)
  292. {
  293. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  294. if (engines == null) // No engine at all
  295. return;
  296. if (m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID))
  297. {
  298. XmlDocument doc = new XmlDocument();
  299. doc.LoadXml(m_part.ParentGroup.m_savedScriptState[oldID]);
  300. ////////// CRUFT WARNING ///////////////////////////////////
  301. //
  302. // Old objects will have <ScriptState><State> ...
  303. // This format is XEngine ONLY
  304. //
  305. // New objects have <State Engine="...." ...><ScriptState>...
  306. // This can be passed to any engine
  307. //
  308. XmlNode n = doc.SelectSingleNode("ScriptState");
  309. if (n != null) // Old format data
  310. {
  311. XmlDocument newDoc = new XmlDocument();
  312. XmlElement rootN = newDoc.CreateElement("", "State", "");
  313. XmlAttribute uuidA = newDoc.CreateAttribute("", "UUID", "");
  314. uuidA.Value = oldID.ToString();
  315. rootN.Attributes.Append(uuidA);
  316. XmlAttribute engineA = newDoc.CreateAttribute("", "Engine", "");
  317. engineA.Value = "XEngine";
  318. rootN.Attributes.Append(engineA);
  319. newDoc.AppendChild(rootN);
  320. XmlNode stateN = newDoc.ImportNode(n, true);
  321. rootN.AppendChild(stateN);
  322. // This created document has only the minimun data
  323. // necessary for XEngine to parse it successfully
  324. m_part.ParentGroup.m_savedScriptState[oldID] = newDoc.OuterXml;
  325. }
  326. foreach (IScriptModule e in engines)
  327. {
  328. if (e != null)
  329. {
  330. if (e.SetXMLState(newID, m_part.ParentGroup.m_savedScriptState[oldID]))
  331. break;
  332. }
  333. }
  334. m_part.ParentGroup.m_savedScriptState.Remove(oldID);
  335. }
  336. }
  337. /// <summary>
  338. /// Start a script which is in this prim's inventory.
  339. /// </summary>
  340. /// <param name="itemId">
  341. /// A <see cref="UUID"/>
  342. /// </param>
  343. public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
  344. {
  345. TaskInventoryItem item = GetInventoryItem(itemId);
  346. if (item != null)
  347. CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
  348. else
  349. m_log.ErrorFormat(
  350. "[PRIM INVENTORY]: " +
  351. "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
  352. itemId, m_part.Name, m_part.UUID,
  353. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  354. }
  355. /// <summary>
  356. /// Stop a script which is in this prim's inventory.
  357. /// </summary>
  358. /// <param name="itemId"></param>
  359. /// <param name="sceneObjectBeingDeleted">
  360. /// Should be true if this script is being removed because the scene
  361. /// object is being deleted. This will prevent spurious updates to the client.
  362. /// </param>
  363. public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
  364. {
  365. bool scriptPresent = false;
  366. lock (m_items)
  367. {
  368. if (m_items.ContainsKey(itemId))
  369. scriptPresent = true;
  370. }
  371. if (scriptPresent)
  372. {
  373. if (!sceneObjectBeingDeleted)
  374. m_part.RemoveScriptEvents(itemId);
  375. m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId);
  376. m_part.ParentGroup.AddActiveScriptCount(-1);
  377. }
  378. else
  379. {
  380. m_log.ErrorFormat(
  381. "[PRIM INVENTORY]: " +
  382. "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
  383. itemId, m_part.Name, m_part.UUID,
  384. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  385. }
  386. }
  387. /// <summary>
  388. /// Check if the inventory holds an item with a given name.
  389. /// </summary>
  390. /// <param name="name"></param>
  391. /// <returns></returns>
  392. private bool InventoryContainsName(string name)
  393. {
  394. lock (m_items)
  395. {
  396. foreach (TaskInventoryItem item in m_items.Values)
  397. {
  398. if (item.Name == name)
  399. return true;
  400. }
  401. }
  402. return false;
  403. }
  404. /// <summary>
  405. /// For a given item name, return that name if it is available. Otherwise, return the next available
  406. /// similar name (which is currently the original name with the next available numeric suffix).
  407. /// </summary>
  408. /// <param name="name"></param>
  409. /// <returns></returns>
  410. private string FindAvailableInventoryName(string name)
  411. {
  412. if (!InventoryContainsName(name))
  413. return name;
  414. int suffix=1;
  415. while (suffix < 256)
  416. {
  417. string tryName=String.Format("{0} {1}", name, suffix);
  418. if (!InventoryContainsName(tryName))
  419. return tryName;
  420. suffix++;
  421. }
  422. return String.Empty;
  423. }
  424. /// <summary>
  425. /// Add an item to this prim's inventory. If an item with the same name already exists, then an alternative
  426. /// name is chosen.
  427. /// </summary>
  428. /// <param name="item"></param>
  429. public void AddInventoryItem(TaskInventoryItem item, bool allowedDrop)
  430. {
  431. AddInventoryItem(item.Name, item, allowedDrop);
  432. }
  433. /// <summary>
  434. /// Add an item to this prim's inventory. If an item with the same name already exists, it is replaced.
  435. /// </summary>
  436. /// <param name="item"></param>
  437. public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
  438. {
  439. List<TaskInventoryItem> il = GetInventoryItems();
  440. foreach (TaskInventoryItem i in il)
  441. {
  442. if (i.Name == item.Name)
  443. {
  444. if (i.InvType == (int)InventoryType.LSL)
  445. RemoveScriptInstance(i.ItemID, false);
  446. RemoveInventoryItem(i.ItemID);
  447. break;
  448. }
  449. }
  450. AddInventoryItem(item.Name, item, allowedDrop);
  451. }
  452. /// <summary>
  453. /// Add an item to this prim's inventory.
  454. /// </summary>
  455. /// <param name="name">The name that the new item should have.</param>
  456. /// <param name="item">
  457. /// The item itself. The name within this structure is ignored in favour of the name
  458. /// given in this method's arguments
  459. /// </param>
  460. /// <param name="allowedDrop">
  461. /// Item was only added to inventory because AllowedDrop is set
  462. /// </param>
  463. protected void AddInventoryItem(string name, TaskInventoryItem item, bool allowedDrop)
  464. {
  465. name = FindAvailableInventoryName(name);
  466. if (name == String.Empty)
  467. return;
  468. item.ParentID = m_part.UUID;
  469. item.ParentPartID = m_part.UUID;
  470. item.Name = name;
  471. item.GroupID = m_part.GroupID;
  472. lock (m_items)
  473. m_items.Add(item.ItemID, item);
  474. if (allowedDrop)
  475. m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
  476. else
  477. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  478. m_inventorySerial++;
  479. //m_inventorySerial += 2;
  480. HasInventoryChanged = true;
  481. m_part.ParentGroup.HasGroupChanged = true;
  482. }
  483. /// <summary>
  484. /// Restore a whole collection of items to the prim's inventory at once.
  485. /// We assume that the items already have all their fields correctly filled out.
  486. /// The items are not flagged for persistence to the database, since they are being restored
  487. /// from persistence rather than being newly added.
  488. /// </summary>
  489. /// <param name="items"></param>
  490. public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
  491. {
  492. lock (m_items)
  493. {
  494. foreach (TaskInventoryItem item in items)
  495. {
  496. m_items.Add(item.ItemID, item);
  497. // m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  498. }
  499. m_inventorySerial++;
  500. }
  501. }
  502. /// <summary>
  503. /// Returns an existing inventory item. Returns the original, so any changes will be live.
  504. /// </summary>
  505. /// <param name="itemID"></param>
  506. /// <returns>null if the item does not exist</returns>
  507. public TaskInventoryItem GetInventoryItem(UUID itemId)
  508. {
  509. TaskInventoryItem item;
  510. lock (m_items)
  511. m_items.TryGetValue(itemId, out item);
  512. return item;
  513. }
  514. /// <summary>
  515. /// Get inventory items by name.
  516. /// </summary>
  517. /// <param name="name"></param>
  518. /// <returns>
  519. /// A list of inventory items with that name.
  520. /// If no inventory item has that name then an empty list is returned.
  521. /// </returns>
  522. public IList<TaskInventoryItem> GetInventoryItems(string name)
  523. {
  524. IList<TaskInventoryItem> items = new List<TaskInventoryItem>();
  525. lock (m_items)
  526. {
  527. foreach (TaskInventoryItem item in m_items.Values)
  528. {
  529. if (item.Name == name)
  530. items.Add(item);
  531. }
  532. }
  533. return items;
  534. }
  535. public SceneObjectGroup GetRezReadySceneObject(TaskInventoryItem item)
  536. {
  537. AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
  538. if (null == rezAsset)
  539. {
  540. m_log.WarnFormat(
  541. "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}",
  542. item.AssetID, item.Name, m_part.Name);
  543. return null;
  544. }
  545. string xmlData = Utils.BytesToString(rezAsset.Data);
  546. SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData);
  547. group.ResetIDs();
  548. SceneObjectPart rootPart = group.GetChildPart(group.UUID);
  549. // Since renaming the item in the inventory does not affect the name stored
  550. // in the serialization, transfer the correct name from the inventory to the
  551. // object itself before we rez.
  552. rootPart.Name = item.Name;
  553. rootPart.Description = item.Description;
  554. SceneObjectPart[] partList = group.Parts;
  555. group.SetGroup(m_part.GroupID, null);
  556. // TODO: Remove magic number badness
  557. if ((rootPart.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number
  558. {
  559. if (m_part.ParentGroup.Scene.Permissions.PropagatePermissions())
  560. {
  561. foreach (SceneObjectPart part in partList)
  562. {
  563. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
  564. part.EveryoneMask = item.EveryonePermissions;
  565. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
  566. part.NextOwnerMask = item.NextPermissions;
  567. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
  568. part.GroupMask = item.GroupPermissions;
  569. }
  570. group.ApplyNextOwnerPermissions();
  571. }
  572. }
  573. foreach (SceneObjectPart part in partList)
  574. {
  575. // TODO: Remove magic number badness
  576. if ((part.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number
  577. {
  578. part.LastOwnerID = part.OwnerID;
  579. part.OwnerID = item.OwnerID;
  580. part.Inventory.ChangeInventoryOwner(item.OwnerID);
  581. }
  582. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
  583. part.EveryoneMask = item.EveryonePermissions;
  584. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
  585. part.NextOwnerMask = item.NextPermissions;
  586. if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
  587. part.GroupMask = item.GroupPermissions;
  588. }
  589. rootPart.TrimPermissions();
  590. return group;
  591. }
  592. /// <summary>
  593. /// Update an existing inventory item.
  594. /// </summary>
  595. /// <param name="item">The updated item. An item with the same id must already exist
  596. /// in this prim's inventory.</param>
  597. /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
  598. public bool UpdateInventoryItem(TaskInventoryItem item)
  599. {
  600. return UpdateInventoryItem(item, true, true);
  601. }
  602. public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents)
  603. {
  604. return UpdateInventoryItem(item, fireScriptEvents, true);
  605. }
  606. public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
  607. {
  608. TaskInventoryItem it = GetInventoryItem(item.ItemID);
  609. if (it != null)
  610. {
  611. // m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
  612. item.ParentID = m_part.UUID;
  613. item.ParentPartID = m_part.UUID;
  614. // If group permissions have been set on, check that the groupID is up to date in case it has
  615. // changed since permissions were last set.
  616. if (item.GroupPermissions != (uint)PermissionMask.None)
  617. item.GroupID = m_part.GroupID;
  618. if (item.AssetID == UUID.Zero)
  619. item.AssetID = it.AssetID;
  620. lock (m_items)
  621. {
  622. m_items[item.ItemID] = item;
  623. m_inventorySerial++;
  624. }
  625. if (fireScriptEvents)
  626. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  627. if (considerChanged)
  628. {
  629. HasInventoryChanged = true;
  630. m_part.ParentGroup.HasGroupChanged = true;
  631. }
  632. return true;
  633. }
  634. else
  635. {
  636. m_log.ErrorFormat(
  637. "[PRIM INVENTORY]: " +
  638. "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
  639. item.ItemID, m_part.Name, m_part.UUID,
  640. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  641. }
  642. return false;
  643. }
  644. /// <summary>
  645. /// Remove an item from this prim's inventory
  646. /// </summary>
  647. /// <param name="itemID"></param>
  648. /// <returns>Numeric asset type of the item removed. Returns -1 if the item did not exist
  649. /// in this prim's inventory.</returns>
  650. public int RemoveInventoryItem(UUID itemID)
  651. {
  652. TaskInventoryItem item = GetInventoryItem(itemID);
  653. if (item != null)
  654. {
  655. int type = m_items[itemID].InvType;
  656. if (type == 10) // Script
  657. {
  658. m_part.RemoveScriptEvents(itemID);
  659. m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
  660. }
  661. m_items.Remove(itemID);
  662. m_inventorySerial++;
  663. m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
  664. HasInventoryChanged = true;
  665. m_part.ParentGroup.HasGroupChanged = true;
  666. if (!ContainsScripts())
  667. m_part.RemFlag(PrimFlags.Scripted);
  668. m_part.ScheduleFullUpdate();
  669. return type;
  670. }
  671. else
  672. {
  673. m_log.ErrorFormat(
  674. "[PRIM INVENTORY]: " +
  675. "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
  676. itemID, m_part.Name, m_part.UUID,
  677. m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
  678. }
  679. return -1;
  680. }
  681. private bool CreateInventoryFile()
  682. {
  683. // m_log.DebugFormat(
  684. // "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}",
  685. // m_part.Name, m_part.UUID, m_part.LocalId, m_inventorySerial);
  686. if (m_inventoryFileName == String.Empty ||
  687. m_inventoryFileNameSerial < m_inventorySerial)
  688. {
  689. // Something changed, we need to create a new file
  690. m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
  691. m_inventoryFileNameSerial = m_inventorySerial;
  692. InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
  693. lock (m_items)
  694. {
  695. foreach (TaskInventoryItem item in m_items.Values)
  696. {
  697. // m_log.DebugFormat(
  698. // "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}",
  699. // item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId);
  700. UUID ownerID = item.OwnerID;
  701. uint everyoneMask = 0;
  702. uint baseMask = item.BasePermissions;
  703. uint ownerMask = item.CurrentPermissions;
  704. uint groupMask = item.GroupPermissions;
  705. invString.AddItemStart();
  706. invString.AddNameValueLine("item_id", item.ItemID.ToString());
  707. invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
  708. invString.AddPermissionsStart();
  709. invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
  710. invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
  711. invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
  712. invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
  713. invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
  714. invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
  715. invString.AddNameValueLine("owner_id", ownerID.ToString());
  716. invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
  717. invString.AddNameValueLine("group_id", item.GroupID.ToString());
  718. invString.AddSectionEnd();
  719. invString.AddNameValueLine("asset_id", item.AssetID.ToString());
  720. invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]);
  721. invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]);
  722. invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
  723. invString.AddSaleStart();
  724. invString.AddNameValueLine("sale_type", "not");
  725. invString.AddNameValueLine("sale_price", "0");
  726. invString.AddSectionEnd();
  727. invString.AddNameValueLine("name", item.Name + "|");
  728. invString.AddNameValueLine("desc", item.Description + "|");
  729. invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
  730. invString.AddSectionEnd();
  731. }
  732. }
  733. m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
  734. return true;
  735. }
  736. // No need to recreate, the existing file is fine
  737. return false;
  738. }
  739. /// <summary>
  740. /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
  741. /// </summary>
  742. /// <param name="xferManager"></param>
  743. public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
  744. {
  745. lock (m_items)
  746. {
  747. // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing
  748. // a new script if any previous deletion has left the prim inventory empty.
  749. if (m_items.Count == 0) // No inventory
  750. {
  751. // m_log.DebugFormat(
  752. // "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items",
  753. // m_part.Name, m_part.LocalId, m_part.UUID, client.Name);
  754. client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
  755. return;
  756. }
  757. CreateInventoryFile();
  758. // In principle, we should only do the rest if the inventory changed;
  759. // by sending m_inventorySerial to the client, it ought to know
  760. // that nothing changed and that it doesn't need to request the file.
  761. // Unfortunately, it doesn't look like the client optimizes this;
  762. // the client seems to always come back and request the Xfer,
  763. // no matter what value m_inventorySerial has.
  764. // FIXME: Could probably be > 0 here rather than > 2
  765. if (m_inventoryFileData.Length > 2)
  766. {
  767. // Add the file for Xfer
  768. // m_log.DebugFormat(
  769. // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}",
  770. // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId);
  771. xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
  772. }
  773. // Tell the client we're ready to Xfer the file
  774. client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
  775. Util.StringToBytes256(m_inventoryFileName));
  776. }
  777. }
  778. /// <summary>
  779. /// Process inventory backup
  780. /// </summary>
  781. /// <param name="datastore"></param>
  782. public void ProcessInventoryBackup(ISimulationDataService datastore)
  783. {
  784. if (HasInventoryChanged)
  785. {
  786. HasInventoryChanged = false;
  787. List<TaskInventoryItem> items = GetInventoryItems();
  788. datastore.StorePrimInventory(m_part.UUID, items);
  789. }
  790. }
  791. public class InventoryStringBuilder
  792. {
  793. public string BuildString = String.Empty;
  794. public InventoryStringBuilder(UUID folderID, UUID parentID)
  795. {
  796. BuildString += "\tinv_object\t0\n\t{\n";
  797. AddNameValueLine("obj_id", folderID.ToString());
  798. AddNameValueLine("parent_id", parentID.ToString());
  799. AddNameValueLine("type", "category");
  800. AddNameValueLine("name", "Contents|");
  801. AddSectionEnd();
  802. }
  803. public void AddItemStart()
  804. {
  805. BuildString += "\tinv_item\t0\n";
  806. AddSectionStart();
  807. }
  808. public void AddPermissionsStart()
  809. {
  810. BuildString += "\tpermissions 0\n";
  811. AddSectionStart();
  812. }
  813. public void AddSaleStart()
  814. {
  815. BuildString += "\tsale_info\t0\n";
  816. AddSectionStart();
  817. }
  818. protected void AddSectionStart()
  819. {
  820. BuildString += "\t{\n";
  821. }
  822. public void AddSectionEnd()
  823. {
  824. BuildString += "\t}\n";
  825. }
  826. public void AddLine(string addLine)
  827. {
  828. BuildString += addLine;
  829. }
  830. public void AddNameValueLine(string name, string value)
  831. {
  832. BuildString += "\t\t";
  833. BuildString += name + "\t";
  834. BuildString += value + "\n";
  835. }
  836. public void Close()
  837. {
  838. }
  839. }
  840. public uint MaskEffectivePermissions()
  841. {
  842. uint mask=0x7fffffff;
  843. lock (m_items)
  844. {
  845. foreach (TaskInventoryItem item in m_items.Values)
  846. {
  847. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
  848. mask &= ~((uint)PermissionMask.Copy >> 13);
  849. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
  850. mask &= ~((uint)PermissionMask.Transfer >> 13);
  851. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
  852. mask &= ~((uint)PermissionMask.Modify >> 13);
  853. if (item.InvType != (int)InventoryType.Object)
  854. {
  855. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
  856. mask &= ~((uint)PermissionMask.Copy >> 13);
  857. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
  858. mask &= ~((uint)PermissionMask.Transfer >> 13);
  859. if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
  860. mask &= ~((uint)PermissionMask.Modify >> 13);
  861. }
  862. else
  863. {
  864. if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
  865. mask &= ~((uint)PermissionMask.Copy >> 13);
  866. if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
  867. mask &= ~((uint)PermissionMask.Transfer >> 13);
  868. if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
  869. mask &= ~((uint)PermissionMask.Modify >> 13);
  870. }
  871. if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
  872. mask &= ~(uint)PermissionMask.Copy;
  873. if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
  874. mask &= ~(uint)PermissionMask.Transfer;
  875. if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
  876. mask &= ~(uint)PermissionMask.Modify;
  877. }
  878. }
  879. return mask;
  880. }
  881. public void ApplyNextOwnerPermissions()
  882. {
  883. lock (m_items)
  884. {
  885. foreach (TaskInventoryItem item in m_items.Values)
  886. {
  887. if (item.InvType == (int)InventoryType.Object && (item.CurrentPermissions & 7) != 0)
  888. {
  889. if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
  890. item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
  891. if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
  892. item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
  893. if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
  894. item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
  895. }
  896. item.CurrentPermissions &= item.NextPermissions;
  897. item.BasePermissions &= item.NextPermissions;
  898. item.EveryonePermissions &= item.NextPermissions;
  899. item.OwnerChanged = true;
  900. item.PermsMask = 0;
  901. item.PermsGranter = UUID.Zero;
  902. }
  903. }
  904. }
  905. public void ApplyGodPermissions(uint perms)
  906. {
  907. lock (m_items)
  908. {
  909. foreach (TaskInventoryItem item in m_items.Values)
  910. {
  911. item.CurrentPermissions = perms;
  912. item.BasePermissions = perms;
  913. }
  914. }
  915. m_inventorySerial++;
  916. HasInventoryChanged = true;
  917. }
  918. /// <summary>
  919. /// Returns true if this part inventory contains any scripts. False otherwise.
  920. /// </summary>
  921. /// <returns></returns>
  922. public bool ContainsScripts()
  923. {
  924. lock (m_items)
  925. {
  926. foreach (TaskInventoryItem item in m_items.Values)
  927. {
  928. if (item.InvType == (int)InventoryType.LSL)
  929. {
  930. return true;
  931. }
  932. }
  933. }
  934. return false;
  935. }
  936. public List<UUID> GetInventoryList()
  937. {
  938. List<UUID> ret = new List<UUID>();
  939. lock (m_items)
  940. {
  941. foreach (TaskInventoryItem item in m_items.Values)
  942. ret.Add(item.ItemID);
  943. }
  944. return ret;
  945. }
  946. public List<TaskInventoryItem> GetInventoryItems()
  947. {
  948. List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
  949. lock (m_items)
  950. ret = new List<TaskInventoryItem>(m_items.Values);
  951. return ret;
  952. }
  953. public List<TaskInventoryItem> GetInventoryScripts()
  954. {
  955. List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
  956. lock (m_items)
  957. {
  958. foreach (TaskInventoryItem item in m_items.Values)
  959. if (item.InvType == (int)InventoryType.LSL)
  960. ret.Add(item);
  961. }
  962. return ret;
  963. }
  964. public Dictionary<UUID, string> GetScriptStates()
  965. {
  966. Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
  967. if (m_part.ParentGroup.Scene == null) // Group not in a scene
  968. return ret;
  969. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  970. if (engines == null) // No engine at all
  971. return ret;
  972. List<TaskInventoryItem> scripts = GetInventoryScripts();
  973. foreach (TaskInventoryItem item in scripts)
  974. {
  975. foreach (IScriptModule e in engines)
  976. {
  977. if (e != null)
  978. {
  979. string n = e.GetXMLState(item.ItemID);
  980. if (n != String.Empty)
  981. {
  982. if (!ret.ContainsKey(item.ItemID))
  983. ret[item.ItemID] = n;
  984. break;
  985. }
  986. }
  987. }
  988. }
  989. return ret;
  990. }
  991. public void ResumeScripts()
  992. {
  993. IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
  994. if (engines == null)
  995. return;
  996. List<TaskInventoryItem> scripts = GetInventoryScripts();
  997. foreach (TaskInventoryItem item in scripts)
  998. {
  999. foreach (IScriptModule engine in engines)
  1000. {
  1001. if (engine != null)
  1002. {
  1003. if (item.OwnerChanged)
  1004. engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
  1005. item.OwnerChanged = false;
  1006. engine.ResumeScript(item.ItemID);
  1007. }
  1008. }
  1009. }
  1010. }
  1011. }
  1012. }