InventoryTransferModule.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Reflection;
  30. using log4net;
  31. using Nini.Config;
  32. using OpenMetaverse;
  33. using OpenSim.Framework;
  34. using OpenSim.Framework.Communications.Cache;
  35. using OpenSim.Region.Framework.Interfaces;
  36. using OpenSim.Region.Framework.Scenes;
  37. namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
  38. {
  39. public class InventoryTransferModule : IInventoryTransferModule, IRegionModule
  40. {
  41. private static readonly ILog m_log
  42. = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  43. /// <summary>
  44. private List<Scene> m_Scenelist = new List<Scene>();
  45. private Dictionary<UUID, Scene> m_AgentRegions =
  46. new Dictionary<UUID, Scene>();
  47. private IMessageTransferModule m_TransferModule = null;
  48. #region IRegionModule Members
  49. public void Initialise(Scene scene, IConfigSource config)
  50. {
  51. if (config.Configs["Messaging"] != null)
  52. {
  53. // Allow disabling this module in config
  54. //
  55. if (config.Configs["Messaging"].GetString(
  56. "InventoryTransferModule", "InventoryTransferModule") !=
  57. "InventoryTransferModule")
  58. return;
  59. }
  60. if (!m_Scenelist.Contains(scene))
  61. {
  62. if (m_Scenelist.Count == 0)
  63. {
  64. m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
  65. if (m_TransferModule == null)
  66. m_log.Error("[INVENTORY TRANSFER] No Message transfer module found, transfers will be local only");
  67. }
  68. m_Scenelist.Add(scene);
  69. scene.RegisterModuleInterface<IInventoryTransferModule>(this);
  70. scene.EventManager.OnNewClient += OnNewClient;
  71. scene.EventManager.OnClientClosed += ClientLoggedOut;
  72. scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
  73. }
  74. }
  75. public void PostInitialise()
  76. {
  77. }
  78. public void Close()
  79. {
  80. }
  81. public string Name
  82. {
  83. get { return "InventoryModule"; }
  84. }
  85. public bool IsSharedModule
  86. {
  87. get { return true; }
  88. }
  89. #endregion
  90. private void OnNewClient(IClientAPI client)
  91. {
  92. // Inventory giving is conducted via instant message
  93. client.OnInstantMessage += OnInstantMessage;
  94. }
  95. private Scene FindClientScene(UUID agentId)
  96. {
  97. lock (m_Scenelist)
  98. {
  99. foreach (Scene scene in m_Scenelist)
  100. {
  101. ScenePresence presence = scene.GetScenePresence(agentId);
  102. if (presence != null)
  103. {
  104. if (!presence.IsChildAgent)
  105. return scene;
  106. }
  107. }
  108. }
  109. return null;
  110. }
  111. private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
  112. {
  113. m_log.InfoFormat("OnInstantMessage {0}", im.dialog);
  114. Scene scene = FindClientScene(client.AgentId);
  115. if (scene == null) // Something seriously wrong here.
  116. return;
  117. if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
  118. {
  119. //m_log.DebugFormat("Asset type {0}", ((AssetType)im.binaryBucket[0]));
  120. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  121. UUID copyID;
  122. // First byte is the asset type
  123. AssetType assetType = (AssetType)im.binaryBucket[0];
  124. if (AssetType.Folder == assetType)
  125. {
  126. UUID folderID = new UUID(im.binaryBucket, 1);
  127. m_log.DebugFormat("[AGENT INVENTORY]: Inserting original folder {0} "+
  128. "into agent {1}'s inventory",
  129. folderID, new UUID(im.toAgentID));
  130. InventoryFolderImpl folderCopy
  131. = scene.GiveInventoryFolder(new UUID(im.toAgentID), client.AgentId, folderID, UUID.Zero);
  132. if (folderCopy == null)
  133. {
  134. client.SendAgentAlertMessage("Can't find folder to give. Nothing given.", false);
  135. return;
  136. }
  137. // The outgoing binary bucket should contain only the byte which signals an asset folder is
  138. // being copied and the following bytes for the copied folder's UUID
  139. copyID = folderCopy.ID;
  140. byte[] copyIDBytes = copyID.GetBytes();
  141. im.binaryBucket = new byte[1 + copyIDBytes.Length];
  142. im.binaryBucket[0] = (byte)AssetType.Folder;
  143. Array.Copy(copyIDBytes, 0, im.binaryBucket, 1, copyIDBytes.Length);
  144. if (user != null && !user.IsChildAgent)
  145. {
  146. user.ControllingClient.SendBulkUpdateInventory(folderCopy);
  147. }
  148. }
  149. else
  150. {
  151. // First byte of the array is probably the item type
  152. // Next 16 bytes are the UUID
  153. m_log.Info("OnInstantMessage - giving item");
  154. UUID itemID = new UUID(im.binaryBucket, 1);
  155. m_log.DebugFormat("[AGENT INVENTORY]: Inserting item {0} "+
  156. "into agent {1}'s inventory",
  157. itemID, new UUID(im.toAgentID));
  158. InventoryItemBase itemCopy = scene.GiveInventoryItem(
  159. new UUID(im.toAgentID),
  160. client.AgentId, itemID);
  161. if (itemCopy == null)
  162. {
  163. client.SendAgentAlertMessage("Can't find item to give. Nothing given.", false);
  164. return;
  165. }
  166. copyID = itemCopy.ID;
  167. Array.Copy(copyID.GetBytes(), 0, im.binaryBucket, 1, 16);
  168. if (user != null && !user.IsChildAgent)
  169. {
  170. user.ControllingClient.SendBulkUpdateInventory(itemCopy);
  171. }
  172. }
  173. // Send the IM to the recipient. The item is already
  174. // in their inventory, so it will not be lost if
  175. // they are offline.
  176. //
  177. if (user != null && !user.IsChildAgent)
  178. {
  179. // And notify. Transaction ID is the item ID. We get that
  180. // same ID back on the reply so we know what to act on
  181. //
  182. user.ControllingClient.SendInstantMessage(im);
  183. return;
  184. }
  185. else
  186. {
  187. if (m_TransferModule != null)
  188. m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
  189. }
  190. }
  191. else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
  192. {
  193. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  194. if (user != null) // Local
  195. {
  196. user.ControllingClient.SendInstantMessage(im);
  197. }
  198. else
  199. {
  200. if (m_TransferModule != null)
  201. m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
  202. }
  203. }
  204. else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
  205. {
  206. // Here, the recipient is local and we can assume that the
  207. // inventory is loaded. Courtesy of the above bulk update,
  208. // It will have been pushed to the client, too
  209. //
  210. CachedUserInfo userInfo =
  211. scene.CommsManager.UserProfileCacheService.
  212. GetUserDetails(client.AgentId);
  213. if (userInfo != null)
  214. {
  215. InventoryFolderImpl trashFolder =
  216. userInfo.FindFolderForType((int)AssetType.TrashFolder);
  217. UUID inventoryEntityID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
  218. InventoryItemBase item = userInfo.RootFolder.FindItem(inventoryEntityID);
  219. InventoryFolderBase folder = null;
  220. if (item != null && trashFolder != null)
  221. {
  222. item.Folder = trashFolder.ID;
  223. userInfo.DeleteItem(inventoryEntityID);
  224. scene.AddInventoryItem(client, item);
  225. }
  226. else
  227. {
  228. folder = userInfo.RootFolder.FindFolder(inventoryEntityID);
  229. if (folder != null & trashFolder != null)
  230. {
  231. userInfo.MoveFolder(inventoryEntityID, trashFolder.ID);
  232. }
  233. }
  234. if ((null == item && null == folder) | null == trashFolder)
  235. {
  236. string reason = String.Empty;
  237. if (trashFolder == null)
  238. reason += " Trash folder not found.";
  239. if (item == null)
  240. reason += " Item not found.";
  241. if (folder == null)
  242. reason += " Folder not found.";
  243. client.SendAgentAlertMessage("Unable to delete "+
  244. "received inventory" + reason, false);
  245. }
  246. }
  247. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  248. if (user != null) // Local
  249. {
  250. user.ControllingClient.SendInstantMessage(im);
  251. }
  252. else
  253. {
  254. if (m_TransferModule != null)
  255. m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
  256. }
  257. }
  258. }
  259. public void SetRootAgentScene(UUID agentID, Scene scene)
  260. {
  261. m_AgentRegions[agentID] = scene;
  262. }
  263. public bool NeedSceneCacheClear(UUID agentID, Scene scene)
  264. {
  265. if (!m_AgentRegions.ContainsKey(agentID))
  266. {
  267. // Since we can get here two ways, we need to scan
  268. // the scenes here. This is somewhat more expensive
  269. // but helps avoid a nasty bug
  270. //
  271. foreach (Scene s in m_Scenelist)
  272. {
  273. ScenePresence presence;
  274. if (s.TryGetAvatar(agentID, out presence))
  275. {
  276. // If the agent is in this scene, then we
  277. // are being called twice in a single
  278. // teleport. This is wasteful of cycles
  279. // but harmless due to this 2nd level check
  280. //
  281. // If the agent is found in another scene
  282. // then the list wasn't current
  283. //
  284. // If the agent is totally unknown, then what
  285. // are we even doing here??
  286. //
  287. if (s == scene)
  288. {
  289. //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
  290. return true;
  291. }
  292. else
  293. {
  294. //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
  295. return false;
  296. }
  297. }
  298. }
  299. //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
  300. return true;
  301. }
  302. // The agent is left in current Scene, so we must be
  303. // going to another instance
  304. //
  305. if (m_AgentRegions[agentID] == scene)
  306. {
  307. //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
  308. m_AgentRegions.Remove(agentID);
  309. return true;
  310. }
  311. // Another region has claimed the agent
  312. //
  313. //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
  314. return false;
  315. }
  316. public void ClientLoggedOut(UUID agentID, Scene scene)
  317. {
  318. if (m_AgentRegions.ContainsKey(agentID))
  319. m_AgentRegions.Remove(agentID);
  320. }
  321. /// <summary>
  322. ///
  323. /// </summary>
  324. /// <param name="msg"></param>
  325. private void OnGridInstantMessage(GridInstantMessage msg)
  326. {
  327. // Check if this is ours to handle
  328. //
  329. m_log.Info("OnFridInstantMessage");
  330. if (msg.dialog != (byte) InstantMessageDialog.InventoryOffered)
  331. return;
  332. if (msg.binaryBucket.Length < 17) // Invalid
  333. return;
  334. Scene scene = FindClientScene(new UUID(msg.toAgentID));
  335. // Find agent to deliver to
  336. //
  337. ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID));
  338. if (user == null) // Shouldn't happen
  339. {
  340. m_log.Debug("[INVENTORY TRANSFER] Can't find recipient");
  341. return;
  342. }
  343. CachedUserInfo userInfo =
  344. scene.CommsManager.UserProfileCacheService.
  345. GetUserDetails(user.ControllingClient.AgentId);
  346. if (userInfo == null)
  347. {
  348. m_log.Debug("[INVENTORY TRANSFER] Can't find user info of recipient");
  349. return;
  350. }
  351. AssetType assetType = (AssetType)msg.binaryBucket[0];
  352. if (AssetType.Folder == assetType)
  353. {
  354. UUID folderID = new UUID(msg.binaryBucket, 1);
  355. InventoryFolderBase folder = new InventoryFolderBase();
  356. folder.ID = folderID;
  357. folder.Owner = user.ControllingClient.AgentId;
  358. // Fetch from database
  359. //
  360. if (!userInfo.QueryFolder(folder))
  361. {
  362. m_log.Debug("[INVENTORY TRANSFER] Can't find folder to give");
  363. return;
  364. }
  365. // Get folder info
  366. //
  367. InventoryFolderImpl folderInfo = userInfo.RootFolder.FindFolder(folder.ID);
  368. if (folderInfo == null)
  369. {
  370. m_log.Debug("[INVENTORY TRANSFER] Can't retrieve folder to give");
  371. return;
  372. }
  373. user.ControllingClient.SendBulkUpdateInventory(folderInfo);
  374. // This unelegant, slow kludge is to reload the folders and
  375. // items. Since a folder give can transfer subfolders and
  376. // items, this is the easiest way to pull that stuff in
  377. //
  378. userInfo.DropInventory();
  379. userInfo.FetchInventory();
  380. // Deliver message
  381. //
  382. user.ControllingClient.SendInstantMessage(msg);
  383. }
  384. else
  385. {
  386. UUID itemID = new UUID(msg.binaryBucket, 1);
  387. InventoryItemBase item = new InventoryItemBase();
  388. item.ID = itemID;
  389. item.Owner = user.ControllingClient.AgentId;
  390. // Fetch from database
  391. //
  392. if (!userInfo.QueryItem(item))
  393. {
  394. m_log.Debug("[INVENTORY TRANSFER] Can't find item to give");
  395. return;
  396. }
  397. // Get item info
  398. //
  399. item = userInfo.RootFolder.FindItem(item.ID);
  400. if (item == null)
  401. {
  402. m_log.Debug("[INVENTORY TRANSFER] Can't retrieve item to give");
  403. return;
  404. }
  405. // Update item to viewer (makes it appear in proper folder)
  406. //
  407. user.ControllingClient.SendBulkUpdateInventory(item);
  408. // Deliver message
  409. //
  410. user.ControllingClient.SendInstantMessage(msg);
  411. }
  412. }
  413. }
  414. }