User:Katharine Berry/Scripts/Pandorabot

From The SchomEmunity Wiki
Jump to: navigation, search

Pandorabot | Rotating Online Status | SPD Viewer | Brainfsck Interpreter | Force Reload


This script is an interface to Pandorabots through SL.

Usage

Just change the BOT_ID constant to your bot's botid, and place the script in an object. Say "Shut up" to make it stop listening. Otherwise it listens to everyone, although each person is in a separate conversation.

In-world Scripts

Primary Script

// Pandorabots v2.3.0.1
// Copyright (c) 2007, Katharine Schomer
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Katharine Schomer nor the names of any contributors
//       may be used to endorse or promote products derived from this software
//       without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY KATHARINE SCHOMER ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL KATHARINE SCHOMER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ******************************************************************************

string BOT_ID = "f5d922d97e345aa1"; // The botid of the bot on Pandorabots
integer WIKIPEDIA_ENABLED = TRUE; // Whether it should look certain things up on Wikipedia.
integer EMAIL_ENABLED = TRUE; // Send emails
integer EMAIL_TIMEOUT = 300; // Time in which emails time out.
integer VERBAL_SHUTOFF_ENABLED = TRUE; // Allow for shutting the thing off by voice
list UNWIKIABLE_PHRASES = ["what is my name?"]; // Things not to ever look up on Wikipedia.
integer SINGLE_OBJECT_MIND = TRUE; // Whether to create session IDs unique to the object.

string BOT_API = "http://www.pandorabots.com/pandora/talk-xml";
string WIKIMEDIA_API = "http://ai.spii.co.uk/bots/wiki.php";
list SPECIAL_CHARS = ["<br>","&quot;","&gt;","&lt;"];
list SPECIAL_REPLACEMENTS = ["\n","\"",">","<"];
//The order here is important.
list WIKIPEDIA_TRIGGERS = [
    "what is ","?",
    "what's ","?",
    "what're ","?",
    "what is a ","?",
    "what is an ","?",
    "what is the ","?",
    "what are the ","?",
    "what's a ","?",
    "what's an ","?",
    "who is","?",
    "who are","?",
    "who're","?",
    "who's","?"
];
list EMAIL_TRIGGERS = [
    "i want to email ",
    "i would like to email ",
    "i want to send an email to ",
    "i would like to send an email to ",
    "email ",
    "send an email to "
];
list SHUTOFF_TRIGGERS = [
    "shut up",
    "shut up.",
    "shut up!",
    "be quiet.",
    "be quiet"
];
// These don't do anything.
list WIKTIONARY_TRIGGERS = [
    "what does "," mean?",
    "what's "," mean?"
];

integer EMAIL_LINK = 1;

string EscapeURL(string str) // Wrapper for the buggy llEscapeURL(), which only returns 255 bytes
{
    string escaped = ""; 
    while(str != "")
    {
        escaped += llEscapeURL(llGetSubString(str,0,82));
        str = llDeleteSubString(str,0,82);
    }
    return escaped;
}

string FixHTML(string str)
{
    integer j = 0;
    integer jl = llGetListLength(SPECIAL_CHARS);
    for(j = 0; j < jl; j += 8)
    {
        list special = llList2List(SPECIAL_CHARS,j,j+7);
        list replacements = llList2List(SPECIAL_REPLACEMENTS,j,j+7);
        list s = llParseStringKeepNulls(str,[],special);
        integer i;
        integer l = llGetListLength(s);
        for(i = 1; i < l; i += 2)
        {
            s = llListReplaceList(s, [llList2String(replacements,llListFindList(special,[llList2String(s,i)]))],i,i);
        }
        str = (string)s;
    }
    return str;
}

SendMail(string sender, string to, string subject, string message)
{
    llMessageLinked(LINK_THIS, EMAIL_LINK, message,sender+" "+to+" "+subject);
}

string gBotID = NULL_KEY;
list gEmailsPending = [];

