clockwerk-opensim-stable – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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  
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Reflection;
32 using log4net;
33 using NDesk.Options;
34 using Nini.Config;
35 using OpenMetaverse;
36 using OpenSim.Framework;
37 using OpenSim.Framework.Communications;
38 using OpenSim.Framework.Console;
39 using OpenSim.Region.Framework.Interfaces;
40 using OpenSim.Region.Framework.Scenes;
41 using OpenSim.Services.Interfaces;
42 using Mono.Addins;
43  
44 namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
45 {
46 /// <summary>
47 /// This module loads and saves OpenSimulator inventory archives
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "InventoryArchiverModule")]
50 public class InventoryArchiverModule : ISharedRegionModule, IInventoryArchiverModule
51 {
52 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53  
54 /// <value>
55 /// Enable or disable checking whether the iar user is actually logged in
56 /// </value>
57 // public bool DisablePresenceChecks { get; set; }
58  
59 public event InventoryArchiveSaved OnInventoryArchiveSaved;
60  
61 /// <summary>
62 /// The file to load and save inventory if no filename has been specified
63 /// </summary>
64 protected const string DEFAULT_INV_BACKUP_FILENAME = "user-inventory.iar";
65  
66 /// <value>
67 /// Pending save completions initiated from the console
68 /// </value>
69 protected List<Guid> m_pendingConsoleSaves = new List<Guid>();
70  
71 /// <value>
72 /// All scenes that this module knows about
73 /// </value>
74 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
75 private Scene m_aScene;
76  
77 private IUserAccountService m_UserAccountService;
78 protected IUserAccountService UserAccountService
79 {
80 get
81 {
82 if (m_UserAccountService == null)
83 // What a strange thing to do...
84 foreach (Scene s in m_scenes.Values)
85 {
86 m_UserAccountService = s.RequestModuleInterface<IUserAccountService>();
87 break;
88 }
89  
90 return m_UserAccountService;
91 }
92 }
93  
94  
95 public InventoryArchiverModule() {}
96  
97 // public InventoryArchiverModule(bool disablePresenceChecks)
98 // {
99 // DisablePresenceChecks = disablePresenceChecks;
100 // }
101  
102 #region ISharedRegionModule
103  
104 public void Initialise(IConfigSource source)
105 {
106 }
107  
108 public void AddRegion(Scene scene)
109 {
110 if (m_scenes.Count == 0)
111 {
112 scene.RegisterModuleInterface<IInventoryArchiverModule>(this);
113 OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted;
114  
115 scene.AddCommand(
116 "Archiving", this, "load iar",
117 "load iar [-m|--merge] <first> <last> <inventory path> <password> [<IAR path>]",
118 "Load user inventory archive (IAR).",
119 "-m|--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
120 + "<first> is user's first name." + Environment.NewLine
121 + "<last> is user's last name." + Environment.NewLine
122 + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine
123 + "<password> is the user's password." + Environment.NewLine
124 + "<IAR path> is the filesystem path or URI from which to load the IAR."
125 + string.Format(" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME),
126 HandleLoadInvConsoleCommand);
127  
128 scene.AddCommand(
129 "Archiving", this, "save iar",
130 "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]",
131 "Save user inventory archive (IAR).",
132 "<first> is the user's first name.\n"
133 + "<last> is the user's last name.\n"
134 + "<inventory path> is the path inside the user's inventory for the folder/item to be saved.\n"
135 + "<IAR path> is the filesystem path at which to save the IAR."
136 + string.Format(" If this is not given then the filename {0} in the current directory is used.\n", DEFAULT_INV_BACKUP_FILENAME)
137 + "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
138 + "-c|--creators preserves information about foreign creators.\n"
139 + "-e|--exclude=<name/uuid> don't save the inventory item in archive" + Environment.NewLine
140 + "-f|--excludefolder=<folder/uuid> don't save contents of the folder in archive" + Environment.NewLine
141 + "-v|--verbose extra debug messages.\n"
142 + "--noassets stops assets being saved to the IAR.",
143 HandleSaveInvConsoleCommand);
144  
145 m_aScene = scene;
146 }
147  
148 m_scenes[scene.RegionInfo.RegionID] = scene;
149 }
150  
151 public void RemoveRegion(Scene scene)
152 {
153 }
154  
155 public void Close() {}
156  
157 public void RegionLoaded(Scene scene)
158 {
159 }
160  
161 public void PostInitialise()
162 {
163 }
164  
165 public Type ReplaceableInterface
166 {
167 get { return null; }
168 }
169  
170 public string Name { get { return "Inventory Archiver Module"; } }
171  
172 #endregion
173  
174 /// <summary>
175 /// Trigger the inventory archive saved event.
176 /// </summary>
177 protected internal void TriggerInventoryArchiveSaved(
178 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
179 Exception reportedException)
180 {
181 InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved;
182 if (handlerInventoryArchiveSaved != null)
183 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException);
184 }
185  
186 public bool ArchiveInventory(
187 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
188 {
189 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>());
190 }
191  
192 public bool ArchiveInventory(
193 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream,
194 Dictionary<string, object> options)
195 {
196 if (m_scenes.Count > 0)
197 {
198 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
199  
200 if (userInfo != null)
201 {
202 // if (CheckPresence(userInfo.PrincipalID))
203 // {
204 try
205 {
206 new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, saveStream).Execute(options, UserAccountService);
207 }
208 catch (EntryPointNotFoundException e)
209 {
210 m_log.ErrorFormat(
211 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
212 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
213 m_log.Error(e);
214  
215 return false;
216 }
217  
218 return true;
219 // }
220 // else
221 // {
222 // m_log.ErrorFormat(
223 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
224 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
225 // }
226 }
227 }
228  
229 return false;
230 }
231  
232 public bool ArchiveInventory(
233 Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
234 Dictionary<string, object> options)
235 {
236 // if (!ConsoleUtil.CheckFileDoesNotExist(MainConsole.Instance, savePath))
237 // return false;
238  
239 if (m_scenes.Count > 0)
240 {
241 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
242  
243 if (userInfo != null)
244 {
245 // if (CheckPresence(userInfo.PrincipalID))
246 // {
247 try
248 {
249 new InventoryArchiveWriteRequest(id, this, m_aScene, userInfo, invPath, savePath).Execute(options, UserAccountService);
250 }
251 catch (EntryPointNotFoundException e)
252 {
253 m_log.ErrorFormat(
254 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
255 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
256 m_log.Error(e);
257  
258 return false;
259 }
260  
261 return true;
262 // }
263 // else
264 // {
265 // m_log.ErrorFormat(
266 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
267 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
268 // }
269 }
270 }
271  
272 return false;
273 }
274  
275 public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream)
276 {
277 return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>());
278 }
279  
280 public bool DearchiveInventory(
281 string firstName, string lastName, string invPath, string pass, Stream loadStream,
282 Dictionary<string, object> options)
283 {
284 if (m_scenes.Count > 0)
285 {
286 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
287  
288 if (userInfo != null)
289 {
290 // if (CheckPresence(userInfo.PrincipalID))
291 // {
292 InventoryArchiveReadRequest request;
293 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
294  
295 try
296 {
297 request = new InventoryArchiveReadRequest(m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadStream, merge);
298 }
299 catch (EntryPointNotFoundException e)
300 {
301 m_log.ErrorFormat(
302 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
303 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
304 m_log.Error(e);
305  
306 return false;
307 }
308  
309 UpdateClientWithLoadedNodes(userInfo, request.Execute());
310  
311 return true;
312 // }
313 // else
314 // {
315 // m_log.ErrorFormat(
316 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
317 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
318 // }
319 }
320 else
321 m_log.ErrorFormat("[INVENTORY ARCHIVER]: User {0} {1} not found",
322 firstName, lastName);
323 }
324  
325 return false;
326 }
327  
328 public bool DearchiveInventory(
329 string firstName, string lastName, string invPath, string pass, string loadPath,
330 Dictionary<string, object> options)
331 {
332 if (m_scenes.Count > 0)
333 {
334 UserAccount userInfo = GetUserInfo(firstName, lastName, pass);
335  
336 if (userInfo != null)
337 {
338 // if (CheckPresence(userInfo.PrincipalID))
339 // {
340 InventoryArchiveReadRequest request;
341 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
342  
343 try
344 {
345 request = new InventoryArchiveReadRequest(m_aScene.InventoryService, m_aScene.AssetService, m_aScene.UserAccountService, userInfo, invPath, loadPath, merge);
346 }
347 catch (EntryPointNotFoundException e)
348 {
349 m_log.ErrorFormat(
350 "[INVENTORY ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
351 + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
352 m_log.Error(e);
353  
354 return false;
355 }
356  
357 UpdateClientWithLoadedNodes(userInfo, request.Execute());
358  
359 return true;
360 // }
361 // else
362 // {
363 // m_log.ErrorFormat(
364 // "[INVENTORY ARCHIVER]: User {0} {1} {2} not logged in to this region simulator",
365 // userInfo.FirstName, userInfo.LastName, userInfo.PrincipalID);
366 // }
367 }
368 }
369  
370 return false;
371 }
372  
373 /// <summary>
374 /// Load inventory from an inventory file archive
375 /// </summary>
376 /// <param name="cmdparams"></param>
377 protected void HandleLoadInvConsoleCommand(string module, string[] cmdparams)
378 {
379 try
380 {
381 Dictionary<string, object> options = new Dictionary<string, object>();
382 OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; });
383  
384 List<string> mainParams = optionSet.Parse(cmdparams);
385  
386 if (mainParams.Count < 6)
387 {
388 m_log.Error(
389 "[INVENTORY ARCHIVER]: usage is load iar [-m|--merge] <first name> <last name> <inventory path> <user password> [<load file path>]");
390 return;
391 }
392  
393 string firstName = mainParams[2];
394 string lastName = mainParams[3];
395 string invPath = mainParams[4];
396 string pass = mainParams[5];
397 string loadPath = (mainParams.Count > 6 ? mainParams[6] : DEFAULT_INV_BACKUP_FILENAME);
398  
399 m_log.InfoFormat(
400 "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}",
401 loadPath, invPath, firstName, lastName);
402  
403 if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options))
404 m_log.InfoFormat(
405 "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}",
406 loadPath, firstName, lastName);
407 }
408 catch (InventoryArchiverException e)
409 {
410 m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message);
411 }
412 }
413  
414 /// <summary>
415 /// Save inventory to a file archive
416 /// </summary>
417 /// <param name="cmdparams"></param>
418 protected void HandleSaveInvConsoleCommand(string module, string[] cmdparams)
419 {
420 Guid id = Guid.NewGuid();
421  
422 Dictionary<string, object> options = new Dictionary<string, object>();
423  
424 OptionSet ops = new OptionSet();
425 //ops.Add("v|version=", delegate(string v) { options["version"] = v; });
426 ops.Add("h|home=", delegate(string v) { options["home"] = v; });
427 ops.Add("v|verbose", delegate(string v) { options["verbose"] = v; });
428 ops.Add("c|creators", delegate(string v) { options["creators"] = v; });
429 ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; });
430 ops.Add("e|exclude=", delegate(string v)
431 {
432 if (!options.ContainsKey("exclude"))
433 options["exclude"] = new List<String>();
434 ((List<String>)options["exclude"]).Add(v);
435 });
436 ops.Add("f|excludefolder=", delegate(string v)
437 {
438 if (!options.ContainsKey("excludefolders"))
439 options["excludefolders"] = new List<String>();
440 ((List<String>)options["excludefolders"]).Add(v);
441 });
442  
443 List<string> mainParams = ops.Parse(cmdparams);
444  
445 try
446 {
447 if (mainParams.Count < 6)
448 {
449 m_log.Error(
450 "[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]");
451 return;
452 }
453  
454 if (options.ContainsKey("home"))
455 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");
456  
457 string firstName = mainParams[2];
458 string lastName = mainParams[3];
459 string invPath = mainParams[4];
460 string pass = mainParams[5];
461 string savePath = (mainParams.Count > 6 ? mainParams[6] : DEFAULT_INV_BACKUP_FILENAME);
462  
463 m_log.InfoFormat(
464 "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}",
465 savePath, invPath, firstName, lastName);
466  
467 lock (m_pendingConsoleSaves)
468 m_pendingConsoleSaves.Add(id);
469  
470 ArchiveInventory(id, firstName, lastName, invPath, pass, savePath, options);
471 }
472 catch (InventoryArchiverException e)
473 {
474 m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message);
475 }
476 }
477  
478 private void SaveInvConsoleCommandCompleted(
479 Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream,
480 Exception reportedException)
481 {
482 lock (m_pendingConsoleSaves)
483 {
484 if (m_pendingConsoleSaves.Contains(id))
485 m_pendingConsoleSaves.Remove(id);
486 else
487 return;
488 }
489  
490 if (succeeded)
491 {
492 m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive for {0} {1}", userInfo.FirstName, userInfo.LastName);
493 }
494 else
495 {
496 m_log.ErrorFormat(
497 "[INVENTORY ARCHIVER]: Archive save for {0} {1} failed - {2}",
498 userInfo.FirstName, userInfo.LastName, reportedException.Message);
499 }
500 }
501  
502 /// <summary>
503 /// Get user information for the given name.
504 /// </summary>
505 /// <param name="firstName"></param>
506 /// <param name="lastName"></param>
507 /// <param name="pass">User password</param>
508 /// <returns></returns>
509 protected UserAccount GetUserInfo(string firstName, string lastName, string pass)
510 {
511 UserAccount account
512 = m_aScene.UserAccountService.GetUserAccount(m_aScene.RegionInfo.ScopeID, firstName, lastName);
513  
514 if (null == account)
515 {
516 m_log.ErrorFormat(
517 "[INVENTORY ARCHIVER]: Failed to find user info for {0} {1}",
518 firstName, lastName);
519 return null;
520 }
521  
522 try
523 {
524 string encpass = Util.Md5Hash(pass);
525 if (m_aScene.AuthenticationService.Authenticate(account.PrincipalID, encpass, 1) != string.Empty)
526 {
527 return account;
528 }
529 else
530 {
531 m_log.ErrorFormat(
532 "[INVENTORY ARCHIVER]: Password for user {0} {1} incorrect. Please try again.",
533 firstName, lastName);
534 return null;
535 }
536 }
537 catch (Exception e)
538 {
539 m_log.ErrorFormat("[INVENTORY ARCHIVER]: Could not authenticate password, {0}", e);
540 return null;
541 }
542 }
543  
544 /// <summary>
545 /// Notify the client of loaded nodes if they are logged in
546 /// </summary>
547 /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param>
548 private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes)
549 {
550 if (loadedNodes.Count == 0)
551 return;
552  
553 foreach (Scene scene in m_scenes.Values)
554 {
555 ScenePresence user = scene.GetScenePresence(userInfo.PrincipalID);
556  
557 if (user != null && !user.IsChildAgent)
558 {
559 foreach (InventoryNodeBase node in loadedNodes)
560 {
561 // m_log.DebugFormat(
562 // "[INVENTORY ARCHIVER]: Notifying {0} of loaded inventory node {1}",
563 // user.Name, node.Name);
564  
565 user.ControllingClient.SendBulkUpdateInventory(node);
566 }
567  
568 break;
569 }
570 }
571 }
572  
573 // /// <summary>
574 // /// Check if the given user is present in any of the scenes.
575 // /// </summary>
576 // /// <param name="userId">The user to check</param>
577 // /// <returns>true if the user is in any of the scenes, false otherwise</returns>
578 // protected bool CheckPresence(UUID userId)
579 // {
580 // if (DisablePresenceChecks)
581 // return true;
582 //
583 // foreach (Scene scene in m_scenes.Values)
584 // {
585 // ScenePresence p;
586 // if ((p = scene.GetScenePresence(userId)) != null)
587 // {
588 // p.ControllingClient.SendAgentAlertMessage("Inventory operation has been started", false);
589 // return true;
590 // }
591 // }
592 //
593 // return false;
594 // }
595 }
596 }