mirror of
https://github.com/opensim/opensim.git
synced 2026-08-10 11:33:28 +08:00
Merge branch 'master' into careminster-presence-refactor
This commit is contained in:
@@ -54,6 +54,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
|
||||
private UserAccount m_userInfo;
|
||||
private string m_invPath;
|
||||
|
||||
/// <summary>
|
||||
/// Do we want to merge this load with existing inventory?
|
||||
/// </summary>
|
||||
protected bool m_merge;
|
||||
|
||||
/// <value>
|
||||
/// We only use this to request modules
|
||||
@@ -66,19 +71,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
private Stream m_loadStream;
|
||||
|
||||
public InventoryArchiveReadRequest(
|
||||
Scene scene, UserAccount userInfo, string invPath, string loadPath)
|
||||
Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge)
|
||||
: this(
|
||||
scene,
|
||||
userInfo,
|
||||
invPath,
|
||||
new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress))
|
||||
new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress),
|
||||
merge)
|
||||
{
|
||||
}
|
||||
|
||||
public InventoryArchiveReadRequest(
|
||||
Scene scene, UserAccount userInfo, string invPath, Stream loadStream)
|
||||
Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_merge = merge;
|
||||
m_userInfo = userInfo;
|
||||
m_invPath = invPath;
|
||||
m_loadStream = loadStream;
|
||||
@@ -91,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
/// A list of the inventory nodes loaded. If folders were loaded then only the root folders are
|
||||
/// returned
|
||||
/// </returns>
|
||||
public List<InventoryNodeBase> Execute()
|
||||
public HashSet<InventoryNodeBase> Execute()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -100,7 +107,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
int failedAssetRestores = 0;
|
||||
int successfulItemRestores = 0;
|
||||
|
||||
List<InventoryNodeBase> loadedNodes = new List<InventoryNodeBase>();
|
||||
HashSet<InventoryNodeBase> loadedNodes = new HashSet<InventoryNodeBase>();
|
||||
|
||||
List<InventoryFolderBase> folderCandidates
|
||||
= InventoryArchiveUtils.FindFolderByPath(
|
||||
@@ -158,9 +165,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
{
|
||||
successfulItemRestores++;
|
||||
|
||||
// If we're loading an item directly into the given destination folder then we need to record
|
||||
// it separately from any loaded root folders
|
||||
if (rootDestinationFolder == foundFolder)
|
||||
// If we aren't loading the folder containing the item then well need to update the
|
||||
// viewer separately for that item.
|
||||
if (!loadedNodes.Contains(foundFolder))
|
||||
loadedNodes.Add(item);
|
||||
}
|
||||
}
|
||||
@@ -205,14 +212,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
string iarPath,
|
||||
InventoryFolderBase rootDestFolder,
|
||||
Dictionary <string, InventoryFolderBase> resolvedFolders,
|
||||
List<InventoryNodeBase> loadedNodes)
|
||||
HashSet<InventoryNodeBase> loadedNodes)
|
||||
{
|
||||
string iarPathExisting = iarPath;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID);
|
||||
|
||||
InventoryFolderBase destFolder = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders);
|
||||
InventoryFolderBase destFolder
|
||||
= ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders);
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]",
|
||||
@@ -251,46 +259,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
{
|
||||
// string originalArchivePath = archivePath;
|
||||
|
||||
InventoryFolderBase destFolder = null;
|
||||
|
||||
if (archivePath.Length > 0)
|
||||
while (archivePath.Length > 0)
|
||||
{
|
||||
while (null == destFolder && archivePath.Length > 0)
|
||||
m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
|
||||
|
||||
if (resolvedFolders.ContainsKey(archivePath))
|
||||
{
|
||||
// m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
|
||||
|
||||
if (resolvedFolders.ContainsKey(archivePath))
|
||||
// m_log.DebugFormat(
|
||||
// "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath);
|
||||
return resolvedFolders[archivePath];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_merge)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath);
|
||||
destFolder = resolvedFolders[archivePath];
|
||||
// TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the
|
||||
// iar name and try to find that instead.
|
||||
string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath);
|
||||
List<InventoryFolderBase> folderCandidates
|
||||
= InventoryArchiveUtils.FindFolderByPath(
|
||||
m_scene.InventoryService, m_userInfo.PrincipalID, plainPath);
|
||||
|
||||
if (folderCandidates.Count != 0)
|
||||
{
|
||||
InventoryFolderBase destFolder = folderCandidates[0];
|
||||
resolvedFolders[archivePath] = destFolder;
|
||||
return destFolder;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't include the last slash so find the penultimate one
|
||||
int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2);
|
||||
|
||||
if (penultimateSlashIndex >= 0)
|
||||
{
|
||||
// Remove the last section of path so that we can see if we've already resolved the parent
|
||||
archivePath = archivePath.Remove(penultimateSlashIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't include the last slash so find the penultimate one
|
||||
int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2);
|
||||
|
||||
if (penultimateSlashIndex >= 0)
|
||||
{
|
||||
// Remove the last section of path so that we can see if we've already resolved the parent
|
||||
archivePath = archivePath.Remove(penultimateSlashIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}",
|
||||
// originalArchivePath);
|
||||
archivePath = string.Empty;
|
||||
destFolder = rootDestFolder;
|
||||
}
|
||||
// m_log.DebugFormat(
|
||||
// "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}",
|
||||
// originalArchivePath);
|
||||
archivePath = string.Empty;
|
||||
return rootDestFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null == destFolder)
|
||||
destFolder = rootDestFolder;
|
||||
|
||||
return destFolder;
|
||||
return rootDestFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -316,24 +333,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
string iarPathExisting,
|
||||
string iarPathToReplicate,
|
||||
Dictionary <string, InventoryFolderBase> resolvedFolders,
|
||||
List<InventoryNodeBase> loadedNodes)
|
||||
HashSet<InventoryNodeBase> loadedNodes)
|
||||
{
|
||||
string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
int i = 0;
|
||||
|
||||
while (i < rawDirsToCreate.Length)
|
||||
for (int i = 0; i < rawDirsToCreate.Length; i++)
|
||||
{
|
||||
// m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]);
|
||||
|
||||
if (!rawDirsToCreate[i].Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR))
|
||||
continue;
|
||||
|
||||
int identicalNameIdentifierIndex
|
||||
= rawDirsToCreate[i].LastIndexOf(
|
||||
ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR);
|
||||
|
||||
if (identicalNameIdentifierIndex < 0)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex);
|
||||
|
||||
newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName);
|
||||
@@ -356,8 +370,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
|
||||
if (0 == i)
|
||||
loadedNodes.Add(destFolder);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,12 +91,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
|
||||
scene.AddCommand(
|
||||
this, "load iar",
|
||||
"load iar <first> <last> <inventory path> <password> [<IAR path>]",
|
||||
"load iar <first> <last> <inventory path> <password> [<IAR path>]",
|
||||
//"load iar [--merge] <first> <last> <inventory path> <password> [<IAR path>]",
|
||||
"Load user inventory archive (IAR).",
|
||||
//"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
|
||||
//"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
|
||||
//+ "<first> is user's first name." + Environment.NewLine
|
||||
"<first> is user's first name." + Environment.NewLine
|
||||
"<first> is user's first name." + Environment.NewLine
|
||||
+ "<last> is user's last name." + Environment.NewLine
|
||||
+ "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine
|
||||
+ "<password> is the user's password." + Environment.NewLine
|
||||
@@ -136,16 +136,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
if (handlerInventoryArchiveSaved != null)
|
||||
handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException);
|
||||
}
|
||||
|
||||
|
||||
public bool ArchiveInventory(
|
||||
Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
|
||||
{
|
||||
return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>());
|
||||
}
|
||||
Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream)
|
||||
{
|
||||
return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
public bool ArchiveInventory(
|
||||
Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream,
|
||||
Dictionary<string, object> options)
|
||||
Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream,
|
||||
Dictionary<string, object> options)
|
||||
{
|
||||
if (m_scenes.Count > 0)
|
||||
{
|
||||
@@ -184,8 +184,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
}
|
||||
|
||||
public bool ArchiveInventory(
|
||||
Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
|
||||
Dictionary<string, object> options)
|
||||
Guid id, string firstName, string lastName, string invPath, string pass, string savePath,
|
||||
Dictionary<string, object> options)
|
||||
{
|
||||
if (m_scenes.Count > 0)
|
||||
{
|
||||
@@ -224,13 +224,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
}
|
||||
|
||||
public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream)
|
||||
{
|
||||
return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
{
|
||||
return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
public bool DearchiveInventory(
|
||||
string firstName, string lastName, string invPath, string pass, Stream loadStream,
|
||||
Dictionary<string, object> options)
|
||||
string firstName, string lastName, string invPath, string pass, Stream loadStream,
|
||||
Dictionary<string, object> options)
|
||||
{
|
||||
if (m_scenes.Count > 0)
|
||||
{
|
||||
@@ -241,10 +241,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
if (CheckPresence(userInfo.PrincipalID))
|
||||
{
|
||||
InventoryArchiveReadRequest request;
|
||||
bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
|
||||
|
||||
try
|
||||
{
|
||||
request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream);
|
||||
request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge);
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
@@ -273,8 +274,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
}
|
||||
|
||||
public bool DearchiveInventory(
|
||||
string firstName, string lastName, string invPath, string pass, string loadPath,
|
||||
Dictionary<string, object> options)
|
||||
string firstName, string lastName, string invPath, string pass, string loadPath,
|
||||
Dictionary<string, object> options)
|
||||
{
|
||||
if (m_scenes.Count > 0)
|
||||
{
|
||||
@@ -285,10 +286,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
if (CheckPresence(userInfo.PrincipalID))
|
||||
{
|
||||
InventoryArchiveReadRequest request;
|
||||
bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
|
||||
|
||||
try
|
||||
{
|
||||
request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath);
|
||||
{
|
||||
request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge);
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
@@ -334,7 +336,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
if (mainParams.Count < 6)
|
||||
{
|
||||
m_log.Error(
|
||||
"[INVENTORY ARCHIVER]: usage is load iar <first name> <last name> <inventory path> <user password> [<load file path>]");
|
||||
"[INVENTORY ARCHIVER]: usage is load iar [--merge] <first name> <last name> <inventory path> <user password> [<load file path>]");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -356,7 +358,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
catch (InventoryArchiverException e)
|
||||
{
|
||||
m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -469,7 +471,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
/// Notify the client of loaded nodes if they are logged in
|
||||
/// </summary>
|
||||
/// <param name="loadedNodes">Can be empty. In which case, nothing happens</param>
|
||||
private void UpdateClientWithLoadedNodes(UserAccount userInfo, List<InventoryNodeBase> loadedNodes)
|
||||
private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes)
|
||||
{
|
||||
if (loadedNodes.Count == 0)
|
||||
return;
|
||||
|
||||
@@ -629,7 +629,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
|
||||
|
||||
Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>();
|
||||
List<InventoryNodeBase> nodesLoaded = new List<InventoryNodeBase>();
|
||||
HashSet<InventoryNodeBase> nodesLoaded = new HashSet<InventoryNodeBase>();
|
||||
|
||||
string folder1Name = "1";
|
||||
string folder2aName = "2a";
|
||||
@@ -644,7 +644,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
|
||||
{
|
||||
// Test replication of path1
|
||||
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null)
|
||||
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
|
||||
.ReplicateArchivePathToUserInventory(
|
||||
iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
|
||||
foldersCreated, nodesLoaded);
|
||||
@@ -661,7 +661,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
|
||||
{
|
||||
// Test replication of path2
|
||||
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null)
|
||||
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
|
||||
.ReplicateArchivePathToUserInventory(
|
||||
iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
|
||||
foldersCreated, nodesLoaded);
|
||||
@@ -707,10 +707,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
|
||||
string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
|
||||
|
||||
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null)
|
||||
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
|
||||
.ReplicateArchivePathToUserInventory(
|
||||
itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
|
||||
new Dictionary<string, InventoryFolderBase>(), new List<InventoryNodeBase>());
|
||||
new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
|
||||
|
||||
List<InventoryFolderBase> folder1PostCandidates
|
||||
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
|
||||
@@ -732,5 +732,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b");
|
||||
Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test replication of a partly existing archive path to the user's inventory. This should create
|
||||
/// a merged path.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestMergeIarPath()
|
||||
{
|
||||
TestHelper.InMethod();
|
||||
log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
Scene scene = SceneSetupHelpers.SetupScene("inventory");
|
||||
UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
|
||||
|
||||
string folder1ExistingName = "a";
|
||||
string folder2Name = "b";
|
||||
|
||||
InventoryFolderBase folder1
|
||||
= UserInventoryTestUtils.CreateInventoryFolder(
|
||||
scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
|
||||
|
||||
string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
|
||||
string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
|
||||
|
||||
string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
|
||||
|
||||
new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true)
|
||||
.ReplicateArchivePathToUserInventory(
|
||||
itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
|
||||
new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
|
||||
|
||||
List<InventoryFolderBase> folder1PostCandidates
|
||||
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
|
||||
Assert.That(folder1PostCandidates.Count, Is.EqualTo(1));
|
||||
Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID));
|
||||
|
||||
List<InventoryFolderBase> folder2PostCandidates
|
||||
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b");
|
||||
Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
@@ -173,16 +173,16 @@ namespace OpenSim.Region.CoreModules.Framework.Library
|
||||
m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName);
|
||||
simpleName = GetInventoryPathFromName(simpleName);
|
||||
|
||||
InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName);
|
||||
InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false);
|
||||
try
|
||||
{
|
||||
List<InventoryNodeBase> nodes = archread.Execute();
|
||||
HashSet<InventoryNodeBase> nodes = archread.Execute();
|
||||
if (nodes != null && nodes.Count == 0)
|
||||
{
|
||||
// didn't find the subfolder with the given name; place it on the top
|
||||
m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName);
|
||||
archread.Close();
|
||||
archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName);
|
||||
archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false);
|
||||
archread.Execute();
|
||||
}
|
||||
foreach (InventoryNodeBase node in nodes)
|
||||
|
||||
596
OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
Normal file
596
OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs
Normal file
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using Mono.Addins;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Messages.Linden;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Capabilities;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Caps = OpenSim.Framework.Capabilities.Caps;
|
||||
using OSDArray = OpenMetaverse.StructuredData.OSDArray;
|
||||
using OSDMap = OpenMetaverse.StructuredData.OSDMap;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Media.Moap
|
||||
{
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MoapModule")]
|
||||
public class MoapModule : INonSharedRegionModule, IMoapModule
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public string Name { get { return "MoapModule"; } }
|
||||
public Type ReplaceableInterface { get { return null; } }
|
||||
|
||||
/// <summary>
|
||||
/// Is this module enabled?
|
||||
/// </summary>
|
||||
protected bool m_isEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// The scene to which this module is attached
|
||||
/// </summary>
|
||||
protected Scene m_scene;
|
||||
|
||||
/// <summary>
|
||||
/// Track the ObjectMedia capabilities given to users keyed by path
|
||||
/// </summary>
|
||||
protected Dictionary<string, UUID> m_omCapUsers = new Dictionary<string, UUID>();
|
||||
|
||||
/// <summary>
|
||||
/// Track the ObjectMedia capabilities given to users keyed by agent. Lock m_omCapUsers to manipulate.
|
||||
/// </summary>
|
||||
protected Dictionary<UUID, string> m_omCapUrls = new Dictionary<UUID, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Track the ObjectMediaUpdate capabilities given to users keyed by path
|
||||
/// </summary>
|
||||
protected Dictionary<string, UUID> m_omuCapUsers = new Dictionary<string, UUID>();
|
||||
|
||||
/// <summary>
|
||||
/// Track the ObjectMediaUpdate capabilities given to users keyed by agent. Lock m_omuCapUsers to manipulate
|
||||
/// </summary>
|
||||
protected Dictionary<UUID, string> m_omuCapUrls = new Dictionary<UUID, string>();
|
||||
|
||||
public void Initialise(IConfigSource configSource)
|
||||
{
|
||||
IConfig config = configSource.Configs["MediaOnAPrim"];
|
||||
|
||||
if (config != null && !config.GetBoolean("Enabled", false))
|
||||
m_isEnabled = false;
|
||||
// else
|
||||
// m_log.Debug("[MOAP]: Initialised module.")l
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
m_scene = scene;
|
||||
m_scene.RegisterModuleInterface<IMoapModule>(this);
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene scene) {}
|
||||
|
||||
public void RegionLoaded(Scene scene)
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
m_scene.EventManager.OnRegisterCaps += OnRegisterCaps;
|
||||
m_scene.EventManager.OnDeregisterCaps += OnDeregisterCaps;
|
||||
m_scene.EventManager.OnSceneObjectPartCopy += OnSceneObjectPartCopy;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (!m_isEnabled)
|
||||
return;
|
||||
|
||||
m_scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
|
||||
m_scene.EventManager.OnDeregisterCaps -= OnDeregisterCaps;
|
||||
m_scene.EventManager.OnSceneObjectPartCopy -= OnSceneObjectPartCopy;
|
||||
}
|
||||
|
||||
public void OnRegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[MOAP]: Registering ObjectMedia and ObjectMediaNavigate capabilities for agent {0}", agentID);
|
||||
|
||||
string omCapUrl = "/CAPS/" + UUID.Random();
|
||||
|
||||
lock (m_omCapUsers)
|
||||
{
|
||||
m_omCapUsers[omCapUrl] = agentID;
|
||||
m_omCapUrls[agentID] = omCapUrl;
|
||||
|
||||
// Even though we're registering for POST we're going to get GETS and UPDATES too
|
||||
caps.RegisterHandler(
|
||||
"ObjectMedia", new RestStreamHandler("POST", omCapUrl, HandleObjectMediaMessage));
|
||||
}
|
||||
|
||||
string omuCapUrl = "/CAPS/" + UUID.Random();
|
||||
|
||||
lock (m_omuCapUsers)
|
||||
{
|
||||
m_omuCapUsers[omuCapUrl] = agentID;
|
||||
m_omuCapUrls[agentID] = omuCapUrl;
|
||||
|
||||
// Even though we're registering for POST we're going to get GETS and UPDATES too
|
||||
caps.RegisterHandler(
|
||||
"ObjectMediaNavigate", new RestStreamHandler("POST", omuCapUrl, HandleObjectMediaNavigateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDeregisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
lock (m_omCapUsers)
|
||||
{
|
||||
string path = m_omCapUrls[agentID];
|
||||
m_omCapUrls.Remove(agentID);
|
||||
m_omCapUsers.Remove(path);
|
||||
}
|
||||
|
||||
lock (m_omuCapUsers)
|
||||
{
|
||||
string path = m_omuCapUrls[agentID];
|
||||
m_omuCapUrls.Remove(agentID);
|
||||
m_omuCapUsers.Remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnSceneObjectPartCopy(SceneObjectPart copy, SceneObjectPart original, bool userExposed)
|
||||
{
|
||||
if (original.Shape.Media != null)
|
||||
{
|
||||
PrimitiveBaseShape.MediaList dupeMedia = new PrimitiveBaseShape.MediaList();
|
||||
lock (original.Shape.Media)
|
||||
{
|
||||
foreach (MediaEntry me in original.Shape.Media)
|
||||
{
|
||||
if (me != null)
|
||||
dupeMedia.Add(MediaEntry.FromOSD(me.GetOSD()));
|
||||
else
|
||||
dupeMedia.Add(null);
|
||||
}
|
||||
}
|
||||
|
||||
copy.Shape.Media = dupeMedia;
|
||||
}
|
||||
}
|
||||
|
||||
public MediaEntry GetMediaEntry(SceneObjectPart part, int face)
|
||||
{
|
||||
MediaEntry me = null;
|
||||
|
||||
CheckFaceParam(part, face);
|
||||
|
||||
List<MediaEntry> media = part.Shape.Media;
|
||||
|
||||
if (null == media)
|
||||
{
|
||||
me = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (media)
|
||||
me = media[face];
|
||||
|
||||
// TODO: Really need a proper copy constructor down in libopenmetaverse
|
||||
if (me != null)
|
||||
me = MediaEntry.FromOSD(me.GetOSD());
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[MOAP]: GetMediaEntry for {0} face {1} found {2}", part.Name, face, me);
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
public void SetMediaEntry(SceneObjectPart part, int face, MediaEntry me)
|
||||
{
|
||||
CheckFaceParam(part, face);
|
||||
|
||||
if (null == part.Shape.Media)
|
||||
part.Shape.Media = new PrimitiveBaseShape.MediaList(new MediaEntry[part.GetNumberOfSides()]);
|
||||
|
||||
lock (part.Shape.Media)
|
||||
part.Shape.Media[face] = me;
|
||||
|
||||
UpdateMediaUrl(part, UUID.Zero);
|
||||
part.ScheduleFullUpdate();
|
||||
part.TriggerScriptChangedEvent(Changed.MEDIA);
|
||||
}
|
||||
|
||||
public void ClearMediaEntry(SceneObjectPart part, int face)
|
||||
{
|
||||
SetMediaEntry(part, face, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets or gets per face media textures.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="httpResponse"></param>
|
||||
/// <returns></returns>
|
||||
protected string HandleObjectMediaMessage(
|
||||
string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
|
||||
{
|
||||
// m_log.DebugFormat("[MOAP]: Got ObjectMedia path [{0}], raw request [{1}]", path, request);
|
||||
|
||||
OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request);
|
||||
ObjectMediaMessage omm = new ObjectMediaMessage();
|
||||
omm.Deserialize(osd);
|
||||
|
||||
if (omm.Request is ObjectMediaRequest)
|
||||
return HandleObjectMediaRequest(omm.Request as ObjectMediaRequest);
|
||||
else if (omm.Request is ObjectMediaUpdate)
|
||||
return HandleObjectMediaUpdate(path, omm.Request as ObjectMediaUpdate);
|
||||
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"[MOAP]: ObjectMediaMessage has unrecognized ObjectMediaBlock of {0}",
|
||||
omm.Request.GetType()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle a fetch request for media textures
|
||||
/// </summary>
|
||||
/// <param name="omr"></param>
|
||||
/// <returns></returns>
|
||||
protected string HandleObjectMediaRequest(ObjectMediaRequest omr)
|
||||
{
|
||||
UUID primId = omr.PrimID;
|
||||
|
||||
SceneObjectPart part = m_scene.GetSceneObjectPart(primId);
|
||||
|
||||
if (null == part)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[MOAP]: Received a GET ObjectMediaRequest for prim {0} but this doesn't exist in region {1}",
|
||||
primId, m_scene.RegionInfo.RegionName);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (null == part.Shape.Media)
|
||||
return string.Empty;
|
||||
|
||||
ObjectMediaResponse resp = new ObjectMediaResponse();
|
||||
|
||||
resp.PrimID = primId;
|
||||
|
||||
lock (part.Shape.Media)
|
||||
resp.FaceMedia = part.Shape.Media.ToArray();
|
||||
|
||||
resp.Version = part.MediaUrl;
|
||||
|
||||
string rawResp = OSDParser.SerializeLLSDXmlString(resp.Serialize());
|
||||
|
||||
// m_log.DebugFormat("[MOAP]: Got HandleObjectMediaRequestGet raw response is [{0}]", rawResp);
|
||||
|
||||
return rawResp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle an update of media textures.
|
||||
/// </summary>
|
||||
/// <param name="path">Path on which this request was made</param>
|
||||
/// <param name="omu">/param>
|
||||
/// <returns></returns>
|
||||
protected string HandleObjectMediaUpdate(string path, ObjectMediaUpdate omu)
|
||||
{
|
||||
UUID primId = omu.PrimID;
|
||||
|
||||
SceneObjectPart part = m_scene.GetSceneObjectPart(primId);
|
||||
|
||||
if (null == part)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[MOAP]: Received an UPDATE ObjectMediaRequest for prim {0} but this doesn't exist in region {1}",
|
||||
primId, m_scene.RegionInfo.RegionName);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[MOAP]: Received {0} media entries for prim {1}", omu.FaceMedia.Length, primId);
|
||||
|
||||
// for (int i = 0; i < omu.FaceMedia.Length; i++)
|
||||
// {
|
||||
// MediaEntry me = omu.FaceMedia[i];
|
||||
// string v = (null == me ? "null": OSDParser.SerializeLLSDXmlString(me.GetOSD()));
|
||||
// m_log.DebugFormat("[MOAP]: Face {0} [{1}]", i, v);
|
||||
// }
|
||||
|
||||
if (omu.FaceMedia.Length > part.GetNumberOfSides())
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[MOAP]: Received {0} media entries from client for prim {1} {2} but this prim has only {3} faces. Dropping request.",
|
||||
omu.FaceMedia.Length, part.Name, part.UUID, part.GetNumberOfSides());
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
UUID agentId = default(UUID);
|
||||
|
||||
lock (m_omCapUsers)
|
||||
agentId = m_omCapUsers[path];
|
||||
|
||||
List<MediaEntry> media = part.Shape.Media;
|
||||
|
||||
if (null == media)
|
||||
{
|
||||
// m_log.DebugFormat("[MOAP]: Setting all new media list for {0}", part.Name);
|
||||
part.Shape.Media = new PrimitiveBaseShape.MediaList(omu.FaceMedia);
|
||||
|
||||
for (int i = 0; i < omu.FaceMedia.Length; i++)
|
||||
{
|
||||
if (omu.FaceMedia[i] != null)
|
||||
{
|
||||
// FIXME: Race condition here since some other texture entry manipulator may overwrite/get
|
||||
// overwritten. Unfortunately, PrimitiveBaseShape does not allow us to change texture entry
|
||||
// directly.
|
||||
Primitive.TextureEntry te = part.Shape.Textures;
|
||||
Primitive.TextureEntryFace face = te.CreateFace((uint)i);
|
||||
face.MediaFlags = true;
|
||||
part.Shape.Textures = te;
|
||||
// m_log.DebugFormat(
|
||||
// "[MOAP]: Media flags for face {0} is {1}",
|
||||
// i, part.Shape.Textures.FaceTextures[i].MediaFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to go through the media textures one at a time to make sure that we have permission
|
||||
// to change them
|
||||
|
||||
// FIXME: Race condition here since some other texture entry manipulator may overwrite/get
|
||||
// overwritten. Unfortunately, PrimitiveBaseShape does not allow us to change texture entry
|
||||
// directly.
|
||||
Primitive.TextureEntry te = part.Shape.Textures;
|
||||
|
||||
lock (media)
|
||||
{
|
||||
for (int i = 0; i < media.Count; i++)
|
||||
{
|
||||
if (m_scene.Permissions.CanControlPrimMedia(agentId, part.UUID, i))
|
||||
{
|
||||
media[i] = omu.FaceMedia[i];
|
||||
|
||||
// When a face is cleared this is done by setting the MediaFlags in the TextureEntry via a normal
|
||||
// texture update, so we don't need to worry about clearing MediaFlags here.
|
||||
if (null == media[i])
|
||||
continue;
|
||||
|
||||
Primitive.TextureEntryFace face = te.CreateFace((uint)i);
|
||||
face.MediaFlags = true;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[MOAP]: Media flags for face {0} is {1}",
|
||||
// i, face.MediaFlags);
|
||||
// m_log.DebugFormat("[MOAP]: Set media entry for face {0} on {1}", i, part.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
part.Shape.Textures = te;
|
||||
|
||||
// for (int i2 = 0; i2 < part.Shape.Textures.FaceTextures.Length; i2++)
|
||||
// m_log.DebugFormat("[MOAP]: FaceTexture[{0}] is {1}", i2, part.Shape.Textures.FaceTextures[i2]);
|
||||
}
|
||||
|
||||
UpdateMediaUrl(part, agentId);
|
||||
|
||||
// Arguably, we could avoid sending a full update to the avatar that just changed the texture.
|
||||
part.ScheduleFullUpdate();
|
||||
|
||||
part.TriggerScriptChangedEvent(Changed.MEDIA);
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Received from the viewer if a user has changed the url of a media texture.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="param"></param>
|
||||
/// <param name="httpRequest">/param>
|
||||
/// <param name="httpResponse">/param>
|
||||
/// <returns></returns>
|
||||
protected string HandleObjectMediaNavigateMessage(
|
||||
string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse)
|
||||
{
|
||||
// m_log.DebugFormat("[MOAP]: Got ObjectMediaNavigate request [{0}]", request);
|
||||
|
||||
OSDMap osd = (OSDMap)OSDParser.DeserializeLLSDXml(request);
|
||||
ObjectMediaNavigateMessage omn = new ObjectMediaNavigateMessage();
|
||||
omn.Deserialize(osd);
|
||||
|
||||
UUID primId = omn.PrimID;
|
||||
|
||||
SceneObjectPart part = m_scene.GetSceneObjectPart(primId);
|
||||
|
||||
if (null == part)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[MOAP]: Received an ObjectMediaNavigateMessage for prim {0} but this doesn't exist in region {1}",
|
||||
primId, m_scene.RegionInfo.RegionName);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
UUID agentId = default(UUID);
|
||||
|
||||
lock (m_omuCapUsers)
|
||||
agentId = m_omuCapUsers[path];
|
||||
|
||||
if (!m_scene.Permissions.CanInteractWithPrimMedia(agentId, part.UUID, omn.Face))
|
||||
return string.Empty;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[MOAP]: Received request to update media entry for face {0} on prim {1} {2} to {3}",
|
||||
// omn.Face, part.Name, part.UUID, omn.URL);
|
||||
|
||||
// If media has never been set for this prim, then just return.
|
||||
if (null == part.Shape.Media)
|
||||
return string.Empty;
|
||||
|
||||
MediaEntry me = null;
|
||||
|
||||
lock (part.Shape.Media)
|
||||
me = part.Shape.Media[omn.Face];
|
||||
|
||||
// Do the same if media has not been set up for a specific face
|
||||
if (null == me)
|
||||
return string.Empty;
|
||||
|
||||
if (me.EnableWhiteList)
|
||||
{
|
||||
if (!CheckUrlAgainstWhitelist(omn.URL, me.WhiteList))
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[MOAP]: Blocking change of face {0} on prim {1} {2} to {3} since it's not on the enabled whitelist",
|
||||
// omn.Face, part.Name, part.UUID, omn.URL);
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
me.CurrentURL = omn.URL;
|
||||
|
||||
UpdateMediaUrl(part, agentId);
|
||||
|
||||
part.ScheduleFullUpdate();
|
||||
|
||||
part.TriggerScriptChangedEvent(Changed.MEDIA);
|
||||
|
||||
return OSDParser.SerializeLLSDXmlString(new OSD());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check that the face number is valid for the given prim.
|
||||
/// </summary>
|
||||
/// <param name="part"></param>
|
||||
/// <param name="face"></param>
|
||||
protected void CheckFaceParam(SceneObjectPart part, int face)
|
||||
{
|
||||
if (face < 0)
|
||||
throw new ArgumentException("Face cannot be less than zero");
|
||||
|
||||
int maxFaces = part.GetNumberOfSides() - 1;
|
||||
if (face > maxFaces)
|
||||
throw new ArgumentException(
|
||||
string.Format("Face argument was {0} but max is {1}", face, maxFaces));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the media url of the given part
|
||||
/// </summary>
|
||||
/// <param name="part"></param>
|
||||
/// <param name="updateId">
|
||||
/// The id to attach to this update. Normally, this is the user that changed the
|
||||
/// texture
|
||||
/// </param>
|
||||
protected void UpdateMediaUrl(SceneObjectPart part, UUID updateId)
|
||||
{
|
||||
if (null == part.MediaUrl)
|
||||
{
|
||||
// TODO: We can't set the last changer until we start tracking which cap we give to which agent id
|
||||
part.MediaUrl = "x-mv:0000000000/" + updateId;
|
||||
}
|
||||
else
|
||||
{
|
||||
string rawVersion = part.MediaUrl.Substring(5, 10);
|
||||
int version = int.Parse(rawVersion);
|
||||
part.MediaUrl = string.Format("x-mv:{0:D10}/{1}", ++version, updateId);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[MOAP]: Storing media url [{0}] in prim {1} {2}", part.MediaUrl, part.Name, part.UUID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check the given url against the given whitelist.
|
||||
/// </summary>
|
||||
/// <param name="rawUrl"></param>
|
||||
/// <param name="whitelist"></param>
|
||||
/// <returns>true if the url matches an entry on the whitelist, false otherwise</returns>
|
||||
protected bool CheckUrlAgainstWhitelist(string rawUrl, string[] whitelist)
|
||||
{
|
||||
Uri url = new Uri(rawUrl);
|
||||
|
||||
foreach (string origWlUrl in whitelist)
|
||||
{
|
||||
string wlUrl = origWlUrl;
|
||||
|
||||
// Deal with a line-ending wildcard
|
||||
if (wlUrl.EndsWith("*"))
|
||||
wlUrl = wlUrl.Remove(wlUrl.Length - 1);
|
||||
|
||||
// m_log.DebugFormat("[MOAP]: Checking whitelist URL pattern {0}", origWlUrl);
|
||||
|
||||
// Handle a line starting wildcard slightly differently since this can only match the domain, not the path
|
||||
if (wlUrl.StartsWith("*"))
|
||||
{
|
||||
wlUrl = wlUrl.Substring(1);
|
||||
|
||||
if (url.Host.Contains(wlUrl))
|
||||
{
|
||||
// m_log.DebugFormat("[MOAP]: Whitelist URL {0} matches {1}", origWlUrl, rawUrl);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string urlToMatch = url.Authority + url.AbsolutePath;
|
||||
|
||||
if (urlToMatch.StartsWith(wlUrl))
|
||||
{
|
||||
// m_log.DebugFormat("[MOAP]: Whitelist URL {0} matches {1}", origWlUrl, rawUrl);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,6 +164,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
|
||||
private Dictionary<string, bool> GrantYP = new Dictionary<string, bool>();
|
||||
private IFriendsModule m_friendsModule;
|
||||
private IGroupsModule m_groupsModule;
|
||||
private IMoapModule m_moapModule;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -177,7 +178,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
|
||||
|
||||
string permissionModules = myConfig.GetString("permissionmodules", "DefaultPermissionsModule");
|
||||
|
||||
List<string> modules=new List<string>(permissionModules.Split(','));
|
||||
List<string> modules = new List<string>(permissionModules.Split(','));
|
||||
|
||||
if (!modules.Contains("DefaultPermissionsModule"))
|
||||
return;
|
||||
@@ -249,6 +250,9 @@ namespace OpenSim.Region.CoreModules.World.Permissions
|
||||
m_scene.Permissions.OnDeleteUserInventory += CanDeleteUserInventory; //NOT YET IMPLEMENTED
|
||||
|
||||
m_scene.Permissions.OnTeleport += CanTeleport; //NOT YET IMPLEMENTED
|
||||
|
||||
m_scene.Permissions.OnControlPrimMedia += CanControlPrimMedia;
|
||||
m_scene.Permissions.OnInteractWithPrimMedia += CanInteractWithPrimMedia;
|
||||
|
||||
m_scene.AddCommand(this, "bypass permissions",
|
||||
"bypass permissions <true / false>",
|
||||
@@ -394,6 +398,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions
|
||||
|
||||
if (m_groupsModule == null)
|
||||
m_log.Warn("[PERMISSIONS]: Groups module not found, group permissions will not work");
|
||||
|
||||
m_moapModule = m_scene.RequestModuleInterface<IMoapModule>();
|
||||
|
||||
// This log line will be commented out when no longer required for debugging
|
||||
// if (m_moapModule == null)
|
||||
// m_log.Warn("[PERMISSIONS]: Media on a prim module not found, media on a prim permissions will not work");
|
||||
}
|
||||
|
||||
public void Close()
|
||||
@@ -1894,5 +1904,80 @@ namespace OpenSim.Region.CoreModules.World.Permissions
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
private bool CanControlPrimMedia(UUID agentID, UUID primID, int face)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[PERMISSONS]: Performing CanControlPrimMedia check with agentID {0}, primID {1}, face {2}",
|
||||
// agentID, primID, face);
|
||||
|
||||
if (null == m_moapModule)
|
||||
return false;
|
||||
|
||||
SceneObjectPart part = m_scene.GetSceneObjectPart(primID);
|
||||
if (null == part)
|
||||
return false;
|
||||
|
||||
MediaEntry me = m_moapModule.GetMediaEntry(part, face);
|
||||
|
||||
// If there is no existing media entry then it can be controlled (in this context, created).
|
||||
if (null == me)
|
||||
return true;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[PERMISSIONS]: Checking CanControlPrimMedia for {0} on {1} face {2} with control permissions {3}",
|
||||
// agentID, primID, face, me.ControlPermissions);
|
||||
|
||||
return GenericPrimMediaPermission(part, agentID, me.ControlPermissions);
|
||||
}
|
||||
|
||||
private bool CanInteractWithPrimMedia(UUID agentID, UUID primID, int face)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[PERMISSONS]: Performing CanInteractWithPrimMedia check with agentID {0}, primID {1}, face {2}",
|
||||
// agentID, primID, face);
|
||||
|
||||
if (null == m_moapModule)
|
||||
return false;
|
||||
|
||||
SceneObjectPart part = m_scene.GetSceneObjectPart(primID);
|
||||
if (null == part)
|
||||
return false;
|
||||
|
||||
MediaEntry me = m_moapModule.GetMediaEntry(part, face);
|
||||
|
||||
// If there is no existing media entry then it can be controlled (in this context, created).
|
||||
if (null == me)
|
||||
return true;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[PERMISSIONS]: Checking CanInteractWithPrimMedia for {0} on {1} face {2} with interact permissions {3}",
|
||||
// agentID, primID, face, me.InteractPermissions);
|
||||
|
||||
return GenericPrimMediaPermission(part, agentID, me.InteractPermissions);
|
||||
}
|
||||
|
||||
private bool GenericPrimMediaPermission(SceneObjectPart part, UUID agentID, MediaPermission perms)
|
||||
{
|
||||
// if (IsAdministrator(agentID))
|
||||
// return true;
|
||||
|
||||
if ((perms & MediaPermission.Anyone) == MediaPermission.Anyone)
|
||||
return true;
|
||||
|
||||
if ((perms & MediaPermission.Owner) == MediaPermission.Owner)
|
||||
{
|
||||
if (agentID == part.OwnerID)
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((perms & MediaPermission.Group) == MediaPermission.Group)
|
||||
{
|
||||
if (IsGroupMember(part.GroupID, agentID, 0))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user