Macha

A quick, basic primer on the IRC protocol

October 14, 2010 | categories: Programming, Technology

While working on my Haskell IRC bot, I needed some information on the actual IRC protocol. Much of this information sadly isn't available in any centralised format, and much of the information that is there is just a copy/paste of the RFC. There are two formal descriptions of the IRC protocol, an older one (RFC 1459) and a newer one (RFC 2812), though the actual protocol as used by most servers doesn't adhere exactly to either of these. So, here is a short summary of the information that I have gathered in my research. This is by no means a comprehensive tutorial, but it is sufficient to write a basic IRC bot.

The first part of the IRC protocol is the rough layout of messages. The first, optional part, is the source (username and hostmask, or server) preceded by a colon, as in :holmes.freenode.net . Because they only deal with one other part of the network, the server, clients will rarely, if ever send this part, while servers nearly always will.

The next part of the protocol, seperated by a space is the command name, which is in all-caps. Most of these are pretty much the same as what the user types in after the /. For example, the /join command becomes JOIN. The most notable exception is the PRIVMSG command, which is used for sending a message to a user or channel (it's the same command for both).

After this come the arguments for the command, again, space seperated. Most of these are limited to one word values. The one exception is the final argument, which can have more than one word, and is started off by a colon.

There are a few types of channel, but nearly all the channels you will encounter are of the #channel variety, so we will not go into detail on other types.

Finally, the command is terminated by \r\n, not \n according to the spec, though it seems most servers will accept either.

An example of a full message is as such:

:Macha!~macha@unaffiliated/macha PRIVMSG #botwar :Test response

The first part of any IRC connection is sending the NICK and USER messages. The first of these is simple, just NICK name. The next is the USER message.

An example of a USER message is:

USER username 0 * :Real name

The * part is a remnant of earlier days, and will not need to be changed. The 0 is a bitmask for the user's mode, but with just one switch. Change it to 8 to be invisible to those not in a channel with you.

The next part of the protocol we will discuss is the PING message, because some servers need one immediately after these two messages. The server will send you a message in the format PING :message to which it needs a response of PONG :message. This is the most common case of a server not sending a source. Most servers use the server name as the message part, but this isn't consistent.

For all of the rest of these messages,  there is a source on the other messages from the server side. This is a user and hostmask for a user's message, and a server name otherwise. If you are writing a client, do not send the :source part.

The next message to deal with is JOIN. The basic format of this message from most servers I've tested is

:source JOIN :#channel

although the spec says otherwise as regards the need for the colon. This is pretty self explanatory, and works the same as the /join used in an IRC client. The one unintuitive part of this command is that JOIN 0 leaves all channels.

Its counterpart is PART. Its format is

:source PART #channel :reason

The reason part is optional, and some servers (for example Freenode) seem to just cut it off, as it did not exist in earlier versions of the IRC protocol.

Both of these messages can also accept a list of channels separated by commas when sent from the client, for example PART #channel1,#channel2. Don't put spaces between the channels in this list.

The most important command in the IRC protocol is PRIVMSG. This command is used for sending messages both to channels and between users. Its format is

:source PRIVMSG <target> :Message

where the target is either a user's nick, or a channel name. So to send a message to a channel, use PRIVMSG #channel :Hello, World and to send a private message to a user, send PRIVMSG Nick :Hi!.

The final message you will use in basic usage is QUIT. Its format is

:source QUIT :reason

where the reason is optional.

These commands are sufficient to write a basic IRC bot but are by no means the full list. There are also numeric commands, and you can find more detail on these here.