From 18f2e25b23583643ae0ecdbf4cf8bec0e41e2f4e Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Thu, 6 Feb 2020 06:12:51 +0000 Subject: [PATCH] mantis 8651: try to fix items embedded in notecards. This may need more work --- OpenSim/Framework/SLUtil.cs | 248 ++++++++++++++++++ .../Linden/Caps/BunchOfCaps/BunchOfCaps.cs | 164 ++++++++++-- 2 files changed, 388 insertions(+), 24 deletions(-) diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index 9458625667..b55470f0ef 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -28,6 +28,7 @@ using OpenMetaverse; using System; using System.Collections.Generic; +using System.Globalization; namespace OpenSim.Framework { @@ -190,6 +191,56 @@ namespace OpenSim.Framework private static Dictionary inventory2Content; private static Dictionary content2Asset; private static Dictionary content2Inventory; + private static Dictionary name2Asset = new Dictionary() + { + {"texture", AssetType.Texture }, + {"sound", AssetType.Sound}, + {"callcard", AssetType.CallingCard}, + {"landmark", AssetType.Landmark}, + {"script", (AssetType)4}, + {"clothing", AssetType.Clothing}, + {"object", AssetType.Object}, + {"notecard", AssetType.Notecard}, + {"category", AssetType.Folder}, + {"lsltext", AssetType.LSLText}, + {"lslbyte", AssetType.LSLBytecode}, + {"txtr_tga", AssetType.TextureTGA}, + {"bodypart", AssetType.Bodypart}, + {"snd_wav", AssetType.SoundWAV}, + {"img_tga", AssetType.ImageTGA}, + {"jpeg", AssetType.ImageJPEG}, + {"animatn", AssetType.Animation}, + {"gesture", AssetType.Gesture}, + {"simstate", AssetType.Simstate}, + {"mesh", AssetType.Mesh} +// "settings", AssetType.Settings} + }; + private static Dictionary name2Inventory = new Dictionary() + { + {"texture", FolderType.Texture}, + {"sound", FolderType.Sound}, + {"callcard", FolderType.CallingCard}, + {"landmark", FolderType.Landmark}, + {"script", (FolderType)4}, + {"clothing", FolderType.Clothing}, + {"object", FolderType.Object}, + {"notecard", FolderType.Notecard}, + {"root", FolderType.Root}, + {"lsltext", FolderType.LSLText}, + {"bodypart", FolderType.BodyPart}, + {"trash", FolderType.Trash}, + {"snapshot", FolderType.Snapshot}, + {"lostandfound", FolderType.LostAndFound}, + {"animatn", FolderType.Animation}, + {"gesture", FolderType.Gesture}, + {"favorites", FolderType.Favorites}, + {"currentoutfit", FolderType.CurrentOutfit}, + {"outfit", FolderType.Outfit}, + {"myoutfits", FolderType.MyOutfits}, + {"mesh", FolderType.Mesh}, +// "settings", FolderType.Settings}, + {"suitcase", FolderType.Suitcase} + }; static SLUtil() { @@ -227,6 +278,20 @@ namespace OpenSim.Framework } } + public static AssetType SLAssetName2Type(string name) + { + if (name2Asset.TryGetValue(name, out AssetType type)) + return type; + return AssetType.Unknown; + } + + public static FolderType SLInvName2Type(string name) + { + if (name2Inventory.TryGetValue(name, out FolderType type)) + return type; + return FolderType.None; + } + public static string SLAssetTypeToContentType(int assetType) { string contentType; @@ -534,5 +599,188 @@ namespace OpenSim.Framework { return readNotecard(rawInput).Replace("\r", "").Split('\n'); } + + private static int skipcontrol(string data, int indx) + { + while(indx < data.Length) + { + char c = data[indx]; + switch(c) + { + case '\n': + case '\t': + case '{': + ++indx; + break; + default: + return indx; + } + } + return -1; + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] + static int checkfield(string note, int start, string name, out int end) + { + end = -1; + int limit = note.Length - start; + if(limit > 64) + limit = 64; + int indx = note.IndexOf(name, start, limit); + if (indx < 0) + return -1; + indx += name.Length; + indx = skipcontrol(note, indx); + if (indx < 0) + return -1; + end = note.IndexOfAny(seps, indx); + if (end < 0) + return -1; + return indx; + } + + static char[] seps = new char[]{ '\t','\n'}; + public static InventoryItemBase GetEmbeddedItem(byte[] data, UUID itemID) + { + if(data == null || data.Length < 200) + return null; + + string note = Util.UTF8.GetString(data); + if (String.IsNullOrWhiteSpace(note)) + return null; + + int start = note.IndexOf(itemID.ToString()); + if (start < 0) + return null; + + int end; + start = note.IndexOf("permissions", start, 100); + if (start < 0) + return null; + start = checkfield(note, start, "base_mask", out end); + if (start < 0) + return null; + + if (!uint.TryParse(note.Substring(start, end - start), NumberStyles.HexNumber, Culture.NumberFormatInfo, out uint basemask)) + return null; + + start = checkfield(note, end, "owner_mask", out end); + if (start < 0) + return null; + + if (!uint.TryParse(note.Substring(start, end - start), NumberStyles.HexNumber, Culture.NumberFormatInfo, out uint ownermask)) + return null; + + start = checkfield(note, end, "group_mask", out end); + if (start < 0) + return null; + if (!uint.TryParse(note.Substring(start, end - start), NumberStyles.HexNumber, Culture.NumberFormatInfo, out uint groupmask)) + return null; + + start = checkfield(note, end, "everyone_mask", out end); + if (start < 0) + return null; + if (!uint.TryParse(note.Substring(start, end - start), NumberStyles.HexNumber, Culture.NumberFormatInfo, out uint everyonemask)) + return null; + + start = checkfield(note, end, "next_owner_mask", out end); + if (start < 0) + return null; + if (!uint.TryParse(note.Substring(start, end - start), NumberStyles.HexNumber, Culture.NumberFormatInfo, out uint nextownermask)) + return null; + + start = checkfield(note, end, "creator_id", out end); + if (start < 0) + return null; + if (!UUID.TryParse(note.Substring(start, end - start), out UUID creatorID)) + return null; + + start = checkfield(note, end, "owner_id", out end); + if (start < 0) + return null; + if (!UUID.TryParse(note.Substring(start, end - start), out UUID ownerID)) + return null; + + /* + start = checkfield(note, end, "last_owner_id", out end); + if (start < 0) + return null; + if (!UUID.TryParse(note.Substring(start, end - start), out UUID lastownerID)) + return null; + */ + + int limit = note.Length - end; + if (limit > 120) + limit = 120; + end = note.IndexOf('}', end, limit); // last owner + start = checkfield(note, end, "asset_id", out end); + if (start < 0) + return null; + if (!UUID.TryParse(note.Substring(start, end - start), out UUID assetID)) + return null; + + start = checkfield(note, end, "type", out end); + if (start < 0) + return null; + string typestr = note.Substring(start, end - start); + AssetType assetType = SLAssetName2Type(typestr); + + start = checkfield(note, end, "inv_type", out end); + if (start < 0) + return null; + string inttypestr = note.Substring(start, end - start); + FolderType invType = SLInvName2Type(inttypestr); + + start = checkfield(note, end, "flags", out end); + if (start < 0) + return null; + if (!uint.TryParse(note.Substring(start, end - start), NumberStyles.HexNumber, Culture.NumberFormatInfo, out uint flags)) + return null; + + limit = note.Length - end; + if (limit > 120) + limit = 120; + end = note.IndexOf('}', end, limit); // skip sale + start = checkfield(note, end, "name", out end); + if (start < 0) + return null; + + string name = note.Substring(start, end - start - 1); + + start = checkfield(note, end, "desc", out end); + if (start < 0) + return null; + string desc = note.Substring(start, end - start - 1); + /* + start = checkfield(note, end, "creation_date", out end); + if (start < 0) + return null; + if (!int.TryParse(note.Substring(start, end - start), out int creationdate)) + return null; + */ + + InventoryItemBase item = new InventoryItemBase(); + item.AssetID = assetID; + item.AssetType = (sbyte)assetType; + item.BasePermissions = basemask; + item.CreationDate = Util.UnixTimeSinceEpoch(); + item.CreatorData = ""; + item.CreatorId = creatorID.ToString(); + item.CurrentPermissions = ownermask; + item.Description = desc; + item.Flags = flags; + item.Folder = UUID.Zero; + item.GroupID = UUID.Zero; + item.GroupOwned = false; + item.GroupPermissions = groupmask; + item.InvType = (sbyte)invType; + item.Name = name; + item.NextPermissions = nextownermask; + item.Owner = ownerID; + item.SalePrice = 0; + item.SaleType = (byte)SaleType.Not; + item.ID = UUID.Random(); + return item; + } } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index 35e18a09bd..0b4f9ef0ca 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -1420,6 +1420,8 @@ namespace OpenSim.Region.ClientStack.Linden IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { InventoryItemBase copyItem = null; + IClientAPI client = null; + try { OSDMap content = (OSDMap)OSDParser.DeserializeLLSDXml(request); @@ -1428,49 +1430,163 @@ namespace OpenSim.Region.ClientStack.Linden UUID folderID = content["folder-id"].AsUUID(); UUID itemID = content["item-id"].AsUUID(); + UUID noteAssetID = UUID.Zero; // m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, FolderID:{0}, ItemID:{1}, NotecardID:{2}, ObjectID:{3}", folderID, itemID, notecardID, objectID); + m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); + if (objectID != UUID.Zero) { SceneObjectPart part = m_Scene.GetSceneObjectPart(objectID); - if (part != null) - { -// TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(notecardID); + if(part == null) + throw new Exception("find object with notecard item" + notecardID.ToString()); + if (!m_Scene.Permissions.CanCopyObjectInventory(notecardID, objectID, m_HostCapsObj.AgentID)) return CopyInventoryFromNotecardError(httpResponse); - } - } - - InventoryItemBase item = null; - IClientAPI client = null; - - m_Scene.TryGetClient(m_HostCapsObj.AgentID, out client); - item = m_Scene.InventoryService.GetItem(m_HostCapsObj.AgentID, itemID); - if (item != null) - { - string message; - copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, item.Owner, itemID, folderID, out message); - if (copyItem != null && client != null) - { - m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder); - client.SendBulkUpdateInventory(copyItem); - } + TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(notecardID); + if(taskItem == null || taskItem.AssetID == UUID.Zero) + throw new Exception("Failed to find notecard item" + notecardID.ToString()); + noteAssetID = taskItem.AssetID; } else { - m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard - Failed to retrieve item {0} from notecard {1}", itemID, notecardID); - if (client != null) - client.SendAlertMessage("Failed to retrieve item"); + InventoryItemBase localitem = m_Scene.InventoryService.GetItem(m_HostCapsObj.AgentID, itemID); + if (localitem != null) + { + string message; + copyItem = m_Scene.GiveInventoryItem(m_HostCapsObj.AgentID, localitem.Owner, itemID, folderID, out message); + if (copyItem == null) + throw new Exception("Failed to find notecard item" + notecardID.ToString()); + + m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0}, FolderID:{1}", copyItem.ID, copyItem.Folder); + if (client != null) + client.SendBulkUpdateInventory(copyItem); + return ""; + } + + if (notecardID != UUID.Zero) + { + InventoryItemBase noteItem = m_Scene.InventoryService.GetItem(m_HostCapsObj.AgentID, notecardID); + if (noteItem == null || noteItem.AssetID == UUID.Zero) + throw new Exception("Failed to find notecard item" + notecardID.ToString()); + noteAssetID = noteItem.AssetID; + } } + + AssetBase noteAsset = m_Scene.AssetService.Get(noteAssetID.ToString()); + if (noteAsset == null || noteAsset.Type != (sbyte)AssetType.Notecard) + throw new Exception("Failed to find notecard asset" + notecardID.ToString()); + + InventoryItemBase item = SLUtil.GetEmbeddedItem(noteAsset.Data, itemID); + if(item == null) + throw new Exception("Failed to open notecard asset" + notecardID.ToString()); + + noteAsset = m_Scene.AssetService.Get(item.AssetID.ToString()); + if (noteAsset == null) + throw new Exception("Failed to find notecard " + notecardID.ToString() +" item "+ itemID.ToString() + " asset"); + + if (!m_Scene.Permissions.CanTransferUserInventory(itemID, item.Owner, m_HostCapsObj.AgentID)) + throw new Exception("Notecard item permissions check fail" + notecardID.ToString()); + + if (!m_Scene.Permissions.BypassPermissions()) + { + if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0) + throw new Exception("Notecard item permissions check fail" + notecardID.ToString()); + } + + if (m_Scene.Permissions.PropagatePermissions() && item.Owner != m_HostCapsObj.AgentID) + { + uint permsMask = ~((uint)PermissionMask.Copy | + (uint)PermissionMask.Transfer | + (uint)PermissionMask.Modify | + (uint)PermissionMask.Export); + + uint nextPerms = permsMask | (item.NextPermissions & + ((uint)PermissionMask.Copy | + (uint)PermissionMask.Transfer | + (uint)PermissionMask.Modify)); + + if (nextPerms == permsMask) + nextPerms |= (uint)PermissionMask.Transfer; + + uint basePerms = item.BasePermissions | + (uint)PermissionMask.Move; + uint ownerPerms = item.CurrentPermissions; + + uint foldedPerms = (item.CurrentPermissions & (uint)PermissionMask.FoldedMask) << (int)PermissionMask.FoldingShift; + if (foldedPerms != 0 && item.InvType == (int)InventoryType.Object) + { + foldedPerms |= permsMask; + + bool isRootMod = (item.CurrentPermissions & + (uint)PermissionMask.Modify) != 0 ? + true : false; + + ownerPerms &= foldedPerms; + basePerms &= foldedPerms; + + if (isRootMod) + { + ownerPerms |= (uint)PermissionMask.Modify; + basePerms |= (uint)PermissionMask.Modify; + } + } + + ownerPerms &= nextPerms; + basePerms &= nextPerms; + basePerms &= ~(uint)PermissionMask.FoldedMask; + basePerms |= ((basePerms >> 13) & 7) | (((basePerms & (uint)PermissionMask.Export) != 0) ? (uint)PermissionMask.FoldedExport : 0); + item.BasePermissions = basePerms; + item.CurrentPermissions = ownerPerms; + item.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; + item.Flags &= ~(uint)(InventoryItemFlags.ObjectOverwriteBase | InventoryItemFlags.ObjectOverwriteOwner | InventoryItemFlags.ObjectOverwriteGroup | InventoryItemFlags.ObjectOverwriteEveryone | InventoryItemFlags.ObjectOverwriteNextOwner); + item.NextPermissions = item.NextPermissions; + item.EveryOnePermissions = item.EveryOnePermissions & nextPerms; + item.GroupPermissions = 0; + } + + InventoryFolderBase folder = null; + if (folderID != UUID.Zero) + folder = m_Scene.InventoryService.GetFolder(m_HostCapsObj.AgentID, folderID); + + if (folder == null && Enum.IsDefined(typeof(FolderType), (sbyte)item.AssetType)) + folder = m_Scene.InventoryService.GetFolderForType(m_HostCapsObj.AgentID, (FolderType)item.AssetType); + + if(folder == null) + folder = m_Scene.InventoryService.GetRootFolder(m_HostCapsObj.AgentID); + + if(folder == null) + throw new Exception("Failed to find a folder for the notecard item" + notecardID.ToString()); + + item.Folder = folder.ID; + + UUID senderId = item.Owner; + item.Owner = m_HostCapsObj.AgentID; + + IInventoryAccessModule invAccess = m_Scene.RequestModuleInterface(); + if (invAccess != null) + invAccess.TransferInventoryAssets(item, senderId, m_HostCapsObj.AgentID); + + if(!m_Scene.InventoryService.AddItem(item)) + throw new Exception("Failed create the notecard item" + notecardID.ToString()); + + m_log.InfoFormat("[CAPS]: CopyInventoryFromNotecard, ItemID:{0} FolderID:{1}", item.ID, item.Folder); + if (client != null) + client.SendBulkUpdateInventory(item); + return ""; } catch (Exception e) { - m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard : {0}", e.ToString()); + m_log.ErrorFormat("[CAPS]: CopyInventoryFromNotecard : {0}", e.Message); copyItem = null; } if(copyItem == null) + { + if (client != null) + client.SendAlertMessage("Failed to retrieve item"); return CopyInventoryFromNotecardError(httpResponse); + } return ""; }