/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ using System; using System.Collections.Generic; using System.Xml.Serialization; using libsecondlife; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes.Scripting; namespace OpenSim.Region.Environment.Scenes { public partial class SceneObjectPart : IScriptHost { private string m_inventoryFileName = String.Empty; /// /// The inventory folder for this prim /// private LLUUID m_folderID = LLUUID.Zero; /// /// Exposing this is not particularly good, but it's one of the least evils at the moment to see /// folder id from prim inventory item data, since it's not (yet) actually stored with the prim. /// public LLUUID FolderID { get { return m_folderID; } set { m_folderID = value; } } /// /// Serial count for inventory file , used to tell if inventory has changed /// no need for this to be part of Database backup /// protected uint m_inventorySerial = 0; public uint InventorySerial { get { return m_inventorySerial; } set { m_inventorySerial = value; } } /// /// Holds in memory prim inventory /// protected TaskInventoryDictionary m_taskInventory = new TaskInventoryDictionary(); public TaskInventoryDictionary TaskInventory { get { return m_taskInventory; } set { m_taskInventory = value; } } /// /// Tracks whether inventory has changed since the last persistent backup /// private bool HasInventoryChanged; /// /// Reset LLUUIDs for all the items in the prim's inventory. This involves either generating /// new ones or setting existing UUIDs to the correct parent UUIDs /// /// /// public void StartScript(TaskInventoryItem item) { // MainLog.Instance.Verbose( // "PRIMINVENTORY", // "Starting script {0}, {1} in prim {2}, {3}", // item.Name, item.ItemID, Name, UUID); AssetBase rezAsset = m_parentGroup.Scene.AssetCache.GetAsset(item.AssetID, false); if (rezAsset != null) { string script = Helpers.FieldToUTF8String(rezAsset.Data); m_parentGroup.Scene.EventManager.TriggerRezScript(LocalID, item.ItemID, script); } else { MainLog.Instance.Error( "PRIMINVENTORY", "Couldn't start script {0}, {1} since asset ID {2} could not be found", item.Name, item.ItemID, item.AssetID); } } /// /// Start a script which is in this prim's inventory. /// /// /// A /// public void StartScript(LLUUID itemId) { lock (m_taskInventory) { if (m_taskInventory.ContainsKey(itemId)) { StartScript(m_taskInventory[itemId]); } else { MainLog.Instance.Error( "PRIMINVENTORY", "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2}", itemId, Name, UUID); } } } /// /// Stop a script which is in this prim's inventory. /// /// public void StopScript(LLUUID itemId) { if (m_taskInventory.ContainsKey(itemId)) { m_parentGroup.Scene.EventManager.TriggerRemoveScript(LocalID, itemId); } else { MainLog.Instance.Error( "PRIMINVENTORY", "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2}", itemId, Name, UUID); } } /// /// Add an item to this prim's inventory. /// /// public void AddInventoryItem(TaskInventoryItem item) { item.ParentID = m_folderID; item.CreationDate = 1000; item.ParentPartID = UUID; lock (m_taskInventory) { m_taskInventory.Add(item.ItemID, item); TriggerScriptChangedEvent(Changed.INVENTORY); } m_inventorySerial++; HasInventoryChanged = true; } /// /// Add a whole collection of items to the prim's inventory at once. We assume that the items already /// have all their fields correctly filled out. /// /// public void AddInventoryItems(ICollection items) { lock (m_taskInventory) { foreach (TaskInventoryItem item in items) { m_taskInventory.Add(item.ItemID, item); TriggerScriptChangedEvent(Changed.INVENTORY); } } m_inventorySerial++; } /// /// Returns an existing inventory item. Returns the original, so any changes will be live. /// /// /// null if the item does not exist public TaskInventoryItem GetInventoryItem(LLUUID itemID) { lock (m_taskInventory) { if (m_taskInventory.ContainsKey(itemID)) { return m_taskInventory[itemID]; } else { MainLog.Instance.Error( "PRIMINVENTORY", "Tried to retrieve item ID {0} from prim {1}, {2} but the item does not exist in this inventory", itemID, Name, UUID); } } return null; } /// /// Update an existing inventory item. /// /// The updated item. An item with the same id must already exist /// in this prim's inventory. /// false if the item did not exist, true if the update occurred succesfully public bool UpdateInventoryItem(TaskInventoryItem item) { lock (m_taskInventory) { if (m_taskInventory.ContainsKey(item.ItemID)) { m_taskInventory[item.ItemID] = item; m_inventorySerial++; TriggerScriptChangedEvent(Changed.INVENTORY); HasInventoryChanged = true; return true; } else { MainLog.Instance.Error( "PRIMINVENTORY", "Tried to retrieve item ID {0} from prim {1}, {2} but the item does not exist in this inventory", item.ItemID, Name, UUID); } } return false; } /// /// Remove an item from this prim's inventory /// /// /// Numeric asset type of the item removed. Returns -1 if the item did not exist /// in this prim's inventory. public int RemoveInventoryItem(LLUUID itemID) { lock (m_taskInventory) { if (m_taskInventory.ContainsKey(itemID)) { int type = m_taskInventory[itemID].InvType; m_taskInventory.Remove(itemID); m_inventorySerial++; TriggerScriptChangedEvent(Changed.INVENTORY); HasInventoryChanged = true; return type; } else { MainLog.Instance.Error( "PRIMINVENTORY", "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory", itemID, Name, UUID); } } return -1; } /// /// /// /// /// public bool GetInventoryFileName(IClientAPI client, uint localID) { if (m_inventorySerial > 0) { client.SendTaskInventory(m_uuid, (short) m_inventorySerial, Helpers.StringToField(m_inventoryFileName)); return true; } else { client.SendTaskInventory(m_uuid, 0, new byte[0]); return false; } } public void RequestInventoryFile(IXfer xferManager) { byte[] fileData = new byte[0]; InventoryStringBuilder invString = new InventoryStringBuilder(m_folderID, UUID); lock (m_taskInventory) { foreach (TaskInventoryItem item in m_taskInventory.Values) { invString.AddItemStart(); invString.AddNameValueLine("item_id", item.ItemID.ToString()); invString.AddNameValueLine("parent_id", item.ParentID.ToString()); invString.AddPermissionsStart(); invString.AddNameValueLine("base_mask", "0x7FFFFFFF"); invString.AddNameValueLine("owner_mask", "0x7FFFFFFF"); invString.AddNameValueLine("group_mask", "0x7FFFFFFF"); invString.AddNameValueLine("everyone_mask", "0x7FFFFFFF"); invString.AddNameValueLine("next_owner_mask", "0x7FFFFFFF"); invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); invString.AddNameValueLine("owner_id", item.OwnerID.ToString()); invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); invString.AddNameValueLine("group_id", item.GroupID.ToString()); invString.AddSectionEnd(); invString.AddNameValueLine("asset_id", item.AssetID.ToString()); invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]); invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]); invString.AddNameValueLine("flags", "0x00"); invString.AddNameValueLine("name", item.Name + "|"); invString.AddNameValueLine("desc", item.Description + "|"); invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); invString.AddSectionEnd(); } } fileData = Helpers.StringToField(invString.BuildString); // MainLog.Instance.Verbose( // "PRIMINVENTORY", "RequestInventoryFile fileData: {0}", Helpers.FieldToUTF8String(fileData)); if (fileData.Length > 2) { xferManager.AddNewFile(m_inventoryFileName, fileData); } } /// /// Process inventory backup /// /// public void ProcessInventoryBackup(IRegionDataStore datastore) { if (HasInventoryChanged) { datastore.StorePrimInventory(UUID, TaskInventory); HasInventoryChanged = false; } } public class InventoryStringBuilder { public string BuildString = String.Empty; public InventoryStringBuilder(LLUUID folderID, LLUUID parentID) { BuildString += "\tinv_object\t0\n\t{\n"; AddNameValueLine("obj_id", folderID.ToString()); AddNameValueLine("parent_id", parentID.ToString()); AddNameValueLine("type", "category"); AddNameValueLine("name", "Contents"); AddSectionEnd(); } public void AddItemStart() { BuildString += "\tinv_item\t0\n"; BuildString += "\t{\n"; } public void AddPermissionsStart() { BuildString += "\tpermissions 0\n"; BuildString += "\t{\n"; } public void AddSectionEnd() { BuildString += "\t}\n"; } public void AddLine(string addLine) { BuildString += addLine; } public void AddNameValueLine(string name, string value) { BuildString += "\t\t"; BuildString += name + "\t"; BuildString += value + "\n"; } public void Close() { } } } }