Richard Suchenwirth 2007-10-21 - In the Tcl chatroom we discussed IRC chatting, and one user was not happy with picoIRC 0.2 - he didn't want the GUI, only the bot behavior... which I modelled as a first shot to
So, in several iterations, this script minibot.tcl came out, which has some rudimentary knowledge of Chinese and Russian, can do math, and string toupper:
#!/usr/bin/env tclsh set ::server irc.freenode.org set ::chan #tcl set ::me minibot proc recv {} { gets $::fd line puts $line # handle PING messages from server if {[lindex [split $line] 0] eq "PING"} { send "PONG [info hostname] [lindex [split $line] 1]"; return } if {[regexp {:([^!]*)![^ ].* +PRIVMSG ([^ :]+) +(.*[Mm]inibot)(.+)} $line -> \ nick target msg cmd]} { if {$nick eq "ijchain"} {regexp {<([^>]+)>(.+)} $msg -> nick msg} set hit 0 foreach pattern [array names ::patterns] { if [string match "*$pattern*" $cmd] { set cmd [string trim $cmd {.,:? }] if [catch {mini eval $::patterns($pattern) $cmd} res] { set res $::errorInfo } foreach line [split $res \n] { send "PRIVMSG $::chan :$line" } incr hit break } } if !$hit {send "PRIVMSG $::chan :Sorry, no idea."} } }
#----------- Patterns for response:
set patterns(time) {clock format [clock sec] ;#} set patterns(expr) safeexpr proc safeexpr args {expr [string map {\[ ( \] ) expr ""} $args]} set patterns(eggdrop) {set _ "Please check https://wiki.tcl-lang.org/6601" ;#} set patterns(toupper) string set patterns(Windows) {set _ "I'd prefer not to discuss Windows..." ;#} set {patterns(translate "good" to Russian)} {set _ \u0425\u043E\u0440\u043E\u0448\u043E ;#} set patterns(Beijing) {set _ \u5317\u4EAC ;#} set patterns(Tokyo) {set _ \u4E1C\u4EAC ;#} set {patterns(your Wiki page)} {set _ https://wiki.tcl-lang.org/20205 ;#} set patterns(zzz) {set _ "zzz well!" ;#} set patterns(man) safeman proc safeman args {return https://www.tcl-lang.org/man/tcl8.4/TclCmd/[lindex $args 1].htm} set {patterns(where can I read about)} gotowiki proc gotowiki args {return "Try https://wiki.tcl-lang.org/[lindex $args end]"} set patterns(thank) {set _ "You're welcome." ;#} set patterns(worry) worry proc worry args { return "Why do [string map {I you my your your my you me} $args]?" }
#-- let the show begin... :^)
interp create -safe mini foreach i {safeexpr safeman gotowiki worry} { interp alias mini $i {} $i } proc in {list element} {expr {[lsearch -exact $list $element]>=0}} proc send str {puts $::fd $str;flush $::fd} set ::fd [socket $::server 6667] fconfigure $fd -encoding utf-8 send "NICK minibot" send "USER $::me 0 * :PicoIRC user" send "JOIN $::chan" fileevent $::fd readable recv vwait forever
Examples from the chat:
suchenwi minibot, which is your Wiki page? <minibot> https://wiki.tcl-lang.org/20205 suchenwi ah, thanks suchenwi minibot expr 6*7 <minibot> 42 suchenwi minibot, what's your local time? <minibot> Sun Oct 21 01:26:59 (MEZ) - Mitteleurop. Sommerzeit 2007
With sufficient tweaking, this could be used to replace Eggdrop some day :^)
Lectus: I was searching for some example code of an IRC bot, but instead using irc library from tcllib which hides the IRC protocol details. Found the code below on the internet:
#!/usr/bin/env tclsh8.5 # (If that doesn't work, try /usr/bin/tclsh8.5 or /usr/local/bin/tclsh8.5) # First off, get the irc package out of tcllib. package require irc # This creates a variable called name which contains the name - you'll probably want to change this. # Note that two : in front of a variable name just means that it's in the global namespace. set name tclbot # More variables, with the channel and server names. set server chat.freenode.net set channel #shellium-bots # Now, create the connection object. This just creates a handle to use for managing the connection, and saves it to a variable set conn [irc::connection] # Next, register an "event handler". These are called when the relevant IRC command is received $conn registerevent PRIVMSG { # The "msg" command can be used inside an event handler to get the IRC message. "split" is used to split the message into a list at blanks. set msg [split [msg]] # If the bot received the message directly, then send it back the person directly # Otherwise, send it to the channel # The "who" command (event handler only) says who sent the message # The "target" command (event handler only) says who the message was sent to if {[target] eq $::name} { set who [who] } else { set who [target] } # Now, only do further processing if the first word is the bot's name. "string tolower" makes a string lowercase. "lindex" returns a list item at a certain index. if {[string tolower [lindex $msg 0]] eq $::name} { # Switch, based on the second word of the message. switch [string tolower [lindex $msg 1]] { stardate { # Send a message with the current stardate. # the "privmsg" subcommand sends a message to a user or channel # "clock seconds" returns the number of seconds since the Unix Epoch # "clock format" formats a Unix date into a human-readable format. We'll be taking advantage of an easter egg that returns the Stardate. $::conn privmsg $who [clock format [clock seconds] -format "%Q"] } default { # This is called if the second word of the message doesn't match anything else in the "switch". # We'll just send an ACTION (/me) saying that this bot shrugs. \001 means ASCII char 1 (SOH). $::conn privmsg $who "\001ACTION shrugs\001" } } } } # Now that all the event handlers we need are registered, connect. These commands should be pretty self-explanatory. $conn connect $server $conn nick $name $conn user $name $name $name "A little pure-Tcl bot" $conn join $channel # Now just sit and wait for messages - the irc package handles everything else. vwait forever
Credit goes to: http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Tcl