29 using System.Collections.Generic;
31 using System.Reflection;
36 using OpenSim.Framework;
37 using OpenSim.Framework.Console;
38 using OpenSim.Region.Framework.Interfaces;
39 using OpenSim.Region.Framework.Scenes;
40 using OpenSim.Services.Interfaces;
43 namespace OpenSim.
Region.CoreModules.
Avatar.Inventory.Archiver
48 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"InventoryArchiverModule")]
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
64 protected const string DEFAULT_INV_BACKUP_FILENAME =
"user-inventory.iar";
69 protected List<UUID> m_pendingConsoleTasks =
new List<UUID>();
74 private Dictionary<UUID, Scene> m_scenes =
new Dictionary<UUID, Scene>();
75 private Scene m_aScene;
82 if (m_UserAccountService == null)
84 foreach (
Scene s
in m_scenes.Values)
90 return m_UserAccountService;
102 #region ISharedRegionModule
110 if (m_scenes.Count == 0)
113 OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted;
114 OnInventoryArchiveLoaded += LoadInvConsoleCommandCompleted;
117 "Archiving",
this,
"load iar",
118 "load iar [-m|--merge] <first> <last> <inventory path> <password> [<IAR path>]",
119 "Load user inventory archive (IAR).",
120 "-m|--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
121 +
"<first> is user's first name." + Environment.NewLine
122 +
"<last> is user's last name." + Environment.NewLine
123 +
"<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine
124 +
"<password> is the user's password." + Environment.NewLine
125 +
"<IAR path> is the filesystem path or URI from which to load the IAR."
126 + string.Format(
" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME),
127 HandleLoadInvConsoleCommand);
130 "Archiving",
this,
"save iar",
131 "save iar [-h|--home=<url>] [--noassets] <first> <last> <inventory path> <password> [<IAR path>] [-c|--creators] [-e|--exclude=<name/uuid>] [-f|--excludefolder=<foldername/uuid>] [-v|--verbose]",
132 "Save user inventory archive (IAR).",
133 "<first> is the user's first name.\n"
134 +
"<last> is the user's last name.\n"
135 +
"<inventory path> is the path inside the user's inventory for the folder/item to be saved.\n"
136 +
"<IAR path> is the filesystem path at which to save the IAR."
137 + string.Format(
" If this is not given then the filename {0} in the current directory is used.\n", DEFAULT_INV_BACKUP_FILENAME)
138 +
"-h|--home=<url> adds the url of the profile service to the saved user information.\n"
139 +
"-c|--creators preserves information about foreign creators.\n"
140 +
"-e|--exclude=<name/uuid> don't save the inventory item in archive" + Environment.NewLine
141 +
"-f|--excludefolder=<folder/uuid> don't save contents of the folder in archive" + Environment.NewLine
142 +
"-v|--verbose extra debug messages.\n"
143 +
"--noassets stops assets being saved to the IAR."
144 +
"--perm=<permissions> stops items with insufficient permissions from being saved to the IAR.\n"
145 +
" <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer, \"M\" = Modify.\n",
146 HandleSaveInvConsoleCommand);
151 m_scenes[scene.RegionInfo.RegionID] = scene;
168 public Type ReplaceableInterface
173 public string Name {
get {
return "Inventory Archiver Module"; } }
180 protected internal void TriggerInventoryArchiveSaved(
181 UUID
id,
bool succeeded,
UserAccount userInfo,
string invPath, Stream saveStream,
182 Exception reportedException,
int SaveCount,
int FilterCount)
185 if (handlerInventoryArchiveSaved != null)
186 handlerInventoryArchiveSaved(
id, succeeded, userInfo, invPath, saveStream, reportedException, SaveCount , FilterCount);
192 protected internal void TriggerInventoryArchiveLoaded(
193 UUID
id,
bool succeeded,
UserAccount userInfo,
string invPath, Stream loadStream,
194 Exception reportedException,
int LoadCount)
197 if (handlerInventoryArchiveLoaded != null)
198 handlerInventoryArchiveLoaded(
id, succeeded, userInfo, invPath, loadStream, reportedException, LoadCount);
202 UUID
id,
string firstName,
string lastName,
string invPath,
string pass, Stream saveStream)
204 return ArchiveInventory(
id, firstName, lastName, invPath, pass, saveStream,
new Dictionary<string, object>());
208 UUID
id,
string firstName,
string lastName,
string invPath,
string pass, Stream saveStream,
209 Dictionary<string, object>
options)
211 if (m_scenes.Count > 0)
213 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
215 if (userInfo != null)
223 catch (EntryPointNotFoundException e)
226 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
227 +
"If you've manually installed Mono, have you appropriately updated zlib1g as well?");
248 UUID
id,
string firstName,
string lastName,
string invPath,
string pass,
string savePath,
249 Dictionary<string, object>
options)
254 if (m_scenes.Count > 0)
256 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
258 if (userInfo != null)
266 catch (EntryPointNotFoundException e)
269 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
270 +
"If you've manually installed Mono, have you appropriately updated zlib1g as well?");
290 public bool DearchiveInventory(UUID
id,
string firstName,
string lastName,
string invPath,
string pass, Stream loadStream)
292 return DearchiveInventory(
id, firstName, lastName, invPath, pass, loadStream,
new Dictionary<string, object>());
296 UUID
id,
string firstName,
string lastName,
string invPath,
string pass, Stream loadStream,
297 Dictionary<string, object>
options)
299 if (m_scenes.Count > 0)
301 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
303 if (userInfo != null)
308 bool merge = (options.ContainsKey(
"merge") ? (
bool)options[
"merge"] :
false);
312 request =
new InventoryArchiveReadRequest(
id,
this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge);
314 catch (EntryPointNotFoundException e)
317 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
318 +
"If you've manually installed Mono, have you appropriately updated zlib1g as well?");
324 UpdateClientWithLoadedNodes(userInfo, request.
Execute());
336 m_log.ErrorFormat(
"[INVENTORY ARCHIVER]: User {0} {1} not found",
337 firstName, lastName);
344 UUID
id,
string firstName,
string lastName,
string invPath,
string pass,
string loadPath,
345 Dictionary<string, object>
options)
347 if (m_scenes.Count > 0)
349 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
351 if (userInfo != null)
356 bool merge = (options.ContainsKey(
"merge") ? (
bool)options[
"merge"] :
false);
360 request =
new InventoryArchiveReadRequest(
id,
this, m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge);
362 catch (EntryPointNotFoundException e)
365 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
366 +
"If you've manually installed Mono, have you appropriately updated zlib1g as well?");
372 UpdateClientWithLoadedNodes(userInfo, request.
Execute());
396 UUID id = UUID.Random();
398 Dictionary<string, object>
options =
new Dictionary<string, object>();
399 OptionSet optionSet =
new OptionSet().Add(
"m|merge", delegate (
string v) { options[
"merge"] = v != null; });
401 List<string> mainParams = optionSet.Parse(cmdparams);
403 if (mainParams.Count < 6)
406 "[INVENTORY ARCHIVER]: usage is load iar [-m|--merge] <first name> <last name> <inventory path> <user password> [<load file path>]");
410 string firstName = mainParams[2];
411 string lastName = mainParams[3];
412 string invPath = mainParams[4];
413 string pass = mainParams[5];
414 string loadPath = (mainParams.Count > 6 ? mainParams[6] : DEFAULT_INV_BACKUP_FILENAME);
417 "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}",
418 loadPath, invPath, firstName, lastName);
420 lock (m_pendingConsoleTasks)
421 m_pendingConsoleTasks.Add(id);
423 DearchiveInventory(
id, firstName, lastName, invPath, pass, loadPath, options);
427 m_log.ErrorFormat(
"[INVENTORY ARCHIVER]: {0}", e.Message);
437 UUID id = UUID.Random();
439 Dictionary<string, object>
options =
new Dictionary<string, object>();
441 OptionSet ops =
new OptionSet();
443 ops.Add(
"h|home=", delegate(
string v) { options[
"home"] = v; });
444 ops.Add(
"v|verbose", delegate(
string v) { options[
"verbose"] = v; });
445 ops.Add(
"c|creators", delegate(
string v) { options[
"creators"] = v; });
446 ops.Add(
"noassets", delegate(
string v) { options[
"noassets"] = v != null; });
447 ops.Add(
"e|exclude=", delegate(
string v)
449 if (!options.ContainsKey(
"exclude"))
450 options[
"exclude"] =
new List<String>();
451 ((List<String>)options[
"exclude"]).Add(v);
453 ops.Add(
"f|excludefolder=", delegate(
string v)
455 if (!options.ContainsKey(
"excludefolders"))
456 options[
"excludefolders"] =
new List<String>();
457 ((List<String>)options[
"excludefolders"]).Add(v);
459 ops.Add(
"perm=", delegate(
string v) { options[
"checkPermissions"] = v; });
461 List<string> mainParams = ops.Parse(cmdparams);
465 if (mainParams.Count < 6)
468 "[INVENTORY ARCHIVER]: save iar [-h|--home=<url>] [--noassets] <first> <last> <inventory path> <password> [<IAR path>] [-c|--creators] [-e|--exclude=<name/uuid>] [-f|--excludefolder=<foldername/uuid>] [-v|--verbose]");
472 if (options.ContainsKey(
"home"))
473 m_log.WarnFormat(
"[INVENTORY ARCHIVER]: Please be aware that inventory archives with creator information are not compatible with OpenSim 0.7.0.2 and earlier. Do not use the -home option if you want to produce a compatible IAR");
475 string firstName = mainParams[2];
476 string lastName = mainParams[3];
477 string invPath = mainParams[4];
478 string pass = mainParams[5];
479 string savePath = (mainParams.Count > 6 ? mainParams[6] : DEFAULT_INV_BACKUP_FILENAME);
482 "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}",
483 savePath, invPath, firstName, lastName);
485 lock (m_pendingConsoleTasks)
486 m_pendingConsoleTasks.Add(id);
488 ArchiveInventory(
id, firstName, lastName, invPath, pass, savePath, options);
492 m_log.ErrorFormat(
"[INVENTORY ARCHIVER]: {0}", e.Message);
496 private void SaveInvConsoleCommandCompleted(
497 UUID
id,
bool succeeded,
UserAccount userInfo,
string invPath, Stream saveStream,
498 Exception reportedException,
int SaveCount,
int FilterCount)
500 lock (m_pendingConsoleTasks)
502 if (m_pendingConsoleTasks.Contains(
id))
503 m_pendingConsoleTasks.Remove(
id);
512 m_log.InfoFormat(
"[INVENTORY ARCHIVER]: Saved archive with {0} items for {1} {2}", SaveCount, userInfo.FirstName, userInfo.LastName);
514 m_log.InfoFormat(
"[INVENTORY ARCHIVER]: Saved archive with {0} items for {1} {2}. Skipped {3} items due to exclude and/or perm switches", SaveCount, userInfo.FirstName, userInfo.LastName, FilterCount);
519 "[INVENTORY ARCHIVER]: Archive save for {0} {1} failed - {2}",
520 userInfo.FirstName, userInfo.LastName, reportedException.Message);
524 private void LoadInvConsoleCommandCompleted(
525 UUID
id,
bool succeeded,
UserAccount userInfo,
string invPath, Stream loadStream,
526 Exception reportedException,
int LoadCount)
528 lock (m_pendingConsoleTasks)
530 if (m_pendingConsoleTasks.Contains(
id))
531 m_pendingConsoleTasks.Remove(
id);
538 m_log.InfoFormat(
"[INVENTORY ARCHIVER]: Loaded {0} items from archive {1} for {2} {3}", LoadCount, invPath, userInfo.FirstName, userInfo.LastName);
543 "[INVENTORY ARCHIVER]: Archive load for {0} {1} failed - {2}",
544 userInfo.FirstName, userInfo.LastName, reportedException.Message);
558 = m_aScene.UserAccountService.GetUserAccount(m_aScene.RegionInfo.ScopeID, firstName, lastName);
563 "[INVENTORY ARCHIVER]: Failed to find user info for {0} {1}",
564 firstName, lastName);
597 private void UpdateClientWithLoadedNodes(
UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes)
599 if (loadedNodes.Count == 0)
602 foreach (
Scene scene
in m_scenes.Values)
604 ScenePresence user = scene.GetScenePresence(userInfo.PrincipalID);
614 user.ControllingClient.SendBulkUpdateInventory(node);
InventoryArchiverModule()
Signals an inventory archiving problem
HashSet< InventoryNodeBase > Execute()
Execute the request
delegate void InventoryArchiveSaved(UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, Exception reportedException, int saveCount, int filterCount)
Used for the OnInventoryArchiveSaved event.
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
delegate void InventoryArchiveLoaded(UUID id, bool succeeded, UserAccount userInfo, string invPath, Stream loadStream, Exception reportedException, int loadCount)
Used for the OnInventoryArchiveLoaded event.
bool ArchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, Stream saveStream, Dictionary< string, object > options)
Archive a user's inventory folder to the given stream
bool ArchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, string savePath, Dictionary< string, object > options)
void HandleSaveInvConsoleCommand(string module, string[] cmdparams)
Save inventory to a file archive
bool DearchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, Stream loadStream, Dictionary< string, object > options)
Dearchive a user's inventory folder from the given stream
bool ArchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
Archive a user's inventory folder to the given stream
This module loads and saves OpenSimulator inventory archives
void HandleLoadInvConsoleCommand(string module, string[] cmdparams)
Load inventory from an inventory file archive
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
bool DearchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, string loadPath, Dictionary< string, object > options)
UserAccount GetUserInfo(string firstName, string lastName, string pass)
Get user information for the given name.
InventoryArchiveLoaded OnInventoryArchiveLoaded
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
Common base class for inventory nodes of different types (files, folders, etc.)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
InventoryArchiveSaved OnInventoryArchiveSaved
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
bool DearchiveInventory(UUID id, string firstName, string lastName, string invPath, string pass, Stream loadStream)
Dearchive a user's inventory folder from the given stream