Merge branch 'master' of ssh://3dhosting.de/var/git/careminster into ubitwork

UbitUmarov [2012-04-01 10:20:11]
Merge branch 'master' of ssh://3dhosting.de/var/git/careminster into ubitwork
Filename
CONTRIBUTORS.txt
OpenSim/Data/MSSQL/MSSQLManager.cs
OpenSim/Data/Null/NullFriendsData.cs
OpenSim/Data/Null/NullPresenceData.cs
OpenSim/Data/Tests/RegionTests.cs
OpenSim/Framework/ICallingCardModule.cs
OpenSim/Framework/IClientAPI.cs
OpenSim/Framework/LandData.cs
OpenSim/Framework/Servers/VersionInfo.cs
OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs
OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs
OpenSim/Region/Framework/Interfaces/ICallingCardModule.cs
OpenSim/Region/Framework/Interfaces/IFriendsModule.cs
OpenSim/Region/Framework/Scenes/EventManager.cs
OpenSim/Region/Framework/Scenes/Scene.cs
OpenSim/Region/Framework/Scenes/SceneGraph.cs
OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
OpenSim/Region/Framework/Scenes/ScenePresence.cs
OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs
OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
OpenSim/Services/Interfaces/IFriendsService.cs
OpenSim/Services/PresenceService/PresenceService.cs
OpenSim/Tests/Common/Helpers/SceneHelpers.cs
OpenSim/Tests/Common/Mock/TestClient.cs
bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config
bin/lib32/BulletSim.dll
bin/lib32/libBulletSim.so
bin/lib64/BulletSim.dll
bin/lib64/libBulletSim.so
bin/libBulletSim-x86_64.so
bin/libBulletSim.so
prebuild.xml
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt
index 089d2f5..287073b 100644
--- a/CONTRIBUTORS.txt
+++ b/CONTRIBUTORS.txt
@@ -71,6 +71,7 @@ what it is today.
 * CharlieO
 * ChrisDown
 * Chris Yeoh (IBM)
+* controlbreak
 * coyled
 * Daedius
 * Dong Jun Lan (IBM)
diff --git a/OpenSim/Data/MSSQL/MSSQLManager.cs b/OpenSim/Data/MSSQL/MSSQLManager.cs
index 575fd21..62c38d3 100644
--- a/OpenSim/Data/MSSQL/MSSQLManager.cs
+++ b/OpenSim/Data/MSSQL/MSSQLManager.cs
@@ -104,6 +104,11 @@ namespace OpenSim.Data.MSSQL
             {
                 return SqlDbType.BigInt;
             }
+            if (type == typeof(DateTime))
+            {
+                return SqlDbType.DateTime;
+            }
+
             return SqlDbType.VarChar;
         }

diff --git a/OpenSim/Data/Null/NullFriendsData.cs b/OpenSim/Data/Null/NullFriendsData.cs
index 0a4b242..473999f 100644
--- a/OpenSim/Data/Null/NullFriendsData.cs
+++ b/OpenSim/Data/Null/NullFriendsData.cs
@@ -28,6 +28,9 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.Reflection;
+using System.Threading;
+using log4net;
 using OpenMetaverse;
 using OpenSim.Framework;
 using OpenSim.Data;
@@ -36,12 +39,26 @@ namespace OpenSim.Data.Null
 {
     public class NullFriendsData : IFriendsData
     {
+//        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
         private static List<FriendsData> m_Data = new List<FriendsData>();

         public NullFriendsData(string connectionString, string realm)
         {
         }

+        /// <summary>
+        /// Clear all friends data
+        /// </summary>
+        /// <remarks>
+        /// This is required by unit tests to clear the static data between test runs.
+        /// </remarks>
+        public static void Clear()
+        {
+            lock (m_Data)
+                m_Data.Clear();
+        }
+
         public FriendsData[] GetFriends(UUID principalID)
         {
             return GetFriends(principalID.ToString());
@@ -56,20 +73,30 @@ namespace OpenSim.Data.Null
         /// <returns></returns>
         public FriendsData[] GetFriends(string userID)
         {
-            List<FriendsData> lst = m_Data.FindAll(fdata =>
+            lock (m_Data)
             {
-                return fdata.PrincipalID == userID.ToString();
-            });
-
-            if (lst != null)
-            {
-                lst.ForEach(f =>
+                List<FriendsData> lst = m_Data.FindAll(fdata =>
                 {
-                    FriendsData f2 = m_Data.Find(candidateF2 => f.Friend == candidateF2.PrincipalID);
-                    if (f2 != null) { f.Data["TheirFlags"] = f2.Data["Flags"]; }
+                    return fdata.PrincipalID == userID.ToString();
                 });
-
-                return lst.ToArray();
+
+                if (lst != null)
+                {
+                    lst.ForEach(f =>
+                    {
+                        FriendsData f2 = m_Data.Find(candidateF2 => f.Friend == candidateF2.PrincipalID);
+                        if (f2 != null)
+                            f.Data["TheirFlags"] = f2.Data["Flags"];
+
+    //                    m_log.DebugFormat(
+    //                        "[NULL FRIENDS DATA]: Got {0} {1} {2} for {3}",
+    //                        f.Friend, f.Data["Flags"], f2 != null ? f.Data["TheirFlags"] : "not found!", f.PrincipalID);
+                    });
+
+    //                m_log.DebugFormat("[NULL FRIENDS DATA]: Got {0} friends for {1}", lst.Count, userID);
+
+                    return lst.ToArray();
+                }
             }

             return new FriendsData[0];
@@ -80,7 +107,11 @@ namespace OpenSim.Data.Null
             if (data == null)
                 return false;

-            m_Data.Add(data);
+//            m_log.DebugFormat(
+//                "[NULL FRIENDS DATA]: Storing {0} {1} {2}", data.PrincipalID, data.Friend, data.Data["Flags"]);
+
+            lock (m_Data)
+                m_Data.Add(data);

             return true;
         }
@@ -92,14 +123,21 @@ namespace OpenSim.Data.Null

         public bool Delete(string userID, string friendID)
         {
-            List<FriendsData> lst = m_Data.FindAll(delegate(FriendsData fdata) { return fdata.PrincipalID == userID.ToString(); });
-            if (lst != null)
+            lock (m_Data)
             {
-                FriendsData friend = lst.Find(delegate(FriendsData fdata) { return fdata.Friend == friendID; });
-                if (friendID != null)
+                List<FriendsData> lst = m_Data.FindAll(delegate(FriendsData fdata) { return fdata.PrincipalID == userID.ToString(); });
+                if (lst != null)
                 {
-                    m_Data.Remove(friend);
-                    return true;
+                    FriendsData friend = lst.Find(delegate(FriendsData fdata) { return fdata.Friend == friendID; });
+                    if (friendID != null)
+                    {
+    //                    m_log.DebugFormat(
+    //                        "[NULL FRIENDS DATA]: Deleting friend {0} {1} for {2}",
+    //                        friend.Friend, friend.Data["Flags"], friend.PrincipalID);
+
+                        m_Data.Remove(friend);
+                        return true;
+                    }
                 }
             }

diff --git a/OpenSim/Data/Null/NullPresenceData.cs b/OpenSim/Data/Null/NullPresenceData.cs
index 91f1cc5..c06c223 100644
--- a/OpenSim/Data/Null/NullPresenceData.cs
+++ b/OpenSim/Data/Null/NullPresenceData.cs
@@ -110,7 +110,6 @@ namespace OpenSim.Data.Null
             return false;
         }

-
         public PresenceData[] Get(string field, string data)
         {
             if (Instance != this)
diff --git a/OpenSim/Data/Tests/RegionTests.cs b/OpenSim/Data/Tests/RegionTests.cs
index 1d806fc..1f03ec5 100644
--- a/OpenSim/Data/Tests/RegionTests.cs
+++ b/OpenSim/Data/Tests/RegionTests.cs
@@ -244,10 +244,10 @@ namespace OpenSim.Data.Tests
             SceneObjectPart[] newparts = newsog.Parts;
             Assert.That(newparts.Length,Is.EqualTo(4), "Assert.That(newparts.Length,Is.EqualTo(4))");

-            Assert.That(newsog.HasChildPrim(tmp0), "Assert.That(newsog.HasChildPrim(tmp0))");
-            Assert.That(newsog.HasChildPrim(tmp1), "Assert.That(newsog.HasChildPrim(tmp1))");
-            Assert.That(newsog.HasChildPrim(tmp2), "Assert.That(newsog.HasChildPrim(tmp2))");
-            Assert.That(newsog.HasChildPrim(tmp3), "Assert.That(newsog.HasChildPrim(tmp3))");
+            Assert.That(newsog.ContainsPart(tmp0), "Assert.That(newsog.ContainsPart(tmp0))");
+            Assert.That(newsog.ContainsPart(tmp1), "Assert.That(newsog.ContainsPart(tmp1))");
+            Assert.That(newsog.ContainsPart(tmp2), "Assert.That(newsog.ContainsPart(tmp2))");
+            Assert.That(newsog.ContainsPart(tmp3), "Assert.That(newsog.ContainsPart(tmp3))");
         }

         [Test]
diff --git a/OpenSim/Framework/ICallingCardModule.cs b/OpenSim/Framework/ICallingCardModule.cs
deleted file mode 100644
index 17e6de35..0000000
--- a/OpenSim/Framework/ICallingCardModule.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using OpenMetaverse;
-using OpenSim.Framework;
-
-namespace OpenSim.Framework
-{
-    public interface ICallingCardModule
-    {
-        UUID CreateCallingCard(UUID userID, UUID creatorID, UUID folderID);
-    }
-}
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 004b1a6..2be78da 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -301,9 +301,9 @@ namespace OpenSim.Framework
     public delegate void ConfirmXfer(IClientAPI remoteClient, ulong xferID, uint packetID);

     public delegate void FriendActionDelegate(
-        IClientAPI remoteClient, UUID agentID, UUID transactionID, List<UUID> callingCardFolders);
+        IClientAPI remoteClient, UUID transactionID, List<UUID> callingCardFolders);

-    public delegate void FriendshipTermination(IClientAPI remoteClient, UUID agentID, UUID ExID);
+    public delegate void FriendshipTermination(IClientAPI remoteClient, UUID ExID);

     public delegate void MoneyTransferRequest(
         UUID sourceID, UUID destID, int amount, int transactionType, string description);
@@ -464,7 +464,7 @@ namespace OpenSim.Framework
     public delegate void AvatarNotesUpdate(IClientAPI client, UUID targetID, string notes);
     public delegate void MuteListRequest(IClientAPI client, uint muteCRC);
     public delegate void AvatarInterestUpdate(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages);
-    public delegate void GrantUserFriendRights(IClientAPI client, UUID requester, UUID target, int rights);
+    public delegate void GrantUserFriendRights(IClientAPI client, UUID target, int rights);
     public delegate void PlacesQuery(UUID QueryID, UUID TransactionID, string QueryText, uint QueryFlags, byte Category, string SimName, IClientAPI client);

     public delegate void AgentFOV(IClientAPI client, float verticalAngle);
@@ -717,7 +717,7 @@ namespace OpenSim.Framework
         /// The scene agent for this client.  This will only be set if the client has an agent in a scene (i.e. if it
         /// is connected).
         /// </summary>
-        ISceneAgent SceneAgent { get; }
+        ISceneAgent SceneAgent { get; set; }

         UUID SessionId { get; }

diff --git a/OpenSim/Framework/LandData.cs b/OpenSim/Framework/LandData.cs
index 9a9a6bf..dcaa46d 100644
--- a/OpenSim/Framework/LandData.cs
+++ b/OpenSim/Framework/LandData.cs
@@ -69,7 +69,7 @@ namespace OpenSim.Framework
                                 (uint) ParcelFlags.AllowAPrimitiveEntry |
                                 (uint) ParcelFlags.AllowDeedToGroup |
                                 (uint) ParcelFlags.CreateObjects | (uint) ParcelFlags.AllowOtherScripts |
-                                (uint) ParcelFlags.SoundLocal;
+                                (uint) ParcelFlags.SoundLocal | (uint) ParcelFlags.AllowVoiceChat;

         private byte _landingType = 0;
         private string _name = "Your Parcel";
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
index 63ec257..016a174 100644
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ b/OpenSim/Framework/Servers/VersionInfo.cs
@@ -39,7 +39,8 @@ namespace OpenSim
             RC1,
             RC2,
             Release,
-            Post_Fixes
+            Post_Fixes,
+            Extended
         }

         public static string Version
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index d0920d2..3118613 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -396,7 +396,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             }
         }
         public UUID AgentId { get { return m_agentId; } }
-        public ISceneAgent SceneAgent { get; private set; }
+        public ISceneAgent SceneAgent { get; set; }
         public UUID ActiveGroupId { get { return m_activeGroupID; } }
         public string ActiveGroupName { get { return m_activeGroupName; } }
         public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } }
@@ -719,7 +719,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP

         public virtual void Start()
         {
-            SceneAgent = m_scene.AddNewClient(this, PresenceType.User);
+            m_scene.AddNewClient(this, PresenceType.User);

             RefreshGroupMembership();
         }
@@ -5913,7 +5913,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             // My guess is this is the folder to stick the calling card into
             List<UUID> callingCardFolders = new List<UUID>();

