aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs216
-rw-r--r--bin/OpenSim.ini.example22
2 files changed, 191 insertions, 47 deletions
diff --git a/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
index ab60763..acc25dd 100644
--- a/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
+++ b/OpenSim/Region/Environment/Modules/Avatar/Concierge/ConciergeModule.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using System.IO; 31using System.IO;
31using System.Net.Sockets; 32using System.Net.Sockets;
@@ -34,8 +35,10 @@ using System.Text.RegularExpressions;
34using System.Threading; 35using System.Threading;
35using log4net; 36using log4net;
36using Nini.Config; 37using Nini.Config;
38using Nwc.XmlRpc;
37using OpenMetaverse; 39using OpenMetaverse;
38using OpenSim.Framework; 40using OpenSim.Framework;
41using OpenSim.Framework.Servers;
39using OpenSim.Region.Environment.Interfaces; 42using OpenSim.Region.Environment.Interfaces;
40using OpenSim.Region.Environment.Scenes; 43using OpenSim.Region.Environment.Scenes;
41using OpenSim.Region.Environment.Modules.Avatar.Chat; 44using OpenSim.Region.Environment.Modules.Avatar.Chat;
@@ -48,15 +51,20 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
48 51
49 private const int DEBUG_CHANNEL = 2147483647; 52 private const int DEBUG_CHANNEL = 2147483647;
50 53
51 private int _conciergeChannel = 42;
52 private List<IScene> _scenes = new List<IScene>(); 54 private List<IScene> _scenes = new List<IScene>();
53 private List<IScene> _conciergedScenes = new List<IScene>(); 55 private List<IScene> _conciergedScenes = new List<IScene>();
54 private Dictionary<IScene, List<string>> _sceneAttendees = new Dictionary<IScene, List<string>>(); 56 private Dictionary<IScene, List<ScenePresence>> _sceneAttendees = new Dictionary<IScene, List<ScenePresence>>();
57 private bool _replacingChatModule = false;
58
55 private IConfig _config; 59 private IConfig _config;
60
56 private string _whoami = "conferencier"; 61 private string _whoami = "conferencier";
57 private bool _replacingChatModule = false;
58 private Regex _regions = null; 62 private Regex _regions = null;
59 private string _welcomes = null; 63 private string _welcomes = null;
64 private int _conciergeChannel = 42;
65 private string _announceEntering = "{0} enters {1} (now {2} visitors in this region)";
66 private string _announceLeaving = "{0} leaves {1} (back to {2} visitors in this region)";
67 private string _xmlRpcPassword = String.Empty;
60 68
61 internal object _syncy = new object(); 69 internal object _syncy = new object();
62 70
@@ -108,6 +116,9 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
108 _conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", _conciergeChannel); 116 _conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", _conciergeChannel);
109 _whoami = _config.GetString("whoami", "conferencier"); 117 _whoami = _config.GetString("whoami", "conferencier");
110 _welcomes = _config.GetString("welcomes", _welcomes); 118 _welcomes = _config.GetString("welcomes", _welcomes);
119 _announceEntering = _config.GetString("announce_entering", _announceEntering);
120 _announceLeaving = _config.GetString("announce_leaving", _announceLeaving);
121 _xmlRpcPassword = _config.GetString("password", _xmlRpcPassword);
111 _log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", _whoami); 122 _log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", _whoami);
112 123
113 // calculate regions Regex 124 // calculate regions Regex
@@ -116,10 +127,12 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
116 string regions = _config.GetString("regions", String.Empty); 127 string regions = _config.GetString("regions", String.Empty);
117 if (!String.IsNullOrEmpty(regions)) 128 if (!String.IsNullOrEmpty(regions))
118 { 129 {
119 _regions = new Regex(regions, RegexOptions.Compiled | RegexOptions.IgnoreCase); 130 _regions = new Regex(@regions, RegexOptions.Compiled | RegexOptions.IgnoreCase);
120 } 131 }
121 } 132 }
122 133
134 scene.CommsManager.HttpServer.AddXmlRPCHandler("concierge_update_welcome", XmlRpcUpdateWelcomeMethod, false);
135
123 lock (_syncy) 136 lock (_syncy)
124 { 137 {
125 if (!_scenes.Contains(scene)) 138 if (!_scenes.Contains(scene))
@@ -244,17 +257,13 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
244 { 257 {
245 client.OnLogout += OnClientLoggedOut; 258 client.OnLogout += OnClientLoggedOut;
246 client.OnConnectionClosed += OnClientLoggedOut; 259 client.OnConnectionClosed += OnClientLoggedOut;
260
247 if (_replacingChatModule) 261 if (_replacingChatModule)
248 client.OnChatFromClient += OnChatFromClient; 262 client.OnChatFromClient += OnChatFromClient;
249
250 if (_conciergedScenes.Contains(client.Scene))
251 {
252 _log.DebugFormat("[Concierge] {0} logs on to {1}", client.Name, client.Scene.RegionInfo.RegionName);
253 AnnounceToAgentsRegion(client, String.Format("{0} logs on to {1}", client.Name,
254 client.Scene.RegionInfo.RegionName));
255 }
256 } 263 }
257 264
265
266
258 public void OnClientLoggedOut(IClientAPI client) 267 public void OnClientLoggedOut(IClientAPI client)
259 { 268 {
260 client.OnLogout -= OnClientLoggedOut; 269 client.OnLogout -= OnClientLoggedOut;
@@ -263,8 +272,10 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
263 if (_conciergedScenes.Contains(client.Scene)) 272 if (_conciergedScenes.Contains(client.Scene))
264 { 273 {
265 _log.DebugFormat("[Concierge] {0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName); 274 _log.DebugFormat("[Concierge] {0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName);
266 AnnounceToAgentsRegion(client, String.Format("{0} logs off from {1}", client.Name, 275 ScenePresence agent = (client.Scene as Scene).GetScenePresence(client.AgentId);
267 client.Scene.RegionInfo.RegionName)); 276 RemoveFromAttendeeList(agent, agent.Scene);
277 AnnounceToAgentsRegion(agent, String.Format(_announceLeaving, agent.Name, agent.Scene.RegionInfo.RegionName,
278 _sceneAttendees[agent.Scene].Count));
268 } 279 }
269 } 280 }
270 281
@@ -274,13 +285,69 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
274 if (_conciergedScenes.Contains(agent.Scene)) 285 if (_conciergedScenes.Contains(agent.Scene))
275 { 286 {
276 _log.DebugFormat("[Concierge] {0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName); 287 _log.DebugFormat("[Concierge] {0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
288 AddToAttendeeList(agent, agent.Scene);
289 WelcomeAvatar(agent, agent.Scene);
290 AnnounceToAgentsRegion(agent, String.Format(_announceEntering, agent.Name, agent.Scene.RegionInfo.RegionName,
291 _sceneAttendees[agent.Scene].Count));
292 }
293 }
294
295
296 public void OnMakeChildAgent(ScenePresence agent)
297 {
298 if (_conciergedScenes.Contains(agent.Scene))
299 {
300 _log.DebugFormat("[Concierge] {0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
301 RemoveFromAttendeeList(agent, agent.Scene);
302 AnnounceToAgentsRegion(agent, String.Format(_announceLeaving, agent.Name, agent.Scene.RegionInfo.RegionName,
303 _sceneAttendees[agent.Scene].Count));
304 }
305 }
277 306
278 // welcome mechanics: check whether we have a welcomes 307 protected void AddToAttendeeList(ScenePresence agent, Scene scene)
279 // directory set and wether there is a region specific 308 {
280 // welcome file there: if yes, send it to the agent 309 lock(_sceneAttendees)
281 if (!String.IsNullOrEmpty(_welcomes)) 310 {
311 if (!_sceneAttendees.ContainsKey(scene))
312 _sceneAttendees[scene] = new List<ScenePresence>();
313 List<ScenePresence> attendees = _sceneAttendees[scene];
314 if (!attendees.Contains(agent))
315 attendees.Add(agent);
316 }
317 }
318
319 protected void RemoveFromAttendeeList(ScenePresence agent, Scene scene)
320 {
321 lock(_sceneAttendees)
322 {
323 if (!_sceneAttendees.ContainsKey(scene))
324 {
325 _log.WarnFormat("[Concierge] attendee list missing for region {0}", scene.RegionInfo.RegionName);
326 return;
327 }
328 List<ScenePresence> attendees = _sceneAttendees[scene];
329 if (!attendees.Contains(agent))
330 {
331 _log.WarnFormat("[Concierge] avatar {0} sneaked in (not on attendee list of region {1})",
332 agent.Name, scene.RegionInfo.RegionName);
333 return;
334 }
335 attendees.Remove(agent);
336 }
337 }
338
339 protected void WelcomeAvatar(ScenePresence agent, Scene scene)
340 {
341 // welcome mechanics: check whether we have a welcomes
342 // directory set and wether there is a region specific
343 // welcome file there: if yes, send it to the agent
344 if (!String.IsNullOrEmpty(_welcomes))
345 {
346 string[] welcomes = new string[] {
347 Path.Combine(_welcomes, agent.Scene.RegionInfo.RegionName),
348 Path.Combine(_welcomes, "DEFAULT")};
349 foreach (string welcome in welcomes)
282 { 350 {
283 string welcome = Path.Combine(_welcomes, agent.Scene.RegionInfo.RegionName);
284 if (File.Exists(welcome)) 351 if (File.Exists(welcome))
285 { 352 {
286 try 353 try
@@ -288,46 +355,22 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
288 string[] welcomeLines = File.ReadAllLines(welcome); 355 string[] welcomeLines = File.ReadAllLines(welcome);
289 foreach (string l in welcomeLines) 356 foreach (string l in welcomeLines)
290 { 357 {
291 AnnounceToAgent(agent, String.Format(l, agent.Name, agent.Scene.RegionInfo.RegionName, _whoami)); 358 AnnounceToAgent(agent, String.Format(l, agent.Name, scene.RegionInfo.RegionName, _whoami));
292 } 359 }
293 } 360 }
294 catch (IOException ioe) 361 catch (IOException ioe)
295 { 362 {
296 _log.ErrorFormat("[Concierge] run into trouble reading welcome file {0} for region {1} for avatar {2}: {3}", 363 _log.ErrorFormat("[Concierge] run into trouble reading welcome file {0} for region {1} for avatar {2}: {3}",
297 welcome, agent.Scene.RegionInfo.RegionName, agent.Name, ioe); 364 welcome, scene.RegionInfo.RegionName, agent.Name, ioe);
298 } 365 }
299 catch (FormatException fe) 366 catch (FormatException fe)
300 { 367 {
301 _log.ErrorFormat("[Concierge] welcome file {0} is malformed: {1}", welcome, fe); 368 _log.ErrorFormat("[Concierge] welcome file {0} is malformed: {1}", welcome, fe);
302 } 369 }
303 } else { 370 }
304 _log.DebugFormat("[Concierge] not playing out welcome message: {0} not found", welcome); 371 return;
305 }
306 } 372 }
307 373 _log.DebugFormat("[Concierge] no welcome message for region {0}", scene.RegionInfo.RegionName);
308 AnnounceToAgentsRegion(agent, String.Format("{0} enters {1}", agent.Name,
309 agent.Scene.RegionInfo.RegionName));
310 }
311 }
312
313
314 public void OnMakeChildAgent(ScenePresence agent)
315 {
316 if (_conciergedScenes.Contains(agent.Scene))
317 {
318 _log.DebugFormat("[Concierge] {0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
319 AnnounceToAgentsRegion(agent, String.Format("{0} leaves {1}", agent.Name,
320 agent.Scene.RegionInfo.RegionName));
321 }
322 }
323
324
325 public void ClientLoggedOut(IClientAPI client)
326 {
327 if (_conciergedScenes.Contains(client.Scene))
328 {
329 _log.DebugFormat("[Concierge] {0} logs out of {1}", client.Name, client.Scene.RegionInfo.RegionName);
330 AnnounceToAgentsRegion(client, String.Format("{0} logs out of {1}", client.Name, client.Scene.RegionInfo.RegionName));
331 } 374 }
332 } 375 }
333 376
@@ -372,5 +415,84 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Concierge
372 agent.ControllingClient.SendChatMessage(msg, (byte) ChatTypeEnum.Say, PosOfGod, _whoami, UUID.Zero, 415 agent.ControllingClient.SendChatMessage(msg, (byte) ChatTypeEnum.Say, PosOfGod, _whoami, UUID.Zero,
373 (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully); 416 (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
374 } 417 }
418
419 private static void checkStringParameters(XmlRpcRequest request, string[] param)
420 {
421 Hashtable requestData = (Hashtable) request.Params[0];
422 foreach (string p in param)
423 {
424 if (!requestData.Contains(p))
425 throw new Exception(String.Format("missing string parameter {0}", p));
426 if (String.IsNullOrEmpty((string)requestData[p]))
427 throw new Exception(String.Format("parameter {0} is empty", p));
428 }
429 }
430
431 private static void checkIntegerParams(XmlRpcRequest request, string[] param)
432 {
433 Hashtable requestData = (Hashtable) request.Params[0];
434 foreach (string p in param)
435 {
436 if (!requestData.Contains(p))
437 throw new Exception(String.Format("missing integer parameter {0}", p));
438 }
439 }
440
441 public XmlRpcResponse XmlRpcUpdateWelcomeMethod(XmlRpcRequest request)
442 {
443 _log.Info("[Concierge]: processing UpdateWelcome request");
444 XmlRpcResponse response = new XmlRpcResponse();
445 Hashtable responseData = new Hashtable();
446
447 try
448 {
449 Hashtable requestData = (Hashtable)request.Params[0];
450 checkStringParameters(request, new string[] { "password", "region", "welcome" });
451
452 // check password
453 if (!String.IsNullOrEmpty(_xmlRpcPassword) &&
454 (string)requestData["password"] != _xmlRpcPassword) throw new Exception("wrong password");
455
456 if (String.IsNullOrEmpty(_welcomes))
457 throw new Exception("welcome templates are not enabled, ask your OpenSim operator to set the \"welcomes\" option in the [Concierge] section of OpenSim.ini");
458
459 string msg = (string)requestData["welcome"];
460 if (String.IsNullOrEmpty(msg))
461 throw new Exception("empty parameter \"welcome\"");
462
463 string regionName = (string)requestData["region"];
464 IScene scene = _scenes.Find(delegate(IScene s) { return s.RegionInfo.RegionName == regionName; });
465 if (scene == null)
466 throw new Exception(String.Format("unknown region \"{0}\"", regionName));
467
468 if (!_conciergedScenes.Contains(scene))
469 throw new Exception(String.Format("region \"{0}\" is not a concierged region.", regionName));
470
471 string welcome = Path.Combine(_welcomes, regionName);
472 if (File.Exists(welcome))
473 {
474 _log.InfoFormat("[Concierge] UpdateWelcome: updating existing template \"{0}\"", welcome);
475 string welcomeBackup = String.Format("{0}~", welcome);
476 if (File.Exists(welcomeBackup))
477 File.Delete(welcomeBackup);
478 File.Move(welcome, welcomeBackup);
479 }
480 File.WriteAllText(welcome, msg);
481
482 responseData["success"] = "true";
483 response.Value = responseData;
484 }
485 catch (Exception e)
486 {
487 _log.InfoFormat("[Concierge] UpdateWelcome failed: {0}", e.Message);
488
489 responseData["success"] = "false";
490 responseData["error"] = e.Message;
491
492 response.Value = responseData;
493 }
494 _log.Debug("[Concierge]: done processing UpdateWelcome request");
495 return response;
496 }
375 } 497 }
376} \ No newline at end of file 498} \ No newline at end of file
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example
index 08dc27e..8a5bdd7 100644
--- a/bin/OpenSim.ini.example
+++ b/bin/OpenSim.ini.example
@@ -411,10 +411,29 @@ flush-on-error=true
411;; relay_private_channels = true: will relay IRC chat from/to private in-world channels 411;; relay_private_channels = true: will relay IRC chat from/to private in-world channels
412;; relay_private_channel_out -- channel to send messages out to the IRC bridge 412;; relay_private_channel_out -- channel to send messages out to the IRC bridge
413;; relay_private_channel_in -- channel to receive message from the IRC bridge 413;; relay_private_channel_in -- channel to receive message from the IRC bridge
414;; relay_chat = false: IRC bridge will not relay normal chat
414;; access_password -- simple security device 415;; access_password -- simple security device
416;;
417;; so, to just relay chat from an IRC channel to in-world region and vice versa:
418;;
419;; relay_private_channels = false
420;; relay_chat = true
421;;
422;; to relay chat only to/from private in-world channels:
423;;
424;; relay_chat = false
425;; relay_private_channels = true
426;; relay_private_channel_in = 2226
427;; relay_private_channel_out = 2225
428;;
429;; in this example, all chat coming in from IRC will be send out via
430;; in-world channel 2226, and all chat from in-world channel 2225 will
431;; be relayed to the IRC channel.
432;;
415;relay_private_channels = false 433;relay_private_channels = false
416;relay_private_channel_in = 2226 434;relay_private_channel_in = 2226
417;relay_private_channel_out = 2225 435;relay_private_channel_out = 2225
436;relay_chat = true
418;access_password = foobar 437;access_password = foobar
419 438
420;fallback_region = name of "default" region 439;fallback_region = name of "default" region
@@ -798,6 +817,9 @@ enabled = false
798; name of the concierge 817; name of the concierge
799whoami = "jeeves" 818whoami = "jeeves"
800 819
820; password for updating the welcome message templates via XmlRpc
821password = SECRET
822
801; regex specifying for which regions concierge service is desired; if 823; regex specifying for which regions concierge service is desired; if
802; empty, then for all 824; empty, then for all
803regions = "^MeetingSpace-" 825regions = "^MeetingSpace-"