aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs541
1 files changed, 14 insertions, 527 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 580e06f..fceca8e 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -44,109 +44,14 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion;
44 44
45namespace OpenSim.Region.CoreModules.Avatar.Friends 45namespace OpenSim.Region.CoreModules.Avatar.Friends
46{ 46{
47 /* 47 public class FriendsModule : ISharedRegionModule, IFriendsModule
48 This module handles adding/removing friends, and the the presence
49 notification process for login/logoff of friends.
50
51 The presence notification works as follows:
52 - After the user initially connects to a region (so we now have a UDP
53 connection to work with), this module fetches the friends of user
54 (those are cached), their on-/offline status, and info about the
55 region they are in from the MessageServer.
56 - (*) It then informs the user about the on-/offline status of her friends.
57 - It then informs all online friends currently on this region-server about
58 user's new online status (this will save some network traffic, as local
59 messages don't have to be transferred inter-region, and it will be all
60 that has to be done in Standalone Mode).
61 - For the rest of the online friends (those not on this region-server),
62 this module uses the provided region-information to map users to
63 regions, and sends one notification to every region containing the
64 friends to inform on that server.
65 - The region-server will handle that in the following way:
66 - If it finds the friend, it informs her about the user being online.
67 - If it doesn't find the friend (maybe she TPed away in the meantime),
68 it stores that information.
69 - After it processed all friends, it returns the list of friends it
70 couldn't find.
71 - If this list isn't empty, the FriendsModule re-requests information
72 about those online friends that have been missed and starts at (*)
73 again until all friends have been found, or until it tried 3 times
74 (to prevent endless loops due to some uncaught error).
75
76 NOTE: Online/Offline notifications don't need to be sent on region change.
77
78 We implement two XMLRpc handlers here, handling all the inter-region things
79 we have to handle:
80 - On-/Offline-Notifications (bulk)
81 - Terminate Friendship messages (single)
82 */
83
84 public class FriendsModule : IRegionModule, IFriendsModule
85 { 48 {
86 private class Transaction 49 public void Initialise(IConfigSource config)
87 { 50 {
88 public UUID agentID;
89 public string agentName;
90 public uint count;
91
92 public Transaction(UUID agentID, string agentName)
93 {
94 this.agentID = agentID;
95 this.agentName = agentName;
96 this.count = 1;
97 }
98 }
99
100 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
101
102 private Cache m_friendLists = new Cache(CacheFlags.AllowUpdate);
103
104 private Dictionary<UUID, ulong> m_rootAgents = new Dictionary<UUID, ulong>();
105
106 private Dictionary<UUID, UUID> m_pendingCallingcardRequests = new Dictionary<UUID,UUID>();
107
108 private Scene m_initialScene; // saves a lookup if we don't have a specific scene
109 private Dictionary<ulong, Scene> m_scenes = new Dictionary<ulong,Scene>();
110 private IMessageTransferModule m_TransferModule = null;
111
112 private IGridService m_gridServices = null;
113
114 #region IRegionModule Members
115
116 public void Initialise(Scene scene, IConfigSource config)
117 {
118 lock (m_scenes)
119 {
120 if (m_scenes.Count == 0)
121 {
122 MainServer.Instance.AddXmlRPCHandler("presence_update_bulk", processPresenceUpdateBulk);
123 MainServer.Instance.AddXmlRPCHandler("terminate_friend", processTerminateFriend);
124 m_friendLists.DefaultTTL = new TimeSpan(1, 0, 0); // store entries for one hour max
125 m_initialScene = scene;
126 }
127
128 if (!m_scenes.ContainsKey(scene.RegionInfo.RegionHandle))
129 m_scenes[scene.RegionInfo.RegionHandle] = scene;
130 }
131
132 scene.RegisterModuleInterface<IFriendsModule>(this);
133
134 scene.EventManager.OnNewClient += OnNewClient;
135 scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
136 scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel;
137 scene.EventManager.OnMakeChildAgent += MakeChildAgent;
138 scene.EventManager.OnClientClosed += ClientClosed;
139 } 51 }
140 52
141 public void PostInitialise() 53 public void PostInitialise()
142 { 54 {
143 if (m_scenes.Count > 0)
144 {
145 m_TransferModule = m_initialScene.RequestModuleInterface<IMessageTransferModule>();
146 m_gridServices = m_initialScene.GridService;
147 }
148 if (m_TransferModule == null)
149 m_log.Error("[FRIENDS]: Unable to find a message transfer module, friendship offers will not work");
150 } 55 }
151 56
152 public void Close() 57 public void Close()
@@ -674,448 +579,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
674 // ... and add the calling card 579 // ... and add the calling card
675 CreateCallingCard(initiator.ControllingClient, fromAgentID, folder.ID, fromName); 580 CreateCallingCard(initiator.ControllingClient, fromAgentID, folder.ID, fromName);
676 } 581 }
582>>>>>>> master:OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
677 } 583 }
678 584
679 private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) 585 public void AddRegion(Scene scene)
680 {
681 m_log.DebugFormat("[FRIEND]: Got approve friendship from {0} {1}, agentID {2}, tid {3}",
682 client.Name, client.AgentId, agentID, friendID);
683
684 // store the new friend persistently for both avatars
685 m_initialScene.StoreAddFriendship(friendID, agentID, (uint) FriendRights.CanSeeOnline);
686
687 // The cache entries aren't valid anymore either, as we just added a friend to both sides.
688 lock (m_friendLists)
689 {
690 m_friendLists.Invalidate(agentID.ToString());
691 m_friendLists.Invalidate(friendID.ToString());
692 }
693
694 // if it's a local friend, we don't have to do the lookup
695 ScenePresence friendPresence = GetAnyPresenceFromAgentID(friendID);
696
697 if (friendPresence != null)
698 {
699 m_log.Debug("[FRIEND]: Local agent detected.");
700
701 // create calling card
702 CreateCallingCard(client, friendID, callingCardFolders[0], friendPresence.Name);
703
704 // local message means OnGridInstantMessage won't be triggered, so do the work here.
705 friendPresence.ControllingClient.SendInstantMessage(
706 new GridInstantMessage(client.Scene, agentID,
707 client.Name, friendID,
708 (byte)InstantMessageDialog.FriendshipAccepted,
709 agentID.ToString(), false, Vector3.Zero));
710 ApproveFriendship(agentID, friendID, client.Name);
711 }
712 else
713 {
714 m_log.Debug("[FRIEND]: Remote agent detected.");
715
716 // fetch the friend's name for the calling card.
717 CachedUserInfo info = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(friendID);
718
719 // create calling card
720 CreateCallingCard(client, friendID, callingCardFolders[0],
721 info.UserProfile.FirstName + " " + info.UserProfile.SurName);
722
723 // Compose (remote) response to friend.
724 GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID,
725 (byte)InstantMessageDialog.FriendshipAccepted,
726 agentID.ToString(), false, Vector3.Zero);
727 if (m_TransferModule != null)
728 {
729 m_TransferModule.SendInstantMessage(msg,
730 delegate(bool success) {
731 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
732 }
733 );
734 }
735 }
736
737 // tell client that new friend is online
738 client.SendAgentOnline(new UUID[] { friendID });
739 }
740
741 private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
742 {
743 m_log.DebugFormat("[FRIEND]: Got deny friendship from {0} {1}, agentID {2}, tid {3}",
744 client.Name, client.AgentId, agentID, friendID);
745
746 // Compose response to other agent.
747 GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID,
748 (byte)InstantMessageDialog.FriendshipDeclined,
749 agentID.ToString(), false, Vector3.Zero);
750 // send decline to initiator
751 if (m_TransferModule != null)
752 {
753 m_TransferModule.SendInstantMessage(msg,
754 delegate(bool success) {
755 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
756 }
757 );
758 }
759 }
760
761 private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID)
762 {
763 // client.AgentId == agentID!
764
765 // this removes the friends from the stored friendlists. After the next login, they will be gone...
766 m_initialScene.StoreRemoveFriendship(agentID, exfriendID);
767
768 // ... now tell the two involved clients that they aren't friends anymore.
769
770 // I don't know why we have to tell <agent>, as this was caused by her, but that's how it works in SL...
771 client.SendTerminateFriend(exfriendID);
772
773 // now send the friend, if online
774 ScenePresence presence = GetAnyPresenceFromAgentID(exfriendID);
775 if (presence != null)
776 {
777 m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", agentID, exfriendID);
778 presence.ControllingClient.SendTerminateFriend(agentID);
779 }
780 else
781 {
782 // retry 3 times, in case the agent TPed from the last known region...
783 for (int retry = 0; retry < 3; ++retry)
784 {
785 // wasn't sent, so ex-friend wasn't around on this region-server. Fetch info and try to send
786 UserAgentData data = m_initialScene.CommsManager.UserService.GetAgentByUUID(exfriendID);
787
788 if (null == data)
789 break;
790
791 if (!data.AgentOnline)
792 {
793 m_log.DebugFormat("[FRIEND]: {0} is offline, so not sending TerminateFriend", exfriendID);
794 break; // if ex-friend isn't online, we don't need to send
795 }
796
797 m_log.DebugFormat("[FRIEND]: Sending remote terminate friend {0} to agent {1}@{2}",
798 agentID, exfriendID, data.Handle);
799
800 // try to send to foreign region, retry if it fails (friend TPed away, for example)
801 if (TriggerTerminateFriend(data.Handle, exfriendID, agentID)) break;
802 }
803 }
804
805 // clean up cache: FriendList is wrong now...
806 lock (m_friendLists)
807 {
808 m_friendLists.Invalidate(agentID.ToString());
809 m_friendLists.Invalidate(exfriendID.ToString());
810 }
811 }
812
813 #endregion
814
815 #region CallingCards
816
817 private void OnOfferCallingCard(IClientAPI client, UUID destID, UUID transactionID)
818 { 586 {
819 m_log.DebugFormat("[CALLING CARD]: got offer from {0} for {1}, transaction {2}",
820 client.AgentId, destID, transactionID);
821 // This might be slightly wrong. On a multi-region server, we might get the child-agent instead of the root-agent
822 // (or the root instead of the child)
823 ScenePresence destAgent = GetAnyPresenceFromAgentID(destID);
824 if (destAgent == null)
825 {
826 client.SendAlertMessage("The person you have offered a card to can't be found anymore.");
827 return;
828 }
829
830 lock (m_pendingCallingcardRequests)
831 {
832 m_pendingCallingcardRequests[transactionID] = client.AgentId;
833 }
834 // inform the destination agent about the offer
835 destAgent.ControllingClient.SendOfferCallingCard(client.AgentId, transactionID);
836 } 587 }
837 588
838 private void CreateCallingCard(IClientAPI client, UUID creator, UUID folder, string name) 589 public void RegionLoaded(Scene scene)
839 { 590 {
840 InventoryItemBase item = new InventoryItemBase();
841 item.AssetID = UUID.Zero;
842 item.AssetType = (int)AssetType.CallingCard;
843 item.BasePermissions = (uint)PermissionMask.Copy;
844 item.CreationDate = Util.UnixTimeSinceEpoch();
845 item.CreatorId = creator.ToString();
846 item.CurrentPermissions = item.BasePermissions;
847 item.Description = "";
848 item.EveryOnePermissions = (uint)PermissionMask.None;
849 item.Flags = 0;
850 item.Folder = folder;
851 item.GroupID = UUID.Zero;
852 item.GroupOwned = false;
853 item.ID = UUID.Random();
854 item.InvType = (int)InventoryType.CallingCard;
855 item.Name = name;
856 item.NextPermissions = item.EveryOnePermissions;
857 item.Owner = client.AgentId;
858 item.SalePrice = 10;
859 item.SaleType = (byte)SaleType.Not;
860 ((Scene)client.Scene).AddInventoryItem(client, item);
861 } 591 }
862 592
863 private void OnAcceptCallingCard(IClientAPI client, UUID transactionID, UUID folderID) 593 public void RemoveRegion(Scene scene)
864 { 594 {
865 m_log.DebugFormat("[CALLING CARD]: User {0} ({1} {2}) accepted tid {3}, folder {4}",
866 client.AgentId,
867 client.FirstName, client.LastName,
868 transactionID, folderID);
869 UUID destID;
870 lock (m_pendingCallingcardRequests)
871 {
872 if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID))
873 {
874 m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.",
875 client.Name);
876 return;
877 }
878 // else found pending calling card request with that transaction.
879 m_pendingCallingcardRequests.Remove(transactionID);
880 }
881
882
883 ScenePresence destAgent = GetAnyPresenceFromAgentID(destID);
884 // inform sender of the card that destination declined the offer
885 if (destAgent != null) destAgent.ControllingClient.SendAcceptCallingCard(transactionID);
886
887 // put a calling card into the inventory of receiver
888 CreateCallingCard(client, destID, folderID, destAgent.Name);
889 } 595 }
890 596
891 private void OnDeclineCallingCard(IClientAPI client, UUID transactionID) 597 public void Close()
892 { 598 {
893 m_log.DebugFormat("[CALLING CARD]: User {0} (ID:{1}) declined card, tid {2}",
894 client.Name, client.AgentId, transactionID);
895 UUID destID;
896 lock (m_pendingCallingcardRequests)
897 {
898 if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID))
899 {
900 m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.",
901 client.Name);
902 return;
903 }
904 // else found pending calling card request with that transaction.
905 m_pendingCallingcardRequests.Remove(transactionID);
906 }
907
908 ScenePresence destAgent = GetAnyPresenceFromAgentID(destID);
909 // inform sender of the card that destination declined the offer
910 if (destAgent != null) destAgent.ControllingClient.SendDeclineCallingCard(transactionID);
911 } 599 }
912 600
913 /// <summary> 601 public string Name
914 /// Send presence information about a client to other clients in both this region and others.
915 /// </summary>
916 /// <param name="client"></param>
917 /// <param name="friendList"></param>
918 /// <param name="iAmOnline"></param>
919 private void SendPresenceState(IClientAPI client, List<FriendListItem> friendList, bool iAmOnline)
920 { 602 {
921 //m_log.DebugFormat("[FRIEND]: {0} logged {1}; sending presence updates", client.Name, iAmOnline ? "in" : "out"); 603 get { return "FriendsModule"; }
922
923 if (friendList == null || friendList.Count == 0)
924 {
925 //m_log.DebugFormat("[FRIEND]: {0} doesn't have friends.", client.Name);
926 return; // nothing we can do if she doesn't have friends...
927 }
928
929 // collect sets of friendIDs; to send to (online and offline), and to receive from
930 // TODO: If we ever switch to .NET >= 3, replace those Lists with HashSets.
931 // I can't believe that we have Dictionaries, but no Sets, considering Java introduced them years ago...
932 List<UUID> friendIDsToSendTo = new List<UUID>();
933 List<UUID> candidateFriendIDsToReceive = new List<UUID>();
934
935 foreach (FriendListItem item in friendList)
936 {
937 if (((item.FriendListOwnerPerms | item.FriendPerms) & (uint)FriendRights.CanSeeOnline) != 0)
938 {
939 // friend is allowed to see my presence => add
940 if ((item.FriendListOwnerPerms & (uint)FriendRights.CanSeeOnline) != 0)
941 friendIDsToSendTo.Add(item.Friend);
942
943 if ((item.FriendPerms & (uint)FriendRights.CanSeeOnline) != 0)
944 candidateFriendIDsToReceive.Add(item.Friend);
945 }
946 }
947
948 // we now have a list of "interesting" friends (which we have to find out on-/offline state for),
949 // friends we want to send our online state to (if *they* are online, too), and
950 // friends we want to receive online state for (currently unknown whether online or not)
951
952 // as this processing might take some time and friends might TP away, we try up to three times to
953 // reach them. Most of the time, we *will* reach them, and this loop won't loop
954 int retry = 0;
955 do
956 {
957 // build a list of friends to look up region-information and on-/offline-state for
958 List<UUID> friendIDsToLookup = new List<UUID>(friendIDsToSendTo);
959 foreach (UUID uuid in candidateFriendIDsToReceive)
960 {
961 if (!friendIDsToLookup.Contains(uuid)) friendIDsToLookup.Add(uuid);
962 }
963
964 m_log.DebugFormat(
965 "[FRIEND]: {0} to lookup, {1} to send to, {2} candidates to receive from for agent {3}",
966 friendIDsToLookup.Count, friendIDsToSendTo.Count, candidateFriendIDsToReceive.Count, client.Name);
967
968 // we have to fetch FriendRegionInfos, as the (cached) FriendListItems don't
969 // necessarily contain the correct online state...
970 Dictionary<UUID, FriendRegionInfo> friendRegions = m_initialScene.GetFriendRegionInfos(friendIDsToLookup);
971 m_log.DebugFormat(
972 "[FRIEND]: Found {0} regionInfos for {1} friends of {2}",
973 friendRegions.Count, friendIDsToLookup.Count, client.Name);
974
975 // argument for SendAgentOn/Offline; we shouldn't generate that repeatedly within loops.
976 UUID[] agentArr = new UUID[] { client.AgentId };
977
978 // first, send to friend presence state to me, if I'm online...
979 if (iAmOnline)
980 {
981 List<UUID> friendIDsToReceive = new List<UUID>();
982
983 for (int i = candidateFriendIDsToReceive.Count - 1; i >= 0; --i)
984 {
985 UUID uuid = candidateFriendIDsToReceive[i];
986 FriendRegionInfo info;
987 if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline)
988 {
989 friendIDsToReceive.Add(uuid);
990 }
991 }
992
993 m_log.DebugFormat(
994 "[FRIEND]: Sending {0} online friends to {1}", friendIDsToReceive.Count, client.Name);
995
996 if (friendIDsToReceive.Count > 0)
997 client.SendAgentOnline(friendIDsToReceive.ToArray());
998
999 // clear them for a possible second iteration; we don't have to repeat this
1000 candidateFriendIDsToReceive.Clear();
1001 }
1002
1003 // now, send my presence state to my friends
1004 for (int i = friendIDsToSendTo.Count - 1; i >= 0; --i)
1005 {
1006 UUID uuid = friendIDsToSendTo[i];
1007 FriendRegionInfo info;
1008 if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline)
1009 {
1010 // any client is good enough, root or child...
1011 ScenePresence agent = GetAnyPresenceFromAgentID(uuid);
1012 if (agent != null)
1013 {
1014 //m_log.DebugFormat("[FRIEND]: Found local agent {0}", agent.Name);
1015
1016 // friend is online and on this server...
1017 if (iAmOnline) agent.ControllingClient.SendAgentOnline(agentArr);
1018 else agent.ControllingClient.SendAgentOffline(agentArr);
1019
1020 // done, remove it
1021 friendIDsToSendTo.RemoveAt(i);
1022 }
1023 }
1024 else
1025 {
1026 //m_log.DebugFormat("[FRIEND]: Friend {0} ({1}) is offline; not sending.", uuid, i);
1027
1028 // friend is offline => no need to try sending
1029 friendIDsToSendTo.RemoveAt(i);
1030 }
1031 }
1032
1033 m_log.DebugFormat("[FRIEND]: Have {0} friends to contact via inter-region comms.", friendIDsToSendTo.Count);
1034
1035 // we now have all the friends left that are online (we think), but not on this region-server
1036 if (friendIDsToSendTo.Count > 0)
1037 {
1038 // sort them into regions
1039 Dictionary<ulong, List<UUID>> friendsInRegion = new Dictionary<ulong,List<UUID>>();
1040 foreach (UUID uuid in friendIDsToSendTo)
1041 {
1042 ulong handle = friendRegions[uuid].regionHandle; // this can't fail as we filtered above already
1043 List<UUID> friends;
1044 if (!friendsInRegion.TryGetValue(handle, out friends))
1045 {
1046 friends = new List<UUID>();
1047 friendsInRegion[handle] = friends;
1048 }
1049 friends.Add(uuid);
1050 }
1051 m_log.DebugFormat("[FRIEND]: Found {0} regions to send to.", friendRegions.Count);
1052
1053 // clear uuids list and collect missed friends in it for the next retry
1054 friendIDsToSendTo.Clear();
1055
1056 // send bulk updates to the region
1057 foreach (KeyValuePair<ulong, List<UUID>> pair in friendsInRegion)
1058 {
1059 //m_log.DebugFormat("[FRIEND]: Inform {0} friends in region {1} that user {2} is {3}line",
1060 // pair.Value.Count, pair.Key, client.Name, iAmOnline ? "on" : "off");
1061
1062 friendIDsToSendTo.AddRange(InformFriendsInOtherRegion(client.AgentId, pair.Key, pair.Value, iAmOnline));
1063 }
1064 }
1065 // now we have in friendIDsToSendTo only the agents left that TPed away while we tried to contact them.
1066 // In most cases, it will be empty, and it won't loop here. But sometimes, we have to work harder and try again...
1067 }
1068 while (++retry < 3 && friendIDsToSendTo.Count > 0);
1069 } 604 }
1070 605
1071 private void OnEconomyDataRequest(UUID agentID) 606 public Type ReplaceableInterface
1072 { 607 {
1073 // KLUDGE: This is the only way I found to get a message (only) after login was completed and the 608 get { return null; }
1074 // client is connected enough to receive UDP packets).
1075 // This packet seems to be sent only once, just after connection was established to the first
1076 // region after login.
1077 // We use it here to trigger a presence update; the old update-on-login was never be heard by
1078 // the freshly logged in viewer, as it wasn't connected to the region at that time.
1079 // TODO: Feel free to replace this by a better solution if you find one.
1080
1081 // get the agent. This should work every time, as we just got a packet from it
1082 //ScenePresence agent = GetRootPresenceFromAgentID(agentID);
1083 // KLUDGE 2: As this is sent quite early, the avatar isn't here as root agent yet. So, we have to cheat a bit
1084 ScenePresence agent = GetAnyPresenceFromAgentID(agentID);
1085
1086 // just to be paranoid...
1087 if (agent == null)
1088 {
1089 m_log.ErrorFormat("[FRIEND]: Got a packet from agent {0} who can't be found anymore!?", agentID);
1090 return;
1091 }
1092
1093 List<FriendListItem> fl;
1094 lock (m_friendLists)
1095 {
1096 fl = (List<FriendListItem>)m_friendLists.Get(agent.ControllingClient.AgentId.ToString(),
1097 m_initialScene.GetFriendList);
1098 }
1099
1100 // tell everyone that we are online
1101 SendPresenceState(agent.ControllingClient, fl, true);
1102 } 609 }
1103 610
1104 private void OnLogout(IClientAPI remoteClient) 611 public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient,
612 string offerMessage)
1105 { 613 {
1106 List<FriendListItem> fl;
1107 lock (m_friendLists)
1108 {
1109 fl = (List<FriendListItem>)m_friendLists.Get(remoteClient.AgentId.ToString(),
1110 m_initialScene.GetFriendList);
1111 }
1112
1113 // tell everyone that we are offline
1114 SendPresenceState(remoteClient, fl, false);
1115 }
1116 private void GrantUserFriendRights(IClientAPI remoteClient, UUID requester, UUID target, int rights)
1117 {
1118 ((Scene)remoteClient.Scene).CommsManager.UpdateUserFriendPerms(requester, target, (uint)rights);
1119 } 614 }
1120 public void FindAgent(IClientAPI remoteClient, UUID hunter, UUID target) 615 public void FindAgent(IClientAPI remoteClient, UUID hunter, UUID target)
1121 { 616 {
@@ -1140,15 +635,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
1140 635
1141 public List<FriendListItem> GetUserFriends(UUID agentID) 636 public List<FriendListItem> GetUserFriends(UUID agentID)
1142 { 637 {
1143 List<FriendListItem> fl; 638 return null;
1144 lock (m_friendLists)
1145 {
1146 fl = (List<FriendListItem>)m_friendLists.Get(agentID.ToString(),
1147 m_initialScene.GetFriendList);
1148 }
1149
1150 return fl;
1151 } 639 }
1152 } 640 }
1153 #endregion
1154} 641}