[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 * connect to channel #tcl on IRC * listen to what is said * if someone mentions its name (minibot), tries to parse the message and answer 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 http://wiki.tcl.tk/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 _ http://wiki.tcl.tk/20205 ;#} set patterns(zzz) {set _ "zzz well!" ;#} set patterns(man) safeman proc safeman args {return http://www.tcl.tk/man/tcl8.4/TclCmd/[lindex $args 1].htm} set {patterns(where can I read about)} gotowiki proc gotowiki args {return "Try http://wiki.tcl.tk/[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? http://wiki.tcl.tk/20205 suchenwi ah, thanks suchenwi minibot expr 6*7 42 suchenwi minibot, what's your local time? 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 <> Example | Internet