## # # alice.tcl v1.2.0 - by strikelight ([sL] @ EFNet) (September 16, 2002) # # - Read the README.TXT for script details, help, and contact info. # ## #### CONFIGURATION #### ## File to save alice cookies to ## set alice_cookiesfile "$nick.cookies" ## Every night, expire cookies that have not been accessed in how many days? ## set alice_cookiesexpire 5 ## Let your bot respond to private messages? (0 = No, 1 = Yes) ## set alice_respondpriv 1 ## Let your bot respond to comments in channel when bot's name is mentioned? ## # (0 = No, 1 = Yes) [ For eggdrop versions less than 1.5.x # ( 1.5.x+ users should use .chanset #channel +alice ) ] set alice_respondchan 1 ## Require bot's nick to be in all lines of a public conversation in order # for it to respond, after initial contact? (ie. alice: hello there) # (if alice_respondchan is set to 1, or channel is set to +alice, else ignore this) # (0 = No, 1 = Yes) set alice_respondrequirenick 1 ## Respond with user's nick? (ie. user: Hi, how are you?) # (if alice_respondchan is set to 1, or channel is set to +alice, else ignore this) # (0 = No, 1 = Yes) set alice_respondwithnick 1 ## Channels to listen on (if alice_respondchan is set to 1, else ignore this) ## # (Separate multiple channels by space, use * to indicate all channels) # [ For eggdrop versions less than 1.5.x only , 1.5.x+ users should # use .chanset #channel +alice ] # eg. set alice_channels "#channel1 #channel2 #etc" .. or : set alice_channels "#linuxtalk #mswindows" ## Also if alice_respondchan is set to 1 or channel is set to +alice, # (otherwise ignore this), how long a silence should the bot wait for # user's text in a channel after the first contact is made before # giving up on their conversation? (in minutes) set alice_timeoutchat 5 ## Log conversations? # 0 = No # 1 = Yes set alice_logging 0 ## If logging on, what directory should the logs be stored in? # (Note1: If directory doesn't exist, you must create it) # (Note2: Ignore this if you don't want to log) set alice_log_path "logs/" ## Which server should I use for the alice engine? # 0 = www.alicebot.org (Alice) # 1 = www.agentruby.com (Ruby) # 2 = a program E server (Phillip) # 3 = jaczone.com (Cyber-Ivar) # 4 = neodave.civ.pl (Hippie) # 5 = your own program-D alice server # 6 = Actual Hippie Program-C # 7 = Actual Hippie Program-C # 8 = your own pandorabots engine (www.pandorabots.com) # 9 = A runabot.com AOL Instant Messenger bot (www.runabot.com) set alice_engine 0 # If using your own alice server (program-D), enter the url here: #set alice_url "http://yourserver.here.com:2001/" # If using your own actual Hippie Program-C, set path here: #set alice_hippie_path "/home/user/eggdrop/C/command_alice" # If using your own actual Hippie Program-C, set path to ini file here: #set alice_hippie_inipath "/home/user/eggdrop/C/data/alice.ini" # If using your own actual Hippie Program-C, set path to log info here: #set alice_hippie_logpath "/home/user/eggdrop/C/log/" #### END OF CONFIGURATION (STOP EDITTING HERE!!) #### if {[info exists egghttp(version)]} { regsub -all "\\." $egghttp(version) "" egghttpnumvers } if {($alice_engine < 6) && (![info exists egghttp(version)] || ($egghttpnumvers < 103))} { putlog "alice.tcl : Could not load alice.tcl, egghttp.tcl 1.0.3 or greater is required." putlog "alice.tcl : You may download it from http://www.TCLScript.com" catch {unset alice_url} catch {unset alice_timeoutchat} catch {unset alice_channels} catch {unset alice_respondchan} catch {unset alice_respondrequirenick} catch {unset alice_respondwithnick} catch {unset alice_respondpriv} catch {unset alice_cookiesexpire} catch {unset alice_cookiesfile} catch {unset alice_engine} catch {unset alice_logging} catch {unset alice_hippie_path} catch {unset alice_hippie_inipath} catch {unset alice_hippie_logpath} } elseif {($alice_engine == 6) && (![info exists bgexec(version)])} { putlog "alice.tcl : Could not load alice.tcl, bgexec.tcl is required." putlog "alice.tcl : You may download it from http://www.TCLScript.com" catch {unset alice_url} catch {unset alice_timeoutchat} catch {unset alice_channels} catch {unset alice_respondchan} catch {unset alice_respondrequirenick} catch {unset alice_respondwithnick} catch {unset alice_respondpriv} catch {unset alice_cookiesexpire} catch {unset alice_cookiesfile} catch {unset alice_engine} catch {unset alice_logging} catch {unset alice_hippie_path} catch {unset alice_hippie_inipath} catch {unset alice_hippie_logpath} } elseif {$alice_engine == -1} { putlog "alice.tcl : You have not fully configured your Alice.tcl script." putlog "alice.tcl : Please edit the configuration, and then restart." putlog "alice.tcl : alice.tcl has NOT been loaded." } else { set alice_version "1.2.0" set alice_chanflag [catch {setudef flag alice}] switch $alice_engine { 0 { set alice_url "http://alice.sunlitsurf.com:2009/a.l.i.c.e./" set alice_input "text" set alice_cookie_method 0 set alice_query_method 0 } 1 { set alice_url "http://www.agentruby.com:2001/" set alice_input "text" set alice_cookie_method 0 set alice_query_method 0 } 2 { set alice_url "http://217.6.247.139/alicebot/src/talk.php" set alice_input "input" set alice_cookie_method 0 set alice_query_method 0 } 3 { set alice_url "http://213.67.11.109/" set alice_input "text" set alice_cookie_method 0 set alice_query_method 0 } 4 { set alice_url "http://neodave.civ.pl/hippie/hippie.cgi" set alice_input "text" set alice_cookie_method 1 set alice_query_method 1 } 5 { set alice_url $alice_url set alice_input "text" set alice_cookie_method 0 set alice_query_method 0 } 6 { set alice_url "" } default { set alice_url "http://alice.sunlitsurf.com:2009/a.l.i.c.e./" set alice_input "text" set alice_cookie_method 0 set alice_query_method 0 } } # MISC PROCS ## strip_html : remove text that begins with <, ends with >, and everything in between proc strip_html {text} { regsub -all ">" $text \x81 text regsub -all "<\[^\x81\]*\x81" $text {} text regsub -all " " $text " " text regsub -all "&" $text {\&} text regsub -all """ $text "\'" text regsub -all "©" $text "(c)" text regsub -all "&#" $text "#" text regsub -all "<" $text "<" text regsub -all ">" $text ">" text regsub -all "%20" $text " " text return $text } ## lstring_remove : remove all elements from a list that contain the matching remove pattern proc lstring_remove {list remove} { set newlist "" foreach item $list { if {![string match "*[string tolower $remove]*" [string tolower $item]]} { lappend newlist $item } } return $newlist } ## nearestindex : return the string index where char occurs in text, nearest to # a specified index proc nearestindex {text index {char " "}} { set tchar [string index $text $index] while {($tchar != $char) && ($index >= 0)} { incr index -1 set tchar [string index $text $index] } return $index } ## istoldquiet : check to see if the text says for the bot to be quiet proc istoldquiet {text} { set exprs {shush {be *quiet} bye cya ttyl {talk* later} {i* leav} {got* go} {shut *up} shutup {leave me *alone} {go away} quiet shh} foreach item $exprs { if {[string match "*$item*" [string tolower $text]]} { return 1 } } return 0 } # Alice Formatting Procs ## alice:corrections : replace any occurances of the alice name with the bot's name instead # also fix misc. html codes to plain text proc alice:corrections {text} { global nick regsub -all -- "alice" $text "$nick" text regsub -all -- "Alice" $text "$nick" text regsub -all -- "ALICE" $text "$nick" text regsub -all -- "A.L.I.C.E." $text "$nick" text regsub -all -- "A.L.I.C.E" $text "$nick" text regsub -all -- "a.l.i.c.e." $text "$nick" text regsub -all -- "a.l.i.c.e" $text "$nick" text regsub -all -- "ruby" $text "$nick" text regsub -all -- "Ruby" $text "$nick" text regsub -all -- "sofia" $text "$nick" text regsub -all -- "Sofia" $text "$nick" text regsub -all -- "testbot" $text "$nick" text regsub -all -- "TestBot" $text "$nick" text regsub -all -- "ivar" $text "$nick" text regsub -all -- "Ivar" $text "$nick" text regsub -all -- "[format %c 9]" $text "" text regsub -all -- "parent.noAnswer=1;" $text "" text regsub -all -- "charNoAnswer \\(\\);" $text "" text regsub -all -- "charSpeak\\(\"" $text "" text regsub -all -- "\"\\);" $text "" text return $text } ## alice:fixquery : replace all spaces with "%20" or "+" depending on query_method # first line of this proc by Wcc (thanks mate) (27/6/02) proc alice:fixquery {text} { regsub -all -- {\002|\037|\026|\017|\003([0-9][0-9]?(,[0-9][0-9]?)?)?|||([0-9][0-9]?(,[0-9][0-9]?)?)?|} $text "" text global alice_query_method if {$alice_query_method == 0} { regsub -all -- " " $text "%20" text } elseif {$alice_query_method == 1} { regsub -all -- " " $text "+" text } return $text } # Alice Logging Procs ## alice:logdata : save data to logfile proc alice:logdata {where who what} { global alice_logging alice_log_path if {!$alice_logging} { return 0 } set file "${where}.alice.log" regsub -all -nocase \\| $file _ file if {[catch {set outfile [open "${alice_log_path}${file}" a+]}]} { return 0 } set dtime [clock format [clock seconds] -format "\[(%m.%d.%y) %H:%M\]"] puts $outfile "$dtime <$who> $what" close $outfile return 1 } # Alice Cookie Procs ## alice:getcookies : return the saved cookie for a person # (cookies are used so that alice remembers the person) proc alice:getcookies {who} { global alice_cookies set who [string tolower $who] if {![info exists alice_cookies($who,data)]} { return "" } return $alice_cookies($who,data) } ## alice:setcookies : store a cookie for a person proc alice:setcookies {who cookies} { global alice_cookies set who [string tolower $who] set ocookies [alice:getcookies $who] if {($ocookies != "") && ([llength [split $cookies]] == 2)} { set ncookies "" foreach ck $ocookies { if {[string match "*jsessionid*" $ck]} { if {[string index $ck [expr [string length $ck] - 1]] != ";"} { append ck ";" } append ncookies "$ck " } } append ncookies $cookies set cookies $ncookies } elseif {($ocookies != "") && ([llength [split $cookies]] == 1)} { set ncookies "" foreach ck $ocookies { if {[string match "*alicebot_*" $ck]} { if {[string index $ck [expr [string length $ck] - 1]] != ";"} { append ck ";" } append ncookies "$ck " } } append ncookies $cookies set cookies $ncookies } set alice_cookies($who,data) "$cookies" set alice_cookies($who,time) "[clock seconds]" return 1 } ## alice:savecookies : save cookies to file proc alice:savecookies {} { global alice_cookiesfile alice_cookies set outfile [open "$alice_cookiesfile" w] puts $outfile [list array set alice_cookies [array get alice_cookies]] close $outfile return 1 } ## alice:loadcookies : load cookies from file proc alice:loadcookies {} { global alice_cookiesfile alice_cookies catch {unset alice_cookies} source $alice_cookiesfile } ## alice:expirecookies : remove old cookies proc alice:expirecookies {} { global alice_cookies alice_cookiesexpire set seconds [expr $alice_cookiesexpire * 24 * 60 * 60] foreach cookie [array names alice_cookies *,time] { if {[expr [clock seconds] - $alice_cookies($cookie)] >= $seconds} { set who [lindex [split $cookie ","] 0] catch {unset alice_cookies($who,time)} catch {unset alice_cookies($who,data)} } } } ## alice:time_cookie : call the expire cookies procedure bind time - "16 * * * *" alice:time_cookie proc alice:time_cookie {mi ho da mo yr} { putloglev o * "ALICE: Expiring old alice cookies ..." alice:expirecookies putloglev o * "ALICE: Saving alice cookie data ..." alice:savecookies } # Alice Connection Procs ## alice:query : send user's text to the alice engine on the web to wait for a reply proc alice:query {who where text} { global alice_url alice_input alice_cookie_method alice_engine global alice_hippie_path alice_hippie_inipath alice_hippie_logpath if {$alice_engine == 6} { if {[catch {bgexec "$alice_hippie_path -i $alice_hippie_inipath -u ${alice_hippie_logpath}${who} \"$text\"" [list alice:execresponse $who $where]} err]} { putlog "alice.tcl : Error executing hippie command program. ($err) Did you install it?" } return -1 } set text [alice:fixquery $text] set cookies [alice:getcookies $who] if {$cookies != ""} { if {$alice_cookie_method == 0} { set sock [egghttp:geturl $alice_url [list alice:response $who $where] -query $alice_input=$text -headers "Cookie: $cookies"] } elseif {$alice_cookie_method == 1} { set sock [egghttp:geturl $alice_url [list alice:response $who $where] -query $alice_input=$text&$cookies] } alice:setcookies $who "$cookies" } else { if {$alice_cookie_method == 0} { set sock [egghttp:geturl $alice_url [list alice:response $who $where] -query $alice_input=$text] } elseif {$alice_cookie_method == 1} { if {$alice_engine == 4} { set cookies "&virtual=none" } set sock [egghttp:geturl $alice_url [list alice:response $who $where] -query $alice_input=${text}${cookies}] } } return $sock } ## alice:response : parse alice's response and show the user proc alice:response {who where sock} { global alice_engine alice_respondwithnick botnick set headers [egghttp:headers $sock] set data [egghttp:data $sock] set response "" if {([egghttp:errormsg $sock] != "Ok") || ($data == "")} { catch {alice:timeoutchat $who $where} egghttp:cleanup $sock return } egghttp:cleanup $sock set cookies "" foreach line [split $headers "\n"] { if {[string match "*Set-Cookie:*" $line]} { set what [lindex [split $line " "] 1] if {$alice_engine != 4} { if {[string match "*Expires*" $what]} { set what [string range $what 0 [expr [string first "Expires" $what] - 2]] } if {[string match "*Path*" $what]} { set what [string range $what 0 [expr [string first "Path" $what] - 2]] } } if {($alice_engine == 4) && ([string match "*VIR=*" $what])} { set what [string range $what [expr [string first "VIR=" $what] + 4] [expr [string first $what ";"] - 1]] set what "virtual=$what" } if {$what != ""} { append cookies "; $what" } } } set cookies [string range $cookies 2 end] if {$cookies != ""} { alice:setcookies $who "$cookies" } set a 0 foreach line [split $data "\n"] { # programE specific instructions if {$alice_engine == 2} { if {[string match "*#FFFFFF*" $line]} { incr a } if {($a >= 1) && ([string match "*#ffff66*" $line])} { set apos [expr [string last "#ffff66" $line] + 9] set response [string range $line $apos [string length $line]] } elseif {($a >= 1)} { append response [string trim $line] } if {($a >= 1) && ([string match "**" $line])} { break } continue } # hippie cgi specific instructions if {$alice_engine == 4} { if {[string match "*Hippie said*" $line]} { incr a set line [string range $line [expr [string first "said:" $line] + 5] end] } if {($a >= 1) && (![string match "*\"http://neodave*" $line])} { append response [string trim $line] } if {[string match "*\"http://neodave*" $line]} { break } continue } if {($a >= 1) && ![string match "*