-            UUID agentID = afriendpack.AgentData.AgentID;
             UUID transactionID = afriendpack.TransactionBlock.TransactionID;

             for (int fi = 0; fi < afriendpack.FolderData.Length; fi++)
@@ -5924,10 +5923,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             FriendActionDelegate handlerApproveFriendRequest = OnApproveFriendRequest;
             if (handlerApproveFriendRequest != null)
             {
-                handlerApproveFriendRequest(this, agentID, transactionID, callingCardFolders);
+                handlerApproveFriendRequest(this, transactionID, callingCardFolders);
             }
-            return true;

+            return true;
         }

         private bool HandlerDeclineFriendship(IClientAPI sender, Packet Pack)
@@ -5946,7 +5945,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             if (OnDenyFriendRequest != null)
             {
                 OnDenyFriendRequest(this,
-                                    dfriendpack.AgentData.AgentID,
                                     dfriendpack.TransactionBlock.TransactionID,
                                     null);
             }
@@ -5966,14 +5964,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             }
             #endregion

-            UUID listOwnerAgentID = tfriendpack.AgentData.AgentID;
             UUID exFriendID = tfriendpack.ExBlock.OtherID;
             FriendshipTermination TerminateFriendshipHandler = OnTerminateFriendship;
             if (TerminateFriendshipHandler != null)
             {
-                TerminateFriendshipHandler(this, listOwnerAgentID, exFriendID);
+                TerminateFriendshipHandler(this, exFriendID);
                 return true;
             }
+
             return false;
         }

@@ -11378,12 +11376,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                     return true;
             }
             #endregion
+
             GrantUserFriendRights GrantUserRightsHandler = OnGrantUserRights;
             if (GrantUserRightsHandler != null)
                 GrantUserRightsHandler(this,
-                    GrantUserRights.AgentData.AgentID,
                     GrantUserRights.Rights[0].AgentRelated,
                     GrantUserRights.Rights[0].RelatedRights);
+
             return true;
         }

@@ -12455,7 +12454,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                 ItemData.Add(ItemDataMap);
             }

-            llsd.Add("ItemData", ItemData);
+            llsd.Add("InventoryData", ItemData);

             eq.Enqueue(BuildEvent("RemoveInventoryItem",
                     llsd), AgentId);
@@ -12499,6 +12498,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                     llsd), AgentId);
         }

+        private byte[] EncodeU32(uint val)
+        {
+            byte[] ret = BitConverter.GetBytes(val);
+            if (BitConverter.IsLittleEndian)
+                Array.Reverse(ret);
+            return ret;
+        }
+
         public void SendBulkUpdateInventory(InventoryFolderBase[] folders, InventoryItemBase[] items)
         {
             IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
@@ -12514,6 +12521,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             OSDMap AgentDataMap = new OSDMap(1);
             AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
             AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
+            AgentDataMap.Add("TransactionID", OSD.FromUUID(UUID.Random()));

             OSDArray AgentData = new OSDArray(1);
             AgentData.Add(AgentDataMap);
@@ -12541,10 +12549,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             foreach (InventoryItemBase item in items)
             {
                 OSDMap ItemDataMap = new OSDMap();
+
+                ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID));
+                ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder));
+
+                ItemDataMap.Add("CreatorID", OSD.FromUUID(item.CreatorIdAsUuid));
+                ItemDataMap.Add("OwnerID", OSD.FromUUID(item.Owner));
+                ItemDataMap.Add("GroupID", OSD.FromUUID(item.GroupID));
+                ItemDataMap.Add("BaseMask", OSD.FromBinary(EncodeU32((uint)item.BasePermissions)));
+                ItemDataMap.Add("OwnerMask", OSD.FromBinary(EncodeU32((uint)item.CurrentPermissions)));
+                ItemDataMap.Add("GroupMask", OSD.FromBinary(EncodeU32((uint)item.GroupPermissions)));
+                ItemDataMap.Add("EveryoneMask", OSD.FromBinary(EncodeU32((uint)item.EveryOnePermissions)));
+                ItemDataMap.Add("NextOwnerMask", OSD.FromBinary(EncodeU32((uint)item.NextPermissions)));
+                ItemDataMap.Add("GroupOwned", OSD.FromBoolean(item.GroupOwned));
+                ItemDataMap.Add("AssetID", OSD.FromUUID(item.AssetID));
+                ItemDataMap.Add("Type", OSD.FromInteger(item.AssetType));
+                ItemDataMap.Add("InvType", OSD.FromInteger(item.InvType));
+                ItemDataMap.Add("Flags", OSD.FromBinary(EncodeU32((uint)item.Flags)));
+                ItemDataMap.Add("SaleType", OSD.FromInteger((byte)item.SaleType));
+                ItemDataMap.Add("SalePrice", OSD.FromInteger(item.SalePrice));
+                ItemDataMap.Add("Name", OSD.FromString(item.Name));
+                ItemDataMap.Add("Description", OSD.FromString(item.Description));
+                ItemDataMap.Add("CreationDate", OSD.FromInteger(item.CreationDate));
+
+                ItemDataMap.Add("CRC", OSD.FromBinary(EncodeU32(
+                        Helpers.InventoryCRC(1000, 0, (sbyte)item.InvType,
+                        (sbyte)item.AssetType, item.AssetID,
+                        item.GroupID, 100,
+                        item.Owner, item.CreatorIdAsUuid,
+                        item.ID, item.Folder,
+                        (uint)PermissionMask.All, 1, (uint)PermissionMask.All, (uint)PermissionMask.All,
+                        (uint)PermissionMask.All)
+                )));
+                ItemDataMap.Add("CallbackID", 0);
+
                 ItemData.Add(ItemDataMap);
             }

             llsd.Add("ItemData", ItemData);
