Net::IRC - DEAD SINCE 2004 Perl interface to the Internet Relay Chat protocol


Net-IRC documentation Contained in the Net-IRC distribution.

Index


Code Index:

NAME

Top

Net::IRC - DEAD SINCE 2004 Perl interface to the Internet Relay Chat protocol

USE THESE INSTEAD

Top

This module has been abandoned and is no longer developed. This release serves only to warn current and future users about this and to direct them to supported and actively-developed libraries for connecting Perl to IRC. Most new users will want to use Bot::BasicBot, whereas more advanced users will appreciate the flexibility offered by POE::Component::IRC. We understand that porting code to a new framework can be difficult. Please stop by #perl on irc.freenode.net and we'll be happy to help you out with bringing your bots into the modern era.

SYNOPSIS

Top

    use Net::IRC;

    $irc = new Net::IRC;
    $conn = $irc->newconn(Nick    => 'some_nick',
                          Server  => 'some.irc.server.com',
	                  Port    =>  6667,
			  Ircname => 'Some witty comment.');
    $irc->start;

DESCRIPTION

Top

This module has been abandoned and deprecated since 2004. The original authors have moved onto POE::Component::IRC and more modern techniques. This distribution is not maintained and only uploaded to present successively louder "don't use this" warnings to those unaware.

Welcome to Net::IRC, a work in progress. First intended to be a quick tool for writing an IRC script in Perl, Net::IRC has grown into a comprehensive Perl implementation of the IRC protocol (RFC 1459), developed by several members of the EFnet IRC channel #perl, and maintained in channel #net-irc.

There are 4 component modules which make up Net::IRC:

The central concept that Net::IRC is built around is that of handlers (or hooks, or callbacks, or whatever the heck you feel like calling them). We tried to make it a completely event-driven model, a la Tk -- for every conceivable type of event that your client might see on IRC, you can give your program a custom subroutine to call. But wait, there's more! There are 3 levels of handler precedence:

And even better, you can choose to call your custom handlers before or after the default handlers instead of replacing them, if you wish. In short, it's not perfect, but it's about as good as you can get and still be documentable, given the sometimes horrendous complexity of the IRC protocol.

GETTING STARTED

Top

Initialization

To start a Net::IRC script, you need two things: a Net::IRC object, and a Net::IRC::Connection object. The Connection object does the dirty work of connecting to the server; the IRC object handles the input and output for it. To that end, say something like this:

    use Net::IRC;

    $irc = new Net::IRC;

    $conn = $irc->newconn(Nick    => 'some_nick',
                          Server  => 'some.irc.server.com');

...or something similar. Acceptable parameters to newconn() are:

Handlers

Once that's over and done with, you need to set up some handlers if you want your bot to do anything more than sit on a connection and waste resources. Handlers are references to subroutines which get called when a specific event occurs. Here's a sample handler sub:

    # What to do when the bot successfully connects.
    sub on_connect {
        my $self = shift;

        print "Joining #IRC.pm...";
        $self->join("#IRC.pm");
        $self->privmsg("#IRC.pm", "Hi there.");
    }

The arguments to a handler function are always the same:

$_[0]:

The Connection object that's calling it.

$_[1]:

An Event object (see below) that describes what the handler is responding to.

Got it? If not, see the examples in the irctest script that came with this distribution. Anyhow, once you've defined your handler subroutines, you need to add them to the list of handlers as either a global handler (affects all Connection objects) or a local handler (affects only a single Connection). To do so, say something along these lines:

    $self->add_global_handler('376', \&on_connect);     # global
    $self->add_handler('msg', \&on_msg);                # local

376, incidentally, is the server number for "end of MOTD", which is an event that the server sends to you after you're connected. See Event.pm for a list of all possible numeric codes. The 'msg' event gets called whenever someone else on IRC sends your client a private message. For a big list of possible events, see the Event List section in the documentation for Net::IRC::Event.

Getting Connected

When you've set up all your handlers, the following command will put your program in an infinite loop, grabbing input from all open connections and passing it off to the proper handlers:

    $irc->start;

Note that new connections can be added and old ones dropped from within your handlers even after you call this. Just don't expect any code below the call to start() to ever get executed.

If you're tying Net::IRC into another event-based module, such as perl/Tk, there's a nifty do_one_loop() method provided for your convenience. Calling $irc->do_one_loop() runs through the IRC.pm event loop once, hands all ready filehandles over to the appropriate handler subs, then returns control to your program.

METHOD DESCRIPTIONS

