opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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  
28 using System;
29 using System.Xml;
30 using System.IO;
31 using System.Collections.Generic;
32 using System.Collections;
33 using System.Reflection;
34 using System.Threading;
35 using OpenMetaverse;
36 using log4net;
37 using OpenSim.Framework;
38 using OpenSim.Region.Framework.Interfaces;
39 using OpenSim.Region.Framework.Scenes.Scripting;
40 using OpenSim.Region.Framework.Scenes.Serialization;
41 using PermissionMask = OpenSim.Framework.PermissionMask;
42  
43 namespace 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 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
404 if (engines.Length == 0) // No engine at all
405 return oldID;
406  
407 UUID stateID = oldID;
408 if (!m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID))
409 stateID = loadedID;
410 if (m_part.ParentGroup.m_savedScriptState.ContainsKey(stateID))
411 {
412 XmlDocument doc = new XmlDocument();
413  
414 doc.LoadXml(m_part.ParentGroup.m_savedScriptState[stateID]);
415  
416 ////////// CRUFT WARNING ///////////////////////////////////
417 //
418 // Old objects will have <ScriptState><State> ...
419 // This format is XEngine ONLY
420 //
421 // New objects have <State Engine="...." ...><ScriptState>...
422 // This can be passed to any engine
423 //
424 XmlNode n = doc.SelectSingleNode("ScriptState");
425 if (n != null) // Old format data
426 {
427 XmlDocument newDoc = new XmlDocument();
428  
429 XmlElement rootN = newDoc.CreateElement("", "State", "");
430 XmlAttribute uuidA = newDoc.CreateAttribute("", "UUID", "");
431 uuidA.Value = stateID.ToString();
432 rootN.Attributes.Append(uuidA);
433 XmlAttribute engineA = newDoc.CreateAttribute("", "Engine", "");
434 engineA.Value = "XEngine";
435 rootN.Attributes.Append(engineA);
436  
437 newDoc.AppendChild(rootN);
438  
439 XmlNode stateN = newDoc.ImportNode(n, true);
440 rootN.AppendChild(stateN);
441  
442 // This created document has only the minimun data
443 // necessary for XEngine to parse it successfully
444  
445 m_part.ParentGroup.m_savedScriptState[stateID] = newDoc.OuterXml;
446 }
447  
448 foreach (IScriptModule e in engines)
449 {
450 if (e != null)
451 {
452 if (e.SetXMLState(newID, m_part.ParentGroup.m_savedScriptState[stateID]))
453 break;
454 }
455 }
456  
457 m_part.ParentGroup.m_savedScriptState.Remove(stateID);
458 }
459  
460 return stateID;
461 }
462  
463 public bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
464 {
465 TaskInventoryItem item = GetInventoryItem(itemId);
466 if (item != null)
467 {
468 return CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
469 }
470 else
471 {
472 m_log.ErrorFormat(
473 "[PRIM INVENTORY]: Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
474 itemId, m_part.Name, m_part.UUID,
475 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
476  
477 return false;
478 }
479 }
480  
481 /// <summary>
482 /// Stop and remove a script which is in this prim's inventory.
483 /// </summary>
484 /// <param name="itemId"></param>
485 /// <param name="sceneObjectBeingDeleted">
486 /// Should be true if this script is being removed because the scene
487 /// object is being deleted. This will prevent spurious updates to the client.
488 /// </param>
489 public void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted)
490 {
491 bool scriptPresent = false;
492  
493 lock (m_items)
494 {
495 if (m_items.ContainsKey(itemId))
496 scriptPresent = true;
497 }
498  
499 if (scriptPresent)
500 {
501 if (!sceneObjectBeingDeleted)
502 m_part.RemoveScriptEvents(itemId);
503  
504 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId);
505 m_part.ParentGroup.AddActiveScriptCount(-1);
506 }
507 else
508 {
509 m_log.WarnFormat(
510 "[PRIM INVENTORY]: " +
511 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
512 itemId, m_part.Name, m_part.UUID,
513 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
514 }
515 }
516  
517 /// <summary>
518 /// Stop a script which is in this prim's inventory.
519 /// </summary>
520 /// <param name="itemId"></param>
521 /// <param name="sceneObjectBeingDeleted">
522 /// Should be true if this script is being removed because the scene
523 /// object is being deleted. This will prevent spurious updates to the client.
524 /// </param>
525 public void StopScriptInstance(UUID itemId)
526 {
527 TaskInventoryItem scriptItem;
528  
529 lock (m_items)
530 m_items.TryGetValue(itemId, out scriptItem);
531  
532 if (scriptItem != null)
533 {
534 StopScriptInstance(scriptItem);
535 }
536 else
537 {
538 m_log.WarnFormat(
539 "[PRIM INVENTORY]: " +
540 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}",
541 itemId, m_part.Name, m_part.UUID,
542 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
543 }
544 }
545  
546 /// <summary>
547 /// Stop a script which is in this prim's inventory.
548 /// </summary>
549 /// <param name="itemId"></param>
550 /// <param name="sceneObjectBeingDeleted">
551 /// Should be true if this script is being removed because the scene
552 /// object is being deleted. This will prevent spurious updates to the client.
553 /// </param>
554 public void StopScriptInstance(TaskInventoryItem item)
555 {
556 if (m_part.ParentGroup.Scene != null)
557 m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID);
558  
559 // At the moment, even stopped scripts are counted as active, which is probably wrong.
560 // m_part.ParentGroup.AddActiveScriptCount(-1);
561 }
562  
563 /// <summary>
564 /// Check if the inventory holds an item with a given name.
565 /// </summary>
566 /// <param name="name"></param>
567 /// <returns></returns>
568 private bool InventoryContainsName(string name)
569 {
570 lock (m_items)
571 {
572 foreach (TaskInventoryItem item in m_items.Values)
573 {
574 if (item.Name == name)
575 return true;
576 }
577 }
578 return false;
579 }
580  
581 /// <summary>
582 /// For a given item name, return that name if it is available. Otherwise, return the next available
583 /// similar name (which is currently the original name with the next available numeric suffix).
584 /// </summary>
585 /// <param name="name"></param>
586 /// <returns></returns>
587 private string FindAvailableInventoryName(string name)
588 {
589 if (!InventoryContainsName(name))
590 return name;
591  
592 int suffix=1;
593 while (suffix < 256)
594 {
595 string tryName=String.Format("{0} {1}", name, suffix);
596 if (!InventoryContainsName(tryName))
597 return tryName;
598 suffix++;
599 }
600 return String.Empty;
601 }
602  
603 /// <summary>
604 /// Add an item to this prim's inventory. If an item with the same name already exists, then an alternative
605 /// name is chosen.
606 /// </summary>
607 /// <param name="item"></param>
608 public void AddInventoryItem(TaskInventoryItem item, bool allowedDrop)
609 {
610 AddInventoryItem(item.Name, item, allowedDrop);
611 }
612  
613 /// <summary>
614 /// Add an item to this prim's inventory. If an item with the same name already exists, it is replaced.
615 /// </summary>
616 /// <param name="item"></param>
617 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
618 {
619 List<TaskInventoryItem> il = GetInventoryItems();
620  
621 foreach (TaskInventoryItem i in il)
622 {
623 if (i.Name == item.Name)
624 {
625 if (i.InvType == (int)InventoryType.LSL)
626 RemoveScriptInstance(i.ItemID, false);
627  
628 RemoveInventoryItem(i.ItemID);
629 break;
630 }
631 }
632  
633 AddInventoryItem(item.Name, item, allowedDrop);
634 }
635  
636 /// <summary>
637 /// Add an item to this prim's inventory.
638 /// </summary>
639 /// <param name="name">The name that the new item should have.</param>
640 /// <param name="item">
641 /// The item itself. The name within this structure is ignored in favour of the name
642 /// given in this method's arguments
643 /// </param>
644 /// <param name="allowedDrop">
645 /// Item was only added to inventory because AllowedDrop is set
646 /// </param>
647 protected void AddInventoryItem(string name, TaskInventoryItem item, bool allowedDrop)
648 {
649 name = FindAvailableInventoryName(name);
650 if (name == String.Empty)
651 return;
652  
653 item.ParentID = m_part.UUID;
654 item.ParentPartID = m_part.UUID;
655 item.Name = name;
656 item.GroupID = m_part.GroupID;
657  
658 lock (m_items)
659 m_items.Add(item.ItemID, item);
660  
661 if (allowedDrop)
662 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
663 else
664 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
665  
666 m_inventorySerial++;
667 //m_inventorySerial += 2;
668 HasInventoryChanged = true;
669 m_part.ParentGroup.HasGroupChanged = true;
670 }
671  
672 /// <summary>
673 /// Restore a whole collection of items to the prim's inventory at once.
674 /// We assume that the items already have all their fields correctly filled out.
675 /// The items are not flagged for persistence to the database, since they are being restored
676 /// from persistence rather than being newly added.
677 /// </summary>
678 /// <param name="items"></param>
679 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
680 {
681 lock (m_items)
682 {
683 foreach (TaskInventoryItem item in items)
684 {
685 m_items.Add(item.ItemID, item);
686 // m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
687 }
688 m_inventorySerial++;
689 }
690 }
691  
692 /// <summary>
693 /// Returns an existing inventory item. Returns the original, so any changes will be live.
694 /// </summary>
695 /// <param name="itemID"></param>
696 /// <returns>null if the item does not exist</returns>
697 public TaskInventoryItem GetInventoryItem(UUID itemId)
698 {
699 TaskInventoryItem item;
700  
701 lock (m_items)
702 m_items.TryGetValue(itemId, out item);
703  
704 return item;
705 }
706  
707 public TaskInventoryItem GetInventoryItem(string name)
708 {
709 lock (m_items)
710 {
711 foreach (TaskInventoryItem item in m_items.Values)
712 {
713 if (item.Name == name)
714 return item;
715 }
716 }
717  
718 return null;
719 }
720  
721 public List<TaskInventoryItem> GetInventoryItems(string name)
722 {
723 List<TaskInventoryItem> items = new List<TaskInventoryItem>();
724  
725 lock (m_items)
726 {
727 foreach (TaskInventoryItem item in m_items.Values)
728 {
729 if (item.Name == name)
730 items.Add(item);
731 }
732 }
733  
734 return items;
735 }
736  
737 public bool GetRezReadySceneObjects(TaskInventoryItem item, out List<SceneObjectGroup> objlist, out List<Vector3> veclist)
738 {
739 AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString());
740  
741 if (null == rezAsset)
742 {
743 m_log.WarnFormat(
744 "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}",
745 item.AssetID, item.Name, m_part.Name);
746 objlist = null;
747 veclist = null;
748 return false;
749 }
750  
751 Vector3 bbox;
752 float offsetHeight;
753  
754 bool single = m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight);
755  
756 for (int i = 0; i < objlist.Count; i++)
757 {
758 SceneObjectGroup group = objlist[i];
759  
760 group.ResetIDs();
761  
762 SceneObjectPart rootPart = group.GetPart(group.UUID);
763  
764 // Since renaming the item in the inventory does not affect the name stored
765 // in the serialization, transfer the correct name from the inventory to the
766 // object itself before we rez.
767 // Only do these for the first object if we are rezzing a coalescence.
768 if (i == 0)
769 {
770 rootPart.Name = item.Name;
771 rootPart.Description = item.Description;
772 }
773  
774 group.SetGroup(m_part.GroupID, null);
775  
776 foreach (SceneObjectPart part in group.Parts)
777 {
778 // Convert between InventoryItem classes. You can never have too many similar but slightly different classes :)
779 InventoryItemBase dest = new InventoryItemBase(item.ItemID, item.OwnerID);
780 dest.BasePermissions = item.BasePermissions;
781 dest.CurrentPermissions = item.CurrentPermissions;
782 dest.EveryOnePermissions = item.EveryonePermissions;
783 dest.GroupPermissions = item.GroupPermissions;
784 dest.NextPermissions = item.NextPermissions;
785 dest.Flags = item.Flags;
786  
787 part.ApplyPermissionsOnRez(dest, false, m_part.ParentGroup.Scene);
788 }
789  
790 rootPart.TrimPermissions();
791 }
792  
793 return true;
794 }
795  
796 /// <summary>
797 /// Update an existing inventory item.
798 /// </summary>
799 /// <param name="item">The updated item. An item with the same id must already exist
800 /// in this prim's inventory.</param>
801 /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
802 public bool UpdateInventoryItem(TaskInventoryItem item)
803 {
804 return UpdateInventoryItem(item, true, true);
805 }
806  
807 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents)
808 {
809 return UpdateInventoryItem(item, fireScriptEvents, true);
810 }
811  
812 public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
813 {
814 TaskInventoryItem it = GetInventoryItem(item.ItemID);
815 if (it != null)
816 {
817 // m_log.DebugFormat("[PRIM INVENTORY]: Updating item {0} in {1}", item.Name, m_part.Name);
818  
819 item.ParentID = m_part.UUID;
820 item.ParentPartID = m_part.UUID;
821  
822 // If group permissions have been set on, check that the groupID is up to date in case it has
823 // changed since permissions were last set.
824 if (item.GroupPermissions != (uint)PermissionMask.None)
825 item.GroupID = m_part.GroupID;
826  
827 if (item.AssetID == UUID.Zero)
828 item.AssetID = it.AssetID;
829  
830 lock (m_items)
831 {
832 m_items[item.ItemID] = item;
833 m_inventorySerial++;
834 }
835  
836 if (fireScriptEvents)
837 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
838  
839 if (considerChanged)
840 {
841 HasInventoryChanged = true;
842 m_part.ParentGroup.HasGroupChanged = true;
843 }
844  
845 return true;
846 }
847 else
848 {
849 m_log.ErrorFormat(
850 "[PRIM INVENTORY]: " +
851 "Tried to retrieve item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
852 item.ItemID, m_part.Name, m_part.UUID,
853 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
854 }
855 return false;
856  
857 }
858  
859 /// <summary>
860 /// Remove an item from this prim's inventory
861 /// </summary>
862 /// <param name="itemID"></param>
863 /// <returns>Numeric asset type of the item removed. Returns -1 if the item did not exist
864 /// in this prim's inventory.</returns>
865 public int RemoveInventoryItem(UUID itemID)
866 {
867 TaskInventoryItem item = GetInventoryItem(itemID);
868 if (item != null)
869 {
870 int type = m_items[itemID].InvType;
871 if (type == 10) // Script
872 {
873 m_part.RemoveScriptEvents(itemID);
874 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
875 }
876 m_items.Remove(itemID);
877 m_inventorySerial++;
878 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
879  
880 HasInventoryChanged = true;
881 m_part.ParentGroup.HasGroupChanged = true;
882  
883 if (!ContainsScripts())
884 m_part.RemFlag(PrimFlags.Scripted);
885  
886 m_part.ScheduleFullUpdate();
887  
888 return type;
889  
890 }
891 else
892 {
893 m_log.ErrorFormat(
894 "[PRIM INVENTORY]: " +
895 "Tried to remove item ID {0} from prim {1}, {2} at {3} in {4} but the item does not exist in this inventory",
896 itemID, m_part.Name, m_part.UUID,
897 m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName);
898 }
899  
900 return -1;
901 }
902  
903 private bool CreateInventoryFile()
904 {
905 // m_log.DebugFormat(
906 // "[PRIM INVENTORY]: Creating inventory file for {0} {1} {2}, serial {3}",
907 // m_part.Name, m_part.UUID, m_part.LocalId, m_inventorySerial);
908  
909 if (m_inventoryFileName == String.Empty ||
910 m_inventoryFileNameSerial < m_inventorySerial)
911 {
912 // Something changed, we need to create a new file
913 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
914 m_inventoryFileNameSerial = m_inventorySerial;
915  
916 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
917  
918 lock (m_items)
919 {
920 foreach (TaskInventoryItem item in m_items.Values)
921 {
922 // m_log.DebugFormat(
923 // "[PRIM INVENTORY]: Adding item {0} {1} for serial {2} on prim {3} {4} {5}",
924 // item.Name, item.ItemID, m_inventorySerial, m_part.Name, m_part.UUID, m_part.LocalId);
925  
926 UUID ownerID = item.OwnerID;
927 uint everyoneMask = 0;
928 uint baseMask = item.BasePermissions;
929 uint ownerMask = item.CurrentPermissions;
930 uint groupMask = item.GroupPermissions;
931  
932 invString.AddItemStart();
933 invString.AddNameValueLine("item_id", item.ItemID.ToString());
934 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
935  
936 invString.AddPermissionsStart();
937  
938 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
939 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
940 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(groupMask));
941 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
942 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
943  
944 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
945 invString.AddNameValueLine("owner_id", ownerID.ToString());
946  
947 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
948  
949 invString.AddNameValueLine("group_id", item.GroupID.ToString());
950 invString.AddSectionEnd();
951  
952 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
953 invString.AddNameValueLine("type", Utils.AssetTypeToString((AssetType)item.Type));
954 invString.AddNameValueLine("inv_type", Utils.InventoryTypeToString((InventoryType)item.InvType));
955 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
956  
957 invString.AddSaleStart();
958 invString.AddNameValueLine("sale_type", "not");
959 invString.AddNameValueLine("sale_price", "0");
960 invString.AddSectionEnd();
961  
962 invString.AddNameValueLine("name", item.Name + "|");
963 invString.AddNameValueLine("desc", item.Description + "|");
964  
965 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
966 invString.AddSectionEnd();
967 }
968 }
969  
970 m_inventoryFileData = Utils.StringToBytes(invString.BuildString);
971  
972 return true;
973 }
974  
975 // No need to recreate, the existing file is fine
976 return false;
977 }
978  
979 /// <summary>
980 /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
981 /// </summary>
982 /// <param name="xferManager"></param>
983 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
984 {
985 lock (m_items)
986 {
987 // Don't send a inventory xfer name if there are no items. Doing so causes viewer 3 to crash when rezzing
988 // a new script if any previous deletion has left the prim inventory empty.
989 if (m_items.Count == 0) // No inventory
990 {
991 // m_log.DebugFormat(
992 // "[PRIM INVENTORY]: Not sending inventory data for part {0} {1} {2} for {3} since no items",
993 // m_part.Name, m_part.LocalId, m_part.UUID, client.Name);
994  
995 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
996 return;
997 }
998  
999 CreateInventoryFile();
1000  
1001 // In principle, we should only do the rest if the inventory changed;
1002 // by sending m_inventorySerial to the client, it ought to know
1003 // that nothing changed and that it doesn't need to request the file.
1004 // Unfortunately, it doesn't look like the client optimizes this;
1005 // the client seems to always come back and request the Xfer,
1006 // no matter what value m_inventorySerial has.
1007 // FIXME: Could probably be > 0 here rather than > 2
1008 if (m_inventoryFileData.Length > 2)
1009 {
1010 // Add the file for Xfer
1011 // m_log.DebugFormat(
1012 // "[PRIM INVENTORY]: Adding inventory file {0} (length {1}) for transfer on {2} {3} {4}",
1013 // m_inventoryFileName, m_inventoryFileData.Length, m_part.Name, m_part.UUID, m_part.LocalId);
1014  
1015 xferManager.AddNewFile(m_inventoryFileName, m_inventoryFileData);
1016 }
1017  
1018 // Tell the client we're ready to Xfer the file
1019 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
1020 Util.StringToBytes256(m_inventoryFileName));
1021 }
1022 }
1023  
1024 /// <summary>
1025 /// Process inventory backup
1026 /// </summary>
1027 /// <param name="datastore"></param>
1028 public void ProcessInventoryBackup(ISimulationDataService datastore)
1029 {
1030 if (HasInventoryChanged)
1031 {
1032 HasInventoryChanged = false;
1033 List<TaskInventoryItem> items = GetInventoryItems();
1034 datastore.StorePrimInventory(m_part.UUID, items);
1035  
1036 }
1037 }
1038  
1039 public class InventoryStringBuilder
1040 {
1041 public string BuildString = String.Empty;
1042  
1043 public InventoryStringBuilder(UUID folderID, UUID parentID)
1044 {
1045 BuildString += "\tinv_object\t0\n\t{\n";
1046 AddNameValueLine("obj_id", folderID.ToString());
1047 AddNameValueLine("parent_id", parentID.ToString());
1048 AddNameValueLine("type", "category");
1049 AddNameValueLine("name", "Contents|");
1050 AddSectionEnd();
1051 }
1052  
1053 public void AddItemStart()
1054 {
1055 BuildString += "\tinv_item\t0\n";
1056 AddSectionStart();
1057 }
1058  
1059 public void AddPermissionsStart()
1060 {
1061 BuildString += "\tpermissions 0\n";
1062 AddSectionStart();
1063 }
1064  
1065 public void AddSaleStart()
1066 {
1067 BuildString += "\tsale_info\t0\n";
1068 AddSectionStart();
1069 }
1070  
1071 protected void AddSectionStart()
1072 {
1073 BuildString += "\t{\n";
1074 }
1075  
1076 public void AddSectionEnd()
1077 {
1078 BuildString += "\t}\n";
1079 }
1080  
1081 public void AddLine(string addLine)
1082 {
1083 BuildString += addLine;
1084 }
1085  
1086 public void AddNameValueLine(string name, string value)
1087 {
1088 BuildString += "\t\t";
1089 BuildString += name + "\t";
1090 BuildString += value + "\n";
1091 }
1092  
1093 public void Close()
1094 {
1095 }
1096 }
1097  
1098 public uint MaskEffectivePermissions()
1099 {
1100 uint mask=0x7fffffff;
1101  
1102 lock (m_items)
1103 {
1104 foreach (TaskInventoryItem item in m_items.Values)
1105 {
1106 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
1107 mask &= ~((uint)PermissionMask.Copy >> 13);
1108 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
1109 mask &= ~((uint)PermissionMask.Transfer >> 13);
1110 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
1111 mask &= ~((uint)PermissionMask.Modify >> 13);
1112  
1113 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1114 mask &= ~(uint)PermissionMask.Copy;
1115 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
1116 mask &= ~(uint)PermissionMask.Transfer;
1117 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
1118 mask &= ~(uint)PermissionMask.Modify;
1119 }
1120 }
1121  
1122 return mask;
1123 }
1124  
1125 public void ApplyNextOwnerPermissions()
1126 {
1127 lock (m_items)
1128 {
1129 foreach (TaskInventoryItem item in m_items.Values)
1130 {
1131 // m_log.DebugFormat (
1132 // "[SCENE OBJECT PART INVENTORY]: Applying next permissions {0} to {1} in {2} with current {3}, base {4}, everyone {5}",
1133 // item.NextPermissions, item.Name, m_part.Name, item.CurrentPermissions, item.BasePermissions, item.EveryonePermissions);
1134  
1135 if (item.InvType == (int)InventoryType.Object)
1136 {
1137 uint perms = item.CurrentPermissions;
1138 PermissionsUtil.ApplyFoldedPermissions(perms, ref perms);
1139 item.CurrentPermissions = perms;
1140 }
1141  
1142 item.CurrentPermissions &= item.NextPermissions;
1143 item.BasePermissions &= item.NextPermissions;
1144 item.EveryonePermissions &= item.NextPermissions;
1145 item.OwnerChanged = true;
1146 item.PermsMask = 0;
1147 item.PermsGranter = UUID.Zero;
1148 }
1149 }
1150 }
1151  
1152 public void ApplyGodPermissions(uint perms)
1153 {
1154 lock (m_items)
1155 {
1156 foreach (TaskInventoryItem item in m_items.Values)
1157 {
1158 item.CurrentPermissions = perms;
1159 item.BasePermissions = perms;
1160 }
1161 }
1162  
1163 m_inventorySerial++;
1164 HasInventoryChanged = true;
1165 }
1166  
1167 /// <summary>
1168 /// Returns true if this part inventory contains any scripts. False otherwise.
1169 /// </summary>
1170 /// <returns></returns>
1171 public bool ContainsScripts()
1172 {
1173 lock (m_items)
1174 {
1175 foreach (TaskInventoryItem item in m_items.Values)
1176 {
1177 if (item.InvType == (int)InventoryType.LSL)
1178 {
1179 return true;
1180 }
1181 }
1182 }
1183  
1184 return false;
1185 }
1186  
1187 /// <summary>
1188 /// Returns the count of scripts in this parts inventory.
1189 /// </summary>
1190 /// <returns></returns>
1191 public int ScriptCount()
1192 {
1193 int count = 0;
1194 lock (m_items)
1195 {
1196 foreach (TaskInventoryItem item in m_items.Values)
1197 {
1198 if (item.InvType == (int)InventoryType.LSL)
1199 {
1200 count++;
1201 }
1202 }
1203 }
1204  
1205 return count;
1206 }
1207 /// <summary>
1208 /// Returns the count of running scripts in this parts inventory.
1209 /// </summary>
1210 /// <returns></returns>
1211 public int RunningScriptCount()
1212 {
1213 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1214 if (engines.Length == 0)
1215 return 0;
1216  
1217 int count = 0;
1218 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
1219  
1220 foreach (TaskInventoryItem item in scripts)
1221 {
1222 foreach (IScriptModule engine in engines)
1223 {
1224 if (engine != null)
1225 {
1226 if (engine.GetScriptState(item.ItemID))
1227 {
1228 count++;
1229 }
1230 }
1231 }
1232 }
1233 return count;
1234 }
1235  
1236 public List<UUID> GetInventoryList()
1237 {
1238 List<UUID> ret = new List<UUID>();
1239  
1240 lock (m_items)
1241 {
1242 foreach (TaskInventoryItem item in m_items.Values)
1243 ret.Add(item.ItemID);
1244 }
1245  
1246 return ret;
1247 }
1248  
1249 public List<TaskInventoryItem> GetInventoryItems()
1250 {
1251 List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
1252  
1253 lock (m_items)
1254 ret = new List<TaskInventoryItem>(m_items.Values);
1255  
1256 return ret;
1257 }
1258  
1259 public List<TaskInventoryItem> GetInventoryItems(InventoryType type)
1260 {
1261 List<TaskInventoryItem> ret = new List<TaskInventoryItem>();
1262  
1263 lock (m_items)
1264 {
1265 foreach (TaskInventoryItem item in m_items.Values)
1266 if (item.InvType == (int)type)
1267 ret.Add(item);
1268 }
1269  
1270 return ret;
1271 }
1272  
1273 public Dictionary<UUID, string> GetScriptStates()
1274 {
1275 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
1276  
1277 if (m_part.ParentGroup.Scene == null) // Group not in a scene
1278 return ret;
1279  
1280 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1281  
1282 if (engines.Length == 0) // No engine at all
1283 return ret;
1284  
1285 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
1286  
1287 foreach (TaskInventoryItem item in scripts)
1288 {
1289 foreach (IScriptModule e in engines)
1290 {
1291 if (e != null)
1292 {
1293 // m_log.DebugFormat(
1294 // "[PRIM INVENTORY]: Getting script state from engine {0} for {1} in part {2} in group {3} in {4}",
1295 // e.Name, item.Name, m_part.Name, m_part.ParentGroup.Name, m_part.ParentGroup.Scene.Name);
1296  
1297 string n = e.GetXMLState(item.ItemID);
1298 if (n != String.Empty)
1299 {
1300 if (!ret.ContainsKey(item.ItemID))
1301 ret[item.ItemID] = n;
1302 break;
1303 }
1304 }
1305 }
1306 }
1307  
1308 return ret;
1309 }
1310  
1311 public void ResumeScripts()
1312 {
1313 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
1314 if (engines.Length == 0)
1315 return;
1316  
1317 List<TaskInventoryItem> scripts = GetInventoryItems(InventoryType.LSL);
1318  
1319 foreach (TaskInventoryItem item in scripts)
1320 {
1321 foreach (IScriptModule engine in engines)
1322 {
1323 if (engine != null)
1324 {
1325 // m_log.DebugFormat(
1326 // "[PRIM INVENTORY]: Resuming script {0} {1} for {2}, OwnerChanged {3}",
1327 // item.Name, item.ItemID, item.OwnerID, item.OwnerChanged);
1328  
1329 engine.ResumeScript(item.ItemID);
1330  
1331 if (item.OwnerChanged)
1332 engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER });
1333  
1334 item.OwnerChanged = false;
1335 }
1336 }
1337 }
1338 }
1339 }
1340 }