InventoryTransferModule.cs 17 KB

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