+
+            eq.Enqueue(BuildEvent("BulkUpdateInventory",
+                    llsd), AgentId);
         }
     }
 }
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
new file mode 100644
index 0000000..d942e87
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
@@ -0,0 +1,313 @@
+/*
+ * 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.Generic;
+using System.Reflection;
+using log4net;
+using Nini.Config;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
+using OpenSim.Services.Interfaces;
+using Mono.Addins;
+
+namespace OpenSim.Region.CoreModules.Avatar.Friends
+{
+    [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XCallingCard")]
+    public class CallingCardModule : ISharedRegionModule, ICallingCardModule
+    {
+        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+        protected List<Scene> m_Scenes = new List<Scene>();
+        protected bool m_Enabled = true;
+
+        public void Initialise(IConfigSource source)
+        {
+            IConfig ccConfig = source.Configs["XCallingCard"];
+            if (ccConfig != null)
+                m_Enabled = ccConfig.GetBoolean("Enabled", true);
+        }
+
+        public void AddRegion(Scene scene)
+        {
+            if (!m_Enabled)
+                return;
+
+            m_Scenes.Add(scene);
+
+            scene.RegisterModuleInterface<ICallingCardModule>(this);
+        }
+
+        public void RemoveRegion(Scene scene)
+        {
+            if (!m_Enabled)
+                return;
+
+            m_Scenes.Remove(scene);
+
+            scene.EventManager.OnNewClient -= OnNewClient;
+            scene.EventManager.OnIncomingInstantMessage +=
+                    OnIncomingInstantMessage;
+
+            scene.UnregisterModuleInterface<ICallingCardModule>(this);
+        }
+
+        public void RegionLoaded(Scene scene)
+        {
+            if (!m_Enabled)
+                return;
+            scene.EventManager.OnNewClient += OnNewClient;
+        }
+
+        public void PostInitialise()
+        {
+        }
+
+        public void Close()
+        {
+        }
+
+        public Type ReplaceableInterface
+        {
+            get { return null; }
+        }
+
+        public string Name
+        {
+            get { return "XCallingCardModule"; }
+        }
+
+        private void OnNewClient(IClientAPI client)
+        {
+            client.OnOfferCallingCard += OnOfferCallingCard;
+            client.OnAcceptCallingCard += OnAcceptCallingCard;
+            client.OnDeclineCallingCard += OnDeclineCallingCard;
+        }
+
+        private void OnOfferCallingCard(IClientAPI client, UUID destID, UUID transactionID)
+        {
+            ScenePresence sp = GetClientPresence(client.AgentId);
+            if (sp != null)
+            {
+                // If we're in god mode, we reverse the meaning. Offer
+                // calling card becomes "Take a calling card" for that
+                // person, no matter if they agree or not.
+                if (sp.GodLevel >= 200)
+                {
+                    CreateCallingCard(client.AgentId, destID, UUID.Zero, true);
+                    return;
+                }
+            }
+
+            IClientAPI dest = FindClientObject(destID);
+            if (dest != null)
+            {
+                DoCallingCardOffer(dest, client.AgentId);
+                return;
+            }
+
+            IMessageTransferModule transferModule =
+                    m_Scenes[0].RequestModuleInterface<IMessageTransferModule>();
+
+            if (transferModule != null)
+            {
+                transferModule.SendInstantMessage(new GridInstantMessage(
+                        client.Scene, client.AgentId,
+                        client.FirstName+" "+client.LastName,
+                        destID, (byte)211, false,
+                        String.Empty,
+                        transactionID, false, new Vector3(), new byte[0]),
+                        delegate(bool success) {} );
+            }
+        }
+
+        private void DoCallingCardOffer(IClientAPI dest, UUID from)
+        {
+            UUID itemID = CreateCallingCard(dest.AgentId, from, UUID.Zero, false);
+
+            dest.SendOfferCallingCard(from, itemID);
+        }
+
+        // Create a calling card in the user's inventory. This is called
+        // from direct calling card creation, when the offer is forwarded,
+        // and from the friends module when the friend is confirmed.
+        // Because of the latter, it will send a bulk inventory update
+        // if the receiving user is in the same simulator.
+        public UUID CreateCallingCard(UUID userID, UUID creatorID, UUID folderID)
+        {
+            return CreateCallingCard(userID, creatorID, folderID, false);
+        }
+
+        private UUID CreateCallingCard(UUID userID, UUID creatorID, UUID folderID, bool isGod)
+        {
+            IUserAccountService userv = m_Scenes[0].UserAccountService;
+            if (userv == null)
+                return UUID.Zero;
+
+            UserAccount info = userv.GetUserAccount(UUID.Zero, creatorID);
+            if (info == null)
+                return UUID.Zero;
+
+            IInventoryService inv = m_Scenes[0].InventoryService;
+            if (inv == null)
+                return UUID.Zero;
+
+            if (folderID == UUID.Zero)
+            {
+                InventoryFolderBase folder = inv.GetFolderForType(userID,
+                        AssetType.CallingCard);
+
+                if (folder == null) // Nowhere to put it
+                    return UUID.Zero;
+
+                folderID = folder.ID;
+            }
+
+            m_log.DebugFormat("[XCALLINGCARD]: Creating calling card for {0} in inventory of {1}", info.Name, userID);
+
+            InventoryItemBase item = new InventoryItemBase();
+            item.AssetID = UUID.Zero;
+            item.AssetType = (int)AssetType.CallingCard;
+            item.BasePermissions = (uint)(PermissionMask.Copy | PermissionMask.Modify);
+            if (isGod)
+                item.BasePermissions = (uint)(PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Move);
+
+            item.EveryOnePermissions = (uint)PermissionMask.None;
+            item.CurrentPermissions = item.BasePermissions;
+            item.NextPermissions = (uint)(PermissionMask.Copy | PermissionMask.Modify);
+
+            item.ID = UUID.Random();
+            item.CreatorId = creatorID.ToString();
+            item.Owner = userID;
+            item.GroupID = UUID.Zero;
+            item.GroupOwned = false;
+            item.Folder = folderID;
+
+            item.CreationDate = Util.UnixTimeSinceEpoch();
+            item.InvType = (int)InventoryType.CallingCard;
+            item.Flags = 0;
+
+            item.Name = info.Name;
+            item.Description = "";
+
+            item.SalePrice = 10;
+            item.SaleType = (byte)SaleType.Not;
+
+            inv.AddItem(item);
+
+            IClientAPI client = FindClientObject(userID);
+            if (client != null)
+                client.SendBulkUpdateInventory(item);
+
+            return item.ID;
+        }
+
+        private void OnAcceptCallingCard(IClientAPI client, UUID transactionID, UUID folderID)
+        {
+        }
+
+        private void OnDeclineCallingCard(IClientAPI client, UUID transactionID)
+        {
+            IInventoryService invService = m_Scenes[0].InventoryService;
+
+            InventoryFolderBase trashFolder =
+                    invService.GetFolderForType(client.AgentId, AssetType.TrashFolder);
+
+            InventoryItemBase item = new InventoryItemBase(transactionID, client.AgentId);
+            item = invService.GetItem(item);
+
+            if (item != null && trashFolder != null)
+            {
+                item.Folder = trashFolder.ID;
+                List<UUID> uuids = new List<UUID>();
+                uuids.Add(item.ID);
+                invService.DeleteItems(item.Owner, uuids);
+                m_Scenes[0].AddInventoryItem(client, item);
+            }
+        }
+
+        public IClientAPI FindClientObject(UUID agentID)
+        {
+            Scene scene = GetClientScene(agentID);
+            if (scene == null)
+                return null;
+
+            ScenePresence presence = scene.GetScenePresence(agentID);
+            if (presence == null)
+                return null;
+
+            return presence.ControllingClient;
+        }
+
+        private Scene GetClientScene(UUID agentId)
+        {
+            lock (m_Scenes)
+            {
+                foreach (Scene scene in m_Scenes)
+                {
+                    ScenePresence presence = scene.GetScenePresence(agentId);
+                    if (presence != null)
+                    {
+                        if (!presence.IsChildAgent)
+                            return scene;
+                    }
+                }
+            }
+            return null;
+        }
+
+        private ScenePresence GetClientPresence(UUID agentId)
+        {
+            lock (m_Scenes)
+            {
+                foreach (Scene scene in m_Scenes)
+                {
+                    ScenePresence presence = scene.GetScenePresence(agentId);
+                    if (presence != null)
+                    {
+                        if (!presence.IsChildAgent)
+                            return presence;
+                    }
+                }
+            }
+            return null;
+        }
+
+        private void OnIncomingInstantMessage(GridInstantMessage msg)
+        {
+            if (msg.dialog == (uint)211)
+            {
+                IClientAPI client = FindClientObject(new UUID(msg.toAgentID));
+                if (client == null)
+                    return;
+
+                DoCallingCardOffer(client, new UUID(msg.fromAgentID));
+            }
+        }
+    }
+}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 8e32fcc..f64c161 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -51,6 +51,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
 {
     public class FriendsModule : ISharedRegionModule, IFriendsModule
     {
+        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
         protected bool m_Enabled = false;

         protected class UserFriendData
@@ -72,7 +74,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
         }

         protected static readonly FriendInfo[] EMPTY_FRIENDS = new FriendInfo[0];
-        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

         protected List<Scene> m_Scenes = new List<Scene>();

@@ -109,7 +110,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             }
         }

-        protected IFriendsService FriendsService
+        public IFriendsService FriendsService
         {
             get
             {
@@ -156,7 +157,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                     InitModule(config);

                     m_Enabled = true;
-                    m_log.InfoFormat("[FRIENDS MODULE]: {0} enabled.", Name);
+                    m_log.DebugFormat("[FRIENDS MODULE]: {0} enabled.", Name);
                 }
             }
         }
@@ -201,7 +202,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             if (!m_Enabled)
                 return;

-            m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name);
+//            m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name);

             m_Scenes.Add(scene);
             scene.RegisterModuleInterface<IFriendsModule>(this);
@@ -212,14 +213,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             scene.EventManager.OnClientLogin += OnClientLogin;
         }

-        public virtual void RegionLoaded(Scene scene)
-        {
-            scene.AddCommand(
-                "Friends", this, "friends show cache",
-                "friends show cache [<first-name> <last-name>]",
-                "Show the friends cache for the given user",
-                HandleFriendsShowCacheCommand);
-        }
+        public virtual void RegionLoaded(Scene scene) {}

         public void RemoveRegion(Scene scene)
         {
@@ -241,13 +235,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends

         #endregion

-        public virtual uint GetFriendPerms(UUID principalID, UUID friendID)
+        public virtual int GetRightsGrantedByFriend(UUID principalID, UUID friendID)
         {
-            FriendInfo[] friends = GetFriends(principalID);
+            FriendInfo[] friends = GetFriendsFromCache(principalID);
             FriendInfo finfo = GetFriend(friends, friendID);
             if (finfo != null)
             {
-                return (uint)finfo.TheirFlags;
+                return finfo.TheirFlags;
             }

             return 0;
@@ -258,9 +252,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             client.OnInstantMessage += OnInstantMessage;
             client.OnApproveFriendRequest += OnApproveFriendRequest;
             client.OnDenyFriendRequest += OnDenyFriendRequest;
-            client.OnTerminateFriendship += (thisClient, agentID, exfriendID) => RemoveFriendship(thisClient, exfriendID);
-            client.OnGrantUserRights += OnGrantUserRights;
+            client.OnTerminateFriendship += RemoveFriendship;
+            client.OnGrantUserRights += GrantRights;

+            // We need to cache information for child agents as well as root agents so that friend edit/move/delete
+            // permissions will work across borders where both regions are on different simulators.
+            //
             // Do not do this asynchronously.  If we do, then subsequent code can outrace CacheFriends() and
             // return misleading results from the still empty friends cache.
             // If we absolutely need to do this asynchronously, then a signalling mechanism is needed so that calls
@@ -352,18 +349,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends

             // Send the friends online
             List<UUID> online = GetOnlineFriends(agentID);
-            if (online.Count > 0)
-            {
-                m_log.DebugFormat(
-                    "[FRIENDS MODULE]: User {0} in region {1} has {2} friends online",
-                    client.Name, client.Scene.RegionInfo.RegionName, online.Count);

+            if (online.Count > 0)
                 client.SendAgentOnline(online.ToArray());
-            }

             // Send outstanding friendship offers
             List<string> outstanding = new List<string>();
-            FriendInfo[] friends = GetFriends(agentID);
+            FriendInfo[] friends = GetFriendsFromCache(agentID);
             foreach (FriendInfo fi in friends)
             {
                 if (fi.TheirFlags == -1)
@@ -419,23 +411,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
         List<UUID> GetOnlineFriends(UUID userID)
         {
             List<string> friendList = new List<string>();
-            List<UUID> online = new List<UUID>();

-            FriendInfo[] friends = GetFriends(userID);
+            FriendInfo[] friends = GetFriendsFromCache(userID);
             foreach (FriendInfo fi in friends)
             {
-                if (((fi.TheirFlags & 1) != 0) && (fi.TheirFlags != -1))
+                if (((fi.TheirFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1))
                     friendList.Add(fi.Friend);
             }

+            List<UUID> online = new List<UUID>();
+
             if (friendList.Count > 0)
                 GetOnlineFriends(userID, friendList, online);

+//            m_log.DebugFormat(
+//                "[FRIENDS MODULE]: User {0} has {1} friends online", userID, online.Count);
+
             return online;
         }

         protected virtual void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
         {
+//            m_log.DebugFormat(
+//                "[FRIENDS MODULE]: Looking for online presence of {0} users for {1}", friendList.Count, userID);
+
             PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
             foreach (PresenceInfo pi in presence)
             {
@@ -486,13 +485,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
         /// <param name="online"></param>
         private void StatusChange(UUID agentID, bool online)
         {
-            FriendInfo[] friends = GetFriends(agentID);
+            FriendInfo[] friends = GetFriendsFromCache(agentID);
             if (friends.Length > 0)
             {
                 List<FriendInfo> friendList = new List<FriendInfo>();
                 foreach (FriendInfo fi in friends)
                 {
-                    if (((fi.MyFlags & 1) != 0) && (fi.TheirFlags != -1))
+                    if (((fi.MyFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1))
                         friendList.Add(fi);
                 }

@@ -558,7 +557,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                 m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2} ({3})", principalID, client.FirstName + client.LastName, friendID, im.fromAgentName);

                 // Check that the friendship doesn't exist yet
-                FriendInfo[] finfos = GetFriends(principalID);
+                FriendInfo[] finfos = GetFriendsFromCache(principalID);
                 if (finfos != null)
                 {
                     FriendInfo f = GetFriend(finfos, friendID);
@@ -611,7 +610,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             return (account == null) ? "Unknown" : account.FirstName + " " + account.LastName;
         }

-        protected virtual void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
+        protected virtual void OnApproveFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
         {
             m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", client.AgentId, friendID);

@@ -628,7 +627,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                 ccm.CreateCallingCard(client.AgentId, friendID, UUID.Zero);
             }

-            // Update the local cache
+            // Update the local cache.
             RecacheFriends(client);

             //
@@ -656,18 +655,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             }
         }

-        private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
+        private void OnDenyFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
         {
-            m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", agentID, friendID);
+            m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", client.AgentId, friendID);

-            DeleteFriendship(agentID, friendID);
+            DeleteFriendship(client.AgentId, friendID);

             //
             // Notify the friend
             //

             // Try local
-            if (LocalFriendshipDenied(agentID, client.Name, friendID))
+            if (LocalFriendshipDenied(client.AgentId, client.Name, friendID))
                 return;

             PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
@@ -678,7 +677,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                 {
                     GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
                     if (region != null)
-                        m_FriendsSimConnector.FriendshipDenied(region, agentID, client.Name, friendID);
+                        m_FriendsSimConnector.FriendshipDenied(region, client.AgentId, client.Name, friendID);
                     else
                         m_log.WarnFormat("[FRIENDS]: Could not find region {0} in locating {1}", friendSession.RegionID, friendID);
                 }
@@ -715,23 +714,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             }
         }

-        private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights)
+        public void GrantRights(IClientAPI remoteClient, UUID friendID, int rights)
         {
-            m_log.DebugFormat("[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}", requester, rights, target);
+            UUID requester = remoteClient.AgentId;

-            FriendInfo[] friends = GetFriends(remoteClient.AgentId);
+            m_log.DebugFormat(
+                "[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}",
+                requester, rights, friendID);
+
+            FriendInfo[] friends = GetFriendsFromCache(requester);
             if (friends.Length == 0)
             {
                 return;
             }

             // Let's find the friend in this user's friend list
-            FriendInfo friend = GetFriend(friends, target);
+            FriendInfo friend = GetFriend(friends, friendID);

             if (friend != null) // Found it
             {
                 // Store it on the DB
-                if (!StoreRights(requester, target, rights))
+                if (!StoreRights(requester, friendID, rights))
                 {
                     remoteClient.SendAlertMessage("Unable to grant rights.");
                     return;
@@ -742,17 +745,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                 friend.MyFlags = rights;

                 // Always send this back to the original client
-                remoteClient.SendChangeUserRights(requester, target, rights);
+                remoteClient.SendChangeUserRights(requester, friendID, rights);

                 //
                 // Notify the friend
                 //

                 // Try local
-                if (LocalGrantRights(requester, target, myFlags, rights))
+                if (LocalGrantRights(requester, friendID, myFlags, rights))
                     return;

-                PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { target.ToString() });
+                PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
                 if (friendSessions != null && friendSessions.Length > 0)
                 {
                     PresenceInfo friendSession = friendSessions[0];
@@ -761,12 +764,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                         GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
                         // TODO: You might want to send the delta to save the lookup
                         // on the other end!!
-                        m_FriendsSimConnector.GrantRights(region, requester, target, myFlags, rights);
+                        m_FriendsSimConnector.GrantRights(region, requester, friendID, myFlags, rights);
                     }
                 }
             }
             else
-                m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", target, requester);
+            {
+                m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", friendID, requester);
+            }
         }

         protected virtual FriendInfo GetFriend(FriendInfo[] friends, UUID friendID)
@@ -810,7 +815,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                     ccm.CreateCallingCard(friendID, userID, UUID.Zero);
                 }

-
                 // Update the local cache
                 RecacheFriends(friendClient);

@@ -904,20 +908,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
         #endregion

         #region Get / Set friends in several flavours
-        /// <summary>
-        /// Get friends from local cache only
-        /// </summary>
-        /// <param name="agentID"></param>
-        /// <returns>
-        /// An empty array if the user has no friends or friends have not been cached.
-        /// </returns>
-        protected FriendInfo[] GetFriends(UUID agentID)
+
+        public FriendInfo[] GetFriendsFromCache(UUID userID)
         {
             UserFriendData friendsData;

             lock (m_Friends)
             {
-                if (m_Friends.TryGetValue(agentID, out friendsData))
+                if (m_Friends.TryGetValue(userID, out friendsData))
                     return friendsData.Friends;
             }

@@ -935,13 +933,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             // Update local cache
             lock (m_Friends)
             {
-                FriendInfo[] friends = GetFriends(friendID);
+                FriendInfo[] friends = GetFriendsFromCache(friendID);
                 FriendInfo finfo = GetFriend(friends, userID);
                 finfo.TheirFlags = rights;
             }
         }

-        protected virtual FriendInfo[] GetFriendsFromService(IClientAPI client)
+        public virtual FriendInfo[] GetFriendsFromService(IClientAPI client)
         {
             return FriendsService.GetFriends(client.AgentId);
         }
@@ -959,12 +957,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             }
         }

-        /// <summary>
-        /// Are friends cached on this simulator for a particular user?
-        /// </summary>
-        /// <param name="userID"></param>
-        /// <returns></returns>
-        protected bool AreFriendsCached(UUID userID)
+        public bool AreFriendsCached(UUID userID)
         {
             lock (m_Friends)
                 return m_Friends.ContainsKey(userID);
@@ -983,8 +976,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends

         protected virtual void StoreFriendships(UUID agentID, UUID friendID)
         {
-            FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), 1);
-            FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 1);
+            FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), (int)FriendRights.CanSeeOnline);
+            FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), (int)FriendRights.CanSeeOnline);
         }

         protected virtual bool DeleteFriendship(UUID agentID, UUID exfriendID)
@@ -995,61 +988,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
         }

         #endregion
-
-        protected void HandleFriendsShowCacheCommand(string module, string[] cmd)
-        {
-            if (cmd.Length != 5)
-            {
-                MainConsole.Instance.OutputFormat("Usage: friends show cache [<first-name> <last-name>]");
-                return;
-            }
-
-            string firstName = cmd[3];
-            string lastName = cmd[4];
-
-            IUserManagement umModule = m_Scenes[0].RequestModuleInterface<IUserManagement>();
-            UUID userId = umModule.GetUserIdByName(firstName, lastName);
-
-//            UserAccount ua
-//                = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, firstName, lastName);
-
-            if (userId == UUID.Zero)
-            {
-                MainConsole.Instance.OutputFormat("No such user as {0} {1}", firstName, lastName);
-                return;
-            }
-
-            if (!AreFriendsCached(userId))
-            {
-                MainConsole.Instance.OutputFormat("No friends cached on this simulator for {0} {1}", firstName, lastName);
-                return;
-            }
-
-            MainConsole.Instance.OutputFormat("Cached friends for {0} {1}:", firstName, lastName);
-
-            MainConsole.Instance.OutputFormat("UUID\n");
-
-            FriendInfo[] friends = GetFriends(userId);
-
-            foreach (FriendInfo friend in friends)
-            {
-//                MainConsole.Instance.OutputFormat(friend.PrincipalID.ToString());
-
-//                string friendFirstName, friendLastName;
-//
-//                UserAccount friendUa
-//                    = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, friend.PrincipalID);
-
-                UUID friendId;
-                string friendName;
-
-                if (UUID.TryParse(friend.Friend, out friendId))
-                    friendName = umModule.GetUserName(friendId);
-                else
-                    friendName = friend.Friend;
-
-                MainConsole.Instance.OutputFormat("{0} {1} {2}", friendName, friend.MyFlags, friend.TheirFlags);
-            }
-        }
     }
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
index e50a84a..9a6d277 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
@@ -105,12 +105,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends

         #endregion

-        protected override void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
+        protected override void OnApproveFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
         {
             // Update the local cache. Yes, we need to do it right here
             // because the HGFriendsService placed something on the DB
             // from under the sim
-            base.OnApproveFriendRequest(client, agentID, friendID, callingCardFolders);
+            base.OnApproveFriendRequest(client, friendID, callingCardFolders);
         }

         protected override bool CacheFriends(IClientAPI client)
@@ -163,7 +163,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                     UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, client.AgentId);
                     if (account == null) // foreign
                     {
-                        FriendInfo[] friends = GetFriends(client.AgentId);
+                        FriendInfo[] friends = GetFriendsFromCache(client.AgentId);
                         foreach (FriendInfo f in friends)
                         {
                             client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, f.TheirFlags);
@@ -300,8 +300,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             return null;
         }

-
-        protected override FriendInfo[] GetFriendsFromService(IClientAPI client)
+        public override FriendInfo[] GetFriendsFromService(IClientAPI client)
         {
 //            m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name);
             Boolean agentIsLocal = true;
@@ -346,7 +345,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends

             if (agentIsLocal) // agent is local, friend is foreigner
             {
-                FriendInfo[] finfos = GetFriends(agentID);
+                FriendInfo[] finfos = GetFriendsFromCache(agentID);
                 FriendInfo finfo = GetFriend(finfos, friendID);
                 if (finfo != null)
                 {
@@ -453,7 +452,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                 bool confirming = false;
                 if (friendUUI == string.Empty)
                 {
-                    finfos = GetFriends(agentID);
+                    finfos = GetFriendsFromCache(agentID);
                     foreach (FriendInfo finfo in finfos)
                     {
                         if (finfo.TheirFlags == -1)
@@ -546,7 +545,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             // Delete any previous friendship relations
             FriendInfo[] finfos = null;
             FriendInfo f = null;
-            finfos = GetFriends(a1);
+            finfos = GetFriendsFromCache(a1);
             if (finfos != null)
             {
                 f = GetFriend(finfos, a2);
@@ -558,7 +557,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
                 }
             }

-            finfos = GetFriends(a2);
+            finfos = GetFriendsFromCache(a2);
             if (finfos != null)
             {
                 f = GetFriend(finfos, a1);
@@ -595,7 +594,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
             if (agentIsLocal) // agent is local, 'friend' is foreigner
             {
                 // We need to look for its information in the friends list itself
-                FriendInfo[] finfos = GetFriends(agentID);
+                FriendInfo[] finfos = GetFriendsFromCache(agentID);
                 FriendInfo finfo = GetFriend(finfos, exfriendID);
                 if (finfo != null)
                 {
@@ -639,7 +638,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
         private string GetUUI(UUID localUser, UUID foreignUser)
         {
             // Let's see if the user is here by any chance
-            FriendInfo[] finfos = GetFriends(localUser);
+            FriendInfo[] finfos = GetFriendsFromCache(localUser);
             if (finfos != EMPTY_FRIENDS) // friend is here, cool
             {
                 FriendInfo finfo = GetFriend(finfos, foreignUser);
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
index 682fbab..45b4264 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
@@ -30,6 +30,7 @@ using System.Collections.Generic;
 using Nini.Config;
 using NUnit.Framework;
 using OpenMetaverse;
+using OpenSim.Data.Null;
 using OpenSim.Framework;
 using OpenSim.Region.CoreModules.Avatar.Friends;
 using OpenSim.Region.Framework.Scenes;
@@ -44,9 +45,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
         private FriendsModule m_fm;
         private TestScene m_scene;

+        [TestFixtureSetUp]
+        public void FixtureInit()
+        {
+            // Don't allow tests to be bamboozled by asynchronous events.  Execute everything on the same thread.
+            Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
+        }
+
+        [TestFixtureTearDown]
+        public void TearDown()
+        {
+            // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
+            // threads.  Possibly, later tests should be rewritten so none of them require async stuff (which regression
+            // tests really shouldn't).
+            Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
+        }
+
         [SetUp]
         public void Init()
         {
+            // We must clear friends data between tests since Data.Null holds it in static properties.  This is necessary
+            // so that different services and simulator can share the data in standalone mode.  This is pretty horrible
+            // effectively the statics are global variables.
+            NullFriendsData.Clear();
+
             IConfigSource config = new IniConfigSource();
             config.AddConfig("Modules");
             // Not strictly necessary since FriendsModule assumes it is the default (!)
@@ -62,7 +84,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
         }

         [Test]
-        public void TestNoFriends()
+        public void TestLoginWithNoFriends()
         {
             TestHelpers.InMethod();
 //            log4net.Config.XmlConfigurator.Configure();
@@ -76,6 +98,76 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
         }

         [Test]
+        public void TestLoginWithOfflineFriends()
+        {
+            TestHelpers.InMethod();
+//            log4net.Config.XmlConfigurator.Configure();
+
+            UUID user1Id = TestHelpers.ParseTail(0x1);
+            UUID user2Id = TestHelpers.ParseTail(0x2);
+
+//            UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id);
+//            UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id);
+//
+//            m_fm.AddFriendship(user1Id, user2Id);
+
+            ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id);
+            ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id);
+
+            m_fm.AddFriendship(sp1.ControllingClient, user2Id);
+
+            // Not necessary for this test.  CanSeeOnline is automatically granted.
+//            m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline);
+
+            // We must logout from the client end so that the presence service is correctly updated by the presence
+            // detector.  This is listening to the OnConnectionClosed event on the client.
+            ((TestClient)sp1.ControllingClient).Logout();
+            ((TestClient)sp2.ControllingClient).Logout();
+//            m_scene.RemoveClient(sp1.UUID, true);
+//            m_scene.RemoveClient(sp2.UUID, true);
+
+            ScenePresence sp1Redux = SceneHelpers.AddScenePresence(m_scene, user1Id);
+
+            // We don't expect to receive notifications of offline friends on login, just online.
+            Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0));
+            Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(0));
+        }
+
+        [Test]
+        public void TestLoginWithOnlineFriends()
+        {
+            TestHelpers.InMethod();
+//            log4net.Config.XmlConfigurator.Configure();
+
+            UUID user1Id = TestHelpers.ParseTail(0x1);
+            UUID user2Id = TestHelpers.ParseTail(0x2);
+
+//            UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id);
+//            UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id);
+//
+//            m_fm.AddFriendship(user1Id, user2Id);
+
+            ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id);
+            ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id);
+
+            m_fm.AddFriendship(sp1.ControllingClient, user2Id);
+
+            // Not necessary for this test.  CanSeeOnline is automatically granted.
+//            m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline);
+
+            // We must logout from the client end so that the presence service is correctly updated by the presence
+            // detector.  This is listening to the OnConnectionClosed event on the client.
+//            ((TestClient)sp1.ControllingClient).Logout();
+            ((TestClient)sp2.ControllingClient).Logout();
+//            m_scene.RemoveClient(user2Id, true);
+
+            ScenePresence sp2Redux = SceneHelpers.AddScenePresence(m_scene, user2Id);
+
+            Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0));
+            Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(1));
+        }
+
+        [Test]
         public void TestAddFriendshipWhileOnline()
         {
             TestHelpers.InMethod();
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index aaba7fd..6fc8e4d 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -71,7 +71,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
                 if (name == Name)
                 {
                     InitialiseCommon(source);
-                    IConfig transferConfig = source.Configs["HGEntityTransfer"];
+                    IConfig transferConfig = source.Configs["HGEntityTransferModule"];
                     if (transferConfig != null)
                         m_RestrictInventoryAccessAbroad = transferConfig.GetBoolean("RestrictInventoryAccessAbroad", false);

@@ -94,6 +94,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
             client.OnTeleportHomeRequest += TriggerTeleportHome;
             client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
             client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
+            client.OnCompleteMovementToRegion += new Action<IClientAPI, bool>(OnCompleteMovementToRegion);
+        }
+
+        protected void OnCompleteMovementToRegion(IClientAPI client, bool arg2)
+        {
+            // HACK HACK -- just seeing how the viewer responds
+            // Let's send the Suitcase or the real root folder folder for incoming HG agents
+            // Visiting agents get their suitcase contents; incoming local users get their real root folder's content
+            m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: OnCompleteMovementToRegion of user {0}", client.AgentId);
+            object sp = null;
+            if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
+            {
+                if (sp is ScenePresence)
+                {
+                    AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
+                    if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
+                    {
+                        m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: ViaHGLogin");
+                        if (m_RestrictInventoryAccessAbroad)
+                        {
+                            RestoreRootFolderContents(client);
+                        }
+                    }
+                }
+            }
         }


@@ -105,6 +130,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
                 {
                     m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService);
                     m_Initialized = true;
+
+                    scene.AddCommand(
+                    "HG", this, "send inventory",
+                    "send inventory",
+                    "Don't use this",
+                    HandleSendInventory);
+
                 }

         }
@@ -374,7 +406,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
                     InventoryFolderBase root = m_Scenes[0].InventoryService.GetRootFolder(client.AgentId);
                     if (root != null)
                     {
-                        m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Removing root inventory");
+                        m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Removing root inventory for user {0}", client.AgentId);
                         InventoryCollection content = m_Scenes[0].InventoryService.GetFolderContent(client.AgentId, root.ID);
                         UUID[] ids = new UUID[content.Folders.Count];
                         int i = 0;
@@ -393,12 +425,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer

         private void RestoreRootFolderContents(IClientAPI client)
         {
-            // Restore the user's inventory, because we removed it earlier on
-            InventoryFolderBase root = m_Scenes[0].InventoryService.GetRootFolder(client.AgentId);
-            if (root != null)
+            if (client is IClientCore)
             {
-                m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Restoring root inventory");
-                client.SendBulkUpdateInventory(root);
+                IClientCore core = (IClientCore)client;
+                IClientInventory inv;
+
+                if (core.TryGet<IClientInventory>(out inv))
+                {
+                    InventoryFolderBase root = m_Scenes[0].InventoryService.GetRootFolder(client.AgentId);
+                    client.SendBulkUpdateInventory(root);
+                    //if (root != null)
+                    //{
+                    //    m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Restoring root inventory for user {0}", client.AgentId);
+                    //    InventoryCollection content = m_Scenes[0].InventoryService.GetFolderContent(client.AgentId, root.ID);
+                    //    m_log.DebugFormat("[XXX]: Folder name {0}, id {1}, parent {2}", root.Name, root.ID, root.ParentID);
+                    //    foreach (InventoryItemBase i in content.Items)
+                    //        m_log.DebugFormat("[XXX]:   Name={0}, folderID={1}", i.Name, i.Folder);
+
+                    //    inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray());
+                    //}
+                }
             }
         }

@@ -418,5 +464,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
             region.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), (int)0);
             return region;
         }
+
+        protected void HandleSendInventory(string module, string[] cmd)
+        {
+            m_Scenes[0].ForEachClient(delegate(IClientAPI client)
+            {
+                RestoreRootFolderContents(client);
+            });
+        }
+
     }
 }
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 192d55f..aa99692 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -966,6 +966,30 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
                 }
             }

+            int primcount = 0;
+            foreach (SceneObjectGroup g in objlist)
+                primcount += g.PrimCount;
+
+            if (!m_Scene.Permissions.CanRezObject(
+                primcount, remoteClient.AgentId, pos)
+                && !isAttachment)
+            {
+                // The client operates in no fail mode. It will
+                // have already removed the item from the folder
+                // if it's no copy.
+                // Put it back if it's not an attachment
+                //
+                if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment))
+                    remoteClient.SendBulkUpdateInventory(item);
+
+                ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y);
+                remoteClient.SendAlertMessage(string.Format(
+                    "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.",
+                    item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName));
+
+                return false;
+            }
+
             for (int i = 0; i < objlist.Count; i++)
             {
                 SceneObjectGroup so = objlist[i];
diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
index ef9b4e0..176c86d 100644
--- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
@@ -319,7 +319,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
                 // Send message to avatar
                 if (channel == 0)
                 {
-                    m_scene.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Owner, 0, pos, name, id, false);
+                    m_scene.SimChatBroadcast(Utils.StringToBytes(msg), ChatTypeEnum.Broadcast, 0, pos, name, id, false);
                 }

                 List<SceneObjectGroup> attachments = sp.GetAttachments();
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
index 6d3ace9..3b862da 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
@@ -93,8 +93,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
             if (config == null)
                 return;

-            int refreshminutes = Convert.ToInt32(config.GetString("RefreshTime"));
-            if (refreshminutes <= 0)
+            int refreshminutes = Convert.ToInt32(config.GetString("RefreshTime", "-1"));
+            if (refreshminutes < 0)
             {
                 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: No refresh time given in config. Module disabled.");
                 return;
@@ -117,12 +117,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
                 return;
             }

-            m_refreshTimer.Enabled = true;
-            m_refreshTimer.AutoReset = true;
-            m_refreshTimer.Interval = m_refreshtime;
-            m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
+            if (m_refreshtime > 0)
+            {
+                m_refreshTimer.Enabled = true;
+                m_refreshTimer.AutoReset = true;
+                m_refreshTimer.Interval = m_refreshtime;
+                m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
+            }

-            m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with refresh time {0}min and service object {1}",
+            m_log.InfoFormat("[MAP IMAGE SERVICE MODULE]: enabled with refresh time {0} min and service object {1}",
                              refreshminutes, service);

             m_enabled = true;
@@ -238,4 +241,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
index e2e383f..ccfbf78 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs
@@ -27,14 +27,12 @@
 using System;
 using System.Collections.Generic;
 using System.Reflection;
-
+using log4net;
+using OpenMetaverse;
 using OpenSim.Framework;
 using OpenSim.Region.Framework.Scenes;
 using OpenSim.Services.Interfaces;

-using OpenMetaverse;
-using log4net;
-
 namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
 {
     public class PresenceDetector
@@ -97,7 +95,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence
 //                m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName);
                 m_PresenceService.LogoutAgent(client.SessionId);
             }
-
         }
     }
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index 4a654a3..82ccaf8 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -487,7 +487,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions
             return false;
         }

-        protected bool IsFriendWithPerms(UUID user,UUID objectOwner)
+        protected bool IsFriendWithPerms(UUID user, UUID objectOwner)
         {
             if (user == UUID.Zero)
                 return false;
@@ -495,11 +495,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions
             if (m_friendsModule == null)
                 return false;

-            uint friendPerms = m_friendsModule.GetFriendPerms(user, objectOwner);
-            if ((friendPerms & (uint)FriendRights.CanModifyObjects) != 0)
-                return true;
-
-            return false;
+            int friendPerms = m_friendsModule.GetRightsGrantedByFriend(user, objectOwner);
+            return (friendPerms & (int)FriendRights.CanModifyObjects) != 0;
         }

         protected bool IsEstateManager(UUID user)
@@ -508,6 +505,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions

             return m_scene.RegionInfo.EstateSettings.IsEstateManager(user);
         }
+
 #endregion

         public bool PropagatePermissions()
diff --git a/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs
index ab8e1bf..f5f35bb 100644
--- a/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs
+++ b/OpenSim/Region/CoreModules/World/Vegetation/VegetationModule.cs
@@ -79,7 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Vegetation
             }

             SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
-            SceneObjectPart rootPart = sceneObject.GetChildPart(sceneObject.UUID);
+            SceneObjectPart rootPart = sceneObject.GetPart(sceneObject.UUID);

             // if grass or tree, make phantom
             //rootPart.TrimPermissions();
diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs
index 6163fd1..e6f2855 100644
--- a/OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs
@@ -64,6 +64,9 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
         private bool m_useAntiAliasing = false; // TODO: Make this a config option
         private bool m_Enabled = false;

+        private Bitmap lastImage = null;
+        private DateTime lastImageTime = DateTime.MinValue;
+
         #region IRegionModule Members

         public void Initialise(IConfigSource source)
@@ -86,14 +89,9 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap

             List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
             if (renderers.Count > 0)
-            {
-                m_primMesher = RenderingLoader.LoadRenderer(renderers[0]);
-                m_log.Info("[MAPTILE]: Loaded prim mesher " + m_primMesher.ToString());
-            }
+                m_log.Info("[MAPTILE]: Loaded prim mesher " + renderers[0]);
             else
-            {
                 m_log.Info("[MAPTILE]: No prim mesher loaded, prim rendering will be disabled");
-            }

             m_scene.RegisterModuleInterface<IMapImageGenerator>(this);
         }
@@ -126,9 +124,25 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap

         public Bitmap CreateMapTile()
         {
+            if ((DateTime.Now - lastImageTime).TotalSeconds < 3600)
+            {
+                return lastImage.Clone(new Rectangle(0, 0, 256, 256), lastImage.PixelFormat);
+            }
+
+            List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory());
+            if (renderers.Count > 0)
+            {
+                m_primMesher = RenderingLoader.LoadRenderer(renderers[0]);
+            }
+
             Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f);
             Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, (int)Constants.RegionSize, (int)Constants.RegionSize, (float)Constants.RegionSize, (float)Constants.RegionSize);
-            return CreateMapTile(viewport, false);
+            Bitmap tile = CreateMapTile(viewport, false);
+            m_primMesher = null;
+
+            lastImage = tile;
+            lastImageTime = DateTime.Now;
+            return lastImage.Clone(new Rectangle(0, 0, 256, 256), lastImage.PixelFormat);
         }

         public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures)
@@ -655,4 +669,4 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
             return result;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Region/Framework/Interfaces/ICallingCardModule.cs b/OpenSim/Region/Framework/Interfaces/ICallingCardModule.cs
new file mode 100644
index 0000000..69682ac
--- /dev/null
+++ b/OpenSim/Region/Framework/Interfaces/ICallingCardModule.cs
@@ -0,0 +1,40 @@
+/*
+ * 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.Generic;
+using System.Text;
+using OpenMetaverse;
+using OpenSim.Framework;
+
+namespace OpenSim.Framework
+{
+    public interface ICallingCardModule
+    {
+        UUID CreateCallingCard(UUID userID, UUID creatorID, UUID folderID);
+    }
+}
diff --git a/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs b/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs
index 061799e..7e87006 100644
--- a/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs
@@ -25,15 +25,32 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */

