< Day Day Up > |
Hack 33 IRC with Perl and Net::IRC
The IRC protocol looks a bit weird and can be hard to understand. Fortunately, you don't have to know it to make a bot. Net::IRC is a Perl module that lets you make IRC clients. It allows you to think about what your bot actually does, instead of having to think about all those little noninteresting protocol details [Hack #32] . This hack will explain how to write a simple Perl IRC bot using Net::IRC. 5.4.1 PreparationsYou can download the Net::IRC module from CPAN at http://search.cpan.org/dist/Net-IRC. If you're lucky, you may be able to get it straight from your operating system's package manager. It is worth noting that Net::IRC is known to work on Unix systems only. It may work on Windows; it's just not very well supported. To demonstrate how Net::IRC works, we're going to write a little infobot. The bot will do one simple task: remember facts and repeat them when asked. This will end up covering enough detail for you to make your own bots with Net::IRC. 5.4.2 The CodeCreate a file called infobot.pl and write the following: #!/usr/bin/perl use Net::IRC; # Set up the connection to the IRC server. $irc = new Net::IRC; $conn = $irc->newconn( Server => 'irc.freenode.net', Nick => 'InfoBot_pl', Ircname => 'InfoBot.pl' ); # Open the database. dbmopen( %info, 'infobot', 0644 ); # Connect the handlers to the events. $conn->add_handler( 376, \&join_channel ); $conn->add_handler( 422, \&join_channel ); $conn->add_handler( 'public', \&message ); # Start the Net::IRC event loop. $irc->start; sub join_channel { my( $conn, $event ) = @_; print( 'We\'re connected!' . "\n" ); $conn->join( '#irchacks' ); } sub message { my( $conn, $event ) = @_; my( $msg ) = $event->args; if( $msg =~ /^(.*)\?$/ ) { # Someone requested information. Let's see if we know it. if( $info{lc($1)} ne '' ) { $conn->privmsg( $event->to, $event->nick . ': ' . $1 . ' == ' . $info{lc($1)} ); } } elsif( $msg =~ /^(.+?) *=+ *(.+?)$/ ) { # Someone gave us information. Save it. $info{lc($1)} = $2; $conn->privmsg( $event->to, $event->nick . ': OK' ); } } As you may have noticed, Net::IRC is another event-driven IRC bot framework. So as soon as a certain event happens, a handler is called to handle this event. The preceding code illustrates two event handlers: one to join the necessary channels as soon as the connection to the server is successfully made, and one to process incoming messages. To handle an event, one should first write the handler. A handler is a subroutine that accepts two arguments. The first argument is a connection object, which allows the handler to get some information or perform some operations on the connection where the event happened. The second argument is the event object, which describes the event itself. For example, a channel message or someone joining a channel might trigger an event, which will be described by the event object. Information can be retrieved from these objects by calling methods. You may notice a few of the available methods in the previous source code. Others can be found in more complete example programs (one comes with the Net::IRC module source). After writing the handler, you have to tell Net::IRC to use it. And, of course, when to use it. To get a list of all possible events, see the documentation (perldoc Net::IRC::Event). As you can see in the code, you also may specify a numeric event. This number is an IRC status reply code. A list of valid reply codes can be found in the IRC RFC (RFC 2813, http://www.faqs.org/rfcs/rfc2813.html). The numbers used here are the "No MOTD here" and "End of MOTD" codes. Most (if not all) IRC servers try to send the MOTD (message of the day) as soon as the user is connected, so it's a good idea to send the JOIN commands as soon as the MOTD is sent. In case you were wondering, dbmopen() ties a Perl hash to a database file. This means that everything you store in the %info hash will be saved in that file. And of course, if a database already exists, all the information in there will suddenly appear in the %info hash. This means you can restart the bot without it forgetting the things it just learned. Regular expressions are used in the message handler to work out whether someone is asking a question or if they are saying a new fact that the bot can learn. If you are interested in extending this bot, you can get more information about Perl regular expressions by typing perldoc perlre on the command line. 5.4.3 Running the HackYou can run the bot by entering: % perl infobot.pl 5.4.4 The ResultsWhen the bot connects to your server and joins your channel, you can begin feeding it with facts. Unless you change the preceding source code, the bot will be called InfoBot_pl: -!- InfoBot_pl [~wilmer@jona.ipv6.gaast.net] has joined #irc_hacks <lintux> Perl? <InfoBot_pl> lintux: Perl == Cool <lintux> Perl = Cool, but sometimes hard to read <InfoBot_pl> lintux: OK <lintux> Perl? <InfoBot_pl> lintux: Perl == Cool, but sometimes hard to read <lintux> IRC Hacks? <InfoBot_pl> lintux: IRC Hacks == A very cool book from O'Reilly <lintux> Is there anything else you can tell me? As you see, the bot didn't answer the last question, because it didn't have an answer. You might wonder why it doesn't say, "Hey, I don't know that." The reason for this is quite simple—you don't want your bot to start talking every time someone asks a question. Good bots talk only when they're asked something. It's often a good idea to remember this when you're writing your own bots, otherwise you may kick off some nasty debates. As a matter of fact, the bot shown here might also be regarded as a bit too trigger-happy. But since it's just a proof of concept, let's not worry about that. This should be enough to get you started. If you want to learn more, you can look at some other (more complete) examples. There's a nice sample bot inside the Net::IRC tarball. If you want more, try to find more examples by searching for "Net::IRC bot" on Google. I also recommend you to take a look at Pink, at http://www.lintux.cx/~lintux/pink.html, which is quite a versatile bot, written using the Net::IRC module. Unfortunately, some parts of the source may be hard to understand for people who don't read Dutch. —Wilmer van der Gaast |
< Day Day Up > |