diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 089d2f544c..287073bbf8 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 575fd210c1..62c38d3568 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 0a4b2426a8..473999fdb2 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 m_Data = new List(); public NullFriendsData(string connectionString, string realm) { } + /// + /// Clear all friends data + /// + /// + /// This is required by unit tests to clear the static data between test runs. + /// + 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 /// public FriendsData[] GetFriends(string userID) { - List lst = m_Data.FindAll(fdata => + lock (m_Data) { - return fdata.PrincipalID == userID.ToString(); - }); - - if (lst != null) - { - lst.ForEach(f => + List 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 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 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 91f1cc561e..c06c223a81 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 1d806fc5eb..1f03ec5c20 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 17e6de35b6..0000000000 --- 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 881f815a46..2be78dacf1 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 callingCardFolders); + IClientAPI remoteClient, UUID transactionID, List 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); diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs index 63ec257c40..016a1744ef 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 54fc7f44f7..0496b7de26 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -5913,7 +5913,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP // My guess is this is the folder to stick the calling card into List callingCardFolders = new List(); - 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; } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs index 5e2a651715..d942e8742a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs @@ -1,4 +1,31 @@ -using System; +/* + * 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; @@ -10,7 +37,7 @@ using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using Mono.Addins; -namespace Careminster.XCallingCard.Modules +namespace OpenSim.Region.CoreModules.Avatar.Friends { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XCallingCard")] public class CallingCardModule : ISharedRegionModule, ICallingCardModule diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 4cc0e1972b..f64c161271 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -51,12 +51,15 @@ 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 { public UUID PrincipalID; public FriendInfo[] Friends; + public int Refcount; public bool IsFriend(string friend) { @@ -71,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 m_Scenes = new List(); @@ -108,7 +110,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - protected IFriendsService FriendsService + public IFriendsService FriendsService { get { @@ -155,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); } } } @@ -200,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(this); @@ -211,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 [ ]", - "Show the friends cache for the given user", - HandleFriendsShowCacheCommand); - } + public virtual void RegionLoaded(Scene scene) {} public void RemoveRegion(Scene scene) { @@ -240,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; @@ -254,15 +249,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends private void OnNewClient(IClientAPI client) { - if (client.SceneAgent.IsChildAgent) - return; - 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 @@ -283,14 +278,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends UUID agentID = client.AgentId; lock (m_Friends) { - UserFriendData friendsData = new UserFriendData(); - friendsData.PrincipalID = agentID; - friendsData.Friends = GetFriendsFromService(client); + UserFriendData friendsData; + if (m_Friends.TryGetValue(agentID, out friendsData)) + { + friendsData.Refcount++; + return false; + } + else + { + friendsData = new UserFriendData(); + friendsData.PrincipalID = agentID; + friendsData.Friends = GetFriendsFromService(client); + friendsData.Refcount = 1; - m_Friends[agentID] = friendsData; + m_Friends[agentID] = friendsData; + return true; + } } - - return true; } private void OnClientClosed(UUID agentID, Scene scene) @@ -300,17 +304,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { // do this for root agents closing out StatusChange(agentID, false); + } - lock (m_Friends) - m_Friends.Remove(agentID); + lock (m_Friends) + { + UserFriendData friendsData; + if (m_Friends.TryGetValue(agentID, out friendsData)) + { + friendsData.Refcount--; + if (friendsData.Refcount <= 0) + m_Friends.Remove(agentID); + } } } private void OnMakeRootAgent(ScenePresence sp) { - // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event - // is on the critical path for transferring an avatar from one region to another. - CacheFriends(sp.ControllingClient); + RecacheFriends(sp.ControllingClient); } private void OnClientLogin(IClientAPI client) @@ -339,18 +349,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // Send the friends online List 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 outstanding = new List(); - FriendInfo[] friends = GetFriends(agentID); + FriendInfo[] friends = GetFriendsFromCache(agentID); foreach (FriendInfo fi in friends) { if (fi.TheirFlags == -1) @@ -406,23 +411,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends List GetOnlineFriends(UUID userID) { List friendList = new List(); - List online = new List(); - 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 online = new List(); + 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 friendList, /*collector*/ List 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) { @@ -473,13 +485,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends /// private void StatusChange(UUID agentID, bool online) { - FriendInfo[] friends = GetFriends(agentID); + FriendInfo[] friends = GetFriendsFromCache(agentID); if (friends.Length > 0) { List friendList = new List(); 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); } @@ -545,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); @@ -598,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 callingCardFolders) + protected virtual void OnApproveFriendRequest(IClientAPI client, UUID friendID, List callingCardFolders) { m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", client.AgentId, friendID); @@ -616,7 +628,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } // Update the local cache. - CacheFriends(client); + RecacheFriends(client); // // Notify the friend @@ -643,18 +655,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List callingCardFolders) + private void OnDenyFriendRequest(IClientAPI client, UUID friendID, List 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() }); @@ -665,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); } @@ -678,7 +690,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends client.SendAlertMessage("Unable to terminate friendship on this sim."); // Update local cache - CacheFriends(client); + RecacheFriends(client); client.SendTerminateFriend(exfriendID); @@ -702,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; @@ -729,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]; @@ -748,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) @@ -797,9 +815,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends ccm.CreateCallingCard(friendID, userID, UUID.Zero); } - // Update the local cache - CacheFriends(friendClient); + RecacheFriends(friendClient); // we're done return true; @@ -832,7 +849,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // the friend in this sim as root agent friendClient.SendTerminateFriend(exfriendID); // update local cache - CacheFriends(friendClient); + RecacheFriends(friendClient); // we're done return true; } @@ -891,20 +908,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends #endregion #region Get / Set friends in several flavours - /// - /// Get friends from local cache only - /// - /// - /// - /// An empty array if the user has no friends or friends have not been cached. - /// - 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; } @@ -922,23 +933,31 @@ 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); } - /// - /// Are friends cached on this simulator for a particular user? - /// - /// - /// - protected bool AreFriendsCached(UUID userID) + protected void RecacheFriends(IClientAPI client) + { + // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event + // is on the critical path for transferring an avatar from one region to another. + UUID agentID = client.AgentId; + lock (m_Friends) + { + UserFriendData friendsData; + if (m_Friends.TryGetValue(agentID, out friendsData)) + friendsData.Friends = GetFriendsFromService(client); + } + } + + public bool AreFriendsCached(UUID userID) { lock (m_Friends) return m_Friends.ContainsKey(userID); @@ -957,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) @@ -969,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 [ ]"); - return; - } - - string firstName = cmd[3]; - string lastName = cmd[4]; - - IUserManagement umModule = m_Scenes[0].RequestModuleInterface(); - 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); - } - } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index 7bc30181a0..9a6d277252 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 callingCardFolders) + protected override void OnApproveFriendRequest(IClientAPI client, UUID friendID, List 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) @@ -121,7 +121,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { UUID agentID = client.AgentId; // we do this only for the root agent - if (!client.SceneAgent.IsChildAgent) + if (m_Friends[agentID].Refcount == 1) { // We need to preload the user management cache with the names // of foreign friends, just like we do with SOPs' creators @@ -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) { @@ -426,14 +425,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode); agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); agentFriendService = agentClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); - CacheFriends(agentClient); + RecacheFriends(agentClient); } if (friendClient != null) { friendClientCircuit = ((Scene)(friendClient.Scene)).AuthenticateHandler.GetAgentCircuitData(friendClient.CircuitCode); friendUUI = Util.ProduceUserUniversalIdentifier(friendClientCircuit); friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); - CacheFriends(friendClient); + RecacheFriends(friendClient); } m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", @@ -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 682fbab142..45b4264c91 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(); @@ -75,6 +97,76 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests Assert.That(((TestClient)sp.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(0)); } + [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() { diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 192d55fd90..aa996924af 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 ef9b4e069b..176c86de12 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 attachments = sp.GetAttachments(); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs index e2e383f060..ccfbf78a29 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 4a654a38dd..82ccaf8264 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 ab8e1bf0b7..f5f35bb92e 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/Framework/Interfaces/ICallingCardModule.cs b/OpenSim/Region/Framework/Interfaces/ICallingCardModule.cs new file mode 100644 index 0000000000..69682aca0d --- /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 061799e394..7e87006706 100644 --- a/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IFriendsModule.cs @@ -25,14 +25,31 @@ * 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 { + /// + /// Are friends cached on this simulator for a particular user? + /// + /// + /// + bool AreFriendsCached(UUID userID); + + /// + /// Get friends from local cache only + /// + /// + /// + /// An empty array if the user has no friends or friends have not been cached. + /// + FriendInfo[] GetFriendsFromCache(UUID userID); + /// /// Add a friendship between two users. /// @@ -55,7 +72,27 @@ namespace OpenSim.Region.Framework.Interfaces /// void RemoveFriendship(IClientAPI client, UUID exFriendID); - uint GetFriendPerms(UUID PrincipalID, UUID FriendID); + /// + /// Get permissions granted by a friend. + /// + /// The user. + /// The friend that granted. + /// The permissions. These come from the FriendRights enum. + int GetRightsGrantedByFriend(UUID userID, UUID friendID); + + /// + /// Grant permissions for a friend. + /// + /// + /// 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. + /// + /// The user granting the permissions. + /// The friend. + /// These come from the FriendRights enum. + 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/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index cf3270da1e..539ca14410 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( @@ -4348,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 ccc3f32467..9fdbc54e5f 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); } /// @@ -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); } /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index f3660a5659..2effa251c7 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 /// null if the item does not exist 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 /// false if the item did not exist, true if the update occurred succesfully 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 90ad098556..11fd7215e5 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); } + /// + /// Does this group contain the given part? + /// should be able to remove these methods once we have a entity index in scene + /// + /// + /// + 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; + } + /// /// The root part of this scene object /// @@ -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 /// /// - /// null if a child part with the primID was not found - public SceneObjectPart GetChildPart(UUID primID) + /// null if a part with the primID was not found + 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 /// /// - /// null if a child part with the local ID was not found - public SceneObjectPart GetChildPart(uint localID) + /// null if a part with the local ID was not found + 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; } - /// - /// Does this group contain the child prim - /// should be able to remove these methods once we have a entity index in scene - /// - /// - /// - public bool HasChildPrim(UUID primID) - { - return m_parts.ContainsKey(primID); - } - - /// - /// Does this group contain the child prim - /// should be able to remove these methods once we have a entity index in scene - /// - /// - /// - 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 /// The object group of the newly delinked prim. Null if part could not be found 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 /// 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 /// 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 /// 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 /// 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 /// 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 /// 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 ac44ce9402..a2649eed91 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/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs new file mode 100644 index 0000000000..e68f9d07a3 --- /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 +{ + /// + /// A module that just holds commands for inspecting avatar appearance. + /// + [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(); + m_userManagementModule = m_scene.RequestModuleInterface(); + + if (m_friendsModule != null && m_userManagementModule != null) + { + m_scene.AddCommand( + "Friends", this, "friends show", + "friends show [--cache] ", + "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 options = new Dictionary(); + OptionSet optionSet = new OptionSet().Add("c|cache", delegate (string v) { options["cache"] = v != null; }); + + List mainParams = optionSet.Parse(cmd); + + if (mainParams.Count != 4) + { + MainConsole.Instance.OutputFormat("Usage: friends show [--cache] "); + 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/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs index a17eb41740..51b0592356 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 4d7c40eb46..edfc0ef684 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); }); diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs index a9998866d2..cb686e26e6 100644 --- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenMetaverse; using log4net; using Nini.Config; @@ -58,6 +59,8 @@ namespace OpenSim.Services.HypergridService private UserAccountCache m_Cache; + private ExpiringCache> m_SuitcaseTrees = new ExpiringCache>(); + public HGSuitcaseInventoryService(IConfigSource config, string configName) : base(config, configName) { @@ -147,16 +150,17 @@ namespace OpenSim.Services.HypergridService return GetRootFolder(principalID); } - // - // Use the inherited methods - // 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 { - XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); if (suitcase != null) { coll = base.GetFolderContent(principalID, suitcase.folderID); @@ -180,68 +184,69 @@ namespace OpenSim.Services.HypergridService return coll; } - //public List GetFolderItems(UUID principalID, UUID folderID) - //{ - //} - - //public override bool AddFolder(InventoryFolderBase folder) - //{ - // // Check if it's under the Suitcase folder - // List skel = base.GetInventorySkeleton(folder.Owner); - // InventoryFolderBase suitcase = GetRootFolder(folder.Owner); - // List suitDescendents = GetDescendents(skel, suitcase.ID); - - // foreach (InventoryFolderBase f in suitDescendents) - // if (folder.ParentID == f.ID) - // { - // XInventoryFolder xFolder = ConvertFromOpenSim(folder); - // return m_Database.StoreFolder(xFolder); - // } - // return false; - //} - - private List GetDescendents(List lst, UUID root) + public override List GetFolderItems(UUID principalID, UUID folderID) { - List direct = lst.FindAll(delegate(InventoryFolderBase f) { return f.ParentID == root; }); - if (direct == null) - return new List(); + // 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); - List indirect = new List(); - foreach (InventoryFolderBase f in direct) - indirect.AddRange(GetDescendents(lst, f.ID)); + if (!IsWithinSuitcaseTree(folderID, root, suitcase)) + return new List(); - direct.AddRange(indirect); - return direct; + return base.GetFolderItems(principalID, folderID); } - // Use inherited method - //public bool UpdateFolder(InventoryFolderBase folder) - //{ - //} + 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); - //public override bool MoveFolder(InventoryFolderBase folder) - //{ - // XInventoryFolder[] x = m_Database.GetFolders( - // new string[] { "folderID" }, - // new string[] { folder.ID.ToString() }); + if (!IsWithinSuitcaseTree(folder.ParentID, root, suitcase)) + return false; - // if (x.Length == 0) - // 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; + } - // // Check if it's under the Suitcase folder - // List skel = base.GetInventorySkeleton(folder.Owner); - // InventoryFolderBase suitcase = GetRootFolder(folder.Owner); - // List suitDescendents = GetDescendents(skel, suitcase.ID); + return base.AddFolder(folder); + } - // foreach (InventoryFolderBase f in suitDescendents) - // if (folder.ParentID == f.ID) - // { - // x[0].parentFolderID = folder.ParentID; - // return m_Database.StoreFolder(x[0]); - // } + public bool UpdateFolder(InventoryFolderBase folder) + { + XInventoryFolder root = GetRootXFolder(folder.Owner); + XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner); - // return false; - //} + 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 folderIDs) { @@ -255,78 +260,110 @@ namespace OpenSim.Services.HypergridService return false; } - // Unfortunately we need to use the inherited method because of how DeRez works. - // The viewer sends the folderID hard-wired in the derez message - //public override bool AddItem(InventoryItemBase item) - //{ - // // Check if it's under the Suitcase folder - // List skel = base.GetInventorySkeleton(item.Owner); - // InventoryFolderBase suitcase = GetRootFolder(item.Owner); - // List suitDescendents = GetDescendents(skel, suitcase.ID); + 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); - // foreach (InventoryFolderBase f in suitDescendents) - // if (item.Folder == f.ID) - // return m_Database.StoreItem(ConvertFromOpenSim(item)); + if (!IsWithinSuitcaseTree(item.Folder, root, suitcase)) + return false; - // 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; + } - //public override bool UpdateItem(InventoryItemBase item) - //{ - // // Check if it's under the Suitcase folder - // List skel = base.GetInventorySkeleton(item.Owner); - // InventoryFolderBase suitcase = GetRootFolder(item.Owner); - // List suitDescendents = GetDescendents(skel, suitcase.ID); + return base.AddItem(item); - // foreach (InventoryFolderBase f in suitDescendents) - // if (item.Folder == f.ID) - // return m_Database.StoreItem(ConvertFromOpenSim(item)); + } - // return false; - //} + public override bool UpdateItem(InventoryItemBase item) + { + XInventoryFolder root = GetRootXFolder(item.Owner); + XInventoryFolder suitcase = GetSuitcaseXFolder(item.Owner); - //public override bool MoveItems(UUID principalID, List items) - //{ - // // Principal is b0rked. *sigh* - // // - // // Let's assume they all have the same principal - // // Check if it's under the Suitcase folder - // List skel = base.GetInventorySkeleton(items[0].Owner); - // InventoryFolderBase suitcase = GetRootFolder(items[0].Owner); - // List suitDescendents = GetDescendents(skel, suitcase.ID); + if (!IsWithinSuitcaseTree(item.Folder, root, suitcase)) + return false; - // foreach (InventoryItemBase i in items) - // { - // foreach (InventoryFolderBase f in suitDescendents) - // if (i.Folder == f.ID) - // m_Database.MoveItem(i.ID.ToString(), i.Folder.ToString()); - // } + return base.UpdateItem(item); + } - // return true; - //} + public override bool MoveItems(UUID principalID, List 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 bool DeleteItems(UUID principalID, List itemIDs) - //{ - //} + public override bool DeleteItems(UUID principalID, List itemIDs) + { + return false; + } - //public override InventoryItemBase GetItem(InventoryItemBase item) - //{ - // InventoryItemBase it = base.GetItem(item); - // if (it != null) - // { - // UserAccount user = m_Cache.GetUser(it.CreatorId); + public override InventoryItemBase GetItem(InventoryItemBase item) + { + InventoryItemBase it = base.GetItem(item); + XInventoryFolder root = GetRootXFolder(it.Owner); + XInventoryFolder suitcase = GetSuitcaseXFolder(it.Owner); - // // 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; - //} + if (it != null) + { + if (!IsWithinSuitcaseTree(it.Folder, root, suitcase)) + return null; - //public InventoryFolderBase GetFolder(InventoryFolderBase folder) - //{ - //} + 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 GetActiveGestures(UUID principalID) //{ @@ -336,6 +373,19 @@ namespace OpenSim.Services.HypergridService //{ //} + #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( @@ -364,5 +414,53 @@ namespace OpenSim.Services.HypergridService suitcase.folderID = rootID; suitcase.parentFolderID = UUID.Zero; } + + private List GetFolderTree(UUID root) + { + List t = null; + if (m_SuitcaseTrees.TryGetValue(root, out t)) + return t; + + t = GetFolderTreeRecursive(root); + m_SuitcaseTrees.AddOrUpdate(root, t, 120); + return t; + } + + private List GetFolderTreeRecursive(UUID root) + { + List tree = new List(); + 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 tree = new List(); + 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 1664f3b3e1..d0d3b1002d 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; + + /// + /// The permissions that this user has granted to the friend. + /// public int MyFlags; + + /// + /// The permissions that the friend has granted to this user. + /// 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 c8ac38e63a..ed2703eda5 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 7bf08ae702..318758d984 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 64dd1e48d1..6a7cb0aa83 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -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(); @@ -902,12 +896,29 @@ namespace OpenSim.Tests.Common.Mock { } + /// + /// This is a TestClient only method to do shutdown tasks that are normally carried out by LLUDPServer.RemoveClient() + /// + 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(); + } + public void Close() { - Close(true); - } - public void Close(bool sendStop) - { + // 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/prebuild.xml b/prebuild.xml index 0123c2af68..2f114da19f 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1325,6 +1325,7 @@ ../../../bin/ + @@ -1764,6 +1765,7 @@ + @@ -3009,6 +3011,7 @@ +