User inventory folder
Inheritance: InventoryNodeBase
 // Constructors
 public InventoryFolderImpl (InventoryFolderBase folderbase)
 {
     Owner = folderbase.Owner;
     ID = folderbase.ID;
     Name = folderbase.Name;
     ParentID = folderbase.ParentID;
     Type = folderbase.Type;
     Version = folderbase.Version;
 }
 public override void FromOSD(OSDMap map)
 {
     OSDArray items = (OSDArray) map["Items"];
     Items = items.ConvertAll<InventoryItemBase>((osd) =>
                                                     {
                                                         InventoryItemBase item = new InventoryItemBase();
                                                         item.FromOSD((OSDMap) osd);
                                                         return item;
                                                     }
         );
     OSDArray folders = (OSDArray) map["Folders"];
     Folders = folders.ConvertAll<InventoryFolderBase>((osd) =>
                                                           {
                                                               InventoryFolderBase folder =
                                                                   new InventoryFolderBase();
                                                               folder.FromOSD((OSDMap) osd);
                                                               return folder;
                                                           }
         );
     UserID = map["UserID"];
     FolderID = map["FolderID"];
 }
        public virtual bool MoveFolder(InventoryFolderBase folder)
        {
            object remoteValue = DoRemoteByURL("InventoryServerURI", folder);
            if (remoteValue != null || m_doRemoteOnly)
                return remoteValue == null ? false : (bool) remoteValue;

            List<InventoryFolderBase> x = m_Database.GetFolders(
                new[] {"folderID"},
                new[] {folder.ID.ToString()});

            if (x.Count == 0)
                return false;

            x[0].ParentID = folder.ParentID;

            return m_Database.StoreFolder(x[0]);
        }
 public virtual bool StoreFolder(InventoryFolderBase folder)
 {
     QueryFilter filter = new QueryFilter();
     filter.andFilters["folderID"] = folder.ID;
     GD.Delete(m_foldersrealm, filter);
     Dictionary<string, object> row = new Dictionary<string, object>(6);
     row["folderName"] = folder.Name;
     row["type"] = folder.Type;
     row["version"] = folder.Version;
     row["folderID"] = folder.ID;
     row["agentID"] = folder.Owner;
     row["parentFolderID"] = folder.ParentID;
     return GD.Insert(m_foldersrealm, row);
 }
        /// <summary>
        ///     Find an item given a PATH_DELIMITOR delimited path starting from this folder.
        ///     This method does not handle paths that contain multiple delimiters
        ///     FIXME: We do not yet handle situations where folders or items have the same name.  We could handle this by some
        ///     XPath like expression
        ///     FIXME: Delimiters which occur in names themselves are not currently escapable.
        /// </summary>
        /// <param name="inventoryService">
        ///     Inventory service to query
        /// </param>
        /// <param name="startFolder">
        ///     The folder from which the path starts
        /// </param>
        /// <param name="path">
        ///     The path to the required item.
        /// </param>
        /// <returns>null if the item is not found</returns>
        public static InventoryItemBase FindItemByPath(
            IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
        {
            // If the path isn't just / then trim any starting extraneous slashes
            path = path.TrimStart(new[] { PATH_DELIMITER });

            string[] components = SplitEscapedPath(path);
            components[0] = UnescapePath(components[0]);

            //string[] components = path.Split(new string[] { PATH_DELIMITER }, 2, StringSplitOptions.None);

            if (components.Length == 1)
            {
                //MainConsole.Instance.DebugFormat(
                //    "FOUND SINGLE COMPONENT [{0}].  Looking for this in [{1}] {2}", components[0], startFolder.Name, startFolder.ID);

                List<InventoryItemBase> items = inventoryService.GetFolderItems(startFolder.Owner, startFolder.ID);

                //MainConsole.Instance.DebugFormat("[INVENTORY ARCHIVE UTILS]: Found {0} items in FindItemByPath()", items.Count);

                return items.FirstOrDefault(item => item.Name == components[0]);
            }
            else
            {
                //MainConsole.Instance.DebugFormat("FOUND COMPONENTS [{0}] and [{1}]", components[0], components[1]);

                InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID);

                return (from folder in contents.Folders
                        where folder.Name == components[0]
                        select FindItemByPath(inventoryService, folder, components[1])).FirstOrDefault();
            }
        }
        AvatarAppearance CopyWearablesAndAttachments (UUID destination, UUID source,
                                                             AvatarAppearance avatarAppearance,
                                                             InventoryFolderBase destinationFolder, UUID agentid,
                                                             OSDMap itemsMap,
                                                             out List<InventoryItemBase> items)
        {
            items = new List<InventoryItemBase> ();

            if (destinationFolder == null) {
                MainConsole.Instance.Error ("[Avatar Archiver]: Cannot locate folder(s) for copying wearables!");
                return avatarAppearance;
            }

            List<InventoryItemBase> litems = new List<InventoryItemBase> ();
            foreach (KeyValuePair<string, OSD> kvp in itemsMap) {
                InventoryItemBase item = new InventoryItemBase ();
                item.FromOSD ((OSDMap)kvp.Value);
                MainConsole.Instance.Info ("[Avatar Archiver]: Loading item " + item.ID);
                litems.Add (item);
            }

            // Wearables
            AvatarWearable [] wearables = avatarAppearance.Wearables;
            MainConsole.Instance.InfoFormat ("[Avatar Archiver] Adding {0} wearables", wearables.Length);

            for (int i = 0; i < wearables.Length; i++) {
                AvatarWearable wearable = wearables [i];
                for (int ii = 0; ii < wearable.Count; ii++) {
                    if (wearable [ii].ItemID != UUID.Zero) {
                        // Get inventory item and copy it
                        InventoryItemBase item = inventoryService.GetItem (UUID.Zero, wearable [ii].ItemID);

                        if (item == null) {
                            //Attempt to get from the map if it doesn't already exist on the grid
                            item = litems.First ((itm) => itm.ID == wearable [ii].ItemID);
                        }
                        if (item != null) {
                            InventoryItemBase destinationItem = inventoryService.InnerGiveInventoryItem (destination,
                                                                                                        destination,
                                                                                                        item,
                                                                                                        destinationFolder
                                                                                                            .ID,
                                                                                                        false, false);
                            items.Add (destinationItem);
                            MainConsole.Instance.DebugFormat ("[Avatar Archiver]: Added item {0} to folder {1}",
                                                             destinationItem.ID, destinationFolder.ID);

                            // Wear item
                            AvatarWearable newWearable = new AvatarWearable ();
                            newWearable.Wear (destinationItem.ID, destinationItem.AssetID);
                            avatarAppearance.SetWearable (i, newWearable);
                        } else {
                            MainConsole.Instance.WarnFormat ("[Avatar Archiver]: Unable to transfer {0} to folder {1}",
                                                            wearable [ii].ItemID, destinationFolder.ID);
                        }
                    }
                }
            }

            // Attachments
            List<AvatarAttachment> attachments = avatarAppearance.GetAttachments ();
            MainConsole.Instance.InfoFormat ("[Avatar Archiver] Adding {0} attachments", attachments.Count);

            foreach (AvatarAttachment attachment in attachments) {
                int attachpoint = attachment.AttachPoint;
                UUID itemID = attachment.ItemID;

                if (itemID != UUID.Zero) {

                    // Get inventory item and copy it
                    InventoryItemBase item = inventoryService.GetItem (UUID.Zero, itemID);

                    if (item == null) {
                        //Attempt to get from the map if it doesn't already exist on the grid
                        item = litems.First ((itm) => itm.ID == itemID);
                    }

                    if (item != null) {
                        InventoryItemBase destinationItem = inventoryService.InnerGiveInventoryItem (destination,
                                                                                                    destination, item,
                                                                                                    destinationFolder.ID,
                                                                                                    false, false);
                        items.Add (destinationItem);
                        MainConsole.Instance.DebugFormat ("[Avatar Archiver]: Added item {0} to folder {1}", destinationItem.ID,
                                                         destinationFolder.ID);

                        // Attach item
                        avatarAppearance.SetAttachment (attachpoint, destinationItem.ID, destinationItem.AssetID);
                        MainConsole.Instance.DebugFormat ("[Avatar Archiver]: Attached {0}", destinationItem.ID);
                    } else {
                        MainConsole.Instance.WarnFormat ("[Avatar Archiver]: Error transferring {0} to folder {1}", itemID,
                                                        destinationFolder.ID);
                    }
                }
            }
            return avatarAppearance;
        }
        /// <summary>
        ///     Delete a scene object from a scene and place in the given avatar's inventory.
        ///     Returns the UUID of the newly created asset.
        /// </summary>
        /// <param name="action"></param>
        /// <param name="folderID"></param>
        /// <param name="objectGroups"></param>
        /// <param name="agentId"></param>
        /// <param name="itemID"></param>
        public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID,
                                              List<ISceneEntity> objectGroups, UUID agentId, out UUID itemID)
        {
            itemID = UUID.Zero;
            if (objectGroups.Count == 0)
                return UUID.Zero;

            // Get the user info of the item destination
            //
            IScenePresence SP = m_scene.GetScenePresence(agentId);
            UUID userID = UUID.Zero;

            if (action == DeRezAction.Take || action == DeRezAction.AcquireToUserInventory ||
                action == DeRezAction.SaveToExistingUserInventoryItem)
            {
                // Take or take copy require a taker
                // Saving changes requires a local user
                //
                if (SP == null || SP.ControllingClient == null)
                    return UUID.Zero;

                userID = agentId;
            }
            else
            {
                // All returns / deletes go to the object owner
                //

                userID = objectGroups[0].OwnerID;
            }

            if (userID == UUID.Zero) // Can't proceed
            {
                return UUID.Zero;
            }

            // If we're returning someone's item, it goes back to the
            // owner's Lost And Found folder.
            // Delete is treated like return in this case
            // Deleting your own items makes them go to trash
            //

            InventoryFolderBase folder = null;
            InventoryItemBase item;

            if (DeRezAction.SaveToExistingUserInventoryItem == action)
            {
                item = m_scene.InventoryService.GetItem(userID, objectGroups[0].RootChild.FromUserInventoryItemID);

                //item = userInfo.RootFolder.FindItem(
                //        objectGroup.RootPart.FromUserInventoryItemID);

                if (item == null)
                {
                    MainConsole.Instance.DebugFormat(
                        "[Agent inventory]: Object {0} {1} scheduled for save to inventory has already been deleted.",
                        objectGroups[0].Name, objectGroups[0].UUID);
                    return UUID.Zero;
                }
            }
            else
            {
                // Folder magic
                //
                if (action == DeRezAction.Delete)
                {
                    // Deleting someone else's item
                    //

                    if (SP == null || SP.ControllingClient == null ||
                        objectGroups[0].OwnerID != agentId)
                    {
                        folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown, FolderType.LostAndFound);
                    }
                    else
                    {
                        folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown, FolderType.Trash);
                    }
                }
                else if (action == DeRezAction.Return)
                {
                    // Dump to lost + found unconditionally
                    //
                    folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown, FolderType.LostAndFound);
                }

                if (folderID == UUID.Zero && folder == null)
                {
                    if (action == DeRezAction.Delete)
                    {
                        // Deletes go to trash by default
                        //
                        folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown, FolderType.Trash);
                    }
                    else
                    {
                        if (SP == null || SP.ControllingClient == null ||
                            objectGroups[0].OwnerID != agentId)
                        {
                            folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown, FolderType.LostAndFound);
                        }
                        else
                        {
                            folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown, FolderType.Trash);
                        }
                    }
                }

                // Override and put into where it came from, if it came
                // from anywhere in inventory
                //
                if (action == DeRezAction.Attachment || action == DeRezAction.Take ||
                    action == DeRezAction.AcquireToUserInventory)
                {
                    if (objectGroups[0].RootChild.FromUserInventoryItemID != UUID.Zero)
                    {
                        InventoryFolderBase f =
                            new InventoryFolderBase(objectGroups[0].RootChild.FromUserInventoryItemID, userID);
                        folder = m_scene.InventoryService.GetFolder(f);
                    }
                    else
                    {
                        folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Object, FolderType.Object);
                    }
                }

                if (folder == null) // None of the above
                {
                    folder = new InventoryFolderBase(folderID);
                }

                item = new InventoryItemBase
                           {
                               CreatorId = objectGroups[0].RootChild.CreatorID.ToString(),
                               ID = UUID.Random(),
                               InvType = (int) InventoryType.Object,
                               Folder = folder.ID,
                               Owner = userID
                           };
            }

            AssetBase asset;
            UUID assetID = SaveAsAsset(objectGroups, out asset);
            item.AssetID = assetID;
            if (DeRezAction.SaveToExistingUserInventoryItem != action)
            {
                item.Description = asset.Description;
                item.Name = asset.Name;
                item.AssetType = asset.Type;
            }

            if (DeRezAction.SaveToExistingUserInventoryItem == action)
            {
                m_scene.InventoryService.UpdateItem(item);
            }
            else
            {
                if (SP != null && SP.ControllingClient != null &&
                    (SP.ControllingClient.AgentId != objectGroups[0].OwnerID) &&
                    m_scene.Permissions.PropagatePermissions())
                {
                    foreach (ISceneEntity group in objectGroups)
                    {
                        uint perms = group.GetEffectivePermissions();
                        uint nextPerms = (perms & 7) << 13;
                        if ((nextPerms & (uint) PermissionMask.Copy) == 0)
                            perms &= ~(uint) PermissionMask.Copy;
                        if ((nextPerms & (uint) PermissionMask.Transfer) == 0)
                            perms &= ~(uint) PermissionMask.Transfer;
                        if ((nextPerms & (uint) PermissionMask.Modify) == 0)
                            perms &= ~(uint) PermissionMask.Modify;

                        // Make sure all bits but the ones we want are clear
                        // on take.
                        // This will be applied to the current perms, so
                        // it will do what we want.
                        group.RootChild.NextOwnerMask &=
                            ((uint) PermissionMask.Copy |
                             (uint) PermissionMask.Transfer |
                             (uint) PermissionMask.Modify);
                        group.RootChild.NextOwnerMask |=
                            (uint) PermissionMask.Move;

                        item.BasePermissions = perms & group.RootChild.NextOwnerMask;
                        item.CurrentPermissions = item.BasePermissions;
                        item.NextPermissions = group.RootChild.NextOwnerMask;
                        item.EveryOnePermissions = group.RootChild.EveryoneMask & group.RootChild.NextOwnerMask;
                        item.GroupPermissions = group.RootChild.GroupMask & group.RootChild.NextOwnerMask;

                        // Magic number badness. Maybe this deserves an Enum.
                        // bit 4 (16) is the "Slam" bit, it means treat as passed
                        // and apply next owner perms on rez
                        item.CurrentPermissions |= 16; // Slam!

                        item.SalePrice = group.RootChild.SalePrice;
                        item.SaleType = group.RootChild.ObjectSaleType;
                    }
                }
                else
                {
                    foreach (ISceneEntity group in objectGroups)
                    {
                        item.BasePermissions = group.GetEffectivePermissions();
                        item.CurrentPermissions = group.GetEffectivePermissions();
                        item.NextPermissions = group.RootChild.NextOwnerMask;
                        item.EveryOnePermissions = group.RootChild.EveryoneMask;
                        item.GroupPermissions = group.RootChild.GroupMask;

                        item.SalePrice = group.RootChild.SalePrice;
                        item.SaleType = group.RootChild.ObjectSaleType;

                        item.CurrentPermissions &=
                            ((uint) PermissionMask.Copy |
                             (uint) PermissionMask.Transfer |
                             (uint) PermissionMask.Modify |
                             (uint) PermissionMask.Move |
                             7); // Preserve folded permissions
                    }
                }

                if (objectGroups.Count != 1)
                    item.Flags |= (uint) InventoryItemFlags.ObjectHasMultipleItems;
                item.CreationDate = Util.UnixTimeSinceEpoch();

                m_LLCLientInventoryModule.AddInventoryItem(item);

                if (SP != null && SP.ControllingClient != null && item.Owner == SP.ControllingClient.AgentId)
                {
                    SP.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
                }
                else
                {
                    IScenePresence notifyUser = m_scene.GetScenePresence(item.Owner);
                    if (notifyUser != null)
                    {
                        notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
                    }
                }
            }
            itemID = item.ID;
            return assetID;
        }
        /// <summary>
        ///     Save an inventory folder
        /// </summary>
        /// <param name="inventoryFolder">The inventory folder to save</param>
        /// <param name="path">The path to which the folder should be saved</param>
        /// <param name="saveThisFolderItself">If true, save this folder itself.  If false, only saves contents</param>
        protected void SaveInvFolder(InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself)
        {
            // ignore viewer folders (special folders?)
            if (inventoryFolder.Name.StartsWith ("#"))
                return;

            if (saveThisFolderItself)
            {
                path += CreateArchiveFolderName(inventoryFolder);

                // We need to make sure that we record empty folders
                m_archiveWriter.WriteDir(path);
            }

            InventoryCollection contents
                = m_inventoryService.GetFolderContent(inventoryFolder.Owner, inventoryFolder.ID);

            foreach (InventoryFolderBase childFolder in contents.Folders)
            {
                SaveInvFolder(childFolder, path, true);
            }

            foreach (InventoryItemBase item in contents.Items)
            {
                SaveInvItem(item, path);
            }
        }
        public virtual bool AddFolder(InventoryFolderBase folder)
        {
            object remoteValue = DoRemoteByURL("InventoryServerURI", folder);
            if (remoteValue != null || m_doRemoteOnly)
                return remoteValue == null ? false : (bool) remoteValue;

            InventoryFolderBase check = GetFolder(folder);
            if (check != null)
                return false;

            return m_Database.StoreFolder(folder);
        }
        public virtual InventoryFolderBase GetFolder(InventoryFolderBase folder)
        {
            object remoteValue = DoRemoteByURL("InventoryServerURI", folder);
            if (remoteValue != null || m_doRemoteOnly)
                return (InventoryFolderBase) remoteValue;

            List<InventoryFolderBase> folders = m_Database.GetFolders(
                new[] {"folderID"},
                new[] {folder.ID.ToString()});

            if (folders.Count == 0)
                return null;

            return folders[0];
        }
        public virtual bool ForcePurgeFolder(InventoryFolderBase folder)
        {
            object remoteValue = DoRemoteByURL("InventoryServerURI", folder);
            if (remoteValue != null || m_doRemoteOnly)
                return remoteValue == null ? false : (bool)remoteValue;

            List<InventoryFolderBase> subFolders = m_Database.GetFolders(
                new[] {"parentFolderID"},
                new[] {folder.ID.ToString()});

            foreach (InventoryFolderBase x in subFolders)
            {
                ForcePurgeFolder(x);
                m_Database.DeleteFolders("folderID", x.ID.ToString(), false);
            }

            m_Database.DeleteItems("parentFolderID", folder.ID.ToString());
            m_Database.DeleteFolders("folderID", folder.ID.ToString(), false);

            return true;
        }
        public virtual void FixInventory(IScene scene, string[] cmd)
        {
            string userName = MainConsole.Instance.Prompt("Name of user");
            UserAccount account = m_UserAccountService.GetUserAccount(null, userName);
            if (account == null)
            {
                MainConsole.Instance.Warn("Could not find user");
                return;
            }
            InventoryFolderBase rootFolder = GetRootFolder(account.PrincipalID);

            //Fix having a default root folder
            if (rootFolder == null)
            {
                MainConsole.Instance.Warn("Fixing default root folder...");
                List<InventoryFolderBase> skel = GetInventorySkeleton(account.PrincipalID);
                if (skel.Count == 0)
                {
                    CreateUserInventory(account.PrincipalID, false);
                    rootFolder = GetRootFolder(account.PrincipalID);
                }
                else
                {
                    rootFolder = new InventoryFolderBase
                                     {
                                         Name = "My Inventory",
                                         Type = (short) AssetType.RootFolder,
                                         Version = 1,
                                         ID = skel[0].ParentID,
                                         Owner = account.PrincipalID,
                                         ParentID = UUID.Zero
                                     };
                }
            }
            //Check against multiple root folders
            List<InventoryFolderBase> rootFolders = GetRootFolders(account.PrincipalID);
            List<UUID> badFolders = new List<UUID>();
            if (rootFolders.Count != 1)
            {
                //No duplicate folders!
                foreach (
                    InventoryFolderBase f in rootFolders.Where(f => !badFolders.Contains(f.ID) && f.ID != rootFolder.ID)
                    )
                {
                    MainConsole.Instance.Warn("Removing duplicate root folder " + f.Name);
                    badFolders.Add(f.ID);
                }
            }
            //Fix any root folders that shouldn't be root folders
            List<InventoryFolderBase> skeleton = GetInventorySkeleton(account.PrincipalID);
            List<UUID> foundFolders = new List<UUID>();
            foreach (InventoryFolderBase f in skeleton)
            {
                if (!foundFolders.Contains(f.ID))
                    foundFolders.Add(f.ID);
                if (f.Name == "My Inventory" && f.ParentID != UUID.Zero)
                {
                    //Merge them all together
                    badFolders.Add(f.ID);
                }
            }
            foreach (InventoryFolderBase f in skeleton)
            {
                if ((!foundFolders.Contains(f.ParentID) && f.ParentID != UUID.Zero) ||
                    f.ID == f.ParentID)
                {
                    //The viewer loses the parentID when something goes wrong
                    //it puts it in the top where My Inventory should be
                    //We need to put it back in the My Inventory folder, as the sub folders are right for some reason
                    f.ParentID = rootFolder.ID;
                    m_Database.StoreFolder(f);
                    MainConsole.Instance.WarnFormat("Fixing folder {0}", f.Name);
                }
                else if (badFolders.Contains(f.ParentID))
                {
                    //Put it back in the My Inventory folder
                    f.ParentID = rootFolder.ID;
                    m_Database.StoreFolder(f);
                    MainConsole.Instance.WarnFormat("Fixing folder {0}", f.Name);
                }
                else if (f.Type == (short) AssetType.CurrentOutfitFolder)
                {
                    List<InventoryItemBase> items = GetFolderItems(account.PrincipalID, f.ID);
                    //Check the links!
                    List<UUID> brokenLinks = new List<UUID>();
                    foreach (InventoryItemBase item in items)
                    {
                        InventoryItemBase linkedItem = null;
                        if ((linkedItem = GetItem(account.PrincipalID, item.AssetID)) == null)
                        {
                            //Broken link...
                            brokenLinks.Add(item.ID);
                        }
                        else if (linkedItem.ID == AvatarWearable.DEFAULT_EYES_ITEM ||
                                 linkedItem.ID == AvatarWearable.DEFAULT_SHAPE_ITEM ||
                                 linkedItem.ID == AvatarWearable.DEFAULT_HAIR_ITEM ||
                                 linkedItem.ID == AvatarWearable.DEFAULT_PANTS_ITEM ||
                                 linkedItem.ID == AvatarWearable.DEFAULT_SHIRT_ITEM ||
                                 linkedItem.ID == AvatarWearable.DEFAULT_SKIN_ITEM)
                        {
                            //Default item link, needs removed
                            brokenLinks.Add(item.ID);
                        }
                    }
                    if (brokenLinks.Count != 0)
                        DeleteItems(account.PrincipalID, brokenLinks);
                }
                else if (f.Type == (short) AssetType.Mesh)
                {
                    ForcePurgeFolder(f);
                }
            }
            foreach (UUID id in badFolders)
            {
                m_Database.DeleteFolders("folderID", id.ToString(), false);
            }
            //Make sure that all default folders exist
            CreateUserInventory(account.PrincipalID, false);
            //Refetch the skeleton now
            skeleton = GetInventorySkeleton(account.PrincipalID);
            Dictionary<int, UUID> defaultFolders = new Dictionary<int, UUID>();
            Dictionary<UUID, UUID> changedFolders = new Dictionary<UUID, UUID>();
            foreach (InventoryFolderBase folder in skeleton.Where(folder => folder.Type != -1))
            {
                if (!defaultFolders.ContainsKey(folder.Type))
                    defaultFolders[folder.Type] = folder.ID;
                else
                    changedFolders.Add(folder.ID, defaultFolders[folder.Type]);
            }
            foreach (InventoryFolderBase folder in skeleton)
            {
                if (folder.Type != -1 && defaultFolders[folder.Type] != folder.ID)
                {
                    //Delete the dup
                    ForcePurgeFolder(folder);
                    MainConsole.Instance.Warn("Purging duplicate default inventory type folder " + folder.Name);
                }
                if (changedFolders.ContainsKey(folder.ParentID))
                {
                    folder.ParentID = changedFolders[folder.ParentID];
                    MainConsole.Instance.Warn("Merging child folder of default inventory type " + folder.Name);
                    m_Database.StoreFolder(folder);
                }
            }
            MainConsole.Instance.Warn("Completed the check");
        }
        public virtual bool DeleteFolders(UUID principalID, List<UUID> folderIDs)
        {
            object remoteValue = DoRemoteByURL("InventoryServerURI", principalID, folderIDs);
            if (remoteValue != null || m_doRemoteOnly)
                return remoteValue == null ? false : (bool) remoteValue;

            if (!m_AllowDelete)
            {
                foreach (UUID id in folderIDs)
                {
                    if (!ParentIsLinkFolder(id))
                        continue;
                    InventoryFolderBase f = new InventoryFolderBase {ID = id};
                    PurgeFolder(f);
                    m_Database.DeleteFolders("folderID", id.ToString(), true);
                }
                return true;
            }

            // Ignore principal ID, it's bogus at connector level
            foreach (UUID id in folderIDs)
            {
                if (!ParentIsTrash(id))
                    continue;
                InventoryFolderBase f = new InventoryFolderBase {ID = id};
                PurgeFolder(f);
                m_Database.DeleteFolders("folderID", id.ToString(), true);
            }

            return true;
        }
        protected InventoryFolderBase CreateFolder(UUID principalID, UUID parentID, int type, string name)
        {
            InventoryFolderBase newFolder = new InventoryFolderBase
                                                {
                                                    Name = name,
                                                    Type = (short) type,
                                                    Version = 1,
                                                    ID = UUID.Random(),
                                                    Owner = principalID,
                                                    ParentID = parentID
                                                };

            m_Database.StoreFolder(newFolder);

            return newFolder;
        }
        public virtual bool UpdateFolder(InventoryFolderBase folder)
        {
            object remoteValue = DoRemoteByURL("InventoryServerURI", folder);
            if (remoteValue != null || m_doRemoteOnly)
                return remoteValue == null ? false : (bool) remoteValue;

            if (!m_AllowDelete) //Initial item MUST be created as a link folder
                if (folder.Type == (sbyte) AssetType.LinkFolder)
                    return false;

            InventoryFolderBase check = GetFolder(folder);
            if (check == null)
                return AddFolder(folder);

            if (check.Type != -1 || folder.Type != -1)
            {
                if (folder.Version > check.Version)
                    return false;
                check.Version = folder.Version;
                check.Type = folder.Type;
                check.Version++;
                return m_Database.StoreFolder(check);
            }

            if (folder.Version < check.Version)
                folder.Version = check.Version;
            folder.ID = check.ID;

            folder.Version++;
            return m_Database.StoreFolder(folder);
        }
        /// <summary>
        ///     Constructor
        /// </summary>
        public InventoryArchiveWriteRequest(
            Guid id, InventoryArchiverModule module, IRegistryCore registry,
            UserAccount userInfo, string invPath, Stream saveStream, bool UseAssets, InventoryFolderBase folderBase,
            List<AssetBase> assetsToAdd, string checkPermissions)
        {
            m_id = id;
            m_module = module;
            m_registry = registry;
            m_userInfo = userInfo;
            m_invPath = invPath;
            m_saveStream = saveStream;
            m_saveAssets = UseAssets;
            m_defaultFolderToSave = folderBase;
            m_assetsToAdd = assetsToAdd;

            // Set Permission filter if available
            if (checkPermissions != null)
                FilterContent = checkPermissions.ToUpper();

            // some necessary services
            m_inventoryService = m_registry.RequestModuleInterface<IInventoryService> ();
            m_assetService = m_registry.RequestModuleInterface<IAssetService> ();
            m_accountService = m_registry.RequestModuleInterface<IUserAccountService> ();

            // lastly as it is dependant
            m_assetGatherer = new UuidGatherer(m_assetService);
        }
 /// <summary>
 ///     Create the archive name for a particular folder.
 /// </summary>
 /// These names are prepended with an inventory folder's UUID so that more than one folder can have the
 /// same name
 /// <param name="folder"></param>
 /// <returns></returns>
 public static string CreateArchiveFolderName(InventoryFolderBase folder)
 {
     return CreateArchiveFolderName(folder.Name, folder.ID);
 }
        public byte [] CreateInventoryCategory (string path, Stream request, OSHttpRequest httpRequest,
                                               OSHttpResponse httpResponse)
        {
            OSDMap map = (OSDMap)OSDParser.DeserializeLLSDXml (HttpServerHandlerHelpers.ReadFully (request));
            UUID folder_id = map ["folder_id"].AsUUID ();
            UUID parent_id = map ["parent_id"].AsUUID ();
            int type = map ["type"].AsInteger ();
            string name = map ["name"].AsString ();

            InventoryFolderBase newFolder
                = new InventoryFolderBase (
                      folder_id, name, m_agentID, (short)type, parent_id, 1);
            m_inventoryService.AddFolder (newFolder);
            OSDMap resp = new OSDMap ();
            resp ["folder_id"] = folder_id;
            resp ["parent_id"] = parent_id;
            resp ["type"] = type;
            resp ["name"] = name;

            return OSDParser.SerializeLLSDXmlBytes (map);
        }