default
{
    state_entry()
    {
        if(SINGLE_OBJECT_MIND)
        {
            gBotID = llDumpList2String(llParseString2List(llGetKey(),["-"],[]),"");
        }
        else
        {
            gBotID = "";
        }
        llListen(0,"",NULL_KEY,"");
    }
    
    on_rez(integer param)
    {
        llResetScript();
    }

    listen(integer channel, string name, key id, string message)
    {
        string lmessage = llToLower(message);
        if(llGetSubString(message,0,2) == "/me")
        {
            message = name+llGetSubString(message,3,-1);
        }
        if(EMAIL_ENABLED)
        {
            integer pos = llListFindList(gEmailsPending, [id]);
            if(~pos)
            {
                string first = llGetSubString(name,0,llSubStringIndex(name," ") - 1);
                if(lmessage == "cancel email" || lmessage == "cancel message")
                {
                    gEmailsPending = llDeleteSubList(gEmailsPending,pos,pos+4);
                    llSay(0, first+", your email has been deleted.");
                }
                else if(llList2String(gEmailsPending,pos+3) == "") // Blank "subject"
                {
                    if((llGetSubString(message,0,0) == "\"" && llGetSubString(message,-1,-1) == "\"") || (llGetSubString(message,0,0) == "'" && llGetSubString(message,-1,-1) == "'"))
                    {
                        message = llGetSubString(message,1,-2);
                    }
                    gEmailsPending = llListReplaceList(gEmailsPending,[message],pos+3,pos+3);
                    llSay(0,first+", please give a message for this email. You may send multiple lines - to complete the message, say \"End of message\".");
                    llSay(0,"You may also cancel the sending by saying \"Cancel email\".");
                }
                else
                {
                    if(lmessage == "eom" || lmessage == "end of message" || lmessage == "end of email" || lmessage == "eof")
                    {
                        string message = llStringTrim(llList2String(gEmailsPending,pos+4),STRING_TRIM);
                        if(message == "")
                        {
                            llSay(0,"You must have a message body before sending! Remember, to cancel, just say \"cancel email\".");
                        }
                        else
                        {
                            string subject = llList2String(gEmailsPending,pos+3);
                            string to = llList2String(gEmailsPending,pos+2);
                            SendMail(name,to,subject,message);
                            gEmailsPending = llDeleteSubList(gEmailsPending,pos,pos+4);
                            llSay(0,first+", your message has been sent.");
                        }
                    }
                    else
                    {
                        gEmailsPending = llListReplaceList(gEmailsPending,[llList2String(gEmailsPending,pos+4)+"\n"+message],pos+4,pos+4);
                    }
                }
                return;
            }
            else
            {
                integer len = llGetListLength(EMAIL_TRIGGERS);
                while(len--)
                {
                    string trigger = llList2String(EMAIL_TRIGGERS, len);
                    if(!llSubStringIndex(lmessage,trigger)) // Checking if it's zero - ! is faster though.
                    {
                        message = llGetSubString(message,llStringLength(trigger),-1);
                        if(message != "")
                        {
                            integer asperand = llSubStringIndex(message,"@"); // So how many people know that @ is an asperand?
                            if(asperand > 0 && ~llSubStringIndex(llGetSubString(message,asperand+2,-1),"."))
                            {
                                gEmailsPending = (gEmailsPending=[])+gEmailsPending + [id, llGetUnixTime(), message, "", ""];
                                llSay(0,llGetSubString(name,0,llSubStringIndex(name," ") - 1)+", I am preparing an email to "+message+". Please specify a subject line.");
                                llSetTimerEvent(30.0);
                            }
                            else
                            {
                                llSay(0,"You may indeed want to email "+message+" - but that's not an email address!");
                            }
                        }
                        return;
                    }
                }
            }
        }
        if(VERBAL_SHUTOFF_ENABLED)
        {
            if(~llListFindList(SHUTOFF_TRIGGERS,[lmessage]))
            {
                llSetTimerEvent(0.0);
                state off;
            }
        }
        if(WIKIPEDIA_ENABLED)
        {
            if(!~llListFindList(UNWIKIABLE_PHRASES,[lmessage]))
            {
                integer len = llGetListLength(WIKIPEDIA_TRIGGERS);
                while(len--)
                {
                    string trigger = llList2String(WIKIPEDIA_TRIGGERS,--len); // Warning: clever code
                    if(!llSubStringIndex(lmessage,trigger)) // Checking if it's zero - ! is faster though.
                    {
                        string ending = llList2String(WIKIPEDIA_TRIGGERS,len+1);
                        integer endinglen = llStringLength(ending);
                        if(llGetSubString(lmessage,-endinglen,-1) == ending)
                        {
                            message = llGetSubString(message,llStringLength(trigger),-endinglen - 1);
                            llHTTPRequest(WIKIMEDIA_API+"?site=wikipedia&query="+EscapeURL(message),[],"");
                            return;
                        }
                    }
                }
            }
        }
        string request = "botid="+BOT_ID+"&input="+EscapeURL(message)+"&custid="+llDumpList2String(llParseString2List(id,["-"],[]),"")+gBotID;
        llHTTPRequest(BOT_API,[HTTP_METHOD,"POST",HTTP_MIMETYPE,"application/x-www-form-urlencoded"],request);
        return;
    }
    
    http_response(key id, integer status, list mdata, string body)
    {
        if(status >= 200 && status < 300)
        {
            integer pos = llSubStringIndex(body,"<message>");
            integer endpos = 0;
            if(!~pos)
            {
                pos = llSubStringIndex(body,"<that>") + 6;
                endpos = llSubStringIndex(body,"</that>") - 1;
                llSay(0,FixHTML(llGetSubString(body,pos,endpos)));
            }
            else
            {
                endpos = llSubStringIndex(body,"</message>");
                llSay(0,FixHTML(llGetSubString(body,pos,endpos)));
            }
        }
        else
        {
            llSay(0,"HTTP error #"+(string)status+".");
        }
    }
    
    timer()
    {
        integer len = llGetListLength(gEmailsPending);
        integer i;
        integer time = llGetUnixTime();
        for(i = 1; i < len; i += 4)
        {
            if(time - llList2Integer(gEmailsPending,i) >= EMAIL_TIMEOUT)
            {
                llInstantMessage(llList2Key(gEmailsPending,i - 1),"Your email has not been sent, because you took too long over it.");
                gEmailsPending = llDeleteSubList(gEmailsPending,i - 1, i + 3);
                i -= 4;
                len -= 4;
            }
        }
        if(len <= 0)
        {
            llSetTimerEvent(0.0);
        }
    }
                
}

