diff --git a/OpenSim/Data/IFriendsData.cs b/OpenSim/Data/IFriendsData.cs index 52e7f1419a..3fdf87b51a 100644 --- a/OpenSim/Data/IFriendsData.cs +++ b/OpenSim/Data/IFriendsData.cs @@ -46,6 +46,7 @@ namespace OpenSim.Data { bool Store(FriendsData data); bool Delete(UUID ownerID, string friend); + bool Delete(string ownerID, string friend); FriendsData[] GetFriends(UUID principalID); FriendsData[] GetFriends(string principalID); } diff --git a/OpenSim/Data/MSSQL/MSSQLFriendsData.cs b/OpenSim/Data/MSSQL/MSSQLFriendsData.cs index ba1b085ef6..0b178f14cc 100644 --- a/OpenSim/Data/MSSQL/MSSQLFriendsData.cs +++ b/OpenSim/Data/MSSQL/MSSQLFriendsData.cs @@ -51,6 +51,11 @@ namespace OpenSim.Data.MSSQL } public bool Delete(UUID principalID, string friend) + { + return Delete(principalID.ToString(), friend); + } + + public bool Delete(string principalID, string friend) { using (SqlConnection conn = new SqlConnection(m_ConnectionString)) using (SqlCommand cmd = new SqlCommand()) diff --git a/OpenSim/Data/MySQL/MySQLFriendsData.cs b/OpenSim/Data/MySQL/MySQLFriendsData.cs index 69fac9d3f1..130ba5e9c2 100644 --- a/OpenSim/Data/MySQL/MySQLFriendsData.cs +++ b/OpenSim/Data/MySQL/MySQLFriendsData.cs @@ -43,6 +43,11 @@ namespace OpenSim.Data.MySQL } public bool Delete(UUID principalID, string friend) + { + return Delete(principalID.ToString(), friend); + } + + public bool Delete(string principalID, string friend) { MySqlCommand cmd = new MySqlCommand(); @@ -56,11 +61,6 @@ namespace OpenSim.Data.MySQL } public FriendsData[] GetFriends(UUID principalID) - { - return GetFriends(principalID.ToString()); - } - - public FriendsData[] GetFriends(string principalID) { MySqlCommand cmd = new MySqlCommand(); @@ -69,5 +69,14 @@ namespace OpenSim.Data.MySQL return DoQuery(cmd); } + + public FriendsData[] GetFriends(string principalID) + { + MySqlCommand cmd = new MySqlCommand(); + + cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID LIKE ?PrincipalID", m_Realm); + cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString() + '%'); + return DoQuery(cmd); + } } } diff --git a/OpenSim/Data/Null/NullFriendsData.cs b/OpenSim/Data/Null/NullFriendsData.cs index 2bfdc7a72d..d90788a111 100644 --- a/OpenSim/Data/Null/NullFriendsData.cs +++ b/OpenSim/Data/Null/NullFriendsData.cs @@ -77,7 +77,12 @@ namespace OpenSim.Data.Null return true; } - public bool Delete(UUID userID, string friendID) + public bool Delete(UUID principalID, string friend) + { + return Delete(principalID.ToString(), friend); + } + + public bool Delete(string userID, string friendID) { List lst = m_Data.FindAll(delegate(FriendsData fdata) { return fdata.PrincipalID == userID.ToString(); }); if (lst != null) diff --git a/OpenSim/Data/SQLite/SQLiteFriendsData.cs b/OpenSim/Data/SQLite/SQLiteFriendsData.cs index d925412dba..b14c3482bb 100644 --- a/OpenSim/Data/SQLite/SQLiteFriendsData.cs +++ b/OpenSim/Data/SQLite/SQLiteFriendsData.cs @@ -63,6 +63,11 @@ namespace OpenSim.Data.SQLite } public bool Delete(UUID principalID, string friend) + { + return Delete(principalID.ToString(), friend); + } + + public bool Delete(string principalID, string friend) { SqliteCommand cmd = new SqliteCommand(); diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index af21cb55cc..e5ff27a6d8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1703,9 +1703,9 @@ namespace OpenSim.Framework /// /// /// - public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname) + public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) { - uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; string[] parts = value.Split(';'); if (parts.Length >= 1) @@ -1724,6 +1724,8 @@ namespace OpenSim.Framework lastname = name[1]; } } + if (parts.Length >= 4) + secret = parts[3]; return true; } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 4879d20800..7d948136f1 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -272,11 +272,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - protected virtual FriendInfo[] GetFriendsFromService(IClientAPI client) - { - return FriendsService.GetFriends(client.AgentId); - } - private void OnClientClosed(UUID agentID, Scene scene) { ScenePresence sp = scene.GetScenePresence(agentID); @@ -300,7 +295,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends private void OnMakeRootAgent(ScenePresence sp) { - UpdateFriendsCache(sp.ControllingClient); + RefetchFriends(sp.ControllingClient); } private void OnClientLogin(IClientAPI client) @@ -544,11 +539,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - protected virtual void StoreBackwards(UUID friendID, UUID agentID) - { - FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 0); - } - private void ForwardFriendshipOffer(UUID agentID, UUID friendID, GridInstantMessage im) { // !!!!!!!! This is a hack so that we don't have to keep state (transactionID/imSessionID) @@ -587,7 +577,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends StoreFriendships(agentID, friendID); // Update the local cache - UpdateFriendsCache(client); + RefetchFriends(client); // // Notify the friend @@ -614,18 +604,11 @@ 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); - } - private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List callingCardFolders) { m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", agentID, friendID); - FriendsService.Delete(agentID, friendID.ToString()); - FriendsService.Delete(friendID, agentID.ToString()); + DeleteFriendship(agentID, friendID); // // Notify the friend @@ -652,10 +635,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID) { - DeleteFriendship(agentID, exfriendID); + if (!DeleteFriendship(agentID, exfriendID)) + client.SendAlertMessage("Unable to terminate friendship on this sim."); // Update local cache - UpdateFriendsCache(client); + RefetchFriends(client); client.SendTerminateFriend(exfriendID); @@ -679,12 +663,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - protected virtual void DeleteFriendship(UUID agentID, UUID exfriendID) - { - FriendsService.Delete(agentID, exfriendID.ToString()); - FriendsService.Delete(exfriendID, agentID.ToString()); - } - private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights) { m_log.DebugFormat("[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}", requester, rights, target); @@ -702,7 +680,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (friend != null) // Found it { // Store it on the DB - if (!SimpleStore(requester, target, rights)) + if (!StoreRights(requester, target, rights)) { remoteClient.SendAlertMessage("Unable to grant rights."); return; @@ -740,12 +718,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", target, requester); } - protected virtual bool SimpleStore(UUID agentID, UUID friendID, int rights) - { - FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), rights); - return true; - } - protected virtual FriendInfo GetFriend(FriendInfo[] friends, UUID friendID) { foreach (FriendInfo fi in friends) @@ -782,7 +754,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends friendClient.SendInstantMessage(im); // Update the local cache - UpdateFriendsCache(friendClient); + RefetchFriends(friendClient); // we're done return true; @@ -815,7 +787,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends // the friend in this sim as root agent friendClient.SendTerminateFriend(exfriendID); // update local cache - UpdateFriendsCache(friendClient); + RefetchFriends(friendClient); // we're done return true; } @@ -874,6 +846,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends #endregion + #region Get / Set friends in several flavours + /// + /// Get friends from local cache only + /// + /// + /// protected FriendInfo[] GetFriends(UUID agentID) { UserFriendData friendsData; @@ -887,17 +865,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return EMPTY_FRIENDS; } - private void UpdateFriendsCache(IClientAPI client) - { - UUID agentID = client.AgentId; - lock (m_Friends) - { - UserFriendData friendsData; - if (m_Friends.TryGetValue(agentID, out friendsData)) - friendsData.Friends = GetFriendsFromService(client); - } - } - + /// + /// Update loca cache only + /// + /// + /// + /// protected void UpdateLocalCache(UUID userID, UUID friendID, int rights) { // Update local cache @@ -908,5 +881,47 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends finfo.TheirFlags = rights; } } + + protected virtual FriendInfo[] GetFriendsFromService(IClientAPI client) + { + return FriendsService.GetFriends(client.AgentId); + } + + private void RefetchFriends(IClientAPI client) + { + UUID agentID = client.AgentId; + lock (m_Friends) + { + UserFriendData friendsData; + if (m_Friends.TryGetValue(agentID, out friendsData)) + friendsData.Friends = GetFriendsFromService(client); + } + } + + protected virtual bool StoreRights(UUID agentID, UUID friendID, int rights) + { + FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), rights); + return true; + } + + protected virtual void StoreBackwards(UUID friendID, UUID agentID) + { + FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 0); + } + + protected virtual void StoreFriendships(UUID agentID, UUID friendID) + { + FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), 1); + FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 1); + } + + protected virtual bool DeleteFriendship(UUID agentID, UUID exfriendID) + { + FriendsService.Delete(agentID, exfriendID.ToString()); + FriendsService.Delete(exfriendID, agentID.ToString()); + return true; + } + + #endregion } } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index abffb94b69..c55839f20b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -72,8 +72,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends UUID id; if (!UUID.TryParse(finfo.Friend, out id)) { - string url = string.Empty, first = string.Empty, last = string.Empty; - if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last)) + string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; + if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp)) { IUserManagement uMan = m_Scenes[0].RequestModuleInterface(); uMan.AddUser(id, url + ";" + first + " " + last); @@ -103,22 +103,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return false; } - protected override FriendInfo[] GetFriendsFromService(IClientAPI client) - { - UserAccount account1 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, client.AgentId); - if (account1 != null) - return base.GetFriendsFromService(client); - - // Foreigner - AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); - string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); - - FriendInfo[] finfos = FriendsService.GetFriends(agentUUI); - m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, agentUUI); - return finfos; - } - - protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) { first = "Unknown"; last = "User"; @@ -126,8 +110,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return true; // fid is not a UUID... - string url = string.Empty; - if (Util.ParseUniversalUserIdentifier(fid, out agentID, out url, out first, out last)) + string url = string.Empty, tmp = string.Empty; + if (Util.ParseUniversalUserIdentifier(fid, out agentID, out url, out first, out last, out tmp)) { IUserManagement userMan = m_Scenes[0].RequestModuleInterface(); userMan.AddUser(agentID, url + ";" + first + " " + last); @@ -164,7 +148,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return "Please confirm this friendship you made while you were away."; } - protected override bool SimpleStore(UUID agentID, UUID friendID, int rights) + protected override FriendInfo GetFriend(FriendInfo[] friends, UUID friendID) + { + foreach (FriendInfo fi in friends) + { + if (fi.Friend.StartsWith(friendID.ToString())) + return fi; + } + return null; + } + + + protected override FriendInfo[] GetFriendsFromService(IClientAPI client) + { + UserAccount account1 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, client.AgentId); + if (account1 != null) + return base.GetFriendsFromService(client); + + FriendInfo[] finfos = new FriendInfo[0]; + // Foreigner + AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); + if (agentClientCircuit != null) + { + string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); + + m_log.DebugFormat("[XXX] GetFriendsFromService to {0}", agentUUI); + finfos = FriendsService.GetFriends(agentUUI); + m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, agentUUI); + } + return finfos; + } + + protected override bool StoreRights(UUID agentID, UUID friendID, int rights) { UserAccount account1 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, agentID); UserAccount account2 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, friendID); @@ -172,30 +187,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (account1 != null && account2 != null) { // local grid users - return base.SimpleStore(agentID, friendID, rights); + return base.StoreRights(agentID, friendID, rights); } - if (account1 != null) + if (account1 != null) // agent is local, friend is foreigner { FriendInfo[] finfos = GetFriends(agentID); - if (finfos.Length > 0) + FriendInfo finfo = GetFriend(finfos, friendID); + if (finfo != null) { - FriendInfo finfo = GetFriend(finfos, friendID); FriendsService.StoreFriend(agentID.ToString(), finfo.Friend, rights); return true; } } - if (account2 != null) + + if (account2 != null) // agent is foreigner, friend is local { - IClientAPI client = LocateClientObject(agentID); - if (client != null) + string agentUUI = GetUUI(friendID, agentID); + if (agentUUI != string.Empty) { - AgentCircuitData acircuit = m_Scenes[0].AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); - if (acircuit != null) - { - FriendsService.StoreFriend(Util.ProduceUserUniversalIdentifier(acircuit), friendID.ToString(), rights); - return true; - } + FriendsService.StoreFriend(agentUUI, friendID.ToString(), rights); + return true; } } @@ -233,7 +245,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends return; } - // ok, at least one of them is foreigner, let's get their data IClientAPI agentClient = LocateClientObject(agentID); IClientAPI friendClient = LocateClientObject(friendID); @@ -257,13 +268,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); } - m_log.DebugFormat("[XXX] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", + m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", agentUUI, friendUUI, agentFriendService, friendFriendService); + // Generate a random 8-character hex number that will sign this friendship + string secret = UUID.Random().ToString().Substring(0, 8); + if (agentAccount != null) // agent is local, 'friend' is foreigner { // This may happen when the agent returned home, in which case the friend is not there - // We need to llok for its information in the friends list itself + // We need to look for its information in the friends list itself + bool confirming = false; if (friendUUI == string.Empty) { FriendInfo[] finfos = GetFriends(agentID); @@ -272,35 +287,41 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (finfo.TheirFlags == -1) { if (finfo.Friend.StartsWith(friendID.ToString())) + { friendUUI = finfo.Friend; + confirming = true; + } } } } - // store in the local friends service a reference to the foreign friend - FriendsService.StoreFriend(agentID.ToString(), friendUUI, 1); - // and also the converse - FriendsService.StoreFriend(friendUUI, agentID.ToString(), 1); + // If it's confirming the friendship, we already have the full friendUUI with the secret + string theFriendUUID = confirming ? friendUUI : friendUUI + ";" + secret; - if (friendClientCircuit != null) + // store in the local friends service a reference to the foreign friend + FriendsService.StoreFriend(agentID.ToString(), theFriendUUID, 1); + // and also the converse + FriendsService.StoreFriend(theFriendUUID, agentID.ToString(), 1); + + if (!confirming && friendClientCircuit != null) { // store in the foreign friends service a reference to the local agent HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID); - friendsConn.NewFriendship(friendID, agentUUI); + friendsConn.NewFriendship(friendID, agentUUI + ";" + secret); } } else if (friendAccount != null) // 'friend' is local, agent is foreigner { // store in the local friends service a reference to the foreign agent - FriendsService.StoreFriend(friendID.ToString(), agentUUI, 1); + FriendsService.StoreFriend(friendID.ToString(), agentUUI + ";" + secret, 1); // and also the converse - FriendsService.StoreFriend(agentUUI, friendID.ToString(), 1); + FriendsService.StoreFriend(agentUUI + ";" + secret, friendID.ToString(), 1); if (agentClientCircuit != null) { // store in the foreign friends service a reference to the local agent HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(agentFriendService, agentClientCircuit.SessionID, agentClientCircuit.ServiceSessionID); - friendsConn.NewFriendship(agentID, friendUUI); + friendsConn.NewFriendship(agentID, friendUUI + ";" + secret); } } else // They're both foreigners! @@ -309,43 +330,112 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends if (agentClientCircuit != null) { friendsConn = new HGFriendsServicesConnector(agentFriendService, agentClientCircuit.SessionID, agentClientCircuit.ServiceSessionID); - friendsConn.NewFriendship(agentID, friendUUI); + friendsConn.NewFriendship(agentID, friendUUI + ";" + secret); } if (friendClientCircuit != null) { friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID); - friendsConn.NewFriendship(friendID, agentUUI); + friendsConn.NewFriendship(friendID, agentUUI + ";" + secret); } } // my brain hurts now } - protected override FriendInfo GetFriend(FriendInfo[] friends, UUID friendID) + protected override bool DeleteFriendship(UUID agentID, UUID exfriendID) { - foreach (FriendInfo fi in friends) + UserAccount agentAccount = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, agentID); + UserAccount friendAccount = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, exfriendID); + // Are they both local users? + if (agentAccount != null && friendAccount != null) { - if (fi.Friend.StartsWith(friendID.ToString())) - return fi; + // local grid users + return base.DeleteFriendship(agentID, exfriendID); } - return null; - } - protected override void DeleteFriendship(UUID agentID, UUID exfriendID) - { - base.DeleteFriendship(agentID, exfriendID); - // Maybe some of the base deletes will fail. - // Let's delete the local friendship with foreign friend - FriendInfo[] friends = GetFriends(agentID); - foreach (FriendInfo finfo in friends) + // ok, at least one of them is foreigner, let's get their data + string agentUUI = string.Empty; + string friendUUI = string.Empty; + + if (agentAccount != null) // agent is local, 'friend' is foreigner { - if (finfo.Friend != exfriendID.ToString() && finfo.Friend.StartsWith(exfriendID.ToString())) + // We need to look for its information in the friends list itself + FriendInfo[] finfos = GetFriends(agentID); + FriendInfo finfo = GetFriend(finfos, exfriendID); + if (finfo != null) { - FriendsService.Delete(agentID, exfriendID.ToString()); - // TODO: delete the friendship on the other side - // Should use the homeurl given in finfo.Friend + friendUUI = finfo.Friend; + + // delete in the local friends service the reference to the foreign friend + FriendsService.Delete(agentID, friendUUI); + // and also the converse + FriendsService.Delete(friendUUI, agentID.ToString()); + + // notify the exfriend's service + Util.FireAndForget(delegate { Delete(exfriendID, agentID, friendUUI); }); + + m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentID, friendUUI); + return true; } } + else if (friendAccount != null) // agent is foreigner, 'friend' is local + { + agentUUI = GetUUI(exfriendID, agentID); + + if (agentUUI != string.Empty) + { + // delete in the local friends service the reference to the foreign agent + FriendsService.Delete(exfriendID, agentUUI); + // and also the converse + FriendsService.Delete(agentUUI, exfriendID.ToString()); + + // notify the agent's service? + Util.FireAndForget(delegate { Delete(agentID, exfriendID, agentUUI); }); + + m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentUUI, exfriendID); + return true; + } + } + //else They're both foreigners! Can't handle this + + return false; } + private string GetUUI(UUID localUser, UUID foreignUser) + { + // Let's see if the user is here by any chance + FriendInfo[] finfos = GetFriends(localUser); + if (finfos != EMPTY_FRIENDS) // friend is here, cool + { + FriendInfo finfo = GetFriend(finfos, foreignUser); + if (finfo != null) + { + return finfo.Friend; + } + } + else // user is not currently on this sim, need to get from the service + { + finfos = FriendsService.GetFriends(localUser); + foreach (FriendInfo finfo in finfos) + { + if (finfo.Friend.StartsWith(foreignUser.ToString())) // found it! + { + return finfo.Friend; + } + } + } + return string.Empty; + } + + private void Delete(UUID foreignUser, UUID localUser, string uui) + { + UUID id; + string url = string.Empty, secret = string.Empty, tmp = string.Empty; + if (Util.ParseUniversalUserIdentifier(uui, out id, out url, out tmp, out tmp, out secret)) + { + m_log.DebugFormat("[HGFRIENDS MODULE]: Deleting friendship from {0}", url); + HGFriendsServicesConnector friendConn = new HGFriendsServicesConnector(url); + friendConn.DeleteFriendship(foreignUser, localUser, secret); + } + } } } diff --git a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs index 71c3c73349..9969086a90 100644 --- a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs @@ -91,6 +91,9 @@ namespace OpenSim.Server.Handlers.Friends case "deletefriend": return DeleteFriend(request); + case "deletefriend_string": + return DeleteFriendString(request); + } m_log.DebugFormat("[FRIENDS HANDLER]: unknown method {0} request {1}", method.Length, method); } @@ -184,7 +187,25 @@ namespace OpenSim.Server.Handlers.Friends else return FailureResult(); } - + + byte[] DeleteFriendString(Dictionary request) + { + string principalID = string.Empty; + if (request.ContainsKey("PRINCIPALID")) + principalID = request["PRINCIPALID"].ToString(); + else + m_log.WarnFormat("[FRIENDS HANDLER]: no principalID in request to delete friend"); + string friend = string.Empty; + if (request.ContainsKey("FRIEND")) + friend = request["FRIEND"].ToString(); + + bool success = m_FriendsService.Delete(principalID, friend); + if (success) + return SuccessResult(); + else + return FailureResult(); + } + #endregion #region Misc diff --git a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs index dde7875321..a83d0e8b44 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs @@ -88,6 +88,8 @@ namespace OpenSim.Server.Handlers.Hypergrid case "newfriendship": return NewFriendship(request); + case "deletefriendship": + return DeleteFriendship(request); } m_log.DebugFormat("[HGFRIENDS HANDLER]: unknown method {0} request {1}", method.Length, method); } @@ -143,11 +145,21 @@ namespace OpenSim.Server.Handlers.Hypergrid // OK, can proceed FriendInfo friend = new FriendInfo(request); + UUID friendID; + string tmp = string.Empty; + if (!Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out tmp, out tmp, out tmp, out tmp)) + return FailureResult(); + + m_log.DebugFormat("[HGFRIENDS HANDLER]: New friendship {0} {1}", friend.PrincipalID, friend.Friend); + + // If the friendship already exists, return fail + FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID); + foreach (FriendInfo finfo in finfos) + if (finfo.Friend.StartsWith(friendID.ToString())) + return FailureResult(); // the user needs to confirm when he gets home bool success = m_FriendsService.StoreFriend(friend.PrincipalID.ToString(), friend.Friend, 0); - //if (success) - // m_FriendsService.StoreFriend(friend.Friend, friend.PrincipalID.ToString(), 1); if (success) return SuccessResult(); @@ -155,6 +167,33 @@ namespace OpenSim.Server.Handlers.Hypergrid return FailureResult(); } + byte[] DeleteFriendship(Dictionary request) + { + FriendInfo friend = new FriendInfo(request); + string secret = string.Empty; + if (request.ContainsKey("SECRET")) + secret = request["SECRET"].ToString(); + + if (secret == string.Empty) + return FailureResult(); + + FriendInfo[] finfos = m_FriendsService.GetFriends(friend.PrincipalID); + foreach (FriendInfo finfo in finfos) + { + // We check the secret here + if (finfo.Friend.StartsWith(friend.Friend) && finfo.Friend.EndsWith(secret)) + { + m_log.DebugFormat("[HGFRIENDS HANDLER]: Delete friendship {0} {1}", friend.PrincipalID, friend.Friend); + m_FriendsService.Delete(friend.PrincipalID, finfo.Friend); + m_FriendsService.Delete(finfo.Friend, friend.PrincipalID.ToString()); + + return SuccessResult(); + } + } + + return FailureResult(); + } + #endregion #region Misc diff --git a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs index d1afea22ed..08f1dc3133 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs @@ -211,6 +211,16 @@ namespace OpenSim.Services.Connectors.Friends } + public bool Delete(string PrincipalID, string Friend) + { + Dictionary sendData = new Dictionary(); + sendData["PRINCIPALID"] = PrincipalID.ToString(); + sendData["FRIEND"] = Friend; + sendData["METHOD"] = "deletefriend_string"; + + return Delete(sendData, PrincipalID, Friend); + } + public bool Delete(UUID PrincipalID, string Friend) { Dictionary sendData = new Dictionary(); @@ -218,6 +228,11 @@ namespace OpenSim.Services.Connectors.Friends sendData["FRIEND"] = Friend; sendData["METHOD"] = "deletefriend"; + return Delete(sendData, PrincipalID.ToString(), Friend); + } + + public bool Delete(Dictionary sendData, string PrincipalID, string Friend) + { string reply = string.Empty; try { diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs index f8238897bf..d699f596a2 100644 --- a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs @@ -54,6 +54,11 @@ namespace OpenSim.Services.Connectors.Hypergrid { } + public HGFriendsServicesConnector(string serverURI) + { + m_ServerURI = serverURI.TrimEnd('/'); + } + public HGFriendsServicesConnector(string serverURI, UUID sessionID, string serviceKey) { m_ServerURI = serverURI.TrimEnd('/'); @@ -151,6 +156,51 @@ namespace OpenSim.Services.Connectors.Hypergrid } + public bool DeleteFriendship(UUID PrincipalID, UUID Friend, string secret) + { + FriendInfo finfo = new FriendInfo(); + finfo.PrincipalID = PrincipalID; + finfo.Friend = Friend.ToString(); + + Dictionary sendData = finfo.ToKeyValuePairs(); + + sendData["METHOD"] = "deletefriendship"; + sendData["SECRET"] = secret; + + string reply = string.Empty; + try + { + reply = SynchronousRestFormsRequester.MakeRequest("POST", + m_ServerURI + "/hgfriends", + ServerUtils.BuildQueryString(sendData)); + } + catch (Exception e) + { + m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Exception when contacting friends server: {0}", e.Message); + return false; + } + + if (reply != string.Empty) + { + Dictionary replyData = ServerUtils.ParseXmlResponse(reply); + + if ((replyData != null) && replyData.ContainsKey("Result") && (replyData["Result"] != null)) + { + bool success = false; + Boolean.TryParse(replyData["Result"].ToString(), out success); + return success; + } + else + m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Delete {0} {1} received null response", + PrincipalID, Friend); + } + else + m_log.DebugFormat("[HGFRIENDS CONNECTOR]: DeleteFriend received null reply"); + + return false; + + } + #endregion } } \ No newline at end of file diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs index b1c34dd39b..7422d94b44 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs @@ -103,7 +103,7 @@ namespace OpenSim.Services.Connectors.SimianGrid if (!UUID.TryParse(principalID, out friend.PrincipalID)) { string tmp = string.Empty; - if (!Util.ParseUniversalUserIdentifier(principalID, out friend.PrincipalID, out tmp, out tmp, out tmp)) + if (!Util.ParseUniversalUserIdentifier(principalID, out friend.PrincipalID, out tmp, out tmp, out tmp, out tmp)) // bad record. ignore this entry continue; } @@ -163,6 +163,11 @@ namespace OpenSim.Services.Connectors.SimianGrid } public bool Delete(UUID principalID, string friend) + { + return Delete(principalID.ToString(), friend); + } + + public bool Delete(string principalID, string friend) { if (String.IsNullOrEmpty(m_serverUrl)) return true; diff --git a/OpenSim/Services/Friends/FriendsService.cs b/OpenSim/Services/Friends/FriendsService.cs index 4664cb30c0..e2033ac93d 100644 --- a/OpenSim/Services/Friends/FriendsService.cs +++ b/OpenSim/Services/Friends/FriendsService.cs @@ -75,7 +75,7 @@ namespace OpenSim.Services.Friends if (!UUID.TryParse(d.PrincipalID, out i.PrincipalID)) { string tmp = string.Empty; - if (!Util.ParseUniversalUserIdentifier(d.PrincipalID, out i.PrincipalID, out tmp, out tmp, out tmp)) + if (!Util.ParseUniversalUserIdentifier(d.PrincipalID, out i.PrincipalID, out tmp, out tmp, out tmp, out tmp)) // bad record. ignore this entry continue; } @@ -101,6 +101,11 @@ namespace OpenSim.Services.Friends return m_Database.Store(d); } + public bool Delete(string principalID, string friend) + { + return m_Database.Delete(principalID, friend); + } + public virtual bool Delete(UUID PrincipalID, string Friend) { return m_Database.Delete(PrincipalID, Friend); diff --git a/OpenSim/Services/HypergridService/HGFriendsService.cs b/OpenSim/Services/HypergridService/HGFriendsService.cs deleted file mode 100644 index 1829ae3116..0000000000 --- a/OpenSim/Services/HypergridService/HGFriendsService.cs +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 OpenMetaverse; -using OpenSim.Framework; -using System; -using System.Collections.Generic; -using OpenSim.Services.Interfaces; -using OpenSim.Services.Friends; -using OpenSim.Data; -using Nini.Config; -using log4net; -using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; - -namespace OpenSim.Services.HypergridService -{ - public class HGFriendsService : FriendsService, IFriendsService - { - public HGFriendsService(IConfigSource config) : base(config) - { - } - - /// - /// Overrides base. - /// Storing new friendships from the outside is a tricky, sensitive operation, and it - /// needs to be done under certain restrictions. - /// First of all, if the friendship already exists, this is a no-op. In other words, - /// we cannot change just the flags, it needs to be a new friendship. - /// Second, we store it as flags=0 always, independent of what the caller sends. The - /// owner of the friendship needs to confirm when it gets back home. - /// - /// - /// - /// - /// - public override bool StoreFriend(string PrincipalID, string Friend, int flags) - { - UUID userID; - if (UUID.TryParse(PrincipalID, out userID)) - { - FriendsData[] friendsData = m_Database.GetFriends(userID.ToString()); - List fList = new List(friendsData); - if (fList.Find(delegate(FriendsData fdata) - { - return fdata.Friend == Friend; - }) != null) - return false; - } - else - return false; - - FriendsData d = new FriendsData(); - d.PrincipalID = PrincipalID; - d.Friend = Friend; - d.Data = new Dictionary(); - d.Data["Flags"] = "0"; - - return m_Database.Store(d); - } - - } -} diff --git a/OpenSim/Services/Interfaces/IFriendsService.cs b/OpenSim/Services/Interfaces/IFriendsService.cs index 0a8efad11a..1664f3b3e1 100644 --- a/OpenSim/Services/Interfaces/IFriendsService.cs +++ b/OpenSim/Services/Interfaces/IFriendsService.cs @@ -77,5 +77,6 @@ namespace OpenSim.Services.Interfaces FriendInfo[] GetFriends(string PrincipalID); bool StoreFriend(string PrincipalID, string Friend, int flags); bool Delete(UUID PrincipalID, string Friend); + bool Delete(string PrincipalID, string Friend); } } diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 4fac951659..f68c078c39 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs @@ -628,7 +628,7 @@ namespace OpenSim.Services.LLLoginService else { string tmp; - if (Util.ParseUniversalUserIdentifier(finfo.Friend, out friendID, out tmp, out tmp, out tmp)) + if (Util.ParseUniversalUserIdentifier(finfo.Friend, out friendID, out tmp, out tmp, out tmp, out tmp)) buddyitem.BuddyID = friendID.ToString(); else // junk entry diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index 324c258c30..f8e8ae2062 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -142,7 +142,7 @@ UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService" [HGFriendsService] - LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGFriendsService" + LocalServiceModule = "OpenSim.Services.FriendsService.dll:FriendsService" UserAgentService = "OpenSim.Services.HypergridService.dll:UserAgentService" ;; This should always be the very last thing on this file