diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | 807 |
1 files changed, 807 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs new file mode 100644 index 0000000..27b7376 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | |||
@@ -0,0 +1,807 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using System.Threading; | ||
33 | using log4net; | ||
34 | using Nini.Config; | ||
35 | using Nwc.XmlRpc; | ||
36 | using Mono.Addins; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | using OpenSim.Services.Connectors.Hypergrid; | ||
43 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
44 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; | ||
45 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
46 | |||
47 | namespace OpenSim.Region.CoreModules.Avatar.Friends | ||
48 | { | ||
49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HGFriendsModule")] | ||
50 | public class HGFriendsModule : FriendsModule, ISharedRegionModule, IFriendsModule, IFriendsSimConnector | ||
51 | { | ||
52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | |||
54 | private int m_levelHGFriends = 0; | ||
55 | |||
56 | IUserManagement m_uMan; | ||
57 | public IUserManagement UserManagementModule | ||
58 | { | ||
59 | get | ||
60 | { | ||
61 | if (m_uMan == null) | ||
62 | m_uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>(); | ||
63 | return m_uMan; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | protected HGFriendsServicesConnector m_HGFriendsConnector = new HGFriendsServicesConnector(); | ||
68 | protected HGStatusNotifier m_StatusNotifier; | ||
69 | |||
70 | #region ISharedRegionModule | ||
71 | public override string Name | ||
72 | { | ||
73 | get { return "HGFriendsModule"; } | ||
74 | } | ||
75 | |||
76 | public override void AddRegion(Scene scene) | ||
77 | { | ||
78 | if (!m_Enabled) | ||
79 | return; | ||
80 | |||
81 | base.AddRegion(scene); | ||
82 | scene.RegisterModuleInterface<IFriendsSimConnector>(this); | ||
83 | } | ||
84 | |||
85 | public override void RegionLoaded(Scene scene) | ||
86 | { | ||
87 | if (!m_Enabled) | ||
88 | return; | ||
89 | if (m_StatusNotifier == null) | ||
90 | m_StatusNotifier = new HGStatusNotifier(this); | ||
91 | } | ||
92 | |||
93 | protected override void InitModule(IConfigSource config) | ||
94 | { | ||
95 | base.InitModule(config); | ||
96 | |||
97 | // Additionally to the base method | ||
98 | IConfig friendsConfig = config.Configs["HGFriendsModule"]; | ||
99 | if (friendsConfig != null) | ||
100 | { | ||
101 | m_levelHGFriends = friendsConfig.GetInt("LevelHGFriends", 0); | ||
102 | |||
103 | // TODO: read in all config variables pertaining to | ||
104 | // HG friendship permissions | ||
105 | } | ||
106 | } | ||
107 | |||
108 | #endregion | ||
109 | |||
110 | #region IFriendsSimConnector | ||
111 | |||
112 | /// <summary> | ||
113 | /// Notify the user that the friend's status changed | ||
114 | /// </summary> | ||
115 | /// <param name="userID">user to be notified</param> | ||
116 | /// <param name="friendID">friend whose status changed</param> | ||
117 | /// <param name="online">status</param> | ||
118 | /// <returns></returns> | ||
119 | public bool StatusNotify(UUID friendID, UUID userID, bool online) | ||
120 | { | ||
121 | return LocalStatusNotification(friendID, userID, online); | ||
122 | } | ||
123 | |||
124 | #endregion | ||
125 | |||
126 | protected override void OnInstantMessage(IClientAPI client, GridInstantMessage im) | ||
127 | { | ||
128 | if ((InstantMessageDialog)im.dialog == InstantMessageDialog.FriendshipOffered) | ||
129 | { | ||
130 | // we got a friendship offer | ||
131 | UUID principalID = new UUID(im.fromAgentID); | ||
132 | UUID friendID = new UUID(im.toAgentID); | ||
133 | |||
134 | // Check if friendID is foreigner and if principalID has the permission | ||
135 | // to request friendships with foreigners. If not, return immediately. | ||
136 | if (!UserManagementModule.IsLocalGridUser(friendID)) | ||
137 | { | ||
138 | ScenePresence avatar = null; | ||
139 | ((Scene)client.Scene).TryGetScenePresence(principalID, out avatar); | ||
140 | |||
141 | if (avatar == null) | ||
142 | return; | ||
143 | |||
144 | if (avatar.UserLevel < m_levelHGFriends) | ||
145 | { | ||
146 | client.SendAgentAlertMessage("Unable to send friendship invitation to foreigner. Insufficient permissions.", false); | ||
147 | return; | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | base.OnInstantMessage(client, im); | ||
153 | } | ||
154 | |||
155 | protected override void OnApproveFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders) | ||
156 | { | ||
157 | // Update the local cache. Yes, we need to do it right here | ||
158 | // because the HGFriendsService placed something on the DB | ||
159 | // from under the sim | ||
160 | base.OnApproveFriendRequest(client, friendID, callingCardFolders); | ||
161 | } | ||
162 | |||
163 | protected override bool CacheFriends(IClientAPI client) | ||
164 | { | ||
165 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Entered CacheFriends for {0}", client.Name); | ||
166 | |||
167 | if (base.CacheFriends(client)) | ||
168 | { | ||
169 | UUID agentID = client.AgentId; | ||
170 | // we do this only for the root agent | ||
171 | if (m_Friends[agentID].Refcount == 1) | ||
172 | { | ||
173 | // We need to preload the user management cache with the names | ||
174 | // of foreign friends, just like we do with SOPs' creators | ||
175 | foreach (FriendInfo finfo in m_Friends[agentID].Friends) | ||
176 | { | ||
177 | if (finfo.TheirFlags != -1) | ||
178 | { | ||
179 | UUID id; | ||
180 | if (!UUID.TryParse(finfo.Friend, out id)) | ||
181 | { | ||
182 | string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty; | ||
183 | if (Util.ParseUniversalUserIdentifier(finfo.Friend, out id, out url, out first, out last, out tmp)) | ||
184 | { | ||
185 | IUserManagement uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>(); | ||
186 | m_log.DebugFormat("[HGFRIENDS MODULE]: caching {0}", finfo.Friend); | ||
187 | uMan.AddUser(id, url + ";" + first + " " + last); | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | |||
193 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting CacheFriends for {0} since detected root agent", client.Name); | ||
194 | return true; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting CacheFriends for {0} since detected not root agent", client.Name); | ||
199 | return false; | ||
200 | } | ||
201 | |||
202 | public override bool SendFriendsOnlineIfNeeded(IClientAPI client) | ||
203 | { | ||
204 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Entering SendFriendsOnlineIfNeeded for {0}", client.Name); | ||
205 | |||
206 | if (base.SendFriendsOnlineIfNeeded(client)) | ||
207 | { | ||
208 | AgentCircuitData aCircuit = ((Scene)client.Scene).AuthenticateHandler.GetAgentCircuitData(client.AgentId); | ||
209 | if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0) | ||
210 | { | ||
211 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, client.AgentId); | ||
212 | if (account == null) // foreign | ||
213 | { | ||
214 | FriendInfo[] friends = GetFriendsFromCache(client.AgentId); | ||
215 | foreach (FriendInfo f in friends) | ||
216 | { | ||
217 | client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, f.TheirFlags); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting SendFriendsOnlineIfNeeded for {0}", client.Name); | ||
224 | return false; | ||
225 | } | ||
226 | |||
227 | protected override void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online) | ||
228 | { | ||
229 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetOnlineFriends for {0}", userID); | ||
230 | |||
231 | List<string> fList = new List<string>(); | ||
232 | foreach (string s in friendList) | ||
233 | { | ||
234 | if (s.Length < 36) | ||
235 | m_log.WarnFormat( | ||
236 | "[HGFRIENDS MODULE]: Ignoring friend {0} ({1} chars) for {2} since identifier too short", | ||
237 | s, s.Length, userID); | ||
238 | else | ||
239 | fList.Add(s.Substring(0, 36)); | ||
240 | } | ||
241 | |||
242 | // FIXME: also query the presence status of friends in other grids (like in HGStatusNotifier.Notify()) | ||
243 | |||
244 | PresenceInfo[] presence = PresenceService.GetAgents(fList.ToArray()); | ||
245 | foreach (PresenceInfo pi in presence) | ||
246 | { | ||
247 | UUID presenceID; | ||
248 | if (UUID.TryParse(pi.UserID, out presenceID)) | ||
249 | online.Add(presenceID); | ||
250 | } | ||
251 | |||
252 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetOnlineFriends for {0}", userID); | ||
253 | } | ||
254 | |||
255 | protected override void StatusNotify(List<FriendInfo> friendList, UUID userID, bool online) | ||
256 | { | ||
257 | //m_log.DebugFormat("[HGFRIENDS MODULE]: Entering StatusNotify for {0}", userID); | ||
258 | |||
259 | // First, let's divide the friends on a per-domain basis | ||
260 | Dictionary<string, List<FriendInfo>> friendsPerDomain = new Dictionary<string, List<FriendInfo>>(); | ||
261 | foreach (FriendInfo friend in friendList) | ||
262 | { | ||
263 | UUID friendID; | ||
264 | if (UUID.TryParse(friend.Friend, out friendID)) | ||
265 | { | ||
266 | if (!friendsPerDomain.ContainsKey("local")) | ||
267 | friendsPerDomain["local"] = new List<FriendInfo>(); | ||
268 | friendsPerDomain["local"].Add(friend); | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | // it's a foreign friend | ||
273 | string url = string.Empty, tmp = string.Empty; | ||
274 | if (Util.ParseUniversalUserIdentifier(friend.Friend, out friendID, out url, out tmp, out tmp, out tmp)) | ||
275 | { | ||
276 | // Let's try our luck in the local sim. Who knows, maybe it's here | ||
277 | if (LocalStatusNotification(userID, friendID, online)) | ||
278 | continue; | ||
279 | |||
280 | if (!friendsPerDomain.ContainsKey(url)) | ||
281 | friendsPerDomain[url] = new List<FriendInfo>(); | ||
282 | friendsPerDomain[url].Add(friend); | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | // For the local friends, just call the base method | ||
288 | // Let's do this first of all | ||
289 | if (friendsPerDomain.ContainsKey("local")) | ||
290 | base.StatusNotify(friendsPerDomain["local"], userID, online); | ||
291 | |||
292 | m_StatusNotifier.Notify(userID, friendsPerDomain, online); | ||
293 | |||
294 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting StatusNotify for {0}", userID); | ||
295 | } | ||
296 | |||
297 | protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) | ||
298 | { | ||
299 | first = "Unknown"; last = "UserHGGAI"; | ||
300 | if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last)) | ||
301 | return true; | ||
302 | |||
303 | // fid is not a UUID... | ||
304 | string url = string.Empty, tmp = string.Empty, f = string.Empty, l = string.Empty; | ||
305 | if (Util.ParseUniversalUserIdentifier(fid, out agentID, out url, out f, out l, out tmp)) | ||
306 | { | ||
307 | if (!agentID.Equals(UUID.Zero)) | ||
308 | { | ||
309 | m_uMan.AddUser(agentID, f, l, url); | ||
310 | |||
311 | string name = m_uMan.GetUserName(agentID); | ||
312 | string[] parts = name.Trim().Split(new char[] { ' ' }); | ||
313 | if (parts.Length == 2) | ||
314 | { | ||
315 | first = parts[0]; | ||
316 | last = parts[1]; | ||
317 | } | ||
318 | else | ||
319 | { | ||
320 | first = f; | ||
321 | last = l; | ||
322 | } | ||
323 | return true; | ||
324 | } | ||
325 | } | ||
326 | return false; | ||
327 | } | ||
328 | |||
329 | protected override string GetFriendshipRequesterName(UUID agentID) | ||
330 | { | ||
331 | return m_uMan.GetUserName(agentID); | ||
332 | } | ||
333 | |||
334 | protected override string FriendshipMessage(string friendID) | ||
335 | { | ||
336 | UUID id; | ||
337 | if (UUID.TryParse(friendID, out id)) | ||
338 | return base.FriendshipMessage(friendID); | ||
339 | |||
340 | return "Please confirm this friendship you made while you were away."; | ||
341 | } | ||
342 | |||
343 | protected override FriendInfo GetFriend(FriendInfo[] friends, UUID friendID) | ||
344 | { | ||
345 | foreach (FriendInfo fi in friends) | ||
346 | { | ||
347 | if (fi.Friend.StartsWith(friendID.ToString())) | ||
348 | return fi; | ||
349 | } | ||
350 | return null; | ||
351 | } | ||
352 | |||
353 | public override FriendInfo[] GetFriendsFromService(IClientAPI client) | ||
354 | { | ||
355 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name); | ||
356 | Boolean agentIsLocal = true; | ||
357 | if (UserManagementModule != null) | ||
358 | agentIsLocal = UserManagementModule.IsLocalGridUser(client.AgentId); | ||
359 | |||
360 | if (agentIsLocal) | ||
361 | return base.GetFriendsFromService(client); | ||
362 | |||
363 | FriendInfo[] finfos = new FriendInfo[0]; | ||
364 | // Foreigner | ||
365 | AgentCircuitData agentClientCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); | ||
366 | if (agentClientCircuit != null) | ||
367 | { | ||
368 | // Note that this is calling a different interface than base; this one calls with a string param! | ||
369 | finfos = FriendsService.GetFriends(client.AgentId.ToString()); | ||
370 | m_log.DebugFormat("[HGFRIENDS MODULE]: Fetched {0} local friends for visitor {1}", finfos.Length, client.AgentId.ToString()); | ||
371 | } | ||
372 | |||
373 | // m_log.DebugFormat("[HGFRIENDS MODULE]: Exiting GetFriendsFromService for {0}", client.Name); | ||
374 | |||
375 | return finfos; | ||
376 | } | ||
377 | |||
378 | protected override bool StoreRights(UUID agentID, UUID friendID, int rights) | ||
379 | { | ||
380 | Boolean agentIsLocal = true; | ||
381 | Boolean friendIsLocal = true; | ||
382 | if (UserManagementModule != null) | ||
383 | { | ||
384 | agentIsLocal = UserManagementModule.IsLocalGridUser(agentID); | ||
385 | friendIsLocal = UserManagementModule.IsLocalGridUser(friendID); | ||
386 | } | ||
387 | |||
388 | // Are they both local users? | ||
389 | if (agentIsLocal && friendIsLocal) | ||
390 | { | ||
391 | // local grid users | ||
392 | return base.StoreRights(agentID, friendID, rights); | ||
393 | } | ||
394 | |||
395 | if (agentIsLocal) // agent is local, friend is foreigner | ||
396 | { | ||
397 | FriendInfo[] finfos = GetFriendsFromCache(agentID); | ||
398 | FriendInfo finfo = GetFriend(finfos, friendID); | ||
399 | if (finfo != null) | ||
400 | { | ||
401 | FriendsService.StoreFriend(agentID.ToString(), finfo.Friend, rights); | ||
402 | return true; | ||
403 | } | ||
404 | } | ||
405 | |||
406 | if (friendIsLocal) // agent is foreigner, friend is local | ||
407 | { | ||
408 | string agentUUI = GetUUI(friendID, agentID); | ||
409 | if (agentUUI != string.Empty) | ||
410 | { | ||
411 | FriendsService.StoreFriend(agentUUI, friendID.ToString(), rights); | ||
412 | return true; | ||
413 | } | ||
414 | } | ||
415 | |||
416 | return false; | ||
417 | } | ||
418 | |||
419 | protected override void StoreBackwards(UUID friendID, UUID agentID) | ||
420 | { | ||
421 | bool agentIsLocal = true; | ||
422 | // bool friendIsLocal = true; | ||
423 | |||
424 | if (UserManagementModule != null) | ||
425 | { | ||
426 | agentIsLocal = UserManagementModule.IsLocalGridUser(agentID); | ||
427 | // friendIsLocal = UserManagementModule.IsLocalGridUser(friendID); | ||
428 | } | ||
429 | |||
430 | // Is the requester a local user? | ||
431 | if (agentIsLocal) | ||
432 | { | ||
433 | // local grid users | ||
434 | m_log.DebugFormat("[HGFRIENDS MODULE]: Friendship requester is local. Storing backwards."); | ||
435 | |||
436 | base.StoreBackwards(friendID, agentID); | ||
437 | return; | ||
438 | } | ||
439 | |||
440 | // no provision for this temporary friendship state when user is not local | ||
441 | //FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 0); | ||
442 | } | ||
443 | |||
444 | protected override void StoreFriendships(UUID agentID, UUID friendID) | ||
445 | { | ||
446 | Boolean agentIsLocal = true; | ||
447 | Boolean friendIsLocal = true; | ||
448 | if (UserManagementModule != null) | ||
449 | { | ||
450 | agentIsLocal = UserManagementModule.IsLocalGridUser(agentID); | ||
451 | friendIsLocal = UserManagementModule.IsLocalGridUser(friendID); | ||
452 | } | ||
453 | |||
454 | // Are they both local users? | ||
455 | if (agentIsLocal && friendIsLocal) | ||
456 | { | ||
457 | // local grid users | ||
458 | m_log.DebugFormat("[HGFRIENDS MODULE]: Users are both local"); | ||
459 | base.StoreFriendships(agentID, friendID); | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | // ok, at least one of them is foreigner, let's get their data | ||
464 | IClientAPI agentClient = LocateClientObject(agentID); | ||
465 | IClientAPI friendClient = LocateClientObject(friendID); | ||
466 | AgentCircuitData agentClientCircuit = null; | ||
467 | AgentCircuitData friendClientCircuit = null; | ||
468 | string agentUUI = string.Empty; | ||
469 | string friendUUI = string.Empty; | ||
470 | string agentFriendService = string.Empty; | ||
471 | string friendFriendService = string.Empty; | ||
472 | |||
473 | if (agentClient != null) | ||
474 | { | ||
475 | agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode); | ||
476 | agentUUI = Util.ProduceUserUniversalIdentifier(agentClientCircuit); | ||
477 | agentFriendService = agentClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); | ||
478 | RecacheFriends(agentClient); | ||
479 | } | ||
480 | if (friendClient != null) | ||
481 | { | ||
482 | friendClientCircuit = ((Scene)(friendClient.Scene)).AuthenticateHandler.GetAgentCircuitData(friendClient.CircuitCode); | ||
483 | friendUUI = Util.ProduceUserUniversalIdentifier(friendClientCircuit); | ||
484 | friendFriendService = friendClientCircuit.ServiceURLs["FriendsServerURI"].ToString(); | ||
485 | RecacheFriends(friendClient); | ||
486 | } | ||
487 | |||
488 | m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", | ||
489 | agentUUI, friendUUI, agentFriendService, friendFriendService); | ||
490 | |||
491 | // Generate a random 8-character hex number that will sign this friendship | ||
492 | string secret = UUID.Random().ToString().Substring(0, 8); | ||
493 | |||
494 | string theFriendUUID = friendUUI + ";" + secret; | ||
495 | string agentUUID = agentUUI + ";" + secret; | ||
496 | |||
497 | if (agentIsLocal) // agent is local, 'friend' is foreigner | ||
498 | { | ||
499 | // This may happen when the agent returned home, in which case the friend is not there | ||
500 | // We need to look for its information in the friends list itself | ||
501 | FriendInfo[] finfos = null; | ||
502 | bool confirming = false; | ||
503 | if (friendUUI == string.Empty) | ||
504 | { | ||
505 | finfos = GetFriendsFromCache(agentID); | ||
506 | foreach (FriendInfo finfo in finfos) | ||
507 | { | ||
508 | if (finfo.TheirFlags == -1) | ||
509 | { | ||
510 | if (finfo.Friend.StartsWith(friendID.ToString())) | ||
511 | { | ||
512 | friendUUI = finfo.Friend; | ||
513 | theFriendUUID = friendUUI; | ||
514 | UUID utmp = UUID.Zero; | ||
515 | string url = String.Empty; | ||
516 | string first = String.Empty; | ||
517 | string last = String.Empty; | ||
518 | |||
519 | // If it's confirming the friendship, we already have the full UUI with the secret | ||
520 | if (Util.ParseUniversalUserIdentifier(theFriendUUID, out utmp, out url, out first, out last, out secret)) | ||
521 | { | ||
522 | agentUUID = agentUUI + ";" + secret; | ||
523 | m_uMan.AddUser(utmp, first, last, url); | ||
524 | } | ||
525 | confirming = true; | ||
526 | break; | ||
527 | } | ||
528 | } | ||
529 | } | ||
530 | if (!confirming) | ||
531 | { | ||
532 | friendUUI = m_uMan.GetUserUUI(friendID); | ||
533 | theFriendUUID = friendUUI + ";" + secret; | ||
534 | } | ||
535 | |||
536 | friendFriendService = m_uMan.GetUserServerURL(friendID, "FriendsServerURI"); | ||
537 | |||
538 | // m_log.DebugFormat("[HGFRIENDS MODULE] HG Friendship! thisUUI={0}; friendUUI={1}; foreignThisFriendService={2}; foreignFriendFriendService={3}", | ||
539 | // agentUUI, friendUUI, agentFriendService, friendFriendService); | ||
540 | |||
541 | } | ||
542 | |||
543 | // Delete any previous friendship relations | ||
544 | DeletePreviousRelations(agentID, friendID); | ||
545 | |||
546 | // store in the local friends service a reference to the foreign friend | ||
547 | FriendsService.StoreFriend(agentID.ToString(), theFriendUUID, 1); | ||
548 | // and also the converse | ||
549 | FriendsService.StoreFriend(theFriendUUID, agentID.ToString(), 1); | ||
550 | |||
551 | //if (!confirming) | ||
552 | //{ | ||
553 | // store in the foreign friends service a reference to the local agent | ||
554 | HGFriendsServicesConnector friendsConn = null; | ||
555 | if (friendClientCircuit != null) // the friend is here, validate session | ||
556 | friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID); | ||
557 | else // the friend is not here, he initiated the request in his home world | ||
558 | friendsConn = new HGFriendsServicesConnector(friendFriendService); | ||
559 | |||
560 | friendsConn.NewFriendship(friendID, agentUUID); | ||
561 | //} | ||
562 | } | ||
563 | else if (friendIsLocal) // 'friend' is local, agent is foreigner | ||
564 | { | ||
565 | // Delete any previous friendship relations | ||
566 | DeletePreviousRelations(agentID, friendID); | ||
567 | |||
568 | // store in the local friends service a reference to the foreign agent | ||
569 | FriendsService.StoreFriend(friendID.ToString(), agentUUI + ";" + secret, 1); | ||
570 | // and also the converse | ||
571 | FriendsService.StoreFriend(agentUUI + ";" + secret, friendID.ToString(), 1); | ||
572 | |||
573 | if (agentClientCircuit != null) | ||
574 | { | ||
575 | // store in the foreign friends service a reference to the local agent | ||
576 | HGFriendsServicesConnector friendsConn = new HGFriendsServicesConnector(agentFriendService, agentClientCircuit.SessionID, agentClientCircuit.ServiceSessionID); | ||
577 | friendsConn.NewFriendship(agentID, friendUUI + ";" + secret); | ||
578 | } | ||
579 | } | ||
580 | else // They're both foreigners! | ||
581 | { | ||
582 | HGFriendsServicesConnector friendsConn; | ||
583 | if (agentClientCircuit != null) | ||
584 | { | ||
585 | friendsConn = new HGFriendsServicesConnector(agentFriendService, agentClientCircuit.SessionID, agentClientCircuit.ServiceSessionID); | ||
586 | friendsConn.NewFriendship(agentID, friendUUI + ";" + secret); | ||
587 | } | ||
588 | if (friendClientCircuit != null) | ||
589 | { | ||
590 | friendsConn = new HGFriendsServicesConnector(friendFriendService, friendClientCircuit.SessionID, friendClientCircuit.ServiceSessionID); | ||
591 | friendsConn.NewFriendship(friendID, agentUUI + ";" + secret); | ||
592 | } | ||
593 | } | ||
594 | // my brain hurts now | ||
595 | } | ||
596 | |||
597 | private void DeletePreviousRelations(UUID a1, UUID a2) | ||
598 | { | ||
599 | // Delete any previous friendship relations | ||
600 | FriendInfo[] finfos = null; | ||
601 | FriendInfo f = null; | ||
602 | finfos = GetFriendsFromCache(a1); | ||
603 | if (finfos != null) | ||
604 | { | ||
605 | f = GetFriend(finfos, a2); | ||
606 | if (f != null) | ||
607 | { | ||
608 | FriendsService.Delete(a1, f.Friend); | ||
609 | // and also the converse | ||
610 | FriendsService.Delete(f.Friend, a1.ToString()); | ||
611 | } | ||
612 | } | ||
613 | |||
614 | finfos = GetFriendsFromCache(a2); | ||
615 | if (finfos != null) | ||
616 | { | ||
617 | f = GetFriend(finfos, a1); | ||
618 | if (f != null) | ||
619 | { | ||
620 | FriendsService.Delete(a2, f.Friend); | ||
621 | // and also the converse | ||
622 | FriendsService.Delete(f.Friend, a2.ToString()); | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | |||
627 | protected override bool DeleteFriendship(UUID agentID, UUID exfriendID) | ||
628 | { | ||
629 | Boolean agentIsLocal = true; | ||
630 | Boolean friendIsLocal = true; | ||
631 | if (UserManagementModule != null) | ||
632 | { | ||
633 | agentIsLocal = UserManagementModule.IsLocalGridUser(agentID); | ||
634 | friendIsLocal = UserManagementModule.IsLocalGridUser(exfriendID); | ||
635 | } | ||
636 | |||
637 | // Are they both local users? | ||
638 | if (agentIsLocal && friendIsLocal) | ||
639 | { | ||
640 | // local grid users | ||
641 | return base.DeleteFriendship(agentID, exfriendID); | ||
642 | } | ||
643 | |||
644 | // ok, at least one of them is foreigner, let's get their data | ||
645 | string agentUUI = string.Empty; | ||
646 | string friendUUI = string.Empty; | ||
647 | |||
648 | if (agentIsLocal) // agent is local, 'friend' is foreigner | ||
649 | { | ||
650 | // We need to look for its information in the friends list itself | ||
651 | FriendInfo[] finfos = GetFriendsFromCache(agentID); | ||
652 | FriendInfo finfo = GetFriend(finfos, exfriendID); | ||
653 | if (finfo != null) | ||
654 | { | ||
655 | friendUUI = finfo.Friend; | ||
656 | |||
657 | // delete in the local friends service the reference to the foreign friend | ||
658 | FriendsService.Delete(agentID, friendUUI); | ||
659 | // and also the converse | ||
660 | FriendsService.Delete(friendUUI, agentID.ToString()); | ||
661 | |||
662 | // notify the exfriend's service | ||
663 | Util.FireAndForget( | ||
664 | delegate { Delete(exfriendID, agentID, friendUUI); }, null, "HGFriendsModule.DeleteFriendshipForeignFriend"); | ||
665 | |||
666 | m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentID, friendUUI); | ||
667 | return true; | ||
668 | } | ||
669 | } | ||
670 | else if (friendIsLocal) // agent is foreigner, 'friend' is local | ||
671 | { | ||
672 | agentUUI = GetUUI(exfriendID, agentID); | ||
673 | |||
674 | if (agentUUI != string.Empty) | ||
675 | { | ||
676 | // delete in the local friends service the reference to the foreign agent | ||
677 | FriendsService.Delete(exfriendID, agentUUI); | ||
678 | // and also the converse | ||
679 | FriendsService.Delete(agentUUI, exfriendID.ToString()); | ||
680 | |||
681 | // notify the agent's service? | ||
682 | Util.FireAndForget( | ||
683 | delegate { Delete(agentID, exfriendID, agentUUI); }, null, "HGFriendsModule.DeleteFriendshipLocalFriend"); | ||
684 | |||
685 | m_log.DebugFormat("[HGFRIENDS MODULE]: {0} terminated {1}", agentUUI, exfriendID); | ||
686 | return true; | ||
687 | } | ||
688 | } | ||
689 | //else They're both foreigners! Can't handle this | ||
690 | |||
691 | return false; | ||
692 | } | ||
693 | |||
694 | private string GetUUI(UUID localUser, UUID foreignUser) | ||
695 | { | ||
696 | // Let's see if the user is here by any chance | ||
697 | FriendInfo[] finfos = GetFriendsFromCache(localUser); | ||
698 | if (finfos != EMPTY_FRIENDS) // friend is here, cool | ||
699 | { | ||
700 | FriendInfo finfo = GetFriend(finfos, foreignUser); | ||
701 | if (finfo != null) | ||
702 | { | ||
703 | return finfo.Friend; | ||
704 | } | ||
705 | } | ||
706 | else // user is not currently on this sim, need to get from the service | ||
707 | { | ||
708 | finfos = FriendsService.GetFriends(localUser); | ||
709 | foreach (FriendInfo finfo in finfos) | ||
710 | { | ||
711 | if (finfo.Friend.StartsWith(foreignUser.ToString())) // found it! | ||
712 | { | ||
713 | return finfo.Friend; | ||
714 | } | ||
715 | } | ||
716 | } | ||
717 | return string.Empty; | ||
718 | } | ||
719 | |||
720 | private void Delete(UUID foreignUser, UUID localUser, string uui) | ||
721 | { | ||
722 | UUID id; | ||
723 | string url = string.Empty, secret = string.Empty, tmp = string.Empty; | ||
724 | if (Util.ParseUniversalUserIdentifier(uui, out id, out url, out tmp, out tmp, out secret)) | ||
725 | { | ||
726 | m_log.DebugFormat("[HGFRIENDS MODULE]: Deleting friendship from {0}", url); | ||
727 | HGFriendsServicesConnector friendConn = new HGFriendsServicesConnector(url); | ||
728 | friendConn.DeleteFriendship(foreignUser, localUser, secret); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | protected override bool ForwardFriendshipOffer(UUID agentID, UUID friendID, GridInstantMessage im) | ||
733 | { | ||
734 | if (base.ForwardFriendshipOffer(agentID, friendID, im)) | ||
735 | return true; | ||
736 | |||
737 | // OK, that didn't work, so let's try to find this user somewhere | ||
738 | if (!m_uMan.IsLocalGridUser(friendID)) | ||
739 | { | ||
740 | string friendsURL = m_uMan.GetUserServerURL(friendID, "FriendsServerURI"); | ||
741 | if (friendsURL != string.Empty) | ||
742 | { | ||
743 | m_log.DebugFormat("[HGFRIENDS MODULE]: Forwading friendship from {0} to {1} @ {2}", agentID, friendID, friendsURL); | ||
744 | GridRegion region = new GridRegion(); | ||
745 | region.ServerURI = friendsURL; | ||
746 | |||
747 | string name = im.fromAgentName; | ||
748 | if (m_uMan.IsLocalGridUser(agentID)) | ||
749 | { | ||
750 | IClientAPI agentClient = LocateClientObject(agentID); | ||
751 | AgentCircuitData agentClientCircuit = ((Scene)(agentClient.Scene)).AuthenticateHandler.GetAgentCircuitData(agentClient.CircuitCode); | ||
752 | string agentHomeService = string.Empty; | ||
753 | try | ||
754 | { | ||
755 | agentHomeService = agentClientCircuit.ServiceURLs["HomeURI"].ToString(); | ||
756 | string lastname = "@" + new Uri(agentHomeService).Authority; | ||
757 | string firstname = im.fromAgentName.Replace(" ", "."); | ||
758 | name = firstname + lastname; | ||
759 | } | ||
760 | catch (KeyNotFoundException) | ||
761 | { | ||
762 | m_log.DebugFormat("[HGFRIENDS MODULE]: Key HomeURI not found for user {0}", agentID); | ||
763 | return false; | ||
764 | } | ||
765 | catch (NullReferenceException) | ||
766 | { | ||
767 | m_log.DebugFormat("[HGFRIENDS MODULE]: Null HomeUri for local user {0}", agentID); | ||
768 | return false; | ||
769 | } | ||
770 | catch (UriFormatException) | ||
771 | { | ||
772 | m_log.DebugFormat("[HGFRIENDS MODULE]: Malformed HomeUri {0} for local user {1}", agentHomeService, agentID); | ||
773 | return false; | ||
774 | } | ||
775 | } | ||
776 | |||
777 | m_HGFriendsConnector.FriendshipOffered(region, agentID, friendID, im.message, name); | ||
778 | |||
779 | return true; | ||
780 | } | ||
781 | } | ||
782 | |||
783 | return false; | ||
784 | } | ||
785 | |||
786 | public override bool LocalFriendshipOffered(UUID toID, GridInstantMessage im) | ||
787 | { | ||
788 | if (base.LocalFriendshipOffered(toID, im)) | ||
789 | { | ||
790 | if (im.fromAgentName.Contains("@")) | ||
791 | { | ||
792 | string[] parts = im.fromAgentName.Split(new char[] { '@' }); | ||
793 | if (parts.Length == 2) | ||
794 | { | ||
795 | string[] fl = parts[0].Trim().Split(new char[] { '.' }); | ||
796 | if (fl.Length == 2) | ||
797 | m_uMan.AddUser(new UUID(im.fromAgentID), fl[0], fl[1], "http://" + parts[1]); | ||
798 | else | ||
799 | m_uMan.AddUser(new UUID(im.fromAgentID), fl[0], "", "http://" + parts[1]); | ||
800 | } | ||
801 | } | ||
802 | return true; | ||
803 | } | ||
804 | return false; | ||
805 | } | ||
806 | } | ||
807 | } \ No newline at end of file | ||