diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index 204603d3b0..3c3c2477f1 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs @@ -1052,7 +1052,7 @@ namespace OpenSim.Client.MXP.ClientStack { } - public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, bool fetchFolders, bool fetchItems) + public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, int version, bool fetchFolders, bool fetchItems) { // Need to translate to MXP somehow } diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index 4a54c679fd..81ebf31393 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs @@ -606,7 +606,7 @@ namespace OpenSim.Client.VWoHTTP.ClientStack throw new System.NotImplementedException(); } - public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, bool fetchFolders, bool fetchItems) + public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, int version, bool fetchFolders, bool fetchItems) { throw new System.NotImplementedException(); } diff --git a/OpenSim/Framework/Capabilities/Caps.cs b/OpenSim/Framework/Capabilities/Caps.cs index 1dfb2d48c3..ccfe800e17 100644 --- a/OpenSim/Framework/Capabilities/Caps.cs +++ b/OpenSim/Framework/Capabilities/Caps.cs @@ -208,7 +208,7 @@ namespace OpenSim.Framework.Capabilities // As of RC 1.22.9 of the Linden client this is // supported - m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); + //m_capsHandlers["WebFetchInventoryDescendents"] =new RestStreamHandler("POST", capsBase + m_fetchInventoryPath, FetchInventoryDescendentsRequest); // justincc: I've disabled the CAPS service for now to fix problems with selecting textures, and // subsequent inventory breakage, in the edit object pane (such as mantis 1085). This requires diff --git a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs index aa71536c6c..6648c36e14 100644 --- a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs +++ b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs @@ -679,7 +679,7 @@ namespace OpenSim.Framework.Communications.Cache /// /// /// true if the request was queued or successfully processed, false otherwise - public bool SendInventoryDecendents(IClientAPI client, UUID folderID, bool fetchFolders, bool fetchItems) + public bool SendInventoryDecendents(IClientAPI client, UUID folderID, int version, bool fetchFolders, bool fetchItems) { if (m_hasReceivedInventory) { @@ -693,7 +693,7 @@ namespace OpenSim.Framework.Communications.Cache client.SendInventoryFolderDetails( client.AgentId, folderID, folder.RequestListOfItems(), - folder.RequestListOfFolders(), fetchFolders, fetchItems); + folder.RequestListOfFolders(), version, fetchFolders, fetchItems); return true; } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index d304345b83..0f88b93243 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1124,7 +1124,7 @@ namespace OpenSim.Framework void ReprioritizeUpdates(StateUpdateTypes type, UpdatePriorityHandler handler); void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, - List folders, bool fetchFolders, + List folders, int version, bool fetchFolders, bool fetchItems); void FlushPrimUpdates(); diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index db0c3b8692..bd5df19bb7 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -1251,7 +1251,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Do we need to send folder information? /// Do we need to send item information? public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, - List folders, + List folders, int version, bool fetchFolders, bool fetchItems) { // An inventory descendents packet consists of a single agent section and an inventory details @@ -1266,172 +1266,104 @@ namespace OpenSim.Region.ClientStack.LindenUDP // 6 to 7 items at a time, so let's stick with 6 int MAX_ITEMS_PER_PACKET = 6; - //Ckrinke This variable is not used, so comment out to remove the warning from the compiler (3-21-08) - //Ckrinke uint FULL_MASK_PERMISSIONS = 2147483647; - + int totalItems = fetchItems ? items.Count : 0; + int totalFolders = fetchFolders ? folders.Count : 0; int itemsSent = 0; - if (fetchItems) - { - InventoryDescendentsPacket descend = CreateInventoryDescendentsPacket(ownerID, folderID); + int foldersSent = 0; + int foldersToSend = 0; + int itemsToSend = 0; - if (items.Count < MAX_ITEMS_PER_PACKET) + InventoryDescendentsPacket currentPacket = null; + + // Handle empty folders + // + if (totalItems == 0 && totalFolders == 0) + currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, 0, 0); + + // To preserve SL compatibility, we will NOT combine folders and items in one packet + // + while(itemsSent < totalItems || foldersSent < totalFolders) + { + if (currentPacket == null) // Start a new packet { - descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items.Count]; + foldersToSend = totalFolders - foldersSent; + if (foldersToSend > MAX_ITEMS_PER_PACKET) + foldersToSend = MAX_ITEMS_PER_PACKET; + + if (foldersToSend == 0) + { + itemsToSend = totalItems - itemsSent; + if (itemsToSend > MAX_ITEMS_PER_PACKET) + itemsToSend = MAX_ITEMS_PER_PACKET; + } + + currentPacket = CreateInventoryDescendentsPacket(ownerID, folderID, version, foldersToSend, itemsToSend); } + + if (foldersToSend-- > 0) + currentPacket.FolderData[foldersSent % MAX_ITEMS_PER_PACKET] = CreateFolderDataBlock(folders[foldersSent++]); + else if(itemsToSend-- > 0) + currentPacket.ItemData[itemsSent % MAX_ITEMS_PER_PACKET] = CreateItemDataBlock(items[itemsSent++]); else { - descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[MAX_ITEMS_PER_PACKET]; + OutPacket(currentPacket, ThrottleOutPacketType.Asset); + currentPacket = null; } - // Descendents must contain the *total* number of descendents (plus folders, whether we - // fetch them or not), not the number of entries we send in this packet. For consistency, - // I'll use it for folder-requests, too, although I wasn't able to get one with - // FetchFolders = true. - // TODO this should be checked with FetchFolders = true - descend.AgentData.Descendents = items.Count + folders.Count; - - int count = 0; - int i = 0; - foreach (InventoryItemBase item in items) - { - descend.ItemData[i] = new InventoryDescendentsPacket.ItemDataBlock(); - descend.ItemData[i].ItemID = item.ID; - descend.ItemData[i].AssetID = item.AssetID; - descend.ItemData[i].CreatorID = item.CreatorIdAsUuid; - descend.ItemData[i].BaseMask = item.BasePermissions; - descend.ItemData[i].Description = Util.StringToBytes256(item.Description); - descend.ItemData[i].EveryoneMask = item.EveryOnePermissions; - descend.ItemData[i].OwnerMask = item.CurrentPermissions; - descend.ItemData[i].FolderID = item.Folder; - descend.ItemData[i].InvType = (sbyte)item.InvType; - descend.ItemData[i].Name = Util.StringToBytes256(item.Name); - descend.ItemData[i].NextOwnerMask = item.NextPermissions; - descend.ItemData[i].OwnerID = item.Owner; - descend.ItemData[i].Type = (sbyte)item.AssetType; - - descend.ItemData[i].GroupID = item.GroupID; - descend.ItemData[i].GroupOwned = item.GroupOwned; - descend.ItemData[i].GroupMask = item.GroupPermissions; - descend.ItemData[i].CreationDate = item.CreationDate; - descend.ItemData[i].SalePrice = item.SalePrice; - descend.ItemData[i].SaleType = item.SaleType; - descend.ItemData[i].Flags = item.Flags; - - descend.ItemData[i].CRC = - Helpers.InventoryCRC(descend.ItemData[i].CreationDate, descend.ItemData[i].SaleType, - descend.ItemData[i].InvType, descend.ItemData[i].Type, - descend.ItemData[i].AssetID, descend.ItemData[i].GroupID, - descend.ItemData[i].SalePrice, - descend.ItemData[i].OwnerID, descend.ItemData[i].CreatorID, - descend.ItemData[i].ItemID, descend.ItemData[i].FolderID, - descend.ItemData[i].EveryoneMask, - descend.ItemData[i].Flags, descend.ItemData[i].OwnerMask, - descend.ItemData[i].GroupMask, item.CurrentPermissions); - - i++; - count++; - itemsSent++; - if (i == MAX_ITEMS_PER_PACKET) - { - descend.Header.Zerocoded = true; - AddNullFolderBlockToDecendentsPacket(ref descend); - OutPacket(descend, ThrottleOutPacketType.Asset); - - if ((items.Count - count) > 0) - { - descend = CreateInventoryDescendentsPacket(ownerID, folderID); - if ((items.Count - count) < MAX_ITEMS_PER_PACKET) - { - descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items.Count - count]; - } - else - { - descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[MAX_ITEMS_PER_PACKET]; - } - descend.AgentData.Descendents = items.Count + folders.Count; - i = 0; - } - } - } - - if (0 < i && i < MAX_ITEMS_PER_PACKET) - { - AddNullFolderBlockToDecendentsPacket(ref descend); - OutPacket(descend, ThrottleOutPacketType.Asset); - } } - //send subfolders - if (fetchFolders) - { - InventoryDescendentsPacket descend = CreateInventoryDescendentsPacket(ownerID, folderID); + if (currentPacket != null) + OutPacket(currentPacket, ThrottleOutPacketType.Asset); + } - if (folders.Count < MAX_ITEMS_PER_PACKET) - { - descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[folders.Count]; - } - else - { - descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[MAX_ITEMS_PER_PACKET]; - } + private InventoryDescendentsPacket.FolderDataBlock CreateFolderDataBlock(InventoryFolderBase folder) + { + InventoryDescendentsPacket.FolderDataBlock newBlock = new InventoryDescendentsPacket.FolderDataBlock(); + newBlock.FolderID = folder.ID; + newBlock.Name = Util.StringToBytes256(folder.Name); + newBlock.ParentID = folder.ParentID; + newBlock.Type = (sbyte)folder.Type; - // Not sure if this scenario ever actually occurs, but nonetheless we include the items - // count even if we're not sending item data for the same reasons as above. - descend.AgentData.Descendents = items.Count + folders.Count; + return newBlock; + } - int i = 0; - int count = 0; - foreach (InventoryFolderBase folder in folders) - { - descend.FolderData[i] = new InventoryDescendentsPacket.FolderDataBlock(); - descend.FolderData[i].FolderID = folder.ID; - descend.FolderData[i].Name = Util.StringToBytes256(folder.Name); - descend.FolderData[i].ParentID = folder.ParentID; - descend.FolderData[i].Type = (sbyte)folder.Type; + private InventoryDescendentsPacket.ItemDataBlock CreateItemDataBlock(InventoryItemBase item) + { + InventoryDescendentsPacket.ItemDataBlock newBlock = new InventoryDescendentsPacket.ItemDataBlock(); + newBlock.ItemID = item.ID; + newBlock.AssetID = item.AssetID; + newBlock.CreatorID = item.CreatorIdAsUuid; + newBlock.BaseMask = item.BasePermissions; + newBlock.Description = Util.StringToBytes256(item.Description); + newBlock.EveryoneMask = item.EveryOnePermissions; + newBlock.OwnerMask = item.CurrentPermissions; + newBlock.FolderID = item.Folder; + newBlock.InvType = (sbyte)item.InvType; + newBlock.Name = Util.StringToBytes256(item.Name); + newBlock.NextOwnerMask = item.NextPermissions; + newBlock.OwnerID = item.Owner; + newBlock.Type = (sbyte)item.AssetType; - i++; - count++; - itemsSent++; - if (i == MAX_ITEMS_PER_PACKET) - { - AddNullItemBlockToDescendentsPacket(ref descend); - OutPacket(descend, ThrottleOutPacketType.Asset); + newBlock.GroupID = item.GroupID; + newBlock.GroupOwned = item.GroupOwned; + newBlock.GroupMask = item.GroupPermissions; + newBlock.CreationDate = item.CreationDate; + newBlock.SalePrice = item.SalePrice; + newBlock.SaleType = item.SaleType; + newBlock.Flags = item.Flags; - if ((folders.Count - count) > 0) - { - descend = CreateInventoryDescendentsPacket(ownerID, folderID); - if ((folders.Count - count) < MAX_ITEMS_PER_PACKET) - { - descend.FolderData = - new InventoryDescendentsPacket.FolderDataBlock[folders.Count - count]; - } - else - { - descend.FolderData = - new InventoryDescendentsPacket.FolderDataBlock[MAX_ITEMS_PER_PACKET]; - } - descend.AgentData.Descendents = items.Count + folders.Count; - i = 0; - } - } - } + newBlock.CRC = + Helpers.InventoryCRC(newBlock.CreationDate, newBlock.SaleType, + newBlock.InvType, newBlock.Type, + newBlock.AssetID, newBlock.GroupID, + newBlock.SalePrice, + newBlock.OwnerID, newBlock.CreatorID, + newBlock.ItemID, newBlock.FolderID, + newBlock.EveryoneMask, + newBlock.Flags, newBlock.OwnerMask, + newBlock.GroupMask, newBlock.NextOwnerMask); - if (0 < i && i < MAX_ITEMS_PER_PACKET) - { - AddNullItemBlockToDescendentsPacket(ref descend); - OutPacket(descend, ThrottleOutPacketType.Asset); - } - } - - if (itemsSent == 0) - { - // no items found. - InventoryDescendentsPacket descend = CreateInventoryDescendentsPacket(ownerID, folderID); - descend.AgentData.Descendents = 0; - AddNullItemBlockToDescendentsPacket(ref descend); - AddNullFolderBlockToDecendentsPacket(ref descend); - OutPacket(descend, ThrottleOutPacketType.Asset); - } + return newBlock; } private void AddNullFolderBlockToDecendentsPacket(ref InventoryDescendentsPacket packet) @@ -1473,14 +1405,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP // No need to add CRC } - private InventoryDescendentsPacket CreateInventoryDescendentsPacket(UUID ownerID, UUID folderID) + private InventoryDescendentsPacket CreateInventoryDescendentsPacket(UUID ownerID, UUID folderID, int version, int folders, int items) { InventoryDescendentsPacket descend = (InventoryDescendentsPacket)PacketPool.Instance.GetPacket(PacketType.InventoryDescendents); descend.Header.Zerocoded = true; descend.AgentData.AgentID = AgentId; descend.AgentData.OwnerID = ownerID; descend.AgentData.FolderID = folderID; - descend.AgentData.Version = 1; + descend.AgentData.Version = version; + + if (folders > 0) + descend.FolderData = new InventoryDescendentsPacket.FolderDataBlock[folders]; + else + AddNullFolderBlockToDecendentsPacket(ref descend); + + if (items > 0) + descend.ItemData = new InventoryDescendentsPacket.ItemDataBlock[items]; + else + AddNullItemBlockToDescendentsPacket(ref descend); return descend; } diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 5a5fcfe8c5..5891c7e0f1 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -538,6 +538,7 @@ namespace OpenSim.Region.Examples.SimpleModule public virtual void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, + int version, bool fetchFolders, bool fetchItems) { diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 4d76b4ef6a..00743fcf3c 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -1175,7 +1175,13 @@ namespace OpenSim.Region.Framework.Scenes { m_log.DebugFormat("[AGENT INVENTORY]: Send Inventory Folder {0} Update to {1} {2}", folder.Name, client.FirstName, client.LastName); InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID); - client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, fetchFolders, fetchItems); + InventoryFolderBase containingFolder = new InventoryFolderBase(); + containingFolder.ID = folder.ID; + containingFolder.Owner = client.AgentId; + containingFolder = InventoryService.GetFolder(containingFolder); + int version = containingFolder.Version; + + client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, version, fetchFolders, fetchItems); } /// diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs index 1a91f0c9b0..47fbeb45db 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs @@ -462,7 +462,7 @@ namespace OpenSim.Region.Framework.Scenes { remoteClient.SendInventoryFolderDetails( fold.Owner, folderID, fold.RequestListOfItems(), - fold.RequestListOfFolders(), fetchFolders, fetchItems); + fold.RequestListOfFolders(), fold.Version, fetchFolders, fetchItems); return; } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 4b0d01a2ec..f1bd7054ab 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1055,7 +1055,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, bool fetchFolders, bool fetchItems) + public void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, int version, bool fetchFolders, bool fetchItems) { } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index f7cadaabd2..cf81198382 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -627,6 +627,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC public virtual void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, + int version, bool fetchFolders, bool fetchItems) { diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 0f642b945f..9ec93110d2 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -631,6 +631,7 @@ namespace OpenSim.Tests.Common.Mock public virtual void SendInventoryFolderDetails(UUID ownerID, UUID folderID, List items, List folders, + int version, bool fetchFolders, bool fetchItems) {