Threat level

From OpenSimulator

(Difference between revisions)
Jump to: navigation, search
m
m (Indentation)
 
(7 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Template:Quicklinks}} To permit region owners to enable the extended scripting functionality of [[OSSL]], without allowing malicious scripts to access potentially troublesome functions, each OSSL function is assigned a '''threat level''', and access to the functions is granted or denied based on a default threshold set in '''OpenSim.ini''' (which can be overridden for individual functions on a case-by-case basis).  Review [[OSSL_Enabling_Functions]] page with a full example for Implementing the various osFunctions for your system.
+
{{Quicklinks}}
 +
To permit region owners to enable the extended scripting functionality of [[OSSL]], without allowing malicious scripts to access potentially troublesome functions, each OSSL function is assigned a '''threat level''', and access to the functions is granted or denied based on a default threshold set in '''OpenSim.ini''' (which can be overridden for individual functions on a case-by-case basis). Review [[OSSL Enabling Functions]] page with a full example for Implementing the various osFunctions for your system.
  
 
The threat levels, from wholly unthreatening to most potentially damaging, are:  
 
The threat levels, from wholly unthreatening to most potentially damaging, are:  
Line 5: Line 6:
 
;None  
 
;None  
 
:Function is no threat at all. It doesn't constitute a threat to either users or the system and has no known side effects.  
 
:Function is no threat at all. It doesn't constitute a threat to either users or the system and has no known side effects.  
 +
:Functions with the threat level "''None''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:None]]
 +
 
;Nuisance  
 
;Nuisance  
 
:Abuse of this command can cause a nuisance to the region operator, such as log message spew.  
 
:Abuse of this command can cause a nuisance to the region operator, such as log message spew.  
 +
:Functions with the threat level "''Nuisance''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:Nuisance]]
 +
 
;VeryLow  
 
;VeryLow  
 
:Extreme levels of abuse of this function can cause impaired functioning of the region, or very gullible users can be tricked into experiencing harmless effects.  
 
:Extreme levels of abuse of this function can cause impaired functioning of the region, or very gullible users can be tricked into experiencing harmless effects.  
 +
:Functions with the threat level "''VeryLow''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:VeryLow]]
 +
 
;Low  
 
;Low  
 
:Intentional abuse can cause crashes or malfunction under certain circumstances, which can be easily rectified; or certain users can be tricked into certain situations in an avoidable manner.  
 
:Intentional abuse can cause crashes or malfunction under certain circumstances, which can be easily rectified; or certain users can be tricked into certain situations in an avoidable manner.  
 +
:Functions with the threat level "''Low''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:Low]]
 +
 
;Moderate  
 
;Moderate  
 
:Intentional abuse can cause denial of service and crashes with potential of data or state loss; or trusting users can be tricked into embarrassing or uncomfortable situations.  
 
:Intentional abuse can cause denial of service and crashes with potential of data or state loss; or trusting users can be tricked into embarrassing or uncomfortable situations.  
 +
:Functions with the threat level "''Moderate''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:Moderate]]
 +
 
;High  
 
;High  
 
:Casual abuse can cause impaired functionality or temporary denial of service conditions. Intentional abuse can easily cause crashes with potential data loss, or can be used to trick experienced and cautious users into unwanted situations, or changes global data permanently and without undo ability.  
 
:Casual abuse can cause impaired functionality or temporary denial of service conditions. Intentional abuse can easily cause crashes with potential data loss, or can be used to trick experienced and cautious users into unwanted situations, or changes global data permanently and without undo ability.  
 +
:Functions with the threat level "''High''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:High]]
 +
 
;VeryHigh  
 
;VeryHigh  
 
:Even normal use may, depending on the number of instances, or frequency of use, result in severe service impairment or crash with loss of data, or can be used to cause unwanted or harmful effects on users without giving the user a means to avoid it.  
 
:Even normal use may, depending on the number of instances, or frequency of use, result in severe service impairment or crash with loss of data, or can be used to cause unwanted or harmful effects on users without giving the user a means to avoid it.  
 +
:Functions with the threat level "''VeryHigh''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:VeryHigh]]
 +
 
;Severe  
 
;Severe  
 
