aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/Avatar
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/OptionalModules/Avatar
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/OptionalModules/Avatar')
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs196
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs17
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs5
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs160
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs41
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs303
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs98
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs220
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs41
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs75
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs289
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs272
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs214
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs71
16 files changed, 1421 insertions, 593 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
index d718a2f..2f9bb1e 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Appearance/AppearanceInfoModule.cs
@@ -51,7 +51,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
51 { 51 {
52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53 53
54 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>(); 54 private List<Scene> m_scenes = new List<Scene>();
55
55// private IAvatarFactoryModule m_avatarFactory; 56// private IAvatarFactoryModule m_avatarFactory;
56 57
57 public string Name { get { return "Appearance Information Module"; } } 58 public string Name { get { return "Appearance Information Module"; } }
@@ -83,7 +84,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
83// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); 84// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
84 85
85 lock (m_scenes) 86 lock (m_scenes)
86 m_scenes.Remove(scene.RegionInfo.RegionID); 87 m_scenes.Remove(scene);
87 } 88 }
88 89
89 public void RegionLoaded(Scene scene) 90 public void RegionLoaded(Scene scene)
@@ -91,7 +92,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
91// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 92// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
92 93
93 lock (m_scenes) 94 lock (m_scenes)
94 m_scenes[scene.RegionInfo.RegionID] = scene; 95 m_scenes.Add(scene);
95 96
96 scene.AddCommand( 97 scene.AddCommand(
97 "Users", this, "show appearance", 98 "Users", this, "show appearance",
@@ -102,7 +103,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
102 scene.AddCommand( 103 scene.AddCommand(
103 "Users", this, "appearance show", 104 "Users", this, "appearance show",
104 "appearance show [<first-name> <last-name>]", 105 "appearance show [<first-name> <last-name>]",
105 "Show appearance information for each avatar in the simulator.", 106 "Show appearance information for avatars.",
106 "This command checks whether the simulator has all the baked textures required to display an avatar to other viewers. " 107 "This command checks whether the simulator has all the baked textures required to display an avatar to other viewers. "
107 + "\nIf not, then appearance is 'corrupt' and other avatars will continue to see it as a cloud." 108 + "\nIf not, then appearance is 'corrupt' and other avatars will continue to see it as a cloud."
108 + "\nOptionally, you can view just a particular avatar's appearance information." 109 + "\nOptionally, you can view just a particular avatar's appearance information."
@@ -132,6 +133,21 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
132 "Find out which avatar uses the given asset as a baked texture, if any.", 133 "Find out which avatar uses the given asset as a baked texture, if any.",
133 "You can specify just the beginning of the uuid, e.g. 2008a8d. A longer UUID must be in dashed format.", 134 "You can specify just the beginning of the uuid, e.g. 2008a8d. A longer UUID must be in dashed format.",
134 HandleFindAppearanceCommand); 135 HandleFindAppearanceCommand);
136
137 scene.AddCommand(
138 "Users", this, "wearables show",
139 "wearables show [<first-name> <last-name>]",
140 "Show information about wearables for avatars.",
141 "If no avatar name is given then a general summary for all avatars in the scene is shown.\n"
142 + "If an avatar name is given then specific information about current wearables is shown.",
143 HandleShowWearablesCommand);
144
145 scene.AddCommand(
146 "Users", this, "wearables check",
147 "wearables check <first-name> <last-name>",
148 "Check that the wearables of a given avatar in the scene are valid.",
149 "This currently checks that the wearable assets themselves and any assets referenced by them exist.",
150 HandleCheckWearablesCommand);
135 } 151 }
136 152
137 private void HandleSendAppearanceCommand(string module, string[] cmd) 153 private void HandleSendAppearanceCommand(string module, string[] cmd)
@@ -155,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
155 171
156 lock (m_scenes) 172 lock (m_scenes)
157 { 173 {
158 foreach (Scene scene in m_scenes.Values) 174 foreach (Scene scene in m_scenes)
159 { 175 {
160 if (targetNameSupplied) 176 if (targetNameSupplied)
161 { 177 {
@@ -186,7 +202,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
186 } 202 }
187 } 203 }
188 204
189 protected void HandleShowAppearanceCommand(string module, string[] cmd) 205 private void HandleShowAppearanceCommand(string module, string[] cmd)
190 { 206 {
191 if (cmd.Length != 2 && cmd.Length < 4) 207 if (cmd.Length != 2 && cmd.Length < 4)
192 { 208 {
@@ -207,7 +223,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
207 223
208 lock (m_scenes) 224 lock (m_scenes)
209 { 225 {
210 foreach (Scene scene in m_scenes.Values) 226 foreach (Scene scene in m_scenes)
211 { 227 {
212 if (targetNameSupplied) 228 if (targetNameSupplied)
213 { 229 {
@@ -222,7 +238,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
222 { 238 {
223 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp); 239 bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp);
224 MainConsole.Instance.OutputFormat( 240 MainConsole.Instance.OutputFormat(
225 "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); 241 "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete");
226 } 242 }
227 ); 243 );
228 } 244 }
@@ -243,7 +259,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
243 259
244 lock (m_scenes) 260 lock (m_scenes)
245 { 261 {
246 foreach (Scene scene in m_scenes.Values) 262 foreach (Scene scene in m_scenes)
247 { 263 {
248 ScenePresence sp = scene.GetScenePresence(firstname, lastname); 264 ScenePresence sp = scene.GetScenePresence(firstname, lastname);
249 if (sp != null && !sp.IsChildAgent) 265 if (sp != null && !sp.IsChildAgent)
@@ -263,7 +279,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
263 } 279 }
264 } 280 }
265 281
266 protected void HandleFindAppearanceCommand(string module, string[] cmd) 282 private void HandleFindAppearanceCommand(string module, string[] cmd)
267 { 283 {
268 if (cmd.Length != 3) 284 if (cmd.Length != 3)
269 { 285 {
@@ -277,7 +293,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
277 293
278 lock (m_scenes) 294 lock (m_scenes)
279 { 295 {
280 foreach (Scene scene in m_scenes.Values) 296 foreach (Scene scene in m_scenes)
281 { 297 {
282 scene.ForEachRootScenePresence( 298 scene.ForEachRootScenePresence(
283 sp => 299 sp =>
@@ -304,5 +320,163 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance
304 string.Join(", ", matchedAvatars.ToList().ConvertAll<string>(sp => sp.Name).ToArray())); 320 string.Join(", ", matchedAvatars.ToList().ConvertAll<string>(sp => sp.Name).ToArray()));
305 } 321 }
306 } 322 }
323
324 protected void HandleShowWearablesCommand(string module, string[] cmd)
325 {
326 if (cmd.Length != 2 && cmd.Length < 4)
327 {
328 MainConsole.Instance.OutputFormat("Usage: wearables show [<first-name> <last-name>]");
329 return;
330 }
331
332 bool targetNameSupplied = false;
333 string optionalTargetFirstName = null;
334 string optionalTargetLastName = null;
335
336 if (cmd.Length >= 4)
337 {
338 targetNameSupplied = true;
339 optionalTargetFirstName = cmd[2];
340 optionalTargetLastName = cmd[3];
341 }
342
343 StringBuilder sb = new StringBuilder();
344
345 if (targetNameSupplied)
346 {
347 lock (m_scenes)
348 {
349 foreach (Scene scene in m_scenes)
350 {
351 ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName);
352 if (sp != null && !sp.IsChildAgent)
353 AppendWearablesDetailReport(sp, sb);
354 }
355 }
356 }
357 else
358 {
359 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
360 cdt.AddColumn("Name", ConsoleDisplayUtil.UserNameSize);
361 cdt.AddColumn("Wearables", 2);
362
363 lock (m_scenes)
364 {
365 foreach (Scene scene in m_scenes)
366 {
367 scene.ForEachRootScenePresence(
368 sp =>
369 {
370 int count = 0;
371
372 for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++)
373 count += sp.Appearance.Wearables[i].Count;
374
375 cdt.AddRow(sp.Name, count);
376 }
377 );
378 }
379 }
380
381 sb.Append(cdt.ToString());
382 }
383
384 MainConsole.Instance.Output(sb.ToString());
385 }
386
387 private void HandleCheckWearablesCommand(string module, string[] cmd)
388 {
389 if (cmd.Length != 4)
390 {
391 MainConsole.Instance.OutputFormat("Usage: wearables check <first-name> <last-name>");
392 return;
393 }
394
395 string firstname = cmd[2];
396 string lastname = cmd[3];
397
398 StringBuilder sb = new StringBuilder();
399 UuidGatherer uuidGatherer = new UuidGatherer(m_scenes[0].AssetService);
400
401 lock (m_scenes)
402 {
403 foreach (Scene scene in m_scenes)
404 {
405 ScenePresence sp = scene.GetScenePresence(firstname, lastname);
406 if (sp != null && !sp.IsChildAgent)
407 {
408 sb.AppendFormat("Wearables checks for {0}\n\n", sp.Name);
409
410 for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++)
411 {
412 AvatarWearable aw = sp.Appearance.Wearables[i];
413
414 if (aw.Count > 0)
415 {
416 sb.Append(Enum.GetName(typeof(WearableType), i));
417 sb.Append("\n");
418
419 for (int j = 0; j < aw.Count; j++)
420 {
421 WearableItem wi = aw[j];
422
423 ConsoleDisplayList cdl = new ConsoleDisplayList();
424 cdl.Indent = 2;
425 cdl.AddRow("Item UUID", wi.ItemID);
426 cdl.AddRow("Assets", "");
427 sb.Append(cdl.ToString());
428
429 uuidGatherer.AddForInspection(wi.AssetID);
430 uuidGatherer.GatherAll();
431 string[] assetStrings
432 = Array.ConvertAll<UUID, string>(uuidGatherer.GatheredUuids.Keys.ToArray(), u => u.ToString());
433
434 bool[] existChecks = scene.AssetService.AssetsExist(assetStrings);
435
436 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
437 cdt.Indent = 4;
438 cdt.AddColumn("Type", 10);
439 cdt.AddColumn("UUID", ConsoleDisplayUtil.UuidSize);
440 cdt.AddColumn("Found", 5);
441
442 for (int k = 0; k < existChecks.Length; k++)
443 cdt.AddRow(
444 (AssetType)uuidGatherer.GatheredUuids[new UUID(assetStrings[k])],
445 assetStrings[k], existChecks[k] ? "yes" : "no");
446
447 sb.Append(cdt.ToString());
448 sb.Append("\n");
449 }
450 }
451 }
452 }
453 }
454 }
455
456 MainConsole.Instance.Output(sb.ToString());
457 }
458
459 private void AppendWearablesDetailReport(ScenePresence sp, StringBuilder sb)
460 {
461 sb.AppendFormat("\nWearables for {0}\n", sp.Name);
462
463 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
464 cdt.AddColumn("Type", 10);
465 cdt.AddColumn("Item UUID", ConsoleDisplayUtil.UuidSize);
466 cdt.AddColumn("Asset UUID", ConsoleDisplayUtil.UuidSize);
467
468 for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++)
469 {
470 AvatarWearable aw = sp.Appearance.Wearables[i];
471
472 for (int j = 0; j < aw.Count; j++)
473 {
474 WearableItem wi = aw[j];
475 cdt.AddRow(Enum.GetName(typeof(WearableType), i), wi.ItemID, wi.AssetID);
476 }
477 }
478
479 sb.Append(cdt.ToString());
480 }
307 } 481 }
308} \ No newline at end of file 482} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
index d97e3b3..0333747 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs
@@ -176,16 +176,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
176// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", 176// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n",
177// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, 177// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID,
178// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); 178// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos);
179 ct.Rows.Add( 179
180 new ConsoleDisplayTableRow( 180 ct.AddRow(
181 new List<string>() 181 attachmentObject.Name,
182 { 182 attachmentObject.LocalId,
183 attachmentObject.Name, 183 attachmentObject.FromItemID,
184 attachmentObject.LocalId.ToString(), 184 ((AttachmentPoint)attachmentObject.AttachmentPoint),
185 attachmentObject.FromItemID.ToString(), 185 attachmentObject.RootPart.AttachedPos);
186 ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(),
187 attachmentObject.RootPart.AttachedPos.ToString()
188 }));
189// } 186// }
190 } 187 }
191 188
diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
index d7fb272..535bf67 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/TempAttachmentsModule.cs
@@ -40,6 +40,7 @@ using OpenSim.Framework.Monitoring;
40using OpenSim.Region.ClientStack.LindenUDP; 40using OpenSim.Region.ClientStack.LindenUDP;
41using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using PermissionMask = OpenSim.Framework.PermissionMask;
43 44
44namespace OpenSim.Region.OptionalModules.Avatar.Attachments 45namespace OpenSim.Region.OptionalModules.Avatar.Attachments
45{ 46{
@@ -76,7 +77,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
76 77
77 if (m_console != null) 78 if (m_console != null)
78 { 79 {
79 m_console.AddCommand("TempATtachModule", false, "set auto_grant_attach_perms", "set auto_grant_attach_perms true|false", "Allow objects owned by the region owner os estate managers to obtain attach permissions without asking the user", SetAutoGrantAttachPerms); 80 m_console.AddCommand("TempAttachModule", false, "set auto_grant_attach_perms", "set auto_grant_attach_perms true|false", "Allow objects owned by the region owner or estate managers to obtain attach permissions without asking the user", SetAutoGrantAttachPerms);
80 } 81 }
81 } 82 }
82 else 83 else
@@ -183,7 +184,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
183 hostPart.ParentGroup.RootPart.ScheduleFullUpdate(); 184 hostPart.ParentGroup.RootPart.ScheduleFullUpdate();
184 } 185 }
185 186
186 return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true) ? 1 : 0; 187 return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, false, true) ? 1 : 0;
187 } 188 }
188 } 189 }
189} 190}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
index 66265d8..b5d9fda 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/ChannelState.cs
@@ -55,42 +55,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
55 // These are the IRC Connector configurable parameters with hard-wired 55 // These are the IRC Connector configurable parameters with hard-wired
56 // default values (retained for compatability). 56 // default values (retained for compatability).
57 57
58 internal string Server = null; 58 internal string Server = null;
59 internal string Password = null; 59 internal string Password = null;
60 internal string IrcChannel = null; 60 internal string IrcChannel = null;
61 internal string BaseNickname = "OSimBot"; 61 internal string BaseNickname = "OSimBot";
62 internal uint Port = 6667; 62 internal uint Port = 6667;
63 internal string User = null; 63 internal string User = null;
64 64
65 internal bool ClientReporting = true; 65 internal bool ClientReporting = true;
66 internal bool RelayChat = true; 66 internal bool RelayChat = true;
67 internal bool RelayPrivateChannels = false; 67 internal bool RelayPrivateChannels = false;
68 internal int RelayChannel = 1; 68 internal int RelayChannel = 1;
69 internal List<int> ValidInWorldChannels = new List<int>(); 69 internal List<int> ValidInWorldChannels = new List<int>();
70 70
71 // Connector agnostic parameters. These values are NOT shared with the 71 // Connector agnostic parameters. These values are NOT shared with the
72 // connector and do not differentiate at an IRC level 72 // connector and do not differentiate at an IRC level
73 73
74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}"; 74 internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}";
75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}"; 75 internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
76 internal int RelayChannelOut = -1; 76 internal int RelayChannelOut = -1;
77 internal bool RandomizeNickname = true; 77 internal bool RandomizeNickname = true;
78 internal bool CommandsEnabled = false; 78 internal bool CommandsEnabled = false;
79 internal int CommandChannel = -1; 79 internal int CommandChannel = -1;
80 internal int ConnectDelay = 10; 80 internal int ConnectDelay = 10;
81 internal int PingDelay = 15; 81 internal int PingDelay = 15;
82 internal string DefaultZone = "Sim"; 82 internal string DefaultZone = "Sim";
83 83
84 internal string _accessPassword = String.Empty; 84 internal string _accessPassword = String.Empty;
85 internal Regex AccessPasswordRegex = null; 85 internal Regex AccessPasswordRegex = null;
86 internal List<string> ExcludeList = new List<string>(); 86 internal List<string> ExcludeList = new List<string>();
87 internal string AccessPassword 87 internal string AccessPassword
88 { 88 {
89 get { return _accessPassword; } 89 get { return _accessPassword; }
90 set 90 set
91 { 91 {
92 _accessPassword = value; 92 _accessPassword = value;
93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword), 93 AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
94 RegexOptions.Compiled); 94 RegexOptions.Compiled);
95 } 95 }
96 } 96 }
@@ -99,9 +99,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
99 99
100 // IRC connector reference 100 // IRC connector reference
101 101
102 internal IRCConnector irc = null; 102 internal IRCConnector irc = null;
103 103
104 internal int idn = _idk_++; 104 internal int idn = _idk_++;
105 105
106 // List of regions dependent upon this connection 106 // List of regions dependent upon this connection
107 107
@@ -119,29 +119,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
119 119
120 internal ChannelState(ChannelState model) 120 internal ChannelState(ChannelState model)
121 { 121 {
122 Server = model.Server; 122 Server = model.Server;
123 Password = model.Password; 123 Password = model.Password;
124 IrcChannel = model.IrcChannel; 124 IrcChannel = model.IrcChannel;
125 Port = model.Port; 125 Port = model.Port;
126 BaseNickname = model.BaseNickname; 126 BaseNickname = model.BaseNickname;
127 RandomizeNickname = model.RandomizeNickname; 127 RandomizeNickname = model.RandomizeNickname;
128 User = model.User; 128 User = model.User;
129 CommandsEnabled = model.CommandsEnabled; 129 CommandsEnabled = model.CommandsEnabled;
130 CommandChannel = model.CommandChannel; 130 CommandChannel = model.CommandChannel;
131 RelayChat = model.RelayChat; 131 RelayChat = model.RelayChat;
132 RelayPrivateChannels = model.RelayPrivateChannels; 132 RelayPrivateChannels = model.RelayPrivateChannels;
133 RelayChannelOut = model.RelayChannelOut; 133 RelayChannelOut = model.RelayChannelOut;
134 RelayChannel = model.RelayChannel; 134 RelayChannel = model.RelayChannel;
135 ValidInWorldChannels = model.ValidInWorldChannels; 135 ValidInWorldChannels = model.ValidInWorldChannels;
136 PrivateMessageFormat = model.PrivateMessageFormat; 136 PrivateMessageFormat = model.PrivateMessageFormat;
137 NoticeMessageFormat = model.NoticeMessageFormat; 137 NoticeMessageFormat = model.NoticeMessageFormat;
138 ClientReporting = model.ClientReporting; 138 ClientReporting = model.ClientReporting;
139 AccessPassword = model.AccessPassword; 139 AccessPassword = model.AccessPassword;
140 DefaultZone = model.DefaultZone; 140 DefaultZone = model.DefaultZone;
141 ConnectDelay = model.ConnectDelay; 141 ConnectDelay = model.ConnectDelay;
142 PingDelay = model.PingDelay; 142 PingDelay = model.PingDelay;
143 } 143 }
144 144
145 // Read the configuration file, performing variable substitution and any 145 // Read the configuration file, performing variable substitution and any
146 // necessary aliasing. See accompanying documentation for how this works. 146 // necessary aliasing. See accompanying documentation for how this works.
147 // If you don't need variables, then this works exactly as before. 147 // If you don't need variables, then this works exactly as before.
@@ -160,54 +160,54 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
160 160
161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region); 161 m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region);
162 162
163 cs.Server = Substitute(rs, config.GetString("server", null)); 163 cs.Server = Substitute(rs, config.GetString("server", null));
164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server); 164 m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server);
165 cs.Password = Substitute(rs, config.GetString("password", null)); 165 cs.Password = Substitute(rs, config.GetString("password", null));
166 // probably not a good idea to put a password in the log file 166 // probably not a good idea to put a password in the log file
167 cs.User = Substitute(rs, config.GetString("user", null)); 167 cs.User = Substitute(rs, config.GetString("user", null));
168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null)); 168 cs.IrcChannel = Substitute(rs, config.GetString("channel", null));
169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel); 169 m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel);
170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port)))); 170 cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port))));
171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port); 171 m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port);
172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname)); 172 cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname));
173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname); 173 m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname);
174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname)))); 174 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname))));
175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 175 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname)))); 176 cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname))));
177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); 177 m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname);
178 cs.User = Substitute(rs, config.GetString("username", cs.User)); 178 cs.User = Substitute(rs, config.GetString("username", cs.User));
179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User); 179 m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User);
180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled)))); 180 cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled))));
181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled); 181 m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled);
182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel)))); 182 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel))));
183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 183 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel)))); 184 cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel))));
185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); 185 m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel);
186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat)))); 186 cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat))));
187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat); 187 m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat);
188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels)))); 188 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels))));
189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 189 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels)))); 190 cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); 191 m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels);
192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut)))); 192 cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut))));
193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut); 193 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut);
194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel)))); 194 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel))));
195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 195 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel)))); 196 cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel))));
197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); 197 m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel);
198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat)); 198 cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat));
199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat); 199 m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat);
200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat)); 200 cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat));
201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat); 201 m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat);
202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0; 202 cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting ? "1" : "0"))) > 0;
203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 203 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting)))); 204 cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting))));
205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); 205 m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone)); 206 cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone));
207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone); 207 m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone);
208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay)))); 208 cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay))));
209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay); 209 m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay);
210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay)))); 210 cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay))));
211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay); 211 m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay);
212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword)); 212 cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword); 213 m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
@@ -217,7 +217,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
217 { 217 {
218 cs.ExcludeList.Add(name.Trim().ToLower()); 218 cs.ExcludeList.Add(name.Trim().ToLower());
219 } 219 }
220 220
221 // Fail if fundamental information is still missing 221 // Fail if fundamental information is still missing
222 222
223 if (cs.Server == null) 223 if (cs.Server == null)
@@ -306,8 +306,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
306 306
307 IRCBridgeModule.m_channels.Add(cs); 307 IRCBridgeModule.m_channels.Add(cs);
308 308
309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", 309 m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}",
310 cs.idn, rs.Region, cs.DefaultZone, 310 cs.idn, rs.Region, cs.DefaultZone,
311 cs.CommandsEnabled ? "enabled" : "not enabled", 311 cs.CommandsEnabled ? "enabled" : "not enabled",
312 cs.RelayPrivateChannels ? "relayed" : "not relayed"); 312 cs.RelayPrivateChannels ? "relayed" : "not relayed");
313 } 313 }
@@ -417,7 +417,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
417 private bool IsAConnectionMatchFor(ChannelState cs) 417 private bool IsAConnectionMatchFor(ChannelState cs)
418 { 418 {
419 return ( 419 return (
420 Server == cs.Server && 420 Server == cs.Server &&
421 IrcChannel == cs.IrcChannel && 421 IrcChannel == cs.IrcChannel &&
422 Port == cs.Port && 422 Port == cs.Port &&
423 BaseNickname == cs.BaseNickname && 423 BaseNickname == cs.BaseNickname &&
@@ -461,7 +461,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
461 461
462 string result = instr; 462 string result = instr;
463 463
464 if (result == null || result.Length == 0) 464 if (string.IsNullOrEmpty(result))
465 return result; 465 return result;
466 466
467 // Repeatedly scan the string until all possible 467 // Repeatedly scan the string until all possible
@@ -473,27 +473,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
473 { 473 {
474 474
475 string vvar = arg.Match(result).ToString(); 475 string vvar = arg.Match(result).ToString();
476 string var = vvar.Substring(1,vvar.Length-2).Trim(); 476 string var = vvar.Substring(1, vvar.Length - 2).Trim();
477 477
478 switch (var.ToLower()) 478 switch (var.ToLower())
479 { 479 {
480 case "%region" : 480 case "%region":
481 result = result.Replace(vvar, rs.Region); 481 result = result.Replace(vvar, rs.Region);
482 break; 482 break;
483 case "%host" : 483 case "%host":
484 result = result.Replace(vvar, rs.Host); 484 result = result.Replace(vvar, rs.Host);
485 break; 485 break;
486 case "%locx" : 486 case "%locx":
487 result = result.Replace(vvar, rs.LocX); 487 result = result.Replace(vvar, rs.LocX);
488 break; 488 break;
489 case "%locy" : 489 case "%locy":
490 result = result.Replace(vvar, rs.LocY); 490 result = result.Replace(vvar, rs.LocY);
491 break; 491 break;
492 case "%k" : 492 case "%k":
493 result = result.Replace(vvar, rs.IDK); 493 result = result.Replace(vvar, rs.IDK);
494 break; 494 break;
495 default : 495 default:
496 result = result.Replace(vvar, rs.config.GetString(var,var)); 496 result = result.Replace(vvar, rs.config.GetString(var, var));
497 break; 497 break;
498 } 498 }
499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result); 499 // m_log.DebugFormat("[IRC-Channel] Parse[2]: {0}", result);
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
index 2e1d03d..351dbfe 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCBridgeModule.cs
@@ -46,18 +46,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 internal static bool m_pluginEnabled = false; 49 internal static bool Enabled = false;
50 internal static IConfig m_config = null; 50 internal static IConfig m_config = null;
51 51
52 internal static List<ChannelState> m_channels = new List<ChannelState>(); 52 internal static List<ChannelState> m_channels = new List<ChannelState>();
53 internal static List<RegionState> m_regions = new List<RegionState>(); 53 internal static List<RegionState> m_regions = new List<RegionState>();
54 54
55 internal static string m_password = String.Empty; 55 internal static string m_password = String.Empty;
56 internal RegionState m_region = null; 56 internal RegionState m_region = null;
57 57
58 #region INonSharedRegionModule Members 58 #region INonSharedRegionModule Members
59 59
60 public Type ReplaceableInterface 60 public Type ReplaceableInterface
61 { 61 {
62 get { return null; } 62 get { return null; }
63 } 63 }
@@ -72,13 +72,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
72 m_config = config.Configs["IRC"]; 72 m_config = config.Configs["IRC"];
73 if (m_config == null) 73 if (m_config == null)
74 { 74 {
75// m_log.InfoFormat("[IRC-Bridge] module not configured"); 75 // m_log.InfoFormat("[IRC-Bridge] module not configured");
76 return; 76 return;
77 } 77 }
78 78
79 if (!m_config.GetBoolean("enabled", false)) 79 if (!m_config.GetBoolean("enabled", false))
80 { 80 {
81// m_log.InfoFormat("[IRC-Bridge] module disabled in configuration"); 81 // m_log.InfoFormat("[IRC-Bridge] module disabled in configuration");
82 return; 82 return;
83 } 83 }
84 84
@@ -87,19 +87,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password); 87 m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password);
88 } 88 }
89 89
90 m_pluginEnabled = true; 90 Enabled = true;
91 m_log.InfoFormat("[IRC-Bridge]: Module enabled"); 91
92 m_log.InfoFormat("[IRC-Bridge]: Module is enabled");
92 } 93 }
93 94
94 public void AddRegion(Scene scene) 95 public void AddRegion(Scene scene)
95 { 96 {
96 if (m_pluginEnabled) 97 if (Enabled)
97 { 98 {
98 try 99 try
99 { 100 {
100 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName); 101 m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName);
102
101 if (!String.IsNullOrEmpty(m_password)) 103 if (!String.IsNullOrEmpty(m_password))
102 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false); 104 MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false);
105
103 m_region = new RegionState(scene, m_config); 106 m_region = new RegionState(scene, m_config);
104 lock (m_regions) m_regions.Add(m_region); 107 lock (m_regions) m_regions.Add(m_region);
105 m_region.Open(); 108 m_region.Open();
@@ -123,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
123 126
124 public void RemoveRegion(Scene scene) 127 public void RemoveRegion(Scene scene)
125 { 128 {
126 if (!m_pluginEnabled) 129 if (!Enabled)
127 return; 130 return;
128 131
129 if (m_region == null) 132 if (m_region == null)
@@ -150,12 +153,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
150 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry"); 153 m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry");
151 154
152 XmlRpcResponse response = new XmlRpcResponse(); 155 XmlRpcResponse response = new XmlRpcResponse();
153 Hashtable responseData = new Hashtable(); 156 Hashtable responseData = new Hashtable();
154 157
155 try 158 try
156 { 159 {
157 Hashtable requestData = (Hashtable)request.Params[0]; 160 Hashtable requestData = (Hashtable)request.Params[0];
158 bool found = false; 161 bool found = false;
159 string region = String.Empty; 162 string region = String.Empty;
160 163
161 if (m_password != String.Empty) 164 if (m_password != String.Empty)
@@ -169,18 +172,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
169 if (!requestData.ContainsKey("region")) 172 if (!requestData.ContainsKey("region"))
170 throw new Exception("No region name specified"); 173 throw new Exception("No region name specified");
171 region = (string)requestData["region"]; 174 region = (string)requestData["region"];
172 175
173 foreach (RegionState rs in m_regions) 176 foreach (RegionState rs in m_regions)
174 { 177 {
175 if (rs.Region == region) 178 if (rs.Region == region)
176 { 179 {
177 responseData["server"] = rs.cs.Server; 180 responseData["server"] = rs.cs.Server;
178 responseData["port"] = (int)rs.cs.Port; 181 responseData["port"] = (int)rs.cs.Port;
179 responseData["user"] = rs.cs.User; 182 responseData["user"] = rs.cs.User;
180 responseData["channel"] = rs.cs.IrcChannel; 183 responseData["channel"] = rs.cs.IrcChannel;
181 responseData["enabled"] = rs.cs.irc.Enabled; 184 responseData["enabled"] = rs.cs.irc.Enabled;
182 responseData["connected"] = rs.cs.irc.Connected; 185 responseData["connected"] = rs.cs.irc.Connected;
183 responseData["nickname"] = rs.cs.irc.Nick; 186 responseData["nickname"] = rs.cs.irc.Nick;
184 found = true; 187 found = true;
185 break; 188 break;
186 } 189 }
@@ -195,7 +198,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message); 198 m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message);
196 199
197 responseData["success"] = "false"; 200 responseData["success"] = "false";
198 responseData["error"] = e.Message; 201 responseData["error"] = e.Message;
199 } 202 }
200 finally 203 finally
201 { 204 {
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
index a014798..6985371 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -52,17 +52,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
52 52
53 // Local constants 53 // Local constants
54 54
55 // This computation is not the real region center if the region is larger than 256.
56 // This computation isn't fixed because there is not a handle back to the region.
55 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 57 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
56 private static readonly char[] CS_SPACE = { ' ' }; 58 private static readonly char[] CS_SPACE = { ' ' };
57 59
58 private const int WD_INTERVAL = 1000; // base watchdog interval 60 private const int WD_INTERVAL = 1000; // base watchdog interval
59 private static int PING_PERIOD = 15; // WD intervals per PING 61 private static int PING_PERIOD = 15; // WD intervals per PING
60 private static int ICCD_PERIOD = 10; // WD intervals between Connects 62 private static int ICCD_PERIOD = 10; // WD intervals between Connects
61 private static int L_TIMEOUT = 25; // Login time out interval 63 private static int L_TIMEOUT = 25; // Login time out interval
62 64
63 private static int _idk_ = 0; // core connector identifier 65 private static int _idk_ = 0; // core connector identifier
64 private static int _pdk_ = 0; // ping interval counter 66 private static int _pdk_ = 0; // ping interval counter
65 private static int _icc_ = ICCD_PERIOD; // IRC connect counter 67 private static int _icc_ = ICCD_PERIOD; // IRC connect counter
66 68
67 // List of configured connectors 69 // List of configured connectors
68 70
@@ -107,13 +109,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
107 109
108 internal int m_resetk = 0; 110 internal int m_resetk = 0;
109 111
110 // Working threads
111
112 private Thread m_listener = null;
113
114 private Object msyncConnect = new Object(); 112 private Object msyncConnect = new Object();
115 113
116 internal bool m_randomizeNick = true; // add random suffix 114 internal bool m_randomizeNick = true; // add random suffix
117 internal string m_baseNick = null; // base name for randomizing 115 internal string m_baseNick = null; // base name for randomizing
118 internal string m_nick = null; // effective nickname 116 internal string m_nick = null; // effective nickname
119 117
@@ -122,7 +120,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
122 get { return m_nick; } 120 get { return m_nick; }
123 set { m_nick = value; } 121 set { m_nick = value; }
124 } 122 }
125 123
126 private bool m_enabled = false; // connector enablement 124 private bool m_enabled = false; // connector enablement
127 public bool Enabled 125 public bool Enabled
128 { 126 {
@@ -130,8 +128,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
130 } 128 }
131 129
132 private bool m_connected = false; // connection status 130 private bool m_connected = false; // connection status
133 private bool m_pending = false; // login disposition 131 private bool m_pending = false; // login disposition
134 private int m_timeout = L_TIMEOUT; // login timeout counter 132 private int m_timeout = L_TIMEOUT; // login timeout counter
135 public bool Connected 133 public bool Connected
136 { 134 {
137 get { return m_connected; } 135 get { return m_connected; }
@@ -143,9 +141,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
143 get { return m_ircChannel; } 141 get { return m_ircChannel; }
144 set { m_ircChannel = value; } 142 set { m_ircChannel = value; }
145 } 143 }
146 144
147 private uint m_port = 6667; // session port 145 private uint m_port = 6667; // session port
148 public uint Port 146 public uint Port
149 { 147 {
150 get { return m_port; } 148 get { return m_port; }
151 set { m_port = value; } 149 set { m_port = value; }
@@ -172,10 +170,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
172 170
173 // Network interface 171 // Network interface
174 172
175 private TcpClient m_tcp; 173 private TcpClient m_tcp;
176 private NetworkStream m_stream = null; 174 private NetworkStream m_stream = null;
177 private StreamReader m_reader; 175 private StreamReader m_reader;
178 private StreamWriter m_writer; 176 private StreamWriter m_writer;
179 177
180 // Channel characteristic info (if available) 178 // Channel characteristic info (if available)
181 179
@@ -193,26 +191,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
193 191
194 // Prepare network interface 192 // Prepare network interface
195 193
196 m_tcp = null; 194 m_tcp = null;
197 m_writer = null; 195 m_writer = null;
198 m_reader = null; 196 m_reader = null;
199 197
200 // Setup IRC session parameters 198 // Setup IRC session parameters
201 199
202 m_server = cs.Server; 200 m_server = cs.Server;
203 m_password = cs.Password; 201 m_password = cs.Password;
204 m_baseNick = cs.BaseNickname; 202 m_baseNick = cs.BaseNickname;
205 m_randomizeNick = cs.RandomizeNickname; 203 m_randomizeNick = cs.RandomizeNickname;
206 m_ircChannel = cs.IrcChannel; 204 m_ircChannel = cs.IrcChannel;
207 m_port = cs.Port; 205 m_port = cs.Port;
208 m_user = cs.User; 206 m_user = cs.User;
209 207
210 if (m_watchdog == null) 208 if (m_watchdog == null)
211 { 209 {
212 // Non-differentiating 210 // Non-differentiating
213 211
214 ICCD_PERIOD = cs.ConnectDelay; 212 ICCD_PERIOD = cs.ConnectDelay;
215 PING_PERIOD = cs.PingDelay; 213 PING_PERIOD = cs.PingDelay;
216 214
217 // Smaller values are not reasonable 215 // Smaller values are not reasonable
218 216
@@ -235,7 +233,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
235 233
236 if (m_randomizeNick) 234 if (m_randomizeNick)
237 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 235 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
238 else 236 else
239 m_nick = m_baseNick; 237 m_nick = m_baseNick;
240 238
241 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); 239 m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn);
@@ -295,18 +293,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
295 m_nick, m_ircChannel, m_server)); 293 m_nick, m_ircChannel, m_server));
296 m_writer.Flush(); 294 m_writer.Flush();
297 } 295 }
298 catch (Exception) {} 296 catch (Exception) { }
299 297
300 298
301 m_connected = false; 299 m_connected = false;
302 300
303 try { m_writer.Close(); } catch (Exception) {} 301 try { m_writer.Close(); }
304 try { m_reader.Close(); } catch (Exception) {} 302 catch (Exception) { }
305 try { m_stream.Close(); } catch (Exception) {} 303 try { m_reader.Close(); }
306 try { m_tcp.Close(); } catch (Exception) {} 304 catch (Exception) { }
305 try { m_stream.Close(); }
306 catch (Exception) { }
307 try { m_tcp.Close(); }
308 catch (Exception) { }
307 309
308 } 310 }
309 311
310 lock (m_connectors) 312 lock (m_connectors)
311 m_connectors.Remove(this); 313 m_connectors.Remove(this);
312 314
@@ -347,20 +349,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
347 if (m_connected) return; 349 if (m_connected) return;
348 350
349 m_connected = true; 351 m_connected = true;
350 m_pending = true; 352 m_pending = true;
351 m_timeout = L_TIMEOUT; 353 m_timeout = L_TIMEOUT;
352 354
353 m_tcp = new TcpClient(m_server, (int)m_port); 355 m_tcp = new TcpClient(m_server, (int)m_port);
354 m_stream = m_tcp.GetStream(); 356 m_stream = m_tcp.GetStream();
355 m_reader = new StreamReader(m_stream); 357 m_reader = new StreamReader(m_stream);
356 m_writer = new StreamWriter(m_stream); 358 m_writer = new StreamWriter(m_stream);
357 359
358 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); 360 m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port);
359 361
360 m_listener = new Thread(new ThreadStart(ListenerRun)); 362 WorkManager.StartThread(ListenerRun, "IRCConnectionListenerThread", ThreadPriority.Normal, true, false);
361 m_listener.Name = "IRCConnectorListenerThread";
362 m_listener.IsBackground = true;
363 m_listener.Start();
364 363
365 // This is the message order recommended by RFC 2812 364 // This is the message order recommended by RFC 2812
366 if (m_password != null) 365 if (m_password != null)
@@ -418,12 +417,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
418 // the socket and it will disappear of its own accord, once this 417 // the socket and it will disappear of its own accord, once this
419 // processing is completed. 418 // processing is completed.
420 419
421 try { m_writer.Close(); } catch (Exception) {} 420 try { m_writer.Close(); }
422 try { m_reader.Close(); } catch (Exception) {} 421 catch (Exception) { }
423 try { m_tcp.Close(); } catch (Exception) {} 422 try { m_reader.Close(); }
423 catch (Exception) { }
424 try { m_tcp.Close(); }
425 catch (Exception) { }
424 426
425 m_connected = false; 427 m_connected = false;
426 m_pending = false; 428 m_pending = false;
427 m_resetk++; 429 m_resetk++;
428 430
429 } 431 }
@@ -495,27 +497,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
495 { 497 {
496 498
497 string inputLine; 499 string inputLine;
498 int resetk = m_resetk; 500 int resetk = m_resetk;
499 501
500 try 502 try
501 { 503 {
502 while (m_enabled && m_connected) 504 while (m_enabled && m_connected)
503 { 505 {
504
505 if ((inputLine = m_reader.ReadLine()) == null) 506 if ((inputLine = m_reader.ReadLine()) == null)
506 throw new Exception("Listener input socket closed"); 507 throw new Exception("Listener input socket closed");
507 508
509 Watchdog.UpdateThread();
510
508 // m_log.Info("[IRCConnector]: " + inputLine); 511 // m_log.Info("[IRCConnector]: " + inputLine);
509 512
510 if (inputLine.Contains("PRIVMSG")) 513 if (inputLine.Contains("PRIVMSG"))
511 { 514 {
512
513 Dictionary<string, string> data = ExtractMsg(inputLine); 515 Dictionary<string, string> data = ExtractMsg(inputLine);
514 516
515 // Any chat ??? 517 // Any chat ???
516 if (data != null) 518 if (data != null)
517 { 519 {
518
519 OSChatMessage c = new OSChatMessage(); 520 OSChatMessage c = new OSChatMessage();
520 c.Message = data["msg"]; 521 c.Message = data["msg"];
521 c.Type = ChatTypeEnum.Region; 522 c.Type = ChatTypeEnum.Region;
@@ -531,9 +532,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
531 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9)); 532 c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9));
532 533
533 ChannelState.OSChat(this, c, false); 534 ChannelState.OSChat(this, c, false);
534
535 } 535 }
536
537 } 536 }
538 else 537 else
539 { 538 {
@@ -553,9 +552,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
553 552
554 if (m_enabled && (m_resetk == resetk)) 553 if (m_enabled && (m_resetk == resetk))
555 Reconnect(); 554 Reconnect();
555
556 Watchdog.RemoveThread();
556 } 557 }
557 558
558 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)", 559 private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
559 RegexOptions.Multiline); 560 RegexOptions.Multiline);
560 561
561 private Dictionary<string, string> ExtractMsg(string input) 562 private Dictionary<string, string> ExtractMsg(string input)
@@ -617,8 +618,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
617 string[] commArgs; 618 string[] commArgs;
618 string c_server = m_server; 619 string c_server = m_server;
619 620
620 string pfx = String.Empty; 621 string pfx = String.Empty;
621 string cmd = String.Empty; 622 string cmd = String.Empty;
622 string parms = String.Empty; 623 string parms = String.Empty;
623 624
624 // ":" indicates that a prefix is present 625 // ":" indicates that a prefix is present
@@ -627,15 +628,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
627 // ":" indicates that the remainder of the 628 // ":" indicates that the remainder of the
628 // line is a single parameter value. 629 // line is a single parameter value.
629 630
630 commArgs = command.Split(CS_SPACE,2); 631 commArgs = command.Split(CS_SPACE, 2);
631 632
632 if (commArgs[0].StartsWith(":")) 633 if (commArgs[0].StartsWith(":"))
633 { 634 {
634 pfx = commArgs[0].Substring(1); 635 pfx = commArgs[0].Substring(1);
635 commArgs = commArgs[1].Split(CS_SPACE,2); 636 commArgs = commArgs[1].Split(CS_SPACE, 2);
636 } 637 }
637 638
638 cmd = commArgs[0]; 639 cmd = commArgs[0];
639 parms = commArgs[1]; 640 parms = commArgs[1];
640 641
641 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd); 642 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd);
@@ -646,44 +647,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
646 // Messages 001-004 are always sent 647 // Messages 001-004 are always sent
647 // following signon. 648 // following signon.
648 649
649 case "001" : // Welcome ... 650 case "001": // Welcome ...
650 case "002" : // Server information 651 case "002": // Server information
651 case "003" : // Welcome ... 652 case "003": // Welcome ...
652 break; 653 break;
653 case "004" : // Server information 654 case "004": // Server information
654 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 655 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
655 commArgs = parms.Split(CS_SPACE); 656 commArgs = parms.Split(CS_SPACE);
656 c_server = commArgs[1]; 657 c_server = commArgs[1];
657 m_server = c_server; 658 m_server = c_server;
658 version = commArgs[2]; 659 version = commArgs[2];
659 usermod = commArgs[3]; 660 usermod = commArgs[3];
660 chanmod = commArgs[4]; 661 chanmod = commArgs[4];
661 break; 662 break;
662 case "005" : // Server information 663 case "005": // Server information
663 break; 664 break;
664 case "042" : 665 case "042":
665 case "250" : 666 case "250":
666 case "251" : 667 case "251":
667 case "252" : 668 case "252":
668 case "254" : 669 case "254":
669 case "255" : 670 case "255":
670 case "265" : 671 case "265":
671 case "266" : 672 case "266":
672 case "332" : // Subject 673 case "332": // Subject
673 case "333" : // Subject owner (?) 674 case "333": // Subject owner (?)
674 case "353" : // Name list 675 case "353": // Name list
675 case "366" : // End-of-Name list marker 676 case "366": // End-of-Name list marker
676 case "372" : // MOTD body 677 case "372": // MOTD body
677 case "375" : // MOTD start 678 case "375": // MOTD start
678 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 679 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
679 break; 680 break;
680 case "376" : // MOTD end 681 case "376": // MOTD end
681 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 682 // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
682 motd = true; 683 motd = true;
683 break; 684 break;
684 case "451" : // Not registered 685 case "451": // Not registered
685 break; 686 break;
686 case "433" : // Nickname in use 687 case "433": // Nickname in use
687 // Gen a new name 688 // Gen a new name
688 m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 689 m_nick = m_baseNick + Util.RandomClass.Next(1, 99);
689 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick); 690 m_log.ErrorFormat("[IRC-Connector-{0}]: [{1}] IRC SERVER reports NicknameInUse, trying {2}", idn, cmd, m_nick);
@@ -695,29 +696,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
695 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); 696 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel));
696 m_writer.Flush(); 697 m_writer.Flush();
697 break; 698 break;
698 case "479" : // Bad channel name, etc. This will never work, so disable the connection 699 case "479": // Bad channel name, etc. This will never work, so disable the connection
699 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 700 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
700 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd); 701 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd);
701 m_enabled = false; 702 m_enabled = false;
702 m_connected = false; 703 m_connected = false;
703 m_pending = false; 704 m_pending = false;
704 break; 705 break;
705 case "NOTICE" : 706 case "NOTICE":
706 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 707 // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]);
707 break; 708 break;
708 case "ERROR" : 709 case "ERROR":
709 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); 710 m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]);
710 if (parms.Contains("reconnect too fast")) 711 if (parms.Contains("reconnect too fast"))
711 ICCD_PERIOD++; 712 ICCD_PERIOD++;
712 m_pending = false; 713 m_pending = false;
713 Reconnect(); 714 Reconnect();
714 break; 715 break;
715 case "PING" : 716 case "PING":
716 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 717 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
717 m_writer.WriteLine(String.Format("PONG {0}", parms)); 718 m_writer.WriteLine(String.Format("PONG {0}", parms));
718 m_writer.Flush(); 719 m_writer.Flush();
719 break; 720 break;
720 case "PONG" : 721 case "PONG":
721 break; 722 break;
722 case "JOIN": 723 case "JOIN":
723 if (m_pending) 724 if (m_pending)
@@ -748,19 +749,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
748 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); 749 m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms);
749 eventIrcQuit(pfx, cmd, parms); 750 eventIrcQuit(pfx, cmd, parms);
750 break; 751 break;
751 default : 752 default:
752 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms); 753 m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms);
753 break; 754 break;
754 } 755 }
755 756
756 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd); 757 // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd);
757 758
758 } 759 }
759 760
760 public void eventIrcJoin(string prefix, string command, string parms) 761 public void eventIrcJoin(string prefix, string command, string parms)
761 { 762 {
762 string[] args = parms.Split(CS_SPACE,2); 763 string[] args = parms.Split(CS_SPACE, 2);
763 string IrcUser = prefix.Split('!')[0]; 764 string IrcUser = prefix.Split('!')[0];
764 string IrcChannel = args[0]; 765 string IrcChannel = args[0];
765 766
766 if (IrcChannel.StartsWith(":")) 767 if (IrcChannel.StartsWith(":"))
@@ -772,8 +773,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
772 773
773 public void eventIrcPart(string prefix, string command, string parms) 774 public void eventIrcPart(string prefix, string command, string parms)
774 { 775 {
775 string[] args = parms.Split(CS_SPACE,2); 776 string[] args = parms.Split(CS_SPACE, 2);
776 string IrcUser = prefix.Split('!')[0]; 777 string IrcUser = prefix.Split('!')[0];
777 string IrcChannel = args[0]; 778 string IrcChannel = args[0];
778 779
779 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel); 780 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCPart {1}:{2}", idn, m_server, m_ircChannel);
@@ -782,7 +783,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
782 783
783 public void eventIrcMode(string prefix, string command, string parms) 784 public void eventIrcMode(string prefix, string command, string parms)
784 { 785 {
785 string[] args = parms.Split(CS_SPACE,2); 786 string[] args = parms.Split(CS_SPACE, 2);
786 string UserMode = args[1]; 787 string UserMode = args[1];
787 788
788 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel); 789 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCMode {1}:{2}", idn, m_server, m_ircChannel);
@@ -794,7 +795,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
794 795
795 public void eventIrcNickChange(string prefix, string command, string parms) 796 public void eventIrcNickChange(string prefix, string command, string parms)
796 { 797 {
797 string[] args = parms.Split(CS_SPACE,2); 798 string[] args = parms.Split(CS_SPACE, 2);
798 string UserOldNick = prefix.Split('!')[0]; 799 string UserOldNick = prefix.Split('!')[0];
799 string UserNewNick = args[0].Remove(0, 1); 800 string UserNewNick = args[0].Remove(0, 1);
800 801
@@ -804,11 +805,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
804 805
805 public void eventIrcKick(string prefix, string command, string parms) 806 public void eventIrcKick(string prefix, string command, string parms)
806 { 807 {
807 string[] args = parms.Split(CS_SPACE,3); 808 string[] args = parms.Split(CS_SPACE, 3);
808 string UserKicker = prefix.Split('!')[0]; 809 string UserKicker = prefix.Split('!')[0];
809 string IrcChannel = args[0]; 810 string IrcChannel = args[0];
810 string UserKicked = args[1]; 811 string UserKicked = args[1];
811 string KickMessage = args[2]; 812 string KickMessage = args[2];
812 813
813 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel); 814 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel);
814 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); 815 BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage);
@@ -822,7 +823,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
822 823
823 public void eventIrcQuit(string prefix, string command, string parms) 824 public void eventIrcQuit(string prefix, string command, string parms)
824 { 825 {
825 string IrcUser = prefix.Split('!')[0]; 826 string IrcUser = prefix.Split('!')[0];
826 string QuitMessage = parms; 827 string QuitMessage = parms;
827 828
828 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel); 829 m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCQuit {1}:{2}", idn, m_server, m_ircChannel);
@@ -842,65 +843,65 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
842 843
843 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_); 844 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_);
844 845
845 _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger 846 _pdk_ = (_pdk_ + 1) % PING_PERIOD; // cycle the ping trigger
846 _icc_++; // increment the inter-consecutive-connect-delay counter 847 _icc_++; // increment the inter-consecutive-connect-delay counter
847 848
848 lock (m_connectors) 849 lock (m_connectors)
849 foreach (IRCConnector connector in m_connectors) 850 foreach (IRCConnector connector in m_connectors)
850 { 851 {
851 852
852 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); 853 // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector);
853 854
854 if (connector.Enabled) 855 if (connector.Enabled)
855 {
856 if (!connector.Connected)
857 { 856 {
858 try 857 if (!connector.Connected)
859 { 858 {
860 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); 859 try
861 connector.Connect(); 860 {
861 // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel);
862 connector.Connect();
863 }
864 catch (Exception e)
865 {
866 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
867 }
862 } 868 }
863 catch (Exception e) 869 else
864 { 870 {
865 m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message);
866 }
867 }
868 else
869 {
870 871
871 if (connector.m_pending) 872 if (connector.m_pending)
872 {
873 if (connector.m_timeout == 0)
874 { 873 {
875 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); 874 if (connector.m_timeout == 0)
876 connector.Reconnect(); 875 {
876 m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn);
877 connector.Reconnect();
878 }
879 else
880 connector.m_timeout--;
877 } 881 }
878 else
879 connector.m_timeout--;
880 }
881 882
882 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long 883 // Being marked connected is not enough to ping. Socket establishment can sometimes take a long
883 // time, in which case the watch dog might try to ping the server before the socket has been 884 // time, in which case the watch dog might try to ping the server before the socket has been
884 // set up, with nasty side-effects. 885 // set up, with nasty side-effects.
885 886
886 else if (_pdk_ == 0) 887 else if (_pdk_ == 0)
887 {
888 try
889 {
890 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
891 connector.m_writer.Flush();
892 }
893 catch (Exception e)
894 { 888 {
895 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); 889 try
896 m_log.Debug(e); 890 {
897 connector.Reconnect(); 891 connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server));
892 connector.m_writer.Flush();
893 }
894 catch (Exception e)
895 {
896 m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message);
897 m_log.Debug(e);
898 connector.Reconnect();
899 }
898 } 900 }
899 }
900 901
902 }
901 } 903 }
902 } 904 }
903 }
904 905
905 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed"); 906 // m_log.InfoFormat("[IRC-Watchdog] Status scan completed");
906 907
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
index 53b103e..5505001 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
@@ -41,49 +41,73 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
41 41
42 internal class RegionState 42 internal class RegionState
43 { 43 {
44
45 private static readonly ILog m_log = 44 private static readonly ILog m_log =
46 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 46
47 // This computation is not the real region center if the region is larger than 256.
48 // This computation isn't fixed because there is not a handle back to the region.
48 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 49 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
49 private const int DEBUG_CHANNEL = 2147483647; 50 private const int DEBUG_CHANNEL = 2147483647;
50 51
51 private static int _idk_ = 0; 52 private static int _idk_ = 0;
52 53
53 // Runtime variables; these values are assigned when the 54 // Runtime variables; these values are assigned when the
54 // IrcState is created and remain constant thereafter. 55 // IrcState is created and remain constant thereafter.
55 56
56 internal string Region = String.Empty; 57 internal string Region = String.Empty;
57 internal string Host = String.Empty; 58 internal string Host = String.Empty;
58 internal string LocX = String.Empty; 59 internal string LocX = String.Empty;
59 internal string LocY = String.Empty; 60 internal string LocY = String.Empty;
60 internal string IDK = String.Empty; 61 internal string IDK = String.Empty;
61 62
62 // System values - used only be the IRC classes themselves 63 // System values - used only be the IRC classes themselves
63 64
64 internal ChannelState cs = null; // associated IRC configuration 65 internal ChannelState cs = null; // associated IRC configuration
65 internal Scene scene = null; // associated scene 66 internal Scene scene = null; // associated scene
66 internal IConfig config = null; // configuration file reference 67 internal IConfig config = null; // configuration file reference
67 internal bool enabled = true; 68 internal bool enabled = true;
68 69
70 //AgentAlert
71 internal bool showAlert = false;
72 internal string alertMessage = String.Empty;
73 internal IDialogModule dialogModule = null;
74
69 // This list is used to keep track of who is here, and by 75 // This list is used to keep track of who is here, and by
70 // implication, who is not. 76 // implication, who is not.
71 77
72 internal List<IClientAPI> clients = new List<IClientAPI>(); 78 internal List<IClientAPI> clients = new List<IClientAPI>();
73 79
74 // Setup runtime variable values 80 // Setup runtime variable values
75 81
76 public RegionState(Scene p_scene, IConfig p_config) 82 public RegionState(Scene p_scene, IConfig p_config)
77 { 83 {
78 84 scene = p_scene;
79 scene = p_scene;
80 config = p_config; 85 config = p_config;
81 86
82 Region = scene.RegionInfo.RegionName; 87 Region = scene.RegionInfo.RegionName;
83 Host = scene.RegionInfo.ExternalHostName; 88 Host = scene.RegionInfo.ExternalHostName;
84 LocX = Convert.ToString(scene.RegionInfo.RegionLocX); 89 LocX = Convert.ToString(scene.RegionInfo.RegionLocX);
85 LocY = Convert.ToString(scene.RegionInfo.RegionLocY); 90 LocY = Convert.ToString(scene.RegionInfo.RegionLocY);
86 IDK = Convert.ToString(_idk_++); 91 IDK = Convert.ToString(_idk_++);
92
93 showAlert = config.GetBoolean("alert_show", false);
94 string alertServerInfo = String.Empty;
95
96 if (showAlert)
97 {
98 bool showAlertServerInfo = config.GetBoolean("alert_show_serverinfo", true);
99
100 if (showAlertServerInfo)
101 alertServerInfo = String.Format("\nServer: {0}\nPort: {1}\nChannel: {2}\n\n",
102 config.GetString("server", ""), config.GetString("port", ""), config.GetString("channel", ""));
103
104 string alertPreMessage = config.GetString("alert_msg_pre", "This region is linked to Irc.");
105 string alertPostMessage = config.GetString("alert_msg_post", "Everything you say in public chat can be listened.");
106
107 alertMessage = String.Format("{0}\n{1}{2}", alertPreMessage, alertServerInfo, alertPostMessage);
108
109 dialogModule = scene.RequestModuleInterface<IDialogModule>();
110 }
87 111
88 // OpenChannel conditionally establishes a connection to the 112 // OpenChannel conditionally establishes a connection to the
89 // IRC server. The request will either succeed, or it will 113 // IRC server. The request will either succeed, or it will
@@ -93,9 +117,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
93 117
94 // Connect channel to world events 118 // Connect channel to world events
95 119
96 scene.EventManager.OnChatFromWorld += OnSimChat; 120 scene.EventManager.OnChatFromWorld += OnSimChat;
97 scene.EventManager.OnChatFromClient += OnSimChat; 121 scene.EventManager.OnChatFromClient += OnSimChat;
98 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; 122 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
99 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; 123 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
100 124
101 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region); 125 m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region);
@@ -106,8 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
106 130
107 ~RegionState() 131 ~RegionState()
108 { 132 {
109 if (cs != null) 133 if (cs != null)
110 cs.RemoveRegion(this); 134 cs.RemoveRegion(this);
111 } 135 }
112 136
113 // Called by PostInitialize after all regions have been created 137 // Called by PostInitialize after all regions have been created
@@ -138,7 +162,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
138 { 162 {
139 if (clients.Contains(client)) 163 if (clients.Contains(client))
140 { 164 {
141 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 165 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
142 { 166 {
143 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name); 167 m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name);
144 //Check if this person is excluded from IRC 168 //Check if this person is excluded from IRC
@@ -147,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
147 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name)); 171 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name));
148 } 172 }
149 } 173 }
150 client.OnLogout -= OnClientLoggedOut; 174 client.OnLogout -= OnClientLoggedOut;
151 client.OnConnectionClosed -= OnClientLoggedOut; 175 client.OnConnectionClosed -= OnClientLoggedOut;
152 clients.Remove(client); 176 clients.Remove(client);
153 } 177 }
@@ -171,13 +195,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
171 { 195 {
172 if (clients.Contains(client)) 196 if (clients.Contains(client))
173 { 197 {
174 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 198 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
175 { 199 {
176 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); 200 string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname);
177 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName); 201 m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName);
178 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName)); 202 cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName));
179 } 203 }
180 client.OnLogout -= OnClientLoggedOut; 204 client.OnLogout -= OnClientLoggedOut;
181 client.OnConnectionClosed -= OnClientLoggedOut; 205 client.OnConnectionClosed -= OnClientLoggedOut;
182 clients.Remove(client); 206 clients.Remove(client);
183 } 207 }
@@ -195,14 +219,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
195 219
196 private void OnMakeRootAgent(ScenePresence presence) 220 private void OnMakeRootAgent(ScenePresence presence)
197 { 221 {
198
199 IClientAPI client = presence.ControllingClient; 222 IClientAPI client = presence.ControllingClient;
200 223
201 try 224 try
202 { 225 {
203 if (!clients.Contains(client)) 226 if (!clients.Contains(client))
204 { 227 {
205 client.OnLogout += OnClientLoggedOut; 228 client.OnLogout += OnClientLoggedOut;
206 client.OnConnectionClosed += OnClientLoggedOut; 229 client.OnConnectionClosed += OnClientLoggedOut;
207 clients.Add(client); 230 clients.Add(client);
208 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) 231 if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting))
@@ -216,17 +239,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
216 } 239 }
217 } 240 }
218 } 241 }
242
243 if (dialogModule != null && showAlert)
244 dialogModule.SendAlertToUser(client, alertMessage, true);
219 } 245 }
220 catch (Exception ex) 246 catch (Exception ex)
221 { 247 {
222 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message); 248 m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message);
223 m_log.Debug(ex); 249 m_log.Debug(ex);
224 } 250 }
225
226 } 251 }
227 252
228 // This handler detects chat events int he virtual world. 253 // This handler detects chat events int he virtual world.
229
230 public void OnSimChat(Object sender, OSChatMessage msg) 254 public void OnSimChat(Object sender, OSChatMessage msg)
231 { 255 {
232 256
@@ -317,14 +341,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
317 // that evident. 341 // that evident.
318 342
319 default: 343 default:
320 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", 344 m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}",
321 Region, msg.Message); 345 Region, msg.Message);
322 cs.irc.Send(msg.Message); 346 cs.irc.Send(msg.Message);
323 break; 347 break;
324 } 348 }
325 } 349 }
326 catch (Exception ex) 350 catch (Exception ex)
327 { 351 {
328 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}", 352 m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}",
329 Region, ex.Message); 353 Region, ex.Message);
330 m_log.Debug(ex); 354 m_log.Debug(ex);
@@ -366,7 +390,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
366 390
367 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message); 391 m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
368 392
369 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) 393 if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
370 { 394 {
371 string txt = msg.Message; 395 string txt = msg.Message;
372 if (txt.StartsWith("/me ")) 396 if (txt.StartsWith("/me "))
@@ -376,13 +400,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
376 return; 400 return;
377 } 401 }
378 402
379 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && 403 if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
380 msg.Channel == cs.RelayChannelOut) 404 msg.Channel == cs.RelayChannelOut)
381 { 405 {
382 Match m = cs.AccessPasswordRegex.Match(msg.Message); 406 Match m = cs.AccessPasswordRegex.Match(msg.Message);
383 if (null != m) 407 if (null != m)
384 { 408 {
385 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), 409 m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
386 m.Groups["message"].ToString()); 410 m.Groups["message"].ToString());
387 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(), 411 cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
388 scene.RegionInfo.RegionName, m.Groups["message"].ToString()); 412 scene.RegionInfo.RegionName, m.Groups["message"].ToString());
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
index 018357a..c48e585 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
@@ -375,11 +375,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge
375 scene.GetRootAgentCount(), scene.RegionInfo.RegionName, 375 scene.GetRootAgentCount(), scene.RegionInfo.RegionName,
376 scene.RegionInfo.RegionID, 376 scene.RegionInfo.RegionID,
377 DateTime.UtcNow.ToString("s"))); 377 DateTime.UtcNow.ToString("s")));
378
378 scene.ForEachRootScenePresence(delegate(ScenePresence sp) 379 scene.ForEachRootScenePresence(delegate(ScenePresence sp)
379 { 380 {
380 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID)); 381 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID));
381 list.Append("</avatars>");
382 }); 382 });
383
384 list.Append("</avatars>");
383 string payload = list.ToString(); 385 string payload = list.ToString();
384 386
385 // post via REST to broker 387 // post via REST to broker
diff --git a/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs
new file mode 100644
index 0000000..5a6b284
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs
@@ -0,0 +1,220 @@
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33using System.Text.RegularExpressions;
34using log4net;
35using Mono.Addins;
36using NDesk.Options;
37using Nini.Config;
38using OpenMetaverse;
39using OpenSim.Framework;
40using OpenSim.Framework.Console;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43
44namespace OpenSim.Region.OptionalModules.Avatar.SitStand
45{
46 /// <summary>
47 /// A module that just holds commands for changing avatar sitting and standing states.
48 /// </summary>
49 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AnimationsCommandModule")]
50 public class SitStandCommandModule : INonSharedRegionModule
51 {
52// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private Scene m_scene;
55
56 public string Name { get { return "SitStand Command Module"; } }
57
58 public Type ReplaceableInterface { get { return null; } }
59
60 public void Initialise(IConfigSource source)
61 {
62// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: INITIALIZED MODULE");
63 }
64
65 public void PostInitialise()
66 {
67// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: POST INITIALIZED MODULE");
68 }
69
70 public void Close()
71 {
72// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: CLOSED MODULE");
73 }
74
75 public void AddRegion(Scene scene)
76 {
77// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
78 }
79
80 public void RemoveRegion(Scene scene)
81 {
82// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
83 }
84
85 public void RegionLoaded(Scene scene)
86 {
87// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
88
89 m_scene = scene;
90
91 scene.AddCommand(
92 "Users", this, "sit user name",
93 "sit user name [--regex] <first-name> <last-name>",
94 "Sit the named user on an unoccupied object with a sit target.",
95 "If there are no such objects then nothing happens.\n"
96 + "If --regex is specified then the names are treated as regular expressions.",
97 HandleSitUserNameCommand);
98
99 scene.AddCommand(
100 "Users", this, "stand user name",
101 "stand user name [--regex] <first-name> <last-name>",
102 "Stand the named user.",
103 "If --regex is specified then the names are treated as regular expressions.",
104 HandleStandUserNameCommand);
105 }
106
107 private void HandleSitUserNameCommand(string module, string[] cmd)
108 {
109 if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
110 return;
111
112 if (cmd.Length < 5)
113 {
114 MainConsole.Instance.Output("Usage: sit user name [--regex] <first-name> <last-name>");
115 return;
116 }
117
118 List<ScenePresence> scenePresences = GetScenePresences(cmd);
119
120 foreach (ScenePresence sp in scenePresences)
121 {
122 if (sp.SitGround || sp.IsSatOnObject)
123 continue;
124
125 SceneObjectPart sitPart = null;
126 List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups();
127
128 foreach (SceneObjectGroup sceneObject in sceneObjects)
129 {
130 if (sceneObject.IsAttachment)
131 continue;
132
133 foreach (SceneObjectPart part in sceneObject.Parts)
134 {
135 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
136 {
137 sitPart = part;
138 break;
139 }
140 }
141 }
142
143 if (sitPart != null)
144 {
145 MainConsole.Instance.OutputFormat(
146 "Sitting {0} on {1} {2} in {3}",
147 sp.Name, sitPart.ParentGroup.Name, sitPart.ParentGroup.UUID, m_scene.Name);
148
149 sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, sitPart.UUID, Vector3.Zero);
150 sp.HandleAgentSit(sp.ControllingClient, sp.UUID);
151 }
152 else
153 {
154 MainConsole.Instance.OutputFormat(
155 "Could not find any unoccupied set seat on which to sit {0} in {1}. Aborting",
156 sp.Name, m_scene.Name);
157
158 break;
159 }
160 }
161 }
162
163 private void HandleStandUserNameCommand(string module, string[] cmd)
164 {
165 if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null)
166 return;
167
168 if (cmd.Length < 5)
169 {
170 MainConsole.Instance.Output("Usage: stand user name [--regex] <first-name> <last-name>");
171 return;
172 }
173
174 List<ScenePresence> scenePresences = GetScenePresences(cmd);
175
176 foreach (ScenePresence sp in scenePresences)
177 {
178 if (sp.SitGround || sp.IsSatOnObject)
179 {
180 MainConsole.Instance.OutputFormat("Standing {0} in {1}", sp.Name, m_scene.Name);
181 sp.StandUp();
182 }
183 }
184 }
185
186 private List<ScenePresence> GetScenePresences(string[] cmdParams)
187 {
188 bool useRegex = false;
189 OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
190
191 List<string> mainParams = options.Parse(cmdParams);
192
193 string firstName = mainParams[3];
194 string lastName = mainParams[4];
195
196 List<ScenePresence> scenePresencesMatched = new List<ScenePresence>();
197
198 if (useRegex)
199 {
200 Regex nameRegex = new Regex(string.Format("{0} {1}", firstName, lastName));
201 List<ScenePresence> scenePresences = m_scene.GetScenePresences();
202
203 foreach (ScenePresence sp in scenePresences)
204 {
205 if (!sp.IsChildAgent && nameRegex.IsMatch(sp.Name))
206 scenePresencesMatched.Add(sp);
207 }
208 }
209 else
210 {
211 ScenePresence sp = m_scene.GetScenePresence(firstName, lastName);
212
213 if (sp != null && !sp.IsChildAgent)
214 scenePresencesMatched.Add(sp);
215 }
216
217 return scenePresencesMatched;
218 }
219 }
220} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index 37ab35a..45af212 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -65,7 +65,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
65 // Capability string prefixes 65 // Capability string prefixes
66 private static readonly string m_parcelVoiceInfoRequestPath = "0207/"; 66 private static readonly string m_parcelVoiceInfoRequestPath = "0207/";
67 private static readonly string m_provisionVoiceAccountRequestPath = "0208/"; 67 private static readonly string m_provisionVoiceAccountRequestPath = "0208/";
68 private static readonly string m_chatSessionRequestPath = "0209/"; 68 //private static readonly string m_chatSessionRequestPath = "0209/";
69 69
70 // Control info 70 // Control info
71 private static bool m_Enabled = false; 71 private static bool m_Enabled = false;
@@ -326,15 +326,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
326 "ParcelVoiceInfoRequest", 326 "ParcelVoiceInfoRequest",
327 agentID.ToString())); 327 agentID.ToString()));
328 328
329 caps.RegisterHandler( 329 //caps.RegisterHandler(
330 "ChatSessionRequest", 330 // "ChatSessionRequest",
331 new RestStreamHandler( 331 // new RestStreamHandler(
332 "POST", 332 // "POST",
333 capsBase + m_chatSessionRequestPath, 333 // capsBase + m_chatSessionRequestPath,
334 (request, path, param, httpRequest, httpResponse) 334 // (request, path, param, httpRequest, httpResponse)
335 => ChatSessionRequest(scene, request, path, param, agentID, caps), 335 // => ChatSessionRequest(scene, request, path, param, agentID, caps),
336 "ChatSessionRequest", 336 // "ChatSessionRequest",
337 agentID.ToString())); 337 // agentID.ToString()));
338 } 338 }
339 339
340 /// <summary> 340 /// <summary>
@@ -551,13 +551,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
551 reqStream.Close(); 551 reqStream.Close();
552 } 552 }
553 553
554 HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse(); 554 using (HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse())
555 Encoding encoding = Util.UTF8; 555 {
556 StreamReader fwdresponsestream = new StreamReader(fwdrsp.GetResponseStream(), encoding); 556 Encoding encoding = Util.UTF8;
557 fwdresponsestr = fwdresponsestream.ReadToEnd(); 557
558 fwdresponsecontenttype = fwdrsp.ContentType; 558 using (Stream s = fwdrsp.GetResponseStream())
559 fwdresponsecode = (int)fwdrsp.StatusCode; 559 {
560 fwdresponsestream.Close(); 560 using (StreamReader fwdresponsestream = new StreamReader(s))
561 {
562 fwdresponsestr = fwdresponsestream.ReadToEnd();
563 fwdresponsecontenttype = fwdrsp.ContentType;
564 fwdresponsecode = (int)fwdrsp.StatusCode;
565 }
566 }
567 }
561 568
562 response["content_type"] = fwdresponsecontenttype; 569 response["content_type"] = fwdresponsecontenttype;
563 response["str_response_string"] = fwdresponsestr; 570 response["str_response_string"] = fwdresponsestr;
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
index 881807a..dd44564 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs
@@ -92,7 +92,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
92 // Capability strings 92 // Capability strings
93 private static readonly string m_parcelVoiceInfoRequestPath = "0107/"; 93 private static readonly string m_parcelVoiceInfoRequestPath = "0107/";
94 private static readonly string m_provisionVoiceAccountRequestPath = "0108/"; 94 private static readonly string m_provisionVoiceAccountRequestPath = "0108/";
95 private static readonly string m_chatSessionRequestPath = "0109/"; 95 //private static readonly string m_chatSessionRequestPath = "0109/";
96 96
97 // Control info, e.g. vivox server, admin user, admin password 97 // Control info, e.g. vivox server, admin user, admin password
98 private static bool m_pluginEnabled = false; 98 private static bool m_pluginEnabled = false;
@@ -117,6 +117,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
117 117
118 private IConfig m_config; 118 private IConfig m_config;
119 119
120 private object m_Lock;
121
120 public void Initialise(IConfigSource config) 122 public void Initialise(IConfigSource config)
121 { 123 {
122 124
@@ -128,6 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
128 if (!m_config.GetBoolean("enabled", false)) 130 if (!m_config.GetBoolean("enabled", false))
129 return; 131 return;
130 132
133 m_Lock = new object();
134
131 try 135 try
132 { 136 {
133 // retrieve configuration variables 137 // retrieve configuration variables
@@ -429,15 +433,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
429 "ParcelVoiceInfoRequest", 433 "ParcelVoiceInfoRequest",
430 agentID.ToString())); 434 agentID.ToString()));
431 435
432 caps.RegisterHandler( 436 //caps.RegisterHandler(
433 "ChatSessionRequest", 437 // "ChatSessionRequest",
434 new RestStreamHandler( 438 // new RestStreamHandler(
435 "POST", 439 // "POST",
436 capsBase + m_chatSessionRequestPath, 440 // capsBase + m_chatSessionRequestPath,
437 (request, path, param, httpRequest, httpResponse) 441 // (request, path, param, httpRequest, httpResponse)
438 => ChatSessionRequest(scene, request, path, param, agentID, caps), 442 // => ChatSessionRequest(scene, request, path, param, agentID, caps),
439 "ChatSessionRequest", 443 // "ChatSessionRequest",
440 agentID.ToString())); 444 // agentID.ToString()));
441 } 445 }
442 446
443 /// <summary> 447 /// <summary>
@@ -818,11 +822,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
818 { 822 {
819 string requrl = String.Format(m_vivoxChannelPath, m_vivoxServer, "create", channelId, m_authToken); 823 string requrl = String.Format(m_vivoxChannelPath, m_vivoxServer, "create", channelId, m_authToken);
820 824
821 if (parent != null && parent != String.Empty) 825 if (!string.IsNullOrEmpty(parent))
822 { 826 {
823 requrl = String.Format("{0}&chan_parent={1}", requrl, parent); 827 requrl = String.Format("{0}&chan_parent={1}", requrl, parent);
824 } 828 }
825 if (description != null && description != String.Empty) 829 if (!string.IsNullOrEmpty(description))
826 { 830 {
827 requrl = String.Format("{0}&chan_desc={1}", requrl, description); 831 requrl = String.Format("{0}&chan_desc={1}", requrl, description);
828 } 832 }
@@ -832,7 +836,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
832 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); 836 requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff);
833 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); 837 requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel);
834 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); 838 requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange);
835 requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); 839 requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance);
836 840
837 XmlElement resp = VivoxCall(requrl, true); 841 XmlElement resp = VivoxCall(requrl, true);
838 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) 842 if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri))
@@ -858,7 +862,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
858 // requrl = String.Format("{0}&chan_parent={1}", requrl, parent); 862 // requrl = String.Format("{0}&chan_parent={1}", requrl, parent);
859 // } 863 // }
860 864
861 if (description != null && description != String.Empty) 865 if (!string.IsNullOrEmpty(description))
862 { 866 {
863 requrl = String.Format("{0}&chan_desc={1}", requrl, description); 867 requrl = String.Format("{0}&chan_desc={1}", requrl, description);
864 } 868 }
@@ -1043,7 +1047,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1043 private XmlElement VivoxDeleteChannel(string parent, string channelid) 1047 private XmlElement VivoxDeleteChannel(string parent, string channelid)
1044 { 1048 {
1045 string requrl = String.Format(m_vivoxChannelDel, m_vivoxServer, "delete", channelid, m_authToken); 1049 string requrl = String.Format(m_vivoxChannelDel, m_vivoxServer, "delete", channelid, m_authToken);
1046 if (parent != null && parent != String.Empty) 1050 if (!string.IsNullOrEmpty(parent))
1047 { 1051 {
1048 requrl = String.Format("{0}&chan_parent={1}", requrl, parent); 1052 requrl = String.Format("{0}&chan_parent={1}", requrl, parent);
1049 } 1053 }
@@ -1111,27 +1115,32 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1111 1115
1112 doc = new XmlDocument(); 1116 doc = new XmlDocument();
1113 1117
1114 try 1118 // Let's serialize all calls to Vivox. Most of these are driven by
1119 // the clients (CAPs), when the user arrives at the region. We don't
1120 // want to issue many simultaneous http requests to Vivox, because mono
1121 // doesn't like that
1122 lock (m_Lock)
1115 { 1123 {
1116 // Otherwise prepare the request 1124 try
1117 m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); 1125 {
1118 1126 // Otherwise prepare the request
1119 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); 1127 m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl);
1120 HttpWebResponse rsp = null;
1121 1128
1122 // We are sending just parameters, no content 1129 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl);
1123 req.ContentLength = 0;
1124 1130
1125 // Send request and retrieve the response 1131 // We are sending just parameters, no content
1126 rsp = (HttpWebResponse)req.GetResponse(); 1132 req.ContentLength = 0;
1127 1133
1128 XmlTextReader rdr = new XmlTextReader(rsp.GetResponseStream()); 1134 // Send request and retrieve the response
1129 doc.Load(rdr); 1135 using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse())
1130 rdr.Close(); 1136 using (Stream s = rsp.GetResponseStream())
1131 } 1137 using (XmlTextReader rdr = new XmlTextReader(s))
1132 catch (Exception e) 1138 doc.Load(rdr);
1133 { 1139 }
1134 m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); 1140 catch (Exception e)
1141 {
1142 m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message);
1143 }
1135 } 1144 }
1136 1145
1137 // If we're debugging server responses, dump the whole 1146 // If we're debugging server responses, dump the whole
@@ -1316,4 +1325,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice
1316 return false; 1325 return false;
1317 } 1326 }
1318 } 1327 }
1319} \ No newline at end of file 1328}
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
index 2802e2f..e1b6abb 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsMessagingModule.cs
@@ -55,8 +55,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
55 private IGroupsServicesConnector m_groupData = null; 55 private IGroupsServicesConnector m_groupData = null;
56 56
57 // Config Options 57 // Config Options
58 private bool m_groupMessagingEnabled = false; 58 private bool m_groupMessagingEnabled;
59 private bool m_debugEnabled = true; 59 private bool m_debugEnabled;
60 60
61 /// <summary> 61 /// <summary>
62 /// If enabled, module only tries to send group IMs to online users by querying cached presence information. 62 /// If enabled, module only tries to send group IMs to online users by querying cached presence information.
@@ -113,7 +113,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
113 if (m_messageOnlineAgentsOnly) 113 if (m_messageOnlineAgentsOnly)
114 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>(); 114 m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
115 115
116 m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true); 116 m_debugEnabled = groupsConfig.GetBoolean("MessagingDebugEnabled", m_debugEnabled);
117 } 117 }
118 118
119 m_log.InfoFormat( 119 m_log.InfoFormat(
@@ -127,6 +127,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
127 return; 127 return;
128 128
129 scene.RegisterModuleInterface<IGroupsMessagingModule>(this); 129 scene.RegisterModuleInterface<IGroupsMessagingModule>(this);
130
131 scene.AddCommand(
132 "Debug",
133 this,
134 "debug groups messaging verbose",
135 "debug groups messaging verbose <true|false>",
136 "This setting turns on very verbose groups messaging debugging",
137 HandleDebugGroupsMessagingVerbose);
130 } 138 }
131 139
132 public void RegionLoaded(Scene scene) 140 public void RegionLoaded(Scene scene)
@@ -218,6 +226,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
218 226
219 #endregion 227 #endregion
220 228
229 private void HandleDebugGroupsMessagingVerbose(object modules, string[] args)
230 {
231 if (args.Length < 5)
232 {
233 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
234 return;
235 }
236
237 bool verbose = false;
238 if (!bool.TryParse(args[4], out verbose))
239 {
240 MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
241 return;
242 }
243
244 m_debugEnabled = verbose;
245
246 MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled);
247 }
248
221 /// <summary> 249 /// <summary>
222 /// Not really needed, but does confirm that the group exists. 250 /// Not really needed, but does confirm that the group exists.
223 /// </summary> 251 /// </summary>
@@ -237,11 +265,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
237 return false; 265 return false;
238 } 266 }
239 } 267 }
240 268
241 public void SendMessageToGroup(GridInstantMessage im, UUID groupID) 269 public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
242 { 270 {
243 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID); 271 SendMessageToGroup(im, groupID, new UUID(im.fromAgentID), null);
272 }
273
274 public void SendMessageToGroup(
275 GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func<GroupMembersData, bool> sendCondition)
276 {
277 int requestStartTick = Environment.TickCount;
278
279 List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(sendingAgentForGroupCalls, groupID);
244 int groupMembersCount = groupMembers.Count; 280 int groupMembersCount = groupMembers.Count;
281 HashSet<string> attemptDeliveryUuidSet = null;
245 282
246 if (m_messageOnlineAgentsOnly) 283 if (m_messageOnlineAgentsOnly)
247 { 284 {
@@ -257,10 +294,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
257 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); 294 m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
258 } 295 }
259 296
260 HashSet<string> onlineAgentsUuidSet = new HashSet<string>(); 297 attemptDeliveryUuidSet
261 Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); 298 = new HashSet<string>(Array.ConvertAll<PresenceInfo, string>(onlineAgents, pi => pi.UserID));
299
300 //Array.ForEach<PresenceInfo>(onlineAgents, pi => attemptDeliveryUuidSet.Add(pi.UserID));
262 301
263 groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); 302 //groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
264 303
265 // if (m_debugEnabled) 304 // if (m_debugEnabled)
266// m_log.DebugFormat( 305// m_log.DebugFormat(
@@ -269,26 +308,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
269 } 308 }
270 else 309 else
271 { 310 {
311 attemptDeliveryUuidSet
312 = new HashSet<string>(groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()));
313
272 if (m_debugEnabled) 314 if (m_debugEnabled)
273 m_log.DebugFormat( 315 m_log.DebugFormat(
274 "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members", 316 "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members",
275 groupID, groupMembers.Count); 317 groupID, groupMembers.Count);
276 } 318 }
277
278 int requestStartTick = Environment.TickCount;
279 319
280 foreach (GroupMembersData member in groupMembers) 320 foreach (GroupMembersData member in groupMembers)
281 { 321 {
282 if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID)) 322 if (sendCondition != null)
323 {
324 if (!sendCondition(member))
325 {
326 if (m_debugEnabled)
327 m_log.DebugFormat(
328 "[GROUPS-MESSAGING]: Not sending to {0} as they do not fulfill send condition",
329 member.AgentID);
330
331 continue;
332 }
333 }
334 else if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID))
283 { 335 {
284 // Don't deliver messages to people who have dropped this session 336 // Don't deliver messages to people who have dropped this session
285 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: {0} has dropped session, not delivering to them", member.AgentID); 337 if (m_debugEnabled)
338 m_log.DebugFormat(
339 "[GROUPS-MESSAGING]: {0} has dropped session, not delivering to them", member.AgentID);
340
286 continue; 341 continue;
287 } 342 }
288 343
289 // Copy Message 344 // Copy Message
290 GridInstantMessage msg = new GridInstantMessage(); 345 GridInstantMessage msg = new GridInstantMessage();
291 msg.imSessionID = groupID.Guid; 346 msg.imSessionID = im.imSessionID;
292 msg.fromAgentName = im.fromAgentName; 347 msg.fromAgentName = im.fromAgentName;
293 msg.message = im.message; 348 msg.message = im.message;
294 msg.dialog = im.dialog; 349 msg.dialog = im.dialog;
@@ -304,26 +359,51 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
304 359
305 msg.toAgentID = member.AgentID.Guid; 360 msg.toAgentID = member.AgentID.Guid;
306 361
307 IClientAPI client = GetActiveClient(member.AgentID); 362 if (attemptDeliveryUuidSet.Contains(member.AgentID.ToString()))
308 if (client == null)
309 { 363 {
310 // If they're not local, forward across the grid 364 IClientAPI client = GetActiveClient(member.AgentID);
311 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} via Grid", member.AgentID); 365 if (client == null)
312 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); 366 {
367 int startTick = Environment.TickCount;
368
369 // If they're not local, forward across the grid
370 m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { });
371
372 if (m_debugEnabled)
373 m_log.DebugFormat(
374 "[GROUPS-MESSAGING]: Delivering to {0} via grid took {1} ms",
375 member.AgentID, Environment.TickCount - startTick);
376 }
377 else
378 {
379 int startTick = Environment.TickCount;
380
381 ProcessMessageFromGroupSession(msg, client);
382
383 // Deliver locally, directly
384 if (m_debugEnabled)
385 m_log.DebugFormat(
386 "[GROUPS-MESSAGING]: Delivering to {0} locally took {1} ms",
387 member.AgentID, Environment.TickCount - startTick);
388 }
313 } 389 }
314 else 390 else
315 { 391 {
316 // Deliver locally, directly 392 int startTick = Environment.TickCount;
317 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); 393
318 ProcessMessageFromGroupSession(msg); 394 m_msgTransferModule.HandleUndeliverableMessage(msg, delegate(bool success) { });
395
396 if (m_debugEnabled)
397 m_log.DebugFormat(
398 "[GROUPS-MESSAGING]: Handling undeliverable message for {0} took {1} ms",
399 member.AgentID, Environment.TickCount - startTick);
319 } 400 }
320 } 401 }
321 402
322 // Temporary for assessing how long it still takes to send messages to large online groups. 403 if (m_debugEnabled)
323 if (m_messageOnlineAgentsOnly)
324 m_log.DebugFormat( 404 m_log.DebugFormat(
325 "[GROUPS-MESSAGING]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", 405 "[GROUPS-MESSAGING]: Total SendMessageToGroup for group {0} with {1} members, {2} candidates for delivery took {3} ms",
326 groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); 406 groupID, groupMembersCount, attemptDeliveryUuidSet.Count(), Environment.TickCount - requestStartTick);
327 } 407 }
328 408
329 #region SimGridEventHandlers 409 #region SimGridEventHandlers
@@ -348,7 +428,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
348 // Any other message type will not be delivered to a client by the 428 // Any other message type will not be delivered to a client by the
349 // Instant Message Module 429 // Instant Message Module
350 430
351
352 if (m_debugEnabled) 431 if (m_debugEnabled)
353 { 432 {
354 m_log.DebugFormat("[GROUPS-MESSAGING]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 433 m_log.DebugFormat("[GROUPS-MESSAGING]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
@@ -362,13 +441,35 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
362 || (msg.dialog == (byte)InstantMessageDialog.SessionAdd) 441 || (msg.dialog == (byte)InstantMessageDialog.SessionAdd)
363 || (msg.dialog == (byte)InstantMessageDialog.SessionDrop))) 442 || (msg.dialog == (byte)InstantMessageDialog.SessionDrop)))
364 { 443 {
365 ProcessMessageFromGroupSession(msg); 444 IClientAPI client = null;
445
446 if (msg.dialog == (byte)InstantMessageDialog.SessionSend)
447 {
448 client = GetActiveClient(new UUID(msg.toAgentID));
449
450 if (client != null)
451 {
452 if (m_debugEnabled)
453 m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} locally", client.Name);
454 }
455 else
456 {
457 m_log.WarnFormat("[GROUPS-MESSAGING]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
458
459 return;
460 }
461 }
462
463 ProcessMessageFromGroupSession(msg, client);
366 } 464 }
367 } 465 }
368 466
369 private void ProcessMessageFromGroupSession(GridInstantMessage msg) 467 private void ProcessMessageFromGroupSession(GridInstantMessage msg, IClientAPI client)
370 { 468 {
371 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID); 469 if (m_debugEnabled)
470 m_log.DebugFormat(
471 "[GROUPS-MESSAGING]: Session message from {0} going to agent {1}, sessionID {2}, type {3}",
472 msg.fromAgentName, msg.toAgentID, msg.imSessionID, (InstantMessageDialog)msg.dialog);
372 473
373 UUID AgentID = new UUID(msg.fromAgentID); 474 UUID AgentID = new UUID(msg.fromAgentID);
374 UUID GroupID = new UUID(msg.imSessionID); 475 UUID GroupID = new UUID(msg.imSessionID);
@@ -392,74 +493,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
392 // Add them to the session for now, and Invite them 493 // Add them to the session for now, and Invite them
393 m_groupData.AgentInvitedToGroupChatSession(AgentID, GroupID); 494 m_groupData.AgentInvitedToGroupChatSession(AgentID, GroupID);
394 495
395 UUID toAgentID = new UUID(msg.toAgentID); 496 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero, GroupID, null);
396 IClientAPI activeClient = GetActiveClient(toAgentID); 497 if (groupInfo != null)
397 if (activeClient != null)
398 { 498 {
399 GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero, GroupID, null); 499 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Sending chatterbox invite instant message");
400 if (groupInfo != null) 500
401 { 501 // Force? open the group session dialog???
402 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Sending chatterbox invite instant message"); 502 // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg);
403 503 IEventQueue eq = client.Scene.RequestModuleInterface<IEventQueue>();
404 // Force? open the group session dialog??? 504 eq.ChatterboxInvitation(
405 // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); 505 GroupID
406 IEventQueue eq = activeClient.Scene.RequestModuleInterface<IEventQueue>(); 506 , groupInfo.GroupName
407 eq.ChatterboxInvitation( 507 , new UUID(msg.fromAgentID)
408 GroupID 508 , msg.message
409 , groupInfo.GroupName 509 , new UUID(msg.toAgentID)
410 , new UUID(msg.fromAgentID) 510 , msg.fromAgentName
411 , msg.message 511 , msg.dialog
412 , new UUID(msg.toAgentID) 512 , msg.timestamp
413 , msg.fromAgentName 513 , msg.offline == 1
414 , msg.dialog 514 , (int)msg.ParentEstateID
415 , msg.timestamp 515 , msg.Position
416 , msg.offline == 1 516 , 1
417 , (int)msg.ParentEstateID 517 , new UUID(msg.imSessionID)
418 , msg.Position 518 , msg.fromGroup
419 , 1 519 , Utils.StringToBytes(groupInfo.GroupName)
420 , new UUID(msg.imSessionID) 520 );
421 , msg.fromGroup 521
422 , Utils.StringToBytes(groupInfo.GroupName) 522 eq.ChatterBoxSessionAgentListUpdates(
423 ); 523 new UUID(GroupID)
424 524 , new UUID(msg.fromAgentID)
425 eq.ChatterBoxSessionAgentListUpdates( 525 , new UUID(msg.toAgentID)
426 new UUID(GroupID) 526 , false //canVoiceChat
427 , new UUID(msg.fromAgentID) 527 , false //isModerator
428 , new UUID(msg.toAgentID) 528 , false //text mute
429 , false //canVoiceChat 529 );
430 , false //isModerator
431 , false //text mute
432 );
433 }
434 } 530 }
531
532 break;
435 } 533 }
436 else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID, GroupID)) 534 else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID, GroupID))
437 { 535 {
438 // User hasn't dropped, so they're in the session, 536 // User hasn't dropped, so they're in the session,
439 // maybe we should deliver it. 537 // maybe we should deliver it.
440 IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); 538 client.SendInstantMessage(msg);
441 if (client != null)
442 {
443 // Deliver locally, directly
444 if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} locally", client.Name);
445 client.SendInstantMessage(msg);
446 }
447 else
448 {
449 m_log.WarnFormat("[GROUPS-MESSAGING]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
450 }
451 } 539 }
540
452 break; 541 break;
453 542
454 default: 543 default:
455 m_log.WarnFormat("[GROUPS-MESSAGING]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString()); 544 client.SendInstantMessage(msg);
456 break; 545
546 break;;
457 } 547 }
458 } 548 }
459 549
460 #endregion 550 #endregion
461 551
462
463 #region ClientEvents 552 #region ClientEvents
464 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) 553 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
465 { 554 {
@@ -548,15 +637,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
548 // Don't log any normal IMs (privacy!) 637 // Don't log any normal IMs (privacy!)
549 if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent) 638 if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent)
550 { 639 {
551 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromGroup({0})", im.fromGroup ? "True" : "False"); 640 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromGroup({0})", im.fromGroup ? "True" : "False");
552 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString()); 641 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: Dialog({0})", (InstantMessageDialog)im.dialog);
553 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromAgentID({0})", im.fromAgentID.ToString()); 642 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromAgentID({0})", im.fromAgentID);
554 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromAgentName({0})", im.fromAgentName.ToString()); 643 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromAgentName({0})", im.fromAgentName);
555 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: imSessionID({0})", im.imSessionID.ToString()); 644 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: imSessionID({0})", im.imSessionID);
556 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: message({0})", im.message.ToString()); 645 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: message({0})", im.message);
557 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: offline({0})", im.offline.ToString()); 646 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: offline({0})", im.offline);
558 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: toAgentID({0})", im.toAgentID.ToString()); 647 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: toAgentID({0})", im.toAgentID);
559 m_log.WarnFormat("[GROUPS-MESSAGING]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket")); 648 m_log.DebugFormat("[GROUPS-MESSAGING]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket"));
560 } 649 }
561 } 650 }
562 651
@@ -567,7 +656,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
567 /// </summary> 656 /// </summary>
568 private IClientAPI GetActiveClient(UUID agentID) 657 private IClientAPI GetActiveClient(UUID agentID)
569 { 658 {
570 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Looking for local client {0}", agentID); 659 if (m_debugEnabled)
660 m_log.DebugFormat("[GROUPS-MESSAGING]: Looking for local client {0}", agentID);
571 661
572 IClientAPI child = null; 662 IClientAPI child = null;
573 663
@@ -579,12 +669,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
579 { 669 {
580 if (!sp.IsChildAgent) 670 if (!sp.IsChildAgent)
581 { 671 {
582 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Found root agent for client : {0}", sp.ControllingClient.Name); 672 if (m_debugEnabled)
673 m_log.DebugFormat("[GROUPS-MESSAGING]: Found root agent for client : {0}", sp.ControllingClient.Name);
674
583 return sp.ControllingClient; 675 return sp.ControllingClient;
584 } 676 }
585 else 677 else
586 { 678 {
587 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Found child agent for client : {0}", sp.ControllingClient.Name); 679 if (m_debugEnabled)
680 m_log.DebugFormat("[GROUPS-MESSAGING]: Found child agent for client : {0}", sp.ControllingClient.Name);
681
588 child = sp.ControllingClient; 682 child = sp.ControllingClient;
589 } 683 }
590 } 684 }
@@ -593,12 +687,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
593 // If we didn't find a root, then just return whichever child we found, or null if none 687 // If we didn't find a root, then just return whichever child we found, or null if none
594 if (child == null) 688 if (child == null)
595 { 689 {
596 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Could not find local client for agent : {0}", agentID); 690 if (m_debugEnabled)
691 m_log.DebugFormat("[GROUPS-MESSAGING]: Could not find local client for agent : {0}", agentID);
597 } 692 }
598 else 693 else
599 { 694 {
600 if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Returning child agent for client : {0}", child.Name); 695 if (m_debugEnabled)
696 m_log.DebugFormat("[GROUPS-MESSAGING]: Returning child agent for client : {0}", child.Name);
601 } 697 }
698
602 return child; 699 return child;
603 } 700 }
604 701
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
index 29f9591..1565da9 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/GroupsModule.cs
@@ -35,10 +35,10 @@ using Nini.Config;
35using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.StructuredData; 36using OpenMetaverse.StructuredData;
37using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces; 40using OpenSim.Services.Interfaces;
41using System.Text;
42using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; 42using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags;
43 43
44namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups 44namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
@@ -76,9 +76,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
76 76
77 private List<Scene> m_sceneList = new List<Scene>(); 77 private List<Scene> m_sceneList = new List<Scene>();
78 78
79 private IMessageTransferModule m_msgTransferModule = null; 79 private IMessageTransferModule m_msgTransferModule;
80
81 private IGroupsMessagingModule m_groupsMessagingModule;
80 82
81 private IGroupsServicesConnector m_groupData = null; 83 private IGroupsServicesConnector m_groupData;
82 84
83 // Configuration settings 85 // Configuration settings
84 private bool m_groupsEnabled = false; 86 private bool m_groupsEnabled = false;
@@ -184,10 +186,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
184 if (m_msgTransferModule == null) 186 if (m_msgTransferModule == null)
185 { 187 {
186 m_groupsEnabled = false; 188 m_groupsEnabled = false;
187 m_log.Warn("[GROUPS]: Could not get MessageTransferModule"); 189 m_log.Warn("[GROUPS]: Could not get IMessageTransferModule");
188 } 190 }
189 } 191 }
190 192
193 if (m_groupsMessagingModule == null)
194 {
195 m_groupsMessagingModule = scene.RequestModuleInterface<IGroupsMessagingModule>();
196
197 // No message transfer module, no notices, group invites, rejects, ejects, etc
198 if (m_groupsMessagingModule == null)
199 m_log.Warn("[GROUPS]: Could not get IGroupsMessagingModule");
200 }
201
191 lock (m_sceneList) 202 lock (m_sceneList)
192 { 203 {
193 m_sceneList.Add(scene); 204 m_sceneList.Add(scene);
@@ -250,7 +261,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
250 261
251 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; 262 client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
252 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; 263 client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
253 client.OnDirFindQuery += OnDirFindQuery;
254 client.OnRequestAvatarProperties += OnRequestAvatarProperties; 264 client.OnRequestAvatarProperties += OnRequestAvatarProperties;
255 265
256 // Used for Notices and Group Invites/Accept/Reject 266 // Used for Notices and Group Invites/Accept/Reject
@@ -303,21 +313,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
303 } 313 }
304 */ 314 */
305 315
306 void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart)
307 {
308 if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
309 {
310 if (m_debugEnabled)
311 m_log.DebugFormat(
312 "[GROUPS]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})",
313 System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart);
314
315 // TODO: This currently ignores pretty much all the query flags including Mature and sort order
316 remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentID(remoteClient), queryText).ToArray());
317 }
318
319 }
320
321 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID) 316 private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
322 { 317 {
323 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 318 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
@@ -361,7 +356,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
361 356
362 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) 357 private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
363 { 358 {
364 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 359 if (m_debugEnabled)
360 m_log.DebugFormat(
361 "[GROUPS]: {0} called for {1}, message type {2}",
362 System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name, (InstantMessageDialog)im.dialog);
365 363
366 // Group invitations 364 // Group invitations
367 if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)) 365 if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline))
@@ -437,81 +435,160 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
437 string Subject = im.message.Substring(0, im.message.IndexOf('|')); 435 string Subject = im.message.Substring(0, im.message.IndexOf('|'));
438 string Message = im.message.Substring(Subject.Length + 1); 436 string Message = im.message.Substring(Subject.Length + 1);
439 437
438 InventoryItemBase item = null;
439 bool hasAttachment = false;
440 UUID itemID = UUID.Zero; //Assignment to quiet compiler
441 UUID ownerID = UUID.Zero; //Assignment to quiet compiler
440 byte[] bucket; 442 byte[] bucket;
441 443
442 if ((im.binaryBucket.Length == 1) && (im.binaryBucket[0] == 0)) 444 if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0)
443 {
444 bucket = new byte[19];
445 bucket[0] = 0; //dunno
446 bucket[1] = 0; //dunno
447 GroupID.ToBytes(bucket, 2);
448 bucket[18] = 0; //dunno
449 }
450 else
451 { 445 {
452 string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket); 446 string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket);
453 binBucket = binBucket.Remove(0, 14).Trim(); 447 binBucket = binBucket.Remove(0, 14).Trim();
454 if (m_debugEnabled) 448
449 OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket);
450 if (binBucketOSD is OSD)
455 { 451 {
456 m_log.WarnFormat("I don't understand a group notice binary bucket of: {0}", binBucket); 452 OSDMap binBucketMap = (OSDMap)binBucketOSD;
453
454 itemID = binBucketMap["item_id"].AsUUID();
455 ownerID = binBucketMap["owner_id"].AsUUID();
456
457 //Attempt to get the details of the attached item.
458 //If sender doesn't own the attachment, the item
459 //variable will be set to null and attachment will
460 //not be included with the group notice.
461 Scene scene = (Scene)remoteClient.Scene;
462 item = new InventoryItemBase(itemID, ownerID);
463 item = scene.InventoryService.GetItem(item);
457 464
458 OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket); 465 if (item != null)
459
460 foreach (string key in binBucketOSD.Keys)
461 { 466 {
462 if (binBucketOSD.ContainsKey(key)) 467 //Got item details so include the attachment.
463 { 468 hasAttachment = true;
464 m_log.WarnFormat("{0}: {1}", key, binBucketOSD[key].ToString());
465 }
466 } 469 }
467 } 470 }
468 471 else
469 // treat as if no attachment 472 {
473 m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType());
474 }
475 }
476
477 if (hasAttachment)
478 {
479 //Bucket contains information about attachment.
480 //
481 //Byte offset and description of bucket data:
482 //0: 1 byte indicating if attachment is present
483 //1: 1 byte indicating the type of attachment
484 //2: 16 bytes - Group UUID
485 //18: 16 bytes - UUID of the attachment owner
486 //34: 16 bytes - UUID of the attachment
487 //50: variable - Name of the attachment
488 //??: NUL byte to terminate the attachment name
489 byte[] name = Encoding.UTF8.GetBytes(item.Name);
490 bucket = new byte[51 + name.Length];//3 bytes, 3 UUIDs, and name
491 bucket[0] = 1; //Has attachment flag
492 bucket[1] = (byte)item.InvType; //Type of Attachment
493 GroupID.ToBytes(bucket, 2);
494 ownerID.ToBytes(bucket, 18);
495 itemID.ToBytes(bucket, 34);
496 name.CopyTo(bucket, 50);
497 }
498 else
499 {
470 bucket = new byte[19]; 500 bucket = new byte[19];
471 bucket[0] = 0; //dunno 501 bucket[0] = 0; //Has attachment flag
472 bucket[1] = 0; //dunno 502 bucket[1] = 0; //Type of attachment
473 GroupID.ToBytes(bucket, 2); 503 GroupID.ToBytes(bucket, 2);
474 bucket[18] = 0; //dunno 504 bucket[18] = 0; //NUL terminate name of attachment
475 } 505 }
476 506
477
478 m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket); 507 m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket);
479 if (OnNewGroupNotice != null) 508 if (OnNewGroupNotice != null)
480 { 509 {
481 OnNewGroupNotice(GroupID, NoticeID); 510 OnNewGroupNotice(GroupID, NoticeID);
482 } 511 }
483 512
484 // Send notice out to everyone that wants notices 513 if (m_debugEnabled)
485 foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID))
486 { 514 {
487 if (m_debugEnabled) 515 foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID))
488 { 516 {
489 UserAccount targetUser = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, member.AgentID); 517 if (m_debugEnabled)
490 if (targetUser != null)
491 { 518 {
492 m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices); 519 UserAccount targetUser
493 } 520 = m_sceneList[0].UserAccountService.GetUserAccount(
494 else 521 remoteClient.Scene.RegionInfo.ScopeID, member.AgentID);
495 { 522
496 m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, member.AgentID, member.AcceptNotices); 523 if (targetUser != null)
524 {
525 m_log.DebugFormat(
526 "[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})",
527 NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices);
528 }
529 else
530 {
531 m_log.DebugFormat(
532 "[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})",
533 NoticeID, member.AgentID, member.AcceptNotices);
534 }
497 } 535 }
498 } 536 }
537 }
499 538
500 if (member.AcceptNotices) 539 GridInstantMessage msg
501 { 540 = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
502 // Build notice IIM
503 GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
504 541
505 msg.toAgentID = member.AgentID.Guid; 542 if (m_groupsMessagingModule != null)
506 OutgoingInstantMessage(msg, member.AgentID); 543 m_groupsMessagingModule.SendMessageToGroup(
507 } 544 msg, GroupID, remoteClient.AgentId, gmd => gmd.AcceptNotices);
545 }
546 }
547
548 if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted)
549 {
550 //Is bucket large enough to hold UUID of the attachment?
551 if (im.binaryBucket.Length < 16)
552 return;
553
554 UUID noticeID = new UUID(im.imSessionID);
555
556 if (m_debugEnabled)
557 m_log.DebugFormat("[GROUPS]: Requesting notice {0} for {1}", noticeID, remoteClient.AgentId);
558
559 GroupNoticeInfo notice = m_groupData.GetGroupNotice(GetRequestingAgentID(remoteClient), noticeID);
560 if (notice != null)
561 {
562 UUID giver = new UUID(notice.BinaryBucket, 18);
563 UUID attachmentUUID = new UUID(notice.BinaryBucket, 34);
564
565 if (m_debugEnabled)
566 m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId);
567
568 string message;
569 InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId,
570 giver, attachmentUUID, out message);
571
572 if (itemCopy == null)
573 {
574 remoteClient.SendAgentAlertMessage(message, false);
575 return;
508 } 576 }
577
578 remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0);
579 }
580 else
581 {
582 if (m_debugEnabled)
583 m_log.DebugFormat(
584 "[GROUPS]: Could not find notice {0} for {1} on GroupNoticeInventoryAccepted.",
585 noticeID, remoteClient.AgentId);
509 } 586 }
510 } 587 }
511 588
512 // Interop, received special 210 code for ejecting a group member 589 // Interop, received special 210 code for ejecting a group member
513 // this only works within the comms servers domain, and won't work hypergrid 590 // this only works within the comms servers domain, and won't work hypergrid
514 // TODO:FIXME: Use a presense server of some kind to find out where the 591 // TODO:FIXME: Use a presence server of some kind to find out where the
515 // client actually is, and try contacting that region directly to notify them, 592 // client actually is, and try contacting that region directly to notify them,
516 // or provide the notification via xmlrpc update queue 593 // or provide the notification via xmlrpc update queue
517 if ((im.dialog == 210)) 594 if ((im.dialog == 210))
@@ -764,7 +841,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
764 remoteClient.SendCreateGroupReply(UUID.Zero, false, "You have got insufficient funds to create a group."); 841 remoteClient.SendCreateGroupReply(UUID.Zero, false, "You have got insufficient funds to create a group.");
765 return UUID.Zero; 842 return UUID.Zero;
766 } 843 }
767 money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, "Group Creation"); 844 money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, MoneyTransactionType.GroupCreate);
768 } 845 }
769 UUID groupID = m_groupData.CreateGroup(GetRequestingAgentID(remoteClient), name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, GetRequestingAgentID(remoteClient)); 846 UUID groupID = m_groupData.CreateGroup(GetRequestingAgentID(remoteClient), name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, GetRequestingAgentID(remoteClient));
770 847
@@ -889,26 +966,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
889 966
890 if (data != null) 967 if (data != null)
891 { 968 {
892 GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null); 969 GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
893
894 GridInstantMessage msg = new GridInstantMessage();
895 msg.imSessionID = UUID.Zero.Guid;
896 msg.fromAgentID = data.GroupID.Guid;
897 msg.toAgentID = GetRequestingAgentID(remoteClient).Guid;
898 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
899 msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName;
900 msg.message = data.noticeData.Subject + "|" + data.Message;
901 msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested;
902 msg.fromGroup = true;
903 msg.offline = (byte)0;
904 msg.ParentEstateID = 0;
905 msg.Position = Vector3.Zero;
906 msg.RegionID = UUID.Zero.Guid;
907 msg.binaryBucket = data.BinaryBucket;
908 970
909 OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient)); 971 OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
910 } 972 }
911
912 } 973 }
913 974
914 public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog) 975 public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog)
@@ -916,10 +977,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
916 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); 977 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
917 978
918 GridInstantMessage msg = new GridInstantMessage(); 979 GridInstantMessage msg = new GridInstantMessage();
919 msg.imSessionID = UUID.Zero.Guid; 980 byte[] bucket;
981
982 msg.imSessionID = groupNoticeID.Guid;
920 msg.toAgentID = agentID.Guid; 983 msg.toAgentID = agentID.Guid;
921 msg.dialog = dialog; 984 msg.dialog = dialog;
922 // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice;
923 msg.fromGroup = true; 985 msg.fromGroup = true;
924 msg.offline = (byte)0; 986 msg.offline = (byte)0;
925 msg.ParentEstateID = 0; 987 msg.ParentEstateID = 0;
@@ -933,13 +995,38 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
933 msg.timestamp = info.noticeData.Timestamp; 995 msg.timestamp = info.noticeData.Timestamp;
934 msg.fromAgentName = info.noticeData.FromName; 996 msg.fromAgentName = info.noticeData.FromName;
935 msg.message = info.noticeData.Subject + "|" + info.Message; 997 msg.message = info.noticeData.Subject + "|" + info.Message;
936 msg.binaryBucket = info.BinaryBucket; 998
999 if (info.BinaryBucket[0] > 0)
1000 {
1001 //32 is due to not needing space for two of the UUIDs.
1002 //(Don't need UUID of attachment or its owner in IM)
1003 //50 offset gets us to start of attachment name.
1004 //We are skipping the attachment flag, type, and
1005 //the three UUID fields at the start of the bucket.
1006 bucket = new byte[info.BinaryBucket.Length-32];
1007 bucket[0] = 1; //Has attachment
1008 bucket[1] = info.BinaryBucket[1];
1009 Array.Copy(info.BinaryBucket, 50,
1010 bucket, 18, info.BinaryBucket.Length-50);
1011 }
1012 else
1013 {
1014 bucket = new byte[19];
1015 bucket[0] = 0; //No attachment
1016 bucket[1] = 0; //Attachment type
1017 bucket[18] = 0; //NUL terminate name
1018 }
1019
1020 info.GroupID.ToBytes(bucket, 2);
1021 msg.binaryBucket = bucket;
937 } 1022 }
938 else 1023 else
939 { 1024 {
940 if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID); 1025 if (m_debugEnabled)
1026 m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID);
1027
941 msg.fromAgentID = UUID.Zero.Guid; 1028 msg.fromAgentID = UUID.Zero.Guid;
942 msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ; 1029 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
943 msg.fromAgentName = string.Empty; 1030 msg.fromAgentName = string.Empty;
944 msg.message = string.Empty; 1031 msg.message = string.Empty;
945 msg.binaryBucket = new byte[0]; 1032 msg.binaryBucket = new byte[0];
@@ -1063,7 +1150,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1063 // Message to ejector 1150 // Message to ejector
1064 // Interop, received special 210 code for ejecting a group member 1151 // Interop, received special 210 code for ejecting a group member
1065 // this only works within the comms servers domain, and won't work hypergrid 1152 // this only works within the comms servers domain, and won't work hypergrid
1066 // TODO:FIXME: Use a presense server of some kind to find out where the 1153 // TODO:FIXME: Use a presence server of some kind to find out where the
1067 // client actually is, and try contacting that region directly to notify them, 1154 // client actually is, and try contacting that region directly to notify them,
1068 // or provide the notification via xmlrpc update queue 1155 // or provide the notification via xmlrpc update queue
1069 1156
@@ -1178,6 +1265,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1178 } 1265 }
1179 } 1266 }
1180 1267
1268 public List<DirGroupsReplyData> FindGroups(IClientAPI remoteClient, string query)
1269 {
1270 return m_groupData.FindGroups(GetRequestingAgentID(remoteClient), query);
1271 }
1272
1273
1181 #endregion 1274 #endregion
1182 1275
1183 #region Client/Update Tools 1276 #region Client/Update Tools
@@ -1222,7 +1315,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1222 AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID)); 1315 AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID));
1223 AgentData.Add(AgentDataMap); 1316 AgentData.Add(AgentDataMap);
1224 1317
1225
1226 OSDArray GroupData = new OSDArray(data.Length); 1318 OSDArray GroupData = new OSDArray(data.Length);
1227 OSDArray NewGroupData = new OSDArray(data.Length); 1319 OSDArray NewGroupData = new OSDArray(data.Length);
1228 1320
@@ -1288,7 +1380,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1288 presence.Grouptitle = Title; 1380 presence.Grouptitle = Title;
1289 1381
1290 if (! presence.IsChildAgent) 1382 if (! presence.IsChildAgent)
1291 presence.SendAvatarDataToAllAgents(); 1383 presence.SendAvatarDataToAllClients();
1292 } 1384 }
1293 } 1385 }
1294 } 1386 }
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
index 7bae8f7..1cb4747 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
@@ -42,7 +42,6 @@ using OpenMetaverse;
42using OpenMetaverse.StructuredData; 42using OpenMetaverse.StructuredData;
43 43
44using OpenSim.Framework; 44using OpenSim.Framework;
45using OpenSim.Framework.Communications;
46using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Services.Interfaces; 46using OpenSim.Services.Interfaces;
48 47
@@ -212,8 +211,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
212 m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR]: Initializing {0}", this.Name); 211 m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR]: Initializing {0}", this.Name);
213 212
214 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty); 213 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty);
215 if ((m_groupsServerURI == null) || 214 if (string.IsNullOrEmpty(m_groupsServerURI))
216 (m_groupsServerURI == string.Empty))
217 { 215 {
218 m_log.ErrorFormat("Please specify a valid Simian Server for GroupsServerURI in OpenSim.ini, [Groups]"); 216 m_log.ErrorFormat("Please specify a valid Simian Server for GroupsServerURI in OpenSim.ini, [Groups]");
219 m_connectorEnabled = false; 217 m_connectorEnabled = false;
@@ -438,7 +436,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
438 return null; 436 return null;
439 } 437 }
440 } 438 }
441 else if ((groupName != null) && (groupName != string.Empty)) 439 else if (!string.IsNullOrEmpty(groupName))
442 { 440 {
443 if (!SimianGetFirstGenericEntry("Group", groupName, out groupID, out GroupInfoMap)) 441 if (!SimianGetFirstGenericEntry("Group", groupName, out groupID, out GroupInfoMap))
444 { 442 {
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
index c1bdacb..9a42bac 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs
@@ -26,15 +26,25 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Net;
29using System.Reflection; 32using System.Reflection;
30using Nini.Config; 33using Nini.Config;
31using NUnit.Framework; 34using NUnit.Framework;
32using OpenMetaverse; 35using OpenMetaverse;
36using OpenMetaverse.Messages.Linden;
37using OpenMetaverse.Packets;
38using OpenMetaverse.StructuredData;
33using OpenSim.Framework; 39using OpenSim.Framework;
34using OpenSim.Framework.Communications; 40using OpenSim.Framework.Servers;
41using OpenSim.Framework.Servers.HttpServer;
42using OpenSim.Region.ClientStack.Linden;
43using OpenSim.Region.CoreModules.Avatar.InstantMessage;
44using OpenSim.Region.CoreModules.Framework;
35using OpenSim.Region.Framework.Scenes; 45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
36using OpenSim.Tests.Common; 47using OpenSim.Tests.Common;
37using OpenSim.Tests.Common.Mock;
38 48
39namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests 49namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
40{ 50{
@@ -44,11 +54,28 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
44 [TestFixture] 54 [TestFixture]
45 public class GroupsModuleTests : OpenSimTestCase 55 public class GroupsModuleTests : OpenSimTestCase
46 { 56 {
57 [SetUp]
58 public override void SetUp()
59 {
60 base.SetUp();
61
62 uint port = 9999;
63 uint sslPort = 9998;
64
65 // This is an unfortunate bit of clean up we have to do because MainServer manages things through static
66 // variables and the VM is not restarted between tests.
67 MainServer.RemoveHttpServer(port);
68
69 BaseHttpServer server = new BaseHttpServer(port, false, sslPort, "");
70 MainServer.AddHttpServer(server);
71 MainServer.Instance = server;
72 }
73
47 [Test] 74 [Test]
48 public void TestBasic() 75 public void TestSendAgentGroupDataUpdate()
49 { 76 {
50 TestHelpers.InMethod(); 77 TestHelpers.InMethod();
51// log4net.Config.XmlConfigurator.Configure(); 78// TestHelpers.EnableLogging();
52 79
53 TestScene scene = new SceneHelpers().SetupScene(); 80 TestScene scene = new SceneHelpers().SetupScene();
54 IConfigSource configSource = new IniConfigSource(); 81 IConfigSource configSource = new IniConfigSource();
@@ -56,8 +83,185 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests
56 config.Set("Enabled", true); 83 config.Set("Enabled", true);
57 config.Set("Module", "GroupsModule"); 84 config.Set("Module", "GroupsModule");
58 config.Set("DebugEnabled", true); 85 config.Set("DebugEnabled", true);
86
87 GroupsModule gm = new GroupsModule();
88 EventQueueGetModule eqgm = new EventQueueGetModule();
89
90 // We need a capabilities module active so that adding the scene presence creates an event queue in the
91 // EventQueueGetModule
59 SceneHelpers.SetupSceneModules( 92 SceneHelpers.SetupSceneModules(
60 scene, configSource, new object[] { new MockGroupsServicesConnector() }); 93 scene, configSource, gm, new MockGroupsServicesConnector(), new CapabilitiesModule(), eqgm);
94
95 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseStem("1"));
96
97 gm.SendAgentGroupDataUpdate(sp.ControllingClient);
98
99 Hashtable eventsResponse = eqgm.GetEvents(UUID.Zero, sp.UUID);
100
101 Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK));
102
103// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]);
104
105 OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]);
106 OSDArray eventsOsd = (OSDArray)rawOsd["events"];
107
108 bool foundUpdate = false;
109 foreach (OSD osd in eventsOsd)
110 {
111 OSDMap eventOsd = (OSDMap)osd;
112
113 if (eventOsd["message"] == "AgentGroupDataUpdate")
114 foundUpdate = true;
115 }
116
117 Assert.That(foundUpdate, Is.True, "Did not find AgentGroupDataUpdate in response");
118
119 // TODO: More checking of more actual event data.
120 }
121
122 [Test]
123 public void TestSendGroupNotice()
124 {
125 TestHelpers.InMethod();
126// TestHelpers.EnableLogging();
127
128 TestScene scene = new SceneHelpers().SetupScene();
129
130 MessageTransferModule mtm = new MessageTransferModule();
131 GroupsModule gm = new GroupsModule();
132 GroupsMessagingModule gmm = new GroupsMessagingModule();
133 MockGroupsServicesConnector mgsc = new MockGroupsServicesConnector();
134
135 IConfigSource configSource = new IniConfigSource();
136
137 {
138 IConfig config = configSource.AddConfig("Messaging");
139 config.Set("MessageTransferModule", mtm.Name);
140 }
141
142 {
143 IConfig config = configSource.AddConfig("Groups");
144 config.Set("Enabled", true);
145 config.Set("Module", gm.Name);
146 config.Set("DebugEnabled", true);
147 config.Set("MessagingModule", gmm.Name);
148 config.Set("MessagingEnabled", true);
149 }
150
151 SceneHelpers.SetupSceneModules(scene, configSource, mgsc, mtm, gm, gmm);
152
153 UUID userId = TestHelpers.ParseTail(0x1);
154 string subjectText = "newman";
155 string messageText = "Hello";
156 string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText);
157
158 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
159 TestClient tc = (TestClient)sp.ControllingClient;
160
161 UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true);
162 gm.JoinGroupRequest(tc, groupID);
163
164 // Create a second user who doesn't want to receive notices
165 ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2));
166 TestClient tc2 = (TestClient)sp2.ControllingClient;
167 gm.JoinGroupRequest(tc2, groupID);
168 gm.SetGroupAcceptNotices(tc2, groupID, false, true);
169
170 List<GridInstantMessage> spReceivedMessages = new List<GridInstantMessage>();
171 tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im);
172
173 List<GridInstantMessage> sp2ReceivedMessages = new List<GridInstantMessage>();
174 tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im);
175
176 GridInstantMessage noticeIm = new GridInstantMessage();
177 noticeIm.fromAgentID = userId.Guid;
178 noticeIm.toAgentID = groupID.Guid;
179 noticeIm.message = combinedSubjectMessage;
180 noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice;
181
182 tc.HandleImprovedInstantMessage(noticeIm);
183
184 Assert.That(spReceivedMessages.Count, Is.EqualTo(1));
185 Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage));
186
187 List<GroupNoticeData> notices = mgsc.GetGroupNotices(UUID.Zero, groupID);
188 Assert.AreEqual(1, notices.Count);
189
190 // OpenSimulator (possibly also SL) transport the notice ID as the session ID!
191 Assert.AreEqual(notices[0].NoticeID.Guid, spReceivedMessages[0].imSessionID);
192
193 Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0));
194 }
195
196 /// <summary>
197 /// Run test with the MessageOnlineUsersOnly flag set.
198 /// </summary>
199 [Test]
200 public void TestSendGroupNoticeOnlineOnly()
201 {
202 TestHelpers.InMethod();
203 // TestHelpers.EnableLogging();
204
205 TestScene scene = new SceneHelpers().SetupScene();
206
207 MessageTransferModule mtm = new MessageTransferModule();
208 GroupsModule gm = new GroupsModule();
209 GroupsMessagingModule gmm = new GroupsMessagingModule();
210
211 IConfigSource configSource = new IniConfigSource();
212
213 {
214 IConfig config = configSource.AddConfig("Messaging");
215 config.Set("MessageTransferModule", mtm.Name);
216 }
217
218 {
219 IConfig config = configSource.AddConfig("Groups");
220 config.Set("Enabled", true);
221 config.Set("Module", gm.Name);
222 config.Set("DebugEnabled", true);
223 config.Set("MessagingModule", gmm.Name);
224 config.Set("MessagingEnabled", true);
225 config.Set("MessageOnlineUsersOnly", true);
226 }
227
228 SceneHelpers.SetupSceneModules(scene, configSource, new MockGroupsServicesConnector(), mtm, gm, gmm);
229
230 UUID userId = TestHelpers.ParseTail(0x1);
231 string subjectText = "newman";
232 string messageText = "Hello";
233 string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText);
234
235 ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1));
236 TestClient tc = (TestClient)sp.ControllingClient;
237
238 UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true);
239 gm.JoinGroupRequest(tc, groupID);
240
241 // Create a second user who doesn't want to receive notices
242 ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2));
243 TestClient tc2 = (TestClient)sp2.ControllingClient;
244 gm.JoinGroupRequest(tc2, groupID);
245 gm.SetGroupAcceptNotices(tc2, groupID, false, true);
246
247 List<GridInstantMessage> spReceivedMessages = new List<GridInstantMessage>();
248 tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im);
249
250 List<GridInstantMessage> sp2ReceivedMessages = new List<GridInstantMessage>();
251 tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im);
252
253 GridInstantMessage noticeIm = new GridInstantMessage();
254 noticeIm.fromAgentID = userId.Guid;
255 noticeIm.toAgentID = groupID.Guid;
256 noticeIm.message = combinedSubjectMessage;
257 noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice;
258
259 tc.HandleImprovedInstantMessage(noticeIm);
260
261 Assert.That(spReceivedMessages.Count, Is.EqualTo(1));
262 Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage));
263
264 Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0));
61 } 265 }
62 } 266 }
63} \ No newline at end of file 267} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
index 1101851..20555e4 100644
--- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs
@@ -41,7 +41,6 @@ using OpenMetaverse;
41using OpenMetaverse.StructuredData; 41using OpenMetaverse.StructuredData;
42 42
43using OpenSim.Framework; 43using OpenSim.Framework;
44using OpenSim.Framework.Communications;
45using OpenSim.Region.Framework.Interfaces; 44using OpenSim.Region.Framework.Interfaces;
46using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
47 46
@@ -168,8 +167,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
168 m_log.DebugFormat("[XMLRPC-GROUPS-CONNECTOR]: Initializing {0}", this.Name); 167 m_log.DebugFormat("[XMLRPC-GROUPS-CONNECTOR]: Initializing {0}", this.Name);
169 168
170 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty); 169 m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty);
171 if ((m_groupsServerURI == null) || 170 if (string.IsNullOrEmpty(m_groupsServerURI))
172 (m_groupsServerURI == string.Empty))
173 { 171 {
174 m_log.ErrorFormat("Please specify a valid URL for GroupsServerURI in OpenSim.ini, [Groups]"); 172 m_log.ErrorFormat("Please specify a valid URL for GroupsServerURI in OpenSim.ini, [Groups]");
175 m_connectorEnabled = false; 173 m_connectorEnabled = false;
@@ -354,7 +352,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
354 { 352 {
355 param["GroupID"] = GroupID.ToString(); 353 param["GroupID"] = GroupID.ToString();
356 } 354 }
357 if ((GroupName != null) && (GroupName != string.Empty)) 355 if (!string.IsNullOrEmpty(GroupName))
358 { 356 {
359 param["Name"] = GroupName.ToString(); 357 param["Name"] = GroupName.ToString();
360 } 358 }
@@ -1013,7 +1011,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1013 Hashtable respData = (Hashtable)resp.Value; 1011 Hashtable respData = (Hashtable)resp.Value;
1014 if (respData.Contains("error") && !respData.Contains("succeed")) 1012 if (respData.Contains("error") && !respData.Contains("succeed"))
1015 { 1013 {
1016 LogRespDataToConsoleError(respData); 1014 LogRespDataToConsoleError(requestingAgentID, function, param, respData);
1017 } 1015 }
1018 1016
1019 return respData; 1017 return respData;
@@ -1041,20 +1039,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
1041 return error; 1039 return error;
1042 } 1040 }
1043 1041
1044 private void LogRespDataToConsoleError(Hashtable respData) 1042 private void LogRespDataToConsoleError(UUID requestingAgentID, string function, Hashtable param, Hashtable respData)
1045 { 1043 {
1046 m_log.Error("[XMLRPC-GROUPS-CONNECTOR]: Error:"); 1044 m_log.ErrorFormat(
1047 1045 "[XMLRPC-GROUPS-CONNECTOR]: Error when calling {0} for {1} with params {2}. Response params are {3}",
1048 foreach (string key in respData.Keys) 1046 function, requestingAgentID, Util.PrettyFormatToSingleLine(param), Util.PrettyFormatToSingleLine(respData));
1049 {
1050 m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: Key: {0}", key);
1051
1052 string[] lines = respData[key].ToString().Split(new char[] { '\n' });
1053 foreach (string line in lines)
1054 {
1055 m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: {0}", line);
1056 }
1057 }
1058 } 1047 }
1059 1048
1060 /// <summary> 1049 /// <summary>
@@ -1146,28 +1135,38 @@ namespace Nwc.XmlRpc
1146 request.AllowWriteStreamBuffering = true; 1135 request.AllowWriteStreamBuffering = true;
1147 request.KeepAlive = !_disableKeepAlive; 1136 request.KeepAlive = !_disableKeepAlive;
1148 1137
1149 Stream stream = request.GetRequestStream(); 1138 using (Stream stream = request.GetRequestStream())
1150 XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII);
1151 _serializer.Serialize(xml, this);
1152 xml.Flush();
1153 xml.Close();
1154
1155 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
1156 StreamReader input = new StreamReader(response.GetResponseStream());
1157
1158 string inputXml = input.ReadToEnd();
1159 XmlRpcResponse resp;
1160 try
1161 { 1139 {
1162 resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); 1140 using (XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII))
1141 {
1142 _serializer.Serialize(xml, this);
1143 xml.Flush();
1144 }
1163 } 1145 }
1164 catch (Exception e) 1146
1147 XmlRpcResponse resp;
1148
1149 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
1165 { 1150 {
1166 RequestResponse = inputXml; 1151 using (Stream s = response.GetResponseStream())
1167 throw e; 1152 {
1153 using (StreamReader input = new StreamReader(s))
1154 {
1155 string inputXml = input.ReadToEnd();
1156
1157 try
1158 {
1159 resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml);
1160 }
1161 catch (Exception e)
1162 {
1163 RequestResponse = inputXml;
1164 throw e;
1165 }
1166 }
1167 }
1168 } 1168 }
1169 input.Close(); 1169
1170 response.Close();
1171 return resp; 1170 return resp;
1172 } 1171 }
1173 } 1172 }