diff options
Diffstat (limited to 'OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs')
-rw-r--r-- | OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs new file mode 100644 index 0000000..c48e585 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs | |||
@@ -0,0 +1,627 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Net.Sockets; | ||
34 | using System.Reflection; | ||
35 | using System.Text; | ||
36 | using System.Text.RegularExpressions; | ||
37 | using System.Threading; | ||
38 | using log4net; | ||
39 | using Mono.Addins; | ||
40 | using Nini.Config; | ||
41 | using Nwc.XmlRpc; | ||
42 | using OpenMetaverse; | ||
43 | using OpenSim.Framework; | ||
44 | using OpenSim.Framework.Servers; | ||
45 | using OpenSim.Region.Framework.Interfaces; | ||
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Region.CoreModules.Avatar.Chat; | ||
48 | |||
49 | namespace OpenSim.Region.OptionalModules.Avatar.Concierge | ||
50 | { | ||
51 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ConciergeModule")] | ||
52 | public class ConciergeModule : ChatModule, ISharedRegionModule | ||
53 | { | ||
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private const int DEBUG_CHANNEL = 2147483647; | ||
57 | |||
58 | private List<IScene> m_scenes = new List<IScene>(); | ||
59 | private List<IScene> m_conciergedScenes = new List<IScene>(); | ||
60 | |||
61 | private bool m_replacingChatModule = false; | ||
62 | |||
63 | private IConfig m_config; | ||
64 | |||
65 | private string m_whoami = "conferencier"; | ||
66 | private Regex m_regions = null; | ||
67 | private string m_welcomes = null; | ||
68 | private int m_conciergeChannel = 42; | ||
69 | private string m_announceEntering = "{0} enters {1} (now {2} visitors in this region)"; | ||
70 | private string m_announceLeaving = "{0} leaves {1} (back to {2} visitors in this region)"; | ||
71 | private string m_xmlRpcPassword = String.Empty; | ||
72 | private string m_brokerURI = String.Empty; | ||
73 | private int m_brokerUpdateTimeout = 300; | ||
74 | |||
75 | internal object m_syncy = new object(); | ||
76 | |||
77 | internal bool m_enabled = false; | ||
78 | |||
79 | #region ISharedRegionModule Members | ||
80 | public override void Initialise(IConfigSource config) | ||
81 | { | ||
82 | m_config = config.Configs["Concierge"]; | ||
83 | |||
84 | if (null == m_config) | ||
85 | return; | ||
86 | |||
87 | if (!m_config.GetBoolean("enabled", false)) | ||
88 | return; | ||
89 | |||
90 | m_enabled = true; | ||
91 | |||
92 | |||
93 | // check whether ChatModule has been disabled: if yes, | ||
94 | // then we'll "stand in" | ||
95 | try | ||
96 | { | ||
97 | if (config.Configs["Chat"] == null) | ||
98 | { | ||
99 | // if Chat module has not been configured it's | ||
100 | // enabled by default, so we are not going to | ||
101 | // replace it. | ||
102 | m_replacingChatModule = false; | ||
103 | } | ||
104 | else | ||
105 | { | ||
106 | m_replacingChatModule = !config.Configs["Chat"].GetBoolean("enabled", true); | ||
107 | } | ||
108 | } | ||
109 | catch (Exception) | ||
110 | { | ||
111 | m_replacingChatModule = false; | ||
112 | } | ||
113 | |||
114 | m_log.InfoFormat("[Concierge] {0} ChatModule", m_replacingChatModule ? "replacing" : "not replacing"); | ||
115 | |||
116 | // take note of concierge channel and of identity | ||
117 | m_conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", m_conciergeChannel); | ||
118 | m_whoami = m_config.GetString("whoami", "conferencier"); | ||
119 | m_welcomes = m_config.GetString("welcomes", m_welcomes); | ||
120 | m_announceEntering = m_config.GetString("announce_entering", m_announceEntering); | ||
121 | m_announceLeaving = m_config.GetString("announce_leaving", m_announceLeaving); | ||
122 | m_xmlRpcPassword = m_config.GetString("password", m_xmlRpcPassword); | ||
123 | m_brokerURI = m_config.GetString("broker", m_brokerURI); | ||
124 | m_brokerUpdateTimeout = m_config.GetInt("broker_timeout", m_brokerUpdateTimeout); | ||
125 | |||
126 | m_log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", m_whoami); | ||
127 | |||
128 | // calculate regions Regex | ||
129 | if (m_regions == null) | ||
130 | { | ||
131 | string regions = m_config.GetString("regions", String.Empty); | ||
132 | if (!String.IsNullOrEmpty(regions)) | ||
133 | { | ||
134 | m_regions = new Regex(@regions, RegexOptions.Compiled | RegexOptions.IgnoreCase); | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | |||
140 | public override void AddRegion(Scene scene) | ||
141 | { | ||
142 | if (!m_enabled) return; | ||
143 | |||
144 | MainServer.Instance.AddXmlRPCHandler("concierge_update_welcome", XmlRpcUpdateWelcomeMethod, false); | ||
145 | |||
146 | lock (m_syncy) | ||
147 | { | ||
148 | if (!m_scenes.Contains(scene)) | ||
149 | { | ||
150 | m_scenes.Add(scene); | ||
151 | |||
152 | if (m_regions == null || m_regions.IsMatch(scene.RegionInfo.RegionName)) | ||
153 | m_conciergedScenes.Add(scene); | ||
154 | |||
155 | // subscribe to NewClient events | ||
156 | scene.EventManager.OnNewClient += OnNewClient; | ||
157 | |||
158 | // subscribe to *Chat events | ||
159 | scene.EventManager.OnChatFromWorld += OnChatFromWorld; | ||
160 | if (!m_replacingChatModule) | ||
161 | scene.EventManager.OnChatFromClient += OnChatFromClient; | ||
162 | scene.EventManager.OnChatBroadcast += OnChatBroadcast; | ||
163 | |||
164 | // subscribe to agent change events | ||
165 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||
166 | scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; | ||
167 | } | ||
168 | } | ||
169 | m_log.InfoFormat("[Concierge]: initialized for {0}", scene.RegionInfo.RegionName); | ||
170 | } | ||
171 | |||
172 | public override void RemoveRegion(Scene scene) | ||
173 | { | ||
174 | if (!m_enabled) return; | ||
175 | |||
176 | MainServer.Instance.RemoveXmlRPCHandler("concierge_update_welcome"); | ||
177 | |||
178 | lock (m_syncy) | ||
179 | { | ||
180 | // unsubscribe from NewClient events | ||
181 | scene.EventManager.OnNewClient -= OnNewClient; | ||
182 | |||
183 | // unsubscribe from *Chat events | ||
184 | scene.EventManager.OnChatFromWorld -= OnChatFromWorld; | ||
185 | if (!m_replacingChatModule) | ||
186 | scene.EventManager.OnChatFromClient -= OnChatFromClient; | ||
187 | scene.EventManager.OnChatBroadcast -= OnChatBroadcast; | ||
188 | |||
189 | // unsubscribe from agent change events | ||
190 | scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; | ||
191 | scene.EventManager.OnMakeChildAgent -= OnMakeChildAgent; | ||
192 | |||
193 | if (m_scenes.Contains(scene)) | ||
194 | { | ||
195 | m_scenes.Remove(scene); | ||
196 | } | ||
197 | |||
198 | if (m_conciergedScenes.Contains(scene)) | ||
199 | { | ||
200 | m_conciergedScenes.Remove(scene); | ||
201 | } | ||
202 | } | ||
203 | m_log.InfoFormat("[Concierge]: removed {0}", scene.RegionInfo.RegionName); | ||
204 | } | ||
205 | |||
206 | public override void PostInitialise() | ||
207 | { | ||
208 | } | ||
209 | |||
210 | public override void Close() | ||
211 | { | ||
212 | } | ||
213 | |||
214 | new public Type ReplaceableInterface | ||
215 | { | ||
216 | get { return null; } | ||
217 | } | ||
218 | |||
219 | public override string Name | ||
220 | { | ||
221 | get { return "ConciergeModule"; } | ||
222 | } | ||
223 | #endregion | ||
224 | |||
225 | #region ISimChat Members | ||
226 | public override void OnChatBroadcast(Object sender, OSChatMessage c) | ||
227 | { | ||
228 | if (m_replacingChatModule) | ||
229 | { | ||
230 | // distribute chat message to each and every avatar in | ||
231 | // the region | ||
232 | base.OnChatBroadcast(sender, c); | ||
233 | } | ||
234 | |||
235 | // TODO: capture logic | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | public override void OnChatFromClient(Object sender, OSChatMessage c) | ||
240 | { | ||
241 | if (m_replacingChatModule) | ||
242 | { | ||
243 | // replacing ChatModule: need to redistribute | ||
244 | // ChatFromClient to interested subscribers | ||
245 | c = FixPositionOfChatMessage(c); | ||
246 | |||
247 | Scene scene = (Scene)c.Scene; | ||
248 | scene.EventManager.TriggerOnChatFromClient(sender, c); | ||
249 | |||
250 | if (m_conciergedScenes.Contains(c.Scene)) | ||
251 | { | ||
252 | // when we are replacing ChatModule, we treat | ||
253 | // OnChatFromClient like OnChatBroadcast for | ||
254 | // concierged regions, effectively extending the | ||
255 | // range of chat to cover the whole | ||
256 | // region. however, we don't do this for whisper | ||
257 | // (got to have some privacy) | ||
258 | if (c.Type != ChatTypeEnum.Whisper) | ||
259 | { | ||
260 | base.OnChatBroadcast(sender, c); | ||
261 | return; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | // redistribution will be done by base class | ||
266 | base.OnChatFromClient(sender, c); | ||
267 | } | ||
268 | |||
269 | // TODO: capture chat | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | public override void OnChatFromWorld(Object sender, OSChatMessage c) | ||
274 | { | ||
275 | if (m_replacingChatModule) | ||
276 | { | ||
277 | if (m_conciergedScenes.Contains(c.Scene)) | ||
278 | { | ||
279 | // when we are replacing ChatModule, we treat | ||
280 | // OnChatFromClient like OnChatBroadcast for | ||
281 | // concierged regions, effectively extending the | ||
282 | // range of chat to cover the whole | ||
283 | // region. however, we don't do this for whisper | ||
284 | // (got to have some privacy) | ||
285 | if (c.Type != ChatTypeEnum.Whisper) | ||
286 | { | ||
287 | base.OnChatBroadcast(sender, c); | ||
288 | return; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | base.OnChatFromWorld(sender, c); | ||
293 | } | ||
294 | return; | ||
295 | } | ||
296 | #endregion | ||
297 | |||
298 | |||
299 | public override void OnNewClient(IClientAPI client) | ||
300 | { | ||
301 | client.OnLogout += OnClientLoggedOut; | ||
302 | |||
303 | if (m_replacingChatModule) | ||
304 | client.OnChatFromClient += OnChatFromClient; | ||
305 | } | ||
306 | |||
307 | |||
308 | |||
309 | public void OnClientLoggedOut(IClientAPI client) | ||
310 | { | ||
311 | client.OnLogout -= OnClientLoggedOut; | ||
312 | client.OnConnectionClosed -= OnClientLoggedOut; | ||
313 | |||
314 | if (m_conciergedScenes.Contains(client.Scene)) | ||
315 | { | ||
316 | Scene scene = client.Scene as Scene; | ||
317 | m_log.DebugFormat("[Concierge]: {0} logs off from {1}", client.Name, scene.RegionInfo.RegionName); | ||
318 | AnnounceToAgentsRegion(scene, String.Format(m_announceLeaving, client.Name, scene.RegionInfo.RegionName, scene.GetRootAgentCount())); | ||
319 | UpdateBroker(scene); | ||
320 | } | ||
321 | } | ||
322 | |||
323 | |||
324 | public void OnMakeRootAgent(ScenePresence agent) | ||
325 | { | ||
326 | if (m_conciergedScenes.Contains(agent.Scene)) | ||
327 | { | ||
328 | Scene scene = agent.Scene; | ||
329 | m_log.DebugFormat("[Concierge]: {0} enters {1}", agent.Name, scene.RegionInfo.RegionName); | ||
330 | WelcomeAvatar(agent, scene); | ||
331 | AnnounceToAgentsRegion(scene, String.Format(m_announceEntering, agent.Name, | ||
332 | scene.RegionInfo.RegionName, scene.GetRootAgentCount())); | ||
333 | UpdateBroker(scene); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | |||
338 | public void OnMakeChildAgent(ScenePresence agent) | ||
339 | { | ||
340 | if (m_conciergedScenes.Contains(agent.Scene)) | ||
341 | { | ||
342 | Scene scene = agent.Scene; | ||
343 | m_log.DebugFormat("[Concierge]: {0} leaves {1}", agent.Name, scene.RegionInfo.RegionName); | ||
344 | AnnounceToAgentsRegion(scene, String.Format(m_announceLeaving, agent.Name, | ||
345 | scene.RegionInfo.RegionName, scene.GetRootAgentCount())); | ||
346 | UpdateBroker(scene); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | internal class BrokerState | ||
351 | { | ||
352 | public string Uri; | ||
353 | public string Payload; | ||
354 | public HttpWebRequest Poster; | ||
355 | public Timer Timer; | ||
356 | |||
357 | public BrokerState(string uri, string payload, HttpWebRequest poster) | ||
358 | { | ||
359 | Uri = uri; | ||
360 | Payload = payload; | ||
361 | Poster = poster; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | protected void UpdateBroker(Scene scene) | ||
366 | { | ||
367 | if (String.IsNullOrEmpty(m_brokerURI)) | ||
368 | return; | ||
369 | |||
370 | string uri = String.Format(m_brokerURI, scene.RegionInfo.RegionName, scene.RegionInfo.RegionID); | ||
371 | |||
372 | // create XML sniplet | ||
373 | StringBuilder list = new StringBuilder(); | ||
374 | list.Append(String.Format("<avatars count=\"{0}\" region_name=\"{1}\" region_uuid=\"{2}\" timestamp=\"{3}\">\n", | ||
375 | scene.GetRootAgentCount(), scene.RegionInfo.RegionName, | ||
376 | scene.RegionInfo.RegionID, | ||
377 | DateTime.UtcNow.ToString("s"))); | ||
378 | |||
379 | scene.ForEachRootScenePresence(delegate(ScenePresence sp) | ||
380 | { | ||
381 | list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID)); | ||
382 | }); | ||
383 | |||
384 | list.Append("</avatars>"); | ||
385 | string payload = list.ToString(); | ||
386 | |||
387 | // post via REST to broker | ||
388 | HttpWebRequest updatePost = WebRequest.Create(uri) as HttpWebRequest; | ||
389 | updatePost.Method = "POST"; | ||
390 | updatePost.ContentType = "text/xml"; | ||
391 | updatePost.ContentLength = payload.Length; | ||
392 | updatePost.UserAgent = "OpenSim.Concierge"; | ||
393 | |||
394 | |||
395 | BrokerState bs = new BrokerState(uri, payload, updatePost); | ||
396 | bs.Timer = new Timer(delegate(object state) | ||
397 | { | ||
398 | BrokerState b = state as BrokerState; | ||
399 | b.Poster.Abort(); | ||
400 | b.Timer.Dispose(); | ||
401 | m_log.Debug("[Concierge]: async broker POST abort due to timeout"); | ||
402 | }, bs, m_brokerUpdateTimeout * 1000, Timeout.Infinite); | ||
403 | |||
404 | try | ||
405 | { | ||
406 | updatePost.BeginGetRequestStream(UpdateBrokerSend, bs); | ||
407 | m_log.DebugFormat("[Concierge] async broker POST to {0} started", uri); | ||
408 | } | ||
409 | catch (WebException we) | ||
410 | { | ||
411 | m_log.ErrorFormat("[Concierge] async broker POST to {0} failed: {1}", uri, we.Status); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | private void UpdateBrokerSend(IAsyncResult result) | ||
416 | { | ||
417 | BrokerState bs = null; | ||
418 | try | ||
419 | { | ||
420 | bs = result.AsyncState as BrokerState; | ||
421 | string payload = bs.Payload; | ||
422 | HttpWebRequest updatePost = bs.Poster; | ||
423 | |||
424 | using (StreamWriter payloadStream = new StreamWriter(updatePost.EndGetRequestStream(result))) | ||
425 | { | ||
426 | payloadStream.Write(payload); | ||
427 | payloadStream.Close(); | ||
428 | } | ||
429 | updatePost.BeginGetResponse(UpdateBrokerDone, bs); | ||
430 | } | ||
431 | catch (WebException we) | ||
432 | { | ||
433 | m_log.DebugFormat("[Concierge]: async broker POST to {0} failed: {1}", bs.Uri, we.Status); | ||
434 | } | ||
435 | catch (Exception) | ||
436 | { | ||
437 | m_log.DebugFormat("[Concierge]: async broker POST to {0} failed", bs.Uri); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | private void UpdateBrokerDone(IAsyncResult result) | ||
442 | { | ||
443 | BrokerState bs = null; | ||
444 | try | ||
445 | { | ||
446 | bs = result.AsyncState as BrokerState; | ||
447 | HttpWebRequest updatePost = bs.Poster; | ||
448 | using (HttpWebResponse response = updatePost.EndGetResponse(result) as HttpWebResponse) | ||
449 | { | ||
450 | m_log.DebugFormat("[Concierge] broker update: status {0}", response.StatusCode); | ||
451 | } | ||
452 | bs.Timer.Dispose(); | ||
453 | } | ||
454 | catch (WebException we) | ||
455 | { | ||
456 | m_log.ErrorFormat("[Concierge] broker update to {0} failed with status {1}", bs.Uri, we.Status); | ||
457 | if (null != we.Response) | ||
458 | { | ||
459 | using (HttpWebResponse resp = we.Response as HttpWebResponse) | ||
460 | { | ||
461 | m_log.ErrorFormat("[Concierge] response from {0} status code: {1}", bs.Uri, resp.StatusCode); | ||
462 | m_log.ErrorFormat("[Concierge] response from {0} status desc: {1}", bs.Uri, resp.StatusDescription); | ||
463 | m_log.ErrorFormat("[Concierge] response from {0} server: {1}", bs.Uri, resp.Server); | ||
464 | |||
465 | if (resp.ContentLength > 0) | ||
466 | { | ||
467 | StreamReader content = new StreamReader(resp.GetResponseStream()); | ||
468 | m_log.ErrorFormat("[Concierge] response from {0} content: {1}", bs.Uri, content.ReadToEnd()); | ||
469 | content.Close(); | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | |||
476 | protected void WelcomeAvatar(ScenePresence agent, Scene scene) | ||
477 | { | ||
478 | // welcome mechanics: check whether we have a welcomes | ||
479 | // directory set and wether there is a region specific | ||
480 | // welcome file there: if yes, send it to the agent | ||
481 | if (!String.IsNullOrEmpty(m_welcomes)) | ||
482 | { | ||
483 | string[] welcomes = new string[] { | ||
484 | Path.Combine(m_welcomes, agent.Scene.RegionInfo.RegionName), | ||
485 | Path.Combine(m_welcomes, "DEFAULT")}; | ||
486 | foreach (string welcome in welcomes) | ||
487 | { | ||
488 | if (File.Exists(welcome)) | ||
489 | { | ||
490 | try | ||
491 | { | ||
492 | string[] welcomeLines = File.ReadAllLines(welcome); | ||
493 | foreach (string l in welcomeLines) | ||
494 | { | ||
495 | AnnounceToAgent(agent, String.Format(l, agent.Name, scene.RegionInfo.RegionName, m_whoami)); | ||
496 | } | ||
497 | } | ||
498 | catch (IOException ioe) | ||
499 | { | ||
500 | m_log.ErrorFormat("[Concierge]: run into trouble reading welcome file {0} for region {1} for avatar {2}: {3}", | ||
501 | welcome, scene.RegionInfo.RegionName, agent.Name, ioe); | ||
502 | } | ||
503 | catch (FormatException fe) | ||
504 | { | ||
505 | m_log.ErrorFormat("[Concierge]: welcome file {0} is malformed: {1}", welcome, fe); | ||
506 | } | ||
507 | } | ||
508 | return; | ||
509 | } | ||
510 | m_log.DebugFormat("[Concierge]: no welcome message for region {0}", scene.RegionInfo.RegionName); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | static private Vector3 PosOfGod = new Vector3(128, 128, 9999); | ||
515 | |||
516 | // protected void AnnounceToAgentsRegion(Scene scene, string msg) | ||
517 | // { | ||
518 | // ScenePresence agent = null; | ||
519 | // if ((client.Scene is Scene) && (client.Scene as Scene).TryGetScenePresence(client.AgentId, out agent)) | ||
520 | // AnnounceToAgentsRegion(agent, msg); | ||
521 | // else | ||
522 | // m_log.DebugFormat("[Concierge]: could not find an agent for client {0}", client.Name); | ||
523 | // } | ||
524 | |||
525 | protected void AnnounceToAgentsRegion(IScene scene, string msg) | ||
526 | { | ||
527 | OSChatMessage c = new OSChatMessage(); | ||
528 | c.Message = msg; | ||
529 | c.Type = ChatTypeEnum.Say; | ||
530 | c.Channel = 0; | ||
531 | c.Position = PosOfGod; | ||
532 | c.From = m_whoami; | ||
533 | c.Sender = null; | ||
534 | c.SenderUUID = UUID.Zero; | ||
535 | c.Scene = scene; | ||
536 | |||
537 | if (scene is Scene) | ||
538 | (scene as Scene).EventManager.TriggerOnChatBroadcast(this, c); | ||
539 | } | ||
540 | |||
541 | protected void AnnounceToAgent(ScenePresence agent, string msg) | ||
542 | { | ||
543 | OSChatMessage c = new OSChatMessage(); | ||
544 | c.Message = msg; | ||
545 | c.Type = ChatTypeEnum.Say; | ||
546 | c.Channel = 0; | ||
547 | c.Position = PosOfGod; | ||
548 | c.From = m_whoami; | ||
549 | c.Sender = null; | ||
550 | c.SenderUUID = UUID.Zero; | ||
551 | c.Scene = agent.Scene; | ||
552 | |||
553 | agent.ControllingClient.SendChatMessage( | ||
554 | msg, (byte) ChatTypeEnum.Say, PosOfGod, m_whoami, UUID.Zero, UUID.Zero, | ||
555 | (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); | ||
556 | } | ||
557 | |||
558 | private static void checkStringParameters(XmlRpcRequest request, string[] param) | ||
559 | { | ||
560 | Hashtable requestData = (Hashtable) request.Params[0]; | ||
561 | foreach (string p in param) | ||
562 | { | ||
563 | if (!requestData.Contains(p)) | ||
564 | throw new Exception(String.Format("missing string parameter {0}", p)); | ||
565 | if (String.IsNullOrEmpty((string)requestData[p])) | ||
566 | throw new Exception(String.Format("parameter {0} is empty", p)); | ||
567 | } | ||
568 | } | ||
569 | |||
570 | public XmlRpcResponse XmlRpcUpdateWelcomeMethod(XmlRpcRequest request, IPEndPoint remoteClient) | ||
571 | { | ||
572 | m_log.Info("[Concierge]: processing UpdateWelcome request"); | ||
573 | XmlRpcResponse response = new XmlRpcResponse(); | ||
574 | Hashtable responseData = new Hashtable(); | ||
575 | |||
576 | try | ||
577 | { | ||
578 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
579 | checkStringParameters(request, new string[] { "password", "region", "welcome" }); | ||
580 | |||
581 | // check password | ||
582 | if (!String.IsNullOrEmpty(m_xmlRpcPassword) && | ||
583 | (string)requestData["password"] != m_xmlRpcPassword) throw new Exception("wrong password"); | ||
584 | |||
585 | if (String.IsNullOrEmpty(m_welcomes)) | ||
586 | throw new Exception("welcome templates are not enabled, ask your OpenSim operator to set the \"welcomes\" option in the [Concierge] section of OpenSim.ini"); | ||
587 | |||
588 | string msg = (string)requestData["welcome"]; | ||
589 | if (String.IsNullOrEmpty(msg)) | ||
590 | throw new Exception("empty parameter \"welcome\""); | ||
591 | |||
592 | string regionName = (string)requestData["region"]; | ||
593 | IScene scene = m_scenes.Find(delegate(IScene s) { return s.RegionInfo.RegionName == regionName; }); | ||
594 | if (scene == null) | ||
595 | throw new Exception(String.Format("unknown region \"{0}\"", regionName)); | ||
596 | |||
597 | if (!m_conciergedScenes.Contains(scene)) | ||
598 | throw new Exception(String.Format("region \"{0}\" is not a concierged region.", regionName)); | ||
599 | |||
600 | string welcome = Path.Combine(m_welcomes, regionName); | ||
601 | if (File.Exists(welcome)) | ||
602 | { | ||
603 | m_log.InfoFormat("[Concierge]: UpdateWelcome: updating existing template \"{0}\"", welcome); | ||
604 | string welcomeBackup = String.Format("{0}~", welcome); | ||
605 | if (File.Exists(welcomeBackup)) | ||
606 | File.Delete(welcomeBackup); | ||
607 | File.Move(welcome, welcomeBackup); | ||
608 | } | ||
609 | File.WriteAllText(welcome, msg); | ||
610 | |||
611 | responseData["success"] = "true"; | ||
612 | response.Value = responseData; | ||
613 | } | ||
614 | catch (Exception e) | ||
615 | { | ||
616 | m_log.InfoFormat("[Concierge]: UpdateWelcome failed: {0}", e.Message); | ||
617 | |||
618 | responseData["success"] = "false"; | ||
619 | responseData["error"] = e.Message; | ||
620 | |||
621 | response.Value = responseData; | ||
622 | } | ||
623 | m_log.Debug("[Concierge]: done processing UpdateWelcome request"); | ||
624 | return response; | ||
625 | } | ||
626 | } | ||
627 | } | ||