aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar
diff options
context:
space:
mode:
authorMelanie2012-03-31 02:18:02 +0100
committerMelanie2012-03-31 02:18:02 +0100
commitf3132c45d98af7bb38251ad95013c433b5eda9e5 (patch)
treeefc3d6c0529678c0a56f5a505a52944012ea607a /OpenSim/Region/CoreModules/Avatar
parentMerge branch 'master' into careminster (diff)
parentrefactor: Rename SOG.GetChildPart() to GetPart() since it can also return the... (diff)
downloadopensim-SC-f3132c45d98af7bb38251ad95013c433b5eda9e5.zip
opensim-SC-f3132c45d98af7bb38251ad95013c433b5eda9e5.tar.gz
opensim-SC-f3132c45d98af7bb38251ad95013c433b5eda9e5.tar.bz2
opensim-SC-f3132c45d98af7bb38251ad95013c433b5eda9e5.tar.xz
Merge branch 'master' into careminster
Conflicts: OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs OpenSim/Tests/Common/Mock/TestClient.cs
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs31
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs243
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs27
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs94
4 files changed, 238 insertions, 157 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
index 5e2a651..d942e87 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
@@ -1,4 +1,31 @@
1using System; 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.Reflection; 30using System.Reflection;
4using log4net; 31using log4net;
@@ -10,7 +37,7 @@ using OpenSim.Region.Framework.Scenes;
10using OpenSim.Services.Interfaces; 37using OpenSim.Services.Interfaces;
11using Mono.Addins; 38using Mono.Addins;
12 39
13namespace Careminster.XCallingCard.Modules 40namespace OpenSim.Region.CoreModules.Avatar.Friends
14{ 41{
15 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XCallingCard")] 42 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XCallingCard")]
16 public class CallingCardModule : ISharedRegionModule, ICallingCardModule 43 public class CallingCardModule : ISharedRegionModule, ICallingCardModule
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 4cc0e19..f64c161 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
51{ 51{
52 public class FriendsModule : ISharedRegionModule, IFriendsModule 52 public class FriendsModule : ISharedRegionModule, IFriendsModule
53 { 53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
54 protected bool m_Enabled = false; 56 protected bool m_Enabled = false;
55 57
56 protected class UserFriendData 58 protected class UserFriendData
57 { 59 {
58 public UUID PrincipalID; 60 public UUID PrincipalID;
59 public FriendInfo[] Friends; 61 public FriendInfo[] Friends;
62 public int Refcount;
60 63
61 public bool IsFriend(string friend) 64 public bool IsFriend(string friend)
62 { 65 {
@@ -71,7 +74,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
71 } 74 }
72 75
73 protected static readonly FriendInfo[] EMPTY_FRIENDS = new FriendInfo[0]; 76 protected static readonly FriendInfo[] EMPTY_FRIENDS = new FriendInfo[0];
74 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
75 77
76 protected List<Scene> m_Scenes = new List<Scene>(); 78 protected List<Scene> m_Scenes = new List<Scene>();
77 79
@@ -108,7 +110,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
108 } 110 }
109 } 111 }
110 112
111 protected IFriendsService FriendsService 113 public IFriendsService FriendsService
112 { 114 {
113 get 115 get
114 { 116 {
@@ -155,7 +157,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
155 InitModule(config); 157 InitModule(config);
156 158
157 m_Enabled = true; 159 m_Enabled = true;
158 m_log.InfoFormat("[FRIENDS MODULE]: {0} enabled.", Name); 160 m_log.DebugFormat("[FRIENDS MODULE]: {0} enabled.", Name);
159 } 161 }
160 } 162 }
161 } 163 }
@@ -200,7 +202,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
200 if (!m_Enabled) 202 if (!m_Enabled)
201 return; 203 return;
202 204
203 m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name); 205// m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name);
204 206
205 m_Scenes.Add(scene); 207 m_Scenes.Add(scene);
206 scene.RegisterModuleInterface<IFriendsModule>(this); 208 scene.RegisterModuleInterface<IFriendsModule>(this);
@@ -211,14 +213,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
211 scene.EventManager.OnClientLogin += OnClientLogin; 213 scene.EventManager.OnClientLogin += OnClientLogin;
212 } 214 }
213 215
214 public virtual void RegionLoaded(Scene scene) 216 public virtual void RegionLoaded(Scene scene) {}
215 {
216 scene.AddCommand(
217 "Friends", this, "friends show cache",
218 "friends show cache [<first-name> <last-name>]",
219 "Show the friends cache for the given user",
220 HandleFriendsShowCacheCommand);
221 }
222 217
223 public void RemoveRegion(Scene scene) 218 public void RemoveRegion(Scene scene)
224 { 219 {
@@ -240,13 +235,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
240 235
241 #endregion 236 #endregion
242 237
243 public virtual uint GetFriendPerms(UUID principalID, UUID friendID) 238 public virtual int GetRightsGrantedByFriend(UUID principalID, UUID friendID)
244 { 239 {
245 FriendInfo[] friends = GetFriends(principalID); 240 FriendInfo[] friends = GetFriendsFromCache(principalID);
246 FriendInfo finfo = GetFriend(friends, friendID); 241 FriendInfo finfo = GetFriend(friends, friendID);
247 if (finfo != null) 242 if (finfo != null)
248 { 243 {
249 return (uint)finfo.TheirFlags; 244 return finfo.TheirFlags;
250 } 245 }
251 246
252 return 0; 247 return 0;
@@ -254,15 +249,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
254 249
255 private void OnNewClient(IClientAPI client) 250 private void OnNewClient(IClientAPI client)
256 { 251 {
257 if (client.SceneAgent.IsChildAgent)
258 return;
259
260 client.OnInstantMessage += OnInstantMessage; 252 client.OnInstantMessage += OnInstantMessage;
261 client.OnApproveFriendRequest += OnApproveFriendRequest; 253 client.OnApproveFriendRequest += OnApproveFriendRequest;
262 client.OnDenyFriendRequest += OnDenyFriendRequest; 254 client.OnDenyFriendRequest += OnDenyFriendRequest;
263 client.OnTerminateFriendship += (thisClient, agentID, exfriendID) => RemoveFriendship(thisClient, exfriendID); 255 client.OnTerminateFriendship += RemoveFriendship;
264 client.OnGrantUserRights += OnGrantUserRights; 256 client.OnGrantUserRights += GrantRights;
265 257
258 // We need to cache information for child agents as well as root agents so that friend edit/move/delete
259 // permissions will work across borders where both regions are on different simulators.
260 //
266 // Do not do this asynchronously. If we do, then subsequent code can outrace CacheFriends() and 261 // Do not do this asynchronously. If we do, then subsequent code can outrace CacheFriends() and
267 // return misleading results from the still empty friends cache. 262 // return misleading results from the still empty friends cache.
268 // If we absolutely need to do this asynchronously, then a signalling mechanism is needed so that calls 263 // 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
283 UUID agentID = client.AgentId; 278 UUID agentID = client.AgentId;
284 lock (m_Friends) 279 lock (m_Friends)
285 { 280 {
286 UserFriendData friendsData = new UserFriendData(); 281 UserFriendData friendsData;
287 friendsData.PrincipalID = agentID; 282 if (m_Friends.TryGetValue(agentID, out friendsData))
288 friendsData.Friends = GetFriendsFromService(client); 283 {
284 friendsData.Refcount++;
285 return false;
286 }
287 else
288 {
289 friendsData = new UserFriendData();
290 friendsData.PrincipalID = agentID;
291 friendsData.Friends = GetFriendsFromService(client);
292 friendsData.Refcount = 1;
289 293
290 m_Friends[agentID] = friendsData; 294 m_Friends[agentID] = friendsData;
295 return true;
296 }
291 } 297 }
292
293 return true;
294 } 298 }
295 299
296 private void OnClientClosed(UUID agentID, Scene scene) 300 private void OnClientClosed(UUID agentID, Scene scene)
@@ -300,17 +304,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
300 { 304 {
301 // do this for root agents closing out 305 // do this for root agents closing out
302 StatusChange(agentID, false); 306 StatusChange(agentID, false);
307 }
303 308
304 lock (m_Friends) 309 lock (m_Friends)
305 m_Friends.Remove(agentID); 310 {
311 UserFriendData friendsData;
312 if (m_Friends.TryGetValue(agentID, out friendsData))
313 {
314 friendsData.Refcount--;
315 if (friendsData.Refcount <= 0)
316 m_Friends.Remove(agentID);
317 }
306 } 318 }
307 } 319 }
308 320
309 private void OnMakeRootAgent(ScenePresence sp) 321 private void OnMakeRootAgent(ScenePresence sp)
310 { 322 {
311 // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event 323 RecacheFriends(sp.ControllingClient);
312 // is on the critical path for transferring an avatar from one region to another.
313 CacheFriends(sp.ControllingClient);
314 } 324 }
315 325
316 private void OnClientLogin(IClientAPI client) 326 private void OnClientLogin(IClientAPI client)
@@ -339,18 +349,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
339 349
340 // Send the friends online 350 // Send the friends online
341 List<UUID> online = GetOnlineFriends(agentID); 351 List<UUID> online = GetOnlineFriends(agentID);
342 if (online.Count > 0)
343 {
344 m_log.DebugFormat(
345 "[FRIENDS MODULE]: User {0} in region {1} has {2} friends online",
346 client.Name, client.Scene.RegionInfo.RegionName, online.Count);
347 352
353 if (online.Count > 0)
348 client.SendAgentOnline(online.ToArray()); 354 client.SendAgentOnline(online.ToArray());
349 }
350 355
351 // Send outstanding friendship offers 356 // Send outstanding friendship offers
352 List<string> outstanding = new List<string>(); 357 List<string> outstanding = new List<string>();
353 FriendInfo[] friends = GetFriends(agentID); 358 FriendInfo[] friends = GetFriendsFromCache(agentID);
354 foreach (FriendInfo fi in friends) 359 foreach (FriendInfo fi in friends)
355 { 360 {
356 if (fi.TheirFlags == -1) 361 if (fi.TheirFlags == -1)
@@ -406,23 +411,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
406 List<UUID> GetOnlineFriends(UUID userID) 411 List<UUID> GetOnlineFriends(UUID userID)
407 { 412 {
408 List<string> friendList = new List<string>(); 413 List<string> friendList = new List<string>();
409 List<UUID> online = new List<UUID>();
410 414
411 FriendInfo[] friends = GetFriends(userID); 415 FriendInfo[] friends = GetFriendsFromCache(userID);
412 foreach (FriendInfo fi in friends) 416 foreach (FriendInfo fi in friends)
413 { 417 {
414 if (((fi.TheirFlags & 1) != 0) && (fi.TheirFlags != -1)) 418 if (((fi.TheirFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1))
415 friendList.Add(fi.Friend); 419 friendList.Add(fi.Friend);
416 } 420 }
417 421
422 List<UUID> online = new List<UUID>();
423
418 if (friendList.Count > 0) 424 if (friendList.Count > 0)
419 GetOnlineFriends(userID, friendList, online); 425 GetOnlineFriends(userID, friendList, online);
420 426
427// m_log.DebugFormat(
428// "[FRIENDS MODULE]: User {0} has {1} friends online", userID, online.Count);
429
421 return online; 430 return online;
422 } 431 }
423 432
424 protected virtual void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online) 433 protected virtual void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
425 { 434 {
435// m_log.DebugFormat(
436// "[FRIENDS MODULE]: Looking for online presence of {0} users for {1}", friendList.Count, userID);
437
426 PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray()); 438 PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
427 foreach (PresenceInfo pi in presence) 439 foreach (PresenceInfo pi in presence)
428 { 440 {
@@ -473,13 +485,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
473 /// <param name="online"></param> 485 /// <param name="online"></param>
474 private void StatusChange(UUID agentID, bool online) 486 private void StatusChange(UUID agentID, bool online)
475 { 487 {
476 FriendInfo[] friends = GetFriends(agentID); 488 FriendInfo[] friends = GetFriendsFromCache(agentID);
477 if (friends.Length > 0) 489 if (friends.Length > 0)
478 { 490 {
479 List<FriendInfo> friendList = new List<FriendInfo>(); 491 List<FriendInfo> friendList = new List<FriendInfo>();
480 foreach (FriendInfo fi in friends) 492 foreach (FriendInfo fi in friends)
481 { 493 {
482 if (((fi.MyFlags & 1) != 0) && (fi.TheirFlags != -1)) 494 if (((fi.MyFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1))
483 friendList.Add(fi); 495 friendList.Add(fi);
484 } 496 }
485 497
@@ -545,7 +557,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
545 m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2} ({3})", principalID, client.FirstName + client.LastName, friendID, im.fromAgentName); 557 m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2} ({3})", principalID, client.FirstName + client.LastName, friendID, im.fromAgentName);
546 558
547 // Check that the friendship doesn't exist yet 559 // Check that the friendship doesn't exist yet
548 FriendInfo[] finfos = GetFriends(principalID); 560 FriendInfo[] finfos = GetFriendsFromCache(principalID);
549 if (finfos != null) 561 if (finfos != null)
550 { 562 {
551 FriendInfo f = GetFriend(finfos, friendID); 563 FriendInfo f = GetFriend(finfos, friendID);
@@ -598,7 +610,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
598 return (account == null) ? "Unknown" : account.FirstName + " " + account.LastName; 610 return (account == null) ? "Unknown" : account.FirstName + " " + account.LastName;
599 } 611 }
600 612
601 protected virtual void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) 613 protected virtual void OnApproveFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
602 { 614 {
603 m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", client.AgentId, friendID); 615 m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", client.AgentId, friendID);
604 616
@@ -616,7 +628,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
616 } 628 }
617 629
618 // Update the local cache. 630 // Update the local cache.
619 CacheFriends(client); 631 RecacheFriends(client);
620 632
621 // 633 //
622 // Notify the friend 634 // Notify the friend
@@ -643,18 +655,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
643 } 655 }
644 } 656 }
645 657
646 private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) 658 private void OnDenyFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
647 { 659 {
648 m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", agentID, friendID); 660 m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", client.AgentId, friendID);
649 661
650 DeleteFriendship(agentID, friendID); 662 DeleteFriendship(client.AgentId, friendID);
651 663
652 // 664 //
653 // Notify the friend 665 // Notify the friend
654 // 666 //
655 667
656 // Try local 668 // Try local
657 if (LocalFriendshipDenied(agentID, client.Name, friendID)) 669 if (LocalFriendshipDenied(client.AgentId, client.Name, friendID))
658 return; 670 return;
659 671
660 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() }); 672 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
@@ -665,7 +677,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
665 { 677 {
666 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); 678 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
667 if (region != null) 679 if (region != null)
668 m_FriendsSimConnector.FriendshipDenied(region, agentID, client.Name, friendID); 680 m_FriendsSimConnector.FriendshipDenied(region, client.AgentId, client.Name, friendID);
669 else 681 else
670 m_log.WarnFormat("[FRIENDS]: Could not find region {0} in locating {1}", friendSession.RegionID, friendID); 682 m_log.WarnFormat("[FRIENDS]: Could not find region {0} in locating {1}", friendSession.RegionID, friendID);
671 } 683 }
@@ -678,7 +690,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
678 client.SendAlertMessage("Unable to terminate friendship on this sim."); 690 client.SendAlertMessage("Unable to terminate friendship on this sim.");
679 691
680 // Update local cache 692 // Update local cache
681 CacheFriends(client); 693 RecacheFriends(client);
682 694
683 client.SendTerminateFriend(exfriendID); 695 client.SendTerminateFriend(exfriendID);
684 696
@@ -702,23 +714,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
702 } 714 }
703 } 715 }
704 716
705 private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights) 717 public void GrantRights(IClientAPI remoteClient, UUID friendID, int rights)
706 { 718 {
707 m_log.DebugFormat("[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}", requester, rights, target); 719 UUID requester = remoteClient.AgentId;
708 720
709 FriendInfo[] friends = GetFriends(remoteClient.AgentId); 721 m_log.DebugFormat(
722 "[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}",
723 requester, rights, friendID);
724
725 FriendInfo[] friends = GetFriendsFromCache(requester);
710 if (friends.Length == 0) 726 if (friends.Length == 0)
711 { 727 {
712 return; 728 return;
713 } 729 }
714 730
715 // Let's find the friend in this user's friend list 731 // Let's find the friend in this user's friend list
716 FriendInfo friend = GetFriend(friends, target); 732 FriendInfo friend = GetFriend(friends, friendID);
717 733
718 if (friend != null) // Found it 734 if (friend != null) // Found it
719 { 735 {
720 // Store it on the DB 736 // Store it on the DB
721 if (!StoreRights(requester, target, rights)) 737 if (!StoreRights(requester, friendID, rights))
722 { 738 {
723 remoteClient.SendAlertMessage("Unable to grant rights."); 739 remoteClient.SendAlertMessage("Unable to grant rights.");
724 return; 740 return;
@@ -729,17 +745,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
729 friend.MyFlags = rights; 745 friend.MyFlags = rights;
730 746
731 // Always send this back to the original client 747 // Always send this back to the original client
732 remoteClient.SendChangeUserRights(requester, target, rights); 748 remoteClient.SendChangeUserRights(requester, friendID, rights);
733 749
734 // 750 //
735 // Notify the friend 751 // Notify the friend
736 // 752 //
737 753
738 // Try local 754 // Try local
739 if (LocalGrantRights(requester, target, myFlags, rights)) 755 if (LocalGrantRights(requester, friendID, myFlags, rights))
740 return; 756 return;
741 757
742 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { target.ToString() }); 758 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
743 if (friendSessions != null && friendSessions.Length > 0) 759 if (friendSessions != null && friendSessions.Length > 0)
744 { 760 {
745 PresenceInfo friendSession = friendSessions[0]; 761 PresenceInfo friendSession = friendSessions[0];
@@ -748,12 +764,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
748 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); 764 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
749 // TODO: You might want to send the delta to save the lookup 765 // TODO: You might want to send the delta to save the lookup
750 // on the other end!! 766 // on the other end!!
751 m_FriendsSimConnector.GrantRights(region, requester, target, myFlags, rights); 767 m_FriendsSimConnector.GrantRights(region, requester, friendID, myFlags, rights);
752 } 768 }
753 } 769 }
754 } 770 }
755 else 771 else
756 m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", target, requester); 772 {
773 m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", friendID, requester);
774 }
757 } 775 }
758 776
759 protected virtual FriendInfo GetFriend(FriendInfo[] friends, UUID friendID) 777 protected virtual FriendInfo GetFriend(FriendInfo[] friends, UUID friendID)
@@ -797,9 +815,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
797 ccm.CreateCallingCard(friendID, userID, UUID.Zero); 815 ccm.CreateCallingCard(friendID, userID, UUID.Zero);
798 } 816 }
799 817
800
801 // Update the local cache 818 // Update the local cache
802 CacheFriends(friendClient); 819 RecacheFriends(friendClient);
803 820
804 // we're done 821 // we're done
805 return true; 822 return true;
@@ -832,7 +849,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
832 // the friend in this sim as root agent 849 // the friend in this sim as root agent
833 friendClient.SendTerminateFriend(exfriendID); 850 friendClient.SendTerminateFriend(exfriendID);
834 // update local cache 851 // update local cache
835 CacheFriends(friendClient); 852 RecacheFriends(friendClient);
836 // we're done 853 // we're done
837 return true; 854 return true;
838 } 855 }
@@ -891,20 +908,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
891 #endregion 908 #endregion
892 909
893 #region Get / Set friends in several flavours 910 #region Get / Set friends in several flavours
894 /// <summary> 911
895 /// Get friends from local cache only 912 public FriendInfo[] GetFriendsFromCache(UUID userID)
896 /// </summary>
897 /// <param name="agentID"></param>
898 /// <returns>
899 /// An empty array if the user has no friends or friends have not been cached.
900 /// </returns>
901 protected FriendInfo[] GetFriends(UUID agentID)
902 { 913 {
903 UserFriendData friendsData; 914 UserFriendData friendsData;
904 915
905 lock (m_Friends) 916 lock (m_Friends)
906 { 917 {
907 if (m_Friends.TryGetValue(agentID, out friendsData)) 918 if (m_Friends.TryGetValue(userID, out friendsData))
908 return friendsData.Friends; 919 return friendsData.Friends;
909 } 920 }
910 921
@@ -922,23 +933,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
922 // Update local cache 933 // Update local cache
923 lock (m_Friends) 934 lock (m_Friends)
924 { 935 {
925 FriendInfo[] friends = GetFriends(friendID); 936 FriendInfo[] friends = GetFriendsFromCache(friendID);
926 FriendInfo finfo = GetFriend(friends, userID); 937 FriendInfo finfo = GetFriend(friends, userID);
927 finfo.TheirFlags = rights; 938 finfo.TheirFlags = rights;
928 } 939 }
929 } 940 }
930 941
931 protected virtual FriendInfo[] GetFriendsFromService(IClientAPI client) 942 public virtual FriendInfo[] GetFriendsFromService(IClientAPI client)
932 { 943 {
933 return FriendsService.GetFriends(client.AgentId); 944 return FriendsService.GetFriends(client.AgentId);
934 } 945 }
935 946
936 /// <summary> 947 protected void RecacheFriends(IClientAPI client)
937 /// Are friends cached on this simulator for a particular user? 948 {
938 /// </summary> 949 // FIXME: Ideally, we want to avoid doing this here since it sits the EventManager.OnMakeRootAgent event
939 /// <param name="userID"></param> 950 // is on the critical path for transferring an avatar from one region to another.
940 /// <returns></returns> 951 UUID agentID = client.AgentId;
941 protected bool AreFriendsCached(UUID userID) 952 lock (m_Friends)
953 {
954 UserFriendData friendsData;
955 if (m_Friends.TryGetValue(agentID, out friendsData))
956 friendsData.Friends = GetFriendsFromService(client);
957 }
958 }
959
960 public bool AreFriendsCached(UUID userID)
942 { 961 {
943 lock (m_Friends) 962 lock (m_Friends)
944 return m_Friends.ContainsKey(userID); 963 return m_Friends.ContainsKey(userID);
@@ -957,8 +976,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
957 976
958 protected virtual void StoreFriendships(UUID agentID, UUID friendID) 977 protected virtual void StoreFriendships(UUID agentID, UUID friendID)
959 { 978 {
960 FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), 1); 979 FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), (int)FriendRights.CanSeeOnline);
961 FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 1); 980 FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), (int)FriendRights.CanSeeOnline);
962 } 981 }
963 982
964 protected virtual bool DeleteFriendship(UUID agentID, UUID exfriendID) 983 protected virtual bool DeleteFriendship(UUID agentID, UUID exfriendID)
@@ -969,61 +988,5 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
969 } 988 }
970 989
971 #endregion 990 #endregion
972
973 protected void HandleFriendsShowCacheCommand(string module, string[] cmd)
974 {
975 if (cmd.Length != 5)
976 {
977 MainConsole.Instance.OutputFormat("Usage: friends show cache [<first-name> <last-name>]");
978 return;
979 }
980
981 string firstName = cmd[3];
982 string lastName = cmd[4];
983
984 IUserManagement umModule = m_Scenes[0].RequestModuleInterface<IUserManagement>();
985 UUID userId = umModule.GetUserIdByName(firstName, lastName);
986
987// UserAccount ua
988// = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, firstName, lastName);
989
990 if (userId == UUID.Zero)
991 {
992 MainConsole.Instance.OutputFormat("No such user as {0} {1}", firstName, lastName);
993 return;
994 }
995
996 if (!AreFriendsCached(userId))
997 {
998 MainConsole.Instance.OutputFormat("No friends cached on this simulator for {0} {1}", firstName, lastName);
999 return;
1000 }
1001
1002 MainConsole.Instance.OutputFormat("Cached friends for {0} {1}:", firstName, lastName);
1003
1004 MainConsole.Instance.OutputFormat("UUID\n");
1005
1006 FriendInfo[] friends = GetFriends(userId);
1007
1008 foreach (FriendInfo friend in friends)
1009 {
1010// MainConsole.Instance.OutputFormat(friend.PrincipalID.ToString());
1011
1012// string friendFirstName, friendLastName;
1013//
1014// UserAccount friendUa
1015// = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, friend.PrincipalID);
1016
1017 UUID friendId;
1018 string friendName;
1019
1020 if (UUID.TryParse(friend.Friend, out friendId))
1021 friendName = umModule.GetUserName(friendId);
1022 else
1023 friendName = friend.Friend;
1024
1025 MainConsole.Instance.OutputFormat("{0} {1} {2}", friendName, friend.MyFlags, friend.TheirFlags);
1026 }
1027 }
1028 } 991 }
1029} 992}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
index 7bc3018..9a6d277 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
@@ -105,12 +105,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
105 105
106 #endregion 106 #endregion
107 107
108 protected override void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) 108 protected override void OnApproveFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
109 { 109 {
110 // Update the local cache. Yes, we need to do it right here 110 // Update the local cache. Yes, we need to do it right here
111 // because the HGFriendsService placed something on the DB 111 // because the HGFriendsService placed something on the DB
112 // from under the sim 112 // from under the sim
113 base.OnApproveFriendRequest(client, agentID, friendID, callingCardFolders); 113 base.OnApproveFriendRequest(client, friendID, callingCardFolders);
114 } 114 }
115 115
116 protected override bool CacheFriends(IClientAPI client) 116 protected override bool CacheFriends(IClientAPI client)
@@ -121,7 +121,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
121 { 121 {
122 UUID agentID = client.AgentId; 122 UUID agentID = client.AgentId;
123 // we do this only for the root agent 123 // we do this only for the root agent
124 if (!client.SceneAgent.IsChildAgent) 124 if (m_Friends[agentID].Refcount == 1)
125 { 125 {
126 // We need to preload the user management cache with the names 126 // We need to preload the user management cache with the names
127 // of foreign friends, just like we do with SOPs' creators 127 // of foreign friends, just like we do with SOPs' creators
@@ -163,7 +163,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
163 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, client.AgentId); 163 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, client.AgentId);
164 if (account == null) // foreign 164 if (account == null) // foreign
165 { 165 {
166 FriendInfo[] friends = GetFriends(client.AgentId); 166 FriendInfo[] friends = GetFriendsFromCache(client.AgentId);
167 foreach (FriendInfo f in friends) 167 foreach (FriendInfo f in friends)
168 { 168 {
169 client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, f.TheirFlags); 169 client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, f.TheirFlags);
@@ -300,8 +300,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
300 return null; 300 return null;
301 } 301 }
302 302
303 303 public override FriendInfo[] GetFriendsFromService(IClientAPI client)
304 protected override FriendInfo[] GetFriendsFromService(IClientAPI client)
305 { 304 {
306// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); 305// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name);
307 Boolean agentIsLocal = true; 306 Boolean agentIsLocal = true;
@@ -346,7 +345,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
346 345
347 if (agentIsLocal) // agent is local, friend is foreigner 346 if (agentIsLocal) // agent is local, friend is foreigner
348 { 347 {
349 FriendInfo[] finfos = GetFriends(agentID); 348 FriendInfo[] finfos = GetFriendsFromCache(agentID);
350 FriendInfo finfo = GetFriend(finfos, friendID); 349 FriendInfo finfo = GetFriend(finfos, friendID);
351 if (finfo != null) 350 if (finfo != null)
352 { 351 {
@@ -426,14 +425,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
426 agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode); 425 agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode);
427 agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); 426 agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit);
428 agentFriendService = agentClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); 427 agentFriendService = agentClientCircuit.ServiceURLs["FriendsServerURI"].ToString();
429 CacheFriends(agentClient); 428 RecacheFriends(agentClient);
430 } 429 }
431 if (friendClient != null) 430 if (friendClient != null)
432 { 431 {
433 friendClientCircuit = ((Scene)(friendClient.Scene)).AuthenticateHandler.GetAgentCircuitData(friendClient.CircuitCode); 432 friendClientCircuit = ((Scene)(friendClient.Scene)).AuthenticateHandler.GetAgentCircuitData(friendClient.CircuitCode);
434 friendUUI = Util.ProduceUserUniversalIdentifier(friendClientCircuit); 433 friendUUI = Util.ProduceUserUniversalIdentifier(friendClientCircuit);
435 friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); 434 friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString();
436 CacheFriends(friendClient); 435 RecacheFriends(friendClient);
437 } 436 }
438 437
439 m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", 438 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
453 bool confirming = false; 452 bool confirming = false;
454 if (friendUUI == string.Empty) 453 if (friendUUI == string.Empty)
455 { 454 {
456 finfos = GetFriends(agentID); 455 finfos = GetFriendsFromCache(agentID);
457 foreach (FriendInfo finfo in finfos) 456 foreach (FriendInfo finfo in finfos)
458 { 457 {
459 if (finfo.TheirFlags == -1) 458 if (finfo.TheirFlags == -1)
@@ -546,7 +545,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
546 // Delete any previous friendship relations 545 // Delete any previous friendship relations
547 FriendInfo[] finfos = null; 546 FriendInfo[] finfos = null;
548 FriendInfo f = null; 547 FriendInfo f = null;
549 finfos = GetFriends(a1); 548 finfos = GetFriendsFromCache(a1);
550 if (finfos != null) 549 if (finfos != null)
551 { 550 {
552 f = GetFriend(finfos, a2); 551 f = GetFriend(finfos, a2);
@@ -558,7 +557,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
558 } 557 }
559 } 558 }
560 559
561 finfos = GetFriends(a2); 560 finfos = GetFriendsFromCache(a2);
562 if (finfos != null) 561 if (finfos != null)
563 { 562 {
564 f = GetFriend(finfos, a1); 563 f = GetFriend(finfos, a1);
@@ -595,7 +594,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
595 if (agentIsLocal) // agent is local, 'friend' is foreigner 594 if (agentIsLocal) // agent is local, 'friend' is foreigner
596 { 595 {
597 // We need to look for its information in the friends list itself 596 // We need to look for its information in the friends list itself
598 FriendInfo[] finfos = GetFriends(agentID); 597 FriendInfo[] finfos = GetFriendsFromCache(agentID);
599 FriendInfo finfo = GetFriend(finfos, exfriendID); 598 FriendInfo finfo = GetFriend(finfos, exfriendID);
600 if (finfo != null) 599 if (finfo != null)
601 { 600 {
@@ -639,7 +638,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
639 private string GetUUI(UUID localUser, UUID foreignUser) 638 private string GetUUI(UUID localUser, UUID foreignUser)
640 { 639 {
641 // Let's see if the user is here by any chance 640 // Let's see if the user is here by any chance
642 FriendInfo[] finfos = GetFriends(localUser); 641 FriendInfo[] finfos = GetFriendsFromCache(localUser);
643 if (finfos != EMPTY_FRIENDS) // friend is here, cool 642 if (finfos != EMPTY_FRIENDS) // friend is here, cool
644 { 643 {
645 FriendInfo finfo = GetFriend(finfos, foreignUser); 644 FriendInfo finfo = GetFriend(finfos, foreignUser);
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
index 682fbab..45b4264 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs
@@ -30,6 +30,7 @@ using System.Collections.Generic;
30using Nini.Config; 30using Nini.Config;
31using NUnit.Framework; 31using NUnit.Framework;
32using OpenMetaverse; 32using OpenMetaverse;
33using OpenSim.Data.Null;
33using OpenSim.Framework; 34using OpenSim.Framework;
34using OpenSim.Region.CoreModules.Avatar.Friends; 35using OpenSim.Region.CoreModules.Avatar.Friends;
35using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
@@ -44,9 +45,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
44 private FriendsModule m_fm; 45 private FriendsModule m_fm;
45 private TestScene m_scene; 46 private TestScene m_scene;
46 47
48 [TestFixtureSetUp]
49 public void FixtureInit()
50 {
51 // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
52 Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
53 }
54
55 [TestFixtureTearDown]
56 public void TearDown()
57 {
58 // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
59 // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
60 // tests really shouldn't).
61 Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
62 }
63
47 [SetUp] 64 [SetUp]
48 public void Init() 65 public void Init()
49 { 66 {
67 // We must clear friends data between tests since Data.Null holds it in static properties. This is necessary
68 // so that different services and simulator can share the data in standalone mode. This is pretty horrible
69 // effectively the statics are global variables.
70 NullFriendsData.Clear();
71
50 IConfigSource config = new IniConfigSource(); 72 IConfigSource config = new IniConfigSource();
51 config.AddConfig("Modules"); 73 config.AddConfig("Modules");
52 // Not strictly necessary since FriendsModule assumes it is the default (!) 74 // Not strictly necessary since FriendsModule assumes it is the default (!)
@@ -62,7 +84,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
62 } 84 }
63 85
64 [Test] 86 [Test]
65 public void TestNoFriends() 87 public void TestLoginWithNoFriends()
66 { 88 {
67 TestHelpers.InMethod(); 89 TestHelpers.InMethod();
68// log4net.Config.XmlConfigurator.Configure(); 90// log4net.Config.XmlConfigurator.Configure();
@@ -76,6 +98,76 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
76 } 98 }
77 99
78 [Test] 100 [Test]
101 public void TestLoginWithOfflineFriends()
102 {
103 TestHelpers.InMethod();
104// log4net.Config.XmlConfigurator.Configure();
105
106 UUID user1Id = TestHelpers.ParseTail(0x1);
107 UUID user2Id = TestHelpers.ParseTail(0x2);
108
109// UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id);
110// UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id);
111//
112// m_fm.AddFriendship(user1Id, user2Id);
113
114 ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id);
115 ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id);
116
117 m_fm.AddFriendship(sp1.ControllingClient, user2Id);
118
119 // Not necessary for this test. CanSeeOnline is automatically granted.
120// m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline);
121
122 // We must logout from the client end so that the presence service is correctly updated by the presence
123 // detector. This is listening to the OnConnectionClosed event on the client.
124 ((TestClient)sp1.ControllingClient).Logout();
125 ((TestClient)sp2.ControllingClient).Logout();
126// m_scene.RemoveClient(sp1.UUID, true);
127// m_scene.RemoveClient(sp2.UUID, true);
128
129 ScenePresence sp1Redux = SceneHelpers.AddScenePresence(m_scene, user1Id);
130
131 // We don't expect to receive notifications of offline friends on login, just online.
132 Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0));
133 Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(0));
134 }
135
136 [Test]
137 public void TestLoginWithOnlineFriends()
138 {
139 TestHelpers.InMethod();
140// log4net.Config.XmlConfigurator.Configure();
141
142 UUID user1Id = TestHelpers.ParseTail(0x1);
143 UUID user2Id = TestHelpers.ParseTail(0x2);
144
145// UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id);
146// UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id);
147//
148// m_fm.AddFriendship(user1Id, user2Id);
149
150 ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id);
151 ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id);
152
153 m_fm.AddFriendship(sp1.ControllingClient, user2Id);
154
155 // Not necessary for this test. CanSeeOnline is automatically granted.
156// m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline);
157
158 // We must logout from the client end so that the presence service is correctly updated by the presence
159 // detector. This is listening to the OnConnectionClosed event on the client.
160// ((TestClient)sp1.ControllingClient).Logout();
161 ((TestClient)sp2.ControllingClient).Logout();
162// m_scene.RemoveClient(user2Id, true);
163
164 ScenePresence sp2Redux = SceneHelpers.AddScenePresence(m_scene, user2Id);
165
166 Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0));
167 Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(1));
168 }
169
170 [Test]
79 public void TestAddFriendshipWhileOnline() 171 public void TestAddFriendshipWhileOnline()
80 { 172 {
81 TestHelpers.InMethod(); 173 TestHelpers.InMethod();