FetchInvDescHandler.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Linq;
  31. using System.Reflection;
  32. using System.Text;
  33. using log4net;
  34. using Nini.Config;
  35. using OpenMetaverse;
  36. using OpenMetaverse.StructuredData;
  37. using OpenSim.Framework;
  38. using OpenSim.Framework.Capabilities;
  39. using OpenSim.Region.Framework.Interfaces;
  40. using OpenSim.Framework.Servers.HttpServer;
  41. using OpenSim.Services.Interfaces;
  42. using Caps = OpenSim.Framework.Capabilities.Caps;
  43. namespace OpenSim.Capabilities.Handlers
  44. {
  45. public class FetchInvDescHandler
  46. {
  47. private static readonly ILog m_log =
  48. LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  49. private IInventoryService m_InventoryService;
  50. private ILibraryService m_LibraryService;
  51. private IScene m_Scene;
  52. // private object m_fetchLock = new Object();
  53. public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s)
  54. {
  55. m_InventoryService = invService;
  56. m_LibraryService = libService;
  57. m_Scene = s;
  58. }
  59. public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
  60. {
  61. //m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request);
  62. // nasty temporary hack here, the linden client falsely
  63. // identifies the uuid 00000000-0000-0000-0000-000000000000
  64. // as a string which breaks us
  65. //
  66. // correctly mark it as a uuid
  67. //
  68. request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
  69. // another hack <integer>1</integer> results in a
  70. // System.ArgumentException: Object type System.Int32 cannot
  71. // be converted to target type: System.Boolean
  72. //
  73. request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
  74. request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
  75. Hashtable hash = new Hashtable();
  76. try
  77. {
  78. hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
  79. }
  80. catch (LLSD.LLSDParseException e)
  81. {
  82. m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
  83. m_log.Error("Request: " + request);
  84. }
  85. ArrayList foldersrequested = (ArrayList)hash["folders"];
  86. StringBuilder tmpresponse = new StringBuilder(1024);
  87. StringBuilder tmpbadfolders = new StringBuilder(1024);
  88. List<LLSDFetchInventoryDescendents> folders = new List<LLSDFetchInventoryDescendents>();
  89. for (int i = 0; i < foldersrequested.Count; i++)
  90. {
  91. Hashtable inventoryhash = (Hashtable)foldersrequested[i];
  92. LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
  93. try
  94. {
  95. LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
  96. }
  97. catch (Exception e)
  98. {
  99. m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e);
  100. continue;
  101. }
  102. folders.Add(llsdRequest);
  103. }
  104. if (folders.Count > 0)
  105. {
  106. List<UUID> bad_folders = new List<UUID>();
  107. List<InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders);
  108. //m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count);
  109. if (invcollSet == null)
  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. string inventoryitemstr = string.Empty;
  117. foreach (InventoryCollectionWithDescendents icoll in invcollSet)
  118. {
  119. LLSDInventoryFolderContents thiscontents = contentsToLLSD(icoll.Collection, icoll.Descendents);
  120. inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(thiscontents);
  121. // inventoryitemstr = inventoryitemstr.Replace("<llsd>", "");
  122. // inventoryitemstr = inventoryitemstr.Replace("</llsd>", "");
  123. // inventoryitemstr = inventoryitemstr.Substring(6,inventoryitemstr.Length - 13);
  124. // tmpresponse.Append(inventoryitemstr);
  125. tmpresponse.Append(inventoryitemstr.Substring(6,inventoryitemstr.Length - 13));
  126. }
  127. //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders));
  128. foreach (UUID bad in bad_folders)
  129. {
  130. tmpbadfolders.Append("<map><key>folder_id</key><uuid>");
  131. tmpbadfolders.Append(bad.ToString());
  132. tmpbadfolders.Append("</uuid><key>error</key><string>Unknown</string></map>");
  133. }
  134. }
  135. StringBuilder lastresponse = new StringBuilder(1024);
  136. lastresponse.Append("<llsd>");
  137. if(tmpresponse.Length > 0)
  138. {
  139. lastresponse.Append("<map><key>folders</key><array>");
  140. lastresponse.Append(tmpresponse.ToString());
  141. lastresponse.Append("</array></map>");
  142. }
  143. else
  144. lastresponse.Append("<map><key>folders</key><array /></map>");
  145. if(tmpbadfolders.Length > 0)
  146. {
  147. lastresponse.Append("<map><key>bad_folders</key><array>");
  148. lastresponse.Append(tmpbadfolders.ToString());
  149. lastresponse.Append("</array></map>");
  150. }
  151. lastresponse.Append("</llsd>");
  152. return lastresponse.ToString();
  153. }
  154. /// <summary>
  155. /// Construct an LLSD reply packet to a CAPS inventory request
  156. /// </summary>
  157. /// <param name="invFetch"></param>
  158. /// <returns></returns>
  159. private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
  160. {
  161. LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
  162. LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
  163. contents.agent_id = invFetch.owner_id;
  164. contents.owner_id = invFetch.owner_id;
  165. contents.folder_id = invFetch.folder_id;
  166. reply.folders.Array.Add(contents);
  167. InventoryCollection inv = new InventoryCollection();
  168. inv.Folders = new List<InventoryFolderBase>();
  169. inv.Items = new List<InventoryItemBase>();
  170. int version = 0;
  171. int descendents = 0;
  172. #pragma warning disable 0612
  173. inv = Fetch(
  174. invFetch.owner_id, invFetch.folder_id, invFetch.owner_id,
  175. invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents);
  176. #pragma warning restore 0612
  177. if (inv != null && inv.Folders != null)
  178. {
  179. foreach (InventoryFolderBase invFolder in inv.Folders)
  180. {
  181. contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
  182. }
  183. descendents += inv.Folders.Count;
  184. }
  185. if (inv != null && inv.Items != null)
  186. {
  187. foreach (InventoryItemBase invItem in inv.Items)
  188. {
  189. contents.items.Array.Add(ConvertInventoryItem(invItem));
  190. }
  191. }
  192. contents.descendents = descendents;
  193. contents.version = version;
  194. //m_log.DebugFormat(
  195. // "[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}",
  196. // invFetch.folder_id,
  197. // invFetch.fetch_items,
  198. // invFetch.fetch_folders,
  199. // contents.items.Array.Count,
  200. // contents.categories.Array.Count,
  201. // invFetch.owner_id);
  202. return reply;
  203. }
  204. private LLSDInventoryFolderContents contentsToLLSD(InventoryCollection inv, int descendents)
  205. {
  206. LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
  207. contents.agent_id = inv.OwnerID;
  208. contents.owner_id = inv.OwnerID;
  209. contents.folder_id = inv.FolderID;
  210. if (inv.Folders != null)
  211. {
  212. foreach (InventoryFolderBase invFolder in inv.Folders)
  213. {
  214. contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
  215. }
  216. }
  217. if (inv.Items != null)
  218. {
  219. foreach (InventoryItemBase invItem in inv.Items)
  220. {
  221. contents.items.Array.Add(ConvertInventoryItem(invItem));
  222. }
  223. }
  224. contents.descendents = descendents;
  225. contents.version = inv.Version;
  226. return contents;
  227. }
  228. /// <summary>
  229. /// Old style. Soon to be deprecated.
  230. /// </summary>
  231. /// <param name="request"></param>
  232. /// <param name="httpRequest"></param>
  233. /// <param name="httpResponse"></param>
  234. /// <returns></returns>
  235. [Obsolete]
  236. private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
  237. {
  238. //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count);
  239. StringBuilder tmpresponse = new StringBuilder(1024);
  240. StringBuilder tmpbadfolders = new StringBuilder(1024);
  241. for (int i = 0; i < foldersrequested.Count; i++)
  242. {
  243. string inventoryitemstr = "";
  244. Hashtable inventoryhash = (Hashtable)foldersrequested[i];
  245. LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
  246. try
  247. {
  248. LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
  249. }
  250. catch (Exception e)
  251. {
  252. m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e);
  253. }
  254. LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
  255. if (null == reply)
  256. {
  257. tmpbadfolders.Append("<map><key>folder_id</key><uuid>");
  258. tmpbadfolders.Append(llsdRequest.folder_id.ToString());
  259. tmpbadfolders.Append("</uuid><key>error</key><string>Unknown</string></map>");
  260. }
  261. else
  262. {
  263. inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
  264. inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
  265. inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
  266. }
  267. tmpresponse.Append(inventoryitemstr);
  268. }
  269. StringBuilder lastresponse = new StringBuilder(1024);
  270. lastresponse.Append("<llsd>");
  271. if(tmpresponse.Length > 0)
  272. {
  273. lastresponse.Append("<map><key>folders</key><array>");
  274. lastresponse.Append(tmpresponse.ToString());
  275. lastresponse.Append("</array></map>");
  276. }
  277. else
  278. lastresponse.Append("<map><key>folders</key><array /></map>");
  279. if(tmpbadfolders.Length > 0)
  280. {
  281. lastresponse.Append("<map><key>bad_folders</key><array>");
  282. lastresponse.Append(tmpbadfolders.ToString());
  283. lastresponse.Append("</array></map>");
  284. }
  285. lastresponse.Append("</llsd>");
  286. return lastresponse.ToString();
  287. }
  288. /// <summary>
  289. /// Handle the caps inventory descendents fetch.
  290. /// </summary>
  291. /// <param name="agentID"></param>
  292. /// <param name="folderID"></param>
  293. /// <param name="ownerID"></param>
  294. /// <param name="fetchFolders"></param>
  295. /// <param name="fetchItems"></param>
  296. /// <param name="sortOrder"></param>
  297. /// <param name="version"></param>
  298. /// <returns>An empty InventoryCollection if the inventory look up failed</returns>
  299. [Obsolete]
  300. private InventoryCollection Fetch(
  301. UUID agentID, UUID folderID, UUID ownerID,
  302. bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents)
  303. {
  304. //m_log.DebugFormat(
  305. // "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
  306. // fetchFolders, fetchItems, folderID, agentID);
  307. // FIXME MAYBE: We're not handling sortOrder!
  308. version = 0;
  309. descendents = 0;
  310. InventoryFolderImpl fold;
  311. if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner)
  312. {
  313. if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null)
  314. {
  315. InventoryCollection ret = new InventoryCollection();
  316. ret.Folders = new List<InventoryFolderBase>();
  317. ret.Items = fold.RequestListOfItems();
  318. descendents = ret.Folders.Count + ret.Items.Count;
  319. return ret;
  320. }
  321. }
  322. InventoryCollection contents = new InventoryCollection();
  323. if (folderID != UUID.Zero)
  324. {
  325. InventoryCollection fetchedContents = m_InventoryService.GetFolderContent(agentID, folderID);
  326. if (fetchedContents == null)
  327. {
  328. m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of folder {0} for user {1}", folderID, agentID);
  329. return contents;
  330. }
  331. contents = fetchedContents;
  332. InventoryFolderBase containingFolder = m_InventoryService.GetFolder(agentID, folderID);
  333. if (containingFolder != null)
  334. {
  335. //m_log.DebugFormat(
  336. // "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}",
  337. // containingFolder.Name, containingFolder.ID, agentID);
  338. version = containingFolder.Version;
  339. if (fetchItems && containingFolder.Type != (short)FolderType.Trash)
  340. {
  341. List<InventoryItemBase> itemsToReturn = contents.Items;
  342. List<InventoryItemBase> originalItems = new List<InventoryItemBase>(itemsToReturn);
  343. // descendents must only include the links, not the linked items we add
  344. descendents = originalItems.Count;
  345. // Add target items for links in this folder before the links themselves.
  346. foreach (InventoryItemBase item in originalItems)
  347. {
  348. if (item.AssetType == (int)AssetType.Link)
  349. {
  350. InventoryItemBase linkedItem = m_InventoryService.GetItem(agentID, item.AssetID);
  351. // Take care of genuinely broken links where the target doesn't exist
  352. // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
  353. // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
  354. // rather than having to keep track of every folder requested in the recursion.
  355. if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
  356. itemsToReturn.Insert(0, linkedItem);
  357. }
  358. }
  359. }
  360. }
  361. }
  362. else
  363. {
  364. // Lost items don't really need a version
  365. version = 1;
  366. }
  367. return contents;
  368. }
  369. private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> libFolders, List<InventoryCollectionWithDescendents> result)
  370. {
  371. InventoryFolderImpl fold;
  372. foreach (LLSDFetchInventoryDescendents f in libFolders)
  373. {
  374. if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null)
  375. {
  376. InventoryCollectionWithDescendents ret = new InventoryCollectionWithDescendents();
  377. ret.Collection = new InventoryCollection();
  378. // ret.Collection.Folders = new List<InventoryFolderBase>();
  379. ret.Collection.Folders = fold.RequestListOfFolders();
  380. ret.Collection.Items = fold.RequestListOfItems();
  381. ret.Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner;
  382. ret.Collection.FolderID = f.folder_id;
  383. ret.Collection.Version = fold.Version;
  384. ret.Descendents = ret.Collection.Items.Count + ret.Collection.Folders.Count;
  385. result.Add(ret);
  386. //m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID);
  387. }
  388. }
  389. }
  390. private List<InventoryCollectionWithDescendents> Fetch(List<LLSDFetchInventoryDescendents> fetchFolders, List<UUID> bad_folders)
  391. {
  392. //m_log.DebugFormat(
  393. // "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id);
  394. // FIXME MAYBE: We're not handling sortOrder!
  395. List<InventoryCollectionWithDescendents> result = new List<InventoryCollectionWithDescendents>();
  396. if(fetchFolders.Count <= 0)
  397. return result;
  398. List<LLSDFetchInventoryDescendents> libFolders = new List<LLSDFetchInventoryDescendents>();
  399. List<LLSDFetchInventoryDescendents> otherFolders = new List<LLSDFetchInventoryDescendents>();
  400. HashSet<UUID> libIDs = new HashSet<UUID>();
  401. HashSet<UUID> otherIDs = new HashSet<UUID>();
  402. bool dolib = (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null);
  403. UUID libOwner = UUID.Zero;
  404. if(dolib)
  405. libOwner = m_LibraryService.LibraryRootFolder.Owner;
  406. // Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense
  407. // and can kill the sim (all root folders have parent_id Zero)
  408. // send something.
  409. foreach(LLSDFetchInventoryDescendents f in fetchFolders)
  410. {
  411. if (f.folder_id == UUID.Zero)
  412. {
  413. InventoryCollectionWithDescendents zeroColl = new InventoryCollectionWithDescendents();
  414. zeroColl.Collection = new InventoryCollection();
  415. zeroColl.Collection.OwnerID = f.owner_id;
  416. zeroColl.Collection.Version = 0;
  417. zeroColl.Collection.FolderID = f.folder_id;
  418. zeroColl.Descendents = 0;
  419. result.Add(zeroColl);
  420. continue;
  421. }
  422. if(dolib && f.owner_id == libOwner)
  423. {
  424. if(libIDs.Contains(f.folder_id))
  425. continue;
  426. libIDs.Add(f.folder_id);
  427. libFolders.Add(f);
  428. continue;
  429. }
  430. if(otherIDs.Contains(f.folder_id))
  431. continue;
  432. otherIDs.Add(f.folder_id);
  433. otherFolders.Add(f);
  434. }
  435. if(otherFolders.Count > 0)
  436. {
  437. UUID[] fids = new UUID[otherFolders.Count];
  438. int i = 0;
  439. foreach (LLSDFetchInventoryDescendents f in otherFolders)
  440. fids[i++] = f.folder_id;
  441. //m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids));
  442. InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(otherFolders[0].owner_id, fids);
  443. if (fetchedContents == null)
  444. return null;
  445. if (fetchedContents.Length == 0)
  446. {
  447. foreach (LLSDFetchInventoryDescendents freq in otherFolders)
  448. BadFolder(freq, null, bad_folders);
  449. }
  450. else
  451. {
  452. i = 0;
  453. // Do some post-processing. May need to fetch more from inv server for links
  454. foreach (InventoryCollection contents in fetchedContents)
  455. {
  456. // Find the original request
  457. LLSDFetchInventoryDescendents freq = otherFolders[i++];
  458. InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents();
  459. coll.Collection = contents;
  460. if (BadFolder(freq, contents, bad_folders))
  461. continue;
  462. // Next: link management
  463. ProcessLinks(freq, coll);
  464. result.Add(coll);
  465. }
  466. }
  467. }
  468. if(dolib && libFolders.Count > 0)
  469. {
  470. AddLibraryFolders(libFolders, result);
  471. }
  472. return result;
  473. }
  474. private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List<UUID> bad_folders)
  475. {
  476. bool bad = false;
  477. if (contents == null)
  478. {
  479. bad_folders.Add(freq.folder_id);
  480. bad = true;
  481. }
  482. // The inventory server isn't sending FolderID in the collection...
  483. // Must fetch it individually
  484. else if (contents.FolderID == UUID.Zero)
  485. {
  486. InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id);
  487. if (containingFolder != null)
  488. {
  489. contents.FolderID = containingFolder.ID;
  490. contents.OwnerID = containingFolder.Owner;
  491. contents.Version = containingFolder.Version;
  492. }
  493. else
  494. {
  495. m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id);
  496. bad_folders.Add(freq.folder_id);
  497. bad = true;
  498. }
  499. }
  500. return bad;
  501. }
  502. private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll)
  503. {
  504. InventoryCollection contents = coll.Collection;
  505. if (freq.fetch_items && contents.Items != null)
  506. {
  507. // viewers are lasy and want a copy of the linked item sent before the link to it
  508. // descendents must only include the links, not the linked items we add
  509. coll.Descendents = contents.Items.Count + contents.Folders.Count;
  510. // look for item links
  511. List<UUID> itemIDs = new List<UUID>();
  512. foreach (InventoryItemBase item in contents.Items)
  513. {
  514. //m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType);
  515. if (item.AssetType == (int)AssetType.Link)
  516. itemIDs.Add(item.AssetID);
  517. }
  518. // get the linked if any
  519. if (itemIDs.Count > 0)
  520. {
  521. InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray());
  522. if (linked == null)
  523. {
  524. // OMG!!! One by one!!! This is fallback code, in case the backend isn't updated
  525. m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one.");
  526. linked = new InventoryItemBase[itemIDs.Count];
  527. int i = 0;
  528. foreach (UUID id in itemIDs)
  529. {
  530. linked[i++] = m_InventoryService.GetItem(freq.owner_id, id);
  531. }
  532. }
  533. if (linked != null)
  534. {
  535. List<InventoryItemBase> linkedItems = new List<InventoryItemBase>();
  536. // check for broken
  537. foreach (InventoryItemBase linkedItem in linked)
  538. {
  539. // Take care of genuinely broken links where the target doesn't exist
  540. // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
  541. // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
  542. // rather than having to keep track of every folder requested in the recursion.
  543. if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
  544. {
  545. linkedItems.Add(linkedItem);
  546. //m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder);
  547. }
  548. }
  549. // insert them
  550. if(linkedItems.Count > 0)
  551. contents.Items.InsertRange(0,linkedItems);
  552. }
  553. }
  554. }
  555. }
  556. /// <summary>
  557. /// Convert an internal inventory folder object into an LLSD object.
  558. /// </summary>
  559. /// <param name="invFolder"></param>
  560. /// <returns></returns>
  561. private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
  562. {
  563. LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
  564. llsdFolder.folder_id = invFolder.ID;
  565. llsdFolder.parent_id = invFolder.ParentID;
  566. llsdFolder.name = invFolder.Name;
  567. llsdFolder.type = invFolder.Type;
  568. llsdFolder.preferred_type = -1;
  569. return llsdFolder;
  570. }
  571. /// <summary>
  572. /// Convert an internal inventory item object into an LLSD object.
  573. /// </summary>
  574. /// <param name="invItem"></param>
  575. /// <returns></returns>
  576. private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
  577. {
  578. LLSDInventoryItem llsdItem = new LLSDInventoryItem();
  579. llsdItem.asset_id = invItem.AssetID;
  580. llsdItem.created_at = invItem.CreationDate;
  581. llsdItem.desc = invItem.Description;
  582. llsdItem.flags = (int)invItem.Flags;
  583. llsdItem.item_id = invItem.ID;
  584. llsdItem.name = invItem.Name;
  585. llsdItem.parent_id = invItem.Folder;
  586. llsdItem.type = invItem.AssetType;
  587. llsdItem.inv_type = invItem.InvType;
  588. llsdItem.permissions = new LLSDPermissions();
  589. llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
  590. llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
  591. llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
  592. llsdItem.permissions.group_id = invItem.GroupID;
  593. llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
  594. llsdItem.permissions.is_owner_group = invItem.GroupOwned;
  595. llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
  596. llsdItem.permissions.owner_id = invItem.Owner;
  597. llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
  598. llsdItem.sale_info = new LLSDSaleInfo();
  599. llsdItem.sale_info.sale_price = invItem.SalePrice;
  600. llsdItem.sale_info.sale_type = invItem.SaleType;
  601. return llsdItem;
  602. }
  603. }
  604. class InventoryCollectionWithDescendents
  605. {
  606. public InventoryCollection Collection;
  607. public int Descendents;
  608. }
  609. }