FriendsModule.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767
  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. using System;
  28. using System.Collections;
  29. using System.Collections.Generic;
  30. using System.Reflection;
  31. using log4net;
  32. using Nini.Config;
  33. using Nwc.XmlRpc;
  34. using OpenMetaverse;
  35. using OpenSim.Framework;
  36. using OpenSim.Framework.Communications;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes;
  39. using OpenSim.Services.Interfaces;
  40. using OpenSim.Services.Connectors.Friends;
  41. using OpenSim.Server.Base;
  42. using OpenSim.Framework.Servers.HttpServer;
  43. using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
  44. using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
  45. using GridRegion = OpenSim.Services.Interfaces.GridRegion;
  46. namespace OpenSim.Region.CoreModules.Avatar.Friends
  47. {
  48. public class FriendsModule : ISharedRegionModule, IFriendsModule
  49. {
  50. protected class UserFriendData
  51. {
  52. public UUID PrincipalID;
  53. public FriendInfo[] Friends;
  54. public int Refcount;
  55. public bool IsFriend(string friend)
  56. {
  57. foreach (FriendInfo fi in Friends)
  58. {
  59. if (fi.Friend == friend)
  60. return true;
  61. }
  62. return false;
  63. }
  64. }
  65. private static readonly FriendInfo[] EMPTY_FRIENDS = new FriendInfo[0];
  66. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  67. protected List<Scene> m_Scenes = new List<Scene>();
  68. protected IPresenceService m_PresenceService = null;
  69. protected IFriendsService m_FriendsService = null;
  70. protected FriendsSimConnector m_FriendsSimConnector;
  71. protected Dictionary<UUID, UserFriendData> m_Friends =
  72. new Dictionary<UUID, UserFriendData>();
  73. protected HashSet<UUID> m_NeedsListOfFriends = new HashSet<UUID>();
  74. protected IPresenceService PresenceService
  75. {
  76. get
  77. {
  78. if (m_PresenceService == null)
  79. {
  80. if (m_Scenes.Count > 0)
  81. m_PresenceService = m_Scenes[0].RequestModuleInterface<IPresenceService>();
  82. }
  83. return m_PresenceService;
  84. }
  85. }
  86. protected IFriendsService FriendsService
  87. {
  88. get
  89. {
  90. if (m_FriendsService == null)
  91. {
  92. if (m_Scenes.Count > 0)
  93. m_FriendsService = m_Scenes[0].RequestModuleInterface<IFriendsService>();
  94. }
  95. return m_FriendsService;
  96. }
  97. }
  98. protected IGridService GridService
  99. {
  100. get { return m_Scenes[0].GridService; }
  101. }
  102. public IUserAccountService UserAccountService
  103. {
  104. get { return m_Scenes[0].UserAccountService; }
  105. }
  106. public IScene Scene
  107. {
  108. get
  109. {
  110. if (m_Scenes.Count > 0)
  111. return m_Scenes[0];
  112. else
  113. return null;
  114. }
  115. }
  116. public void Initialise(IConfigSource config)
  117. {
  118. IConfig friendsConfig = config.Configs["Friends"];
  119. if (friendsConfig != null)
  120. {
  121. int mPort = friendsConfig.GetInt("Port", 0);
  122. string connector = friendsConfig.GetString("Connector", String.Empty);
  123. Object[] args = new Object[] { config };
  124. m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(connector, args);
  125. m_FriendsSimConnector = new FriendsSimConnector();
  126. // Instantiate the request handler
  127. IHttpServer server = MainServer.GetHttpServer((uint)mPort);
  128. server.AddStreamHandler(new FriendsRequestHandler(this));
  129. }
  130. if (m_FriendsService == null)
  131. {
  132. m_log.Error("[FRIENDS]: No Connector defined in section Friends, or failed to load, cannot continue");
  133. throw new Exception("Connector load error");
  134. }
  135. }
  136. public void PostInitialise()
  137. {
  138. }
  139. public void Close()
  140. {
  141. }
  142. public void AddRegion(Scene scene)
  143. {
  144. m_Scenes.Add(scene);
  145. scene.RegisterModuleInterface<IFriendsModule>(this);
  146. scene.EventManager.OnNewClient += OnNewClient;
  147. scene.EventManager.OnClientClosed += OnClientClosed;
  148. scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
  149. scene.EventManager.OnClientLogin += OnClientLogin;
  150. }
  151. public void RegionLoaded(Scene scene)
  152. {
  153. }
  154. public void RemoveRegion(Scene scene)
  155. {
  156. m_Scenes.Remove(scene);
  157. }
  158. public string Name
  159. {
  160. get { return "FriendsModule"; }
  161. }
  162. public Type ReplaceableInterface
  163. {
  164. get { return null; }
  165. }
  166. public uint GetFriendPerms(UUID principalID, UUID friendID)
  167. {
  168. FriendInfo[] friends = GetFriends(principalID);
  169. foreach (FriendInfo fi in friends)
  170. {
  171. if (fi.Friend == friendID.ToString())
  172. return (uint)fi.TheirFlags;
  173. }
  174. return 0;
  175. }
  176. private void OnNewClient(IClientAPI client)
  177. {
  178. client.OnInstantMessage += OnInstantMessage;
  179. client.OnApproveFriendRequest += OnApproveFriendRequest;
  180. client.OnDenyFriendRequest += OnDenyFriendRequest;
  181. client.OnTerminateFriendship += OnTerminateFriendship;
  182. client.OnGrantUserRights += OnGrantUserRights;
  183. // Asynchronously fetch the friends list or increment the refcount for the existing
  184. // friends list
  185. Util.FireAndForget(
  186. delegate(object o)
  187. {
  188. lock (m_Friends)
  189. {
  190. UserFriendData friendsData;
  191. if (m_Friends.TryGetValue(client.AgentId, out friendsData))
  192. {
  193. friendsData.Refcount++;
  194. }
  195. else
  196. {
  197. friendsData = new UserFriendData();
  198. friendsData.PrincipalID = client.AgentId;
  199. friendsData.Friends = FriendsService.GetFriends(client.AgentId);
  200. friendsData.Refcount = 1;
  201. m_Friends[client.AgentId] = friendsData;
  202. }
  203. }
  204. }
  205. );
  206. }
  207. private void OnClientClosed(UUID agentID, Scene scene)
  208. {
  209. ScenePresence sp = scene.GetScenePresence(agentID);
  210. if (sp != null && !sp.IsChildAgent)
  211. {
  212. // do this for root agents closing out
  213. StatusChange(agentID, false);
  214. }
  215. lock (m_Friends)
  216. {
  217. UserFriendData friendsData;
  218. if (m_Friends.TryGetValue(agentID, out friendsData))
  219. {
  220. friendsData.Refcount--;
  221. if (friendsData.Refcount <= 0)
  222. m_Friends.Remove(agentID);
  223. }
  224. }
  225. }
  226. private void OnMakeRootAgent(ScenePresence sp)
  227. {
  228. UUID agentID = sp.ControllingClient.AgentId;
  229. UpdateFriendsCache(agentID);
  230. }
  231. private void OnClientLogin(IClientAPI client)
  232. {
  233. UUID agentID = client.AgentId;
  234. // Inform the friends that this user is online
  235. StatusChange(agentID, true);
  236. // Register that we need to send the list of online friends to this user
  237. lock (m_NeedsListOfFriends)
  238. m_NeedsListOfFriends.Add(agentID);
  239. }
  240. public void SendFriendsOnlineIfNeeded(IClientAPI client)
  241. {
  242. UUID agentID = client.AgentId;
  243. // Check if the online friends list is needed
  244. lock (m_NeedsListOfFriends)
  245. {
  246. if (!m_NeedsListOfFriends.Remove(agentID))
  247. return;
  248. }
  249. // Send the friends online
  250. List<UUID> online = GetOnlineFriends(agentID);
  251. if (online.Count > 0)
  252. {
  253. m_log.DebugFormat("[FRIENDS MODULE]: User {0} in region {1} has {2} friends online", client.AgentId, client.Scene.RegionInfo.RegionName, online.Count);
  254. client.SendAgentOnline(online.ToArray());
  255. }
  256. // Send outstanding friendship offers
  257. List<string> outstanding = new List<string>();
  258. FriendInfo[] friends = GetFriends(agentID);
  259. foreach (FriendInfo fi in friends)
  260. {
  261. if (fi.TheirFlags == -1)
  262. outstanding.Add(fi.Friend);
  263. }
  264. GridInstantMessage im = new GridInstantMessage(client.Scene, UUID.Zero, String.Empty, agentID, (byte)InstantMessageDialog.FriendshipOffered,
  265. "Will you be my friend?", true, Vector3.Zero);
  266. foreach (string fid in outstanding)
  267. {
  268. UUID fromAgentID;
  269. if (!UUID.TryParse(fid, out fromAgentID))
  270. continue;
  271. UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, fromAgentID);
  272. PresenceInfo presence = PresenceService.GetAgent(fromAgentID);
  273. im.fromAgentID = fromAgentID.Guid;
  274. im.fromAgentName = account.FirstName + " " + account.LastName;
  275. im.offline = (byte)((presence == null) ? 1 : 0);
  276. im.imSessionID = im.fromAgentID;
  277. // Finally
  278. LocalFriendshipOffered(agentID, im);
  279. }
  280. }
  281. List<UUID> GetOnlineFriends(UUID userID)
  282. {
  283. List<string> friendList = new List<string>();
  284. List<UUID> online = new List<UUID>();
  285. FriendInfo[] friends = GetFriends(userID);
  286. foreach (FriendInfo fi in friends)
  287. {
  288. if (((fi.TheirFlags & 1) != 0) && (fi.TheirFlags != -1))
  289. friendList.Add(fi.Friend);
  290. }
  291. if (friendList.Count > 0)
  292. {
  293. PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
  294. foreach (PresenceInfo pi in presence)
  295. {
  296. UUID presenceID;
  297. if (UUID.TryParse(pi.UserID, out presenceID))
  298. online.Add(presenceID);
  299. }
  300. }
  301. return online;
  302. }
  303. /// <summary>
  304. /// Find the client for a ID
  305. /// </summary>
  306. public IClientAPI LocateClientObject(UUID agentID)
  307. {
  308. Scene scene = GetClientScene(agentID);
  309. if (scene != null)
  310. {
  311. ScenePresence presence = scene.GetScenePresence(agentID);
  312. if (presence != null)
  313. return presence.ControllingClient;
  314. }
  315. return null;
  316. }
  317. /// <summary>
  318. /// Find the scene for an agent
  319. /// </summary>
  320. private Scene GetClientScene(UUID agentId)
  321. {
  322. lock (m_Scenes)
  323. {
  324. foreach (Scene scene in m_Scenes)
  325. {
  326. ScenePresence presence = scene.GetScenePresence(agentId);
  327. if (presence != null && !presence.IsChildAgent)
  328. return scene;
  329. }
  330. }
  331. return null;
  332. }
  333. /// <summary>
  334. /// Caller beware! Call this only for root agents.
  335. /// </summary>
  336. /// <param name="agentID"></param>
  337. /// <param name="online"></param>
  338. private void StatusChange(UUID agentID, bool online)
  339. {
  340. FriendInfo[] friends = GetFriends(agentID);
  341. if (friends.Length > 0)
  342. {
  343. List<FriendInfo> friendList = new List<FriendInfo>();
  344. foreach (FriendInfo fi in friends)
  345. {
  346. if (((fi.MyFlags & 1) != 0) && (fi.TheirFlags != -1))
  347. friendList.Add(fi);
  348. }
  349. Util.FireAndForget(
  350. delegate
  351. {
  352. foreach (FriendInfo fi in friendList)
  353. {
  354. //m_log.DebugFormat("[FRIENDS]: Notifying {0}", fi.PrincipalID);
  355. // Notify about this user status
  356. StatusNotify(fi, agentID, online);
  357. }
  358. }
  359. );
  360. }
  361. }
  362. private void StatusNotify(FriendInfo friend, UUID userID, bool online)
  363. {
  364. UUID friendID;
  365. if (UUID.TryParse(friend.Friend, out friendID))
  366. {
  367. // Try local
  368. if (LocalStatusNotification(userID, friendID, online))
  369. return;
  370. // The friend is not here [as root]. Let's forward.
  371. PresenceInfo friendSession = PresenceService.GetAgent(friendID);
  372. if (friendSession != null && friendSession.RegionID != UUID.Zero) // let's guard against sessions-gone-bad with the RegionID check
  373. {
  374. GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
  375. //m_log.DebugFormat("[FRIENDS]: Remote Notify to region {0}", region.RegionName);
  376. m_FriendsSimConnector.StatusNotify(region, userID, friendID, online);
  377. }
  378. }
  379. else
  380. {
  381. m_log.WarnFormat("[FRIENDS]: Error parsing friend ID {0}", friend.Friend);
  382. }
  383. }
  384. private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
  385. {
  386. if ((InstantMessageDialog)im.dialog == InstantMessageDialog.FriendshipOffered)
  387. {
  388. // we got a friendship offer
  389. UUID principalID = new UUID(im.fromAgentID);
  390. UUID friendID = new UUID(im.toAgentID);
  391. m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2}", principalID, im.fromAgentName, friendID);
  392. // This user wants to be friends with the other user.
  393. // Let's add the relation backwards, in case the other is not online
  394. FriendsService.StoreFriend(friendID, principalID.ToString(), 0);
  395. // Now let's ask the other user to be friends with this user
  396. ForwardFriendshipOffer(principalID, friendID, im);
  397. }
  398. }
  399. private void ForwardFriendshipOffer(UUID agentID, UUID friendID, GridInstantMessage im)
  400. {
  401. // !!!!!!!! This is a hack so that we don't have to keep state (transactionID/imSessionID)
  402. // We stick this agent's ID as imSession, so that it's directly available on the receiving end
  403. im.imSessionID = im.fromAgentID;
  404. // Try the local sim
  405. UserAccount account = UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, agentID);
  406. im.fromAgentName = (account == null) ? "Unknown" : account.FirstName + " " + account.LastName;
  407. if (LocalFriendshipOffered(friendID, im))
  408. return;
  409. // The prospective friend is not here [as root]. Let's forward.
  410. PresenceInfo friendSession = PresenceService.GetAgent(friendID);
  411. if (friendSession != null)
  412. {
  413. GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
  414. m_FriendsSimConnector.FriendshipOffered(region, agentID, friendID, im.message);
  415. }
  416. // If the prospective friend is not online, he'll get the message upon login.
  417. }
  418. private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
  419. {
  420. m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", agentID, friendID);
  421. FriendsService.StoreFriend(agentID, friendID.ToString(), 1);
  422. FriendsService.StoreFriend(friendID, agentID.ToString(), 1);
  423. // Update the local cache
  424. UpdateFriendsCache(agentID);
  425. //
  426. // Notify the friend
  427. //
  428. // Try Local
  429. if (LocalFriendshipApproved(agentID, client.Name, friendID))
  430. {
  431. client.SendAgentOnline(new UUID[] { friendID });
  432. return;
  433. }
  434. // The friend is not here
  435. PresenceInfo friendSession = PresenceService.GetAgent(friendID);
  436. if (friendSession != null)
  437. {
  438. GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
  439. m_FriendsSimConnector.FriendshipApproved(region, agentID, client.Name, friendID);
  440. client.SendAgentOnline(new UUID[] { friendID });
  441. }
  442. }
  443. private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
  444. {
  445. m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", agentID, friendID);
  446. FriendsService.Delete(agentID, friendID.ToString());
  447. FriendsService.Delete(friendID, agentID.ToString());
  448. //
  449. // Notify the friend
  450. //
  451. // Try local
  452. if (LocalFriendshipDenied(agentID, client.Name, friendID))
  453. return;
  454. PresenceInfo friendSession = PresenceService.GetAgent(friendID);
  455. if (friendSession != null)
  456. {
  457. GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
  458. if (region != null)
  459. m_FriendsSimConnector.FriendshipDenied(region, agentID, client.Name, friendID);
  460. else
  461. m_log.WarnFormat("[FRIENDS]: Could not find region {0} in locating {1}", friendSession.RegionID, friendID);
  462. }
  463. }
  464. private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID)
  465. {
  466. FriendsService.Delete(agentID, exfriendID.ToString());
  467. FriendsService.Delete(exfriendID, agentID.ToString());
  468. // Update local cache
  469. UpdateFriendsCache(agentID);
  470. client.SendTerminateFriend(exfriendID);
  471. //
  472. // Notify the friend
  473. //
  474. // Try local
  475. if (LocalFriendshipTerminated(exfriendID))
  476. return;
  477. PresenceInfo friendSession = PresenceService.GetAgent(exfriendID);
  478. if (friendSession != null)
  479. {
  480. GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
  481. m_FriendsSimConnector.FriendshipTerminated(region, agentID, exfriendID);
  482. }
  483. }
  484. private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights)
  485. {
  486. FriendInfo[] friends = GetFriends(remoteClient.AgentId);
  487. if (friends.Length == 0)
  488. return;
  489. m_log.DebugFormat("[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}", requester, rights, target);
  490. // Let's find the friend in this user's friend list
  491. FriendInfo friend = null;
  492. foreach (FriendInfo fi in friends)
  493. {
  494. if (fi.Friend == target.ToString())
  495. friend = fi;
  496. }
  497. if (friend != null) // Found it
  498. {
  499. // Store it on the DB
  500. FriendsService.StoreFriend(requester, target.ToString(), rights);
  501. // Store it in the local cache
  502. int myFlags = friend.MyFlags;
  503. friend.MyFlags = rights;
  504. // Always send this back to the original client
  505. remoteClient.SendChangeUserRights(requester, target, rights);
  506. //
  507. // Notify the friend
  508. //
  509. // Try local
  510. if (LocalGrantRights(requester, target, myFlags, rights))
  511. return;
  512. PresenceInfo friendSession = PresenceService.GetAgent(target);
  513. if (friendSession != null)
  514. {
  515. GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
  516. // TODO: You might want to send the delta to save the lookup
  517. // on the other end!!
  518. m_FriendsSimConnector.GrantRights(region, requester, target, myFlags, rights);
  519. }
  520. }
  521. }
  522. #region Local
  523. public bool LocalFriendshipOffered(UUID toID, GridInstantMessage im)
  524. {
  525. IClientAPI friendClient = LocateClientObject(toID);
  526. if (friendClient != null)
  527. {
  528. // the prospective friend in this sim as root agent
  529. friendClient.SendInstantMessage(im);
  530. // we're done
  531. return true;
  532. }
  533. return false;
  534. }
  535. public bool LocalFriendshipApproved(UUID userID, string userName, UUID friendID)
  536. {
  537. IClientAPI friendClient = LocateClientObject(friendID);
  538. if (friendClient != null)
  539. {
  540. // the prospective friend in this sim as root agent
  541. GridInstantMessage im = new GridInstantMessage(Scene, userID, userName, friendID,
  542. (byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero);
  543. friendClient.SendInstantMessage(im);
  544. // Update the local cache
  545. UpdateFriendsCache(friendID);
  546. // we're done
  547. return true;
  548. }
  549. return false;
  550. }
  551. public bool LocalFriendshipDenied(UUID userID, string userName, UUID friendID)
  552. {
  553. IClientAPI friendClient = LocateClientObject(friendID);
  554. if (friendClient != null)
  555. {
  556. // the prospective friend in this sim as root agent
  557. GridInstantMessage im = new GridInstantMessage(Scene, userID, userName, friendID,
  558. (byte)OpenMetaverse.InstantMessageDialog.FriendshipDeclined, userID.ToString(), false, Vector3.Zero);
  559. friendClient.SendInstantMessage(im);
  560. // we're done
  561. return true;
  562. }
  563. return false;
  564. }
  565. public bool LocalFriendshipTerminated(UUID exfriendID)
  566. {
  567. IClientAPI friendClient = LocateClientObject(exfriendID);
  568. if (friendClient != null)
  569. {
  570. // the friend in this sim as root agent
  571. friendClient.SendTerminateFriend(exfriendID);
  572. // update local cache
  573. UpdateFriendsCache(exfriendID);
  574. // we're done
  575. return true;
  576. }
  577. return false;
  578. }
  579. public bool LocalGrantRights(UUID userID, UUID friendID, int userFlags, int rights)
  580. {
  581. IClientAPI friendClient = LocateClientObject(friendID);
  582. if (friendClient != null)
  583. {
  584. bool onlineBitChanged = ((rights ^ userFlags) & (int)FriendRights.CanSeeOnline) != 0;
  585. if (onlineBitChanged)
  586. {
  587. if ((rights & (int)FriendRights.CanSeeOnline) == 1)
  588. friendClient.SendAgentOnline(new UUID[] { new UUID(userID) });
  589. else
  590. friendClient.SendAgentOffline(new UUID[] { new UUID(userID) });
  591. }
  592. else
  593. {
  594. bool canEditObjectsChanged = ((rights ^ userFlags) & (int)FriendRights.CanModifyObjects) != 0;
  595. if (canEditObjectsChanged)
  596. friendClient.SendChangeUserRights(userID, friendID, rights);
  597. }
  598. // Update local cache
  599. lock (m_Friends)
  600. {
  601. FriendInfo[] friends = GetFriends(friendID);
  602. foreach (FriendInfo finfo in friends)
  603. {
  604. if (finfo.Friend == userID.ToString())
  605. finfo.TheirFlags = rights;
  606. }
  607. }
  608. return true;
  609. }
  610. return false;
  611. }
  612. public bool LocalStatusNotification(UUID userID, UUID friendID, bool online)
  613. {
  614. IClientAPI friendClient = LocateClientObject(friendID);
  615. if (friendClient != null)
  616. {
  617. //m_log.DebugFormat("[FRIENDS]: Local Status Notify {0} that user {1} is {2}", friendID, userID, online);
  618. // the friend in this sim as root agent
  619. if (online)
  620. friendClient.SendAgentOnline(new UUID[] { userID });
  621. else
  622. friendClient.SendAgentOffline(new UUID[] { userID });
  623. // we're done
  624. return true;
  625. }
  626. return false;
  627. }
  628. #endregion
  629. private FriendInfo[] GetFriends(UUID agentID)
  630. {
  631. UserFriendData friendsData;
  632. lock (m_Friends)
  633. {
  634. if (m_Friends.TryGetValue(agentID, out friendsData))
  635. return friendsData.Friends;
  636. }
  637. return EMPTY_FRIENDS;
  638. }
  639. private void UpdateFriendsCache(UUID agentID)
  640. {
  641. lock (m_Friends)
  642. {
  643. UserFriendData friendsData;
  644. if (m_Friends.TryGetValue(agentID, out friendsData))
  645. friendsData.Friends = FriendsService.GetFriends(agentID);
  646. }
  647. }
  648. }
  649. }