merging changes from IRCBridgeModule in to XIRCBridgeModule; swapping
OpenSim.ini config tags in preparation for merge of IRCBridgeModule and XIRCBridgeModule.0.6.0-stable
parent
d0c8d7a177
commit
d6d2a38e76
|
@ -50,6 +50,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
|
|
||||||
private static Regex arg = new Regex(@"\[[^\[\]]*\]");
|
private static Regex arg = new Regex(@"\[[^\[\]]*\]");
|
||||||
private static int _idk_ = 0;
|
private static int _idk_ = 0;
|
||||||
|
private static int DEBUG_CHANNEL = 2147483647;
|
||||||
|
|
||||||
// These are the IRC Connector configurable parameters with hard-wired
|
// These are the IRC Connector configurable parameters with hard-wired
|
||||||
// default values (retained for compatability).
|
// default values (retained for compatability).
|
||||||
|
@ -61,8 +62,10 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
internal string User = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
|
internal string User = "USER OpenSimBot 8 * :I'm an OpenSim to IRC bot";
|
||||||
|
|
||||||
internal bool ClientReporting = true;
|
internal bool ClientReporting = true;
|
||||||
|
internal bool RelayChat = true;
|
||||||
internal bool RelayPrivateChannels = false;
|
internal bool RelayPrivateChannels = false;
|
||||||
internal int RelayChannel = 1;
|
internal int RelayChannel = 1;
|
||||||
|
internal List<int> ValidInWorldChannels = new List<int>();
|
||||||
|
|
||||||
// Connector agnostic parameters. These values are NOT shared with the
|
// Connector agnostic parameters. These values are NOT shared with the
|
||||||
// connector and do not differentiate at an IRC level
|
// connector and do not differentiate at an IRC level
|
||||||
|
@ -71,13 +74,27 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
|
internal string NoticeMessageFormat = "PRIVMSG {0} :<{2}> {3}";
|
||||||
internal int RelayChannelOut = -1;
|
internal int RelayChannelOut = -1;
|
||||||
internal bool RandomizeNickname = true;
|
internal bool RandomizeNickname = true;
|
||||||
internal string AccessPassword = "badkitty";
|
|
||||||
internal bool CommandsEnabled = false;
|
internal bool CommandsEnabled = false;
|
||||||
internal int CommandChannel = -1;
|
internal int CommandChannel = -1;
|
||||||
internal int ConnectDelay = 10;
|
internal int ConnectDelay = 10;
|
||||||
internal int PingDelay = 15;
|
internal int PingDelay = 15;
|
||||||
internal string DefaultZone = "Sim";
|
internal string DefaultZone = "Sim";
|
||||||
|
|
||||||
|
internal string _accessPassword = String.Empty;
|
||||||
|
internal Regex AccessPasswordRegex = null;
|
||||||
|
internal string AccessPassword
|
||||||
|
{
|
||||||
|
get { return _accessPassword; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_accessPassword = value;
|
||||||
|
AccessPasswordRegex = new Regex(String.Format(@"^{0},\s*(?<avatar>[^,]+),\s*(?<message>.+)$", _accessPassword),
|
||||||
|
RegexOptions.Compiled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// IRC connector reference
|
// IRC connector reference
|
||||||
|
|
||||||
internal XIRCConnector irc = null;
|
internal XIRCConnector irc = null;
|
||||||
|
@ -108,9 +125,11 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
User = model.User;
|
User = model.User;
|
||||||
CommandsEnabled = model.CommandsEnabled;
|
CommandsEnabled = model.CommandsEnabled;
|
||||||
CommandChannel = model.CommandChannel;
|
CommandChannel = model.CommandChannel;
|
||||||
|
RelayChat = model.RelayChat;
|
||||||
RelayPrivateChannels = model.RelayPrivateChannels;
|
RelayPrivateChannels = model.RelayPrivateChannels;
|
||||||
RelayChannelOut = model.RelayChannelOut;
|
RelayChannelOut = model.RelayChannelOut;
|
||||||
RelayChannel = model.RelayChannel;
|
RelayChannel = model.RelayChannel;
|
||||||
|
ValidInWorldChannels = model.ValidInWorldChannels;
|
||||||
PrivateMessageFormat = model.PrivateMessageFormat;
|
PrivateMessageFormat = model.PrivateMessageFormat;
|
||||||
NoticeMessageFormat = model.NoticeMessageFormat;
|
NoticeMessageFormat = model.NoticeMessageFormat;
|
||||||
ClientReporting = model.ClientReporting;
|
ClientReporting = model.ClientReporting;
|
||||||
|
@ -158,6 +177,8 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
m_log.DebugFormat("[IRC-Channel-{0}] CommandChannel : <{1}>", cs.idn, 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);
|
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))));
|
||||||
|
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))));
|
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);
|
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))));
|
cs.RelayPrivateChannels = Convert.ToBoolean(Substitute(rs, config.GetString("useworldcomm", Convert.ToString(cs.RelayPrivateChannels))));
|
||||||
|
@ -176,14 +197,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
|
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);
|
m_log.DebugFormat("[IRC-Channel-{0}] ClientReporting : <{1}>", cs.idn, cs.ClientReporting);
|
||||||
cs.AccessPassword = Substitute(rs, config.GetString("access_password", cs.AccessPassword));
|
|
||||||
m_log.DebugFormat("[IRC-Channel-{0}] AccessPassword : <{1}>", cs.idn, cs.AccessPassword);
|
|
||||||
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);
|
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);
|
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);
|
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);
|
||||||
|
|
||||||
|
|
||||||
// Fail if fundamental information is still missing
|
// Fail if fundamental information is still missing
|
||||||
|
|
||||||
|
@ -199,6 +221,15 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
|
|
||||||
// Set the channel state for this region
|
// Set the channel state for this region
|
||||||
|
|
||||||
|
if (cs.RelayChat)
|
||||||
|
{
|
||||||
|
cs.ValidInWorldChannels.Add(0);
|
||||||
|
cs.ValidInWorldChannels.Add(DEBUG_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cs.RelayPrivateChannels)
|
||||||
|
cs.ValidInWorldChannels.Add(cs.RelayChannelOut);
|
||||||
|
|
||||||
rs.cs = Integrate(rs, cs);
|
rs.cs = Integrate(rs, cs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -377,18 +408,18 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
private bool IsAPerfectMatchFor(ChannelState cs)
|
private bool IsAPerfectMatchFor(ChannelState cs)
|
||||||
{
|
{
|
||||||
return ( IsAConnectionMatchFor(cs) &&
|
return ( IsAConnectionMatchFor(cs) &&
|
||||||
|
RelayChannelOut == cs.RelayChannelOut &&
|
||||||
RelayChannelOut == cs.RelayChannelOut &&
|
PrivateMessageFormat == cs.PrivateMessageFormat &&
|
||||||
PrivateMessageFormat == cs.PrivateMessageFormat &&
|
NoticeMessageFormat == cs.NoticeMessageFormat &&
|
||||||
NoticeMessageFormat == cs.NoticeMessageFormat &&
|
RandomizeNickname == cs.RandomizeNickname &&
|
||||||
RandomizeNickname == cs.RandomizeNickname &&
|
AccessPassword == cs.AccessPassword &&
|
||||||
AccessPassword == cs.AccessPassword &&
|
CommandsEnabled == cs.CommandsEnabled &&
|
||||||
CommandsEnabled == cs.CommandsEnabled &&
|
CommandChannel == cs.CommandChannel &&
|
||||||
CommandChannel == cs.CommandChannel &&
|
DefaultZone == cs.DefaultZone &&
|
||||||
DefaultZone == cs.DefaultZone &&
|
RelayPrivateChannels == cs.RelayPrivateChannels &&
|
||||||
RelayPrivateChannels == cs.RelayPrivateChannels &&
|
RelayChannel == cs.RelayChannel &&
|
||||||
RelayChannel == cs.RelayChannel &&
|
RelayChat == cs.RelayChat &&
|
||||||
ClientReporting == cs.ClientReporting
|
ClientReporting == cs.ClientReporting
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((m_config = config.Configs["IRC"]) == null)
|
if ((m_config = config.Configs["OIRC"]) == null)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[IRC] module not configured");
|
m_log.InfoFormat("[IRC] module not configured");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -177,23 +177,23 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_server = config.Configs["IRC"].GetString("server");
|
m_server = config.Configs["OIRC"].GetString("server");
|
||||||
m_baseNick = config.Configs["IRC"].GetString("nick", "OSimBot");
|
m_baseNick = config.Configs["OIRC"].GetString("nick", "OSimBot");
|
||||||
|
|
||||||
m_randomizeNick = config.Configs["IRC"].GetBoolean("randomize_nick", m_randomizeNick);
|
m_randomizeNick = config.Configs["OIRC"].GetBoolean("randomize_nick", m_randomizeNick);
|
||||||
m_randomizeNick = config.Configs["IRC"].GetBoolean("nicknum", m_randomizeNick); // compat
|
m_randomizeNick = config.Configs["OIRC"].GetBoolean("nicknum", m_randomizeNick); // compat
|
||||||
m_ircChannel = config.Configs["IRC"].GetString("channel");
|
m_ircChannel = config.Configs["OIRC"].GetString("channel");
|
||||||
m_port = (uint)config.Configs["IRC"].GetInt("port", (int)m_port);
|
m_port = (uint)config.Configs["OIRC"].GetInt("port", (int)m_port);
|
||||||
m_user = config.Configs["IRC"].GetString("username", m_user);
|
m_user = config.Configs["OIRC"].GetString("username", m_user);
|
||||||
m_privmsgformat = config.Configs["IRC"].GetString("msgformat", m_privmsgformat);
|
m_privmsgformat = config.Configs["OIRC"].GetString("msgformat", m_privmsgformat);
|
||||||
|
|
||||||
m_clientReporting = config.Configs["IRC"].GetInt("verbosity", 2) > 0;
|
m_clientReporting = config.Configs["OIRC"].GetInt("verbosity", 2) > 0;
|
||||||
m_clientReporting = config.Configs["IRC"].GetBoolean("report_clients", m_clientReporting);
|
m_clientReporting = config.Configs["OIRC"].GetBoolean("report_clients", m_clientReporting);
|
||||||
|
|
||||||
m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("relay_private_channels", m_relayPrivateChannels);
|
m_relayPrivateChannels = config.Configs["OIRC"].GetBoolean("relay_private_channels", m_relayPrivateChannels);
|
||||||
m_relayPrivateChannels = config.Configs["IRC"].GetBoolean("useworldcomm", m_relayPrivateChannels); //compat
|
m_relayPrivateChannels = config.Configs["OIRC"].GetBoolean("useworldcomm", m_relayPrivateChannels); //compat
|
||||||
m_relayChannel = config.Configs["IRC"].GetInt("relay_private_channel_in", m_relayChannel);
|
m_relayChannel = config.Configs["OIRC"].GetInt("relay_private_channel_in", m_relayChannel);
|
||||||
m_relayChannel = config.Configs["IRC"].GetInt("inchannel", m_relayChannel);
|
m_relayChannel = config.Configs["OIRC"].GetInt("inchannel", m_relayChannel);
|
||||||
|
|
||||||
if (m_server != null && m_baseNick != null && m_ircChannel != null)
|
if (m_server != null && m_baseNick != null && m_ircChannel != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using log4net;
|
using log4net;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
@ -331,27 +332,16 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// drop all messages coming in on a private channel,
|
// drop messages unless they are on a valid in-world
|
||||||
// except if we are relaying private channels, in which
|
// channel as configured in the ChannelState
|
||||||
// case we drop if the private channel is not the
|
|
||||||
// configured m_relayChannelOut
|
|
||||||
|
|
||||||
if (cs.RelayPrivateChannels)
|
if (!cs.ValidInWorldChannels.Contains(msg.Channel))
|
||||||
{
|
|
||||||
if (msg.Channel != 0 && msg.Channel != DEBUG_CHANNEL && msg.Channel != cs.RelayChannelOut)
|
|
||||||
{
|
|
||||||
m_log.DebugFormat("[IRC-Region {0}] dropping message {1} on channel {2}", Region, msg, msg.Channel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (msg.Channel != 0 && msg.Channel != DEBUG_CHANNEL)
|
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[IRC-Region {0}] dropping message {1} on channel {2}", Region, msg, msg.Channel);
|
m_log.DebugFormat("[IRC-Region {0}] dropping message {1} on channel {2}", Region, msg, msg.Channel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScenePresence avatar = null;
|
ScenePresence avatar = null;
|
||||||
|
|
||||||
string fromName = msg.From;
|
string fromName = msg.From;
|
||||||
|
|
||||||
if (msg.Sender != null)
|
if (msg.Sender != null)
|
||||||
|
@ -368,31 +358,26 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
|
|
||||||
m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
|
m_log.DebugFormat("[IRC-Region {0}] heard on channel {1} : {2}", Region, msg.Channel, msg.Message);
|
||||||
|
|
||||||
if (null != avatar)
|
if (null != avatar && cs.RelayChat && (msg.Channel == 0 || msg.Channel == DEBUG_CHANNEL))
|
||||||
{
|
{
|
||||||
string txt = msg.Message;
|
string txt = msg.Message;
|
||||||
if (txt.StartsWith("/me "))
|
if (txt.StartsWith("/me "))
|
||||||
txt = String.Format("{0} {1}", fromName, msg.Message.Substring(4));
|
txt = String.Format("{0} {1}", fromName, msg.Message.Substring(4));
|
||||||
|
|
||||||
cs.irc.PrivMsg(cs.PrivateMessageFormat, fromName, Region, txt);
|
cs.irc.PrivMsg(cs.PrivateMessageFormat, fromName, Region, txt);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
//Message came from an object
|
|
||||||
char[] splits = { ',' };
|
|
||||||
string[] tokens = msg.Message.Split(splits,3); // This is certainly wrong
|
|
||||||
|
|
||||||
if (tokens.Length == 3)
|
if (null == avatar && cs.RelayPrivateChannels && null != cs.AccessPassword &&
|
||||||
|
msg.Channel == cs.RelayChannelOut)
|
||||||
|
{
|
||||||
|
Match m = cs.AccessPasswordRegex.Match(msg.Message);
|
||||||
|
if (null != m)
|
||||||
{
|
{
|
||||||
if (tokens[0] == cs.AccessPassword) // This is my really simple check
|
m_log.DebugFormat("[IRC] relaying message from {0}: {1}", m.Groups["avatar"].ToString(),
|
||||||
{
|
m.Groups["message"].ToString());
|
||||||
m_log.DebugFormat("[IRC-Region {0}] message from object {1}, {2}", Region, tokens[0], tokens[1]);
|
cs.irc.PrivMsg(cs.PrivateMessageFormat, m.Groups["avatar"].ToString(),
|
||||||
cs.irc.PrivMsg(cs.PrivateMessageFormat, tokens[1], scene.RegionInfo.RegionName, tokens[2]);
|
scene.RegionInfo.RegionName, m.Groups["message"].ToString());
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_log.WarnFormat("[IRC-Region {0}] prim security key mismatch <{1}> not <{2}>", Region, tokens[0], cs.AccessPassword);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((m_config = config.Configs["XIRC"]) == null)
|
if ((m_config = config.Configs["IRC"]) == null)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[XIRC-Bridge] module not configured");
|
m_log.InfoFormat("[XIRC-Bridge] module not configured");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -521,6 +521,9 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Regex RE = new Regex(@":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)",
|
||||||
|
RegexOptions.Multiline);
|
||||||
|
|
||||||
private Dictionary<string, string> ExtractMsg(string input)
|
private Dictionary<string, string> ExtractMsg(string input)
|
||||||
{
|
{
|
||||||
//examines IRC commands and extracts any private messages
|
//examines IRC commands and extracts any private messages
|
||||||
|
@ -529,8 +532,6 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Chat
|
||||||
// m_log.InfoFormat("[IRC-Connector-{0}]: ExtractMsg: {1}", idn, input);
|
// m_log.InfoFormat("[IRC-Connector-{0}]: ExtractMsg: {1}", idn, input);
|
||||||
|
|
||||||
Dictionary<string, string> result = null;
|
Dictionary<string, string> result = null;
|
||||||
string regex = @":(?<nick>[\w-]*)!(?<user>\S*) PRIVMSG (?<channel>\S+) :(?<msg>.*)";
|
|
||||||
Regex RE = new Regex(regex, RegexOptions.Multiline);
|
|
||||||
MatchCollection matches = RE.Matches(input);
|
MatchCollection matches = RE.Matches(input);
|
||||||
|
|
||||||
// Get some direct matches $1 $4 is a
|
// Get some direct matches $1 $4 is a
|
||||||
|
|
Loading…
Reference in New Issue