diff --git a/OpenSim/Framework/Communications/OspResolver.cs b/OpenSim/Framework/Communications/OspResolver.cs
new file mode 100644
index 0000000000..708bb847a8
--- /dev/null
+++ b/OpenSim/Framework/Communications/OspResolver.cs
@@ -0,0 +1,130 @@
+/*
+ * 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 OpenSim 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.Reflection;
+using System.Text;
+using log4net;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Framework.Communications.Cache;
+
+namespace OpenSim.Framework.Communications
+{
+ ///
+ /// Resolves OpenSim Profile Anchors (OSPA). An OSPA is a string used to provide information for
+ /// identifying user profiles or supplying a simple name if no profile is available.
+ ///
+ public class OspResolver
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public const string OSPA_PREFIX = "ospi:";
+ public const string OSPA_NAME_KEY = "n";
+ public const string OSPA_NAME_VALUE_SEPARATOR = " ";
+ public const string OSPA_TUPLE_SEPARATOR = "|";
+ public static readonly char[] OSPA_TUPLE_SEPARATOR_ARRAY = OSPA_TUPLE_SEPARATOR.ToCharArray();
+ public const string OSPA_KEY_VALUE_PAIR_SEPARATOR = "=";
+
+ ///
+ /// Resolve an osp string into the most suitable internal OpenSim identifier.
+ ///
+ ///
+ /// In some cases this will be a UUID if a suitable profile exists on the system. In other cases, this may
+ /// just return the same identifier after creating a temporary profile.
+ ///
+ ///
+ ///
+ ///
+ /// A suitable internal OpenSim identifier. If the input string wasn't ospi data, then we simply
+ /// return that same string. If the input string was ospi data but no valid profile information has been found,
+ /// then returns null.
+ ///
+ public static string Resolve(string ospa, CommunicationsManager commsManager)
+ {
+ if (!ospa.StartsWith(OSPA_PREFIX))
+ return ospa;
+
+ string ospaMeat = ospa.Substring(OSPA_PREFIX.Length);
+ string[] ospaTuples = ospaMeat.Split(OSPA_TUPLE_SEPARATOR_ARRAY);
+
+ foreach (string tuple in ospaTuples)
+ {
+ int tupleSeparatorIndex = tuple.IndexOf(OSPA_TUPLE_SEPARATOR);
+
+ if (tupleSeparatorIndex < 0)
+ {
+ m_log.WarnFormat("[OSPA RESOLVER]: Ignoring non-tuple component {0} in OSPA {1}", tuple, ospa);
+ continue;
+ }
+
+ string key = tuple.Remove(tupleSeparatorIndex).Trim();
+ string value = tuple.Substring(tupleSeparatorIndex + 1).Trim();
+
+ if (OSPA_NAME_KEY == key)
+ return ResolveOspaName(value, commsManager);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Resolve an OSPI name by querying existing persistent user profiles. If there is no persistent user profile
+ /// then a temporary user profile is inserted in the cache.
+ ///
+ ///
+ ///
+ ///
+ /// An OpenSim internal identifier for the name given. Returns null if the name was not valid
+ ///
+ protected static string ResolveOspaName(string name, CommunicationsManager commsManager)
+ {
+ int nameSeparatorIndex = name.IndexOf(OSPA_NAME_VALUE_SEPARATOR);
+
+ if (nameSeparatorIndex < 0)
+ {
+ m_log.WarnFormat("[OSPA RESOLVER]: Ignoring unseparated name {0}", name);
+ return null;
+ }
+
+ string firstName = name.Remove(nameSeparatorIndex).TrimEnd();
+ string lastName = name.Substring(nameSeparatorIndex + 1).TrimStart();
+
+ CachedUserInfo userInfo = commsManager.UserProfileCacheService.GetUserDetails(firstName, lastName);
+ if (userInfo != null)
+ return userInfo.UserProfile.ID.ToString();
+
+ UserProfileData tempUserProfile = new UserProfileData();
+ tempUserProfile.FirstName = firstName;
+ tempUserProfile.SurName = lastName;
+ tempUserProfile.ID = new UUID(Utils.MD5(Encoding.Unicode.GetBytes(tempUserProfile.Name)), 0);
+
+ commsManager.UserService.AddTemporaryUserProfile(tempUserProfile);
+
+ return tempUserProfile.ID.ToString();
+ }
+ }
+}
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index f1993b2279..cad259d4fe 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -373,7 +373,6 @@ namespace OpenSim.Framework
return SHA1.ComputeHash(Encoding.Default.GetBytes(src));
}
-
public static int fast_distance2d(int x, int y)
{
x = Math.Abs(x);
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
index 2ecb7d4e50..75e39d1cca 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
@@ -57,7 +57,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
///
private Stream m_loadStream;
- CommunicationsManager commsManager;
+ protected CommunicationsManager m_commsManager;
public InventoryArchiveReadRequest(
CachedUserInfo userInfo, string invPath, string loadPath, CommunicationsManager commsManager)
@@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
m_userInfo = userInfo;
m_invPath = invPath;
m_loadStream = loadStream;
- this.commsManager = commsManager;
+ m_commsManager = commsManager;
}
///
@@ -101,7 +101,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
//
// FIXME: FetchInventory should probably be assumed to by async anyway, since even standalones might
// use a remote inventory service, though this is vanishingly rare at the moment.
- if (null == commsManager.UserAdminService)
+ if (null == m_commsManager.UserAdminService)
{
m_log.ErrorFormat(
"[INVENTORY ARCHIVER]: Have not yet received inventory info for user {0} {1}",
@@ -156,7 +156,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
// Don't use the item ID that's in the file
item.ID = UUID.Random();
- item.CreatorId = m_userInfo.UserProfile.ID.ToString();
+ string ospResolvedId = OspResolver.Resolve(item.CreatorId, m_commsManager);
+ if (null != ospResolvedId)
+ item.CreatorId = ospResolvedId;
+
item.Owner = m_userInfo.UserProfile.ID;
// Reset folder ID to the one in which we want to load it
@@ -352,7 +355,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
asset.Type = assetType;
asset.Data = data;
- commsManager.AssetCache.AddAsset(asset);
+ m_commsManager.AssetCache.AddAsset(asset);
return true;
}
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
index 302d2145be..5ae1cbd83d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs
@@ -204,9 +204,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
string userFirstName = "Mr";
string userLastName = "Tiddles";
- string folderName = "a";
- string archiveFolderName
- = string.Format("{0}{1}{2}", folderName, ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR, UUID.Random());
+ UUID userUuid = UUID.Parse("00000000-0000-0000-0000-000000000555");
string itemName = "b.lsl";
string archiveItemName
= string.Format("{0}{1}{2}", itemName, "_", UUID.Random());
@@ -218,29 +216,33 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
item1.Name = itemName;
item1.AssetID = UUID.Random();
item1.GroupID = UUID.Random();
+ item1.CreatorId = userUuid.ToString();
+ //item1.CreatorId = "00000000-0000-0000-0000-000000000444";
+ item1.Owner = UUID.Parse(item1.CreatorId);
string item1FileName
- = string.Format("{0}{1}/{2}", ArchiveConstants.INVENTORY_PATH, archiveFolderName, archiveItemName);
+ = string.Format("{0}{1}", ArchiveConstants.INVENTORY_PATH, archiveItemName);
tar.WriteFile(item1FileName, UserInventoryItemSerializer.Serialize(item1));
tar.Close();
- MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
-
+ MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
SerialiserModule serialiserModule = new SerialiserModule();
InventoryArchiverModule archiverModule = new InventoryArchiverModule();
// Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene
Scene scene = SceneSetupHelpers.SetupScene();
SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
- scene.CommsManager.UserAdminService.AddUser(userFirstName, userLastName, "meowfood", String.Empty, 1000, 1000);
+ scene.CommsManager.UserAdminService.AddUser(
+ userFirstName, userLastName, "meowfood", String.Empty, 1000, 1000, userUuid);
archiverModule.DearchiveInventory(userFirstName, userLastName, "/", archiveReadStream);
- CachedUserInfo userInfo = scene.CommsManager.UserProfileCacheService.GetUserDetails(userFirstName, userLastName);
- InventoryFolderImpl foundFolder = userInfo.RootFolder.FindFolderByPath(folderName);
- Assert.That(foundFolder, Is.Not.Null, string.Format("Folder {0} not found on load", folderName));
+ CachedUserInfo userInfo
+ = scene.CommsManager.UserProfileCacheService.GetUserDetails(userFirstName, userLastName);
+ InventoryItemBase foundItem = userInfo.RootFolder.FindItemByPath(itemName);
- InventoryItemBase foundItem = foundFolder.FindItemByPath(itemName);
- Assert.That(foundItem, Is.Not.Null, string.Format("Item {0} not found on load", itemName));
+ // Currently, creator and ownership both revert to the loader
+ Assert.That(foundItem.CreatorId, Is.EqualTo(userUuid.ToString()));
+ Assert.That(foundItem.Owner, Is.EqualTo(userUuid));
Console.WriteLine("Finished TestLoadIarV0p1()");
}