Merge branch 'careminster-presence-refactor' of ssh://3dhosting.de/var/git/careminster into careminster-presence-refactor

This commit is contained in:
Melanie Thielker
2010-08-07 03:40:01 +02:00
52 changed files with 29254 additions and 24487 deletions

View File

@@ -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++;
}
}

View File

@@ -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;

View File

@@ -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));
}
}
}

View File

@@ -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)

View 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;
}
}
}

View File

@@ -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;
}
}
}
}