// Constructors
 public InventoryFolderImpl(InventoryFolderBase folderbase)
 {
     Owner = folderbase.Owner;
     ID = folderbase.ID;
     Name = folderbase.Name;
     ParentID = folderbase.ParentID;
     Type = folderbase.Type;
     Version = folderbase.Version;
 }
        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 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"];
 }
        /// <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;
        }
        /// <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;
        }
        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>
        /// Find a folder given a PATH_DELIMITER delimited path starting from this folder
        /// </summary>
        ///
        /// This method does not handle paths that contain multiple delimitors
        ///
        /// FIXME: We have no way of distinguishing folders with the same path.
        ///
        /// FIXME: Delimitors 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 char[] { 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)
            {
                if (folder.Name == components[0])
                {
                    if (components.Length > 1)
                        foundFolders.AddRange(FindFolderByPath(inventoryService, folder, components[1]));
                    else
                        foundFolders.Add(folder);
                }
            }

            return foundFolders;
        }
        /// <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 = null;

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

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

                if (null == item)
                {
                    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,
                                                                           AssetType.LostAndFoundFolder);
                    }
                    else
                    {
                        folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown,
                                                                           AssetType.TrashFolder);
                    }
                }
                else if (action == DeRezAction.Return)
                {
                    // Dump to lost + found unconditionally
                    //
                    folder = m_scene.InventoryService.GetFolderForType(userID, InventoryType.Unknown,
                                                                       AssetType.LostAndFoundFolder);
                }

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

                // 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,
                                                                           AssetType.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>
 /// 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 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);
        }
        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);
        }
        /// <summary>
        /// Execute the inventory write request
        /// </summary>
        public void Execute(string fileName)
        {
            Stream m_saveStream = new GZipStream (new FileStream (fileName, FileMode.Create), CompressionMode.Compress);
            try
            {
                InventoryFolderBase inventoryFolder = new InventoryFolderBase (UUID.Zero, UUID.Zero);
                if (m_rootFolders.Count == 1)
                    inventoryFolder = m_rootFolders[0];

                bool saveFolderContentsOnly = false;

                m_archiveWriter = new TarArchiveWriter (m_saveStream);

                if (inventoryFolder != null)
                {
                    //recurse through all dirs getting dirs and files
                    SaveInvFolder (inventoryFolder, ArchiveConstants.INVENTORY_PATH, !saveFolderContentsOnly);
                }
            }
            catch (Exception)
            {
                m_saveStream.Close ();
                throw;
            }
            foreach (AssetBase asset in m_loadedAssets.Values)
            {
                WriteData (asset);
            }
            m_saveStream.Close ();
            MessageBox.Show ("Save complete!");
        }
        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,
                                                                                           AssetType.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>
        /// 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)
        {
            string[] rawDirsToCreate = iarPathToReplicate.Split (new char[] { '/' }, 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);

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

                newFolderName = InventoryArchiveUtils.UnescapeArchivePath (newFolderName);
                UUID newFolderId = UUID.Random ();

                // 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, UUID.Zero,
                        (short)AssetType.Unknown, destFolder.ID, 1);

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

                m_folders.Add (destFolder);
                if(!m_childFolders.ContainsKey(destFolder.ParentID))
                    m_childFolders.Add (destFolder.ParentID, new List<InventoryFolderBase>());
                m_childFolders[destFolder.ParentID].Add (destFolder);
                m_folderList.Add (destFolder.ID, destFolder);
            }
        }
        /// <summary>
        /// Find an item given a PATH_DELIMITOR delimited path starting from this folder.
        ///
        /// This method does not handle paths that contain multiple delimitors
        ///
        /// 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: Delimitors 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">
        /// <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 char[] { 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);

                foreach (InventoryItemBase item in items)
                {
            //                    MainConsole.Instance.DebugFormat("[INVENTORY ARCHIVE UTILS]: Inspecting item {0} {1}", item.Name, item.ID);

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

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

                foreach (InventoryFolderBase folder in contents.Folders)
                {
                    if (folder.Name == components[0])
                        return FindItemByPath(inventoryService, folder, components[1]);
                }
            }

            // We didn't find an item or intermediate folder with the given name
            return null;
        }
 /// <summary>
 /// Load an item from the archive
 /// </summary>
 /// <param name="filePath">The archive path for the item</param>
 /// <param name="data">The raw item data</param>
 /// <param name="rootDestinationFolder">The root destination folder for loaded items</param>
 /// <param name="nodesLoaded">All the inventory nodes (items and folders) loaded so far</param>
 protected InventoryItemBase LoadItem(byte[] data, InventoryFolderBase loadFolder)
 {
     InventoryItemBase item = UserInventoryItemSerializer.Deserialize (data);
     item.Folder = loadFolder.ID;
     if(!m_items.ContainsKey(item.Folder))
         m_items.Add (item.Folder, new List<InventoryItemBase>());
     m_items[item.Folder].Add (item);
     m_itemList[item.ID] = item;
     return item;
 }
        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>
        /// 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 desintation folder.
        /// <param name="rootDestinationFolder">
        /// 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];
                }
                else
                {
                    // Don't include the last slash so find the penultimate one
                    int penultimateSlashIndex = archivePath.LastIndexOf ("/", archivePath.Length - 2);

                    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>
        ///     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>();
            try
            {
                string filePath = "ERROR";
                int successfulAssetRestores = 0;
                int failedAssetRestores = 0;
                int successfulItemRestores = 0;

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

                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);

                    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 = -1;                              // 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)
                    {
                        var fName = Path.GetFileName (filePath);
                        if (fName.StartsWith ("."))                 // ignore hidden files
                            continue;
                    }

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

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

                        if ((successfulAssetRestores)%50 == 0)
                            MainConsole.Instance.InfoFormat(
                                " [INVENTORY ARCHIVER]: Loaded {0} assets...",
                                successfulAssetRestores);
                    }
                    else if (filePath.StartsWith(ArchiveConstants.INVENTORY_PATH))
                    {
                        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("/") + 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.InfoFormat(
                                        "[INVENTORY ARCHIVER]: Restored {0} items...",successfulItemRestores);

                                // 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.InfoFormat(
                            "[INVENTORY ARCHIVER]: Loaded {0} items of {1}...",
                            successfulItemLoaded, itemsSavedOff.Count);
                }
                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);

                return loadedNodes;
            }
            finally
            {
                m_loadStream.Close();
            }
        }
        /// <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)
        {
            if (saveThisFolderItself)
            {
                path += CreateArchiveFolderName (inventoryFolder);

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

            InventoryCollection contents = FindInventoryCollection (inventoryFolder.Owner, inventoryFolder.ID);

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

            foreach (InventoryItemBase item in contents.Items)
            {
                SaveInvItem (item, path);
            }
        }
        /// <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);

                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) AssetType.Unknown, 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);
                        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 LoadIAR(string fileName)
        {
            //Load the iar into memory
            TarArchiveReader archive = new TarArchiveReader (new GZipStream (ArchiveHelpers.GetStream (fileName), CompressionMode.Decompress));

            byte[] data;
            TarArchiveReader.TarEntryType entryType;
            string filePath;

            InventoryFolderBase rootDestFolder = new InventoryFolderBase (UUID.Zero, UUID.Zero);
            Dictionary<string, InventoryFolderBase> resolvedFolders = new Dictionary<string, InventoryFolderBase> ();

            while ((data = archive.ReadEntry (out filePath, out entryType)) != null)
            {
                if (filePath.StartsWith (ArchiveConstants.ASSETS_PATH))
                {
                    LoadAsset (filePath, data);
                }
                else if (filePath.StartsWith (ArchiveConstants.INVENTORY_PATH))
                {
                    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 ("/") + 1);

                    InventoryFolderBase foundFolder
                        = ReplicateArchivePathToUserInventory (
                            filePath, rootDestFolder, ref resolvedFolders);

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

            archive.Close ();

            //Got the .iar loaded into memory now
            // Time to put it into the GUI

            RebuildTreeView ();
        }
        /// <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);

                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 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();
            }
        }