+using System.Collections.Generic;
 using OpenMetaverse;
 using OpenSim.Framework;
-using System.Collections.Generic;
+using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;

 namespace OpenSim.Region.Framework.Interfaces
 {
     public interface IFriendsModule
     {
         /// <summary>
+        /// Are friends cached on this simulator for a particular user?
+        /// </summary>
+        /// <param name="userID"></param>
+        /// <returns></returns>
+        bool AreFriendsCached(UUID userID);
+
+        /// <summary>
+        /// Get friends from local cache only
+        /// </summary>
+        /// <param name="userID"></param>
+        /// <returns>
+        /// An empty array if the user has no friends or friends have not been cached.
+        /// </returns>
+        FriendInfo[] GetFriendsFromCache(UUID userID);
+
+        /// <summary>
         /// Add a friendship between two users.
         /// </summary>
         /// <remarks>
@@ -55,7 +72,27 @@ namespace OpenSim.Region.Framework.Interfaces
         /// <param name="exFriendID"></param>
         void RemoveFriendship(IClientAPI client, UUID exFriendID);

-        uint GetFriendPerms(UUID PrincipalID, UUID FriendID);
+        /// <summary>
+        /// Get permissions granted by a friend.
+        /// </summary>
+        /// <param name="userID">The user.</param>
+        /// <param name="friendID">The friend that granted.</param>
+        /// <returns>The permissions.  These come from the FriendRights enum.</returns>
+        int GetRightsGrantedByFriend(UUID userID, UUID friendID);
+
+        /// <summary>
+        /// Grant permissions for a friend.
+        /// </summary>
+        /// <remarks>
+        /// This includes giving them the ability to see when the user is online and permission to edit the user's
+        /// objects.
+        /// Granting lower permissions than the friend currently has will rescind the extra permissions.
+        /// </remarks>
+        /// <param name="remoteClient">The user granting the permissions.</param>
+        /// <param name="friendID">The friend.</param>
+        /// <param name="perms">These come from the FriendRights enum.</param>
+        void GrantRights(IClientAPI remoteClient, UUID friendID, int perms);
+
         bool SendFriendsOnlineIfNeeded(IClientAPI client);
     }
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 470ce2e..741d233 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -75,6 +75,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// Triggered when a new client is added to the scene.
         /// </summary>
         /// <remarks>
+        /// This is triggered for both child and root agent client connections.
         /// Triggered before OnClientLogin.
         /// </remarks>
         public event OnNewClientDelegate OnNewClient;
@@ -195,7 +196,7 @@ namespace OpenSim.Region.Framework.Scenes
         public delegate void ClientClosed(UUID clientID, Scene scene);

         /// <summary>
-        /// Fired when a client is removed from a scene.
+        /// Fired when a client is removed from a scene whether it's a child or a root agent.
         /// </summary>
         /// <remarks>
         /// At the point of firing, the scene still contains the client's scene presence.
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index cac178d..539ca14 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1883,7 +1883,7 @@ namespace OpenSim.Region.Framework.Scenes
             {
                 AddRestoredSceneObject(group, true, true);
                 EventManager.TriggerOnSceneObjectLoaded(group);
-                SceneObjectPart rootPart = group.GetChildPart(group.UUID);
+                SceneObjectPart rootPart = group.GetPart(group.UUID);
                 rootPart.Flags &= ~PrimFlags.Scripted;
                 rootPart.TrimPermissions();

@@ -2031,10 +2031,16 @@ namespace OpenSim.Region.Framework.Scenes
             if (Permissions.CanRezObject(1, ownerID, pos))
             {
                 // rez ON the ground, not IN the ground
-               // pos.Z += 0.25F; The rez point should now be correct so that its not in the ground
+                // pos.Z += 0.25F; The rez point should now be correct so that its not in the ground

                 AddNewPrim(ownerID, groupID, pos, rot, shape);
             }
+            else
+            {
+                IClientAPI client = null;
+                if (TryGetClient(ownerID, out client))
+                    client.SendAlertMessage("You cannot create objects here.");
+            }
         }

         public virtual SceneObjectGroup AddNewPrim(
@@ -2795,6 +2801,10 @@ namespace OpenSim.Region.Framework.Scenes
                     sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName);
             }

