aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs1346
1 files changed, 1346 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
new file mode 100644
index 0000000..ec39726
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -0,0 +1,1346 @@
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
28using System;
29using System.Xml;
30using System.IO;
31using System.Collections.Generic;
32using System.Collections;
33using System.Reflection;
34using System.Threading;
35using OpenMetaverse;
36using log4net;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes.Scripting;
40using OpenSim.Region.Framework.Scenes.Serialization;
41using PermissionMask = OpenSim.Framework.PermissionMask;
42
43namespace OpenSim.Region.Framework.Scenes
44{
45 public class SceneObjectPartInventory : IEntityInventory
46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 private string m_inventoryFileName = String.Empty;
50 private byte[] m_inventoryFileData = new byte[0];
51 private uint m_inventoryFileNameSerial = 0;
52
53 /// <value>
54 /// The part to which the inventory belongs.
55 /// </value>
56 private SceneObjectPart m_part;
57
58 /// <summary>
59 /// Serial count for inventory file , used to tell if inventory has changed
60 /// no need for this to be part of Database backup
61 /// </summary>
62 protected uint m_inventorySerial = 0;
63
64 /// <summary>
65 /// Holds in memory prim inventory
66 /// </summary>
67 protected TaskInventoryDictionary m_items = new TaskInventoryDictionary();
68
69 /// <summary>
70 /// Tracks whether inventory has changed since the last persistent backup
71 /// </summary>
72 internal bool HasInventoryChanged;
73
74 /// <value>
75 /// Inventory serial number
76 /// </value>
77 protected internal uint Serial
78 {
79 get { return m_inventorySerial; }
80 set { m_inventorySerial = value; }
81 }
82
83 /// <value>
84 /// Raw inventory data
85 /// </value>
86 protected internal TaskInventoryDictionary Items
87 {
88 get { return m_items; }
89 set
90 {
91 m_items = value;
92 m_inventorySerial++;
93 QueryScriptStates();
94 }
95 }
96
97 public int Count
98 {
99 get
100 {
101 lock (m_items)
102 return m_items.Count;
103 }
104 }
105
106 /// <summary>
107 /// Constructor
108 /// </summary>
109 /// <param name="part">
110 /// A <see cref="SceneObjectPart"/>
111 /// </param>
112 public SceneObjectPartInventory(SceneObjectPart part)
113 {
114 m_part = part;
115 }
116
117 /// <summary>
118 /// Force the task inventory of this prim to persist at the next update sweep
119 /// </summary>
120 public void ForceInventoryPersistence()
121 {
122 HasInventoryChanged = true;
123 }
124
125 /// <summary>
126 /// Reset UUIDs for all the items in the prim's inventory.
127 /// </summary>
128 /// <remarks>
129 /// This involves either generating
130 /// new ones or setting existing UUIDs to the correct parent UUIDs.
131 ///
132 /// If this method is called and there are inventory items, then we regard the inventory as having changed.
133 /// </remarks>
134 public void ResetInventoryIDs()
135 {
136 if (null == m_part)
137 return;
138
139 lock (m_items)
140 {
141 if (0 == m_items.Count)
142 return;
143
144 IList<TaskInventoryItem> items = GetInventoryItems();
145 m_items.Clear();
146
147 foreach (TaskInventoryItem item in items)
148 {
149 item.ResetIDs(m_part.UUID);
150 m_items.Add(item.ItemID, item);
151 }
152 }
153 }
154
155 public void ResetObjectID()
156 {
157 lock (Items)
158 {
159 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
160 Items.Clear();
161
162 foreach (TaskInventoryItem item in items)
163 {
164 item.ParentPartID = m_part.UUID;
165 item.ParentID = m_part.UUID;
166 Items.Add(item.ItemID, item);
167 }
168 }
169 }
170
171 /// <summary>
172 /// Change every item in this inventory to a new owner.
173 /// </summary>
174 /// <param name="ownerId"></param>
175 public void ChangeInventoryOwner(UUID ownerId)
176 {
177 lock (Items)
178 {
179 if (0 == Items.Count)
180 {
181 return;
182 }
183 }
184
185 HasInventoryChanged = true;
186 m_part.ParentGroup.HasGroupChanged = true;
187 List<TaskInventoryItem> items = GetInventoryItems();
188 foreach (TaskInventoryItem item in items)
189 {
190 if (ownerId != item.OwnerID)
191 item.LastOwnerID = item.OwnerID;
192
193 item.OwnerID = ownerId;
194 item.PermsMask = 0;
195 item.PermsGranter = UUID.Zero;
196 item.OwnerChanged = true;
197 }
198 }
199
200 /// <summary>
201 /// Change every item in this inventory to a new group.
202 /// </summary>
203 /// <param name="groupID"></param>
204 public void ChangeInventoryGroup(UUID groupID)
205 {
206 lock (Items)
207 {
208 if (0 == Items.Count)
209 {
210 return;
211 }
212 }
213
214 // Don't let this set the HasGroupChanged flag for attachments
215 // as this happens during rez and we don't want a new asset
216 // for each attachment each time
217 if (!m_part.ParentGroup.IsAttachment)
218 {
219 HasInventoryChanged = true;
220 m_part.ParentGroup.HasGroupChanged = true;
221 }
222
223 List<TaskInventoryItem> items = GetInventoryItems();
224 foreach (TaskInventoryItem item in items)
225 {
226 if (groupID != item.GroupID)
227 item.GroupID = groupID;
228 }
229 }
230
231 private void QueryScriptStates()
232 {
233 if (m_part == null || m_part.ParentGroup == null || m_part.ParentGroup.Scene == null)
234 return;
235
236 lock (Items)
237 {
238 foreach (TaskInventoryItem item in Items.Values)
239 {
240 bool running;
241 if (TryGetScriptInstanceRunning(m_part.ParentGroup.Scene, item, out running))
242 item.ScriptRunning = running;
243 }
244 }
245 }
246
247 public bool TryGetScriptInstanceRunning(UUID itemId, out bool running)
248 {
249 running = false;
250
251 TaskInventoryItem item = GetInventoryItem(itemId);
252
253 if (item == null)
254 return false;
255
256 return TryGetScriptInstanceRunning(m_part.ParentGroup.Scene, item, out running);
257 }
258
259 public static bool TryGetScriptInstanceRunning(Scene scene, TaskInventoryItem item, out bool running)
260 {
261 running = false;
262
263 if (item.InvType != (int)InventoryType.LSL)
264 return false;
265
266 IScriptModule[] engines = scene.RequestModuleInterfaces<IScriptModule>();
267 if (engines == null) // No engine at all
268 return false;
269
270 foreach (IScriptModule e in engines)
271 {
272 if (e.HasScript(item.ItemID, out running))
273 return true;
274 }
275
276 return false;
277 }
278
279 public int CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
280 {
281 int scriptsValidForStarting = 0;
282
283 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
284 foreach (TaskInventoryItem item in scripts)
285 if (CreateScriptInstance(item, startParam, postOnRez, engine, stateSource))
286 scriptsValidForStarting++;
287
288 return scriptsValidForStarting;
289 }
290
291 public ArrayList GetScriptErrors(UUID itemID)
292 {
293 ArrayList ret = new ArrayList();
294
295 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
296
297 foreach (IScriptModule e in engines)
298 {
299 if (e != null)
300 {
301 ArrayList errors = e.GetScriptErrors(itemID);
302 foreach (Object line in errors)
303 ret.Add(line);
304 }
305 }
306
307 return ret;
308 }
309
310 /// <summary>
311 /// Stop and remove all the scripts in this prim.
312 /// </summary>
313 /// <param name="sceneObjectBeingDeleted">
314 /// Should be true if these scripts are being removed because the scene
315 /// object is being deleted. This will prevent spurious updates to the client.
316 /// </param>
317 public void RemoveScriptInstances(bool sceneObjectBeingDeleted)
318 {
319 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
320 foreach (TaskInventoryItem item in scripts)
321 RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted);
322 }
323
324 /// <summary>
325 /// Stop all the scripts in this prim.
326 /// </summary>
327 public void StopScriptInstances()
328 {
329 GetInventoryItems(InventoryType.LSL).ForEach(i => StopScriptInstance(i));
330 }
331
332 /// <summary>
333 /// Start a script which is in this prim's inventory.
334 /// </summary>
335 /// <param name="item"></param>
336 /// <returns>true if the script instance was created, false otherwise</returns>
337 public bool CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource)
338 {
339// m_log.DebugFormat("[PRIM INVENTORY]: Starting script {0} {1} in prim {2} {3} in {4}",
340// item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName);
341
342 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
343 return false;
344
345 m_part.AddFlag(PrimFlags.Scripted);
346
347 if (m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts)
348 return false;
349
350 if (stateSource == 2 && // Prim crossing
351 m_part.ParentGroup.Scene.m_trustBinaries)
352 {
353 lock (m_items)
354 {
355 m_items[item.ItemID].PermsMask = 0;
356 m_items[item.ItemID].PermsGranter = UUID.Zero;
357 }
358
359 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
360 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
361 m_part.ParentGroup.AddActiveScriptCount(1);
362 m_part.ScheduleFullUpdate();
363 return true;
364 }
365
366 AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
367 if (null == asset)
368 {
369 m_log.ErrorFormat(
370 "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found",
371 item.Name, item.ItemID, m_part.AbsolutePosition,
372 m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID);
373
374 return false;
375 }
376 else
377 {
378 if (m_part.ParentGroup.m_savedScriptState != null)
379 item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID);
380
381 lock (m_items)
382 {
383 m_items[item.ItemID].OldItemID = item.OldItemID;
384 m_items[item.ItemID].PermsMask = 0;
385 m_items[item.ItemID].PermsGranter = UUID.Zero;
386 }
387
388 string script = Utils.BytesToString(asset.Data);
389 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
390 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
391 if (!item.ScriptRunning)
392 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(
393 m_part.LocalId, item.ItemID);
394 m_part.ParentGroup.AddActiveScriptCount(1);
395 m_part.ScheduleFullUpdate();
396
397 return true;
398 }
399 }
400
401 private UUID RestoreSavedScriptState(UUID loadedID, UUID oldID, UUID newID)
402 {
403// m_log.DebugFormat(
404// "[PRIM INVENTORY]: Restoring scripted state for item {0}, oldID {1}, loadedID {2}",
405// newID, oldID, loadedID);
406
407 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
408 if (engines.Length == 0) // No engine at all
409 return oldID;
410
411 UUID stateID = oldID;
412 if (!m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID))
413 stateID = loadedID;
414 if (m_part.ParentGroup.m_savedScriptState.ContainsKey(stateID))
415 {
416 XmlDocument doc = new XmlDocument();
417
418 doc.LoadXml(m_part.ParentGroup.m_savedScriptState[stateID]);
419
420 ////////// CRUFT WARNING ///////////////////////////////////
421 //
422 // Old objects will have <ScriptState><State> ...
423 // This format is XEngine ONLY
424 //
425 // New objects have <State Engine="...." ...><ScriptState>...
426 // This can be passed to any engine
427 //
428 XmlNode n = doc.SelectSingleNode("ScriptState");
429 if (n != null) // Old format data
430 {
431 XmlDocument newDoc = new XmlDocument();
432
433 XmlElement rootN = newDoc.CreateElement("", "State", "");
434 XmlAttribute uuidA = newDoc.CreateAttribute("", "UUID", "");
435 uuidA.Value = stateID.ToString();
436 rootN.Attributes.Append(uuidA);
437 XmlAttribute engineA = newDoc.CreateAttribute("", "Engine", "");
438 engineA.Value = "XEngine";
439 rootN.Attributes.Append(engineA);
440
441 newDoc.AppendChild(rootN);
442
443 XmlNode stateN = newDoc.ImportNode(n, true);
444 rootN.AppendChild(stateN);
445
446 // This created document has only the minimun data
447 // necessary for XEngine to parse it successfully
448
449// m_log.DebugFormat("[PRIM INVENTORY]: Adding legacy state {0} in {1}", stateID, newID);
450
451 m_part.ParentGroup.m_savedScriptState[stateID] = newDoc.OuterXml;
452 }
453
454 foreach (IScriptModule e in engines)
455 {
456 if (e != null)
457 {
458 if (e.SetXMLState(newID, m_part.ParentGroup.m_savedScriptState[stateID]))
459 break;
460 }
461 }
462
463 m_part.ParentGroup.m_savedScriptState.Remove(stateID);
464 }
465
466 return stateID;
467 }
468
469 public bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
470 {
471 TaskInventoryItem item = GetInventoryItem(itemId);
472 if (item != null)
473 {
474 return CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
475 }
476 else
477 {
478 m_log.ErrorFormat(
479 "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
480 itemId, m_part.Name, m_part.UUID,
481 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
482
483 return false;
484 }
485 }
486
487 /// <summary>
488 /// Stop and remove a script which is in this prim's inventory.
489 /// </summary>
490 /// <param name="itemId"></param>
491 /// <param name="sceneObjectBeingDeleted">
492 /// Should be true if this script is being removed because the scene
493 /// object is being deleted. This will prevent spurious updates to the client.
494 /// </param>
495 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
496 {
497 bool scriptPresent = false;
498
499 lock (m_items)
500 {
501 if (m_items.ContainsKey(itemId))
502 scriptPresent = true;
503 }
504
505 if (scriptPresent)
506 {
507 if (!sceneObjectBeingDeleted)
508 m_part.RemoveScriptEvents(itemId);
509
510 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId);
511 m_part.ParentGroup.AddActiveScriptCount(-1);
512 }
513 else
514 {
515 m_log.WarnFormat(
516 "[PRIM INVENTORY]: " +
517 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
518 itemId, m_part.Name, m_part.UUID,
519 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
520 }
521 }
522
523 /// <summary>
524 /// Stop a script which is in this prim's inventory.
525 /// </summary>
526 /// <param name="itemId"></param>
527 /// <param name="sceneObjectBeingDeleted">
528 /// Should be true if this script is being removed because the scene
529 /// object is being deleted. This will prevent spurious updates to the client.
530 /// </param>
531 public void StopScriptInstance(UUID itemId)
532 {
533 TaskInventoryItem scriptItem;
534
535 lock (m_items)
536 m_items.TryGetValue(itemId, out scriptItem);
537
538 if (scriptItem != null)
539 {
540 StopScriptInstance(scriptItem);
541 }
542 else
543 {
544 m_log.WarnFormat(
545 "[PRIM INVENTORY]: " +
546 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
547 itemId, m_part.Name, m_part.UUID,
548 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
549 }
550 }
551
552 /// <summary>
553 /// Stop a script which is in this prim's inventory.
554 /// </summary>
555 /// <param name="itemId"></param>
556 /// <param name="sceneObjectBeingDeleted">
557 /// Should be true if this script is being removed because the scene
558 /// object is being deleted. This will prevent spurious updates to the client.
559 /// </param>
560 public void StopScriptInstance(TaskInventoryItem item)
561 {
562 if (m_part.ParentGroup.Scene != null)
563 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID);
564
565 // At the moment, even stopped scripts are counted as active, which is probably wrong.
566// m_part.ParentGroup.AddActiveScriptCount(-1);
567 }
568
569 /// <summary>
570 /// Check if the inventory holds an item with a given name.
571 /// </summary>
572 /// <param name="name"></param>
573 /// <returns></returns>
574 private bool InventoryContainsName(string name)
575 {
576 lock (m_items)
577 {
578 foreach (TaskInventoryItem item in m_items.Values)
579 {
580 if (item.Name == name)
581 return true;
582 }
583 }
584 return false;
585 }
586
587 /// <summary>
588 /// For a given item name, return that name if it is available. Otherwise, return the next available
589 /// similar name (which is currently the original name with the next available numeric suffix).
590 /// </summary>
591 /// <param name="name"></param>
592 /// <returns></returns>
593 private string FindAvailableInventoryName(string name)
594 {
595 if (!InventoryContainsName(name))
596 return name;
597
598 int suffix=1;
599 while (suffix < 256)
600 {
601 string tryName=String.Format("{0} {1}", name, suffix);
602 if (!InventoryContainsName(tryName))
603 return tryName;
604 suffix++;
605 }
606 return String.Empty;
607 }
608
609 /// <summary>
610 /// Add an item to this prim's inventory. If an item with the same name already exists, then an alternative
611 /// name is chosen.
612 /// </summary>
613 /// <param name="item"></param>
614 public void AddInventoryItem(TaskInventoryItem item, bool allowedDrop)
615 {
616 AddInventoryItem(item.Name, item, allowedDrop);
617 }
618
619 /// <summary>
620 /// Add an item to this prim's inventory. If an item with the same name already exists, it is replaced.
621 /// </summary>
622 /// <param name="item"></param>
623 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
624 {
625 List<TaskInventoryItem> il = GetInventoryItems();
626
627 foreach (TaskInventoryItem i in il)
628 {
629 if (i.Name == item.Name)
630 {
631 if (i.InvType == (int)InventoryType.LSL)
632 RemoveScriptInstance(i.ItemID, false);
633
634 RemoveInventoryItem(i.ItemID);
635 break;
636 }
637 }
638
639 AddInventoryItem(item.Name, item, allowedDrop);
640 }
641
642 /// <summary>
643 /// Add an item to this prim's inventory.
644 /// </summary>
645 /// <param name="name">The name that the new item should have.</param>
646 /// <param name="item">
647 /// The item itself. The name within this structure is ignored in favour of the name
648 /// given in this method's arguments
649 /// </param>
650 /// <param name="allowedDrop">
651 /// Item was only added to inventory because AllowedDrop is set
652 /// </param>
653 protected void AddInventoryItem(string name, TaskInventoryItem item, bool allowedDrop)
654 {
655 name = FindAvailableInventoryName(name);
656 if (name == String.Empty)
657 return;
658
659 item.ParentID = m_part.UUID;
660 item.ParentPartID = m_part.UUID;
661 item.Name = name;
662 item.GroupID = m_part.GroupID;
663
664 lock (m_items)
665 m_items.Add(item.ItemID, item);
666
667 if (allowedDrop)
668 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
669 else
670 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
671
672 m_inventorySerial++;
673 //m_inventorySerial += 2;
674 HasInventoryChanged = true;
675 m_part.ParentGroup.HasGroupChanged = true;
676 }
677
678 /// <summary>
679 /// Restore a whole collection of items to the prim's inventory at once.
680 /// We assume that the items already have all their fields correctly filled out.
681 /// The items are not flagged for persistence to the database, since they are being restored
682 /// from persistence rather than being newly added.
683 /// </summary>
684 /// <param name="items"></param>
685 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
686 {
687 lock (m_items)
688 {
689 foreach (TaskInventoryItem item in items)
690 {
691 m_items.Add(item.ItemID, item);
692// m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
693 }
694 m_inventorySerial++;
695 }
696 }
697
698 /// <summary>
699 /// Returns an existing inventory item. Returns the original, so any changes will be live.
700 /// </summary>
701 /// <param name="itemID"></param>
702 /// <returns>null if the item does not exist</returns>
703 public TaskInventoryItem GetInventoryItem(UUID itemId)
704 {
705 TaskInventoryItem item;
706
707 lock (m_items)
708 m_items.TryGetValue(itemId, out item);
709
710 return item;
711 }
712
713 public TaskInventoryItem GetInventoryItem(string name)
714 {
715 lock (m_items)
716 {
717 foreach (TaskInventoryItem item in m_items.Values)
718 {
719 if (item.Name == name)
720 return item;
721 }
722 }
723
724 return null;
725 }
726
727 public List<TaskInventoryItem> GetInventoryItems(string name)
728 {
729 List<TaskInventoryItem> items = new List<TaskInventoryItem>();
730
731 lock (m_items)
732 {
733 foreach (TaskInventoryItem item in m_items.Values)
734 {
735 if (item.Name == name)
736 items.Add(item);
737 }
738 }
739
740 return items;
741 }
742
743 public bool GetRezReadySceneObjects(TaskInventoryItem item, out List<SceneObjectGroup> objlist, out List<Vector3> veclist)
744 {
745 AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
746
747 if (null == rezAsset)
748 {
749 m_log.WarnFormat(
750 "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}",
751 item.AssetID, item.Name, m_part.Name);
752 objlist = null;
753 veclist = null;
754 return false;
755 }
756
757 Vector3 bbox;
758 float offsetHeight;
759
760 m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight);
761
762 for (int i = 0; i < objlist.Count; i++)
763 {
764 SceneObjectGroup group = objlist[i];
765
766 group.ResetIDs();
767
768 SceneObjectPart rootPart = group.GetPart(group.UUID);
769
770 // Since renaming the item in the inventory does not affect the name stored
771 // in the serialization, transfer the correct name from the inventory to the
772 // object itself before we rez.
773 // Only do these for the first object if we are rezzing a coalescence.
774 if (i == 0)
775 {
776 rootPart.Name = item.Name;
777 rootPart.Description = item.Description;
778 }
779
780 group.SetGroup(m_part.GroupID, null);
781
782 foreach (SceneObjectPart part in group.Parts)
783 {
784 // Convert between InventoryItem classes. You can never have too many similar but slightly different classes :)
785 InventoryItemBase dest = new InventoryItemBase(item.ItemID, item.OwnerID);
786 dest.BasePermissions = item.BasePermissions;
787 dest.CurrentPermissions = item.CurrentPermissions;
788 dest.EveryOnePermissions = item.EveryonePermissions;
789 dest.GroupPermissions = item.GroupPermissions;
790 dest.NextPermissions = item.NextPermissions;
791 dest.Flags = item.Flags;
792
793 part.ApplyPermissionsOnRez(dest, false, m_part.ParentGroup.Scene);
794 }
795
796 rootPart.TrimPermissions();
797 }
798
799 return true;
800 }
801
802 /// <summary>
803 /// Update an existing inventory item.
804 /// </summary>
805 /// <param name="item">The updated item. An item with the same id must already exist
806 /// in this prim's inventory.</param>
807 /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
808 public bool UpdateInventoryItem(TaskInventoryItem item)
809 {
810 return UpdateInventoryItem(item, true, true);
811 }
812
813 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents)
814 {
815 return UpdateInventoryItem(item, fireScriptEvents, true);
816 }
817
818 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
819 {
820 TaskInventoryItem it = GetInventoryItem(item.ItemID);
821 if (it != null)
822 {
823// m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
824
825 item.ParentID = m_part.UUID;
826 item.ParentPartID = m_part.UUID;
827
828 // If group permissions have been set on, check that the groupID is up to date in case it has
829 // changed since permissions were last set.
830 if (item.GroupPermissions != (uint)PermissionMask.None)
831 item.GroupID = m_part.GroupID;
832
833 if (item.AssetID == UUID.Zero)
834 item.AssetID = it.AssetID;
835
836 lock (m_items)
837 {
838 m_items[item.ItemID] = item;
839 m_inventorySerial++;
840 }
841
842 if (fireScriptEvents)
843 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
844
845 if (considerChanged)
846 {
847 HasInventoryChanged = true;
848 m_part.ParentGroup.HasGroupChanged = true;
849 }
850
851 return true;
852 }
853 else
854 {
855 m_log.ErrorFormat(
856 "[PRIM INVENTORY]: " +
857 "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
858 item.ItemID, m_part.Name, m_part.UUID,
859 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
860 }
861 return false;
862
863 }
864
865 /// <summary>
866 /// Remove an item from this prim's inventory
867 /// </summary>
868 /// <param name="itemID"></param>
869 /// <returns>Numeric asset type of the item removed. Returns -1 if the item did not exist
870 /// in this prim's inventory.</returns>
871 public int RemoveInventoryItem(UUID itemID)
872 {
873 TaskInventoryItem item = GetInventoryItem(itemID);
874 if (item != null)
875 {
876 int type = m_items[itemID].InvType;
877 if (type == 10) // Script
878 {
879 // route it through here, to handle script cleanup tasks
880 RemoveScriptInstance(itemID, false);
881 }
882 m_items.Remove(itemID);
883 m_inventorySerial++;
884 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
885
886 HasInventoryChanged = true;
887 m_part.ParentGroup.HasGroupChanged = true;
888
889 if (!ContainsScripts())
890 m_part.RemFlag(PrimFlags.Scripted);
891
892 m_part.ScheduleFullUpdate();
893
894 return type;
895
896 }
897 else
898 {
899 m_log.ErrorFormat(
900 "[PRIM INVENTORY]: " +
901 "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
902 itemID, m_part.Name, m_part.UUID,
903 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
904 }
905
906 return -1;
907 }
908
909 private bool CreateInventoryFile()
910 {
911// m_log.DebugFormat(
912// "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}",
913// m_part.Name, m_part.UUID, m_part.LocalId, m_inventorySerial);
914
915 if (m_inventoryFileName == String.Empty ||
916 m_inventoryFileNameSerial < m_inventorySerial)
917 {
918 // Something changed, we need to create a new file
919 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
920 m_inventoryFileNameSerial = m_inventorySerial;
921
922 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
923
924 lock (m_items)
925 {
926 foreach (TaskInventoryItem item in m_items.Values)
927 {
928// m_log.DebugFormat(
929// "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}",
930// item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId);
931
932 UUID ownerID = item.OwnerID;
933 uint everyoneMask = 0;
934 uint baseMask = item.BasePermissions;
935 uint ownerMask = item.CurrentPermissions;
936 uint groupMask = item.GroupPermissions;
937
938 invString.AddItemStart();
939 invString.AddNameValueLine("item_id", item.ItemID.ToString());
940 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
941
942 invString.AddPermissionsStart();
943
944 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
945 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
946 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
947 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
948 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
949
950 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
951 invString.AddNameValueLine("owner_id", ownerID.ToString());
952
953 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
954
955 invString.AddNameValueLine("group_id", item.GroupID.ToString());
956 invString.AddSectionEnd();
957
958 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
959 invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type));
960 invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType));
961 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
962
963 invString.AddSaleStart();
964 invString.AddNameValueLine("sale_type", "not");
965 invString.AddNameValueLine("sale_price", "0");
966 invString.AddSectionEnd();
967
968 invString.AddNameValueLine("name", item.Name + "|");
969 invString.AddNameValueLine("desc", item.Description + "|");
970
971 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
972 invString.AddSectionEnd();
973 }
974 }
975
976 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
977
978 return true;
979 }
980
981 // No need to recreate, the existing file is fine
982 return false;
983 }
984
985 /// <summary>
986 /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
987 /// </summary>
988 /// <param name="xferManager"></param>
989 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
990 {
991 lock (m_items)
992 {
993 // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing
994 // a new script if any previous deletion has left the prim inventory empty.
995 if (m_items.Count == 0) // No inventory
996 {
997// m_log.DebugFormat(
998// "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items",
999// m_part.Name, m_part.LocalId, m_part.UUID, client.Name);
1000
1001 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
1002 return;
1003 }
1004
1005 CreateInventoryFile();
1006
1007 // In principle, we should only do the rest if the inventory changed;
1008 // by sending m_inventorySerial to the client, it ought to know
1009 // that nothing changed and that it doesn't need to request the file.
1010 // Unfortunately, it doesn't look like the client optimizes this;
1011 // the client seems to always come back and request the Xfer,
1012 // no matter what value m_inventorySerial has.
1013 // FIXME: Could probably be > 0 here rather than > 2
1014 if (m_inventoryFileData.Length > 2)
1015 {
1016 // Add the file for Xfer
1017 // m_log.DebugFormat(
1018 // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}",
1019 // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId);
1020
1021 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
1022 }
1023
1024 // Tell the client we're ready to Xfer the file
1025 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
1026 Util.StringToBytes256(m_inventoryFileName));
1027 }
1028 }
1029
1030 /// <summary>
1031 /// Process inventory backup
1032 /// </summary>
1033 /// <param name="datastore"></param>
1034 public void ProcessInventoryBackup(ISimulationDataService datastore)
1035 {
1036 if (HasInventoryChanged)
1037 {
1038 HasInventoryChanged = false;
1039 List<TaskInventoryItem> items = GetInventoryItems();
1040 datastore.StorePrimInventory(m_part.UUID, items);
1041
1042 }
1043 }
1044
1045 public class InventoryStringBuilder
1046 {
1047 public string BuildString = String.Empty;
1048
1049 public InventoryStringBuilder(UUID folderID, UUID parentID)
1050 {
1051 BuildString += "\tinv_object\t0\n\t{\n";
1052 AddNameValueLine("obj_id", folderID.ToString());
1053 AddNameValueLine("parent_id", parentID.ToString());
1054 AddNameValueLine("type", "category");
1055 AddNameValueLine("name", "Contents|");
1056 AddSectionEnd();
1057 }
1058
1059 public void AddItemStart()
1060 {
1061 BuildString += "\tinv_item\t0\n";
1062 AddSectionStart();
1063 }
1064
1065 public void AddPermissionsStart()
1066 {
1067 BuildString += "\tpermissions 0\n";
1068 AddSectionStart();
1069 }
1070
1071 public void AddSaleStart()
1072 {
1073 BuildString += "\tsale_info\t0\n";
1074 AddSectionStart();
1075 }
1076
1077 protected void AddSectionStart()
1078 {
1079 BuildString += "\t{\n";
1080 }
1081
1082 public void AddSectionEnd()
1083 {
1084 BuildString += "\t}\n";
1085 }
1086
1087 public void AddLine(string addLine)
1088 {
1089 BuildString += addLine;
1090 }
1091
1092 public void AddNameValueLine(string name, string value)
1093 {
1094 BuildString += "\t\t";
1095 BuildString += name + "\t";
1096 BuildString += value + "\n";
1097 }
1098
1099 public void Close()
1100 {
1101 }
1102 }
1103
1104 public uint MaskEffectivePermissions()
1105 {
1106 uint mask=0x7fffffff;
1107
1108 lock (m_items)
1109 {
1110 foreach (TaskInventoryItem item in m_items.Values)
1111 {
1112 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1113 mask &= ~((uint)PermissionMask.Copy >> 13);
1114 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1115 mask &= ~((uint)PermissionMask.Transfer >> 13);
1116 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1117 mask &= ~((uint)PermissionMask.Modify >> 13);
1118
1119 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1120 mask &= ~(uint)PermissionMask.Copy;
1121 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1122 mask &= ~(uint)PermissionMask.Transfer;
1123 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1124 mask &= ~(uint)PermissionMask.Modify;
1125 }
1126 }
1127
1128 return mask;
1129 }
1130
1131 public void ApplyNextOwnerPermissions()
1132 {
1133 lock (m_items)
1134 {
1135 foreach (TaskInventoryItem item in m_items.Values)
1136 {
1137// m_log.DebugFormat (
1138// "[SCENE OBJECT PART INVENTORY]: Applying next permissions {0} to {1} in {2} with current {3}, base {4}, everyone {5}",
1139// item.NextPermissions, item.Name, m_part.Name, item.CurrentPermissions, item.BasePermissions, item.EveryonePermissions);
1140
1141 if (item.InvType == (int)InventoryType.Object)
1142 {
1143 uint perms = item.CurrentPermissions;
1144 PermissionsUtil.ApplyFoldedPermissions(perms, ref perms);
1145 item.CurrentPermissions = perms;
1146 }
1147
1148 item.CurrentPermissions &= item.NextPermissions;
1149 item.BasePermissions &= item.NextPermissions;
1150 item.EveryonePermissions &= item.NextPermissions;
1151 item.OwnerChanged = true;
1152 item.PermsMask = 0;
1153 item.PermsGranter = UUID.Zero;
1154 }
1155 }
1156 }
1157
1158 public void ApplyGodPermissions(uint perms)
1159 {
1160 lock (m_items)
1161 {
1162 foreach (TaskInventoryItem item in m_items.Values)
1163 {
1164 item.CurrentPermissions = perms;
1165 item.BasePermissions = perms;
1166 }
1167 }
1168
1169 m_inventorySerial++;
1170 HasInventoryChanged = true;
1171 }
1172
1173 /// <summary>
1174 /// Returns true if this part inventory contains any scripts. False otherwise.
1175 /// </summary>
1176 /// <returns></returns>
1177 public bool ContainsScripts()
1178 {
1179 lock (m_items)
1180 {
1181 foreach (TaskInventoryItem item in m_items.Values)
1182 {
1183 if (item.InvType == (int)InventoryType.LSL)
1184 {
1185 return true;
1186 }
1187 }
1188 }
1189
1190 return false;
1191 }
1192
1193 /// <summary>
1194 /// Returns the count of scripts in this parts inventory.
1195 /// </summary>
1196 /// <returns></returns>
1197 public int ScriptCount()
1198 {
1199 int count = 0;
1200 lock (m_items)
1201 {
1202 foreach (TaskInventoryItem item in m_items.Values)
1203 {
1204 if (item.InvType == (int)InventoryType.LSL)
1205 {
1206 count++;
1207 }
1208 }
1209 }
1210
1211 return count;
1212 }
1213 /// <summary>
1214 /// Returns the count of running scripts in this parts inventory.
1215 /// </summary>
1216 /// <returns></returns>
1217 public int RunningScriptCount()
1218 {
1219 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1220 if (engines.Length == 0)
1221 return 0;
1222
1223 int count = 0;
1224 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
1225
1226 foreach (TaskInventoryItem item in scripts)
1227 {
1228 foreach (IScriptModule engine in engines)
1229 {
1230 if (engine != null)
1231 {
1232 if (engine.GetScriptState(item.ItemID))
1233 {
1234 count++;
1235 }
1236 }
1237 }
1238 }
1239 return count;
1240 }
1241
1242 public List<UUID> GetInventoryList()
1243 {
1244 List<UUID> ret = new List<UUID>();
1245
1246 lock (m_items)
1247 {
1248 foreach (TaskInventoryItem item in m_items.Values)
1249 ret.Add(item.ItemID);
1250 }
1251
1252 return ret;
1253 }
1254
1255 public List<TaskInventoryItem> GetInventoryItems()
1256 {
1257 List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
1258
1259 lock (m_items)
1260 ret = new List<TaskInventoryItem>(m_items.Values);
1261
1262 return ret;
1263 }
1264
1265 public List<TaskInventoryItem> GetInventoryItems(InventoryType type)
1266 {
1267 List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
1268
1269 lock (m_items)
1270 {
1271 foreach (TaskInventoryItem item in m_items.Values)
1272 if (item.InvType == (int)type)
1273 ret.Add(item);
1274 }
1275
1276 return ret;
1277 }
1278
1279 public Dictionary<UUID, string> GetScriptStates()
1280 {
1281 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
1282
1283 if (m_part.ParentGroup.Scene == null) // Group not in a scene
1284 return ret;
1285
1286 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1287
1288 if (engines.Length == 0) // No engine at all
1289 return ret;
1290
1291 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
1292
1293 foreach (TaskInventoryItem item in scripts)
1294 {
1295 foreach (IScriptModule e in engines)
1296 {
1297 if (e != null)
1298 {
1299// m_log.DebugFormat(
1300// "[PRIM INVENTORY]: Getting script state from engine {0} for {1} in part {2} in group {3} in {4}",
1301// e.Name, item.Name, m_part.Name, m_part.ParentGroup.Name, m_part.ParentGroup.Scene.Name);
1302
1303 string n = e.GetXMLState(item.ItemID);
1304 if (n != String.Empty)
1305 {
1306 if (!ret.ContainsKey(item.ItemID))
1307 ret[item.ItemID] = n;
1308 break;
1309 }
1310 }
1311 }
1312 }
1313
1314 return ret;
1315 }
1316
1317 public void ResumeScripts()
1318 {
1319 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1320 if (engines.Length == 0)
1321 return;
1322
1323 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
1324
1325 foreach (TaskInventoryItem item in scripts)
1326 {
1327 foreach (IScriptModule engine in engines)
1328 {
1329 if (engine != null)
1330 {
1331// m_log.DebugFormat(
1332// "[PRIM INVENTORY]: Resuming script {0} {1} for {2}, OwnerChanged {3}",
1333// item.Name, item.ItemID, item.OwnerID, item.OwnerChanged);
1334
1335 engine.ResumeScript(item.ItemID);
1336
1337 if (item.OwnerChanged)
1338 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
1339
1340 item.OwnerChanged = false;
1341 }
1342 }
1343 }
1344 }
1345 }
1346}