From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Thu, 3 Nov 2016 21:44:39 +1000 Subject: Initial update to OpenSim 0.8.2.1 source code. --- .../Avatar/Appearance/AppearanceInfoModule.cs | 196 ++++++++++++- .../Avatar/Attachments/AttachmentsCommandModule.cs | 17 +- .../Avatar/Attachments/TempAttachmentsModule.cs | 5 +- .../OptionalModules/Avatar/Chat/ChannelState.cs | 160 +++++------ .../OptionalModules/Avatar/Chat/IRCBridgeModule.cs | 41 +-- .../OptionalModules/Avatar/Chat/IRCConnector.cs | 303 +++++++++++---------- .../OptionalModules/Avatar/Chat/RegionState.cs | 98 ++++--- .../Avatar/Concierge/ConciergeModule.cs | 6 +- .../Avatar/SitStand/SitStandCommandsModule.cs | 220 +++++++++++++++ .../Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs | 41 +-- .../Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | 75 ++--- .../Avatar/XmlRpcGroups/GroupsMessagingModule.cs | 289 +++++++++++++------- .../Avatar/XmlRpcGroups/GroupsModule.cs | 272 ++++++++++++------ .../SimianGroupsServicesConnectorModule.cs | 6 +- .../Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs | 214 ++++++++++++++- .../XmlRpcGroupsServicesConnectorModule.cs | 71 +++-- 16 files changed, 1421 insertions(+), 593 deletions(-) create mode 100644 OpenSim/Region/OptionalModules/Avatar/SitStand/SitStandCommandsModule.cs (limited to 'OpenSim/Region/OptionalModules/Avatar') 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 { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private Dictionary m_scenes = new Dictionary(); + private List m_scenes = new List(); + // private IAvatarFactoryModule m_avatarFactory; public string Name { get { return "Appearance Information Module"; } } @@ -83,7 +84,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance // m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); lock (m_scenes) - m_scenes.Remove(scene.RegionInfo.RegionID); + m_scenes.Remove(scene); } public void RegionLoaded(Scene scene) @@ -91,7 +92,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance // m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); lock (m_scenes) - m_scenes[scene.RegionInfo.RegionID] = scene; + m_scenes.Add(scene); scene.AddCommand( "Users", this, "show appearance", @@ -102,7 +103,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance scene.AddCommand( "Users", this, "appearance show", "appearance show [ ]", - "Show appearance information for each avatar in the simulator.", + "Show appearance information for avatars.", "This command checks whether the simulator has all the baked textures required to display an avatar to other viewers. " + "\nIf not, then appearance is 'corrupt' and other avatars will continue to see it as a cloud." + "\nOptionally, you can view just a particular avatar's appearance information." @@ -132,6 +133,21 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance "Find out which avatar uses the given asset as a baked texture, if any.", "You can specify just the beginning of the uuid, e.g. 2008a8d. A longer UUID must be in dashed format.", HandleFindAppearanceCommand); + + scene.AddCommand( + "Users", this, "wearables show", + "wearables show [ ]", + "Show information about wearables for avatars.", + "If no avatar name is given then a general summary for all avatars in the scene is shown.\n" + + "If an avatar name is given then specific information about current wearables is shown.", + HandleShowWearablesCommand); + + scene.AddCommand( + "Users", this, "wearables check", + "wearables check ", + "Check that the wearables of a given avatar in the scene are valid.", + "This currently checks that the wearable assets themselves and any assets referenced by them exist.", + HandleCheckWearablesCommand); } private void HandleSendAppearanceCommand(string module, string[] cmd) @@ -155,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance lock (m_scenes) { - foreach (Scene scene in m_scenes.Values) + foreach (Scene scene in m_scenes) { if (targetNameSupplied) { @@ -186,7 +202,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance } } - protected void HandleShowAppearanceCommand(string module, string[] cmd) + private void HandleShowAppearanceCommand(string module, string[] cmd) { if (cmd.Length != 2 && cmd.Length < 4) { @@ -207,7 +223,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance lock (m_scenes) { - foreach (Scene scene in m_scenes.Values) + foreach (Scene scene in m_scenes) { if (targetNameSupplied) { @@ -222,7 +238,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance { bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(sp); MainConsole.Instance.OutputFormat( - "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "corrupt"); + "{0} baked appearance texture is {1}", sp.Name, bakedTextureValid ? "OK" : "incomplete"); } ); } @@ -243,7 +259,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance lock (m_scenes) { - foreach (Scene scene in m_scenes.Values) + foreach (Scene scene in m_scenes) { ScenePresence sp = scene.GetScenePresence(firstname, lastname); if (sp != null && !sp.IsChildAgent) @@ -263,7 +279,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance } } - protected void HandleFindAppearanceCommand(string module, string[] cmd) + private void HandleFindAppearanceCommand(string module, string[] cmd) { if (cmd.Length != 3) { @@ -277,7 +293,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance lock (m_scenes) { - foreach (Scene scene in m_scenes.Values) + foreach (Scene scene in m_scenes) { scene.ForEachRootScenePresence( sp => @@ -304,5 +320,163 @@ namespace OpenSim.Region.OptionalModules.Avatar.Appearance string.Join(", ", matchedAvatars.ToList().ConvertAll(sp => sp.Name).ToArray())); } } + + protected void HandleShowWearablesCommand(string module, string[] cmd) + { + if (cmd.Length != 2 && cmd.Length < 4) + { + MainConsole.Instance.OutputFormat("Usage: wearables show [ ]"); + return; + } + + bool targetNameSupplied = false; + string optionalTargetFirstName = null; + string optionalTargetLastName = null; + + if (cmd.Length >= 4) + { + targetNameSupplied = true; + optionalTargetFirstName = cmd[2]; + optionalTargetLastName = cmd[3]; + } + + StringBuilder sb = new StringBuilder(); + + if (targetNameSupplied) + { + lock (m_scenes) + { + foreach (Scene scene in m_scenes) + { + ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName); + if (sp != null && !sp.IsChildAgent) + AppendWearablesDetailReport(sp, sb); + } + } + } + else + { + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Name", ConsoleDisplayUtil.UserNameSize); + cdt.AddColumn("Wearables", 2); + + lock (m_scenes) + { + foreach (Scene scene in m_scenes) + { + scene.ForEachRootScenePresence( + sp => + { + int count = 0; + + for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++) + count += sp.Appearance.Wearables[i].Count; + + cdt.AddRow(sp.Name, count); + } + ); + } + } + + sb.Append(cdt.ToString()); + } + + MainConsole.Instance.Output(sb.ToString()); + } + + private void HandleCheckWearablesCommand(string module, string[] cmd) + { + if (cmd.Length != 4) + { + MainConsole.Instance.OutputFormat("Usage: wearables check "); + return; + } + + string firstname = cmd[2]; + string lastname = cmd[3]; + + StringBuilder sb = new StringBuilder(); + UuidGatherer uuidGatherer = new UuidGatherer(m_scenes[0].AssetService); + + lock (m_scenes) + { + foreach (Scene scene in m_scenes) + { + ScenePresence sp = scene.GetScenePresence(firstname, lastname); + if (sp != null && !sp.IsChildAgent) + { + sb.AppendFormat("Wearables checks for {0}\n\n", sp.Name); + + for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++) + { + AvatarWearable aw = sp.Appearance.Wearables[i]; + + if (aw.Count > 0) + { + sb.Append(Enum.GetName(typeof(WearableType), i)); + sb.Append("\n"); + + for (int j = 0; j < aw.Count; j++) + { + WearableItem wi = aw[j]; + + ConsoleDisplayList cdl = new ConsoleDisplayList(); + cdl.Indent = 2; + cdl.AddRow("Item UUID", wi.ItemID); + cdl.AddRow("Assets", ""); + sb.Append(cdl.ToString()); + + uuidGatherer.AddForInspection(wi.AssetID); + uuidGatherer.GatherAll(); + string[] assetStrings + = Array.ConvertAll(uuidGatherer.GatheredUuids.Keys.ToArray(), u => u.ToString()); + + bool[] existChecks = scene.AssetService.AssetsExist(assetStrings); + + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.Indent = 4; + cdt.AddColumn("Type", 10); + cdt.AddColumn("UUID", ConsoleDisplayUtil.UuidSize); + cdt.AddColumn("Found", 5); + + for (int k = 0; k < existChecks.Length; k++) + cdt.AddRow( + (AssetType)uuidGatherer.GatheredUuids[new UUID(assetStrings[k])], + assetStrings[k], existChecks[k] ? "yes" : "no"); + + sb.Append(cdt.ToString()); + sb.Append("\n"); + } + } + } + } + } + } + + MainConsole.Instance.Output(sb.ToString()); + } + + private void AppendWearablesDetailReport(ScenePresence sp, StringBuilder sb) + { + sb.AppendFormat("\nWearables for {0}\n", sp.Name); + + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Type", 10); + cdt.AddColumn("Item UUID", ConsoleDisplayUtil.UuidSize); + cdt.AddColumn("Asset UUID", ConsoleDisplayUtil.UuidSize); + + for (int i = (int)WearableType.Shape; i < (int)WearableType.Physics; i++) + { + AvatarWearable aw = sp.Appearance.Wearables[i]; + + for (int j = 0; j < aw.Count; j++) + { + WearableItem wi = aw[j]; + cdt.AddRow(Enum.GetName(typeof(WearableType), i), wi.ItemID, wi.AssetID); + } + } + + sb.Append(cdt.ToString()); + } } } \ 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 // " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", // attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, // (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); - ct.Rows.Add( - new ConsoleDisplayTableRow( - new List() - { - attachmentObject.Name, - attachmentObject.LocalId.ToString(), - attachmentObject.FromItemID.ToString(), - ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(), - attachmentObject.RootPart.AttachedPos.ToString() - })); + + ct.AddRow( + attachmentObject.Name, + attachmentObject.LocalId, + attachmentObject.FromItemID, + ((AttachmentPoint)attachmentObject.AttachmentPoint), + attachmentObject.RootPart.AttachedPos); // } } 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; using OpenSim.Region.ClientStack.LindenUDP; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using PermissionMask = OpenSim.Framework.PermissionMask; namespace OpenSim.Region.OptionalModules.Avatar.Attachments { @@ -76,7 +77,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments if (m_console != null) { - 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); + 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); } } else @@ -183,7 +184,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments hostPart.ParentGroup.RootPart.ScheduleFullUpdate(); } - return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, true) ? 1 : 0; + return attachmentsModule.AttachObject(target, hostPart.ParentGroup, (uint)attachmentPoint, false, false, true) ? 1 : 0; } } } 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 // These are the IRC Connector configurable parameters with hard-wired // default values (retained for compatability). - internal string Server = null; - internal string Password = null; - internal string IrcChannel = null; - internal string BaseNickname = "OSimBot"; - internal uint Port = 6667; - internal string User = null; - - internal bool ClientReporting = true; - internal bool RelayChat = true; - internal bool RelayPrivateChannels = false; - internal int RelayChannel = 1; + internal string Server = null; + internal string Password = null; + internal string IrcChannel = null; + internal string BaseNickname = "OSimBot"; + internal uint Port = 6667; + internal string User = null; + + internal bool ClientReporting = true; + internal bool RelayChat = true; + internal bool RelayPrivateChannels = false; + internal int RelayChannel = 1; internal List ValidInWorldChannels = new List(); // Connector agnostic parameters. These values are NOT shared with the // connector and do not differentiate at an IRC level internal string PrivateMessageFormat = "PRIVMSG {0} :<{2}> {1} {3}"; - internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}"; - internal int RelayChannelOut = -1; - internal bool RandomizeNickname = true; - internal bool CommandsEnabled = false; - internal int CommandChannel = -1; - internal int ConnectDelay = 10; - internal int PingDelay = 15; - internal string DefaultZone = "Sim"; - - internal string _accessPassword = String.Empty; - internal Regex AccessPasswordRegex = null; - internal List ExcludeList = new List(); + internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}"; + internal int RelayChannelOut = -1; + internal bool RandomizeNickname = true; + internal bool CommandsEnabled = false; + internal int CommandChannel = -1; + internal int ConnectDelay = 10; + internal int PingDelay = 15; + internal string DefaultZone = "Sim"; + + internal string _accessPassword = String.Empty; + internal Regex AccessPasswordRegex = null; + internal List ExcludeList = new List(); internal string AccessPassword { get { return _accessPassword; } - set + set { _accessPassword = value; - AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?[^,]+),\s*(?.+)$", _accessPassword), + AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?[^,]+),\s*(?.+)$", _accessPassword), RegexOptions.Compiled); } } @@ -99,9 +99,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // IRC connector reference - internal IRCConnector irc = null; + internal IRCConnector irc = null; - internal int idn = _idk_++; + internal int idn = _idk_++; // List of regions dependent upon this connection @@ -119,29 +119,29 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat internal ChannelState(ChannelState model) { - Server = model.Server; - Password = model.Password; - IrcChannel = model.IrcChannel; - Port = model.Port; - BaseNickname = model.BaseNickname; - RandomizeNickname = model.RandomizeNickname; - User = model.User; - CommandsEnabled = model.CommandsEnabled; - CommandChannel = model.CommandChannel; - RelayChat = model.RelayChat; + Server = model.Server; + Password = model.Password; + IrcChannel = model.IrcChannel; + Port = model.Port; + BaseNickname = model.BaseNickname; + RandomizeNickname = model.RandomizeNickname; + User = model.User; + CommandsEnabled = model.CommandsEnabled; + CommandChannel = model.CommandChannel; + RelayChat = model.RelayChat; RelayPrivateChannels = model.RelayPrivateChannels; - RelayChannelOut = model.RelayChannelOut; - RelayChannel = model.RelayChannel; + RelayChannelOut = model.RelayChannelOut; + RelayChannel = model.RelayChannel; ValidInWorldChannels = model.ValidInWorldChannels; PrivateMessageFormat = model.PrivateMessageFormat; - NoticeMessageFormat = model.NoticeMessageFormat; - ClientReporting = model.ClientReporting; - AccessPassword = model.AccessPassword; - DefaultZone = model.DefaultZone; - ConnectDelay = model.ConnectDelay; - PingDelay = model.PingDelay; + NoticeMessageFormat = model.NoticeMessageFormat; + ClientReporting = model.ClientReporting; + AccessPassword = model.AccessPassword; + DefaultZone = model.DefaultZone; + ConnectDelay = model.ConnectDelay; + PingDelay = model.PingDelay; } - + // Read the configuration file, performing variable substitution and any // necessary aliasing. See accompanying documentation for how this works. // If you don't need variables, then this works exactly as before. @@ -160,54 +160,54 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_log.DebugFormat("[IRC-Channel-{0}] Initial request by Region {1} to connect to IRC", cs.idn, rs.Region); - cs.Server = Substitute(rs, config.GetString("server", null)); + cs.Server = Substitute(rs, config.GetString("server", null)); m_log.DebugFormat("[IRC-Channel-{0}] Server : <{1}>", cs.idn, cs.Server); - cs.Password = Substitute(rs, config.GetString("password", null)); + cs.Password = Substitute(rs, config.GetString("password", null)); // probably not a good idea to put a password in the log file - cs.User = Substitute(rs, config.GetString("user", null)); - cs.IrcChannel = Substitute(rs, config.GetString("channel", null)); + cs.User = Substitute(rs, config.GetString("user", null)); + cs.IrcChannel = Substitute(rs, config.GetString("channel", null)); m_log.DebugFormat("[IRC-Channel-{0}] IrcChannel : <{1}>", cs.idn, cs.IrcChannel); - cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port)))); + cs.Port = Convert.ToUInt32(Substitute(rs, config.GetString("port", Convert.ToString(cs.Port)))); m_log.DebugFormat("[IRC-Channel-{0}] Port : <{1}>", cs.idn, cs.Port); - cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname)); + cs.BaseNickname = Substitute(rs, config.GetString("nick", cs.BaseNickname)); m_log.DebugFormat("[IRC-Channel-{0}] BaseNickname : <{1}>", cs.idn, cs.BaseNickname); - cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname)))); + cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("randomize_nick", Convert.ToString(cs.RandomizeNickname)))); m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); - cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname)))); + cs.RandomizeNickname = Convert.ToBoolean(Substitute(rs, config.GetString("nicknum", Convert.ToString(cs.RandomizeNickname)))); m_log.DebugFormat("[IRC-Channel-{0}] RandomizeNickname : <{1}>", cs.idn, cs.RandomizeNickname); - cs.User = Substitute(rs, config.GetString("username", cs.User)); + cs.User = Substitute(rs, config.GetString("username", cs.User)); m_log.DebugFormat("[IRC-Channel-{0}] User : <{1}>", cs.idn, cs.User); - cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled)))); + cs.CommandsEnabled = Convert.ToBoolean(Substitute(rs, config.GetString("commands_enabled", Convert.ToString(cs.CommandsEnabled)))); m_log.DebugFormat("[IRC-Channel-{0}] CommandsEnabled : <{1}>", cs.idn, cs.CommandsEnabled); - cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel)))); + cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("commandchannel", Convert.ToString(cs.CommandChannel)))); m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); - cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel)))); + cs.CommandChannel = Convert.ToInt32(Substitute(rs, config.GetString("command_channel", Convert.ToString(cs.CommandChannel)))); m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, cs.CommandChannel); - cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat)))); + cs.RelayChat = Convert.ToBoolean(Substitute(rs, config.GetString("relay_chat", Convert.ToString(cs.RelayChat)))); m_log.DebugFormat("[IRC-Channel-{0}] RelayChat : <{1}>", cs.idn, cs.RelayChat); cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("relay_private_channels", Convert.ToString(cs.RelayPrivateChannels)))); m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels)))); m_log.DebugFormat("[IRC-Channel-{0}] RelayPrivateChannels : <{1}>", cs.idn, cs.RelayPrivateChannels); - cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut)))); + cs.RelayChannelOut = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_out", Convert.ToString(cs.RelayChannelOut)))); m_log.DebugFormat("[IRC-Channel-{0}] RelayChannelOut : <{1}>", cs.idn, cs.RelayChannelOut); - cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel)))); + cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("relay_private_channel_in", Convert.ToString(cs.RelayChannel)))); m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); - cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel)))); + cs.RelayChannel = Convert.ToInt32(Substitute(rs, config.GetString("inchannel", Convert.ToString(cs.RelayChannel)))); m_log.DebugFormat("[IRC-Channel-{0}] RelayChannel : <{1}>", cs.idn, cs.RelayChannel); cs.PrivateMessageFormat = Substitute(rs, config.GetString("msgformat", cs.PrivateMessageFormat)); m_log.DebugFormat("[IRC-Channel-{0}] PrivateMessageFormat : <{1}>", cs.idn, cs.PrivateMessageFormat); cs.NoticeMessageFormat = Substitute(rs, config.GetString("noticeformat", cs.NoticeMessageFormat)); m_log.DebugFormat("[IRC-Channel-{0}] NoticeMessageFormat : <{1}>", cs.idn, cs.NoticeMessageFormat); - cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting?"1":"0"))) > 0; + cs.ClientReporting = Convert.ToInt32(Substitute(rs, config.GetString("verbosity", cs.ClientReporting ? "1" : "0"))) > 0; m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); - cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting)))); + cs.ClientReporting = Convert.ToBoolean(Substitute(rs, config.GetString("report_clients", Convert.ToString(cs.ClientReporting)))); m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting); - cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone)); + cs.DefaultZone = Substitute(rs, config.GetString("fallback_region", cs.DefaultZone)); m_log.DebugFormat("[IRC-Channel-{0}] DefaultZone : <{1}>", cs.idn, cs.DefaultZone); - cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay)))); + cs.ConnectDelay = Convert.ToInt32(Substitute(rs, config.GetString("connect_delay", Convert.ToString(cs.ConnectDelay)))); m_log.DebugFormat("[IRC-Channel-{0}] ConnectDelay : <{1}>", cs.idn, cs.ConnectDelay); - cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay)))); + cs.PingDelay = Convert.ToInt32(Substitute(rs, config.GetString("ping_delay", Convert.ToString(cs.PingDelay)))); m_log.DebugFormat("[IRC-Channel-{0}] PingDelay : <{1}>", cs.idn, cs.PingDelay); cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword)); m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword); @@ -217,7 +217,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat { cs.ExcludeList.Add(name.Trim().ToLower()); } - + // Fail if fundamental information is still missing if (cs.Server == null) @@ -306,8 +306,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat IRCBridgeModule.m_channels.Add(cs); - m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", - cs.idn, rs.Region, cs.DefaultZone, + m_log.InfoFormat("[IRC-Channel-{0}] New channel initialized for {1}, nick: {2}, commands {3}, private channels {4}", + cs.idn, rs.Region, cs.DefaultZone, cs.CommandsEnabled ? "enabled" : "not enabled", cs.RelayPrivateChannels ? "relayed" : "not relayed"); } @@ -417,7 +417,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat private bool IsAConnectionMatchFor(ChannelState cs) { return ( - Server == cs.Server && + Server == cs.Server && IrcChannel == cs.IrcChannel && Port == cs.Port && BaseNickname == cs.BaseNickname && @@ -461,7 +461,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat string result = instr; - if (result == null || result.Length == 0) + if (string.IsNullOrEmpty(result)) return result; // Repeatedly scan the string until all possible @@ -473,27 +473,27 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat { string vvar = arg.Match(result).ToString(); - string var = vvar.Substring(1,vvar.Length-2).Trim(); + string var = vvar.Substring(1, vvar.Length - 2).Trim(); switch (var.ToLower()) { - case "%region" : + case "%region": result = result.Replace(vvar, rs.Region); break; - case "%host" : + case "%host": result = result.Replace(vvar, rs.Host); break; - case "%locx" : + case "%locx": result = result.Replace(vvar, rs.LocX); break; - case "%locy" : + case "%locy": result = result.Replace(vvar, rs.LocY); break; - case "%k" : + case "%k": result = result.Replace(vvar, rs.IDK); break; - default : - result = result.Replace(vvar, rs.config.GetString(var,var)); + default: + result = result.Replace(vvar, rs.config.GetString(var, var)); break; } // 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 { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - internal static bool m_pluginEnabled = false; + internal static bool Enabled = false; internal static IConfig m_config = null; internal static List m_channels = new List(); - internal static List m_regions = new List(); + internal static List m_regions = new List(); internal static string m_password = String.Empty; internal RegionState m_region = null; #region INonSharedRegionModule Members - public Type ReplaceableInterface + public Type ReplaceableInterface { get { return null; } } @@ -72,13 +72,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_config = config.Configs["IRC"]; if (m_config == null) { -// m_log.InfoFormat("[IRC-Bridge] module not configured"); + // m_log.InfoFormat("[IRC-Bridge] module not configured"); return; } if (!m_config.GetBoolean("enabled", false)) { -// m_log.InfoFormat("[IRC-Bridge] module disabled in configuration"); + // m_log.InfoFormat("[IRC-Bridge] module disabled in configuration"); return; } @@ -87,19 +87,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_password = config.Configs["RemoteAdmin"].GetString("access_password", m_password); } - m_pluginEnabled = true; - m_log.InfoFormat("[IRC-Bridge]: Module enabled"); + Enabled = true; + + m_log.InfoFormat("[IRC-Bridge]: Module is enabled"); } public void AddRegion(Scene scene) { - if (m_pluginEnabled) + if (Enabled) { try { m_log.InfoFormat("[IRC-Bridge] Connecting region {0}", scene.RegionInfo.RegionName); + if (!String.IsNullOrEmpty(m_password)) MainServer.Instance.AddXmlRPCHandler("irc_admin", XmlRpcAdminMethod, false); + m_region = new RegionState(scene, m_config); lock (m_regions) m_regions.Add(m_region); m_region.Open(); @@ -123,7 +126,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat public void RemoveRegion(Scene scene) { - if (!m_pluginEnabled) + if (!Enabled) return; if (m_region == null) @@ -150,12 +153,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_log.Debug("[IRC-Bridge]: XML RPC Admin Entry"); XmlRpcResponse response = new XmlRpcResponse(); - Hashtable responseData = new Hashtable(); + Hashtable responseData = new Hashtable(); try { Hashtable requestData = (Hashtable)request.Params[0]; - bool found = false; + bool found = false; string region = String.Empty; if (m_password != String.Empty) @@ -169,18 +172,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat if (!requestData.ContainsKey("region")) throw new Exception("No region name specified"); region = (string)requestData["region"]; - + foreach (RegionState rs in m_regions) { if (rs.Region == region) { - responseData["server"] = rs.cs.Server; - responseData["port"] = (int)rs.cs.Port; - responseData["user"] = rs.cs.User; - responseData["channel"] = rs.cs.IrcChannel; - responseData["enabled"] = rs.cs.irc.Enabled; + responseData["server"] = rs.cs.Server; + responseData["port"] = (int)rs.cs.Port; + responseData["user"] = rs.cs.User; + responseData["channel"] = rs.cs.IrcChannel; + responseData["enabled"] = rs.cs.irc.Enabled; responseData["connected"] = rs.cs.irc.Connected; - responseData["nickname"] = rs.cs.irc.Nick; + responseData["nickname"] = rs.cs.irc.Nick; found = true; break; } @@ -195,7 +198,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_log.ErrorFormat("[IRC-Bridge] XML RPC Admin request failed : {0}", e.Message); responseData["success"] = "false"; - responseData["error"] = e.Message; + responseData["error"] = e.Message; } finally { 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 // Local constants + // This computation is not the real region center if the region is larger than 256. + // This computation isn't fixed because there is not a handle back to the region. private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); - private static readonly char[] CS_SPACE = { ' ' }; + private static readonly char[] CS_SPACE = { ' ' }; - private const int WD_INTERVAL = 1000; // base watchdog interval - private static int PING_PERIOD = 15; // WD intervals per PING - private static int ICCD_PERIOD = 10; // WD intervals between Connects - private static int L_TIMEOUT = 25; // Login time out interval + private const int WD_INTERVAL = 1000; // base watchdog interval + private static int PING_PERIOD = 15; // WD intervals per PING + private static int ICCD_PERIOD = 10; // WD intervals between Connects + private static int L_TIMEOUT = 25; // Login time out interval - private static int _idk_ = 0; // core connector identifier - private static int _pdk_ = 0; // ping interval counter - private static int _icc_ = ICCD_PERIOD; // IRC connect counter + private static int _idk_ = 0; // core connector identifier + private static int _pdk_ = 0; // ping interval counter + private static int _icc_ = ICCD_PERIOD; // IRC connect counter // List of configured connectors @@ -107,13 +109,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat internal int m_resetk = 0; - // Working threads - - private Thread m_listener = null; - private Object msyncConnect = new Object(); - internal bool m_randomizeNick = true; // add random suffix + internal bool m_randomizeNick = true; // add random suffix internal string m_baseNick = null; // base name for randomizing internal string m_nick = null; // effective nickname @@ -122,7 +120,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat get { return m_nick; } set { m_nick = value; } } - + private bool m_enabled = false; // connector enablement public bool Enabled { @@ -130,8 +128,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat } private bool m_connected = false; // connection status - private bool m_pending = false; // login disposition - private int m_timeout = L_TIMEOUT; // login timeout counter + private bool m_pending = false; // login disposition + private int m_timeout = L_TIMEOUT; // login timeout counter public bool Connected { get { return m_connected; } @@ -143,9 +141,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat get { return m_ircChannel; } set { m_ircChannel = value; } } - + private uint m_port = 6667; // session port - public uint Port + public uint Port { get { return m_port; } set { m_port = value; } @@ -172,10 +170,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // Network interface - private TcpClient m_tcp; + private TcpClient m_tcp; private NetworkStream m_stream = null; - private StreamReader m_reader; - private StreamWriter m_writer; + private StreamReader m_reader; + private StreamWriter m_writer; // Channel characteristic info (if available) @@ -193,26 +191,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // Prepare network interface - m_tcp = null; + m_tcp = null; m_writer = null; m_reader = null; // Setup IRC session parameters - m_server = cs.Server; - m_password = cs.Password; - m_baseNick = cs.BaseNickname; + m_server = cs.Server; + m_password = cs.Password; + m_baseNick = cs.BaseNickname; m_randomizeNick = cs.RandomizeNickname; - m_ircChannel = cs.IrcChannel; - m_port = cs.Port; - m_user = cs.User; + m_ircChannel = cs.IrcChannel; + m_port = cs.Port; + m_user = cs.User; if (m_watchdog == null) { // Non-differentiating - ICCD_PERIOD = cs.ConnectDelay; - PING_PERIOD = cs.PingDelay; + ICCD_PERIOD = cs.ConnectDelay; + PING_PERIOD = cs.PingDelay; // Smaller values are not reasonable @@ -235,7 +233,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat if (m_randomizeNick) m_nick = m_baseNick + Util.RandomClass.Next(1, 99); - else + else m_nick = m_baseNick; m_log.InfoFormat("[IRC-Connector-{0}]: Initialization complete", idn); @@ -295,18 +293,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_nick, m_ircChannel, m_server)); m_writer.Flush(); } - catch (Exception) {} - + catch (Exception) { } + m_connected = false; - try { m_writer.Close(); } catch (Exception) {} - try { m_reader.Close(); } catch (Exception) {} - try { m_stream.Close(); } catch (Exception) {} - try { m_tcp.Close(); } catch (Exception) {} + try { m_writer.Close(); } + catch (Exception) { } + try { m_reader.Close(); } + catch (Exception) { } + try { m_stream.Close(); } + catch (Exception) { } + try { m_tcp.Close(); } + catch (Exception) { } } - + lock (m_connectors) m_connectors.Remove(this); @@ -347,20 +349,17 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat if (m_connected) return; m_connected = true; - m_pending = true; - m_timeout = L_TIMEOUT; + m_pending = true; + m_timeout = L_TIMEOUT; - m_tcp = new TcpClient(m_server, (int)m_port); + m_tcp = new TcpClient(m_server, (int)m_port); m_stream = m_tcp.GetStream(); m_reader = new StreamReader(m_stream); m_writer = new StreamWriter(m_stream); - m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); + m_log.InfoFormat("[IRC-Connector-{0}]: Connected to {1}:{2}", idn, m_server, m_port); - m_listener = new Thread(new ThreadStart(ListenerRun)); - m_listener.Name = "IRCConnectorListenerThread"; - m_listener.IsBackground = true; - m_listener.Start(); + WorkManager.StartThread(ListenerRun, "IRCConnectionListenerThread", ThreadPriority.Normal, true, false); // This is the message order recommended by RFC 2812 if (m_password != null) @@ -418,12 +417,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // the socket and it will disappear of its own accord, once this // processing is completed. - try { m_writer.Close(); } catch (Exception) {} - try { m_reader.Close(); } catch (Exception) {} - try { m_tcp.Close(); } catch (Exception) {} + try { m_writer.Close(); } + catch (Exception) { } + try { m_reader.Close(); } + catch (Exception) { } + try { m_tcp.Close(); } + catch (Exception) { } m_connected = false; - m_pending = false; + m_pending = false; m_resetk++; } @@ -495,27 +497,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat { string inputLine; - int resetk = m_resetk; + int resetk = m_resetk; try { while (m_enabled && m_connected) { - if ((inputLine = m_reader.ReadLine()) == null) throw new Exception("Listener input socket closed"); + Watchdog.UpdateThread(); + // m_log.Info("[IRCConnector]: " + inputLine); if (inputLine.Contains("PRIVMSG")) { - Dictionary data = ExtractMsg(inputLine); // Any chat ??? if (data != null) { - OSChatMessage c = new OSChatMessage(); c.Message = data["msg"]; c.Type = ChatTypeEnum.Region; @@ -531,9 +532,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat c.Message = String.Format("/me {0}", c.Message.Substring(8, c.Message.Length - 9)); ChannelState.OSChat(this, c, false); - } - } else { @@ -553,9 +552,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat if (m_enabled && (m_resetk == resetk)) Reconnect(); + + Watchdog.RemoveThread(); } - private Regex RE = new Regex(@":(?[\w-]*)!(?\S*) PRIVMSG (?\S+) :(?.*)", + private Regex RE = new Regex(@":(?[\w-]*)!(?\S*) PRIVMSG (?\S+) :(?.*)", RegexOptions.Multiline); private Dictionary ExtractMsg(string input) @@ -617,8 +618,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat string[] commArgs; string c_server = m_server; - string pfx = String.Empty; - string cmd = String.Empty; + string pfx = String.Empty; + string cmd = String.Empty; string parms = String.Empty; // ":" indicates that a prefix is present @@ -627,15 +628,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // ":" indicates that the remainder of the // line is a single parameter value. - commArgs = command.Split(CS_SPACE,2); + commArgs = command.Split(CS_SPACE, 2); if (commArgs[0].StartsWith(":")) { pfx = commArgs[0].Substring(1); - commArgs = commArgs[1].Split(CS_SPACE,2); + commArgs = commArgs[1].Split(CS_SPACE, 2); } - cmd = commArgs[0]; + cmd = commArgs[0]; parms = commArgs[1]; // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}>", idn, pfx, cmd); @@ -646,44 +647,44 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // Messages 001-004 are always sent // following signon. - case "001" : // Welcome ... - case "002" : // Server information - case "003" : // Welcome ... + case "001": // Welcome ... + case "002": // Server information + case "003": // Welcome ... break; - case "004" : // Server information + case "004": // Server information m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); commArgs = parms.Split(CS_SPACE); c_server = commArgs[1]; m_server = c_server; - version = commArgs[2]; - usermod = commArgs[3]; - chanmod = commArgs[4]; + version = commArgs[2]; + usermod = commArgs[3]; + chanmod = commArgs[4]; break; - case "005" : // Server information + case "005": // Server information break; - case "042" : - case "250" : - case "251" : - case "252" : - case "254" : - case "255" : - case "265" : - case "266" : - case "332" : // Subject - case "333" : // Subject owner (?) - case "353" : // Name list - case "366" : // End-of-Name list marker - case "372" : // MOTD body - case "375" : // MOTD start + case "042": + case "250": + case "251": + case "252": + case "254": + case "255": + case "265": + case "266": + case "332": // Subject + case "333": // Subject owner (?) + case "353": // Name list + case "366": // End-of-Name list marker + case "372": // MOTD body + case "375": // MOTD start // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); break; - case "376" : // MOTD end + case "376": // MOTD end // m_log.InfoFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); motd = true; break; - case "451" : // Not registered + case "451": // Not registered break; - case "433" : // Nickname in use + case "433": // Nickname in use // Gen a new name m_nick = m_baseNick + Util.RandomClass.Next(1, 99); 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 m_writer.WriteLine(String.Format("JOIN {0}", m_ircChannel)); m_writer.Flush(); break; - case "479" : // Bad channel name, etc. This will never work, so disable the connection - m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); + case "479": // Bad channel name, etc. This will never work, so disable the connection + m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]); m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] Connector disabled", idn, cmd); - m_enabled = false; + m_enabled = false; m_connected = false; - m_pending = false; + m_pending = false; break; - case "NOTICE" : + case "NOTICE": // m_log.WarnFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); break; - case "ERROR" : - m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE,2)[1]); + case "ERROR": + m_log.ErrorFormat("[IRC-Connector-{0}] [{1}] {2}", idn, cmd, parms.Split(CS_SPACE, 2)[1]); if (parms.Contains("reconnect too fast")) ICCD_PERIOD++; - m_pending = false; + m_pending = false; Reconnect(); break; - case "PING" : + case "PING": m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); m_writer.WriteLine(String.Format("PONG {0}", parms)); m_writer.Flush(); break; - case "PONG" : + case "PONG": break; case "JOIN": if (m_pending) @@ -748,19 +749,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_log.DebugFormat("[IRC-Connector-{0}] [{1}] parms = <{2}>", idn, cmd, parms); eventIrcQuit(pfx, cmd, parms); break; - default : + default: m_log.DebugFormat("[IRC-Connector-{0}] Command '{1}' ignored, parms = {2}", idn, cmd, parms); break; } // m_log.DebugFormat("[IRC-Connector-{0}] prefix = <{1}> cmd = <{2}> complete", idn, pfx, cmd); - + } public void eventIrcJoin(string prefix, string command, string parms) { - string[] args = parms.Split(CS_SPACE,2); - string IrcUser = prefix.Split('!')[0]; + string[] args = parms.Split(CS_SPACE, 2); + string IrcUser = prefix.Split('!')[0]; string IrcChannel = args[0]; if (IrcChannel.StartsWith(":")) @@ -772,8 +773,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat public void eventIrcPart(string prefix, string command, string parms) { - string[] args = parms.Split(CS_SPACE,2); - string IrcUser = prefix.Split('!')[0]; + string[] args = parms.Split(CS_SPACE, 2); + string IrcUser = prefix.Split('!')[0]; string IrcChannel = args[0]; 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 public void eventIrcMode(string prefix, string command, string parms) { - string[] args = parms.Split(CS_SPACE,2); + string[] args = parms.Split(CS_SPACE, 2); string UserMode = args[1]; 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 public void eventIrcNickChange(string prefix, string command, string parms) { - string[] args = parms.Split(CS_SPACE,2); + string[] args = parms.Split(CS_SPACE, 2); string UserOldNick = prefix.Split('!')[0]; string UserNewNick = args[0].Remove(0, 1); @@ -804,11 +805,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat public void eventIrcKick(string prefix, string command, string parms) { - string[] args = parms.Split(CS_SPACE,3); - string UserKicker = prefix.Split('!')[0]; - string IrcChannel = args[0]; - string UserKicked = args[1]; - string KickMessage = args[2]; + string[] args = parms.Split(CS_SPACE, 3); + string UserKicker = prefix.Split('!')[0]; + string IrcChannel = args[0]; + string UserKicked = args[1]; + string KickMessage = args[2]; m_log.DebugFormat("[IRC-Connector-{0}] Event: IRCKick {1}:{2}", idn, m_server, m_ircChannel); BroadcastSim(UserKicker, "/me kicks kicks {0} off {1} saying \"{2}\"", UserKicked, IrcChannel, KickMessage); @@ -822,7 +823,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat public void eventIrcQuit(string prefix, string command, string parms) { - string IrcUser = prefix.Split('!')[0]; + string IrcUser = prefix.Split('!')[0]; string QuitMessage = parms; 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 // m_log.InfoFormat("[IRC-Watchdog] Status scan, pdk = {0}, icc = {1}", _pdk_, _icc_); - _pdk_ = (_pdk_+1)%PING_PERIOD; // cycle the ping trigger + _pdk_ = (_pdk_ + 1) % PING_PERIOD; // cycle the ping trigger _icc_++; // increment the inter-consecutive-connect-delay counter lock (m_connectors) - foreach (IRCConnector connector in m_connectors) - { + foreach (IRCConnector connector in m_connectors) + { - // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); + // m_log.InfoFormat("[IRC-Watchdog] Scanning {0}", connector); - if (connector.Enabled) - { - if (!connector.Connected) + if (connector.Enabled) { - try + if (!connector.Connected) { - // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); - connector.Connect(); + try + { + // m_log.DebugFormat("[IRC-Watchdog] Connecting {1}:{2}", connector.idn, connector.m_server, connector.m_ircChannel); + connector.Connect(); + } + catch (Exception e) + { + m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message); + } } - catch (Exception e) + else { - m_log.ErrorFormat("[IRC-Watchdog] Exception on connector {0}: {1} ", connector.idn, e.Message); - } - } - else - { - if (connector.m_pending) - { - if (connector.m_timeout == 0) + if (connector.m_pending) { - m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); - connector.Reconnect(); + if (connector.m_timeout == 0) + { + m_log.ErrorFormat("[IRC-Watchdog] Login timed-out for connector {0}, reconnecting", connector.idn); + connector.Reconnect(); + } + else + connector.m_timeout--; } - else - connector.m_timeout--; - } - // Being marked connected is not enough to ping. Socket establishment can sometimes take a long - // time, in which case the watch dog might try to ping the server before the socket has been - // set up, with nasty side-effects. + // Being marked connected is not enough to ping. Socket establishment can sometimes take a long + // time, in which case the watch dog might try to ping the server before the socket has been + // set up, with nasty side-effects. - else if (_pdk_ == 0) - { - try - { - connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server)); - connector.m_writer.Flush(); - } - catch (Exception e) + else if (_pdk_ == 0) { - m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); - m_log.Debug(e); - connector.Reconnect(); + try + { + connector.m_writer.WriteLine(String.Format("PING :{0}", connector.m_server)); + connector.m_writer.Flush(); + } + catch (Exception e) + { + m_log.ErrorFormat("[IRC-PingRun] Exception on connector {0}: {1} ", connector.idn, e.Message); + m_log.Debug(e); + connector.Reconnect(); + } } - } + } } } - } // m_log.InfoFormat("[IRC-Watchdog] Status scan completed"); 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 internal class RegionState { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + // This computation is not the real region center if the region is larger than 256. + // This computation isn't fixed because there is not a handle back to the region. private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); - private const int DEBUG_CHANNEL = 2147483647; + private const int DEBUG_CHANNEL = 2147483647; - private static int _idk_ = 0; + private static int _idk_ = 0; // Runtime variables; these values are assigned when the // IrcState is created and remain constant thereafter. - internal string Region = String.Empty; - internal string Host = String.Empty; - internal string LocX = String.Empty; - internal string LocY = String.Empty; - internal string IDK = String.Empty; + internal string Region = String.Empty; + internal string Host = String.Empty; + internal string LocX = String.Empty; + internal string LocY = String.Empty; + internal string IDK = String.Empty; // System values - used only be the IRC classes themselves - internal ChannelState cs = null; // associated IRC configuration - internal Scene scene = null; // associated scene - internal IConfig config = null; // configuration file reference - internal bool enabled = true; - + internal ChannelState cs = null; // associated IRC configuration + internal Scene scene = null; // associated scene + internal IConfig config = null; // configuration file reference + internal bool enabled = true; + + //AgentAlert + internal bool showAlert = false; + internal string alertMessage = String.Empty; + internal IDialogModule dialogModule = null; + // This list is used to keep track of who is here, and by // implication, who is not. - internal List clients = new List(); + internal List clients = new List(); // Setup runtime variable values public RegionState(Scene p_scene, IConfig p_config) { - - scene = p_scene; + scene = p_scene; config = p_config; Region = scene.RegionInfo.RegionName; - Host = scene.RegionInfo.ExternalHostName; - LocX = Convert.ToString(scene.RegionInfo.RegionLocX); - LocY = Convert.ToString(scene.RegionInfo.RegionLocY); - IDK = Convert.ToString(_idk_++); + Host = scene.RegionInfo.ExternalHostName; + LocX = Convert.ToString(scene.RegionInfo.RegionLocX); + LocY = Convert.ToString(scene.RegionInfo.RegionLocY); + IDK = Convert.ToString(_idk_++); + + showAlert = config.GetBoolean("alert_show", false); + string alertServerInfo = String.Empty; + + if (showAlert) + { + bool showAlertServerInfo = config.GetBoolean("alert_show_serverinfo", true); + + if (showAlertServerInfo) + alertServerInfo = String.Format("\nServer: {0}\nPort: {1}\nChannel: {2}\n\n", + config.GetString("server", ""), config.GetString("port", ""), config.GetString("channel", "")); + + string alertPreMessage = config.GetString("alert_msg_pre", "This region is linked to Irc."); + string alertPostMessage = config.GetString("alert_msg_post", "Everything you say in public chat can be listened."); + + alertMessage = String.Format("{0}\n{1}{2}", alertPreMessage, alertServerInfo, alertPostMessage); + + dialogModule = scene.RequestModuleInterface(); + } // OpenChannel conditionally establishes a connection to the // IRC server. The request will either succeed, or it will @@ -93,9 +117,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // Connect channel to world events - scene.EventManager.OnChatFromWorld += OnSimChat; + scene.EventManager.OnChatFromWorld += OnSimChat; scene.EventManager.OnChatFromClient += OnSimChat; - scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; + scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; scene.EventManager.OnMakeChildAgent += OnMakeChildAgent; m_log.InfoFormat("[IRC-Region {0}] Initialization complete", Region); @@ -106,8 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat ~RegionState() { - if (cs != null) - cs.RemoveRegion(this); + if (cs != null) + cs.RemoveRegion(this); } // Called by PostInitialize after all regions have been created @@ -138,7 +162,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat { if (clients.Contains(client)) { - if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) + if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) { m_log.InfoFormat("[IRC-Region {0}]: {1} has left", Region, client.Name); //Check if this person is excluded from IRC @@ -147,7 +171,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", client.Name)); } } - client.OnLogout -= OnClientLoggedOut; + client.OnLogout -= OnClientLoggedOut; client.OnConnectionClosed -= OnClientLoggedOut; clients.Remove(client); } @@ -171,13 +195,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat { if (clients.Contains(client)) { - if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) + if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) { string clientName = String.Format("{0} {1}", presence.Firstname, presence.Lastname); m_log.DebugFormat("[IRC-Region {0}] {1} has left", Region, clientName); cs.irc.PrivMsg(cs.NoticeMessageFormat, cs.irc.Nick, Region, String.Format("{0} has left", clientName)); } - client.OnLogout -= OnClientLoggedOut; + client.OnLogout -= OnClientLoggedOut; client.OnConnectionClosed -= OnClientLoggedOut; clients.Remove(client); } @@ -195,14 +219,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat private void OnMakeRootAgent(ScenePresence presence) { - IClientAPI client = presence.ControllingClient; try { if (!clients.Contains(client)) { - client.OnLogout += OnClientLoggedOut; + client.OnLogout += OnClientLoggedOut; client.OnConnectionClosed += OnClientLoggedOut; clients.Add(client); if (enabled && (cs.irc.Enabled) && (cs.irc.Connected) && (cs.ClientReporting)) @@ -216,17 +239,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat } } } + + if (dialogModule != null && showAlert) + dialogModule.SendAlertToUser(client, alertMessage, true); } catch (Exception ex) { m_log.ErrorFormat("[IRC-Region {0}]: MakeRootAgent exception: {1}", Region, ex.Message); m_log.Debug(ex); } - } // This handler detects chat events int he virtual world. - public void OnSimChat(Object sender, OSChatMessage msg) { @@ -317,14 +341,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat // that evident. default: - m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", + m_log.DebugFormat("[IRC-Region {0}] Forwarding unrecognized command to IRC : {1}", Region, msg.Message); cs.irc.Send(msg.Message); break; } } catch (Exception ex) - { + { m_log.WarnFormat("[IRC-Region {0}] error processing in-world command channel input: {1}", Region, ex.Message); m_log.Debug(ex); @@ -366,7 +390,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message); - if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) + if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL)) { string txt = msg.Message; if (txt.StartsWith("/me ")) @@ -376,13 +400,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat return; } - if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && + if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword && msg.Channel == cs.RelayChannelOut) { Match m = cs.AccessPasswordRegex.Match(msg.Message); if (null != m) { - m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), + m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(), m.Groups["message"].ToString()); cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(), 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 scene.GetRootAgentCount(), scene.RegionInfo.RegionName, scene.RegionInfo.RegionID, DateTime.UtcNow.ToString("s"))); + scene.ForEachRootScenePresence(delegate(ScenePresence sp) { - list.Append(String.Format(" \n", sp.Name, sp.UUID)); - list.Append(""); + list.Append(String.Format(" \n", sp.Name, sp.UUID)); }); + + list.Append(""); string payload = list.ToString(); // 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 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using log4net; +using Mono.Addins; +using NDesk.Options; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.OptionalModules.Avatar.SitStand +{ + /// + /// A module that just holds commands for changing avatar sitting and standing states. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AnimationsCommandModule")] + public class SitStandCommandModule : INonSharedRegionModule + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene; + + public string Name { get { return "SitStand Command Module"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: INITIALIZED MODULE"); + } + + public void PostInitialise() + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: POST INITIALIZED MODULE"); + } + + public void Close() + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); + } + + public void RemoveRegion(Scene scene) + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + } + + public void RegionLoaded(Scene scene) + { +// m_log.DebugFormat("[ANIMATIONS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); + + m_scene = scene; + + scene.AddCommand( + "Users", this, "sit user name", + "sit user name [--regex] ", + "Sit the named user on an unoccupied object with a sit target.", + "If there are no such objects then nothing happens.\n" + + "If --regex is specified then the names are treated as regular expressions.", + HandleSitUserNameCommand); + + scene.AddCommand( + "Users", this, "stand user name", + "stand user name [--regex] ", + "Stand the named user.", + "If --regex is specified then the names are treated as regular expressions.", + HandleStandUserNameCommand); + } + + private void HandleSitUserNameCommand(string module, string[] cmd) + { + if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) + return; + + if (cmd.Length < 5) + { + MainConsole.Instance.Output("Usage: sit user name [--regex] "); + return; + } + + List scenePresences = GetScenePresences(cmd); + + foreach (ScenePresence sp in scenePresences) + { + if (sp.SitGround || sp.IsSatOnObject) + continue; + + SceneObjectPart sitPart = null; + List sceneObjects = m_scene.GetSceneObjectGroups(); + + foreach (SceneObjectGroup sceneObject in sceneObjects) + { + if (sceneObject.IsAttachment) + continue; + + foreach (SceneObjectPart part in sceneObject.Parts) + { + if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) + { + sitPart = part; + break; + } + } + } + + if (sitPart != null) + { + MainConsole.Instance.OutputFormat( + "Sitting {0} on {1} {2} in {3}", + sp.Name, sitPart.ParentGroup.Name, sitPart.ParentGroup.UUID, m_scene.Name); + + sp.HandleAgentRequestSit(sp.ControllingClient, sp.UUID, sitPart.UUID, Vector3.Zero); + sp.HandleAgentSit(sp.ControllingClient, sp.UUID); + } + else + { + MainConsole.Instance.OutputFormat( + "Could not find any unoccupied set seat on which to sit {0} in {1}. Aborting", + sp.Name, m_scene.Name); + + break; + } + } + } + + private void HandleStandUserNameCommand(string module, string[] cmd) + { + if (MainConsole.Instance.ConsoleScene != m_scene && MainConsole.Instance.ConsoleScene != null) + return; + + if (cmd.Length < 5) + { + MainConsole.Instance.Output("Usage: stand user name [--regex] "); + return; + } + + List scenePresences = GetScenePresences(cmd); + + foreach (ScenePresence sp in scenePresences) + { + if (sp.SitGround || sp.IsSatOnObject) + { + MainConsole.Instance.OutputFormat("Standing {0} in {1}", sp.Name, m_scene.Name); + sp.StandUp(); + } + } + } + + private List GetScenePresences(string[] cmdParams) + { + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdParams); + + string firstName = mainParams[3]; + string lastName = mainParams[4]; + + List scenePresencesMatched = new List(); + + if (useRegex) + { + Regex nameRegex = new Regex(string.Format("{0} {1}", firstName, lastName)); + List scenePresences = m_scene.GetScenePresences(); + + foreach (ScenePresence sp in scenePresences) + { + if (!sp.IsChildAgent && nameRegex.IsMatch(sp.Name)) + scenePresencesMatched.Add(sp); + } + } + else + { + ScenePresence sp = m_scene.GetScenePresence(firstName, lastName); + + if (sp != null && !sp.IsChildAgent) + scenePresencesMatched.Add(sp); + } + + return scenePresencesMatched; + } + } +} \ 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 // Capability string prefixes private static readonly string m_parcelVoiceInfoRequestPath = "0207/"; private static readonly string m_provisionVoiceAccountRequestPath = "0208/"; - private static readonly string m_chatSessionRequestPath = "0209/"; + //private static readonly string m_chatSessionRequestPath = "0209/"; // Control info private static bool m_Enabled = false; @@ -326,15 +326,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice "ParcelVoiceInfoRequest", agentID.ToString())); - caps.RegisterHandler( - "ChatSessionRequest", - new RestStreamHandler( - "POST", - capsBase + m_chatSessionRequestPath, - (request, path, param, httpRequest, httpResponse) - => ChatSessionRequest(scene, request, path, param, agentID, caps), - "ChatSessionRequest", - agentID.ToString())); + //caps.RegisterHandler( + // "ChatSessionRequest", + // new RestStreamHandler( + // "POST", + // capsBase + m_chatSessionRequestPath, + // (request, path, param, httpRequest, httpResponse) + // => ChatSessionRequest(scene, request, path, param, agentID, caps), + // "ChatSessionRequest", + // agentID.ToString())); } /// @@ -551,13 +551,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice reqStream.Close(); } - HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse(); - Encoding encoding = Util.UTF8; - StreamReader fwdresponsestream = new StreamReader(fwdrsp.GetResponseStream(), encoding); - fwdresponsestr = fwdresponsestream.ReadToEnd(); - fwdresponsecontenttype = fwdrsp.ContentType; - fwdresponsecode = (int)fwdrsp.StatusCode; - fwdresponsestream.Close(); + using (HttpWebResponse fwdrsp = (HttpWebResponse)forwardreq.GetResponse()) + { + Encoding encoding = Util.UTF8; + + using (Stream s = fwdrsp.GetResponseStream()) + { + using (StreamReader fwdresponsestream = new StreamReader(s)) + { + fwdresponsestr = fwdresponsestream.ReadToEnd(); + fwdresponsecontenttype = fwdrsp.ContentType; + fwdresponsecode = (int)fwdrsp.StatusCode; + } + } + } response["content_type"] = fwdresponsecontenttype; 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 // Capability strings private static readonly string m_parcelVoiceInfoRequestPath = "0107/"; private static readonly string m_provisionVoiceAccountRequestPath = "0108/"; - private static readonly string m_chatSessionRequestPath = "0109/"; + //private static readonly string m_chatSessionRequestPath = "0109/"; // Control info, e.g. vivox server, admin user, admin password private static bool m_pluginEnabled = false; @@ -117,6 +117,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice private IConfig m_config; + private object m_Lock; + public void Initialise(IConfigSource config) { @@ -128,6 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice if (!m_config.GetBoolean("enabled", false)) return; + m_Lock = new object(); + try { // retrieve configuration variables @@ -429,15 +433,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice "ParcelVoiceInfoRequest", agentID.ToString())); - caps.RegisterHandler( - "ChatSessionRequest", - new RestStreamHandler( - "POST", - capsBase + m_chatSessionRequestPath, - (request, path, param, httpRequest, httpResponse) - => ChatSessionRequest(scene, request, path, param, agentID, caps), - "ChatSessionRequest", - agentID.ToString())); + //caps.RegisterHandler( + // "ChatSessionRequest", + // new RestStreamHandler( + // "POST", + // capsBase + m_chatSessionRequestPath, + // (request, path, param, httpRequest, httpResponse) + // => ChatSessionRequest(scene, request, path, param, agentID, caps), + // "ChatSessionRequest", + // agentID.ToString())); } /// @@ -818,11 +822,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice { string requrl = String.Format(m_vivoxChannelPath, m_vivoxServer, "create", channelId, m_authToken); - if (parent != null && parent != String.Empty) + if (!string.IsNullOrEmpty(parent)) { requrl = String.Format("{0}&chan_parent={1}", requrl, parent); } - if (description != null && description != String.Empty) + if (!string.IsNullOrEmpty(description)) { requrl = String.Format("{0}&chan_desc={1}", requrl, description); } @@ -832,7 +836,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); - requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); + requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance); XmlElement resp = VivoxCall(requrl, true); if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) @@ -858,7 +862,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice // requrl = String.Format("{0}&chan_parent={1}", requrl, parent); // } - if (description != null && description != String.Empty) + if (!string.IsNullOrEmpty(description)) { requrl = String.Format("{0}&chan_desc={1}", requrl, description); } @@ -1043,7 +1047,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice private XmlElement VivoxDeleteChannel(string parent, string channelid) { string requrl = String.Format(m_vivoxChannelDel, m_vivoxServer, "delete", channelid, m_authToken); - if (parent != null && parent != String.Empty) + if (!string.IsNullOrEmpty(parent)) { requrl = String.Format("{0}&chan_parent={1}", requrl, parent); } @@ -1111,27 +1115,32 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice doc = new XmlDocument(); - try + // Let's serialize all calls to Vivox. Most of these are driven by + // the clients (CAPs), when the user arrives at the region. We don't + // want to issue many simultaneous http requests to Vivox, because mono + // doesn't like that + lock (m_Lock) { - // Otherwise prepare the request - m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); - - HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); - HttpWebResponse rsp = null; + try + { + // Otherwise prepare the request + m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); - // We are sending just parameters, no content - req.ContentLength = 0; + HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); - // Send request and retrieve the response - rsp = (HttpWebResponse)req.GetResponse(); + // We are sending just parameters, no content + req.ContentLength = 0; - XmlTextReader rdr = new XmlTextReader(rsp.GetResponseStream()); - doc.Load(rdr); - rdr.Close(); - } - catch (Exception e) - { - m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); + // Send request and retrieve the response + using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse()) + using (Stream s = rsp.GetResponseStream()) + using (XmlTextReader rdr = new XmlTextReader(s)) + doc.Load(rdr); + } + catch (Exception e) + { + m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); + } } // If we're debugging server responses, dump the whole @@ -1316,4 +1325,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice return false; } } -} \ No newline at end of file +} 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 private IGroupsServicesConnector m_groupData = null; // Config Options - private bool m_groupMessagingEnabled = false; - private bool m_debugEnabled = true; + private bool m_groupMessagingEnabled; + private bool m_debugEnabled; /// /// 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 if (m_messageOnlineAgentsOnly) m_usersOnlineCache = new ExpiringCache(); - m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true); + m_debugEnabled = groupsConfig.GetBoolean("MessagingDebugEnabled", m_debugEnabled); } m_log.InfoFormat( @@ -127,6 +127,14 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups return; scene.RegisterModuleInterface(this); + + scene.AddCommand( + "Debug", + this, + "debug groups messaging verbose", + "debug groups messaging verbose ", + "This setting turns on very verbose groups messaging debugging", + HandleDebugGroupsMessagingVerbose); } public void RegionLoaded(Scene scene) @@ -218,6 +226,26 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups #endregion + private void HandleDebugGroupsMessagingVerbose(object modules, string[] args) + { + if (args.Length < 5) + { + MainConsole.Instance.Output("Usage: debug groups messaging verbose "); + return; + } + + bool verbose = false; + if (!bool.TryParse(args[4], out verbose)) + { + MainConsole.Instance.Output("Usage: debug groups messaging verbose "); + return; + } + + m_debugEnabled = verbose; + + MainConsole.Instance.OutputFormat("{0} verbose logging set to {1}", Name, m_debugEnabled); + } + /// /// Not really needed, but does confirm that the group exists. /// @@ -237,11 +265,20 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups return false; } } - + public void SendMessageToGroup(GridInstantMessage im, UUID groupID) { - List groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID), groupID); + SendMessageToGroup(im, groupID, new UUID(im.fromAgentID), null); + } + + public void SendMessageToGroup( + GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func sendCondition) + { + int requestStartTick = Environment.TickCount; + + List groupMembers = m_groupData.GetGroupMembers(sendingAgentForGroupCalls, groupID); int groupMembersCount = groupMembers.Count; + HashSet attemptDeliveryUuidSet = null; if (m_messageOnlineAgentsOnly) { @@ -257,10 +294,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds); } - HashSet onlineAgentsUuidSet = new HashSet(); - Array.ForEach(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID)); + attemptDeliveryUuidSet + = new HashSet(Array.ConvertAll(onlineAgents, pi => pi.UserID)); + + //Array.ForEach(onlineAgents, pi => attemptDeliveryUuidSet.Add(pi.UserID)); - groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); + //groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList(); // if (m_debugEnabled) // m_log.DebugFormat( @@ -269,26 +308,42 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups } else { + attemptDeliveryUuidSet + = new HashSet(groupMembers.ConvertAll(gmd => gmd.AgentID.ToString())); + if (m_debugEnabled) m_log.DebugFormat( "[GROUPS-MESSAGING]: SendMessageToGroup called for group {0} with {1} visible members", groupID, groupMembers.Count); - } - - int requestStartTick = Environment.TickCount; + } foreach (GroupMembersData member in groupMembers) { - if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID)) + if (sendCondition != null) + { + if (!sendCondition(member)) + { + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: Not sending to {0} as they do not fulfill send condition", + member.AgentID); + + continue; + } + } + else if (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID, groupID)) { // Don't deliver messages to people who have dropped this session - if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: {0} has dropped session, not delivering to them", member.AgentID); + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: {0} has dropped session, not delivering to them", member.AgentID); + continue; } // Copy Message GridInstantMessage msg = new GridInstantMessage(); - msg.imSessionID = groupID.Guid; + msg.imSessionID = im.imSessionID; msg.fromAgentName = im.fromAgentName; msg.message = im.message; msg.dialog = im.dialog; @@ -304,26 +359,51 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups msg.toAgentID = member.AgentID.Guid; - IClientAPI client = GetActiveClient(member.AgentID); - if (client == null) + if (attemptDeliveryUuidSet.Contains(member.AgentID.ToString())) { - // If they're not local, forward across the grid - if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} via Grid", member.AgentID); - m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); + IClientAPI client = GetActiveClient(member.AgentID); + if (client == null) + { + int startTick = Environment.TickCount; + + // If they're not local, forward across the grid + m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { }); + + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: Delivering to {0} via grid took {1} ms", + member.AgentID, Environment.TickCount - startTick); + } + else + { + int startTick = Environment.TickCount; + + ProcessMessageFromGroupSession(msg, client); + + // Deliver locally, directly + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: Delivering to {0} locally took {1} ms", + member.AgentID, Environment.TickCount - startTick); + } } else { - // Deliver locally, directly - if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name); - ProcessMessageFromGroupSession(msg); + int startTick = Environment.TickCount; + + m_msgTransferModule.HandleUndeliverableMessage(msg, delegate(bool success) { }); + + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: Handling undeliverable message for {0} took {1} ms", + member.AgentID, Environment.TickCount - startTick); } } - // Temporary for assessing how long it still takes to send messages to large online groups. - if (m_messageOnlineAgentsOnly) + if (m_debugEnabled) m_log.DebugFormat( - "[GROUPS-MESSAGING]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms", - groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick); + "[GROUPS-MESSAGING]: Total SendMessageToGroup for group {0} with {1} members, {2} candidates for delivery took {3} ms", + groupID, groupMembersCount, attemptDeliveryUuidSet.Count(), Environment.TickCount - requestStartTick); } #region SimGridEventHandlers @@ -348,7 +428,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // Any other message type will not be delivered to a client by the // Instant Message Module - if (m_debugEnabled) { m_log.DebugFormat("[GROUPS-MESSAGING]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -362,13 +441,35 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups || (msg.dialog == (byte)InstantMessageDialog.SessionAdd) || (msg.dialog == (byte)InstantMessageDialog.SessionDrop))) { - ProcessMessageFromGroupSession(msg); + IClientAPI client = null; + + if (msg.dialog == (byte)InstantMessageDialog.SessionSend) + { + client = GetActiveClient(new UUID(msg.toAgentID)); + + if (client != null) + { + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} locally", client.Name); + } + else + { + m_log.WarnFormat("[GROUPS-MESSAGING]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); + + return; + } + } + + ProcessMessageFromGroupSession(msg, client); } } - private void ProcessMessageFromGroupSession(GridInstantMessage msg) + private void ProcessMessageFromGroupSession(GridInstantMessage msg, IClientAPI client) { - if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID); + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS-MESSAGING]: Session message from {0} going to agent {1}, sessionID {2}, type {3}", + msg.fromAgentName, msg.toAgentID, msg.imSessionID, (InstantMessageDialog)msg.dialog); UUID AgentID = new UUID(msg.fromAgentID); UUID GroupID = new UUID(msg.imSessionID); @@ -392,74 +493,62 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // Add them to the session for now, and Invite them m_groupData.AgentInvitedToGroupChatSession(AgentID, GroupID); - UUID toAgentID = new UUID(msg.toAgentID); - IClientAPI activeClient = GetActiveClient(toAgentID); - if (activeClient != null) + GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero, GroupID, null); + if (groupInfo != null) { - GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero, GroupID, null); - if (groupInfo != null) - { - if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Sending chatterbox invite instant message"); - - // Force? open the group session dialog??? - // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); - IEventQueue eq = activeClient.Scene.RequestModuleInterface(); - eq.ChatterboxInvitation( - GroupID - , groupInfo.GroupName - , new UUID(msg.fromAgentID) - , msg.message - , new UUID(msg.toAgentID) - , msg.fromAgentName - , msg.dialog - , msg.timestamp - , msg.offline == 1 - , (int)msg.ParentEstateID - , msg.Position - , 1 - , new UUID(msg.imSessionID) - , msg.fromGroup - , Utils.StringToBytes(groupInfo.GroupName) - ); - - eq.ChatterBoxSessionAgentListUpdates( - new UUID(GroupID) - , new UUID(msg.fromAgentID) - , new UUID(msg.toAgentID) - , false //canVoiceChat - , false //isModerator - , false //text mute - ); - } + if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Sending chatterbox invite instant message"); + + // Force? open the group session dialog??? + // and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg); + IEventQueue eq = client.Scene.RequestModuleInterface(); + eq.ChatterboxInvitation( + GroupID + , groupInfo.GroupName + , new UUID(msg.fromAgentID) + , msg.message + , new UUID(msg.toAgentID) + , msg.fromAgentName + , msg.dialog + , msg.timestamp + , msg.offline == 1 + , (int)msg.ParentEstateID + , msg.Position + , 1 + , new UUID(msg.imSessionID) + , msg.fromGroup + , Utils.StringToBytes(groupInfo.GroupName) + ); + + eq.ChatterBoxSessionAgentListUpdates( + new UUID(GroupID) + , new UUID(msg.fromAgentID) + , new UUID(msg.toAgentID) + , false //canVoiceChat + , false //isModerator + , false //text mute + ); } + + break; } else if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID, GroupID)) { // User hasn't dropped, so they're in the session, // maybe we should deliver it. - IClientAPI client = GetActiveClient(new UUID(msg.toAgentID)); - if (client != null) - { - // Deliver locally, directly - if (m_debugEnabled) m_log.DebugFormat("[GROUPS-MESSAGING]: Delivering to {0} locally", client.Name); - client.SendInstantMessage(msg); - } - else - { - m_log.WarnFormat("[GROUPS-MESSAGING]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID); - } + client.SendInstantMessage(msg); } + break; default: - m_log.WarnFormat("[GROUPS-MESSAGING]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString()); - break; + client.SendInstantMessage(msg); + + break;; } } #endregion - #region ClientEvents private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) { @@ -548,15 +637,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // Don't log any normal IMs (privacy!) if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent) { - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromGroup({0})", im.fromGroup ? "True" : "False"); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString()); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromAgentID({0})", im.fromAgentID.ToString()); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: fromAgentName({0})", im.fromAgentName.ToString()); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: imSessionID({0})", im.imSessionID.ToString()); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: message({0})", im.message.ToString()); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: offline({0})", im.offline.ToString()); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: toAgentID({0})", im.toAgentID.ToString()); - m_log.WarnFormat("[GROUPS-MESSAGING]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket")); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromGroup({0})", im.fromGroup ? "True" : "False"); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: Dialog({0})", (InstantMessageDialog)im.dialog); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromAgentID({0})", im.fromAgentID); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: fromAgentName({0})", im.fromAgentName); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: imSessionID({0})", im.imSessionID); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: message({0})", im.message); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: offline({0})", im.offline); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: toAgentID({0})", im.toAgentID); + m_log.DebugFormat("[GROUPS-MESSAGING]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket")); } } @@ -567,7 +656,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups /// private IClientAPI GetActiveClient(UUID agentID) { - if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Looking for local client {0}", agentID); + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS-MESSAGING]: Looking for local client {0}", agentID); IClientAPI child = null; @@ -579,12 +669,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups { if (!sp.IsChildAgent) { - if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Found root agent for client : {0}", sp.ControllingClient.Name); + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS-MESSAGING]: Found root agent for client : {0}", sp.ControllingClient.Name); + return sp.ControllingClient; } else { - if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Found child agent for client : {0}", sp.ControllingClient.Name); + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS-MESSAGING]: Found child agent for client : {0}", sp.ControllingClient.Name); + child = sp.ControllingClient; } } @@ -593,12 +687,15 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // If we didn't find a root, then just return whichever child we found, or null if none if (child == null) { - if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Could not find local client for agent : {0}", agentID); + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS-MESSAGING]: Could not find local client for agent : {0}", agentID); } else { - if (m_debugEnabled) m_log.WarnFormat("[GROUPS-MESSAGING]: Returning child agent for client : {0}", child.Name); + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS-MESSAGING]: Returning child agent for client : {0}", child.Name); } + return child; } 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; using OpenMetaverse; using OpenMetaverse.StructuredData; using OpenSim.Framework; -using OpenSim.Framework.Communications; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; +using System.Text; using DirFindFlags = OpenMetaverse.DirectoryManager.DirFindFlags; namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups @@ -76,9 +76,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups private List m_sceneList = new List(); - private IMessageTransferModule m_msgTransferModule = null; + private IMessageTransferModule m_msgTransferModule; + + private IGroupsMessagingModule m_groupsMessagingModule; - private IGroupsServicesConnector m_groupData = null; + private IGroupsServicesConnector m_groupData; // Configuration settings private bool m_groupsEnabled = false; @@ -184,10 +186,19 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups if (m_msgTransferModule == null) { m_groupsEnabled = false; - m_log.Warn("[GROUPS]: Could not get MessageTransferModule"); + m_log.Warn("[GROUPS]: Could not get IMessageTransferModule"); } } + if (m_groupsMessagingModule == null) + { + m_groupsMessagingModule = scene.RequestModuleInterface(); + + // No message transfer module, no notices, group invites, rejects, ejects, etc + if (m_groupsMessagingModule == null) + m_log.Warn("[GROUPS]: Could not get IGroupsMessagingModule"); + } + lock (m_sceneList) { m_sceneList.Add(scene); @@ -250,7 +261,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest; client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest; - client.OnDirFindQuery += OnDirFindQuery; client.OnRequestAvatarProperties += OnRequestAvatarProperties; // Used for Notices and Group Invites/Accept/Reject @@ -303,21 +313,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups } */ - void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart) - { - if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups) - { - if (m_debugEnabled) - m_log.DebugFormat( - "[GROUPS]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})", - System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart); - - // TODO: This currently ignores pretty much all the query flags including Mature and sort order - remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentID(remoteClient), queryText).ToArray()); - } - - } - private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID) { if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); @@ -361,7 +356,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im) { - if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS]: {0} called for {1}, message type {2}", + System.Reflection.MethodBase.GetCurrentMethod().Name, remoteClient.Name, (InstantMessageDialog)im.dialog); // Group invitations if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline)) @@ -437,81 +435,160 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups string Subject = im.message.Substring(0, im.message.IndexOf('|')); string Message = im.message.Substring(Subject.Length + 1); + InventoryItemBase item = null; + bool hasAttachment = false; + UUID itemID = UUID.Zero; //Assignment to quiet compiler + UUID ownerID = UUID.Zero; //Assignment to quiet compiler byte[] bucket; - if ((im.binaryBucket.Length == 1) && (im.binaryBucket[0] == 0)) - { - bucket = new byte[19]; - bucket[0] = 0; //dunno - bucket[1] = 0; //dunno - GroupID.ToBytes(bucket, 2); - bucket[18] = 0; //dunno - } - else + if (im.binaryBucket.Length >= 1 && im.binaryBucket[0] > 0) { string binBucket = OpenMetaverse.Utils.BytesToString(im.binaryBucket); binBucket = binBucket.Remove(0, 14).Trim(); - if (m_debugEnabled) + + OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket); + if (binBucketOSD is OSD) { - m_log.WarnFormat("I don't understand a group notice binary bucket of: {0}", binBucket); + OSDMap binBucketMap = (OSDMap)binBucketOSD; + + itemID = binBucketMap["item_id"].AsUUID(); + ownerID = binBucketMap["owner_id"].AsUUID(); + + //Attempt to get the details of the attached item. + //If sender doesn't own the attachment, the item + //variable will be set to null and attachment will + //not be included with the group notice. + Scene scene = (Scene)remoteClient.Scene; + item = new InventoryItemBase(itemID, ownerID); + item = scene.InventoryService.GetItem(item); - OSDMap binBucketOSD = (OSDMap)OSDParser.DeserializeLLSDXml(binBucket); - - foreach (string key in binBucketOSD.Keys) + if (item != null) { - if (binBucketOSD.ContainsKey(key)) - { - m_log.WarnFormat("{0}: {1}", key, binBucketOSD[key].ToString()); - } + //Got item details so include the attachment. + hasAttachment = true; } } - - // treat as if no attachment + else + { + m_log.DebugFormat("[Groups]: Received OSD with unexpected type: {0}", binBucketOSD.GetType()); + } + } + + if (hasAttachment) + { + //Bucket contains information about attachment. + // + //Byte offset and description of bucket data: + //0: 1 byte indicating if attachment is present + //1: 1 byte indicating the type of attachment + //2: 16 bytes - Group UUID + //18: 16 bytes - UUID of the attachment owner + //34: 16 bytes - UUID of the attachment + //50: variable - Name of the attachment + //??: NUL byte to terminate the attachment name + byte[] name = Encoding.UTF8.GetBytes(item.Name); + bucket = new byte[51 + name.Length];//3 bytes, 3 UUIDs, and name + bucket[0] = 1; //Has attachment flag + bucket[1] = (byte)item.InvType; //Type of Attachment + GroupID.ToBytes(bucket, 2); + ownerID.ToBytes(bucket, 18); + itemID.ToBytes(bucket, 34); + name.CopyTo(bucket, 50); + } + else + { bucket = new byte[19]; - bucket[0] = 0; //dunno - bucket[1] = 0; //dunno + bucket[0] = 0; //Has attachment flag + bucket[1] = 0; //Type of attachment GroupID.ToBytes(bucket, 2); - bucket[18] = 0; //dunno + bucket[18] = 0; //NUL terminate name of attachment } - m_groupData.AddGroupNotice(GetRequestingAgentID(remoteClient), GroupID, NoticeID, im.fromAgentName, Subject, Message, bucket); if (OnNewGroupNotice != null) { OnNewGroupNotice(GroupID, NoticeID); } - // Send notice out to everyone that wants notices - foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID)) + if (m_debugEnabled) { - if (m_debugEnabled) + foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentID(remoteClient), GroupID)) { - UserAccount targetUser = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, member.AgentID); - if (targetUser != null) + if (m_debugEnabled) { - m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices); - } - else - { - m_log.DebugFormat("[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", NoticeID, member.AgentID, member.AcceptNotices); + UserAccount targetUser + = m_sceneList[0].UserAccountService.GetUserAccount( + remoteClient.Scene.RegionInfo.ScopeID, member.AgentID); + + if (targetUser != null) + { + m_log.DebugFormat( + "[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", + NoticeID, targetUser.FirstName + " " + targetUser.LastName, member.AcceptNotices); + } + else + { + m_log.DebugFormat( + "[GROUPS]: Prepping group notice {0} for agent: {1} who Accepts Notices ({2})", + NoticeID, member.AgentID, member.AcceptNotices); + } } } + } - if (member.AcceptNotices) - { - // Build notice IIM - GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); + GridInstantMessage msg + = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice); - msg.toAgentID = member.AgentID.Guid; - OutgoingInstantMessage(msg, member.AgentID); - } + if (m_groupsMessagingModule != null) + m_groupsMessagingModule.SendMessageToGroup( + msg, GroupID, remoteClient.AgentId, gmd => gmd.AcceptNotices); + } + } + + if (im.dialog == (byte)InstantMessageDialog.GroupNoticeInventoryAccepted) + { + //Is bucket large enough to hold UUID of the attachment? + if (im.binaryBucket.Length < 16) + return; + + UUID noticeID = new UUID(im.imSessionID); + + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS]: Requesting notice {0} for {1}", noticeID, remoteClient.AgentId); + + GroupNoticeInfo notice = m_groupData.GetGroupNotice(GetRequestingAgentID(remoteClient), noticeID); + if (notice != null) + { + UUID giver = new UUID(notice.BinaryBucket, 18); + UUID attachmentUUID = new UUID(notice.BinaryBucket, 34); + + if (m_debugEnabled) + m_log.DebugFormat("[Groups]: Giving inventory from {0} to {1}", giver, remoteClient.AgentId); + + string message; + InventoryItemBase itemCopy = ((Scene)(remoteClient.Scene)).GiveInventoryItem(remoteClient.AgentId, + giver, attachmentUUID, out message); + + if (itemCopy == null) + { + remoteClient.SendAgentAlertMessage(message, false); + return; } + + remoteClient.SendInventoryItemCreateUpdate(itemCopy, 0); + } + else + { + if (m_debugEnabled) + m_log.DebugFormat( + "[GROUPS]: Could not find notice {0} for {1} on GroupNoticeInventoryAccepted.", + noticeID, remoteClient.AgentId); } } - + // Interop, received special 210 code for ejecting a group member // this only works within the comms servers domain, and won't work hypergrid - // TODO:FIXME: Use a presense server of some kind to find out where the + // TODO:FIXME: Use a presence server of some kind to find out where the // client actually is, and try contacting that region directly to notify them, // or provide the notification via xmlrpc update queue if ((im.dialog == 210)) @@ -764,7 +841,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups remoteClient.SendCreateGroupReply(UUID.Zero, false, "You have got insufficient funds to create a group."); return UUID.Zero; } - money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, "Group Creation"); + money.ApplyCharge(GetRequestingAgentID(remoteClient), money.GroupCreationCharge, MoneyTransactionType.GroupCreate); } UUID groupID = m_groupData.CreateGroup(GetRequestingAgentID(remoteClient), name, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish, GetRequestingAgentID(remoteClient)); @@ -889,26 +966,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups if (data != null) { - GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null); - - GridInstantMessage msg = new GridInstantMessage(); - msg.imSessionID = UUID.Zero.Guid; - msg.fromAgentID = data.GroupID.Guid; - msg.toAgentID = GetRequestingAgentID(remoteClient).Guid; - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); - msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName; - msg.message = data.noticeData.Subject + "|" + data.Message; - msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested; - msg.fromGroup = true; - msg.offline = (byte)0; - msg.ParentEstateID = 0; - msg.Position = Vector3.Zero; - msg.RegionID = UUID.Zero.Guid; - msg.binaryBucket = data.BinaryBucket; + GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested); OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient)); } - } public GridInstantMessage CreateGroupNoticeIM(UUID agentID, UUID groupNoticeID, byte dialog) @@ -916,10 +977,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name); GridInstantMessage msg = new GridInstantMessage(); - msg.imSessionID = UUID.Zero.Guid; + byte[] bucket; + + msg.imSessionID = groupNoticeID.Guid; msg.toAgentID = agentID.Guid; msg.dialog = dialog; - // msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNotice; msg.fromGroup = true; msg.offline = (byte)0; msg.ParentEstateID = 0; @@ -933,13 +995,38 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups msg.timestamp = info.noticeData.Timestamp; msg.fromAgentName = info.noticeData.FromName; msg.message = info.noticeData.Subject + "|" + info.Message; - msg.binaryBucket = info.BinaryBucket; + + if (info.BinaryBucket[0] > 0) + { + //32 is due to not needing space for two of the UUIDs. + //(Don't need UUID of attachment or its owner in IM) + //50 offset gets us to start of attachment name. + //We are skipping the attachment flag, type, and + //the three UUID fields at the start of the bucket. + bucket = new byte[info.BinaryBucket.Length-32]; + bucket[0] = 1; //Has attachment + bucket[1] = info.BinaryBucket[1]; + Array.Copy(info.BinaryBucket, 50, + bucket, 18, info.BinaryBucket.Length-50); + } + else + { + bucket = new byte[19]; + bucket[0] = 0; //No attachment + bucket[1] = 0; //Attachment type + bucket[18] = 0; //NUL terminate name + } + + info.GroupID.ToBytes(bucket, 2); + msg.binaryBucket = bucket; } else { - if (m_debugEnabled) m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID); + if (m_debugEnabled) + m_log.DebugFormat("[GROUPS]: Group Notice {0} not found, composing empty message.", groupNoticeID); + msg.fromAgentID = UUID.Zero.Guid; - msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); ; + msg.timestamp = (uint)Util.UnixTimeSinceEpoch(); msg.fromAgentName = string.Empty; msg.message = string.Empty; msg.binaryBucket = new byte[0]; @@ -1063,7 +1150,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups // Message to ejector // Interop, received special 210 code for ejecting a group member // this only works within the comms servers domain, and won't work hypergrid - // TODO:FIXME: Use a presense server of some kind to find out where the + // TODO:FIXME: Use a presence server of some kind to find out where the // client actually is, and try contacting that region directly to notify them, // or provide the notification via xmlrpc update queue @@ -1178,6 +1265,12 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups } } + public List FindGroups(IClientAPI remoteClient, string query) + { + return m_groupData.FindGroups(GetRequestingAgentID(remoteClient), query); + } + + #endregion #region Client/Update Tools @@ -1222,7 +1315,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID)); AgentData.Add(AgentDataMap); - OSDArray GroupData = new OSDArray(data.Length); OSDArray NewGroupData = new OSDArray(data.Length); @@ -1288,7 +1380,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups presence.Grouptitle = Title; if (! presence.IsChildAgent) - presence.SendAvatarDataToAllAgents(); + presence.SendAvatarDataToAllClients(); } } } 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; using OpenMetaverse.StructuredData; using OpenSim.Framework; -using OpenSim.Framework.Communications; using OpenSim.Region.Framework.Interfaces; using OpenSim.Services.Interfaces; @@ -212,8 +211,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR]: Initializing {0}", this.Name); m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty); - if ((m_groupsServerURI == null) || - (m_groupsServerURI == string.Empty)) + if (string.IsNullOrEmpty(m_groupsServerURI)) { m_log.ErrorFormat("Please specify a valid Simian Server for GroupsServerURI in OpenSim.ini, [Groups]"); m_connectorEnabled = false; @@ -438,7 +436,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups return null; } } - else if ((groupName != null) && (groupName != string.Empty)) + else if (!string.IsNullOrEmpty(groupName)) { if (!SimianGetFirstGenericEntry("Group", groupName, out groupID, out GroupInfoMap)) { 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 @@ */ using System; +using System.Collections; +using System.Collections.Generic; +using System.Net; using System.Reflection; using Nini.Config; using NUnit.Framework; using OpenMetaverse; +using OpenMetaverse.Messages.Linden; +using OpenMetaverse.Packets; +using OpenMetaverse.StructuredData; using OpenSim.Framework; -using OpenSim.Framework.Communications; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.ClientStack.Linden; +using OpenSim.Region.CoreModules.Avatar.InstantMessage; +using OpenSim.Region.CoreModules.Framework; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups; using OpenSim.Tests.Common; -using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests { @@ -44,11 +54,28 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests [TestFixture] public class GroupsModuleTests : OpenSimTestCase { + [SetUp] + public override void SetUp() + { + base.SetUp(); + + uint port = 9999; + uint sslPort = 9998; + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + MainServer.RemoveHttpServer(port); + + BaseHttpServer server = new BaseHttpServer(port, false, sslPort, ""); + MainServer.AddHttpServer(server); + MainServer.Instance = server; + } + [Test] - public void TestBasic() + public void TestSendAgentGroupDataUpdate() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); TestScene scene = new SceneHelpers().SetupScene(); IConfigSource configSource = new IniConfigSource(); @@ -56,8 +83,185 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests config.Set("Enabled", true); config.Set("Module", "GroupsModule"); config.Set("DebugEnabled", true); + + GroupsModule gm = new GroupsModule(); + EventQueueGetModule eqgm = new EventQueueGetModule(); + + // We need a capabilities module active so that adding the scene presence creates an event queue in the + // EventQueueGetModule SceneHelpers.SetupSceneModules( - scene, configSource, new object[] { new MockGroupsServicesConnector() }); + scene, configSource, gm, new MockGroupsServicesConnector(), new CapabilitiesModule(), eqgm); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseStem("1")); + + gm.SendAgentGroupDataUpdate(sp.ControllingClient); + + Hashtable eventsResponse = eqgm.GetEvents(UUID.Zero, sp.UUID); + + Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK)); + +// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]); + + OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]); + OSDArray eventsOsd = (OSDArray)rawOsd["events"]; + + bool foundUpdate = false; + foreach (OSD osd in eventsOsd) + { + OSDMap eventOsd = (OSDMap)osd; + + if (eventOsd["message"] == "AgentGroupDataUpdate") + foundUpdate = true; + } + + Assert.That(foundUpdate, Is.True, "Did not find AgentGroupDataUpdate in response"); + + // TODO: More checking of more actual event data. + } + + [Test] + public void TestSendGroupNotice() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + TestScene scene = new SceneHelpers().SetupScene(); + + MessageTransferModule mtm = new MessageTransferModule(); + GroupsModule gm = new GroupsModule(); + GroupsMessagingModule gmm = new GroupsMessagingModule(); + MockGroupsServicesConnector mgsc = new MockGroupsServicesConnector(); + + IConfigSource configSource = new IniConfigSource(); + + { + IConfig config = configSource.AddConfig("Messaging"); + config.Set("MessageTransferModule", mtm.Name); + } + + { + IConfig config = configSource.AddConfig("Groups"); + config.Set("Enabled", true); + config.Set("Module", gm.Name); + config.Set("DebugEnabled", true); + config.Set("MessagingModule", gmm.Name); + config.Set("MessagingEnabled", true); + } + + SceneHelpers.SetupSceneModules(scene, configSource, mgsc, mtm, gm, gmm); + + UUID userId = TestHelpers.ParseTail(0x1); + string subjectText = "newman"; + string messageText = "Hello"; + string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + TestClient tc = (TestClient)sp.ControllingClient; + + UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true); + gm.JoinGroupRequest(tc, groupID); + + // Create a second user who doesn't want to receive notices + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2)); + TestClient tc2 = (TestClient)sp2.ControllingClient; + gm.JoinGroupRequest(tc2, groupID); + gm.SetGroupAcceptNotices(tc2, groupID, false, true); + + List spReceivedMessages = new List(); + tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im); + + List sp2ReceivedMessages = new List(); + tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im); + + GridInstantMessage noticeIm = new GridInstantMessage(); + noticeIm.fromAgentID = userId.Guid; + noticeIm.toAgentID = groupID.Guid; + noticeIm.message = combinedSubjectMessage; + noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice; + + tc.HandleImprovedInstantMessage(noticeIm); + + Assert.That(spReceivedMessages.Count, Is.EqualTo(1)); + Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage)); + + List notices = mgsc.GetGroupNotices(UUID.Zero, groupID); + Assert.AreEqual(1, notices.Count); + + // OpenSimulator (possibly also SL) transport the notice ID as the session ID! + Assert.AreEqual(notices[0].NoticeID.Guid, spReceivedMessages[0].imSessionID); + + Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0)); + } + + /// + /// Run test with the MessageOnlineUsersOnly flag set. + /// + [Test] + public void TestSendGroupNoticeOnlineOnly() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); + + TestScene scene = new SceneHelpers().SetupScene(); + + MessageTransferModule mtm = new MessageTransferModule(); + GroupsModule gm = new GroupsModule(); + GroupsMessagingModule gmm = new GroupsMessagingModule(); + + IConfigSource configSource = new IniConfigSource(); + + { + IConfig config = configSource.AddConfig("Messaging"); + config.Set("MessageTransferModule", mtm.Name); + } + + { + IConfig config = configSource.AddConfig("Groups"); + config.Set("Enabled", true); + config.Set("Module", gm.Name); + config.Set("DebugEnabled", true); + config.Set("MessagingModule", gmm.Name); + config.Set("MessagingEnabled", true); + config.Set("MessageOnlineUsersOnly", true); + } + + SceneHelpers.SetupSceneModules(scene, configSource, new MockGroupsServicesConnector(), mtm, gm, gmm); + + UUID userId = TestHelpers.ParseTail(0x1); + string subjectText = "newman"; + string messageText = "Hello"; + string combinedSubjectMessage = string.Format("{0}|{1}", subjectText, messageText); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + TestClient tc = (TestClient)sp.ControllingClient; + + UUID groupID = gm.CreateGroup(tc, "group1", null, true, UUID.Zero, 0, true, true, true); + gm.JoinGroupRequest(tc, groupID); + + // Create a second user who doesn't want to receive notices + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x2)); + TestClient tc2 = (TestClient)sp2.ControllingClient; + gm.JoinGroupRequest(tc2, groupID); + gm.SetGroupAcceptNotices(tc2, groupID, false, true); + + List spReceivedMessages = new List(); + tc.OnReceivedInstantMessage += im => spReceivedMessages.Add(im); + + List sp2ReceivedMessages = new List(); + tc2.OnReceivedInstantMessage += im => sp2ReceivedMessages.Add(im); + + GridInstantMessage noticeIm = new GridInstantMessage(); + noticeIm.fromAgentID = userId.Guid; + noticeIm.toAgentID = groupID.Guid; + noticeIm.message = combinedSubjectMessage; + noticeIm.dialog = (byte)InstantMessageDialog.GroupNotice; + + tc.HandleImprovedInstantMessage(noticeIm); + + Assert.That(spReceivedMessages.Count, Is.EqualTo(1)); + Assert.That(spReceivedMessages[0].message, Is.EqualTo(combinedSubjectMessage)); + + Assert.That(sp2ReceivedMessages.Count, Is.EqualTo(0)); } } } \ 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; using OpenMetaverse.StructuredData; using OpenSim.Framework; -using OpenSim.Framework.Communications; using OpenSim.Region.Framework.Interfaces; using OpenSim.Services.Interfaces; @@ -168,8 +167,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups m_log.DebugFormat("[XMLRPC-GROUPS-CONNECTOR]: Initializing {0}", this.Name); m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty); - if ((m_groupsServerURI == null) || - (m_groupsServerURI == string.Empty)) + if (string.IsNullOrEmpty(m_groupsServerURI)) { m_log.ErrorFormat("Please specify a valid URL for GroupsServerURI in OpenSim.ini, [Groups]"); m_connectorEnabled = false; @@ -354,7 +352,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups { param["GroupID"] = GroupID.ToString(); } - if ((GroupName != null) && (GroupName != string.Empty)) + if (!string.IsNullOrEmpty(GroupName)) { param["Name"] = GroupName.ToString(); } @@ -1013,7 +1011,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups Hashtable respData = (Hashtable)resp.Value; if (respData.Contains("error") && !respData.Contains("succeed")) { - LogRespDataToConsoleError(respData); + LogRespDataToConsoleError(requestingAgentID, function, param, respData); } return respData; @@ -1041,20 +1039,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups return error; } - private void LogRespDataToConsoleError(Hashtable respData) + private void LogRespDataToConsoleError(UUID requestingAgentID, string function, Hashtable param, Hashtable respData) { - m_log.Error("[XMLRPC-GROUPS-CONNECTOR]: Error:"); - - foreach (string key in respData.Keys) - { - m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: Key: {0}", key); - - string[] lines = respData[key].ToString().Split(new char[] { '\n' }); - foreach (string line in lines) - { - m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: {0}", line); - } - } + m_log.ErrorFormat( + "[XMLRPC-GROUPS-CONNECTOR]: Error when calling {0} for {1} with params {2}. Response params are {3}", + function, requestingAgentID, Util.PrettyFormatToSingleLine(param), Util.PrettyFormatToSingleLine(respData)); } /// @@ -1146,28 +1135,38 @@ namespace Nwc.XmlRpc request.AllowWriteStreamBuffering = true; request.KeepAlive = !_disableKeepAlive; - Stream stream = request.GetRequestStream(); - XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII); - _serializer.Serialize(xml, this); - xml.Flush(); - xml.Close(); - - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - StreamReader input = new StreamReader(response.GetResponseStream()); - - string inputXml = input.ReadToEnd(); - XmlRpcResponse resp; - try + using (Stream stream = request.GetRequestStream()) { - resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); + using (XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII)) + { + _serializer.Serialize(xml, this); + xml.Flush(); + } } - catch (Exception e) + + XmlRpcResponse resp; + + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { - RequestResponse = inputXml; - throw e; + using (Stream s = response.GetResponseStream()) + { + using (StreamReader input = new StreamReader(s)) + { + string inputXml = input.ReadToEnd(); + + try + { + resp = (XmlRpcResponse)_deserializer.Deserialize(inputXml); + } + catch (Exception e) + { + RequestResponse = inputXml; + throw e; + } + } + } } - input.Close(); - response.Close(); + return resp; } } -- cgit v1.1