+            // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
+            // client is for a root or child agent.
+            client.SceneAgent = sp;
+
             m_LastLogin = Util.EnvironmentTickCount();

             // Cache the user's name
@@ -4344,7 +4354,7 @@ namespace OpenSim.Region.Framework.Scenes
             {
                 if (ent is SceneObjectGroup)
                 {
-                    SceneObjectPart part = ((SceneObjectGroup)ent).GetChildPart(((SceneObjectGroup)ent).UUID);
+                    SceneObjectPart part = ((SceneObjectGroup)ent).GetPart(((SceneObjectGroup)ent).UUID);
                     if (part != null)
                     {
                         if (part.Name == cmdparams[2])
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index ccc3f32..9fdbc54 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -941,7 +941,7 @@ namespace OpenSim.Region.Framework.Scenes

             if (sog != null)
             {
-                if (sog.HasChildPrim(localID))
+                if (sog.ContainsPart(localID))
                 {
 //                    m_log.DebugFormat(
 //                        "[SCENE GRAPH]: Found scene object {0} {1} {2} containing part with local id {3} in {4}.  Returning.",
@@ -969,7 +969,7 @@ namespace OpenSim.Region.Framework.Scenes
                 if (ent is SceneObjectGroup)
                 {
                     sog = (SceneObjectGroup)ent;
-                    if (sog.HasChildPrim(localID))
+                    if (sog.ContainsPart(localID))
                     {
                         lock (SceneObjectGroupsByLocalPartID)
                             SceneObjectGroupsByLocalPartID[localID] = sog;
@@ -1007,7 +1007,7 @@ namespace OpenSim.Region.Framework.Scenes
                 if (ent is SceneObjectGroup)
                 {
                     sog = (SceneObjectGroup)ent;
-                    if (sog.HasChildPrim(fullID))
+                    if (sog.ContainsPart(fullID))
                     {
                         lock (SceneObjectGroupsByFullPartID)
                             SceneObjectGroupsByFullPartID[fullID] = sog;
@@ -1096,7 +1096,7 @@ namespace OpenSim.Region.Framework.Scenes
             SceneObjectGroup group = GetGroupByPrim(localID);
             if (group == null)
                 return null;
-            return group.GetChildPart(localID);
+            return group.GetPart(localID);
         }

         /// <summary>
@@ -1143,7 +1143,7 @@ namespace OpenSim.Region.Framework.Scenes
             SceneObjectGroup group = GetGroupByPrim(fullID);
             if (group == null)
                 return null;
-            return group.GetChildPart(fullID);
+            return group.GetPart(fullID);
         }

         /// <summary>
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
index f3660a5..2effa25 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -92,7 +92,7 @@ namespace OpenSim.Region.Framework.Scenes

             UUID newItemId = (copyItemID != UUID.Zero) ? copyItemID : item.ID;

-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 TaskInventoryItem taskItem = new TaskInventoryItem();
@@ -166,7 +166,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <returns>null if the item does not exist</returns>
         public TaskInventoryItem GetInventoryItem(uint primID, UUID itemID)
         {
-            SceneObjectPart part = GetChildPart(primID);
+            SceneObjectPart part = GetPart(primID);
             if (part != null)
             {
                 return part.Inventory.GetInventoryItem(itemID);
@@ -190,7 +190,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <returns>false if the item did not exist, true if the update occurred succesfully</returns>
         public bool UpdateInventoryItem(TaskInventoryItem item)
         {
-            SceneObjectPart part = GetChildPart(item.ParentPartID);
+            SceneObjectPart part = GetPart(item.ParentPartID);
             if (part != null)
             {
                 part.Inventory.UpdateInventoryItem(item);
@@ -210,7 +210,7 @@ namespace OpenSim.Region.Framework.Scenes

         public int RemoveInventoryItem(uint localID, UUID itemID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 int type = part.Inventory.RemoveInventoryItem(itemID);
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 90ad098..11fd721 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -412,6 +412,24 @@ namespace OpenSim.Region.Framework.Scenes
             return m_parts.ContainsKey(partID);
         }

+        /// <summary>
+        /// Does this group contain the given part?
+        /// should be able to remove these methods once we have a entity index in scene
+        /// </summary>
+        /// <param name="localID"></param>
+        /// <returns></returns>
+        public bool ContainsPart(uint localID)
+        {
+            SceneObjectPart[] parts = m_parts.GetArray();
+            for (int i = 0; i < parts.Length; i++)
+            {
+                if (parts[i].LocalId == localID)
+                    return true;
+            }
+
+            return false;
+        }
+
         /// <value>
         /// The root part of this scene object
         /// </value>
@@ -1636,7 +1654,7 @@ namespace OpenSim.Region.Framework.Scenes

         public UUID GetPartsFullID(uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 return part.UUID;
@@ -1652,7 +1670,7 @@ namespace OpenSim.Region.Framework.Scenes
             }
             else
             {
-                SceneObjectPart part = GetChildPart(localId);
+                SceneObjectPart part = GetPart(localId);
                 OnGrabPart(part, offsetPos, remoteClient);
             }
         }
@@ -2513,8 +2531,8 @@ namespace OpenSim.Region.Framework.Scenes
         /// Get a part with a given UUID
         /// </summary>
         /// <param name="primID"></param>
-        /// <returns>null if a child part with the primID was not found</returns>
-        public SceneObjectPart GetChildPart(UUID primID)
+        /// <returns>null if a part with the primID was not found</returns>
+        public SceneObjectPart GetPart(UUID primID)
         {
             SceneObjectPart childPart;
             m_parts.TryGetValue(primID, out childPart);
@@ -2525,8 +2543,8 @@ namespace OpenSim.Region.Framework.Scenes
         /// Get a part with a given local ID
         /// </summary>
         /// <param name="localID"></param>
-        /// <returns>null if a child part with the local ID was not found</returns>
-        public SceneObjectPart GetChildPart(uint localID)
+        /// <returns>null if a part with the local ID was not found</returns>
+        public SceneObjectPart GetPart(uint localID)
         {
             SceneObjectPart[] parts = m_parts.GetArray();
             for (int i = 0; i < parts.Length; i++)
@@ -2538,35 +2556,6 @@ namespace OpenSim.Region.Framework.Scenes
             return null;
         }

-        /// <summary>
-        /// Does this group contain the child prim
-        /// should be able to remove these methods once we have a entity index in scene
-        /// </summary>
-        /// <param name="primID"></param>
-        /// <returns></returns>
-        public bool HasChildPrim(UUID primID)
-        {
-            return m_parts.ContainsKey(primID);
-        }
-
-        /// <summary>
-        /// Does this group contain the child prim
-        /// should be able to remove these methods once we have a entity index in scene
-        /// </summary>
-        /// <param name="localID"></param>
-        /// <returns></returns>
-        public bool HasChildPrim(uint localID)
-        {
-            SceneObjectPart[] parts = m_parts.GetArray();
-            for (int i = 0; i < parts.Length; i++)
-            {
-                if (parts[i].LocalId == localID)
-                    return true;
-            }
-
-            return false;
-        }
-
         #endregion

         #region Packet Handlers
@@ -2720,7 +2709,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <returns>The object group of the newly delinked prim.  Null if part could not be found</returns>
         public SceneObjectGroup DelinkFromGroup(uint partID, bool sendEvents)
         {
-            SceneObjectPart linkPart = GetChildPart(partID);
+            SceneObjectPart linkPart = GetPart(partID);

             if (linkPart != null)
             {
@@ -3024,7 +3013,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <param name="localID"></param>
         public void SetPartName(string name, uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 part.Name = name;
@@ -3033,7 +3022,7 @@ namespace OpenSim.Region.Framework.Scenes

         public void SetPartDescription(string des, uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 part.Description = des;
@@ -3042,7 +3031,7 @@ namespace OpenSim.Region.Framework.Scenes

         public void SetPartText(string text, uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 part.SetText(text);
@@ -3051,7 +3040,7 @@ namespace OpenSim.Region.Framework.Scenes

         public void SetPartText(string text, UUID partID)
         {
-            SceneObjectPart part = GetChildPart(partID);
+            SceneObjectPart part = GetPart(partID);
             if (part != null)
             {
                 part.SetText(text);
@@ -3060,7 +3049,7 @@ namespace OpenSim.Region.Framework.Scenes

         public string GetPartName(uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 return part.Name;
@@ -3070,7 +3059,7 @@ namespace OpenSim.Region.Framework.Scenes

         public string GetPartDescription(uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 return part.Description;
@@ -3088,7 +3077,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <param name="SetVolumeDetect"></param>
         public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
         {
-            SceneObjectPart selectionPart = GetChildPart(localID);
+            SceneObjectPart selectionPart = GetPart(localID);

             if (SetTemporary && Scene != null)
             {
@@ -3148,7 +3137,7 @@ namespace OpenSim.Region.Framework.Scenes

         public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 part.UpdateExtraParam(type, inUse, data);
@@ -3173,7 +3162,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <param name="textureEntry"></param>
         public void UpdateTextureEntry(uint localID, byte[] textureEntry)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 part.UpdateTextureEntry(textureEntry);
@@ -3205,7 +3194,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <param name="shapeBlock"></param>
         public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 part.UpdateShape(shapeBlock);
@@ -3395,7 +3384,7 @@ namespace OpenSim.Region.Framework.Scenes

         public void UpdateSinglePosition(Vector3 pos, uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);

             if (part != null)
             {
@@ -3508,7 +3497,8 @@ namespace OpenSim.Region.Framework.Scenes
         /// <param name="localID"></param>
         public void UpdateSingleRotation(Quaternion rot, uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
+
             SceneObjectPart[] parts = m_parts.GetArray();

             if (part != null)
@@ -3537,7 +3527,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// <param name="localID"></param>
         public void UpdateSingleRotation(Quaternion rot, Vector3 pos, uint localID)
         {
-            SceneObjectPart part = GetChildPart(localID);
+            SceneObjectPart part = GetPart(localID);
             if (part != null)
             {
                 if (m_rootPart.PhysActor != null)
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
index ac44ce9..a2649ee 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -815,7 +815,7 @@ namespace OpenSim.Region.Framework.Scenes

             group.ResetIDs();

-            SceneObjectPart rootPart = group.GetChildPart(group.UUID);
+            SceneObjectPart rootPart = group.GetPart(group.UUID);

             // Since renaming the item in the inventory does not affect the name stored
             // in the serialization, transfer the correct name from the inventory to the
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index ee8a236..ed3a7f1 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1237,22 +1237,6 @@ namespace OpenSim.Region.Framework.Scenes
                     friendsModule.SendFriendsOnlineIfNeeded(ControllingClient);
             }

-            // HACK HACK -- just seeing how the viewer responds
-            // Let's send the Suitcase or the real root folder folder for incoming HG agents
-            // Visiting agents get their suitcase contents; incoming local users get their real root folder's content
-            AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(UUID);
-            if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
-            {
-                // HACK FOR NOW. JUST TESTING, SO KEEPING EVERYONE ELSE OUT OF THESE TESTS
-                IConfig config = m_scene.Config.Configs["HGEntityTransferModule"];
-                if (config != null && config.GetBoolean("RestrictInventoryAccessAbroad", false))
-                {
-                    m_log.DebugFormat("[SCENE]: Sending root folder to viewer...");
-                    InventoryFolderBase root = m_scene.InventoryService.GetRootFolder(client.AgentId);
-                    //InventoryCollection rootContents = InventoryService.GetFolderContent(client.AgentId, root.ID);
-                    client.SendBulkUpdateInventory(root);
-                }
-            }

 //            m_log.DebugFormat(
 //                "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 655f3a5..a37e997 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -55,7 +55,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server

         private UUID m_agentID = UUID.Random();

-        public ISceneAgent SceneAgent { get; private set; }
+        public ISceneAgent SceneAgent { get; set; }

         private string m_username;
         private string m_nick;
@@ -903,7 +903,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server

         public void Start()
         {
-            SceneAgent = m_scene.AddNewClient(this, PresenceType.User);
+            m_scene.AddNewClient(this, PresenceType.User);

             // Mimicking LLClientView which gets always set appearance from client.
             AvatarAppearance appearance;
diff --git a/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs
new file mode 100644
index 0000000..e68f9d0
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs
@@ -0,0 +1,189 @@
+/*
+ * 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.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using log4net;
+using Mono.Addins;
+using NDesk.Options;
+using Nini.Config;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Framework.Console;
+using OpenSim.Framework.Statistics;
+using OpenSim.Region.ClientStack.LindenUDP;
+using OpenSim.Region.CoreModules.Avatar.Friends;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
+using OpenSim.Services.Interfaces;
+using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
+
+namespace OpenSim.Region.OptionalModules.Avatar.Friends
+{
+    /// <summary>
+    /// A module that just holds commands for inspecting avatar appearance.
+    /// </summary>
+    [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FriendsCommandModule")]
+    public class FriendsCommandsModule : ISharedRegionModule
+    {
+//        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+        private Scene m_scene;
+        private IFriendsModule m_friendsModule;
+        private IUserManagement m_userManagementModule;
+
+//        private IAvatarFactoryModule m_avatarFactory;
+
+        public string Name { get { return "Appearance Information Module"; } }
+
+        public Type ReplaceableInterface { get { return null; } }
+
+        public void Initialise(IConfigSource source)
+        {
+//            m_log.DebugFormat("[FRIENDS COMMAND MODULE]: INITIALIZED MODULE");
+        }
+
+        public void PostInitialise()
+        {
+//            m_log.DebugFormat("[FRIENDS COMMAND MODULE]: POST INITIALIZED MODULE");
+        }
+
+        public void Close()
+        {
+//            m_log.DebugFormat("[FRIENDS COMMAND MODULE]: CLOSED MODULE");
+        }
+
+        public void AddRegion(Scene scene)
+        {
+//            m_log.DebugFormat("[FRIENDS COMMANDO MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
+        }
+
+        public void RemoveRegion(Scene scene)
+        {
+//            m_log.DebugFormat("[FRIENDS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
+        }
+
+        public void RegionLoaded(Scene scene)
+        {
+//            m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
+
+            if (m_scene == null)
+                m_scene = scene;
+
+            m_friendsModule = m_scene.RequestModuleInterface<IFriendsModule>();
+            m_userManagementModule = m_scene.RequestModuleInterface<IUserManagement>();
+
+            if (m_friendsModule != null && m_userManagementModule != null)
+            {
+                m_scene.AddCommand(
+                    "Friends", this, "friends show",
+                    "friends show [--cache] <first-name> <last-name>",
+                    "Show the friends for the given user if they exist.\n",
+                    "The --cache option will show locally cached information for that user.",
+                    HandleFriendsShowCommand);
+            }
+        }
+
+        protected void HandleFriendsShowCommand(string module, string[] cmd)
+        {
+            Dictionary<string, object> options = new Dictionary<string, object>();
+            OptionSet optionSet = new OptionSet().Add("c|cache", delegate (string v) { options["cache"] = v != null; });
+
+            List<string> mainParams = optionSet.Parse(cmd);
+
+            if (mainParams.Count != 4)
+            {
+                MainConsole.Instance.OutputFormat("Usage: friends show [--cache] <first-name> <last-name>");
+                return;
+            }
+
+            string firstName = mainParams[2];
+            string lastName = mainParams[3];
+
+            UUID userId = m_userManagementModule.GetUserIdByName(firstName, lastName);
+
+//            UserAccount ua
+//                = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, firstName, lastName);
+
+            if (userId == UUID.Zero)
+            {
+                MainConsole.Instance.OutputFormat("No such user as {0} {1}", firstName, lastName);
+                return;
+            }
+
+            FriendInfo[] friends;
+
+            if (options.ContainsKey("cache"))
+            {
+                if (!m_friendsModule.AreFriendsCached(userId))
+                {
+                    MainConsole.Instance.OutputFormat("No friends cached on this simulator for {0} {1}", firstName, lastName);
+                    return;
+                }
+                else
+                {
+                    friends = m_friendsModule.GetFriendsFromCache(userId);
+                }
+            }
+            else
+            {
+                // FIXME: We're forced to do this right now because IFriendsService has no region connectors.  We can't
+                // just expose FriendsModule.GetFriendsFromService() because it forces an IClientAPI requirement that
+                // can't currently be changed because of HGFriendsModule code that takes the scene from the client.
+                friends = ((FriendsModule)m_friendsModule).FriendsService.GetFriends(userId);
+            }
+
+            MainConsole.Instance.OutputFormat("Friends for {0} {1} {2}:", firstName, lastName, userId);
+
+            MainConsole.Instance.OutputFormat("UUID, Name, MyFlags, TheirFlags");
+
+            foreach (FriendInfo friend in friends)
+            {
+//                MainConsole.Instance.OutputFormat(friend.PrincipalID.ToString());
+
+//                string friendFirstName, friendLastName;
+//
+//                UserAccount friendUa
+//                    = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, friend.PrincipalID);
+
+                UUID friendId;
+                string friendName;
+
+                if (UUID.TryParse(friend.Friend, out friendId))
+                    friendName = m_userManagementModule.GetUserName(friendId);
+                else
+                    friendName = friend.Friend;
+
+                MainConsole.Instance.OutputFormat(
+                    "{0} {1} {2} {3}", friend.Friend, friendName, friend.MyFlags, friend.TheirFlags);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index a2375fe..c3335f0 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -72,7 +72,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
             get { return m_ownerID; }
         }

-        public ISceneAgent SceneAgent { get { throw new NotImplementedException(); } }
+        public ISceneAgent SceneAgent { get; set; }

         public void Say(string message)
         {
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
index a17eb41..51b0592 100644
--- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
+++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
@@ -510,7 +510,7 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
             }

             SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
-            SceneObjectPart rootPart = sceneObject.GetChildPart(sceneObject.UUID);
+            SceneObjectPart rootPart = sceneObject.GetPart(sceneObject.UUID);

             rootPart.AddFlag(PrimFlags.Phantom);

diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 4d7c40e..ce05b8c 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -4214,7 +4214,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
             World.ForEachRootScenePresence(delegate(ScenePresence presence)
             {
                 SceneObjectPart sitPart = presence.ParentPart;
-                if (sitPart != null && m_host.ParentGroup.HasChildPrim(sitPart.LocalId))
+                if (sitPart != null && m_host.ParentGroup.ContainsPart(sitPart.LocalId))
                     nametable.Add(presence.ControllingClient.Name);
             });

@@ -4680,12 +4680,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
                     // agent must not be a god
                     if (presence.GodLevel >= 200) return;

+                    if (simname == String.Empty)
+                        simname = World.RegionInfo.RegionName;
+
                     // agent must be over the owners land
                     if (m_host.OwnerID == World.LandChannel.GetLandObject(
                             presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
                     {
                         World.RequestTeleportLocation(presence.ControllingClient, simname, new Vector3((float)pos.x, (float)pos.y, (float)pos.z), new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z), (uint)TeleportFlags.ViaLocation);
                     }
+                    else // or must be wearing the prim
+                    {
+                        if (m_host.ParentGroup.AttachmentPoint != 0 && m_host.OwnerID == presence.UUID)
+                        {
+                            World.RequestTeleportLocation(presence.ControllingClient, simname, new Vector3((float)pos.x, (float)pos.y, (float)pos.z), new Vector3((float)lookAt.x, (float)lookAt.y, (float)lookAt.z), (uint)TeleportFlags.ViaLocation);
+                        }
+                    }
                 }
             }
         }
diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
new file mode 100644
index 0000000..cb686e2
--- /dev/null
+++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
@@ -0,0 +1,466 @@
+/*
+ * 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.Generic;
+using System.Linq;
+using OpenMetaverse;
+using log4net;
+using Nini.Config;
+using System.Reflection;
+using OpenSim.Services.Base;
+using OpenSim.Services.Interfaces;
+using OpenSim.Services.InventoryService;
+using OpenSim.Data;
+using OpenSim.Framework;
+using OpenSim.Server.Base;
+
+namespace OpenSim.Services.HypergridService
+{
+    /// <summary>
+    /// Hypergrid inventory service. It serves the IInventoryService interface,
+    /// but implements it in ways that are appropriate for inter-grid
+    /// inventory exchanges. Specifically, it does not performs deletions
+    /// and it responds to GetRootFolder requests with the ID of the
+    /// Suitcase folder, not the actual "My Inventory" folder.
+    /// </summary>
+    public class HGSuitcaseInventoryService : XInventoryService, IInventoryService
+    {
+        private static readonly ILog m_log =
+                LogManager.GetLogger(
+                MethodBase.GetCurrentMethod().DeclaringType);
+
+        private string m_HomeURL;
+        private IUserAccountService m_UserAccountService;
+
+        private UserAccountCache m_Cache;
+
+        private ExpiringCache<UUID, List<XInventoryFolder>> m_SuitcaseTrees = new ExpiringCache<UUID,List<XInventoryFolder>>();
+
+        public HGSuitcaseInventoryService(IConfigSource config, string configName)
+            : base(config, configName)
+        {
+            m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Starting with config name {0}", configName);
+            if (configName != string.Empty)
+                m_ConfigName = configName;
+
+            if (m_Database == null)
+                m_log.WarnFormat("[XXX]: m_Database is null!");
+
+            //
+            // Try reading the [InventoryService] section, if it exists
+            //
+            IConfig invConfig = config.Configs[m_ConfigName];
+            if (invConfig != null)
+            {
+                // realm = authConfig.GetString("Realm", realm);
+                string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty);
+                if (userAccountsDll == string.Empty)
+                    throw new Exception("Please specify UserAccountsService in HGInventoryService configuration");
+
+                Object[] args = new Object[] { config };
+                m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args);
+                if (m_UserAccountService == null)
+                    throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll));
+
+                // legacy configuration [obsolete]
+                m_HomeURL = invConfig.GetString("ProfileServerURI", string.Empty);
+                // Preferred
+                m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL);
+
+                m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService);
+            }
+
+            m_log.Debug("[HG SUITCASE INVENTORY SERVICE]: Starting...");
+        }
+
+        public override bool CreateUserInventory(UUID principalID)
+        {
+            // NOGO
+            return false;
+        }
+
+
+        public override List<InventoryFolderBase> GetInventorySkeleton(UUID principalID)
+        {
+            // NOGO for this inventory service
+            return new List<InventoryFolderBase>();
+        }
+
+        public override InventoryFolderBase GetRootFolder(UUID principalID)
+        {
+            m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetRootFolder for {0}", principalID);
+            if (m_Database == null)
+                m_log.ErrorFormat("[XXX]: m_Database is NULL!");
+
+            // Let's find out the local root folder
+            XInventoryFolder root = GetRootXFolder(principalID); ;
+            if (root == null)
+            {
+                m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to retrieve local root folder for user {0}", principalID);
+            }
+
+            // Warp! Root folder for travelers is the suitcase folder
+            XInventoryFolder suitcase = GetSuitcaseXFolder(principalID);
+
+            if (suitcase == null)
+            {
+                m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder. Creating it...", principalID);
+                // make one, and let's add it to the user's inventory as a direct child of the root folder
+                suitcase = CreateFolder(principalID, root.folderID, 100, "My Suitcase");
+                if (suitcase == null)
+                    m_log.ErrorFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to create suitcase folder");
+
+                m_Database.StoreFolder(suitcase);
+            }
+
+            // Now let's change the folder ID to match that of the real root folder
+            SetAsRootFolder(suitcase, root.folderID);
+
+            return ConvertToOpenSim(suitcase);
+        }
+
+        public override InventoryFolderBase GetFolderForType(UUID principalID, AssetType type)
+        {
+            //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type);
+            return GetRootFolder(principalID);
+        }
+
+        public override InventoryCollection GetFolderContent(UUID principalID, UUID folderID)
+        {
+            InventoryCollection coll = null;
+            XInventoryFolder suitcase = GetSuitcaseXFolder(principalID);
+            XInventoryFolder root = GetRootXFolder(principalID);
+
+            if (!IsWithinSuitcaseTree(folderID, root, suitcase))
+                return new InventoryCollection();
+
+            if (folderID == root.folderID) // someone's asking for the root folder, we'll give them the suitcase
+            {
+                if (suitcase != null)
+                {
+                    coll = base.GetFolderContent(principalID, suitcase.folderID);
+                    foreach (InventoryFolderBase f in coll.Folders)
+                        f.ParentID = root.folderID;
+                    foreach (InventoryItemBase i in coll.Items)
+                        i.Folder = root.folderID;
+                    m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderContent for root folder returned content for suitcase folder");
+                }
+            }
+            else
+            {
+                coll = base.GetFolderContent(principalID, folderID);
+                m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetFolderContent for non-root folder {0}", folderID);
+            }
+            if (coll == null)
+            {
+                m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Something wrong with user {0}'s suitcase folder", principalID);
+                coll = new InventoryCollection();
+            }
+            return coll;
+        }
+
+        public override List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
+        {
+            // Let's do a bit of sanity checking, more than the base service does
+            // make sure the given folder exists under the suitcase tree of this user
+            XInventoryFolder root = GetRootXFolder(principalID);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(principalID);
+
+            if (!IsWithinSuitcaseTree(folderID, root, suitcase))
+                return new List<InventoryItemBase>();
+
+            return base.GetFolderItems(principalID, folderID);
+        }
+
+        public override bool AddFolder(InventoryFolderBase folder)
+        {
+            // Let's do a bit of sanity checking, more than the base service does
+            // make sure the given folder's parent folder exists under the suitcase tree of this user
+            XInventoryFolder root = GetRootXFolder(folder.Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner);
+
+            if (!IsWithinSuitcaseTree(folder.ParentID, root, suitcase))
+                return false;
+
+            // OK, it's legit
+            // Check if it's under the Root folder directly
+            if (folder.ParentID == root.folderID)
+            {
+                // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead
+                m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder for root folder for user {0}. Adding in suitcase instead", folder.Owner);
+                folder.ParentID = suitcase.folderID;
+            }
+
+            return base.AddFolder(folder);
+       }
+
+        public bool UpdateFolder(InventoryFolderBase folder)
+        {
+            XInventoryFolder root = GetRootXFolder(folder.Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner);
+
+            if (!IsWithinSuitcaseTree(folder.ID, root, suitcase))
+                return false;
+
+            return base.UpdateFolder(folder);
+        }
+
+        public override bool MoveFolder(InventoryFolderBase folder)
+        {
+            XInventoryFolder root = GetRootXFolder(folder.Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner);
+
+            if (!IsWithinSuitcaseTree(folder.ID, root, suitcase) || !IsWithinSuitcaseTree(folder.ParentID, root, suitcase))
+                return false;
+
+            if (folder.ParentID == root.folderID)
+            {
+                // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead
+                m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveFolder to root folder for user {0}. Moving it to suitcase instead", folder.Owner);
+                folder.ParentID = suitcase.folderID;
+            }
+
+            return base.MoveFolder(folder);
+        }
+
+        public override bool DeleteFolders(UUID principalID, List<UUID> folderIDs)
+        {
+            // NOGO
+            return false;
+        }
+
+        public override bool PurgeFolder(InventoryFolderBase folder)
+        {
+            // NOGO
+            return false;
+        }
+
+        public override bool AddItem(InventoryItemBase item)
+        {
+            // Let's do a bit of sanity checking, more than the base service does
+            // make sure the given folder's parent folder exists under the suitcase tree of this user
+            XInventoryFolder root = GetRootXFolder(item.Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(item.Owner);
+
+            if (!IsWithinSuitcaseTree(item.Folder, root, suitcase))
+                return false;
+
+            // OK, it's legit
+            // Check if it's under the Root folder directly
+            if (item.Folder == root.folderID)
+            {
+                // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead
+                m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: AddItem for root folder for user {0}. Adding in suitcase instead", item.Owner);
+                item.Folder = suitcase.folderID;
+            }
+
+            return base.AddItem(item);
+
+        }
+
+        public override bool UpdateItem(InventoryItemBase item)
+        {
+            XInventoryFolder root = GetRootXFolder(item.Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(item.Owner);
+
+            if (!IsWithinSuitcaseTree(item.Folder, root, suitcase))
+                return false;
+
+            return base.UpdateItem(item);
+        }
+
+        public override bool MoveItems(UUID principalID, List<InventoryItemBase> items)
+        {
+            // Principal is b0rked. *sigh*
+
+            XInventoryFolder root = GetRootXFolder(items[0].Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(items[0].Owner);
+
+            if (!IsWithinSuitcaseTree(items[0].Folder, root, suitcase))
+                return false;
+
+            foreach (InventoryItemBase it in items)
+                if (it.Folder == root.folderID)
+                {
+                    // someone's trying to add a subfolder of the root folder, we'll add it to the suitcase instead
+                    m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: MoveItem to root folder for user {0}. Moving it to suitcase instead", it.Owner);
+                    it.Folder = suitcase.folderID;
+                }
+
+            return base.MoveItems(principalID, items);
+
+        }
+
+        // Let these pass. Use inherited methods.
+        public override bool DeleteItems(UUID principalID, List<UUID> itemIDs)
+        {
+            return false;
+        }
+
+        public override InventoryItemBase GetItem(InventoryItemBase item)
+        {
+            InventoryItemBase it = base.GetItem(item);
+            XInventoryFolder root = GetRootXFolder(it.Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(it.Owner);
+
+            if (it != null)
+            {
+                if (!IsWithinSuitcaseTree(it.Folder, root, suitcase))
+                    return null;
+
+                if (it.Folder == suitcase.folderID)
+                    it.Folder = root.folderID;
+
+                //    UserAccount user = m_Cache.GetUser(it.CreatorId);
+
+                //    // Adjust the creator data
+                //    if (user != null && it != null && (it.CreatorData == null || it.CreatorData == string.Empty))
+                //        it.CreatorData = m_HomeURL + ";" + user.FirstName + " " + user.LastName;
+                //}
+            }
+
+            return it;
+        }
+
+        public override InventoryFolderBase GetFolder(InventoryFolderBase folder)
+        {
+            InventoryFolderBase f = base.GetFolder(folder);
+            XInventoryFolder root = GetRootXFolder(f.Owner);
+            XInventoryFolder suitcase = GetSuitcaseXFolder(f.Owner);
+
+            if (f != null)
+            {
+                if (!IsWithinSuitcaseTree(f.ID, root, suitcase))
+                    return null;
+
+                if (f.ParentID == suitcase.folderID)
+                    f.ParentID = root.folderID;
+            }
+
+            return f;
+        }
+
+        //public List<InventoryItemBase> GetActiveGestures(UUID principalID)
+        //{
+        //}
+
+        //public int GetAssetPermissions(UUID principalID, UUID assetID)
+        //{
+        //}
+
+        #region Auxiliary functions
+        private XInventoryFolder GetXFolder(UUID userID, UUID folderID)
+        {
+            XInventoryFolder[] folders = m_Database.GetFolders(
+                    new string[] { "agentID", "folderID" },
+                    new string[] { userID.ToString(), folderID.ToString() });
+
+            if (folders.Length == 0)
+                return null;
+
+            return folders[0];
+        }
+
+        private XInventoryFolder GetRootXFolder(UUID principalID)
+        {
+            XInventoryFolder[] folders = m_Database.GetFolders(
+                new string[] { "agentID", "folderName", "type" },
+                new string[] { principalID.ToString(), "My Inventory", ((int)AssetType.RootFolder).ToString() });
+
+            if (folders != null && folders.Length > 0)
+                return folders[0];
+            return null;
+        }
+
+        private XInventoryFolder GetSuitcaseXFolder(UUID principalID)
+        {
+            // Warp! Root folder for travelers
+            XInventoryFolder[] folders = m_Database.GetFolders(
+                    new string[] { "agentID", "type" },
+                    new string[] { principalID.ToString(), "100" }); // This is a special folder type...
+
+            if (folders != null && folders.Length > 0)
+                return folders[0];
+            return null;
+        }
+
+        private void SetAsRootFolder(XInventoryFolder suitcase, UUID rootID)
+        {
+            suitcase.folderID = rootID;
+            suitcase.parentFolderID = UUID.Zero;
+        }
+
+        private List<XInventoryFolder> GetFolderTree(UUID root)
+        {
+            List<XInventoryFolder> t = null;
+            if (m_SuitcaseTrees.TryGetValue(root, out t))
+                return t;
+
+            t = GetFolderTreeRecursive(root);
+            m_SuitcaseTrees.AddOrUpdate(root, t, 120);
+            return t;
+        }
+
+        private List<XInventoryFolder> GetFolderTreeRecursive(UUID root)
+        {
+            List<XInventoryFolder> tree = new List<XInventoryFolder>();
+            XInventoryFolder[] folders = m_Database.GetFolders(
+                    new string[] { "parentFolderID" },
+                    new string[] { root.ToString() });
+
+            if (folders == null || (folders != null && folders.Length == 0))
+                return tree; // empty tree
+            else
+            {
+                foreach (XInventoryFolder f in folders)
+                {
+                    tree.Add(f);
+                    tree.AddRange(GetFolderTreeRecursive(f.folderID));
+                }
+                return tree;
+            }
+
+        }
+
+        private bool IsWithinSuitcaseTree(UUID folderID, XInventoryFolder root, XInventoryFolder suitcase)
+        {
+            List<XInventoryFolder> tree = new List<XInventoryFolder>();
+            tree.Add(root); // Warp! the tree is the real root folder plus the children of the suitcase folder
+            tree.AddRange(GetFolderTree(suitcase.folderID));
+            XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl)
+            {
+                if (fl.folderID == folderID) return true;
+                else return false;
+            });
+
+            if (f == null) return false;
+            else return true;
+        }
+        #endregion
+    }
+}
diff --git a/OpenSim/Services/Interfaces/IFriendsService.cs b/OpenSim/Services/Interfaces/IFriendsService.cs
index 1664f3b..d0d3b10 100644
--- a/OpenSim/Services/Interfaces/IFriendsService.cs
+++ b/OpenSim/Services/Interfaces/IFriendsService.cs
@@ -36,7 +36,15 @@ namespace OpenSim.Services.Interfaces
     {
         public UUID PrincipalID;
         public string Friend;
+
+        /// <summary>
+        /// The permissions that this user has granted to the friend.
+        /// </summary>
         public int MyFlags;
+
+        /// <summary>
+        /// The permissions that the friend has granted to this user.
+        /// </summary>
         public int TheirFlags;

         public FriendInfo()
@@ -51,7 +59,7 @@ namespace OpenSim.Services.Interfaces
             Friend = string.Empty;
             if (kvp.ContainsKey("Friend") && kvp["Friend"] != null)
                 Friend = kvp["Friend"].ToString();
-            MyFlags = 0;
+            MyFlags = (int)FriendRights.None;
             if (kvp.ContainsKey("MyFlags") && kvp["MyFlags"] != null)
                 Int32.TryParse(kvp["MyFlags"].ToString(), out MyFlags);
             TheirFlags = 0;
diff --git a/OpenSim/Services/PresenceService/PresenceService.cs b/OpenSim/Services/PresenceService/PresenceService.cs
index c8ac38e..ed2703e 100644
--- a/OpenSim/Services/PresenceService/PresenceService.cs
+++ b/OpenSim/Services/PresenceService/PresenceService.cs
@@ -151,11 +151,12 @@ namespace OpenSim.Services.PresenceService

                     info.Add(ret);
                 }
+
+//                m_log.DebugFormat(
+//                    "[PRESENCE SERVICE]: GetAgents for {0} found {1} presences", userIDStr, data.Length);
             }

-            // m_log.DebugFormat("[PRESENCE SERVICE]: GetAgents for {0} userIDs found {1} presences", userIDs.Length, info.Count);
             return info.ToArray();
         }
-
     }
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
index 7bf08ae..318758d 100644
--- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs
@@ -369,8 +369,11 @@ namespace OpenSim.Tests.Common
             agentData.AgentID = agentId;
             agentData.firstname = firstName;
             agentData.lastname = "testlastname";
-            agentData.SessionID = UUID.Zero;
-            agentData.SecureSessionID = UUID.Zero;
+
+            // XXX: Sessions must be unique, otherwise one presence can overwrite another in NullPresenceData.
+            agentData.SessionID = UUID.Random();
+            agentData.SecureSessionID = UUID.Random();
+
             agentData.circuitcode = 123;
             agentData.BaseFolder = UUID.Zero;
             agentData.InventoryFolder = UUID.Zero;
@@ -416,7 +419,10 @@ namespace OpenSim.Tests.Common
             // We emulate the proper login sequence here by doing things in four stages

             // Stage 0: login
-            scene.PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID);
+            // We need to punch through to the underlying service because scene will not, correctly, let us call it
+            // through it's reference to the LPSC
+            LocalPresenceServicesConnector lpsc = (LocalPresenceServicesConnector)scene.PresenceService;
+            lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID);

             // Stages 1 & 2
             ScenePresence sp = IntroduceClientToScene(scene, agentData, TeleportFlags.ViaLogin);
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index 81a5cf7..6a7cb0a 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -329,7 +329,7 @@ namespace OpenSim.Tests.Common.Mock
         /// </value>
         private UUID m_agentId;

-        public ISceneAgent SceneAgent { get { throw new NotImplementedException(); } }
+        public ISceneAgent SceneAgent { get; set; }

         /// <value>
         /// The last caps seed url that this client was given.
@@ -349,15 +349,9 @@ namespace OpenSim.Tests.Common.Mock
             get { return m_agentId; }
         }

-        public UUID SessionId
-        {
-            get { return UUID.Zero; }
-        }
+        public UUID SessionId { get; set; }

-        public UUID SecureSessionId
-        {
-            get { return UUID.Zero; }
-        }
+        public UUID SecureSessionId { get; set; }

         public virtual string FirstName
         {
@@ -381,11 +375,9 @@ namespace OpenSim.Tests.Common.Mock
             get { return true; }
             set { }
         }
-        public bool IsLoggingOut
-        {
-            get { return false; }
-            set { }
-        }
+
+        public bool IsLoggingOut { get; set; }
+
         public UUID ActiveGroupId
         {
             get { return UUID.Zero; }
@@ -451,6 +443,8 @@ namespace OpenSim.Tests.Common.Mock
             m_lastName = agentData.lastname;
             m_circuitCode = agentData.circuitcode;
             m_scene = scene;
+            SessionId = agentData.SessionID;
+            SecureSessionId = agentData.SecureSessionID;
             CapsSeedUrl = agentData.CapsPath;

             ReceivedOfflineNotifications = new List<UUID>();
@@ -902,12 +896,29 @@ namespace OpenSim.Tests.Common.Mock
         {
         }

-        public void Close()
+        /// <summary>
+        /// This is a TestClient only method to do shutdown tasks that are normally carried out by LLUDPServer.RemoveClient()
+        /// </summary>
+        public void Logout()
+        {
+            // We must set this here so that the presence is removed from the PresenceService by the PresenceDetector
+            IsLoggingOut = true;
+
+            Close();
+        }
+
+        public void Close(bool c)
         {
-            Close(true);
+            Close();
         }
-        public void Close(bool sendStop)
+
+        public void Close()
         {
+            // Fire the callback for this connection closing
+            // This is necesary to get the presence detector to notice that a client has logged out.
+            if (OnConnectionClosed != null)
+                OnConnectionClosed(this);
+
             m_scene.RemoveClient(AgentId, true);
         }

diff --git a/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config b/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config
index 026417a..1bc7e41 100755
--- a/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config
+++ b/bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config
@@ -1,6 +1,6 @@
 <configuration>
-  <dllmap os="windows" cpu="x86" dll="BulletSim" target="BulletSim" />
-  <dllmap os="windows" cpu="x86-64,ia64" dll="BulletSim" target="BulletSim-x86_64" />
-  <dllmap os="!windows,osx" cpu="x86" dll="BulletSim" target="./libBulletSim.so" />
-  <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="BulletSim" target="./libBulletSim-x86_64.so" />
+  <dllmap os="windows" cpu="x86" dll="BulletSim" target="lib32/BulletSim" />
+  <dllmap os="windows" cpu="x86-64,ia64" dll="BulletSim" target="lib64/BulletSim" />
+  <dllmap os="!windows,osx" cpu="x86" dll="BulletSim" target="lib32/libBulletSim.so" />
+  <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="BulletSim" target="lib64/libBulletSim.so" />
 </configuration>
diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll
index 5bef6e9..2c28063 100755
Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ
diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so
index 9882f5b..f40f446 100755
Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ
diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll
index 9f09ef8..d9e5e89 100755
Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ
diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so
index fa47bf1..06770a4 100755
Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ
diff --git a/bin/libBulletSim-x86_64.so b/bin/libBulletSim-x86_64.so
deleted file mode 100755
index 527eda5..0000000
Binary files a/bin/libBulletSim-x86_64.so and /dev/null differ
diff --git a/bin/libBulletSim.so b/bin/libBulletSim.so
deleted file mode 100755
index 9f91bfd..0000000
Binary files a/bin/libBulletSim.so and /dev/null differ
diff --git a/prebuild.xml b/prebuild.xml
index 0123c2a..2f114da 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -1325,6 +1325,7 @@

       <ReferencePath>../../../bin/</ReferencePath>
       <Reference name="System"/>
+      <Reference name="System.Core"/>
       <Reference name="System.Xml"/>
       <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
       <Reference name="OpenMetaverse" path="../../../bin/"/>
@@ -1764,6 +1765,7 @@
       <Reference name="System.Xml"/>
       <Reference name="System.Drawing"/>
       <Reference name="System.Web"/>
+      <Reference name="NDesk.Options" path="../../../bin/"/>
       <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
       <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
       <Reference name="OpenMetaverse" path="../../../bin/"/>
@@ -3009,6 +3011,7 @@
       <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
       <Reference name="OpenMetaverse" path="../../../bin/"/>
       <Reference name="OpenSim.Data"/>
+      <Reference name="OpenSim.Data.Null"/>
       <Reference name="OpenSim.Framework"/>
       <Reference name="OpenSim.Framework.Serialization"/>
       <Reference name="OpenSim.Framework.Communications"/>
ViewGit