|< Day Day Up >|
Hack 36 A Simple Python IRC Client
Python doesn't include an IRC module as standard, but connecting is nonetheless easy. Make a simple client that connects to an IRC server.
Python is becoming a popular language for writing IRC bots. This can be attributed to the way you can achieve quite a lot with just a little bit of code. Python does not include an IRC module as standard, but there are a few Python IRC modules written by other people.
In some cases, you're better off writing your own IRC client from scratch instead of using something like IRCLib [Hack #37] . Fortunately, Python is a powerful language, and you can write a client with as few as 30 lines of code. The following example connects to IRC and responds to PINGs.
5.7.1 The Code
import sys import socket import string HOST="irc.freenode.net" PORT=6667 NICK="MauBot" IDENT="maubot" REALNAME="MauritsBot" readbuffer="" s=socket.socket( ) s.connect((HOST, PORT)) s.send("NICK %s\r\n" % NICK) s.send("USER %s %s bla :%s\r\n" % (IDENT, HOST, REALNAME)) while 1: readbuffer=readbuffer+s.recv(1024) temp=string.split(readbuffer, "\n") readbuffer=temp.pop( ) for line in temp: line=string.rstrip(line) line=string.split(line) if(line=="PING"): s.send("PONG %s\r\n" % line)
Lots of this code should be self-explanatory by now. It starts by importing all the modules you're going to need. The second block of code is a bunch of variables that you can change. These determine which server we connect to, the nickname we use, and so forth.
The block of code after that is the first one that actually does anything. It creates a socket and connects to the server of choice. This example will connect to the freenode IRC network (irc.freenode.net). It also registers the client by sending NICK and USER commands to the server.
The bot then enters an infinite loop (to shut it down, press Ctrl-C). The first block of code inside the loop reads a maximum of 1024 bytes from the server and appends it to the readbuffer. You need a readbuffer because you might not always be able to read complete IRC commands from the server (due to a saturated Internet connection, operating system limits, etc). So whatever you read, you need to append it to the read buffer. The read buffer is then split into a list of strings, using \n as a separator. The last line in this list is possibly a half-received line, so it is stored back into the read buffer.
Before we're able to process the lines from the read buffer in a normal manner, there's one thing left to do. You need to remove the trailing \r character from the end of the lines. The string.rstrip( ) function does exactly this.
I can hear you thinking, "IRC uses \r\n as a message separator. Why don't you just split the lines using that as a separator, instead of just \n? You won't end up with an \r in the first place, then." This would be a better solution, if it weren't for some stubborn IRC networks that choose to ignore the RFC and use \n instead. So although the RFC says each message is supposed to be separated by an \r\n, you need to treat \r as optional.
Now that you have "clean" lines to process, you need to look for PING commands sent to the client. If the server sends it PING :randomstring, you need to reply with PONG :randomstring. The last three lines of code do this. The line is split into a list of strings, using a space as a separator. The if statement checks to see if the line started with a PING and sends back a PONG in response.
That's all there is to it. Of course, this bot doesn't do anything yet, but I'm sure you're able to figure out how to go on from here. One last thing—you may have noticed that I'm not using a send buffer. If you send something over an Internet socket, it's not guaranteed that all data is actually sent. So if you wanted to make this example completely resilient, you'd need to implement a send buffer to store any data you might not be able to send. This simple bot does not include this feature, as it isn't often required and would make the example more complex. If this is a concern, you can use IRCLib [Hack #37], which implements the send buffer for you.
5.7.2 Running the Hack
% python simplebot.py
|< Day Day Up >|