Scripters, please scrutinize for bugs or suggestions, before it gets posted to examples.
To read or copy this script, hit the QUOTE button at the bottom, so you see the indentation.
CODE
// Allow/Deny configuration script - Lear Cale - v0b
// Send "ALLOW?" LM to test, get "ALLOW" LM if av is permitted.
// To use this script:
// From another script send "ALLOW?" LM, passing av's key. (Integer parm is ignored.)
// If allowed, an LM is sent (to this prim only), num=1, str="ALLOW", key=av
// Configuration:
// Reads all cards containing the CardName string (anywhere in the card name)
// Reconfigures automatically whenever any of its config cards change.
// Notecards must be full-perm!
string CardName = ".ALLOW";
// In notecards, use lines like these (omitting the // that makes them comments here):
// allow | Joe Avatar
// allow | jane Doe
// deny | griefu Arbuthnot
// allow | ALL
// allow | GROUP
// debug | -1 | all debugging enabled
// debug | 1 | chat allowed/denied
// debug | 0x10 | dump config
// Object owner is always allowed, unless explicitly denied
// Case-sensitive.
// Comments are allowed and begin with "/".
// You can also add a comment to any config line, following another "|":
// deny | Wimpy Jones | this is the moron who spammed everyone
// By default, this script simply does not reply when disallowed.
// Set this to TRUE to get a "deny" LM response in that case.
integer ReplyOnDeny = FALSE;
// If no "allow" lines appear, everyone is allowed except those explicitly denied
// To default to allowing group instead of everyone, change this to TRUE
integer AllowGroupByDefault = FALSE;
// Delimiters for configs: vertical bar. Any number of spaces are allowed.
list DELIMS = [ "|" ];
// End of configurable globals ======================
list Allowed; // list of names of allowed avs
list Denied; // list of names of denied avs
integer AllowGroup; // whether to allow avs wearing group tag of object's group
integer AllowAll; // whether to allow all
// debugs:
// 0x01 = allow/deny
// 0x10 = debug config
integer Debug;
debug(integer mask, string str) {
if (mask & Debug) {
llWhisper(0, llGetScriptName() + ": " + str);
}
}
// Parse a configuration line.
// Ignore unrecognized commands, for forward/backwards compatibility
parse_config_line(string data) {
// strip leading space
data = llStringTrim(data, STRING_TRIM_HEAD);
// skip comments and blank lines
if (llGetSubString(data,0,0) == "/" || llStringLength(data) < 3) {
return;
}
list ldata = llParseStringKeepNulls(data, DELIMS, []);
string cmd = llStringTrim(llList2String(ldata, 0), STRING_TRIM);
string arg1 = llStringTrim(llList2String(ldata, 1), STRING_TRIM);
if (cmd == "allow") {
if (arg1 == "ALL") {
AllowAll = TRUE;
} else if (arg1 == "GROUP") {
AllowGroup = TRUE;
} else {
Allowed += arg1;
}
} else if (cmd == "deny") {
Denied += (list)arg1;
} else if (cmd == "debug") {
Debug += (integer)arg1;
}
}
// Configuration postprocessing
config_done() {
debug(0x10, "Allowed: " + llList2CSV(Allowed));
debug(0x10, "Denied: " + llList2CSV(Denied));
// set default behavior if unconfigured
if (!AllowAll && !AllowGroup && llGetListLength(Allowed) == 0) {
if (AllowGroupByDefault) {
AllowGroup = TRUE;
} else {
AllowAll = TRUE;
}
}
debug(0x10, "Allow All: " + (string)AllowAll + ", Allow Group: " + (string)AllowGroup);
llOwnerSay(llGetScriptName() + ": Config done");
}
// Determine whether given avatar is allowed
integer av_allowed(key id) {
string av = llKey2Name(id);
// Check if av is explicitly denied
if (llListFindList(Denied, (list)av) >= 0) {
return FALSE;
}
// allow owner unless explicitly denied
if (id == llGetOwner()) {
return TRUE;
}
if (AllowAll) {
return TRUE;
}
if (AllowGroup && llSameGroup(id)) {
return TRUE;
}
// Check if av is explicitly allowed
if (llListFindList(Allowed, (list)av) >= 0) {
return TRUE;
}
// Sorry, bub, no joy for you
return FALSE;
}
// Globals for reading card config
integer ConfigLineIndex;
list ConfigCards; // list of names of config cards
string ConfigCardName; // name of card being read
integer ConfigCardIndex; // index of next card to read
key ConfigQueryId;
string ConfigCardKeys; // to see if anything changed
// Get list of cards that contain our config notecard substring.
// Return list of keys of cards, for checking if notecards have
// changed (a notecard gets a new key every time it's saved).
string get_cards() {
ConfigCards = [];
string keys = "";
string item;
integer ix = llGetInventoryNumber(INVENTORY_NOTECARD);
while (ix-- > 0) {
item = llGetInventoryName(INVENTORY_NOTECARD, ix);
if (llSubStringIndex(item, CardName) >= 0) {
ConfigCards += (list) item;
keys += (string)llGetInventoryKey(item);
}
}
// Sorting them shouldn't be necessary, but I think I've seen them out of order
ConfigCards = llListSort(ConfigCards, 1, TRUE);
return keys;
}
// Start reading the next card.
// Return FALSE if there are no more cards to read.
integer next_card()
{
if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
ConfigCards = [];
return (FALSE);
}
ConfigLineIndex = 0;
ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
ConfigCardIndex++;
ConfigQueryId = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
llOwnerSay(llGetScriptName() + ": Reading " + ConfigCardName);
return (TRUE);
}
// In this state, we read the notecards
default {
state_entry() {
ConfigCardKeys = get_cards();
ConfigCardIndex = 0;
// start reading cards
if (! next_card()) {
// No cards to read: we're done
state s_on;
}
}
dataserver(key query_id, string data) {
if (query_id != ConfigQueryId) {
return; // ignore data for other scripts
}
if (data == EOF) {
// done with this card, start next one
if (next_card()) {
return;
}
// No more cards; we're done reading.
state s_on;
}
// Parse config line and request the next line.
parse_config_line(llStringTrim(data, STRING_TRIM));
ConfigQueryId = llGetNotecardLine(ConfigCardName, ++ConfigLineIndex);
}
// If any of our notecards changed, bag it and start over.
changed(integer change) {
if (change & CHANGED_INVENTORY) {
if (get_cards() != ConfigCardKeys) {
llResetScript();
}
}
}
state_exit() {
config_done();
}
}
// Operational state. Respond to "ALLOW?" queries.
// You can replace the rest of this script with your own code,
// using the av_allowed() function, rather than doing the
// authentication and your behavior in separate scripts.
state s_on {
link_message(integer sender, integer num, string str, key id) {
if (str == "ALLOW?") {
if (av_allowed(id)) {
debug(1, llKey2Name(id) + " allowed");
llMessageLinked(LINK_THIS, 0, "ALLOW", id);
} else {
debug(1, llKey2Name(id) + " denied");
if (ReplyOnDeny) {
llMessageLinked(LINK_THIS, 0, "DENY", id);
}
}
}
}
// PUT THIS IN EVERY STATE so the script will re-read its config if it changes.
changed(integer change) {
if (change & CHANGED_INVENTORY) {
if (get_cards() != ConfigCardKeys) {
llResetScript();
}
}
}
}
)

