aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Avatar/Friends
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs353
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs599
2 files changed, 837 insertions, 115 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index 5baf078..f82716d 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -49,6 +49,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
49{ 49{
50 public class FriendsModule : ISharedRegionModule, IFriendsModule 50 public class FriendsModule : ISharedRegionModule, IFriendsModule
51 { 51 {
52 protected bool m_Enabled = false;
53
52 protected class UserFriendData 54 protected class UserFriendData
53 { 55 {
54 public UUID PrincipalID; 56 public UUID PrincipalID;
@@ -67,7 +69,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
67 } 69 }
68 } 70 }
69 71
70 private static readonly FriendInfo[] EMPTY_FRIENDS = new FriendInfo[0]; 72 protected static readonly FriendInfo[] EMPTY_FRIENDS = new FriendInfo[0];
71 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 73 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
72 74
73 protected List<Scene> m_Scenes = new List<Scene>(); 75 protected List<Scene> m_Scenes = new List<Scene>();
@@ -130,8 +132,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
130 } 132 }
131 } 133 }
132 134
135 #region ISharedRegionModule
133 public void Initialise(IConfigSource config) 136 public void Initialise(IConfigSource config)
134 { 137 {
138 IConfig moduleConfig = config.Configs["Modules"];
139 if (moduleConfig != null)
140 {
141 string name = moduleConfig.GetString("FriendsModule", "FriendsModule");
142 if (name == Name)
143 {
144 InitModule(config);
145
146 m_Enabled = true;
147 m_log.InfoFormat("[FRIENDS MODULE]: {0} enabled.", Name);
148 }
149 }
150 }
151
152 protected void InitModule(IConfigSource config)
153 {
135 IConfig friendsConfig = config.Configs["Friends"]; 154 IConfig friendsConfig = config.Configs["Friends"];
136 if (friendsConfig != null) 155 if (friendsConfig != null)
137 { 156 {
@@ -153,7 +172,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
153 m_log.Error("[FRIENDS]: No Connector defined in section Friends, or failed to load, cannot continue"); 172 m_log.Error("[FRIENDS]: No Connector defined in section Friends, or failed to load, cannot continue");
154 throw new Exception("Connector load error"); 173 throw new Exception("Connector load error");
155 } 174 }
156
157 } 175 }
158 176
159 public void PostInitialise() 177 public void PostInitialise()
@@ -164,8 +182,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
164 { 182 {
165 } 183 }
166 184
167 public void AddRegion(Scene scene) 185 public virtual void AddRegion(Scene scene)
168 { 186 {
187 if (!m_Enabled)
188 return;
189 m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name);
190
169 m_Scenes.Add(scene); 191 m_Scenes.Add(scene);
170 scene.RegisterModuleInterface<IFriendsModule>(this); 192 scene.RegisterModuleInterface<IFriendsModule>(this);
171 193
@@ -181,10 +203,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
181 203
182 public void RemoveRegion(Scene scene) 204 public void RemoveRegion(Scene scene)
183 { 205 {
206 if (!m_Enabled)
207 return;
208
184 m_Scenes.Remove(scene); 209 m_Scenes.Remove(scene);
185 } 210 }
186 211
187 public string Name 212 public virtual string Name
188 { 213 {
189 get { return "FriendsModule"; } 214 get { return "FriendsModule"; }
190 } 215 }
@@ -194,13 +219,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
194 get { return null; } 219 get { return null; }
195 } 220 }
196 221
197 public uint GetFriendPerms(UUID principalID, UUID friendID) 222 #endregion
223
224 public virtual uint GetFriendPerms(UUID principalID, UUID friendID)
198 { 225 {
199 FriendInfo[] friends = GetFriends(principalID); 226 FriendInfo[] friends = GetFriends(principalID);
200 foreach (FriendInfo fi in friends) 227 FriendInfo finfo = GetFriend(friends, friendID);
228 if (finfo != null)
201 { 229 {
202 if (fi.Friend == friendID.ToString()) 230 return (uint)finfo.TheirFlags;
203 return (uint)fi.TheirFlags;
204 } 231 }
205 232
206 return 0; 233 return 0;
@@ -214,30 +241,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
214 client.OnTerminateFriendship += OnTerminateFriendship; 241 client.OnTerminateFriendship += OnTerminateFriendship;
215 client.OnGrantUserRights += OnGrantUserRights; 242 client.OnGrantUserRights += OnGrantUserRights;
216 243
217 // Asynchronously fetch the friends list or increment the refcount for the existing 244 Util.FireAndForget(delegate { FetchFriendslist(client); });
218 // friends list 245 }
219 Util.FireAndForget( 246
220 delegate(object o) 247 /// Fetch the friends list or increment the refcount for the existing
248 /// friends list
249 /// Returns true if the list was fetched, false if it wasn't
250 protected virtual bool FetchFriendslist(IClientAPI client)
251 {
252 UUID agentID = client.AgentId;
253 lock (m_Friends)
254 {
255 UserFriendData friendsData;
256 if (m_Friends.TryGetValue(agentID, out friendsData))
221 { 257 {
222 lock (m_Friends) 258 friendsData.Refcount++;
223 { 259 return false;
224 UserFriendData friendsData; 260 }
225 if (m_Friends.TryGetValue(client.AgentId, out friendsData)) 261 else
226 { 262 {
227 friendsData.Refcount++; 263 friendsData = new UserFriendData();
228 } 264 friendsData.PrincipalID = agentID;
229 else 265 friendsData.Friends = GetFriendsFromService(client);
230 { 266 friendsData.Refcount = 1;
231 friendsData = new UserFriendData();
232 friendsData.PrincipalID = client.AgentId;
233 friendsData.Friends = FriendsService.GetFriends(client.AgentId);
234 friendsData.Refcount = 1;
235 267
236 m_Friends[client.AgentId] = friendsData; 268 m_Friends[agentID] = friendsData;
237 } 269 return true;
238 }
239 } 270 }
240 ); 271 }
241 } 272 }
242 273
243 private void OnClientClosed(UUID agentID, Scene scene) 274 private void OnClientClosed(UUID agentID, Scene scene)
@@ -263,14 +294,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
263 294
264 private void OnMakeRootAgent(ScenePresence sp) 295 private void OnMakeRootAgent(ScenePresence sp)
265 { 296 {
266 UUID agentID = sp.ControllingClient.AgentId; 297 RefetchFriends(sp.ControllingClient);
267 UpdateFriendsCache(agentID);
268 } 298 }
269 299
270 private void OnClientLogin(IClientAPI client) 300 private void OnClientLogin(IClientAPI client)
271 { 301 {
272 UUID agentID = client.AgentId; 302 UUID agentID = client.AgentId;
273 303
304 //m_log.DebugFormat("[XXX]: OnClientLogin!");
274 // Inform the friends that this user is online 305 // Inform the friends that this user is online
275 StatusChange(agentID, true); 306 StatusChange(agentID, true);
276 307
@@ -279,7 +310,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
279 m_NeedsListOfFriends.Add(agentID); 310 m_NeedsListOfFriends.Add(agentID);
280 } 311 }
281 312
282 public void SendFriendsOnlineIfNeeded(IClientAPI client) 313 public virtual bool SendFriendsOnlineIfNeeded(IClientAPI client)
283 { 314 {
284 UUID agentID = client.AgentId; 315 UUID agentID = client.AgentId;
285 316
@@ -287,7 +318,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
287 lock (m_NeedsListOfFriends) 318 lock (m_NeedsListOfFriends)
288 { 319 {
289 if (!m_NeedsListOfFriends.Remove(agentID)) 320 if (!m_NeedsListOfFriends.Remove(agentID))
290 return; 321 return false;
291 } 322 }
292 323
293 // Send the friends online 324 // Send the friends online
@@ -313,10 +344,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
313 foreach (string fid in outstanding) 344 foreach (string fid in outstanding)
314 { 345 {
315 UUID fromAgentID; 346 UUID fromAgentID;
316 if (!UUID.TryParse(fid, out fromAgentID)) 347 string firstname = "Unknown", lastname = "User";
348 if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname))
349 {
350 m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid);
317 continue; 351 continue;
318 352 }
319 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, fromAgentID);
320 353
321 PresenceInfo presence = null; 354 PresenceInfo presence = null;
322 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { fid }); 355 PresenceInfo[] presences = PresenceService.GetAgents(new string[] { fid });
@@ -326,13 +359,37 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
326 im.offline = 0; 359 im.offline = 0;
327 360
328 im.fromAgentID = fromAgentID.Guid; 361 im.fromAgentID = fromAgentID.Guid;
329 im.fromAgentName = account.FirstName + " " + account.LastName; 362 im.fromAgentName = firstname + " " + lastname;
330 im.offline = (byte)((presence == null) ? 1 : 0); 363 im.offline = (byte)((presence == null) ? 1 : 0);
331 im.imSessionID = im.fromAgentID; 364 im.imSessionID = im.fromAgentID;
365 im.message = FriendshipMessage(fid);
332 366
333 // Finally 367 // Finally
334 LocalFriendshipOffered(agentID, im); 368 LocalFriendshipOffered(agentID, im);
335 } 369 }
370
371 return true;
372 }
373
374 protected virtual string FriendshipMessage(string friendID)
375 {
376 return "Will you be my friend?";
377 }
378
379 protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
380 {
381 first = "Unknown"; last = "User";
382 if (!UUID.TryParse(fid, out agentID))
383 return false;
384
385 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(scopeID, agentID);
386 if (account != null)
387 {
388 first = account.FirstName;
389 last = account.LastName;
390 }
391
392 return true;
336 } 393 }
337 394
338 List<UUID> GetOnlineFriends(UUID userID) 395 List<UUID> GetOnlineFriends(UUID userID)
@@ -348,19 +405,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
348 } 405 }
349 406
350 if (friendList.Count > 0) 407 if (friendList.Count > 0)
351 { 408 GetOnlineFriends(userID, friendList, online);
352 PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
353 foreach (PresenceInfo pi in presence)
354 {
355 UUID presenceID;
356 if (UUID.TryParse(pi.UserID, out presenceID))
357 online.Add(presenceID);
358 }
359 }
360 409
361 return online; 410 return online;
362 } 411 }
363 412
413 protected virtual void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
414 {
415 PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
416 foreach (PresenceInfo pi in presence)
417 {
418 UUID presenceID;
419 if (UUID.TryParse(pi.UserID, out presenceID))
420 online.Add(presenceID);
421 }
422 }
423
364 /// <summary> 424 /// <summary>
365 /// Find the client for a ID 425 /// Find the client for a ID
366 /// </summary> 426 /// </summary>
@@ -415,51 +475,51 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
415 Util.FireAndForget( 475 Util.FireAndForget(
416 delegate 476 delegate
417 { 477 {
418 foreach (FriendInfo fi in friendList) 478 m_log.DebugFormat("[FRIENDS MODULE]: Notifying {0} friends", friendList.Count);
419 { 479 // Notify about this user status
420 //m_log.DebugFormat("[FRIENDS]: Notifying {0}", fi.PrincipalID); 480 StatusNotify(friendList, agentID, online);
421 // Notify about this user status
422 StatusNotify(fi, agentID, online);
423 }
424 } 481 }
425 ); 482 );
426 } 483 }
427 } 484 }
428 485
429 private void StatusNotify(FriendInfo friend, UUID userID, bool online) 486 protected virtual void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
430 { 487 {
431 UUID friendID; 488 foreach (FriendInfo friend in friendList)
432 if (UUID.TryParse(friend.Friend, out friendID))
433 { 489 {
434 // Try local 490 UUID friendID;
435 if (LocalStatusNotification(userID, friendID, online)) 491 if (UUID.TryParse(friend.Friend, out friendID))
436 return;
437
438 // The friend is not here [as root]. Let's forward.
439 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
440 if (friendSessions != null && friendSessions.Length > 0)
441 { 492 {
442 PresenceInfo friendSession = null; 493 // Try local
443 foreach (PresenceInfo pinfo in friendSessions) 494 if (LocalStatusNotification(userID, friendID, online))
444 if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad 495 return;
445 {
446 friendSession = pinfo;
447 break;
448 }
449 496
450 if (friendSession != null) 497 // The friend is not here [as root]. Let's forward.
498 PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
499 if (friendSessions != null && friendSessions.Length > 0)
451 { 500 {
452 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID); 501 PresenceInfo friendSession = null;
453 //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName); 502 foreach (PresenceInfo pinfo in friendSessions)
454 m_FriendsSimConnector.StatusNotify(region, userID, friendID, online); 503 if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad
504 {
505 friendSession = pinfo;
506 break;
507 }
508
509 if (friendSession != null)
510 {
511 GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
512 //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
513 m_FriendsSimConnector.StatusNotify(region, userID, friendID, online);
514 }
455 } 515 }
456 }
457 516
458 // Friend is not online. Ignore. 517 // Friend is not online. Ignore.
459 } 518 }
460 else 519 else
461 { 520 {
462 m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend); 521 m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend);
522 }
463 } 523 }
464 } 524 }
465 525
@@ -475,7 +535,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
475 535
476 // This user wants to be friends with the other user. 536 // This user wants to be friends with the other user.
477 // Let's add the relation backwards, in case the other is not online 537 // Let's add the relation backwards, in case the other is not online
478 FriendsService.StoreFriend(friendID, principalID.ToString(), 0); 538 StoreBackwards(friendID, principalID);
479 539
480 // Now let's ask the other user to be friends with this user 540 // Now let's ask the other user to be friends with this user
481 ForwardFriendshipOffer(principalID, friendID, im); 541 ForwardFriendshipOffer(principalID, friendID, im);
@@ -487,11 +547,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
487 // !!!!!!!! This is a hack so that we don't have to keep state (transactionID/imSessionID) 547 // !!!!!!!! This is a hack so that we don't have to keep state (transactionID/imSessionID)
488 // We stick this agent's ID as imSession, so that it's directly available on the receiving end 548 // We stick this agent's ID as imSession, so that it's directly available on the receiving end
489 im.imSessionID = im.fromAgentID; 549 im.imSessionID = im.fromAgentID;
550 im.fromAgentName = GetFriendshipRequesterName(agentID);
490 551
491 // Try the local sim 552 // Try the local sim
492 UserAccount account = UserAccountService.GetUserAccount(UUID.Zero, agentID);
493 im.fromAgentName = (account == null) ? "Unknown" : account.FirstName + " " + account.LastName;
494
495 if (LocalFriendshipOffered(friendID, im)) 553 if (LocalFriendshipOffered(friendID, im))
496 return; 554 return;
497 555
@@ -509,15 +567,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
509 // If the prospective friend is not online, he'll get the message upon login. 567 // If the prospective friend is not online, he'll get the message upon login.
510 } 568 }
511 569
570 protected virtual string GetFriendshipRequesterName(UUID agentID)
571 {
572 UserAccount account = UserAccountService.GetUserAccount(UUID.Zero, agentID);
573 return (account == null) ? "Unknown" : account.FirstName + " " + account.LastName;
574 }
575
512 private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) 576 private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
513 { 577 {
514 m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", agentID, friendID); 578 m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", agentID, friendID);
515 579
516 FriendsService.StoreFriend(agentID, friendID.ToString(), 1); 580 StoreFriendships(agentID, friendID);
517 FriendsService.StoreFriend(friendID, agentID.ToString(), 1);
518 581
519 // Update the local cache 582 // Update the local cache
520 UpdateFriendsCache(agentID); 583 RefetchFriends(client);
521 584
522 // 585 //
523 // Notify the friend 586 // Notify the friend
@@ -548,8 +611,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
548 { 611 {
549 m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", agentID, friendID); 612 m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", agentID, friendID);
550 613
551 FriendsService.Delete(agentID, friendID.ToString()); 614 DeleteFriendship(agentID, friendID);
552 FriendsService.Delete(friendID, agentID.ToString());
553 615
554 // 616 //
555 // Notify the friend 617 // Notify the friend
@@ -576,11 +638,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
576 638
577 private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID) 639 private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID)
578 { 640 {
579 FriendsService.Delete(agentID, exfriendID.ToString()); 641 if (!DeleteFriendship(agentID, exfriendID))
580 FriendsService.Delete(exfriendID, agentID.ToString()); 642 client.SendAlertMessage("Unable to terminate friendship on this sim.");
581 643
582 // Update local cache 644 // Update local cache
583 UpdateFriendsCache(agentID); 645 RefetchFriends(client);
584 646
585 client.SendTerminateFriend(exfriendID); 647 client.SendTerminateFriend(exfriendID);
586 648
@@ -606,23 +668,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
606 668
607 private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights) 669 private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights)
608 { 670 {
671 m_log.DebugFormat("[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}", requester, rights, target);
672
609 FriendInfo[] friends = GetFriends(remoteClient.AgentId); 673 FriendInfo[] friends = GetFriends(remoteClient.AgentId);
610 if (friends.Length == 0) 674 if (friends.Length == 0)
675 {
611 return; 676 return;
677 }
612 678
613 m_log.DebugFormat("[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}", requester, rights, target);
614 // Let's find the friend in this user's friend list 679 // Let's find the friend in this user's friend list
615 FriendInfo friend = null; 680 FriendInfo friend = GetFriend(friends, target);
616 foreach (FriendInfo fi in friends)
617 {
618 if (fi.Friend == target.ToString())
619 friend = fi;
620 }
621 681
622 if (friend != null) // Found it 682 if (friend != null) // Found it
623 { 683 {
624 // Store it on the DB 684 // Store it on the DB
625 FriendsService.StoreFriend(requester, target.ToString(), rights); 685 if (!StoreRights(requester, target, rights))
686 {
687 remoteClient.SendAlertMessage("Unable to grant rights.");
688 return;
689 }
626 690
627 // Store it in the local cache 691 // Store it in the local cache
628 int myFlags = friend.MyFlags; 692 int myFlags = friend.MyFlags;
@@ -652,6 +716,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
652 } 716 }
653 } 717 }
654 } 718 }
719 else
720 m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", target, requester);
721 }
722
723 protected virtual FriendInfo GetFriend(FriendInfo[] friends, UUID friendID)
724 {
725 foreach (FriendInfo fi in friends)
726 {
727 if (fi.Friend == friendID.ToString())
728 return fi;
729 }
730 return null;
655 } 731 }
656 732
657 #region Local 733 #region Local
@@ -680,7 +756,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
680 friendClient.SendInstantMessage(im); 756 friendClient.SendInstantMessage(im);
681 757
682 // Update the local cache 758 // Update the local cache
683 UpdateFriendsCache(friendID); 759 RefetchFriends(friendClient);
684 760
685 // we're done 761 // we're done
686 return true; 762 return true;
@@ -713,7 +789,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
713 // the friend in this sim as root agent 789 // the friend in this sim as root agent
714 friendClient.SendTerminateFriend(exfriendID); 790 friendClient.SendTerminateFriend(exfriendID);
715 // update local cache 791 // update local cache
716 UpdateFriendsCache(exfriendID); 792 RefetchFriends(friendClient);
717 // we're done 793 // we're done
718 return true; 794 return true;
719 } 795 }
@@ -743,15 +819,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
743 } 819 }
744 820
745 // Update local cache 821 // Update local cache
746 lock (m_Friends) 822 UpdateLocalCache(userID, friendID, rights);
747 {
748 FriendInfo[] friends = GetFriends(friendID);
749 foreach (FriendInfo finfo in friends)
750 {
751 if (finfo.Friend == userID.ToString())
752 finfo.TheirFlags = rights;
753 }
754 }
755 823
756 return true; 824 return true;
757 } 825 }
@@ -780,7 +848,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
780 848
781 #endregion 849 #endregion
782 850
783 private FriendInfo[] GetFriends(UUID agentID) 851 #region Get / Set friends in several flavours
852 /// <summary>
853 /// Get friends from local cache only
854 /// </summary>
855 /// <param name="agentID"></param>
856 /// <returns></returns>
857 protected FriendInfo[] GetFriends(UUID agentID)
784 { 858 {
785 UserFriendData friendsData; 859 UserFriendData friendsData;
786 860
@@ -793,14 +867,63 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
793 return EMPTY_FRIENDS; 867 return EMPTY_FRIENDS;
794 } 868 }
795 869
796 private void UpdateFriendsCache(UUID agentID) 870 /// <summary>
871 /// Update loca cache only
872 /// </summary>
873 /// <param name="userID"></param>
874 /// <param name="friendID"></param>
875 /// <param name="rights"></param>
876 protected void UpdateLocalCache(UUID userID, UUID friendID, int rights)
877 {
878 // Update local cache
879 lock (m_Friends)
880 {
881 FriendInfo[] friends = GetFriends(friendID);
882 FriendInfo finfo = GetFriend(friends, userID);
883 finfo.TheirFlags = rights;
884 }
885 }
886
887 protected virtual FriendInfo[] GetFriendsFromService(IClientAPI client)
888 {
889 return FriendsService.GetFriends(client.AgentId);
890 }
891
892 private void RefetchFriends(IClientAPI client)
797 { 893 {
894 UUID agentID = client.AgentId;
798 lock (m_Friends) 895 lock (m_Friends)
799 { 896 {
800 UserFriendData friendsData; 897 UserFriendData friendsData;
801 if (m_Friends.TryGetValue(agentID, out friendsData)) 898 if (m_Friends.TryGetValue(agentID, out friendsData))
802 friendsData.Friends = FriendsService.GetFriends(agentID); 899 friendsData.Friends = GetFriendsFromService(client);
803 } 900 }
804 } 901 }
902
903 protected virtual bool StoreRights(UUID agentID, UUID friendID, int rights)
904 {
905 FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), rights);
906 return true;
907 }
908
909 protected virtual void StoreBackwards(UUID friendID, UUID agentID)
910 {
911 FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 0);
912 }
913
914 protected virtual void StoreFriendships(UUID agentID, UUID friendID)
915 {
916 FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), 1);
917 FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 1);
918 }
919
920 protected virtual bool DeleteFriendship(UUID agentID, UUID exfriendID)
921 {
922 FriendsService.Delete(agentID, exfriendID.ToString());
923 FriendsService.Delete(exfriendID, agentID.ToString());
924 return true;
925 }
926
927 #endregion
805 } 928 }
806} 929}
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
new file mode 100644
index 0000000..b0a7567
--- /dev/null
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs
@@ -0,0 +1,599 @@
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;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using Nini.Config;
34using Nwc.XmlRpc;
35using Mono.Addins;
36using OpenMetaverse;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Services.Connectors.Hypergrid;
42using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
43using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
44using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45
46namespace OpenSim.Region.CoreModules.Avatar.Friends
47{
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
49 public class HGFriendsModule : FriendsModule, ISharedRegionModule, IFriendsModule, IFriendsSimConnector
50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 #region ISharedRegionModule
54 public override string Name
55 {
56 get { return "HGFriendsModule"; }
57 }
58
59 public override void AddRegion(Scene scene)
60 {
61 if (!m_Enabled)
62 return;
63
64 base.AddRegion(scene);
65 scene.RegisterModuleInterface<IFriendsSimConnector>(this);
66 }
67
68 #endregion
69
70 #region IFriendsSimConnector
71
72 /// <summary>
73 /// Notify the user that the friend's status changed
74 /// </summary>
75 /// <param name="userID">user to be notified</param>
76 /// <param name="friendID">friend whose status changed</param>
77 /// <param name="online">status</param>
78 /// <returns></returns>
79 public bool StatusNotify(UUID userID, UUID friendID, bool online)
80 {
81 return LocalStatusNotification(friendID, userID, online);
82 }
83
84 #endregion
85
86 protected override bool FetchFriendslist(IClientAPI client)
87 {
88 if (base.FetchFriendslist(client))
89 {
90 UUID agentID = client.AgentId;
91 // We need to preload the user management cache with the names
92 // of foreign friends, just like we do with SOPs' creators
93 foreach (FriendInfo finfo in m_Friends[agentID].Friends)
94 {
95 if (finfo.TheirFlags != -1)
96 {
97 UUID id;
98 if (!UUID.TryParse(finfo.Friend, out id))
99 {
100 string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
101 if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp))
102 {
103 IUserManagement uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>();
104 uMan.AddUser(id, url + ";" + first + " " + last);
105 }
106 }
107 }
108 }
109 return true;
110 }
111 return false;
112 }
113
114 public override bool SendFriendsOnlineIfNeeded(IClientAPI client)
115 {
116 if (base.SendFriendsOnlineIfNeeded(client))
117 {
118 UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, client.AgentId);
119 if (account == null) // foreign
120 {
121 FriendInfo[] friends = GetFriends(client.AgentId);
122 foreach (FriendInfo f in friends)
123 {
124 client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, f.TheirFlags);
125 }
126 }
127 }
128 return false;
129 }
130
131 protected override void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
132 {
133 // Let's single out the UUIs
134 List<string> localFriends = new List<string>();
135 List<string> foreignFriends = new List<string>();
136 string tmp = string.Empty;
137
138 foreach (string s in friendList)
139 {
140 UUID id;
141 if (UUID.TryParse(s, out id))
142 localFriends.Add(s);
143 else if (Util.ParseUniversalUserIdentifier(s, out id, out tmp, out tmp, out tmp, out tmp))
144 {
145 foreignFriends.Add(s);
146 // add it here too, who knows maybe the foreign friends happens to be on this grid
147 localFriends.Add(id.ToString());
148 }
149 }
150
151 // OK, see who's present on this grid
152 List<string> toBeRemoved = new List<string>();
153 PresenceInfo[] presence = PresenceService.GetAgents(localFriends.ToArray());
154 foreach (PresenceInfo pi in presence)
155 {
156 UUID presenceID;
157 if (UUID.TryParse(pi.UserID, out presenceID))
158 {
159 online.Add(presenceID);
160 foreach (string s in foreignFriends)
161 if (s.StartsWith(pi.UserID))
162 toBeRemoved.Add(s);
163 }
164 }
165
166 foreach (string s in toBeRemoved)
167 foreignFriends.Remove(s);
168
169 // OK, let's send this up the stack, and leave a closure here
170 // collecting online friends in other grids
171 Util.FireAndForget(delegate { CollectOnlineFriendsElsewhere(userID, foreignFriends); });
172
173 }
174
175 private void CollectOnlineFriendsElsewhere(UUID userID, List<string> foreignFriends)
176 {
177 // let's divide the friends on a per-domain basis
178 Dictionary<string, List<string>> friendsPerDomain = new Dictionary<string, List<string>>();
179 foreach (string friend in foreignFriends)
180 {
181 UUID friendID;
182 if (!UUID.TryParse(friend, out friendID))
183 {
184 // it's a foreign friend
185 string url = string.Empty, tmp = string.Empty;
186 if (Util.ParseUniversalUserIdentifier(friend, out friendID, out url, out tmp, out tmp, out tmp))
187 {
188 if (!friendsPerDomain.ContainsKey(url))
189 friendsPerDomain[url] = new List<string>();
190 friendsPerDomain[url].Add(friend);
191 }
192 }
193 }
194
195 // Now, call those worlds
196
197 foreach (KeyValuePair<string, List<string>> kvp in friendsPerDomain)
198 {
199 List<string> ids = new List<string>();
200 foreach (string f in kvp.Value)
201 ids.Add(f);
202 UserAgentServiceConnector uConn = new UserAgentServiceConnector(kvp.Key);
203 List<UUID> online = uConn.GetOnlineFriends(userID, ids);
204 // Finally send the notifications to the user
205 // this whole process may take a while, so let's check at every
206 // iteration that the user is still here
207 IClientAPI client = LocateClientObject(userID);
208 if (client != null)
209 client.SendAgentOnline(online.ToArray());
210 else
211 break;
212 }
213
214 }
215
216 protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online)
217 {
218 // First, let's divide the friends on a per-domain basis
219 Dictionary<string, List<FriendInfo>> friendsPerDomain = new Dictionary<string, List<FriendInfo>>();
220 foreach (FriendInfo friend in friendList)
221 {
222 UUID friendID;
223 if (UUID.TryParse(friend.Friend, out friendID))
224 {
225 if (!friendsPerDomain.ContainsKey("local"))
226 friendsPerDomain["local"] = new List<FriendInfo>();
227 friendsPerDomain["local"].Add(friend);
228 }
229 else
230 {
231 // it's a foreign friend
232 string url = string.Empty, tmp = string.Empty;
233 if (Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out url, out tmp, out tmp, out tmp))
234 {
235 // Let's try our luck in the local sim. Who knows, maybe it's here
236 if (LocalStatusNotification(userID, friendID, online))
237 continue;
238
239 if (!friendsPerDomain.ContainsKey(url))
240 friendsPerDomain[url] = new List<FriendInfo>();
241 friendsPerDomain[url].Add(friend);
242 }
243 }
244 }
245
246 // For the local friends, just call the base method
247 // Let's do this first of all
248 if (friendsPerDomain.ContainsKey("local"))
249 base.StatusNotify(friendsPerDomain["local"], userID, online);
250
251 foreach (KeyValuePair<string, List<FriendInfo>> kvp in friendsPerDomain)
252 {
253 if (kvp.Key != "local")
254 {
255 // For the others, call the user agent service
256 List<string> ids = new List<string>();
257 foreach (FriendInfo f in kvp.Value)
258 ids.Add(f.Friend);
259 UserAgentServiceConnector uConn = new UserAgentServiceConnector(kvp.Key);
260 uConn.StatusNotification(ids, userID, online);
261 }
262 }
263 }
264
265 protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last)
266 {
267 first = "Unknown"; last = "User";
268 if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last))
269 return true;
270
271 // fid is not a UUID...
272 string url = string.Empty, tmp = string.Empty;
273 if (Util.ParseUniversalUserIdentifier(fid, out agentID, out url, out first, out last, out tmp))
274 {
275 IUserManagement userMan = m_Scenes[0].RequestModuleInterface<IUserManagement>();
276 userMan.AddUser(agentID, url + ";" + first + " " + last);
277
278 try // our best
279 {
280 string[] parts = userMan.GetUserName(agentID).Split();
281 first = parts[0];
282 last = parts[1];
283 }
284 catch { }
285 return true;
286 }
287 return false;
288 }
289
290 protected override string GetFriendshipRequesterName(UUID agentID)
291 {
292 // For the time being we assume that HG friendship requests can only happen
293 // when avies are on the same region.
294 IClientAPI client = LocateClientObject(agentID);
295 if (client != null)
296 return client.FirstName + " " + client.LastName;
297 else
298 return base.GetFriendshipRequesterName(agentID);
299 }
300
301 protected override string FriendshipMessage(string friendID)
302 {
303 UUID id;
304 if (UUID.TryParse(friendID, out id))
305 return base.FriendshipMessage(friendID);
306
307 return "Please confirm this friendship you made while you were away.";
308 }
309
310 protected override FriendInfo GetFriend(FriendInfo[] friends, UUID friendID)
311 {
312 foreach (FriendInfo fi in friends)
313 {
314 if (fi.Friend.StartsWith(friendID.ToString()))
315 return fi;
316 }
317 return null;
318 }
319
320
321 protected override FriendInfo[] GetFriendsFromService(IClientAPI client)
322 {
323 UserAccount account1 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, client.AgentId);
324 if (account1 != null)
325 return base.GetFriendsFromService(client);
326
327 FriendInfo[] finfos = new FriendInfo[0];
328 // Foreigner
329 AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode);
330 if (agentClientCircuit != null)
331 {
332 string agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit);
333
334 finfos = FriendsService.GetFriends(agentUUI);
335 m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, agentUUI);
336 }
337 return finfos;
338 }
339
340 protected override bool StoreRights(UUID agentID, UUID friendID, int rights)
341 {
342 UserAccount account1 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, agentID);
343 UserAccount account2 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, friendID);
344 // Are they both local users?
345 if (account1 != null && account2 != null)
346 {
347 // local grid users
348 return base.StoreRights(agentID, friendID, rights);
349 }
350
351 if (account1 != null) // agent is local, friend is foreigner
352 {
353 FriendInfo[] finfos = GetFriends(agentID);
354 FriendInfo finfo = GetFriend(finfos, friendID);
355 if (finfo != null)
356 {
357 FriendsService.StoreFriend(agentID.ToString(), finfo.Friend, rights);
358 return true;
359 }
360 }
361
362 if (account2 != null) // agent is foreigner, friend is local
363 {
364 string agentUUI = GetUUI(friendID, agentID);
365 if (agentUUI != string.Empty)
366 {
367 FriendsService.StoreFriend(agentUUI, friendID.ToString(), rights);
368 return true;
369 }
370 }
371
372 return false;
373
374 }
375
376 protected override void StoreBackwards(UUID friendID, UUID agentID)
377 {
378 UserAccount account1 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, agentID);
379 UserAccount account2 = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, friendID);
380 // Are they both local users?
381 if (account1 != null && account2 != null)
382 {
383 // local grid users
384 m_log.DebugFormat("[HGFRIENDS MODULE]: Users are both local");
385 base.StoreBackwards(friendID, agentID);
386 return;
387 }
388
389 // no provision for this temporary friendship state
390 //FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 0);
391 }
392
393 protected override void StoreFriendships(UUID agentID, UUID friendID)
394 {
395 UserAccount agentAccount = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, agentID);
396 UserAccount friendAccount = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, friendID);
397 // Are they both local users?
398 if (agentAccount != null && friendAccount != null)
399 {
400 // local grid users
401 m_log.DebugFormat("[HGFRIENDS MODULE]: Users are both local");
402 base.StoreFriendships(agentID, friendID);
403 return;
404 }
405
406 // ok, at least one of them is foreigner, let's get their data
407 IClientAPI agentClient = LocateClientObject(agentID);
408 IClientAPI friendClient = LocateClientObject(friendID);
409 AgentCircuitData agentClientCircuit = null;
410 AgentCircuitData friendClientCircuit = null;
411 string agentUUI = string.Empty;
412 string friendUUI = string.Empty;
413 string agentFriendService = string.Empty;
414 string friendFriendService = string.Empty;
415
416 if (agentClient != null)
417 {
418 agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode);
419 agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit);
420 agentFriendService = agentClientCircuit.ServiceURLs["FriendsServerURI"].ToString();
421 }
422 if (friendClient != null)
423 {
424 friendClientCircuit = ((Scene)(friendClient.Scene)).AuthenticateHandler.GetAgentCircuitData(friendClient.CircuitCode);
425 friendUUI = Util.ProduceUserUniversalIdentifier(friendClientCircuit);
426 friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString();
427 }
428
429 m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}",
430 agentUUI, friendUUI, agentFriendService, friendFriendService);
431
432 // Generate a random 8-character hex number that will sign this friendship
433 string secret = UUID.Random().ToString().Substring(0, 8);
434
435 if (agentAccount != null) // agent is local, 'friend' is foreigner
436 {
437 // This may happen when the agent returned home, in which case the friend is not there
438 // We need to look for its information in the friends list itself
439 bool confirming = false;
440 if (friendUUI == string.Empty)
441 {
442 FriendInfo[] finfos = GetFriends(agentID);
443 foreach (FriendInfo finfo in finfos)
444 {
445 if (finfo.TheirFlags == -1)
446 {
447 if (finfo.Friend.StartsWith(friendID.ToString()))
448 {
449 friendUUI = finfo.Friend;
450 confirming = true;
451 }
452 }
453 }
454 }
455
456 // If it's confirming the friendship, we already have the full friendUUI with the secret
457 string theFriendUUID = confirming ? friendUUI : friendUUI + ";" + secret;
458
459 // store in the local friends service a reference to the foreign friend
460 FriendsService.StoreFriend(agentID.ToString(), theFriendUUID, 1);
461 // and also the converse
462 FriendsService.StoreFriend(theFriendUUID, agentID.ToString(), 1);
463
464 if (!confirming && friendClientCircuit != null)
465 {
466 // store in the foreign friends service a reference to the local agent
467 HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID);
468 friendsConn.NewFriendship(friendID, agentUUI + ";" + secret);
469 }
470 }
471 else if (friendAccount != null) // 'friend' is local, agent is foreigner
472 {
473 // store in the local friends service a reference to the foreign agent
474 FriendsService.StoreFriend(friendID.ToString(), agentUUI + ";" + secret, 1);
475 // and also the converse
476 FriendsService.StoreFriend(agentUUI + ";" + secret, friendID.ToString(), 1);
477
478 if (agentClientCircuit != null)
479 {
480 // store in the foreign friends service a reference to the local agent
481 HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(agentFriendService, agentClientCircuit.SessionID, agentClientCircuit.ServiceSessionID);
482 friendsConn.NewFriendship(agentID, friendUUI + ";" + secret);
483 }
484 }
485 else // They're both foreigners!
486 {
487 HGFriendsServicesConnector friendsConn;
488 if (agentClientCircuit != null)
489 {
490 friendsConn = new HGFriendsServicesConnector(agentFriendService, agentClientCircuit.SessionID, agentClientCircuit.ServiceSessionID);
491 friendsConn.NewFriendship(agentID, friendUUI + ";" + secret);
492 }
493 if (friendClientCircuit != null)
494 {
495 friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID);
496 friendsConn.NewFriendship(friendID, agentUUI + ";" + secret);
497 }
498 }
499 // my brain hurts now
500 }
501
502 protected override bool DeleteFriendship(UUID agentID, UUID exfriendID)
503 {
504 UserAccount agentAccount = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, agentID);
505 UserAccount friendAccount = UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, exfriendID);
506 // Are they both local users?
507 if (agentAccount != null && friendAccount != null)
508 {
509 // local grid users
510 return base.DeleteFriendship(agentID, exfriendID);
511 }
512
513 // ok, at least one of them is foreigner, let's get their data
514 string agentUUI = string.Empty;
515 string friendUUI = string.Empty;
516
517 if (agentAccount != null) // agent is local, 'friend' is foreigner
518 {
519 // We need to look for its information in the friends list itself
520 FriendInfo[] finfos = GetFriends(agentID);
521 FriendInfo finfo = GetFriend(finfos, exfriendID);
522 if (finfo != null)
523 {
524 friendUUI = finfo.Friend;
525
526 // delete in the local friends service the reference to the foreign friend
527 FriendsService.Delete(agentID, friendUUI);
528 // and also the converse
529 FriendsService.Delete(friendUUI, agentID.ToString());
530
531 // notify the exfriend's service
532 Util.FireAndForget(delegate { Delete(exfriendID, agentID, friendUUI); });
533
534 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentID, friendUUI);
535 return true;
536 }
537 }
538 else if (friendAccount != null) // agent is foreigner, 'friend' is local
539 {
540 agentUUI = GetUUI(exfriendID, agentID);
541
542 if (agentUUI != string.Empty)
543 {
544 // delete in the local friends service the reference to the foreign agent
545 FriendsService.Delete(exfriendID, agentUUI);
546 // and also the converse
547 FriendsService.Delete(agentUUI, exfriendID.ToString());
548
549 // notify the agent's service?
550 Util.FireAndForget(delegate { Delete(agentID, exfriendID, agentUUI); });
551
552 m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentUUI, exfriendID);
553 return true;
554 }
555 }
556 //else They're both foreigners! Can't handle this
557
558 return false;
559 }
560
561 private string GetUUI(UUID localUser, UUID foreignUser)
562 {
563 // Let's see if the user is here by any chance
564 FriendInfo[] finfos = GetFriends(localUser);
565 if (finfos != EMPTY_FRIENDS) // friend is here, cool
566 {
567 FriendInfo finfo = GetFriend(finfos, foreignUser);
568 if (finfo != null)
569 {
570 return finfo.Friend;
571 }
572 }
573 else // user is not currently on this sim, need to get from the service
574 {
575 finfos = FriendsService.GetFriends(localUser);
576 foreach (FriendInfo finfo in finfos)
577 {
578 if (finfo.Friend.StartsWith(foreignUser.ToString())) // found it!
579 {
580 return finfo.Friend;
581 }
582 }
583 }
584 return string.Empty;
585 }
586
587 private void Delete(UUID foreignUser, UUID localUser, string uui)
588 {
589 UUID id;
590 string url = string.Empty, secret = string.Empty, tmp = string.Empty;
591 if (Util.ParseUniversalUserIdentifier(uui, out id, out url, out tmp, out tmp, out secret))
592 {
593 m_log.DebugFormat("[HGFRIENDS MODULE]: Deleting friendship from {0}", url);
594 HGFriendsServicesConnector friendConn = new HGFriendsServicesConnector(url);
595 friendConn.DeleteFriendship(foreignUser, localUser, secret);
596 }
597 }
598 }
599}