// SPDX-License-Identifier: MIT // Copyright (c) 2026 Incoprea // Audit menu action routes // Not compiled or tested in-world // Setup: Add a saved plain-text notecard named Config. Use label|action rows. Edit ACTIONS in the script to your supported commands. Touch as owner; reset to scan again. // Stop / restore: Remove or disable. This auditor never changes object settings or inventory. // Notes: Reads at most 40 short lines, skips blanks and # comments, and times out each asynchronous request after 20 seconds. Does not execute any action. This catches stale labels and unknown action tokens before wiring a menu. // License: see LICENSE in this distribution. // Original Incoprea example. MIT. list ACTIONS=["show","hide","help","close"]; list labels; key pending=NULL_KEY; integer lineNumber; integer scannedRows; integer issues; integer finished; issue(string text) { ++issues; llOwnerSay("Line "+(string)(lineNumber+1)+": "+text); } requestLine() { pending=llGetNotecardLine("Config",lineNumber); llSetTimerEvent(20); } finish() { pending=NULL_KEY; finished=TRUE; llSetTimerEvent(0); llOwnerSay("Audited rows: "+(string)scannedRows+"; findings: "+(string)issues); } check(string data) { list p=llParseStringKeepNulls(data,["|"],[]); if(llGetListLength(p)!=2) { issue("Expected label|action."); return; } string label=llList2String(p,0); string action=llList2String(p,1); if(label=="" || llStringLength(label)>24)issue("Label must be 1-24 characters."); if(llListFindList(labels,[label])!=-1)issue("Duplicate menu label."); else labels += [label]; if(llListFindList(ACTIONS,[action])==-1)issue("Unknown action: "+action); } default { touch_start(integer touches) { if(llDetectedKey(0)!=llGetOwner())return; if(pending!=NULL_KEY || finished) { llOwnerSay("Reset before starting another audit."); return; } if(llGetInventoryType("Config")!=INVENTORY_NOTECARD) { llOwnerSay("Add a saved Config notecard."); return; } requestLine(); } dataserver(key query,string data) { if(query!=pending || pending==NULL_KEY)return; if(data==EOF) { finish(); return; } data=llStringTrim(data,STRING_TRIM); if(data!="" && llGetSubString(data,0,0)!="#") { ++scannedRows; check(data); } ++lineNumber; if(lineNumber>=40) { llOwnerSay("40-line cap reached; report may be partial."); finish(); return; } requestLine(); } timer() { pending=NULL_KEY; finished=TRUE; llSetTimerEvent(0); llOwnerSay("Audit timed out; partial checks only. Reset to retry."); } changed(integer flags) { if(flags & (CHANGED_OWNER|CHANGED_INVENTORY))llResetScript(); } }