diff options
Diffstat (limited to 'OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs')
-rw-r--r-- | OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs | 545 |
1 files changed, 141 insertions, 404 deletions
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs index 427a310..2a25d9c 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs | |||
@@ -64,7 +64,7 @@ namespace OpenSim.Capabilities.Handlers | |||
64 | public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 64 | public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
65 | { | 65 | { |
66 | //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); | 66 | //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request); |
67 | 67 | ||
68 | Hashtable hash = new Hashtable(); | 68 | Hashtable hash = new Hashtable(); |
69 | try | 69 | try |
70 | { | 70 | { |
@@ -77,12 +77,12 @@ namespace OpenSim.Capabilities.Handlers | |||
77 | } | 77 | } |
78 | 78 | ||
79 | ArrayList foldersrequested = (ArrayList)hash["folders"]; | 79 | ArrayList foldersrequested = (ArrayList)hash["folders"]; |
80 | hash.Clear(); | ||
80 | 81 | ||
81 | List<LLSDFetchInventoryDescendents> folders = new List<LLSDFetchInventoryDescendents>(); | 82 | List<LLSDFetchInventoryDescendents> folders = new List<LLSDFetchInventoryDescendents>(); |
82 | for (int i = 0; i < foldersrequested.Count; i++) | 83 | for (int i = 0; i < foldersrequested.Count; i++) |
83 | { | 84 | { |
84 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | 85 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; |
85 | |||
86 | LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); | 86 | LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); |
87 | 87 | ||
88 | try | 88 | try |
@@ -98,37 +98,90 @@ namespace OpenSim.Capabilities.Handlers | |||
98 | folders.Add(llsdRequest); | 98 | folders.Add(llsdRequest); |
99 | } | 99 | } |
100 | 100 | ||
101 | foldersrequested.Clear(); | ||
102 | |||
101 | if(folders.Count == 0) | 103 | if(folders.Count == 0) |
102 | return "<llsd><map><key>folders</key><array /></map></llsd>"; | 104 | return "<llsd><map><key>folders</key><array /></map></llsd>"; |
103 | 105 | ||
104 | List<UUID> bad_folders = new List<UUID>(); | 106 | List<UUID> bad_folders = new List<UUID>(); |
105 | 107 | ||
106 | List<InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders); | 108 | int total_folders = 0; |
109 | int total_items = 0; | ||
110 | List<InventoryCollection> invcollSet = Fetch(folders, bad_folders, ref total_folders, ref total_items); | ||
107 | //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); | 111 | //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count); |
108 | 112 | ||
109 | if (invcollSet == null) | 113 | int invcollSetCount = invcollSet.Count; |
110 | { | ||
111 | m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol."); | ||
112 | #pragma warning disable 0612 | ||
113 | return FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse); | ||
114 | #pragma warning restore 0612 | ||
115 | } | ||
116 | 114 | ||
117 | StringBuilder lastresponse = new StringBuilder(1024); | 115 | int mem = 8192 + ((256 * invcollSetCount + |
116 | 384 * total_folders + | ||
117 | 1024 * total_items + | ||
118 | 128 * bad_folders.Count) & 0x7ffff000); | ||
119 | |||
120 | StringBuilder lastresponse = new StringBuilder(mem); | ||
118 | lastresponse.Append("<llsd>"); | 121 | lastresponse.Append("<llsd>"); |
119 | 122 | ||
120 | if(invcollSet.Count > 0) | 123 | if(invcollSetCount > 0) |
121 | { | 124 | { |
122 | lastresponse.Append("<map><key>folders</key><array>"); | 125 | lastresponse.Append("<map><key>folders</key><array>"); |
123 | foreach (InventoryCollectionWithDescendents icoll in invcollSet) | 126 | int i = 0; |
127 | InventoryCollection thiscoll; | ||
128 | for(i = 0; i < invcollSetCount; i++) | ||
124 | { | 129 | { |
125 | LLSDInventoryFolderContents thiscontents = contentsToLLSD(icoll.Collection, icoll.Descendents); | 130 | thiscoll = invcollSet[i]; |
126 | lastresponse.Append(LLSDHelpers.SerialiseLLSDReplyNoHeader(thiscontents)); | 131 | invcollSet[i] = null; |
132 | |||
133 | LLSDxmlEncode.AddMap(lastresponse); | ||
134 | LLSDxmlEncode.AddElem("agent_id", thiscoll.OwnerID, lastresponse); | ||
135 | LLSDxmlEncode.AddElem("descendents", thiscoll.Descendents, lastresponse); | ||
136 | LLSDxmlEncode.AddElem("folder_id", thiscoll.FolderID, lastresponse); | ||
137 | |||
138 | if(thiscoll.Folders == null || thiscoll.Folders.Count == 0) | ||
139 | LLSDxmlEncode.AddEmptyArray("categories", lastresponse); | ||
140 | else | ||
141 | { | ||
142 | LLSDxmlEncode.AddArray("categories", lastresponse); | ||
143 | foreach (InventoryFolderBase invFolder in thiscoll.Folders) | ||
144 | { | ||
145 | LLSDxmlEncode.AddMap(lastresponse); | ||
146 | |||
147 | LLSDxmlEncode.AddElem("folder_id", invFolder.ID, lastresponse); | ||
148 | LLSDxmlEncode.AddElem("parent_id", invFolder.ParentID, lastresponse); | ||
149 | LLSDxmlEncode.AddElem("name", invFolder.Name, lastresponse); | ||
150 | LLSDxmlEncode.AddElem("type", invFolder.Type, lastresponse); | ||
151 | LLSDxmlEncode.AddElem("preferred_type", (int)-1, lastresponse); | ||
152 | LLSDxmlEncode.AddElem("version", invFolder.Version, lastresponse); | ||
153 | |||
154 | LLSDxmlEncode.AddEndMap(lastresponse); | ||
155 | } | ||
156 | LLSDxmlEncode.AddEndArray(lastresponse); | ||
157 | } | ||
158 | |||
159 | if(thiscoll.Items == null || thiscoll.Items.Count == 0) | ||
160 | LLSDxmlEncode.AddEmptyArray("items", lastresponse); | ||
161 | else | ||
162 | { | ||
163 | LLSDxmlEncode.AddArray("items", lastresponse); | ||
164 | foreach (InventoryItemBase invItem in thiscoll.Items) | ||
165 | { | ||
166 | invItem.ToLLSDxml(lastresponse); | ||
167 | } | ||
168 | |||
169 | LLSDxmlEncode.AddEndArray(lastresponse); | ||
170 | } | ||
171 | |||
172 | LLSDxmlEncode.AddElem("owner_id", thiscoll.OwnerID, lastresponse); | ||
173 | LLSDxmlEncode.AddElem("version", thiscoll.Version, lastresponse); | ||
174 | |||
175 | LLSDxmlEncode.AddEndMap(lastresponse); | ||
176 | invcollSet[i] = null; | ||
127 | } | 177 | } |
128 | lastresponse.Append("</array></map>"); | 178 | lastresponse.Append("</array></map>"); |
179 | thiscoll = null; | ||
129 | } | 180 | } |
130 | else | 181 | else |
182 | { | ||
131 | lastresponse.Append("<map><key>folders</key><array /></map>"); | 183 | lastresponse.Append("<map><key>folders</key><array /></map>"); |
184 | } | ||
132 | 185 | ||
133 | //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); | 186 | //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); |
134 | if(bad_folders.Count > 0) | 187 | if(bad_folders.Count > 0) |
@@ -144,298 +197,47 @@ namespace OpenSim.Capabilities.Handlers | |||
144 | } | 197 | } |
145 | lastresponse.Append("</llsd>"); | 198 | lastresponse.Append("</llsd>"); |
146 | 199 | ||
147 | return lastresponse.ToString();; | ||
148 | } | ||
149 | |||
150 | /// <summary> | ||
151 | /// Construct an LLSD reply packet to a CAPS inventory request | ||
152 | /// </summary> | ||
153 | /// <param name="invFetch"></param> | ||
154 | /// <returns></returns> | ||
155 | private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch) | ||
156 | { | ||
157 | LLSDInventoryDescendents reply = new LLSDInventoryDescendents(); | ||
158 | LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); | ||
159 | contents.agent_id = invFetch.owner_id; | ||
160 | contents.owner_id = invFetch.owner_id; | ||
161 | contents.folder_id = invFetch.folder_id; | ||
162 | |||
163 | reply.folders.Array.Add(contents); | ||
164 | InventoryCollection inv = new InventoryCollection(); | ||
165 | inv.Folders = new List<InventoryFolderBase>(); | ||
166 | inv.Items = new List<InventoryItemBase>(); | ||
167 | int version = 0; | ||
168 | int descendents = 0; | ||
169 | |||
170 | #pragma warning disable 0612 | ||
171 | inv = Fetch( | ||
172 | invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, | ||
173 | invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents); | ||
174 | #pragma warning restore 0612 | ||
175 | |||
176 | if (inv != null && inv.Folders != null) | ||
177 | { | ||
178 | foreach (InventoryFolderBase invFolder in inv.Folders) | ||
179 | { | ||
180 | contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); | ||
181 | } | ||
182 | |||
183 | descendents += inv.Folders.Count; | ||
184 | } | ||
185 | |||
186 | if (inv != null && inv.Items != null) | ||
187 | { | ||
188 | foreach (InventoryItemBase invItem in inv.Items) | ||
189 | { | ||
190 | contents.items.Array.Add(ConvertInventoryItem(invItem)); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | contents.descendents = descendents; | ||
195 | contents.version = version; | ||
196 | |||
197 | //m_log.DebugFormat( | ||
198 | // "[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}", | ||
199 | // invFetch.folder_id, | ||
200 | // invFetch.fetch_items, | ||
201 | // invFetch.fetch_folders, | ||
202 | // contents.items.Array.Count, | ||
203 | // contents.categories.Array.Count, | ||
204 | // invFetch.owner_id); | ||
205 | |||
206 | return reply; | ||
207 | } | ||
208 | |||
209 | private LLSDInventoryFolderContents contentsToLLSD(InventoryCollection inv, int descendents) | ||
210 | { | ||
211 | LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); | ||
212 | contents.agent_id = inv.OwnerID; | ||
213 | contents.owner_id = inv.OwnerID; | ||
214 | contents.folder_id = inv.FolderID; | ||
215 | |||
216 | if (inv.Folders != null) | ||
217 | { | ||
218 | foreach (InventoryFolderBase invFolder in inv.Folders) | ||
219 | { | ||
220 | contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | if (inv.Items != null) | ||
225 | { | ||
226 | foreach (InventoryItemBase invItem in inv.Items) | ||
227 | { | ||
228 | contents.items.Array.Add(ConvertInventoryItem(invItem)); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | contents.descendents = descendents; | ||
233 | contents.version = inv.Version; | ||
234 | |||
235 | return contents; | ||
236 | } | ||
237 | /// <summary> | ||
238 | /// Old style. Soon to be deprecated. | ||
239 | /// </summary> | ||
240 | /// <param name="request"></param> | ||
241 | /// <param name="httpRequest"></param> | ||
242 | /// <param name="httpResponse"></param> | ||
243 | /// <returns></returns> | ||
244 | [Obsolete] | ||
245 | private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
246 | { | ||
247 | //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count); | ||
248 | |||
249 | StringBuilder tmpresponse = new StringBuilder(1024); | ||
250 | StringBuilder tmpbadfolders = new StringBuilder(1024); | ||
251 | |||
252 | for (int i = 0; i < foldersrequested.Count; i++) | ||
253 | { | ||
254 | string inventoryitemstr = ""; | ||
255 | Hashtable inventoryhash = (Hashtable)foldersrequested[i]; | ||
256 | |||
257 | LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents(); | ||
258 | |||
259 | try | ||
260 | { | ||
261 | LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest); | ||
262 | } | ||
263 | catch (Exception e) | ||
264 | { | ||
265 | m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e); | ||
266 | } | ||
267 | |||
268 | LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest); | ||
269 | |||
270 | if (null == reply) | ||
271 | { | ||
272 | tmpbadfolders.Append("<map><key>folder_id</key><uuid>"); | ||
273 | tmpbadfolders.Append(llsdRequest.folder_id.ToString()); | ||
274 | tmpbadfolders.Append("</uuid><key>error</key><string>Unknown</string></map>"); | ||
275 | } | ||
276 | else | ||
277 | { | ||
278 | inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); | ||
279 | inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", ""); | ||
280 | inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); | ||
281 | } | ||
282 | |||
283 | tmpresponse.Append(inventoryitemstr); | ||
284 | } | ||
285 | |||
286 | StringBuilder lastresponse = new StringBuilder(1024); | ||
287 | lastresponse.Append("<llsd>"); | ||
288 | if(tmpresponse.Length > 0) | ||
289 | { | ||
290 | lastresponse.Append("<map><key>folders</key><array>"); | ||
291 | lastresponse.Append(tmpresponse.ToString()); | ||
292 | lastresponse.Append("</array></map>"); | ||
293 | } | ||
294 | else | ||
295 | lastresponse.Append("<map><key>folders</key><array /></map>"); | ||
296 | |||
297 | if(tmpbadfolders.Length > 0) | ||
298 | { | ||
299 | lastresponse.Append("<map><key>bad_folders</key><array>"); | ||
300 | lastresponse.Append(tmpbadfolders.ToString()); | ||
301 | lastresponse.Append("</array></map>"); | ||
302 | } | ||
303 | lastresponse.Append("</llsd>"); | ||
304 | |||
305 | return lastresponse.ToString(); | 200 | return lastresponse.ToString(); |
306 | } | 201 | } |
307 | 202 | ||
308 | /// <summary> | 203 | private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> libFolders, List<InventoryCollection> result, ref int total_folders, ref int total_items) |
309 | /// Handle the caps inventory descendents fetch. | ||
310 | /// </summary> | ||
311 | /// <param name="agentID"></param> | ||
312 | /// <param name="folderID"></param> | ||
313 | /// <param name="ownerID"></param> | ||
314 | /// <param name="fetchFolders"></param> | ||
315 | /// <param name="fetchItems"></param> | ||
316 | /// <param name="sortOrder"></param> | ||
317 | /// <param name="version"></param> | ||
318 | /// <returns>An empty InventoryCollection if the inventory look up failed</returns> | ||
319 | [Obsolete] | ||
320 | private InventoryCollection Fetch( | ||
321 | UUID agentID, UUID folderID, UUID ownerID, | ||
322 | bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents) | ||
323 | { | ||
324 | //m_log.DebugFormat( | ||
325 | // "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}", | ||
326 | // fetchFolders, fetchItems, folderID, agentID); | ||
327 | |||
328 | // FIXME MAYBE: We're not handling sortOrder! | ||
329 | |||
330 | version = 0; | ||
331 | descendents = 0; | ||
332 | |||
333 | InventoryFolderImpl fold; | ||
334 | if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner) | ||
335 | { | ||
336 | if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null) | ||
337 | { | ||
338 | InventoryCollection ret = new InventoryCollection(); | ||
339 | ret.Folders = new List<InventoryFolderBase>(); | ||
340 | ret.Items = fold.RequestListOfItems(); | ||
341 | descendents = ret.Folders.Count + ret.Items.Count; | ||
342 | |||
343 | return ret; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | InventoryCollection contents = new InventoryCollection(); | ||
348 | |||
349 | if (folderID != UUID.Zero) | ||
350 | { | ||
351 | InventoryCollection fetchedContents = m_InventoryService.GetFolderContent(agentID, folderID); | ||
352 | |||
353 | if (fetchedContents == null) | ||
354 | { | ||
355 | m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of folder {0} for user {1}", folderID, agentID); | ||
356 | return contents; | ||
357 | } | ||
358 | contents = fetchedContents; | ||
359 | InventoryFolderBase containingFolder = m_InventoryService.GetFolder(agentID, folderID); | ||
360 | |||
361 | if (containingFolder != null) | ||
362 | { | ||
363 | //m_log.DebugFormat( | ||
364 | // "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}", | ||
365 | // containingFolder.Name, containingFolder.ID, agentID); | ||
366 | |||
367 | version = containingFolder.Version; | ||
368 | |||
369 | if (fetchItems && containingFolder.Type != (short)FolderType.Trash) | ||
370 | { | ||
371 | List<InventoryItemBase> itemsToReturn = contents.Items; | ||
372 | List<InventoryItemBase> originalItems = new List<InventoryItemBase>(itemsToReturn); | ||
373 | |||
374 | // descendents must only include the links, not the linked items we add | ||
375 | descendents = originalItems.Count; | ||
376 | |||
377 | // Add target items for links in this folder before the links themselves. | ||
378 | foreach (InventoryItemBase item in originalItems) | ||
379 | { | ||
380 | if (item.AssetType == (int)AssetType.Link) | ||
381 | { | ||
382 | InventoryItemBase linkedItem = m_InventoryService.GetItem(agentID, item.AssetID); | ||
383 | |||
384 | // Take care of genuinely broken links where the target doesn't exist | ||
385 | // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, | ||
386 | // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles | ||
387 | // rather than having to keep track of every folder requested in the recursion. | ||
388 | if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) | ||
389 | itemsToReturn.Insert(0, linkedItem); | ||
390 | } | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | // Lost items don't really need a version | ||
398 | version = 1; | ||
399 | } | ||
400 | |||
401 | return contents; | ||
402 | |||
403 | } | ||
404 | |||
405 | private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> libFolders, List<InventoryCollectionWithDescendents> result) | ||
406 | { | 204 | { |
407 | InventoryFolderImpl fold; | 205 | InventoryFolderImpl fold; |
206 | if (m_LibraryService == null || m_LibraryService.LibraryRootFolder == null) | ||
207 | return; | ||
208 | |||
408 | foreach (LLSDFetchInventoryDescendents f in libFolders) | 209 | foreach (LLSDFetchInventoryDescendents f in libFolders) |
409 | { | 210 | { |
410 | if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null) | 211 | if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null) |
411 | { | 212 | { |
412 | InventoryCollectionWithDescendents ret = new InventoryCollectionWithDescendents(); | 213 | InventoryCollection Collection = new InventoryCollection(); |
413 | ret.Collection = new InventoryCollection(); | ||
414 | // ret.Collection.Folders = new List<InventoryFolderBase>(); | 214 | // ret.Collection.Folders = new List<InventoryFolderBase>(); |
415 | ret.Collection.Folders = fold.RequestListOfFolders(); | 215 | Collection.Folders = fold.RequestListOfFolders(); |
416 | ret.Collection.Items = fold.RequestListOfItems(); | 216 | Collection.Items = fold.RequestListOfItems(); |
417 | ret.Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner; | 217 | Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner; |
418 | ret.Collection.FolderID = f.folder_id; | 218 | Collection.FolderID = f.folder_id; |
419 | ret.Collection.Version = fold.Version; | 219 | Collection.Version = fold.Version; |
420 | 220 | ||
421 | ret.Descendents = ret.Collection.Items.Count + ret.Collection.Folders.Count; | 221 | Collection.Descendents = Collection.Items.Count + Collection.Folders.Count; |
422 | result.Add(ret); | 222 | total_folders += Collection.Folders.Count; |
223 | total_items += Collection.Items.Count; | ||
224 | result.Add(Collection); | ||
423 | 225 | ||
424 | //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID); | 226 | //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID); |
425 | } | 227 | } |
426 | } | 228 | } |
427 | } | 229 | } |
428 | 230 | ||
429 | private List<InventoryCollectionWithDescendents> Fetch(List<LLSDFetchInventoryDescendents> fetchFolders, List<UUID> bad_folders) | 231 | private List<InventoryCollection> Fetch(List<LLSDFetchInventoryDescendents> fetchFolders, List<UUID> bad_folders, ref int total_folders, ref int total_items) |
430 | { | 232 | { |
431 | //m_log.DebugFormat( | 233 | //m_log.DebugFormat( |
432 | // "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id); | 234 | // "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id); |
433 | 235 | ||
434 | // FIXME MAYBE: We're not handling sortOrder! | 236 | // FIXME MAYBE: We're not handling sortOrder! |
435 | 237 | ||
436 | List<InventoryCollectionWithDescendents> result = new List<InventoryCollectionWithDescendents>(); | 238 | List<InventoryCollection> result = new List<InventoryCollection>(32); |
437 | List<LLSDFetchInventoryDescendents> libFolders = new List<LLSDFetchInventoryDescendents>(); | 239 | List<LLSDFetchInventoryDescendents> libFolders = new List<LLSDFetchInventoryDescendents>(32); |
438 | List<LLSDFetchInventoryDescendents> otherFolders = new List<LLSDFetchInventoryDescendents>(); | 240 | List<LLSDFetchInventoryDescendents> otherFolders = new List<LLSDFetchInventoryDescendents>(32); |
439 | HashSet<UUID> libIDs = new HashSet<UUID>(); | 241 | HashSet<UUID> libIDs = new HashSet<UUID>(); |
440 | HashSet<UUID> otherIDs = new HashSet<UUID>(); | 242 | HashSet<UUID> otherIDs = new HashSet<UUID>(); |
441 | 243 | ||
@@ -455,13 +257,12 @@ namespace OpenSim.Capabilities.Handlers | |||
455 | if(doneZeroID) | 257 | if(doneZeroID) |
456 | continue; | 258 | continue; |
457 | doneZeroID = true; | 259 | doneZeroID = true; |
458 | InventoryCollectionWithDescendents zeroColl = new InventoryCollectionWithDescendents(); | 260 | InventoryCollection Collection = new InventoryCollection(); |
459 | zeroColl.Collection = new InventoryCollection(); | 261 | Collection.OwnerID = f.owner_id; |
460 | zeroColl.Collection.OwnerID = f.owner_id; | 262 | Collection.Version = 0; |
461 | zeroColl.Collection.Version = 0; | 263 | Collection.FolderID = f.folder_id; |
462 | zeroColl.Collection.FolderID = f.folder_id; | 264 | Collection.Descendents = 0; |
463 | zeroColl.Descendents = 0; | 265 | result.Add(Collection); |
464 | result.Add(zeroColl); | ||
465 | continue; | 266 | continue; |
466 | } | 267 | } |
467 | if(dolib && f.owner_id == libOwner) | 268 | if(dolib && f.owner_id == libOwner) |
@@ -474,10 +275,13 @@ namespace OpenSim.Capabilities.Handlers | |||
474 | } | 275 | } |
475 | if(otherIDs.Contains(f.folder_id)) | 276 | if(otherIDs.Contains(f.folder_id)) |
476 | continue; | 277 | continue; |
278 | |||
477 | otherIDs.Add(f.folder_id); | 279 | otherIDs.Add(f.folder_id); |
478 | otherFolders.Add(f); | 280 | otherFolders.Add(f); |
479 | } | 281 | } |
480 | 282 | ||
283 | fetchFolders.Clear(); | ||
284 | |||
481 | if(otherFolders.Count > 0) | 285 | if(otherFolders.Count > 0) |
482 | { | 286 | { |
483 | int i = 0; | 287 | int i = 0; |
@@ -501,25 +305,33 @@ namespace OpenSim.Capabilities.Handlers | |||
501 | foreach (InventoryCollection contents in fetchedContents) | 305 | foreach (InventoryCollection contents in fetchedContents) |
502 | { | 306 | { |
503 | // Find the original request | 307 | // Find the original request |
504 | LLSDFetchInventoryDescendents freq = otherFolders[i++]; | 308 | LLSDFetchInventoryDescendents freq = otherFolders[i]; |
505 | 309 | otherFolders[i]=null; | |
506 | InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents(); | 310 | i++; |
507 | coll.Collection = contents; | ||
508 | 311 | ||
509 | if (BadFolder(freq, contents, bad_folders)) | 312 | if (BadFolder(freq, contents, bad_folders)) |
510 | continue; | 313 | continue; |
511 | 314 | ||
315 | if(!freq.fetch_folders) | ||
316 | contents.Folders.Clear(); | ||
317 | if(!freq.fetch_items) | ||
318 | contents.Items.Clear(); | ||
319 | |||
320 | contents.Descendents = contents.Items.Count + contents.Folders.Count; | ||
321 | |||
512 | // Next: link management | 322 | // Next: link management |
513 | ProcessLinks(freq, coll); | 323 | ProcessLinks(freq, contents); |
514 | 324 | ||
515 | result.Add(coll); | 325 | total_folders += contents.Folders.Count; |
326 | total_items += contents.Items.Count; | ||
327 | result.Add(contents); | ||
516 | } | 328 | } |
517 | } | 329 | } |
518 | } | 330 | } |
519 | 331 | ||
520 | if(dolib && libFolders.Count > 0) | 332 | if(dolib && libFolders.Count > 0) |
521 | { | 333 | { |
522 | AddLibraryFolders(libFolders, result); | 334 | AddLibraryFolders(libFolders, result, ref total_folders, ref total_items); |
523 | } | 335 | } |
524 | 336 | ||
525 | return result; | 337 | return result; |
@@ -552,123 +364,48 @@ namespace OpenSim.Capabilities.Handlers | |||
552 | return false; | 364 | return false; |
553 | } | 365 | } |
554 | 366 | ||
555 | private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll) | 367 | private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollection contents) |
556 | { | 368 | { |
557 | InventoryCollection contents = coll.Collection; | 369 | if (contents.Items == null || contents.Items.Count == 0) |
370 | return; | ||
558 | 371 | ||
559 | if (freq.fetch_items && contents.Items != null) | 372 | // viewers are lasy and want a copy of the linked item sent before the link to it |
373 | |||
374 | // look for item links | ||
375 | List<UUID> itemIDs = new List<UUID>(); | ||
376 | foreach (InventoryItemBase item in contents.Items) | ||
560 | { | 377 | { |
561 | // viewers are lasy and want a copy of the linked item sent before the link to it | 378 | //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); |
562 | 379 | if (item.AssetType == (int)AssetType.Link) | |
563 | // descendents must only include the links, not the linked items we add | 380 | itemIDs.Add(item.AssetID); |
564 | coll.Descendents = contents.Items.Count + contents.Folders.Count; | 381 | } |
565 | |||
566 | // look for item links | ||
567 | List<UUID> itemIDs = new List<UUID>(); | ||
568 | foreach (InventoryItemBase item in contents.Items) | ||
569 | { | ||
570 | //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); | ||
571 | if (item.AssetType == (int)AssetType.Link) | ||
572 | itemIDs.Add(item.AssetID); | ||
573 | } | ||
574 | 382 | ||
575 | // get the linked if any | 383 | // get the linked if any |
576 | if (itemIDs.Count > 0) | 384 | if (itemIDs.Count > 0) |
577 | { | 385 | { |
578 | InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); | 386 | InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); |
579 | if (linked == null) | ||
580 | { | ||
581 | // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated | ||
582 | m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one."); | ||
583 | linked = new InventoryItemBase[itemIDs.Count]; | ||
584 | int i = 0; | ||
585 | foreach (UUID id in itemIDs) | ||
586 | { | ||
587 | linked[i++] = m_InventoryService.GetItem(freq.owner_id, id); | ||
588 | } | ||
589 | } | ||
590 | 387 | ||
591 | if (linked != null) | 388 | if (linked != null) |
389 | { | ||
390 | List<InventoryItemBase> linkedItems = new List<InventoryItemBase>(); | ||
391 | // check for broken | ||
392 | foreach (InventoryItemBase linkedItem in linked) | ||
592 | { | 393 | { |
593 | List<InventoryItemBase> linkedItems = new List<InventoryItemBase>(); | 394 | // Take care of genuinely broken links where the target doesn't exist |
594 | // check for broken | 395 | // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, |
595 | foreach (InventoryItemBase linkedItem in linked) | 396 | // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles |
397 | // rather than having to keep track of every folder requested in the recursion. | ||
398 | if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) | ||
596 | { | 399 | { |
597 | // Take care of genuinely broken links where the target doesn't exist | 400 | linkedItems.Add(linkedItem); |
598 | // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, | 401 | //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); |
599 | // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles | ||
600 | // rather than having to keep track of every folder requested in the recursion. | ||
601 | if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) | ||
602 | { | ||
603 | linkedItems.Add(linkedItem); | ||
604 | //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); | ||
605 | } | ||
606 | } | 402 | } |
607 | // insert them | ||
608 | if(linkedItems.Count > 0) | ||
609 | contents.Items.InsertRange(0,linkedItems); | ||
610 | } | 403 | } |
404 | // insert them | ||
405 | if(linkedItems.Count > 0) | ||
406 | contents.Items.InsertRange(0, linkedItems); | ||
611 | } | 407 | } |
612 | } | 408 | } |
613 | } | 409 | } |
614 | |||
615 | /// <summary> | ||
616 | /// Convert an internal inventory folder object into an LLSD object. | ||
617 | /// </summary> | ||
618 | /// <param name="invFolder"></param> | ||
619 | /// <returns></returns> | ||
620 | private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder) | ||
621 | { | ||
622 | LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder(); | ||
623 | llsdFolder.folder_id = invFolder.ID; | ||
624 | llsdFolder.parent_id = invFolder.ParentID; | ||
625 | llsdFolder.name = invFolder.Name; | ||
626 | llsdFolder.type = invFolder.Type; | ||
627 | llsdFolder.version = invFolder.Version; | ||
628 | llsdFolder.preferred_type = -1; | ||
629 | |||
630 | return llsdFolder; | ||
631 | } | ||
632 | |||
633 | /// <summary> | ||
634 | /// Convert an internal inventory item object into an LLSD object. | ||
635 | /// </summary> | ||
636 | /// <param name="invItem"></param> | ||
637 | /// <returns></returns> | ||
638 | private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem) | ||
639 | { | ||
640 | LLSDInventoryItem llsdItem = new LLSDInventoryItem(); | ||
641 | llsdItem.asset_id = invItem.AssetID; | ||
642 | llsdItem.created_at = invItem.CreationDate; | ||
643 | llsdItem.desc = invItem.Description; | ||
644 | llsdItem.flags = (int)invItem.Flags; | ||
645 | llsdItem.item_id = invItem.ID; | ||
646 | llsdItem.name = invItem.Name; | ||
647 | llsdItem.parent_id = invItem.Folder; | ||
648 | llsdItem.type = invItem.AssetType; | ||
649 | llsdItem.inv_type = invItem.InvType; | ||
650 | |||
651 | llsdItem.permissions = new LLSDPermissions(); | ||
652 | llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; | ||
653 | llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions; | ||
654 | llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions; | ||
655 | llsdItem.permissions.group_id = invItem.GroupID; | ||
656 | llsdItem.permissions.group_mask = (int)invItem.GroupPermissions; | ||
657 | llsdItem.permissions.is_owner_group = invItem.GroupOwned; | ||
658 | llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions; | ||
659 | llsdItem.permissions.owner_id = invItem.Owner; | ||
660 | llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; | ||
661 | llsdItem.sale_info = new LLSDSaleInfo(); | ||
662 | llsdItem.sale_info.sale_price = invItem.SalePrice; | ||
663 | llsdItem.sale_info.sale_type = invItem.SaleType; | ||
664 | |||
665 | return llsdItem; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | class InventoryCollectionWithDescendents | ||
670 | { | ||
671 | public InventoryCollection Collection; | ||
672 | public int Descendents; | ||
673 | } | 410 | } |
674 | } | 411 | } |