diff options
author | Melanie | 2009-12-28 01:24:15 +0000 |
---|---|---|
committer | Melanie | 2009-12-28 01:24:15 +0000 |
commit | eebddcd5e693a4b56af326546d4222bd594286e0 (patch) | |
tree | b36b509696710a9082627962101323aa562fc552 /OpenSim | |
parent | Allow lists to be embedded in query strings (diff) | |
download | opensim-SC-eebddcd5e693a4b56af326546d4222bd594286e0.zip opensim-SC-eebddcd5e693a4b56af326546d4222bd594286e0.tar.gz opensim-SC-eebddcd5e693a4b56af326546d4222bd594286e0.tar.bz2 opensim-SC-eebddcd5e693a4b56af326546d4222bd594286e0.tar.xz |
Change FriendsModule, InstantMessageModule, MessageTransferModule, MuteListModule, OfflineMessageModule, PresenceModule, InventoryTransferModule and LureModule to new style. Reduce FriendsModule and PresenceModule to shells.
Diffstat (limited to 'OpenSim')
11 files changed, 287 insertions, 1561 deletions
diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs index 6fd3d30..1e85a22 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs | |||
@@ -102,8 +102,6 @@ namespace OpenSim.ApplicationPlugins.LoadRegions | |||
102 | m_log.Info("[LOADREGIONSPLUGIN]: Loading specific shared modules..."); | 102 | m_log.Info("[LOADREGIONSPLUGIN]: Loading specific shared modules..."); |
103 | m_log.Info("[LOADREGIONSPLUGIN]: DynamicTextureModule..."); | 103 | m_log.Info("[LOADREGIONSPLUGIN]: DynamicTextureModule..."); |
104 | m_openSim.ModuleLoader.LoadDefaultSharedModule(new DynamicTextureModule()); | 104 | m_openSim.ModuleLoader.LoadDefaultSharedModule(new DynamicTextureModule()); |
105 | m_log.Info("[LOADREGIONSPLUGIN]: InstantMessageModule..."); | ||
106 | m_openSim.ModuleLoader.LoadDefaultSharedModule(new InstantMessageModule()); | ||
107 | m_log.Info("[LOADREGIONSPLUGIN]: LoadImageURLModule..."); | 105 | m_log.Info("[LOADREGIONSPLUGIN]: LoadImageURLModule..."); |
108 | m_openSim.ModuleLoader.LoadDefaultSharedModule(new LoadImageURLModule()); | 106 | m_openSim.ModuleLoader.LoadDefaultSharedModule(new LoadImageURLModule()); |
109 | m_log.Info("[LOADREGIONSPLUGIN]: XMLRPCModule..."); | 107 | m_log.Info("[LOADREGIONSPLUGIN]: XMLRPCModule..."); |
@@ -217,4 +215,4 @@ namespace OpenSim.ApplicationPlugins.LoadRegions | |||
217 | } | 215 | } |
218 | } | 216 | } |
219 | } | 217 | } |
220 | } \ No newline at end of file | 218 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index d6a82ef..f5d30b7 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | |||
@@ -44,1088 +44,50 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; | |||
44 | 44 | ||
45 | namespace OpenSim.Region.CoreModules.Avatar.Friends | 45 | namespace OpenSim.Region.CoreModules.Avatar.Friends |
46 | { | 46 | { |
47 | /* | 47 | public class FriendsModule : ISharedRegionModule, IFriendsModule |
48 | This module handles adding/removing friends, and the the presence | ||
49 | notification process for login/logoff of friends. | ||
50 | |||
51 | The presence notification works as follows: | ||
52 | - After the user initially connects to a region (so we now have a UDP | ||
53 | connection to work with), this module fetches the friends of user | ||
54 | (those are cached), their on-/offline status, and info about the | ||
55 | region they are in from the MessageServer. | ||
56 | - (*) It then informs the user about the on-/offline status of her friends. | ||
57 | - It then informs all online friends currently on this region-server about | ||
58 | user's new online status (this will save some network traffic, as local | ||
59 | messages don't have to be transferred inter-region, and it will be all | ||
60 | that has to be done in Standalone Mode). | ||
61 | - For the rest of the online friends (those not on this region-server), | ||
62 | this module uses the provided region-information to map users to | ||
63 | regions, and sends one notification to every region containing the | ||
64 | friends to inform on that server. | ||
65 | - The region-server will handle that in the following way: | ||
66 | - If it finds the friend, it informs her about the user being online. | ||
67 | - If it doesn't find the friend (maybe she TPed away in the meantime), | ||
68 | it stores that information. | ||
69 | - After it processed all friends, it returns the list of friends it | ||
70 | couldn't find. | ||
71 | - If this list isn't empty, the FriendsModule re-requests information | ||
72 | about those online friends that have been missed and starts at (*) | ||
73 | again until all friends have been found, or until it tried 3 times | ||
74 | (to prevent endless loops due to some uncaught error). | ||
75 | |||
76 | NOTE: Online/Offline notifications don't need to be sent on region change. | ||
77 | |||
78 | We implement two XMLRpc handlers here, handling all the inter-region things | ||
79 | we have to handle: | ||
80 | - On-/Offline-Notifications (bulk) | ||
81 | - Terminate Friendship messages (single) | ||
82 | */ | ||
83 | |||
84 | public class FriendsModule : IRegionModule, IFriendsModule | ||
85 | { | 48 | { |
86 | private class Transaction | 49 | public void Initialise(IConfigSource config) |
87 | { | 50 | { |
88 | public UUID agentID; | ||
89 | public string agentName; | ||
90 | public uint count; | ||
91 | |||
92 | public Transaction(UUID agentID, string agentName) | ||
93 | { | ||
94 | this.agentID = agentID; | ||
95 | this.agentName = agentName; | ||
96 | this.count = 1; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
101 | |||
102 | private Cache m_friendLists = new Cache(CacheFlags.AllowUpdate); | ||
103 | |||
104 | private Dictionary<UUID, ulong> m_rootAgents = new Dictionary<UUID, ulong>(); | ||
105 | |||
106 | private Dictionary<UUID, UUID> m_pendingCallingcardRequests = new Dictionary<UUID,UUID>(); | ||
107 | |||
108 | private Scene m_initialScene; // saves a lookup if we don't have a specific scene | ||
109 | private Dictionary<ulong, Scene> m_scenes = new Dictionary<ulong,Scene>(); | ||
110 | private IMessageTransferModule m_TransferModule = null; | ||
111 | |||
112 | private IGridService m_gridServices = null; | ||
113 | |||
114 | #region IRegionModule Members | ||
115 | |||
116 | public void Initialise(Scene scene, IConfigSource config) | ||
117 | { | ||
118 | lock (m_scenes) | ||
119 | { | ||
120 | if (m_scenes.Count == 0) | ||
121 | { | ||
122 | MainServer.Instance.AddXmlRPCHandler("presence_update_bulk", processPresenceUpdateBulk); | ||
123 | MainServer.Instance.AddXmlRPCHandler("terminate_friend", processTerminateFriend); | ||
124 | m_friendLists.DefaultTTL = new TimeSpan(1, 0, 0); // store entries for one hour max | ||
125 | m_initialScene = scene; | ||
126 | } | ||
127 | |||
128 | if (!m_scenes.ContainsKey(scene.RegionInfo.RegionHandle)) | ||
129 | m_scenes[scene.RegionInfo.RegionHandle] = scene; | ||
130 | } | ||
131 | |||
132 | scene.RegisterModuleInterface<IFriendsModule>(this); | ||
133 | |||
134 | scene.EventManager.OnNewClient += OnNewClient; | ||
135 | scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; | ||
136 | scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel; | ||
137 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | ||
138 | scene.EventManager.OnClientClosed += ClientClosed; | ||
139 | } | 51 | } |
140 | 52 | ||
141 | public void PostInitialise() | 53 | public void PostInitialise() |
142 | { | 54 | { |
143 | if (m_scenes.Count > 0) | ||
144 | { | ||
145 | m_TransferModule = m_initialScene.RequestModuleInterface<IMessageTransferModule>(); | ||
146 | m_gridServices = m_initialScene.GridService; | ||
147 | } | ||
148 | if (m_TransferModule == null) | ||
149 | m_log.Error("[FRIENDS]: Unable to find a message transfer module, friendship offers will not work"); | ||
150 | } | ||
151 | |||
152 | public void Close() | ||
153 | { | ||
154 | } | ||
155 | |||
156 | public string Name | ||
157 | { | ||
158 | get { return "FriendsModule"; } | ||
159 | } | ||
160 | |||
161 | public bool IsSharedModule | ||
162 | { | ||
163 | get { return true; } | ||
164 | } | ||
165 | |||
166 | #endregion | ||
167 | |||
168 | #region IInterregionFriendsComms | ||
169 | |||
170 | public List<UUID> InformFriendsInOtherRegion(UUID agentId, ulong destRegionHandle, List<UUID> friends, bool online) | ||
171 | { | ||
172 | List<UUID> tpdAway = new List<UUID>(); | ||
173 | |||
174 | // destRegionHandle is a region on another server | ||
175 | uint x = 0, y = 0; | ||
176 | Utils.LongToUInts(destRegionHandle, out x, out y); | ||
177 | GridRegion info = m_gridServices.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, (int)x, (int)y); | ||
178 | if (info != null) | ||
179 | { | ||
180 | string httpServer = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/presence_update_bulk"; | ||
181 | |||
182 | Hashtable reqParams = new Hashtable(); | ||
183 | reqParams["agentID"] = agentId.ToString(); | ||
184 | reqParams["agentOnline"] = online; | ||
185 | int count = 0; | ||
186 | foreach (UUID uuid in friends) | ||
187 | { | ||
188 | reqParams["friendID_" + count++] = uuid.ToString(); | ||
189 | } | ||
190 | reqParams["friendCount"] = count; | ||
191 | |||
192 | IList parameters = new ArrayList(); | ||
193 | parameters.Add(reqParams); | ||
194 | try | ||
195 | { | ||
196 | XmlRpcRequest request = new XmlRpcRequest("presence_update_bulk", parameters); | ||
197 | XmlRpcResponse response = request.Send(httpServer, 5000); | ||
198 | Hashtable respData = (Hashtable)response.Value; | ||
199 | |||
200 | count = (int)respData["friendCount"]; | ||
201 | for (int i = 0; i < count; ++i) | ||
202 | { | ||
203 | UUID uuid; | ||
204 | if (UUID.TryParse((string)respData["friendID_" + i], out uuid)) tpdAway.Add(uuid); | ||
205 | } | ||
206 | } | ||
207 | catch (WebException e) | ||
208 | { | ||
209 | // Ignore connect failures, simulators come and go | ||
210 | // | ||
211 | if (!e.Message.Contains("ConnectFailure")) | ||
212 | { | ||
213 | m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e); | ||
214 | } | ||
215 | } | ||
216 | catch (Exception e) | ||
217 | { | ||
218 | m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e); | ||
219 | } | ||
220 | } | ||
221 | else m_log.WarnFormat("[OGS1 GRID SERVICES]: Couldn't find region {0}???", destRegionHandle); | ||
222 | |||
223 | return tpdAway; | ||
224 | } | ||
225 | |||
226 | public bool TriggerTerminateFriend(ulong destRegionHandle, UUID agentID, UUID exFriendID) | ||
227 | { | ||
228 | // destRegionHandle is a region on another server | ||
229 | uint x = 0, y = 0; | ||
230 | Utils.LongToUInts(destRegionHandle, out x, out y); | ||
231 | GridRegion info = m_gridServices.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, (int)x, (int)y); | ||
232 | if (info == null) | ||
233 | { | ||
234 | m_log.WarnFormat("[OGS1 GRID SERVICES]: Couldn't find region {0}", destRegionHandle); | ||
235 | return false; // region not found??? | ||
236 | } | ||
237 | |||
238 | string httpServer = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/presence_update_bulk"; | ||
239 | |||
240 | Hashtable reqParams = new Hashtable(); | ||
241 | reqParams["agentID"] = agentID.ToString(); | ||
242 | reqParams["friendID"] = exFriendID.ToString(); | ||
243 | |||
244 | IList parameters = new ArrayList(); | ||
245 | parameters.Add(reqParams); | ||
246 | try | ||
247 | { | ||
248 | XmlRpcRequest request = new XmlRpcRequest("terminate_friend", parameters); | ||
249 | XmlRpcResponse response = request.Send(httpServer, 5000); | ||
250 | Hashtable respData = (Hashtable)response.Value; | ||
251 | |||
252 | return (bool)respData["success"]; | ||
253 | } | ||
254 | catch (Exception e) | ||
255 | { | ||
256 | m_log.Error("[OGS1 GRID SERVICES]: InformFriendsInOtherRegion XMLRPC failure: ", e); | ||
257 | return false; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | #endregion | ||
262 | |||
263 | #region Incoming XMLRPC messages | ||
264 | /// <summary> | ||
265 | /// Receive presence information changes about clients in other regions. | ||
266 | /// </summary> | ||
267 | /// <param name="req"></param> | ||
268 | /// <returns></returns> | ||
269 | public XmlRpcResponse processPresenceUpdateBulk(XmlRpcRequest req, IPEndPoint remoteClient) | ||
270 | { | ||
271 | Hashtable requestData = (Hashtable)req.Params[0]; | ||
272 | |||
273 | List<UUID> friendsNotHere = new List<UUID>(); | ||
274 | |||
275 | // this is called with the expectation that all the friends in the request are on this region-server. | ||
276 | // But as some time passed since we checked (on the other region-server, via the MessagingServer), | ||
277 | // some of the friends might have teleported away. | ||
278 | // Actually, even now, between this line and the sending below, some people could TP away. So, | ||
279 | // we'll have to lock the m_rootAgents list for the duration to prevent/delay that. | ||
280 | lock (m_rootAgents) | ||
281 | { | ||
282 | List<ScenePresence> friendsHere = new List<ScenePresence>(); | ||
283 | |||
284 | try | ||
285 | { | ||
286 | UUID agentID = new UUID((string)requestData["agentID"]); | ||
287 | bool agentOnline = (bool)requestData["agentOnline"]; | ||
288 | int count = (int)requestData["friendCount"]; | ||
289 | for (int i = 0; i < count; ++i) | ||
290 | { | ||
291 | UUID uuid; | ||
292 | if (UUID.TryParse((string)requestData["friendID_" + i], out uuid)) | ||
293 | { | ||
294 | if (m_rootAgents.ContainsKey(uuid)) friendsHere.Add(GetRootPresenceFromAgentID(uuid)); | ||
295 | else friendsNotHere.Add(uuid); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | // now send, as long as they are still here... | ||
300 | UUID[] agentUUID = new UUID[] { agentID }; | ||
301 | if (agentOnline) | ||
302 | { | ||
303 | foreach (ScenePresence agent in friendsHere) | ||
304 | { | ||
305 | agent.ControllingClient.SendAgentOnline(agentUUID); | ||
306 | } | ||
307 | } | ||
308 | else | ||
309 | { | ||
310 | foreach (ScenePresence agent in friendsHere) | ||
311 | { | ||
312 | agent.ControllingClient.SendAgentOffline(agentUUID); | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | catch(Exception e) | ||
317 | { | ||
318 | m_log.Warn("[FRIENDS]: Got exception while parsing presence_update_bulk request:", e); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | // no need to lock anymore; if TPs happen now, worst case is that we have an additional agent in this region, | ||
323 | // which should be caught on the next iteration... | ||
324 | Hashtable result = new Hashtable(); | ||
325 | int idx = 0; | ||
326 | foreach (UUID uuid in friendsNotHere) | ||
327 | { | ||
328 | result["friendID_" + idx++] = uuid.ToString(); | ||
329 | } | ||
330 | result["friendCount"] = idx; | ||
331 | |||
332 | XmlRpcResponse response = new XmlRpcResponse(); | ||
333 | response.Value = result; | ||
334 | |||
335 | return response; | ||
336 | } | ||
337 | |||
338 | public XmlRpcResponse processTerminateFriend(XmlRpcRequest req, IPEndPoint remoteClient) | ||
339 | { | ||
340 | Hashtable requestData = (Hashtable)req.Params[0]; | ||
341 | |||
342 | bool success = false; | ||
343 | |||
344 | UUID agentID; | ||
345 | UUID friendID; | ||
346 | if (requestData.ContainsKey("agentID") && UUID.TryParse((string)requestData["agentID"], out agentID) && | ||
347 | requestData.ContainsKey("friendID") && UUID.TryParse((string)requestData["friendID"], out friendID)) | ||
348 | { | ||
349 | // try to find it and if it is there, prevent it to vanish before we sent the message | ||
350 | lock (m_rootAgents) | ||
351 | { | ||
352 | if (m_rootAgents.ContainsKey(agentID)) | ||
353 | { | ||
354 | m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", friendID, agentID); | ||
355 | GetRootPresenceFromAgentID(agentID).ControllingClient.SendTerminateFriend(friendID); | ||
356 | success = true; | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
361 | // return whether we were successful | ||
362 | Hashtable result = new Hashtable(); | ||
363 | result["success"] = success; | ||
364 | |||
365 | XmlRpcResponse response = new XmlRpcResponse(); | ||
366 | response.Value = result; | ||
367 | return response; | ||
368 | } | ||
369 | |||
370 | #endregion | ||
371 | |||
372 | #region Scene events | ||
373 | |||
374 | private void OnNewClient(IClientAPI client) | ||
375 | { | ||
376 | // All friends establishment protocol goes over instant message | ||
377 | // There's no way to send a message from the sim | ||
378 | // to a user to 'add a friend' without causing dialog box spam | ||
379 | |||
380 | // Subscribe to instant messages | ||
381 | client.OnInstantMessage += OnInstantMessage; | ||
382 | |||
383 | // Friend list management | ||
384 | client.OnApproveFriendRequest += OnApproveFriendRequest; | ||
385 | client.OnDenyFriendRequest += OnDenyFriendRequest; | ||
386 | client.OnTerminateFriendship += OnTerminateFriendship; | ||
387 | |||
388 | // ... calling card handling... | ||
389 | client.OnOfferCallingCard += OnOfferCallingCard; | ||
390 | client.OnAcceptCallingCard += OnAcceptCallingCard; | ||
391 | client.OnDeclineCallingCard += OnDeclineCallingCard; | ||
392 | |||
393 | // we need this one exactly once per agent session (see comments in the handler below) | ||
394 | client.OnEconomyDataRequest += OnEconomyDataRequest; | ||
395 | |||
396 | // if it leaves, we want to know, too | ||
397 | client.OnLogout += OnLogout; | ||
398 | client.OnGrantUserRights += GrantUserFriendRights; | ||
399 | |||
400 | } | ||
401 | |||
402 | private void ClientClosed(UUID AgentId, Scene scene) | ||
403 | { | ||
404 | // agent's client was closed. As we handle logout in OnLogout, this here has only to handle | ||
405 | // TPing away (root agent is closed) or TPing/crossing in a region far enough away (client | ||
406 | // agent is closed). | ||
407 | // NOTE: In general, this doesn't mean that the agent logged out, just that it isn't around | ||
408 | // in one of the regions here anymore. | ||
409 | lock (m_rootAgents) | ||
410 | { | ||
411 | if (m_rootAgents.ContainsKey(AgentId)) | ||
412 | { | ||
413 | m_rootAgents.Remove(AgentId); | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | |||
418 | private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) | ||
419 | { | ||
420 | lock (m_rootAgents) | ||
421 | { | ||
422 | m_rootAgents[avatar.UUID] = avatar.RegionHandle; | ||
423 | // Claim User! my user! Mine mine mine! | ||
424 | } | ||
425 | } | ||
426 | |||
427 | private void MakeChildAgent(ScenePresence avatar) | ||
428 | { | ||
429 | lock (m_rootAgents) | ||
430 | { | ||
431 | if (m_rootAgents.ContainsKey(avatar.UUID)) | ||
432 | { | ||
433 | // only delete if the region matches. As this is a shared module, the avatar could be | ||
434 | // root agent in another region on this server. | ||
435 | if (m_rootAgents[avatar.UUID] == avatar.RegionHandle) | ||
436 | { | ||
437 | m_rootAgents.Remove(avatar.UUID); | ||
438 | // m_log.Debug("[FRIEND]: Removing " + avatar.Firstname + " " + avatar.Lastname + " as a root agent"); | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | #endregion | ||
444 | |||
445 | private ScenePresence GetRootPresenceFromAgentID(UUID AgentID) | ||
446 | { | ||
447 | ScenePresence returnAgent = null; | ||
448 | lock (m_scenes) | ||
449 | { | ||
450 | ScenePresence queryagent = null; | ||
451 | foreach (Scene scene in m_scenes.Values) | ||
452 | { | ||
453 | queryagent = scene.GetScenePresence(AgentID); | ||
454 | if (queryagent != null) | ||
455 | { | ||
456 | if (!queryagent.IsChildAgent) | ||
457 | { | ||
458 | returnAgent = queryagent; | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | } | ||
463 | } | ||
464 | return returnAgent; | ||
465 | } | ||
466 | |||
467 | private ScenePresence GetAnyPresenceFromAgentID(UUID AgentID) | ||
468 | { | ||
469 | ScenePresence returnAgent = null; | ||
470 | lock (m_scenes) | ||
471 | { | ||
472 | ScenePresence queryagent = null; | ||
473 | foreach (Scene scene in m_scenes.Values) | ||
474 | { | ||
475 | queryagent = scene.GetScenePresence(AgentID); | ||
476 | if (queryagent != null) | ||
477 | { | ||
478 | returnAgent = queryagent; | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | return returnAgent; | ||
484 | } | ||
485 | |||
486 | public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, string offerMessage) | ||
487 | { | ||
488 | CachedUserInfo userInfo = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(fromUserId); | ||
489 | |||
490 | if (userInfo != null) | ||
491 | { | ||
492 | GridInstantMessage msg = new GridInstantMessage( | ||
493 | toUserClient.Scene, fromUserId, userInfo.UserProfile.Name, toUserClient.AgentId, | ||
494 | (byte)InstantMessageDialog.FriendshipOffered, offerMessage, false, Vector3.Zero); | ||
495 | |||
496 | FriendshipOffered(msg); | ||
497 | } | ||
498 | else | ||
499 | { | ||
500 | m_log.ErrorFormat("[FRIENDS]: No user found for id {0} in OfferFriendship()", fromUserId); | ||
501 | } | ||
502 | } | ||
503 | |||
504 | #region FriendRequestHandling | ||
505 | |||
506 | private void OnInstantMessage(IClientAPI client, GridInstantMessage im) | ||
507 | { | ||
508 | // Friend Requests go by Instant Message.. using the dialog param | ||
509 | // https://wiki.secondlife.com/wiki/ImprovedInstantMessage | ||
510 | |||
511 | if (im.dialog == (byte)InstantMessageDialog.FriendshipOffered) // 38 | ||
512 | { | ||
513 | // fromAgentName is the *destination* name (the friend we offer friendship to) | ||
514 | ScenePresence initiator = GetAnyPresenceFromAgentID(new UUID(im.fromAgentID)); | ||
515 | im.fromAgentName = initiator != null ? initiator.Name : "(hippo)"; | ||
516 | |||
517 | FriendshipOffered(im); | ||
518 | } | ||
519 | else if (im.dialog == (byte)InstantMessageDialog.FriendshipAccepted) // 39 | ||
520 | { | ||
521 | FriendshipAccepted(client, im); | ||
522 | } | ||
523 | else if (im.dialog == (byte)InstantMessageDialog.FriendshipDeclined) // 40 | ||
524 | { | ||
525 | FriendshipDeclined(client, im); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /// <summary> | ||
530 | /// Invoked when a user offers a friendship. | ||
531 | /// </summary> | ||
532 | /// | ||
533 | /// <param name="im"></param> | ||
534 | /// <param name="client"></param> | ||
535 | private void FriendshipOffered(GridInstantMessage im) | ||
536 | { | ||
537 | // this is triggered by the initiating agent: | ||
538 | // A local agent offers friendship to some possibly remote friend. | ||
539 | // A IM is triggered, processed here and sent to the friend (possibly in a remote region). | ||
540 | |||
541 | m_log.DebugFormat("[FRIEND]: Offer(38) - From: {0}, FromName: {1} To: {2}, Session: {3}, Message: {4}, Offline {5}", | ||
542 | im.fromAgentID, im.fromAgentName, im.toAgentID, im.imSessionID, im.message, im.offline); | ||
543 | |||
544 | // 1.20 protocol sends an UUID in the message field, instead of the friendship offer text. | ||
545 | // For interoperability, we have to clear that | ||
546 | if (Util.isUUID(im.message)) im.message = ""; | ||
547 | |||
548 | // be sneeky and use the initiator-UUID as transactionID. This means we can be stateless. | ||
549 | // we have to look up the agent name on friendship-approval, though. | ||
550 | im.imSessionID = im.fromAgentID; | ||
551 | |||
552 | if (m_TransferModule != null) | ||
553 | { | ||
554 | // Send it to whoever is the destination. | ||
555 | // If new friend is local, it will send an IM to the viewer. | ||
556 | // If new friend is remote, it will cause a OnGridInstantMessage on the remote server | ||
557 | m_TransferModule.SendInstantMessage( | ||
558 | im, | ||
559 | delegate(bool success) | ||
560 | { | ||
561 | m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); | ||
562 | } | ||
563 | ); | ||
564 | } | ||
565 | } | ||
566 | |||
567 | /// <summary> | ||
568 | /// Invoked when a user accepts a friendship offer. | ||
569 | /// </summary> | ||
570 | /// <param name="im"></param> | ||
571 | /// <param name="client"></param> | ||
572 | private void FriendshipAccepted(IClientAPI client, GridInstantMessage im) | ||
573 | { | ||
574 | m_log.DebugFormat("[FRIEND]: 39 - from client {0}, agent {2} {3}, imsession {4} to {5}: {6} (dialog {7})", | ||
575 | client.AgentId, im.fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog); | ||
576 | } | ||
577 | |||
578 | /// <summary> | ||
579 | /// Invoked when a user declines a friendship offer. | ||
580 | /// </summary> | ||
581 | /// May not currently be used - see OnDenyFriendRequest() instead | ||
582 | /// <param name="im"></param> | ||
583 | /// <param name="client"></param> | ||
584 | private void FriendshipDeclined(IClientAPI client, GridInstantMessage im) | ||
585 | { | ||
586 | UUID fromAgentID = new UUID(im.fromAgentID); | ||
587 | UUID toAgentID = new UUID(im.toAgentID); | ||
588 | |||
589 | // declining the friendship offer causes a type 40 IM being sent to the (possibly remote) initiator | ||
590 | // toAgentID is initiator, fromAgentID declined friendship | ||
591 | m_log.DebugFormat("[FRIEND]: 40 - from client {0}, agent {1} {2}, imsession {3} to {4}: {5} (dialog {6})", | ||
592 | client != null ? client.AgentId.ToString() : "<null>", | ||
593 | fromAgentID, im.fromAgentName, im.imSessionID, im.toAgentID, im.message, im.dialog); | ||
594 | |||
595 | // Send the decline to whoever is the destination. | ||
596 | GridInstantMessage msg | ||
597 | = new GridInstantMessage( | ||
598 | client.Scene, fromAgentID, client.Name, toAgentID, | ||
599 | im.dialog, im.message, im.offline != 0, im.Position); | ||
600 | |||
601 | // If new friend is local, it will send an IM to the viewer. | ||
602 | // If new friend is remote, it will cause a OnGridInstantMessage on the remote server | ||
603 | m_TransferModule.SendInstantMessage(msg, | ||
604 | delegate(bool success) { | ||
605 | m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); | ||
606 | } | ||
607 | ); | ||
608 | } | ||
609 | |||
610 | private void OnGridInstantMessage(GridInstantMessage msg) | ||
611 | { | ||
612 | // This event won't be raised unless we have that agent, | ||
613 | // so we can depend on the above not trying to send | ||
614 | // via grid again | ||
615 | //m_log.DebugFormat("[FRIEND]: Got GridIM from {0}, to {1}, imSession {2}, message {3}, dialog {4}", | ||
616 | // msg.fromAgentID, msg.toAgentID, msg.imSessionID, msg.message, msg.dialog); | ||
617 | |||
618 | if (msg.dialog == (byte)InstantMessageDialog.FriendshipOffered || | ||
619 | msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted || | ||
620 | msg.dialog == (byte)InstantMessageDialog.FriendshipDeclined) | ||
621 | { | ||
622 | // this should succeed as we *know* the root agent is here. | ||
623 | m_TransferModule.SendInstantMessage(msg, | ||
624 | delegate(bool success) { | ||
625 | //m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); | ||
626 | } | ||
627 | ); | ||
628 | } | ||
629 | |||
630 | if (msg.dialog == (byte)InstantMessageDialog.FriendshipAccepted) | ||
631 | { | ||
632 | // for accept friendship, we have to do a bit more | ||
633 | ApproveFriendship(new UUID(msg.fromAgentID), new UUID(msg.toAgentID), msg.fromAgentName); | ||
634 | } | ||
635 | } | ||
636 | |||
637 | private void ApproveFriendship(UUID fromAgentID, UUID toAgentID, string fromName) | ||
638 | { | ||
639 | m_log.DebugFormat("[FRIEND]: Approve friendship from {0} (ID: {1}) to {2}", | ||
640 | fromAgentID, fromName, toAgentID); | ||
641 | |||
642 | // a new friend was added in the initiator's and friend's data, so the cache entries are wrong now. | ||
643 | lock (m_friendLists) | ||
644 | { | ||
645 | m_friendLists.Invalidate(fromAgentID.ToString()); | ||
646 | m_friendLists.Invalidate(toAgentID.ToString()); | ||
647 | } | ||
648 | |||
649 | // now send presence update and add a calling card for the new friend | ||
650 | |||
651 | ScenePresence initiator = GetAnyPresenceFromAgentID(toAgentID); | ||
652 | if (initiator == null) | ||
653 | { | ||
654 | // quite wrong. Shouldn't happen. | ||
655 | m_log.WarnFormat("[FRIEND]: Coudn't find initiator of friend request {0}", toAgentID); | ||
656 | return; | ||
657 | } | ||
658 | |||
659 | m_log.DebugFormat("[FRIEND]: Tell {0} that {1} is online", | ||
660 | initiator.Name, fromName); | ||
661 | // tell initiator that friend is online | ||
662 | initiator.ControllingClient.SendAgentOnline(new UUID[] { fromAgentID }); | ||
663 | |||
664 | // find the folder for the friend... | ||
665 | //InventoryFolderImpl folder = | ||
666 | // initiator.Scene.CommsManager.UserProfileCacheService.GetUserDetails(toAgentID).FindFolderForType((int)InventoryType.CallingCard); | ||
667 | IInventoryService invService = initiator.Scene.InventoryService; | ||
668 | InventoryFolderBase folder = invService.GetFolderForType(toAgentID, AssetType.CallingCard); | ||
669 | if (folder != null) | ||
670 | { | ||
671 | // ... and add the calling card | ||
672 | CreateCallingCard(initiator.ControllingClient, fromAgentID, folder.ID, fromName); | ||
673 | } | ||
674 | } | 55 | } |
675 | 56 | ||
676 | private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) | 57 | public void AddRegion(Scene scene) |
677 | { | 58 | { |
678 | m_log.DebugFormat("[FRIEND]: Got approve friendship from {0} {1}, agentID {2}, tid {3}", | ||
679 | client.Name, client.AgentId, agentID, friendID); | ||
680 | |||
681 | // store the new friend persistently for both avatars | ||
682 | m_initialScene.StoreAddFriendship(friendID, agentID, (uint) FriendRights.CanSeeOnline); | ||
683 | |||
684 | // The cache entries aren't valid anymore either, as we just added a friend to both sides. | ||
685 | lock (m_friendLists) | ||
686 | { | ||
687 | m_friendLists.Invalidate(agentID.ToString()); | ||
688 | m_friendLists.Invalidate(friendID.ToString()); | ||
689 | } | ||
690 | |||
691 | // if it's a local friend, we don't have to do the lookup | ||
692 | ScenePresence friendPresence = GetAnyPresenceFromAgentID(friendID); | ||
693 | |||
694 | if (friendPresence != null) | ||
695 | { | ||
696 | m_log.Debug("[FRIEND]: Local agent detected."); | ||
697 | |||
698 | // create calling card | ||
699 | CreateCallingCard(client, friendID, callingCardFolders[0], friendPresence.Name); | ||
700 | |||
701 | // local message means OnGridInstantMessage won't be triggered, so do the work here. | ||
702 | friendPresence.ControllingClient.SendInstantMessage( | ||
703 | new GridInstantMessage(client.Scene, agentID, | ||
704 | client.Name, friendID, | ||
705 | (byte)InstantMessageDialog.FriendshipAccepted, | ||
706 | agentID.ToString(), false, Vector3.Zero)); | ||
707 | ApproveFriendship(agentID, friendID, client.Name); | ||
708 | } | ||
709 | else | ||
710 | { | ||
711 | m_log.Debug("[FRIEND]: Remote agent detected."); | ||
712 | |||
713 | // fetch the friend's name for the calling card. | ||
714 | CachedUserInfo info = m_initialScene.CommsManager.UserProfileCacheService.GetUserDetails(friendID); | ||
715 | |||
716 | // create calling card | ||
717 | CreateCallingCard(client, friendID, callingCardFolders[0], | ||
718 | info.UserProfile.FirstName + " " + info.UserProfile.SurName); | ||
719 | |||
720 | // Compose (remote) response to friend. | ||
721 | GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID, | ||
722 | (byte)InstantMessageDialog.FriendshipAccepted, | ||
723 | agentID.ToString(), false, Vector3.Zero); | ||
724 | if (m_TransferModule != null) | ||
725 | { | ||
726 | m_TransferModule.SendInstantMessage(msg, | ||
727 | delegate(bool success) { | ||
728 | m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); | ||
729 | } | ||
730 | ); | ||
731 | } | ||
732 | } | ||
733 | |||
734 | // tell client that new friend is online | ||
735 | client.SendAgentOnline(new UUID[] { friendID }); | ||
736 | } | 59 | } |
737 | 60 | ||
738 | private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders) | 61 | public void RegionLoaded(Scene scene) |
739 | { | 62 | { |
740 | m_log.DebugFormat("[FRIEND]: Got deny friendship from {0} {1}, agentID {2}, tid {3}", | ||
741 | client.Name, client.AgentId, agentID, friendID); | ||
742 | |||
743 | // Compose response to other agent. | ||
744 | GridInstantMessage msg = new GridInstantMessage(client.Scene, agentID, client.Name, friendID, | ||
745 | (byte)InstantMessageDialog.FriendshipDeclined, | ||
746 | agentID.ToString(), false, Vector3.Zero); | ||
747 | // send decline to initiator | ||
748 | if (m_TransferModule != null) | ||
749 | { | ||
750 | m_TransferModule.SendInstantMessage(msg, | ||
751 | delegate(bool success) { | ||
752 | m_log.DebugFormat("[FRIEND]: sending IM success = {0}", success); | ||
753 | } | ||
754 | ); | ||
755 | } | ||
756 | } | 63 | } |
757 | 64 | ||
758 | private void OnTerminateFriendship(IClientAPI client, UUID agentID, UUID exfriendID) | 65 | public void RemoveRegion(Scene scene) |
759 | { | 66 | { |
760 | // client.AgentId == agentID! | ||
761 | |||
762 | // this removes the friends from the stored friendlists. After the next login, they will be gone... | ||
763 | m_initialScene.StoreRemoveFriendship(agentID, exfriendID); | ||
764 | |||
765 | // ... now tell the two involved clients that they aren't friends anymore. | ||
766 | |||
767 | // I don't know why we have to tell <agent>, as this was caused by her, but that's how it works in SL... | ||
768 | client.SendTerminateFriend(exfriendID); | ||
769 | |||
770 | // now send the friend, if online | ||
771 | ScenePresence presence = GetAnyPresenceFromAgentID(exfriendID); | ||
772 | if (presence != null) | ||
773 | { | ||
774 | m_log.DebugFormat("[FRIEND]: Sending terminate friend {0} to agent {1}", agentID, exfriendID); | ||
775 | presence.ControllingClient.SendTerminateFriend(agentID); | ||
776 | } | ||
777 | else | ||
778 | { | ||
779 | // retry 3 times, in case the agent TPed from the last known region... | ||
780 | for (int retry = 0; retry < 3; ++retry) | ||
781 | { | ||
782 | // wasn't sent, so ex-friend wasn't around on this region-server. Fetch info and try to send | ||
783 | UserAgentData data = m_initialScene.CommsManager.UserService.GetAgentByUUID(exfriendID); | ||
784 | |||
785 | if (null == data) | ||
786 | break; | ||
787 | |||
788 | if (!data.AgentOnline) | ||
789 | { | ||
790 | m_log.DebugFormat("[FRIEND]: {0} is offline, so not sending TerminateFriend", exfriendID); | ||
791 | break; // if ex-friend isn't online, we don't need to send | ||
792 | } | ||
793 | |||
794 | m_log.DebugFormat("[FRIEND]: Sending remote terminate friend {0} to agent {1}@{2}", | ||
795 | agentID, exfriendID, data.Handle); | ||
796 | |||
797 | // try to send to foreign region, retry if it fails (friend TPed away, for example) | ||
798 | if (TriggerTerminateFriend(data.Handle, exfriendID, agentID)) break; | ||
799 | } | ||
800 | } | ||
801 | |||
802 | // clean up cache: FriendList is wrong now... | ||
803 | lock (m_friendLists) | ||
804 | { | ||
805 | m_friendLists.Invalidate(agentID.ToString()); | ||
806 | m_friendLists.Invalidate(exfriendID.ToString()); | ||
807 | } | ||
808 | } | 67 | } |
809 | 68 | ||
810 | #endregion | 69 | public void Close() |
811 | |||
812 | #region CallingCards | ||
813 | |||
814 | private void OnOfferCallingCard(IClientAPI client, UUID destID, UUID transactionID) | ||
815 | { | ||
816 | m_log.DebugFormat("[CALLING CARD]: got offer from {0} for {1}, transaction {2}", | ||
817 | client.AgentId, destID, transactionID); | ||
818 | // This might be slightly wrong. On a multi-region server, we might get the child-agent instead of the root-agent | ||
819 | // (or the root instead of the child) | ||
820 | ScenePresence destAgent = GetAnyPresenceFromAgentID(destID); | ||
821 | if (destAgent == null) | ||
822 | { | ||
823 | client.SendAlertMessage("The person you have offered a card to can't be found anymore."); | ||
824 | return; | ||
825 | } | ||
826 | |||
827 | lock (m_pendingCallingcardRequests) | ||
828 | { | ||
829 | m_pendingCallingcardRequests[transactionID] = client.AgentId; | ||
830 | } | ||
831 | // inform the destination agent about the offer | ||
832 | destAgent.ControllingClient.SendOfferCallingCard(client.AgentId, transactionID); | ||
833 | } | ||
834 | |||
835 | private void CreateCallingCard(IClientAPI client, UUID creator, UUID folder, string name) | ||
836 | { | ||
837 | InventoryItemBase item = new InventoryItemBase(); | ||
838 | item.AssetID = UUID.Zero; | ||
839 | item.AssetType = (int)AssetType.CallingCard; | ||
840 | item.BasePermissions = (uint)PermissionMask.Copy; | ||
841 | item.CreationDate = Util.UnixTimeSinceEpoch(); | ||
842 | item.CreatorId = creator.ToString(); | ||
843 | item.CurrentPermissions = item.BasePermissions; | ||
844 | item.Description = ""; | ||
845 | item.EveryOnePermissions = (uint)PermissionMask.None; | ||
846 | item.Flags = 0; | ||
847 | item.Folder = folder; | ||
848 | item.GroupID = UUID.Zero; | ||
849 | item.GroupOwned = false; | ||
850 | item.ID = UUID.Random(); | ||
851 | item.InvType = (int)InventoryType.CallingCard; | ||
852 | item.Name = name; | ||
853 | item.NextPermissions = item.EveryOnePermissions; | ||
854 | item.Owner = client.AgentId; | ||
855 | item.SalePrice = 10; | ||
856 | item.SaleType = (byte)SaleType.Not; | ||
857 | ((Scene)client.Scene).AddInventoryItem(client, item); | ||
858 | } | ||
859 | |||
860 | private void OnAcceptCallingCard(IClientAPI client, UUID transactionID, UUID folderID) | ||
861 | { | ||
862 | m_log.DebugFormat("[CALLING CARD]: User {0} ({1} {2}) accepted tid {3}, folder {4}", | ||
863 | client.AgentId, | ||
864 | client.FirstName, client.LastName, | ||
865 | transactionID, folderID); | ||
866 | UUID destID; | ||
867 | lock (m_pendingCallingcardRequests) | ||
868 | { | ||
869 | if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID)) | ||
870 | { | ||
871 | m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.", | ||
872 | client.Name); | ||
873 | return; | ||
874 | } | ||
875 | // else found pending calling card request with that transaction. | ||
876 | m_pendingCallingcardRequests.Remove(transactionID); | ||
877 | } | ||
878 | |||
879 | |||
880 | ScenePresence destAgent = GetAnyPresenceFromAgentID(destID); | ||
881 | // inform sender of the card that destination declined the offer | ||
882 | if (destAgent != null) destAgent.ControllingClient.SendAcceptCallingCard(transactionID); | ||
883 | |||
884 | // put a calling card into the inventory of receiver | ||
885 | CreateCallingCard(client, destID, folderID, destAgent.Name); | ||
886 | } | ||
887 | |||
888 | private void OnDeclineCallingCard(IClientAPI client, UUID transactionID) | ||
889 | { | 70 | { |
890 | m_log.DebugFormat("[CALLING CARD]: User {0} (ID:{1}) declined card, tid {2}", | ||
891 | client.Name, client.AgentId, transactionID); | ||
892 | UUID destID; | ||
893 | lock (m_pendingCallingcardRequests) | ||
894 | { | ||
895 | if (!m_pendingCallingcardRequests.TryGetValue(transactionID, out destID)) | ||
896 | { | ||
897 | m_log.WarnFormat("[CALLING CARD]: Got a AcceptCallingCard from {0} without an offer before.", | ||
898 | client.Name); | ||
899 | return; | ||
900 | } | ||
901 | // else found pending calling card request with that transaction. | ||
902 | m_pendingCallingcardRequests.Remove(transactionID); | ||
903 | } | ||
904 | |||
905 | ScenePresence destAgent = GetAnyPresenceFromAgentID(destID); | ||
906 | // inform sender of the card that destination declined the offer | ||
907 | if (destAgent != null) destAgent.ControllingClient.SendDeclineCallingCard(transactionID); | ||
908 | } | 71 | } |
909 | 72 | ||
910 | /// <summary> | 73 | public string Name |
911 | /// Send presence information about a client to other clients in both this region and others. | ||
912 | /// </summary> | ||
913 | /// <param name="client"></param> | ||
914 | /// <param name="friendList"></param> | ||
915 | /// <param name="iAmOnline"></param> | ||
916 | private void SendPresenceState(IClientAPI client, List<FriendListItem> friendList, bool iAmOnline) | ||
917 | { | 74 | { |
918 | //m_log.DebugFormat("[FRIEND]: {0} logged {1}; sending presence updates", client.Name, iAmOnline ? "in" : "out"); | 75 | get { return "FriendsModule"; } |
919 | |||
920 | if (friendList == null || friendList.Count == 0) | ||
921 | { | ||
922 | //m_log.DebugFormat("[FRIEND]: {0} doesn't have friends.", client.Name); | ||
923 | return; // nothing we can do if she doesn't have friends... | ||
924 | } | ||
925 | |||
926 | // collect sets of friendIDs; to send to (online and offline), and to receive from | ||
927 | // TODO: If we ever switch to .NET >= 3, replace those Lists with HashSets. | ||
928 | // I can't believe that we have Dictionaries, but no Sets, considering Java introduced them years ago... | ||
929 | List<UUID> friendIDsToSendTo = new List<UUID>(); | ||
930 | List<UUID> candidateFriendIDsToReceive = new List<UUID>(); | ||
931 | |||
932 | foreach (FriendListItem item in friendList) | ||
933 | { | ||
934 | if (((item.FriendListOwnerPerms | item.FriendPerms) & (uint)FriendRights.CanSeeOnline) != 0) | ||
935 | { | ||
936 | // friend is allowed to see my presence => add | ||
937 | if ((item.FriendListOwnerPerms & (uint)FriendRights.CanSeeOnline) != 0) | ||
938 | friendIDsToSendTo.Add(item.Friend); | ||
939 | |||
940 | if ((item.FriendPerms & (uint)FriendRights.CanSeeOnline) != 0) | ||
941 | candidateFriendIDsToReceive.Add(item.Friend); | ||
942 | } | ||
943 | } | ||
944 | |||
945 | // we now have a list of "interesting" friends (which we have to find out on-/offline state for), | ||
946 | // friends we want to send our online state to (if *they* are online, too), and | ||
947 | // friends we want to receive online state for (currently unknown whether online or not) | ||
948 | |||
949 | // as this processing might take some time and friends might TP away, we try up to three times to | ||
950 | // reach them. Most of the time, we *will* reach them, and this loop won't loop | ||
951 | int retry = 0; | ||
952 | do | ||
953 | { | ||
954 | // build a list of friends to look up region-information and on-/offline-state for | ||
955 | List<UUID> friendIDsToLookup = new List<UUID>(friendIDsToSendTo); | ||
956 | foreach (UUID uuid in candidateFriendIDsToReceive) | ||
957 | { | ||
958 | if (!friendIDsToLookup.Contains(uuid)) friendIDsToLookup.Add(uuid); | ||
959 | } | ||
960 | |||
961 | m_log.DebugFormat( | ||
962 | "[FRIEND]: {0} to lookup, {1} to send to, {2} candidates to receive from for agent {3}", | ||
963 | friendIDsToLookup.Count, friendIDsToSendTo.Count, candidateFriendIDsToReceive.Count, client.Name); | ||
964 | |||
965 | // we have to fetch FriendRegionInfos, as the (cached) FriendListItems don't | ||
966 | // necessarily contain the correct online state... | ||
967 | Dictionary<UUID, FriendRegionInfo> friendRegions = m_initialScene.GetFriendRegionInfos(friendIDsToLookup); | ||
968 | m_log.DebugFormat( | ||
969 | "[FRIEND]: Found {0} regionInfos for {1} friends of {2}", | ||
970 | friendRegions.Count, friendIDsToLookup.Count, client.Name); | ||
971 | |||
972 | // argument for SendAgentOn/Offline; we shouldn't generate that repeatedly within loops. | ||
973 | UUID[] agentArr = new UUID[] { client.AgentId }; | ||
974 | |||
975 | // first, send to friend presence state to me, if I'm online... | ||
976 | if (iAmOnline) | ||
977 | { | ||
978 | List<UUID> friendIDsToReceive = new List<UUID>(); | ||
979 | |||
980 | for (int i = candidateFriendIDsToReceive.Count - 1; i >= 0; --i) | ||
981 | { | ||
982 | UUID uuid = candidateFriendIDsToReceive[i]; | ||
983 | FriendRegionInfo info; | ||
984 | if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline) | ||
985 | { | ||
986 | friendIDsToReceive.Add(uuid); | ||
987 | } | ||
988 | } | ||
989 | |||
990 | m_log.DebugFormat( | ||
991 | "[FRIEND]: Sending {0} online friends to {1}", friendIDsToReceive.Count, client.Name); | ||
992 | |||
993 | if (friendIDsToReceive.Count > 0) | ||
994 | client.SendAgentOnline(friendIDsToReceive.ToArray()); | ||
995 | |||
996 | // clear them for a possible second iteration; we don't have to repeat this | ||
997 | candidateFriendIDsToReceive.Clear(); | ||
998 | } | ||
999 | |||
1000 | // now, send my presence state to my friends | ||
1001 | for (int i = friendIDsToSendTo.Count - 1; i >= 0; --i) | ||
1002 | { | ||
1003 | UUID uuid = friendIDsToSendTo[i]; | ||
1004 | FriendRegionInfo info; | ||
1005 | if (friendRegions.TryGetValue(uuid, out info) && info != null && info.isOnline) | ||
1006 | { | ||
1007 | // any client is good enough, root or child... | ||
1008 | ScenePresence agent = GetAnyPresenceFromAgentID(uuid); | ||
1009 | if (agent != null) | ||
1010 | { | ||
1011 | //m_log.DebugFormat("[FRIEND]: Found local agent {0}", agent.Name); | ||
1012 | |||
1013 | // friend is online and on this server... | ||
1014 | if (iAmOnline) agent.ControllingClient.SendAgentOnline(agentArr); | ||
1015 | else agent.ControllingClient.SendAgentOffline(agentArr); | ||
1016 | |||
1017 | // done, remove it | ||
1018 | friendIDsToSendTo.RemoveAt(i); | ||
1019 | } | ||
1020 | } | ||
1021 | else | ||
1022 | { | ||
1023 | //m_log.DebugFormat("[FRIEND]: Friend {0} ({1}) is offline; not sending.", uuid, i); | ||
1024 | |||
1025 | // friend is offline => no need to try sending | ||
1026 | friendIDsToSendTo.RemoveAt(i); | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | m_log.DebugFormat("[FRIEND]: Have {0} friends to contact via inter-region comms.", friendIDsToSendTo.Count); | ||
1031 | |||
1032 | // we now have all the friends left that are online (we think), but not on this region-server | ||
1033 | if (friendIDsToSendTo.Count > 0) | ||
1034 | { | ||
1035 | // sort them into regions | ||
1036 | Dictionary<ulong, List<UUID>> friendsInRegion = new Dictionary<ulong,List<UUID>>(); | ||
1037 | foreach (UUID uuid in friendIDsToSendTo) | ||
1038 | { | ||
1039 | ulong handle = friendRegions[uuid].regionHandle; // this can't fail as we filtered above already | ||
1040 | List<UUID> friends; | ||
1041 | if (!friendsInRegion.TryGetValue(handle, out friends)) | ||
1042 | { | ||
1043 | friends = new List<UUID>(); | ||
1044 | friendsInRegion[handle] = friends; | ||
1045 | } | ||
1046 | friends.Add(uuid); | ||
1047 | } | ||
1048 | m_log.DebugFormat("[FRIEND]: Found {0} regions to send to.", friendRegions.Count); | ||
1049 | |||
1050 | // clear uuids list and collect missed friends in it for the next retry | ||
1051 | friendIDsToSendTo.Clear(); | ||
1052 | |||
1053 | // send bulk updates to the region | ||
1054 | foreach (KeyValuePair<ulong, List<UUID>> pair in friendsInRegion) | ||
1055 | { | ||
1056 | //m_log.DebugFormat("[FRIEND]: Inform {0} friends in region {1} that user {2} is {3}line", | ||
1057 | // pair.Value.Count, pair.Key, client.Name, iAmOnline ? "on" : "off"); | ||
1058 | |||
1059 | friendIDsToSendTo.AddRange(InformFriendsInOtherRegion(client.AgentId, pair.Key, pair.Value, iAmOnline)); | ||
1060 | } | ||
1061 | } | ||
1062 | // now we have in friendIDsToSendTo only the agents left that TPed away while we tried to contact them. | ||
1063 | // In most cases, it will be empty, and it won't loop here. But sometimes, we have to work harder and try again... | ||
1064 | } | ||
1065 | while (++retry < 3 && friendIDsToSendTo.Count > 0); | ||
1066 | } | 76 | } |
1067 | 77 | ||
1068 | private void OnEconomyDataRequest(UUID agentID) | 78 | public Type ReplaceableInterface |
1069 | { | 79 | { |
1070 | // KLUDGE: This is the only way I found to get a message (only) after login was completed and the | 80 | get { return null; } |
1071 | // client is connected enough to receive UDP packets). | ||
1072 | // This packet seems to be sent only once, just after connection was established to the first | ||
1073 | // region after login. | ||
1074 | // We use it here to trigger a presence update; the old update-on-login was never be heard by | ||
1075 | // the freshly logged in viewer, as it wasn't connected to the region at that time. | ||
1076 | // TODO: Feel free to replace this by a better solution if you find one. | ||
1077 | |||
1078 | // get the agent. This should work every time, as we just got a packet from it | ||
1079 | //ScenePresence agent = GetRootPresenceFromAgentID(agentID); | ||
1080 | // KLUDGE 2: As this is sent quite early, the avatar isn't here as root agent yet. So, we have to cheat a bit | ||
1081 | ScenePresence agent = GetAnyPresenceFromAgentID(agentID); | ||
1082 | |||
1083 | // just to be paranoid... | ||
1084 | if (agent == null) | ||
1085 | { | ||
1086 | m_log.ErrorFormat("[FRIEND]: Got a packet from agent {0} who can't be found anymore!?", agentID); | ||
1087 | return; | ||
1088 | } | ||
1089 | |||
1090 | List<FriendListItem> fl; | ||
1091 | lock (m_friendLists) | ||
1092 | { | ||
1093 | fl = (List<FriendListItem>)m_friendLists.Get(agent.ControllingClient.AgentId.ToString(), | ||
1094 | m_initialScene.GetFriendList); | ||
1095 | } | ||
1096 | |||
1097 | // tell everyone that we are online | ||
1098 | SendPresenceState(agent.ControllingClient, fl, true); | ||
1099 | } | 81 | } |
1100 | 82 | ||
1101 | private void OnLogout(IClientAPI remoteClient) | 83 | public void OfferFriendship(UUID fromUserId, IClientAPI toUserClient, |
84 | string offerMessage) | ||
1102 | { | 85 | { |
1103 | List<FriendListItem> fl; | ||
1104 | lock (m_friendLists) | ||
1105 | { | ||
1106 | fl = (List<FriendListItem>)m_friendLists.Get(remoteClient.AgentId.ToString(), | ||
1107 | m_initialScene.GetFriendList); | ||
1108 | } | ||
1109 | |||
1110 | // tell everyone that we are offline | ||
1111 | SendPresenceState(remoteClient, fl, false); | ||
1112 | } | ||
1113 | private void GrantUserFriendRights(IClientAPI remoteClient, UUID requester, UUID target, int rights) | ||
1114 | { | ||
1115 | ((Scene)remoteClient.Scene).CommsManager.UpdateUserFriendPerms(requester, target, (uint)rights); | ||
1116 | } | 86 | } |
1117 | 87 | ||
1118 | public List<FriendListItem> GetUserFriends(UUID agentID) | 88 | public List<FriendListItem> GetUserFriends(UUID agentID) |
1119 | { | 89 | { |
1120 | List<FriendListItem> fl; | 90 | return null; |
1121 | lock (m_friendLists) | ||
1122 | { | ||
1123 | fl = (List<FriendListItem>)m_friendLists.Get(agentID.ToString(), | ||
1124 | m_initialScene.GetFriendList); | ||
1125 | } | ||
1126 | |||
1127 | return fl; | ||
1128 | } | 91 | } |
1129 | } | 92 | } |
1130 | #endregion | ||
1131 | } | 93 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs index 9a68749..ab141eb 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/InstantMessageModule.cs | |||
@@ -24,6 +24,7 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | using System; | ||
27 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
28 | using System.Reflection; | 29 | using System.Reflection; |
29 | using log4net; | 30 | using log4net; |
@@ -36,9 +37,10 @@ using OpenSim.Region.Framework.Scenes; | |||
36 | 37 | ||
37 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | 38 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage |
38 | { | 39 | { |
39 | public class InstantMessageModule : IRegionModule | 40 | public class InstantMessageModule : ISharedRegionModule |
40 | { | 41 | { |
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger( |
43 | MethodBase.GetCurrentMethod().DeclaringType); | ||
42 | 44 | ||
43 | /// <value> | 45 | /// <value> |
44 | /// Is this module enabled? | 46 | /// Is this module enabled? |
@@ -51,7 +53,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
51 | 53 | ||
52 | private IMessageTransferModule m_TransferModule = null; | 54 | private IMessageTransferModule m_TransferModule = null; |
53 | 55 | ||
54 | public void Initialise(Scene scene, IConfigSource config) | 56 | public void Initialise(IConfigSource config) |
55 | { | 57 | { |
56 | if (config.Configs["Messaging"] != null) | 58 | if (config.Configs["Messaging"] != null) |
57 | { | 59 | { |
@@ -62,6 +64,12 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
62 | } | 64 | } |
63 | 65 | ||
64 | m_enabled = true; | 66 | m_enabled = true; |
67 | } | ||
68 | |||
69 | public void AddRegion(Scene scene) | ||
70 | { | ||
71 | if (!m_enabled) | ||
72 | return; | ||
65 | 73 | ||
66 | lock (m_scenes) | 74 | lock (m_scenes) |
67 | { | 75 | { |
@@ -74,6 +82,39 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
74 | } | 82 | } |
75 | } | 83 | } |
76 | 84 | ||
85 | public void RegionLoaded(Scene scene) | ||
86 | { | ||
87 | if (!m_enabled) | ||
88 | return; | ||
89 | |||
90 | if (m_TransferModule == null) | ||
91 | { | ||
92 | m_TransferModule = | ||
93 | scene.RequestModuleInterface<IMessageTransferModule>(); | ||
94 | |||
95 | if (m_TransferModule == null) | ||
96 | { | ||
97 | m_log.Error("[INSTANT MESSAGE]: No message transfer module, IM will not work!"); | ||
98 | scene.EventManager.OnClientConnect -= OnClientConnect; | ||
99 | scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; | ||
100 | |||
101 | m_scenes.Clear(); | ||
102 | m_enabled = false; | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | public void RemoveRegion(Scene scene) | ||
108 | { | ||
109 | if (!m_enabled) | ||
110 | return; | ||
111 | |||
112 | lock (m_scenes) | ||
113 | { | ||
114 | m_scenes.Remove(scene); | ||
115 | } | ||
116 | } | ||
117 | |||
77 | void OnClientConnect(IClientCore client) | 118 | void OnClientConnect(IClientCore client) |
78 | { | 119 | { |
79 | IClientIM clientIM; | 120 | IClientIM clientIM; |
@@ -85,15 +126,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
85 | 126 | ||
86 | public void PostInitialise() | 127 | public void PostInitialise() |
87 | { | 128 | { |
88 | if (!m_enabled) | ||
89 | return; | ||
90 | |||
91 | m_TransferModule = | ||
92 | m_scenes[0].RequestModuleInterface<IMessageTransferModule>(); | ||
93 | |||
94 | if (m_TransferModule == null) | ||
95 | m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ | ||
96 | "IM will not work!"); | ||
97 | } | 129 | } |
98 | 130 | ||
99 | public void Close() | 131 | public void Close() |
@@ -105,9 +137,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
105 | get { return "InstantMessageModule"; } | 137 | get { return "InstantMessageModule"; } |
106 | } | 138 | } |
107 | 139 | ||
108 | public bool IsSharedModule | 140 | public Type ReplaceableInterface |
109 | { | 141 | { |
110 | get { return true; } | 142 | get { return null; } |
111 | } | 143 | } |
112 | 144 | ||
113 | #endregion | 145 | #endregion |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index e5159b3..b5019f1 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs | |||
@@ -40,18 +40,17 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; | |||
40 | 40 | ||
41 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | 41 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage |
42 | { | 42 | { |
43 | public class MessageTransferModule : IRegionModule, IMessageTransferModule | 43 | public class MessageTransferModule : ISharedRegionModule, IMessageTransferModule |
44 | { | 44 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
47 | // private bool m_Enabled = false; | 47 | private bool m_Enabled = false; |
48 | protected bool m_Gridmode = false; | ||
49 | protected List<Scene> m_Scenes = new List<Scene>(); | 48 | protected List<Scene> m_Scenes = new List<Scene>(); |
50 | protected Dictionary<UUID, ulong> m_UserRegionMap = new Dictionary<UUID, ulong>(); | 49 | protected Dictionary<UUID, ulong> m_UserRegionMap = new Dictionary<UUID, ulong>(); |
51 | 50 | ||
52 | public event UndeliveredMessage OnUndeliveredMessage; | 51 | public event UndeliveredMessage OnUndeliveredMessage; |
53 | 52 | ||
54 | public virtual void Initialise(Scene scene, IConfigSource config) | 53 | public virtual void Initialise(IConfigSource config) |
55 | { | 54 | { |
56 | IConfig cnf = config.Configs["Messaging"]; | 55 | IConfig cnf = config.Configs["Messaging"]; |
57 | if (cnf != null && cnf.GetString( | 56 | if (cnf != null && cnf.GetString( |
@@ -62,20 +61,19 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
62 | return; | 61 | return; |
63 | } | 62 | } |
64 | 63 | ||
65 | cnf = config.Configs["Startup"]; | 64 | MainServer.Instance.AddXmlRPCHandler( |
66 | if (cnf != null) | 65 | "grid_instant_message", processXMLRPCGridInstantMessage); |
67 | m_Gridmode = cnf.GetBoolean("gridmode", false); | ||
68 | 66 | ||
69 | // m_Enabled = true; | 67 | m_Enabled = true; |
68 | } | ||
69 | |||
70 | public virtual void AddRegion(Scene scene) | ||
71 | { | ||
72 | if (!m_Enabled) | ||
73 | return; | ||
70 | 74 | ||
71 | lock (m_Scenes) | 75 | lock (m_Scenes) |
72 | { | 76 | { |
73 | if (m_Scenes.Count == 0) | ||
74 | { | ||
75 | MainServer.Instance.AddXmlRPCHandler( | ||
76 | "grid_instant_message", processXMLRPCGridInstantMessage); | ||
77 | } | ||
78 | |||
79 | m_log.Debug("[MESSAGE TRANSFER]: Message transfer module active"); | 77 | m_log.Debug("[MESSAGE TRANSFER]: Message transfer module active"); |
80 | scene.RegisterModuleInterface<IMessageTransferModule>(this); | 78 | scene.RegisterModuleInterface<IMessageTransferModule>(this); |
81 | m_Scenes.Add(scene); | 79 | m_Scenes.Add(scene); |
@@ -86,6 +84,21 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
86 | { | 84 | { |
87 | } | 85 | } |
88 | 86 | ||
87 | public virtual void RegionLoaded(Scene scene) | ||
88 | { | ||
89 | } | ||
90 | |||
91 | public virtual void RemoveRegion(Scene scene) | ||
92 | { | ||
93 | if (!m_Enabled) | ||
94 | return; | ||
95 | |||
96 | lock(m_Scenes) | ||
97 | { | ||
98 | m_Scenes.Remove(scene); | ||
99 | } | ||
100 | } | ||
101 | |||
89 | public virtual void Close() | 102 | public virtual void Close() |
90 | { | 103 | { |
91 | } | 104 | } |
@@ -95,9 +108,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
95 | get { return "MessageTransferModule"; } | 108 | get { return "MessageTransferModule"; } |
96 | } | 109 | } |
97 | 110 | ||
98 | public virtual bool IsSharedModule | 111 | public virtual Type ReplaceableInterface |
99 | { | 112 | { |
100 | get { return true; } | 113 | get { return null; } |
101 | } | 114 | } |
102 | 115 | ||
103 | public virtual void SendInstantMessage(GridInstantMessage im, MessageResultNotification result) | 116 | public virtual void SendInstantMessage(GridInstantMessage im, MessageResultNotification result) |
@@ -148,15 +161,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
148 | } | 161 | } |
149 | } | 162 | } |
150 | 163 | ||
151 | if (m_Gridmode) | 164 | SendGridInstantMessageViaXMLRPC(im, result); |
152 | { | ||
153 | //m_log.DebugFormat("[INSTANT MESSAGE]: Delivering via grid"); | ||
154 | // Still here, try send via Grid | ||
155 | SendGridInstantMessageViaXMLRPC(im, result); | ||
156 | return; | ||
157 | } | ||
158 | |||
159 | HandleUndeliveredMessage(im, result); | ||
160 | 165 | ||
161 | return; | 166 | return; |
162 | } | 167 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs index 2d4a635..1ff5865 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MuteListModule.cs | |||
@@ -39,7 +39,7 @@ using OpenSim.Region.Framework.Scenes; | |||
39 | 39 | ||
40 | namespace OpenSim.Region.CoreModules.Avatar.MuteList | 40 | namespace OpenSim.Region.CoreModules.Avatar.MuteList |
41 | { | 41 | { |
42 | public class MuteListModule : IRegionModule | 42 | public class MuteListModule : ISharedRegionModule |
43 | { | 43 | { |
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | 45 | ||
@@ -47,11 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.MuteList | |||
47 | private List<Scene> m_SceneList = new List<Scene>(); | 47 | private List<Scene> m_SceneList = new List<Scene>(); |
48 | private string m_RestURL = String.Empty; | 48 | private string m_RestURL = String.Empty; |
49 | 49 | ||
50 | public void Initialise(Scene scene, IConfigSource config) | 50 | public void Initialise(IConfigSource config) |
51 | { | 51 | { |
52 | if (!enabled) | ||
53 | return; | ||
54 | |||
55 | IConfig cnf = config.Configs["Messaging"]; | 52 | IConfig cnf = config.Configs["Messaging"]; |
56 | if (cnf == null) | 53 | if (cnf == null) |
57 | { | 54 | { |
@@ -59,39 +56,53 @@ namespace OpenSim.Region.CoreModules.Avatar.MuteList | |||
59 | return; | 56 | return; |
60 | } | 57 | } |
61 | 58 | ||
62 | if (cnf != null && cnf.GetString( | 59 | if (cnf != null && cnf.GetString("MuteListModule", "None") != |
63 | "MuteListModule", "None") != | ||
64 | "MuteListModule") | 60 | "MuteListModule") |
65 | { | 61 | { |
66 | enabled = false; | 62 | enabled = false; |
67 | return; | 63 | return; |
68 | } | 64 | } |
69 | 65 | ||
66 | m_RestURL = cnf.GetString("MuteListURL", ""); | ||
67 | if (m_RestURL == "") | ||
68 | { | ||
69 | m_log.Error("[MUTE LIST] Module was enabled, but no URL is given, disabling"); | ||
70 | enabled = false; | ||
71 | return; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | public void AddRegion(Scene scene) | ||
76 | { | ||
77 | if (!enabled) | ||
78 | return; | ||
79 | |||
70 | lock (m_SceneList) | 80 | lock (m_SceneList) |
71 | { | 81 | { |
72 | if (m_SceneList.Count == 0) | 82 | m_SceneList.Add(scene); |
73 | { | ||
74 | m_RestURL = cnf.GetString("MuteListURL", ""); | ||
75 | if (m_RestURL == "") | ||
76 | { | ||
77 | m_log.Error("[MUTE LIST] Module was enabled, but no URL is given, disabling"); | ||
78 | enabled = false; | ||
79 | return; | ||
80 | } | ||
81 | } | ||
82 | if (!m_SceneList.Contains(scene)) | ||
83 | m_SceneList.Add(scene); | ||
84 | 83 | ||
85 | scene.EventManager.OnNewClient += OnNewClient; | 84 | scene.EventManager.OnNewClient += OnNewClient; |
86 | } | 85 | } |
87 | } | 86 | } |
88 | 87 | ||
89 | public void PostInitialise() | 88 | public void RegionLoaded(Scene scene) |
89 | { | ||
90 | } | ||
91 | |||
92 | public void RemoveRegion(Scene scene) | ||
90 | { | 93 | { |
91 | if (!enabled) | 94 | if (!enabled) |
92 | return; | 95 | return; |
93 | 96 | ||
94 | if (m_SceneList.Count == 0) | 97 | lock (m_SceneList) |
98 | { | ||
99 | m_SceneList.Remove(scene); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | public void PostInitialise() | ||
104 | { | ||
105 | if (!enabled) | ||
95 | return; | 106 | return; |
96 | 107 | ||
97 | m_log.Debug("[MUTE LIST] Mute list enabled"); | 108 | m_log.Debug("[MUTE LIST] Mute list enabled"); |
@@ -102,26 +113,15 @@ namespace OpenSim.Region.CoreModules.Avatar.MuteList | |||
102 | get { return "MuteListModule"; } | 113 | get { return "MuteListModule"; } |
103 | } | 114 | } |
104 | 115 | ||
105 | public bool IsSharedModule | 116 | public Type ReplaceableInterface |
106 | { | 117 | { |
107 | get { return true; } | 118 | get { return null; } |
108 | } | 119 | } |
109 | 120 | ||
110 | public void Close() | 121 | public void Close() |
111 | { | 122 | { |
112 | } | 123 | } |
113 | 124 | ||
114 | // private IClientAPI FindClient(UUID agentID) | ||
115 | // { | ||
116 | // foreach (Scene s in m_SceneList) | ||
117 | // { | ||
118 | // ScenePresence presence = s.GetScenePresence(agentID); | ||
119 | // if (presence != null && !presence.IsChildAgent) | ||
120 | // return presence.ControllingClient; | ||
121 | // } | ||
122 | // return null; | ||
123 | // } | ||
124 | |||
125 | private void OnNewClient(IClientAPI client) | 125 | private void OnNewClient(IClientAPI client) |
126 | { | 126 | { |
127 | client.OnMuteListRequest += OnMuteListRequest; | 127 | client.OnMuteListRequest += OnMuteListRequest; |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index 1614b70..a835c52 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs | |||
@@ -40,78 +40,88 @@ using OpenSim.Region.Framework.Scenes; | |||
40 | 40 | ||
41 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | 41 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage |
42 | { | 42 | { |
43 | public class OfflineMessageModule : IRegionModule | 43 | public class OfflineMessageModule : ISharedRegionModule |
44 | { | 44 | { |
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
47 | private bool enabled = true; | 47 | private bool enabled = true; |
48 | private List<Scene> m_SceneList = new List<Scene>(); | 48 | private List<Scene> m_SceneList = new List<Scene>(); |
49 | private string m_RestURL = String.Empty; | 49 | private string m_RestURL = String.Empty; |
50 | IMessageTransferModule m_TransferModule = null; | ||
50 | 51 | ||
51 | public void Initialise(Scene scene, IConfigSource config) | 52 | public void Initialise(IConfigSource config) |
52 | { | 53 | { |
53 | if (!enabled) | ||
54 | return; | ||
55 | |||
56 | IConfig cnf = config.Configs["Messaging"]; | 54 | IConfig cnf = config.Configs["Messaging"]; |
57 | if (cnf == null) | 55 | if (cnf == null) |
58 | { | 56 | { |
59 | enabled = false; | 57 | enabled = false; |
60 | return; | 58 | return; |
61 | } | 59 | } |
62 | if (cnf != null && cnf.GetString( | 60 | if (cnf != null && cnf.GetString("OfflineMessageModule", "None") != |
63 | "OfflineMessageModule", "None") != | ||
64 | "OfflineMessageModule") | 61 | "OfflineMessageModule") |
65 | { | 62 | { |
66 | enabled = false; | 63 | enabled = false; |
67 | return; | 64 | return; |
68 | } | 65 | } |
69 | 66 | ||
67 | m_RestURL = cnf.GetString("OfflineMessageURL", ""); | ||
68 | if (m_RestURL == "") | ||
69 | { | ||
70 | m_log.Error("[OFFLINE MESSAGING] Module was enabled, but no URL is given, disabling"); | ||
71 | enabled = false; | ||
72 | return; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | public void AddRegion(Scene scene) | ||
77 | { | ||
78 | if (!enabled) | ||
79 | return; | ||
80 | |||
70 | lock (m_SceneList) | 81 | lock (m_SceneList) |
71 | { | 82 | { |
72 | if (m_SceneList.Count == 0) | 83 | m_SceneList.Add(scene); |
73 | { | ||
74 | m_RestURL = cnf.GetString("OfflineMessageURL", ""); | ||
75 | if (m_RestURL == "") | ||
76 | { | ||
77 | m_log.Error("[OFFLINE MESSAGING] Module was enabled, but no URL is given, disabling"); | ||
78 | enabled = false; | ||
79 | return; | ||
80 | } | ||
81 | } | ||
82 | if (!m_SceneList.Contains(scene)) | ||
83 | m_SceneList.Add(scene); | ||
84 | 84 | ||
85 | scene.EventManager.OnNewClient += OnNewClient; | 85 | scene.EventManager.OnNewClient += OnNewClient; |
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | public void PostInitialise() | 89 | public void RegionLoaded(Scene scene) |
90 | { | 90 | { |
91 | if (!enabled) | 91 | if (!enabled) |
92 | return; | 92 | return; |
93 | 93 | ||
94 | if (m_SceneList.Count == 0) | 94 | if (m_TransferModule == null) |
95 | return; | ||
96 | |||
97 | IMessageTransferModule trans = m_SceneList[0].RequestModuleInterface<IMessageTransferModule>(); | ||
98 | if (trans == null) | ||
99 | { | 95 | { |
100 | enabled = false; | 96 | m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>(); |
101 | 97 | if (m_TransferModule == null) | |
102 | lock (m_SceneList) | ||
103 | { | 98 | { |
104 | foreach (Scene s in m_SceneList) | 99 | scene.EventManager.OnNewClient -= OnNewClient; |
105 | s.EventManager.OnNewClient -= OnNewClient; | ||
106 | 100 | ||
101 | enabled = false; | ||
107 | m_SceneList.Clear(); | 102 | m_SceneList.Clear(); |
103 | |||
104 | m_log.Error("[OFFLINE MESSAGING] No message transfer module is enabled. Diabling offline messages"); | ||
108 | } | 105 | } |
106 | m_TransferModule.OnUndeliveredMessage += UndeliveredMessage; | ||
107 | } | ||
108 | } | ||
109 | 109 | ||
110 | m_log.Error("[OFFLINE MESSAGING] No message transfer module is enabled. Diabling offline messages"); | 110 | public void RemoveRegion(Scene scene) |
111 | { | ||
112 | if (!enabled) | ||
111 | return; | 113 | return; |
114 | |||
115 | lock (m_SceneList) | ||
116 | { | ||
117 | m_SceneList.Remove(scene); | ||
112 | } | 118 | } |
119 | } | ||
113 | 120 | ||
114 | trans.OnUndeliveredMessage += UndeliveredMessage; | 121 | public void PostInitialise() |
122 | { | ||
123 | if (!enabled) | ||
124 | return; | ||
115 | 125 | ||
116 | m_log.Debug("[OFFLINE MESSAGING] Offline messages enabled"); | 126 | m_log.Debug("[OFFLINE MESSAGING] Offline messages enabled"); |
117 | } | 127 | } |
@@ -121,9 +131,9 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | |||
121 | get { return "OfflineMessageModule"; } | 131 | get { return "OfflineMessageModule"; } |
122 | } | 132 | } |
123 | 133 | ||
124 | public bool IsSharedModule | 134 | public Type ReplaceableInterface |
125 | { | 135 | { |
126 | get { return true; } | 136 | get { return null; } |
127 | } | 137 | } |
128 | 138 | ||
129 | public void Close() | 139 | public void Close() |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs index f5ab454..267a90a 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/PresenceModule.cs | |||
@@ -24,6 +24,7 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | using System; | ||
27 | using System.Collections; | 28 | using System.Collections; |
28 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
29 | using System.Net; | 30 | using System.Net; |
@@ -39,404 +40,54 @@ using GridRegion = OpenSim.Services.Interfaces.GridRegion; | |||
39 | 40 | ||
40 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage | 41 | namespace OpenSim.Region.CoreModules.Avatar.InstantMessage |
41 | { | 42 | { |
42 | public class PresenceModule : IRegionModule, IPresenceModule | 43 | public class PresenceModule : ISharedRegionModule, IPresenceModule |
43 | { | 44 | { |
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | private static readonly ILog m_log = LogManager.GetLogger( |
45 | 46 | MethodBase.GetCurrentMethod().DeclaringType); | |
46 | private bool m_Enabled = false; | ||
47 | private bool m_Gridmode = false; | ||
48 | |||
49 | // some default scene for doing things that aren't connected to a specific scene. Avoids locking. | ||
50 | private Scene m_initialScene; | ||
51 | |||
52 | private List<Scene> m_Scenes = new List<Scene>(); | ||
53 | |||
54 | // we currently are only interested in root-agents. If the root isn't here, we don't know the region the | ||
55 | // user is in, so we have to ask the messaging server anyway. | ||
56 | private Dictionary<UUID, Scene> m_RootAgents = | ||
57 | new Dictionary<UUID, Scene>(); | ||
58 | 47 | ||
59 | public event PresenceChange OnPresenceChange; | 48 | public event PresenceChange OnPresenceChange; |
60 | public event BulkPresenceData OnBulkPresenceData; | 49 | public event BulkPresenceData OnBulkPresenceData; |
61 | 50 | ||
62 | public void Initialise(Scene scene, IConfigSource config) | 51 | public void Initialise(IConfigSource config) |
63 | { | 52 | { |
64 | lock (m_Scenes) | ||
65 | { | ||
66 | // This is a shared module; Initialise will be called for every region on this server. | ||
67 | // Only check config once for the first region. | ||
68 | if (m_Scenes.Count == 0) | ||
69 | { | ||
70 | IConfig cnf = config.Configs["Messaging"]; | ||
71 | if (cnf != null && cnf.GetString( | ||
72 | "PresenceModule", "PresenceModule") != | ||
73 | "PresenceModule") | ||
74 | return; | ||
75 | |||
76 | cnf = config.Configs["Startup"]; | ||
77 | if (cnf != null) | ||
78 | m_Gridmode = cnf.GetBoolean("gridmode", false); | ||
79 | |||
80 | m_Enabled = true; | ||
81 | |||
82 | m_initialScene = scene; | ||
83 | } | ||
84 | |||
85 | if (m_Gridmode) | ||
86 | NotifyMessageServerOfStartup(scene); | ||
87 | |||
88 | m_Scenes.Add(scene); | ||
89 | } | ||
90 | |||
91 | scene.RegisterModuleInterface<IPresenceModule>(this); | ||
92 | |||
93 | scene.EventManager.OnNewClient += OnNewClient; | ||
94 | scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene; | ||
95 | scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; | ||
96 | } | 53 | } |
97 | 54 | ||
98 | public void PostInitialise() | 55 | public void AddRegion(Scene scene) |
99 | { | 56 | { |
100 | } | 57 | } |
101 | 58 | ||
102 | public void Close() | 59 | public void RegionLoaded(Scene scene) |
103 | { | 60 | { |
104 | if (!m_Gridmode || !m_Enabled) | ||
105 | return; | ||
106 | |||
107 | if (OnPresenceChange != null) | ||
108 | { | ||
109 | lock (m_RootAgents) | ||
110 | { | ||
111 | // on shutdown, users are kicked, too | ||
112 | foreach (KeyValuePair<UUID, Scene> pair in m_RootAgents) | ||
113 | { | ||
114 | OnPresenceChange(new PresenceInfo(pair.Key, UUID.Zero)); | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | |||
119 | lock (m_Scenes) | ||
120 | { | ||
121 | foreach (Scene scene in m_Scenes) | ||
122 | NotifyMessageServerOfShutdown(scene); | ||
123 | } | ||
124 | } | 61 | } |
125 | 62 | ||
126 | public string Name | 63 | public void RemoveRegion(Scene scene) |
127 | { | 64 | { |
128 | get { return "PresenceModule"; } | ||
129 | } | ||
130 | |||
131 | public bool IsSharedModule | ||
132 | { | ||
133 | get { return true; } | ||
134 | } | ||
135 | |||
136 | public void RequestBulkPresenceData(UUID[] users) | ||
137 | { | ||
138 | if (OnBulkPresenceData != null) | ||
139 | { | ||
140 | PresenceInfo[] result = new PresenceInfo[users.Length]; | ||
141 | if (m_Gridmode) | ||
142 | { | ||
143 | // first check the local information | ||
144 | List<UUID> uuids = new List<UUID>(); // the uuids to check remotely | ||
145 | List<int> indices = new List<int>(); // just for performance. | ||
146 | lock (m_RootAgents) | ||
147 | { | ||
148 | for (int i = 0; i < uuids.Count; ++i) | ||
149 | { | ||
150 | Scene scene; | ||
151 | if (m_RootAgents.TryGetValue(users[i], out scene)) | ||
152 | { | ||
153 | result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID); | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | uuids.Add(users[i]); | ||
158 | indices.Add(i); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | // now we have filtered out all the local root agents. The rest we have to request info about | ||
164 | Dictionary<UUID, FriendRegionInfo> infos = m_initialScene.GetFriendRegionInfos(uuids); | ||
165 | for (int i = 0; i < uuids.Count; ++i) | ||
166 | { | ||
167 | FriendRegionInfo info; | ||
168 | if (infos.TryGetValue(uuids[i], out info) && info.isOnline) | ||
169 | { | ||
170 | UUID regionID = info.regionID; | ||
171 | if (regionID == UUID.Zero) | ||
172 | { | ||
173 | // TODO this is the old messaging-server protocol; only the regionHandle is available. | ||
174 | // Fetch region-info to get the id | ||
175 | uint x = 0, y = 0; | ||
176 | Utils.LongToUInts(info.regionHandle, out x, out y); | ||
177 | GridRegion regionInfo = m_initialScene.GridService.GetRegionByPosition(m_initialScene.RegionInfo.ScopeID, | ||
178 | (int)x, (int)y); | ||
179 | regionID = regionInfo.RegionID; | ||
180 | } | ||
181 | result[indices[i]] = new PresenceInfo(uuids[i], regionID); | ||
182 | } | ||
183 | else result[indices[i]] = new PresenceInfo(uuids[i], UUID.Zero); | ||
184 | } | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | // in standalone mode, we have all the info locally available. | ||
189 | lock (m_RootAgents) | ||
190 | { | ||
191 | for (int i = 0; i < users.Length; ++i) | ||
192 | { | ||
193 | Scene scene; | ||
194 | if (m_RootAgents.TryGetValue(users[i], out scene)) | ||
195 | { | ||
196 | result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID); | ||
197 | } | ||
198 | else | ||
199 | { | ||
200 | result[i] = new PresenceInfo(users[i], UUID.Zero); | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | |||
206 | // tell everyone | ||
207 | OnBulkPresenceData(result); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | // new client doesn't mean necessarily that user logged in, it just means it entered one of the | ||
212 | // the regions on this server | ||
213 | public void OnNewClient(IClientAPI client) | ||
214 | { | ||
215 | client.OnConnectionClosed += OnConnectionClosed; | ||
216 | client.OnLogout += OnLogout; | ||
217 | |||
218 | // KLUDGE: See handler for details. | ||
219 | client.OnEconomyDataRequest += OnEconomyDataRequest; | ||
220 | } | 65 | } |
221 | 66 | ||
222 | // connection closed just means *one* client connection has been closed. It doesn't mean that the | 67 | public void PostInitialise() |
223 | // user has logged off; it might have just TPed away. | ||
224 | public void OnConnectionClosed(IClientAPI client) | ||
225 | { | ||
226 | // TODO: Have to think what we have to do here... | ||
227 | // Should we just remove the root from the list (if scene matches)? | ||
228 | if (!(client.Scene is Scene)) | ||
229 | return; | ||
230 | Scene scene = (Scene)client.Scene; | ||
231 | |||
232 | lock (m_RootAgents) | ||
233 | { | ||
234 | Scene rootScene; | ||
235 | if (!(m_RootAgents.TryGetValue(client.AgentId, out rootScene)) || scene != rootScene) | ||
236 | return; | ||
237 | |||
238 | m_RootAgents.Remove(client.AgentId); | ||
239 | } | ||
240 | |||
241 | // Should it have logged off, we'll do the logout part in OnLogout, even if no root is stored | ||
242 | // anymore. It logged off, after all... | ||
243 | } | ||
244 | |||
245 | // Triggered when the user logs off. | ||
246 | public void OnLogout(IClientAPI client) | ||
247 | { | ||
248 | if (!(client.Scene is Scene)) | ||
249 | return; | ||
250 | Scene scene = (Scene)client.Scene; | ||
251 | |||
252 | // On logout, we really remove the client from rootAgents, even if the scene doesn't match | ||
253 | lock (m_RootAgents) | ||
254 | { | ||
255 | if (m_RootAgents.ContainsKey(client.AgentId)) m_RootAgents.Remove(client.AgentId); | ||
256 | } | ||
257 | |||
258 | // now inform the messaging server and anyone who is interested | ||
259 | NotifyMessageServerOfAgentLeaving(client.AgentId, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle); | ||
260 | if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(client.AgentId, UUID.Zero)); | ||
261 | } | ||
262 | |||
263 | public void OnSetRootAgentScene(UUID agentID, Scene scene) | ||
264 | { | ||
265 | // OnSetRootAgentScene can be called from several threads at once (with different agentID). | ||
266 | // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without | ||
267 | // correct locking). | ||
268 | lock (m_RootAgents) | ||
269 | { | ||
270 | Scene rootScene; | ||
271 | if (m_RootAgents.TryGetValue(agentID, out rootScene) && scene == rootScene) | ||
272 | { | ||
273 | return; | ||
274 | } | ||
275 | m_RootAgents[agentID] = scene; | ||
276 | } | ||
277 | |||
278 | // inform messaging server that agent changed the region | ||
279 | Util.FireAndForget( | ||
280 | delegate(object o) | ||
281 | { | ||
282 | NotifyMessageServerOfAgentLocation(agentID, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle); | ||
283 | } | ||
284 | ); | ||
285 | } | ||
286 | |||
287 | private void OnEconomyDataRequest(UUID agentID) | ||
288 | { | 68 | { |
289 | // KLUDGE: This is the only way I found to get a message (only) after login was completed and the | ||
290 | // client is connected enough to receive UDP packets. | ||
291 | // This packet seems to be sent only once, just after connection was established to the first | ||
292 | // region after login. | ||
293 | // We use it here to trigger a presence update; the old update-on-login was never be heard by | ||
294 | // the freshly logged in viewer, as it wasn't connected to the region at that time. | ||
295 | // TODO: Feel free to replace this by a better solution if you find one. | ||
296 | |||
297 | // get the agent. This should work every time, as we just got a packet from it | ||
298 | ScenePresence agent = null; | ||
299 | lock (m_Scenes) | ||
300 | { | ||
301 | foreach (Scene scene in m_Scenes) | ||
302 | { | ||
303 | agent = scene.GetScenePresence(agentID); | ||
304 | if (agent != null) break; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | // just to be paranoid... | ||
309 | if (agent == null) | ||
310 | { | ||
311 | m_log.ErrorFormat("[PRESENCE]: Got a packet from agent {0} who can't be found anymore!?", agentID); | ||
312 | return; | ||
313 | } | ||
314 | |||
315 | // we are a bit premature here, but the next packet will switch this child agent to root. | ||
316 | if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(agentID, agent.Scene.RegionInfo.RegionID)); | ||
317 | } | 69 | } |
318 | 70 | ||
319 | public void OnMakeChildAgent(ScenePresence agent) | 71 | public void Close() |
320 | { | 72 | { |
321 | // OnMakeChildAgent can be called from several threads at once (with different agent). | ||
322 | // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without | ||
323 | // correct locking). | ||
324 | lock (m_RootAgents) | ||
325 | { | ||
326 | Scene rootScene; | ||
327 | if (m_RootAgents.TryGetValue(agent.UUID, out rootScene) && agent.Scene == rootScene) | ||
328 | { | ||
329 | m_RootAgents.Remove(agent.UUID); | ||
330 | } | ||
331 | } | ||
332 | // don't notify the messaging-server; either this agent just had been downgraded and another one will be upgraded | ||
333 | // to root momentarily (which will notify the messaging-server), or possibly it will be closed in a moment, | ||
334 | // which will update the messaging-server, too. | ||
335 | } | 73 | } |
336 | 74 | ||
337 | private void NotifyMessageServerOfStartup(Scene scene) | 75 | public string Name |
338 | { | 76 | { |
339 | Hashtable xmlrpcdata = new Hashtable(); | 77 | get { return "PresenceModule"; } |
340 | xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString(); | ||
341 | ArrayList SendParams = new ArrayList(); | ||
342 | SendParams.Add(xmlrpcdata); | ||
343 | try | ||
344 | { | ||
345 | XmlRpcRequest UpRequest = new XmlRpcRequest("region_startup", SendParams); | ||
346 | XmlRpcResponse resp = UpRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
347 | |||
348 | Hashtable responseData = (Hashtable)resp.Value; | ||
349 | if (responseData == null || (!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
350 | { | ||
351 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName); | ||
352 | } | ||
353 | } | ||
354 | catch (WebException) | ||
355 | { | ||
356 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName); | ||
357 | } | ||
358 | } | 78 | } |
359 | 79 | ||
360 | private void NotifyMessageServerOfShutdown(Scene scene) | 80 | public Type ReplaceableInterface |
361 | { | 81 | { |
362 | if (m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL == string.Empty) | 82 | get { return null; } |
363 | return; | ||
364 | |||
365 | Hashtable xmlrpcdata = new Hashtable(); | ||
366 | xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString(); | ||
367 | ArrayList SendParams = new ArrayList(); | ||
368 | SendParams.Add(xmlrpcdata); | ||
369 | try | ||
370 | { | ||
371 | XmlRpcRequest DownRequest = new XmlRpcRequest("region_shutdown", SendParams); | ||
372 | XmlRpcResponse resp = DownRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
373 | |||
374 | Hashtable responseData = (Hashtable)resp.Value; | ||
375 | if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
376 | { | ||
377 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName); | ||
378 | } | ||
379 | } | ||
380 | catch (WebException) | ||
381 | { | ||
382 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName); | ||
383 | } | ||
384 | } | 83 | } |
385 | 84 | ||
386 | private void NotifyMessageServerOfAgentLocation(UUID agentID, UUID region, ulong regionHandle) | 85 | public void RequestBulkPresenceData(UUID[] users) |
387 | { | 86 | { |
388 | if (m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL == string.Empty) | ||
389 | return; | ||
390 | |||
391 | Hashtable xmlrpcdata = new Hashtable(); | ||
392 | xmlrpcdata["AgentID"] = agentID.ToString(); | ||
393 | xmlrpcdata["RegionUUID"] = region.ToString(); | ||
394 | xmlrpcdata["RegionHandle"] = regionHandle.ToString(); | ||
395 | ArrayList SendParams = new ArrayList(); | ||
396 | SendParams.Add(xmlrpcdata); | ||
397 | try | ||
398 | { | ||
399 | XmlRpcRequest LocationRequest = new XmlRpcRequest("agent_location", SendParams); | ||
400 | XmlRpcResponse resp = LocationRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
401 | |||
402 | Hashtable responseData = (Hashtable)resp.Value; | ||
403 | if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
404 | { | ||
405 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString()); | ||
406 | } | ||
407 | } | ||
408 | catch (WebException) | ||
409 | { | ||
410 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString()); | ||
411 | } | ||
412 | } | 87 | } |
413 | 88 | ||
414 | private void NotifyMessageServerOfAgentLeaving(UUID agentID, UUID region, ulong regionHandle) | 89 | public void OnNewClient(IClientAPI client) |
415 | { | 90 | { |
416 | if (m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL == string.Empty) | ||
417 | return; | ||
418 | |||
419 | Hashtable xmlrpcdata = new Hashtable(); | ||
420 | xmlrpcdata["AgentID"] = agentID.ToString(); | ||
421 | xmlrpcdata["RegionUUID"] = region.ToString(); | ||
422 | xmlrpcdata["RegionHandle"] = regionHandle.ToString(); | ||
423 | ArrayList SendParams = new ArrayList(); | ||
424 | SendParams.Add(xmlrpcdata); | ||
425 | try | ||
426 | { | ||
427 | XmlRpcRequest LeavingRequest = new XmlRpcRequest("agent_leaving", SendParams); | ||
428 | XmlRpcResponse resp = LeavingRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
429 | |||
430 | Hashtable responseData = (Hashtable)resp.Value; | ||
431 | if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
432 | { | ||
433 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString()); | ||
434 | } | ||
435 | } | ||
436 | catch (WebException) | ||
437 | { | ||
438 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString()); | ||
439 | } | ||
440 | } | 91 | } |
441 | } | 92 | } |
442 | } | 93 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index d9a021f..55d4f14 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs | |||
@@ -39,7 +39,7 @@ using OpenSim.Services.Interfaces; | |||
39 | 39 | ||
40 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | 40 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer |
41 | { | 41 | { |
42 | public class InventoryTransferModule : IInventoryTransferModule, IRegionModule | 42 | public class InventoryTransferModule : IInventoryTransferModule, ISharedRegionModule |
43 | { | 43 | { |
44 | private static readonly ILog m_log | 44 | private static readonly ILog m_log |
45 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -50,10 +50,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
50 | new Dictionary<UUID, Scene>(); | 50 | new Dictionary<UUID, Scene>(); |
51 | 51 | ||
52 | private IMessageTransferModule m_TransferModule = null; | 52 | private IMessageTransferModule m_TransferModule = null; |
53 | private bool m_Enabled = true; | ||
53 | 54 | ||
54 | #region IRegionModule Members | 55 | #region IRegionModule Members |
55 | 56 | ||
56 | public void Initialise(Scene scene, IConfigSource config) | 57 | public void Initialise(IConfigSource config) |
57 | { | 58 | { |
58 | if (config.Configs["Messaging"] != null) | 59 | if (config.Configs["Messaging"] != null) |
59 | { | 60 | { |
@@ -62,29 +63,56 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
62 | if (config.Configs["Messaging"].GetString( | 63 | if (config.Configs["Messaging"].GetString( |
63 | "InventoryTransferModule", "InventoryTransferModule") != | 64 | "InventoryTransferModule", "InventoryTransferModule") != |
64 | "InventoryTransferModule") | 65 | "InventoryTransferModule") |
66 | { | ||
67 | m_Enabled = false; | ||
65 | return; | 68 | return; |
69 | } | ||
66 | } | 70 | } |
71 | } | ||
67 | 72 | ||
68 | if (!m_Scenelist.Contains(scene)) | 73 | public void AddRegion(Scene scene) |
69 | { | 74 | { |
70 | m_Scenelist.Add(scene); | 75 | if (!m_Enabled) |
76 | return; | ||
71 | 77 | ||
72 | scene.RegisterModuleInterface<IInventoryTransferModule>(this); | 78 | m_Scenelist.Add(scene); |
73 | 79 | ||
74 | scene.EventManager.OnNewClient += OnNewClient; | 80 | scene.RegisterModuleInterface<IInventoryTransferModule>(this); |
75 | scene.EventManager.OnClientClosed += ClientLoggedOut; | 81 | |
76 | scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; | 82 | scene.EventManager.OnNewClient += OnNewClient; |
77 | } | 83 | scene.EventManager.OnClientClosed += ClientLoggedOut; |
84 | scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; | ||
78 | } | 85 | } |
79 | 86 | ||
80 | public void PostInitialise() | 87 | public void RegionLoaded(Scene scene) |
81 | { | 88 | { |
82 | if (m_Scenelist.Count > 0) | 89 | if (m_TransferModule == null) |
83 | { | 90 | { |
84 | m_TransferModule = m_Scenelist[0].RequestModuleInterface<IMessageTransferModule>(); | 91 | m_TransferModule = m_Scenelist[0].RequestModuleInterface<IMessageTransferModule>(); |
85 | if (m_TransferModule == null) | 92 | if (m_TransferModule == null) |
93 | { | ||
86 | m_log.Error("[INVENTORY TRANSFER] No Message transfer module found, transfers will be local only"); | 94 | m_log.Error("[INVENTORY TRANSFER] No Message transfer module found, transfers will be local only"); |
95 | m_Enabled = false; | ||
96 | |||
97 | m_Scenelist.Clear(); | ||
98 | scene.EventManager.OnNewClient -= OnNewClient; | ||
99 | scene.EventManager.OnClientClosed -= ClientLoggedOut; | ||
100 | scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; | ||
101 | } | ||
87 | } | 102 | } |
103 | |||
104 | } | ||
105 | |||
106 | public void RemoveRegion(Scene scene) | ||
107 | { | ||
108 | scene.EventManager.OnNewClient -= OnNewClient; | ||
109 | scene.EventManager.OnClientClosed -= ClientLoggedOut; | ||
110 | scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; | ||
111 | m_Scenelist.Remove(scene); | ||
112 | } | ||
113 | |||
114 | public void PostInitialise() | ||
115 | { | ||
88 | } | 116 | } |
89 | 117 | ||
90 | public void Close() | 118 | public void Close() |
@@ -96,9 +124,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
96 | get { return "InventoryModule"; } | 124 | get { return "InventoryModule"; } |
97 | } | 125 | } |
98 | 126 | ||
99 | public bool IsSharedModule | 127 | public Type ReplaceableInterface |
100 | { | 128 | { |
101 | get { return true; } | 129 | get { return null; } |
102 | } | 130 | } |
103 | 131 | ||
104 | #endregion | 132 | #endregion |
diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs index 261bd6c..d1d7df2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs | |||
@@ -37,34 +37,72 @@ using OpenSim.Region.Framework.Scenes; | |||
37 | 37 | ||
38 | namespace OpenSim.Region.CoreModules.Avatar.Lure | 38 | namespace OpenSim.Region.CoreModules.Avatar.Lure |
39 | { | 39 | { |
40 | public class LureModule : IRegionModule | 40 | public class LureModule : ISharedRegionModule |
41 | { | 41 | { |
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger( |
43 | MethodBase.GetCurrentMethod().DeclaringType); | ||
43 | 44 | ||
44 | private readonly List<Scene> m_scenes = new List<Scene>(); | 45 | private readonly List<Scene> m_scenes = new List<Scene>(); |
45 | 46 | ||
46 | private IMessageTransferModule m_TransferModule = null; | 47 | private IMessageTransferModule m_TransferModule = null; |
48 | private bool m_Enabled = true; | ||
47 | 49 | ||
48 | public void Initialise(Scene scene, IConfigSource config) | 50 | public void Initialise(IConfigSource config) |
49 | { | 51 | { |
50 | if (config.Configs["Messaging"] != null) | 52 | if (config.Configs["Messaging"] != null) |
51 | { | 53 | { |
52 | if (config.Configs["Messaging"].GetString( | 54 | if (config.Configs["Messaging"].GetString( |
53 | "LureModule", "LureModule") != | 55 | "LureModule", "LureModule") != |
54 | "LureModule") | 56 | "LureModule") |
55 | return; | 57 | m_Enabled = false; |
56 | } | 58 | } |
59 | } | ||
60 | |||
61 | public void AddRegion(Scene scene) | ||
62 | { | ||
63 | if (!m_Enabled) | ||
64 | return; | ||
57 | 65 | ||
58 | lock (m_scenes) | 66 | lock (m_scenes) |
59 | { | 67 | { |
60 | if (!m_scenes.Contains(scene)) | 68 | m_scenes.Add(scene); |
69 | scene.EventManager.OnNewClient += OnNewClient; | ||
70 | scene.EventManager.OnIncomingInstantMessage += | ||
71 | OnGridInstantMessage; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | public void RegionLoaded(Scene scene) | ||
76 | { | ||
77 | if (m_TransferModule == null) | ||
78 | { | ||
79 | m_TransferModule = | ||
80 | scene.RequestModuleInterface<IMessageTransferModule>(); | ||
81 | |||
82 | if (m_TransferModule == null) | ||
61 | { | 83 | { |
62 | m_scenes.Add(scene); | 84 | m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ |
63 | scene.EventManager.OnNewClient += OnNewClient; | 85 | "lures will not work!"); |
64 | scene.EventManager.OnIncomingInstantMessage += | 86 | |
87 | m_Enabled = false; | ||
88 | m_scenes.Clear(); | ||
89 | scene.EventManager.OnNewClient -= OnNewClient; | ||
90 | scene.EventManager.OnIncomingInstantMessage -= | ||
65 | OnGridInstantMessage; | 91 | OnGridInstantMessage; |
66 | } | 92 | } |
67 | } | 93 | } |
94 | |||
95 | } | ||
96 | |||
97 | public void RemoveRegion(Scene scene) | ||
98 | { | ||
99 | lock (m_scenes) | ||
100 | { | ||
101 | m_scenes.Remove(scene); | ||
102 | scene.EventManager.OnNewClient -= OnNewClient; | ||
103 | scene.EventManager.OnIncomingInstantMessage -= | ||
104 | OnGridInstantMessage; | ||
105 | } | ||
68 | } | 106 | } |
69 | 107 | ||
70 | void OnNewClient(IClientAPI client) | 108 | void OnNewClient(IClientAPI client) |
@@ -76,12 +114,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure | |||
76 | 114 | ||
77 | public void PostInitialise() | 115 | public void PostInitialise() |
78 | { | 116 | { |
79 | m_TransferModule = | ||
80 | m_scenes[0].RequestModuleInterface<IMessageTransferModule>(); | ||
81 | |||
82 | if (m_TransferModule == null) | ||
83 | m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ | ||
84 | "lures will not work!"); | ||
85 | } | 117 | } |
86 | 118 | ||
87 | public void Close() | 119 | public void Close() |
@@ -93,9 +125,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure | |||
93 | get { return "LureModule"; } | 125 | get { return "LureModule"; } |
94 | } | 126 | } |
95 | 127 | ||
96 | public bool IsSharedModule | 128 | public Type ReplaceableInterface |
97 | { | 129 | { |
98 | get { return true; } | 130 | get { return null; } |
99 | } | 131 | } |
100 | 132 | ||
101 | public void OnInstantMessage(IClientAPI client, GridInstantMessage im) | 133 | public void OnInstantMessage(IClientAPI client, GridInstantMessage im) |
diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml index beb2307..40a13f4 100644 --- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml +++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml | |||
@@ -17,6 +17,14 @@ | |||
17 | <RegionModule id="HGWorldMapModule" type="OpenSim.Region.CoreModules.Hypergrid.HGWorldMapModule" /> | 17 | <RegionModule id="HGWorldMapModule" type="OpenSim.Region.CoreModules.Hypergrid.HGWorldMapModule" /> |
18 | <RegionModule id="UrlModule" type="OpenSim.Region.CoreModules.Scripting.LSLHttp.UrlModule" /> | 18 | <RegionModule id="UrlModule" type="OpenSim.Region.CoreModules.Scripting.LSLHttp.UrlModule" /> |
19 | <RegionModule id="Chat" type="OpenSim.Region.CoreModules.Avatar.Chat.ChatModule" /> | 19 | <RegionModule id="Chat" type="OpenSim.Region.CoreModules.Avatar.Chat.ChatModule" /> |
20 | <RegionModule id="FriendsModule" type="OpenSim.Region.CoreModules.Avatar.Friends.FriendsModule" /> | ||
21 | <RegionModule id="PresenceModule" type="OpenSim.Region.CoreModules.Avatar.InstantMessage.PresenceModule" /> | ||
22 | <RegionModule id="MuteListModule" type="OpenSim.Region.CoreModules.Avatar.InstantMessage.MuteListModule" /> | ||
23 | <RegionModule id="OfflineMessageModule" type="OpenSim.Region.CoreModules.Avatar.InstantMessage.OfflineMessageModule" /> | ||
24 | <RegionModule id="InstantMessageModule" type="OpenSim.Region.CoreModules.Avatar.InstantMessage.InstantMessageModule" /> | ||
25 | <RegionModule id="MessageTransferModule" type="OpenSim.Region.CoreModules.Avatar.InstantMessage.MessageTransferModule" /> | ||
26 | <RegionModule id="LureModule" type="OpenSim.Region.CoreModules.Avatar.Lure.LureModule" /> | ||
27 | <RegionModule id="InventoryTransferModule" type="OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.InventoryTransferModule" /> | ||
20 | <RegionModule id="CoreAssetCache" type="OpenSim.Region.CoreModules.Asset.CoreAssetCache" /> | 28 | <RegionModule id="CoreAssetCache" type="OpenSim.Region.CoreModules.Asset.CoreAssetCache" /> |
21 | <RegionModule id="GlynnTuckerAssetCache" type="OpenSim.Region.CoreModules.Asset.GlynnTuckerAssetCache" /> | 29 | <RegionModule id="GlynnTuckerAssetCache" type="OpenSim.Region.CoreModules.Asset.GlynnTuckerAssetCache" /> |
22 | <RegionModule id="CenomeMemoryAssetCache" type="OpenSim.Region.CoreModules.Asset.CenomeMemoryAssetCache"/> | 30 | <RegionModule id="CenomeMemoryAssetCache" type="OpenSim.Region.CoreModules.Asset.CenomeMemoryAssetCache"/> |
diff --git a/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs b/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs index 630c6a3..d44c1e1 100644 --- a/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IPresenceModule.cs | |||
@@ -31,13 +31,13 @@ namespace OpenSim.Region.Framework.Interfaces | |||
31 | { | 31 | { |
32 | public struct PresenceInfo | 32 | public struct PresenceInfo |
33 | { | 33 | { |
34 | public UUID userID; | 34 | public string UserID; |
35 | public UUID regionID; | 35 | public UUID RegionID; |
36 | 36 | ||
37 | public PresenceInfo(UUID userID, UUID regionID) | 37 | public PresenceInfo(string userID, UUID regionID) |
38 | { | 38 | { |
39 | this.userID = userID; | 39 | UserID = userID; |
40 | this.regionID = regionID; | 40 | RegionID = regionID; |
41 | } | 41 | } |
42 | } | 42 | } |
43 | 43 | ||