Monday, November 08, 2010 at 12:04 AM.
system.verbs.builtins.mainResponder.neuterText
on neuterText (s, flNeuterMacros=true, flNeuterTags=true, adrLegalTags=nil) { <<Neuter HTML tags and macros in a string of text. <<Changes: <<Sat, May 1, 1999 at 11:23:41 AM by SMD <<allow each item in config.mainresponder.prefs.legaltags to be a table <<if it is a table, then it must contain two entries: <<flLegal - is the tag legal, or should it be neutered <<flClose - must the tag be closed? <<if the item isn't a table, then it is assumed that the tag should be closed (thus preserving previous functionality) <<Sat, 01 May 1999 18:57:16 GMT by AR <<Minor code rorganizations. <<Sat, 22 May 1999 19:15:42 GMT by AR <<Added safeScriptParser sub-routine. <<10/4/99; 6:14:32 PM by PBS <<It's not enough to allow only macros that are one-word identifiers. Better to allow the sysop to configure which macros are legal via a legalMacros table, similar to the legalTags table. <<This table lives at config.mainResponder.prefs.legalMacros. <<The top-level subtables are names of macros. Inside each subtable is one item: flLegal. <<If a macro isn't in the legalMacros table, it gets neutered. <<If flLegal is true, then macros which otherwise pass the tests are okay. If false, then the macro gets neutered. <<We made items in this table subtables, rather than booleans, so the mechanism can be extended later. <<But, like legalTags, you can use simple booleans instead. <<11/3/99; 9:47:34 AM by PBS <<There's now one version of this script that works with both 6.0 and 6.1 and greater. <<Only the 6.1 version allows safe macros with parameters. In 6.0 safe macros can be identifiers only. <<If pta^.legalTags is defined, use the table that points to rather than the global table at config.mainResponder.prefs.legalTags. This way sites can over-ride the global settings. <<03/15/00; 6:06:36 PM by PBS <<Check the value of pta^.enableSafeMacros -- if it's false, macros should be neutered. <<03/28/01; 5:51:26 PM by PBS <<New optional parameter: adrLegalTags is the address of a legal tags table to use. This way, when this script is called as part of an XML-RPC handler, we can use the legal tags table for the site. local (flUseKernelVerbs = false); if defined (html.neuterTags) { flUseKernelVerbs = true}; local (pta); try {pta = html.getPageTableAddress ()}; if flNeuterMacros { local (adrTable = @config.mainResponder.prefs.legalMacros); //global table only if (defined (adrTable^)) and (pta != nil) and (defined (pta^.enableSafeMacros)) and (pta^.enableSafeMacros) { //neuter all but legal macros. PBS 03/15/00: check the value of pta^.enableSafeMacros. It must be true, or macros will be neutered. if flUseKernelVerbs { s = html.neuterMacros (s, adrTable)} //html.neuterMacros is a new kernel verb in 6.1 else { on safeScriptParser (s) { if s == "" { return ""}; local (i = 1, balance=0, j=0, macrostring, safeTo=0); on isSafe (m) { m = string.trimWhiteSpace (m); local (ct = string.length (m)); if ct > 0 { if not (string.isAlpha (m[1])) { return false}; while (ct > 1) { if not (string.isAlpha (m[ct]) or string.isNumeric (m[ct])) { return false}; ct--}}; bundle { //PBS 10/4/99: check the legal macros table at config.mainResponder.prefs.legalMacros. if not defined (adrTable^) { //PBS 10/4/99: if the legal macros table isn't defined, then this macro isn't legal return (false)}; if not defined (adrTable^.[m]) { //PBS 10/4/99: if this macro isn't in the legal macros table, then this macro isn't legal return (false)}; case typeOf (adrTable^.[m]) { //handle tables or simple booleans tableType { if not defined (adrTable^.[m].flLegal) { //PBS 10/4/99: if there's no flLegal boolean for this macro, then this macro isn't legal return (false)}; if not (adrTable^.[m].flLegal) { //PBS 10/4/99: if the flLegal boolean is false, then this macro isn't legal return (false)}}; booleanType { if not (adrTable^.[m]) { return (false)}}} else { return (false)}}; return true}; while (i <= sizeof(s)) { case s[i] { '{' { if balance == 0 { //remember position of outer opening brace j = i}; balance++}; '}' { if balance > 0 { balance--; if balance == 0 { //found outer closing brace macrostring = string.mid (s, j+1, i-j-1); if not (isSafe (macrostring)) { local (repl = macrostring); repl = string.replaceAll (repl, "{", "{"); repl = string.replaceAll (repl, "}", "}"); repl = "{" + repl + "}"; s = string.delete (s, j, i-j+1); s = string.insert (repl, s, j); i = i + string.length (repl) - (string.length (macrostring) + 2)}; j = 0; safeTo = i}} //remember until what position the string is safe (for final cleanup) else { //convert to html entity local (repl = "}"); s = string.delete (s, i, 1); s = string.insert (repl, s, i); i = i - 1 + string.length (repl)}}}; i++}; if balance > 0 { //there's cleanup to do local (repl = string.mid (s, safeTo + 1, infinity)); repl = string.replaceAll (repl, "{", "{"); repl = string.replaceAll (repl, "}", "}"); s = string.delete (s, safeTo + 1, infinity); s = s + repl}; return (s)}; s = safeScriptParser (s)}} else { //no safe macros, neuter all macros s = string.replaceall (s, "{", "{")}}; if flNeuterTags { local (adrTable = @config.mainResponder.prefs.legalTags); if (pta != nil) and defined (pta^.legalTags) { adrTable = pta^.legalTags}; //a site may over-ride the global legal tags table with its own table if adrLegalTags != nil { //PBS 03/28/01: caller can specify a legal tags table adrTable = adrLegalTags}; if flUseKernelVerbs { s = html.neuterTags (s, adrTable)} else { //use the script-based version local (legaltags); //copy the table bundle { //initialize legaltags table local (i); legaltags = adrTable^; for i = sizeof (legaltags) downto 1 { //delete all the false ones, set the remaining to 0 if typeof (legaltags [i]) != tableType { // if the legaltags item isn't a table, make it one (in the local copy) local (fl = legaltags [i]); new (tabletype, @legaltags.[nameof(legaltags [i])]); legaltags[i].flLegal = fl; legaltags[i].flClose = true}; if not legaltags [i].flLegal { delete (@legaltags [i])}; legaltags [i].count = 0}}; <<we count the levels of each of the tags so we can generate closing tags at the end on isLegalTag (tagname) { return (defined (legaltags [tagname]))}; local (ix = 1); while ix <= sizeof (s) { if s[ix] == '<' { local (i, ixstarttagname = ix); for i = ix to sizeof (s) { if (s [i] == '>') or (i == sizeof (s)) { local (tagname = string.mid (s, ix + 1, i - ix - 1)); local (flclosetag = false); if tagname beginswith "/" { tagname = string.delete (tagname, 1, 1); flclosetag = true}; if tagname contains ' ' { //ignore any attributes tagname = string.nthfield (tagname, ' ', 1)}; if isLegalTag (tagname) { if legaltags [tagname].flclose { if flclosetag { legaltags [tagname].count--} else { legaltags [tagname].count++}}} else { s = string.delete (s, ix, 1); //delete the < s = string.insert ("<", s, ix)}; //replace with < break}}}; ix++}; bundle { //emit closing tags for all unclosed tags local (i, j); for i = 1 to sizeof (legaltags) { if legaltags [i].count > 0 { local (closetag = "</" + nameof (legaltags [i]) + ">"); for j = 1 to legaltags [i].count { s = s + closetag}}}}}}; return (s)}; <<on neuterText (s, flNeuterMacros=true, flNeuterTags=true) //6.1-only version <<Neuter HTML tags and macros in a string of text. <<Changes: <<Sat, May 1, 1999 at 11:23:41 AM by SMD <<allow each item in config.mainresponder.prefs.legaltags to be a table <<if it is a table, then it must contain two entries: <<flLegal - is the tag legal, or should it be neutered <<flClose - must the tag be closed? <<if the item isn't a table, then it is assumed that the tag should be closed (thus preserving previous functionality) <<Sat, 01 May 1999 18:57:16 GMT by AR <<Minor code rorganizations. <<Sat, 22 May 1999 19:15:42 GMT by AR <<Added safeScriptParser sub-routine. <<10/4/99; 6:14:32 PM by PBS <<It's not enough to allow only macros that are one-word identifiers. Better to allow the sysop to configure which macros are legal via a legalMacros table, similar to the legalTags table. <<This table lives at config.mainResponder.prefs.legalMacros. <<The top-level subtables are names of macros. Inside each subtable is one item: flLegal. <<If a macro isn't in the legalMacros table, it gets neutered. <<If flLegal is true, then macros which otherwise pass the tests are okay. If false, then the macro gets neutered. <<We made items in this table subtables, rather than booleans, so the mechanism can be extended later. <<But, like legalTags, you can use simple booleans instead. <<if flNeuterMacros <<local (pta, adrtable = @config.mainResponder.prefs.legalMacros) <<try { pta = html.getPageTableAddress () } <<if (pta != nil) and defined (pta^.enableSafeMacros) and pta^.enableSafeMacros and defined (adrtable^) <<s = html.neuterMacros (s, @config.mainResponder.prefs.legalMacros) <<else <<s = string.replaceall (s, "{", "{") <<if flNeuterTags <<s = html.neuterTags (s, @config.mainResponder.prefs.legalTags) <<return (s) <<on neuterText (s, flNeuterMacros=true, flNeuterTags=true) //old code <<Neuter HTML tags and macros in a string of text. <<Changes: <<Sat, May 1, 1999 at 11:23:41 AM by SMD <<allow each item in config.mainresponder.prefs.legaltags to be a table <<if it is a table, then it must contain two entries: <<flLegal - is the tag legal, or should it be neutered <<flClose - must the tag be closed? <<if the item isn't a table, then it is assumed that the tag should be closed (thus preserving previous functionality) <<Sat, 01 May 1999 18:57:16 GMT by AR <<Minor code rorganizations. <<Sat, 22 May 1999 19:15:42 GMT by AR <<Added safeScriptParser sub-routine. <<10/4/99; 6:14:32 PM by PBS <<It's not enough to allow only macros that are one-word identifiers. Better to allow the sysop to configure which macros are legal via a legalMacros table, similar to the legalTags table. <<This table lives at config.mainResponder.prefs.legalMacros. <<The top-level subtables are names of macros. Inside each subtable is one item: flLegal. <<If a macro isn't in the legalMacros table, it gets neutered. <<If flLegal is true, then macros which otherwise pass the tests are okay. If false, then the macro gets neutered. <<We made items in this table subtables, rather than booleans, so the mechanism can be extended later. <<But, like legalTags, you can use simple booleans instead. <<if flNeuterTags <<local (legaltags) //copy the table <<bundle //initialize legaltags table <<local (i) <<legaltags = config.mainResponder.prefs.legalTags <<for i = sizeof (legaltags) downto 1 //delete all the false ones, set the remaining to 0 <<if typeof (legaltags [i]) != tableType // if the legaltags item isn't a table, make it one (in the local copy) <<local (fl = legaltags [i]) <<new (tabletype, @legaltags.[nameof(legaltags [i])]) <<legaltags[i].flLegal = fl <<legaltags[i].flClose = true <<if not legaltags [i].flLegal <<delete (@legaltags [i]) <<legaltags [i].count = 0 <<we count the levels of each of the tags so we can generate closing tags at the end <<on isLegalTag (tagname) <<return (defined (legaltags [tagname])) <<local (ix = 1) <<while ix <= sizeof (s) <<if s[ix] == '<' <<local (i, ixstarttagname = ix) <<for i = ix to sizeof (s) <<if (s [i] == '>') or (i == sizeof (s)) <<local (tagname = string.mid (s, ix + 1, i - ix - 1)) <<local (flclosetag = false) <<if tagname beginswith "/" <<tagname = string.delete (tagname, 1, 1) <<flclosetag = true <<if tagname contains ' ' //ignore any attributes <<tagname = string.nthfield (tagname, ' ', 1) <<if isLegalTag (tagname) <<if legaltags [tagname].flclose <<if flclosetag <<legaltags [tagname].count-- <<else <<legaltags [tagname].count++ <<else <<s = string.delete (s, ix, 1) //delete the < <<s = string.insert ("<", s, ix) //replace with < <<break <<ix++ <<bundle //emit closing tags for all unclosed tags <<local (i, j) <<for i = 1 to sizeof (legaltags) <<if legaltags [i].count > 0 <<local (closetag = "</" + nameof (legaltags [i]) + ">") <<for j = 1 to legaltags [i].count <<s = s + closetag <<if flNeuterMacros <<local (pta) <<try { pta = html.getPageTableAddress () } <<if (pta != nil) and defined (pta^.enableSafeMacros) and pta^.enableSafeMacros <<on safeScriptParser (s) <<if s == "" <<return "" <<local (i = 1, balance=0, j=0, macrostring, safeTo=0) <<on isSafe (m) <<m = string.trimWhiteSpace (m) <<local (ct = string.length (m)) <<if ct > 0 <<if not (string.isAlpha (m[1])) <<return false <<while (ct > 1) <<if not (string.isAlpha (m[ct]) or string.isNumeric (m[ct])) <<return false <<ct-- << <<bundle //PBS 10/4/99: check the legal macros table at config.mainResponder.prefs.legalMacros. <<local (adrLegalMacros = @config.mainResponder.prefs.legalMacros) <<if not defined (adrLegalMacros^) //PBS 10/4/99: if the legal macros table isn't defined, then this macro isn't legal <<return (false) <<if not defined (adrLegalMacros^.[m]) //PBS 10/4/99: if this macro isn't in the legal macros table, then this macro isn't legal <<return (false) <<case typeOf (adrLegalMacros^.[m]) //handle tables or simple booleans <<tableType <<if not defined (adrLegalMacros^.[m].flLegal) //PBS 10/4/99: if there's no flLegal boolean for this macro, then this macro isn't legal <<return (false) <<if not (adrLegalMacros^.[m].flLegal) //PBS 10/4/99: if the flLegal boolean is false, then this macro isn't legal <<return (false) <<booleanType <<if not (adrLegalMacros^.[m]) <<return (false) <<else <<return (false) << <<return true <<while (i <= sizeof(s)) <<case s[i] <<'{' <<if balance == 0 //remember position of outer opening brace <<j = i <<balance++ <<'}' <<if balance > 0 <<balance-- <<if balance == 0 //found outer closing brace <<macrostring = string.mid (s, j+1, i-j-1) <<if not (isSafe (macrostring)) <<local (repl = macrostring) <<repl = string.replaceAll (repl, "{", "{") <<repl = string.replaceAll (repl, "}", "}") <<repl = "{" + repl + "}" <<s = string.delete (s, j, i-j+1) <<s = string.insert (repl, s, j) <<i = i + string.length (repl) - (string.length (macrostring) + 2) <<j = 0 <<safeTo = i //remember until what position the string is safe (for final cleanup) <<else //convert to html entity <<local (repl = "}") <<s = string.delete (s, i, 1) <<s = string.insert (repl, s, i) <<i = i - 1 + string.length (repl) <<i++ <<if balance > 0 //there's cleanup to do <<local (repl = string.mid (s, safeTo + 1, infinity)) <<repl = string.replaceAll (repl, "{", "{") <<repl = string.replaceAll (repl, "}", "}") <<s = string.delete (s, safeTo + 1, infinity) <<s = s + repl << <<return (s) <<s = safeScriptParser (s) <<else <<s = string.replaceall (s, "{", "{") <<return (s) <<bundle //test code <<local (s = "This is a <pre>test</pre>.<br> For the <b>next</b> sixty seconds this station will conduct a test of the emergency broadcast <i>system.") <<dialog.alert (neuterText (s)) <<bundle //test code for safeScripts <<local (t); new (tableType, @t) <<html.setPageTableAddress (@t) <<t.enableSafeMacros = true <<local (s ="aaaaa {bbb} cccc {\"ddd\"} {x++} {user.prefs.name} {clock.now ()}") <<dialog.alert (neuterText (s))
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.