diff options
-rw-r--r-- | OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | 551 |
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) |