state off
{
    state_entry()
    {
        gEmailsPending = [];
    }
    
    touch_start(integer num)
    {
        state default;
    }
}

Emailer

This script just sends emails. Place it in the same prim as the other script.

integer EMAIL_LINK = 1;

default
{
    link_message(integer sender, integer num, string str, key id)
    {
        if(num == EMAIL_LINK)
        {
            list stuff = llParseString2List(id,[" "],[]);
            string name = llList2String(stuff,0)+" "+llList2String(stuff,1);
            string to = llList2String(stuff,2);
            string subject = llDumpList2String(llList2List(stuff,3,-1)," ");
            llEmail(to,subject,str+"\n \n(Message sent on behalf of "+name+")");
        }
    }
}

Wikipedia script

If you want to run your own Wikipedia proxy, use this script and change the WIKIMEDIA_API constant:

<?php
/* Copyright (c) 2007, Katharine Berry
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Katharine Berry nor the names of any contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY KATHARINE BERRY ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL KATHARINE BERRY BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

function unhtmlentities($string)
{
    // replace numeric entities
    $string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
    $string = preg_replace('~&#([0-9]+);~e', 'chr("\\1")', $string);
    // replace literal entities
    $trans_tbl = get_html_translation_table(HTML_ENTITIES);
    $trans_tbl = array_flip($trans_tbl);
    return strtr($string, $trans_tbl);
}

if($_GET['site'] == 'wikipedia')
{
	$search = stripslashes($_GET['query']);
	$url = str_replace(' ','_',$search);
	$text = file_get_contents("http://en.wikipedia.org/wiki/{$url}");
	$text = preg_replace('~</?[ai].*?>~is','',$text);
	$oldtext = $text;
	preg_match('~<title>(.+?) - Wikipedia, the free encyclopedia</title>~i',$text,$matches);
	$path = urlencode(str_replace(' ','_',$matches[1]));
	$title = $matches[1];
	while((strpos($oldtext,'</table>') < strpos($oldtext,'<p>') && strpos($oldtext,'</table>') !== false))
	{
		$oldtext = $text;
		$text = substr($text,strpos($text,'</table>')+8);
	}
	$oldtext = preg_replace('~<div class=.+?>.+?</div>~is','',$oldtext);
	if(!preg_match('~<p>([^<>]{0,15}<b>[^<>]+?</b>[^<>]{2,2}.+?)</p>~is',$oldtext,$matches))
	{
		preg_match('~<p>(.+?)</p>~is',$oldtext,$matches);
	}
	$lines = wordwrap(htmlentities(str_replace("\n",' ',preg_replace('~\[([0-9]+?|[a-z]+?needed)\]~is','',unhtmlentities(strip_tags($matches[0]))))),1000,"<br>",true);
	print "<result success=\"0\"><input>".htmlentities($search)."</input><that>".htmlentities($title).": {$lines}";
}
?>