Writing an IRC bot in Tcl
This article will teach you how to create a simple IRC bot in pure Tcl - without Eggdrop. The Tcl standard library, tcllib, actually contains a package with commands for connecting to IRC; we'll use that here. It provides a layer of abstraction between the programmer and the raw IRC protocol, and also deals with PINGs automatically. I'll assume that the reader knows some programming, but not that they know Tcl.
This bot will do two things:
- Join a channel
- Respond to messages that begin with its name
- Specifically, you can get the current Stardate. Or, the bot will just shrug.
You can just paste this code into a file and it'll work. However, you should read it through - the comments explain how everything works, and that's the whole point of this page. Lines beginning with a # are comments. There is also documentation for the irc package available.
#!/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
And there you go. Make sure that you're allowed to run bots in the channel you have this bot set up to go to.
Example:
<jdpage> tclbot hello
*** tclbot shrugs
<jdpage> tclbot stardate
<tclbot> Stardate 64150.9