InventoryTransferModule.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  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.Region.Framework.Interfaces;
  35. using OpenSim.Region.Framework.Scenes;
  36. using OpenSim.Services.Interfaces;
  37. namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
  38. {
  39. public class InventoryTransferModule : IInventoryTransferModule, ISharedRegionModule
  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. private bool m_Enabled = true;
  49. #region IRegionModule Members
  50. public void Initialise(IConfigSource config)
  51. {
  52. if (config.Configs["Messaging"] != null)
  53. {
  54. // Allow disabling this module in config
  55. //
  56. if (config.Configs["Messaging"].GetString(
  57. "InventoryTransferModule", "InventoryTransferModule") !=
  58. "InventoryTransferModule")
  59. {
  60. m_Enabled = false;
  61. return;
  62. }
  63. }
  64. }
  65. public void AddRegion(Scene scene)
  66. {
  67. if (!m_Enabled)
  68. return;
  69. m_Scenelist.Add(scene);
  70. scene.RegisterModuleInterface<IInventoryTransferModule>(this);
  71. scene.EventManager.OnNewClient += OnNewClient;
  72. scene.EventManager.OnClientClosed += ClientLoggedOut;
  73. scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
  74. scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene;
  75. }
  76. public void RegionLoaded(Scene scene)
  77. {
  78. if (m_TransferModule == null)
  79. {
  80. m_TransferModule = m_Scenelist[0].RequestModuleInterface<IMessageTransferModule>();
  81. if (m_TransferModule == null)
  82. {
  83. m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
  84. m_Enabled = false;
  85. m_Scenelist.Clear();
  86. scene.EventManager.OnNewClient -= OnNewClient;
  87. scene.EventManager.OnClientClosed -= ClientLoggedOut;
  88. scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
  89. scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
  90. }
  91. }
  92. }
  93. public void RemoveRegion(Scene scene)
  94. {
  95. scene.EventManager.OnNewClient -= OnNewClient;
  96. scene.EventManager.OnClientClosed -= ClientLoggedOut;
  97. scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
  98. scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene;
  99. m_Scenelist.Remove(scene);
  100. }
  101. public void PostInitialise()
  102. {
  103. }
  104. public void Close()
  105. {
  106. }
  107. public string Name
  108. {
  109. get { return "InventoryModule"; }
  110. }
  111. public Type ReplaceableInterface
  112. {
  113. get { return null; }
  114. }
  115. #endregion
  116. private void OnNewClient(IClientAPI client)
  117. {
  118. // Inventory giving is conducted via instant message
  119. client.OnInstantMessage += OnInstantMessage;
  120. }
  121. protected void OnSetRootAgentScene(UUID id, Scene scene)
  122. {
  123. m_AgentRegions[id] = scene;
  124. }
  125. private Scene FindClientScene(UUID agentId)
  126. {
  127. lock (m_Scenelist)
  128. {
  129. foreach (Scene scene in m_Scenelist)
  130. {
  131. ScenePresence presence = scene.GetScenePresence(agentId);
  132. if (presence != null)
  133. return scene;
  134. }
  135. }
  136. return null;
  137. }
  138. private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
  139. {
  140. m_log.DebugFormat(
  141. "[INVENTORY TRANSFER]: {0} IM type received from {1}",
  142. (InstantMessageDialog)im.dialog, client.Name);
  143. Scene scene = FindClientScene(client.AgentId);
  144. if (scene == null) // Something seriously wrong here.
  145. return;
  146. if (im.dialog == (byte) InstantMessageDialog.InventoryOffered)
  147. {
  148. //m_log.DebugFormat("Asset type {0}", ((AssetType)im.binaryBucket[0]));
  149. if (im.binaryBucket.Length < 17) // Invalid
  150. return;
  151. UUID receipientID = new UUID(im.toAgentID);
  152. ScenePresence user = scene.GetScenePresence(receipientID);
  153. UUID copyID;
  154. // First byte is the asset type
  155. AssetType assetType = (AssetType)im.binaryBucket[0];
  156. if (AssetType.Folder == assetType)
  157. {
  158. UUID folderID = new UUID(im.binaryBucket, 1);
  159. m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+
  160. "into agent {1}'s inventory",
  161. folderID, new UUID(im.toAgentID));
  162. InventoryFolderBase folderCopy
  163. = scene.GiveInventoryFolder(receipientID, client.AgentId, folderID, UUID.Zero);
  164. if (folderCopy == null)
  165. {
  166. client.SendAgentAlertMessage("Can't find folder to give. Nothing given.", false);
  167. return;
  168. }
  169. // The outgoing binary bucket should contain only the byte which signals an asset folder is
  170. // being copied and the following bytes for the copied folder's UUID
  171. copyID = folderCopy.ID;
  172. byte[] copyIDBytes = copyID.GetBytes();
  173. im.binaryBucket = new byte[1 + copyIDBytes.Length];
  174. im.binaryBucket[0] = (byte)AssetType.Folder;
  175. Array.Copy(copyIDBytes, 0, im.binaryBucket, 1, copyIDBytes.Length);
  176. if (user != null)
  177. {
  178. user.ControllingClient.SendBulkUpdateInventory(folderCopy);
  179. }
  180. // HACK!!
  181. im.imSessionID = folderID.Guid;
  182. }
  183. else
  184. {
  185. // First byte of the array is probably the item type
  186. // Next 16 bytes are the UUID
  187. UUID itemID = new UUID(im.binaryBucket, 1);
  188. m_log.DebugFormat("[INVENTORY TRANSFER]: (giving) Inserting item {0} "+
  189. "into agent {1}'s inventory",
  190. itemID, new UUID(im.toAgentID));
  191. InventoryItemBase itemCopy = scene.GiveInventoryItem(
  192. new UUID(im.toAgentID),
  193. client.AgentId, itemID);
  194. if (itemCopy == null)
  195. {
  196. client.SendAgentAlertMessage("Can't find item to give. Nothing given.", false);
  197. return;
  198. }
  199. copyID = itemCopy.ID;
  200. Array.Copy(copyID.GetBytes(), 0, im.binaryBucket, 1, 16);
  201. if (user != null)
  202. {
  203. user.ControllingClient.SendBulkUpdateInventory(itemCopy);
  204. }
  205. // HACK!!
  206. im.imSessionID = itemID.Guid;
  207. }
  208. // Send the IM to the recipient. The item is already
  209. // in their inventory, so it will not be lost if
  210. // they are offline.
  211. //
  212. if (user != null)
  213. {
  214. user.ControllingClient.SendInstantMessage(im);
  215. return;
  216. }
  217. else
  218. {
  219. if (m_TransferModule != null)
  220. m_TransferModule.SendInstantMessage(im, delegate(bool success)
  221. {
  222. if (!success)
  223. client.SendAlertMessage("User not online. Inventory has been saved");
  224. });
  225. }
  226. }
  227. else if (im.dialog == (byte) InstantMessageDialog.InventoryAccepted)
  228. {
  229. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  230. if (user != null) // Local
  231. {
  232. user.ControllingClient.SendInstantMessage(im);
  233. }
  234. else
  235. {
  236. if (m_TransferModule != null)
  237. m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
  238. }
  239. }
  240. else if (im.dialog == (byte) InstantMessageDialog.InventoryDeclined)
  241. {
  242. // Here, the recipient is local and we can assume that the
  243. // inventory is loaded. Courtesy of the above bulk update,
  244. // It will have been pushed to the client, too
  245. //
  246. IInventoryService invService = scene.InventoryService;
  247. InventoryFolderBase trashFolder =
  248. invService.GetFolderForType(client.AgentId, AssetType.TrashFolder);
  249. UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
  250. InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
  251. item = invService.GetItem(item);
  252. InventoryFolderBase folder = null;
  253. if (item != null && trashFolder != null)
  254. {
  255. item.Folder = trashFolder.ID;
  256. // Diva comment: can't we just update this item???
  257. List<UUID> uuids = new List<UUID>();
  258. uuids.Add(item.ID);
  259. invService.DeleteItems(item.Owner, uuids);
  260. scene.AddInventoryItem(client, item);
  261. }
  262. else
  263. {
  264. folder = new InventoryFolderBase(inventoryID, client.AgentId);
  265. folder = invService.GetFolder(folder);
  266. if (folder != null & trashFolder != null)
  267. {
  268. folder.ParentID = trashFolder.ID;
  269. invService.MoveFolder(folder);
  270. }
  271. }
  272. if ((null == item && null == folder) | null == trashFolder)
  273. {
  274. string reason = String.Empty;
  275. if (trashFolder == null)
  276. reason += " Trash folder not found.";
  277. if (item == null)
  278. reason += " Item not found.";
  279. if (folder == null)
  280. reason += " Folder not found.";
  281. client.SendAgentAlertMessage("Unable to delete "+
  282. "received inventory" + reason, false);
  283. }
  284. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  285. if (user != null) // Local
  286. {
  287. user.ControllingClient.SendInstantMessage(im);
  288. }
  289. else
  290. {
  291. if (m_TransferModule != null)
  292. m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
  293. }
  294. }
  295. }
  296. public bool NeedSceneCacheClear(UUID agentID, Scene scene)
  297. {
  298. if (!m_AgentRegions.ContainsKey(agentID))
  299. {
  300. // Since we can get here two ways, we need to scan
  301. // the scenes here. This is somewhat more expensive
  302. // but helps avoid a nasty bug
  303. //
  304. foreach (Scene s in m_Scenelist)
  305. {
  306. ScenePresence presence;
  307. if (s.TryGetScenePresence(agentID, out presence))
  308. {
  309. // If the agent is in this scene, then we
  310. // are being called twice in a single
  311. // teleport. This is wasteful of cycles
  312. // but harmless due to this 2nd level check
  313. //
  314. // If the agent is found in another scene
  315. // then the list wasn't current
  316. //
  317. // If the agent is totally unknown, then what
  318. // are we even doing here??
  319. //
  320. if (s == scene)
  321. {
  322. //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName);
  323. return true;
  324. }
  325. else
  326. {
  327. //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName);
  328. return false;
  329. }
  330. }
  331. }
  332. //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName);
  333. return true;
  334. }
  335. // The agent is left in current Scene, so we must be
  336. // going to another instance
  337. //
  338. if (m_AgentRegions[agentID] == scene)
  339. {
  340. //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName);
  341. m_AgentRegions.Remove(agentID);
  342. return true;
  343. }
  344. // Another region has claimed the agent
  345. //
  346. //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName);
  347. return false;
  348. }
  349. public void ClientLoggedOut(UUID agentID, Scene scene)
  350. {
  351. if (m_AgentRegions.ContainsKey(agentID))
  352. m_AgentRegions.Remove(agentID);
  353. }
  354. /// <summary>
  355. ///
  356. /// </summary>
  357. /// <param name="msg"></param>
  358. private void OnGridInstantMessage(GridInstantMessage msg)
  359. {
  360. // Check if this is ours to handle
  361. //
  362. Scene scene = FindClientScene(new UUID(msg.toAgentID));
  363. if (scene == null)
  364. return;
  365. // Find agent to deliver to
  366. //
  367. ScenePresence user = scene.GetScenePresence(new UUID(msg.toAgentID));
  368. // Just forward to local handling
  369. OnInstantMessage(user.ControllingClient, msg);
  370. }
  371. }
  372. }