Top

This section contains only the methods in IRC.pm itself. Lists of the methods in Net::IRC::Connection, Net::IRC::Event, or Net::IRC::DCC are in their respective modules' documentation; just perldoc Net::IRC::Connection (or Event or DCC or whatever) to read them. Functions take no arguments unless otherwise specified in their description.

By the way, expect Net::IRC to use AutoLoader sometime in the future, once it becomes a little more stable.

AUTHORS

Top

URL

Top

Up-to-date source and information about the Net::IRC project can be found at http://www.sourceforge.net/projects/net-irc/ .

SEE ALSO

Top


Net-IRC documentation Contained in the Net-IRC distribution.

#####################################################################
#                                                                   #
#   Net::IRC -- Object-oriented Perl interface to an IRC server     #
#                                                                   #
#   IRC.pm: A nifty little wrapper that makes your life easier.     #
#                                                                   #
#          Copyright (c) 1997 Greg Bacon & Dennis Taylor.           #
#                       All rights reserved.                        #
#                                                                   #
#      This module is free software; you can redistribute or        #
#      modify it under the terms of Perl's Artistic License.        #
#                                                                   #
#####################################################################
# $Id: IRC.pm,v 1.10 2004/04/30 18:02:51 jmuhlich Exp $


package Net::IRC;

BEGIN { require 5.004; }    # needs IO::* and $coderef->(@args) syntax 

use Net::IRC::Connection;
use Net::IRC::EventQueue;
use IO::Select;
use Carp;


# grab the drop-in replacement for time() from Time::HiRes, if it's available
BEGIN {
   Time::HiRes->import('time') if eval "require Time::HiRes";
}


use strict;
use vars qw($VERSION);

$VERSION = "0.79";

sub new {
  my $proto = shift;
  
  my $self = {
    '_conn'             => [],
    '_connhash'         => {},
    '_error'            => IO::Select->new(),
    '_debug'            => 0,
    '_schedulequeue'    => new Net::IRC::EventQueue(),
    '_outputqueue'      => new Net::IRC::EventQueue(),
    '_read'             => IO::Select->new(),
    '_timeout'          => 1,
    '_write'            => IO::Select->new(),
  };
  
  bless $self, $proto;
  
  return $self;
}

sub outputqueue {
  my $self = shift;
  return $self->{_outputqueue};
}

sub schedulequeue {
  my $self = shift;
  return $self->{_schedulequeue};
}

# Front end to addfh(), below. Sets it to read by default.
# Takes at least 1 arg:  an object to add to the select loop.
#           (optional)   a flag string to pass to addfh() (see below)
sub addconn {
  my ($self, $conn) = @_;
  
  $self->addfh( $conn->socket, $conn->can('parse'), ($_[2] || 'r'), $conn);
}

