aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs551
1 files changed, 1 insertions, 550 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
index fceca8e..123e2dd 100644
--- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
@@ -58,530 +58,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
58 { 58 {
59 } 59 }
60 60
61 public string Name
62 {
63 get { return "FriendsModule"; }
64 }
65
66 public bool IsSharedModule
67 {
68 get { return true; }
69 }
70
71 #endregion
72
73 #region IInterregionFriendsComms
74
75 public List<UUID> InformFriendsInOtherRegion(UUID agentId, ulong destRegionHandle, List<UUID> friends, bool online)
76 {
77 List<UUID> tpdAway = new List<UUID>();
78
79 // destRegionHandle is a region on another server
80 uint x = 0, y = 0;
81 Utils.LongToUInts(destRegionHandle, out x, out y);
82 GridRegion info = m_gridServices.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, (int)x, (int)y);
83 if (info != null)
84 {
85 string httpServer = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/presence_update_bulk";
86
87 Hashtable reqParams = new Hashtable();
88 reqParams["agentID"] = agentId.ToString();
89 reqParams["agentOnline"] = online;
90 int count = 0;
91 foreach (UUID uuid in friends)
92 {
93 reqParams["friendID_" + count++] = uuid.ToString();
94 }
95 reqParams["friendCount"] = count;
96
97 IList parameters = new ArrayList();
98 parameters.Add(reqParams);
99 try
100 {
101 XmlRpcRequest request = new XmlRpcRequest("presence_update_bulk", parameters);
102 XmlRpcResponse response = request.Send(httpServer, 5000);
103 Hashtable respData = (Hashtable)response.Value;
104
105 count = (int)respData["friendCount"];
106 for (int i = 0; i < count; ++i)
107 {
108 UUID uuid;
109 if (UUID.TryParse((string)respData["friendID_" + i], out uuid)) tpdAway.Add(uuid);
110 }
111 }
112 catch (WebException e)
113 {
114 // Ignore connect failures, simulators come and go
115 //
116 if (!e.Message.Contains("ConnectFailure"))
117 {
118 m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e);
119 }
120 }
121 catch (Exception e)
122 {
123 m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e);
124 }
125 }
126 else m_log.WarnFormat("[OGS1 GRID SERVICES]: Couldn't find region {0}???", destRegionHandle);
127
128 return tpdAway;
129 }
130
131 public bool TriggerTerminateFriend(ulong destRegionHandle, UUID agentID, UUID exFriendID)
132 {
133 // destRegionHandle is a region on another server
134 uint x = 0, y = 0;
135 Utils.LongToUInts(destRegionHandle, out x, out y);
136 GridRegion info = m_gridServices.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, (int)x, (int)y);
137 if (info == null)
138 {
139 m_log.WarnFormat("[OGS1 GRID SERVICES]: Couldn't find region {0}", destRegionHandle);
140 return false; // region not found???
141 }
142
143 string httpServer = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/presence_update_bulk";
144
145 Hashtable reqParams = new Hashtable();
146 reqParams["agentID"] = agentID.ToString();
147 reqParams["friendID"] = exFriendID.ToString();
148
149 IList parameters = new ArrayList();
150 parameters.Add(reqParams);
151 try
152 {
153 XmlRpcRequest request = new XmlRpcRequest("terminate_friend", parameters);
154 XmlRpcResponse response = request.Send(httpServer, 5000);
155 Hashtable respData = (Hashtable)response.Value;
156
157 return (bool)respData["success"];
158 }
159 catch (Exception e)
160 {
161 m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e);
162 return false;
163 }
164 }
165
166 #endregion
167
168 #region Incoming XMLRPC messages
169 /// <summary>
170 /// Receive presence information changes about clients in other regions.
171 /// </summary>
172 /// <param name="req"></param>
173 /// <returns></returns>
174 public XmlRpcResponse processPresenceUpdateBulk(XmlRpcRequest req, IPEndPoint remoteClient)
175 {
176 Hashtable requestData = (Hashtable)req.Params[0];
177
178 List<UUID> friendsNotHere = new List<UUID>();
179
180 // this is called with the expectation that all the friends in the request are on this region-server.
181 // But as some time passed since we checked (on the other region-server, via the MessagingServer),
182 // some of the friends might have teleported away.
183 // Actually, even now, between this line and the sending below, some people could TP away. So,
184 // we'll have to lock the m_rootAgents list for the duration to prevent/delay that.
185 lock (m_rootAgents)
186 {
187 List<ScenePresence> friendsHere = new List<ScenePresence>();
188
189 try
190 {
191 UUID agentID = new UUID((string)requestData["agentID"]);
192 bool agentOnline = (bool)requestData["agentOnline"];
193 int count = (int)requestData["friendCount"];
194 for (int i = 0; i < count; ++i)
195 {
196 UUID uuid;
197 if (UUID.TryParse((string)requestData["friendID_" + i], out uuid))
198 {
199 if (m_rootAgents.ContainsKey(uuid)) friendsHere.Add(GetRootPresenceFromAgentID(uuid));
200 else friendsNotHere.Add(uuid);
201 }
202 }
203
204 // now send, as long as they are still here...
205 UUID[] agentUUID = new UUID[] { agentID };
206 if (agentOnline)
207 {
208 foreach (ScenePresence agent in friendsHere)
209 {
210 agent.ControllingClient.SendAgentOnline(agentUUID);
211 }
212 }
213 else
214 {
215 foreach (ScenePresence agent in friendsHere)
216 {
217 agent.ControllingClient.SendAgentOffline(agentUUID);
218 }
219 }
220 }
221 catch(Exception e)
222 {
223 m_log.Warn("[FRIENDS]: Got exception while parsing presence_update_bulk request:", e);
224 }
225 }
226
227 // no need to lock anymore; if TPs happen now, worst case is that we have an additional agent in this region,
228 // which should be caught on the next iteration...
229 Hashtable result = new Hashtable();
230 int idx = 0;
231 foreach (UUID uuid in friendsNotHere)
232 {
233 result["friendID_" + idx++] = uuid.ToString();
234 }
235 result["friendCount"] = idx;
236
237 XmlRpcResponse response = new XmlRpcResponse();
238 response.Value = result;
239
240 return response;
241 }
242
243 public XmlRpcResponse processTerminateFriend(XmlRpcRequest req, IPEndPoint remoteClient)
244 {
245 Hashtable requestData = (Hashtable)req.Params[0];
246
247 bool success = false;
248
249 UUID agentID;
250 UUID friendID;
251 if (requestData.ContainsKey("agentID") && UUID.TryParse((string)requestData["agentID"], out agentID) &&
252 requestData.ContainsKey("friendID") && UUID.TryParse((string)requestData["friendID"], out friendID))
253 {
254 // try to find it and if it is there, prevent it to vanish before we sent the message
255 lock (m_rootAgents)
256 {
257 if (m_rootAgents.ContainsKey(agentID))
258 {
259 m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", friendID, agentID);
260 GetRootPresenceFromAgentID(agentID).ControllingClient.SendTerminateFriend(friendID);
261 success = true;
262 }
263 }
264 }
265
266 // return whether we were successful
267 Hashtable result = new Hashtable();
268 result["success"] = success;
269
270 XmlRpcResponse response = new XmlRpcResponse();
271 response.Value = result;
272 return response;
273 }
274
275 #endregion
276
277 #region Scene events
278
279 private void OnNewClient(IClientAPI client)
280 {
281 // All friends establishment protocol goes over instant message
282 // There's no way to send a message from the sim
283 // to a user to 'add a friend' without causing dialog box spam
284
285 // Subscribe to instant messages
286 client.OnInstantMessage += OnInstantMessage;
287
288 // Friend list management
289 client.OnApproveFriendRequest += OnApproveFriendRequest;
290 client.OnDenyFriendRequest += OnDenyFriendRequest;
291 client.OnTerminateFriendship += OnTerminateFriendship;
292
293 // ... calling card handling...
294 client.OnOfferCallingCard += OnOfferCallingCard;
295 client.OnAcceptCallingCard += OnAcceptCallingCard;
296 client.OnDeclineCallingCard += OnDeclineCallingCard;
297
298 // we need this one exactly once per agent session (see comments in the handler below)
299 client.OnEconomyDataRequest += OnEconomyDataRequest;
300
301 // if it leaves, we want to know, too
302 client.OnLogout += OnLogout;
303
304 client.OnGrantUserRights += GrantUserFriendRights;
305 client.OnTrackAgentEvent += FindAgent;
306 client.OnFindAgentEvent += FindAgent;
307
308 }
309
310 private void ClientClosed(UUID AgentId, Scene scene)
311 {
312 // agent's client was closed. As we handle logout in OnLogout, this here has only to handle
313 // TPing away (root agent is closed) or TPing/crossing in a region far enough away (client
314 // agent is closed).
315 // NOTE: In general, this doesn't mean that the agent logged out, just that it isn't around
316 // in one of the regions here anymore.
317 lock (m_rootAgents)
318 {
319 if (m_rootAgents.ContainsKey(AgentId))
320 {
321 m_rootAgents.Remove(AgentId);
322 }
323 }
324 }
325
326 private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID)
327 {
328 lock (m_rootAgents)
329 {
330 m_rootAgents[avatar.UUID] = avatar.RegionHandle;
331 // Claim User! my user! Mine mine mine!
332 }
333 }
334
335 private void MakeChildAgent(ScenePresence avatar)
336 {
337 lock (m_rootAgents)
338 {
339 if (m_rootAgents.ContainsKey(avatar.UUID))
340 {
341 // only delete if the region matches. As this is a shared module, the avatar could be
342 // root agent in another region on this server.
343 if (m_rootAgents[avatar.UUID] == avatar.RegionHandle)
344 {
345 m_rootAgents.Remove(avatar.UUID);
346// m_log.Debug("[FRIEND]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent");
347 }
348 }
349 }
350 }
351 #endregion
352
353 private ScenePresence GetRootPresenceFromAgentID(UUID AgentID)
354 {
355 ScenePresence returnAgent = null;
356 lock (m_scenes)
357 {
358 ScenePresence queryagent = null;
359 foreach (Scene scene in m_scenes.Values)
360 {
361 queryagent = scene.GetScenePresence(AgentID);
362 if (queryagent != null)
363 {
364 if (!queryagent.IsChildAgent)
365 {
366 returnAgent = queryagent;
367 break;
368 }
369 }
370 }
371 }
372 return returnAgent;
373 }
374
375 private ScenePresence GetAnyPresenceFromAgentID(UUID AgentID)
376 {
377 ScenePresence returnAgent = null;
378 lock (m_scenes)
379 {
380 ScenePresence queryagent = null;
381 foreach (Scene scene in m_scenes.Values)
382 {
383 queryagent = scene.GetScenePresence(AgentID);
384 if (queryagent != null)
385 {
386 returnAgent = queryagent;
387 break;
388 }
389 }
390 }
391 return returnAgent;
392 }
393
394 public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, string offerMessage)
395 {
396 CachedUserInfo userInfo = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(fromUserId);
397
398 if (userInfo != null)
399 {
400 GridInstantMessage msg = new GridInstantMessage(
401 toUserClient.Scene, fromUserId, userInfo.UserProfile.Name, toUserClient.AgentId,
402 (byte)InstantMessageDialog.FriendshipOffered, offerMessage, false, Vector3.Zero);
403
404 FriendshipOffered(msg);
405 }
406 else
407 {
408 m_log.ErrorFormat("[FRIENDS]: No user found for id {0} in OfferFriendship()", fromUserId);
409 }
410 }
411
412 #region FriendRequestHandling
413
414 private void OnInstantMessage(IClientAPI client, GridInstantMessage im)
415 {
416 // Friend Requests go by Instant Message.. using the dialog param
417 // https://wiki.secondlife.com/wiki/ImprovedInstantMessage
418
419 if (im.dialog == (byte)InstantMessageDialog.FriendshipOffered) // 38
420 {
421 // fromAgentName is the *destination* name (the friend we offer friendship to)
422 ScenePresence initiator = GetAnyPresenceFromAgentID(new UUID(im.fromAgentID));
423 im.fromAgentName = initiator != null ? initiator.Name : "(hippo)";
424
425 FriendshipOffered(im);
426 }
427 else if (im.dialog == (byte)InstantMessageDialog.FriendshipAccepted) // 39
428 {
429 FriendshipAccepted(client, im);
430 }
431 else if (im.dialog == (byte)InstantMessageDialog.FriendshipDeclined) // 40
432 {
433 FriendshipDeclined(client, im);
434 }
435 }
436
437 /// <summary>
438 /// Invoked when a user offers a friendship.
439 /// </summary>
440 ///
441 /// <param name="im"></param>
442 /// <param name="client"></param>
443 private void FriendshipOffered(GridInstantMessage im)
444 {
445 // this is triggered by the initiating agent:
446 // A local agent offers friendship to some possibly remote friend.
447 // A IM is triggered, processed here and sent to the friend (possibly in a remote region).
448
449 m_log.DebugFormat("[FRIEND]: Offer(38) - From: {0}, FromName: {1} To: {2}, Session: {3}, Message: {4}, Offline {5}",
450 im.fromAgentID, im.fromAgentName, im.toAgentID, im.imSessionID, im.message, im.offline);
451
452 // 1.20 protocol sends an UUID in the message field, instead of the friendship offer text.
453 // For interoperability, we have to clear that
454 if (Util.isUUID(im.message)) im.message = "";
455
456 // be sneeky and use the initiator-UUID as transactionID. This means we can be stateless.
457 // we have to look up the agent name on friendship-approval, though.
458 im.imSessionID = im.fromAgentID;
459
460 if (m_TransferModule != null)
461 {
462 // Send it to whoever is the destination.
463 // If new friend is local, it will send an IM to the viewer.
464 // If new friend is remote, it will cause a OnGridInstantMessage on the remote server
465 m_TransferModule.SendInstantMessage(
466 im,
467 delegate(bool success)
468 {
469 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
470 }
471 );
472 }
473 }
474
475 /// <summary>
476 /// Invoked when a user accepts a friendship offer.
477 /// </summary>
478 /// <param name="im"></param>
479 /// <param name="client"></param>
480 private void FriendshipAccepted(IClientAPI client, GridInstantMessage im)
481 {
482 m_log.DebugFormat("[FRIEND]: 39 - from client {0}, agent {2} {3}, imsession {4} to {5}: {6} (dialog {7})",
483 client.AgentId, im.fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog);
484 }
485
486 /// <summary>
487 /// Invoked when a user declines a friendship offer.
488 /// </summary>
489 /// May not currently be used - see OnDenyFriendRequest() instead
490 /// <param name="im"></param>
491 /// <param name="client"></param>
492 private void FriendshipDeclined(IClientAPI client, GridInstantMessage im)
493 {
494 UUID fromAgentID = new UUID(im.fromAgentID);
495 UUID toAgentID = new UUID(im.toAgentID);
496
497 // declining the friendship offer causes a type 40 IM being sent to the (possibly remote) initiator
498 // toAgentID is initiator, fromAgentID declined friendship
499 m_log.DebugFormat("[FRIEND]: 40 - from client {0}, agent {1} {2}, imsession {3} to {4}: {5} (dialog {6})",
500 client != null ? client.AgentId.ToString() : "<null>",
501 fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog);
502
503 // Send the decline to whoever is the destination.
504 GridInstantMessage msg
505 = new GridInstantMessage(
506 client.Scene, fromAgentID, client.Name, toAgentID,
507 im.dialog, im.message, im.offline != 0, im.Position);
508
509 // If new friend is local, it will send an IM to the viewer.
510 // If new friend is remote, it will cause a OnGridInstantMessage on the remote server
511 m_TransferModule.SendInstantMessage(msg,
512 delegate(bool success) {
513 m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
514 }
515 );
516 }
517
518 private void OnGridInstantMessage(GridInstantMessage msg)
519 {
520 // This event won't be raised unless we have that agent,
521 // so we can depend on the above not trying to send
522 // via grid again
523 //m_log.DebugFormat("[FRIEND]: Got GridIM from {0}, to {1}, imSession {2}, message {3}, dialog {4}",
524 // msg.fromAgentID, msg.toAgentID, msg.imSessionID, msg.message, msg.dialog);
525
526 if (msg.dialog == (byte)InstantMessageDialog.FriendshipOffered ||
527 msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted ||
528 msg.dialog == (byte)InstantMessageDialog.FriendshipDeclined)
529 {
530 // this should succeed as we *know* the root agent is here.
531 m_TransferModule.SendInstantMessage(msg,
532 delegate(bool success) {
533 //m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success);
534 }
535 );
536 }
537
538 if (msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted)
539 {
540 // for accept friendship, we have to do a bit more
541 ApproveFriendship(new UUID(msg.fromAgentID), new UUID(msg.toAgentID), msg.fromAgentName);
542 }
543 }
544
545 private void ApproveFriendship(UUID fromAgentID, UUID toAgentID, string fromName)
546 {
547 m_log.DebugFormat("[FRIEND]: Approve friendship from {0} (ID: {1}) to {2}",
548 fromAgentID, fromName, toAgentID);
549
550 // a new friend was added in the initiator's and friend's data, so the cache entries are wrong now.
551 lock (m_friendLists)
552 {
553 m_friendLists.Invalidate(fromAgentID.ToString());
554 m_friendLists.Invalidate(toAgentID.ToString());
555 }
556
557 // now send presence update and add a calling card for the new friend
558
559 ScenePresence initiator = GetAnyPresenceFromAgentID(toAgentID);
560 if (initiator == null)
561 {
562 // quite wrong. Shouldn't happen.
563 m_log.WarnFormat("[FRIEND]: Coudn't find initiator of friend request {0}", toAgentID);
564 return;
565 }
566
567 m_log.DebugFormat("[FRIEND]: Tell {0} that {1} is online",
568 initiator.Name, fromName);
569 // tell initiator that friend is online
570 initiator.ControllingClient.SendAgentOnline(new UUID[] { fromAgentID });
571
572 // find the folder for the friend...
573 //InventoryFolderImpl folder =
574 // initiator.Scene.CommsManager.UserProfileCacheService.GetUserDetails(toAgentID).FindFolderForType((int)InventoryType.CallingCard);
575 IInventoryService invService = initiator.Scene.InventoryService;
576 InventoryFolderBase folder = invService.GetFolderForType(toAgentID, AssetType.CallingCard);
577 if (folder != null)
578 {
579 // ... and add the calling card
580 CreateCallingCard(initiator.ControllingClient, fromAgentID, folder.ID, fromName);
581 }
582>>>>>>> master:OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs
583 }
584
585 public void AddRegion(Scene scene) 61 public void AddRegion(Scene scene)
586 { 62 {
587 } 63 }
@@ -594,10 +70,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
594 { 70 {
595 } 71 }
596 72
597 public void Close()
598 {
599 }
600
601 public string Name 73 public string Name
602 { 74 {
603 get { return "FriendsModule"; } 75 get { return "FriendsModule"; }
@@ -608,29 +80,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
608 get { return null; } 80 get { return null; }
609 } 81 }
610 82
611 public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, 83 public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, string offerMessage)
612 string offerMessage)
613 {
614 }
615 public void FindAgent(IClientAPI remoteClient, UUID hunter, UUID target)
616 { 84 {
617 List<FriendListItem> friendList = GetUserFriends(hunter);
618 foreach (FriendListItem item in friendList)
619 {
620 if(item.onlinestatus == true)
621 {
622 if(item.Friend == target && (item.FriendPerms & (uint)FriendRights.CanSeeOnMap) != 0)
623 {
624 ScenePresence SPTarget = ((Scene)remoteClient.Scene).GetScenePresence(target);
625 string regionname = SPTarget.Scene.RegionInfo.RegionName;
626 remoteClient.SendScriptTeleportRequest("FindAgent", regionname,new Vector3(SPTarget.AbsolutePosition),new Vector3(SPTarget.Lookat));
627 }
628 }
629 else
630 {
631 remoteClient.SendAgentAlertMessage("The agent you are looking for is not online.", false);
632 }
633 }
634 } 85 }
635 86
636 public List<FriendListItem> GetUserFriends(UUID agentID) 87 public List<FriendListItem> GetUserFriends(UUID agentID)