SmIRC 0.70
SmIRC bots
Starting with version 0.60, SmIRC now provides generic bot support.
What is a "bot"?
A bot is an IRC program, that automatically responds to predefined events on
IRC. Short for a "robot", a bot can do things like sending a greeting message
to anyone who joins a channel. A bot can also look for anyone saying the word
"beer" on a channel, and immediately replying with a message "* A gives B a
can of beer.".
Bots are generally frowned upon. But they're an inseparable part of the IRC
culture. As long as you stick to harmless fun like that, nobody will mind.
What language do I need to use in order to write a bot?
You can write a bot using your favorite language. SmIRC does NOT come
with a scripting language of its own. Why should it? Just use any UNIX
language that you're comfortable with. Write a Perl script, or write a C
program. Anything that can read from standard input, or write to standard
output, can become a bot.
Ok, what exactly is a bot, in SmIRC?
Specifically, when a bot program is running, SmIRC sends to the bot a copy of
everything that appears in a window, format in a special way. All bots running
in SmIRC share the same IRC connection, with SmIRC taking care of all the
dirty low-level details. You don't need to know anything about the IRC
protocol.
SmIRC receives IRC messages from the IRC server, figures out in which window
the message should be displayed, shows the message, then sends the message to
every bot running in that window.
Each bot can be thought of as running in one window, which can be either a
server window, or a channel window. But, you can have multiple copies of the
same bot program, each copy running in a separate window.
The bot receives, on standard input, a copy of every message that SmIRC
displays. Unless otherwise stated, each message is formatted as follows:
-
Each message will be terminate by a newline character.
-
The message is formatted as follows: CODE<TAB>ARG1<TAB>ARG2...,
where <TAB> is a tab character.
In other words, each message is one or more tab-separated fields. The message,
and the fields, directly correspond to a stringTable resource entry
in SmIRC's resource file. Take a look at
/usr/lib/X11R6/app-defaults/Smirc, starting with the section labeled
"Various messages". That section contains a list of all possible messages that
can appear. NOTE: the stringTable resources will also include various
other text messages, such as window titles.
The first field is the name of the resource, such as "LOOKINGUP", or
"CONNECTING". The remaining fields are any fill-in parameters for this
message. For example, for the NICKCHANGE message, the second field is the old
nickname, and the third field is the new nickname.
A bot program causes things to happen simply by printing messages. Anything
that the bot program prints to standard output will be interpreted EXACTLY as
if it were typed in the command buffer. For example, printing "/join
#newbies", followed by a newline, will join this channel. Printing "Hello!",
followed by a newline, sends a hello message to the channel.
Anything that the bot program prints to standard error is simply displayed in
the window.
Important things you should know about bots
Your bot program must be able to keep up with its input. If your bot can't
keep up, or if it locks up, SmIRC will dutifully save all messages pending for
the bot, internally. This will cause SmIRC to grow in size, using up all
available memory.
Generally, I'm giving you enough rope to hang yourself. Don't blame me if you
do something silly, and crash your machine.
Output from your bot program will - some form or fashion - reappear on input.
That's because anything that's typed in usually results in some message to be
displayed, and subsequently sent back to the bot. If you're not careful,
you'll send your bot program into an infinite loop.
When the window is closed, SmIRC will close the standard input, output, and
error to every bot program running in that window. Your bot program is
expected to be able to detect it, and go away. SmIRC will not kill the
process, nor wait for it to finish.
OK, ok, I've read all of the above, and I have my bot ready, now
what?
SmIRC expects to find bots in several places:
/usr/local/etc/smirc
|
|
/usr/local/share/smirc
|
|
$HOME/.smirc
|
|
The name of the bot program must end with a ".bot" extension. To run
a bot in a window, simply type:
/botname arguments
In the command buffer, where botname is the name of the bot program,
without the ".bot" extension.
Starting with version 0.62 of SmIRC, you can also type:
/RUN botname arguments
Arguments received by the bot process
The bot process is executed with the following arguments:
-
arg[1] - The first argument will be either the fixed string SERVER, if the bot
is running in a server window, or the fixed string CHANNEL if the bot is
running in a channel window.
-
arg[2] - The second argument will be the name of the channel, if the bot is
running in a channel window. For bots running in a server window, this
argument will be the name of the server SmIRC is connected to, or an empty
string if SmIRC is not connected to any server.
-
arg[3] - The third argument will be the current nickname if the bot is running
in a channel window. For bots running in a server window, this argument will
be the server port number SmIRC is connected to, or an empty string if
SmIRC is not connected to a server
-
arg[4] - The fourth argument will be the arguments specified
by the user when invoking the bot.
How to automatically start bots for a new channel, or a server window
SmIRC will run everything in the $HOME/.smirc/chanbots
subdirectory, every time you join a new channel.
Everything in $HOME/.smirc/serverbots subdirectory is started every
time a new server window is opened, which includes the first server window
displayed when you start SmIRC.
Everything in $HOME/.smirc/privbots is started every time a private
chat window is created.
Hints for writing bots
There is a new subdirectory, /usr/local/share/smirc/samples, starting with the 0.60
release. This subdirectory contains some useful, generic, bots, written in
Perl. Use them as a guide for writing your own.
Comparing nicknames
If you are comparing two nickname variables for equivalence, consider the fact
that nicknames are case-insensitive. Also, keep in mind that according to
RFC1459, the characters "{", "}", and "|" are lowercase equivalents of the
characters "[", "]", and "\".
Determining when someone joins, or leaves, the channel
When a bot is started from ~/.smirc/chanbots, the bot will get a
series of RPLDEFAULT messages for "353" messages from the IRC server, which
contain the list of nicknames on the channel. That is followed by a RPLDEFAULT
"366" message. The bot program can use these messages to build a list of
nicknames on the channel. At any time, the bot can issue a /NAMES
command to receive a fresh set of nickname listings. NOTE: if you
define a RPL353, or a RPL366 resource in the stringTable portion of the
resource file, the bot will get these messages instead.
A bot will get a USERJOIN message whenever someone joins the channel,
and either a USERPART, USERKICK, or USERQUIT
message whenever someone leaves the channel.
A bot will get either a NICKCHANGE, or a
MYNICKCHANGE message if someone's nick changes.
Determining when SmIRC connects or disconnects from a server
A bot script may need to track whether or not SmIRC is connected to a server.
This is not straightforward, because there are quite a few messages involved.
In putting together the 0.60 release, I added some messages to help in this
task, and I suggest that bots consider the following approach:
-
A CONNECTING message is sent when SmIRC attempts to establish a
connection to the server.
-
A SYSERR message is sent if the connection request fails.
-
A 433 message is sent if the connection request cannot be completed
because of a nickname collision. The connection attempt is STILL in progress,
and may be completed if another /NICK command is sent, resolving the
nickname collision.
-
A READY message is sent if a connection to the IRC server is
successfully completed.
-
A DISCONNECTED message is sent if a connection to the IRC server is
terminated unexpectedly.
-
A TERMINATED message is sent if a connection to the IRC server is
closed naturally, by a /QUIT command.
Extra commands for bot programs
Also, there are some commands that can be sent by a bot, to standard output,
that are handled internally by SmIRC. These commands are only available to
bots, you can't enter them in the input buffer.
/_CTCPHANDLER cmd
Notifies SmIRC that this bot can handle this CTCP command. Since SmIRC
displays CTCP messages in a channel window, all bots running in the window
will always receive CTCP messages. After displaying the message, SmIRC will
acknowledge it with an CTCPUNKNOWNERRMSG message.
This command, available to bots only, will suppress the CTCPUNKNOWNERRMSG
reply. The bot will always receive either a CTCPCMD, or a CTCPCMDACK message
(see the resources file), this just suppresses the error message.
Also, there are some interesting side effects here. If there's a CTCP message
to a channel where you have a handler bot running, a CTCPUNKNOWNERRMSG message
will not be sent. However, if some wag /PRIVMSGs you a CTCP command, since it
will not go into the channel window, SmIRC will reply with a
CTCPUNKNOWNERRMSG. /_CTCPHANDLER command is window-specific.
/_TIMER nnn
Sometimes it may be necessary for a bot to pause for a period of time, or to
wait for a period of time for an expected response to arrive, and, if it
doesn't come, time out. Actually pausing the bot process IS NOT
RECOMMENDED. While a bot process is paused, SmIRC will continue to queue
up output for the bot process, eating up memory.
The /_TIMER command (note the leading underscore) sets a timer in
SmIRC. The parameter to the /_TIMER command is the number of seconds
for the timer to run. When the time expires, the bot process will receive a
_TIMEOUT command on standard input (note the leading underscore). The
basic idea is to send the /_TIMER command, then wait either for the
expected response, or a _TIMEOUT message.
If the number of seconds is 0, any existing timer is canceled. HOWEVER
it is possible that the /_TIMER 0 command is sent just after the
timer expires, and SmIRC already prepared the _TIMEOUT message to be
sent to the bot, but the bot hasn't received it yet, so you may STILL receive
a _TIMEOUT message after supposedly canceling the timer.
If the number of seconds is 0, after any existing timer is canceled, SmIRC
will send a _CANCEL message (note the leading underscore) to the bot
process, signifying the timer being canceled.
This has a possibly useful side-effect. SmIRC will ALWAYS send a
_CANCEL message in response to a /_TIMER 0 command.
Therefore, if a bot process find itself in a situation where it knows it may
have a lot of unprocessed messages from SmIRC waiting, it can quickly flush
them out by sending a /_TIMER 0 command, and discarding any messages
it received until it gets a _CANCEL. (Note, that this will NOT work
if one of the unprocessed messages is a response to a prior /TIMER
0.)
Each bot process has only ONE timer it can set, however, each separate bot
process has its own, private, timer. If you attempt to set a timer before the
previous one goes off, the timer is simply reset for a new expiration time.
HOWEVER, because of a previously-mentioned race condition, a _TIMEOUT
response may or may not be sent to the bot process, therefore, you will lose
track of your timer, and you should ALWAYS reset the timer first.
Examples???
The /usr/local/share/smirc/samples subdirectory contains some sample bots, written in
Perl.