# Adds a filehandle to the select loop. Tasty and flavorful.
# Takes 3 args:  a filehandle or socket to add
#                a coderef (can be undef) to pass the ready filehandle to for
#                  user-specified reading/writing/error handling.
#    (optional)  a string with r/w/e flags, similar to C's fopen() syntax,
#                  except that you can combine flags (i.e., "rw").
#    (optional)  an object that the coderef is a method of
sub addfh {
  my ($self, $fh, $code, $flag, $obj) = @_;
  my ($letter);
  
  die "Not enough arguments to IRC->addfh()" unless defined $code;
  
  if ($flag) {
    foreach $letter (split(//, lc $flag)) {
      if ($letter eq 'r') {
        $self->{_read}->add( $fh );
      } elsif ($letter eq 'w') {
        $self->{_write}->add( $fh );
      } elsif ($letter eq 'e') {
        $self->{_error}->add( $fh );
      }
    }
  } else {
    $self->{_read}->add( $fh );
  }
  
  $self->{_connhash}->{$fh} = [ $code, $obj ];
}

# Sets or returns the debugging flag for this object.
# Takes 1 optional arg: a new boolean value for the flag.
sub debug {
  my $self = shift;
  
  if (@_) {
    $self->{_debug} = $_[0];
  }
  return $self->{_debug};
}

# Goes through one iteration of the main event loop. Useful for integrating
# other event-based systems (Tk, etc.) with Net::IRC.
# Takes no args.
sub do_one_loop {
  my $self = shift;
  my ($ev, $sock, $time, $nexttimer, $timeout);
  my (undef, undef, undef, $caller) = caller(1);

  $time = time();             # no use calling time() all the time.

  if(!$self->outputqueue->is_empty) {
    my $outputevent = undef;
    while(defined($outputevent = $self->outputqueue->head)
          && $outputevent->time <= $time) {
      $outputevent = $self->outputqueue->dequeue();
      $outputevent->content->{coderef}->(@{$outputevent->content->{args}});
    }
    $nexttimer = $self->outputqueue->head->time if !$self->outputqueue->is_empty();
  }

  # we don't want to bother waiting on input or running
  # scheduled events if we're just flushing the output queue
  # so we bail out here
  return if $caller eq 'Net::IRC::flush_output_queue';

  # Check the queue for scheduled events to run.
  if(!$self->schedulequeue->is_empty) {
    my $scheduledevent = undef;
    while(defined($scheduledevent = $self->schedulequeue->head) && $scheduledevent->time <= $time) {
      $scheduledevent = $self->schedulequeue->dequeue();
      $scheduledevent->content->{coderef}->(@{$scheduledevent->content->{args}});
    }
    if(!$self->schedulequeue->is_empty()
       && $nexttimer
       && $self->schedulequeue->head->time < $nexttimer) {
      $nexttimer = $self->schedulequeue->head->time;
    }
  }

  # Block until input arrives, then hand the filehandle over to the
  # user-supplied coderef. Look! It's a freezer full of government cheese!
  
  if ($nexttimer) {
    $timeout = $nexttimer - $time < $self->{_timeout}
    ? $nexttimer - $time : $self->{_timeout};
  } else {
    $timeout = $self->{_timeout};
  }
  foreach $ev (IO::Select->select($self->{_read},
                                  $self->{_write},
                                  $self->{_error},
                                  $timeout)) {
    foreach $sock (@{$ev}) {
      my $conn = $self->{_connhash}->{$sock};
      $conn or next;
    
      # $conn->[0] is a code reference to a handler sub.
      # $conn->[1] is optionally an object which the
      #    handler sub may be a method of.
      
      $conn->[0]->($conn->[1] ? ($conn->[1], $sock) : $sock);
    }
  }
}

sub flush_output_queue {
  my $self = shift;

  while(!$self->outputqueue->is_empty()) {
    $self->do_one_loop();
  }
}

# Creates and returns a new Connection object.
# Any args here get passed to Connection->connect().
sub newconn {
  my $self = shift;
  my $conn = Net::IRC::Connection->new($self, @_);
  
  return if $conn->error;
  return $conn;
}

# Takes the args passed to it by Connection->schedule()... see it for details.
sub enqueue_scheduled_event {
  my $self = shift;
  my $time = shift;
  my $coderef = shift;
  my @args = @_;

  return $self->schedulequeue->enqueue($time, { coderef => $coderef, args => \@args });
}

# Takes a scheduled event ID to remove from the queue.
# Returns the deleted coderef, if you actually care.
sub dequeue_scheduled_event {
  my ($self, $id) = @_;
  $self->schedulequeue->dequeue($id);
}

# Takes the args passed to it by Connection->schedule()... see it for details.
sub enqueue_output_event {
  my $self = shift;
  my $time = shift;
  my $coderef = shift;
  my @args = @_;

  return $self->outputqueue->enqueue($time, { coderef => $coderef, args => \@args });
}

# Takes a scheduled event ID to remove from the queue.
# Returns the deleted coderef, if you actually care.
sub dequeue_output_event {
  my ($self, $id) = @_;
  $self->outputqueue->dequeue($id);
}

# Front-end for removefh(), below.
# Takes 1 arg:  a Connection (or DCC or whatever) to remove.
sub removeconn {
  my ($self, $conn) = @_;
  
  $self->removefh( $conn->socket );
}

# Given a filehandle, removes it from all select lists. You get the picture.
sub removefh {
  my ($self, $fh) = @_;
  
  $self->{_read}->remove( $fh );
  $self->{_write}->remove( $fh );
  $self->{_error}->remove( $fh );
  delete $self->{_connhash}->{$fh};
}

# Begin the main loop. Wheee. Hope you remembered to set up your handlers
# first... (takes no args, of course)
sub start {
  my $self = shift;
  
  while (1) {
    $self->do_one_loop();
  }
}

# Sets or returns the current timeout, in seconds, for the select loop.
# Takes 1 optional arg:  the new value for the timeout, in seconds.
# Fractional timeout values are just fine, as per the core select().
sub timeout {
  my $self = shift;
  
  if (@_) { $self->{_timeout} = $_[0] }
  return $self->{_timeout};
}

1;


__END__