private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List <UUID> bad_folders) { bool bad = false; if (contents == null) { bad_folders.Add(freq.folder_id); bad = true; } // The inventory server isn't sending FolderID in the collection... // Must fetch it individually else if (contents.FolderID == UUID.Zero) { InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id); if (containingFolder != null) { contents.FolderID = containingFolder.ID; contents.OwnerID = containingFolder.Owner; contents.Version = containingFolder.Version; } else { m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id); bad_folders.Add(freq.folder_id); bad = true; } } return(bad); }
private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List <UUID> bad_folders) { if (contents == null) { bad_folders.Add(freq.folder_id); return(true); } // The inventory server isn't sending FolderID in the collection... // Must fetch it individually if (contents.FolderID == UUID.Zero) { InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id); if (containingFolder == null) { bad_folders.Add(freq.folder_id); return(true); } contents.FolderID = containingFolder.ID; contents.OwnerID = containingFolder.Owner; contents.Version = containingFolder.Version; } return(false); }
private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List <UUID> bad_folders) { bool bad = false; if (contents == null) { bad_folders.Add(freq.folder_id); bad = true; } // The inventory server isn't sending FolderID in the collection... // Must fetch it individually else if (contents.FolderID == UUID.Zero) { InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id); if (containingFolder != null) { contents.FolderID = containingFolder.ID; contents.OwnerID = containingFolder.Owner; contents.Version = containingFolder.Version; } else { // Was it really a request for folder Zero? // This is an overkill, but Firestorm really asks for folder Zero. // I'm leaving the code here for the time being, but commented. if (freq.folder_id == UUID.Zero) { //coll.Collection.OwnerID = freq.owner_id; //coll.Collection.FolderID = contents.FolderID; //containingFolder = m_InventoryService.GetRootFolder(freq.owner_id); //if (containingFolder != null) //{ // m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Request for parent of folder {0}", containingFolder.ID); // coll.Collection.Folders.Clear(); // coll.Collection.Folders.Add(containingFolder); // if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null) // { // InventoryFolderBase lib = new InventoryFolderBase(m_LibraryService.LibraryRootFolder.ID, m_LibraryService.LibraryRootFolder.Owner); // lib.Name = m_LibraryService.LibraryRootFolder.Name; // lib.Type = m_LibraryService.LibraryRootFolder.Type; // lib.Version = m_LibraryService.LibraryRootFolder.Version; // coll.Collection.Folders.Add(lib); // } // coll.Collection.Items.Clear(); //} } else { m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id); bad_folders.Add(freq.folder_id); } bad = true; } } return(bad); }
/// <summary> /// Construct an LLSD reply packet to a CAPS inventory request /// </summary> /// <param name="invFetch"></param> /// <returns></returns> private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) { LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); contents.agent_id = invFetch.owner_id; contents.owner_id = invFetch.owner_id; contents.folder_id = invFetch.folder_id; reply.folders.Array.Add(contents); InventoryCollection inv = new InventoryCollection(); inv.Folders = new List <InventoryFolderBase>(); inv.Items = new List <InventoryItemBase>(); int version = 0; int descendents = 0; #pragma warning disable 0612 inv = Fetch( invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents); #pragma warning restore 0612 if (inv != null && inv.Folders != null) { foreach (InventoryFolderBase invFolder in inv.Folders) { contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); } descendents += inv.Folders.Count; } if (inv != null && inv.Items != null) { foreach (InventoryItemBase invItem in inv.Items) { contents.items.Array.Add(ConvertInventoryItem(invItem)); } } contents.descendents = descendents; contents.version = version; //m_log.DebugFormat( // "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}", // invFetch.folder_id, // invFetch.fetch_items, // invFetch.fetch_folders, // contents.items.Array.Count, // contents.categories.Array.Count, // invFetch.owner_id); return(reply); }
private List <InventoryCollectionWithDescendents> Fetch(List <LLSDFetchInventoryDescendents> fetchFolders, List <UUID> bad_folders) { //m_log.DebugFormat( // "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id); // FIXME MAYBE: We're not handling sortOrder! List <InventoryCollectionWithDescendents> result = new List <InventoryCollectionWithDescendents>(); AddLibraryFolders(fetchFolders, result); if (fetchFolders.Count > 0) { UUID[] fids = new UUID[fetchFolders.Count]; int i = 0; foreach (LLSDFetchInventoryDescendents f in fetchFolders) { fids[i++] = f.folder_id; } //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids)); InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(fetchFolders[0].owner_id, fids); if (fetchedContents == null || (fetchedContents != null && fetchedContents.Length == 0)) { //m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of multiple folders for user {0}", fetchFolders[0].owner_id); return(null); } i = 0; // Do some post-processing. May need to fetch more from inv server for links foreach (InventoryCollection contents in fetchedContents) { // Find the original request LLSDFetchInventoryDescendents freq = fetchFolders[i++]; InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents(); coll.Collection = contents; if (BadFolder(freq, contents, bad_folders)) { continue; } // Next: link management ProcessLinks(freq, coll); result.Add(coll); } } return(result); }
private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollection contents) { if (contents.Items == null || contents.Items.Count == 0) { return; } // viewers are lasy and want a copy of the linked item sent before the link to it // look for item links List <UUID> itemIDs = new List <UUID>(); foreach (InventoryItemBase item in contents.Items) { //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); if (item.AssetType == (int)AssetType.Link) { itemIDs.Add(item.AssetID); } } // get the linked if any if (itemIDs.Count > 0) { InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); if (linked != null) { List <InventoryItemBase> linkedItems = new List <InventoryItemBase>(linked.Length); // check for broken foreach (InventoryItemBase linkedItem in linked) { // Take care of genuinely broken links where the target doesn't exist // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles // rather than having to keep track of every folder requested in the recursion. if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) { linkedItems.Add(linkedItem); //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); } } // insert them if (linkedItems.Count > 0) { contents.Items.InsertRange(0, linkedItems); } } } }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // lock (m_fetchLock) // { // m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request {0}", request); // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid // request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException e) { m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } if (response.Length == 0) { // Ter-guess: If requests fail a lot, the client seems to stop requesting descendants. // Therefore, I'm concluding that the client only has so many threads available to do requests // and when a thread stalls.. is stays stalled. // Therefore we need to return something valid response = "<llsd><map><key>folders</key><array /></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } // m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response); return(response); // } }
public void FetchInventoryDescendentsRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, ExpiringKey <UUID> BadRequests) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); List <LLSDFetchInventoryDescendents> folders = null; List <UUID> bad_folders = new List <UUID>(); try { OSDArray foldersrequested = null; OSD tmp = OSDParser.DeserializeLLSDXml(httpRequest.InputStream); httpRequest.InputStream.Dispose(); OSDMap map = (OSDMap)tmp; if (map.TryGetValue("folders", out tmp) && tmp is OSDArray) { foldersrequested = tmp as OSDArray; } if (foldersrequested == null || foldersrequested.Count == 0) { httpResponse.RawBuffer = EmptyResponse; return; } folders = new List <LLSDFetchInventoryDescendents>(foldersrequested.Count); for (int i = 0; i < foldersrequested.Count; i++) { OSDMap mfolder = foldersrequested[i] as OSDMap; UUID id = mfolder["folder_id"].AsUUID(); if (BadRequests.ContainsKey(id)) { bad_folders.Add(id); } else { LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { llsdRequest.folder_id = id; llsdRequest.owner_id = mfolder["owner_id"].AsUUID(); llsdRequest.sort_order = mfolder["sort_order"].AsInteger(); llsdRequest.fetch_folders = mfolder["fetch_folders"].AsBoolean(); llsdRequest.fetch_items = mfolder["fetch_items"].AsBoolean(); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e.Message); continue; } folders.Add(llsdRequest); } } foldersrequested = null; map.Clear(); map = null; } catch (Exception e) { m_log.ErrorFormat("[FETCH INV DESC]: fail parsing request: {0}", e.Message); httpResponse.RawBuffer = EmptyResponse; return; } if (folders == null || folders.Count == 0) { if (bad_folders.Count == 0) { httpResponse.RawBuffer = EmptyResponse; return; } StringBuilder sb = osStringBuilderCache.Acquire(); sb.Append("[WEB FETCH INV DESC HANDLER]: Unable to fetch folders owned by "); sb.Append("Unknown"); sb.Append(" :"); int limit = 5; int count = 0; foreach (UUID bad in bad_folders) { if (BadRequests.ContainsKey(bad)) { continue; } sb.Append(" "); sb.Append(bad.ToString()); ++count; if (--limit < 0) { break; } } if (count > 0) { if (limit < 0) { sb.Append(" ..."); } m_log.Warn(osStringBuilderCache.GetStringAndRelease(sb)); } else { osStringBuilderCache.Release(sb); } sb = osStringBuilderCache.Acquire(); sb.Append("<llsd><map><key>folders</key><array /></map><map><key>bad_folders</key><array>"); foreach (UUID bad in bad_folders) { sb.Append("<map><key>folder_id</key><uuid>"); sb.Append(bad.ToString()); sb.Append("</uuid><key>error</key><string>Unknown</string></map>"); } sb.Append("</array></map></llsd>"); httpResponse.RawBuffer = Util.UTF8NBGetbytes(osStringBuilderCache.GetStringAndRelease(sb)); return; } int total_folders = 0; int total_items = 0; UUID requester = folders[0].owner_id; List <InventoryCollection> invcollSet = Fetch(folders, bad_folders, ref total_folders, ref total_items); //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); int invcollSetCount = 0; if (invcollSet != null) { invcollSetCount = invcollSet.Count; } int mem = 8192 + ((256 * invcollSetCount + 384 * total_folders + 1024 * total_items + 128 * bad_folders.Count) & 0x7ffff000); StringBuilder lastresponse = new StringBuilder(mem); lastresponse.Append("<llsd>"); if (invcollSetCount > 0) { lastresponse.Append("<map><key>folders</key><array>"); int i = 0; InventoryCollection thiscoll; for (i = 0; i < invcollSetCount; i++) { thiscoll = invcollSet[i]; invcollSet[i] = null; LLSDxmlEncode.AddMap(lastresponse); LLSDxmlEncode.AddElem("agent_id", thiscoll.OwnerID, lastresponse); LLSDxmlEncode.AddElem("descendents", thiscoll.Descendents, lastresponse); LLSDxmlEncode.AddElem("folder_id", thiscoll.FolderID, lastresponse); if (thiscoll.Folders == null || thiscoll.Folders.Count == 0) { LLSDxmlEncode.AddEmptyArray("categories", lastresponse); } else { LLSDxmlEncode.AddArray("categories", lastresponse); foreach (InventoryFolderBase invFolder in thiscoll.Folders) { LLSDxmlEncode.AddMap(lastresponse); LLSDxmlEncode.AddElem("folder_id", invFolder.ID, lastresponse); LLSDxmlEncode.AddElem("parent_id", invFolder.ParentID, lastresponse); LLSDxmlEncode.AddElem("name", invFolder.Name, lastresponse); LLSDxmlEncode.AddElem("type", invFolder.Type, lastresponse); LLSDxmlEncode.AddElem("preferred_type", (int)-1, lastresponse); LLSDxmlEncode.AddElem("version", invFolder.Version, lastresponse); LLSDxmlEncode.AddEndMap(lastresponse); } LLSDxmlEncode.AddEndArray(lastresponse); } if (thiscoll.Items == null || thiscoll.Items.Count == 0) { LLSDxmlEncode.AddEmptyArray("items", lastresponse); } else { LLSDxmlEncode.AddArray("items", lastresponse); foreach (InventoryItemBase invItem in thiscoll.Items) { invItem.ToLLSDxml(lastresponse); } LLSDxmlEncode.AddEndArray(lastresponse); } LLSDxmlEncode.AddElem("owner_id", thiscoll.OwnerID, lastresponse); LLSDxmlEncode.AddElem("version", thiscoll.Version, lastresponse); LLSDxmlEncode.AddEndMap(lastresponse); invcollSet[i] = null; } lastresponse.Append("</array></map>"); thiscoll = null; } else { lastresponse.Append("<map><key>folders</key><array /></map>"); } if (bad_folders.Count > 0) { lastresponse.Append("<map><key>bad_folders</key><array>"); foreach (UUID bad in bad_folders) { BadRequests.Add(bad); lastresponse.Append("<map><key>folder_id</key><uuid>"); lastresponse.Append(bad.ToString()); lastresponse.Append("</uuid><key>error</key><string>Unknown</string></map>"); } lastresponse.Append("</array></map>"); StringBuilder sb = osStringBuilderCache.Acquire(); sb.Append("[WEB FETCH INV DESC HANDLER]: Unable to fetch folders owned by "); sb.Append(requester.ToString()); sb.Append(" :"); int limit = 9; foreach (UUID bad in bad_folders) { sb.Append(" "); sb.Append(bad.ToString()); if (--limit < 0) { break; } } if (limit < 0) { sb.Append(" ..."); } m_log.Warn(osStringBuilderCache.GetStringAndRelease(sb)); } lastresponse.Append("</llsd>"); httpResponse.RawBuffer = Util.UTF8NBGetbytes(lastresponse.ToString()); }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); ArrayList foldersrequested = null; try { Hashtable hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); foldersrequested = (ArrayList)hash["folders"]; hash = null; } catch (Exception e) { m_log.ErrorFormat("[FETCH INV DESC]: fail parsing request: '{0}'; path: '{1}'; exception: '{2}'", request, path, e.Message); foldersrequested = null; } if (foldersrequested == null || foldersrequested.Count == 0) { return("<llsd><map><key>folders</key><array /></map></llsd>"); } List <LLSDFetchInventoryDescendents> folders = new List <LLSDFetchInventoryDescendents>(); for (int i = 0; i < foldersrequested.Count; i++) { Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e.Message); continue; } folders.Add(llsdRequest); } foldersrequested.Clear(); if (folders.Count == 0) { return("<llsd><map><key>folders</key><array /></map></llsd>"); } List <UUID> bad_folders = new List <UUID>(); int total_folders = 0; int total_items = 0; List <InventoryCollection> invcollSet = Fetch(folders, bad_folders, ref total_folders, ref total_items); //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); int invcollSetCount = 0; if (invcollSet != null) { invcollSetCount = invcollSet.Count; } int mem = 8192 + ((256 * invcollSetCount + 384 * total_folders + 1024 * total_items + 128 * bad_folders.Count) & 0x7ffff000); StringBuilder lastresponse = new StringBuilder(mem); lastresponse.Append("<llsd>"); if (invcollSetCount > 0) { lastresponse.Append("<map><key>folders</key><array>"); int i = 0; InventoryCollection thiscoll; for (i = 0; i < invcollSetCount; i++) { thiscoll = invcollSet[i]; invcollSet[i] = null; LLSDxmlEncode.AddMap(lastresponse); LLSDxmlEncode.AddElem("agent_id", thiscoll.OwnerID, lastresponse); LLSDxmlEncode.AddElem("descendents", thiscoll.Descendents, lastresponse); LLSDxmlEncode.AddElem("folder_id", thiscoll.FolderID, lastresponse); if (thiscoll.Folders == null || thiscoll.Folders.Count == 0) { LLSDxmlEncode.AddEmptyArray("categories", lastresponse); } else { LLSDxmlEncode.AddArray("categories", lastresponse); foreach (InventoryFolderBase invFolder in thiscoll.Folders) { LLSDxmlEncode.AddMap(lastresponse); LLSDxmlEncode.AddElem("folder_id", invFolder.ID, lastresponse); LLSDxmlEncode.AddElem("parent_id", invFolder.ParentID, lastresponse); LLSDxmlEncode.AddElem("name", invFolder.Name, lastresponse); LLSDxmlEncode.AddElem("type", invFolder.Type, lastresponse); LLSDxmlEncode.AddElem("preferred_type", (int)-1, lastresponse); LLSDxmlEncode.AddElem("version", invFolder.Version, lastresponse); LLSDxmlEncode.AddEndMap(lastresponse); } LLSDxmlEncode.AddEndArray(lastresponse); } if (thiscoll.Items == null || thiscoll.Items.Count == 0) { LLSDxmlEncode.AddEmptyArray("items", lastresponse); } else { LLSDxmlEncode.AddArray("items", lastresponse); foreach (InventoryItemBase invItem in thiscoll.Items) { invItem.ToLLSDxml(lastresponse); } LLSDxmlEncode.AddEndArray(lastresponse); } LLSDxmlEncode.AddElem("owner_id", thiscoll.OwnerID, lastresponse); LLSDxmlEncode.AddElem("version", thiscoll.Version, lastresponse); LLSDxmlEncode.AddEndMap(lastresponse); invcollSet[i] = null; } lastresponse.Append("</array></map>"); thiscoll = null; } else { lastresponse.Append("<map><key>folders</key><array /></map>"); } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); if (bad_folders.Count > 0) { lastresponse.Append("<map><key>bad_folders</key><array>"); foreach (UUID bad in bad_folders) { lastresponse.Append("<map><key>folder_id</key><uuid>"); lastresponse.Append(bad.ToString()); lastresponse.Append("</uuid><key>error</key><string>Unknown</string></map>"); } lastresponse.Append("</array></map>"); } lastresponse.Append("</llsd>"); return(lastresponse.ToString()); }
private List <InventoryCollection> Fetch(List <LLSDFetchInventoryDescendents> fetchFolders, List <UUID> bad_folders, ref int total_folders, ref int total_items) { //m_log.DebugFormat( // "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id); // FIXME MAYBE: We're not handling sortOrder! List <InventoryCollection> result = new List <InventoryCollection>(32); List <LLSDFetchInventoryDescendents> libFolders = new List <LLSDFetchInventoryDescendents>(32); List <LLSDFetchInventoryDescendents> otherFolders = new List <LLSDFetchInventoryDescendents>(32); HashSet <UUID> libIDs = new HashSet <UUID>(); HashSet <UUID> otherIDs = new HashSet <UUID>(); bool dolib = (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null); UUID libOwner = UUID.Zero; if (dolib) { libOwner = m_LibraryService.LibraryRootFolder.Owner; } // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense // and can kill the sim (all root folders have parent_id Zero) // send something. bool doneZeroID = false; foreach (LLSDFetchInventoryDescendents f in fetchFolders) { if (f.folder_id == UUID.Zero) { if (doneZeroID) { continue; } doneZeroID = true; InventoryCollection Collection = new InventoryCollection(); Collection.OwnerID = f.owner_id; Collection.Version = 0; Collection.FolderID = f.folder_id; Collection.Descendents = 0; result.Add(Collection); continue; } if (dolib && f.owner_id == libOwner) { if (libIDs.Contains(f.folder_id)) { continue; } libIDs.Add(f.folder_id); libFolders.Add(f); continue; } if (otherIDs.Contains(f.folder_id)) { continue; } otherIDs.Add(f.folder_id); otherFolders.Add(f); } fetchFolders.Clear(); if (otherFolders.Count > 0) { int i = 0; //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids)); InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(otherFolders[0].owner_id, otherIDs.ToArray()); if (fetchedContents == null) { return(null); } if (fetchedContents.Length == 0) { foreach (LLSDFetchInventoryDescendents freq in otherFolders) { BadFolder(freq, null, bad_folders); } } else { i = 0; // Do some post-processing. May need to fetch more from inv server for links foreach (InventoryCollection contents in fetchedContents) { // Find the original request LLSDFetchInventoryDescendents freq = otherFolders[i]; otherFolders[i] = null; i++; if (BadFolder(freq, contents, bad_folders)) { continue; } if (!freq.fetch_folders) { contents.Folders.Clear(); } if (!freq.fetch_items) { contents.Items.Clear(); } contents.Descendents = contents.Items.Count + contents.Folders.Count; // Next: link management ProcessLinks(freq, contents); total_folders += contents.Folders.Count; total_items += contents.Items.Count; result.Add(contents); } } } if (dolib && libFolders.Count > 0) { AddLibraryFolders(libFolders, result, ref total_folders, ref total_items); } return(result); }
private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll) { InventoryCollection contents = coll.Collection; if (freq.fetch_items && contents.Items != null) { List <InventoryItemBase> itemsToReturn = contents.Items; // descendents must only include the links, not the linked items we add coll.Descendents = itemsToReturn.Count; // Add target items for links in this folder before the links themselves. List <UUID> itemIDs = new List <UUID>(); List <UUID> folderIDs = new List <UUID>(); foreach (InventoryItemBase item in itemsToReturn) { //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); if (item.AssetType == (int)AssetType.Link) { itemIDs.Add(item.AssetID); } else if (item.AssetType == (int)AssetType.LinkFolder) { folderIDs.Add(item.AssetID); } } //m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count); // Scan for folder links and insert the items they target and those links at the head of the return data if (folderIDs.Count > 0) { InventoryCollection[] linkedFolders = m_InventoryService.GetMultipleFoldersContent(coll.Collection.OwnerID, folderIDs.ToArray()); foreach (InventoryCollection linkedFolderContents in linkedFolders) { if (linkedFolderContents == null) { continue; } List <InventoryItemBase> links = linkedFolderContents.Items; itemsToReturn.InsertRange(0, links); } } if (itemIDs.Count > 0) { InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); if (linked == null) { // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); linked = new InventoryItemBase[itemIDs.Count]; int i = 0; InventoryItemBase item = new InventoryItemBase(); item.Owner = freq.owner_id; foreach (UUID id in itemIDs) { item.ID = id; linked[i++] = m_InventoryService.GetItem(item); } } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Processing folder {0}. Existing items:", freq.folder_id); //foreach (InventoryItemBase item in itemsToReturn) // m_log.DebugFormat("[XXX]: {0} {1} {2}", item.Name, item.AssetType, item.Folder); if (linked != null) { foreach (InventoryItemBase linkedItem in linked) { // Take care of genuinely broken links where the target doesn't exist // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles // rather than having to keep track of every folder requested in the recursion. if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) { itemsToReturn.Insert(0, linkedItem); //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); } } } } } }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid // request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException e) { m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; string bad_folders_response = ""; List <LLSDFetchInventoryDescendents> folders = new List <LLSDFetchInventoryDescendents>(); for (int i = 0; i < foldersrequested.Count; i++) { Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); continue; } // Filter duplicate folder ids that bad viewers may send if (folders.Find(f => f.folder_id == llsdRequest.folder_id) == null) { folders.Add(llsdRequest); } } if (folders.Count > 0) { List <UUID> bad_folders = new List <UUID>(); List <InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders); //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); if (invcollSet == null) { m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol."); #pragma warning disable 0612 return(FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse)); #pragma warning restore 0612 } string inventoryitemstr = string.Empty; foreach (InventoryCollectionWithDescendents icoll in invcollSet) { LLSDInventoryDescendents reply = ToLLSD(icoll.Collection, icoll.Descendents); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); foreach (UUID bad in bad_folders) { bad_folders_response += "<uuid>" + bad + "</uuid>"; } } if (response.Length == 0) { /* Viewers expect a bad_folders array when not available */ if (bad_folders_response.Length != 0) { response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array /></map></llsd>"; } } else { if (bad_folders_response.Length != 0) { response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request for {0} folders. Item count {1}", folders.Count, item_count); //m_log.Debug("[WEB FETCH INV DESC HANDLER] " + response); return(response); }
private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count); string response = ""; string bad_folders_response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); if (null == reply) { bad_folders_response += "<uuid>" + llsdRequest.folder_id.ToString() + "</uuid>"; } else { inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); } response += inventoryitemstr; } if (response.Length == 0) { /* Viewers expect a bad_folders array when not available */ if (bad_folders_response.Length != 0) { response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array /></map></llsd>"; } } else { if (bad_folders_response.Length != 0) { response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } } // m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response); return(response); // } }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid // request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException e) { m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); throw; } ArrayList foldersrequested = (ArrayList)hash["folders"]; string response = ""; string bad_folders_response = ""; for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); if (null == reply) { bad_folders_response += "<uuid>" + llsdRequest.folder_id.ToString() + "</uuid>"; } else { inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); response += inventoryitemstr; } } if (response.Length == 0) { /* Viewers expect a bad_folders array when not available */ if (bad_folders_response.Length != 0) { response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array /></map></llsd>"; } } else { if (bad_folders_response.Length != 0) { response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; } else { response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; } } return(response); }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException e) { m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); } ArrayList foldersrequested = (ArrayList)hash["folders"]; List <LLSDFetchInventoryDescendents> folders = new List <LLSDFetchInventoryDescendents>(); for (int i = 0; i < foldersrequested.Count; i++) { Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); continue; } folders.Add(llsdRequest); } if (folders.Count == 0) { return("<llsd><map><key>folders</key><array /></map></llsd>"); } List <UUID> bad_folders = new List <UUID>(); List <InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders); //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); if (invcollSet == null) { m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol."); #pragma warning disable 0612 return(FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse)); #pragma warning restore 0612 } StringBuilder lastresponse = new StringBuilder(1024); lastresponse.Append("<llsd>"); if (invcollSet.Count > 0) { lastresponse.Append("<map><key>folders</key><array>"); foreach (InventoryCollectionWithDescendents icoll in invcollSet) { LLSDInventoryFolderContents thiscontents = contentsToLLSD(icoll.Collection, icoll.Descendents); lastresponse.Append(LLSDHelpers.SerialiseLLSDReplyNoHeader(thiscontents)); } lastresponse.Append("</array></map>"); } else { lastresponse.Append("<map><key>folders</key><array /></map>"); } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); if (bad_folders.Count > 0) { lastresponse.Append("<map><key>bad_folders</key><array>"); foreach (UUID bad in bad_folders) { lastresponse.Append("<map><key>folder_id</key><uuid>"); lastresponse.Append(bad.ToString()); lastresponse.Append("</uuid><key>error</key><string>Unknown</string></map>"); } lastresponse.Append("</array></map>"); } lastresponse.Append("</llsd>"); return(lastresponse.ToString());; }
private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll) { InventoryCollection contents = coll.Collection; if (freq.fetch_items && contents.Items != null) { // viewers are lasy and want a copy of the linked item sent before the link to it // descendents must only include the links, not the linked items we add coll.Descendents = contents.Items.Count + contents.Folders.Count; // look for item links List <UUID> itemIDs = new List <UUID>(); foreach (InventoryItemBase item in contents.Items) { //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); if (item.AssetType == (int)AssetType.Link) { itemIDs.Add(item.AssetID); } } // get the linked if any if (itemIDs.Count > 0) { InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); if (linked == null) { // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); linked = new InventoryItemBase[itemIDs.Count]; int i = 0; foreach (UUID id in itemIDs) { linked[i++] = m_InventoryService.GetItem(freq.owner_id, id); } } if (linked != null) { List <InventoryItemBase> linkedItems = new List <InventoryItemBase>(); // check for broken foreach (InventoryItemBase linkedItem in linked) { // Take care of genuinely broken links where the target doesn't exist // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles // rather than having to keep track of every folder requested in the recursion. if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) { linkedItems.Add(linkedItem); //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); } } // insert them if (linkedItems.Count > 0) { contents.Items.InsertRange(0, linkedItems); } } } } }
private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count); StringBuilder tmpresponse = new StringBuilder(1024); StringBuilder tmpbadfolders = new StringBuilder(1024); for (int i = 0; i < foldersrequested.Count; i++) { string inventoryitemstr = ""; Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); } LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); if (null == reply) { tmpbadfolders.Append("<map><key>folder_id</key><uuid>"); tmpbadfolders.Append(llsdRequest.folder_id.ToString()); tmpbadfolders.Append("</uuid><key>error</key><string>Unknown</string></map>"); } else { inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); } tmpresponse.Append(inventoryitemstr); } StringBuilder lastresponse = new StringBuilder(1024); lastresponse.Append("<llsd>"); if (tmpresponse.Length > 0) { lastresponse.Append("<map><key>folders</key><array>"); lastresponse.Append(tmpresponse.ToString()); lastresponse.Append("</array></map>"); } else { lastresponse.Append("<map><key>folders</key><array /></map>"); } if (tmpbadfolders.Length > 0) { lastresponse.Append("<map><key>bad_folders</key><array>"); lastresponse.Append(tmpbadfolders.ToString()); lastresponse.Append("</array></map>"); } lastresponse.Append("</llsd>"); return(lastresponse.ToString()); }
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); // nasty temporary hack here, the linden client falsely // identifies the uuid 00000000-0000-0000-0000-000000000000 // as a string which breaks us // // correctly mark it as a uuid // request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>"); // another hack <integer>1</integer> results in a // System.ArgumentException: Object type System.Int32 cannot // be converted to target type: System.Boolean // request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>"); request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>"); Hashtable hash = new Hashtable(); try { hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request)); } catch (LLSD.LLSDParseException e) { m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace); m_log.Error("Request: " + request); } ArrayList foldersrequested = (ArrayList)hash["folders"]; StringBuilder tmpresponse = new StringBuilder(1024); StringBuilder tmpbadfolders = new StringBuilder(1024); List <LLSDFetchInventoryDescendents> folders = new List <LLSDFetchInventoryDescendents>(); for (int i = 0; i < foldersrequested.Count; i++) { Hashtable inventoryhash = (Hashtable)foldersrequested[i]; LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); try { LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); } catch (Exception e) { m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); continue; } folders.Add(llsdRequest); } if (folders.Count > 0) { List <UUID> bad_folders = new List <UUID>(); List <InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders); //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); if (invcollSet == null) { m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol."); #pragma warning disable 0612 return(FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse)); #pragma warning restore 0612 } string inventoryitemstr = string.Empty; foreach (InventoryCollectionWithDescendents icoll in invcollSet) { LLSDInventoryFolderContents thiscontents = contentsToLLSD(icoll.Collection, icoll.Descendents); inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(thiscontents); // inventoryitemstr = inventoryitemstr.Replace("<llsd>", ""); // inventoryitemstr = inventoryitemstr.Replace("</llsd>", ""); // inventoryitemstr = inventoryitemstr.Substring(6,inventoryitemstr.Length - 13); // tmpresponse.Append(inventoryitemstr); tmpresponse.Append(inventoryitemstr.Substring(6, inventoryitemstr.Length - 13)); } //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); foreach (UUID bad in bad_folders) { tmpbadfolders.Append("<map><key>folder_id</key><uuid>"); tmpbadfolders.Append(bad.ToString()); tmpbadfolders.Append("</uuid><key>error</key><string>Unknown</string></map>"); } } StringBuilder lastresponse = new StringBuilder(1024); lastresponse.Append("<llsd>"); if (tmpresponse.Length > 0) { lastresponse.Append("<map><key>folders</key><array>"); lastresponse.Append(tmpresponse.ToString()); lastresponse.Append("</array></map>"); } else { lastresponse.Append("<map><key>folders</key><array /></map>"); } if (tmpbadfolders.Length > 0) { lastresponse.Append("<map><key>bad_folders</key><array>"); lastresponse.Append(tmpbadfolders.ToString()); lastresponse.Append("</array></map>"); } lastresponse.Append("</llsd>"); return(lastresponse.ToString()); }