*" $line]} { append response [string trim $line] } if {($a >= 1) && ([string match "*

*" $line] || [string match "*check_return()*" $line] || [string match "**" $line] || [string match "*jaczone.com*" $line])} { break } if {[string match "*response-line*" $line] || [string match "*\"botresponse\"*" $line] || ([string match "*offline for maint*" $line] && ($alice_engine != 3)) \ || [string match "**" $line] || [string match "*Perhaps that*" $line]} { incr a } } if {$response != ""} { set response [strip_html $response] set response [alice:corrections $response] set response [string trimleft $response "\}"] set response [string trim $response] if {[string length $response] >= 256} { while {($response != "") && ([string length $response] >= 256)} { set tmp [nearestindex "$response" 256] if {$tmp != -1} { set text [string range $response 0 [expr $tmp - 1]] set response [string range $response [expr $tmp + 1] end] } else { set text [string range $response 0 256] set response [string range $response 257 end] } if {[validchan $where] && $alice_respondwithnick} { set text "$who: $text" } alice:logdata "$where" "$botnick" "$text" puthelp "PRIVMSG $where :$text" } } if {$response != ""} { if {[validchan $where] && $alice_respondwithnick} { set response "$who: $response" } alice:logdata "$where" "$botnick" "$response" puthelp "PRIVMSG $where :$response" } } } ## alice:execresponse : parse alice's response and show the user proc alice:execresponse {who where data} { global alice_engine alice_respondwithnick botnick set response "" foreach line [split $data "\n"] { append response [string trim $line] } if {$response != ""} { set response [strip_html $response] set response [alice:corrections $response] set response [string trimleft $response "\}"] set response [string trim $response] if {[string length $response] >= 256} { while {($response != "") && ([string length $response] >= 256)} { set tmp [nearestindex "$response" 256] if {$tmp != -1} { set text [string range $response 0 [expr $tmp - 1]] set response [string range $response [expr $tmp + 1] end] } else { set text [string range $response 0 256] set response [string range $response 257 end] } if {[validchan $where] && $alice_respondwithnick} { set text "$who: $text" } alice:logdata "$where" "$botnick" "$text" puthelp "PRIVMSG $where :$text" } } if {$response != ""} { if {[validchan $where] && $alice_respondwithnick} { set response "$who: $response" } alice:logdata "$where" "$botnick" "$response" puthelp "PRIVMSG $where :$response" } } } proc alice:timeoutchat {who where} { global alice_chat catch {unset alice_chat($who,$where)} } # Alice Chat Binding Procs if {$alice_respondpriv} { bind msgm - * alice:msg_query proc alice:msg_query {nick uhost hand text} { global botnick if {([string tolower $nick] == [string tolower $botnick]) || ([matchattr $hand b])} { return } # let's not bother looking at passwords and stuff ... -sL (6/13/02) if {[regexp pass|op|invite|ident|addhost [string tolower [lindex [split $text] 0]]]} { set text "" return 0 } set where "[string tolower $nick]" if {($hand != "") && ($hand != "*")} { set who "[string tolower $hand]" } else { set who "[string tolower $nick]" } alice:logdata $where $who "$text" alice:query $who $where "$text" return 0 } } if {($alice_respondchan) || (!$alice_chanflag)} { proc alice:isrespondchan {chan} { global alice_chanflag alice_channels if {!$alice_chanflag} { if {[lsearch -exact [channel info $chan] +alice] != -1} { return 1 } else { return 0 } } else { if {($alice_channels == "*") || ([lsearch [split [string tolower $alice_channels]] $chan] != -1)} { return 1 } else { return 0 } } } bind pubm - * alice:pub_query proc alice:pub_query {nick uhost hand chan text} { global botnick alice_channels alice_timeoutchat alice_chat alice_respondrequirenick if {([string tolower $nick] == [string tolower $botnick]) || ([matchattr $hand b])} { return } set chan [string tolower $chan] if {![alice:isrespondchan $chan]} { return } set where "$chan" if {($hand != "") && ($hand != "*")} { set who "[string tolower $hand]" } else { set who "[string tolower $nick]" } if {(![string match "*[string tolower $botnick]*" [string tolower $text]]) && (![info exists alice_chat($who,$chan)])} { return } if {(![string match "*[string tolower $botnick]*" [string tolower $text]] && $alice_respondrequirenick)} { return } if {![info exists alice_chat($who,$chan)]} { set alice_chat($who,$chan) [utimer [expr $alice_timeoutchat * 60] "alice:timeoutchat $who $chan"] } else { catch {killutimer $alice_chat($who,$chan)} set alice_chat($who,$chan) [utimer [expr $alice_timeoutchat * 60] "alice:timeoutchat $who $chan"] } if {[istoldquiet $text]} { alice:timeoutchat $who $where } set text [join [lstring_remove [split $text] $botnick]] alice:logdata $where $who "$text" alice:query $who $where "$text" } } ## create cookies file if it doesn't exist if {![file exists $alice_cookiesfile]} { set outfile [open $alice_cookiesfile w] close $outfile catch {unset outfile} } ## load cookies file alice:loadcookies putlog "alice.tcl $alice_version by strikelight is now loaded." }