aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Capabilities/Handlers/FetchInventory
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Capabilities/Handlers/FetchInventory')
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs496
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs70
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs5
3 files changed, 188 insertions, 383 deletions
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs
index 53ed115..427a310 100644
--- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs
@@ -30,6 +30,7 @@ using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Linq; 31using System.Linq;
32using System.Reflection; 32using System.Reflection;
33using System.Text;
33using log4net; 34using log4net;
34using Nini.Config; 35using Nini.Config;
35using OpenMetaverse; 36using OpenMetaverse;
@@ -60,26 +61,10 @@ namespace OpenSim.Capabilities.Handlers
60 m_Scene = s; 61 m_Scene = s;
61 } 62 }
62 63
63
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 // nasty temporary hack here, the linden client falsely
69 // identifies the uuid 00000000-0000-0000-0000-000000000000
70 // as a string which breaks us
71 //
72 // correctly mark it as a uuid
73 //
74 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
75
76 // another hack <integer>1</integer> results in a
77 // System.ArgumentException: Object type System.Int32 cannot
78 // be converted to target type: System.Boolean
79 //
80 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
81 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
82
83 Hashtable hash = new Hashtable(); 68 Hashtable hash = new Hashtable();
84 try 69 try
85 { 70 {
@@ -92,10 +77,7 @@ namespace OpenSim.Capabilities.Handlers
92 } 77 }
93 78
94 ArrayList foldersrequested = (ArrayList)hash["folders"]; 79 ArrayList foldersrequested = (ArrayList)hash["folders"];
95 80
96 string response = "";
97 string bad_folders_response = "";
98
99 List<LLSDFetchInventoryDescendents> folders = new List<LLSDFetchInventoryDescendents>(); 81 List<LLSDFetchInventoryDescendents> folders = new List<LLSDFetchInventoryDescendents>();
100 for (int i = 0; i < foldersrequested.Count; i++) 82 for (int i = 0; i < foldersrequested.Count; i++)
101 { 83 {
@@ -113,72 +95,56 @@ namespace OpenSim.Capabilities.Handlers
113 continue; 95 continue;
114 } 96 }
115 97
116 // Filter duplicate folder ids that bad viewers may send 98 folders.Add(llsdRequest);
117 if (folders.Find(f => f.folder_id == llsdRequest.folder_id) == null)
118 folders.Add(llsdRequest);
119
120 } 99 }
121 100
122 if (folders.Count > 0) 101 if(folders.Count == 0)
123 { 102 return "<llsd><map><key>folders</key><array /></map></llsd>";
124 List<UUID> bad_folders = new List<UUID>();
125 List<InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders);
126 //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count);
127
128 if (invcollSet == null)
129 {
130 m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol.");
131#pragma warning disable 0612
132 return FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse);
133#pragma warning restore 0612
134 }
135
136 string inventoryitemstr = string.Empty;
137 foreach (InventoryCollectionWithDescendents icoll in invcollSet)
138 {
139 LLSDInventoryDescendents reply = ToLLSD(icoll.Collection, icoll.Descendents);
140 103
141 inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply); 104 List<UUID> bad_folders = new List<UUID>();
142 inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
143 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
144 105
145 response += inventoryitemstr; 106 List<InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders);
146 } 107 //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count);
147 108
148 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders)); 109 if (invcollSet == null)
149 foreach (UUID bad in bad_folders) 110 {
150 bad_folders_response += "<uuid>" + bad + "</uuid>"; 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
151 } 115 }
152 116
153 if (response.Length == 0) 117 StringBuilder lastresponse = new StringBuilder(1024);
118 lastresponse.Append("<llsd>");
119
120 if(invcollSet.Count > 0)
154 { 121 {
155 /* Viewers expect a bad_folders array when not available */ 122 lastresponse.Append("<map><key>folders</key><array>");
156 if (bad_folders_response.Length != 0) 123 foreach (InventoryCollectionWithDescendents icoll in invcollSet)
157 {
158 response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
159 }
160 else
161 { 124 {
162 response = "<llsd><map><key>folders</key><array /></map></llsd>"; 125 LLSDInventoryFolderContents thiscontents = contentsToLLSD(icoll.Collection, icoll.Descendents);
126 lastresponse.Append(LLSDHelpers.SerialiseLLSDReplyNoHeader(thiscontents));
163 } 127 }
128 lastresponse.Append("</array></map>");
164 } 129 }
165 else 130 else
131 lastresponse.Append("<map><key>folders</key><array /></map>");
132
133 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders));
134 if(bad_folders.Count > 0)
166 { 135 {
167 if (bad_folders_response.Length != 0) 136 lastresponse.Append("<map><key>bad_folders</key><array>");
168 { 137 foreach (UUID bad in bad_folders)
169 response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
170 }
171 else
172 { 138 {
173 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>"; 139 lastresponse.Append("<map><key>folder_id</key><uuid>");
140 lastresponse.Append(bad.ToString());
141 lastresponse.Append("</uuid><key>error</key><string>Unknown</string></map>");
174 } 142 }
143 lastresponse.Append("</array></map>");
175 } 144 }
145 lastresponse.Append("</llsd>");
176 146
177 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request for {0} folders. Item count {1}", folders.Count, item_count); 147 return lastresponse.ToString();;
178 //m_log.Debug("[WEB FETCH INV DESC HANDLER] " + response);
179
180 return response;
181
182 } 148 }
183 149
184 /// <summary> 150 /// <summary>
@@ -240,24 +206,19 @@ namespace OpenSim.Capabilities.Handlers
240 return reply; 206 return reply;
241 } 207 }
242 208
243 private LLSDInventoryDescendents ToLLSD(InventoryCollection inv, int descendents) 209 private LLSDInventoryFolderContents contentsToLLSD(InventoryCollection inv, int descendents)
244 { 210 {
245 LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
246 LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents(); 211 LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
247 contents.agent_id = inv.OwnerID; 212 contents.agent_id = inv.OwnerID;
248 contents.owner_id = inv.OwnerID; 213 contents.owner_id = inv.OwnerID;
249 contents.folder_id = inv.FolderID; 214 contents.folder_id = inv.FolderID;
250 215
251 reply.folders.Array.Add(contents);
252
253 if (inv.Folders != null) 216 if (inv.Folders != null)
254 { 217 {
255 foreach (InventoryFolderBase invFolder in inv.Folders) 218 foreach (InventoryFolderBase invFolder in inv.Folders)
256 { 219 {
257 contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); 220 contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
258 } 221 }
259
260 descendents += inv.Folders.Count;
261 } 222 }
262 223
263 if (inv.Items != null) 224 if (inv.Items != null)
@@ -271,7 +232,7 @@ namespace OpenSim.Capabilities.Handlers
271 contents.descendents = descendents; 232 contents.descendents = descendents;
272 contents.version = inv.Version; 233 contents.version = inv.Version;
273 234
274 return reply; 235 return contents;
275 } 236 }
276 /// <summary> 237 /// <summary>
277 /// Old style. Soon to be deprecated. 238 /// Old style. Soon to be deprecated.
@@ -285,8 +246,8 @@ namespace OpenSim.Capabilities.Handlers
285 { 246 {
286 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count); 247 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count);
287 248
288 string response = ""; 249 StringBuilder tmpresponse = new StringBuilder(1024);
289 string bad_folders_response = ""; 250 StringBuilder tmpbadfolders = new StringBuilder(1024);
290 251
291 for (int i = 0; i < foldersrequested.Count; i++) 252 for (int i = 0; i < foldersrequested.Count; i++)
292 { 253 {
@@ -308,7 +269,9 @@ namespace OpenSim.Capabilities.Handlers
308 269
309 if (null == reply) 270 if (null == reply)
310 { 271 {
311 bad_folders_response += "<uuid>" + llsdRequest.folder_id.ToString() + "</uuid>"; 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>");
312 } 275 }
313 else 276 else
314 { 277 {
@@ -317,39 +280,29 @@ namespace OpenSim.Capabilities.Handlers
317 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", ""); 280 inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
318 } 281 }
319 282
320 response += inventoryitemstr; 283 tmpresponse.Append(inventoryitemstr);
321 } 284 }
322 285
323 if (response.Length == 0) 286 StringBuilder lastresponse = new StringBuilder(1024);
287 lastresponse.Append("<llsd>");
288 if(tmpresponse.Length > 0)
324 { 289 {
325 /* Viewers expect a bad_folders array when not available */ 290 lastresponse.Append("<map><key>folders</key><array>");
326 if (bad_folders_response.Length != 0) 291 lastresponse.Append(tmpresponse.ToString());
327 { 292 lastresponse.Append("</array></map>");
328 response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
329 }
330 else
331 {
332 response = "<llsd><map><key>folders</key><array /></map></llsd>";
333 }
334 } 293 }
335 else 294 else
295 lastresponse.Append("<map><key>folders</key><array /></map>");
296
297 if(tmpbadfolders.Length > 0)
336 { 298 {
337 if (bad_folders_response.Length != 0) 299 lastresponse.Append("<map><key>bad_folders</key><array>");
338 { 300 lastresponse.Append(tmpbadfolders.ToString());
339 response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>"; 301 lastresponse.Append("</array></map>");
340 }
341 else
342 {
343 response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
344 }
345 } 302 }
303 lastresponse.Append("</llsd>");
346 304
347 // m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request"); 305 return lastresponse.ToString();
348 //m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response);
349
350 return response;
351
352 // }
353 } 306 }
354 307
355 /// <summary> 308 /// <summary>
@@ -436,108 +389,7 @@ namespace OpenSim.Capabilities.Handlers
436 itemsToReturn.Insert(0, linkedItem); 389 itemsToReturn.Insert(0, linkedItem);
437 } 390 }
438 } 391 }
439
440 // Now scan for folder links and insert the items they target and those links at the head of the return data
441
442/* dont send contents of LinkFolders.
443from docs seems this was never a spec
444
445 foreach (InventoryItemBase item in originalItems)
446 {
447 if (item.AssetType == (int)AssetType.LinkFolder)
448 {
449 InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID);
450 List<InventoryItemBase> links = linkedFolderContents.Items;
451
452 itemsToReturn.InsertRange(0, links);
453
454 foreach (InventoryItemBase link in linkedFolderContents.Items)
455 {
456 // Take care of genuinely broken links where the target doesn't exist
457 // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
458 // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
459 // rather than having to keep track of every folder requested in the recursion.
460 if (link != null)
461 {
462// m_log.DebugFormat(
463// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}",
464// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name);
465
466 InventoryItemBase linkedItem
467 = m_InventoryService.GetItem(new InventoryItemBase(link.AssetID));
468
469 if (linkedItem != null)
470 itemsToReturn.Insert(0, linkedItem);
471 }
472 }
473 }
474 }
475*/
476 } 392 }
477
478// foreach (InventoryItemBase item in contents.Items)
479// {
480// m_log.DebugFormat(
481// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}",
482// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID);
483// }
484
485 // =====
486
487//
488// foreach (InventoryItemBase linkedItem in linkedItemsToAdd)
489// {
490// m_log.DebugFormat(
491// "[WEB FETCH INV DESC HANDLER]: Inserted linked item {0} for link in folder {1} for agent {2}",
492// linkedItem.Name, folderID, agentID);
493//
494// contents.Items.Add(linkedItem);
495// }
496//
497// // If the folder requested contains links, then we need to send those folders first, otherwise the links
498// // will be broken in the viewer.
499// HashSet<UUID> linkedItemFolderIdsToSend = new HashSet<UUID>();
500// foreach (InventoryItemBase item in contents.Items)
501// {
502// if (item.AssetType == (int)AssetType.Link)
503// {
504// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID));
505//
506// // Take care of genuinely broken links where the target doesn't exist
507// // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
508// // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
509// // rather than having to keep track of every folder requested in the recursion.
510// if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
511// {
512// // We don't need to send the folder if source and destination of the link are in the same
513// // folder.
514// if (linkedItem.Folder != containingFolder.ID)
515// linkedItemFolderIdsToSend.Add(linkedItem.Folder);
516// }
517// }
518// }
519//
520// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
521// {
522// m_log.DebugFormat(
523// "[WEB FETCH INV DESC HANDLER]: Recursively fetching folder {0} linked by item in folder {1} for agent {2}",
524// linkedItemFolderId, folderID, agentID);
525//
526// int dummyVersion;
527// InventoryCollection linkedCollection
528// = Fetch(
529// agentID, linkedItemFolderId, ownerID, fetchFolders, fetchItems, sortOrder, out dummyVersion);
530//
531// InventoryFolderBase linkedFolder = new InventoryFolderBase(linkedItemFolderId);
532// linkedFolder.Owner = agentID;
533// linkedFolder = m_InventoryService.GetFolder(linkedFolder);
534//
535//// contents.Folders.AddRange(linkedCollection.Folders);
536//
537// contents.Folders.Add(linkedFolder);
538// contents.Items.AddRange(linkedCollection.Items);
539// }
540// }
541 } 393 }
542 } 394 }
543 else 395 else
@@ -550,33 +402,26 @@ from docs seems this was never a spec
550 402
551 } 403 }
552 404
553 private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> fetchFolders, List<InventoryCollectionWithDescendents> result) 405 private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> libFolders, List<InventoryCollectionWithDescendents> result)
554 { 406 {
555 InventoryFolderImpl fold; 407 InventoryFolderImpl fold;
556 if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null) 408 foreach (LLSDFetchInventoryDescendents f in libFolders)
557 { 409 {
558 List<LLSDFetchInventoryDescendents> libfolders = fetchFolders.FindAll(f => f.owner_id == m_LibraryService.LibraryRootFolder.Owner); 410 if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null)
559 fetchFolders.RemoveAll(f => libfolders.Contains(f));
560
561 //m_log.DebugFormat("[XXX]: Found {0} library folders in request", libfolders.Count);
562
563 foreach (LLSDFetchInventoryDescendents f in libfolders)
564 { 411 {
565 if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null) 412 InventoryCollectionWithDescendents ret = new InventoryCollectionWithDescendents();
566 { 413 ret.Collection = new InventoryCollection();
567 InventoryCollectionWithDescendents ret = new InventoryCollectionWithDescendents(); 414// ret.Collection.Folders = new List<InventoryFolderBase>();
568 ret.Collection = new InventoryCollection(); 415 ret.Collection.Folders = fold.RequestListOfFolders();
569 ret.Collection.Folders = new List<InventoryFolderBase>(); 416 ret.Collection.Items = fold.RequestListOfItems();
570 ret.Collection.Items = fold.RequestListOfItems(); 417 ret.Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner;
571 ret.Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner; 418 ret.Collection.FolderID = f.folder_id;
572 ret.Collection.FolderID = f.folder_id; 419 ret.Collection.Version = fold.Version;
573 ret.Collection.Version = fold.Version; 420
574 421 ret.Descendents = ret.Collection.Items.Count + ret.Collection.Folders.Count;
575 ret.Descendents = ret.Collection.Items.Count; 422 result.Add(ret);
576 result.Add(ret); 423
577 424 //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID);
578 //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID);
579 }
580 } 425 }
581 } 426 }
582 } 427 }
@@ -589,117 +434,122 @@ from docs seems this was never a spec
589 // FIXME MAYBE: We're not handling sortOrder! 434 // FIXME MAYBE: We're not handling sortOrder!
590 435
591 List<InventoryCollectionWithDescendents> result = new List<InventoryCollectionWithDescendents>(); 436 List<InventoryCollectionWithDescendents> result = new List<InventoryCollectionWithDescendents>();
437 List<LLSDFetchInventoryDescendents> libFolders = new List<LLSDFetchInventoryDescendents>();
438 List<LLSDFetchInventoryDescendents> otherFolders = new List<LLSDFetchInventoryDescendents>();
439 HashSet<UUID> libIDs = new HashSet<UUID>();
440 HashSet<UUID> otherIDs = new HashSet<UUID>();
592 441
593 AddLibraryFolders(fetchFolders, result); 442 bool dolib = (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null);
443 UUID libOwner = UUID.Zero;
444 if(dolib)
445 libOwner = m_LibraryService.LibraryRootFolder.Owner;
594 446
595 // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense 447 // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense
596 // and can kill the sim (all root folders have parent_id Zero) 448 // and can kill the sim (all root folders have parent_id Zero)
597 LLSDFetchInventoryDescendents zero = fetchFolders.Find(f => f.folder_id == UUID.Zero); 449 // send something.
598 if (zero != null) 450 bool doneZeroID = false;
451 foreach(LLSDFetchInventoryDescendents f in fetchFolders)
599 { 452 {
600 fetchFolders.Remove(zero); 453 if (f.folder_id == UUID.Zero)
601 BadFolder(zero, null, bad_folders); 454 {
455 if(doneZeroID)
456 continue;
457 doneZeroID = true;
458 InventoryCollectionWithDescendents zeroColl = new InventoryCollectionWithDescendents();
459 zeroColl.Collection = new InventoryCollection();
460 zeroColl.Collection.OwnerID = f.owner_id;
461 zeroColl.Collection.Version = 0;
462 zeroColl.Collection.FolderID = f.folder_id;
463 zeroColl.Descendents = 0;
464 result.Add(zeroColl);
465 continue;
466 }
467 if(dolib && f.owner_id == libOwner)
468 {
469 if(libIDs.Contains(f.folder_id))
470 continue;
471 libIDs.Add(f.folder_id);
472 libFolders.Add(f);
473 continue;
474 }
475 if(otherIDs.Contains(f.folder_id))
476 continue;
477 otherIDs.Add(f.folder_id);
478 otherFolders.Add(f);
602 } 479 }
603 480
604 if (fetchFolders.Count > 0) 481 if(otherFolders.Count > 0)
605 { 482 {
606 UUID[] fids = new UUID[fetchFolders.Count];
607 int i = 0; 483 int i = 0;
608 foreach (LLSDFetchInventoryDescendents f in fetchFolders)
609 fids[i++] = f.folder_id;
610 484
611 //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids)); 485 //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids));
612 486
613 InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(fetchFolders[0].owner_id, fids); 487 InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(otherFolders[0].owner_id, otherIDs.ToArray());
614 488
615 if (fetchedContents == null || (fetchedContents != null && fetchedContents.Length == 0)) 489 if (fetchedContents == null)
490 return null;
491
492 if (fetchedContents.Length == 0)
616 { 493 {
617 m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of multiple folders for user {0}", fetchFolders[0].owner_id); 494 foreach (LLSDFetchInventoryDescendents freq in otherFolders)
618 foreach (LLSDFetchInventoryDescendents freq in fetchFolders)
619 BadFolder(freq, null, bad_folders); 495 BadFolder(freq, null, bad_folders);
620 return null;
621 } 496 }
622 497 else
623 i = 0;
624 // Do some post-processing. May need to fetch more from inv server for links
625 foreach (InventoryCollection contents in fetchedContents)
626 { 498 {
627 // Find the original request 499 i = 0;
628 LLSDFetchInventoryDescendents freq = fetchFolders[i++]; 500 // Do some post-processing. May need to fetch more from inv server for links
501 foreach (InventoryCollection contents in fetchedContents)
502 {
503 // Find the original request
504 LLSDFetchInventoryDescendents freq = otherFolders[i++];
629 505
630 InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents(); 506 InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents();
631 coll.Collection = contents; 507 coll.Collection = contents;
632 508
633 if (BadFolder(freq, contents, bad_folders)) 509 if (BadFolder(freq, contents, bad_folders))
634 continue; 510 continue;
635 511
636 // Next: link management 512 // Next: link management
637 ProcessLinks(freq, coll); 513 ProcessLinks(freq, coll);
638 514
639 result.Add(coll); 515 result.Add(coll);
516 }
640 } 517 }
641 } 518 }
642 519
520 if(dolib && libFolders.Count > 0)
521 {
522 AddLibraryFolders(libFolders, result);
523 }
524
643 return result; 525 return result;
644 } 526 }
645 527
646 private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List<UUID> bad_folders) 528 private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List<UUID> bad_folders)
647 { 529 {
648 bool bad = false;
649 if (contents == null) 530 if (contents == null)
650 { 531 {
651 bad_folders.Add(freq.folder_id); 532 bad_folders.Add(freq.folder_id);
652 bad = true; 533 return true;
653 } 534 }
654 535
655 // The inventory server isn't sending FolderID in the collection... 536 // The inventory server isn't sending FolderID in the collection...
656 // Must fetch it individually 537 // Must fetch it individually
657 else if (contents.FolderID == UUID.Zero) 538 if (contents.FolderID == UUID.Zero)
658 { 539 {
659 InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id); 540 InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id);
660 541 if (containingFolder == null)
661 if (containingFolder != null)
662 {
663 contents.FolderID = containingFolder.ID;
664 contents.OwnerID = containingFolder.Owner;
665 contents.Version = containingFolder.Version;
666 }
667 else
668 { 542 {
669 // Was it really a request for folder Zero? 543 m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id);
670 // This is an overkill, but Firestorm really asks for folder Zero. 544 bad_folders.Add(freq.folder_id);
671 // I'm leaving the code here for the time being, but commented. 545 return true;
672 if (freq.folder_id == UUID.Zero)
673 {
674 //coll.Collection.OwnerID = freq.owner_id;
675 //coll.Collection.FolderID = contents.FolderID;
676 //containingFolder = m_InventoryService.GetRootFolder(freq.owner_id);
677 //if (containingFolder != null)
678 //{
679 // m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Request for parent of folder {0}", containingFolder.ID);
680 // coll.Collection.Folders.Clear();
681 // coll.Collection.Folders.Add(containingFolder);
682 // if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null)
683 // {
684 // InventoryFolderBase lib = new InventoryFolderBase(m_LibraryService.LibraryRootFolder.ID, m_LibraryService.LibraryRootFolder.Owner);
685 // lib.Name = m_LibraryService.LibraryRootFolder.Name;
686 // lib.Type = m_LibraryService.LibraryRootFolder.Type;
687 // lib.Version = m_LibraryService.LibraryRootFolder.Version;
688 // coll.Collection.Folders.Add(lib);
689 // }
690 // coll.Collection.Items.Clear();
691 //}
692 }
693 else
694 {
695 m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id);
696 bad_folders.Add(freq.folder_id);
697 }
698 bad = true;
699 } 546 }
547 contents.FolderID = containingFolder.ID;
548 contents.OwnerID = containingFolder.Owner;
549 contents.Version = containingFolder.Version;
700 } 550 }
701 551
702 return bad; 552 return false;
703 } 553 }
704 554
705 private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll) 555 private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll)
@@ -708,42 +558,21 @@ from docs seems this was never a spec
708 558
709 if (freq.fetch_items && contents.Items != null) 559 if (freq.fetch_items && contents.Items != null)
710 { 560 {
711 List<InventoryItemBase> itemsToReturn = contents.Items; 561 // viewers are lasy and want a copy of the linked item sent before the link to it
712 562
713 // descendents must only include the links, not the linked items we add 563 // descendents must only include the links, not the linked items we add
714 coll.Descendents = itemsToReturn.Count; 564 coll.Descendents = contents.Items.Count + contents.Folders.Count;
715 565
716 // Add target items for links in this folder before the links themselves. 566 // look for item links
717 List<UUID> itemIDs = new List<UUID>(); 567 List<UUID> itemIDs = new List<UUID>();
718 List<UUID> folderIDs = new List<UUID>(); 568 foreach (InventoryItemBase item in contents.Items)
719 foreach (InventoryItemBase item in itemsToReturn)
720 { 569 {
721 //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType); 570 //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType);
722 if (item.AssetType == (int)AssetType.Link) 571 if (item.AssetType == (int)AssetType.Link)
723 itemIDs.Add(item.AssetID); 572 itemIDs.Add(item.AssetID);
724
725// else if (item.AssetType == (int)AssetType.LinkFolder)
726// folderIDs.Add(item.AssetID);
727 }
728
729 //m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count);
730
731 // Scan for folder links and insert the items they target and those links at the head of the return data
732 if (folderIDs.Count > 0)
733 {
734 InventoryCollection[] linkedFolders = m_InventoryService.GetMultipleFoldersContent(coll.Collection.OwnerID, folderIDs.ToArray());
735 foreach (InventoryCollection linkedFolderContents in linkedFolders)
736 {
737 if (linkedFolderContents == null)
738 continue;
739
740 List<InventoryItemBase> links = linkedFolderContents.Items;
741
742 itemsToReturn.InsertRange(0, links);
743
744 }
745 } 573 }
746 574
575 // get the linked if any
747 if (itemIDs.Count > 0) 576 if (itemIDs.Count > 0)
748 { 577 {
749 InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray()); 578 InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray());
@@ -758,13 +587,11 @@ from docs seems this was never a spec
758 linked[i++] = m_InventoryService.GetItem(freq.owner_id, id); 587 linked[i++] = m_InventoryService.GetItem(freq.owner_id, id);
759 } 588 }
760 } 589 }
761 590
762 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Processing folder {0}. Existing items:", freq.folder_id);
763 //foreach (InventoryItemBase item in itemsToReturn)
764 // m_log.DebugFormat("[XXX]: {0} {1} {2}", item.Name, item.AssetType, item.Folder);
765
766 if (linked != null) 591 if (linked != null)
767 { 592 {
593 List<InventoryItemBase> linkedItems = new List<InventoryItemBase>();
594 // check for broken
768 foreach (InventoryItemBase linkedItem in linked) 595 foreach (InventoryItemBase linkedItem in linked)
769 { 596 {
770 // Take care of genuinely broken links where the target doesn't exist 597 // Take care of genuinely broken links where the target doesn't exist
@@ -773,14 +600,16 @@ from docs seems this was never a spec
773 // rather than having to keep track of every folder requested in the recursion. 600 // rather than having to keep track of every folder requested in the recursion.
774 if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) 601 if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
775 { 602 {
776 itemsToReturn.Insert(0, linkedItem); 603 linkedItems.Add(linkedItem);
777 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder); 604 //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder);
778 } 605 }
779 } 606 }
607 // insert them
608 if(linkedItems.Count > 0)
609 contents.Items.InsertRange(0,linkedItems);
780 } 610 }
781 } 611 }
782 } 612 }
783
784 } 613 }
785 614
786 /// <summary> 615 /// <summary>
@@ -795,6 +624,7 @@ from docs seems this was never a spec
795 llsdFolder.parent_id = invFolder.ParentID; 624 llsdFolder.parent_id = invFolder.ParentID;
796 llsdFolder.name = invFolder.Name; 625 llsdFolder.name = invFolder.Name;
797 llsdFolder.type = invFolder.Type; 626 llsdFolder.type = invFolder.Type;
627 llsdFolder.version = invFolder.Version;
798 llsdFolder.preferred_type = -1; 628 llsdFolder.preferred_type = -1;
799 629
800 return llsdFolder; 630 return llsdFolder;
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs
index e239a90..0d7766c 100644
--- a/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/FetchInventory2Handler.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System.Reflection; 28using System.Reflection;
29using System.Text;
29using OpenMetaverse; 30using OpenMetaverse;
30using OpenMetaverse.StructuredData; 31using OpenMetaverse.StructuredData;
31using OpenSim.Framework; 32using OpenSim.Framework;
@@ -59,9 +60,6 @@ namespace OpenSim.Capabilities.Handlers
59 OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request)); 60 OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request));
60 OSDArray itemsRequested = (OSDArray)requestmap["items"]; 61 OSDArray itemsRequested = (OSDArray)requestmap["items"];
61 62
62 string reply;
63 LLSDFetchInventory llsdReply = new LLSDFetchInventory();
64
65 UUID[] itemIDs = new UUID[itemsRequested.Count]; 63 UUID[] itemIDs = new UUID[itemsRequested.Count];
66 int i = 0; 64 int i = 0;
67 65
@@ -92,55 +90,31 @@ namespace OpenSim.Capabilities.Handlers
92 items[i++] = m_inventoryService.GetItem(UUID.Zero, id); 90 items[i++] = m_inventoryService.GetItem(UUID.Zero, id);
93 } 91 }
94 92
95 foreach (InventoryItemBase item in items) 93 StringBuilder lsl = LLSDxmlEncode.Start(4096);
94 LLSDxmlEncode.AddMap(lsl);
95
96 if(m_agentID == UUID.Zero && items.Length > 0)
97 LLSDxmlEncode.AddElem("agent_id", items[0].Owner, lsl);
98 else
99 LLSDxmlEncode.AddElem("agent_id", m_agentID, lsl);
100
101 if(items == null || items.Length == 0)
102 {
103 LLSDxmlEncode.AddEmptyArray("items", lsl);
104 }
105 else
96 { 106 {
97 if (item != null) 107 LLSDxmlEncode.AddArray("items", lsl);
108 foreach (InventoryItemBase item in items)
98 { 109 {
99 // We don't know the agent that this request belongs to so we'll use the agent id of the item 110 if (item != null)
100 // which will be the same for all items. 111 item.ToLLSDxml(lsl);
101 llsdReply.agent_id = item.Owner;
102 llsdReply.items.Array.Add(ConvertInventoryItem(item));
103 } 112 }
104 } 113 LLSDxmlEncode.AddEndArray(lsl);
105 114 }
106 reply = LLSDHelpers.SerialiseLLSDReply(llsdReply);
107 115
108 return reply; 116 LLSDxmlEncode.AddEndMap(lsl);
109 } 117 return LLSDxmlEncode.End(lsl);;
110
111 /// <summary>
112 /// Convert an internal inventory item object into an LLSD object.
113 /// </summary>
114 /// <param name="invItem"></param>
115 /// <returns></returns>
116 private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
117 {
118 LLSDInventoryItem llsdItem = new LLSDInventoryItem();
119 llsdItem.asset_id = invItem.AssetID;
120 llsdItem.created_at = invItem.CreationDate;
121 llsdItem.desc = invItem.Description;
122 llsdItem.flags = ((int)invItem.Flags) & 0xff;
123 llsdItem.item_id = invItem.ID;
124 llsdItem.name = invItem.Name;
125 llsdItem.parent_id = invItem.Folder;
126 llsdItem.type = invItem.AssetType;
127 llsdItem.inv_type = invItem.InvType;
128
129 llsdItem.permissions = new LLSDPermissions();
130 llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
131 llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
132 llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
133 llsdItem.permissions.group_id = invItem.GroupID;
134 llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
135 llsdItem.permissions.is_owner_group = invItem.GroupOwned;
136 llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
137 llsdItem.permissions.owner_id = invItem.Owner;
138 llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
139 llsdItem.sale_info = new LLSDSaleInfo();
140 llsdItem.sale_info.sale_price = invItem.SalePrice;
141 llsdItem.sale_info.sale_type = invItem.SaleType;
142
143 return llsdItem;
144 } 118 }
145 } 119 }
146} 120}
diff --git a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs
index 4143aa3..1e9a993 100644
--- a/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs
+++ b/OpenSim/Capabilities/Handlers/FetchInventory/Tests/FetchInventoryDescendents2HandlerTests.cs
@@ -267,6 +267,7 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
267 [Test] 267 [Test]
268 public void Test_005_FolderZero() 268 public void Test_005_FolderZero()
269 { 269 {
270
270 TestHelpers.InMethod(); 271 TestHelpers.InMethod();
271 272
272 Init(); 273 Init();
@@ -283,11 +284,11 @@ namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
283 284
284 Assert.That(llsdresponse != null, Is.True, "Incorrect null response"); 285 Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
285 Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response"); 286 Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response");
286 Assert.That(llsdresponse.Contains("bad_folders</key><array><uuid>00000000-0000-0000-0000-000000000000"), Is.True, "Folder Zero should be a bad folder"); 287 // we do return a answer now
288 //Assert.That(llsdresponse.Contains("bad_folders</key><array><uuid>00000000-0000-0000-0000-000000000000"), Is.True, "Folder Zero should be a bad folder");
287 289
288 Console.WriteLine(llsdresponse); 290 Console.WriteLine(llsdresponse);
289 } 291 }
290
291 } 292 }
292 293
293} \ No newline at end of file 294} \ No newline at end of file