PageRenderTime 82ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 2ms

/OpenMetaverse/Modules/InventoryManager.cs

https://bitbucket.org/VirtualReality/3rdparty-addon-modules
C# | 4807 lines | 3114 code | 580 blank | 1113 comment | 501 complexity | 3547c5ae30eec944425933a7545fecd0 MD5 | raw file
  1. /*
  2. * Copyright (c) 2006-2008, openmetaverse.org
  3. * All rights reserved.
  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. *
  8. * - Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. * - Neither the name of the openmetaverse.org nor the names
  11. * of its contributors may be used to endorse or promote products derived from
  12. * this software without specific prior written permission.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  18. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  19. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  20. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  21. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  22. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  23. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  24. * POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. using System;
  27. using System.Collections.Generic;
  28. using System.Net;
  29. using System.Text.RegularExpressions;
  30. using System.Threading;
  31. using System.Text;
  32. using System.Runtime.Serialization;
  33. using OpenMetaverse.Http;
  34. using OpenMetaverse.Messages.Linden;
  35. using OpenMetaverse.StructuredData;
  36. using OpenMetaverse.Packets;
  37. namespace OpenMetaverse
  38. {
  39. #region Enums
  40. [Flags]
  41. public enum InventorySortOrder : int
  42. {
  43. /// <summary>Sort by name</summary>
  44. ByName = 0,
  45. /// <summary>Sort by date</summary>
  46. ByDate = 1,
  47. /// <summary>Sort folders by name, regardless of whether items are
  48. /// sorted by name or date</summary>
  49. FoldersByName = 2,
  50. /// <summary>Place system folders at the top</summary>
  51. SystemFoldersToTop = 4
  52. }
  53. /// <summary>
  54. /// Possible destinations for DeRezObject request
  55. /// </summary>
  56. public enum DeRezDestination : byte
  57. {
  58. /// <summary></summary>
  59. AgentInventorySave = 0,
  60. /// <summary>Copy from in-world to agent inventory</summary>
  61. AgentInventoryCopy = 1,
  62. /// <summary>Derez to TaskInventory</summary>
  63. TaskInventory = 2,
  64. /// <summary></summary>
  65. Attachment = 3,
  66. /// <summary>Take Object</summary>
  67. AgentInventoryTake = 4,
  68. /// <summary></summary>
  69. ForceToGodInventory = 5,
  70. /// <summary>Delete Object</summary>
  71. TrashFolder = 6,
  72. /// <summary>Put an avatar attachment into agent inventory</summary>
  73. AttachmentToInventory = 7,
  74. /// <summary></summary>
  75. AttachmentExists = 8,
  76. /// <summary>Return an object back to the owner's inventory</summary>
  77. ReturnToOwner = 9,
  78. /// <summary>Return a deeded object back to the last owner's inventory</summary>
  79. ReturnToLastOwner = 10
  80. }
  81. /// <summary>
  82. /// Upper half of the Flags field for inventory items
  83. /// </summary>
  84. [Flags]
  85. public enum InventoryItemFlags : uint
  86. {
  87. None = 0,
  88. /// <summary>Indicates that the NextOwner permission will be set to the
  89. /// most restrictive set of permissions found in the object set
  90. /// (including linkset items and object inventory items) on next rez</summary>
  91. ObjectSlamPerm = 0x100,
  92. /// <summary>Indicates that the object sale information has been
  93. /// changed</summary>
  94. ObjectSlamSale = 0x1000,
  95. /// <summary>If set, and a slam bit is set, indicates BaseMask will be overwritten on Rez</summary>
  96. ObjectOverwriteBase = 0x010000,
  97. /// <summary>If set, and a slam bit is set, indicates OwnerMask will be overwritten on Rez</summary>
  98. ObjectOverwriteOwner = 0x020000,
  99. /// <summary>If set, and a slam bit is set, indicates GroupMask will be overwritten on Rez</summary>
  100. ObjectOverwriteGroup = 0x040000,
  101. /// <summary>If set, and a slam bit is set, indicates EveryoneMask will be overwritten on Rez</summary>
  102. ObjectOverwriteEveryone = 0x080000,
  103. /// <summary>If set, and a slam bit is set, indicates NextOwnerMask will be overwritten on Rez</summary>
  104. ObjectOverwriteNextOwner = 0x100000,
  105. /// <summary>Indicates whether this object is composed of multiple
  106. /// items or not</summary>
  107. ObjectHasMultipleItems = 0x200000,
  108. /// <summary>Indicates that the asset is only referenced by this
  109. /// inventory item. If this item is deleted or updated to reference a
  110. /// new assetID, the asset can be deleted</summary>
  111. SharedSingleReference = 0x40000000,
  112. }
  113. #endregion Enums
  114. #region Inventory Object Classes
  115. /// <summary>
  116. /// Base Class for Inventory Items
  117. /// </summary>
  118. [Serializable()]
  119. public abstract class InventoryBase : ISerializable
  120. {
  121. /// <summary><seealso cref="OpenMetaverse.UUID"/> of item/folder</summary>
  122. public UUID UUID;
  123. /// <summary><seealso cref="OpenMetaverse.UUID"/> of parent folder</summary>
  124. public UUID ParentUUID;
  125. /// <summary>Name of item/folder</summary>
  126. public string Name;
  127. /// <summary>Item/Folder Owners <seealso cref="OpenMetaverse.UUID"/></summary>
  128. public UUID OwnerID;
  129. /// <summary>
  130. /// Constructor, takes an itemID as a parameter
  131. /// </summary>
  132. /// <param name="itemID">The <seealso cref="OpenMetaverse.UUID"/> of the item</param>
  133. public InventoryBase(UUID itemID)
  134. {
  135. if (itemID == UUID.Zero)
  136. Logger.Log("Initializing an InventoryBase with UUID.Zero", Helpers.LogLevel.Warning);
  137. UUID = itemID;
  138. }
  139. /// <summary>
  140. ///
  141. /// </summary>
  142. /// <returns></returns>
  143. public virtual void GetObjectData(SerializationInfo info, StreamingContext ctxt)
  144. {
  145. info.AddValue("UUID", UUID);
  146. info.AddValue("ParentUUID", ParentUUID);
  147. info.AddValue("Name", Name);
  148. info.AddValue("OwnerID", OwnerID);
  149. }
  150. /// <summary>
  151. ///
  152. /// </summary>
  153. /// <returns></returns>
  154. public InventoryBase(SerializationInfo info, StreamingContext ctxt)
  155. {
  156. UUID = (UUID)info.GetValue("UUID", typeof(UUID));
  157. ParentUUID = (UUID)info.GetValue("ParentUUID", typeof(UUID));
  158. Name = (string)info.GetValue("Name", typeof(string));
  159. OwnerID = (UUID)info.GetValue("OwnerID", typeof(UUID));
  160. }
  161. /// <summary>
  162. /// Generates a number corresponding to the value of the object to support the use of a hash table,
  163. /// suitable for use in hashing algorithms and data structures such as a hash table
  164. /// </summary>
  165. /// <returns>A Hashcode of all the combined InventoryBase fields</returns>
  166. public override int GetHashCode()
  167. {
  168. return UUID.GetHashCode() ^ ParentUUID.GetHashCode() ^ Name.GetHashCode() ^ OwnerID.GetHashCode();
  169. }
  170. /// <summary>
  171. /// Determine whether the specified <seealso cref="OpenMetaverse.InventoryBase"/> object is equal to the current object
  172. /// </summary>
  173. /// <param name="o">InventoryBase object to compare against</param>
  174. /// <returns>true if objects are the same</returns>
  175. public override bool Equals(object o)
  176. {
  177. InventoryBase inv = o as InventoryBase;
  178. return inv != null && Equals(inv);
  179. }
  180. /// <summary>
  181. /// Determine whether the specified <seealso cref="OpenMetaverse.InventoryBase"/> object is equal to the current object
  182. /// </summary>
  183. /// <param name="o">InventoryBase object to compare against</param>
  184. /// <returns>true if objects are the same</returns>
  185. public virtual bool Equals(InventoryBase o)
  186. {
  187. return o.UUID == UUID
  188. && o.ParentUUID == ParentUUID
  189. && o.Name == Name
  190. && o.OwnerID == OwnerID;
  191. }
  192. }
  193. /// <summary>
  194. /// An Item in Inventory
  195. /// </summary>
  196. [Serializable()]
  197. public class InventoryItem : InventoryBase
  198. {
  199. public override string ToString()
  200. {
  201. return AssetType + " " + AssetUUID + " (" + InventoryType + " " + UUID + ") '" + Name + "'/'" +
  202. Description + "' " + Permissions;
  203. }
  204. /// <summary>The <seealso cref="OpenMetaverse.UUID"/> of this item</summary>
  205. public UUID AssetUUID;
  206. /// <summary>The combined <seealso cref="OpenMetaverse.Permissions"/> of this item</summary>
  207. public Permissions Permissions;
  208. /// <summary>The type of item from <seealso cref="OpenMetaverse.AssetType"/></summary>
  209. public AssetType AssetType;
  210. /// <summary>The type of item from the <seealso cref="OpenMetaverse.InventoryType"/> enum</summary>
  211. public InventoryType InventoryType;
  212. /// <summary>The <seealso cref="OpenMetaverse.UUID"/> of the creator of this item</summary>
  213. public UUID CreatorID;
  214. /// <summary>A Description of this item</summary>
  215. public string Description;
  216. /// <summary>The <seealso cref="OpenMetaverse.Group"/>s <seealso cref="OpenMetaverse.UUID"/> this item is set to or owned by</summary>
  217. public UUID GroupID;
  218. /// <summary>If true, item is owned by a group</summary>
  219. public bool GroupOwned;
  220. /// <summary>The price this item can be purchased for</summary>
  221. public int SalePrice;
  222. /// <summary>The type of sale from the <seealso cref="OpenMetaverse.SaleType"/> enum</summary>
  223. public SaleType SaleType;
  224. /// <summary>Combined flags from <seealso cref="OpenMetaverse.InventoryItemFlags"/></summary>
  225. public uint Flags;
  226. /// <summary>Time and date this inventory item was created, stored as
  227. /// UTC (Coordinated Universal Time)</summary>
  228. public DateTime CreationDate;
  229. /// <summary>Used to update the AssetID in requests sent to the server</summary>
  230. public UUID TransactionID;
  231. /// <summary>The <seealso cref="OpenMetaverse.UUID"/> of the previous owner of the item</summary>
  232. public UUID LastOwnerID;
  233. /// <summary>
  234. /// Construct a new InventoryItem object
  235. /// </summary>
  236. /// <param name="itemID">The <seealso cref="OpenMetaverse.UUID"/> of the item</param>
  237. public InventoryItem(UUID itemID)
  238. : base(itemID) { }
  239. /// <summary>
  240. /// Construct a new InventoryItem object of a specific Type
  241. /// </summary>
  242. /// <param name="type">The type of item from <seealso cref="OpenMetaverse.InventoryType"/></param>
  243. /// <param name="itemID"><seealso cref="OpenMetaverse.UUID"/> of the item</param>
  244. public InventoryItem(InventoryType type, UUID itemID) : base(itemID) { InventoryType = type; }
  245. /// <summary>
  246. /// Indicates inventory item is a link
  247. /// </summary>
  248. /// <returns>True if inventory item is a link to another inventory item</returns>
  249. public bool IsLink()
  250. {
  251. return AssetType == AssetType.Link || AssetType == AssetType.LinkFolder;
  252. }
  253. /// <summary>
  254. ///
  255. /// </summary>
  256. /// <returns></returns>
  257. override public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
  258. {
  259. base.GetObjectData(info, ctxt);
  260. info.AddValue("AssetUUID", AssetUUID, typeof(UUID));
  261. info.AddValue("Permissions", Permissions, typeof(Permissions));
  262. info.AddValue("AssetType", AssetType);
  263. info.AddValue("InventoryType", InventoryType);
  264. info.AddValue("CreatorID", CreatorID);
  265. info.AddValue("Description", Description);
  266. info.AddValue("GroupID", GroupID);
  267. info.AddValue("GroupOwned", GroupOwned);
  268. info.AddValue("SalePrice", SalePrice);
  269. info.AddValue("SaleType", SaleType);
  270. info.AddValue("Flags", Flags);
  271. info.AddValue("CreationDate", CreationDate);
  272. info.AddValue("LastOwnerID", LastOwnerID);
  273. }
  274. /// <summary>
  275. ///
  276. /// </summary>
  277. /// <returns></returns>
  278. public InventoryItem(SerializationInfo info, StreamingContext ctxt)
  279. : base(info, ctxt)
  280. {
  281. AssetUUID = (UUID)info.GetValue("AssetUUID", typeof(UUID));
  282. Permissions = (Permissions)info.GetValue("Permissions", typeof(Permissions));
  283. AssetType = (AssetType)info.GetValue("AssetType", typeof(AssetType));
  284. InventoryType = (InventoryType)info.GetValue("InventoryType", typeof(InventoryType));
  285. CreatorID = (UUID)info.GetValue("CreatorID", typeof(UUID));
  286. Description = (string)info.GetValue("Description", typeof(string));
  287. GroupID = (UUID)info.GetValue("GroupID", typeof(UUID));
  288. GroupOwned = (bool)info.GetValue("GroupOwned", typeof(bool));
  289. SalePrice = (int)info.GetValue("SalePrice", typeof(int));
  290. SaleType = (SaleType)info.GetValue("SaleType", typeof(SaleType));
  291. Flags = (uint)info.GetValue("Flags", typeof(uint));
  292. CreationDate = (DateTime)info.GetValue("CreationDate", typeof(DateTime));
  293. LastOwnerID = (UUID)info.GetValue("LastOwnerID", typeof(UUID));
  294. }
  295. /// <summary>
  296. /// Generates a number corresponding to the value of the object to support the use of a hash table.
  297. /// Suitable for use in hashing algorithms and data structures such as a hash table
  298. /// </summary>
  299. /// <returns>A Hashcode of all the combined InventoryItem fields</returns>
  300. public override int GetHashCode()
  301. {
  302. return AssetUUID.GetHashCode() ^ Permissions.GetHashCode() ^ AssetType.GetHashCode() ^
  303. InventoryType.GetHashCode() ^ Description.GetHashCode() ^ GroupID.GetHashCode() ^
  304. GroupOwned.GetHashCode() ^ SalePrice.GetHashCode() ^ SaleType.GetHashCode() ^
  305. Flags.GetHashCode() ^ CreationDate.GetHashCode() ^ LastOwnerID.GetHashCode();
  306. }
  307. /// <summary>
  308. /// Compares an object
  309. /// </summary>
  310. /// <param name="o">The object to compare</param>
  311. /// <returns>true if comparison object matches</returns>
  312. public override bool Equals(object o)
  313. {
  314. InventoryItem item = o as InventoryItem;
  315. return item != null && Equals(item);
  316. }
  317. /// <summary>
  318. /// Determine whether the specified <seealso cref="OpenMetaverse.InventoryBase"/> object is equal to the current object
  319. /// </summary>
  320. /// <param name="o">The <seealso cref="OpenMetaverse.InventoryBase"/> object to compare against</param>
  321. /// <returns>true if objects are the same</returns>
  322. public override bool Equals(InventoryBase o)
  323. {
  324. InventoryItem item = o as InventoryItem;
  325. return item != null && Equals(item);
  326. }
  327. /// <summary>
  328. /// Determine whether the specified <seealso cref="OpenMetaverse.InventoryItem"/> object is equal to the current object
  329. /// </summary>
  330. /// <param name="o">The <seealso cref="OpenMetaverse.InventoryItem"/> object to compare against</param>
  331. /// <returns>true if objects are the same</returns>
  332. public bool Equals(InventoryItem o)
  333. {
  334. return base.Equals(o as InventoryBase)
  335. && o.AssetType == AssetType
  336. && o.AssetUUID == AssetUUID
  337. && o.CreationDate == CreationDate
  338. && o.Description == Description
  339. && o.Flags == Flags
  340. && o.GroupID == GroupID
  341. && o.GroupOwned == GroupOwned
  342. && o.InventoryType == InventoryType
  343. && o.Permissions.Equals(Permissions)
  344. && o.SalePrice == SalePrice
  345. && o.SaleType == SaleType
  346. && o.LastOwnerID == LastOwnerID;
  347. }
  348. }
  349. /// <summary>
  350. /// InventoryTexture Class representing a graphical image
  351. /// </summary>
  352. /// <seealso cref="ManagedImage"/>
  353. [Serializable()]
  354. public class InventoryTexture : InventoryItem
  355. {
  356. /// <summary>
  357. /// Construct an InventoryTexture object
  358. /// </summary>
  359. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  360. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  361. public InventoryTexture(UUID itemID)
  362. : base(itemID)
  363. {
  364. InventoryType = InventoryType.Texture;
  365. }
  366. /// <summary>
  367. /// Construct an InventoryTexture object from a serialization stream
  368. /// </summary>
  369. public InventoryTexture(SerializationInfo info, StreamingContext ctxt)
  370. : base(info, ctxt)
  371. {
  372. InventoryType = InventoryType.Texture;
  373. }
  374. }
  375. /// <summary>
  376. /// InventorySound Class representing a playable sound
  377. /// </summary>
  378. [Serializable()]
  379. public class InventorySound : InventoryItem
  380. {
  381. /// <summary>
  382. /// Construct an InventorySound object
  383. /// </summary>
  384. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  385. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  386. public InventorySound(UUID itemID)
  387. : base(itemID)
  388. {
  389. InventoryType = InventoryType.Sound;
  390. }
  391. /// <summary>
  392. /// Construct an InventorySound object from a serialization stream
  393. /// </summary>
  394. public InventorySound(SerializationInfo info, StreamingContext ctxt)
  395. : base(info, ctxt)
  396. {
  397. InventoryType = InventoryType.Sound;
  398. }
  399. }
  400. /// <summary>
  401. /// InventoryCallingCard Class, contains information on another avatar
  402. /// </summary>
  403. [Serializable()]
  404. public class InventoryCallingCard : InventoryItem
  405. {
  406. /// <summary>
  407. /// Construct an InventoryCallingCard object
  408. /// </summary>
  409. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  410. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  411. public InventoryCallingCard(UUID itemID)
  412. : base(itemID)
  413. {
  414. InventoryType = InventoryType.CallingCard;
  415. }
  416. /// <summary>
  417. /// Construct an InventoryCallingCard object from a serialization stream
  418. /// </summary>
  419. public InventoryCallingCard(SerializationInfo info, StreamingContext ctxt)
  420. : base(info, ctxt)
  421. {
  422. InventoryType = InventoryType.CallingCard;
  423. }
  424. }
  425. /// <summary>
  426. /// InventoryLandmark Class, contains details on a specific location
  427. /// </summary>
  428. [Serializable()]
  429. public class InventoryLandmark : InventoryItem
  430. {
  431. /// <summary>
  432. /// Construct an InventoryLandmark object
  433. /// </summary>
  434. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  435. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  436. public InventoryLandmark(UUID itemID)
  437. : base(itemID)
  438. {
  439. InventoryType = InventoryType.Landmark;
  440. }
  441. /// <summary>
  442. /// Construct an InventoryLandmark object from a serialization stream
  443. /// </summary>
  444. public InventoryLandmark(SerializationInfo info, StreamingContext ctxt)
  445. : base(info, ctxt)
  446. {
  447. InventoryType = InventoryType.Landmark;
  448. }
  449. /// <summary>
  450. /// Landmarks use the InventoryItemFlags struct and will have a flag of 1 set if they have been visited
  451. /// </summary>
  452. public bool LandmarkVisited
  453. {
  454. get { return (Flags & 1) != 0; }
  455. set
  456. {
  457. if (value) Flags |= 1;
  458. else Flags &= ~1u;
  459. }
  460. }
  461. }
  462. /// <summary>
  463. /// InventoryObject Class contains details on a primitive or coalesced set of primitives
  464. /// </summary>
  465. [Serializable()]
  466. public class InventoryObject : InventoryItem
  467. {
  468. /// <summary>
  469. /// Construct an InventoryObject object
  470. /// </summary>
  471. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  472. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  473. public InventoryObject(UUID itemID)
  474. : base(itemID)
  475. {
  476. InventoryType = InventoryType.Object;
  477. }
  478. /// <summary>
  479. /// Construct an InventoryObject object from a serialization stream
  480. /// </summary>
  481. public InventoryObject(SerializationInfo info, StreamingContext ctxt)
  482. : base(info, ctxt)
  483. {
  484. InventoryType = InventoryType.Object;
  485. }
  486. /// <summary>
  487. /// Gets or sets the upper byte of the Flags value
  488. /// </summary>
  489. public InventoryItemFlags ItemFlags
  490. {
  491. get { return (InventoryItemFlags)(Flags & ~0xFF); }
  492. set { Flags = (uint)value | (Flags & 0xFF); }
  493. }
  494. /// <summary>
  495. /// Gets or sets the object attachment point, the lower byte of the Flags value
  496. /// </summary>
  497. public AttachmentPoint AttachPoint
  498. {
  499. get { return (AttachmentPoint)(Flags & 0xFF); }
  500. set { Flags = (uint)value | (Flags & 0xFFFFFF00); }
  501. }
  502. }
  503. /// <summary>
  504. /// InventoryNotecard Class, contains details on an encoded text document
  505. /// </summary>
  506. [Serializable()]
  507. public class InventoryNotecard : InventoryItem
  508. {
  509. /// <summary>
  510. /// Construct an InventoryNotecard object
  511. /// </summary>
  512. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  513. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  514. public InventoryNotecard(UUID itemID)
  515. : base(itemID)
  516. {
  517. InventoryType = InventoryType.Notecard;
  518. }
  519. /// <summary>
  520. /// Construct an InventoryNotecard object from a serialization stream
  521. /// </summary>
  522. public InventoryNotecard(SerializationInfo info, StreamingContext ctxt)
  523. : base(info, ctxt)
  524. {
  525. InventoryType = InventoryType.Notecard;
  526. }
  527. }
  528. /// <summary>
  529. /// InventoryCategory Class
  530. /// </summary>
  531. /// <remarks>TODO: Is this even used for anything?</remarks>
  532. [Serializable()]
  533. public class InventoryCategory : InventoryItem
  534. {
  535. /// <summary>
  536. /// Construct an InventoryCategory object
  537. /// </summary>
  538. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  539. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  540. public InventoryCategory(UUID itemID)
  541. : base(itemID)
  542. {
  543. InventoryType = InventoryType.Category;
  544. }
  545. /// <summary>
  546. /// Construct an InventoryCategory object from a serialization stream
  547. /// </summary>
  548. public InventoryCategory(SerializationInfo info, StreamingContext ctxt)
  549. : base(info, ctxt)
  550. {
  551. InventoryType = InventoryType.Category;
  552. }
  553. }
  554. /// <summary>
  555. /// InventoryLSL Class, represents a Linden Scripting Language object
  556. /// </summary>
  557. [Serializable()]
  558. public class InventoryLSL : InventoryItem
  559. {
  560. /// <summary>
  561. /// Construct an InventoryLSL object
  562. /// </summary>
  563. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  564. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  565. public InventoryLSL(UUID itemID)
  566. : base(itemID)
  567. {
  568. InventoryType = InventoryType.LSL;
  569. }
  570. /// <summary>
  571. /// Construct an InventoryLSL object from a serialization stream
  572. /// </summary>
  573. public InventoryLSL(SerializationInfo info, StreamingContext ctxt)
  574. : base(info, ctxt)
  575. {
  576. InventoryType = InventoryType.LSL;
  577. }
  578. }
  579. /// <summary>
  580. /// InventorySnapshot Class, an image taken with the viewer
  581. /// </summary>
  582. [Serializable()]
  583. public class InventorySnapshot : InventoryItem
  584. {
  585. /// <summary>
  586. /// Construct an InventorySnapshot object
  587. /// </summary>
  588. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  589. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  590. public InventorySnapshot(UUID itemID)
  591. : base(itemID)
  592. {
  593. InventoryType = InventoryType.Snapshot;
  594. }
  595. /// <summary>
  596. /// Construct an InventorySnapshot object from a serialization stream
  597. /// </summary>
  598. public InventorySnapshot(SerializationInfo info, StreamingContext ctxt)
  599. : base(info, ctxt)
  600. {
  601. InventoryType = InventoryType.Snapshot;
  602. }
  603. }
  604. /// <summary>
  605. /// InventoryAttachment Class, contains details on an attachable object
  606. /// </summary>
  607. [Serializable()]
  608. public class InventoryAttachment : InventoryItem
  609. {
  610. /// <summary>
  611. /// Construct an InventoryAttachment object
  612. /// </summary>
  613. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  614. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  615. public InventoryAttachment(UUID itemID)
  616. : base(itemID)
  617. {
  618. InventoryType = InventoryType.Attachment;
  619. }
  620. /// <summary>
  621. /// Construct an InventoryAttachment object from a serialization stream
  622. /// </summary>
  623. public InventoryAttachment(SerializationInfo info, StreamingContext ctxt)
  624. : base(info, ctxt)
  625. {
  626. InventoryType = InventoryType.Attachment;
  627. }
  628. /// <summary>
  629. /// Get the last AttachmentPoint this object was attached to
  630. /// </summary>
  631. public AttachmentPoint AttachmentPoint
  632. {
  633. get { return (AttachmentPoint)Flags; }
  634. set { Flags = (uint)value; }
  635. }
  636. }
  637. /// <summary>
  638. /// InventoryWearable Class, details on a clothing item or body part
  639. /// </summary>
  640. [Serializable()]
  641. public class InventoryWearable : InventoryItem
  642. {
  643. /// <summary>
  644. /// Construct an InventoryWearable object
  645. /// </summary>
  646. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  647. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  648. public InventoryWearable(UUID itemID) : base(itemID) { InventoryType = InventoryType.Wearable; }
  649. /// <summary>
  650. /// Construct an InventoryWearable object from a serialization stream
  651. /// </summary>
  652. public InventoryWearable(SerializationInfo info, StreamingContext ctxt)
  653. : base(info, ctxt)
  654. {
  655. InventoryType = InventoryType.Wearable;
  656. }
  657. /// <summary>
  658. /// The <seealso cref="OpenMetaverse.WearableType"/>, Skin, Shape, Skirt, Etc
  659. /// </summary>
  660. public WearableType WearableType
  661. {
  662. get { return (WearableType)Flags; }
  663. set { Flags = (uint)value; }
  664. }
  665. }
  666. /// <summary>
  667. /// InventoryAnimation Class, A bvh encoded object which animates an avatar
  668. /// </summary>
  669. [Serializable()]
  670. public class InventoryAnimation : InventoryItem
  671. {
  672. /// <summary>
  673. /// Construct an InventoryAnimation object
  674. /// </summary>
  675. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  676. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  677. public InventoryAnimation(UUID itemID)
  678. : base(itemID)
  679. {
  680. InventoryType = InventoryType.Animation;
  681. }
  682. /// <summary>
  683. /// Construct an InventoryAnimation object from a serialization stream
  684. /// </summary>
  685. public InventoryAnimation(SerializationInfo info, StreamingContext ctxt)
  686. : base(info, ctxt)
  687. {
  688. InventoryType = InventoryType.Animation;
  689. }
  690. }
  691. /// <summary>
  692. /// InventoryGesture Class, details on a series of animations, sounds, and actions
  693. /// </summary>
  694. [Serializable()]
  695. public class InventoryGesture : InventoryItem
  696. {
  697. /// <summary>
  698. /// Construct an InventoryGesture object
  699. /// </summary>
  700. /// <param name="itemID">A <seealso cref="OpenMetaverse.UUID"/> which becomes the
  701. /// <seealso cref="OpenMetaverse.InventoryItem"/> objects AssetUUID</param>
  702. public InventoryGesture(UUID itemID)
  703. : base(itemID)
  704. {
  705. InventoryType = InventoryType.Gesture;
  706. }
  707. /// <summary>
  708. /// Construct an InventoryGesture object from a serialization stream
  709. /// </summary>
  710. public InventoryGesture(SerializationInfo info, StreamingContext ctxt)
  711. : base(info, ctxt)
  712. {
  713. InventoryType = InventoryType.Gesture;
  714. }
  715. }
  716. /// <summary>
  717. /// A folder contains <seealso cref="T:OpenMetaverse.InventoryItem"/>s and has certain attributes specific
  718. /// to itself
  719. /// </summary>
  720. [Serializable()]
  721. public class InventoryFolder : InventoryBase
  722. {
  723. /// <summary>The Preferred <seealso cref="T:OpenMetaverse.AssetType"/> for a folder.</summary>
  724. public AssetType PreferredType;
  725. /// <summary>The Version of this folder</summary>
  726. public int Version;
  727. /// <summary>Number of child items this folder contains.</summary>
  728. public int DescendentCount;
  729. /// <summary>
  730. /// Constructor
  731. /// </summary>
  732. /// <param name="itemID">UUID of the folder</param>
  733. public InventoryFolder(UUID itemID)
  734. : base(itemID)
  735. {
  736. PreferredType = AssetType.Unknown;
  737. Version = 1;
  738. DescendentCount = 0;
  739. }
  740. /// <summary>
  741. ///
  742. /// </summary>
  743. /// <returns></returns>
  744. public override string ToString()
  745. {
  746. return Name;
  747. }
  748. /// <summary>
  749. /// Get Serilization data for this InventoryFolder object
  750. /// </summary>
  751. override public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
  752. {
  753. base.GetObjectData(info, ctxt);
  754. info.AddValue("PreferredType", PreferredType, typeof(AssetType));
  755. info.AddValue("Version", Version);
  756. info.AddValue("DescendentCount", DescendentCount);
  757. }
  758. /// <summary>
  759. /// Construct an InventoryFolder object from a serialization stream
  760. /// </summary>
  761. public InventoryFolder(SerializationInfo info, StreamingContext ctxt)
  762. : base(info, ctxt)
  763. {
  764. PreferredType = (AssetType)info.GetValue("PreferredType", typeof(AssetType));
  765. Version = (int)info.GetValue("Version", typeof(int));
  766. DescendentCount = (int)info.GetValue("DescendentCount", typeof(int));
  767. }
  768. /// <summary>
  769. ///
  770. /// </summary>
  771. /// <returns></returns>
  772. public override int GetHashCode()
  773. {
  774. return PreferredType.GetHashCode() ^ Version.GetHashCode() ^ DescendentCount.GetHashCode();
  775. }
  776. /// <summary>
  777. ///
  778. /// </summary>
  779. /// <param name="o"></param>
  780. /// <returns></returns>
  781. public override bool Equals(object o)
  782. {
  783. InventoryFolder folder = o as InventoryFolder;
  784. return folder != null && Equals(folder);
  785. }
  786. /// <summary>
  787. ///
  788. /// </summary>
  789. /// <param name="o"></param>
  790. /// <returns></returns>
  791. public override bool Equals(InventoryBase o)
  792. {
  793. InventoryFolder folder = o as InventoryFolder;
  794. return folder != null && Equals(folder);
  795. }
  796. /// <summary>
  797. ///
  798. /// </summary>
  799. /// <param name="o"></param>
  800. /// <returns></returns>
  801. public bool Equals(InventoryFolder o)
  802. {
  803. return base.Equals(o as InventoryBase)
  804. && o.DescendentCount == DescendentCount
  805. && o.PreferredType == PreferredType
  806. && o.Version == Version;
  807. }
  808. }
  809. #endregion Inventory Object Classes
  810. /// <summary>
  811. /// Tools for dealing with agents inventory
  812. /// </summary>
  813. [Serializable()]
  814. public class InventoryManager
  815. {
  816. /// <summary>Used for converting shadow_id to asset_id</summary>
  817. public static readonly UUID MAGIC_ID = new UUID("3c115e51-04f4-523c-9fa6-98aff1034730");
  818. protected struct InventorySearch
  819. {
  820. public UUID Folder;
  821. public UUID Owner;
  822. public string[] Path;
  823. public int Level;
  824. }
  825. #region Delegates
  826. /// <summary>
  827. /// Callback for inventory item creation finishing
  828. /// </summary>
  829. /// <param name="success">Whether the request to create an inventory
  830. /// item succeeded or not</param>
  831. /// <param name="item">Inventory item being created. If success is
  832. /// false this will be null</param>
  833. public delegate void ItemCreatedCallback(bool success, InventoryItem item);
  834. /// <summary>
  835. /// Callback for an inventory item being create from an uploaded asset
  836. /// </summary>
  837. /// <param name="success">true if inventory item creation was successful</param>
  838. /// <param name="status"></param>
  839. /// <param name="itemID"></param>
  840. /// <param name="assetID"></param>
  841. public delegate void ItemCreatedFromAssetCallback(bool success, string status, UUID itemID, UUID assetID);
  842. /// <summary>
  843. ///
  844. /// </summary>
  845. /// <param name="item"></param>
  846. public delegate void ItemCopiedCallback(InventoryBase item);
  847. /// <summary>The event subscribers, null of no subscribers</summary>
  848. private EventHandler<ItemReceivedEventArgs> m_ItemReceived;
  849. ///<summary>Raises the ItemReceived Event</summary>
  850. /// <param name="e">A ItemReceivedEventArgs object containing
  851. /// the data sent from the simulator</param>
  852. protected virtual void OnItemReceived(ItemReceivedEventArgs e)
  853. {
  854. EventHandler<ItemReceivedEventArgs> handler = m_ItemReceived;
  855. if (handler != null)
  856. handler(this, e);
  857. }
  858. /// <summary>Thread sync lock object</summary>
  859. private readonly object m_ItemReceivedLock = new object();
  860. /// <summary>Raised when the simulator sends us data containing
  861. /// ...</summary>
  862. public event EventHandler<ItemReceivedEventArgs> ItemReceived
  863. {
  864. add { lock (m_ItemReceivedLock) { m_ItemReceived += value; } }
  865. remove { lock (m_ItemReceivedLock) { m_ItemReceived -= value; } }
  866. }
  867. /// <summary>The event subscribers, null of no subscribers</summary>
  868. private EventHandler<FolderUpdatedEventArgs> m_FolderUpdated;
  869. ///<summary>Raises the FolderUpdated Event</summary>
  870. /// <param name="e">A FolderUpdatedEventArgs object containing
  871. /// the data sent from the simulator</param>
  872. protected virtual void OnFolderUpdated(FolderUpdatedEventArgs e)
  873. {
  874. EventHandler<FolderUpdatedEventArgs> handler = m_FolderUpdated;
  875. if (handler != null)
  876. handler(this, e);
  877. }
  878. /// <summary>Thread sync lock object</summary>
  879. private readonly object m_FolderUpdatedLock = new object();
  880. /// <summary>Raised when the simulator sends us data containing
  881. /// ...</summary>
  882. public event EventHandler<FolderUpdatedEventArgs> FolderUpdated
  883. {
  884. add { lock (m_FolderUpdatedLock) { m_FolderUpdated += value; } }
  885. remove { lock (m_FolderUpdatedLock) { m_FolderUpdated -= value; } }
  886. }
  887. /// <summary>The event subscribers, null of no subscribers</summary>
  888. private EventHandler<InventoryObjectOfferedEventArgs> m_InventoryObjectOffered;
  889. ///<summary>Raises the InventoryObjectOffered Event</summary>
  890. /// <param name="e">A InventoryObjectOfferedEventArgs object containing
  891. /// the data sent from the simulator</param>
  892. protected virtual void OnInventoryObjectOffered(InventoryObjectOfferedEventArgs e)
  893. {
  894. EventHandler<InventoryObjectOfferedEventArgs> handler = m_InventoryObjectOffered;
  895. if (handler != null)
  896. handler(this, e);
  897. }
  898. /// <summary>Thread sync lock object</summary>
  899. private readonly object m_InventoryObjectOfferedLock = new object();
  900. /// <summary>Raised when the simulator sends us data containing
  901. /// an inventory object sent by another avatar or primitive</summary>
  902. public event EventHandler<InventoryObjectOfferedEventArgs> InventoryObjectOffered
  903. {
  904. add { lock (m_InventoryObjectOfferedLock) { m_InventoryObjectOffered += value; } }
  905. remove { lock (m_InventoryObjectOfferedLock) { m_InventoryObjectOffered -= value; } }
  906. }
  907. /// <summary>The event subscribers, null of no subscribers</summary>
  908. private EventHandler<TaskItemReceivedEventArgs> m_TaskItemReceived;
  909. ///<summary>Raises the TaskItemReceived Event</summary>
  910. /// <param name="e">A TaskItemReceivedEventArgs object containing
  911. /// the data sent from the simulator</param>
  912. protected virtual void OnTaskItemReceived(TaskItemReceivedEventArgs e)
  913. {
  914. EventHandler<TaskItemReceivedEventArgs> handler = m_TaskItemReceived;
  915. if (handler != null)
  916. handler(this, e);
  917. }
  918. /// <summary>Thread sync lock object</summary>
  919. private readonly object m_TaskItemReceivedLock = new object();
  920. /// <summary>Raised when the simulator sends us data containing
  921. /// ...</summary>
  922. public event EventHandler<TaskItemReceivedEventArgs> TaskItemReceived
  923. {
  924. add { lock (m_TaskItemReceivedLock) { m_TaskItemReceived += value; } }
  925. remove { lock (m_TaskItemReceivedLock) { m_TaskItemReceived -= value; } }
  926. }
  927. /// <summary>The event subscribers, null of no subscribers</summary>
  928. private EventHandler<FindObjectByPathReplyEventArgs> m_FindObjectByPathReply;
  929. ///<summary>Raises the FindObjectByPath Event</summary>
  930. /// <param name="e">A FindObjectByPathEventArgs object containing
  931. /// the data sent from the simulator</param>
  932. protected virtual void OnFindObjectByPathReply(FindObjectByPathReplyEventArgs e)
  933. {
  934. EventHandler<FindObjectByPathReplyEventArgs> handler = m_FindObjectByPathReply;
  935. if (handler != null)
  936. handler(this, e);
  937. }
  938. /// <summary>Thread sync lock object</summary>
  939. private readonly object m_FindObjectByPathReplyLock = new object();
  940. /// <summary>Raised when the simulator sends us data containing
  941. /// ...</summary>
  942. public event EventHandler<FindObjectByPathReplyEventArgs> FindObjectByPathReply
  943. {
  944. add { lock (m_FindObjectByPathReplyLock) { m_FindObjectByPathReply += value; } }
  945. remove { lock (m_FindObjectByPathReplyLock) { m_FindObjectByPathReply -= value; } }
  946. }
  947. /// <summary>The event subscribers, null of no subscribers</summary>
  948. private EventHandler<TaskInventoryReplyEventArgs> m_TaskInventoryReply;
  949. ///<summary>Raises the TaskInventoryReply Event</summary>
  950. /// <param name="e">A TaskInventoryReplyEventArgs object containing
  951. /// the data sent from the simulator</param>
  952. protected virtual void OnTaskInventoryReply(TaskInventoryReplyEventArgs e)
  953. {
  954. EventHandler<TaskInventoryReplyEventArgs> handler = m_TaskInventoryReply;
  955. if (handler != null)
  956. handler(this, e);
  957. }
  958. /// <summary>Thread sync lock object</summary>
  959. private readonly object m_TaskInventoryReplyLock = new object();
  960. /// <summary>Raised when the simulator sends us data containing
  961. /// ...</summary>
  962. public event EventHandler<TaskInventoryReplyEventArgs> TaskInventoryReply
  963. {
  964. add { lock (m_TaskInventoryReplyLock) { m_TaskInventoryReply += value; } }
  965. remove { lock (m_TaskInventoryReplyLock) { m_TaskInventoryReply -= value; } }
  966. }
  967. /// <summary>
  968. /// Reply received when uploading an inventory asset
  969. /// </summary>
  970. /// <param name="success">Has upload been successful</param>
  971. /// <param name="status">Error message if upload failed</param>
  972. /// <param name="itemID">Inventory asset UUID</param>
  973. /// <param name="assetID">New asset UUID</param>
  974. public delegate void InventoryUploadedAssetCallback(bool success, string status, UUID itemID, UUID assetID);
  975. /// <summary>The event subscribers, null of no subscribers</summary>
  976. private EventHandler<SaveAssetToInventoryEventArgs> m_SaveAssetToInventory;
  977. ///<summary>Raises the SaveAssetToInventory Event</summary>
  978. /// <param name="e">A SaveAssetToInventoryEventArgs object containing
  979. /// the data sent from the simulator</param>
  980. protected virtual void OnSaveAssetToInventory(SaveAssetToInventoryEventArgs e)
  981. {
  982. EventHandler<SaveAssetToInventoryEventArgs> handler = m_SaveAssetToInventory;
  983. if (handler != null)
  984. handler(this, e);
  985. }
  986. /// <summary>Thread sync lock object</summary>
  987. private readonly object m_SaveAssetToInventoryLock = new object();
  988. /// <summary>Raised when the simulator sends us data containing
  989. /// ...</summary>
  990. public event EventHandler<SaveAssetToInventoryEventArgs> SaveAssetToInventory
  991. {
  992. add { lock (m_SaveAssetToInventoryLock) { m_SaveAssetToInventory += value; } }
  993. remove { lock (m_SaveAssetToInventoryLock) { m_SaveAssetToInventory -= value; } }
  994. }
  995. /// <summary>
  996. /// Delegate that is invoked when script upload is completed
  997. /// </summary>
  998. /// <param name="uploadSuccess">Has upload succeded (note, there still might be compile errors)</param>
  999. /// <param name="uploadStatus">Upload status message</param>
  1000. /// <param name="compileSuccess">Is compilation successful</param>
  1001. /// <param name="compileMessages">If compilation failed, list of error messages, null on compilation success</param>
  1002. /// <param name="itemID">Script inventory UUID</param>
  1003. /// <param name="assetID">Script's new asset UUID</param>
  1004. public delegate void ScriptUpdatedCallback(bool uploadSuccess, string uploadStatus, bool compileSuccess, List<string> compileMessages, UUID itemID, UUID assetID);
  1005. /// <summary>The event subscribers, null of no subscribers</summary>
  1006. private EventHandler<ScriptRunningReplyEventArgs> m_ScriptRunningReply;
  1007. ///<summary>Raises the ScriptRunningReply Event</summary>
  1008. /// <param name="e">A ScriptRunningReplyEventArgs object containing
  1009. /// the data sent from the simulator</param>
  1010. protected virtual void OnScriptRunningReply(ScriptRunningReplyEventArgs e)
  1011. {
  1012. EventHandler<ScriptRunningReplyEventArgs> handler = m_ScriptRunningReply;
  1013. if (handler != null)
  1014. handler(this, e);
  1015. }
  1016. /// <summary>Thread sync lock object</summary>
  1017. private readonly object m_ScriptRunningReplyLock = new object();
  1018. /// <summary>Raised when the simulator sends us data containing
  1019. /// ...</summary>
  1020. public event EventHandler<ScriptRunningReplyEventArgs> ScriptRunningReply
  1021. {
  1022. add { lock (m_ScriptRunningReplyLock) { m_ScriptRunningReply += value; } }
  1023. remove { lock (m_ScriptRunningReplyLock) { m_ScriptRunningReply -= value; } }
  1024. }
  1025. #endregion Delegates
  1026. #region String Arrays
  1027. /// <summary>Partial mapping of AssetTypes to folder names</summary>
  1028. private static readonly string[] _NewFolderNames = new string[]
  1029. {
  1030. "Textures",
  1031. "Sounds",
  1032. "Calling Cards",
  1033. "Landmarks",
  1034. "Scripts",
  1035. "Clothing",
  1036. "Objects",
  1037. "Notecards",
  1038. "New Folder",
  1039. "Inventory",
  1040. "Scripts",
  1041. "Scripts",
  1042. "Uncompressed Images",
  1043. "Body Parts",
  1044. "Trash",
  1045. "Photo Album",
  1046. "Lost And Found",
  1047. "Uncompressed Sounds",
  1048. "Uncompressed Images",
  1049. "Uncompressed Images",
  1050. "Animations",
  1051. "Gestures"
  1052. };
  1053. #endregion String Arrays
  1054. private GridClient Client;
  1055. private Inventory _Store;
  1056. //private Random _RandNumbers = new Random();
  1057. private object _CallbacksLock = new object();
  1058. private uint _CallbackPos;
  1059. private Dictionary<uint, ItemCreatedCallback> _ItemCreatedCallbacks = new Dictionary<uint, ItemCreatedCallback>();
  1060. private Dictionary<uint, ItemCopiedCallback> _ItemCopiedCallbacks = new Dictionary<uint, ItemCopiedCallback>();
  1061. private List<InventorySearch> _Searches = new List<InventorySearch>();
  1062. #region Properties
  1063. /// <summary>
  1064. /// Get this agents Inventory data
  1065. /// </summary>
  1066. public Inventory Store { get { return _Store; } }
  1067. #endregion Properties
  1068. /// <summary>
  1069. /// Default constructor
  1070. /// </summary>
  1071. /// <param name="client">Reference to the GridClient object</param>
  1072. public InventoryManager(GridClient client)
  1073. {
  1074. Client = client;
  1075. Client.Network.RegisterCallback(PacketType.UpdateCreateInventoryItem, UpdateCreateInventoryItemHandler);
  1076. Client.Network.RegisterCallback(PacketType.SaveAssetIntoInventory, SaveAssetIntoInventoryHandler);
  1077. Client.Network.RegisterCallback(PacketType.BulkUpdateInventory, BulkUpdateInventoryHandler);
  1078. Client.Network.RegisterEventCallback("BulkUpdateInventory", new Caps.EventQueueCallback(BulkUpdateInventoryCapHandler));
  1079. Client.Network.RegisterCallback(PacketType.MoveInventoryItem, MoveInventoryItemHandler);
  1080. Client.Network.RegisterCallback(PacketType.InventoryDescendents, InventoryDescendentsHandler);
  1081. Client.Network.RegisterCallback(PacketType.FetchInventoryReply, FetchInventoryReplyHandler);
  1082. Client.Network.RegisterCallback(PacketType.ReplyTaskInventory, ReplyTaskInventoryHandler);
  1083. Client.Network.RegisterEventCallback("ScriptRunningReply", new Caps.EventQueueCallback(ScriptRunningReplyMessageHandler));
  1084. // Watch for inventory given to us through instant message
  1085. Client.Self.IM += Self_IM;
  1086. // Register extra parameters with login and parse the inventory data that comes back
  1087. Client.Network.RegisterLoginResponseCallback(
  1088. new NetworkManager.LoginResponseCallback(Network_OnLoginResponse),
  1089. new string[] {
  1090. "inventory-root", "inventory-skeleton", "inventory-lib-root",
  1091. "inventory-lib-owner", "inventory-skel-lib"});
  1092. }
  1093. #region Fetch
  1094. /// <summary>
  1095. /// Fetch an inventory item from the dataserver
  1096. /// </summary>
  1097. /// <param name="itemID">The items <seealso cref="UUID"/></param>
  1098. /// <param name="ownerID">The item Owners <seealso cref="OpenMetaverse.UUID"/></param>
  1099. /// <param name="timeoutMS">a integer representing the number of milliseconds to wait for results</param>
  1100. /// <returns>An <seealso cref="InventoryItem"/> object on success, or null if no item was found</returns>
  1101. /// <remarks>Items will also be sent to the <seealso cref="InventoryManager.OnItemReceived"/> event</remarks>
  1102. public InventoryItem FetchItem(UUID itemID, UUID ownerID, int timeoutMS)
  1103. {
  1104. AutoResetEvent fetchEvent = new AutoResetEvent(false);
  1105. InventoryItem fetchedItem = null;
  1106. EventHandler<ItemReceivedEventArgs> callback =
  1107. delegate(object sender, ItemReceivedEventArgs e)
  1108. {
  1109. if (e.Item.UUID == itemID)
  1110. {
  1111. fetchedItem = e.Item;
  1112. fetchEvent.Set();
  1113. }
  1114. };
  1115. ItemReceived += callback;
  1116. RequestFetchInventory(itemID, ownerID);
  1117. fetchEvent.WaitOne(timeoutMS, false);
  1118. ItemReceived -= callback;
  1119. return fetchedItem;
  1120. }
  1121. /// <summary>
  1122. /// Request A single inventory item
  1123. /// </summary>
  1124. /// <param name="itemID">The items <seealso cref="OpenMetaverse.UUID"/></param>
  1125. /// <param name="ownerID">The item Owners <seealso cref="OpenMetaverse.UUID"/></param>
  1126. /// <seealso cref="InventoryManager.OnItemReceived"/>
  1127. public void RequestFetchInventory(UUID itemID, UUID ownerID)
  1128. {
  1129. FetchInventoryPacket fetch = new FetchInventoryPacket();
  1130. fetch.AgentData = new FetchInventoryPacket.AgentDataBlock();
  1131. fetch.AgentData.AgentID = Client.Self.AgentID;
  1132. fetch.AgentData.SessionID = Client.Self.SessionID;
  1133. fetch.InventoryData = new FetchInventoryPacket.InventoryDataBlock[1];
  1134. fetch.InventoryData[0] = new FetchInventoryPacket.InventoryDataBlock();
  1135. fetch.InventoryData[0].ItemID = itemID;
  1136. fetch.InventoryData[0].OwnerID = ownerID;
  1137. Client.Network.SendPacket(fetch);
  1138. }
  1139. /// <summary>
  1140. /// Request inventory items
  1141. /// </summary>
  1142. /// <param name="itemIDs">Inventory items to request</param>
  1143. /// <param name="ownerIDs">Owners of the inventory items</param>
  1144. /// <seealso cref="InventoryManager.OnItemReceived"/>
  1145. public void RequestFetchInventory(List<UUID> itemIDs, List<UUID> ownerIDs)
  1146. {
  1147. if (itemIDs.Count != ownerIDs.Count)
  1148. throw new ArgumentException("itemIDs and ownerIDs must contain the same number of entries");
  1149. FetchInventoryPacket fetch = new FetchInventoryPacket();
  1150. fetch.AgentData = new FetchInventoryPacket.AgentDataBlock();
  1151. fetch.AgentData.AgentID = Client.Self.AgentID;
  1152. fetch.AgentData.SessionID = Client.Self.SessionID;
  1153. fetch.InventoryData = new FetchInventoryPacket.InventoryDataBlock[itemIDs.Count];
  1154. for (int i = 0; i < itemIDs.Count; i++)
  1155. {
  1156. fetch.InventoryData[i] = new FetchInventoryPacket.InventoryDataBlock();
  1157. fetch.InventoryData[i].ItemID = itemIDs[i];
  1158. fetch.InventoryData[i].OwnerID = ownerIDs[i];
  1159. }
  1160. Client.Network.SendPacket(fetch);
  1161. }
  1162. /// <summary>
  1163. /// Get contents of a folder
  1164. /// </summary>
  1165. /// <param name="folder">The <seealso cref="UUID"/> of the folder to search</param>
  1166. /// <param name="owner">The <seealso cref="UUID"/> of the folders owner</param>
  1167. /// <param name="folders">true to retrieve folders</param>
  1168. /// <param name="items">true to retrieve items</param>
  1169. /// <param name="order">sort order to return results in</param>
  1170. /// <param name="timeoutMS">a integer representing the number of milliseconds to wait for results</param>
  1171. /// <returns>A list of inventory items matching search criteria within folder</returns>
  1172. /// <seealso cref="InventoryManager.RequestFolderContents"/>
  1173. /// <remarks>InventoryFolder.DescendentCount will only be accurate if both folders and items are
  1174. /// requested</remarks>
  1175. public List<InventoryBase> FolderContents(UUID folder, UUID owner, bool folders, bool items,
  1176. InventorySortOrder order, int timeoutMS)
  1177. {
  1178. List<InventoryBase> objects = null;
  1179. AutoResetEvent fetchEvent = new AutoResetEvent(false);
  1180. EventHandler<FolderUpdatedEventArgs> callback =
  1181. delegate(object sender, FolderUpdatedEventArgs e)
  1182. {
  1183. if (e.FolderID == folder
  1184. && _Store[folder] is InventoryFolder)
  1185. {
  1186. // InventoryDescendentsHandler only stores DescendendCount if both folders and items are fetched.
  1187. if (_Store.GetContents(folder).Count >= ((InventoryFolder)_Store[folder]).DescendentCount)
  1188. {
  1189. fetchEvent.Set();
  1190. }
  1191. }
  1192. else
  1193. {
  1194. fetchEvent.Set();
  1195. }
  1196. };
  1197. FolderUpdated += callback;
  1198. RequestFolderContents(folder, owner, folders, items, order);
  1199. if (fetchEvent.WaitOne(timeoutMS, false))
  1200. objects = _Store.GetContents(folder);
  1201. FolderUpdated -= callback;
  1202. return objects;
  1203. }
  1204. /// <summary>
  1205. /// Request the contents of an inventory folder
  1206. /// </summary>
  1207. /// <param name="folder">The folder to search</param>
  1208. /// <param name="owner">The folder owners <seealso cref="UUID"/></param>
  1209. /// <param name="folders">true to return <seealso cref="InventoryManager.InventoryFolder"/>s contained in folder</param>
  1210. /// <param name="items">true to return <seealso cref="InventoryManager.InventoryItem"/>s containd in folder</param>
  1211. /// <param name="order">the sort order to return items in</param>
  1212. /// <seealso cref="InventoryManager.FolderContents"/>
  1213. public void RequestFolderContents(UUID folder, UUID owner, bool folders, bool items,
  1214. InventorySortOrder order)
  1215. {
  1216. FetchInventoryDescendentsPacket fetch = new FetchInventoryDescendentsPacket();
  1217. fetch.AgentData.AgentID = Client.Self.AgentID;
  1218. fetch.AgentData.SessionID = Client.Self.SessionID;
  1219. fetch.InventoryData.FetchFolders = folders;
  1220. fetch.InventoryData.FetchItems = items;
  1221. fetch.InventoryData.FolderID = folder;
  1222. fetch.InventoryData.OwnerID = owner;
  1223. fetch.InventoryData.SortOrder = (int)order;
  1224. Client.Network.SendPacket(fetch);
  1225. }
  1226. /// <summary>
  1227. /// Request the contents of an inventory folder using HTTP capabilities
  1228. /// </summary>
  1229. /// <param name="folderID">The folder to search</param>
  1230. /// <param name="ownerID">The folder owners <seealso cref="UUID"/></param>
  1231. /// <param name="fetchFolders">true to return <seealso cref="InventoryManager.InventoryFolder"/>s contained in folder</param>
  1232. /// <param name="fetchItems">true to return <seealso cref="InventoryManager.InventoryItem"/>s containd in folder</param>
  1233. /// <param name="order">the sort order to return items in</param>
  1234. /// <seealso cref="InventoryManager.FolderContents"/>
  1235. public void RequestFolderContentsCap(UUID folderID, UUID ownerID, bool fetchFolders, bool fetchItems,
  1236. InventorySortOrder order)
  1237. {
  1238. Uri url = null;
  1239. if (Client.Network.CurrentSim.Caps == null ||
  1240. null == (url = Client.Network.CurrentSim.Caps.CapabilityURI("FetchInventoryDescendents2")))
  1241. {
  1242. Logger.Log("FetchInventoryDescendents2 capability not available in the current sim", Helpers.LogLevel.Warning, Client);
  1243. OnFolderUpdated(new FolderUpdatedEventArgs(folderID, false));
  1244. return;
  1245. }
  1246. try
  1247. {
  1248. CapsClient request = new CapsClient(url);
  1249. request.OnComplete += (client, result, error) =>
  1250. {
  1251. try
  1252. {
  1253. if (error != null) throw error;
  1254. OSDArray fetchedFolders = (OSDArray)((OSDMap)result)["folders"];
  1255. for (int fetchedFolderNr = 0; fetchedFolderNr < fetchedFolders.Count; fetchedFolderNr++)
  1256. {
  1257. OSDMap res = (OSDMap)fetchedFolders[fetchedFolderNr];
  1258. InventoryFolder fetchedFolder = null;
  1259. if (_Store.Contains(res["folder_id"])
  1260. && _Store[res["folder_id"]] is InventoryFolder)
  1261. {
  1262. fetchedFolder = (InventoryFolder)_Store[res["folder_id"]];
  1263. }
  1264. else
  1265. {
  1266. fetchedFolder = new InventoryFolder(res["folder_id"]);
  1267. _Store[res["folder_id"]] = fetchedFolder;
  1268. }
  1269. fetchedFolder.DescendentCount = res["descendents"];
  1270. fetchedFolder.Version = res["version"];
  1271. fetchedFolder.OwnerID = res["owner_id"];
  1272. _Store.GetNodeFor(fetchedFolder.UUID).NeedsUpdate = false;
  1273. // Do we have any descendants
  1274. if (fetchedFolder.DescendentCount > 0)
  1275. {
  1276. // Fetch descendent folders
  1277. if (res["categories"] is OSDArray)
  1278. {
  1279. OSDArray folders = (OSDArray)res["categories"];
  1280. for (int i = 0; i < folders.Count; i++)
  1281. {
  1282. OSDMap descFolder = (OSDMap)folders[i];
  1283. InventoryFolder folder;
  1284. if (!_Store.Contains(descFolder["category_id"]))
  1285. {
  1286. folder = new InventoryFolder(descFolder["category_id"]);
  1287. folder.ParentUUID = descFolder["parent_id"];
  1288. _Store[descFolder["category_id"]] = folder;
  1289. }
  1290. else
  1291. {
  1292. folder = (InventoryFolder)_Store[descFolder["category_id"]];
  1293. }
  1294. folder.OwnerID = descFolder["agent_id"];
  1295. folder.ParentUUID = descFolder["parent_id"];
  1296. folder.Name = descFolder["name"];
  1297. folder.Version = descFolder["version"];
  1298. folder.PreferredType = (AssetType)(int)descFolder["type_default"];
  1299. }
  1300. // Fetch descendent items
  1301. OSDArray items = (OSDArray)res["items"];
  1302. for (int i = 0; i < items.Count; i++)
  1303. {
  1304. OSDMap descItem = (OSDMap)items[i];
  1305. InventoryType type = (InventoryType)descItem["inv_type"].AsInteger();
  1306. if (type == InventoryType.Texture && (AssetType)descItem["type"].AsInteger() == AssetType.Object)
  1307. {
  1308. type = InventoryType.Attachment;
  1309. }
  1310. InventoryItem item = CreateInventoryItem(type, descItem["item_id"]);
  1311. item.ParentUUID = descItem["parent_id"];
  1312. item.Name = descItem["name"];
  1313. item.Description = descItem["desc"];
  1314. item.OwnerID = descItem["agent_id"];
  1315. item.AssetUUID = descItem["asset_id"];
  1316. item.AssetType = (AssetType)descItem["type"].AsInteger();
  1317. item.CreationDate = Utils.UnixTimeToDateTime(descItem["created_at"]);
  1318. item.Flags = descItem["flags"];
  1319. OSDMap perms = (OSDMap)descItem["permissions"];
  1320. item.CreatorID = perms["creator_id"];
  1321. item.LastOwnerID = perms["last_owner_id"];
  1322. item.Permissions = new Permissions(perms["base_mask"], perms["everyone_mask"], perms["group_mask"], perms["next_owner_mask"], perms["owner_mask"]);
  1323. item.GroupOwned = perms["is_owner_group"];
  1324. item.GroupID = perms["group_id"];
  1325. OSDMap sale = (OSDMap)descItem["sale_info"];
  1326. item.SalePrice = sale["sale_price"];
  1327. item.SaleType = (SaleType)sale["sale_type"].AsInteger();
  1328. _Store[item.UUID] = item;
  1329. }
  1330. }
  1331. }
  1332. OnFolderUpdated(new FolderUpdatedEventArgs(res["folder_id"], true));
  1333. }
  1334. }
  1335. catch (Exception exc)
  1336. {
  1337. Logger.Log(string.Format("Failed to fetch inventory descendants for folder id {0}: {1}\n{2}", folderID, exc.Message, exc.StackTrace.ToString()), Helpers.LogLevel.Warning, Client);
  1338. OnFolderUpdated(new FolderUpdatedEventArgs(folderID, false));
  1339. return;
  1340. }
  1341. };
  1342. // Construct request
  1343. OSDMap requestedFolder = new OSDMap(1);
  1344. requestedFolder["folder_id"] = folderID;
  1345. requestedFolder["owner_id"] = ownerID;
  1346. requestedFolder["fetch_folders"] = fetchFolders;
  1347. requestedFolder["fetch_items"] = fetchItems;
  1348. requestedFolder["sort_order"] = (int)order;
  1349. OSDArray requestedFolders = new OSDArray(1);
  1350. requestedFolders.Add(requestedFolder);
  1351. OSDMap req = new OSDMap(1);
  1352. req["folders"] = requestedFolders;
  1353. request.BeginGetResponse(req, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  1354. }
  1355. catch (Exception ex)
  1356. {
  1357. Logger.Log(string.Format("Failed to fetch inventory descendants for folder id {0}: {1}\n{2}", folderID, ex.Message, ex.StackTrace.ToString()), Helpers.LogLevel.Warning, Client);
  1358. OnFolderUpdated(new FolderUpdatedEventArgs(folderID, false));
  1359. return;
  1360. }
  1361. }
  1362. #endregion Fetch
  1363. #region Find
  1364. /// <summary>
  1365. /// Returns the UUID of the folder (category) that defaults to
  1366. /// containing 'type'. The folder is not necessarily only for that
  1367. /// type
  1368. /// </summary>
  1369. /// <remarks>This will return the root folder if one does not exist</remarks>
  1370. /// <param name="type"></param>
  1371. /// <returns>The UUID of the desired folder if found, the UUID of the RootFolder
  1372. /// if not found, or UUID.Zero on failure</returns>
  1373. public UUID FindFolderForType(AssetType type)
  1374. {
  1375. if (_Store == null)
  1376. {
  1377. Logger.Log("Inventory is null, FindFolderForType() lookup cannot continue",
  1378. Helpers.LogLevel.Error, Client);
  1379. return UUID.Zero;
  1380. }
  1381. // Folders go in the root
  1382. if (type == AssetType.Folder)
  1383. return _Store.RootFolder.UUID;
  1384. // Loop through each top-level directory and check if PreferredType
  1385. // matches the requested type
  1386. List<InventoryBase> contents = _Store.GetContents(_Store.RootFolder.UUID);
  1387. foreach (InventoryBase inv in contents)
  1388. {
  1389. if (inv is InventoryFolder)
  1390. {
  1391. InventoryFolder folder = inv as InventoryFolder;
  1392. if (folder.PreferredType == type)
  1393. return folder.UUID;
  1394. }
  1395. }
  1396. // No match found, return Root Folder ID
  1397. return _Store.RootFolder.UUID;
  1398. }
  1399. /// <summary>
  1400. /// Find an object in inventory using a specific path to search
  1401. /// </summary>
  1402. /// <param name="baseFolder">The folder to begin the search in</param>
  1403. /// <param name="inventoryOwner">The object owners <seealso cref="UUID"/></param>
  1404. /// <param name="path">A string path to search</param>
  1405. /// <param name="timeoutMS">milliseconds to wait for a reply</param>
  1406. /// <returns>Found items <seealso cref="UUID"/> or <seealso cref="UUID.Zero"/> if
  1407. /// timeout occurs or item is not found</returns>
  1408. public UUID FindObjectByPath(UUID baseFolder, UUID inventoryOwner, string path, int timeoutMS)
  1409. {
  1410. AutoResetEvent findEvent = new AutoResetEvent(false);
  1411. UUID foundItem = UUID.Zero;
  1412. EventHandler<FindObjectByPathReplyEventArgs> callback =
  1413. delegate(object sender, FindObjectByPathReplyEventArgs e)
  1414. {
  1415. if (e.Path == path)
  1416. {
  1417. foundItem = e.InventoryObjectID;
  1418. findEvent.Set();
  1419. }
  1420. };
  1421. FindObjectByPathReply += callback;
  1422. RequestFindObjectByPath(baseFolder, inventoryOwner, path);
  1423. findEvent.WaitOne(timeoutMS, false);
  1424. FindObjectByPathReply -= callback;
  1425. return foundItem;
  1426. }
  1427. /// <summary>
  1428. /// Find inventory items by path
  1429. /// </summary>
  1430. /// <param name="baseFolder">The folder to begin the search in</param>
  1431. /// <param name="inventoryOwner">The object owners <seealso cref="UUID"/></param>
  1432. /// <param name="path">A string path to search, folders/objects separated by a '/'</param>
  1433. /// <remarks>Results are sent to the <seealso cref="InventoryManager.OnFindObjectByPath"/> event</remarks>
  1434. public void RequestFindObjectByPath(UUID baseFolder, UUID inventoryOwner, string path)
  1435. {
  1436. if (path == null || path.Length == 0)
  1437. throw new ArgumentException("Empty path is not supported");
  1438. // Store this search
  1439. InventorySearch search;
  1440. search.Folder = baseFolder;
  1441. search.Owner = inventoryOwner;
  1442. search.Path = path.Split('/');
  1443. search.Level = 0;
  1444. lock (_Searches) _Searches.Add(search);
  1445. // Start the search
  1446. RequestFolderContents(baseFolder, inventoryOwner, true, true, InventorySortOrder.ByName);
  1447. }
  1448. /// <summary>
  1449. /// Search inventory Store object for an item or folder
  1450. /// </summary>
  1451. /// <param name="baseFolder">The folder to begin the search in</param>
  1452. /// <param name="path">An array which creates a path to search</param>
  1453. /// <param name="level">Number of levels below baseFolder to conduct searches</param>
  1454. /// <param name="firstOnly">if True, will stop searching after first match is found</param>
  1455. /// <returns>A list of inventory items found</returns>
  1456. public List<InventoryBase> LocalFind(UUID baseFolder, string[] path, int level, bool firstOnly)
  1457. {
  1458. List<InventoryBase> objects = new List<InventoryBase>();
  1459. //List<InventoryFolder> folders = new List<InventoryFolder>();
  1460. List<InventoryBase> contents = _Store.GetContents(baseFolder);
  1461. foreach (InventoryBase inv in contents)
  1462. {
  1463. if (inv.Name.CompareTo(path[level]) == 0)
  1464. {
  1465. if (level == path.Length - 1)
  1466. {
  1467. objects.Add(inv);
  1468. if (firstOnly) return objects;
  1469. }
  1470. else if (inv is InventoryFolder)
  1471. objects.AddRange(LocalFind(inv.UUID, path, level + 1, firstOnly));
  1472. }
  1473. }
  1474. return objects;
  1475. }
  1476. #endregion Find
  1477. #region Move/Rename
  1478. /// <summary>
  1479. /// Move an inventory item or folder to a new location
  1480. /// </summary>
  1481. /// <param name="item">The <seealso cref="T:InventoryBase"/> item or folder to move</param>
  1482. /// <param name="newParent">The <seealso cref="T:InventoryFolder"/> to move item or folder to</param>
  1483. public void Move(InventoryBase item, InventoryFolder newParent)
  1484. {
  1485. if (item is InventoryFolder)
  1486. MoveFolder(item.UUID, newParent.UUID);
  1487. else
  1488. MoveItem(item.UUID, newParent.UUID);
  1489. }
  1490. /// <summary>
  1491. /// Move an inventory item or folder to a new location and change its name
  1492. /// </summary>
  1493. /// <param name="item">The <seealso cref="T:InventoryBase"/> item or folder to move</param>
  1494. /// <param name="newParent">The <seealso cref="T:InventoryFolder"/> to move item or folder to</param>
  1495. /// <param name="newName">The name to change the item or folder to</param>
  1496. public void Move(InventoryBase item, InventoryFolder newParent, string newName)
  1497. {
  1498. if (item is InventoryFolder)
  1499. MoveFolder(item.UUID, newParent.UUID, newName);
  1500. else
  1501. MoveItem(item.UUID, newParent.UUID, newName);
  1502. }
  1503. /// <summary>
  1504. /// Move and rename a folder
  1505. /// </summary>
  1506. /// <param name="folderID">The source folders <seealso cref="UUID"/></param>
  1507. /// <param name="newparentID">The destination folders <seealso cref="UUID"/></param>
  1508. /// <param name="newName">The name to change the folder to</param>
  1509. public void MoveFolder(UUID folderID, UUID newparentID, string newName)
  1510. {
  1511. UpdateFolderProperties(folderID, newparentID, newName, AssetType.Unknown);
  1512. }
  1513. /// <summary>
  1514. /// Update folder properties
  1515. /// </summary>
  1516. /// <param name="folderID"><seealso cref="UUID"/> of the folder to update</param>
  1517. /// <param name="parentID">Sets folder's parent to <seealso cref="UUID"/></param>
  1518. /// <param name="name">Folder name</param>
  1519. /// <param name="type">Folder type</param>
  1520. public void UpdateFolderProperties(UUID folderID, UUID parentID, string name, AssetType type)
  1521. {
  1522. lock (Store)
  1523. {
  1524. if (_Store.Contains(folderID))
  1525. {
  1526. InventoryFolder inv = (InventoryFolder)Store[folderID];
  1527. inv.Name = name;
  1528. inv.ParentUUID = parentID;
  1529. inv.PreferredType = type;
  1530. _Store.UpdateNodeFor(inv);
  1531. }
  1532. }
  1533. UpdateInventoryFolderPacket invFolder = new UpdateInventoryFolderPacket();
  1534. invFolder.AgentData.AgentID = Client.Self.AgentID;
  1535. invFolder.AgentData.SessionID = Client.Self.SessionID;
  1536. invFolder.FolderData = new UpdateInventoryFolderPacket.FolderDataBlock[1];
  1537. invFolder.FolderData[0] = new UpdateInventoryFolderPacket.FolderDataBlock();
  1538. invFolder.FolderData[0].FolderID = folderID;
  1539. invFolder.FolderData[0].ParentID = parentID;
  1540. invFolder.FolderData[0].Name = Utils.StringToBytes(name);
  1541. invFolder.FolderData[0].Type = (sbyte)type;
  1542. Client.Network.SendPacket(invFolder);
  1543. }
  1544. /// <summary>
  1545. /// Move a folder
  1546. /// </summary>
  1547. /// <param name="folderID">The source folders <seealso cref="UUID"/></param>
  1548. /// <param name="newParentID">The destination folders <seealso cref="UUID"/></param>
  1549. public void MoveFolder(UUID folderID, UUID newParentID)
  1550. {
  1551. lock (Store)
  1552. {
  1553. if (_Store.Contains(folderID))
  1554. {
  1555. InventoryBase inv = Store[folderID];
  1556. inv.ParentUUID = newParentID;
  1557. _Store.UpdateNodeFor(inv);
  1558. }
  1559. }
  1560. MoveInventoryFolderPacket move = new MoveInventoryFolderPacket();
  1561. move.AgentData.AgentID = Client.Self.AgentID;
  1562. move.AgentData.SessionID = Client.Self.SessionID;
  1563. move.AgentData.Stamp = false; //FIXME: ??
  1564. move.InventoryData = new MoveInventoryFolderPacket.InventoryDataBlock[1];
  1565. move.InventoryData[0] = new MoveInventoryFolderPacket.InventoryDataBlock();
  1566. move.InventoryData[0].FolderID = folderID;
  1567. move.InventoryData[0].ParentID = newParentID;
  1568. Client.Network.SendPacket(move);
  1569. }
  1570. /// <summary>
  1571. /// Move multiple folders, the keys in the Dictionary parameter,
  1572. /// to a new parents, the value of that folder's key.
  1573. /// </summary>
  1574. /// <param name="foldersNewParents">A Dictionary containing the
  1575. /// <seealso cref="UUID"/> of the source as the key, and the
  1576. /// <seealso cref="UUID"/> of the destination as the value</param>
  1577. public void MoveFolders(Dictionary<UUID, UUID> foldersNewParents)
  1578. {
  1579. // FIXME: Use two List<UUID> to stay consistent
  1580. lock (Store)
  1581. {
  1582. foreach (KeyValuePair<UUID, UUID> entry in foldersNewParents)
  1583. {
  1584. if (_Store.Contains(entry.Key))
  1585. {
  1586. InventoryBase inv = _Store[entry.Key];
  1587. inv.ParentUUID = entry.Value;
  1588. _Store.UpdateNodeFor(inv);
  1589. }
  1590. }
  1591. }
  1592. //TODO: Test if this truly supports multiple-folder move
  1593. MoveInventoryFolderPacket move = new MoveInventoryFolderPacket();
  1594. move.AgentData.AgentID = Client.Self.AgentID;
  1595. move.AgentData.SessionID = Client.Self.SessionID;
  1596. move.AgentData.Stamp = false; //FIXME: ??
  1597. move.InventoryData = new MoveInventoryFolderPacket.InventoryDataBlock[foldersNewParents.Count];
  1598. int index = 0;
  1599. foreach (KeyValuePair<UUID, UUID> folder in foldersNewParents)
  1600. {
  1601. MoveInventoryFolderPacket.InventoryDataBlock block = new MoveInventoryFolderPacket.InventoryDataBlock();
  1602. block.FolderID = folder.Key;
  1603. block.ParentID = folder.Value;
  1604. move.InventoryData[index++] = block;
  1605. }
  1606. Client.Network.SendPacket(move);
  1607. }
  1608. /// <summary>
  1609. /// Move an inventory item to a new folder
  1610. /// </summary>
  1611. /// <param name="itemID">The <seealso cref="UUID"/> of the source item to move</param>
  1612. /// <param name="folderID">The <seealso cref="UUID"/> of the destination folder</param>
  1613. public void MoveItem(UUID itemID, UUID folderID)
  1614. {
  1615. MoveItem(itemID, folderID, String.Empty);
  1616. }
  1617. /// <summary>
  1618. /// Move and rename an inventory item
  1619. /// </summary>
  1620. /// <param name="itemID">The <seealso cref="UUID"/> of the source item to move</param>
  1621. /// <param name="folderID">The <seealso cref="UUID"/> of the destination folder</param>
  1622. /// <param name="newName">The name to change the folder to</param>
  1623. public void MoveItem(UUID itemID, UUID folderID, string newName)
  1624. {
  1625. lock (_Store)
  1626. {
  1627. if (_Store.Contains(itemID))
  1628. {
  1629. InventoryBase inv = _Store[itemID];
  1630. inv.Name = newName;
  1631. inv.ParentUUID = folderID;
  1632. _Store.UpdateNodeFor(inv);
  1633. }
  1634. }
  1635. MoveInventoryItemPacket move = new MoveInventoryItemPacket();
  1636. move.AgentData.AgentID = Client.Self.AgentID;
  1637. move.AgentData.SessionID = Client.Self.SessionID;
  1638. move.AgentData.Stamp = false; //FIXME: ??
  1639. move.InventoryData = new MoveInventoryItemPacket.InventoryDataBlock[1];
  1640. move.InventoryData[0] = new MoveInventoryItemPacket.InventoryDataBlock();
  1641. move.InventoryData[0].ItemID = itemID;
  1642. move.InventoryData[0].FolderID = folderID;
  1643. move.InventoryData[0].NewName = Utils.StringToBytes(newName);
  1644. Client.Network.SendPacket(move);
  1645. }
  1646. /// <summary>
  1647. /// Move multiple inventory items to new locations
  1648. /// </summary>
  1649. /// <param name="itemsNewParents">A Dictionary containing the
  1650. /// <seealso cref="UUID"/> of the source item as the key, and the
  1651. /// <seealso cref="UUID"/> of the destination folder as the value</param>
  1652. public void MoveItems(Dictionary<UUID, UUID> itemsNewParents)
  1653. {
  1654. lock (_Store)
  1655. {
  1656. foreach (KeyValuePair<UUID, UUID> entry in itemsNewParents)
  1657. {
  1658. if (_Store.Contains(entry.Key))
  1659. {
  1660. InventoryBase inv = _Store[entry.Key];
  1661. inv.ParentUUID = entry.Value;
  1662. _Store.UpdateNodeFor(inv);
  1663. }
  1664. }
  1665. }
  1666. MoveInventoryItemPacket move = new MoveInventoryItemPacket();
  1667. move.AgentData.AgentID = Client.Self.AgentID;
  1668. move.AgentData.SessionID = Client.Self.SessionID;
  1669. move.AgentData.Stamp = false; //FIXME: ??
  1670. move.InventoryData = new MoveInventoryItemPacket.InventoryDataBlock[itemsNewParents.Count];
  1671. int index = 0;
  1672. foreach (KeyValuePair<UUID, UUID> entry in itemsNewParents)
  1673. {
  1674. MoveInventoryItemPacket.InventoryDataBlock block = new MoveInventoryItemPacket.InventoryDataBlock();
  1675. block.ItemID = entry.Key;
  1676. block.FolderID = entry.Value;
  1677. block.NewName = Utils.EmptyBytes;
  1678. move.InventoryData[index++] = block;
  1679. }
  1680. Client.Network.SendPacket(move);
  1681. }
  1682. #endregion Move
  1683. #region Remove
  1684. /// <summary>
  1685. /// Remove descendants of a folder
  1686. /// </summary>
  1687. /// <param name="folder">The <seealso cref="UUID"/> of the folder</param>
  1688. public void RemoveDescendants(UUID folder)
  1689. {
  1690. PurgeInventoryDescendentsPacket purge = new PurgeInventoryDescendentsPacket();
  1691. purge.AgentData.AgentID = Client.Self.AgentID;
  1692. purge.AgentData.SessionID = Client.Self.SessionID;
  1693. purge.InventoryData.FolderID = folder;
  1694. Client.Network.SendPacket(purge);
  1695. // Update our local copy
  1696. lock (_Store)
  1697. {
  1698. if (_Store.Contains(folder))
  1699. {
  1700. List<InventoryBase> contents = _Store.GetContents(folder);
  1701. foreach (InventoryBase obj in contents)
  1702. {
  1703. _Store.RemoveNodeFor(obj);
  1704. }
  1705. }
  1706. }
  1707. }
  1708. /// <summary>
  1709. /// Remove a single item from inventory
  1710. /// </summary>
  1711. /// <param name="item">The <seealso cref="UUID"/> of the inventory item to remove</param>
  1712. public void RemoveItem(UUID item)
  1713. {
  1714. List<UUID> items = new List<UUID>(1);
  1715. items.Add(item);
  1716. Remove(items, null);
  1717. }
  1718. /// <summary>
  1719. /// Remove a folder from inventory
  1720. /// </summary>
  1721. /// <param name="folder">The <seealso cref="UUID"/> of the folder to remove</param>
  1722. public void RemoveFolder(UUID folder)
  1723. {
  1724. List<UUID> folders = new List<UUID>(1);
  1725. folders.Add(folder);
  1726. Remove(null, folders);
  1727. }
  1728. /// <summary>
  1729. /// Remove multiple items or folders from inventory
  1730. /// </summary>
  1731. /// <param name="items">A List containing the <seealso cref="UUID"/>s of items to remove</param>
  1732. /// <param name="folders">A List containing the <seealso cref="UUID"/>s of the folders to remove</param>
  1733. public void Remove(List<UUID> items, List<UUID> folders)
  1734. {
  1735. if ((items == null || items.Count == 0) && (folders == null || folders.Count == 0))
  1736. return;
  1737. RemoveInventoryObjectsPacket rem = new RemoveInventoryObjectsPacket();
  1738. rem.AgentData.AgentID = Client.Self.AgentID;
  1739. rem.AgentData.SessionID = Client.Self.SessionID;
  1740. if (items == null || items.Count == 0)
  1741. {
  1742. // To indicate that we want no items removed:
  1743. rem.ItemData = new RemoveInventoryObjectsPacket.ItemDataBlock[1];
  1744. rem.ItemData[0] = new RemoveInventoryObjectsPacket.ItemDataBlock();
  1745. rem.ItemData[0].ItemID = UUID.Zero;
  1746. }
  1747. else
  1748. {
  1749. lock (_Store)
  1750. {
  1751. rem.ItemData = new RemoveInventoryObjectsPacket.ItemDataBlock[items.Count];
  1752. for (int i = 0; i < items.Count; i++)
  1753. {
  1754. rem.ItemData[i] = new RemoveInventoryObjectsPacket.ItemDataBlock();
  1755. rem.ItemData[i].ItemID = items[i];
  1756. // Update local copy
  1757. if (_Store.Contains(items[i]))
  1758. _Store.RemoveNodeFor(Store[items[i]]);
  1759. }
  1760. }
  1761. }
  1762. if (folders == null || folders.Count == 0)
  1763. {
  1764. // To indicate we want no folders removed:
  1765. rem.FolderData = new RemoveInventoryObjectsPacket.FolderDataBlock[1];
  1766. rem.FolderData[0] = new RemoveInventoryObjectsPacket.FolderDataBlock();
  1767. rem.FolderData[0].FolderID = UUID.Zero;
  1768. }
  1769. else
  1770. {
  1771. lock (_Store)
  1772. {
  1773. rem.FolderData = new RemoveInventoryObjectsPacket.FolderDataBlock[folders.Count];
  1774. for (int i = 0; i < folders.Count; i++)
  1775. {
  1776. rem.FolderData[i] = new RemoveInventoryObjectsPacket.FolderDataBlock();
  1777. rem.FolderData[i].FolderID = folders[i];
  1778. // Update local copy
  1779. if (_Store.Contains(folders[i]))
  1780. _Store.RemoveNodeFor(Store[folders[i]]);
  1781. }
  1782. }
  1783. }
  1784. Client.Network.SendPacket(rem);
  1785. }
  1786. /// <summary>
  1787. /// Empty the Lost and Found folder
  1788. /// </summary>
  1789. public void EmptyLostAndFound()
  1790. {
  1791. EmptySystemFolder(AssetType.LostAndFoundFolder);
  1792. }
  1793. /// <summary>
  1794. /// Empty the Trash folder
  1795. /// </summary>
  1796. public void EmptyTrash()
  1797. {
  1798. EmptySystemFolder(AssetType.TrashFolder);
  1799. }
  1800. private void EmptySystemFolder(AssetType folderType)
  1801. {
  1802. List<InventoryBase> items = _Store.GetContents(_Store.RootFolder);
  1803. UUID folderKey = UUID.Zero;
  1804. foreach (InventoryBase item in items)
  1805. {
  1806. if ((item as InventoryFolder) != null)
  1807. {
  1808. InventoryFolder folder = item as InventoryFolder;
  1809. if (folder.PreferredType == folderType)
  1810. {
  1811. folderKey = folder.UUID;
  1812. break;
  1813. }
  1814. }
  1815. }
  1816. items = _Store.GetContents(folderKey);
  1817. List<UUID> remItems = new List<UUID>();
  1818. List<UUID> remFolders = new List<UUID>();
  1819. foreach (InventoryBase item in items)
  1820. {
  1821. if ((item as InventoryFolder) != null)
  1822. {
  1823. remFolders.Add(item.UUID);
  1824. }
  1825. else
  1826. {
  1827. remItems.Add(item.UUID);
  1828. }
  1829. }
  1830. Remove(remItems, remFolders);
  1831. }
  1832. #endregion Remove
  1833. #region Create
  1834. /// <summary>
  1835. ///
  1836. /// </summary>
  1837. /// <param name="parentFolder"></param>
  1838. /// <param name="name"></param>
  1839. /// <param name="description"></param>
  1840. /// <param name="type"></param>
  1841. /// <param name="assetTransactionID">Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here.</param>
  1842. /// <param name="invType"></param>
  1843. /// <param name="nextOwnerMask"></param>
  1844. /// <param name="callback"></param>
  1845. public void RequestCreateItem(UUID parentFolder, string name, string description, AssetType type, UUID assetTransactionID,
  1846. InventoryType invType, PermissionMask nextOwnerMask, ItemCreatedCallback callback)
  1847. {
  1848. // Even though WearableType 0 is Shape, in this context it is treated as NOT_WEARABLE
  1849. RequestCreateItem(parentFolder, name, description, type, assetTransactionID, invType, (WearableType)0, nextOwnerMask,
  1850. callback);
  1851. }
  1852. /// <summary>
  1853. ///
  1854. /// </summary>
  1855. /// <param name="parentFolder"></param>
  1856. /// <param name="name"></param>
  1857. /// <param name="description"></param>
  1858. /// <param name="type"></param>
  1859. /// <param name="assetTransactionID">Proper use is to upload the inventory's asset first, then provide the Asset's TransactionID here.</param>
  1860. /// <param name="invType"></param>
  1861. /// <param name="wearableType"></param>
  1862. /// <param name="nextOwnerMask"></param>
  1863. /// <param name="callback"></param>
  1864. public void RequestCreateItem(UUID parentFolder, string name, string description, AssetType type, UUID assetTransactionID,
  1865. InventoryType invType, WearableType wearableType, PermissionMask nextOwnerMask, ItemCreatedCallback callback)
  1866. {
  1867. CreateInventoryItemPacket create = new CreateInventoryItemPacket();
  1868. create.AgentData.AgentID = Client.Self.AgentID;
  1869. create.AgentData.SessionID = Client.Self.SessionID;
  1870. create.InventoryBlock.CallbackID = RegisterItemCreatedCallback(callback);
  1871. create.InventoryBlock.FolderID = parentFolder;
  1872. create.InventoryBlock.TransactionID = assetTransactionID;
  1873. create.InventoryBlock.NextOwnerMask = (uint)nextOwnerMask;
  1874. create.InventoryBlock.Type = (sbyte)type;
  1875. create.InventoryBlock.InvType = (sbyte)invType;
  1876. create.InventoryBlock.WearableType = (byte)wearableType;
  1877. create.InventoryBlock.Name = Utils.StringToBytes(name);
  1878. create.InventoryBlock.Description = Utils.StringToBytes(description);
  1879. Client.Network.SendPacket(create);
  1880. }
  1881. /// <summary>
  1882. /// Creates a new inventory folder
  1883. /// </summary>
  1884. /// <param name="parentID">ID of the folder to put this folder in</param>
  1885. /// <param name="name">Name of the folder to create</param>
  1886. /// <returns>The UUID of the newly created folder</returns>
  1887. public UUID CreateFolder(UUID parentID, string name)
  1888. {
  1889. return CreateFolder(parentID, name, AssetType.Unknown);
  1890. }
  1891. /// <summary>
  1892. /// Creates a new inventory folder
  1893. /// </summary>
  1894. /// <param name="parentID">ID of the folder to put this folder in</param>
  1895. /// <param name="name">Name of the folder to create</param>
  1896. /// <param name="preferredType">Sets this folder as the default folder
  1897. /// for new assets of the specified type. Use <code>AssetType.Unknown</code>
  1898. /// to create a normal folder, otherwise it will likely create a
  1899. /// duplicate of an existing folder type</param>
  1900. /// <returns>The UUID of the newly created folder</returns>
  1901. /// <remarks>If you specify a preferred type of <code>AsseType.Folder</code>
  1902. /// it will create a new root folder which may likely cause all sorts
  1903. /// of strange problems</remarks>
  1904. public UUID CreateFolder(UUID parentID, string name, AssetType preferredType)
  1905. {
  1906. UUID id = UUID.Random();
  1907. // Assign a folder name if one is not already set
  1908. if (String.IsNullOrEmpty(name))
  1909. {
  1910. if (preferredType >= AssetType.Texture && preferredType <= AssetType.Gesture)
  1911. {
  1912. name = _NewFolderNames[(int)preferredType];
  1913. }
  1914. else
  1915. {
  1916. name = "New Folder";
  1917. }
  1918. }
  1919. // Create the new folder locally
  1920. InventoryFolder newFolder = new InventoryFolder(id);
  1921. newFolder.Version = 1;
  1922. newFolder.DescendentCount = 0;
  1923. newFolder.ParentUUID = parentID;
  1924. newFolder.PreferredType = preferredType;
  1925. newFolder.Name = name;
  1926. newFolder.OwnerID = Client.Self.AgentID;
  1927. // Update the local store
  1928. try { _Store[newFolder.UUID] = newFolder; }
  1929. catch (InventoryException ie) { Logger.Log(ie.Message, Helpers.LogLevel.Warning, Client, ie); }
  1930. // Create the create folder packet and send it
  1931. CreateInventoryFolderPacket create = new CreateInventoryFolderPacket();
  1932. create.AgentData.AgentID = Client.Self.AgentID;
  1933. create.AgentData.SessionID = Client.Self.SessionID;
  1934. create.FolderData.FolderID = id;
  1935. create.FolderData.ParentID = parentID;
  1936. create.FolderData.Type = (sbyte)preferredType;
  1937. create.FolderData.Name = Utils.StringToBytes(name);
  1938. Client.Network.SendPacket(create);
  1939. return id;
  1940. }
  1941. /// <summary>
  1942. /// Create an inventory item and upload asset data
  1943. /// </summary>
  1944. /// <param name="data">Asset data</param>
  1945. /// <param name="name">Inventory item name</param>
  1946. /// <param name="description">Inventory item description</param>
  1947. /// <param name="assetType">Asset type</param>
  1948. /// <param name="invType">Inventory type</param>
  1949. /// <param name="folderID">Put newly created inventory in this folder</param>
  1950. /// <param name="callback">Delegate that will receive feedback on success or failure</param>
  1951. public void RequestCreateItemFromAsset(byte[] data, string name, string description, AssetType assetType,
  1952. InventoryType invType, UUID folderID, ItemCreatedFromAssetCallback callback)
  1953. {
  1954. Permissions permissions = new Permissions();
  1955. permissions.EveryoneMask = PermissionMask.None;
  1956. permissions.GroupMask = PermissionMask.None;
  1957. permissions.NextOwnerMask = PermissionMask.All;
  1958. RequestCreateItemFromAsset(data, name, description, assetType, invType, folderID, permissions, callback);
  1959. }
  1960. /// <summary>
  1961. /// Create an inventory item and upload asset data
  1962. /// </summary>
  1963. /// <param name="data">Asset data</param>
  1964. /// <param name="name">Inventory item name</param>
  1965. /// <param name="description">Inventory item description</param>
  1966. /// <param name="assetType">Asset type</param>
  1967. /// <param name="invType">Inventory type</param>
  1968. /// <param name="folderID">Put newly created inventory in this folder</param>
  1969. /// <param name="permissions">Permission of the newly created item
  1970. /// (EveryoneMask, GroupMask, and NextOwnerMask of Permissions struct are supported)</param>
  1971. /// <param name="callback">Delegate that will receive feedback on success or failure</param>
  1972. public void RequestCreateItemFromAsset(byte[] data, string name, string description, AssetType assetType,
  1973. InventoryType invType, UUID folderID, Permissions permissions, ItemCreatedFromAssetCallback callback)
  1974. {
  1975. if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null)
  1976. throw new Exception("NewFileAgentInventory capability is not currently available");
  1977. Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("NewFileAgentInventory");
  1978. if (url != null)
  1979. {
  1980. OSDMap query = new OSDMap();
  1981. query.Add("folder_id", OSD.FromUUID(folderID));
  1982. query.Add("asset_type", OSD.FromString(Utils.AssetTypeToString(assetType)));
  1983. query.Add("inventory_type", OSD.FromString(Utils.InventoryTypeToString(invType)));
  1984. query.Add("name", OSD.FromString(name));
  1985. query.Add("description", OSD.FromString(description));
  1986. query.Add("everyone_mask", OSD.FromInteger((int)permissions.EveryoneMask));
  1987. query.Add("group_mask", OSD.FromInteger((int)permissions.GroupMask));
  1988. query.Add("next_owner_mask", OSD.FromInteger((int)permissions.NextOwnerMask));
  1989. query.Add("expected_upload_cost", OSD.FromInteger(Client.Settings.UPLOAD_COST));
  1990. // Make the request
  1991. CapsClient request = new CapsClient(url);
  1992. request.OnComplete += CreateItemFromAssetResponse;
  1993. request.UserData = new object[] { callback, data, Client.Settings.CAPS_TIMEOUT, query };
  1994. request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  1995. }
  1996. else
  1997. {
  1998. throw new Exception("NewFileAgentInventory capability is not currently available");
  1999. }
  2000. }
  2001. /// <summary>
  2002. /// Creates inventory link to another inventory item or folder
  2003. /// </summary>
  2004. /// <param name="folderID">Put newly created link in folder with this UUID</param>
  2005. /// <param name="bse">Inventory item or folder</param>
  2006. /// <param name="callback">Method to call upon creation of the link</param>
  2007. public void CreateLink(UUID folderID, InventoryBase bse, ItemCreatedCallback callback)
  2008. {
  2009. if (bse is InventoryFolder)
  2010. {
  2011. InventoryFolder folder = (InventoryFolder)bse;
  2012. CreateLink(folderID, folder, callback);
  2013. }
  2014. else if (bse is InventoryItem)
  2015. {
  2016. InventoryItem item = (InventoryItem)bse;
  2017. CreateLink(folderID, item.UUID, item.Name, item.Description, AssetType.Link, item.InventoryType, UUID.Random(), callback);
  2018. }
  2019. }
  2020. /// <summary>
  2021. /// Creates inventory link to another inventory item
  2022. /// </summary>
  2023. /// <param name="folderID">Put newly created link in folder with this UUID</param>
  2024. /// <param name="item">Original inventory item</param>
  2025. /// <param name="callback">Method to call upon creation of the link</param>
  2026. public void CreateLink(UUID folderID, InventoryItem item, ItemCreatedCallback callback)
  2027. {
  2028. CreateLink(folderID, item.UUID, item.Name, item.Description, AssetType.Link, item.InventoryType, UUID.Random(), callback);
  2029. }
  2030. /// <summary>
  2031. /// Creates inventory link to another inventory folder
  2032. /// </summary>
  2033. /// <param name="folderID">Put newly created link in folder with this UUID</param>
  2034. /// <param name="folder">Original inventory folder</param>
  2035. /// <param name="callback">Method to call upon creation of the link</param>
  2036. public void CreateLink(UUID folderID, InventoryFolder folder, ItemCreatedCallback callback)
  2037. {
  2038. CreateLink(folderID, folder.UUID, folder.Name, "", AssetType.LinkFolder, InventoryType.Folder, UUID.Random(), callback);
  2039. }
  2040. /// <summary>
  2041. /// Creates inventory link to another inventory item or folder
  2042. /// </summary>
  2043. /// <param name="folderID">Put newly created link in folder with this UUID</param>
  2044. /// <param name="itemID">Original item's UUID</param>
  2045. /// <param name="name">Name</param>
  2046. /// <param name="description">Description</param>
  2047. /// <param name="assetType">Asset Type</param>
  2048. /// <param name="invType">Inventory Type</param>
  2049. /// <param name="transactionID">Transaction UUID</param>
  2050. /// <param name="callback">Method to call upon creation of the link</param>
  2051. public void CreateLink(UUID folderID, UUID itemID, string name, string description, AssetType assetType, InventoryType invType, UUID transactionID, ItemCreatedCallback callback)
  2052. {
  2053. LinkInventoryItemPacket create = new LinkInventoryItemPacket();
  2054. create.AgentData.AgentID = Client.Self.AgentID;
  2055. create.AgentData.SessionID = Client.Self.SessionID;
  2056. create.InventoryBlock.CallbackID = RegisterItemCreatedCallback(callback);
  2057. create.InventoryBlock.FolderID = folderID;
  2058. create.InventoryBlock.TransactionID = transactionID;
  2059. create.InventoryBlock.OldItemID = itemID;
  2060. create.InventoryBlock.Type = (sbyte)assetType;
  2061. create.InventoryBlock.InvType = (sbyte)invType;
  2062. create.InventoryBlock.Name = Utils.StringToBytes(name);
  2063. create.InventoryBlock.Description = Utils.StringToBytes(description);
  2064. Client.Network.SendPacket(create);
  2065. }
  2066. #endregion Create
  2067. #region Copy
  2068. /// <summary>
  2069. ///
  2070. /// </summary>
  2071. /// <param name="item"></param>
  2072. /// <param name="newParent"></param>
  2073. /// <param name="newName"></param>
  2074. /// <param name="callback"></param>
  2075. public void RequestCopyItem(UUID item, UUID newParent, string newName, ItemCopiedCallback callback)
  2076. {
  2077. RequestCopyItem(item, newParent, newName, Client.Self.AgentID, callback);
  2078. }
  2079. /// <summary>
  2080. ///
  2081. /// </summary>
  2082. /// <param name="item"></param>
  2083. /// <param name="newParent"></param>
  2084. /// <param name="newName"></param>
  2085. /// <param name="oldOwnerID"></param>
  2086. /// <param name="callback"></param>
  2087. public void RequestCopyItem(UUID item, UUID newParent, string newName, UUID oldOwnerID,
  2088. ItemCopiedCallback callback)
  2089. {
  2090. List<UUID> items = new List<UUID>(1);
  2091. items.Add(item);
  2092. List<UUID> folders = new List<UUID>(1);
  2093. folders.Add(newParent);
  2094. List<string> names = new List<string>(1);
  2095. names.Add(newName);
  2096. RequestCopyItems(items, folders, names, oldOwnerID, callback);
  2097. }
  2098. /// <summary>
  2099. ///
  2100. /// </summary>
  2101. /// <param name="items"></param>
  2102. /// <param name="targetFolders"></param>
  2103. /// <param name="newNames"></param>
  2104. /// <param name="oldOwnerID"></param>
  2105. /// <param name="callback"></param>
  2106. public void RequestCopyItems(List<UUID> items, List<UUID> targetFolders, List<string> newNames,
  2107. UUID oldOwnerID, ItemCopiedCallback callback)
  2108. {
  2109. if (items.Count != targetFolders.Count || (newNames != null && items.Count != newNames.Count))
  2110. throw new ArgumentException("All list arguments must have an equal number of entries");
  2111. uint callbackID = RegisterItemsCopiedCallback(callback);
  2112. CopyInventoryItemPacket copy = new CopyInventoryItemPacket();
  2113. copy.AgentData.AgentID = Client.Self.AgentID;
  2114. copy.AgentData.SessionID = Client.Self.SessionID;
  2115. copy.InventoryData = new CopyInventoryItemPacket.InventoryDataBlock[items.Count];
  2116. for (int i = 0; i < items.Count; ++i)
  2117. {
  2118. copy.InventoryData[i] = new CopyInventoryItemPacket.InventoryDataBlock();
  2119. copy.InventoryData[i].CallbackID = callbackID;
  2120. copy.InventoryData[i].NewFolderID = targetFolders[i];
  2121. copy.InventoryData[i].OldAgentID = oldOwnerID;
  2122. copy.InventoryData[i].OldItemID = items[i];
  2123. if (newNames != null && !String.IsNullOrEmpty(newNames[i]))
  2124. copy.InventoryData[i].NewName = Utils.StringToBytes(newNames[i]);
  2125. else
  2126. copy.InventoryData[i].NewName = Utils.EmptyBytes;
  2127. }
  2128. Client.Network.SendPacket(copy);
  2129. }
  2130. /// <summary>
  2131. /// Request a copy of an asset embedded within a notecard
  2132. /// </summary>
  2133. /// <param name="objectID">Usually UUID.Zero for copying an asset from a notecard</param>
  2134. /// <param name="notecardID">UUID of the notecard to request an asset from</param>
  2135. /// <param name="folderID">Target folder for asset to go to in your inventory</param>
  2136. /// <param name="itemID">UUID of the embedded asset</param>
  2137. /// <param name="callback">callback to run when item is copied to inventory</param>
  2138. public void RequestCopyItemFromNotecard(UUID objectID, UUID notecardID, UUID folderID, UUID itemID, ItemCopiedCallback callback)
  2139. {
  2140. _ItemCopiedCallbacks[0] = callback; //Notecards always use callback ID 0
  2141. Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("CopyInventoryFromNotecard");
  2142. if (url != null)
  2143. {
  2144. CopyInventoryFromNotecardMessage message = new CopyInventoryFromNotecardMessage();
  2145. message.CallbackID = 0;
  2146. message.FolderID = folderID;
  2147. message.ItemID = itemID;
  2148. message.NotecardID = notecardID;
  2149. message.ObjectID = objectID;
  2150. CapsClient request = new CapsClient(url);
  2151. request.BeginGetResponse(message.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  2152. }
  2153. else
  2154. {
  2155. CopyInventoryFromNotecardPacket copy = new CopyInventoryFromNotecardPacket();
  2156. copy.AgentData.AgentID = Client.Self.AgentID;
  2157. copy.AgentData.SessionID = Client.Self.SessionID;
  2158. copy.NotecardData.ObjectID = objectID;
  2159. copy.NotecardData.NotecardItemID = notecardID;
  2160. copy.InventoryData = new CopyInventoryFromNotecardPacket.InventoryDataBlock[1];
  2161. copy.InventoryData[0] = new CopyInventoryFromNotecardPacket.InventoryDataBlock();
  2162. copy.InventoryData[0].FolderID = folderID;
  2163. copy.InventoryData[0].ItemID = itemID;
  2164. Client.Network.SendPacket(copy);
  2165. }
  2166. }
  2167. #endregion Copy
  2168. #region Update
  2169. /// <summary>
  2170. ///
  2171. /// </summary>
  2172. /// <param name="item"></param>
  2173. public void RequestUpdateItem(InventoryItem item)
  2174. {
  2175. List<InventoryItem> items = new List<InventoryItem>(1);
  2176. items.Add(item);
  2177. RequestUpdateItems(items, UUID.Random());
  2178. }
  2179. /// <summary>
  2180. ///
  2181. /// </summary>
  2182. /// <param name="items"></param>
  2183. public void RequestUpdateItems(List<InventoryItem> items)
  2184. {
  2185. RequestUpdateItems(items, UUID.Random());
  2186. }
  2187. /// <summary>
  2188. ///
  2189. /// </summary>
  2190. /// <param name="items"></param>
  2191. /// <param name="transactionID"></param>
  2192. public void RequestUpdateItems(List<InventoryItem> items, UUID transactionID)
  2193. {
  2194. UpdateInventoryItemPacket update = new UpdateInventoryItemPacket();
  2195. update.AgentData.AgentID = Client.Self.AgentID;
  2196. update.AgentData.SessionID = Client.Self.SessionID;
  2197. update.AgentData.TransactionID = transactionID;
  2198. update.InventoryData = new UpdateInventoryItemPacket.InventoryDataBlock[items.Count];
  2199. for (int i = 0; i < items.Count; i++)
  2200. {
  2201. InventoryItem item = items[i];
  2202. UpdateInventoryItemPacket.InventoryDataBlock block = new UpdateInventoryItemPacket.InventoryDataBlock();
  2203. block.BaseMask = (uint)item.Permissions.BaseMask;
  2204. block.CRC = ItemCRC(item);
  2205. block.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
  2206. block.CreatorID = item.CreatorID;
  2207. block.Description = Utils.StringToBytes(item.Description);
  2208. block.EveryoneMask = (uint)item.Permissions.EveryoneMask;
  2209. block.Flags = (uint)item.Flags;
  2210. block.FolderID = item.ParentUUID;
  2211. block.GroupID = item.GroupID;
  2212. block.GroupMask = (uint)item.Permissions.GroupMask;
  2213. block.GroupOwned = item.GroupOwned;
  2214. block.InvType = (sbyte)item.InventoryType;
  2215. block.ItemID = item.UUID;
  2216. block.Name = Utils.StringToBytes(item.Name);
  2217. block.NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
  2218. block.OwnerID = item.OwnerID;
  2219. block.OwnerMask = (uint)item.Permissions.OwnerMask;
  2220. block.SalePrice = item.SalePrice;
  2221. block.SaleType = (byte)item.SaleType;
  2222. block.TransactionID = item.TransactionID;
  2223. block.Type = (sbyte)item.AssetType;
  2224. update.InventoryData[i] = block;
  2225. }
  2226. Client.Network.SendPacket(update);
  2227. }
  2228. /// <summary>
  2229. ///
  2230. /// </summary>
  2231. /// <param name="data"></param>
  2232. /// <param name="notecardID"></param>
  2233. /// <param name="callback"></param>
  2234. public void RequestUploadNotecardAsset(byte[] data, UUID notecardID, InventoryUploadedAssetCallback callback)
  2235. {
  2236. if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null)
  2237. throw new Exception("UpdateNotecardAgentInventory capability is not currently available");
  2238. Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateNotecardAgentInventory");
  2239. if (url != null)
  2240. {
  2241. OSDMap query = new OSDMap();
  2242. query.Add("item_id", OSD.FromUUID(notecardID));
  2243. // Make the request
  2244. CapsClient request = new CapsClient(url);
  2245. request.OnComplete += UploadInventoryAssetResponse;
  2246. request.UserData = new object[] { new KeyValuePair<InventoryUploadedAssetCallback, byte[]>(callback, data), notecardID };
  2247. request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  2248. }
  2249. else
  2250. {
  2251. throw new Exception("UpdateNotecardAgentInventory capability is not currently available");
  2252. }
  2253. }
  2254. /// <summary>
  2255. /// Save changes to notecard embedded in object contents
  2256. /// </summary>
  2257. /// <param name="data">Encoded notecard asset data</param>
  2258. /// <param name="notecardID">Notecard UUID</param>
  2259. /// <param name="taskID">Object's UUID</param>
  2260. /// <param name="callback">Called upon finish of the upload with status information</param>
  2261. public void RequestUpdateNotecardTask(byte[] data, UUID notecardID, UUID taskID, InventoryUploadedAssetCallback callback)
  2262. {
  2263. if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null)
  2264. throw new Exception("UpdateNotecardTaskInventory capability is not currently available");
  2265. Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateNotecardTaskInventory");
  2266. if (url != null)
  2267. {
  2268. OSDMap query = new OSDMap();
  2269. query.Add("item_id", OSD.FromUUID(notecardID));
  2270. query.Add("task_id", OSD.FromUUID(taskID));
  2271. // Make the request
  2272. CapsClient request = new CapsClient(url);
  2273. request.OnComplete += UploadInventoryAssetResponse;
  2274. request.UserData = new object[] { new KeyValuePair<InventoryUploadedAssetCallback, byte[]>(callback, data), notecardID };
  2275. request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  2276. }
  2277. else
  2278. {
  2279. throw new Exception("UpdateNotecardTaskInventory capability is not currently available");
  2280. }
  2281. }
  2282. /// <summary>
  2283. /// Upload new gesture asset for an inventory gesture item
  2284. /// </summary>
  2285. /// <param name="data">Encoded gesture asset</param>
  2286. /// <param name="gestureID">Gesture inventory UUID</param>
  2287. /// <param name="callback">Callback whick will be called when upload is complete</param>
  2288. public void RequestUploadGestureAsset(byte[] data, UUID gestureID, InventoryUploadedAssetCallback callback)
  2289. {
  2290. if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Caps == null)
  2291. throw new Exception("UpdateGestureAgentInventory capability is not currently available");
  2292. Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateGestureAgentInventory");
  2293. if (url != null)
  2294. {
  2295. OSDMap query = new OSDMap();
  2296. query.Add("item_id", OSD.FromUUID(gestureID));
  2297. // Make the request
  2298. CapsClient request = new CapsClient(url);
  2299. request.OnComplete += UploadInventoryAssetResponse;
  2300. request.UserData = new object[] { new KeyValuePair<InventoryUploadedAssetCallback, byte[]>(callback, data), gestureID };
  2301. request.BeginGetResponse(query, OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  2302. }
  2303. else
  2304. {
  2305. throw new Exception("UpdateGestureAgentInventory capability is not currently available");
  2306. }
  2307. }
  2308. /// <summary>
  2309. /// Update an existing script in an agents Inventory
  2310. /// </summary>
  2311. /// <param name="data">A byte[] array containing the encoded scripts contents</param>
  2312. /// <param name="itemID">the itemID of the script</param>
  2313. /// <param name="mono">if true, sets the script content to run on the mono interpreter</param>
  2314. /// <param name="callback"></param>
  2315. public void RequestUpdateScriptAgentInventory(byte[] data, UUID itemID, bool mono, ScriptUpdatedCallback callback)
  2316. {
  2317. Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateScriptAgent");
  2318. if (url != null)
  2319. {
  2320. UpdateScriptAgentRequestMessage msg = new UpdateScriptAgentRequestMessage();
  2321. msg.ItemID = itemID;
  2322. msg.Target = mono ? "mono" : "lsl2";
  2323. CapsClient request = new CapsClient(url);
  2324. request.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse);
  2325. request.UserData = new object[2] { new KeyValuePair<ScriptUpdatedCallback, byte[]>(callback, data), itemID };
  2326. request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  2327. }
  2328. else
  2329. {
  2330. throw new Exception("UpdateScriptAgent capability is not currently available");
  2331. }
  2332. }
  2333. /// <summary>
  2334. /// Update an existing script in an task Inventory
  2335. /// </summary>
  2336. /// <param name="data">A byte[] array containing the encoded scripts contents</param>
  2337. /// <param name="itemID">the itemID of the script</param>
  2338. /// <param name="taskID">UUID of the prim containting the script</param>
  2339. /// <param name="mono">if true, sets the script content to run on the mono interpreter</param>
  2340. /// <param name="running">if true, sets the script to running</param>
  2341. /// <param name="callback"></param>
  2342. public void RequestUpdateScriptTask(byte[] data, UUID itemID, UUID taskID, bool mono, bool running, ScriptUpdatedCallback callback)
  2343. {
  2344. Uri url = Client.Network.CurrentSim.Caps.CapabilityURI("UpdateScriptTask");
  2345. if (url != null)
  2346. {
  2347. UpdateScriptTaskUpdateMessage msg = new UpdateScriptTaskUpdateMessage();
  2348. msg.ItemID = itemID;
  2349. msg.TaskID = taskID;
  2350. msg.ScriptRunning = running;
  2351. msg.Target = mono ? "mono" : "lsl2";
  2352. CapsClient request = new CapsClient(url);
  2353. request.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse);
  2354. request.UserData = new object[2] { new KeyValuePair<ScriptUpdatedCallback, byte[]>(callback, data), itemID };
  2355. request.BeginGetResponse(msg.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
  2356. }
  2357. else
  2358. {
  2359. throw new Exception("UpdateScriptTask capability is not currently available");
  2360. }
  2361. }
  2362. #endregion Update
  2363. #region Rez/Give
  2364. /// <summary>
  2365. /// Rez an object from inventory
  2366. /// </summary>
  2367. /// <param name="simulator">Simulator to place object in</param>
  2368. /// <param name="rotation">Rotation of the object when rezzed</param>
  2369. /// <param name="position">Vector of where to place object</param>
  2370. /// <param name="item">InventoryItem object containing item details</param>
  2371. public UUID RequestRezFromInventory(Simulator simulator, Quaternion rotation, Vector3 position,
  2372. InventoryItem item)
  2373. {
  2374. return RequestRezFromInventory(simulator, rotation, position, item, Client.Self.ActiveGroup,
  2375. UUID.Random(), true);
  2376. }
  2377. /// <summary>
  2378. /// Rez an object from inventory
  2379. /// </summary>
  2380. /// <param name="simulator">Simulator to place object in</param>
  2381. /// <param name="rotation">Rotation of the object when rezzed</param>
  2382. /// <param name="position">Vector of where to place object</param>
  2383. /// <param name="item">InventoryItem object containing item details</param>
  2384. /// <param name="groupOwner">UUID of group to own the object</param>
  2385. public UUID RequestRezFromInventory(Simulator simulator, Quaternion rotation, Vector3 position,
  2386. InventoryItem item, UUID groupOwner)
  2387. {
  2388. return RequestRezFromInventory(simulator, rotation, position, item, groupOwner, UUID.Random(), true);
  2389. }
  2390. /// <summary>
  2391. /// Rez an object from inventory
  2392. /// </summary>
  2393. /// <param name="simulator">Simulator to place object in</param>
  2394. /// <param name="rotation">Rotation of the object when rezzed</param>
  2395. /// <param name="position">Vector of where to place object</param>
  2396. /// <param name="item">InventoryItem object containing item details</param>
  2397. /// <param name="groupOwner">UUID of group to own the object</param>
  2398. /// <param name="queryID">User defined queryID to correlate replies</param>
  2399. /// <param name="rezSelected">If set to true, the CreateSelected flag
  2400. /// will be set on the rezzed object</param>
  2401. public UUID RequestRezFromInventory(Simulator simulator, Quaternion rotation, Vector3 position,
  2402. InventoryItem item, UUID groupOwner, UUID queryID, bool rezSelected)
  2403. {
  2404. return RequestRezFromInventory(simulator, UUID.Zero, rotation, position, item, groupOwner, queryID,
  2405. rezSelected);
  2406. }
  2407. /// <summary>
  2408. /// Rez an object from inventory
  2409. /// </summary>
  2410. /// <param name="simulator">Simulator to place object in</param>
  2411. /// <param name="taskID">TaskID object when rezzed</param>
  2412. /// <param name="rotation">Rotation of the object when rezzed</param>
  2413. /// <param name="position">Vector of where to place object</param>
  2414. /// <param name="item">InventoryItem object containing item details</param>
  2415. /// <param name="groupOwner">UUID of group to own the object</param>
  2416. /// <param name="queryID">User defined queryID to correlate replies</param>
  2417. /// <param name="rezSelected">If set to true, the CreateSelected flag
  2418. /// will be set on the rezzed object</param>
  2419. public UUID RequestRezFromInventory(Simulator simulator, UUID taskID, Quaternion rotation, Vector3 position,
  2420. InventoryItem item, UUID groupOwner, UUID queryID, bool rezSelected)
  2421. {
  2422. RezObjectPacket add = new RezObjectPacket();
  2423. add.AgentData.AgentID = Client.Self.AgentID;
  2424. add.AgentData.SessionID = Client.Self.SessionID;
  2425. add.AgentData.GroupID = groupOwner;
  2426. add.RezData.FromTaskID = taskID;
  2427. add.RezData.BypassRaycast = 1;
  2428. add.RezData.RayStart = position;
  2429. add.RezData.RayEnd = position;
  2430. add.RezData.RayTargetID = UUID.Zero;
  2431. add.RezData.RayEndIsIntersection = false;
  2432. add.RezData.RezSelected = rezSelected;
  2433. add.RezData.RemoveItem = false;
  2434. add.RezData.ItemFlags = (uint)item.Flags;
  2435. add.RezData.GroupMask = (uint)item.Permissions.GroupMask;
  2436. add.RezData.EveryoneMask = (uint)item.Permissions.EveryoneMask;
  2437. add.RezData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
  2438. add.InventoryData.ItemID = item.UUID;
  2439. add.InventoryData.FolderID = item.ParentUUID;
  2440. add.InventoryData.CreatorID = item.CreatorID;
  2441. add.InventoryData.OwnerID = item.OwnerID;
  2442. add.InventoryData.GroupID = item.GroupID;
  2443. add.InventoryData.BaseMask = (uint)item.Permissions.BaseMask;
  2444. add.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask;
  2445. add.InventoryData.GroupMask = (uint)item.Permissions.GroupMask;
  2446. add.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask;
  2447. add.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
  2448. add.InventoryData.GroupOwned = item.GroupOwned;
  2449. add.InventoryData.TransactionID = queryID;
  2450. add.InventoryData.Type = (sbyte)item.InventoryType;
  2451. add.InventoryData.InvType = (sbyte)item.InventoryType;
  2452. add.InventoryData.Flags = (uint)item.Flags;
  2453. add.InventoryData.SaleType = (byte)item.SaleType;
  2454. add.InventoryData.SalePrice = item.SalePrice;
  2455. add.InventoryData.Name = Utils.StringToBytes(item.Name);
  2456. add.InventoryData.Description = Utils.StringToBytes(item.Description);
  2457. add.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
  2458. Client.Network.SendPacket(add, simulator);
  2459. // Remove from store if the item is no copy
  2460. if (Store.Items.ContainsKey(item.UUID) && Store[item.UUID] is InventoryItem)
  2461. {
  2462. InventoryItem invItem = (InventoryItem)Store[item.UUID];
  2463. if ((invItem.Permissions.OwnerMask & PermissionMask.Copy) == PermissionMask.None)
  2464. {
  2465. Store.RemoveNodeFor(invItem);
  2466. }
  2467. }
  2468. return queryID;
  2469. }
  2470. /// <summary>
  2471. /// DeRez an object from the simulator to the agents Objects folder in the agents Inventory
  2472. /// </summary>
  2473. /// <param name="objectLocalID">The simulator Local ID of the object</param>
  2474. /// <remarks>If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed</remarks>
  2475. public void RequestDeRezToInventory(uint objectLocalID)
  2476. {
  2477. RequestDeRezToInventory(objectLocalID, DeRezDestination.AgentInventoryTake,
  2478. Client.Inventory.FindFolderForType(AssetType.Object), UUID.Random());
  2479. }
  2480. /// <summary>
  2481. /// DeRez an object from the simulator and return to inventory
  2482. /// </summary>
  2483. /// <param name="objectLocalID">The simulator Local ID of the object</param>
  2484. /// <param name="destType">The type of destination from the <seealso cref="DeRezDestination"/> enum</param>
  2485. /// <param name="destFolder">The destination inventory folders <seealso cref="UUID"/> -or-
  2486. /// if DeRezzing object to a tasks Inventory, the Tasks <seealso cref="UUID"/></param>
  2487. /// <param name="transactionID">The transaction ID for this request which
  2488. /// can be used to correlate this request with other packets</param>
  2489. /// <remarks>If objectLocalID is a child primitive in a linkset, the entire linkset will be derezzed</remarks>
  2490. public void RequestDeRezToInventory(uint objectLocalID, DeRezDestination destType, UUID destFolder, UUID transactionID)
  2491. {
  2492. DeRezObjectPacket take = new DeRezObjectPacket();
  2493. take.AgentData.AgentID = Client.Self.AgentID;
  2494. take.AgentData.SessionID = Client.Self.SessionID;
  2495. take.AgentBlock = new DeRezObjectPacket.AgentBlockBlock();
  2496. take.AgentBlock.GroupID = UUID.Zero;
  2497. take.AgentBlock.Destination = (byte)destType;
  2498. take.AgentBlock.DestinationID = destFolder;
  2499. take.AgentBlock.PacketCount = 1;
  2500. take.AgentBlock.PacketNumber = 1;
  2501. take.AgentBlock.TransactionID = transactionID;
  2502. take.ObjectData = new DeRezObjectPacket.ObjectDataBlock[1];
  2503. take.ObjectData[0] = new DeRezObjectPacket.ObjectDataBlock();
  2504. take.ObjectData[0].ObjectLocalID = objectLocalID;
  2505. Client.Network.SendPacket(take);
  2506. }
  2507. /// <summary>
  2508. /// Rez an item from inventory to its previous simulator location
  2509. /// </summary>
  2510. /// <param name="simulator"></param>
  2511. /// <param name="item"></param>
  2512. /// <param name="queryID"></param>
  2513. /// <returns></returns>
  2514. public UUID RequestRestoreRezFromInventory(Simulator simulator, InventoryItem item, UUID queryID)
  2515. {
  2516. RezRestoreToWorldPacket add = new RezRestoreToWorldPacket();
  2517. add.AgentData.AgentID = Client.Self.AgentID;
  2518. add.AgentData.SessionID = Client.Self.SessionID;
  2519. add.InventoryData.ItemID = item.UUID;
  2520. add.InventoryData.FolderID = item.ParentUUID;
  2521. add.InventoryData.CreatorID = item.CreatorID;
  2522. add.InventoryData.OwnerID = item.OwnerID;
  2523. add.InventoryData.GroupID = item.GroupID;
  2524. add.InventoryData.BaseMask = (uint)item.Permissions.BaseMask;
  2525. add.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask;
  2526. add.InventoryData.GroupMask = (uint)item.Permissions.GroupMask;
  2527. add.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask;
  2528. add.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
  2529. add.InventoryData.GroupOwned = item.GroupOwned;
  2530. add.InventoryData.TransactionID = queryID;
  2531. add.InventoryData.Type = (sbyte)item.InventoryType;
  2532. add.InventoryData.InvType = (sbyte)item.InventoryType;
  2533. add.InventoryData.Flags = (uint)item.Flags;
  2534. add.InventoryData.SaleType = (byte)item.SaleType;
  2535. add.InventoryData.SalePrice = item.SalePrice;
  2536. add.InventoryData.Name = Utils.StringToBytes(item.Name);
  2537. add.InventoryData.Description = Utils.StringToBytes(item.Description);
  2538. add.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
  2539. Client.Network.SendPacket(add, simulator);
  2540. return queryID;
  2541. }
  2542. /// <summary>
  2543. /// Give an inventory item to another avatar
  2544. /// </summary>
  2545. /// <param name="itemID">The <seealso cref="UUID"/> of the item to give</param>
  2546. /// <param name="itemName">The name of the item</param>
  2547. /// <param name="assetType">The type of the item from the <seealso cref="AssetType"/> enum</param>
  2548. /// <param name="recipient">The <seealso cref="UUID"/> of the recipient</param>
  2549. /// <param name="doEffect">true to generate a beameffect during transfer</param>
  2550. public void GiveItem(UUID itemID, string itemName, AssetType assetType, UUID recipient,
  2551. bool doEffect)
  2552. {
  2553. byte[] bucket;
  2554. bucket = new byte[17];
  2555. bucket[0] = (byte)assetType;
  2556. Buffer.BlockCopy(itemID.GetBytes(), 0, bucket, 1, 16);
  2557. Client.Self.InstantMessage(
  2558. Client.Self.Name,
  2559. recipient,
  2560. itemName,
  2561. UUID.Random(),
  2562. InstantMessageDialog.InventoryOffered,
  2563. InstantMessageOnline.Online,
  2564. Client.Self.SimPosition,
  2565. Client.Network.CurrentSim.ID,
  2566. bucket);
  2567. if (doEffect)
  2568. {
  2569. Client.Self.BeamEffect(Client.Self.AgentID, recipient, Vector3d.Zero,
  2570. Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random());
  2571. }
  2572. // Remove from store if the item is no copy
  2573. if (Store.Items.ContainsKey(itemID) && Store[itemID] is InventoryItem)
  2574. {
  2575. InventoryItem invItem = (InventoryItem)Store[itemID];
  2576. if ((invItem.Permissions.OwnerMask & PermissionMask.Copy) == PermissionMask.None)
  2577. {
  2578. Store.RemoveNodeFor(invItem);
  2579. }
  2580. }
  2581. }
  2582. /// <summary>
  2583. /// Give an inventory Folder with contents to another avatar
  2584. /// </summary>
  2585. /// <param name="folderID">The <seealso cref="UUID"/> of the Folder to give</param>
  2586. /// <param name="folderName">The name of the folder</param>
  2587. /// <param name="assetType">The type of the item from the <seealso cref="AssetType"/> enum</param>
  2588. /// <param name="recipient">The <seealso cref="UUID"/> of the recipient</param>
  2589. /// <param name="doEffect">true to generate a beameffect during transfer</param>
  2590. public void GiveFolder(UUID folderID, string folderName, AssetType assetType, UUID recipient,
  2591. bool doEffect)
  2592. {
  2593. byte[] bucket;
  2594. List<InventoryItem> folderContents = new List<InventoryItem>();
  2595. Client.Inventory.FolderContents(folderID, Client.Self.AgentID, false, true, InventorySortOrder.ByDate, 1000 * 15).ForEach(
  2596. delegate(InventoryBase ib)
  2597. {
  2598. folderContents.Add(Client.Inventory.FetchItem(ib.UUID, Client.Self.AgentID, 1000 * 10));
  2599. });
  2600. bucket = new byte[17 * (folderContents.Count + 1)];
  2601. //Add parent folder (first item in bucket)
  2602. bucket[0] = (byte)assetType;
  2603. Buffer.BlockCopy(folderID.GetBytes(), 0, bucket, 1, 16);
  2604. //Add contents to bucket after folder
  2605. for (int i = 1; i <= folderContents.Count; ++i)
  2606. {
  2607. bucket[i * 17] = (byte)folderContents[i - 1].AssetType;
  2608. Buffer.BlockCopy(folderContents[i - 1].UUID.GetBytes(), 0, bucket, i * 17 + 1, 16);
  2609. }
  2610. Client.Self.InstantMessage(
  2611. Client.Self.Name,
  2612. recipient,
  2613. folderName,
  2614. UUID.Random(),
  2615. InstantMessageDialog.InventoryOffered,
  2616. InstantMessageOnline.Online,
  2617. Client.Self.SimPosition,
  2618. Client.Network.CurrentSim.ID,
  2619. bucket);
  2620. if (doEffect)
  2621. {
  2622. Client.Self.BeamEffect(Client.Self.AgentID, recipient, Vector3d.Zero,
  2623. Client.Settings.DEFAULT_EFFECT_COLOR, 1f, UUID.Random());
  2624. }
  2625. // Remove from store if items were no copy
  2626. for (int i = 0; i < folderContents.Count; i++)
  2627. {
  2628. if (Store.Items.ContainsKey(folderContents[i].UUID) && Store[folderContents[i].UUID] is InventoryItem)
  2629. {
  2630. InventoryItem invItem = (InventoryItem)Store[folderContents[i].UUID];
  2631. if ((invItem.Permissions.OwnerMask & PermissionMask.Copy) == PermissionMask.None)
  2632. {
  2633. Store.RemoveNodeFor(invItem);
  2634. }
  2635. }
  2636. }
  2637. }
  2638. #endregion Rez/Give
  2639. #region Task
  2640. /// <summary>
  2641. /// Copy or move an <see cref="InventoryItem"/> from agent inventory to a task (primitive) inventory
  2642. /// </summary>
  2643. /// <param name="objectLocalID">The target object</param>
  2644. /// <param name="item">The item to copy or move from inventory</param>
  2645. /// <returns></returns>
  2646. /// <remarks>For items with copy permissions a copy of the item is placed in the tasks inventory,
  2647. /// for no-copy items the object is moved to the tasks inventory</remarks>
  2648. // DocTODO: what does the return UUID correlate to if anything?
  2649. public UUID UpdateTaskInventory(uint objectLocalID, InventoryItem item)
  2650. {
  2651. UUID transactionID = UUID.Random();
  2652. UpdateTaskInventoryPacket update = new UpdateTaskInventoryPacket();
  2653. update.AgentData.AgentID = Client.Self.AgentID;
  2654. update.AgentData.SessionID = Client.Self.SessionID;
  2655. update.UpdateData.Key = 0;
  2656. update.UpdateData.LocalID = objectLocalID;
  2657. update.InventoryData.ItemID = item.UUID;
  2658. update.InventoryData.FolderID = item.ParentUUID;
  2659. update.InventoryData.CreatorID = item.CreatorID;
  2660. update.InventoryData.OwnerID = item.OwnerID;
  2661. update.InventoryData.GroupID = item.GroupID;
  2662. update.InventoryData.BaseMask = (uint)item.Permissions.BaseMask;
  2663. update.InventoryData.OwnerMask = (uint)item.Permissions.OwnerMask;
  2664. update.InventoryData.GroupMask = (uint)item.Permissions.GroupMask;
  2665. update.InventoryData.EveryoneMask = (uint)item.Permissions.EveryoneMask;
  2666. update.InventoryData.NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
  2667. update.InventoryData.GroupOwned = item.GroupOwned;
  2668. update.InventoryData.TransactionID = transactionID;
  2669. update.InventoryData.Type = (sbyte)item.AssetType;
  2670. update.InventoryData.InvType = (sbyte)item.InventoryType;
  2671. update.InventoryData.Flags = (uint)item.Flags;
  2672. update.InventoryData.SaleType = (byte)item.SaleType;
  2673. update.InventoryData.SalePrice = item.SalePrice;
  2674. update.InventoryData.Name = Utils.StringToBytes(item.Name);
  2675. update.InventoryData.Description = Utils.StringToBytes(item.Description);
  2676. update.InventoryData.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
  2677. update.InventoryData.CRC = ItemCRC(item);
  2678. Client.Network.SendPacket(update);
  2679. return transactionID;
  2680. }
  2681. /// <summary>
  2682. /// Retrieve a listing of the items contained in a task (Primitive)
  2683. /// </summary>
  2684. /// <param name="objectID">The tasks <seealso cref="UUID"/></param>
  2685. /// <param name="objectLocalID">The tasks simulator local ID</param>
  2686. /// <param name="timeoutMS">milliseconds to wait for reply from simulator</param>
  2687. /// <returns>A list containing the inventory items inside the task or null
  2688. /// if a timeout occurs</returns>
  2689. /// <remarks>This request blocks until the response from the simulator arrives
  2690. /// or timeoutMS is exceeded</remarks>
  2691. public List<InventoryBase> GetTaskInventory(UUID objectID, UInt32 objectLocalID, Int32 timeoutMS)
  2692. {
  2693. String filename = null;
  2694. AutoResetEvent taskReplyEvent = new AutoResetEvent(false);
  2695. EventHandler<TaskInventoryReplyEventArgs> callback =
  2696. delegate(object sender, TaskInventoryReplyEventArgs e)
  2697. {
  2698. if (e.ItemID == objectID)
  2699. {
  2700. filename = e.AssetFilename;
  2701. taskReplyEvent.Set();
  2702. }
  2703. };
  2704. TaskInventoryReply += callback;
  2705. RequestTaskInventory(objectLocalID);
  2706. if (taskReplyEvent.WaitOne(timeoutMS, false))
  2707. {
  2708. TaskInventoryReply -= callback;
  2709. if (!String.IsNullOrEmpty(filename))
  2710. {
  2711. byte[] assetData = null;
  2712. ulong xferID = 0;
  2713. AutoResetEvent taskDownloadEvent = new AutoResetEvent(false);
  2714. EventHandler<XferReceivedEventArgs> xferCallback =
  2715. delegate(object sender, XferReceivedEventArgs e)
  2716. {
  2717. if (e.Xfer.XferID == xferID)
  2718. {
  2719. assetData = e.Xfer.AssetData;
  2720. taskDownloadEvent.Set();
  2721. }
  2722. };
  2723. Client.Assets.XferReceived += xferCallback;
  2724. // Start the actual asset xfer
  2725. xferID = Client.Assets.RequestAssetXfer(filename, true, false, UUID.Zero, AssetType.Unknown, true);
  2726. if (taskDownloadEvent.WaitOne(timeoutMS, false))
  2727. {
  2728. Client.Assets.XferReceived -= xferCallback;
  2729. String taskList = Utils.BytesToString(assetData);
  2730. return ParseTaskInventory(taskList);
  2731. }
  2732. else
  2733. {
  2734. Logger.Log("Timed out waiting for task inventory download for " + filename, Helpers.LogLevel.Warning, Client);
  2735. Client.Assets.XferReceived -= xferCallback;
  2736. return null;
  2737. }
  2738. }
  2739. else
  2740. {
  2741. Logger.DebugLog("Task is empty for " + objectLocalID, Client);
  2742. return new List<InventoryBase>(0);
  2743. }
  2744. }
  2745. else
  2746. {
  2747. Logger.Log("Timed out waiting for task inventory reply for " + objectLocalID, Helpers.LogLevel.Warning, Client);
  2748. TaskInventoryReply -= callback;
  2749. return null;
  2750. }
  2751. }
  2752. /// <summary>
  2753. /// Request the contents of a tasks (primitives) inventory from the
  2754. /// current simulator
  2755. /// </summary>
  2756. /// <param name="objectLocalID">The LocalID of the object</param>
  2757. /// <seealso cref="TaskInventoryReply"/>
  2758. public void RequestTaskInventory(uint objectLocalID)
  2759. {
  2760. RequestTaskInventory(objectLocalID, Client.Network.CurrentSim);
  2761. }
  2762. /// <summary>
  2763. /// Request the contents of a tasks (primitives) inventory
  2764. /// </summary>
  2765. /// <param name="objectLocalID">The simulator Local ID of the object</param>
  2766. /// <param name="simulator">A reference to the simulator object that contains the object</param>
  2767. /// <seealso cref="TaskInventoryReply"/>
  2768. public void RequestTaskInventory(uint objectLocalID, Simulator simulator)
  2769. {
  2770. RequestTaskInventoryPacket request = new RequestTaskInventoryPacket();
  2771. request.AgentData.AgentID = Client.Self.AgentID;
  2772. request.AgentData.SessionID = Client.Self.SessionID;
  2773. request.InventoryData.LocalID = objectLocalID;
  2774. Client.Network.SendPacket(request, simulator);
  2775. }
  2776. /// <summary>
  2777. /// Move an item from a tasks (Primitive) inventory to the specified folder in the avatars inventory
  2778. /// </summary>
  2779. /// <param name="objectLocalID">LocalID of the object in the simulator</param>
  2780. /// <param name="taskItemID">UUID of the task item to move</param>
  2781. /// <param name="inventoryFolderID">The ID of the destination folder in this agents inventory</param>
  2782. /// <param name="simulator">Simulator Object</param>
  2783. /// <remarks>Raises the <see cref="OnTaskItemReceived"/> event</remarks>
  2784. public void MoveTaskInventory(uint objectLocalID, UUID taskItemID, UUID inventoryFolderID, Simulator simulator)
  2785. {
  2786. MoveTaskInventoryPacket request = new MoveTaskInventoryPacket();
  2787. request.AgentData.AgentID = Client.Self.AgentID;
  2788. request.AgentData.SessionID = Client.Self.SessionID;
  2789. request.AgentData.FolderID = inventoryFolderID;
  2790. request.InventoryData.ItemID = taskItemID;
  2791. request.InventoryData.LocalID = objectLocalID;
  2792. Client.Network.SendPacket(request, simulator);
  2793. }
  2794. /// <summary>
  2795. /// Remove an item from an objects (Prim) Inventory
  2796. /// </summary>
  2797. /// <param name="objectLocalID">LocalID of the object in the simulator</param>
  2798. /// <param name="taskItemID">UUID of the task item to remove</param>
  2799. /// <param name="simulator">Simulator Object</param>
  2800. /// <remarks>You can confirm the removal by comparing the tasks inventory serial before and after the
  2801. /// request with the <see cref="RequestTaskInventory"/> request combined with
  2802. /// the <seealso cref="TaskInventoryReply"/> event</remarks>
  2803. public void RemoveTaskInventory(uint objectLocalID, UUID taskItemID, Simulator simulator)
  2804. {
  2805. RemoveTaskInventoryPacket remove = new RemoveTaskInventoryPacket();
  2806. remove.AgentData.AgentID = Client.Self.AgentID;
  2807. remove.AgentData.SessionID = Client.Self.SessionID;
  2808. remove.InventoryData.ItemID = taskItemID;
  2809. remove.InventoryData.LocalID = objectLocalID;
  2810. Client.Network.SendPacket(remove, simulator);
  2811. }
  2812. /// <summary>
  2813. /// Copy an InventoryScript item from the Agents Inventory into a primitives task inventory
  2814. /// </summary>
  2815. /// <param name="objectLocalID">An unsigned integer representing a primitive being simulated</param>
  2816. /// <param name="item">An <seealso cref="InventoryItem"/> which represents a script object from the agents inventory</param>
  2817. /// <param name="enableScript">true to set the scripts running state to enabled</param>
  2818. /// <returns>A Unique Transaction ID</returns>
  2819. /// <example>
  2820. /// The following example shows the basic steps necessary to copy a script from the agents inventory into a tasks inventory
  2821. /// and assumes the script exists in the agents inventory.
  2822. /// <code>
  2823. /// uint primID = 95899503; // Fake prim ID
  2824. /// UUID scriptID = UUID.Parse("92a7fe8a-e949-dd39-a8d8-1681d8673232"); // Fake Script UUID in Inventory
  2825. ///
  2826. /// Client.Inventory.FolderContents(Client.Inventory.FindFolderForType(AssetType.LSLText), Client.Self.AgentID,
  2827. /// false, true, InventorySortOrder.ByName, 10000);
  2828. ///
  2829. /// Client.Inventory.RezScript(primID, (InventoryItem)Client.Inventory.Store[scriptID]);
  2830. /// </code>
  2831. /// </example>
  2832. // DocTODO: what does the return UUID correlate to if anything?
  2833. public UUID CopyScriptToTask(uint objectLocalID, InventoryItem item, bool enableScript)
  2834. {
  2835. UUID transactionID = UUID.Random();
  2836. RezScriptPacket ScriptPacket = new RezScriptPacket();
  2837. ScriptPacket.AgentData.AgentID = Client.Self.AgentID;
  2838. ScriptPacket.AgentData.SessionID = Client.Self.SessionID;
  2839. ScriptPacket.UpdateBlock.ObjectLocalID = objectLocalID;
  2840. ScriptPacket.UpdateBlock.Enabled = enableScript;
  2841. ScriptPacket.InventoryBlock.ItemID = item.UUID;
  2842. ScriptPacket.InventoryBlock.FolderID = item.ParentUUID;
  2843. ScriptPacket.InventoryBlock.CreatorID = item.CreatorID;
  2844. ScriptPacket.InventoryBlock.OwnerID = item.OwnerID;
  2845. ScriptPacket.InventoryBlock.GroupID = item.GroupID;
  2846. ScriptPacket.InventoryBlock.BaseMask = (uint)item.Permissions.BaseMask;
  2847. ScriptPacket.InventoryBlock.OwnerMask = (uint)item.Permissions.OwnerMask;
  2848. ScriptPacket.InventoryBlock.GroupMask = (uint)item.Permissions.GroupMask;
  2849. ScriptPacket.InventoryBlock.EveryoneMask = (uint)item.Permissions.EveryoneMask;
  2850. ScriptPacket.InventoryBlock.NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
  2851. ScriptPacket.InventoryBlock.GroupOwned = item.GroupOwned;
  2852. ScriptPacket.InventoryBlock.TransactionID = transactionID;
  2853. ScriptPacket.InventoryBlock.Type = (sbyte)item.AssetType;
  2854. ScriptPacket.InventoryBlock.InvType = (sbyte)item.InventoryType;
  2855. ScriptPacket.InventoryBlock.Flags = (uint)item.Flags;
  2856. ScriptPacket.InventoryBlock.SaleType = (byte)item.SaleType;
  2857. ScriptPacket.InventoryBlock.SalePrice = item.SalePrice;
  2858. ScriptPacket.InventoryBlock.Name = Utils.StringToBytes(item.Name);
  2859. ScriptPacket.InventoryBlock.Description = Utils.StringToBytes(item.Description);
  2860. ScriptPacket.InventoryBlock.CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
  2861. ScriptPacket.InventoryBlock.CRC = ItemCRC(item);
  2862. Client.Network.SendPacket(ScriptPacket);
  2863. return transactionID;
  2864. }
  2865. /// <summary>
  2866. /// Request the running status of a script contained in a task (primitive) inventory
  2867. /// </summary>
  2868. /// <param name="objectID">The ID of the primitive containing the script</param>
  2869. /// <param name="scriptID">The ID of the script</param>
  2870. /// <remarks>The <see cref="ScriptRunningReply"/> event can be used to obtain the results of the
  2871. /// request</remarks>
  2872. /// <seealso cref="ScriptRunningReply"/>
  2873. public void RequestGetScriptRunning(UUID objectID, UUID scriptID)
  2874. {
  2875. GetScriptRunningPacket request = new GetScriptRunningPacket();
  2876. request.Script.ObjectID = objectID;
  2877. request.Script.ItemID = scriptID;
  2878. Client.Network.SendPacket(request);
  2879. }
  2880. /// <summary>
  2881. /// Send a request to set the running state of a script contained in a task (primitive) inventory
  2882. /// </summary>
  2883. /// <param name="objectID">The ID of the primitive containing the script</param>
  2884. /// <param name="scriptID">The ID of the script</param>
  2885. /// <param name="running">true to set the script running, false to stop a running script</param>
  2886. /// <remarks>To verify the change you can use the <see cref="RequestGetScriptRunning"/> method combined
  2887. /// with the <see cref="ScriptRunningReply"/> event</remarks>
  2888. public void RequestSetScriptRunning(UUID objectID, UUID scriptID, bool running)
  2889. {
  2890. SetScriptRunningPacket request = new SetScriptRunningPacket();
  2891. request.AgentData.AgentID = Client.Self.AgentID;
  2892. request.AgentData.SessionID = Client.Self.SessionID;
  2893. request.Script.Running = running;
  2894. request.Script.ItemID = scriptID;
  2895. request.Script.ObjectID = objectID;
  2896. Client.Network.SendPacket(request);
  2897. }
  2898. #endregion Task
  2899. #region Helper Functions
  2900. private uint RegisterItemCreatedCallback(ItemCreatedCallback callback)
  2901. {
  2902. lock (_CallbacksLock)
  2903. {
  2904. if (_CallbackPos == UInt32.MaxValue)
  2905. _CallbackPos = 0;
  2906. _CallbackPos++;
  2907. if (_ItemCreatedCallbacks.ContainsKey(_CallbackPos))
  2908. Logger.Log("Overwriting an existing ItemCreatedCallback", Helpers.LogLevel.Warning, Client);
  2909. _ItemCreatedCallbacks[_CallbackPos] = callback;
  2910. return _CallbackPos;
  2911. }
  2912. }
  2913. private uint RegisterItemsCopiedCallback(ItemCopiedCallback callback)
  2914. {
  2915. lock (_CallbacksLock)
  2916. {
  2917. if (_CallbackPos == UInt32.MaxValue)
  2918. _CallbackPos = 0;
  2919. _CallbackPos++;
  2920. if (_ItemCopiedCallbacks.ContainsKey(_CallbackPos))
  2921. Logger.Log("Overwriting an existing ItemsCopiedCallback", Helpers.LogLevel.Warning, Client);
  2922. _ItemCopiedCallbacks[_CallbackPos] = callback;
  2923. return _CallbackPos;
  2924. }
  2925. }
  2926. /// <summary>
  2927. /// Create a CRC from an InventoryItem
  2928. /// </summary>
  2929. /// <param name="iitem">The source InventoryItem</param>
  2930. /// <returns>A uint representing the source InventoryItem as a CRC</returns>
  2931. public static uint ItemCRC(InventoryItem iitem)
  2932. {
  2933. uint CRC = 0;
  2934. // IDs
  2935. CRC += iitem.AssetUUID.CRC(); // AssetID
  2936. CRC += iitem.ParentUUID.CRC(); // FolderID
  2937. CRC += iitem.UUID.CRC(); // ItemID
  2938. // Permission stuff
  2939. CRC += iitem.CreatorID.CRC(); // CreatorID
  2940. CRC += iitem.OwnerID.CRC(); // OwnerID
  2941. CRC += iitem.GroupID.CRC(); // GroupID
  2942. // CRC += another 4 words which always seem to be zero -- unclear if this is a UUID or what
  2943. CRC += (uint)iitem.Permissions.OwnerMask; //owner_mask; // Either owner_mask or next_owner_mask may need to be
  2944. CRC += (uint)iitem.Permissions.NextOwnerMask; //next_owner_mask; // switched with base_mask -- 2 values go here and in my
  2945. CRC += (uint)iitem.Permissions.EveryoneMask; //everyone_mask; // study item, the three were identical.
  2946. CRC += (uint)iitem.Permissions.GroupMask; //group_mask;
  2947. // The rest of the CRC fields
  2948. CRC += (uint)iitem.Flags; // Flags
  2949. CRC += (uint)iitem.InventoryType; // InvType
  2950. CRC += (uint)iitem.AssetType; // Type
  2951. CRC += (uint)Utils.DateTimeToUnixTime(iitem.CreationDate); // CreationDate
  2952. CRC += (uint)iitem.SalePrice; // SalePrice
  2953. CRC += (uint)((uint)iitem.SaleType * 0x07073096); // SaleType
  2954. return CRC;
  2955. }
  2956. /// <summary>
  2957. /// Reverses a cheesy XORing with a fixed UUID to convert a shadow_id to an asset_id
  2958. /// </summary>
  2959. /// <param name="shadowID">Obfuscated shadow_id value</param>
  2960. /// <returns>Deobfuscated asset_id value</returns>
  2961. public static UUID DecryptShadowID(UUID shadowID)
  2962. {
  2963. return shadowID ^ MAGIC_ID;
  2964. }
  2965. /// <summary>
  2966. /// Does a cheesy XORing with a fixed UUID to convert an asset_id to a shadow_id
  2967. /// </summary>
  2968. /// <param name="assetID">asset_id value to obfuscate</param>
  2969. /// <returns>Obfuscated shadow_id value</returns>
  2970. public static UUID EncryptAssetID(UUID assetID)
  2971. {
  2972. return assetID ^ MAGIC_ID;
  2973. }
  2974. /// <summary>
  2975. /// Wrapper for creating a new <seealso cref="InventoryItem"/> object
  2976. /// </summary>
  2977. /// <param name="type">The type of item from the <seealso cref="InventoryType"/> enum</param>
  2978. /// <param name="id">The <seealso cref="UUID"/> of the newly created object</param>
  2979. /// <returns>An <seealso cref="InventoryItem"/> object with the type and id passed</returns>
  2980. public static InventoryItem CreateInventoryItem(InventoryType type, UUID id)
  2981. {
  2982. switch (type)
  2983. {
  2984. case InventoryType.Texture: return new InventoryTexture(id);
  2985. case InventoryType.Sound: return new InventorySound(id);
  2986. case InventoryType.CallingCard: return new InventoryCallingCard(id);
  2987. case InventoryType.Landmark: return new InventoryLandmark(id);
  2988. case InventoryType.Object: return new InventoryObject(id);
  2989. case InventoryType.Notecard: return new InventoryNotecard(id);
  2990. case InventoryType.Category: return new InventoryCategory(id);
  2991. case InventoryType.LSL: return new InventoryLSL(id);
  2992. case InventoryType.Snapshot: return new InventorySnapshot(id);
  2993. case InventoryType.Attachment: return new InventoryAttachment(id);
  2994. case InventoryType.Wearable: return new InventoryWearable(id);
  2995. case InventoryType.Animation: return new InventoryAnimation(id);
  2996. case InventoryType.Gesture: return new InventoryGesture(id);
  2997. default: return new InventoryItem(type, id);
  2998. }
  2999. }
  3000. private InventoryItem SafeCreateInventoryItem(InventoryType InvType, UUID ItemID)
  3001. {
  3002. InventoryItem ret = null;
  3003. if (_Store.Contains(ItemID))
  3004. ret = _Store[ItemID] as InventoryItem;
  3005. if (ret == null)
  3006. ret = CreateInventoryItem(InvType, ItemID);
  3007. return ret;
  3008. }
  3009. private static bool ParseLine(string line, out string key, out string value)
  3010. {
  3011. // Clean up and convert tabs to spaces
  3012. line = line.Trim();
  3013. line = line.Replace('\t', ' ');
  3014. // Shrink all whitespace down to single spaces
  3015. while (line.IndexOf(" ") > 0)
  3016. line = line.Replace(" ", " ");
  3017. if (line.Length > 2)
  3018. {
  3019. int sep = line.IndexOf(' ');
  3020. if (sep > 0)
  3021. {
  3022. key = line.Substring(0, sep);
  3023. value = line.Substring(sep + 1);
  3024. return true;
  3025. }
  3026. }
  3027. else if (line.Length == 1)
  3028. {
  3029. key = line;
  3030. value = String.Empty;
  3031. return true;
  3032. }
  3033. key = null;
  3034. value = null;
  3035. return false;
  3036. }
  3037. /// <summary>
  3038. /// Parse the results of a RequestTaskInventory() response
  3039. /// </summary>
  3040. /// <param name="taskData">A string which contains the data from the task reply</param>
  3041. /// <returns>A List containing the items contained within the tasks inventory</returns>
  3042. public static List<InventoryBase> ParseTaskInventory(string taskData)
  3043. {
  3044. List<InventoryBase> items = new List<InventoryBase>();
  3045. int lineNum = 0;
  3046. string[] lines = taskData.Replace("\r\n", "\n").Split('\n');
  3047. while (lineNum < lines.Length)
  3048. {
  3049. string key, value;
  3050. if (ParseLine(lines[lineNum++], out key, out value))
  3051. {
  3052. if (key == "inv_object")
  3053. {
  3054. #region inv_object
  3055. // In practice this appears to only be used for folders
  3056. UUID itemID = UUID.Zero;
  3057. UUID parentID = UUID.Zero;
  3058. string name = String.Empty;
  3059. AssetType assetType = AssetType.Unknown;
  3060. while (lineNum < lines.Length)
  3061. {
  3062. if (ParseLine(lines[lineNum++], out key, out value))
  3063. {
  3064. if (key == "{")
  3065. {
  3066. continue;
  3067. }
  3068. else if (key == "}")
  3069. {
  3070. break;
  3071. }
  3072. else if (key == "obj_id")
  3073. {
  3074. UUID.TryParse(value, out itemID);
  3075. }
  3076. else if (key == "parent_id")
  3077. {
  3078. UUID.TryParse(value, out parentID);
  3079. }
  3080. else if (key == "type")
  3081. {
  3082. assetType = Utils.StringToAssetType(value);
  3083. }
  3084. else if (key == "name")
  3085. {
  3086. name = value.Substring(0, value.IndexOf('|'));
  3087. }
  3088. }
  3089. }
  3090. if (assetType == AssetType.Folder)
  3091. {
  3092. InventoryFolder folder = new InventoryFolder(itemID);
  3093. folder.Name = name;
  3094. folder.ParentUUID = parentID;
  3095. items.Add(folder);
  3096. }
  3097. else
  3098. {
  3099. InventoryItem item = new InventoryItem(itemID);
  3100. item.Name = name;
  3101. item.ParentUUID = parentID;
  3102. item.AssetType = assetType;
  3103. items.Add(item);
  3104. }
  3105. #endregion inv_object
  3106. }
  3107. else if (key == "inv_item")
  3108. {
  3109. #region inv_item
  3110. // Any inventory item that links to an assetID, has permissions, etc
  3111. UUID itemID = UUID.Zero;
  3112. UUID assetID = UUID.Zero;
  3113. UUID parentID = UUID.Zero;
  3114. UUID creatorID = UUID.Zero;
  3115. UUID ownerID = UUID.Zero;
  3116. UUID lastOwnerID = UUID.Zero;
  3117. UUID groupID = UUID.Zero;
  3118. bool groupOwned = false;
  3119. string name = String.Empty;
  3120. string desc = String.Empty;
  3121. AssetType assetType = AssetType.Unknown;
  3122. InventoryType inventoryType = InventoryType.Unknown;
  3123. DateTime creationDate = Utils.Epoch;
  3124. uint flags = 0;
  3125. Permissions perms = Permissions.NoPermissions;
  3126. SaleType saleType = SaleType.Not;
  3127. int salePrice = 0;
  3128. while (lineNum < lines.Length)
  3129. {
  3130. if (ParseLine(lines[lineNum++], out key, out value))
  3131. {
  3132. if (key == "{")
  3133. {
  3134. continue;
  3135. }
  3136. else if (key == "}")
  3137. {
  3138. break;
  3139. }
  3140. else if (key == "item_id")
  3141. {
  3142. UUID.TryParse(value, out itemID);
  3143. }
  3144. else if (key == "parent_id")
  3145. {
  3146. UUID.TryParse(value, out parentID);
  3147. }
  3148. else if (key == "permissions")
  3149. {
  3150. #region permissions
  3151. while (lineNum < lines.Length)
  3152. {
  3153. if (ParseLine(lines[lineNum++], out key, out value))
  3154. {
  3155. if (key == "{")
  3156. {
  3157. continue;
  3158. }
  3159. else if (key == "}")
  3160. {
  3161. break;
  3162. }
  3163. else if (key == "creator_mask")
  3164. {
  3165. // Deprecated
  3166. uint val;
  3167. if (Utils.TryParseHex(value, out val))
  3168. perms.BaseMask = (PermissionMask)val;
  3169. }
  3170. else if (key == "base_mask")
  3171. {
  3172. uint val;
  3173. if (Utils.TryParseHex(value, out val))
  3174. perms.BaseMask = (PermissionMask)val;
  3175. }
  3176. else if (key == "owner_mask")
  3177. {
  3178. uint val;
  3179. if (Utils.TryParseHex(value, out val))
  3180. perms.OwnerMask = (PermissionMask)val;
  3181. }
  3182. else if (key == "group_mask")
  3183. {
  3184. uint val;
  3185. if (Utils.TryParseHex(value, out val))
  3186. perms.GroupMask = (PermissionMask)val;
  3187. }
  3188. else if (key == "everyone_mask")
  3189. {
  3190. uint val;
  3191. if (Utils.TryParseHex(value, out val))
  3192. perms.EveryoneMask = (PermissionMask)val;
  3193. }
  3194. else if (key == "next_owner_mask")
  3195. {
  3196. uint val;
  3197. if (Utils.TryParseHex(value, out val))
  3198. perms.NextOwnerMask = (PermissionMask)val;
  3199. }
  3200. else if (key == "creator_id")
  3201. {
  3202. UUID.TryParse(value, out creatorID);
  3203. }
  3204. else if (key == "owner_id")
  3205. {
  3206. UUID.TryParse(value, out ownerID);
  3207. }
  3208. else if (key == "last_owner_id")
  3209. {
  3210. UUID.TryParse(value, out lastOwnerID);
  3211. }
  3212. else if (key == "group_id")
  3213. {
  3214. UUID.TryParse(value, out groupID);
  3215. }
  3216. else if (key == "group_owned")
  3217. {
  3218. uint val;
  3219. if (UInt32.TryParse(value, out val))
  3220. groupOwned = (val != 0);
  3221. }
  3222. }
  3223. }
  3224. #endregion permissions
  3225. }
  3226. else if (key == "sale_info")
  3227. {
  3228. #region sale_info
  3229. while (lineNum < lines.Length)
  3230. {
  3231. if (ParseLine(lines[lineNum++], out key, out value))
  3232. {
  3233. if (key == "{")
  3234. {
  3235. continue;
  3236. }
  3237. else if (key == "}")
  3238. {
  3239. break;
  3240. }
  3241. else if (key == "sale_type")
  3242. {
  3243. saleType = Utils.StringToSaleType(value);
  3244. }
  3245. else if (key == "sale_price")
  3246. {
  3247. Int32.TryParse(value, out salePrice);
  3248. }
  3249. }
  3250. }
  3251. #endregion sale_info
  3252. }
  3253. else if (key == "shadow_id")
  3254. {
  3255. UUID shadowID;
  3256. if (UUID.TryParse(value, out shadowID))
  3257. assetID = DecryptShadowID(shadowID);
  3258. }
  3259. else if (key == "asset_id")
  3260. {
  3261. UUID.TryParse(value, out assetID);
  3262. }
  3263. else if (key == "type")
  3264. {
  3265. assetType = Utils.StringToAssetType(value);
  3266. }
  3267. else if (key == "inv_type")
  3268. {
  3269. inventoryType = Utils.StringToInventoryType(value);
  3270. }
  3271. else if (key == "flags")
  3272. {
  3273. UInt32.TryParse(value, out flags);
  3274. }
  3275. else if (key == "name")
  3276. {
  3277. name = value.Substring(0, value.IndexOf('|'));
  3278. }
  3279. else if (key == "desc")
  3280. {
  3281. desc = value.Substring(0, value.IndexOf('|'));
  3282. }
  3283. else if (key == "creation_date")
  3284. {
  3285. uint timestamp;
  3286. if (UInt32.TryParse(value, out timestamp))
  3287. creationDate = Utils.UnixTimeToDateTime(timestamp);
  3288. else
  3289. Logger.Log("Failed to parse creation_date " + value, Helpers.LogLevel.Warning);
  3290. }
  3291. }
  3292. }
  3293. InventoryItem item = CreateInventoryItem(inventoryType, itemID);
  3294. item.AssetUUID = assetID;
  3295. item.AssetType = assetType;
  3296. item.CreationDate = creationDate;
  3297. item.CreatorID = creatorID;
  3298. item.Description = desc;
  3299. item.Flags = flags;
  3300. item.GroupID = groupID;
  3301. item.GroupOwned = groupOwned;
  3302. item.Name = name;
  3303. item.OwnerID = ownerID;
  3304. item.LastOwnerID = lastOwnerID;
  3305. item.ParentUUID = parentID;
  3306. item.Permissions = perms;
  3307. item.SalePrice = salePrice;
  3308. item.SaleType = saleType;
  3309. items.Add(item);
  3310. #endregion inv_item
  3311. }
  3312. else
  3313. {
  3314. Logger.Log("Unrecognized token " + key + " in: " + Environment.NewLine + taskData,
  3315. Helpers.LogLevel.Error);
  3316. }
  3317. }
  3318. }
  3319. return items;
  3320. }
  3321. #endregion Helper Functions
  3322. #region Internal Callbacks
  3323. void Self_IM(object sender, InstantMessageEventArgs e)
  3324. {
  3325. // TODO: MainAvatar.InstantMessageDialog.GroupNotice can also be an inventory offer, should we
  3326. // handle it here?
  3327. if (m_InventoryObjectOffered != null &&
  3328. (e.IM.Dialog == InstantMessageDialog.InventoryOffered
  3329. || e.IM.Dialog == InstantMessageDialog.TaskInventoryOffered))
  3330. {
  3331. AssetType type = AssetType.Unknown;
  3332. UUID objectID = UUID.Zero;
  3333. bool fromTask = false;
  3334. if (e.IM.Dialog == InstantMessageDialog.InventoryOffered)
  3335. {
  3336. if (e.IM.BinaryBucket.Length == 17)
  3337. {
  3338. type = (AssetType)e.IM.BinaryBucket[0];
  3339. objectID = new UUID(e.IM.BinaryBucket, 1);
  3340. fromTask = false;
  3341. }
  3342. else
  3343. {
  3344. Logger.Log("Malformed inventory offer from agent", Helpers.LogLevel.Warning, Client);
  3345. return;
  3346. }
  3347. }
  3348. else if (e.IM.Dialog == InstantMessageDialog.TaskInventoryOffered)
  3349. {
  3350. if (e.IM.BinaryBucket.Length == 1)
  3351. {
  3352. type = (AssetType)e.IM.BinaryBucket[0];
  3353. fromTask = true;
  3354. }
  3355. else
  3356. {
  3357. Logger.Log("Malformed inventory offer from object", Helpers.LogLevel.Warning, Client);
  3358. return;
  3359. }
  3360. }
  3361. // Find the folder where this is going to go
  3362. UUID destinationFolderID = FindFolderForType(type);
  3363. // Fire the callback
  3364. try
  3365. {
  3366. ImprovedInstantMessagePacket imp = new ImprovedInstantMessagePacket();
  3367. imp.AgentData.AgentID = Client.Self.AgentID;
  3368. imp.AgentData.SessionID = Client.Self.SessionID;
  3369. imp.MessageBlock.FromGroup = false;
  3370. imp.MessageBlock.ToAgentID = e.IM.FromAgentID;
  3371. imp.MessageBlock.Offline = 0;
  3372. imp.MessageBlock.ID = e.IM.IMSessionID;
  3373. imp.MessageBlock.Timestamp = 0;
  3374. imp.MessageBlock.FromAgentName = Utils.StringToBytes(Client.Self.Name);
  3375. imp.MessageBlock.Message = Utils.EmptyBytes;
  3376. imp.MessageBlock.ParentEstateID = 0;
  3377. imp.MessageBlock.RegionID = UUID.Zero;
  3378. imp.MessageBlock.Position = Client.Self.SimPosition;
  3379. InventoryObjectOfferedEventArgs args = new InventoryObjectOfferedEventArgs(e.IM, type, objectID, fromTask, destinationFolderID);
  3380. OnInventoryObjectOffered(args);
  3381. if (args.Accept)
  3382. {
  3383. // Accept the inventory offer
  3384. switch (e.IM.Dialog)
  3385. {
  3386. case InstantMessageDialog.InventoryOffered:
  3387. imp.MessageBlock.Dialog = (byte)InstantMessageDialog.InventoryAccepted;
  3388. break;
  3389. case InstantMessageDialog.TaskInventoryOffered:
  3390. imp.MessageBlock.Dialog = (byte)InstantMessageDialog.TaskInventoryAccepted;
  3391. break;
  3392. case InstantMessageDialog.GroupNotice:
  3393. imp.MessageBlock.Dialog = (byte)InstantMessageDialog.GroupNoticeInventoryAccepted;
  3394. break;
  3395. }
  3396. imp.MessageBlock.BinaryBucket = args.FolderID.GetBytes();
  3397. }
  3398. else
  3399. {
  3400. // Decline the inventory offer
  3401. switch (e.IM.Dialog)
  3402. {
  3403. case InstantMessageDialog.InventoryOffered:
  3404. imp.MessageBlock.Dialog = (byte)InstantMessageDialog.InventoryDeclined;
  3405. break;
  3406. case InstantMessageDialog.TaskInventoryOffered:
  3407. imp.MessageBlock.Dialog = (byte)InstantMessageDialog.TaskInventoryDeclined;
  3408. break;
  3409. case InstantMessageDialog.GroupNotice:
  3410. imp.MessageBlock.Dialog = (byte)InstantMessageDialog.GroupNoticeInventoryDeclined;
  3411. break;
  3412. }
  3413. imp.MessageBlock.BinaryBucket = Utils.EmptyBytes;
  3414. }
  3415. Client.Network.SendPacket(imp, e.Simulator);
  3416. }
  3417. catch (Exception ex)
  3418. {
  3419. Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex);
  3420. }
  3421. }
  3422. }
  3423. private void CreateItemFromAssetResponse(CapsClient client, OSD result, Exception error)
  3424. {
  3425. object[] args = (object[])client.UserData;
  3426. ItemCreatedFromAssetCallback callback = (ItemCreatedFromAssetCallback)args[0];
  3427. byte[] itemData = (byte[])args[1];
  3428. int millisecondsTimeout = (int)args[2];
  3429. OSDMap request = (OSDMap)args[3];
  3430. if (result == null)
  3431. {
  3432. try { callback(false, error.Message, UUID.Zero, UUID.Zero); }
  3433. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3434. return;
  3435. }
  3436. if (result.Type == OSDType.Unknown)
  3437. {
  3438. try
  3439. {
  3440. callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero);
  3441. }
  3442. catch (Exception e)
  3443. {
  3444. Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e);
  3445. }
  3446. }
  3447. OSDMap contents = (OSDMap)result;
  3448. string status = contents["state"].AsString().ToLower();
  3449. if (status == "upload")
  3450. {
  3451. string uploadURL = contents["uploader"].AsString();
  3452. Logger.DebugLog("CreateItemFromAsset: uploading to " + uploadURL);
  3453. // This makes the assumption that all uploads go to CurrentSim, to avoid
  3454. // the problem of HttpRequestState not knowing anything about simulators
  3455. CapsClient upload = new CapsClient(new Uri(uploadURL));
  3456. upload.OnComplete += CreateItemFromAssetResponse;
  3457. upload.UserData = new object[] { callback, itemData, millisecondsTimeout, request };
  3458. upload.BeginGetResponse(itemData, "application/octet-stream", millisecondsTimeout);
  3459. }
  3460. else if (status == "complete")
  3461. {
  3462. Logger.DebugLog("CreateItemFromAsset: completed");
  3463. if (contents.ContainsKey("new_inventory_item") && contents.ContainsKey("new_asset"))
  3464. {
  3465. // Request full update on the item in order to update the local store
  3466. RequestFetchInventory(contents["new_inventory_item"].AsUUID(), Client.Self.AgentID);
  3467. try { callback(true, String.Empty, contents["new_inventory_item"].AsUUID(), contents["new_asset"].AsUUID()); }
  3468. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3469. }
  3470. else
  3471. {
  3472. try { callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); }
  3473. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3474. }
  3475. }
  3476. else
  3477. {
  3478. // Failure
  3479. try { callback(false, status, UUID.Zero, UUID.Zero); }
  3480. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3481. }
  3482. }
  3483. private void Network_OnLoginResponse(bool loginSuccess, bool redirect, string message, string reason, LoginResponseData replyData)
  3484. {
  3485. if (loginSuccess)
  3486. {
  3487. // Initialize the store here so we know who owns it:
  3488. _Store = new Inventory(Client, this, Client.Self.AgentID);
  3489. Logger.DebugLog("Setting InventoryRoot to " + replyData.InventoryRoot.ToString(), Client);
  3490. InventoryFolder rootFolder = new InventoryFolder(replyData.InventoryRoot);
  3491. rootFolder.Name = String.Empty;
  3492. rootFolder.ParentUUID = UUID.Zero;
  3493. _Store.RootFolder = rootFolder;
  3494. for (int i = 0; i < replyData.InventorySkeleton.Length; i++)
  3495. _Store.UpdateNodeFor(replyData.InventorySkeleton[i]);
  3496. InventoryFolder libraryRootFolder = new InventoryFolder(replyData.LibraryRoot);
  3497. libraryRootFolder.Name = String.Empty;
  3498. libraryRootFolder.ParentUUID = UUID.Zero;
  3499. _Store.LibraryFolder = libraryRootFolder;
  3500. for (int i = 0; i < replyData.LibrarySkeleton.Length; i++)
  3501. _Store.UpdateNodeFor(replyData.LibrarySkeleton[i]);
  3502. }
  3503. }
  3504. private void UploadInventoryAssetResponse(CapsClient client, OSD result, Exception error)
  3505. {
  3506. OSDMap contents = result as OSDMap;
  3507. KeyValuePair<InventoryUploadedAssetCallback, byte[]> kvp = (KeyValuePair<InventoryUploadedAssetCallback, byte[]>)(((object[])client.UserData)[0]);
  3508. InventoryUploadedAssetCallback callback = kvp.Key;
  3509. byte[] itemData = (byte[])kvp.Value;
  3510. if (error == null && contents != null)
  3511. {
  3512. string status = contents["state"].AsString();
  3513. if (status == "upload")
  3514. {
  3515. Uri uploadURL = contents["uploader"].AsUri();
  3516. if (uploadURL != null)
  3517. {
  3518. // This makes the assumption that all uploads go to CurrentSim, to avoid
  3519. // the problem of HttpRequestState not knowing anything about simulators
  3520. CapsClient upload = new CapsClient(uploadURL);
  3521. upload.OnComplete += UploadInventoryAssetResponse;
  3522. upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) };
  3523. upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT);
  3524. }
  3525. else
  3526. {
  3527. try { callback(false, "Missing uploader URL", UUID.Zero, UUID.Zero); }
  3528. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3529. }
  3530. }
  3531. else if (status == "complete")
  3532. {
  3533. if (contents.ContainsKey("new_asset"))
  3534. {
  3535. // Request full item update so we keep store in sync
  3536. RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID());
  3537. try { callback(true, String.Empty, (UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID()); }
  3538. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3539. }
  3540. else
  3541. {
  3542. try { callback(false, "Failed to parse asset and item UUIDs", UUID.Zero, UUID.Zero); }
  3543. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3544. }
  3545. }
  3546. else
  3547. {
  3548. try { callback(false, status, UUID.Zero, UUID.Zero); }
  3549. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3550. }
  3551. }
  3552. else
  3553. {
  3554. string message = "Unrecognized or empty response";
  3555. if (error != null)
  3556. {
  3557. if (error is WebException)
  3558. message = ((HttpWebResponse)((WebException)error).Response).StatusDescription;
  3559. if (message == null || message == "None")
  3560. message = error.Message;
  3561. }
  3562. try { callback(false, message, UUID.Zero, UUID.Zero); }
  3563. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3564. }
  3565. }
  3566. private void UpdateScriptAgentInventoryResponse(CapsClient client, OSD result, Exception error)
  3567. {
  3568. KeyValuePair<ScriptUpdatedCallback, byte[]> kvp = (KeyValuePair<ScriptUpdatedCallback, byte[]>)(((object[])client.UserData)[0]);
  3569. ScriptUpdatedCallback callback = kvp.Key;
  3570. byte[] itemData = (byte[])kvp.Value;
  3571. if (result == null)
  3572. {
  3573. try { callback(false, error.Message, false, null, UUID.Zero, UUID.Zero); }
  3574. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3575. return;
  3576. }
  3577. OSDMap contents = (OSDMap)result;
  3578. string status = contents["state"].AsString();
  3579. if (status == "upload")
  3580. {
  3581. string uploadURL = contents["uploader"].AsString();
  3582. CapsClient upload = new CapsClient(new Uri(uploadURL));
  3583. upload.OnComplete += new CapsClient.CompleteCallback(UpdateScriptAgentInventoryResponse);
  3584. upload.UserData = new object[2] { kvp, (UUID)(((object[])client.UserData)[1]) };
  3585. upload.BeginGetResponse(itemData, "application/octet-stream", Client.Settings.CAPS_TIMEOUT);
  3586. }
  3587. else if (status == "complete" && callback != null)
  3588. {
  3589. if (contents.ContainsKey("new_asset"))
  3590. {
  3591. // Request full item update so we keep store in sync
  3592. RequestFetchInventory((UUID)(((object[])client.UserData)[1]), contents["new_asset"].AsUUID());
  3593. try
  3594. {
  3595. List<string> compileErrors = null;
  3596. if (contents.ContainsKey("errors"))
  3597. {
  3598. OSDArray errors = (OSDArray)contents["errors"];
  3599. compileErrors = new List<string>(errors.Count);
  3600. for (int i = 0; i < errors.Count; i++)
  3601. {
  3602. compileErrors.Add(errors[i].AsString());
  3603. }
  3604. }
  3605. callback(true,
  3606. status,
  3607. contents["compiled"].AsBoolean(),
  3608. compileErrors,
  3609. (UUID)(((object[])client.UserData)[1]),
  3610. contents["new_asset"].AsUUID());
  3611. }
  3612. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3613. }
  3614. else
  3615. {
  3616. try { callback(false, "Failed to parse asset UUID", false, null, UUID.Zero, UUID.Zero); }
  3617. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3618. }
  3619. }
  3620. else if (callback != null)
  3621. {
  3622. try { callback(false, status, false, null, UUID.Zero, UUID.Zero); }
  3623. catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
  3624. }
  3625. }
  3626. #endregion Internal Handlers
  3627. #region Packet Handlers
  3628. /// <summary>Process an incoming packet and raise the appropriate events</summary>
  3629. /// <param name="sender">The sender</param>
  3630. /// <param name="e">The EventArgs object containing the packet data</param>
  3631. protected void SaveAssetIntoInventoryHandler(object sender, PacketReceivedEventArgs e)
  3632. {
  3633. if (m_SaveAssetToInventory != null)
  3634. {
  3635. Packet packet = e.Packet;
  3636. SaveAssetIntoInventoryPacket save = (SaveAssetIntoInventoryPacket)packet;
  3637. OnSaveAssetToInventory(new SaveAssetToInventoryEventArgs(save.InventoryData.ItemID, save.InventoryData.NewAssetID));
  3638. }
  3639. }
  3640. /// <summary>Process an incoming packet and raise the appropriate events</summary>
  3641. /// <param name="sender">The sender</param>
  3642. /// <param name="e">The EventArgs object containing the packet data</param>
  3643. protected void InventoryDescendentsHandler(object sender, PacketReceivedEventArgs e)
  3644. {
  3645. Packet packet = e.Packet;
  3646. InventoryDescendentsPacket reply = (InventoryDescendentsPacket)packet;
  3647. if (reply.AgentData.Descendents > 0)
  3648. {
  3649. // InventoryDescendantsReply sends a null folder if the parent doesnt contain any folders
  3650. if (reply.FolderData[0].FolderID != UUID.Zero)
  3651. {
  3652. // Iterate folders in this packet
  3653. for (int i = 0; i < reply.FolderData.Length; i++)
  3654. {
  3655. // If folder already exists then ignore, we assume the version cache
  3656. // logic is working and if the folder is stale then it should not be present.
  3657. if (!_Store.Contains(reply.FolderData[i].FolderID))
  3658. {
  3659. InventoryFolder folder = new InventoryFolder(reply.FolderData[i].FolderID);
  3660. folder.ParentUUID = reply.FolderData[i].ParentID;
  3661. folder.Name = Utils.BytesToString(reply.FolderData[i].Name);
  3662. folder.PreferredType = (AssetType)reply.FolderData[i].Type;
  3663. folder.OwnerID = reply.AgentData.OwnerID;
  3664. _Store[folder.UUID] = folder;
  3665. }
  3666. }
  3667. }
  3668. // InventoryDescendantsReply sends a null item if the parent doesnt contain any items.
  3669. if (reply.ItemData[0].ItemID != UUID.Zero)
  3670. {
  3671. // Iterate items in this packet
  3672. for (int i = 0; i < reply.ItemData.Length; i++)
  3673. {
  3674. if (reply.ItemData[i].ItemID != UUID.Zero)
  3675. {
  3676. InventoryItem item;
  3677. /*
  3678. * Objects that have been attached in-world prior to being stored on the
  3679. * asset server are stored with the InventoryType of 0 (Texture)
  3680. * instead of 17 (Attachment)
  3681. *
  3682. * This corrects that behavior by forcing Object Asset types that have an
  3683. * invalid InventoryType with the proper InventoryType of Attachment.
  3684. */
  3685. if ((AssetType)reply.ItemData[i].Type == AssetType.Object
  3686. && (InventoryType)reply.ItemData[i].InvType == InventoryType.Texture)
  3687. {
  3688. item = CreateInventoryItem(InventoryType.Attachment, reply.ItemData[i].ItemID);
  3689. item.InventoryType = InventoryType.Attachment;
  3690. }
  3691. else
  3692. {
  3693. item = CreateInventoryItem((InventoryType)reply.ItemData[i].InvType, reply.ItemData[i].ItemID);
  3694. item.InventoryType = (InventoryType)reply.ItemData[i].InvType;
  3695. }
  3696. item.ParentUUID = reply.ItemData[i].FolderID;
  3697. item.CreatorID = reply.ItemData[i].CreatorID;
  3698. item.AssetType = (AssetType)reply.ItemData[i].Type;
  3699. item.AssetUUID = reply.ItemData[i].AssetID;
  3700. item.CreationDate = Utils.UnixTimeToDateTime((uint)reply.ItemData[i].CreationDate);
  3701. item.Description = Utils.BytesToString(reply.ItemData[i].Description);
  3702. item.Flags = reply.ItemData[i].Flags;
  3703. item.Name = Utils.BytesToString(reply.ItemData[i].Name);
  3704. item.GroupID = reply.ItemData[i].GroupID;
  3705. item.GroupOwned = reply.ItemData[i].GroupOwned;
  3706. item.Permissions = new Permissions(
  3707. reply.ItemData[i].BaseMask,
  3708. reply.ItemData[i].EveryoneMask,
  3709. reply.ItemData[i].GroupMask,
  3710. reply.ItemData[i].NextOwnerMask,
  3711. reply.ItemData[i].OwnerMask);
  3712. item.SalePrice = reply.ItemData[i].SalePrice;
  3713. item.SaleType = (SaleType)reply.ItemData[i].SaleType;
  3714. item.OwnerID = reply.AgentData.OwnerID;
  3715. _Store[item.UUID] = item;
  3716. }
  3717. }
  3718. }
  3719. }
  3720. InventoryFolder parentFolder = null;
  3721. if (_Store.Contains(reply.AgentData.FolderID) &&
  3722. _Store[reply.AgentData.FolderID] is InventoryFolder)
  3723. {
  3724. parentFolder = _Store[reply.AgentData.FolderID] as InventoryFolder;
  3725. }
  3726. else
  3727. {
  3728. Logger.Log("Don't have a reference to FolderID " + reply.AgentData.FolderID.ToString() +
  3729. " or it is not a folder", Helpers.LogLevel.Error, Client);
  3730. return;
  3731. }
  3732. if (reply.AgentData.Version < parentFolder.Version)
  3733. {
  3734. Logger.Log("Got an outdated InventoryDescendents packet for folder " + parentFolder.Name +
  3735. ", this version = " + reply.AgentData.Version + ", latest version = " + parentFolder.Version,
  3736. Helpers.LogLevel.Warning, Client);
  3737. return;
  3738. }
  3739. parentFolder.Version = reply.AgentData.Version;
  3740. // FIXME: reply.AgentData.Descendants is not parentFolder.DescendentCount if we didn't
  3741. // request items and folders
  3742. parentFolder.DescendentCount = reply.AgentData.Descendents;
  3743. _Store.GetNodeFor(reply.AgentData.FolderID).NeedsUpdate = false;
  3744. #region FindObjectsByPath Handling
  3745. if (_Searches.Count > 0)
  3746. {
  3747. lock (_Searches)
  3748. {
  3749. StartSearch:
  3750. // Iterate over all of the outstanding searches
  3751. for (int i = 0; i < _Searches.Count; i++)
  3752. {
  3753. InventorySearch search = _Searches[i];
  3754. List<InventoryBase> folderContents = _Store.GetContents(search.Folder);
  3755. // Iterate over all of the inventory objects in the base search folder
  3756. for (int j = 0; j < folderContents.Count; j++)
  3757. {
  3758. // Check if this inventory object matches the current path node
  3759. if (folderContents[j].Name == search.Path[search.Level])
  3760. {
  3761. if (search.Level == search.Path.Length - 1)
  3762. {
  3763. Logger.DebugLog("Finished path search of " + String.Join("/", search.Path), Client);
  3764. // This is the last node in the path, fire the callback and clean up
  3765. if (m_FindObjectByPathReply != null)
  3766. {
  3767. OnFindObjectByPathReply(new FindObjectByPathReplyEventArgs(String.Join("/", search.Path),
  3768. folderContents[j].UUID));
  3769. }
  3770. // Remove this entry and restart the loop since we are changing the collection size
  3771. _Searches.RemoveAt(i);
  3772. goto StartSearch;
  3773. }
  3774. else
  3775. {
  3776. // We found a match but it is not the end of the path, request the next level
  3777. Logger.DebugLog(String.Format("Matched level {0}/{1} in a path search of {2}",
  3778. search.Level, search.Path.Length - 1, String.Join("/", search.Path)), Client);
  3779. search.Folder = folderContents[j].UUID;
  3780. search.Level++;
  3781. _Searches[i] = search;
  3782. RequestFolderContents(search.Folder, search.Owner, true, true,
  3783. InventorySortOrder.ByName);
  3784. }
  3785. }
  3786. }
  3787. }
  3788. }
  3789. }
  3790. #endregion FindObjectsByPath Handling
  3791. // Callback for inventory folder contents being updated
  3792. OnFolderUpdated(new FolderUpdatedEventArgs(parentFolder.UUID, true));
  3793. }
  3794. /// <summary>
  3795. /// UpdateCreateInventoryItem packets are received when a new inventory item
  3796. /// is created. This may occur when an object that's rezzed in world is
  3797. /// taken into inventory, when an item is created using the CreateInventoryItem
  3798. /// packet, or when an object is purchased
  3799. /// </summary>
  3800. /// <param name="sender">The sender</param>
  3801. /// <param name="e">The EventArgs object containing the packet data</param>
  3802. protected void UpdateCreateInventoryItemHandler(object sender, PacketReceivedEventArgs e)
  3803. {
  3804. Packet packet = e.Packet;
  3805. UpdateCreateInventoryItemPacket reply = packet as UpdateCreateInventoryItemPacket;
  3806. foreach (UpdateCreateInventoryItemPacket.InventoryDataBlock dataBlock in reply.InventoryData)
  3807. {
  3808. if (dataBlock.InvType == (sbyte)InventoryType.Folder)
  3809. {
  3810. Logger.Log("Received InventoryFolder in an UpdateCreateInventoryItem packet, this should not happen!",
  3811. Helpers.LogLevel.Error, Client);
  3812. continue;
  3813. }
  3814. InventoryItem item = CreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID);
  3815. item.AssetType = (AssetType)dataBlock.Type;
  3816. item.AssetUUID = dataBlock.AssetID;
  3817. item.CreationDate = Utils.UnixTimeToDateTime(dataBlock.CreationDate);
  3818. item.CreatorID = dataBlock.CreatorID;
  3819. item.Description = Utils.BytesToString(dataBlock.Description);
  3820. item.Flags = dataBlock.Flags;
  3821. item.GroupID = dataBlock.GroupID;
  3822. item.GroupOwned = dataBlock.GroupOwned;
  3823. item.Name = Utils.BytesToString(dataBlock.Name);
  3824. item.OwnerID = dataBlock.OwnerID;
  3825. item.ParentUUID = dataBlock.FolderID;
  3826. item.Permissions = new Permissions(
  3827. dataBlock.BaseMask,
  3828. dataBlock.EveryoneMask,
  3829. dataBlock.GroupMask,
  3830. dataBlock.NextOwnerMask,
  3831. dataBlock.OwnerMask);
  3832. item.SalePrice = dataBlock.SalePrice;
  3833. item.SaleType = (SaleType)dataBlock.SaleType;
  3834. /*
  3835. * When attaching new objects, an UpdateCreateInventoryItem packet will be
  3836. * returned by the server that has a FolderID/ParentUUID of zero. It is up
  3837. * to the client to make sure that the item gets a good folder, otherwise
  3838. * it will end up inaccesible in inventory.
  3839. */
  3840. if (item.ParentUUID == UUID.Zero)
  3841. {
  3842. // assign default folder for type
  3843. item.ParentUUID = FindFolderForType(item.AssetType);
  3844. Logger.Log("Received an item through UpdateCreateInventoryItem with no parent folder, assigning to folder " +
  3845. item.ParentUUID, Helpers.LogLevel.Info);
  3846. // send update to the sim
  3847. RequestUpdateItem(item);
  3848. }
  3849. // Update the local copy
  3850. _Store[item.UUID] = item;
  3851. // Look for an "item created" callback
  3852. ItemCreatedCallback createdCallback;
  3853. if (_ItemCreatedCallbacks.TryGetValue(dataBlock.CallbackID, out createdCallback))
  3854. {
  3855. _ItemCreatedCallbacks.Remove(dataBlock.CallbackID);
  3856. try { createdCallback(true, item); }
  3857. catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
  3858. }
  3859. // TODO: Is this callback even triggered when items are copied?
  3860. // Look for an "item copied" callback
  3861. ItemCopiedCallback copyCallback;
  3862. if (_ItemCopiedCallbacks.TryGetValue(dataBlock.CallbackID, out copyCallback))
  3863. {
  3864. _ItemCopiedCallbacks.Remove(dataBlock.CallbackID);
  3865. try { copyCallback(item); }
  3866. catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
  3867. }
  3868. //This is triggered when an item is received from a task
  3869. if (m_TaskItemReceived != null)
  3870. {
  3871. OnTaskItemReceived(new TaskItemReceivedEventArgs(item.UUID, dataBlock.FolderID,
  3872. item.CreatorID, item.AssetUUID, item.InventoryType));
  3873. }
  3874. }
  3875. }
  3876. /// <summary>Process an incoming packet and raise the appropriate events</summary>
  3877. /// <param name="sender">The sender</param>
  3878. /// <param name="e">The EventArgs object containing the packet data</param>
  3879. protected void MoveInventoryItemHandler(object sender, PacketReceivedEventArgs e)
  3880. {
  3881. Packet packet = e.Packet;
  3882. MoveInventoryItemPacket move = (MoveInventoryItemPacket)packet;
  3883. for (int i = 0; i < move.InventoryData.Length; i++)
  3884. {
  3885. // FIXME: Do something here
  3886. string newName = Utils.BytesToString(move.InventoryData[i].NewName);
  3887. Logger.Log(String.Format(
  3888. "MoveInventoryItemHandler: Item {0} is moving to Folder {1} with new name \"{2}\". Someone write this function!",
  3889. move.InventoryData[i].ItemID.ToString(), move.InventoryData[i].FolderID.ToString(),
  3890. newName), Helpers.LogLevel.Warning, Client);
  3891. }
  3892. }
  3893. protected void BulkUpdateInventoryCapHandler(string capsKey, Interfaces.IMessage message, Simulator simulator)
  3894. {
  3895. BulkUpdateInventoryMessage msg = (BulkUpdateInventoryMessage)message;
  3896. foreach (BulkUpdateInventoryMessage.FolderDataInfo newFolder in msg.FolderData)
  3897. {
  3898. if (newFolder.FolderID == UUID.Zero) continue;
  3899. InventoryFolder folder;
  3900. if (!_Store.Contains(newFolder.FolderID))
  3901. {
  3902. folder = new InventoryFolder(newFolder.FolderID);
  3903. }
  3904. else
  3905. {
  3906. folder = (InventoryFolder)_Store[newFolder.FolderID];
  3907. }
  3908. folder.Name = newFolder.Name;
  3909. folder.ParentUUID = newFolder.ParentID;
  3910. folder.PreferredType = newFolder.Type;
  3911. _Store[folder.UUID] = folder;
  3912. }
  3913. foreach (BulkUpdateInventoryMessage.ItemDataInfo newItem in msg.ItemData)
  3914. {
  3915. if (newItem.ItemID == UUID.Zero) continue;
  3916. InventoryItem item = SafeCreateInventoryItem(newItem.InvType, newItem.ItemID);
  3917. item.AssetType = newItem.Type;
  3918. item.AssetUUID = newItem.AssetID;
  3919. item.CreationDate = newItem.CreationDate;
  3920. item.CreatorID = newItem.CreatorID;
  3921. item.Description = newItem.Description;
  3922. item.Flags = newItem.Flags;
  3923. item.GroupID = newItem.GroupID;
  3924. item.GroupOwned = newItem.GroupOwned;
  3925. item.Name = newItem.Name;
  3926. item.OwnerID = newItem.OwnerID;
  3927. item.ParentUUID = newItem.FolderID;
  3928. item.Permissions.BaseMask = newItem.BaseMask;
  3929. item.Permissions.EveryoneMask = newItem.EveryoneMask;
  3930. item.Permissions.GroupMask = newItem.GroupMask;
  3931. item.Permissions.NextOwnerMask = newItem.NextOwnerMask;
  3932. item.Permissions.OwnerMask = newItem.OwnerMask;
  3933. item.SalePrice = newItem.SalePrice;
  3934. item.SaleType = newItem.SaleType;
  3935. _Store[item.UUID] = item;
  3936. // Look for an "item created" callback
  3937. ItemCreatedCallback callback;
  3938. if (_ItemCreatedCallbacks.TryGetValue(newItem.CallbackID, out callback))
  3939. {
  3940. _ItemCreatedCallbacks.Remove(newItem.CallbackID);
  3941. try { callback(true, item); }
  3942. catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
  3943. }
  3944. // Look for an "item copied" callback
  3945. ItemCopiedCallback copyCallback;
  3946. if (_ItemCopiedCallbacks.TryGetValue(newItem.CallbackID, out copyCallback))
  3947. {
  3948. _ItemCopiedCallbacks.Remove(newItem.CallbackID);
  3949. try { copyCallback(item); }
  3950. catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
  3951. }
  3952. }
  3953. }
  3954. /// <summary>Process an incoming packet and raise the appropriate events</summary>
  3955. /// <param name="sender">The sender</param>
  3956. /// <param name="e">The EventArgs object containing the packet data</param>
  3957. protected void BulkUpdateInventoryHandler(object sender, PacketReceivedEventArgs e)
  3958. {
  3959. Packet packet = e.Packet;
  3960. BulkUpdateInventoryPacket update = packet as BulkUpdateInventoryPacket;
  3961. if (update.FolderData.Length > 0 && update.FolderData[0].FolderID != UUID.Zero)
  3962. {
  3963. foreach (BulkUpdateInventoryPacket.FolderDataBlock dataBlock in update.FolderData)
  3964. {
  3965. InventoryFolder folder;
  3966. if (!_Store.Contains(dataBlock.FolderID))
  3967. {
  3968. folder = new InventoryFolder(dataBlock.FolderID);
  3969. }
  3970. else
  3971. {
  3972. folder = (InventoryFolder)_Store[dataBlock.FolderID];
  3973. }
  3974. if (dataBlock.Name != null)
  3975. {
  3976. folder.Name = Utils.BytesToString(dataBlock.Name);
  3977. }
  3978. folder.OwnerID = update.AgentData.AgentID;
  3979. folder.ParentUUID = dataBlock.ParentID;
  3980. _Store[folder.UUID] = folder;
  3981. }
  3982. }
  3983. if (update.ItemData.Length > 0 && update.ItemData[0].ItemID != UUID.Zero)
  3984. {
  3985. for (int i = 0; i < update.ItemData.Length; i++)
  3986. {
  3987. BulkUpdateInventoryPacket.ItemDataBlock dataBlock = update.ItemData[i];
  3988. InventoryItem item = SafeCreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID);
  3989. item.AssetType = (AssetType)dataBlock.Type;
  3990. if (dataBlock.AssetID != UUID.Zero) item.AssetUUID = dataBlock.AssetID;
  3991. item.CreationDate = Utils.UnixTimeToDateTime(dataBlock.CreationDate);
  3992. item.CreatorID = dataBlock.CreatorID;
  3993. item.Description = Utils.BytesToString(dataBlock.Description);
  3994. item.Flags = dataBlock.Flags;
  3995. item.GroupID = dataBlock.GroupID;
  3996. item.GroupOwned = dataBlock.GroupOwned;
  3997. item.Name = Utils.BytesToString(dataBlock.Name);
  3998. item.OwnerID = dataBlock.OwnerID;
  3999. item.ParentUUID = dataBlock.FolderID;
  4000. item.Permissions = new Permissions(
  4001. dataBlock.BaseMask,
  4002. dataBlock.EveryoneMask,
  4003. dataBlock.GroupMask,
  4004. dataBlock.NextOwnerMask,
  4005. dataBlock.OwnerMask);
  4006. item.SalePrice = dataBlock.SalePrice;
  4007. item.SaleType = (SaleType)dataBlock.SaleType;
  4008. _Store[item.UUID] = item;
  4009. // Look for an "item created" callback
  4010. ItemCreatedCallback callback;
  4011. if (_ItemCreatedCallbacks.TryGetValue(dataBlock.CallbackID, out callback))
  4012. {
  4013. _ItemCreatedCallbacks.Remove(dataBlock.CallbackID);
  4014. try { callback(true, item); }
  4015. catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
  4016. }
  4017. // Look for an "item copied" callback
  4018. ItemCopiedCallback copyCallback;
  4019. if (_ItemCopiedCallbacks.TryGetValue(dataBlock.CallbackID, out copyCallback))
  4020. {
  4021. _ItemCopiedCallbacks.Remove(dataBlock.CallbackID);
  4022. try { copyCallback(item); }
  4023. catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client, ex); }
  4024. }
  4025. }
  4026. }
  4027. }
  4028. /// <summary>Process an incoming packet and raise the appropriate events</summary>
  4029. /// <param name="sender">The sender</param>
  4030. /// <param name="e">The EventArgs object containing the packet data</param>
  4031. protected void FetchInventoryReplyHandler(object sender, PacketReceivedEventArgs e)
  4032. {
  4033. Packet packet = e.Packet;
  4034. FetchInventoryReplyPacket reply = packet as FetchInventoryReplyPacket;
  4035. foreach (FetchInventoryReplyPacket.InventoryDataBlock dataBlock in reply.InventoryData)
  4036. {
  4037. if (dataBlock.InvType == (sbyte)InventoryType.Folder)
  4038. {
  4039. Logger.Log("Received FetchInventoryReply for an inventory folder, this should not happen!",
  4040. Helpers.LogLevel.Error, Client);
  4041. continue;
  4042. }
  4043. InventoryItem item = CreateInventoryItem((InventoryType)dataBlock.InvType, dataBlock.ItemID);
  4044. item.AssetType = (AssetType)dataBlock.Type;
  4045. item.AssetUUID = dataBlock.AssetID;
  4046. item.CreationDate = Utils.UnixTimeToDateTime(dataBlock.CreationDate);
  4047. item.CreatorID = dataBlock.CreatorID;
  4048. item.Description = Utils.BytesToString(dataBlock.Description);
  4049. item.Flags = dataBlock.Flags;
  4050. item.GroupID = dataBlock.GroupID;
  4051. item.GroupOwned = dataBlock.GroupOwned;
  4052. item.InventoryType = (InventoryType)dataBlock.InvType;
  4053. item.Name = Utils.BytesToString(dataBlock.Name);
  4054. item.OwnerID = dataBlock.OwnerID;
  4055. item.ParentUUID = dataBlock.FolderID;
  4056. item.Permissions = new Permissions(
  4057. dataBlock.BaseMask,
  4058. dataBlock.EveryoneMask,
  4059. dataBlock.GroupMask,
  4060. dataBlock.NextOwnerMask,
  4061. dataBlock.OwnerMask);
  4062. item.SalePrice = dataBlock.SalePrice;
  4063. item.SaleType = (SaleType)dataBlock.SaleType;
  4064. item.UUID = dataBlock.ItemID;
  4065. _Store[item.UUID] = item;
  4066. // Fire the callback for an item being fetched
  4067. if (m_ItemReceived != null)
  4068. {
  4069. OnItemReceived(new ItemReceivedEventArgs(item));
  4070. }
  4071. }
  4072. }
  4073. /// <summary>Process an incoming packet and raise the appropriate events</summary>
  4074. /// <param name="sender">The sender</param>
  4075. /// <param name="e">The EventArgs object containing the packet data</param>
  4076. protected void ReplyTaskInventoryHandler(object sender, PacketReceivedEventArgs e)
  4077. {
  4078. if (m_TaskInventoryReply != null)
  4079. {
  4080. Packet packet = e.Packet;
  4081. ReplyTaskInventoryPacket reply = (ReplyTaskInventoryPacket)packet;
  4082. OnTaskInventoryReply(new TaskInventoryReplyEventArgs(reply.InventoryData.TaskID, reply.InventoryData.Serial,
  4083. Utils.BytesToString(reply.InventoryData.Filename)));
  4084. }
  4085. }
  4086. protected void ScriptRunningReplyMessageHandler(string capsKey, Interfaces.IMessage message, Simulator simulator)
  4087. {
  4088. if (m_ScriptRunningReply != null)
  4089. {
  4090. ScriptRunningReplyMessage msg = (ScriptRunningReplyMessage)message;
  4091. OnScriptRunningReply(new ScriptRunningReplyEventArgs(msg.ObjectID, msg.ItemID, msg.Mono, msg.Running));
  4092. }
  4093. }
  4094. #endregion Packet Handlers
  4095. }
  4096. #region EventArgs
  4097. public class InventoryObjectOfferedEventArgs : EventArgs
  4098. {
  4099. private readonly InstantMessage m_Offer;
  4100. private readonly AssetType m_AssetType;
  4101. private readonly UUID m_ObjectID;
  4102. private readonly bool m_FromTask;
  4103. /// <summary>Set to true to accept offer, false to decline it</summary>
  4104. public bool Accept { get; set; }
  4105. /// <summary>The folder to accept the inventory into, if null default folder for <see cref="AssetType"/> will be used</summary>
  4106. public UUID FolderID { get; set; }
  4107. public InstantMessage Offer { get { return m_Offer; } }
  4108. public AssetType AssetType { get { return m_AssetType; } }
  4109. public UUID ObjectID { get { return m_ObjectID; } }
  4110. public bool FromTask { get { return m_FromTask; } }
  4111. public InventoryObjectOfferedEventArgs(InstantMessage offerDetails, AssetType type, UUID objectID, bool fromTask, UUID folderID)
  4112. {
  4113. this.Accept = false;
  4114. this.FolderID = folderID;
  4115. this.m_Offer = offerDetails;
  4116. this.m_AssetType = type;
  4117. this.m_ObjectID = objectID;
  4118. this.m_FromTask = fromTask;
  4119. }
  4120. }
  4121. public class FolderUpdatedEventArgs : EventArgs
  4122. {
  4123. private readonly UUID m_FolderID;
  4124. public UUID FolderID { get { return m_FolderID; } }
  4125. private readonly bool m_Success;
  4126. public bool Success { get { return m_Success; } }
  4127. public FolderUpdatedEventArgs(UUID folderID, bool success)
  4128. {
  4129. this.m_FolderID = folderID;
  4130. this.m_Success = success;
  4131. }
  4132. }
  4133. public class ItemReceivedEventArgs : EventArgs
  4134. {
  4135. private readonly InventoryItem m_Item;
  4136. public InventoryItem Item { get { return m_Item; } }
  4137. public ItemReceivedEventArgs(InventoryItem item)
  4138. {
  4139. this.m_Item = item;
  4140. }
  4141. }
  4142. public class FindObjectByPathReplyEventArgs : EventArgs
  4143. {
  4144. private readonly String m_Path;
  4145. private readonly UUID m_InventoryObjectID;
  4146. public String Path { get { return m_Path; } }
  4147. public UUID InventoryObjectID { get { return m_InventoryObjectID; } }
  4148. public FindObjectByPathReplyEventArgs(string path, UUID inventoryObjectID)
  4149. {
  4150. this.m_Path = path;
  4151. this.m_InventoryObjectID = inventoryObjectID;
  4152. }
  4153. }
  4154. /// <summary>
  4155. /// Callback when an inventory object is accepted and received from a
  4156. /// task inventory. This is the callback in which you actually get
  4157. /// the ItemID, as in ObjectOfferedCallback it is null when received
  4158. /// from a task.
  4159. /// </summary>
  4160. public class TaskItemReceivedEventArgs : EventArgs
  4161. {
  4162. private readonly UUID m_ItemID;
  4163. private readonly UUID m_FolderID;
  4164. private readonly UUID m_CreatorID;
  4165. private readonly UUID m_AssetID;
  4166. private readonly InventoryType m_Type;
  4167. public UUID ItemID { get { return m_ItemID; } }
  4168. public UUID FolderID { get { return m_FolderID; } }
  4169. public UUID CreatorID { get { return m_CreatorID; } }
  4170. public UUID AssetID { get { return m_AssetID; } }
  4171. public InventoryType Type { get { return m_Type; } }
  4172. public TaskItemReceivedEventArgs(UUID itemID, UUID folderID, UUID creatorID, UUID assetID, InventoryType type)
  4173. {
  4174. this.m_ItemID = itemID;
  4175. this.m_FolderID = folderID;
  4176. this.m_CreatorID = creatorID;
  4177. this.m_AssetID = assetID;
  4178. this.m_Type = type;
  4179. }
  4180. }
  4181. public class TaskInventoryReplyEventArgs : EventArgs
  4182. {
  4183. private readonly UUID m_ItemID;
  4184. private readonly Int16 m_Serial;
  4185. private readonly String m_AssetFilename;
  4186. public UUID ItemID { get { return m_ItemID; } }
  4187. public Int16 Serial { get { return m_Serial; } }
  4188. public String AssetFilename { get { return m_AssetFilename; } }
  4189. public TaskInventoryReplyEventArgs(UUID itemID, short serial, string assetFilename)
  4190. {
  4191. this.m_ItemID = itemID;
  4192. this.m_Serial = serial;
  4193. this.m_AssetFilename = assetFilename;
  4194. }
  4195. }
  4196. public class SaveAssetToInventoryEventArgs : EventArgs
  4197. {
  4198. private readonly UUID m_ItemID;
  4199. private readonly UUID m_NewAssetID;
  4200. public UUID ItemID { get { return m_ItemID; } }
  4201. public UUID NewAssetID { get { return m_NewAssetID; } }
  4202. public SaveAssetToInventoryEventArgs(UUID itemID, UUID newAssetID)
  4203. {
  4204. this.m_ItemID = itemID;
  4205. this.m_NewAssetID = newAssetID;
  4206. }
  4207. }
  4208. public class ScriptRunningReplyEventArgs : EventArgs
  4209. {
  4210. private readonly UUID m_ObjectID;
  4211. private readonly UUID m_ScriptID;
  4212. private readonly bool m_IsMono;
  4213. private readonly bool m_IsRunning;
  4214. public UUID ObjectID { get { return m_ObjectID; } }
  4215. public UUID ScriptID { get { return m_ScriptID; } }
  4216. public bool IsMono { get { return m_IsMono; } }
  4217. public bool IsRunning { get { return m_IsRunning; } }
  4218. public ScriptRunningReplyEventArgs(UUID objectID, UUID sctriptID, bool isMono, bool isRunning)
  4219. {
  4220. this.m_ObjectID = objectID;
  4221. this.m_ScriptID = sctriptID;
  4222. this.m_IsMono = isMono;
  4223. this.m_IsRunning = isRunning;
  4224. }
  4225. }
  4226. #endregion
  4227. }