diff options
author | Dr Scofield | 2009-02-10 13:10:57 +0000 |
---|---|---|
committer | Dr Scofield | 2009-02-10 13:10:57 +0000 |
commit | 180be7de07014aa33bc6066f12a0819b731c1c9d (patch) | |
tree | 3aa13af3cda4b808fa9453655875327699b61311 /OpenSim/Region/Environment/Modules/Avatar/InstantMessage | |
parent | Stopgap measure: To use gridlaunch, or GUI, start opensim with (diff) | |
download | opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.zip opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.gz opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.bz2 opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.xz |
this is step 2 of 2 of the OpenSim.Region.Environment refactor.
NOTHING has been deleted or moved off to forge at this point. what
has happened is that OpenSim.Region.Environment.Modules has been split
in two:
- OpenSim.Region.CoreModules: all those modules that are either
directly or indirectly referenced from other OpenSim packages, or
that provide functionality that the OpenSim developer community
considers core functionality:
CoreModules/Agent/AssetTransaction
CoreModules/Agent/Capabilities
CoreModules/Agent/TextureDownload
CoreModules/Agent/TextureSender
CoreModules/Agent/TextureSender/Tests
CoreModules/Agent/Xfer
CoreModules/Avatar/AvatarFactory
CoreModules/Avatar/Chat/ChatModule
CoreModules/Avatar/Combat
CoreModules/Avatar/Currency/SampleMoney
CoreModules/Avatar/Dialog
CoreModules/Avatar/Friends
CoreModules/Avatar/Gestures
CoreModules/Avatar/Groups
CoreModules/Avatar/InstantMessage
CoreModules/Avatar/Inventory
CoreModules/Avatar/Inventory/Archiver
CoreModules/Avatar/Inventory/Transfer
CoreModules/Avatar/Lure
CoreModules/Avatar/ObjectCaps
CoreModules/Avatar/Profiles
CoreModules/Communications/Local
CoreModules/Communications/REST
CoreModules/Framework/EventQueue
CoreModules/Framework/InterfaceCommander
CoreModules/Hypergrid
CoreModules/InterGrid
CoreModules/Scripting/DynamicTexture
CoreModules/Scripting/EMailModules
CoreModules/Scripting/HttpRequest
CoreModules/Scripting/LoadImageURL
CoreModules/Scripting/VectorRender
CoreModules/Scripting/WorldComm
CoreModules/Scripting/XMLRPC
CoreModules/World/Archiver
CoreModules/World/Archiver/Tests
CoreModules/World/Estate
CoreModules/World/Land
CoreModules/World/Permissions
CoreModules/World/Serialiser
CoreModules/World/Sound
CoreModules/World/Sun
CoreModules/World/Terrain
CoreModules/World/Terrain/DefaultEffects
CoreModules/World/Terrain/DefaultEffects/bin
CoreModules/World/Terrain/DefaultEffects/bin/Debug
CoreModules/World/Terrain/Effects
CoreModules/World/Terrain/FileLoaders
CoreModules/World/Terrain/FloodBrushes
CoreModules/World/Terrain/PaintBrushes
CoreModules/World/Terrain/Tests
CoreModules/World/Vegetation
CoreModules/World/Wind
CoreModules/World/WorldMap
- OpenSim.Region.OptionalModules: all those modules that are not core
modules:
OptionalModules/Avatar/Chat/IRC-stuff
OptionalModules/Avatar/Concierge
OptionalModules/Avatar/Voice/AsterixVoice
OptionalModules/Avatar/Voice/SIPVoice
OptionalModules/ContentManagementSystem
OptionalModules/Grid/Interregion
OptionalModules/Python
OptionalModules/SvnSerialiser
OptionalModules/World/NPC
OptionalModules/World/TreePopulator
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Avatar/InstantMessage')
3 files changed, 0 insertions, 1251 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs deleted file mode 100644 index 3a1b282..0000000 --- a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/InstantMessageModule.cs +++ /dev/null | |||
@@ -1,170 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Net; | ||
32 | using System.Threading; | ||
33 | using OpenMetaverse; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using Nwc.XmlRpc; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Client; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | |||
42 | namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage | ||
43 | { | ||
44 | public class InstantMessageModule : IRegionModule | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | /// <value> | ||
49 | /// Is this module enabled? | ||
50 | /// </value> | ||
51 | private bool m_enabled = false; | ||
52 | |||
53 | private readonly List<Scene> m_scenes = new List<Scene>(); | ||
54 | |||
55 | #region IRegionModule Members | ||
56 | |||
57 | private IMessageTransferModule m_TransferModule = null; | ||
58 | |||
59 | public void Initialise(Scene scene, IConfigSource config) | ||
60 | { | ||
61 | if (config.Configs["Messaging"] != null) | ||
62 | { | ||
63 | if (config.Configs["Messaging"].GetString( | ||
64 | "InstantMessageModule", "InstantMessageModule") != | ||
65 | "InstantMessageModule") | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | m_enabled = true; | ||
70 | |||
71 | lock (m_scenes) | ||
72 | { | ||
73 | if (!m_scenes.Contains(scene)) | ||
74 | { | ||
75 | m_scenes.Add(scene); | ||
76 | scene.EventManager.OnClientConnect += OnClientConnect; | ||
77 | scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | |||
82 | void OnClientConnect(IClientCore client) | ||
83 | { | ||
84 | IClientIM clientIM; | ||
85 | if (client.TryGet(out clientIM)) | ||
86 | { | ||
87 | clientIM.OnInstantMessage += OnInstantMessage; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | public void PostInitialise() | ||
92 | { | ||
93 | if (!m_enabled) | ||
94 | return; | ||
95 | |||
96 | m_TransferModule = | ||
97 | m_scenes[0].RequestModuleInterface<IMessageTransferModule>(); | ||
98 | |||
99 | if (m_TransferModule == null) | ||
100 | m_log.Error("[INSTANT MESSAGE]: No message transfer module, "+ | ||
101 | "IM will not work!"); | ||
102 | } | ||
103 | |||
104 | public void Close() | ||
105 | { | ||
106 | } | ||
107 | |||
108 | public string Name | ||
109 | { | ||
110 | get { return "InstantMessageModule"; } | ||
111 | } | ||
112 | |||
113 | public bool IsSharedModule | ||
114 | { | ||
115 | get { return true; } | ||
116 | } | ||
117 | |||
118 | #endregion | ||
119 | |||
120 | public void OnInstantMessage(IClientAPI client, GridInstantMessage im) | ||
121 | { | ||
122 | byte dialog = im.dialog; | ||
123 | |||
124 | if ( dialog != (byte)InstantMessageDialog.MessageFromAgent | ||
125 | && dialog != (byte)InstantMessageDialog.StartTyping | ||
126 | && dialog != (byte)InstantMessageDialog.StopTyping) | ||
127 | { | ||
128 | return; | ||
129 | } | ||
130 | |||
131 | if (m_TransferModule != null) | ||
132 | { | ||
133 | m_TransferModule.SendInstantMessage(im, | ||
134 | delegate(bool success) | ||
135 | { | ||
136 | if (dialog == (uint)InstantMessageDialog.StartTyping || | ||
137 | dialog == (uint)InstantMessageDialog.StopTyping) | ||
138 | { | ||
139 | return; | ||
140 | } | ||
141 | |||
142 | if ((client != null) && !success) | ||
143 | { | ||
144 | client.SendInstantMessage(new UUID(im.toAgentID), | ||
145 | "Unable to send instant message. "+ | ||
146 | "User is not logged in.", | ||
147 | new UUID(im.fromAgentID), "System", | ||
148 | (byte)InstantMessageDialog.BusyAutoResponse, | ||
149 | (uint)Util.UnixTimeSinceEpoch()); | ||
150 | } | ||
151 | } | ||
152 | ); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /// <summary> | ||
157 | /// | ||
158 | /// </summary> | ||
159 | /// <param name="msg"></param> | ||
160 | private void OnGridInstantMessage(GridInstantMessage msg) | ||
161 | { | ||
162 | // Just call the Text IM handler above | ||
163 | // This event won't be raised unless we have that agent, | ||
164 | // so we can depend on the above not trying to send | ||
165 | // via grid again | ||
166 | // | ||
167 | OnInstantMessage(null, msg); | ||
168 | } | ||
169 | } | ||
170 | } | ||
diff --git a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs deleted file mode 100644 index 347c305..0000000 --- a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/MessageTransferModule.cs +++ /dev/null | |||
@@ -1,655 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Net; | ||
32 | using System.Threading; | ||
33 | using OpenMetaverse; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using Nwc.XmlRpc; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Client; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | |||
42 | namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage | ||
43 | { | ||
44 | public class MessageTransferModule : IRegionModule, IMessageTransferModule | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | // private bool m_Enabled = false; | ||
49 | private bool m_Gridmode = false; | ||
50 | private List<Scene> m_Scenes = new List<Scene>(); | ||
51 | private Dictionary<UUID, ulong> m_UserRegionMap = new Dictionary<UUID, ulong>(); | ||
52 | |||
53 | public void Initialise(Scene scene, IConfigSource config) | ||
54 | { | ||
55 | IConfig cnf = config.Configs["Messaging"]; | ||
56 | if (cnf != null && cnf.GetString( | ||
57 | "MessageTransferModule", "MessageTransferModule") != | ||
58 | "MessageTransferModule") | ||
59 | return; | ||
60 | |||
61 | cnf = config.Configs["Startup"]; | ||
62 | if (cnf != null) | ||
63 | m_Gridmode = cnf.GetBoolean("gridmode", false); | ||
64 | |||
65 | // m_Enabled = true; | ||
66 | |||
67 | lock (m_Scenes) | ||
68 | { | ||
69 | if (m_Scenes.Count == 0) | ||
70 | { | ||
71 | scene.CommsManager.HttpServer.AddXmlRPCHandler( | ||
72 | "grid_instant_message", processXMLRPCGridInstantMessage); | ||
73 | } | ||
74 | |||
75 | scene.RegisterModuleInterface<IMessageTransferModule>(this); | ||
76 | m_Scenes.Add(scene); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | public void PostInitialise() | ||
81 | { | ||
82 | } | ||
83 | |||
84 | public void Close() | ||
85 | { | ||
86 | } | ||
87 | |||
88 | public string Name | ||
89 | { | ||
90 | get { return "MessageTransferModule"; } | ||
91 | } | ||
92 | |||
93 | public bool IsSharedModule | ||
94 | { | ||
95 | get { return true; } | ||
96 | } | ||
97 | |||
98 | public void SendInstantMessage(GridInstantMessage im, MessageResultNotification result) | ||
99 | { | ||
100 | UUID toAgentID = new UUID(im.toAgentID); | ||
101 | |||
102 | m_log.DebugFormat("[INSTANT MESSAGE]: Attempting delivery of IM from {0} to {1}", im.fromAgentName, toAgentID.ToString()); | ||
103 | |||
104 | // Try root avatar only first | ||
105 | foreach (Scene scene in m_Scenes) | ||
106 | { | ||
107 | if (scene.Entities.ContainsKey(toAgentID) && | ||
108 | scene.Entities[toAgentID] is ScenePresence) | ||
109 | { | ||
110 | m_log.DebugFormat("[INSTANT MESSAGE]: Looking for {0} in {1}", toAgentID.ToString(), scene.RegionInfo.RegionName); | ||
111 | // Local message | ||
112 | ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; | ||
113 | if (!user.IsChildAgent) | ||
114 | { | ||
115 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client"); | ||
116 | user.ControllingClient.SendInstantMessage( | ||
117 | new UUID(im.fromAgentID), | ||
118 | im.message, | ||
119 | new UUID(im.toAgentID), | ||
120 | im.fromAgentName, | ||
121 | im.dialog, | ||
122 | im.timestamp, | ||
123 | new UUID(im.imSessionID), | ||
124 | im.fromGroup, | ||
125 | im.binaryBucket); | ||
126 | // Message sent | ||
127 | result(true); | ||
128 | return; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | // try child avatar second | ||
134 | foreach (Scene scene in m_Scenes) | ||
135 | { | ||
136 | // m_log.DebugFormat( | ||
137 | // "[INSTANT MESSAGE]: Looking for child of {0} in {1}", toAgentID, scene.RegionInfo.RegionName); | ||
138 | |||
139 | if (scene.Entities.ContainsKey(toAgentID) && | ||
140 | scene.Entities[toAgentID] is ScenePresence) | ||
141 | { | ||
142 | // Local message | ||
143 | ScenePresence user = (ScenePresence) scene.Entities[toAgentID]; | ||
144 | |||
145 | m_log.DebugFormat("[INSTANT MESSAGE]: Delivering to client"); | ||
146 | user.ControllingClient.SendInstantMessage( | ||
147 | new UUID(im.fromAgentID), | ||
148 | im.message, | ||
149 | new UUID(im.toAgentID), | ||
150 | im.fromAgentName, | ||
151 | im.dialog, | ||
152 | im.timestamp, | ||
153 | new UUID(im.imSessionID), | ||
154 | im.fromGroup, | ||
155 | im.binaryBucket); | ||
156 | // Message sent | ||
157 | result(true); | ||
158 | return; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | if (m_Gridmode) | ||
163 | { | ||
164 | //m_log.DebugFormat("[INSTANT MESSAGE]: Delivering via grid"); | ||
165 | // Still here, try send via Grid | ||
166 | SendGridInstantMessageViaXMLRPC(im, result); | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | //m_log.DebugFormat("[INSTANT MESSAGE]: Undeliverable"); | ||
171 | result(false); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | /// <summary> | ||
176 | /// Process a XMLRPC Grid Instant Message | ||
177 | /// </summary> | ||
178 | /// <param name="request">XMLRPC parameters | ||
179 | /// </param> | ||
180 | /// <returns>Nothing much</returns> | ||
181 | protected virtual XmlRpcResponse processXMLRPCGridInstantMessage(XmlRpcRequest request) | ||
182 | { | ||
183 | bool successful = false; | ||
184 | |||
185 | // TODO: For now, as IMs seem to be a bit unreliable on OSGrid, catch all exception that | ||
186 | // happen here and aren't caught and log them. | ||
187 | try | ||
188 | { | ||
189 | // various rational defaults | ||
190 | UUID fromAgentID = UUID.Zero; | ||
191 | UUID toAgentID = UUID.Zero; | ||
192 | UUID imSessionID = UUID.Zero; | ||
193 | uint timestamp = 0; | ||
194 | string fromAgentName = ""; | ||
195 | string message = ""; | ||
196 | byte dialog = (byte)0; | ||
197 | bool fromGroup = false; | ||
198 | byte offline = (byte)0; | ||
199 | uint ParentEstateID=0; | ||
200 | Vector3 Position = Vector3.Zero; | ||
201 | UUID RegionID = UUID.Zero ; | ||
202 | byte[] binaryBucket = new byte[0]; | ||
203 | |||
204 | float pos_x = 0; | ||
205 | float pos_y = 0; | ||
206 | float pos_z = 0; | ||
207 | //m_log.Info("Processing IM"); | ||
208 | |||
209 | |||
210 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
211 | // Check if it's got all the data | ||
212 | if (requestData.ContainsKey("from_agent_id") | ||
213 | && requestData.ContainsKey("to_agent_id") && requestData.ContainsKey("im_session_id") | ||
214 | && requestData.ContainsKey("timestamp") && requestData.ContainsKey("from_agent_name") | ||
215 | && requestData.ContainsKey("message") && requestData.ContainsKey("dialog") | ||
216 | && requestData.ContainsKey("from_group") | ||
217 | && requestData.ContainsKey("offline") && requestData.ContainsKey("parent_estate_id") | ||
218 | && requestData.ContainsKey("position_x") && requestData.ContainsKey("position_y") | ||
219 | && requestData.ContainsKey("position_z") && requestData.ContainsKey("region_id") | ||
220 | && requestData.ContainsKey("binary_bucket")) | ||
221 | { | ||
222 | // Do the easy way of validating the UUIDs | ||
223 | UUID.TryParse((string)requestData["from_agent_id"], out fromAgentID); | ||
224 | UUID.TryParse((string)requestData["to_agent_id"], out toAgentID); | ||
225 | UUID.TryParse((string)requestData["im_session_id"], out imSessionID); | ||
226 | UUID.TryParse((string)requestData["region_id"], out RegionID); | ||
227 | |||
228 | try | ||
229 | { | ||
230 | timestamp = (uint)Convert.ToInt32((string)requestData["timestamp"]); | ||
231 | } | ||
232 | catch (ArgumentException) | ||
233 | { | ||
234 | } | ||
235 | catch (FormatException) | ||
236 | { | ||
237 | } | ||
238 | catch (OverflowException) | ||
239 | { | ||
240 | } | ||
241 | |||
242 | fromAgentName = (string)requestData["from_agent_name"]; | ||
243 | message = (string)requestData["message"]; | ||
244 | |||
245 | // Bytes don't transfer well over XMLRPC, so, we Base64 Encode them. | ||
246 | string requestData1 = (string)requestData["dialog"]; | ||
247 | if (string.IsNullOrEmpty(requestData1)) | ||
248 | { | ||
249 | dialog = 0; | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | byte[] dialogdata = Convert.FromBase64String(requestData1); | ||
254 | dialog = dialogdata[0]; | ||
255 | } | ||
256 | |||
257 | if ((string)requestData["from_group"] == "TRUE") | ||
258 | fromGroup = true; | ||
259 | |||
260 | string requestData2 = (string)requestData["offline"]; | ||
261 | if (String.IsNullOrEmpty(requestData2)) | ||
262 | { | ||
263 | offline = 0; | ||
264 | } | ||
265 | else | ||
266 | { | ||
267 | byte[] offlinedata = Convert.FromBase64String(requestData2); | ||
268 | offline = offlinedata[0]; | ||
269 | } | ||
270 | |||
271 | try | ||
272 | { | ||
273 | ParentEstateID = (uint)Convert.ToInt32((string)requestData["parent_estate_id"]); | ||
274 | } | ||
275 | catch (ArgumentException) | ||
276 | { | ||
277 | } | ||
278 | catch (FormatException) | ||
279 | { | ||
280 | } | ||
281 | catch (OverflowException) | ||
282 | { | ||
283 | } | ||
284 | |||
285 | try | ||
286 | { | ||
287 | pos_x = (uint)Convert.ToInt32((string)requestData["position_x"]); | ||
288 | } | ||
289 | catch (ArgumentException) | ||
290 | { | ||
291 | } | ||
292 | catch (FormatException) | ||
293 | { | ||
294 | } | ||
295 | catch (OverflowException) | ||
296 | { | ||
297 | } | ||
298 | try | ||
299 | { | ||
300 | pos_y = (uint)Convert.ToInt32((string)requestData["position_y"]); | ||
301 | } | ||
302 | catch (ArgumentException) | ||
303 | { | ||
304 | } | ||
305 | catch (FormatException) | ||
306 | { | ||
307 | } | ||
308 | catch (OverflowException) | ||
309 | { | ||
310 | } | ||
311 | try | ||
312 | { | ||
313 | pos_z = (uint)Convert.ToInt32((string)requestData["position_z"]); | ||
314 | } | ||
315 | catch (ArgumentException) | ||
316 | { | ||
317 | } | ||
318 | catch (FormatException) | ||
319 | { | ||
320 | } | ||
321 | catch (OverflowException) | ||
322 | { | ||
323 | } | ||
324 | |||
325 | Position = new Vector3(pos_x, pos_y, pos_z); | ||
326 | |||
327 | string requestData3 = (string)requestData["binary_bucket"]; | ||
328 | if (string.IsNullOrEmpty(requestData3)) | ||
329 | { | ||
330 | binaryBucket = new byte[0]; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | binaryBucket = Convert.FromBase64String(requestData3); | ||
335 | } | ||
336 | |||
337 | // Create a New GridInstantMessageObject the the data | ||
338 | GridInstantMessage gim = new GridInstantMessage(); | ||
339 | gim.fromAgentID = fromAgentID.Guid; | ||
340 | gim.fromAgentName = fromAgentName; | ||
341 | gim.fromGroup = fromGroup; | ||
342 | gim.imSessionID = imSessionID.Guid; | ||
343 | gim.RegionID = RegionID.Guid; | ||
344 | gim.timestamp = timestamp; | ||
345 | gim.toAgentID = toAgentID.Guid; | ||
346 | gim.message = message; | ||
347 | gim.dialog = dialog; | ||
348 | gim.offline = offline; | ||
349 | gim.ParentEstateID = ParentEstateID; | ||
350 | gim.Position = Position; | ||
351 | gim.binaryBucket = binaryBucket; | ||
352 | |||
353 | |||
354 | // Trigger the Instant message in the scene. | ||
355 | foreach (Scene scene in m_Scenes) | ||
356 | { | ||
357 | if (scene.Entities.ContainsKey(toAgentID) && | ||
358 | scene.Entities[toAgentID] is ScenePresence) | ||
359 | { | ||
360 | ScenePresence user = | ||
361 | (ScenePresence)scene.Entities[toAgentID]; | ||
362 | |||
363 | if (!user.IsChildAgent) | ||
364 | { | ||
365 | scene.EventManager.TriggerIncomingInstantMessage(gim); | ||
366 | successful = true; | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | if (!successful) | ||
371 | { | ||
372 | // If the message can't be delivered to an agent, it | ||
373 | // is likely to be a group IM. On a group IM, the | ||
374 | // imSessionID = toAgentID = group id. Raise the | ||
375 | // unhandled IM event to give the groups module | ||
376 | // a chance to pick it up. We raise that in a random | ||
377 | // scene, since the groups module is shared. | ||
378 | // | ||
379 | m_Scenes[0].EventManager.TriggerUnhandledInstantMessage(gim); | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | catch (Exception e) | ||
384 | { | ||
385 | m_log.Error("[INSTANT MESSAGE]: Caught unexpected exception:", e); | ||
386 | successful = false; | ||
387 | } | ||
388 | |||
389 | //Send response back to region calling if it was successful | ||
390 | // calling region uses this to know when to look up a user's location again. | ||
391 | XmlRpcResponse resp = new XmlRpcResponse(); | ||
392 | Hashtable respdata = new Hashtable(); | ||
393 | if (successful) | ||
394 | respdata["success"] = "TRUE"; | ||
395 | else | ||
396 | respdata["success"] = "FALSE"; | ||
397 | resp.Value = respdata; | ||
398 | |||
399 | return resp; | ||
400 | } | ||
401 | |||
402 | /// <summary> | ||
403 | /// delegate for sending a grid instant message asynchronously | ||
404 | /// </summary> | ||
405 | public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, ulong prevRegionHandle); | ||
406 | |||
407 | private void GridInstantMessageCompleted(IAsyncResult iar) | ||
408 | { | ||
409 | GridInstantMessageDelegate icon = | ||
410 | (GridInstantMessageDelegate)iar.AsyncState; | ||
411 | icon.EndInvoke(iar); | ||
412 | } | ||
413 | |||
414 | |||
415 | protected virtual void SendGridInstantMessageViaXMLRPC(GridInstantMessage im, MessageResultNotification result) | ||
416 | { | ||
417 | GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; | ||
418 | |||
419 | d.BeginInvoke(im, result, 0, GridInstantMessageCompleted, d); | ||
420 | } | ||
421 | |||
422 | /// <summary> | ||
423 | /// Recursive SendGridInstantMessage over XMLRPC method. | ||
424 | /// This is called from within a dedicated thread. | ||
425 | /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from | ||
426 | /// itself, prevRegionHandle will be the last region handle that we tried to send. | ||
427 | /// If the handles are the same, we look up the user's location using the grid. | ||
428 | /// If the handles are still the same, we end. The send failed. | ||
429 | /// </summary> | ||
430 | /// <param name="prevRegionHandle"> | ||
431 | /// Pass in 0 the first time this method is called. It will be called recursively with the last | ||
432 | /// regionhandle tried | ||
433 | /// </param> | ||
434 | protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, ulong prevRegionHandle) | ||
435 | { | ||
436 | UUID toAgentID = new UUID(im.toAgentID); | ||
437 | |||
438 | UserAgentData upd = null; | ||
439 | |||
440 | bool lookupAgent = false; | ||
441 | |||
442 | lock (m_UserRegionMap) | ||
443 | { | ||
444 | if (m_UserRegionMap.ContainsKey(toAgentID)) | ||
445 | { | ||
446 | upd = new UserAgentData(); | ||
447 | upd.AgentOnline = true; | ||
448 | upd.Handle = m_UserRegionMap[toAgentID]; | ||
449 | |||
450 | // We need to compare the current regionhandle with the previous region handle | ||
451 | // or the recursive loop will never end because it will never try to lookup the agent again | ||
452 | if (prevRegionHandle == upd.Handle) | ||
453 | { | ||
454 | lookupAgent = true; | ||
455 | } | ||
456 | } | ||
457 | else | ||
458 | { | ||
459 | lookupAgent = true; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | |||
464 | // Are we needing to look-up an agent? | ||
465 | if (lookupAgent) | ||
466 | { | ||
467 | // Non-cached user agent lookup. | ||
468 | upd = m_Scenes[0].CommsManager.UserService.GetAgentByUUID(toAgentID); | ||
469 | |||
470 | if (upd != null) | ||
471 | { | ||
472 | // check if we've tried this before.. | ||
473 | // This is one way to end the recursive loop | ||
474 | // | ||
475 | if (upd.Handle == prevRegionHandle) | ||
476 | { | ||
477 | m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | ||
478 | result(false); | ||
479 | return; | ||
480 | } | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | ||
485 | result(false); | ||
486 | return; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | if (upd != null) | ||
491 | { | ||
492 | if (upd.AgentOnline) | ||
493 | { | ||
494 | RegionInfo reginfo = m_Scenes[0].SceneGridService.RequestNeighbouringRegionInfo(upd.Handle); | ||
495 | if (reginfo != null) | ||
496 | { | ||
497 | Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); | ||
498 | // Not actually used anymore, left in for compatibility | ||
499 | // Remove at next interface change | ||
500 | // | ||
501 | msgdata["region_handle"] = 0; | ||
502 | bool imresult = doIMSending(reginfo, msgdata); | ||
503 | if (imresult) | ||
504 | { | ||
505 | // IM delivery successful, so store the Agent's location in our local cache. | ||
506 | lock (m_UserRegionMap) | ||
507 | { | ||
508 | if (m_UserRegionMap.ContainsKey(toAgentID)) | ||
509 | { | ||
510 | m_UserRegionMap[toAgentID] = upd.Handle; | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | m_UserRegionMap.Add(toAgentID, upd.Handle); | ||
515 | } | ||
516 | } | ||
517 | result(true); | ||
518 | } | ||
519 | else | ||
520 | { | ||
521 | // try again, but lookup user this time. | ||
522 | // Warning, this must call the Async version | ||
523 | // of this method or we'll be making thousands of threads | ||
524 | // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync | ||
525 | // The version that spawns the thread is SendGridInstantMessageViaXMLRPC | ||
526 | |||
527 | // This is recursive!!!!! | ||
528 | SendGridInstantMessageViaXMLRPCAsync(im, result, | ||
529 | upd.Handle); | ||
530 | } | ||
531 | |||
532 | } | ||
533 | else | ||
534 | { | ||
535 | m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.Handle); | ||
536 | result(false); | ||
537 | } | ||
538 | } | ||
539 | else | ||
540 | { | ||
541 | result(false); | ||
542 | } | ||
543 | } | ||
544 | else | ||
545 | { | ||
546 | m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find user {0}", toAgentID); | ||
547 | result(false); | ||
548 | } | ||
549 | |||
550 | } | ||
551 | |||
552 | /// <summary> | ||
553 | /// This actually does the XMLRPC Request | ||
554 | /// </summary> | ||
555 | /// <param name="reginfo">RegionInfo we pull the data out of to send the request to</param> | ||
556 | /// <param name="xmlrpcdata">The Instant Message data Hashtable</param> | ||
557 | /// <returns>Bool if the message was successfully delivered at the other side.</returns> | ||
558 | private bool doIMSending(RegionInfo reginfo, Hashtable xmlrpcdata) | ||
559 | { | ||
560 | |||
561 | ArrayList SendParams = new ArrayList(); | ||
562 | SendParams.Add(xmlrpcdata); | ||
563 | XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams); | ||
564 | try | ||
565 | { | ||
566 | |||
567 | XmlRpcResponse GridResp = GridReq.Send("http://" + reginfo.ExternalHostName + ":" + reginfo.HttpPort, 3000); | ||
568 | |||
569 | Hashtable responseData = (Hashtable)GridResp.Value; | ||
570 | |||
571 | if (responseData.ContainsKey("success")) | ||
572 | { | ||
573 | if ((string)responseData["success"] == "TRUE") | ||
574 | { | ||
575 | return true; | ||
576 | } | ||
577 | else | ||
578 | { | ||
579 | return false; | ||
580 | } | ||
581 | } | ||
582 | else | ||
583 | { | ||
584 | return false; | ||
585 | } | ||
586 | } | ||
587 | catch (WebException e) | ||
588 | { | ||
589 | m_log.ErrorFormat("[GRID INSTANT MESSAGE]: Error sending message to http://{0}:{1} the host didn't respond ({2})", | ||
590 | reginfo.ExternalHostName, reginfo.HttpPort, e.Message); | ||
591 | } | ||
592 | |||
593 | return false; | ||
594 | } | ||
595 | |||
596 | /// <summary> | ||
597 | /// Get ulong region handle for region by it's Region UUID. | ||
598 | /// We use region handles over grid comms because there's all sorts of free and cool caching. | ||
599 | /// </summary> | ||
600 | /// <param name="regionID">UUID of region to get the region handle for</param> | ||
601 | /// <returns></returns> | ||
602 | // private ulong getLocalRegionHandleFromUUID(UUID regionID) | ||
603 | // { | ||
604 | // ulong returnhandle = 0; | ||
605 | // | ||
606 | // lock (m_Scenes) | ||
607 | // { | ||
608 | // foreach (Scene sn in m_Scenes) | ||
609 | // { | ||
610 | // if (sn.RegionInfo.RegionID == regionID) | ||
611 | // { | ||
612 | // returnhandle = sn.RegionInfo.RegionHandle; | ||
613 | // break; | ||
614 | // } | ||
615 | // } | ||
616 | // } | ||
617 | // return returnhandle; | ||
618 | // } | ||
619 | |||
620 | /// <summary> | ||
621 | /// Takes a GridInstantMessage and converts it into a Hashtable for XMLRPC | ||
622 | /// </summary> | ||
623 | /// <param name="msg">The GridInstantMessage object</param> | ||
624 | /// <returns>Hashtable containing the XMLRPC request</returns> | ||
625 | private Hashtable ConvertGridInstantMessageToXMLRPC(GridInstantMessage msg) | ||
626 | { | ||
627 | Hashtable gim = new Hashtable(); | ||
628 | gim["from_agent_id"] = msg.fromAgentID.ToString(); | ||
629 | // Kept for compatibility | ||
630 | gim["from_agent_session"] = UUID.Zero.ToString(); | ||
631 | gim["to_agent_id"] = msg.toAgentID.ToString(); | ||
632 | gim["im_session_id"] = msg.imSessionID.ToString(); | ||
633 | gim["timestamp"] = msg.timestamp.ToString(); | ||
634 | gim["from_agent_name"] = msg.fromAgentName; | ||
635 | gim["message"] = msg.message; | ||
636 | byte[] dialogdata = new byte[1];dialogdata[0] = msg.dialog; | ||
637 | gim["dialog"] = Convert.ToBase64String(dialogdata,Base64FormattingOptions.None); | ||
638 | |||
639 | if (msg.fromGroup) | ||
640 | gim["from_group"] = "TRUE"; | ||
641 | else | ||
642 | gim["from_group"] = "FALSE"; | ||
643 | byte[] offlinedata = new byte[1]; offlinedata[0] = msg.offline; | ||
644 | gim["offline"] = Convert.ToBase64String(offlinedata, Base64FormattingOptions.None); | ||
645 | gim["parent_estate_id"] = msg.ParentEstateID.ToString(); | ||
646 | gim["position_x"] = msg.Position.X.ToString(); | ||
647 | gim["position_y"] = msg.Position.Y.ToString(); | ||
648 | gim["position_z"] = msg.Position.Z.ToString(); | ||
649 | gim["region_id"] = msg.RegionID.ToString(); | ||
650 | gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket,Base64FormattingOptions.None); | ||
651 | return gim; | ||
652 | } | ||
653 | |||
654 | } | ||
655 | } | ||
diff --git a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/PresenceModule.cs b/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/PresenceModule.cs deleted file mode 100644 index c84d3d5..0000000 --- a/OpenSim/Region/Environment/Modules/Avatar/InstantMessage/PresenceModule.cs +++ /dev/null | |||
@@ -1,426 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Net; | ||
32 | using System.Threading; | ||
33 | using OpenMetaverse; | ||
34 | using log4net; | ||
35 | using Nini.Config; | ||
36 | using Nwc.XmlRpc; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Client; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | |||
42 | namespace OpenSim.Region.Environment.Modules.Avatar.InstantMessage | ||
43 | { | ||
44 | public class PresenceModule : IRegionModule, IPresenceModule | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | private bool m_Enabled = false; | ||
49 | private bool m_Gridmode = false; | ||
50 | |||
51 | // some default scene for doing things that aren't connected to a specific scene. Avoids locking. | ||
52 | private Scene m_initialScene; | ||
53 | |||
54 | private List<Scene> m_Scenes = new List<Scene>(); | ||
55 | |||
56 | // we currently are only interested in root-agents. If the root isn't here, we don't know the region the | ||
57 | // user is in, so we have to ask the messaging server anyway. | ||
58 | private Dictionary<UUID, Scene> m_RootAgents = | ||
59 | new Dictionary<UUID, Scene>(); | ||
60 | |||
61 | public event PresenceChange OnPresenceChange; | ||
62 | public event BulkPresenceData OnBulkPresenceData; | ||
63 | |||
64 | public void Initialise(Scene scene, IConfigSource config) | ||
65 | { | ||
66 | lock (m_Scenes) | ||
67 | { | ||
68 | // This is a shared module; Initialise will be called for every region on this server. | ||
69 | // Only check config once for the first region. | ||
70 | if (m_Scenes.Count == 0) | ||
71 | { | ||
72 | IConfig cnf = config.Configs["Messaging"]; | ||
73 | if (cnf != null && cnf.GetString( | ||
74 | "PresenceModule", "PresenceModule") != | ||
75 | "PresenceModule") | ||
76 | return; | ||
77 | |||
78 | cnf = config.Configs["Startup"]; | ||
79 | if (cnf != null) | ||
80 | m_Gridmode = cnf.GetBoolean("gridmode", false); | ||
81 | |||
82 | m_Enabled = true; | ||
83 | |||
84 | m_initialScene = scene; | ||
85 | } | ||
86 | |||
87 | if (m_Gridmode) | ||
88 | NotifyMessageServerOfStartup(scene); | ||
89 | |||
90 | m_Scenes.Add(scene); | ||
91 | } | ||
92 | |||
93 | scene.RegisterModuleInterface<IPresenceModule>(this); | ||
94 | |||
95 | scene.EventManager.OnNewClient += OnNewClient; | ||
96 | scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene; | ||
97 | scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; | ||
98 | } | ||
99 | |||
100 | public void PostInitialise() | ||
101 | { | ||
102 | } | ||
103 | |||
104 | public void Close() | ||
105 | { | ||
106 | if (!m_Gridmode || !m_Enabled) | ||
107 | return; | ||
108 | |||
109 | if (OnPresenceChange != null) | ||
110 | { | ||
111 | lock (m_RootAgents) | ||
112 | { | ||
113 | // on shutdown, users are kicked, too | ||
114 | foreach (KeyValuePair<UUID, Scene> pair in m_RootAgents) | ||
115 | { | ||
116 | OnPresenceChange(new PresenceInfo(pair.Key, UUID.Zero)); | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | |||
121 | lock (m_Scenes) | ||
122 | { | ||
123 | foreach (Scene scene in m_Scenes) | ||
124 | NotifyMessageServerOfShutdown(scene); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | public string Name | ||
129 | { | ||
130 | get { return "PresenceModule"; } | ||
131 | } | ||
132 | |||
133 | public bool IsSharedModule | ||
134 | { | ||
135 | get { return true; } | ||
136 | } | ||
137 | |||
138 | public void RequestBulkPresenceData(UUID[] users) | ||
139 | { | ||
140 | if (OnBulkPresenceData != null) | ||
141 | { | ||
142 | PresenceInfo[] result = new PresenceInfo[users.Length]; | ||
143 | if (m_Gridmode) | ||
144 | { | ||
145 | // first check the local information | ||
146 | List<UUID> uuids = new List<UUID>(); // the uuids to check remotely | ||
147 | List<int> indices = new List<int>(); // just for performance. | ||
148 | lock (m_RootAgents) | ||
149 | { | ||
150 | for (int i = 0; i < uuids.Count; ++i) | ||
151 | { | ||
152 | Scene scene; | ||
153 | if (m_RootAgents.TryGetValue(users[i], out scene)) | ||
154 | { | ||
155 | result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID); | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | uuids.Add(users[i]); | ||
160 | indices.Add(i); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // now we have filtered out all the local root agents. The rest we have to request info about | ||
166 | Dictionary<UUID, FriendRegionInfo> infos = m_initialScene.GetFriendRegionInfos(uuids); | ||
167 | for (int i = 0; i < uuids.Count; ++i) | ||
168 | { | ||
169 | FriendRegionInfo info; | ||
170 | if (infos.TryGetValue(uuids[i], out info) && info.isOnline) | ||
171 | { | ||
172 | UUID regionID = info.regionID; | ||
173 | if (regionID == UUID.Zero) | ||
174 | { | ||
175 | // TODO this is the old messaging-server protocol; only the regionHandle is available. | ||
176 | // Fetch region-info to get the id | ||
177 | RegionInfo regionInfo = m_initialScene.RequestNeighbouringRegionInfo(info.regionHandle); | ||
178 | regionID = regionInfo.RegionID; | ||
179 | } | ||
180 | result[indices[i]] = new PresenceInfo(uuids[i], regionID); | ||
181 | } | ||
182 | else result[indices[i]] = new PresenceInfo(uuids[i], UUID.Zero); | ||
183 | } | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | // in standalone mode, we have all the info locally available. | ||
188 | lock (m_RootAgents) | ||
189 | { | ||
190 | for (int i = 0; i < users.Length; ++i) | ||
191 | { | ||
192 | Scene scene; | ||
193 | if (m_RootAgents.TryGetValue(users[i], out scene)) | ||
194 | { | ||
195 | result[i] = new PresenceInfo(users[i], scene.RegionInfo.RegionID); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | result[i] = new PresenceInfo(users[i], UUID.Zero); | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | } | ||
204 | |||
205 | // tell everyone | ||
206 | OnBulkPresenceData(result); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | // new client doesn't mean necessarily that user logged in, it just means it entered one of the | ||
211 | // the regions on this server | ||
212 | public void OnNewClient(IClientAPI client) | ||
213 | { | ||
214 | client.OnConnectionClosed += OnConnectionClosed; | ||
215 | client.OnLogout += OnLogout; | ||
216 | |||
217 | // KLUDGE: See handler for details. | ||
218 | client.OnEconomyDataRequest += OnEconomyDataRequest; | ||
219 | } | ||
220 | |||
221 | // connection closed just means *one* client connection has been closed. It doesn't mean that the | ||
222 | // user has logged off; it might have just TPed away. | ||
223 | public void OnConnectionClosed(IClientAPI client) | ||
224 | { | ||
225 | // TODO: Have to think what we have to do here... | ||
226 | // Should we just remove the root from the list (if scene matches)? | ||
227 | if (!(client.Scene is Scene)) | ||
228 | return; | ||
229 | Scene scene = (Scene)client.Scene; | ||
230 | |||
231 | lock (m_RootAgents) | ||
232 | { | ||
233 | Scene rootScene; | ||
234 | if (!(m_RootAgents.TryGetValue(client.AgentId, out rootScene)) || scene != rootScene) | ||
235 | return; | ||
236 | |||
237 | m_RootAgents.Remove(client.AgentId); | ||
238 | } | ||
239 | |||
240 | // Should it have logged off, we'll do the logout part in OnLogout, even if no root is stored | ||
241 | // anymore. It logged off, after all... | ||
242 | } | ||
243 | |||
244 | // Triggered when the user logs off. | ||
245 | public void OnLogout(IClientAPI client) | ||
246 | { | ||
247 | if (!(client.Scene is Scene)) | ||
248 | return; | ||
249 | Scene scene = (Scene)client.Scene; | ||
250 | |||
251 | // On logout, we really remove the client from rootAgents, even if the scene doesn't match | ||
252 | lock (m_RootAgents) | ||
253 | { | ||
254 | if (m_RootAgents.ContainsKey(client.AgentId)) m_RootAgents.Remove(client.AgentId); | ||
255 | } | ||
256 | |||
257 | // now inform the messaging server and anyone who is interested | ||
258 | NotifyMessageServerOfAgentLeaving(client.AgentId, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle); | ||
259 | if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(client.AgentId, UUID.Zero)); | ||
260 | } | ||
261 | |||
262 | public void OnSetRootAgentScene(UUID agentID, Scene scene) | ||
263 | { | ||
264 | // OnSetRootAgentScene can be called from several threads at once (with different agentID). | ||
265 | // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without | ||
266 | // correct locking). | ||
267 | lock (m_RootAgents) | ||
268 | { | ||
269 | Scene rootScene; | ||
270 | if (m_RootAgents.TryGetValue(agentID, out rootScene) && scene == rootScene) | ||
271 | { | ||
272 | return; | ||
273 | } | ||
274 | m_RootAgents[agentID] = scene; | ||
275 | } | ||
276 | // inform messaging server that agent changed the region | ||
277 | NotifyMessageServerOfAgentLocation(agentID, scene.RegionInfo.RegionID, scene.RegionInfo.RegionHandle); | ||
278 | } | ||
279 | |||
280 | private void OnEconomyDataRequest(UUID agentID) | ||
281 | { | ||
282 | // KLUDGE: This is the only way I found to get a message (only) after login was completed and the | ||
283 | // client is connected enough to receive UDP packets. | ||
284 | // This packet seems to be sent only once, just after connection was established to the first | ||
285 | // region after login. | ||
286 | // We use it here to trigger a presence update; the old update-on-login was never be heard by | ||
287 | // the freshly logged in viewer, as it wasn't connected to the region at that time. | ||
288 | // TODO: Feel free to replace this by a better solution if you find one. | ||
289 | |||
290 | // get the agent. This should work every time, as we just got a packet from it | ||
291 | ScenePresence agent = null; | ||
292 | lock (m_Scenes) | ||
293 | { | ||
294 | foreach (Scene scene in m_Scenes) | ||
295 | { | ||
296 | agent = scene.GetScenePresence(agentID); | ||
297 | if (agent != null) break; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | // just to be paranoid... | ||
302 | if (agent == null) | ||
303 | { | ||
304 | m_log.ErrorFormat("[PRESENCE]: Got a packet from agent {0} who can't be found anymore!?", agentID); | ||
305 | return; | ||
306 | } | ||
307 | |||
308 | // we are a bit premature here, but the next packet will switch this child agent to root. | ||
309 | if (OnPresenceChange != null) OnPresenceChange(new PresenceInfo(agentID, agent.Scene.RegionInfo.RegionID)); | ||
310 | } | ||
311 | |||
312 | public void OnMakeChildAgent(ScenePresence agent) | ||
313 | { | ||
314 | // OnMakeChildAgent can be called from several threads at once (with different agent). | ||
315 | // Concurrent access to m_RootAgents is prone to failure on multi-core/-processor systems without | ||
316 | // correct locking). | ||
317 | lock (m_RootAgents) | ||
318 | { | ||
319 | Scene rootScene; | ||
320 | if (m_RootAgents.TryGetValue(agent.UUID, out rootScene) && agent.Scene == rootScene) | ||
321 | { | ||
322 | m_RootAgents.Remove(agent.UUID); | ||
323 | } | ||
324 | } | ||
325 | // don't notify the messaging-server; either this agent just had been downgraded and another one will be upgraded | ||
326 | // to root momentarily (which will notify the messaging-server), or possibly it will be closed in a moment, | ||
327 | // which will update the messaging-server, too. | ||
328 | } | ||
329 | |||
330 | private void NotifyMessageServerOfStartup(Scene scene) | ||
331 | { | ||
332 | Hashtable xmlrpcdata = new Hashtable(); | ||
333 | xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString(); | ||
334 | ArrayList SendParams = new ArrayList(); | ||
335 | SendParams.Add(xmlrpcdata); | ||
336 | try | ||
337 | { | ||
338 | XmlRpcRequest UpRequest = new XmlRpcRequest("region_startup", SendParams); | ||
339 | XmlRpcResponse resp = UpRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
340 | |||
341 | Hashtable responseData = (Hashtable)resp.Value; | ||
342 | if (responseData == null || (!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
343 | { | ||
344 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName); | ||
345 | } | ||
346 | } | ||
347 | catch (System.Net.WebException) | ||
348 | { | ||
349 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region startup for region {0}", scene.RegionInfo.RegionName); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | private void NotifyMessageServerOfShutdown(Scene scene) | ||
354 | { | ||
355 | Hashtable xmlrpcdata = new Hashtable(); | ||
356 | xmlrpcdata["RegionUUID"] = scene.RegionInfo.RegionID.ToString(); | ||
357 | ArrayList SendParams = new ArrayList(); | ||
358 | SendParams.Add(xmlrpcdata); | ||
359 | try | ||
360 | { | ||
361 | XmlRpcRequest DownRequest = new XmlRpcRequest("region_shutdown", SendParams); | ||
362 | XmlRpcResponse resp = DownRequest.Send(scene.CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
363 | |||
364 | Hashtable responseData = (Hashtable)resp.Value; | ||
365 | if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
366 | { | ||
367 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName); | ||
368 | } | ||
369 | } | ||
370 | catch (System.Net.WebException) | ||
371 | { | ||
372 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of region shutdown for region {0}", scene.RegionInfo.RegionName); | ||
373 | } | ||
374 | } | ||
375 | |||
376 | private void NotifyMessageServerOfAgentLocation(UUID agentID, UUID region, ulong regionHandle) | ||
377 | { | ||
378 | Hashtable xmlrpcdata = new Hashtable(); | ||
379 | xmlrpcdata["AgentID"] = agentID.ToString(); | ||
380 | xmlrpcdata["RegionUUID"] = region.ToString(); | ||
381 | xmlrpcdata["RegionHandle"] = regionHandle.ToString(); | ||
382 | ArrayList SendParams = new ArrayList(); | ||
383 | SendParams.Add(xmlrpcdata); | ||
384 | try | ||
385 | { | ||
386 | XmlRpcRequest LocationRequest = new XmlRpcRequest("agent_location", SendParams); | ||
387 | XmlRpcResponse resp = LocationRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
388 | |||
389 | Hashtable responseData = (Hashtable)resp.Value; | ||
390 | if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
391 | { | ||
392 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString()); | ||
393 | } | ||
394 | } | ||
395 | catch (System.Net.WebException) | ||
396 | { | ||
397 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent location for {0}", agentID.ToString()); | ||
398 | } | ||
399 | } | ||
400 | |||
401 | private void NotifyMessageServerOfAgentLeaving(UUID agentID, UUID region, ulong regionHandle) | ||
402 | { | ||
403 | Hashtable xmlrpcdata = new Hashtable(); | ||
404 | xmlrpcdata["AgentID"] = agentID.ToString(); | ||
405 | xmlrpcdata["RegionUUID"] = region.ToString(); | ||
406 | xmlrpcdata["RegionHandle"] = regionHandle.ToString(); | ||
407 | ArrayList SendParams = new ArrayList(); | ||
408 | SendParams.Add(xmlrpcdata); | ||
409 | try | ||
410 | { | ||
411 | XmlRpcRequest LeavingRequest = new XmlRpcRequest("agent_leaving", SendParams); | ||
412 | XmlRpcResponse resp = LeavingRequest.Send(m_Scenes[0].CommsManager.NetworkServersInfo.MessagingURL, 5000); | ||
413 | |||
414 | Hashtable responseData = (Hashtable)resp.Value; | ||
415 | if ((!responseData.ContainsKey("success")) || (string)responseData["success"] != "TRUE") | ||
416 | { | ||
417 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString()); | ||
418 | } | ||
419 | } | ||
420 | catch (System.Net.WebException) | ||
421 | { | ||
422 | m_log.ErrorFormat("[PRESENCE]: Failed to notify message server of agent leaving for {0}", agentID.ToString()); | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | } | ||