aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs')
-rw-r--r--OpenSim/Capabilities/Handlers/FetchInventory/FetchInvDescHandler.cs545
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}