SmIRC 0.62b
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 automatically saying
hello to anyone who joins a channel, or, if anyone says the word "beer"
on a channel, immediately send a message "* A gives B a can of beer.".
Bots are generally frowned upon, but they've become a part of the IRC
culture, so 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 whatever tools you want. SmIRC does NOT
provide you with a scripting language of its own. Why should it? Just use
anything in UNIX 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 or error, can become a bot.
Ok, what exactly is a bot, in SmIRC?
Specifically, when a bot program is running, SmIRC will send to this program
a copy of everything that it sends to a window, in a certain format. Most
standalone bot programs use a separate IRC connection, with a separate
nickname. 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, and dispatches the message to this
window.
Each bot can be thought of as running in one window, which would be
either a server window, or a channel window. You can have a separate copy
of each bot running for multiple channels, one in each window.
The bot program will receive, on standard input, a copy of every message
that SmIRC shows in its window. Unless otherwise stated, each message will
be formatted as follows:
-
Each message will be terminate by a newline character.
-
The message is formatted as follows: CODE\tARG1\tARG2...
In other words, each message is one or more tab-separated fields. The message,
and the fields, directly correspond to the stringTable resource
entries in SmIRC's resource file. Take a look at /usr/lib/X11R6/app-defaults/Smirc,
starting with the section labeled "Various messages". What follows is a
list of all the possible messages that can appear in a window. NOTE: the
stringTable resources also include various other text messages,
such as window titles. The first record is the name of the resource, such
as "LOOKINGUP", or "CONNECTING". The remaining records 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.
Based upon these messages, a bot program can cause things to happen
simply by sending output. Anything that the bot program prints to standard
output will be interpreted EXACTLY as if it was typed into the command
buffer. For example, printing "/join #newbies", followed by a newline,
will join this channel. Printing "Hello!", followed by a newline, sends
this 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 program
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.
Standard error, and standard output from your bot program will, in one
way or another, reappear on standard input, since they will usually cause
some kind of message to be displayed in the window. If you're not carefull,
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/lib/smirc |
|
/usr/lib/smirc |
|
$HOME/.smirc |
|
The name of the bot program should 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 nto 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.
Hints for writing bots
There is a new "samples" subdirectory, starting with the 0.60 release.
This subdirectory contains some usefull, generic, bots, written in Perl.
Use them as a guide for writing your own.
Comparing nicknames
If you are comparing two nickname variables for equivalency, 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 succesfully
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 cancelled. 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 cancelling the timer.
If the number of seconds is 0, after any existing timer is cancelled,
SmIRC will send a _CANCEL message (note the leading underscore)
to the bot process, signifying the timer being cancelled.
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 samples subdirectory in the SmIRC source code tarball contains
some sample bots, written in Perl. Make sure your perl can be found in
/usr/bin, and feel free to experiment with them.