From e977761071a2d614a9a621437fbf86479b414759 Mon Sep 17 00:00:00 2001
From: SignpostMarv
Date: Tue, 23 Oct 2012 15:42:16 +0100
Subject: adding ability for listeners to be filtered by regular expressions
and a general-purpose function to see if a given string matches a given regex
---
.../Scripting/WorldComm/WorldCommModule.cs | 129 ++++++++++++++++++---
OpenSim/Region/Framework/Interfaces/IWorldComm.cs | 25 ++++
.../Shared/Api/Implementation/OSSL_Api.cs | 63 ++++++++++
.../ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs | 24 ++++
.../Shared/Api/Runtime/LSL_Constants.cs | 10 ++
.../ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs | 10 ++
6 files changed, 242 insertions(+), 19 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
index c68ed6b..cf0eb2a 100644
--- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs
@@ -28,6 +28,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Text.RegularExpressions;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
@@ -170,12 +171,42 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
/// UUID of the SceneObjectPart
/// channel to listen on
/// name to filter on
- /// key to filter on (user given, could be totally faked)
+ ///
+ /// key to filter on (user given, could be totally faked)
+ ///
/// msg to filter on
/// number of the scripts handle
- public int Listen(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
+ public int Listen(uint localID, UUID itemID, UUID hostID, int channel,
+ string name, UUID id, string msg)
{
- return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg);
+ return m_listenerManager.AddListener(localID, itemID, hostID,
+ channel, name, id, msg);
+ }
+
+ ///
+ /// Create a listen event callback with the specified filters.
+ /// The parameters localID,itemID are needed to uniquely identify
+ /// the script during 'peek' time. Parameter hostID is needed to
+ /// determine the position of the script.
+ ///
+ /// localID of the script engine
+ /// UUID of the script engine
+ /// UUID of the SceneObjectPart
+ /// channel to listen on
+ /// name to filter on
+ ///
+ /// key to filter on (user given, could be totally faked)
+ ///
+ /// msg to filter on
+ ///
+ /// Bitfield indicating which strings should be processed as regex.
+ ///
+ /// number of the scripts handle
+ public int Listen(uint localID, UUID itemID, UUID hostID, int channel,
+ string name, UUID id, string msg, int regexBitfield)
+ {
+ return m_listenerManager.AddListener(localID, itemID, hostID,
+ channel, name, id, msg, regexBitfield);
}
///
@@ -465,10 +496,20 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_curlisteners = 0;
}
- public int AddListener(uint localID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg)
+ public int AddListener(uint localID, UUID itemID, UUID hostID,
+ int channel, string name, UUID id, string msg)
+ {
+ return AddListener(localID, itemID, hostID, channel, name, id,
+ msg, 0);
+ }
+
+ public int AddListener(uint localID, UUID itemID, UUID hostID,
+ int channel, string name, UUID id, string msg,
+ int regexBitfield)
{
// do we already have a match on this particular filter event?
- List coll = GetListeners(itemID, channel, name, id, msg);
+ List coll = GetListeners(itemID, channel, name, id,
+ msg);
if (coll.Count > 0)
{
@@ -485,7 +526,9 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
if (newHandle > 0)
{
- ListenerInfo li = new ListenerInfo(newHandle, localID, itemID, hostID, channel, name, id, msg);
+ ListenerInfo li = new ListenerInfo(newHandle, localID,
+ itemID, hostID, channel, name, id, msg,
+ regexBitfield);
List listeners;
if (!m_listeners.TryGetValue(channel,out listeners))
@@ -626,6 +669,22 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
return -1;
}
+ /// These are duplicated from ScriptBaseClass
+ /// http://opensimulator.org/mantis/view.php?id=6106#c21945
+ #region Constants for the bitfield parameter of osListenRegex
+
+ ///
+ /// process name parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_NAME = 0x1;
+
+ ///
+ /// process message parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
+
+ #endregion
+
// Theres probably a more clever and efficient way to
// do this, maybe with regex.
// PM2008: Ha, one could even be smart and define a specialized Enumerator.
@@ -651,7 +710,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
continue;
}
- if (li.GetName().Length > 0 && !li.GetName().Equals(name))
+ if (li.GetName().Length > 0 && (
+ ((li.GetRegexBitfield() & OS_LISTEN_REGEX_NAME) != OS_LISTEN_REGEX_NAME && !li.GetName().Equals(name)) ||
+ ((li.GetRegexBitfield() & OS_LISTEN_REGEX_NAME) == OS_LISTEN_REGEX_NAME && !Regex.IsMatch(name, li.GetName()))
+ ))
{
continue;
}
@@ -659,7 +721,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
continue;
}
- if (li.GetMessage().Length > 0 && !li.GetMessage().Equals(msg))
+ if (li.GetMessage().Length > 0 && (
+ ((li.GetRegexBitfield() & OS_LISTEN_REGEX_MESSAGE) != OS_LISTEN_REGEX_MESSAGE && !li.GetMessage().Equals(msg)) ||
+ ((li.GetRegexBitfield() & OS_LISTEN_REGEX_MESSAGE) == OS_LISTEN_REGEX_MESSAGE && !Regex.IsMatch(msg, li.GetMessage()))
+ ))
{
continue;
}
@@ -692,10 +757,13 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
int idx = 0;
Object[] item = new Object[6];
+ int dataItemLength = 6;
while (idx < data.Length)
{
- Array.Copy(data, idx, item, 0, 6);
+ dataItemLength = (idx + 7 == data.Length || (idx + 7 < data.Length && data[idx + 7] is bool)) ? 7 : 6;
+ item = new Object[dataItemLength];
+ Array.Copy(data, idx, item, 0, dataItemLength);
ListenerInfo info =
ListenerInfo.FromData(localID, itemID, hostID, item);
@@ -707,7 +775,7 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_listeners[(int)item[2]].Add(info);
}
- idx+=6;
+ idx+=dataItemLength;
}
}
}
@@ -723,19 +791,33 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
private UUID m_id; // ID to filter messages from
private string m_name; // Object name to filter messages from
private string m_message; // The message
+ private int m_regexBitfield; // The regex bitfield
public ListenerInfo(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message)
{
- Initialise(handle, localID, ItemID, hostID, channel, name, id, message);
+ Initialise(handle, localID, ItemID, hostID, channel, name, id,
+ message, 0);
+ }
+
+ public ListenerInfo(int handle, uint localID, UUID ItemID,
+ UUID hostID, int channel, string name, UUID id,
+ string message, int regexBitfield)
+ {
+ Initialise(handle, localID, ItemID, hostID, channel, name, id,
+ message, regexBitfield);
}
public ListenerInfo(ListenerInfo li, string name, UUID id, string message)
{
- Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message);
+ Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message, 0);
+ }
+
+ public ListenerInfo(ListenerInfo li, string name, UUID id, string message, int regexBitfield)
+ {
+ Initialise(li.m_handle, li.m_localID, li.m_itemID, li.m_hostID, li.m_channel, name, id, message, regexBitfield);
}
- private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name,
- UUID id, string message)
+ private void Initialise(int handle, uint localID, UUID ItemID, UUID hostID, int channel, string name, UUID id, string message, int regexBitfield)
{
m_active = true;
m_handle = handle;
@@ -746,11 +828,12 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
m_name = name;
m_id = id;
m_message = message;
+ m_regexBitfield = regexBitfield;
}
public Object[] GetSerializationData()
{
- Object[] data = new Object[6];
+ Object[] data = new Object[7];
data[0] = m_active;
data[1] = m_handle;
@@ -758,16 +841,19 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
data[3] = m_name;
data[4] = m_id;
data[5] = m_message;
+ data[6] = m_regexBitfield;
return data;
}
public static ListenerInfo FromData(uint localID, UUID ItemID, UUID hostID, Object[] data)
{
- ListenerInfo linfo = new ListenerInfo((int)data[1], localID,
- ItemID, hostID, (int)data[2], (string)data[3],
- (UUID)data[4], (string)data[5]);
- linfo.m_active=(bool)data[0];
+ ListenerInfo linfo = new ListenerInfo((int)data[1], localID, ItemID, hostID, (int)data[2], (string)data[3], (UUID)data[4], (string)data[5]);
+ linfo.m_active = (bool)data[0];
+ if (data.Length >= 7)
+ {
+ linfo.m_regexBitfield = (int)data[6];
+ }
return linfo;
}
@@ -826,5 +912,10 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm
{
return m_id;
}
+
+ public int GetRegexBitfield()
+ {
+ return m_regexBitfield;
+ }
}
}
diff --git a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs
index 8d88065..66b3f3a 100644
--- a/OpenSim/Region/Framework/Interfaces/IWorldComm.cs
+++ b/OpenSim/Region/Framework/Interfaces/IWorldComm.cs
@@ -45,6 +45,14 @@ namespace OpenSim.Region.Framework.Interfaces
void Deactivate();
void Activate();
UUID GetID();
+
+ ///
+ /// Bitfield indicating which strings should be processed as regex.
+ /// 1 corresponds to IWorldCommListenerInfo::GetName()
+ /// 2 corresponds to IWorldCommListenerInfo::GetMessage()
+ ///
+ ///
+ int GetRegexBitfield();
}
public interface IWorldComm
@@ -70,6 +78,23 @@ namespace OpenSim.Region.Framework.Interfaces
/// number of the scripts handle
int Listen(uint LocalID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg);
+ ///
+ /// Create a listen event callback with the specified filters.
+ /// The parameters localID,itemID are needed to uniquely identify
+ /// the script during 'peek' time. Parameter hostID is needed to
+ /// determine the position of the script.
+ ///
+ /// localID of the script engine
+ /// UUID of the script engine
+ /// UUID of the SceneObjectPart
+ /// channel to listen on
+ /// name to filter on
+ /// key to filter on (user given, could be totally faked)
+ /// msg to filter on
+ /// Bitfield indicating which strings should be processed as regex.
+ /// number of the scripts handle
+ int Listen(uint LocalID, UUID itemID, UUID hostID, int channel, string name, UUID id, string msg, int regexBitfield);
+
///
/// This method scans over the objects which registered an interest in listen callbacks.
/// For everyone it finds, it checks if it fits the given filter. If it does, then
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index 0650b90..828288d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -3647,5 +3647,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
DropAttachmentAt(false, pos, rot);
}
+
+ public LSL_Integer osListenRegex(int channelID, string name, string ID, string msg, int regexBitfield)
+ {
+ CheckThreatLevel(ThreatLevel.Low, "osListenRegex");
+ m_host.AddScriptLPS(1);
+ UUID keyID;
+ UUID.TryParse(ID, out keyID);
+
+ // if we want the name to be used as a regular expression, ensure it is valid first.
+ if ((regexBitfield & ScriptBaseClass.OS_LISTEN_REGEX_NAME) == ScriptBaseClass.OS_LISTEN_REGEX_NAME)
+ {
+ try
+ {
+ Regex.IsMatch("", name);
+ }
+ catch (Exception)
+ {
+ OSSLShoutError("Name regex is invalid.");
+ return -1;
+ }
+ }
+
+ // if we want the msg to be used as a regular expression, ensure it is valid first.
+ if ((regexBitfield & ScriptBaseClass.OS_LISTEN_REGEX_MESSAGE) == ScriptBaseClass.OS_LISTEN_REGEX_MESSAGE)
+ {
+ try
+ {
+ Regex.IsMatch("", msg);
+ }
+ catch (Exception)
+ {
+ OSSLShoutError("Message regex is invalid.");
+ return -1;
+ }
+ }
+
+ IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface();
+ return (wComm == null) ? -1 : wComm.Listen(
+ m_host.LocalId,
+ m_item.ItemID,
+ m_host.UUID,
+ channelID,
+ name,
+ keyID,
+ msg,
+ regexBitfield
+ );
+ }
+
+ public LSL_Integer osRegexIsMatch(string input, string pattern)
+ {
+ CheckThreatLevel(ThreatLevel.Low, "osRegexIsMatch");
+ m_host.AddScriptLPS(1);
+ try
+ {
+ return Regex.IsMatch(input, pattern) ? 1 : 0;
+ }
+ catch (Exception)
+ {
+ OSSLShoutError("Possible invalid regular expression detected.");
+ return 0;
+ }
+ }
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
index 93188c9..cdd9ea8 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs
@@ -418,5 +418,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
///
///
void osForceDropAttachmentAt(vector pos, rotation rot);
+
+ ///
+ /// Identical to llListen except for a bitfield which indicates which
+ /// string parameters should be parsed as regex patterns.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// OS_LISTEN_REGEX_NAME
+ /// OS_LISTEN_REGEX_MESSAGE
+ ///
+ ///
+ LSL_Integer osListenRegex(int channelID, string name, string ID,
+ string msg, int regexBitfield);
+
+ ///
+ /// Wraps to bool Regex.IsMatch(string input, string pattern)
+ ///
+ /// string to test for match
+ /// string to use as pattern
+ /// boolean
+ LSL_Integer osRegexIsMatch(string input, string pattern);
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
index 62bd6b8..880841b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs
@@ -716,5 +716,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
public static readonly LSLInteger RCERR_UNKNOWN = -1;
public static readonly LSLInteger RCERR_SIM_PERF_LOW = -2;
public static readonly LSLInteger RCERR_CAST_TIME_EXCEEDED = 3;
+
+ ///
+ /// process name parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_NAME = 0x1;
+
+ ///
+ /// process message parameter as regex
+ ///
+ public const int OS_LISTEN_REGEX_MESSAGE = 0x2;
}
}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index dee1b28..afa9ae0 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -992,5 +992,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
{
m_OSSL_Functions.osForceDropAttachmentAt(pos, rot);
}
+
+ public LSL_Integer osListenRegex(int channelID, string name, string ID, string msg, int regexBitfield)
+ {
+ return m_OSSL_Functions.osListenRegex(channelID, name, ID, msg, regexBitfield);
+ }
+
+ public LSL_Integer osRegexIsMatch(string input, string pattern)
+ {
+ return m_OSSL_Functions.osRegexIsMatch(input, pattern);
+ }
}
}
--
cgit v1.1