InventoryTransferModule.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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 Mono.Addins;
  32. using Nini.Config;
  33. using OpenMetaverse;
  34. using OpenSim.Framework;
  35. using OpenSim.Region.Framework.Interfaces;
  36. using OpenSim.Region.Framework.Scenes;
  37. using OpenSim.Services.Interfaces;
  38. namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
  39. {
  40. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "InventoryTransferModule")]
  41. public class InventoryTransferModule : ISharedRegionModule
  42. {
  43. private static readonly ILog m_log
  44. = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  45. /// <summary>
  46. private List<Scene> m_Scenelist = new List<Scene>();
  47. private IMessageTransferModule m_TransferModule;
  48. private bool m_Enabled = true;
  49. #region Region Module interface
  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.OnIncomingInstantMessage += OnGridInstantMessage;
  73. }
  74. public void RegionLoaded(Scene scene)
  75. {
  76. if (m_TransferModule == null)
  77. {
  78. m_TransferModule = m_Scenelist[0].RequestModuleInterface<IMessageTransferModule>();
  79. if (m_TransferModule == null)
  80. {
  81. m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only");
  82. m_Enabled = false;
  83. // m_Scenelist.Clear();
  84. // scene.EventManager.OnNewClient -= OnNewClient;
  85. scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
  86. }
  87. }
  88. }
  89. public void RemoveRegion(Scene scene)
  90. {
  91. scene.EventManager.OnNewClient -= OnNewClient;
  92. scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
  93. m_Scenelist.Remove(scene);
  94. }
  95. public void PostInitialise()
  96. {
  97. }
  98. public void Close()
  99. {
  100. }
  101. public string Name
  102. {
  103. get { return "InventoryModule"; }
  104. }
  105. public Type ReplaceableInterface
  106. {
  107. get { return null; }
  108. }
  109. #endregion
  110. private void OnNewClient(IClientAPI client)
  111. {
  112. // Inventory giving is conducted via instant message
  113. client.OnInstantMessage += OnInstantMessage;
  114. }
  115. private Scene FindClientScene(UUID agentId)
  116. {
  117. lock (m_Scenelist)
  118. {
  119. foreach (Scene scene in m_Scenelist)
  120. {
  121. ScenePresence presence = scene.GetScenePresence(agentId);
  122. if (presence != null)
  123. return scene;
  124. }
  125. }
  126. return null;
  127. }
  128. private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
  129. {
  130. // m_log.DebugFormat(
  131. // "[INVENTORY TRANSFER]: {0} IM type received from client {1}. From={2} ({3}), To={4}",
  132. // (InstantMessageDialog)im.dialog, client.Name,
  133. // im.fromAgentID, im.fromAgentName, im.toAgentID);
  134. Scene scene = FindClientScene(client.AgentId);
  135. if (scene == null) // Something seriously wrong here.
  136. return;
  137. UUID agentID = client.AgentId;
  138. switch((InstantMessageDialog)im.dialog)
  139. {
  140. case InstantMessageDialog.InventoryOffered:
  141. {
  142. if (im.binaryBucket.Length < 17) // Invalid
  143. return;
  144. UUID recipientID = new UUID(im.toAgentID);
  145. ScenePresence recipientAgent = scene.GetScenePresence(recipientID);
  146. UUID copyID;
  147. // First byte is the asset type
  148. AssetType assetType = (AssetType)im.binaryBucket[0];
  149. if(assetType == AssetType.LinkFolder || assetType == AssetType.Link)
  150. {
  151. client.SendAgentAlertMessage("Can't give a link. Nothing given.", false);
  152. return;
  153. }
  154. if (assetType == AssetType.Folder)
  155. {
  156. UUID folderID = new UUID(im.binaryBucket, 1);
  157. if (folderID == UUID.Zero)
  158. {
  159. client.SendAgentAlertMessage("Can't find folder to give. Nothing given.", false);
  160. return;
  161. }
  162. Dictionary<UUID,AssetType> ids = new Dictionary<UUID, AssetType>();
  163. ids[folderID] = assetType;
  164. if (im.binaryBucket.Length >= 34 && im.binaryBucket.Length % 17 == 0)
  165. {
  166. byte[] iddata = im.binaryBucket;
  167. for (int i = 17; i <= im.binaryBucket.Length - 17; i += 17)
  168. ids[new UUID(iddata, i + 1)] = (AssetType)im.binaryBucket[i];
  169. }
  170. m_log.DebugFormat("[INVENTORY TRANSFER]: offering folder {0} to agent {1}'s inventory",
  171. folderID, recipientID);
  172. InventoryFolderBase folderCopy = scene.GiveInventoryFolder(client, recipientID, agentID, folderID, UUID.Zero, ids);
  173. if (folderCopy == null)
  174. {
  175. client.SendAgentAlertMessage("Can't find folder to give. Nothing given.", false);
  176. return;
  177. }
  178. copyID = folderCopy.ID;
  179. im.imSessionID = copyID.Guid;
  180. if (recipientAgent != null)
  181. {
  182. recipientAgent.ControllingClient.SendBulkUpdateInventory(folderCopy);
  183. }
  184. }
  185. else
  186. {
  187. UUID itemID = new UUID(im.binaryBucket, 1);
  188. if (itemID == UUID.Zero)
  189. {
  190. client.SendAgentAlertMessage("Can't find item to give. Nothing given.", false);
  191. return;
  192. }
  193. m_log.DebugFormat("[INVENTORY TRANSFER]: (giving) Inserting item {0} "+
  194. "into agent {1}'s inventory",
  195. itemID, recipientID);
  196. string message;
  197. InventoryItemBase itemCopy = scene.GiveInventoryItem(recipientID, agentID, itemID, out message);
  198. if (itemCopy == null)
  199. {
  200. client.SendAgentAlertMessage(message, false);
  201. return;
  202. }
  203. copyID = itemCopy.ID;
  204. if (recipientAgent != null)
  205. recipientAgent.ControllingClient.SendBulkUpdateInventory(itemCopy);
  206. im.imSessionID = copyID.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. im.binaryBucket = new byte[17];
  212. im.binaryBucket[0] = (byte)assetType;
  213. copyID.ToBytes(im.binaryBucket, 1);
  214. if (recipientAgent != null)
  215. {
  216. im.offline = 0;
  217. recipientAgent.ControllingClient.SendInstantMessage(im);
  218. return;
  219. }
  220. else
  221. {
  222. im.offline = 0;
  223. if (m_TransferModule != null)
  224. {
  225. m_TransferModule.SendInstantMessage(im, delegate(bool success)
  226. {
  227. if (!success)
  228. client.SendAlertMessage("User not online. Inventory has been saved");
  229. });
  230. }
  231. }
  232. break;
  233. }
  234. case InstantMessageDialog.InventoryAccepted:
  235. {
  236. UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
  237. if(inventoryID == UUID.Zero)
  238. return;
  239. IInventoryService invService = scene.InventoryService;
  240. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  241. if (user != null) // Local
  242. {
  243. user.ControllingClient.SendInstantMessage(im);
  244. }
  245. else
  246. {
  247. if (m_TransferModule != null)
  248. m_TransferModule.SendInstantMessage(im, delegate(bool success) {});
  249. }
  250. break;
  251. }
  252. case InstantMessageDialog.TaskInventoryAccepted:
  253. {
  254. if (im.binaryBucket == null || im.binaryBucket.Length < 16)
  255. return;
  256. UUID destinationFolderID = new UUID(im.binaryBucket, 0);
  257. if(destinationFolderID == UUID.Zero) // uuid-zero is a valid folder ID(?) keeping old code assuming not
  258. return;
  259. IInventoryService invService = scene.InventoryService;
  260. InventoryFolderBase destinationFolder = null;
  261. destinationFolder = invService.GetFolder(agentID, destinationFolderID);
  262. if(destinationFolder == null)
  263. return; // no where to put it
  264. UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
  265. if(inventoryID == UUID.Zero)
  266. return;
  267. InventoryItemBase item = invService.GetItem(agentID, inventoryID);
  268. InventoryFolderBase folder = null;
  269. //UUID? previousParentFolderID = null;
  270. if (item != null) // It's an item
  271. {
  272. if(item.Folder != destinationFolderID)
  273. {
  274. //previousParentFolderID = item.Folder;
  275. item.Folder = destinationFolderID;
  276. invService.MoveItems(item.Owner, new List<InventoryItemBase>() { item });
  277. client.SendInventoryItemCreateUpdate(item, 0);
  278. }
  279. }
  280. else
  281. {
  282. folder = invService.GetFolder(agentID, inventoryID);
  283. if (folder != null) // It's a folder
  284. {
  285. if(folder.ParentID != destinationFolderID)
  286. {
  287. folder.ParentID = destinationFolderID;
  288. invService.MoveFolder(folder);
  289. }
  290. client.SendBulkUpdateInventory(folder, folder.ID);
  291. }
  292. }
  293. break;
  294. }
  295. case InstantMessageDialog.InventoryDeclined:
  296. case InstantMessageDialog.TaskInventoryDeclined:
  297. {
  298. IInventoryService invService = scene.InventoryService;
  299. InventoryFolderBase trashFolder = invService.GetFolderForType(agentID, FolderType.Trash);
  300. if(trashFolder == null) //??
  301. {
  302. client.SendAgentAlertMessage("Trash folder not found", false);
  303. return;
  304. }
  305. UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
  306. if(inventoryID == UUID.Zero)
  307. {
  308. client.SendAgentAlertMessage("Item or folder not found", false);
  309. return;
  310. }
  311. InventoryItemBase item = invService.GetItem(agentID, inventoryID);
  312. InventoryFolderBase folder = null;
  313. if (item != null)
  314. {
  315. if (trashFolder.ID != item.Folder)
  316. {
  317. item.Folder = trashFolder.ID;
  318. invService.MoveItems(item.Owner, new List<InventoryItemBase>() { item });
  319. client.SendInventoryItemCreateUpdate(item, 0);
  320. }
  321. }
  322. else
  323. {
  324. folder = invService.GetFolder(agentID, inventoryID);
  325. if (folder != null)
  326. {
  327. if (trashFolder.ID != folder.ParentID)
  328. {
  329. folder.ParentID = trashFolder.ID;
  330. invService.MoveFolder(folder);
  331. }
  332. client.SendBulkUpdateInventory(folder, folder.ID);
  333. }
  334. }
  335. if (im.dialog == (byte)InstantMessageDialog.InventoryDeclined)
  336. {
  337. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  338. if (user != null) // Local
  339. {
  340. user.ControllingClient.SendInstantMessage(im);
  341. }
  342. else
  343. {
  344. if (m_TransferModule != null)
  345. m_TransferModule.SendInstantMessage(im, delegate(bool success) { });
  346. }
  347. }
  348. break;
  349. }
  350. default:
  351. break;
  352. }
  353. }
  354. /// <summary>
  355. ///
  356. /// </summary>
  357. /// <param name="im"></param>
  358. private void OnGridInstantMessage(GridInstantMessage im)
  359. {
  360. // Check if this is ours to handle
  361. //
  362. Scene scene = FindClientScene(new UUID(im.toAgentID));
  363. if (scene == null)
  364. return;
  365. // Find agent to deliver to
  366. //
  367. ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
  368. if (user == null)
  369. return;
  370. switch((InstantMessageDialog)im.dialog)
  371. {
  372. // This requires a little bit of processing because we have to make the
  373. // new item visible in the recipient's inventory here
  374. //
  375. case InstantMessageDialog.InventoryOffered:
  376. {
  377. if (im.binaryBucket.Length < 17) // Invalid
  378. return;
  379. // First byte is the asset type
  380. AssetType assetType = (AssetType)im.binaryBucket[0];
  381. if (assetType == AssetType.LinkFolder || assetType == AssetType.Link)
  382. return;
  383. UUID recipientID = new UUID(im.toAgentID);
  384. UUID copyID;
  385. if (AssetType.Folder == assetType)
  386. {
  387. UUID folderID = new UUID(im.binaryBucket, 1);
  388. InventoryFolderBase folder = scene.InventoryService.GetFolder(recipientID, folderID);
  389. if (folder == null)
  390. return;
  391. copyID = folder.ID;
  392. user.ControllingClient.SendBulkUpdateInventory(folder);
  393. }
  394. else
  395. {
  396. UUID itemID = new UUID(im.binaryBucket, 1);
  397. InventoryItemBase item = scene.InventoryService.GetItem(recipientID, itemID);
  398. if (item == null)
  399. return;
  400. user.ControllingClient.SendBulkUpdateInventory(item);
  401. copyID = item.ID;
  402. }
  403. im.binaryBucket = new byte[17];
  404. im.binaryBucket[0] = (byte)assetType;
  405. copyID.ToBytes(im.binaryBucket, 1);
  406. user.ControllingClient.SendInstantMessage(im);
  407. break;
  408. }
  409. case InstantMessageDialog.TaskInventoryOffered:
  410. {
  411. if (im.binaryBucket.Length < 1) // Invalid
  412. return;
  413. UUID recipientID = new UUID(im.toAgentID);
  414. // Bucket is the asset type
  415. AssetType assetType = (AssetType)im.binaryBucket[0];
  416. if (AssetType.Folder == assetType)
  417. {
  418. UUID folderID = new UUID(im.imSessionID);
  419. InventoryFolderBase folder = scene.InventoryService.GetFolder(recipientID, folderID);
  420. if (folder != null)
  421. user.ControllingClient.SendBulkUpdateInventory(folder);
  422. }
  423. else
  424. {
  425. UUID itemID = new UUID(im.imSessionID);
  426. InventoryItemBase item = scene.InventoryService.GetItem(recipientID, itemID);
  427. if (item != null)
  428. {
  429. user.ControllingClient.SendBulkUpdateInventory(item);
  430. }
  431. }
  432. // Fix up binary bucket since this may be 17 chars long here
  433. Byte[] bucket = new Byte[1];
  434. bucket[0] = im.binaryBucket[0];
  435. im.binaryBucket = bucket;
  436. user.ControllingClient.SendInstantMessage(im);
  437. break;
  438. }
  439. case InstantMessageDialog.InventoryAccepted:
  440. case InstantMessageDialog.InventoryDeclined:
  441. case InstantMessageDialog.TaskInventoryDeclined:
  442. case InstantMessageDialog.TaskInventoryAccepted:
  443. {
  444. user.ControllingClient.SendInstantMessage(im);
  445. break;
  446. }
  447. default:
  448. break;
  449. }
  450. }
  451. }
  452. }