InventoryArchiverModule.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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.IO;
  30. using System.Reflection;
  31. using log4net;
  32. using Nini.Config;
  33. using OpenMetaverse;
  34. using OpenSim.Framework;
  35. using OpenSim.Framework.Communications;
  36. using OpenSim.Framework.Communications.Cache;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes;
  39. using OpenSim.Services.Interfaces;
  40. namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
  41. {
  42. /// <summary>
  43. /// This module loads and saves OpenSimulator inventory archives
  44. /// </summary>
  45. public class InventoryArchiverModule : IRegionModule, IInventoryArchiverModule
  46. {
  47. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  48. public string Name { get { return "Inventory Archiver Module"; } }
  49. public bool IsSharedModule { get { return true; } }
  50. /// <value>
  51. /// Enable or disable checking whether the iar user is actually logged in
  52. /// </value>
  53. public bool DisablePresenceChecks { get; set; }
  54. public event InventoryArchiveSaved OnInventoryArchiveSaved;
  55. /// <summary>
  56. /// The file to load and save inventory if no filename has been specified
  57. /// </summary>
  58. protected const string DEFAULT_INV_BACKUP_FILENAME = "user-inventory.iar";
  59. /// <value>
  60. /// Pending save completions initiated from the console
  61. /// </value>
  62. protected List<Guid> m_pendingConsoleSaves = new List<Guid>();
  63. /// <value>
  64. /// All scenes that this module knows about
  65. /// </value>
  66. private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
  67. private Scene m_aScene;
  68. public InventoryArchiverModule() {}
  69. public InventoryArchiverModule(bool disablePresenceChecks)
  70. {
  71. DisablePresenceChecks = disablePresenceChecks;
  72. }
  73. public void Initialise(Scene scene, IConfigSource source)
  74. {
  75. if (m_scenes.Count == 0)
  76. {
  77. scene.RegisterModuleInterface<IInventoryArchiverModule>(this);
  78. OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted;
  79. scene.AddCommand(
  80. this, "load iar",
  81. "load iar <first> <last> <inventory path> <password> [<archive path>]",
  82. "Load user inventory archive.", HandleLoadInvConsoleCommand);
  83. scene.AddCommand(
  84. this, "save iar",
  85. "save iar <first> <last> <inventory path> <password> [<archive path>]",
  86. "Save user inventory archive.", HandleSaveInvConsoleCommand);
  87. m_aScene = scene;
  88. }
  89. m_scenes[scene.RegionInfo.RegionID] = scene;
  90. }
  91. public void PostInitialise() {}
  92. public void Close() {}
  93. /// <summary>
  94. /// Trigger the inventory archive saved event.
  95. /// </summary>
  96. protected internal void TriggerInventoryArchiveSaved(
  97. Guid id, bool succeeded, CachedUserInfo userInfo, string invPath, Stream saveStream,
  98. Exception reportedException)
  99. {
  100. InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved;
  101. if (handlerInventoryArchiveSaved != null)
  102. handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException);
  103. }
  104. public bool ArchiveInventory(Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
  105. {
  106. if (m_scenes.Count > 0)
  107. {
  108. CachedUserInfo userInfo = GetUserInfo(firstName, lastName, pass);
  109. if (userInfo != null)
  110. {
  111. if (CheckPresence(userInfo.UserProfile.ID))
  112. {
  113. new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, saveStream).Execute();
  114. return true;
  115. }
  116. else
  117. {
  118. m_log.ErrorFormat(
  119. "[INVENTORY ARCHIVER]: User {0} {1} not logged in to this region simulator",
  120. userInfo.UserProfile.Name, userInfo.UserProfile.ID);
  121. }
  122. }
  123. }
  124. return false;
  125. }
  126. public bool ArchiveInventory(Guid id, string firstName, string lastName, string invPath, string pass, string savePath)
  127. {
  128. if (m_scenes.Count > 0)
  129. {
  130. CachedUserInfo userInfo = GetUserInfo(firstName, lastName, pass);
  131. if (userInfo != null)
  132. {
  133. if (CheckPresence(userInfo.UserProfile.ID))
  134. {
  135. new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, savePath).Execute();
  136. return true;
  137. }
  138. else
  139. {
  140. m_log.ErrorFormat(
  141. "[INVENTORY ARCHIVER]: User {0} {1} not logged in to this region simulator",
  142. userInfo.UserProfile.Name, userInfo.UserProfile.ID);
  143. }
  144. }
  145. }
  146. return false;
  147. }
  148. public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream)
  149. {
  150. if (m_scenes.Count > 0)
  151. {
  152. CachedUserInfo userInfo = GetUserInfo(firstName, lastName, pass);
  153. if (userInfo != null)
  154. {
  155. if (CheckPresence(userInfo.UserProfile.ID))
  156. {
  157. InventoryArchiveReadRequest request =
  158. new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream);
  159. UpdateClientWithLoadedNodes(userInfo, request.Execute());
  160. return true;
  161. }
  162. else
  163. {
  164. m_log.ErrorFormat(
  165. "[INVENTORY ARCHIVER]: User {0} {1} not logged in to this region simulator",
  166. userInfo.UserProfile.Name, userInfo.UserProfile.ID);
  167. }
  168. }
  169. }
  170. return false;
  171. }
  172. public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, string loadPath)
  173. {
  174. if (m_scenes.Count > 0)
  175. {
  176. CachedUserInfo userInfo = GetUserInfo(firstName, lastName, pass);
  177. if (userInfo != null)
  178. {
  179. if (CheckPresence(userInfo.UserProfile.ID))
  180. {
  181. InventoryArchiveReadRequest request =
  182. new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath);
  183. UpdateClientWithLoadedNodes(userInfo, request.Execute());
  184. return true;
  185. }
  186. else
  187. {
  188. m_log.ErrorFormat(
  189. "[INVENTORY ARCHIVER]: User {0} {1} not logged in to this region simulator",
  190. userInfo.UserProfile.Name, userInfo.UserProfile.ID);
  191. }
  192. }
  193. }
  194. return false;
  195. }
  196. /// <summary>
  197. /// Load inventory from an inventory file archive
  198. /// </summary>
  199. /// <param name="cmdparams"></param>
  200. protected void HandleLoadInvConsoleCommand(string module, string[] cmdparams)
  201. {
  202. if (cmdparams.Length < 6)
  203. {
  204. m_log.Error(
  205. "[INVENTORY ARCHIVER]: usage is load iar <first name> <last name> <inventory path> <user password> [<load file path>]");
  206. return;
  207. }
  208. m_log.Info("[INVENTORY ARCHIVER]: PLEASE NOTE THAT THIS FACILITY IS EXPERIMENTAL. BUG REPORTS WELCOME.");
  209. string firstName = cmdparams[2];
  210. string lastName = cmdparams[3];
  211. string invPath = cmdparams[4];
  212. string pass = cmdparams[5];
  213. string loadPath = (cmdparams.Length > 6 ? cmdparams[6] : DEFAULT_INV_BACKUP_FILENAME);
  214. m_log.InfoFormat(
  215. "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}",
  216. loadPath, invPath, firstName, lastName);
  217. if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath))
  218. m_log.InfoFormat(
  219. "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}",
  220. loadPath, firstName, lastName);
  221. }
  222. /// <summary>
  223. /// Save inventory to a file archive
  224. /// </summary>
  225. /// <param name="cmdparams"></param>
  226. protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams)
  227. {
  228. if (cmdparams.Length < 6)
  229. {
  230. m_log.Error(
  231. "[INVENTORY ARCHIVER]: usage is save iar <first name> <last name> <inventory path> <user password> [<save file path>]");
  232. return;
  233. }
  234. m_log.Info("[INVENTORY ARCHIVER]: PLEASE NOTE THAT THIS FACILITY IS EXPERIMENTAL. BUG REPORTS WELCOME.");
  235. string firstName = cmdparams[2];
  236. string lastName = cmdparams[3];
  237. string invPath = cmdparams[4];
  238. string pass = cmdparams[5];
  239. string savePath = (cmdparams.Length > 6 ? cmdparams[6] : DEFAULT_INV_BACKUP_FILENAME);
  240. m_log.InfoFormat(
  241. "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}",
  242. savePath, invPath, firstName, lastName);
  243. Guid id = Guid.NewGuid();
  244. ArchiveInventory(id, firstName, lastName, invPath, pass, savePath);
  245. lock (m_pendingConsoleSaves)
  246. m_pendingConsoleSaves.Add(id);
  247. }
  248. private void SaveInvConsoleCommandCompleted(
  249. Guid id, bool succeeded, CachedUserInfo userInfo, string invPath, Stream saveStream,
  250. Exception reportedException)
  251. {
  252. lock (m_pendingConsoleSaves)
  253. {
  254. if (m_pendingConsoleSaves.Contains(id))
  255. m_pendingConsoleSaves.Remove(id);
  256. else
  257. return;
  258. }
  259. if (succeeded)
  260. {
  261. m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive for {0}", userInfo.UserProfile.Name);
  262. }
  263. else
  264. {
  265. m_log.ErrorFormat(
  266. "[INVENTORY ARCHIVER]: Archive save for {0} failed - {1}",
  267. userInfo.UserProfile.Name, reportedException.Message);
  268. }
  269. }
  270. /// <summary>
  271. /// Get user information for the given name.
  272. /// </summary>
  273. /// <param name="firstName"></param>
  274. /// <param name="lastName"></param>
  275. /// <param name="pass">User password</param>
  276. /// <returns></returns>
  277. protected CachedUserInfo GetUserInfo(string firstName, string lastName, string pass)
  278. {
  279. CachedUserInfo userInfo = m_aScene.CommsManager.UserProfileCacheService.GetUserDetails(firstName, lastName);
  280. //m_aScene.CommsManager.UserService.GetUserProfile(firstName, lastName);
  281. if (null == userInfo)
  282. {
  283. m_log.ErrorFormat(
  284. "[INVENTORY ARCHIVER]: Failed to find user info for {0} {1}",
  285. firstName, lastName);
  286. return null;
  287. }
  288. try
  289. {
  290. if (m_aScene.CommsManager.UserService.AuthenticateUserByPassword(userInfo.UserProfile.ID, pass))
  291. {
  292. return userInfo;
  293. }
  294. else
  295. {
  296. m_log.ErrorFormat(
  297. "[INVENTORY ARCHIVER]: Password for user {0} {1} incorrect. Please try again.",
  298. firstName, lastName);
  299. return null;
  300. }
  301. }
  302. catch (Exception e)
  303. {
  304. m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e.Message);
  305. return null;
  306. }
  307. }
  308. /// <summary>
  309. /// Notify the client of loaded nodes if they are logged in
  310. /// </summary>
  311. /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param>
  312. private void UpdateClientWithLoadedNodes(CachedUserInfo userInfo, List<InventoryNodeBase> loadedNodes)
  313. {
  314. if (loadedNodes.Count == 0)
  315. return;
  316. foreach (Scene scene in m_scenes.Values)
  317. {
  318. ScenePresence user = scene.GetScenePresence(userInfo.UserProfile.ID);
  319. if (user != null && !user.IsChildAgent)
  320. {
  321. foreach (InventoryNodeBase node in loadedNodes)
  322. {
  323. // m_log.DebugFormat(
  324. // "[INVENTORY ARCHIVER]: Notifying {0} of loaded inventory node {1}",
  325. // user.Name, node.Name);
  326. user.ControllingClient.SendBulkUpdateInventory(node);
  327. }
  328. break;
  329. }
  330. }
  331. }
  332. /// <summary>
  333. /// Check if the given user is present in any of the scenes.
  334. /// </summary>
  335. /// <param name="userId">The user to check</param>
  336. /// <returns>true if the user is in any of the scenes, false otherwise</returns>
  337. protected bool CheckPresence(UUID userId)
  338. {
  339. if (DisablePresenceChecks)
  340. return true;
  341. foreach (Scene scene in m_scenes.Values)
  342. {
  343. ScenePresence p;
  344. if ((p = scene.GetScenePresence(userId)) != null)
  345. {
  346. p.ControllingClient.SendAgentAlertMessage("Inventory operation has been started", false);
  347. return true;
  348. }
  349. }
  350. return false;
  351. }
  352. }
  353. }