:Even casual use is a danger to region stability, or function allows console or OS command execution, or function allows taking money without consent, or allows deletion or modification of user data, or allows the compromise of sensitive data by design.
 
:Even casual use is a danger to region stability, or function allows console or OS command execution, or function allows taking money without consent, or allows deletion or modification of user data, or allows the compromise of sensitive data by design.
 +
:Functions with the threat level "''Severe''":
 +
:See [[:Category:OSSL_Functions/ThreatLevel:Severe]]
 +
 +
The '''OSFunctionThreatLevel''' setting in the script engines' configuration sections of OpenSim.ini controls what classes of functions are accessible to scripts owned by any avatar; any function at the same threat level or lower than the value provided for '''OsFunctionThreatLevel''' is permitted to run. If '''OSFunctionThreatLevel''' is absent from the configuration file, the default value is '''VeryLow'''.
  
<br>The '''OSFunctionThreatLevel''' setting in the script engines' configuration sections of OpenSim.ini controls what classes of functions are accessible to scripts owned by any avatar; any function at the same threat level or lower than the value provided for '''OsFunctionThreatLevel''' is permitted to run. If '''OSFunctionThreatLevel''' is absent from the configuration file, the default value is '''VeryLow'''.  
+
We do not recommend that you set a general level above Low unless you have a very high level of trust in all the visitors to the simulator that have the ability to run scripts.
  
OSSL functions may also be permitted or prohibited on an individual basis, by adding '''Allow_*''' lines to the script engine's configuration section. To permit scripts owned by anyone to access a function, even if its threat level exceeds the value of '''OSFunctionThreatLevel''', use the value 'true':  
+
It is safer to explicitly allow certain types of user to run higher threat level OSSL functions on an individual basis.  This can be done by adding '''Allow_*''' lines to the script engine's configuration section. To permit scripts owned by anyone to access a function, even if its threat level exceeds the value of '''OSFunctionThreatLevel''', use the value 'true':  
  
 
<source lang="ini">
 
<source lang="ini">
Line 28: Line 54:
 
</source>  
 
</source>  
  
To prohibit scripts owned by anyone from accessing a function, even if its threat level is equal to or below the value of '''OSFunctionThreatLevel''', use the value 'false':  
+
You can also prohibit individual OSSL functions, even if its threat level is equal to or below the value of '''OSFunctionThreatLevel''':
  
 
<source lang="ini">
 
<source lang="ini">
Line 41: Line 67:
 
</source>  
 
</source>  
  
Below is a list of OSSL functions grouped by threat level:
+
You can also allow categories of users to call given OSSL functions.  Currently, the categories are
  
;None
+
* PARCEL_GROUP_MEMBER: allow if object group is the same group as the parcel
:[[OsDrawEllipse]], [[OsDrawFilledPolygon]], [[OsDrawFilledRectangle]], [[OsDrawImage]], [[OsDrawLine]], [[OsDrawRectangle]], [[OsDrawText]], [[OsGetAgents]], [[OsGetCurrentSunHour]], [[OsGetMapTexture]], [[OsList2Double]], [[OsMovePen]], [[OsParseJSON]], [[OsSetFontName]], [[OsSetFontSize]], [[OsSetPenColour]], [[OsSetPenSize]], [[OsSunSetParam]], [[OsTerrainGetHeight]], [[OsWindActiveModelPluginName]]
+
* PARCEL_OWNER: allow if the object owner is parcel owner
 +
* ESTATE_MANAGER: allow if the object owner is an estate manager
 +
* ESTATE_OWNER: allow if object owner is estate owner
  
;Nuisance
+
For example
:[[OsSetEstateSunSettings]], [[OsSetRegionSunSettings]]
+
  
;VeryLow
+
<source lang="ini">
:[[OsGetDrawStringSize]], [[OsSetDynamicTextureData]], [[OsSetDynamicTextureDataBlend]], [[OsSetDynamicTextureDataBlendFace]], [[OsSetDynamicTextureURL]], [[OsSetDynamicTextureURLBlend]], [[OsSetDynamicTextureURLBlendFace]], [[OsSetParcelMediaURL]], [[OsSetPrimFloatOnWater]], [[OsTerrainFlush]], [[OsWindParamGet]], [[OsWindParamSet]]
+
Allow_osSetRegionWaterHeight = PARCEL_OWNER, ESTATE_OWNER
 +
</source>
  
;Low
+
Note that [[:Category:OSSL functions without threat level|wiki may not have the threat levels for some functions]] or have wrong threat levels. You can check actual threat levels by looking into OpenSim.Region.ScriptEngine.Shared.Api.OSSL_Api class in the source distribution or git master(see CheckThreatLevel() calling).
:[[OsAvatarName2Key]], [[OsFormatString]], [[OsKey2Name]], [[OsLoadedCreationDate]], [[OsLoadedCreationID]], [[OsLoadedCreationTime]], [[OsMessageObject]]
+
  
;Moderate
+
<br />
:[[OsGetGridLoginURI]], [[OsGetGridName]], [[OsGetGridNick]], [[OsGetRegionStats]], [[OsGetSimulatorMemory]], [[OsSetSpeed]]
+
  
;High
+
== Ascertaining privilege to use a function ==
:[[OsCauseDamage]], [[OsCauseHealing]], [[OsGetAgentIP]], [[OsGetLinkPrimitiveParams]], [[OsGetRegionMapTexture]], [[OsGetScriptEngineName]], [[OsGetSimulatorVersion]], [[OsMakeNotecard]], [[OsMatchString]], [[OsNpcCreate]], [[OsNpcMoveTo]], [[OsNpcRemove]], [[OsNpcSay]], [[OsRegionRestart]], [[OsSetRegionWaterHeight]], [[OsSetStateEvents]], [[OsTeleportAgent]], [[OsTerrainSetHeight]]
+
 
+
;VeryHigh
+
:[[OsAvatarPlayAnimation]], [[OsAvatarStopAnimation]], [[OsGetNotecard]], [[OsGetNotecardLine]], [[OsGetNumberOfNotecardLines]], [[OsRegionNotice]], [[OsSetRot]]
+
 
+
;Severe
+
:[[OsConsoleCommand]], [[OsKickAvatar]]
+
 
+
<br>
+
 
+
== Ascertaining privilege to use a function ==
+
  
 
There is not currently a function which would allow a script to determine whether or not it has permission to use any specific OSSL function. Such a function was proposed, but rejected by a developer on the grounds that it could permit a griefer script too much knowledge of its environment (though, as shown below, this information is already available through other methods, albeit less efficient ones).  
 
There is not currently a function which would allow a script to determine whether or not it has permission to use any specific OSSL function. Such a function was proposed, but rejected by a developer on the grounds that it could permit a griefer script too much knowledge of its environment (though, as shown below, this information is already available through other methods, albeit less efficient ones).  
Line 83: Line 98:
 
// various OSSL functions.
 
// various OSSL functions.
 
//
 
//
 +
 
integer WhichProbeFunction; // to tell us which function we're probing
 
integer WhichProbeFunction; // to tell us which function we're probing
 
integer NumberOfFunctionsToCheck; // how many functions are we probing?
 
integer NumberOfFunctionsToCheck; // how many functions are we probing?
list FunctionNames = [ "osTeleportAgent", "osGetAgentIP", "osGetAgents", "osAvatarPlayAnimation",
+
 
"osAvatarStopAnimation", "osAvatarName2Key", "osKey2Name" ];
+
list FunctionNames = [
 +
    "osTeleportAgent",  
 +
    "osGetAgentIP",  
 +
    "osGetAgents",  
 +
    "osAvatarPlayAnimation",
 +
    "osAvatarStopAnimation",  
 +
    "osAvatarName2Key",  
 +
    "osKey2Name"
 +
];
 +
 
 
list FunctionPermitted = [ 0, 0, 0, 0, 0, 0, 0 ]; // 0 = not permitted, 1 = permitted
 
list FunctionPermitted = [ 0, 0, 0, 0, 0, 0, 0 ]; // 0 = not permitted, 1 = permitted
  
  
// isFunctionAvailable() takes the name of a function, and returns 1 if it is available, and 0 if
+
// isFunctionAvailable() takes the name of a function, and returns 1 if it is available,  
// it is forbidden or has not been tested.
+
// and 0 if it is forbidden or has not been tested.
//
+
 
 
integer isFunctionAvailable( string whichFunction )
 
integer isFunctionAvailable( string whichFunction )
 
{
 
{
integer index = llListFindList( FunctionNames, whichFunction );
+
    integer index = llListFindList( FunctionNames, whichFunction );
if (index == -1) return 0; // Return FALSE if the function name wasn't one of the ones we checked.
+
    if (index == -1) return 0; // Return FALSE if the function name wasn't one of the ones we checked.
return llList2Integer( FunctionPermitted, index ); // return the appropriate availability flag.
+
    return llList2Integer( FunctionPermitted, index ); // return the appropriate availability flag.
 
}
 
}
  
Line 104: Line 129:
 
// use this fact to check all of our desired functions in turn, and then pass control to the Running
 
// use this fact to check all of our desired functions in turn, and then pass control to the Running
 
// state once we've checked them all.
 
// state once we've checked them all.
//
+
 
 
default
 
default
 
{
 
{
state_entry()
+
    state_entry()
{
+
    {
llOwnerSay( "Probing OSSL functions to see what we can use" );
+
        llOwnerSay( "Probing OSSL functions to see what we can use" );
NumberOfFunctionsToCheck = llGetListLength( FunctionNames );
+
        NumberOfFunctionsToCheck = llGetListLength( FunctionNames );
WhichProbeFunction = -1;
+
        WhichProbeFunction = -1;
llSetTimerEvent( 0.25 ); // check only four functions a second, just to be nice.
+
        llSetTimerEvent( 0.25 ); // check only four functions a second, just to be nice.
}
+
    }
+
 
timer()
+
    timer()
{
+
    {
string BogusKey = "12345678-1234-1234-1234-123456789abc"; // it doesn't need to be valid
+
        string BogusKey = "12345678-1234-1234-1234-123456789abc"; // it doesn't need to be valid
string s; // for storing the result of string functions
+
        string s; // for storing the result of string functions
list l; // for storing the result of list functions
+
        list l; // for storing the result of list functions
if (++WhichProbeFunction == NumberOfFunctionsToCheck) // Increment WhichProbeFunction; exit if we're done
+
 
{
+
        if (++WhichProbeFunction == NumberOfFunctionsToCheck) // Increment WhichProbeFunction; exit if we're done
llSetTimerEvent( 0.0 ); // stop the timer
+
        {
state Running; // switch to the Running state
+
            llSetTimerEvent( 0.0 ); // stop the timer
}
+
            state Running; // switch to the Running state
llOwnerSay( "Checking function " + llList2String( FunctionNames, WhichProbeFunction )); // say status
+
        }
if (WhichProbeFunction == 0)
+
 
osTeleportAgent( BogusKey, ZERO_VECTOR, ZERO_VECTOR );
+
        llOwnerSay( "Checking function " + llList2String( FunctionNames, WhichProbeFunction )); // say status
else if (WhichProbeFunction == 1)
+
        if (WhichProbeFunction == 0)
s = osGetAgentIP( BogusKey );
+
            osTeleportAgent( BogusKey, ZERO_VECTOR, ZERO_VECTOR );
else if (WhichProbeFunction == 2)
+
        else if (WhichProbeFunction == 1)
l = osGetAgents();
+
            s = osGetAgentIP( BogusKey );
else if (WhichProbeFunction == 3)
+
        else if (WhichProbeFunction == 2)
osAvatarPlayAnimation( BogusKey, BogusKey );
+
            l = osGetAgents();
else if (WhichProbeFunction == 4)
+
        else if (WhichProbeFunction == 3)
osAvatarStopAnimation( BogusKey, BogusKey );
+
            osAvatarPlayAnimation( BogusKey, BogusKey );
else if (WhichProbeFunction == 5)
+
        else if (WhichProbeFunction == 4)
s = osAvatarName2Key( "John", "Smith" );
+
            osAvatarStopAnimation( BogusKey, BogusKey );
else if (WhichProbeFunction == 6)
+
        else if (WhichProbeFunction == 5)
s = osKey2Name( BogusKey );
+
            s = osAvatarName2Key( "John", "Smith" );
+
        else if (WhichProbeFunction == 6)
// If we got here, then the timer() handler didn't crash, which means the function it checked for
+
            s = osKey2Name( BogusKey );
// was actually permitted. So we update the list to indicate that we can use that particular function.
+
 
FunctionPermitted = llListReplaceList( FunctionPermitted, [ 1 ], WhichProbeFunction, WhichProbeFunction );
+
        // If we got here, then the timer() handler didn't crash, which means the function it checked for
}
+
        // was actually permitted. So we update the list to indicate that we can use that particular function.
 +
        FunctionPermitted = llListReplaceList( FunctionPermitted, [ 1 ], WhichProbeFunction, WhichProbeFunction );
 +
    }
 
}
 
}
+
 
 
state Running
 
state Running
 
{
 
{
state_entry()
+
    state_entry()
{
+
    {
string s = "Here are the functions we can use: ";
+
        string s = "Here are the functions we can use: ";
string t = "Here are the functions we cannot use: ";
+
        string t = "Here are the functions we cannot use: ";
integer i = llGetListLength( FunctionNames );
+
        integer i = llGetListLength( FunctionNames );
while (i--)
+
 
if (llList2Integer( FunctionPermitted, i ))
+
        while (i--)
s += llList2String( FunctionNames, i ) + " ";
+
            if (llList2Integer( FunctionPermitted, i ))
else
+
                s += llList2String( FunctionNames, i ) + " ";
t += llList2String( FunctionNames, i ) + " ";
+
            else
llOwnerSay( s );
+
                t += llList2String( FunctionNames, i ) + " ";
llOwnerSay( t );
+
       
if (isFunctionAvailable( "osKey2Name" ))
+
        llOwnerSay( s );
{
+
        llOwnerSay( t );
key theUUID = "190482f8-b1bc-4c36-aa8d-cfb36c8fea61";
+
       
llOwnerSay( "UUID " + (string) theUUID + " maps to the name " + osKey2Name( theUUID ) + "." );
+
        if (isFunctionAvailable( "osKey2Name" ))
}
+
        {
else
+
            key theUUID = "190482f8-b1bc-4c36-aa8d-cfb36c8fea61";
{
+
            llOwnerSay( "UUID " + (string) theUUID + " maps to the name " + osKey2Name( theUUID ) + "." );
llOwnerSay( "osKey2Name() is unavailable; cannot map UUID to name." );
+
        }
}
+
 
}
+
        else
 +
        {
 +
            llOwnerSay( "osKey2Name() is unavailable; cannot map UUID to name." );
 +
        }
 +
    }
 
}
 
}
 
</source>
 
</source>

Latest revision as of 14:22, 28 September 2020

To permit region owners to enable the extended scripting functionality of OSSL, without allowing malicious scripts to access potentially troublesome functions, each OSSL function is assigned a threat level, and access to the functions is granted or denied based on a default threshold set in OpenSim.ini (which can be overridden for individual functions on a case-by-case basis). Review OSSL Enabling Functions page with a full example for Implementing the various osFunctions for your system.

The threat levels, from wholly unthreatening to most potentially damaging, are:

None
Function is no threat at all. It doesn't constitute a threat to either users or the system and has no known side effects.
Functions with the threat level "None":
See Category:OSSL_Functions/ThreatLevel:None
Nuisance
Abuse of this command can cause a nuisance to the region operator, such as log message spew.
Functions with the threat level "Nuisance":
See Category:OSSL_Functions/ThreatLevel:Nuisance
VeryLow
Extreme levels of abuse of this function can cause impaired functioning of the region, or very gullible users can be tricked into experiencing harmless effects.
Functions with the threat level "VeryLow":
See Category:OSSL_Functions/ThreatLevel:VeryLow
Low
Intentional abuse can cause crashes or malfunction under certain circumstances, which can be easily rectified; or certain users can be tricked into certain situations in an avoidable manner.
Functions with the threat level "Low":
See Category:OSSL_Functions/ThreatLevel:Low
Moderate
Intentional abuse can cause denial of service and crashes with potential of data or state loss; or trusting users can be tricked into embarrassing or uncomfortable situations.
Functions with the threat level "Moderate":
See Category:OSSL_Functions/ThreatLevel:Moderate
High
Casual abuse can cause impaired functionality or temporary denial of service conditions. Intentional abuse can easily cause crashes with potential data loss, or can be used to trick experienced and cautious users into unwanted situations, or changes global data permanently and without undo ability.
Functions with the threat level "High":
See Category:OSSL_Functions/ThreatLevel:High
VeryHigh
Even normal use may, depending on the number of instances, or frequency of use, result in severe service impairment or crash with loss of data, or can be used to cause unwanted or harmful effects on users without giving the user a means to avoid it.
Functions with the threat level "VeryHigh":
See Category:OSSL_Functions/ThreatLevel:VeryHigh
Severe
Even casual use is a danger to region stability, or function allows console or OS command execution, or function allows taking money without consent, or allows deletion or modification of user data, or allows the compromise of sensitive data by design.
Functions with the threat level "Severe":
See Category:OSSL_Functions/ThreatLevel:Severe

The OSFunctionThreatLevel setting in the script engines' configuration sections of OpenSim.ini controls what classes of functions are accessible to scripts owned by any avatar; any function at the same threat level or lower than the value provided for OsFunctionThreatLevel is permitted to run. If OSFunctionThreatLevel is absent from the configuration file, the default value is VeryLow.

We do not recommend that you set a general level above Low unless you have a very high level of trust in all the visitors to the simulator that have the ability to run scripts.

It is safer to explicitly allow certain types of user to run higher threat level OSSL functions on an individual basis. This can be done by adding Allow_* lines to the script engine's configuration section. To permit scripts owned by anyone to access a function, even if its threat level exceeds the value of OSFunctionThreatLevel, use the value 'true':

Allow_osMakeNotecard = true

You can also prohibit individual OSSL functions, even if its threat level is equal to or below the value of OSFunctionThreatLevel:

Allow_osMovePen = false

To allow scripts owned by only certain avatars to access a function, use the UUIDs of the avatars owning the scripts. If multiple avatars are to be permitted access, separate the UUIDs with commas:

Allow_osMakeNotecard = a1cbbdd7-8adb-4158-aa52-c0ee882c4492
Allow_osTeleportAgent = a1cbbdd7-8adb-4158-aa52-c0ee882c4492,9cab27da-764c-4469-a628-369d978ba436

You can also allow categories of users to call given OSSL functions. Currently, the categories are

  • PARCEL_GROUP_MEMBER: allow if object group is the same group as the parcel
  • PARCEL_OWNER: allow if the object owner is parcel owner
  • ESTATE_MANAGER: allow if the object owner is an estate manager
  • ESTATE_OWNER: allow if object owner is estate owner

For example

Allow_osSetRegionWaterHeight = PARCEL_OWNER, ESTATE_OWNER

Note that wiki may not have the threat levels for some functions or have wrong threat levels. You can check actual threat levels by looking into OpenSim.Region.ScriptEngine.Shared.Api.OSSL_Api class in the source distribution or git master(see CheckThreatLevel() calling).


[edit] Ascertaining privilege to use a function

There is not currently a function which would allow a script to determine whether or not it has permission to use any specific OSSL function. Such a function was proposed, but rejected by a developer on the grounds that it could permit a griefer script too much knowledge of its environment (though, as shown below, this information is already available through other methods, albeit less efficient ones).

Leaving the question of griefer scripts aside, such knowledge is also useful to legitimate scripts (for instance, an animation vendor with a "Try me!" button, which might use osAvatarPlayAnimation() to demonstrate the animation without requiring the user to explicitly grant permission, but fall back to llStartAnimation() in the event that osAvatarPlayAnimation() is unavailable).

If a script attempts to use an OSSL function that it does not have permission to use, only the current invocation of the event handler which called the function crashes; the script remains running, and the event handler will be executed again the next time the event fires. A script may take advantage of this fact to ascertain which functions are available to it, by using an information-gathering state with a timer to iterate quickly through the OSSL functions it needs; when a function call succeeds, it can then set a variable indicating that the function is available. Once it has iterated through all the functions, it then switches out of the information-gathering state.

// OSSL Function Availability Tester
//
// Demonstrates a method by which a script may determine whether or not it is permitted to call
// various OSSL functions.
//
 
integer WhichProbeFunction; // to tell us which function we're probing
integer NumberOfFunctionsToCheck; // how many functions are we probing?
 
list FunctionNames = [
    "osTeleportAgent", 
    "osGetAgentIP", 
    "osGetAgents", 
    "osAvatarPlayAnimation",
    "osAvatarStopAnimation", 
    "osAvatarName2Key", 
    "osKey2Name"
];
 
list FunctionPermitted = [ 0, 0, 0, 0, 0, 0, 0 ]; // 0 = not permitted, 1 = permitted
 
 
// isFunctionAvailable() takes the name of a function, and returns 1 if it is available, 
// and 0 if it is forbidden or has not been tested.
 
integer isFunctionAvailable( string whichFunction )
{
    integer index = llListFindList( FunctionNames, whichFunction );
    if (index == -1) return 0; // Return FALSE if the function name wasn't one of the ones we checked.
    return llList2Integer( FunctionPermitted, index ); // return the appropriate availability flag.
}
 
// The default state uses the timer to call all the OSSL functions we're interested in using, in turn.
// If the function call fails, the timer event handler will abend, but the script doesn't crash. We can
// use this fact to check all of our desired functions in turn, and then pass control to the Running
// state once we've checked them all.
 
default
{
    state_entry()
    {
        llOwnerSay( "Probing OSSL functions to see what we can use" );
        NumberOfFunctionsToCheck = llGetListLength( FunctionNames );
        WhichProbeFunction = -1;
        llSetTimerEvent( 0.25 ); // check only four functions a second, just to be nice.
    }
 
    timer()
    {
        string BogusKey = "12345678-1234-1234-1234-123456789abc"; // it doesn't need to be valid
        string s; // for storing the result of string functions
        list l; // for storing the result of list functions
 
        if (++WhichProbeFunction == NumberOfFunctionsToCheck) // Increment WhichProbeFunction; exit if we're done
        {
            llSetTimerEvent( 0.0 ); // stop the timer
            state Running; // switch to the Running state
        }
 
        llOwnerSay( "Checking function " + llList2String( FunctionNames, WhichProbeFunction )); // say status
        if (WhichProbeFunction == 0)
            osTeleportAgent( BogusKey, ZERO_VECTOR, ZERO_VECTOR );
        else if (WhichProbeFunction == 1)
            s = osGetAgentIP( BogusKey );
        else if (WhichProbeFunction == 2)
            l = osGetAgents();
        else if (WhichProbeFunction == 3)
            osAvatarPlayAnimation( BogusKey, BogusKey );
        else if (WhichProbeFunction == 4)
            osAvatarStopAnimation( BogusKey, BogusKey );
        else if (WhichProbeFunction == 5)
            s = osAvatarName2Key( "John", "Smith" );
        else if (WhichProbeFunction == 6)
            s = osKey2Name( BogusKey );
 
        // If we got here, then the timer() handler didn't crash, which means the function it checked for
        // was actually permitted. So we update the list to indicate that we can use that particular function.
        FunctionPermitted = llListReplaceList( FunctionPermitted, [ 1 ], WhichProbeFunction, WhichProbeFunction );
    }
}
 
state Running
{
    state_entry()
    {
        string s = "Here are the functions we can use: ";
        string t = "Here are the functions we cannot use: ";
        integer i = llGetListLength( FunctionNames );
 
        while (i--)
            if (llList2Integer( FunctionPermitted, i ))
                s += llList2String( FunctionNames, i ) + " ";
            else
                t += llList2String( FunctionNames, i ) + " ";
 
        llOwnerSay( s );
        llOwnerSay( t );
 
        if (isFunctionAvailable( "osKey2Name" ))
        {
            key theUUID = "190482f8-b1bc-4c36-aa8d-cfb36c8fea61";
            llOwnerSay( "UUID " + (string) theUUID + " maps to the name " + osKey2Name( theUUID ) + "." );
        }
 
        else
        {
            llOwnerSay( "osKey2Name() is unavailable; cannot map UUID to name." );
        }
    }
}
Personal tools
General
About This Wiki