clockwerk-opensim-stable – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | vero | 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 | } |