Ejemplo n.º 19
0
        public AvatarAppearance WearFolder(AvatarAppearance avappearance, UUID user, UUID folderOwnerID)
        {
            InventoryFolderBase Folder2Wear = m_InventoryService.GetFolderByOwnerAndName(folderOwnerID, m_forceUserToWearFolderName);
            if (Folder2Wear != null)
            {
                List<InventoryItemBase> itemsInFolder = m_InventoryService.GetFolderItems(UUID.Zero, Folder2Wear.ID);

                InventoryFolderBase appearanceFolder = m_InventoryService.GetFolderForType(user, InventoryType.Wearable, FolderType.Clothing);
                InventoryFolderBase folderForAppearance = new InventoryFolderBase(UUID.Random(), "GridWear", user, -1,
                                                                                  appearanceFolder.ID, 1);
                List<InventoryFolderBase> userFolders = m_InventoryService.GetFolderFolders(user, appearanceFolder.ID);
                bool alreadyThere = false;
                List<UUID> items2RemoveFromAppearence = new List<UUID>();
                List<UUID> toDelete = new List<UUID>();

                foreach (InventoryFolderBase folder in userFolders)
                {
                    if (folder.Name == folderForAppearance.Name)
                    {
                        List<InventoryItemBase> itemsInCurrentFolder = m_InventoryService.GetFolderItems(UUID.Zero, folder.ID);
                        foreach (InventoryItemBase itemBase in itemsInCurrentFolder)
                        {
                            items2RemoveFromAppearence.Add(itemBase.AssetID);
                            items2RemoveFromAppearence.Add(itemBase.ID);
                            toDelete.Add(itemBase.ID);
                        }
                        folderForAppearance = folder;
                        alreadyThere = true;
                        m_InventoryService.DeleteItems(user, toDelete);
                        break;
                    }
                }

                if (!alreadyThere)
                    m_InventoryService.AddFolder(folderForAppearance);
                else
                {
                    // we have to remove all the old items if they are currently wearing them
                    for (int i = 0; i < avappearance.Wearables.Length; i++)
                    {
                        AvatarWearable wearable = avappearance.Wearables[i];
                        for (int ii = 0; ii < wearable.Count; ii++)
                        {
                            if (items2RemoveFromAppearence.Contains(wearable[ii].ItemID))
                            {
                                avappearance.Wearables[i] = AvatarWearable.DefaultWearables[i];
                                break;
                            }
                        }
                    }

                    List<AvatarAttachment> attachments = avappearance.GetAttachments();
                    foreach (AvatarAttachment attachment in attachments)
                    {
                        if ((items2RemoveFromAppearence.Contains(attachment.AssetID)) ||
                            (items2RemoveFromAppearence.Contains(attachment.ItemID)))
                        {
                            avappearance.DetachAttachment(attachment.ItemID);
                        }
                    }
                }

                // ok, now we have a empty folder, lets add the items
                foreach (InventoryItemBase itemBase in itemsInFolder)
                {
                    InventoryItemBase newcopy = m_InventoryService.InnerGiveInventoryItem(user, folderOwnerID, itemBase,
                                                                                          folderForAppearance.ID,
                                                                                          true, true);

                    if (newcopy.InvType == (int) InventoryType.Object)
                    {
                        byte[] attobj = m_AssetService.GetData(newcopy.AssetID.ToString());

                        if (attobj != null)
                        {
                            string xmlData = Utils.BytesToString(attobj);
                            XmlDocument doc = new XmlDocument();
                            try
                            {
                                doc.LoadXml(xmlData);
                            }
                            catch
                            {
                                continue;
                            }

                            if (doc.FirstChild.OuterXml.StartsWith("<groups>") ||
                                (doc.FirstChild.NextSibling != null &&
                                 doc.FirstChild.NextSibling.OuterXml.StartsWith("<groups>")))
                                continue;

                            string xml;
                            if ((doc.FirstChild.NodeType == XmlNodeType.XmlDeclaration) &&
                                (doc.FirstChild.NextSibling != null))
                                xml = doc.FirstChild.NextSibling.OuterXml;
                            else
                                xml = doc.FirstChild.OuterXml;
                            doc.LoadXml(xml);

                            if (doc.DocumentElement == null) continue;

                            XmlNodeList xmlNodeList = doc.DocumentElement.SelectNodes("//State");
                            int attchspot;
                            if ((xmlNodeList != null) && (int.TryParse(xmlNodeList[0].InnerText, out attchspot)))
                            {
                                AvatarAttachment a = new AvatarAttachment(attchspot, newcopy.ID, newcopy.AssetID);
                                Dictionary<int, List<AvatarAttachment>> ac = avappearance.Attachments;

                                if (!ac.ContainsKey(attchspot))
                                    ac[attchspot] = new List<AvatarAttachment>();

                                ac[attchspot].Add(a);
                                avappearance.Attachments = ac;
                            }
                        }
                    }
                    m_InventoryService.AddItem(newcopy);
                }
            }
            return avappearance;
        }
        /// <summary>
        ///     Execute the request
        /// </summary>
        /// <returns>
        ///     A list of the inventory nodes loaded.  If folders were loaded then only the root folders are
        ///     returned
        /// </returns>
        public HashSet<InventoryNodeBase> Execute (bool loadAll)
        {
            if (m_loadStream == null)
                return new HashSet<InventoryNodeBase> ();
            
            string filePath = "ERROR";
            int successfulAssetRestores = 0;
            int failedAssetRestores = 0;
            int successfulItemRestores = 0;

            HashSet<InventoryNodeBase> loadedNodes = loadAll ? new HashSet<InventoryNodeBase> () : null;

            try {
                List<InventoryFolderBase> folderCandidates
                    = InventoryArchiveUtils.FindFolderByPath (m_inventoryService, m_userInfo.PrincipalID, m_invPath);

                if (folderCandidates.Count == 0) {
                    // try and create requested folder
                    var rootFolder = m_inventoryService.GetRootFolder (m_userInfo.PrincipalID);
                    if (rootFolder == null) {
                        if (m_inventoryService.CreateUserInventory (m_userInfo.PrincipalID, true))
                            rootFolder = m_inventoryService.GetRootFolder (m_userInfo.PrincipalID);
                        else {
                            MainConsole.Instance.Error ("[Inventory Archiver]: Unable to create Inventory root folder");
                            return loadedNodes;       // major bummer
                        }
                    }

                    InventoryFolderBase iarImportFolder = new InventoryFolderBase ();

                    iarImportFolder.ID = UUID.Random ();
                    iarImportFolder.Name = m_invPath;                       // the path
                    iarImportFolder.Owner = m_userInfo.PrincipalID;         // owner
                    iarImportFolder.ParentID = rootFolder.ID;               // the root folder 
                    iarImportFolder.Type = (short)FolderType.None;          // user defined folder
                    iarImportFolder.Version = 1;                            // initial version

                    m_inventoryService.AddFolder (iarImportFolder);

                    // ensure that it now exists...
                    folderCandidates = InventoryArchiveUtils.FindFolderByPath (m_inventoryService, m_userInfo.PrincipalID, m_invPath);
                    if (folderCandidates.Count == 0) {
                        MainConsole.Instance.ErrorFormat ("[Inventory Archiver]: Unable to create Inventory path {0}", m_invPath);
                        return loadedNodes;
                    }
                }

                // we have the base folder... do it...
                InventoryFolderBase rootDestinationFolder = folderCandidates [0];
                archive = new TarArchiveReader (m_loadStream);

                // In order to load identically named folders, we need to keep track of the folders that we have already
                // resolved
                Dictionary<string, InventoryFolderBase> resolvedFolders = new Dictionary<string, InventoryFolderBase> ();

                MainConsole.Instance.Info ("[Archiver]: Commencing load from archive");
                int ticker = 0;

                byte [] data;
                TarArchiveReader.TarEntryType entryType;

                while ((data = archive.ReadEntry (out filePath, out entryType)) != null) {
                    if (TarArchiveReader.TarEntryType.TYPE_NORMAL_FILE == entryType) {
                        string fName;
                        try {
                            fName = Path.GetFileName (filePath);
                            if (fName.StartsWith (".", StringComparison.Ordinal))                 // ignore hidden files
                                continue;
                        } catch {
                            MainConsole.Instance.ErrorFormat ("[Archiver]: Invalid file name in archive: {0}", filePath);
                            continue;
                        }
                    }

                    ticker++;
                    if (ticker % 5 == 0)
                        MainConsole.Instance.Ticker ();

                    if (filePath.StartsWith (ArchiveConstants.ASSETS_PATH, StringComparison.Ordinal)) {
                        if (LoadAsset (filePath, data))
                            successfulAssetRestores++;
                        else
                            failedAssetRestores++;

                        if ((successfulAssetRestores) % 50 == 0)
                            MainConsole.Instance.Ticker(
                                string.Format (" [Inventory Archiver]: Loaded {0} assets...", successfulAssetRestores),true);
                    } else if (filePath.StartsWith (ArchiveConstants.INVENTORY_PATH, StringComparison.Ordinal)) {
                        filePath = filePath.Substring (ArchiveConstants.INVENTORY_PATH.Length);

                        // Trim off the file portion if we aren't already dealing with a directory path
                        if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType)
                            filePath = filePath.Remove (filePath.LastIndexOf ("/", StringComparison.Ordinal) + 1);

                        InventoryFolderBase foundFolder
                            = ReplicateArchivePathToUserInventory (
                                filePath, rootDestinationFolder, ref resolvedFolders, ref loadedNodes);

                        if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY != entryType) {
                            InventoryItemBase item = LoadItem (data, foundFolder);

                            if (item != null) {
                                successfulItemRestores++;

                                if ((successfulItemRestores) % 50 == 0)
                                    MainConsole.Instance.Ticker(
                                        string.Format("[Inventory Archiver]: Restored {0} items...", successfulItemRestores),
                                        true);

                                // If we aren't loading the folder containing the item then well need to update the 
                                // viewer separately for that item.
                                if (loadAll && !loadedNodes.Contains (foundFolder))
                                    loadedNodes.Add (item);
                            }
                            item = null;
                        }
                    } else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) {
                        LoadControlFile (data);
                    }

                    data = null;
                }

                MainConsole.Instance.CleanInfo ("");
                MainConsole.Instance.Info ("[Inventory Archiver]: Saving loaded inventory items");
                ticker = 0;

                int successfulItemLoaded = 0;
                foreach (InventoryItemBase item in itemsSavedOff) {
                    ticker++;
                    if (ticker % 5 == 0)
                        MainConsole.Instance.Ticker ();

                    AddInventoryItem (item);
                    successfulItemLoaded++;

                    if ((successfulItemLoaded) % 50 == 0)
                        MainConsole.Instance.Ticker(
                            string.Format ("[Inventory Archiver]: Restored {0} items of {1}...", 
                                           successfulItemLoaded, itemsSavedOff.Count),
                            true) ;
                }

                itemsSavedOff.Clear ();
                assets2Save.Clear ();

                MainConsole.Instance.CleanInfo ("");
                MainConsole.Instance.InfoFormat (
                    "[Inventory Archiver]: Successfully loaded {0} assets with {1} failures",
                    successfulAssetRestores, failedAssetRestores);
                MainConsole.Instance.InfoFormat ("[Inventory Archiver]: Successfully loaded {0} items",
                                                successfulItemRestores);
                
            } finally {
                m_loadStream.Close ();
            }
            return loadedNodes;
        }
        InventoryItemBase GiveInventoryItem (UUID senderId, UUID recipient, InventoryItemBase item,
                                                    InventoryFolderBase parentFolder)
        {
            InventoryItemBase itemCopy = new InventoryItemBase {
                Owner = recipient,
                CreatorId = item.CreatorId,
                CreatorData = item.CreatorData,
                ID = UUID.Random (),
                AssetID = item.AssetID,
                Description = item.Description,
                Name = item.Name,
                AssetType = item.AssetType,
                InvType = item.InvType,
                Folder = UUID.Zero,
                NextPermissions = (uint)PermissionMask.All,
                GroupPermissions = (uint)PermissionMask.All,
                EveryOnePermissions = (uint)PermissionMask.All,
                CurrentPermissions = (uint)PermissionMask.All
            };

            //Give full permissions for them

            if (parentFolder == null) {
                InventoryFolderBase folder = inventoryService.GetFolderForType (recipient, InventoryType.Unknown,
                                                                               (FolderType)itemCopy.AssetType);

                if (folder != null)
                    itemCopy.Folder = folder.ID;
                else {
                    InventoryFolderBase root = inventoryService.GetRootFolder (recipient);

                    if (root != null)
                        itemCopy.Folder = root.ID;
                    else
                        return null; // No destination
                }
            } else
                itemCopy.Folder = parentFolder.ID; //We already have a folder to put it in

            itemCopy.GroupID = UUID.Zero;
            itemCopy.GroupOwned = false;
            itemCopy.Flags = item.Flags;
            itemCopy.SalePrice = item.SalePrice;
            itemCopy.SaleType = item.SaleType;

            inventoryService.AddItem (itemCopy);
            return itemCopy;
        }
        /// <summary>
        ///     Replicate the inventory paths in the archive to the user's inventory as necessary.
        /// </summary>
        /// <param name="iarPath">The item archive path to replicate</param>
        /// <param name="rootDestFolder">The root folder for the inventory load</param>
        /// <param name="resolvedFolders">
        ///     The folders that we have resolved so far for a given archive path.
        ///     This method will add more folders if necessary
        /// </param>
        /// <param name="loadedNodes">
        ///     Track the inventory nodes created.
        /// </param>
        /// <returns>The last user inventory folder created or found for the archive path</returns>
        public InventoryFolderBase ReplicateArchivePathToUserInventory (
            string iarPath,
            InventoryFolderBase rootDestFolder,
            ref Dictionary<string, InventoryFolderBase> resolvedFolders,
            ref HashSet<InventoryNodeBase> loadedNodes)
        {
            string iarPathExisting = iarPath;

            //MainConsole.Instance.DebugFormat(
            //    "[Inventory Archiver]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID);

            InventoryFolderBase destFolder
                = ResolveDestinationFolder (rootDestFolder, ref iarPathExisting, ref resolvedFolders);

            //MainConsole.Instance.DebugFormat(
            //    "[Inventory Archiver]: originalArchivePath [{0}], section already loaded [{1}]", iarPath, iarPathExisting);

            string iarPathToCreate = iarPath.Substring (iarPathExisting.Length);
            CreateFoldersForPath (destFolder, iarPathExisting, iarPathToCreate, ref resolvedFolders, ref loadedNodes);

            return destFolder;
        }
        public AvatarArchive LoadAvatarArchive (string fileName, UUID principalID)
        {
            AvatarArchive archive = new AvatarArchive ();
            UserAccount account = userAccountService.GetUserAccount (null, principalID);
            if (account == null) {
                MainConsole.Instance.Error ("[Avatar Archiver]: User not found!");
                return null;
            }

            // need to be smart here...
            fileName = PathHelpers.VerifyReadFile (fileName, ".aa", m_storeDirectory);
            if (!File.Exists (fileName)) {
                MainConsole.Instance.Error ("[Avatar Archiver]: Unable to load from file: file does not exist!");
                return null;
            }
            MainConsole.Instance.Info ("[Avatar Archiver]: Loading archive from " + fileName);

            archive.FromOSD ((OSDMap)OSDParser.DeserializeLLSDXml (File.ReadAllText (fileName)));

            AvatarAppearance appearance = ConvertXMLToAvatarAppearance (archive.BodyMap);

            appearance.Owner = principalID;

            InventoryFolderBase AppearanceFolder = inventoryService.GetFolderForType (account.PrincipalID,
                                                                                     InventoryType.Wearable,
                                                                                     FolderType.Clothing);

            if (AppearanceFolder == null) {
                AppearanceFolder = new InventoryFolderBase (); // does not exist so...
                AppearanceFolder.Owner = account.PrincipalID;
                AppearanceFolder.ID = UUID.Random ();
                AppearanceFolder.Type = (short)FolderType.Clothing;
            }

            List<InventoryItemBase> items;

            InventoryFolderBase folderForAppearance
                = new InventoryFolderBase (
                    UUID.Random (), archive.FolderName, account.PrincipalID,
                (short)FolderType.None, AppearanceFolder.ID, 1);

            inventoryService.AddFolder (folderForAppearance);

            folderForAppearance = inventoryService.GetFolder (folderForAppearance);

            try {
                LoadAssets (archive.AssetsMap);
                appearance = CopyWearablesAndAttachments (account.PrincipalID, UUID.Zero, appearance, folderForAppearance,
                                                         account.PrincipalID, archive.ItemsMap, out items);
            } catch (Exception ex) {
                MainConsole.Instance.Warn ("[AvatarArchiver]: Error loading assets and items, " + ex);
            }

            /*  implement fully if we need to
            // inform the client if needed

            ScenePresence SP;
            MainConsole.Instance.ConsoleScenes[0].TryGetScenePresence(account.PrincipalID, out SP);
            if (SP == null)
                return; // nobody home!

            SP.ControllingClient.SendAlertMessage("Appearance loading in progress...");
            SP.ControllingClient.SendBulkUpdateInventory(folderForAppearance);
            */

            MainConsole.Instance.Info ("[Avatar Archiver]: Loaded archive from " + fileName);
            archive.Appearance = appearance;
            return archive;
        }
        /// <summary>
        ///     Resolve a destination folder
        /// </summary>
        /// We require here a root destination folder (usually the root of the user's inventory) and the archive
        /// path.  We also pass in a list of previously resolved folders in case we've found this one previously.
        /// <param name="archivePath">
        ///     The item archive path to resolve.  The portion of the path passed back is that
        ///     which corresponds to the resolved destination folder.
        /// </param>
        /// <param name="rootDestFolder">
        ///     The root folder for the inventory load
        /// </param>
        /// <param name="resolvedFolders">
        ///     The folders that we have resolved so far for a given archive path.
        /// </param>
        /// <returns>
        ///     The folder in the user's inventory that matches best the archive path given.  If no such folder was found
        ///     then the passed in root destination folder is returned.
        /// </returns>
        protected InventoryFolderBase ResolveDestinationFolder (
            InventoryFolderBase rootDestFolder,
            ref string archivePath,
            ref Dictionary<string, InventoryFolderBase> resolvedFolders)
        {
            //string originalArchivePath = archivePath;

            while (archivePath.Length > 0) {
                //MainConsole.Instance.DebugFormat("[Inventory Archiver]: Trying to resolve destination folder {0}", archivePath);

                if (resolvedFolders.ContainsKey (archivePath)) {
                    //MainConsole.Instance.DebugFormat(
                    //    "[Inventory Archiver]: Found previously created folder from archive path {0}", archivePath);
                    return resolvedFolders [archivePath];
                }
                if (m_merge) {
                    // TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the 
                    // iar name and try to find that instead.
                    string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath (archivePath);
                    List<InventoryFolderBase> folderCandidates
                    = InventoryArchiveUtils.FindFolderByPath (m_inventoryService, m_userInfo.PrincipalID, plainPath);

                    if (folderCandidates.Count != 0) {
                        InventoryFolderBase destFolder = folderCandidates [0];
                        resolvedFolders [archivePath] = destFolder;
                        return destFolder;
                    }
                }

                // Don't include the last slash so find the penultimate one
                int penultimateSlashIndex = archivePath.LastIndexOf ("/", archivePath.Length - 2, StringComparison.Ordinal);

                if (penultimateSlashIndex >= 0) {
                    // Remove the last section of path so that we can see if we've already resolved the parent
                    archivePath = archivePath.Remove (penultimateSlashIndex + 1);
                } else {
                    //MainConsole.Instance.DebugFormat(
                    //    "[Inventory Archiver]: Found no previously created folder for archive path {0}", originalArchivePath);
                    archivePath = string.Empty;
                    return rootDestFolder;
                }
            }

            return rootDestFolder;
        }
        /// <summary>
        ///     Find a folder given a PATH_DELIMITER delimited path starting from this folder
        /// </summary>
        /// This method does not handle paths that contain multiple delimiters
        /// 
        /// FIXME: We have no way of distinguishing folders with the same path.
        /// 
        /// FIXME: Delimiters which occur in names themselves are not currently escapable.
        /// <param name="inventoryService">
        ///     Inventory service to query
        /// </param>
        /// <param name="startFolder">
        ///     The folder from which the path starts
        /// </param>
        /// <param name="path">
        ///     The path to the required folder.
        ///     It this is empty or consists only of the PATH_DELIMTER then this folder itself is returned.
        /// </param>
        /// <returns>An empty list if the folder is not found, otherwise a list of all folders that match the name</returns>
        public static List<InventoryFolderBase> FindFolderByPath(
            IInventoryService inventoryService, InventoryFolderBase startFolder, string path)
        {
            List<InventoryFolderBase> foundFolders = new List<InventoryFolderBase>();

            if (path == string.Empty)
            {
                foundFolders.Add(startFolder);
                return foundFolders;
            }

            path = path.Trim();

            if (path == PATH_DELIMITER.ToString())
            {
                foundFolders.Add(startFolder);
                return foundFolders;
            }

            // If the path isn't just / then trim any starting extraneous slashes
            path = path.TrimStart(new[] { PATH_DELIMITER });

            //MainConsole.Instance.DebugFormat("[INVENTORY ARCHIVE UTILS]: Adjusted path in FindFolderByPath() is [{0}]", path);

            string[] components = SplitEscapedPath(path);
            components[0] = UnescapePath(components[0]);

            //string[] components = path.Split(new string[] { PATH_DELIMITER.ToString() }, 2, StringSplitOptions.None);

            InventoryCollection contents = inventoryService.GetFolderContent(startFolder.Owner, startFolder.ID);

            foreach (InventoryFolderBase folder in contents.Folders.Where(folder => folder.Name == components[0]))
            {
                if (components.Length > 1)
                    foundFolders.AddRange(FindFolderByPath(inventoryService, folder, components[1]));
                else
                    foundFolders.Add(folder);
            }
            return foundFolders;
        }
        /// <summary>
        ///     Create a set of folders for the given path.
        /// </summary>
        /// <param name="destFolder">
        ///     The root folder from which the creation will take place.
        /// </param>
        /// <param name="iarPathExisting">
        ///     the part of the iar path that already exists
        /// </param>
        /// <param name="iarPathToReplicate">
        ///     The path to replicate in the user's inventory from iar
        /// </param>
        /// <param name="resolvedFolders">
        ///     The folders that we have resolved so far for a given archive path.
        /// </param>
        /// <param name="loadedNodes">
        ///     Track the inventory nodes created.
        /// </param>
        protected void CreateFoldersForPath (
            InventoryFolderBase destFolder,
            string iarPathExisting,
            string iarPathToReplicate,
            ref Dictionary<string, InventoryFolderBase> resolvedFolders,
            ref HashSet<InventoryNodeBase> loadedNodes)
        {
            string [] rawDirsToCreate = iarPathToReplicate.Split (new [] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < rawDirsToCreate.Length; i++) {
                //MainConsole.Instance.DebugFormat("[Inventory Archiver]: Creating folder {0} from IAR", rawDirsToCreate[i]);

                if (!rawDirsToCreate [i].Contains (ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR))
                    continue;

                int identicalNameIdentifierIndex
                    = rawDirsToCreate [i].LastIndexOf (
                        ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, StringComparison.Ordinal);

                string newFolderName = rawDirsToCreate [i].Remove (identicalNameIdentifierIndex);

                newFolderName = InventoryArchiveUtils.UnescapeArchivePath (newFolderName);
                UUID newFolderId = UUID.Random ();              // assume we need a new ID

                // Asset type has to be Unknown here rather than Folder, otherwise the created folder can't be
                // deleted once the client has relogged.
                // The root folder appears to be labelled AssetType.Folder (shows up as "Category" in the client)
                // even though there is a AssetType.RootCategory
                destFolder
                    = new InventoryFolderBase (
                        newFolderId, newFolderName, m_userInfo.PrincipalID,
                        (short)FolderType.None, destFolder.ID, 1);

                // Check for existing folders
                string resPath = "";
                foreach (var rPath in resolvedFolders) {
                    var pName = rPath.Key;
                    if (pName.Contains (ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR)) {
                        int splitIndex =
                            pName.LastIndexOf (ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, StringComparison.Ordinal);
                        pName = pName.Remove (splitIndex);
                    }

                    resPath += pName + "/";
                }
                var existingFolder = m_inventoryService.GetUserFolderID (m_userInfo.PrincipalID, resPath + newFolderName);
                if (existingFolder.Count == 0)
                    m_inventoryService.AddFolder (destFolder);      // add the folder
                else
                    destFolder.ID = (UUID)existingFolder [0];       // use the existing ID

                // Record that we have now created this folder
                iarPathExisting += rawDirsToCreate [i] + "/";

                MainConsole.Instance.DebugFormat ("[Inventory Archiver]: Created folder {0} from IAR", iarPathExisting);
                resolvedFolders [iarPathExisting] = destFolder;

                if (0 == i && loadedNodes != null)
                    loadedNodes.Add (destFolder);
            }
        }
        void OnInstantMessage(IClientAPI client, GridInstantMessage im)
        {
            //MainConsole.Instance.InfoFormat("[INVENTORY TRANSFER]: OnInstantMessage {0}", im.dialog);
            IScene clientScene = FindClientScene(client.AgentId);
            if (clientScene == null) // Something seriously wrong here.
            {
                MainConsole.Instance.DebugFormat ("[INVENTORY TRANSFER]: Cannot find originating user scene");
                return;
            }

            if (im.Dialog == (byte) InstantMessageDialog.InventoryOffered)
            {
                //MainConsole.Instance.DebugFormat("Asset type {0}", ((AssetType)im.binaryBucket[0]));

                if (im.BinaryBucket.Length < 17) // Invalid
                {
                    MainConsole.Instance.DebugFormat ("[INVENTORY TRANSFER]: Invalid length {0} for asset type {1}",
                        im.BinaryBucket.Length, ((AssetType)im.BinaryBucket[0]));
                    return;
                }

                UUID receipientID = im.ToAgentID;
                IScenePresence recipientUser = null;
                IScene recipientUserScene = FindClientScene(client.AgentId);
                if (recipientUserScene != null)
                    recipientUser = recipientUserScene.GetScenePresence(receipientID);
                UUID copyID;

                // user is online now...
                if (recipientUser != null)
                {

                    // First byte is the asset type
                    AssetType assetType = (AssetType)im.BinaryBucket [0];

                    if (assetType == AssetType.Folder)
                    {
                        UUID folderID = new UUID (im.BinaryBucket, 1);

                        MainConsole.Instance.DebugFormat (
                            "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory",
                            folderID, im.ToAgentID);


                        clientScene.InventoryService.GiveInventoryFolderAsync (
                            receipientID,
                            client.AgentId,
                            folderID,
                            UUID.Zero,
                            (folder) =>
                            {
                                if (folder == null)
                                {
                                    client.SendAgentAlertMessage ("Can't find folder to give. Nothing given.", false);
                                    return;
                                }

                                // The outgoing binary bucket should contain only the byte which signals an asset folder is
                                // being copied and the following bytes for the copied folder's UUID
                                copyID = folder.ID;
                                byte[] copyIDBytes = copyID.GetBytes ();
                                im.BinaryBucket = new byte[ 1 + copyIDBytes.Length ];
                                im.BinaryBucket [0] = (byte)AssetType.Folder;
                                Array.Copy (copyIDBytes, 0, im.BinaryBucket, 1, copyIDBytes.Length);

//                                m_currencyService.UserCurrencyTransfer(im.FromAgentID, im.ToAgentID, 0,
//                                    "Inworld inventory folder transfer", TransactionType.GiveInventory, UUID.Zero);
                            if (moneyService != null)
                                moneyService.Transfer(im.ToAgentID, im.FromAgentID, 0,
                                "Inworld inventory folder transfer", TransactionType.GiveInventory);

                                if (recipientUser != null)
                                {
                                    recipientUser.ControllingClient.SendBulkUpdateInventory (folder);
                                    im.SessionID = copyID;
                                    recipientUser.ControllingClient.SendInstantMessage (im);
                                }
                            });

                    } else
                    {
                        // First byte of the array is probably the item type
                        // Next 16 bytes are the UUID

                        UUID itemID = new UUID (im.BinaryBucket, 1);

                        MainConsole.Instance.DebugFormat (
                            "[INVENTORY TRANSFER]: (giving) Inserting item {0} into agent {1}'s inventory",
                            itemID, im.ToAgentID);

                        clientScene.InventoryService.GiveInventoryItemAsync (
                            im.ToAgentID,
                            im.FromAgentID,
                            itemID,
                            UUID.Zero,
                            false,
                            (itemCopy) =>
                            {
                                if (itemCopy == null)
                                {
                                    MainConsole.Instance.DebugFormat (
                                        "[INVENTORY TRANSFER]: (giving) Unable to find item {0} to give to agent {1}'s inventory",
                                        itemID, im.ToAgentID);
                                    client.SendAgentAlertMessage ("Can't find item to give. Nothing given.", false);
                                    return;
                                }

                                copyID = itemCopy.ID;
                                Array.Copy (copyID.GetBytes (), 0, im.BinaryBucket, 1, 16);
                                
                               if (moneyService != null)
                                  moneyService.Transfer(im.ToAgentID, im.FromAgentID, 0,
                                          "Inworld inventory item transfer", TransactionType.GiveInventory);

                                if (recipientUser != null)
                                {
                                    recipientUser.ControllingClient.SendBulkUpdateInventory (itemCopy);
                                    im.SessionID = itemCopy.ID;
                                    recipientUser.ControllingClient.SendInstantMessage (im);
                                }
                            });
  
                    
                    }
                }  else
                {
                    // recipient is offline.
                    // Send the IM to the recipient. The item is already
                    // in their inventory, so it will not be lost if
                    // they are offline.
                    //
                     if (m_TransferModule != null)
                        m_TransferModule.SendInstantMessage(im);
                }
            }
            else if (im.Dialog == (byte) InstantMessageDialog.InventoryAccepted)
            {
                IScenePresence user = clientScene.GetScenePresence(im.ToAgentID);
                MainConsole.Instance.DebugFormat ("[INVENTORY TRANSFER]: Acceptance message received");

                if (user != null) // Local
                {
                    user.ControllingClient.SendInstantMessage(im);
                }
                else
                {
                    if (m_TransferModule != null)
                        m_TransferModule.SendInstantMessage(im);
                }
            }
            else if (im.Dialog == (byte) InstantMessageDialog.InventoryDeclined)
            {
                // Here, the recipient is local and we can assume that the
                // inventory is loaded. Courtesy of the above bulk update,
                // It will have been pushed to the client, too
                //
                IInventoryService invService = clientScene.InventoryService;
                MainConsole.Instance.DebugFormat ("[INVENTORY TRANSFER]: Declined message received");

                InventoryFolderBase trashFolder =
                    invService.GetFolderForType(client.AgentId, InventoryType.Unknown, FolderType.Trash);

                UUID inventoryID = im.SessionID; // The inventory item/folder, back from it's trip

                InventoryItemBase item = invService.GetItem(client.AgentId, inventoryID);
                InventoryFolderBase folder = null;

                if (item != null && trashFolder != null)
                {
                    item.Folder = trashFolder.ID;

                    // Diva comment: can't we just update this item???
                    List<UUID> uuids = new List<UUID> {item.ID};
                    invService.DeleteItems(item.Owner, uuids);
                    ILLClientInventory inventory = client.Scene.RequestModuleInterface<ILLClientInventory>();
                    if (inventory != null)
                        inventory.AddInventoryItemAsync(client, item);
                }
                else
                {
                    folder = new InventoryFolderBase(inventoryID, client.AgentId);
                    folder = invService.GetFolder(folder);

                    if (folder != null & trashFolder != null)
                    {
                        folder.ParentID = trashFolder.ID;
                        invService.MoveFolder(folder);
                        client.SendBulkUpdateInventory(folder);
                    }
                }

                if ((null == item && null == folder) | null == trashFolder)
                {
                    string reason = String.Empty;

                    if (trashFolder == null)
                        reason += " Trash folder not found.";
                    if (item == null)
                        reason += " Item not found.";
                    if (folder == null)
                        reason += " Folder not found.";

                    client.SendAgentAlertMessage("Unable to delete " +
                                                 "received inventory" + reason, false);
                }

                //m_currencyService.UserCurrencyTransfer(im.FromAgentID, im.ToAgentID, 0,
                //    "Inworld inventory transfer declined", TransactionType.GiveInventory, UUID.Zero);
                if (moneyService != null)
                    moneyService.Transfer(im.ToAgentID, im.FromAgentID, 0,
                        "Inworld inventory transfer declined", TransactionType.GiveInventory);

                IScenePresence user = clientScene.GetScenePresence(im.ToAgentID);

                if (user != null) // Local
                {
                    user.ControllingClient.SendInstantMessage(im);
                }
                else
                {
                    if (m_TransferModule != null)
                        m_TransferModule.SendInstantMessage(im);
                }
            }
        }
        /// <summary>
        ///     Load an item from the archive
        /// </summary>
        /// <param name="data">The raw item data</param>
        /// <param name="loadFolder"> </param>
        protected InventoryItemBase LoadItem (byte [] data, InventoryFolderBase loadFolder)
        {
            InventoryItemBase item = UserInventoryItemSerializer.Deserialize (data);

            UUID ospResolvedId = OspResolver.ResolveOspa (item.CreatorId, m_accountService);
            if (UUID.Zero != ospResolvedId) {
                item.CreatorIdAsUuid = ospResolvedId;

                // Don't preserve the OSPA in the creator id (which actually gets persisted to the
                // database).  Instead, replace with the UUID that we found.
                item.CreatorId = ospResolvedId.ToString ();

                item.CreatorData = string.Empty;
            } else if (string.IsNullOrEmpty (item.CreatorData)) {
                item.CreatorId = m_userInfo.PrincipalID.ToString ();
                item.CreatorIdAsUuid = new UUID (item.CreatorId);
            }

            // Don't use the item ID that's in the file, this could be a local user's folder
            //item.ID = UUID.Random();
            item.Owner = m_userInfo.PrincipalID;

            // Record the creator id for the item's asset so that we can use it later, if necessary, when the asset
            // is loaded.
            // FIXME: This relies on the items coming before the assets in the TAR file.  Need to create stronger
            // checks for this, and maybe even an external tool for creating OARs which enforces this, rather than
            // relying on native tar tools.
            m_creatorIdForAssetId [item.AssetID] = item.CreatorIdAsUuid;

            // Reset folder ID to the one in which we want to load it
            item.Folder = loadFolder.ID;

            itemsSavedOff.Add (item);

            return item;
        }
 List<InventoryFolderBase> ParseInventoryFolders(ref Dictionary<string, List<string>> retVal)
 {
     List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
     if (retVal.Count == 0)
         return folders;
     for (int i = 0; i < retVal.ElementAt(0).Value.Count; i++)
     {
         InventoryFolderBase folder = new InventoryFolderBase {
                                              Name = retVal["folderName"][i],
                                              Type = short.Parse(retVal["type"][i]),
                                              Version = (ushort) int.Parse(retVal["version"][i]),
                                              ID = UUID.Parse(retVal["folderID"][i]),
                                              Owner = UUID.Parse(retVal["agentID"][i]),
                                              ParentID = UUID.Parse(retVal["parentFolderID"][i])
                                          };
         folders.Add(folder);
     }
     //retVal.Clear();
     return folders;
 }
        /// <summary>
        ///     Give an entire inventory folder from one user to another.  The entire contents (including all descendent
        ///     folders) is given.
        /// </summary>
        /// <param name="recipientId"></param>
        /// <param name="senderId">ID of the sender of the item</param>
        /// <param name="folderId"></param>
        /// <param name="recipientParentFolderId">
        ///     The id of the recipient folder in which the send folder should be placed.  If UUID.Zero then the
        ///     recipient folder is the root folder
        /// </param>
        /// <param name="success"></param>
        /// <returns>
        ///     The inventory folder copy given, null if the copy was unsuccessful
        /// </returns>
        public void GiveInventoryFolderAsync(
            UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId, GiveFolderParam success)
        {
            Util.FireAndForget(o =>
                                   {
                                       // Retrieve the folder from the sender
                                       InventoryFolderBase folder = GetFolder(new InventoryFolderBase(folderId));
                                       if (null == folder)
                                       {
                                           MainConsole.Instance.ErrorFormat(
                                               "[InventoryService]: Could not find inventory folder {0} to give",
                                               folderId);
                                           success(null);
                                           return;
                                       }

                                       //Find the folder for the receiver
                                       if (recipientParentFolderId == UUID.Zero)
                                       {
                                           InventoryFolderBase recipientRootFolder = GetRootFolder(recipientId);
                                           if (recipientRootFolder != null)
                                               recipientParentFolderId = recipientRootFolder.ID;
                                           else
                                           {
                                               MainConsole.Instance.WarnFormat(
                                                   "[InventoryService]: Unable to find root folder for receiving agent");
                                               success(null);
                                               return;
                                           }
                                       }

                                       UUID newFolderId = UUID.Random();
                                       InventoryFolderBase newFolder
                                           = new InventoryFolderBase(
                                               newFolderId, folder.Name, recipientId, folder.Type,
                                               recipientParentFolderId, folder.Version);
                                       AddFolder(newFolder);

                                       // Give all the subfolders
                                       InventoryCollection contents = GetFolderContent(senderId, folderId);
                                       foreach (InventoryFolderBase childFolder in contents.Folders)
                                       {
                                           GiveInventoryFolderAsync(recipientId, senderId, childFolder.ID, newFolder.ID,
                                                                    null);
                                       }

                                       // Give all the items
                                       foreach (InventoryItemBase item in contents.Items)
                                       {
                                           InnerGiveInventoryItem(recipientId, senderId, item, newFolder.ID, true, true);
                                       }
                                       success(newFolder);
                                   });
        }