aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs110
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs54
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs50
-rw-r--r--OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs596
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs89
6 files changed, 821 insertions, 86 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index 31dfe14..7683288 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -54,6 +54,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
54 54
55 private UserAccount m_userInfo; 55 private UserAccount m_userInfo;
56 private string m_invPath; 56 private string m_invPath;
57
58 /// <summary>
59 /// Do we want to merge this load with existing inventory?
60 /// </summary>
61 protected bool m_merge;
57 62
58 /// <value> 63 /// <value>
59 /// We only use this to request modules 64 /// We only use this to request modules
@@ -66,19 +71,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
66 private Stream m_loadStream; 71 private Stream m_loadStream;
67 72
68 public InventoryArchiveReadRequest( 73 public InventoryArchiveReadRequest(
69 Scene scene, UserAccount userInfo, string invPath, string loadPath) 74 Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge)
70 : this( 75 : this(
71 scene, 76 scene,
72 userInfo, 77 userInfo,
73 invPath, 78 invPath,
74 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress)) 79 new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress),
80 merge)
75 { 81 {
76 } 82 }
77 83
78 public InventoryArchiveReadRequest( 84 public InventoryArchiveReadRequest(
79 Scene scene, UserAccount userInfo, string invPath, Stream loadStream) 85 Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge)
80 { 86 {
81 m_scene = scene; 87 m_scene = scene;
88 m_merge = merge;
82 m_userInfo = userInfo; 89 m_userInfo = userInfo;
83 m_invPath = invPath; 90 m_invPath = invPath;
84 m_loadStream = loadStream; 91 m_loadStream = loadStream;
@@ -91,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
91 /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are 98 /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are
92 /// returned 99 /// returned
93 /// </returns> 100 /// </returns>
94 public List<InventoryNodeBase> Execute() 101 public HashSet<InventoryNodeBase> Execute()
95 { 102 {
96 try 103 try
97 { 104 {
@@ -100,7 +107,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
100 int failedAssetRestores = 0; 107 int failedAssetRestores = 0;
101 int successfulItemRestores = 0; 108 int successfulItemRestores = 0;
102 109
103 List<InventoryNodeBase> loadedNodes = new List<InventoryNodeBase>(); 110 HashSet<InventoryNodeBase> loadedNodes = new HashSet<InventoryNodeBase>();
104 111
105 List<InventoryFolderBase> folderCandidates 112 List<InventoryFolderBase> folderCandidates
106 = InventoryArchiveUtils.FindFolderByPath( 113 = InventoryArchiveUtils.FindFolderByPath(
@@ -158,9 +165,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
158 { 165 {
159 successfulItemRestores++; 166 successfulItemRestores++;
160 167
161 // If we're loading an item directly into the given destination folder then we need to record 168 // If we aren't loading the folder containing the item then well need to update the
162 // it separately from any loaded root folders 169 // viewer separately for that item.
163 if (rootDestinationFolder == foundFolder) 170 if (!loadedNodes.Contains(foundFolder))
164 loadedNodes.Add(item); 171 loadedNodes.Add(item);
165 } 172 }
166 } 173 }
@@ -205,14 +212,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
205 string iarPath, 212 string iarPath,
206 InventoryFolderBase rootDestFolder, 213 InventoryFolderBase rootDestFolder,
207 Dictionary <string, InventoryFolderBase> resolvedFolders, 214 Dictionary <string, InventoryFolderBase> resolvedFolders,
208 List<InventoryNodeBase> loadedNodes) 215 HashSet<InventoryNodeBase> loadedNodes)
209 { 216 {
210 string iarPathExisting = iarPath; 217 string iarPathExisting = iarPath;
211 218
212// m_log.DebugFormat( 219// m_log.DebugFormat(
213// "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID); 220// "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID);
214 221
215 InventoryFolderBase destFolder = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders); 222 InventoryFolderBase destFolder
223 = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders);
216 224
217// m_log.DebugFormat( 225// m_log.DebugFormat(
218// "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", 226// "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]",
@@ -251,46 +259,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
251 { 259 {
252// string originalArchivePath = archivePath; 260// string originalArchivePath = archivePath;
253 261
254 InventoryFolderBase destFolder = null; 262 while (archivePath.Length > 0)
255
256 if (archivePath.Length > 0)
257 { 263 {
258 while (null == destFolder && archivePath.Length > 0) 264 m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
265
266 if (resolvedFolders.ContainsKey(archivePath))
267 {
268// m_log.DebugFormat(
269// "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath);
270 return resolvedFolders[archivePath];
271 }
272 else
259 { 273 {
260// m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath); 274 if (m_merge)
275 {
276 // TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the
277 // iar name and try to find that instead.
278 string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath);
279 List<InventoryFolderBase> folderCandidates
280 = InventoryArchiveUtils.FindFolderByPath(
281 m_scene.InventoryService, m_userInfo.PrincipalID, plainPath);
282
283 if (folderCandidates.Count != 0)
284 {
285 InventoryFolderBase destFolder = folderCandidates[0];
286 resolvedFolders[archivePath] = destFolder;
287 return destFolder;
288 }
289 }
261 290
262 if (resolvedFolders.ContainsKey(archivePath)) 291 // Don't include the last slash so find the penultimate one
292 int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2);
293
294 if (penultimateSlashIndex >= 0)
263 { 295 {
264// m_log.DebugFormat( 296 // Remove the last section of path so that we can see if we've already resolved the parent
265// "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath); 297 archivePath = archivePath.Remove(penultimateSlashIndex + 1);
266 destFolder = resolvedFolders[archivePath];
267 } 298 }
268 else 299 else
269 { 300 {
270 // Don't include the last slash so find the penultimate one 301// m_log.DebugFormat(
271 int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); 302// "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}",
272 303// originalArchivePath);
273 if (penultimateSlashIndex >= 0) 304 archivePath = string.Empty;
274 { 305 return rootDestFolder;
275 // Remove the last section of path so that we can see if we've already resolved the parent
276 archivePath = archivePath.Remove(penultimateSlashIndex + 1);
277 }
278 else
279 {
280// m_log.DebugFormat(
281// "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}",
282// originalArchivePath);
283 archivePath = string.Empty;
284 destFolder = rootDestFolder;
285 }
286 } 306 }
287 } 307 }
288 } 308 }
289 309
290 if (null == destFolder) 310 return rootDestFolder;
291 destFolder = rootDestFolder;
292
293 return destFolder;
294 } 311 }
295 312
296 /// <summary> 313 /// <summary>
@@ -316,24 +333,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
316 string iarPathExisting, 333 string iarPathExisting,
317 string iarPathToReplicate, 334 string iarPathToReplicate,
318 Dictionary <string, InventoryFolderBase> resolvedFolders, 335 Dictionary <string, InventoryFolderBase> resolvedFolders,
319 List<InventoryNodeBase> loadedNodes) 336 HashSet<InventoryNodeBase> loadedNodes)
320 { 337 {
321 string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); 338 string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
322 int i = 0;
323 339
324 while (i < rawDirsToCreate.Length) 340 for (int i = 0; i < rawDirsToCreate.Length; i++)
325 { 341 {
326// m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]); 342// m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]);
327 343
344 if (!rawDirsToCreate[i].Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR))
345 continue;
346
328 int identicalNameIdentifierIndex 347 int identicalNameIdentifierIndex
329 = rawDirsToCreate[i].LastIndexOf( 348 = rawDirsToCreate[i].LastIndexOf(
330 ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); 349 ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR);
331 350
332 if (identicalNameIdentifierIndex < 0)
333 {
334 i++;
335 continue;
336 }
337 string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); 351 string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex);
338 352
339 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); 353 newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName);
@@ -356,8 +370,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
356 370
357 if (0 == i) 371 if (0 == i)
358 loadedNodes.Add(destFolder); 372 loadedNodes.Add(destFolder);
359
360 i++;
361 } 373 }
362 } 374 }
363 375
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
index f7a2b09..f03f2a1 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
@@ -91,12 +91,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
91 91
92 scene.AddCommand( 92 scene.AddCommand(
93 this, "load iar", 93 this, "load iar",
94 "load iar <first> <last> <inventory path> <password> [<IAR path>]", 94 "load iar <first> <last> <inventory path> <password> [<IAR path>]",
95 //"load iar [--merge] <first> <last> <inventory path> <password> [<IAR path>]", 95 //"load iar [--merge] <first> <last> <inventory path> <password> [<IAR path>]",
96 "Load user inventory archive (IAR).", 96 "Load user inventory archive (IAR).",
97 //"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones" 97 //"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
98 //+ "<first> is user's first name." + Environment.NewLine 98 //+ "<first> is user's first name." + Environment.NewLine
99 "<first> is user's first name." + Environment.NewLine 99 "<first> is user's first name." + Environment.NewLine
100 + "<last> is user's last name." + Environment.NewLine 100 + "<last> is user's last name." + Environment.NewLine
101 + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine 101 + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine
102 + "<password> is the user's password." + Environment.NewLine 102 + "<password> is the user's password." + Environment.NewLine
@@ -136,16 +136,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
136 if (handlerInventoryArchiveSaved != null) 136 if (handlerInventoryArchiveSaved != null)
137 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException); 137 handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException);
138 } 138 }
139 139
140 public bool ArchiveInventory( 140 public bool ArchiveInventory(
141 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream) 141 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
142 { 142 {
143 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>()); 143 return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>());
144 } 144 }
145 145
146 public bool ArchiveInventory( 146 public bool ArchiveInventory(
147 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, 147 Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream,
148 Dictionary<string, object> options) 148 Dictionary<string, object> options)
149 { 149 {
150 if (m_scenes.Count > 0) 150 if (m_scenes.Count > 0)
151 { 151 {
@@ -184,8 +184,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
184 } 184 }
185 185
186 public bool ArchiveInventory( 186 public bool ArchiveInventory(
187 Guid id, string firstName, string lastName, string invPath, string pass, string savePath, 187 Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
188 Dictionary<string, object> options) 188 Dictionary<string, object> options)
189 { 189 {
190 if (m_scenes.Count > 0) 190 if (m_scenes.Count > 0)
191 { 191 {
@@ -224,13 +224,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
224 } 224 }
225 225
226 public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream) 226 public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream)
227 { 227 {
228 return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>()); 228 return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>());
229 } 229 }
230 230
231 public bool DearchiveInventory( 231 public bool DearchiveInventory(
232 string firstName, string lastName, string invPath, string pass, Stream loadStream, 232 string firstName, string lastName, string invPath, string pass, Stream loadStream,
233 Dictionary<string, object> options) 233 Dictionary<string, object> options)
234 { 234 {
235 if (m_scenes.Count > 0) 235 if (m_scenes.Count > 0)
236 { 236 {
@@ -241,10 +241,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
241 if (CheckPresence(userInfo.PrincipalID)) 241 if (CheckPresence(userInfo.PrincipalID))
242 { 242 {
243 InventoryArchiveReadRequest request; 243 InventoryArchiveReadRequest request;
244 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
244 245
245 try 246 try
246 { 247 {
247 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream); 248 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge);
248 } 249 }
249 catch (EntryPointNotFoundException e) 250 catch (EntryPointNotFoundException e)
250 { 251 {
@@ -273,8 +274,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
273 } 274 }
274 275
275 public bool DearchiveInventory( 276 public bool DearchiveInventory(
276 string firstName, string lastName, string invPath, string pass, string loadPath, 277 string firstName, string lastName, string invPath, string pass, string loadPath,
277 Dictionary<string, object> options) 278 Dictionary<string, object> options)
278 { 279 {
279 if (m_scenes.Count > 0) 280 if (m_scenes.Count > 0)
280 { 281 {
@@ -285,10 +286,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
285 if (CheckPresence(userInfo.PrincipalID)) 286 if (CheckPresence(userInfo.PrincipalID))
286 { 287 {
287 InventoryArchiveReadRequest request; 288 InventoryArchiveReadRequest request;
289 bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
288 290
289 try 291 try
290 { 292 {
291 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath); 293 request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge);
292 } 294 }
293 catch (EntryPointNotFoundException e) 295 catch (EntryPointNotFoundException e)
294 { 296 {
@@ -334,7 +336,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
334 if (mainParams.Count < 6) 336 if (mainParams.Count < 6)
335 { 337 {
336 m_log.Error( 338 m_log.Error(
337 "[INVENTORY ARCHIVER]: usage is load iar <first name> <last name> <inventory path> <user password> [<load file path>]"); 339 "[INVENTORY ARCHIVER]: usage is load iar [--merge] <first name> <last name> <inventory path> <user password> [<load file path>]");
338 return; 340 return;
339 } 341 }
340 342
@@ -356,7 +358,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
356 catch (InventoryArchiverException e) 358 catch (InventoryArchiverException e)
357 { 359 {
358 m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message); 360 m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message);
359 } 361 }
360 } 362 }
361 363
362 /// <summary> 364 /// <summary>
@@ -469,7 +471,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
469 /// Notify the client of loaded nodes if they are logged in 471 /// Notify the client of loaded nodes if they are logged in
470 /// </summary> 472 /// </summary>
471 /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param> 473 /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param>
472 private void UpdateClientWithLoadedNodes(UserAccount userInfo, List<InventoryNodeBase> loadedNodes) 474 private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes)
473 { 475 {
474 if (loadedNodes.Count == 0) 476 if (loadedNodes.Count == 0)
475 return; 477 return;
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
index 4531bfd..2d80382 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
@@ -629,7 +629,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
629 UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); 629 UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
630 630
631 Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>(); 631 Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>();
632 List<InventoryNodeBase> nodesLoaded = new List<InventoryNodeBase>(); 632 HashSet<InventoryNodeBase> nodesLoaded = new HashSet<InventoryNodeBase>();
633 633
634 string folder1Name = "1"; 634 string folder1Name = "1";
635 string folder2aName = "2a"; 635 string folder2aName = "2a";
@@ -644,7 +644,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
644 644
645 { 645 {
646 // Test replication of path1 646 // Test replication of path1
647 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) 647 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
648 .ReplicateArchivePathToUserInventory( 648 .ReplicateArchivePathToUserInventory(
649 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 649 iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
650 foldersCreated, nodesLoaded); 650 foldersCreated, nodesLoaded);
@@ -661,7 +661,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
661 661
662 { 662 {
663 // Test replication of path2 663 // Test replication of path2
664 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) 664 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
665 .ReplicateArchivePathToUserInventory( 665 .ReplicateArchivePathToUserInventory(
666 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 666 iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
667 foldersCreated, nodesLoaded); 667 foldersCreated, nodesLoaded);
@@ -707,10 +707,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
707 707
708 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); 708 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
709 709
710 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) 710 new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
711 .ReplicateArchivePathToUserInventory( 711 .ReplicateArchivePathToUserInventory(
712 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), 712 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
713 new Dictionary<string, InventoryFolderBase>(), new List<InventoryNodeBase>()); 713 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
714 714
715 List<InventoryFolderBase> folder1PostCandidates 715 List<InventoryFolderBase> folder1PostCandidates
716 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); 716 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
@@ -732,5 +732,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
732 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); 732 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b");
733 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); 733 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
734 } 734 }
735
736 /// <summary>
737 /// Test replication of a partly existing archive path to the user's inventory. This should create
738 /// a merged path.
739 /// </summary>
740 [Test]
741 public void TestMergeIarPath()
742 {
743 TestHelper.InMethod();
744 log4net.Config.XmlConfigurator.Configure();
745
746 Scene scene = SceneSetupHelpers.SetupScene("inventory");
747 UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
748
749 string folder1ExistingName = "a";
750 string folder2Name = "b";
751
752 InventoryFolderBase folder1
753 = UserInventoryTestUtils.CreateInventoryFolder(
754 scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
755
756 string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
757 string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
758
759 string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
760
761 new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true)
762 .ReplicateArchivePathToUserInventory(
763 itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
764 new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
765
766 List<InventoryFolderBase> folder1PostCandidates
767 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
768 Assert.That(folder1PostCandidates.Count, Is.EqualTo(1));
769 Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID));
770
771 List<InventoryFolderBase> folder2PostCandidates
772 = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b");
773 Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
774 }
735 } 775 }
736} \ No newline at end of file 776} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
index 36dae6b..9c20d68 100644
--- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -173,16 +173,16 @@ namespace OpenSim.Region.CoreModules.Framework.Library
173 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); 173 m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName);
174 simpleName = GetInventoryPathFromName(simpleName); 174 simpleName = GetInventoryPathFromName(simpleName);
175 175
176 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName); 176 InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false);
177 try 177 try
178 { 178 {
179 List<InventoryNodeBase> nodes = archread.Execute(); 179 HashSet<InventoryNodeBase> nodes = archread.Execute();
180 if (nodes != null && nodes.Count == 0) 180 if (nodes != null && nodes.Count == 0)
181 { 181 {
182 // didn't find the subfolder with the given name; place it on the top 182 // didn't find the subfolder with the given name; place it on the top
183 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); 183 m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName);
184 archread.Close(); 184 archread.Close();
185 archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName); 185 archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false);
186 archread.Execute(); 186 archread.Execute();
187 } 187 }
188 foreach (InventoryNodeBase node in nodes) 188 foreach (InventoryNodeBase node in nodes)
diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
new file mode 100644
index 0000000..82ad109
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
@@ -0,0 +1,596 @@
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
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Collections.Specialized;
32using System.Reflection;
33using System.IO;
34using System.Web;
35using System.Xml;
36using log4net;
37using Mono.Addins;
38using Nini.Config;
39using OpenMetaverse;
40using OpenMetaverse.Messages.Linden;
41using OpenMetaverse.StructuredData;
42using OpenSim.Framework;
43using OpenSim.Framework.Capabilities;
44using OpenSim.Framework.Servers;
45using OpenSim.Framework.Servers.HttpServer;
46using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes;
48using OpenSim.Services.Interfaces;
49using Caps = OpenSim.Framework.Capabilities.Caps;
50using OSDArray = OpenMetaverse.StructuredData.OSDArray;
51using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52
53namespace OpenSim.Region.CoreModules.Media.Moap
54{
55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MoapModule")]
56 public class MoapModule : INonSharedRegionModule, IMoapModule
57 {
58 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59
60 public string Name { get { return "MoapModule"; } }
61 public Type ReplaceableInterface { get { return null; } }
62
63 /// <summary>
64 /// Is this module enabled?
65 /// </summary>
66 protected bool m_isEnabled = true;
67
68 /// <summary>
69 /// The scene to which this module is attached
70 /// </summary>
71 protected Scene m_scene;
72
73 /// <summary>
74 /// Track the ObjectMedia capabilities given to users keyed by path
75 /// </summary>
76 protected Dictionary<string, UUID> m_omCapUsers = new Dictionary<string, UUID>();
77
78 /// <summary>
79 /// Track the ObjectMedia capabilities given to users keyed by agent. Lock m_omCapUsers to manipulate.
80 /// </summary>
81 protected Dictionary<UUID, string> m_omCapUrls = new Dictionary<UUID, string>();
82
83 /// <summary>
84 /// Track the ObjectMediaUpdate capabilities given to users keyed by path
85 /// </summary>
86 protected Dictionary<string, UUID> m_omuCapUsers = new Dictionary<string, UUID>();
87
88 /// <summary>
89 /// Track the ObjectMediaUpdate capabilities given to users keyed by agent. Lock m_omuCapUsers to manipulate
90 /// </summary>
91 protected Dictionary<UUID, string> m_omuCapUrls = new Dictionary<UUID, string>();
92
93 public void Initialise(IConfigSource configSource)
94 {
95 IConfig config = configSource.Configs["MediaOnAPrim"];
96
97 if (config != null && !config.GetBoolean("Enabled", false))
98 m_isEnabled = false;
99// else
100// m_log.Debug("[MOAP]: Initialised module.")l
101 }
102
103 public void AddRegion(Scene scene)
104 {
105 if (!m_isEnabled)
106 return;
107
108 m_scene = scene;
109 m_scene.RegisterModuleInterface<IMoapModule>(this);
110 }
111
112 public void RemoveRegion(Scene scene) {}
113
114 public void RegionLoaded(Scene scene)
115 {
116 if (!m_isEnabled)
117 return;
118
119 m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
120 m_scene.EventManager.OnDeregisterCaps += OnDeregisterCaps;
121 m_scene.EventManager.OnSceneObjectPartCopy += OnSceneObjectPartCopy;
122 }
123
124 public void Close()
125 {
126 if (!m_isEnabled)
127 return;
128
129 m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
130 m_scene.EventManager.OnDeregisterCaps -= OnDeregisterCaps;
131 m_scene.EventManager.OnSceneObjectPartCopy -= OnSceneObjectPartCopy;
132 }
133
134 public void OnRegisterCaps(UUID agentID, Caps caps)
135 {
136// m_log.DebugFormat(
137// "[MOAP]: Registering ObjectMedia and ObjectMediaNavigate capabilities for agent {0}", agentID);
138
139 string omCapUrl = "/CAPS/" + UUID.Random();
140
141 lock (m_omCapUsers)
142 {
143 m_omCapUsers[omCapUrl] = agentID;
144 m_omCapUrls[agentID] = omCapUrl;
145
146 // Even though we're registering for POST we're going to get GETS and UPDATES too
147 caps.RegisterHandler(
148 "ObjectMedia", new RestStreamHandler("POST", omCapUrl, HandleObjectMediaMessage));
149 }
150
151 string omuCapUrl = "/CAPS/" + UUID.Random();
152
153 lock (m_omuCapUsers)
154 {
155 m_omuCapUsers[omuCapUrl] = agentID;
156 m_omuCapUrls[agentID] = omuCapUrl;
157
158 // Even though we're registering for POST we're going to get GETS and UPDATES too
159 caps.RegisterHandler(
160 "ObjectMediaNavigate", new RestStreamHandler("POST", omuCapUrl, HandleObjectMediaNavigateMessage));
161 }
162 }
163
164 public void OnDeregisterCaps(UUID agentID, Caps caps)
165 {
166 lock (m_omCapUsers)
167 {
168 string path = m_omCapUrls[agentID];
169 m_omCapUrls.Remove(agentID);
170 m_omCapUsers.Remove(path);
171 }
172
173 lock (m_omuCapUsers)
174 {
175 string path = m_omuCapUrls[agentID];
176 m_omuCapUrls.Remove(agentID);
177 m_omuCapUsers.Remove(path);
178 }
179 }
180
181 protected void OnSceneObjectPartCopy(SceneObjectPart copy, SceneObjectPart original, bool userExposed)
182 {
183 if (original.Shape.Media != null)
184 {
185 PrimitiveBaseShape.MediaList dupeMedia = new PrimitiveBaseShape.MediaList();
186 lock (original.Shape.Media)
187 {
188 foreach (MediaEntry me in original.Shape.Media)
189 {
190 if (me != null)
191 dupeMedia.Add(MediaEntry.FromOSD(me.GetOSD()));
192 else
193 dupeMedia.Add(null);
194 }
195 }
196
197 copy.Shape.Media = dupeMedia;
198 }
199 }
200
201 public MediaEntry GetMediaEntry(SceneObjectPart part, int face)
202 {
203 MediaEntry me = null;
204
205 CheckFaceParam(part, face);
206
207 List<MediaEntry> media = part.Shape.Media;
208
209 if (null == media)
210 {
211 me = null;
212 }
213 else
214 {
215 lock (media)
216 me = media[face];
217
218 // TODO: Really need a proper copy constructor down in libopenmetaverse
219 if (me != null)
220 me = MediaEntry.FromOSD(me.GetOSD());
221 }
222
223// m_log.DebugFormat("[MOAP]: GetMediaEntry for {0} face {1} found {2}", part.Name, face, me);
224
225 return me;
226 }
227
228 public void SetMediaEntry(SceneObjectPart part, int face, MediaEntry me)
229 {
230 CheckFaceParam(part, face);
231
232 if (null == part.Shape.Media)
233 part.Shape.Media = new PrimitiveBaseShape.MediaList(new MediaEntry[part.GetNumberOfSides()]);
234
235 lock (part.Shape.Media)
236 part.Shape.Media[face] = me;
237
238 UpdateMediaUrl(part, UUID.Zero);
239 part.ScheduleFullUpdate();
240 part.TriggerScriptChangedEvent(Changed.MEDIA);
241 }
242
243 public void ClearMediaEntry(SceneObjectPart part, int face)
244 {
245 SetMediaEntry(part, face, null);
246 }
247
248 /// <summary>
249 /// Sets or gets per face media textures.
250 /// </summary>
251 /// <param name="request"></param>
252 /// <param name="path"></param>
253 /// <param name="param"></param>
254 /// <param name="httpRequest"></param>
255 /// <param name="httpResponse"></param>
256 /// <returns></returns>
257 protected string HandleObjectMediaMessage(
258 string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
259 {
260// m_log.DebugFormat("[MOAP]: Got ObjectMedia path [{0}], raw request [{1}]", path, request);
261
262 OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request);
263 ObjectMediaMessage omm = new ObjectMediaMessage();
264 omm.Deserialize(osd);
265
266 if (omm.Request is ObjectMediaRequest)
267 return HandleObjectMediaRequest(omm.Request as ObjectMediaRequest);
268 else if (omm.Request is ObjectMediaUpdate)
269 return HandleObjectMediaUpdate(path, omm.Request as ObjectMediaUpdate);
270
271 throw new Exception(
272 string.Format(
273 "[MOAP]: ObjectMediaMessage has unrecognized ObjectMediaBlock of {0}",
274 omm.Request.GetType()));
275 }
276
277 /// <summary>
278 /// Handle a fetch request for media textures
279 /// </summary>
280 /// <param name="omr"></param>
281 /// <returns></returns>
282 protected string HandleObjectMediaRequest(ObjectMediaRequest omr)
283 {
284 UUID primId = omr.PrimID;
285
286 SceneObjectPart part = m_scene.GetSceneObjectPart(primId);
287
288 if (null == part)
289 {
290 m_log.WarnFormat(
291 "[MOAP]: Received a GET ObjectMediaRequest for prim {0} but this doesn't exist in region {1}",
292 primId, m_scene.RegionInfo.RegionName);
293 return string.Empty;
294 }
295
296 if (null == part.Shape.Media)
297 return string.Empty;
298
299 ObjectMediaResponse resp = new ObjectMediaResponse();
300
301 resp.PrimID = primId;
302
303 lock (part.Shape.Media)
304 resp.FaceMedia = part.Shape.Media.ToArray();
305
306 resp.Version = part.MediaUrl;
307
308 string rawResp = OSDParser.SerializeLLSDXmlString(resp.Serialize());
309
310// m_log.DebugFormat("[MOAP]: Got HandleObjectMediaRequestGet raw response is [{0}]", rawResp);
311
312 return rawResp;
313 }
314
315 /// <summary>
316 /// Handle an update of media textures.
317 /// </summary>
318 /// <param name="path">Path on which this request was made</param>
319 /// <param name="omu">/param>
320 /// <returns></returns>
321 protected string HandleObjectMediaUpdate(string path, ObjectMediaUpdate omu)
322 {
323 UUID primId = omu.PrimID;
324
325 SceneObjectPart part = m_scene.GetSceneObjectPart(primId);
326
327 if (null == part)
328 {
329 m_log.WarnFormat(
330 "[MOAP]: Received an UPDATE ObjectMediaRequest for prim {0} but this doesn't exist in region {1}",
331 primId, m_scene.RegionInfo.RegionName);
332 return string.Empty;
333 }
334
335// m_log.DebugFormat("[MOAP]: Received {0} media entries for prim {1}", omu.FaceMedia.Length, primId);
336
337// for (int i = 0; i < omu.FaceMedia.Length; i++)
338// {
339// MediaEntry me = omu.FaceMedia[i];
340// string v = (null == me ? "null": OSDParser.SerializeLLSDXmlString(me.GetOSD()));
341// m_log.DebugFormat("[MOAP]: Face {0} [{1}]", i, v);
342// }
343
344 if (omu.FaceMedia.Length > part.GetNumberOfSides())
345 {
346 m_log.WarnFormat(
347 "[MOAP]: Received {0} media entries from client for prim {1} {2} but this prim has only {3} faces. Dropping request.",
348 omu.FaceMedia.Length, part.Name, part.UUID, part.GetNumberOfSides());
349 return string.Empty;
350 }
351
352 UUID agentId = default(UUID);
353
354 lock (m_omCapUsers)
355 agentId = m_omCapUsers[path];
356
357 List<MediaEntry> media = part.Shape.Media;
358
359 if (null == media)
360 {
361// m_log.DebugFormat("[MOAP]: Setting all new media list for {0}", part.Name);
362 part.Shape.Media = new PrimitiveBaseShape.MediaList(omu.FaceMedia);
363
364 for (int i = 0; i < omu.FaceMedia.Length; i++)
365 {
366 if (omu.FaceMedia[i] != null)
367 {
368 // FIXME: Race condition here since some other texture entry manipulator may overwrite/get
369 // overwritten. Unfortunately, PrimitiveBaseShape does not allow us to change texture entry
370 // directly.
371 Primitive.TextureEntry te = part.Shape.Textures;
372 Primitive.TextureEntryFace face = te.CreateFace((uint)i);
373 face.MediaFlags = true;
374 part.Shape.Textures = te;
375// m_log.DebugFormat(
376// "[MOAP]: Media flags for face {0} is {1}",
377// i, part.Shape.Textures.FaceTextures[i].MediaFlags);
378 }
379 }
380 }
381 else
382 {
383 // We need to go through the media textures one at a time to make sure that we have permission
384 // to change them
385
386 // FIXME: Race condition here since some other texture entry manipulator may overwrite/get
387 // overwritten. Unfortunately, PrimitiveBaseShape does not allow us to change texture entry
388 // directly.
389 Primitive.TextureEntry te = part.Shape.Textures;
390
391 lock (media)
392 {
393 for (int i = 0; i < media.Count; i++)
394 {
395 if (m_scene.Permissions.CanControlPrimMedia(agentId, part.UUID, i))
396 {
397 media[i] = omu.FaceMedia[i];
398
399 // When a face is cleared this is done by setting the MediaFlags in the TextureEntry via a normal
400 // texture update, so we don't need to worry about clearing MediaFlags here.
401 if (null == media[i])
402 continue;
403
404 Primitive.TextureEntryFace face = te.CreateFace((uint)i);
405 face.MediaFlags = true;
406
407 // m_log.DebugFormat(
408 // "[MOAP]: Media flags for face {0} is {1}",
409 // i, face.MediaFlags);
410 // m_log.DebugFormat("[MOAP]: Set media entry for face {0} on {1}", i, part.Name);
411 }
412 }
413 }
414
415 part.Shape.Textures = te;
416
417// for (int i2 = 0; i2 < part.Shape.Textures.FaceTextures.Length; i2++)
418// m_log.DebugFormat("[MOAP]: FaceTexture[{0}] is {1}", i2, part.Shape.Textures.FaceTextures[i2]);
419 }
420
421 UpdateMediaUrl(part, agentId);
422
423 // Arguably, we could avoid sending a full update to the avatar that just changed the texture.
424 part.ScheduleFullUpdate();
425
426 part.TriggerScriptChangedEvent(Changed.MEDIA);
427
428 return string.Empty;
429 }
430
431 /// <summary>
432 /// Received from the viewer if a user has changed the url of a media texture.
433 /// </summary>
434 /// <param name="request"></param>
435 /// <param name="path"></param>
436 /// <param name="param"></param>
437 /// <param name="httpRequest">/param>
438 /// <param name="httpResponse">/param>
439 /// <returns></returns>
440 protected string HandleObjectMediaNavigateMessage(
441 string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
442 {
443// m_log.DebugFormat("[MOAP]: Got ObjectMediaNavigate request [{0}]", request);
444
445 OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request);
446 ObjectMediaNavigateMessage omn = new ObjectMediaNavigateMessage();
447 omn.Deserialize(osd);
448
449 UUID primId = omn.PrimID;
450
451 SceneObjectPart part = m_scene.GetSceneObjectPart(primId);
452
453 if (null == part)
454 {
455 m_log.WarnFormat(
456 "[MOAP]: Received an ObjectMediaNavigateMessage for prim {0} but this doesn't exist in region {1}",
457 primId, m_scene.RegionInfo.RegionName);
458 return string.Empty;
459 }
460
461 UUID agentId = default(UUID);
462
463 lock (m_omuCapUsers)
464 agentId = m_omuCapUsers[path];
465
466 if (!m_scene.Permissions.CanInteractWithPrimMedia(agentId, part.UUID, omn.Face))
467 return string.Empty;
468
469// m_log.DebugFormat(
470// "[MOAP]: Received request to update media entry for face {0} on prim {1} {2} to {3}",
471// omn.Face, part.Name, part.UUID, omn.URL);
472
473 // If media has never been set for this prim, then just return.
474 if (null == part.Shape.Media)
475 return string.Empty;
476
477 MediaEntry me = null;
478
479 lock (part.Shape.Media)
480 me = part.Shape.Media[omn.Face];
481
482 // Do the same if media has not been set up for a specific face
483 if (null == me)
484 return string.Empty;
485
486 if (me.EnableWhiteList)
487 {
488 if (!CheckUrlAgainstWhitelist(omn.URL, me.WhiteList))
489 {
490// m_log.DebugFormat(
491// "[MOAP]: Blocking change of face {0} on prim {1} {2} to {3} since it's not on the enabled whitelist",
492// omn.Face, part.Name, part.UUID, omn.URL);
493
494 return string.Empty;
495 }
496 }
497
498 me.CurrentURL = omn.URL;
499
500 UpdateMediaUrl(part, agentId);
501
502 part.ScheduleFullUpdate();
503
504 part.TriggerScriptChangedEvent(Changed.MEDIA);
505
506 return OSDParser.SerializeLLSDXmlString(new OSD());
507 }
508
509 /// <summary>
510 /// Check that the face number is valid for the given prim.
511 /// </summary>
512 /// <param name="part"></param>
513 /// <param name="face"></param>
514 protected void CheckFaceParam(SceneObjectPart part, int face)
515 {
516 if (face < 0)
517 throw new ArgumentException("Face cannot be less than zero");
518
519 int maxFaces = part.GetNumberOfSides() - 1;
520 if (face > maxFaces)
521 throw new ArgumentException(
522 string.Format("Face argument was {0} but max is {1}", face, maxFaces));
523 }
524
525 /// <summary>
526 /// Update the media url of the given part
527 /// </summary>
528 /// <param name="part"></param>
529 /// <param name="updateId">
530 /// The id to attach to this update. Normally, this is the user that changed the
531 /// texture
532 /// </param>
533 protected void UpdateMediaUrl(SceneObjectPart part, UUID updateId)
534 {
535 if (null == part.MediaUrl)
536 {
537 // TODO: We can't set the last changer until we start tracking which cap we give to which agent id
538 part.MediaUrl = "x-mv:0000000000/" + updateId;
539 }
540 else
541 {
542 string rawVersion = part.MediaUrl.Substring(5, 10);
543 int version = int.Parse(rawVersion);
544 part.MediaUrl = string.Format("x-mv:{0:D10}/{1}", ++version, updateId);
545 }
546
547// m_log.DebugFormat("[MOAP]: Storing media url [{0}] in prim {1} {2}", part.MediaUrl, part.Name, part.UUID);
548 }
549
550 /// <summary>
551 /// Check the given url against the given whitelist.
552 /// </summary>
553 /// <param name="rawUrl"></param>
554 /// <param name="whitelist"></param>
555 /// <returns>true if the url matches an entry on the whitelist, false otherwise</returns>
556 protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist)
557 {
558 Uri url = new Uri(rawUrl);
559
560 foreach (string origWlUrl in whitelist)
561 {
562 string wlUrl = origWlUrl;
563
564 // Deal with a line-ending wildcard
565 if (wlUrl.EndsWith("*"))
566 wlUrl = wlUrl.Remove(wlUrl.Length - 1);
567
568// m_log.DebugFormat("[MOAP]: Checking whitelist URL pattern {0}", origWlUrl);
569
570 // Handle a line starting wildcard slightly differently since this can only match the domain, not the path
571 if (wlUrl.StartsWith("*"))
572 {
573 wlUrl = wlUrl.Substring(1);
574
575 if (url.Host.Contains(wlUrl))
576 {
577// m_log.DebugFormat("[MOAP]: Whitelist URL {0} matches {1}", origWlUrl, rawUrl);
578 return true;
579 }
580 }
581 else
582 {
583 string urlToMatch = url.Authority + url.AbsolutePath;
584
585 if (urlToMatch.StartsWith(wlUrl))
586 {
587// m_log.DebugFormat("[MOAP]: Whitelist URL {0} matches {1}", origWlUrl, rawUrl);
588 return true;
589 }
590 }
591 }
592
593 return false;
594 }
595 }
596} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index 8223f12..b1747ef 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -164,6 +164,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
164 private Dictionary<string, bool> GrantYP = new Dictionary<string, bool>(); 164 private Dictionary<string, bool> GrantYP = new Dictionary<string, bool>();
165 private IFriendsModule m_friendsModule; 165 private IFriendsModule m_friendsModule;
166 private IGroupsModule m_groupsModule; 166 private IGroupsModule m_groupsModule;
167 private IMoapModule m_moapModule;
167 168
168 #endregion 169 #endregion
169 170
@@ -177,7 +178,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
177 178
178 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule"); 179 string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule");
179 180
180 List<string> modules=new List<string>(permissionModules.Split(',')); 181 List<string> modules = new List<string>(permissionModules.Split(','));
181 182
182 if (!modules.Contains("DefaultPermissionsModule")) 183 if (!modules.Contains("DefaultPermissionsModule"))
183 return; 184 return;
@@ -249,6 +250,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions
249 m_scene.Permissions.OnDeleteUserInventory += CanDeleteUserInventory; //NOT YET IMPLEMENTED 250 m_scene.Permissions.OnDeleteUserInventory += CanDeleteUserInventory; //NOT YET IMPLEMENTED
250 251
251 m_scene.Permissions.OnTeleport += CanTeleport; //NOT YET IMPLEMENTED 252 m_scene.Permissions.OnTeleport += CanTeleport; //NOT YET IMPLEMENTED
253
254 m_scene.Permissions.OnControlPrimMedia += CanControlPrimMedia;
255 m_scene.Permissions.OnInteractWithPrimMedia += CanInteractWithPrimMedia;
252 256
253 m_scene.AddCommand(this, "bypass permissions", 257 m_scene.AddCommand(this, "bypass permissions",
254 "bypass permissions <true / false>", 258 "bypass permissions <true / false>",
@@ -394,6 +398,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions
394 398
395 if (m_groupsModule == null) 399 if (m_groupsModule == null)
396 m_log.Warn("[PERMISSIONS]: Groups module not found, group permissions will not work"); 400 m_log.Warn("[PERMISSIONS]: Groups module not found, group permissions will not work");
401
402 m_moapModule = m_scene.RequestModuleInterface<IMoapModule>();
403
404 // This log line will be commented out when no longer required for debugging
405// if (m_moapModule == null)
406// m_log.Warn("[PERMISSIONS]: Media on a prim module not found, media on a prim permissions will not work");
397 } 407 }
398 408
399 public void Close() 409 public void Close()
@@ -1894,5 +1904,80 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1894 } 1904 }
1895 return(false); 1905 return(false);
1896 } 1906 }
1907
1908 private bool CanControlPrimMedia(UUID agentID, UUID primID, int face)
1909 {
1910// m_log.DebugFormat(
1911// "[PERMISSONS]: Performing CanControlPrimMedia check with agentID {0}, primID {1}, face {2}",
1912// agentID, primID, face);
1913
1914 if (null == m_moapModule)
1915 return false;
1916
1917 SceneObjectPart part = m_scene.GetSceneObjectPart(primID);
1918 if (null == part)
1919 return false;
1920
1921 MediaEntry me = m_moapModule.GetMediaEntry(part, face);
1922
1923 // If there is no existing media entry then it can be controlled (in this context, created).
1924 if (null == me)
1925 return true;
1926
1927// m_log.DebugFormat(
1928// "[PERMISSIONS]: Checking CanControlPrimMedia for {0} on {1} face {2} with control permissions {3}",
1929// agentID, primID, face, me.ControlPermissions);
1930
1931 return GenericPrimMediaPermission(part, agentID, me.ControlPermissions);
1932 }
1933
1934 private bool CanInteractWithPrimMedia(UUID agentID, UUID primID, int face)
1935 {
1936// m_log.DebugFormat(
1937// "[PERMISSONS]: Performing CanInteractWithPrimMedia check with agentID {0}, primID {1}, face {2}",
1938// agentID, primID, face);
1939
1940 if (null == m_moapModule)
1941 return false;
1942
1943 SceneObjectPart part = m_scene.GetSceneObjectPart(primID);
1944 if (null == part)
1945 return false;
1946
1947 MediaEntry me = m_moapModule.GetMediaEntry(part, face);
1948
1949 // If there is no existing media entry then it can be controlled (in this context, created).
1950 if (null == me)
1951 return true;
1952
1953// m_log.DebugFormat(
1954// "[PERMISSIONS]: Checking CanInteractWithPrimMedia for {0} on {1} face {2} with interact permissions {3}",
1955// agentID, primID, face, me.InteractPermissions);
1956
1957 return GenericPrimMediaPermission(part, agentID, me.InteractPermissions);
1958 }
1959
1960 private bool GenericPrimMediaPermission(SceneObjectPart part, UUID agentID, MediaPermission perms)
1961 {
1962// if (IsAdministrator(agentID))
1963// return true;
1964
1965 if ((perms & MediaPermission.Anyone) == MediaPermission.Anyone)
1966 return true;
1967
1968 if ((perms & MediaPermission.Owner) == MediaPermission.Owner)
1969 {
1970 if (agentID == part.OwnerID)
1971 return true;
1972 }
1973
1974 if ((perms & MediaPermission.Group) == MediaPermission.Group)
1975 {
1976 if (IsGroupMember(part.GroupID, agentID, 0))
1977 return true;
1978 }
1979
1980 return false;
1981 }
1897 } 1982 }
1898} 1983} \ No newline at end of file