diff --git a/Core/Config.pm b/Core/Config.pm
index 29afe2751169755a56918ca1ec8c8ac7f88db206..4b9255e35cf425a04fd4f1cf51d5015b8d3fcb4d 100644
--- a/Core/Config.pm
+++ b/Core/Config.pm
@@ -23,14 +23,14 @@ our $logs_dir = "./Logs/";
 
 # Configuration des options de connexion (serveur, login) :
 our $server = 'irc.iiens.net';
-our $port   = 6667;
+our $port   = 7000;
 our $nick   = 'Bot';
 our $passwd = '';
 
 # Informations concernant le Bot :
-our $username = $nick; # En un seul mot...
+our $username = "Net::IRC.Bot"; # En un seul mot...
 our $ircname  = $nick.' by TC';
-our $version  = '0.1.1';
+our $version  = '0.1.2';
 
 # Channel sur lequel on veut que le Bot aille dès la connexion :
 our $channel  = '#dynamiite_test';
diff --git a/Core/Hook.pm b/Core/Hook.pm
index d48ea14a49eb892abfb0cbc520c9075765dc3ccc..62493d845a8b8ca1fe8bb7a22a117c8a99a12aca 100644
--- a/Core/Hook.pm
+++ b/Core/Hook.pm
@@ -43,6 +43,7 @@ our $conn = $irc->newconn(
 						  'Nick'        => $Config::nick,
 						  'Ircname'     => $Config::ircname,
 						  'Username'    => $Config::username,
+						  'SSL'         => 1,
 						  ) 
 						  or 
 						  die $nom_prog.": Can't connect to IRC server.\n";
diff --git a/Modules/Chans.pm b/Modules/Chans.pm
index 49370a12f0c7fa1fbb736a4691a6a99a17db0536..e9fef5325b84e1dd3efb857b259069f0fe4b4fb3 100644
--- a/Modules/Chans.pm
+++ b/Modules/Chans.pm
@@ -62,6 +62,7 @@ sub chan_add
 {
 	my ($chan, $mode) = @_;
 	
+	return 0 if($chan !~ /^#/);
 	$chans{$chan} = defined($mode) ? $mode : "pas op";
 	return 1;
 } # Fin chan_add
diff --git a/Net/IRC.pm b/Net/IRC.pm
new file mode 100755
index 0000000000000000000000000000000000000000..1ead0824259bb5155d4045383231b9d462ffdb4b
--- /dev/null
+++ b/Net/IRC.pm
@@ -0,0 +1,748 @@
+#####################################################################
+#                                                                   #
+#   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.9 2003/09/29 00:02:45 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;
+
+# all this junk below just to conditionally load a module
+# sometimes even perl is braindead...
+eval 'use Time::HiRes qw(time)';
+if(!$@) {
+  sub time ();
+  use subs 'time';
+  require Time::HiRes;
+  Time::HiRes->import('time');
+}
+
+
+use strict;
+use vars qw($VERSION);
+
+$VERSION = "0.75";
+
+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__
+
+
+=head1 NAME
+
+Net::IRC - Perl interface to the Internet Relay Chat protocol
+
+=head1 SYNOPSIS
+
+    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;
+
+=head1 DESCRIPTION
+
+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:
+
+=over
+
+=item *
+
+Net::IRC
+
+The wrapper for everything else, containing methods to generate
+Connection objects (see below) and a connection manager which does an event
+loop on all available filehandles. Sockets or files which are readable (or
+writable, or whatever you want it to select() for) get passed to user-supplied
+handler subroutines in other packages or in user code.
+
+=item *
+
+Net::IRC::Connection
+
+The big time sink on this project. Each Connection instance is a
+single connection to an IRC server. The module itself contains methods for
+every single IRC command available to users (Net::IRC isn't designed for
+writing servers, for obvious reasons), methods to set, retrieve, and call
+handler functions which the user can set (more on this later), and too many
+cute comments. Hey, what can I say, we were bored.
+
+=item *
+
+Net::IRC::Event
+
+Kind of a struct-like object for storing info about things that the
+IRC server tells you (server responses, channel talk, joins and parts, et
+cetera). It records who initiated the event, who it affects, the event
+type, and any other arguments provided for that event. Incidentally, the
+only argument passed to a handler function.
+
+=item *
+
+Net::IRC::DCC
+
+The analogous object to Connection.pm for connecting, sending and
+retrieving with the DCC protocol. Instances of DCC.pm are invoked from
+C<Connection-E<gt>new_{send,get,chat}> in the same way that
+C<IRC-E<gt>newconn> invokes C<Connection-E<gt>new>. This will make more
+sense later, we promise.
+
+=back
+
+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:
+
+=over
+
+=item *
+
+Default handlers
+
+Considering that they're hardwired into Net::IRC, these won't do
+much more than the bare minimum needed to keep the client listening on the
+server, with an option to print (nicely formatted, of course) what it hears
+to whatever filehandles you specify (STDOUT by default). These get called
+only when the user hasn't defined any of his own handlers for this event.
+
+=item *
+
+User-definable global handlers
+
+The user can set up his own subroutines to replace the default
+actions for I<every> IRC connection managed by your program. These only get
+invoked if the user hasn't set up a per-connection handler for the same
+event.
+
+=item *
+
+User-definable per-connection handlers
+
+Simple: this tells a single connection what to do if it gets an event of
+this type. Supersedes global handlers if any are defined for this event.
+
+=back
+
+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.
+
+
+=head1 GETTING STARTED
+
+=head2 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:
+
+=over
+
+=item *
+
+Nick
+
+The nickname you'll be known by on IRC, often limited to a maximum of 9
+letters. Acceptable characters for a nickname are C<[\w{}[]\`^|-]>. If
+you don't specify a nick, it defaults to your username.
+
+=item *
+
+Server
+
+The IRC server to connect to. There are dozens of them across several
+widely-used IRC networks, but the oldest and most popular is EFNet (Eris
+Free Net), home to #perl. See http://www.irchelp.org/ for lists of
+popular servers, or ask a friend.
+
+=item *
+
+Port
+
+The port to connect to this server on. By custom, the default is 6667.
+
+=item *
+
+Username
+
+On systems not running identd, you can set the username for your user@host
+to anything you wish. Note that some IRC servers won't allow connections from
+clients which don't run identd.
+
+=item *
+
+Ircname
+
+A short (maybe 60 or so chars) piece of text, originally intended to display
+your real name, which people often use for pithy quotes and URLs. Defaults to
+the contents of your GECOS field.
+
+=item *
+
+Password
+
+If the IRC server you're trying to write a bot for is
+password-protected, no problem. Just say "C<Password => 'foo'>" and
+you're set.
+
+=item *
+
+SSL
+
+If you wish to connect to an irc server which is using SSL, set this to a
+true value.  Ie: "C<SSL => 1>".
+    
+=back
+
+=head2 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:
+
+=over
+
+=item $_[0]:
+
+The Connection object that's calling it.
+
+=item $_[1]:
+
+An Event object (see below) that describes what the handler is responding to.
+
+=back
+
+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 B<Event List> section in the documentation for
+Net::IRC::Event.
+
+=head2 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 C<start()> to ever get executed.
+
+If you're tying Net::IRC into another event-based module, such as perl/Tk,
+there's a nifty C<do_one_loop()> method provided for your convenience. Calling
+C<$irc-E<gt>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.
+
+=head1 METHOD DESCRIPTIONS
+
+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 C<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.
+
+=over
+
+=item *
+
+addconn()
+
+Adds the specified object's socket to the select loop in C<do_one_loop()>.
+This is mostly for the use of Connection and DCC objects (and for pre-0.5
+compatibility)... for most (read: all) purposes, you can just use C<addfh()>,
+described below.
+
+Takes at least 1 arg:
+
+=over
+
+=item 0.
+
+An object whose socket needs to be added to the select loop
+
+=item 1.
+
+B<Optional:> A string consisting of one or more of the letters r, w, and e.
+Passed directly to C<addfh()>... see the description below for more info.
+
+=back
+
+=item *
+
+addfh()
+
+This sub takes a user's socket or filehandle and a sub to handle it with and
+merges it into C<do_one_loop()>'s list of select()able filehandles. This makes
+integration with other event-based systems (Tk, for instance) a good deal
+easier than in previous releases.
+
+Takes at least 2 args:
+
+=over
+
+=item 0.
+
+A socket or filehandle to monitor
+
+=item 1.
+
+A reference to a subroutine. When C<select()> determines that the filehandle
+is ready, it passes the filehandle to this (presumably user-supplied) sub,
+where you can read from it, write to it, etc. as your script sees fit.
+
+=item 2.
+
+B<Optional:> A string containing any combination of the letters r, w or e
+(standing for read, write, and error, respectively) which determines what
+conditions you're expecting on that filehandle. For example, this line
+select()s $fh (a filehandle, of course) for both reading and writing:
+
+    $irc->addfh( $fh, \&callback, "rw" );
+
+=back
+
+=item *
+
+do_one_loop()
+
+C<select()>s on all open filehandles and passes any ready ones to the
+appropriate handler subroutines. Also responsible for executing scheduled
+events from C<Net::IRC::Connection-E<gt>schedule()> on time.
+
+=item *
+
+new()
+
+A fairly vanilla constructor which creates and returns a new Net::IRC object.
+
+=item *
+
+newconn()
+
+Creates and returns a new Connection object. All arguments are passed straight
+to C<Net::IRC::Connection-E<gt>new()>; examples of common arguments can be
+found in the B<Synopsis> or B<Getting Started> sections.
+
+=item *
+
+removeconn()
+
+Removes the specified object's socket from C<do_one_loop()>'s list of
+select()able filehandles. This is mostly for the use of Connection and DCC
+objects (and for pre-0.5 compatibility)... for most (read: all) purposes,
+you can just use C<removefh()>, described below.
+
+Takes 1 arg:
+
+=over
+
+=item 0.
+
+An object whose socket or filehandle needs to be removed from the select loop
+
+=back
+
+=item *
+
+removefh()
+
+This method removes a given filehandle from C<do_one_loop()>'s list of
+selectable filehandles.
+
+Takes 1 arg:
+
+=over
+
+=item 0.
+
+A socket or filehandle to remove
+
+=back
+
+=item *
+
+start()
+
+Starts an infinite event loop which repeatedly calls C<do_one_loop()> to
+read new events from all open connections and pass them off to any
+applicable handlers.
+
+=item *
+
+timeout()
+
+Sets or returns the current C<select()> timeout for the main event loop, in
+seconds (fractional amounts allowed). See the documentation for the
+C<select()> function for more info.
+
+Takes 1 optional arg:
+
+=over
+
+=item 0.
+
+B<Optional:> A new value for the C<select()> timeout for this IRC object.
+
+=back
+
+=item *
+
+flush_output_queue()
+
+Flushes any waiting messages in the output queue if pacing is enabled. This
+method will not return until the output queue is empty.
+
+=over
+
+=back
+
+=head1 AUTHORS
+
+=over
+
+=item *
+
+Conceived and initially developed by Greg Bacon E<lt>gbacon@adtran.comE<gt>
+and Dennis Taylor E<lt>dennis@funkplanet.comE<gt>.
+
+=item *
+
+Ideas and large amounts of code donated by Nat "King" Torkington
+E<lt>gnat@frii.comE<gt>.
+
+=item *
+
+Currently being hacked on, hacked up, and worked over by the members of the
+Net::IRC developers mailing list. For details, see
+http://www.execpc.com/~corbeau/irc/list.html .
+
+=back
+
+=head1 URL
+
+Up-to-date source and information about the Net::IRC project can be found at
+http://www.sourceforge.net/projects/net-irc/ .
+
+=head1 SEE ALSO
+
+=over
+
+=item *
+
+perl(1).
+
+=item *
+
+RFC 1459: The Internet Relay Chat Protocol
+
+=item *
+
+http://www.irchelp.org/, home of fine IRC resources.
+
+=back
+
+=cut
+
+    
diff --git a/Net/IRC/Connection.pm b/Net/IRC/Connection.pm
new file mode 100755
index 0000000000000000000000000000000000000000..6245b94cd2fd439977cb56f2a48023660499cecc
--- /dev/null
+++ b/Net/IRC/Connection.pm
@@ -0,0 +1,1665 @@
+#####################################################################
+#                                                                   #
+#   Net::IRC -- Object-oriented Perl interface to an IRC server     #
+#                                                                   #
+#   Connection.pm: The basic functions for a simple IRC connection  #
+#                                                                   #
+#                                                                   #
+#    Copyright (c) 2001 Pete Sergeant, 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.        #
+#                                                                   #
+#####################################################################
+
+package Net::IRC::Connection;
+
+use Net::IRC::Event;
+use Net::IRC::DCC;
+use IO::Socket;
+use IO::Socket::INET;
+use Symbol;
+use Carp;
+
+# all this junk below just to conditionally load a module
+# sometimes even perl is braindead...
+
+eval 'use Time::HiRes qw(time)';
+if(!$@) {
+  sub time ();
+  use subs 'time';
+  require Time::HiRes;
+  Time::HiRes->import('time');
+}
+
+use strict;
+
+use vars (
+	'$AUTOLOAD',
+);
+
+
+# The names of the methods to be handled by &AUTOLOAD.
+my %autoloaded = ( 'ircname'  => undef,
+		   'port'     => undef,
+		   'username' => undef,
+		   'socket'   => undef,
+		   'verbose'  => undef,
+		   'parent'   => undef,
+                   'hostname' => undef,
+		   'pacing'   => undef,
+                   'ssl'      => undef,
+		 );
+
+# This hash will contain any global default handlers that the user specifies.
+
+my %_udef = ();
+
+# Creates a new IRC object and assigns some default attributes.
+sub new {
+  my $proto = shift;
+  
+  my $self = {                # obvious defaults go here, rest are user-set
+    _debug      => $_[0]->{_debug},
+    _port       => 6667,
+    # Evals are for non-UNIX machines, just to make sure.
+    _username   => eval { scalar getpwuid($>) } || $ENV{USER} || $ENV{LOGNAME} || "japh",
+    _ircname    => $ENV{IRCNAME} || eval { (getpwuid($>))[6] } || "Just Another Perl Hacker",
+    _nick       => $ENV{IRCNICK} || eval { scalar getpwuid($>) } || $ENV{USER} || $ENV{LOGNAME} || "WankerBot",
+    _ignore     => {},
+    _handler    => {},
+    _verbose    =>  0,       # Is this an OK default?
+    _parent     =>  shift,
+    _frag       =>  '',
+    _connected  =>  0,
+    _maxlinelen =>  510,     # The RFC says we shouldn't exceed this.
+    _lastsl     =>  0,
+    _pacing     =>  0,       # no pacing by default
+    _ssl	=>  0,       # no ssl by default
+    _format     => { 'default' => "[%f:%t]  %m  <%d>", },
+  };
+  
+  bless $self, $proto;
+  # do any necessary initialization here
+  $self->connect(@_) if @_;
+  
+  return $self;
+}
+
+# Takes care of the methods in %autoloaded
+# Sets specified attribute, or returns its value if called without args.
+sub AUTOLOAD {
+    my $self = @_;  ## can't modify @_ for goto &name
+    my $class = ref $self;  ## die here if !ref($self) ?
+    my $meth;
+
+    # -- #perl was here! --
+    #  <Teratogen> absolute power corrupts absolutely, but it's a helluva lot
+    #              of fun.
+    #  <Teratogen> =)
+    
+    ($meth = $AUTOLOAD) =~ s/^.*:://;  ## strip fully qualified portion
+
+    unless (exists $autoloaded{$meth}) {
+	croak "No method called \"$meth\" for $class object.";
+    }
+    
+    eval <<EOSub;
+sub $meth {
+    my \$self = shift;
+	
+    if (\@_) {
+	my \$old = \$self->{"_$meth"};
+	
+	\$self->{"_$meth"} = shift;
+	
+	return \$old;
+    }
+    else {
+	return \$self->{"_$meth"};
+    }
+}
+EOSub
+    
+    # no reason to play this game every time
+    goto &$meth;
+}
+
+# This sub is the common backend to add_handler and add_global_handler
+#
+sub _add_generic_handler {
+  my ($self, $event, $ref, $rp, $hash_ref, $real_name) = @_;
+  my $ev;
+  my %define = ( "replace" => 0, "before" => 1, "after" => 2 );
+  
+  unless (@_ >= 3) {
+    croak "Not enough arguments to $real_name()";
+  }
+  unless (ref($ref) eq 'CODE') {
+    croak "Second argument of $real_name isn't a coderef";
+  }
+  
+  # Translate REPLACE, BEFORE and AFTER.
+  if (not defined $rp) {
+    $rp = 0;
+  } elsif ($rp =~ /^\D/) {
+    $rp = $define{lc $rp} || 0;
+  }
+  
+  foreach $ev (ref $event eq "ARRAY" ? @{$event} : $event) {
+    # Translate numerics to names
+    if ($ev =~ /^\d/) {
+      $ev = Net::IRC::Event->trans($ev);
+      unless ($ev) {
+        carp "Unknown event type in $real_name: $ev";
+        return;
+      }
+    }
+    
+    $hash_ref->{lc $ev} = [ $ref, $rp ];
+  }
+  return 1;
+}
+
+# This sub will assign a user's custom function to a particular event which
+# might be received by any Connection object.
+# Takes 3 args:  the event to modify, as either a string or numeric code
+#                   If passed an arrayref, the array is assumed to contain
+#                   all event names which you want to set this handler for.
+#                a reference to the code to be executed for the event
+#    (optional)  A value indicating whether the user's code should replace
+#                the built-in handler, or be called with it. Possible values:
+#                   0 - Replace the built-in handlers entirely. (the default)
+#                   1 - Call this handler right before the default handler.
+#                   2 - Call this handler right after the default handler.
+# These can also be referred to by the #define-like strings in %define.
+sub add_global_handler {
+  my ($self, $event, $ref, $rp) = @_;
+  return $self->_add_generic_handler($event, $ref, $rp, \%_udef, 'add_global_handler');
+}
+
+# This sub will assign a user's custom function to a particular event which
+# this connection might receive.  Same args as above.
+sub add_handler {
+  my ($self, $event, $ref, $rp) = @_;
+  return $self->_add_generic_handler($event, $ref, $rp, $self->{_handler}, 'add_handler');
+}
+
+# Hooks every event we know about...
+sub add_default_handler {
+  my ($self, $ref, $rp) = @_;
+  foreach my $eventtype (keys(%Net::IRC::Event::_names)) {
+    $self->_add_generic_handler($eventtype, $ref, $rp, $self->{_handler}, 'add_default_handler');
+  }
+  return 1;
+}
+
+# Why do I even bother writing subs this simple? Sends an ADMIN command.
+# Takes 1 optional arg:  the name of the server you want to query.
+sub admin {
+  my $self = shift;        # Thank goodness for AutoLoader, huh?
+                           # Perhaps we'll finally use it soon.
+  
+  $self->sl("ADMIN" . ($_[0] ? " $_[0]" : ""));
+}
+
+# Toggles away-ness with the server.  Optionally takes an away message.
+sub away {
+    my $self = shift;
+    $self->sl("AWAY" . ($_[0] ? " :$_[0]" : ""));
+}
+
+# Attempts to connect to the specified IRC (server, port) with the specified
+#   (nick, username, ircname). Will close current connection if already open.
+sub connect {
+  my $self = shift;
+  my ($password, $sock);
+  
+  if (@_) {
+    my (%arg) = @_;
+    
+    $self->hostname($arg{'LocalAddr'}) if exists $arg{'LocalAddr'};
+    $password = $arg{'Password'} if exists $arg{'Password'};
+    $self->nick($arg{'Nick'}) if exists $arg{'Nick'};
+    $self->port($arg{'Port'}) if exists $arg{'Port'};
+    $self->server($arg{'Server'}) if exists $arg{'Server'};
+    $self->ircname($arg{'Ircname'}) if exists $arg{'Ircname'};
+    $self->username($arg{'Username'}) if exists $arg{'Username'};
+    $self->pacing($arg{'Pacing'}) if exists $arg{'Pacing'};
+    $self->ssl($arg{'SSL'}) if exists $arg{'SSL'};
+  }
+  
+  # Lots of error-checking claptrap first...
+  unless ($self->server) {
+    unless ($ENV{IRCSERVER}) {
+      croak "No server address specified in connect()";
+    }
+    $self->server( $ENV{IRCSERVER} );
+  }
+  unless ($self->nick) {
+    $self->nick($ENV{IRCNICK} || eval { scalar getpwuid($>) }
+                || $ENV{USER} || $ENV{LOGNAME} || "WankerBot");
+  }
+  unless ($self->port) {
+    $self->port($ENV{IRCPORT} || 6667);
+  }
+  unless ($self->ircname)  {
+    $self->ircname($ENV{IRCNAME} || eval { (getpwuid($>))[6] }
+                   || "Just Another Perl Hacker");
+  }
+  unless ($self->username) {
+    $self->username(eval { scalar getpwuid($>) } || $ENV{USER}
+                    || $ENV{LOGNAME} || "japh");
+  }
+  
+  # Now for the socket stuff...
+  if ($self->connected) {
+    $self->quit("Changing servers");
+  }
+  
+  if($self->ssl) {
+    require IO::Socket::SSL;
+    
+    $self->socket(IO::Socket::SSL->new(PeerAddr  => $self->server,
+                                       PeerPort  => $self->port,
+                                       Proto     => "tcp",
+                                       LocalAddr => $self->hostname,
+                                       ));
+  } else {
+    
+    $self->socket(IO::Socket::INET->new(PeerAddr  => $self->server,
+                                        PeerPort  => $self->port,
+                                        Proto     => "tcp",
+                                        LocalAddr => $self->hostname,
+                                        ));
+  }
+  
+  if(!$self->socket) {
+    carp (sprintf "Can't connect to %s:%s!",
+          $self->server, $self->port);
+    $self->error(1);
+    return;
+  }
+  
+  # Send a PASS command if they specified a password. According to
+  # the RFC, we should do this as soon as we connect.
+  if (defined $password) {
+    $self->sl("PASS $password");
+  }
+  
+  # Now, log in to the server...
+  unless ($self->sl('NICK ' . $self->nick()) and
+          $self->sl(sprintf("USER %s %s %s :%s",
+                            $self->username(),
+                            "foo.bar.com",
+                            $self->server(),
+                            $self->ircname()))) {
+    carp "Couldn't send introduction to server: $!";
+    $self->error(1);
+    $! = "Couldn't send NICK/USER introduction to " . $self->server;
+    return;
+  }
+  
+  $self->{_connected} = 1;
+  $self->parent->addconn($self);
+}
+
+# Returns a boolean value based on the state of the object's socket.
+sub connected {
+  my $self = shift;
+  
+  return ( $self->{_connected} and $self->socket() );
+}
+
+# Sends a CTCP request to some hapless victim(s).
+# Takes at least two args:  the type of CTCP request (case insensitive)
+#                           the nick or channel of the intended recipient(s)
+# Any further args are arguments to CLIENTINFO, ERRMSG, or ACTION.
+sub ctcp {
+  my ($self, $type, $target) = splice @_, 0, 3;
+  $type = uc $type;
+  
+  unless ($target) {
+    croak "Not enough arguments to ctcp()";
+  }
+  
+  if ($type eq "PING") {
+    unless ($self->sl("PRIVMSG $target :\001PING " . int(time) . "\001")) {
+      carp "Socket error sending $type request in ctcp()";
+      return;
+    }
+  } elsif (($type eq "CLIENTINFO" or $type eq "ACTION") and @_) {
+    unless ($self->sl("PRIVMSG $target :\001$type " .
+                      CORE::join(" ", @_) . "\001")) {
+      carp "Socket error sending $type request in ctcp()";
+      return;
+    }
+  } elsif ($type eq "ERRMSG") {
+    unless (@_) {
+      carp "Not enough arguments to $type in ctcp()";
+      return;
+    }
+    unless ($self->sl("PRIVMSG $target :\001ERRMSG " .
+                      CORE::join(" ", @_) . "\001")) {
+      carp "Socket error sending $type request in ctcp()";
+      return;
+    }
+  } else {
+    unless ($self->sl("PRIVMSG $target :\001$type " . 
+                      CORE::join(" ",@_) . "\001")) {
+      carp "Socket error sending $type request in ctcp()";
+      return;
+    }
+  }
+}
+
+# Sends replies to CTCP queries. Simple enough, right?
+# Takes 2 args:  the target person or channel to send a reply to
+#                the text of the reply
+sub ctcp_reply {
+  my $self = shift;
+  
+  $self->notice($_[0], "\001" . $_[1] . "\001");
+}
+
+
+# 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};
+}
+
+
+# Dequotes CTCP messages according to ctcp.spec. Nothing special.
+# Then it breaks them into their component parts in a flexible, ircII-
+# compatible manner. This is not quite as trivial. Oh, well.
+# Takes 1 arg:  the line to be dequoted.
+sub dequote {
+  my $line = shift;
+  my ($order, @chunks) = (0, ());    # CHUNG! CHUNG! CHUNG!
+  
+  # Filter misplaced \001s before processing... (Thanks, Tom!)
+  substr($line, rindex($line, "\001"), 1) = '\\a'
+      unless ($line =~ tr/\001//) % 2 == 0;
+  
+  # Thanks to Abigail (abigail@fnx.com) for this clever bit.
+  if (index($line, "\cP") >= 0) {    # dequote low-level \n, \r, ^P, and \0.
+    my (%h) = (n => "\012", r => "\015", 0 => "\0", "\cP" => "\cP");
+    $line =~ s/\cP([nr0\cP])/$h{$1}/g;
+  }
+  $line =~ s/\\([^\\a])/$1/g;  # dequote unnecessarily quoted characters.
+  
+  # If true, it's in odd order... ctcp commands start with first chunk.
+  $order = 1 if index($line, "\001") == 0;
+  @chunks = map { s/\\\\/\\/g; $_ } (split /\cA/, $line);
+  
+  return ($order, @chunks);
+}
+
+# Standard destructor method for the GC routines. (HAHAHAH! DIE! DIE! DIE!)
+sub DESTROY {
+  my $self = shift;
+  $self->handler("destroy", "nobody will ever use this");
+  $self->quit();
+  # anything else?
+}
+
+
+# Disconnects this Connection object cleanly from the server.
+# Takes at least 1 arg:  the format and args parameters to Event->new().
+sub disconnect {
+  my $self = shift;
+  
+  $self->{_connected} = 0;
+  $self->parent->removeconn($self);
+  $self->socket( undef );
+  $self->handler(Net::IRC::Event->new( "disconnect",
+                                       $self->server,
+                                       '',
+                                       @_  ));
+}
+
+
+# Tells IRC.pm if there was an error opening this connection. It's just
+# for sane error passing.
+# Takes 1 optional arg:  the new value for $self->{'iserror'}
+sub error {
+  my $self = shift;
+  
+  $self->{'iserror'} = $_[0] if @_;
+  return $self->{'iserror'};
+}
+
+# Lets the user set or retrieve a format for a message of any sort.
+# Takes at least 1 arg:  the event whose format you're inquiring about
+#           (optional)   the new format to use for this event
+sub format {
+  my ($self, $ev) = splice @_, 0, 2;
+  
+  unless ($ev) {
+    croak "Not enough arguments to format()";
+  }
+  
+  if (@_) {
+    $self->{'_format'}->{$ev} = $_[0];
+  } else {
+    return ($self->{'_format'}->{$ev} ||
+            $self->{'_format'}->{'default'});
+  }
+}
+
+# Calls the appropriate handler function for a specified event.
+# Takes 2 args:  the name of the event to handle
+#                the arguments to the handler function
+sub handler {
+  my ($self, $event) = splice @_, 0, 2;
+  
+  unless (defined $event) {
+    croak 'Too few arguments to Connection->handler()';
+  }
+  
+  # Get name of event.
+  my $ev;
+  if (ref $event) {
+    $ev = $event->type;
+  } elsif (defined $event) {
+    $ev = $event;
+    $event = Net::IRC::Event->new($event, '', '', '');
+  } else {
+    croak "Not enough arguments to handler()";
+  }
+  
+  print STDERR "Trying to handle event '$ev'.\n" if $self->{_debug};
+  
+  my $handler = undef;
+  if (exists $self->{_handler}->{$ev}) {
+    $handler = $self->{_handler}->{$ev};
+  } elsif (exists $_udef{$ev}) {
+    $handler = $_udef{$ev};
+  } else {
+    return $self->_default($event, @_);
+  }
+  
+  my ($code, $rp) = @{$handler};
+  
+  # If we have args left, try to call the handler.
+  if ($rp == 0) {                      # REPLACE
+    &$code($self, $event, @_);
+  } elsif ($rp == 1) {                 # BEFORE
+    &$code($self, $event, @_);
+    $self->_default($event, @_);
+  } elsif ($rp == 2) {                 # AFTER
+    $self->_default($event, @_);
+    &$code($self, $event, @_);
+  } else {
+    confess "Bad parameter passed to handler(): rp=$rp";
+  }
+  
+  warn "Handler for '$ev' called.\n" if $self->{_debug};
+  
+  return 1;
+}
+
+# Lets a user set hostmasks to discard certain messages from, or (if called
+# with only 1 arg), show a list of currently ignored hostmasks of that type.
+# Takes 2 args:  type of ignore (public, msg, ctcp, etc)
+#    (optional)  [mask(s) to be added to list of specified type]
+sub ignore {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments to ignore()";
+  }
+  
+  if (@_ == 1) {
+    if (exists $self->{_ignore}->{$_[0]}) {
+      return @{ $self->{_ignore}->{$_[0]} };
+    } else {
+      return ();
+    }
+  } elsif (@_ > 1) {     # code defensively, remember...
+    my $type = shift;
+    
+    # I moved this part further down as an Obsessive Efficiency
+    # Initiative. It shouldn't be a problem if I do _parse right...
+    # ... but those are famous last words, eh?
+    unless (grep {$_ eq $type}
+            qw(public msg ctcp notice channel nick other all)) {	    
+      carp "$type isn't a valid type to ignore()";
+      return;
+    }
+    
+    if ( exists $self->{_ignore}->{$type} )  {
+      push @{$self->{_ignore}->{$type}}, @_;
+    } else  {
+      $self->{_ignore}->{$type} = [ @_ ];
+    }
+  }
+}
+
+
+# Yet Another Ridiculously Simple Sub. Sends an INFO command.
+# Takes 1 optional arg: the name of the server to query.
+sub info {
+  my $self = shift;
+  
+  $self->sl("INFO" . ($_[0] ? " $_[0]" : ""));
+}
+
+
+# Invites someone to an invite-only channel. Whoop.
+# Takes 2 args:  the nick of the person to invite
+#                the channel to invite them to.
+# I hate the syntax of this command... always seemed like a protocol flaw.
+sub invite {
+  my $self = shift;
+  
+  unless (@_ > 1) {
+    croak "Not enough arguments to invite()";
+  }
+  
+  $self->sl("INVITE $_[0] $_[1]");
+}
+
+# Checks if a particular nickname is in use.
+# Takes at least 1 arg:  nickname(s) to look up.
+sub ison {
+  my $self = shift;
+  
+  unless (@_) {
+    croak 'Not enough args to ison().';
+  }
+  
+  $self->sl("ISON " . CORE::join(" ", @_));
+}
+
+# Joins a channel on the current server if connected, eh?.
+# Corresponds to /JOIN command.
+# Takes 2 args:  name of channel to join
+#                optional channel password, for +k channels
+sub join {
+  my $self = shift;
+  
+  unless ( $self->connected ) {
+    carp "Can't join() -- not connected to a server";
+    return;
+  }
+  
+  unless (@_) {
+    croak "Not enough arguments to join()";
+  }
+  
+  return $self->sl("JOIN $_[0]" . ($_[1] ? " $_[1]" : ""));
+
+}
+
+# Takes at least 2 args:  the channel to kick the bastard from
+#                         the nick of the bastard in question
+#             (optional)  a parting comment to the departing bastard
+sub kick {
+  my $self = shift;
+  
+  unless (@_ > 1) {
+    croak "Not enough arguments to kick()";
+  }
+  return $self->sl("KICK $_[0] $_[1]" . ($_[2] ? " :$_[2]" : ""));
+}
+
+# Gets a list of all the servers that are linked to another visible server.
+# Takes 2 optional args:  it's a bitch to describe, and I'm too tired right
+#                         now, so read the RFC.
+sub links {
+  my ($self) = (shift, undef);
+  
+  $self->sl("LINKS" . (scalar(@_) ? " " . CORE::join(" ", @_[0,1]) : ""));
+}
+
+
+# Requests a list of channels on the server, or a quick snapshot of the current
+# channel (the server returns channel name, # of users, and topic for each).
+sub list {
+  my $self = shift;
+  
+  $self->sl("LIST " . CORE::join(",", @_));
+}
+
+# Sends a request for some server/user stats.
+# Takes 1 optional arg: the name of a server to request the info from.
+sub lusers {
+  my $self = shift;
+  
+  $self->sl("LUSERS" . ($_[0] ? " $_[0]" : ""));
+}
+
+# Gets and/or sets the max line length.  The value previous to the sub
+# call will be returned.
+# Takes 1 (optional) arg: the maximum line length (in bytes)
+sub maxlinelen {
+  my $self = shift;
+  
+  my $ret = $self->{_maxlinelen};
+  
+  $self->{_maxlinelen} = shift if @_;
+  
+  return $ret;
+}
+
+# Sends an action to the channel/nick you specify. It's truly amazing how
+# many IRCers have no idea that /me's are actually sent via CTCP.
+# Takes 2 args:  the channel or nick to bother with your witticism
+#                the action to send (e.g., "weed-whacks billn's hand off.")
+sub me {
+  my $self = shift;
+  
+  $self->ctcp("ACTION", $_[0], $_[1]);
+}
+
+# Change channel and user modes (this one is easy... the handler is a bitch.)
+# Takes at least 1 arg:  the target of the command (channel or nick)
+#             (optional)  the mode string (i.e., "-boo+i")
+#             (optional)  operands of the mode string (nicks, hostmasks, etc.)
+sub mode {
+  my $self = shift;
+  
+  unless (@_ >= 1) {
+    croak "Not enough arguments to mode()";
+  }
+  $self->sl("MODE $_[0] " . CORE::join(" ", @_[1..$#_]));
+}
+
+# Sends a MOTD command to a server.
+# Takes 1 optional arg:  the server to query (defaults to current server)
+sub motd {
+  my $self = shift;
+  
+  $self->sl("MOTD" . ($_[0] ? " $_[0]" : ""));
+}
+
+# Requests the list of users for a particular channel (or the entire net, if
+# you're a masochist).
+# Takes 1 or more optional args:  name(s) of channel(s) to list the users from.
+sub names {
+  my $self = shift;
+  
+  $self->sl("NAMES " . CORE::join(",", @_));
+  
+}   # Was this the easiest sub in the world, or what?
+
+# Creates and returns a DCC CHAT object, analogous to IRC.pm's newconn().
+# Takes at least 1 arg:   An Event object for the DCC CHAT request.
+#                    OR   A list or listref of args to be passed to new(),
+#                         consisting of:
+#                           - A boolean value indicating whether or not
+#                             you're initiating the CHAT connection.
+#                           - The nick of the chattee
+#                           - The address to connect to
+#                           - The port to connect on
+sub new_chat {
+  my $self = shift;
+  my ($init, $nick, $address, $port);
+  
+  if (ref($_[0]) =~ /Event/) {
+    # If it's from an Event object, we can't be initiating, right?
+    ($init, undef, undef, undef, $address, $port) = (0, $_[0]->args);
+    $nick = $_[0]->nick;
+    
+  } elsif (ref($_[0]) eq "ARRAY") {
+    ($init, $nick, $address, $port) = @{$_[0]};
+  } else {
+    ($init, $nick, $address, $port) = @_;
+  }
+  
+  Net::IRC::DCC::CHAT->new($self, $init, $nick, $address, $port);
+}
+
+# Creates and returns a DCC GET object, analogous to IRC.pm's newconn().
+# Takes at least 1 arg:   An Event object for the DCC SEND request.
+#                    OR   A list or listref of args to be passed to new(),
+#                         consisting of:
+#                           - The nick of the file's sender
+#                           - The name of the file to receive
+#                           - The address to connect to
+#                           - The port to connect on
+#                           - The size of the incoming file
+# For all of the above, an extra argument should be added at the end:
+#                         An open filehandle to save the incoming file into,
+#                         in globref, FileHandle, or IO::* form.
+# If you wish to do a DCC RESUME, specify the offset in bytes that you
+# want to start downloading from as the last argument.
+sub new_get {
+  my $self = shift;
+  my ($nick, $name, $address, $port, $size,  $offset, $handle);
+  
+  if (ref($_[0]) =~ /Event/) {
+    (undef, undef, $name, $address, $port, $size) = $_[0]->args;
+    $nick = $_[0]->nick;
+    $handle = $_[1] if defined $_[1];
+  } elsif (ref($_[0]) eq "ARRAY") {
+    ($nick, $name, $address, $port, $size) = @{$_[0]};
+    $handle = $_[1] if defined $_[1];
+  } else {
+    ($nick, $name, $address, $port, $size, $handle) = @_;
+  }
+  
+  unless (defined $handle and ref $handle and
+          (ref $handle eq "GLOB" or $handle->can('print')))
+  {
+    carp ("Filehandle argument to Connection->new_get() must be ".
+          "a glob reference or object");
+    return;                                # is this behavior OK?
+  }
+  
+  my $dcc = Net::IRC::DCC::GET->new( $self, $nick, $address, $port, $size,
+                                     $name, $handle, $offset );
+  
+  $self->parent->addconn($dcc) if $dcc;
+  return $dcc;
+}
+
+# Creates and returns a DCC SEND object, analogous to IRC.pm's newconn().
+# Takes at least 2 args:  The nickname of the person to send to
+#                         The name of the file to send
+#             (optional)  The blocksize for the connection (default 1k)
+sub new_send {
+  my $self = shift;
+  my ($nick, $filename, $blocksize);
+  
+  if (ref($_[0]) eq "ARRAY") {
+    ($nick, $filename, $blocksize) = @{$_[0]};
+  } else {
+    ($nick, $filename, $blocksize) = @_;
+  }
+  
+  Net::IRC::DCC::SEND->new($self, $nick, $filename, $blocksize);
+}
+
+# Selects nick for this object or returns currently set nick.
+# No default; must be set by user.
+# If changed while the object is already connected to a server, it will
+# automatically try to change nicks.
+# Takes 1 arg:  the nick. (I bet you could have figured that out...)
+sub nick {
+  my $self = shift;
+  
+  if (@_)  {
+    $self->{'_nick'} = shift;
+    if ($self->connected) {
+      return $self->sl("NICK " . $self->{'_nick'});
+    }
+  } else {
+    return $self->{'_nick'};
+  }
+}
+
+# Sends a notice to a channel or person.
+# Takes 2 args:  the target of the message (channel or nick)
+#                the text of the message to send
+# The message will be chunked if it is longer than the _maxlinelen 
+# attribute, but it doesn't try to protect against flooding.  If you
+# give it too much info, the IRC server will kick you off!
+sub notice {
+  my ($self, $to) = splice @_, 0, 2;
+  
+  unless (@_) {
+    croak "Not enough arguments to notice()";
+  }
+  
+  my ($buf, $length, $line) = (CORE::join("", @_), $self->{_maxlinelen});
+  
+  while(length($buf) > 0) {
+    ($line, $buf) = unpack("a$length a*", $buf);
+    $self->sl("NOTICE $to :$line");
+  }
+}
+
+# Makes you an IRCop, if you supply the right username and password.
+# Takes 2 args:  Operator's username
+#                Operator's password
+sub oper {
+  my $self = shift;
+  
+  unless (@_ > 1) {
+    croak "Not enough arguments to oper()";
+  }
+  
+  $self->sl("OPER $_[0] $_[1]");
+}
+
+# This function splits apart a raw server line into its component parts
+# (message, target, message type, CTCP data, etc...) and passes it to the
+# appropriate handler. Takes no args, really.
+sub parse {
+  my ($self) = shift;
+  my ($from, $type, $message, @stuff, $itype, $ev, @lines, $line);
+  
+  if (defined ($self->ssl ?
+               sysread($self->socket, $line, 10240) :
+               $self->socket->recv($line, 10240, 0))
+      and
+      (length($self->{_frag}) + length($line)) > 0)  {
+    # grab any remnant from the last go and split into lines
+    my $chunk = $self->{_frag} . $line;
+    @lines = split /\012/, $chunk;
+    
+    # if the last line was incomplete, pop it off the chunk and
+    # stick it back into the frag holder.
+    $self->{_frag} = (substr($chunk, -1) ne "\012" ? pop @lines : '');
+    
+  } else {	
+    # um, if we can read, i say we should read more than 0
+    # besides, recv isn't returning undef on closed
+    # sockets.  getting rid of this connection...
+    $self->disconnect('error', 'Connection reset by peer');
+    return;
+  }
+  
+ PARSELOOP: foreach $line (@lines) {
+   
+   # Clean the lint filter every 2 weeks...
+   $line =~ s/[\012\015]+$//;
+   next unless $line;
+   
+   print STDERR "<<< $line\n" if $self->{_debug};
+   
+   # Like the RFC says: "respond as quickly as possible..."
+   if ($line =~ /^PING/) {
+     $ev = (Net::IRC::Event->new( "ping",
+                                  $self->server,
+                                  $self->nick,
+                                  "serverping",   # FIXME?
+                                  substr($line, 5)
+                                  ));
+     
+     # Had to move this up front to avoid a particularly pernicious bug.
+   } elsif ($line =~ /^NOTICE/) {
+     $ev = Net::IRC::Event->new( "snotice",
+                                 $self->server,
+                                 '',
+                                 'server',
+                                 (split /:/, $line, 2)[1] );
+     
+     
+     # Spurious backslashes are for the benefit of cperl-mode.
+     # Assumption:  all non-numeric message types begin with a letter
+   } elsif ($line =~ /^:?
+            (?:[][}{\w\\\`^|\-]+?    # The nick (valid nickname chars)
+             !                       # The nick-username separator
+             .+?                     # The username
+             \@)?                    # Umm, duh...
+            \S+                      # The hostname
+            \s+                      # Space between mask and message type
+            [A-Za-z]                 # First char of message type
+            [^\s:]+?                 # The rest of the message type
+            /x)                      # That ought to do it for now...
+   {
+     $line = substr $line, 1 if $line =~ /^:/;
+     
+     # Patch submitted for v.0.72
+     # Fixes problems with IPv6 hostnames.
+     # ($from, $line) = split ":", $line, 2;
+     ($from, $line) = $line =~ /^(?:|)(\S+\s+[^:]+):?(.*)/;
+     
+     ($from, $type, @stuff) = split /\s+/, $from;
+     $type = lc $type;
+     # This should be fairly intuitive... (cperl-mode sucks, though)
+     
+     if (defined $line and index($line, "\001") >= 0) {
+       $itype = "ctcp";
+       unless ($type eq "notice") {
+         $type = (($stuff[0] =~ tr/\#\&//) ? "public" : "msg");
+       }
+     } elsif ($type eq "privmsg") {
+       $itype = $type = (($stuff[0] =~ tr/\#\&//) ? "public" : "msg");
+     } elsif ($type eq "notice") {
+       $itype = "notice";
+     } elsif ($type eq "join" or $type eq "part" or
+              $type eq "mode" or $type eq "topic" or
+              $type eq "kick") {
+       $itype = "channel";
+     } elsif ($type eq "nick") {
+       $itype = "nick";
+     } else {
+       $itype = "other";
+     }
+     
+     # This goes through the list of ignored addresses for this message
+     # type and drops out of the sub if it's from an ignored hostmask.
+     
+     study $from;
+     foreach ( $self->ignore($itype), $self->ignore("all") ) {
+       $_ = quotemeta; s/\\\*/.*/g;
+       next PARSELOOP if $from =~ /$_/i;
+     }
+     
+     # It used to look a lot worse. Here was the original version...
+     # the optimization above was proposed by Silmaril, for which I am
+     # eternally grateful. (Mine still looks cooler, though. :)
+     
+     # return if grep { $_ = join('.*', split(/\\\*/,
+     #                  quotemeta($_)));  /$from/ }
+     # ($self->ignore($type), $self->ignore("all"));
+     
+     # Add $line to @stuff for the handlers
+     push @stuff, $line if defined $line;
+     
+     # Now ship it off to the appropriate handler and forget about it.
+     if ( $itype eq "ctcp" ) {       # it's got CTCP in it!
+       $self->parse_ctcp($type, $from, $stuff[0], $line);
+       next;
+       
+     }  elsif ($type eq "public" or $type eq "msg"   or
+               $type eq "notice" or $type eq "mode"  or
+               $type eq "join"   or $type eq "part"  or
+               $type eq "topic"  or $type eq "invite" ) {
+       
+       $ev = Net::IRC::Event->new( $type,
+                                   $from,
+                                   shift(@stuff),
+                                   $type,
+                                   @stuff,
+                                   );
+     } elsif ($type eq "quit" or $type eq "nick") {
+       
+       $ev = Net::IRC::Event->new( $type,
+                                   $from,
+                                   $from,
+                                   $type,
+                                   @stuff,
+                                   );
+     } elsif ($type eq "kick") {
+       
+       $ev = Net::IRC::Event->new( $type,
+                                   $from,
+                                   $stuff[1],
+                                   $type,
+                                   @stuff[0,2..$#stuff],
+                                   );
+       
+     } elsif ($type eq "kill") {
+       $ev = Net::IRC::Event->new($type,
+                                  $from,
+                                  '',
+                                  $type,
+                                  $line);   # Ahh, what the hell.
+     } elsif ($type eq "wallops") {
+       $ev = Net::IRC::Event->new($type,
+                                  $from,
+                                  '',
+                                  $type,
+                                  $line);  
+     } else {
+       carp "Unknown event type: $type";
+     }
+   }
+   elsif ($line =~ /^:?       # Here's Ye Olde Numeric Handler!
+          \S+?                 # the servername (can't assume RFC hostname)
+          \s+?                # Some spaces here...
+          \d+?                # The actual number
+          \b/x                # Some other crap, whatever...
+          ) {
+     $ev = $self->parse_num($line);
+     
+   } elsif ($line =~ /^:(\w+) MODE \1 /) {
+     $ev = Net::IRC::Event->new( 'umode',
+                                 $self->server,
+                                 $self->nick,
+                                 'server',
+                                 substr($line, index($line, ':', 1) + 1));
+     
+   } elsif ($line =~ /^:?       # Here's Ye Olde Server Notice handler!
+            .+?                 # the servername (can't assume RFC hostname)
+            \s+?                # Some spaces here...
+            NOTICE              # The server notice
+            \b/x                # Some other crap, whatever...
+            ) {
+     $ev = Net::IRC::Event->new( 'snotice',
+                                 $self->server,
+                                 '',
+                                 'server',
+                                 (split /\s+/, $line, 3)[2] );
+     
+     
+   } elsif ($line =~ /^ERROR/) {
+     if ($line =~ /^ERROR :Closing [Ll]ink/) {   # is this compatible?
+       
+       $ev = 'done';
+       $self->disconnect( 'error', ($line =~ /(.*)/) );
+       
+     } else {
+       $ev = Net::IRC::Event->new( "error",
+                                   $self->server,
+                                   '',
+                                   'error',
+                                   (split /:/, $line, 2)[1]);
+     }
+   } elsif ($line =~ /^Closing [Ll]ink/) {
+     $ev = 'done';
+     $self->disconnect( 'error', ($line =~ /(.*)/) );
+     
+   }
+   
+   if ($ev) {
+     
+     # We need to be able to fall through if the handler has
+     # already been called (i.e., from within disconnect()).
+     
+     $self->handler($ev) unless $ev eq 'done';
+     
+   } else {
+     # If it gets down to here, it's some exception I forgot about.
+     carp "Funky parse case: $line\n";
+   }
+ }
+}
+
+# The backend that parse() sends CTCP requests off to. Pay no attention
+# to the camel behind the curtain.
+# Takes 4 arguments:  the type of message
+#                     who it's from
+#                     the first bit of stuff
+#                     the line from the server.
+sub parse_ctcp {
+  my ($self, $type, $from, $stuff, $line) = @_;
+  
+  my ($one, $two);
+  my ($odd, @foo) = (&dequote($line));
+  
+  while (($one, $two) = (splice @foo, 0, 2)) {
+    
+    ($one, $two) = ($two, $one) if $odd;
+    
+    my ($ctype) = $one =~ /^(\w+)\b/;
+    my $prefix = undef;
+    if ($type eq 'notice') {
+      $prefix = 'cr';
+    } elsif ($type eq 'public' or
+             $type eq 'msg'   ) {
+      $prefix = 'c';
+    } else {
+      carp "Unknown CTCP type: $type";
+      return;
+    }
+    
+    if ($prefix) {
+      my $handler = $prefix . lc $ctype;   # unit. value prob with $ctype
+      
+      $one =~ s/^$ctype //i;  # strip the CTCP type off the args
+      $self->handler(Net::IRC::Event->new( $handler, $from, $stuff,
+                                           $handler, $one ));
+    }
+    
+    $self->handler(Net::IRC::Event->new($type, $from, $stuff, $type, $two))
+        if $two;
+  }
+  return 1;
+}
+
+# Does special-case parsing for numeric events. Separate from the rest of
+# parse() for clarity reasons (I can hear Tkil gasping in shock now. :-).
+# Takes 1 arg:  the raw server line
+sub parse_num {
+  my ($self, $line) = @_;
+
+  # Figlet protection?  This seems to be a bit closer to the RFC than
+  # the original version, which doesn't seem to handle :trailers quite
+  # correctly. 
+  
+  my ($from, $type, $stuff) = split(/\s+/, $line, 3);
+  my ($blip, $space, $other, @stuff);
+  while ($stuff) {
+    ($blip, $space, $other) = split(/(\s+)/, $stuff, 2);
+    $space = "" unless $space;
+    $other = "" unless $other;       # Thanks to jack velte...
+    if ($blip =~ /^:/) {
+      push @stuff, $blip . $space . $other;
+      last;
+    } else {
+      push @stuff, $blip;
+      $stuff = $other;
+    }
+  }
+  
+  $from = substr $from, 1 if $from =~ /^:/;
+  
+  return Net::IRC::Event->new( $type,
+                               $from,
+                               '',
+                               'server',
+                               @stuff );
+}
+
+# Helps you flee those hard-to-stand channels.
+# Takes at least one arg:  name(s) of channel(s) to leave.
+sub part {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "No arguments provided to part()";
+  }
+  $self->sl("PART " . CORE::join(",", @_));    # "A must!"
+}
+
+
+# Tells what's on the other end of a connection. Returns a 2-element list
+# consisting of the name on the other end and the type of connection.
+# Takes no args.
+sub peer {
+  my $self = shift;
+  
+  return ($self->server(), "IRC connection");
+}
+
+
+# Prints a message to the defined error filehandle(s).
+# No further description should be necessary.
+sub printerr {
+  shift;
+  print STDERR @_, "\n";
+}
+
+# Prints a message to the defined output filehandle(s).
+sub print {
+  shift;
+  print STDOUT @_, "\n";
+}
+
+# Sends a message to a channel or person.
+# Takes 2 args:  the target of the message (channel or nick)
+#                the text of the message to send
+# Don't use this for sending CTCPs... that's what the ctcp() function is for.
+# The message will be chunked if it is longer than the _maxlinelen 
+# attribute, but it doesn't try to protect against flooding.  If you
+# give it too much info, the IRC server will kick you off!
+sub privmsg {
+  my ($self, $to) = splice @_, 0, 2;
+  
+  unless (@_) {
+    croak 'Not enough arguments to privmsg()';
+  }
+  
+  my $buf = CORE::join '', @_;
+  my $length = $self->{_maxlinelen} - 11 - length($to);
+  my $line;
+  
+  if (ref($to) =~ /^(GLOB|IO::Socket)/) {
+    while(length($buf) > 0) {
+      ($line, $buf) = unpack("a$length a*", $buf);
+      send($to, $line . "\012", 0);
+    } 
+  } else {
+    while(length($buf) > 0) {
+      ($line, $buf) = unpack("a$length a*", $buf);
+      if (ref $to eq 'ARRAY') {
+        $self->sl("PRIVMSG ", CORE::join(',', @$to), " :$line");
+      } else {
+        $self->sl("PRIVMSG $to :$line");
+      }
+    }
+  }
+}
+
+
+# Closes connection to IRC server.  (Corresponding function for /QUIT)
+# Takes 1 optional arg:  parting message, defaults to "Leaving" by custom.
+sub quit {
+  my $self = shift;
+  
+  # Do any user-defined stuff before leaving
+  $self->handler("leaving");
+  
+  unless ( $self->connected ) {  return (1)  }
+  
+  # Why bother checking for sl() errors now, after all?  :)
+  # We just send the QUIT command and leave. The server will respond with
+  # a "Closing link" message, and parse() will catch it, close the
+  # connection, and throw a "disconnect" event. Neat, huh? :-)
+  
+  $self->sl("QUIT :" . (defined $_[0] ? $_[0] : "Leaving"));
+  
+  # since the quit sends a line to the server, we need to flush the
+  # output queue to make sure it gets there so the disconnect
+  $self->parent->flush_output_queue();
+  
+  return 1;
+}
+
+# As per the RFC, ask the server to "re-read and process its configuration
+# file."  Your server may or may not take additional arguments.  Generally
+# requires IRCop status.
+sub rehash {
+  my $self = shift;
+  $self->sl("REHASH" . CORE::join(" ", @_));
+}
+
+
+# As per the RFC, "force a server restart itself."  (Love that RFC.)  
+# Takes no arguments.  If it succeeds, you will likely be disconnected,
+# but I assume you already knew that.  This sub is too simple...
+sub restart {
+  my $self = shift;
+  $self->sl("RESTART");
+}
+
+# Schedules an event to be executed after some length of time.
+# Takes at least 2 args:  the number of seconds to wait until it's executed
+#                         a coderef to execute when time's up
+# Any extra args are passed as arguments to the user's coderef.
+sub schedule {
+  my $self = shift;
+  my $time = shift;
+  my $coderef = shift;
+
+  unless($coderef) {
+    croak 'Not enough arguments to Connection->schedule()';
+  }
+  unless(ref($coderef) eq 'CODE') {
+    croak 'Second argument to schedule() isn\'t a coderef';
+  }
+
+  $time += time;
+  $self->parent->enqueue_scheduled_event($time, $coderef, $self, @_);
+}
+
+sub schedule_output_event {
+  my $self = shift;
+  my $time = shift;
+  my $coderef = shift;
+
+  unless($coderef) {
+    croak 'Not enough arguments to Connection->schedule()';
+  }
+  unless(ref($coderef) eq 'CODE') {
+    croak 'Second argument to schedule() isn\'t a coderef';
+  }
+
+  $time += time;
+  $self->parent->enqueue_output_event($time, $coderef, $self, @_);
+}
+
+# Lets J. Random IRCop connect one IRC server to another. How uninteresting.
+# Takes at least 1 arg:  the name of the server to connect your server with
+#            (optional)  the port to connect them on (default 6667)
+#            (optional)  the server to connect to arg #1. Used mainly by
+#                          servers to communicate with each other.
+sub sconnect {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments to sconnect()";
+  }
+  $self->sl("CONNECT " . CORE::join(" ", @_));
+}
+
+# Sets/changes the IRC server which this instance should connect to.
+# Takes 1 arg:  the name of the server (see below for possible syntaxes)
+#                                       ((syntaxen? syntaxi? syntaces?))
+sub server {
+  my ($self) = shift;
+  
+  if (@_)  {
+    # cases like "irc.server.com:6668"
+    if (index($_[0], ':') > 0) {
+      my ($serv, $port) = split /:/, $_[0];
+      if ($port =~ /\D/) {
+        carp "$port is not a valid port number in server()";
+        return;
+      }
+      $self->{_server} = $serv;
+      $self->port($port);
+      
+      # cases like ":6668"  (buried treasure!)
+    } elsif (index($_[0], ':') == 0 and $_[0] =~ /^:(\d+)/) {
+      $self->port($1);
+      
+      # cases like "irc.server.com"
+    } else {
+      $self->{_server} = shift;
+    }
+    return (1);
+    
+  } else {
+    return $self->{_server};
+  }
+}
+
+
+# sends a raw IRC line to the server, possibly with pacing
+sub sl {
+  my $self = shift;
+  my $line = CORE::join '', @_;
+  
+  unless (@_) {
+    croak "Not enough arguments to sl()";
+  }
+  
+  if (! $self->pacing) {
+    return $self->sl_real($line);
+  }
+  
+  # calculate how long to wait before sending this line
+  my $time = time;
+  if ($time - $self->{_lastsl} > $self->pacing) {
+    $self->{_lastsl} = $time;
+  } else {
+    $self->{_lastsl} += $self->pacing;
+  }
+  my $seconds = $self->{_lastsl} - $time;
+  
+  ### DEBUG DEBUG DEBUG
+  if ($self->{_debug}) {
+    print "S-> $seconds $line\n";
+  }
+  
+  $self->schedule_output_event($seconds, \&sl_real, $line);
+}
+
+
+# Sends a raw IRC line to the server.
+# Corresponds to the internal sirc function of the same name.
+# Takes 1 arg:  string to send to server. (duh. :)
+sub sl_real {
+  my $self = shift;
+  my $line = shift;
+  
+  unless ($line) {
+    croak "Not enough arguments to sl_real()";
+  }
+  
+  ### DEBUG DEBUG DEBUG
+  if ($self->{_debug}) {
+    print ">>> $line\n";
+  }
+  
+  # RFC compliance can be kinda nice...
+  my $rv = $self->ssl ?
+      $self->socket->print("$line\015\012") :
+      $self->socket->send("$line\015\012", 0);
+  unless ($rv) {
+    $self->handler("sockerror");
+    return;
+  }
+  return $rv;
+}
+
+# Tells any server that you're an oper on to disconnect from the IRC network.
+# Takes at least 1 arg:  the name of the server to disconnect
+#            (optional)  a comment about why it was disconnected
+sub squit {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments to squit()";
+  }
+  
+  $self->sl("SQUIT $_[0]" . ($_[1] ? " :$_[1]" : ""));
+}
+
+# Gets various server statistics for the specified host.
+# Takes at least 2 arg: the type of stats to request [chiklmouy]
+#            (optional) the server to request from (default is current server)
+sub stats {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments passed to stats()";
+  }
+  
+  $self->sl("STATS $_[0]" . ($_[1] ? " $_[1]" : ""));
+}
+
+# If anyone still has SUMMON enabled, this will implement it for you.
+# If not, well...heh.  Sorry.  First arg mandatory: user to summon.  
+# Second arg optional: a server name.
+sub summon {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments passed to summon()";
+  }
+  
+  $self->sl("SUMMON $_[0]" . ($_[1] ? " $_[1]" : ""));
+}
+
+# Requests timestamp from specified server. Easy enough, right?
+# Takes 1 optional arg:  a server name/mask to query
+# renamed to not collide with things... -- aburke
+sub timestamp {
+  my ($self, $serv) = (shift, undef);
+  
+  $self->sl("TIME" . ($_[0] ? " $_[0]" : ""));
+}
+
+# Sends request for current topic, or changes it to something else lame.
+# Takes at least 1 arg:  the channel whose topic you want to screw around with
+#            (optional)  the new topic you want to impress everyone with
+sub topic {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments to topic()";
+  }
+  
+  # Can you tell I've been reading the Nethack source too much? :)
+  $self->sl("TOPIC $_[0]" . ($_[1] ? " :$_[1]" : ""));
+}
+
+# Sends a trace request to the server. Whoop.
+# Take 1 optional arg:  the server or nickname to trace.
+sub trace {
+  my $self = shift;
+  
+  $self->sl("TRACE" . ($_[0] ? " $_[0]" : ""));
+}
+
+# This method submitted by Dave Schmitt <dschmi1@umbc.edu>. Thanks, Dave!
+sub unignore {
+  my $self = shift;
+  
+  croak "Not enough arguments to unignore()" unless @_;
+  
+  if (@_ == 1) {
+    if (exists $self->{_ignore}->{$_[0]}) {
+      return @{ $self->{_ignore}->{$_[0]} };
+    } else {
+      return ();
+    }
+  } elsif (@_ > 1) {     # code defensively, remember...
+    my $type = shift;
+    
+    # I moved this part further down as an Obsessive Efficiency
+    # Initiative. It shouldn't be a problem if I do _parse right...
+    # ... but those are famous last words, eh?
+    unless (grep {$_ eq $type}
+            qw(public msg ctcp notice channel nick other all)) {
+      carp "$type isn't a valid type to unignore()";
+      return;                                                    
+       }
+    
+    if ( exists $self->{_ignore}->{$type} )  {
+      # removes all specifed entries ala _Perl_Cookbook_ recipe 4.7
+      my @temp = @{$self->{_ignore}->{$type}};
+      @{$self->{_ignore}->{$type}}= ();
+      my %seen = ();
+      foreach my $item (@_) { $seen{$item}=1 }
+      foreach my $item (@temp) {
+        push(@{$self->{_ignore}->{$type}}, $item)
+            unless ($seen{$item});
+      }
+    } else  {
+      carp "no ignore entry for $type to remove";
+    }
+  }
+}
+
+
+# Requests userhost info from the server.
+# Takes at least 1 arg: nickname(s) to look up.
+sub userhost {
+  my $self = shift;
+  
+  unless (@_) {
+    croak 'Not enough args to userhost().';
+  }
+  
+  $self->sl("USERHOST " . CORE::join (" ", @_));
+}
+
+# Sends a users request to the server, which may or may not listen to you.
+# Take 1 optional arg:  the server to query.
+sub users {
+  my $self = shift;
+  
+  $self->sl("USERS" . ($_[0] ? " $_[0]" : ""));
+}
+
+# Asks the IRC server what version and revision of ircd it's running. Whoop.
+# Takes 1 optional arg:  the server name/glob. (default is current server)
+sub version {
+  my $self = shift;
+  
+  $self->sl("VERSION" . ($_[0] ? " $_[0]" : ""));
+}
+
+# Sends a message to all opers on the network. Hypothetically.
+# Takes 1 arg:  the text to send.
+sub wallops {
+  my $self = shift;
+  
+  unless ($_[0]) {
+    croak 'No arguments passed to wallops()';
+  }
+  
+  $self->sl("WALLOPS :" . CORE::join("", @_));
+}
+
+# Asks the server about stuff, you know. Whatever. Pass the Fritos, dude.
+# Takes 2 optional args:  the bit of stuff to ask about
+#                         an "o" (nobody ever uses this...)
+sub who {
+  my $self = shift;
+  
+  # Obfuscation!
+  $self->sl("WHO" . (@_ ? " @_" : ""));
+}
+
+# If you've gotten this far, you probably already know what this does.
+# Takes at least 1 arg:  nickmasks or channels to /whois
+sub whois {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments to whois()";
+  }
+  return $self->sl("WHOIS " . CORE::join(",", @_));
+}
+
+# Same as above, in the past tense.
+# Takes at least 1 arg:  nick to do the /whowas on
+#            (optional)  max number of hits to display
+#            (optional)  server or servermask to query
+sub whowas {
+  my $self = shift;
+  
+  unless (@_) {
+    croak "Not enough arguments to whowas()";
+  }
+  return $self->sl("WHOWAS $_[0]" . ($_[1] ? " $_[1]" : "") .
+                   (($_[1] && $_[2]) ? " $_[2]" : ""));
+}
+
+# This sub executes the default action for an event with no user-defined
+# handlers. It's all in one sub so that we don't have to make a bunch of
+# separate anonymous subs stuffed in a hash.
+sub _default {
+  my ($self, $event) = @_;
+  my $verbose = $self->verbose;
+  
+  # Users should only see this if the programmer (me) fucked up.
+  unless ($event) {
+    croak "You EEEEEDIOT!!! Not enough args to _default()!";
+  }
+  
+  # Reply to PING from server as quickly as possible.
+  if ($event->type eq "ping") {
+    $self->sl("PONG " . (CORE::join ' ', $event->args));
+    
+  } elsif ($event->type eq "disconnect") {
+    
+    # I violate OO tenets. (It's consensual, of course.)
+    unless (keys %{$self->parent->{_connhash}} > 0) {
+      die "No active connections left, exiting...\n";
+    }
+  }
+  
+  return 1;
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Net::IRC::Connection - Object-oriented interface to a single IRC connection
+
+=head1 SYNOPSIS
+
+Hard hat area: This section under construction.
+
+=head1 DESCRIPTION
+
+This documentation is a subset of the main Net::IRC documentation. If
+you haven't already, please "perldoc Net::IRC" before continuing.
+
+Net::IRC::Connection defines a class whose instances are individual
+connections to a single IRC server. Several Net::IRC::Connection objects may
+be handled simultaneously by one Net::IRC object.
+
+=head1 METHOD DESCRIPTIONS
+
+This section is under construction, but hopefully will be finally written up
+by the next release. Please see the C<irctest> script and the source for
+details about this module.
+
+=head1 AUTHORS
+
+Conceived and initially developed by Greg Bacon E<lt>gbacon@adtran.comE<gt> and
+Dennis Taylor E<lt>dennis@funkplanet.comE<gt>.
+
+Ideas and large amounts of code donated by Nat "King" Torkington E<lt>gnat@frii.comE<gt>.
+
+Currently being hacked on, hacked up, and worked over by the members of the
+Net::IRC developers mailing list. For details, see
+http://www.execpc.com/~corbeau/irc/list.html .
+
+=head1 URL
+
+Up-to-date source and information about the Net::IRC project can be found at
+http://netirc.betterbox.net/ .
+
+=head1 SEE ALSO
+
+=over
+
+=item *
+
+perl(1).
+
+=item *
+
+RFC 1459: The Internet Relay Chat Protocol
+
+=item *
+
+http://www.irchelp.org/, home of fine IRC resources.
+
+=back
+
+=cut
+
diff --git a/Net/IRC/DCC.pm b/Net/IRC/DCC.pm
new file mode 100755
index 0000000000000000000000000000000000000000..eccbba327aeea3a1a07e4ae3c394506509c86033
--- /dev/null
+++ b/Net/IRC/DCC.pm
@@ -0,0 +1,808 @@
+#####################################################################
+#                                                                   #
+#   Net::IRC -- Object-oriented Perl interface to an IRC server     #
+#                                                                   #
+#   DCC.pm: An object for Direct Client-to-Client connections.      #
+#                                                                   #
+#          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: DCC.pm,v 1.1.1.1 2002/11/14 17:32:15 jmuhlich Exp $
+
+package Net::IRC::DCC;
+
+use strict;
+
+
+
+# --- #perl was here! ---
+#
+# The comments scattered throughout this module are excerpts from a
+# log saved from one particularly surreal night on #perl. Ahh, the
+# trials of being young, single, and drunk...
+#
+# ---------------------
+#           \merlyn has offered the shower to a randon guy he met in a bar.
+#  fimmtiu: Shower?
+#           \petey raises an eyebrow at \merlyn
+#  \merlyn: but he seems like a nice trucker guy...
+#   archon: you offered to shower with a random guy?
+
+
+# Methods that can be shared between the various DCC classes.
+package Net::IRC::DCC::Connection;
+
+use Carp;
+use Socket;  # need inet_ntoa...
+use strict;
+
+sub fixaddr {
+    my ($address) = @_;
+
+    chomp $address;     # just in case, sigh.
+    if ($address =~ /^\d+$/) {
+        return inet_ntoa(pack "N", $address);
+    } elsif ($address =~ /^[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}$/) {
+        return $address;
+    } elsif ($address =~ tr/a-zA-Z//) {                    # Whee! Obfuscation!
+        return inet_ntoa(((gethostbyname($address))[4])[0]);
+    } else {
+        return;
+    }
+}
+
+sub bytes_in {
+    return shift->{_bin};
+}
+
+sub bytes_out {
+    return shift->{_bout};
+}
+
+sub nick {
+    return shift->{_nick};
+}
+
+sub socket {
+    return shift->{_socket};
+}
+
+sub time {
+    return time - shift->{_time};
+}
+
+sub debug {
+    return shift->{_debug};
+}
+
+# Changes here 1998-04-01 by MJD
+# Optional third argument `$block'.
+# If true, don't break the input into lines... just process it in blocks.
+sub _getline {
+    my ($self, $sock, $block) = @_;
+    my ($input, $line);
+    my $frag = $self->{_frag};
+
+    if (defined $sock->recv($input, 10240)) {
+	$frag .= $input;
+	if (length($frag) > 0) {
+	    
+            warn "Got ". length($frag) ." bytes from $sock\n"
+                if $self->{_debug};
+            
+	    if ($block) {          # Block mode (GET)
+		return $input;
+		
+	    } else {               # Line mode (CHAT)
+		# We're returning \n's 'cause DCC's need 'em
+		my @lines = split /\012/, $frag, -1;
+		$lines[-1] .= "\012";
+		$self->{_frag} = ($frag !~ /\012$/) ? pop @lines : '';
+		return (@lines);
+	    }
+	}
+	else {
+	    # um, if we can read, i say we should read more than 0
+	    # besides, recv isn't returning undef on closed
+	    # sockets.  getting rid of this connection...
+	    
+            warn "recv() received 0 bytes in _getline, closing connection.\n"
+                if $self->{_debug};
+            
+	    $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+							   $self->{_nick},
+							   $self->{_socket},
+							   $self->{_type}));
+	    $self->{_parent}->parent->removefh($sock);
+	    $self->{_socket}->close;
+	    $self->{_fh}->close if $self->{_fh};
+	    return;
+	}
+    } else {
+	# Error, lets scrap this connection
+	
+        warn "recv() returned undef, socket error in _getline()\n"
+            if $self->{_debug};
+	
+        $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_parent}->parent->removefh($sock);
+	$self->{_socket}->close;
+	$self->{_fh}->close if $self->{_fh};
+	return;
+    }
+}
+
+sub DESTROY {
+    my $self = shift;
+    
+    # Only do the Disconnection Dance of Death if the socket is still
+    # live. Duplicate dcc_close events would be a Bad Thing.
+    
+    if ($self->{_socket}->opened) {
+	$self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_socket}->close;
+	close $self->{_fh} if $self->{_fh};
+	$self->{_parent}->{_parent}->parent->removeconn($self);
+    }
+    
+}
+
+sub peer {
+    return ( $_[0]->{_nick}, "DCC " . $_[0]->{_type} );
+}
+
+# -- #perl was here! --
+#     orev: hehe...
+# Silmaril: to, not with.
+#   archon: heheh
+# tmtowtdi: \merlyn will be hacked to death by a psycho
+#   archon: yeah, but with is much more amusing
+
+
+# Connection handling GETs
+package Net::IRC::DCC::GET;
+
+use IO::Socket;
+use Carp;
+use strict;
+
+@Net::IRC::DCC::GET::ISA = qw(Net::IRC::DCC::Connection);
+
+sub new {
+
+    my ($class, $container, $nick, $address,
+	$port, $size, $filename, $handle, $offset) = @_;
+    my ($sock, $fh);
+
+    # get the address into a dotted quad
+    $address = &Net::IRC::DCC::Connection::fixaddr($address);
+    return if $port < 1024 or not defined $address or $size < 1;
+
+    $fh = defined $handle ? $handle : IO::File->new(">$filename");
+
+    unless(defined $fh) {
+        carp "Can't open $filename for writing: $!";
+        $sock = new IO::Socket::INET( Proto    => "tcp",
+				      PeerAddr => "$address:$port" ) and
+        $sock->close();
+        return;
+    }
+
+    binmode $fh;                     # I love this next line. :-)
+    ref $fh eq 'GLOB' ? select((select($fh), $|++)[0]) : $fh->autoflush(1);
+    
+    $sock = new IO::Socket::INET( Proto    => "tcp",
+				  PeerAddr => "$address:$port" );
+
+    if (defined $sock) {
+	$container->handler(Net::IRC::Event->new('dcc_open',
+						 $nick,
+						 $sock,
+						 'get',
+						 'get', $sock));
+	
+    } else {
+        carp "Can't connect to $address: $!";
+        close $fh;
+        return;
+    }
+    
+    $sock->autoflush(1);
+
+    my $self = {
+	_bin        =>  defined $offset ? $offset : 0, # bytes recieved so far
+        _bout       =>  0,      # Bytes we've sent
+        _connected  =>  1,
+	_debug      =>  $container->debug,
+        _fh         =>  $fh,    # FileHandle we will be writing to.
+        _filename   =>  $filename,
+	_frag       =>  '',
+	_nick       =>  $nick,  # Nick of person on other end
+        _parent     =>  $container,
+        _size       =>  $size,  # Expected size of file
+        _socket     =>  $sock,  # Socket we're reading from
+        _time       =>  time, 
+	_type       =>  'GET',
+        };
+
+    bless $self, $class;
+
+    return $self;
+}
+
+# -- #perl was here! --
+#  \merlyn: we were both ogling a bartender named arley
+#  \merlyn: I mean carle
+#  \merlyn: carly
+# Silmaril: man merlyn
+# Silmaril: you should have offered HER the shower.
+#   \petey: all three of them?
+
+sub parse {
+    my ($self) = shift;
+
+    my $line = $self->_getline($_[0], 'BLOCKS');
+
+    next unless defined $line;
+    unless(print {$self->{_fh}} $line) {
+	carp ("Error writing to " . $self->{_filename} . ": $!");
+	close $self->{_fh};
+	$self->{_parent}->parent->removeconn($self);
+	$self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_socket}->close;
+	return;
+    }
+    
+    $self->{_bin} += length($line);
+    
+    
+    # confirm the packet we've just recieved
+    unless ( $self->{_socket}->send( pack("N", $self->{_bin}) ) ) {
+	carp "Error writing to DCC GET socket: $!";
+	close $self->{_fh};
+	$self->{_parent}->parent->removeconn($self);
+	$self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_socket}->close;
+	return;
+    }
+    
+    $self->{_bout} += 4;
+
+    # The file is done.
+    # If we close the socket, the select loop gets screwy because
+    # it won't remove its reference to the socket.
+    if ( $self->{_size} and $self->{_size} <= $self->{_bin} ) {
+        close $self->{_fh};
+        $self->{_parent}->parent->removeconn($self);
+        $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+                                                       $self->{_nick},
+                                                       $self->{_socket},
+                                                       $self->{_type}));
+	$self->{_socket}->close;
+        return;
+    }
+    
+    $self->{_parent}->handler(Net::IRC::Event->new('dcc_update',
+                                                   $self->{_nick},
+                                                   $self,
+                                                   $self->{_type},
+                                                   $self ));
+}
+
+sub filename {
+    return shift->{_filename};
+}
+
+sub size {
+    return shift->{_size};
+}
+
+sub close {
+    my ($self, $sock) = @_;
+    $self->{_fh}->close;
+    $self->{_parent}->parent->removeconn($self);
+    $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+                                                  $self->{_nick},
+                                                  $self->{_socket},
+                                                  $self->{_type}));
+    $self->{_socket}->close;
+    return;
+}
+
+# -- #perl was here! --
+#  \merlyn: I can't type... she created a numbner of very good drinks
+#  \merlyn: She's still at work
+#           \petey resists mentioning that there's "No manual entry
+#           for merlyn."
+# Silmaril: Haven't you ever seen swingers?
+#  \merlyn: she's off tomorrow... will meet me at the bar at 9:30
+# Silmaril: AWWWWwwww yeeeaAAHH.
+#   archon: waka chica waka chica
+
+
+# Connection handling SENDs
+package Net::IRC::DCC::SEND;
+@Net::IRC::DCC::SEND::ISA = qw(Net::IRC::DCC::Connection);
+
+use IO::File;
+use IO::Socket;
+use Carp;
+use strict;
+
+sub new {
+
+    my ($class, $container, $nick, $filename, $blocksize) = @_;
+    my ($size, $port, $fh, $sock, $select);
+
+    $blocksize ||= 1024;
+
+    # Shell-safe DCC filename stuff. Trying to prank-proof this
+    # module is rather difficult.
+    $filename =~ tr/a-zA-Z.+0-9=&()[]%\-\\\/:,/_/c;
+    $fh = new IO::File $filename;
+
+    unless (defined $fh) {
+        carp "Couldn't open $filename for reading: $!";
+	return;
+    }
+
+    binmode $fh;
+    $fh->seek(0, SEEK_END);
+    $size = $fh->tell;
+    $fh->seek(0, SEEK_SET);
+
+    $sock = new IO::Socket::INET( Proto     => "tcp",
+                                  Listen    => 1);
+
+    unless (defined $sock) {
+        carp "Couldn't open DCC SEND socket: $!";
+        $fh->close;
+        return;
+    }    
+
+    $container->ctcp('DCC SEND', $nick, $filename, 
+                     unpack("N",inet_aton($container->hostname())),
+		     $sock->sockport(), $size);
+
+    $sock->autoflush(1);
+
+    my $self = {
+        _bin        =>  0,         # Bytes we've recieved thus far
+        _blocksize  =>  $blocksize,       
+        _bout       =>  0,         # Bytes we've sent
+	_debug      =>  $container->debug,
+        _fh         =>  $fh,       # FileHandle we will be reading from.
+        _filename   =>  $filename,
+	_frag       =>  '',
+	_nick       =>  $nick,
+        _parent     =>  $container,
+        _size       =>  $size,     # Size of file
+        _socket     =>  $sock,     # Socket we're writing to
+        _time       =>  0,         # This gets set by Accept->parse() 
+	_type       =>  'SEND',
+    };
+
+    bless $self, $class;
+    
+    $sock = Net::IRC::DCC::Accept->new($sock, $self);
+
+    unless (defined $sock) {
+        carp "Error in accept: $!";
+        $fh->close;
+        return;
+    }
+
+    return $self;
+}
+
+# -- #perl was here! --
+#  fimmtiu: So a total stranger is using your shower?
+#  \merlyn: yes... a total stranger is using my hotel shower
+#           Stupid coulda sworn \merlyn was married...
+#   \petey: and you have a date.
+#  fimmtiu: merlyn isn't married.
+#   \petey: not a bad combo......
+#  \merlyn: perhaps a adate
+#  \merlyn: not maerried
+#  \merlyn: not even sober. --)
+
+sub parse {
+    my ($self, $sock) = @_;
+    my $size = ($self->_getline($sock, 1))[0];
+    my $buf;
+
+    # i don't know how useful this is, but let's stay consistent
+    $self->{_bin} += 4;
+
+    unless (defined $size) {
+	# Dang! The other end unexpectedly canceled.
+        carp (($self->peer)[1] . " connection to " .
+	      ($self->peer)[0] . " lost");
+	$self->{_fh}->close;
+	$self->{_parent}->parent->removefh($sock);
+        $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_socket}->close;
+	return;
+    }
+    
+    $size = unpack("N", $size);
+    
+    if ($size >= $self->{_size}) {
+
+	if ($self->{_debug}) {
+	    warn "Other end acknowledged entire file ($size >= ",
+		$self->{_size}, ")";
+	}
+        # they've acknowledged the whole file,  we outtie
+        $self->{_fh}->close;
+        $self->{_parent}->parent->removeconn($self);
+        $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_socket}->close;
+        return;
+    } 
+
+    # we're still waiting for acknowledgement, 
+    # better not send any more
+    return if $size < $self->{_bout};
+
+    unless (defined $self->{_fh}->read($buf,$self->{_blocksize})) {
+
+	if ($self->{_debug}) {
+	    warn "Failed to read from source file in DCC SEND!";
+	}
+	$self->{_fh}->close;
+        $self->{_parent}->parent->removeconn($self);
+	$self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_socket}->close;
+        return;
+    }
+
+    unless($self->{_socket}->send($buf)) {
+
+	if ($self->{_debug}) {
+	    warn "send() failed horribly in DCC SEND"
+	}
+        $self->{_fh}->close;
+        $self->{_parent}->parent->removeconn($self);
+        $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+						       $self->{_nick},
+						       $self->{_socket},
+						       $self->{_type}));
+	$self->{_socket}->close;
+	return;
+    }
+
+    $self->{_bout} += length($buf);
+
+    $self->{_parent}->handler(Net::IRC::Event->new('dcc_update',
+						   $self->{_nick},
+						   $self,
+						   $self->{_type},
+						   $self ));
+    
+    return 1;
+}
+
+# -- #perl was here! --
+#  fimmtiu: Man, merlyn, you must be drunk to type like that. :)
+#  \merlyn: too many longislands.
+#  \merlyn: she made them strong
+#   archon: it's a plot
+#  \merlyn: not even a good amoun tof coke
+#   archon: she's in league with the guy in your shower
+#   archon: she gets you drunk and he takes your wallet!
+
+
+# handles CHAT connections
+package Net::IRC::DCC::CHAT;
+@Net::IRC::DCC::CHAT::ISA = qw(Net::IRC::DCC::Connection);
+
+use IO::Socket;
+use Carp;
+use strict;
+
+sub new {
+
+    my ($class, $container, $type, $nick, $address, $port) = @_;
+    my ($sock, $self);
+
+    if ($type) {
+        # we're initiating
+
+        $sock = new IO::Socket::INET( Proto     => "tcp",
+                                      Listen    => 1);
+	
+        unless (defined $sock) {
+            carp "Couldn't open DCC CHAT socket: $!";
+            return;
+        }
+
+	$sock->autoflush(1);
+        $container->ctcp('DCC CHAT', $nick, 'chat',
+                         unpack("N",inet_aton($container->hostname)),
+						        $sock->sockport());
+
+	$self = {
+	    _bin        =>  0,      # Bytes we've recieved thus far
+	    _bout       =>  0,      # Bytes we've sent
+	    _connected  =>  1,
+	    _debug      =>  $container->debug,
+	    _frag       =>  '',
+	    _nick       =>  $nick,  # Nick of the client on the other end
+	    _parent     =>  $container,
+	    _socket     =>  $sock,  # Socket we're reading from
+	    _time       =>  0,      # This gets set by Accept->parse()
+	    _type       =>  'CHAT',
+	};
+	
+	bless $self, $class;
+	
+        $sock = Net::IRC::DCC::Accept->new($sock, $self);
+
+	unless (defined $sock) {
+	    carp "Error in DCC CHAT connect: $!";
+	    return;
+	}
+
+    } else {      # we're connecting
+
+        $address = &Net::IRC::DCC::Connection::fixaddr($address);
+	return if $port < 1024 or not defined $address;
+
+        $sock = new IO::Socket::INET( Proto    => "tcp",
+				      PeerAddr => "$address:$port");
+
+        if (defined $sock) {
+	    $container->handler(Net::IRC::Event->new('dcc_open',
+						     $nick,
+						     $sock,
+						     'chat',
+						     'chat', $sock));
+	} else {
+	    carp "Error in DCC CHAT connect: $!";
+	    return;
+	}
+
+	$sock->autoflush(1);
+
+	$self = {
+	    _bin        =>  0,      # Bytes we've recieved thus far
+	    _bout       =>  0,      # Bytes we've sent
+	    _connected  =>  1,
+	    _nick       =>  $nick,  # Nick of the client on the other end
+	    _parent     =>  $container,
+	    _socket     =>  $sock,  # Socket we're reading from
+	    _time       =>  time,
+	    _type       =>  'CHAT',
+	};
+	
+	bless $self, $class;
+	
+	$self->{_parent}->parent->addfh($self->socket,
+					$self->can('parse'), 'r', $self);
+    }
+
+    return $self;
+}
+
+# -- #perl was here! --
+#  \merlyn: tahtd be coole
+#           KTurner bought the camel today, so somebody can afford one
+#           more drink... ;)
+# tmtowtdi: I've heard of things like this...
+#  \merlyn: as an experience. that is.
+#   archon: i can think of cooler things (;
+#  \merlyn: I don't realiy have that mch in my wallet.
+
+sub parse {
+    my ($self, $sock) = @_;
+
+    foreach my $line ($self->_getline($sock)) {
+	return unless defined $line;
+    
+	$self->{_bin} += length($line);
+	
+	return undef if $line eq "\012";
+	$self->{_bout} += length($line);
+
+	$self->{_parent}->handler(Net::IRC::Event->new('chat',
+						       $self->{_nick},
+						       $self->{_socket},
+						       'chat',
+						       $line));
+	
+	$self->{_parent}->handler(Net::IRC::Event->new('dcc_update',
+						       $self->{_nick},
+						       $self,
+						       $self->{_type},
+						       $self ));
+    }
+}
+
+# Sends a message to a channel or person.
+# Takes 2 args:  the target of the message (channel or nick)
+#                the text of the message to send
+sub privmsg {
+    my ($self) = shift;
+
+    unless (@_) {
+	croak 'Not enough arguments to privmsg()';
+    }
+    
+    # Don't send a CR over DCC CHAT -- it's not wanted.
+    $self->socket->send(join('', @_) . "\012");
+}
+
+
+# -- #perl was here! --
+#  \merlyn: this girl carly at the bar is aBABE
+#   archon: are you sure? you don't sound like you're in a condition to
+#           judge such things (;
+# *** Stupid has set the topic on channel #perl to \merlyn is shit-faced
+#     with a trucker in the shower.
+# tmtowtdi: uh, yeah...
+#  \merlyn: good topic
+
+
+# Sockets waiting for accept() use this to shoehorn into the select loop.
+package Net::IRC::DCC::Accept;
+
+@Net::IRC::DCC::Accept::ISA = qw(Net::IRC::DCC::Connection);
+use Carp;
+use Socket;   # we use a lot of Socket functions in parse()
+use strict;
+
+
+sub new {
+    my ($class, $sock, $parent) = @_;
+    my ($self);
+
+    $self = { _debug    =>  $parent->debug,
+	      _nonblock =>  1,
+	      _socket   =>  $sock,
+	      _parent   =>  $parent,
+	      _type     =>  'accept',
+	  };
+    
+    bless $self, $class;
+
+    # Tkil's gonna love this one. :-)   But what the hell... it's safe to
+    # assume that the only thing initiating DCCs will be Connections, right?
+    # Boy, we're not built for extensibility, I guess. Someday, I'll clean
+    # all of the things like this up.
+    $self->{_parent}->{_parent}->parent->addconn($self);
+    return $self;
+}
+
+sub parse {
+    my ($self) = shift;
+    my ($sock);
+
+    $sock = $self->{_socket}->accept;
+    $self->{_parent}->{_socket} = $sock;
+    $self->{_parent}->{_time} = time;
+
+    if ($self->{_parent}->{_type} eq 'SEND') {
+	# ok, to get the ball rolling, we send them the first packet.
+	my $buf;
+	unless (defined $self->{_parent}->{_fh}->
+		read($buf, $self->{_parent}->{_blocksize})) {
+	    return;
+	}
+	unless (defined $sock->send($buf)) {
+	    $sock->close;
+	    $self->{_parent}->{_fh}->close;
+	    $self->{_parent}->{_parent}->parent->removefh($sock);
+	    $self->{_parent}->handler(Net::IRC::Event->new('dcc_close',
+							   $self->{_nick},
+							   $self->{_socket},
+							   $self->{_type}));
+	    $self->{_socket}->close;
+	    return;
+	}
+    }
+    
+    $self->{_parent}->{_parent}->parent->addconn($self->{_parent});
+    $self->{_parent}->{_parent}->parent->removeconn($self);
+
+    $self->{_parent}->{_parent}->handler(Net::IRC::Event->
+					 new('dcc_open',
+					     $self->{_parent}->{_nick},
+					     $self->{_parent}->{_socket},
+					     $self->{_parent}->{_type},
+					     $self->{_parent}->{_type},
+					     $self->{_parent}->{_socket})
+					 );
+}
+
+
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Net::IRC::DCC - Object-oriented interface to a single DCC connection
+
+=head1 SYNOPSIS
+
+Hard hat area: This section under construction.
+
+=head1 DESCRIPTION
+
+This documentation is a subset of the main Net::IRC documentation. If
+you haven't already, please "perldoc Net::IRC" before continuing.
+
+Net::IRC::DCC defines a few subclasses that handle DCC CHAT, GET, and SEND
+requests for inter-client communication. DCC objects are created by
+C<Connection-E<gt>new_{chat,get,send}()> in much the same way that
+C<IRC-E<gt>newconn()> creates a new connection object.
+
+=head1 METHOD DESCRIPTIONS
+
+This section is under construction, but hopefully will be finally written up
+by the next release. Please see the C<irctest> script and the source for
+details about this module.
+
+=head1 AUTHORS
+
+Conceived and initially developed by Greg Bacon E<lt>gbacon@adtran.comE<gt> and
+Dennis Taylor E<lt>dennis@funkplanet.comE<gt>.
+
+Ideas and large amounts of code donated by Nat "King" Torkington E<lt>gnat@frii.comE<gt>.
+
+Currently being hacked on, hacked up, and worked over by the members of the
+Net::IRC developers mailing list. For details, see
+http://www.execpc.com/~corbeau/irc/list.html .
+
+=head1 URL
+
+Up-to-date source and information about the Net::IRC project can be found at
+http://netirc.betterbox.net/ .
+
+=head1 SEE ALSO
+
+=over
+
+=item *
+
+perl(1).
+
+=item *
+
+RFC 1459: The Internet Relay Chat Protocol
+
+=item *
+
+http://www.irchelp.org/, home of fine IRC resources.
+
+=back
+
+=cut
diff --git a/Net/IRC/Entry.pm b/Net/IRC/Entry.pm
new file mode 100755
index 0000000000000000000000000000000000000000..94a38025c9e195efc3061053b5a44b6e75c52833
--- /dev/null
+++ b/Net/IRC/Entry.pm
@@ -0,0 +1,40 @@
+package Net::IRC::EventQueue::Entry;
+                                                                                                                                     
+use strict;
+                                                                                                                                     
+my $id = 0;
+                                                                                                                                     
+sub new {
+  my $class = shift;
+  my $time = shift;
+  my $content = shift;
+                                                                                                                                     
+  my $self = {
+    'time'  => $time,
+    'content' => $content,
+    'id'    => "$time:" . $id++,
+  };
+                                                                                                                                     
+  bless $self, $class;
+  return $self;
+}
+                                                                                                                                     
+sub id {
+  my $self = shift;
+  return $self->{'id'};
+}
+                                                                                                                                     
+sub time {
+  my $self = shift;
+  $self->{'time'} = $_[0] if @_;
+  return $self->{'time'};
+}
+                                                                                                                                     
+sub content {
+  my $self = shift;
+  $self->{'content'} = $_[0] if @_;
+  return $self->{'content'};
+}
+                                                                                                                                     
+1;
+
diff --git a/Net/IRC/Event.pm b/Net/IRC/Event.pm
new file mode 100755
index 0000000000000000000000000000000000000000..b8ca864ef5c1bddacf17554837556a4bc919d7ea
--- /dev/null
+++ b/Net/IRC/Event.pm
@@ -0,0 +1,856 @@
+#####################################################################
+#                                                                   #
+#   Net::IRC -- Object-oriented Perl interface to an IRC server     #
+#                                                                   #
+#      Event.pm: The basic data type for any IRC occurrence.        #
+#                                                                   #
+#    Copyright (c) 2001 Pete Sergeant, 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.        #
+#                                                                   #
+#####################################################################
+
+# there used to be lots of cute little log quotes from #perl in here
+#
+# they're gone now because they made working on this already crappy
+# code even more annoying... 'HI!!! I'm from #perl and so I don't
+# write understandable, maintainable code!!! You see, i'm a perl
+# badass, so I try to be as obscure as possible in everything I do!'
+#
+# Well, welcome to the real world, guys, where code needs to be
+# maintainable and sane.
+
+package Net::IRC::Event;
+
+use strict;
+our %_names;
+
+# Constructor method for Net::IRC::Event objects.
+# Takes at least 4 args:  the type of event
+#                         the person or server that initiated the event
+#                         the recipient(s) of the event, as arrayref or scalar
+#                         the name of the format string for the event
+#            (optional)   any number of arguments provided by the event
+sub new {
+  my $class = shift;
+  my $type = shift;
+  my $from = shift;
+  my $to = shift;
+  my $format = shift;
+  my $args = \@_;
+  
+  my $self = {
+    'type'   =>  $type,
+    'from'   =>  undef,
+    'to'     =>  ref($to) eq 'ARRAY'  ?  $to  :  [ $to ],
+    'format' =>  $format,
+    'args'   =>  [],
+  };
+  
+  bless $self, $class;
+  
+  if ($self->type !~ /\D/) {
+    $self->type($self->trans($self->type));
+  } else {
+    $self->type(lc($self->type));
+  }
+  
+  $self->from($from);     # sets nick, user, and host
+  $self->args($args);  # strips colons from args
+  
+  return $self;
+}
+
+# Sets or returns an argument list for this event.
+# Takes any number of args:  the arguments for the event.
+sub args {
+  my $self = shift;
+  my $args = shift;
+
+  if($args) {  
+    my (@q, $i, $ct) = @{$args};       # This line is solemnly dedicated to \mjd.
+
+    $self->{'args'} = [ ];
+    while (@q) {
+      $i = shift @q;
+      next unless defined $i;
+
+      if ($i =~ /^:/ and $ct) {                # Concatenate :-args.
+        $i = join ' ', (substr($i, 1), @q);
+        push @{$self->{'args'}}, $i;
+        last;
+      }
+      push @{$self->{'args'}}, $i;
+      $ct++;
+    }
+  }
+
+  return @{$self->{'args'}};
+}
+
+# Dumps the contents of an event to STDERR so you can see what's inside.
+# Takes no args.
+sub dump {
+    my ($self, $arg, $counter) = (shift, undef, 0);   # heh heh!
+
+    printf STDERR "TYPE: %-30s    FORMAT: %-30s\n", $self->type, $self->format;
+    print STDERR "FROM: ", $self->from, "\n";
+    print STDERR "TO: ", join(", ", @{$self->to}), "\n";
+    foreach $arg ($self->args) {
+		print "Arg ", $counter++, ": ", $arg, "\n";
+    }
+}
+
+# Sets or returns the format string for this event.
+# Takes 1 optional arg:  the new value for this event's "format" field.
+sub format {
+    my $self = shift;
+
+    $self->{'format'} = $_[0] if @_;
+    return $self->{'format'};
+}
+
+# Sets or returns the originator of this event
+# Takes 1 optional arg:  the new value for this event's "from" field.
+sub from {
+    my $self = shift;
+    my @part;
+
+    if (@_) {
+      # avoid certain irritating and spurious warnings from this line...
+      { local $^W;
+        @part = split /[\@!]/, $_[0], 3;
+      }
+	
+      $self->nick(defined $part[0] ? $part[0] : '');
+      $self->user(defined $part[1] ? $part[1] : '');
+      $self->host(defined $part[2] ? $part[2] : '');
+      defined $self->user ?
+          $self->userhost($self->user . '@' . $self->host) :
+          $self->userhost($self->host);
+      $self->{'from'} = $_[0];
+    }
+      
+    return $self->{'from'};
+}
+
+# Sets or returns the hostname of this event's initiator
+# Takes 1 optional arg:  the new value for this event's "host" field.
+sub host {
+    my $self = shift;
+
+    $self->{'host'} = $_[0] if @_;
+    return $self->{'host'};
+}
+
+# Sets or returns the nick of this event's initiator
+# Takes 1 optional arg:  the new value for this event's "nick" field.
+sub nick {
+    my $self = shift;
+
+    $self->{'nick'} = $_[0] if @_;
+    return $self->{'nick'};
+}
+
+# Sets or returns the recipient list for this event
+# Takes any number of args:  this event's list of recipients.
+sub to {
+    my $self = shift;
+    
+    $self->{'to'} = [ @_ ] if @_;
+    return wantarray ? @{$self->{'to'}} : $self->{'to'};
+}
+
+# Sets or returns the type of this event
+# Takes 1 optional arg:  the new value for this event's "type" field.
+sub type {
+    my $self = shift;
+    
+    $self->{'type'} = $_[0] if @_;
+    return $self->{'type'};
+}
+
+# Sets or returns the username of this event's initiator
+# Takes 1 optional arg:  the new value for this event's "user" field.
+sub user {
+    my $self = shift;
+
+    $self->{'user'} = $_[0] if @_;
+    return $self->{'user'};
+}
+
+# Just $self->user plus '@' plus $self->host, for convenience.
+sub userhost {
+    my $self = shift;
+    
+    $self->{'userhost'} = $_[0] if @_;
+    return $self->{'userhost'};
+}
+
+# Simple sub for translating server numerics to their appropriate names.
+# Takes one arg:  the number to be translated.
+sub trans {
+    shift if (ref($_[0]) || $_[0]) =~ /^Net::IRC/;
+    my $ev = shift;
+    
+    return (exists $_names{$ev} ? $_names{$ev} : undef);
+}
+
+%_names = (
+	   # suck!  these aren't treated as strings --
+	   # 001 ne 1 for the purpose of hash keying, apparently.
+	   '001' => "welcome",
+	   '002' => "yourhost",
+	   '003' => "created",
+	   '004' => "myinfo",
+	   '005' => "map", 		# Undernet Extension, Kajetan@Hinner.com, 17/11/98
+	   '006' => "mapmore", 		# Undernet Extension, Kajetan@Hinner.com, 17/11/98
+	   '007' => "mapend", 		# Undernet Extension, Kajetan@Hinner.com, 17/11/98	   	   
+	   '008' => "snomask", 		# Undernet Extension, Kajetan@Hinner.com, 17/11/98	   
+	   '009' => "statmemtot", 	# Undernet Extension, Kajetan@Hinner.com, 17/11/98	   
+	   '010' => "statmem", 		# Undernet Extension, Kajetan@Hinner.com, 17/11/98	   
+
+	   200 => "tracelink",
+	   201 => "traceconnecting",
+	   202 => "tracehandshake",
+	   203 => "traceunknown",
+	   204 => "traceoperator",
+	   205 => "traceuser",
+	   206 => "traceserver",
+	   208 => "tracenewtype",
+	   209 => "traceclass",
+	   211 => "statslinkinfo",
+	   212 => "statscommands",
+	   213 => "statscline",
+	   214 => "statsnline",
+	   215 => "statsiline",
+	   216 => "statskline",
+	   217 => "statsqline",
+	   218 => "statsyline",
+	   219 => "endofstats",
+           220 => "statsbline",             # UnrealIrcd, Hendrik Frenzel
+	   221 => "umodeis",
+           222 => "sqline_nick",            # UnrealIrcd, Hendrik Frenzel
+           223 => "statsgline",             # UnrealIrcd, Hendrik Frenzel
+           224 => "statstline",             # UnrealIrcd, Hendrik Frenzel
+           225 => "statseline",             # UnrealIrcd, Hendrik Frenzel
+           226 => "statsnline",             # UnrealIrcd, Hendrik Frenzel
+           227 => "statsvline",             # UnrealIrcd, Hendrik Frenzel
+	   231 => "serviceinfo",
+	   232 => "endofservices",
+	   233 => "service",
+	   234 => "servlist",
+	   235 => "servlistend",
+	   241 => "statslline",
+	   242 => "statsuptime",
+	   243 => "statsoline",
+	   244 => "statshline",
+	   245 => "statssline",		# Reserved, Kajetan@Hinner.com, 17/10/98
+	   246 => "statstline",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   247 => "statsgline",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+### TODO: need numerics to be able to map to multiple strings
+###           247 => "statsxline",             # UnrealIrcd, Hendrik Frenzel
+	   248 => "statsuline",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   249 => "statsdebug",		# Unspecific Extension, Kajetan@Hinner.com, 17/10/98
+	   250 => "luserconns",   # 1998-03-15 -- tkil
+	   251 => "luserclient",
+	   252 => "luserop",
+	   253 => "luserunknown",
+	   254 => "luserchannels",
+	   255 => "luserme",
+	   256 => "adminme",
+	   257 => "adminloc1",
+	   258 => "adminloc2",
+	   259 => "adminemail",
+	   261 => "tracelog",
+	   262 => "endoftrace",  # 1997-11-24 -- archon
+	   265 => "n_local",     # 1997-10-16 -- tkil
+	   266 => "n_global",    # 1997-10-16 -- tkil
+	   271 => "silelist",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   272 => "endofsilelist",	# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   275 => "statsdline",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   280 => "glist",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   281 => "endofglist",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           290 => "helphdr",            # UnrealIrcd, Hendrik Frenzel
+           291 => "helpop",             # UnrealIrcd, Hendrik Frenzel
+           292 => "helptlr",            # UnrealIrcd, Hendrik Frenzel
+           293 => "helphlp",            # UnrealIrcd, Hendrik Frenzel
+           294 => "helpfwd",            # UnrealIrcd, Hendrik Frenzel
+           295 => "helpign",            # UnrealIrcd, Hendrik Frenzel
+
+	   300 => "none",
+	   301 => "away",
+	   302 => "userhost",
+	   303 => "ison",
+	   304 => "rpl_text",           # Bahamut IRCD
+	   305 => "unaway",
+	   306 => "nowaway",
+	   307 => "userip",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           308 => "rulesstart",         # UnrealIrcd, Hendrik Frenzel
+           309 => "endofrules",         # UnrealIrcd, Hendrik Frenzel
+	   310 => "whoishelp",          # (July01-01)Austnet Extension, found by Andypoo <andypoo@secret.com.au>
+	   311 => "whoisuser",
+	   312 => "whoisserver",
+	   313 => "whoisoperator",
+	   314 => "whowasuser",
+	   315 => "endofwho",
+	   316 => "whoischanop",
+	   317 => "whoisidle",
+	   318 => "endofwhois",
+	   319 => "whoischannels",
+	   320 => "whoisvworld",        # (July01-01)Austnet Extension, found by Andypoo <andypoo@secret.com.au>
+	   321 => "liststart",
+	   322 => "list",
+	   323 => "listend",
+	   324 => "channelmodeis",
+	   329 => "channelcreate",  # 1997-11-24 -- archon
+	   331 => "notopic",
+	   332 => "topic",
+	   333 => "topicinfo",      # 1997-11-24 -- archon
+	   334 => "listusage",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           335 => "whoisbot",           # UnrealIrcd, Hendrik Frenzel
+	   341 => "inviting",
+	   342 => "summoning",
+           346 => "invitelist",         # UnrealIrcd, Hendrik Frenzel
+           347 => "endofinvitelist",    # UnrealIrcd, Hendrik Frenzel
+           348 => "exlist",             # UnrealIrcd, Hendrik Frenzel
+           349 => "endofexlist",        # UnrealIrcd, Hendrik Frenzel
+	   351 => "version",
+	   352 => "whoreply",
+	   353 => "namreply",
+	   354 => "whospcrpl",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   361 => "killdone",
+	   362 => "closing",
+	   363 => "closeend",
+	   364 => "links",
+	   365 => "endoflinks",
+	   366 => "endofnames",
+	   367 => "banlist",
+	   368 => "endofbanlist",
+	   369 => "endofwhowas",
+	   371 => "info",
+	   372 => "motd",
+	   373 => "infostart",
+	   374 => "endofinfo",
+	   375 => "motdstart",
+	   376 => "endofmotd",
+	   377 => "motd2",        # 1997-10-16 -- tkil
+	   378 => "austmotd",		# (July01-01)Austnet Extension, found by Andypoo <andypoo@secret.com.au>
+           379 => "whoismodes",         # UnrealIrcd, Hendrik Frenzel
+	   381 => "youreoper",
+	   382 => "rehashing",
+           383 => "youreservice",       # UnrealIrcd, Hendrik Frenzel
+	   384 => "myportis",
+	   385 => "notoperanymore",	# Unspecific Extension, Kajetan@Hinner.com, 17/10/98
+           386 => "qlist",              # UnrealIrcd, Hendrik Frenzel
+           387 => "endofqlist",         # UnrealIrcd, Hendrik Frenzel
+           388 => "alist",              # UnrealIrcd, Hendrik Frenzel
+           389 => "endofalist",         # UnrealIrcd, Hendrik Frenzel
+	   391 => "time",
+	   392 => "usersstart",
+	   393 => "users",
+	   394 => "endofusers",
+	   395 => "nousers",
+
+	   401 => "nosuchnick",
+	   402 => "nosuchserver",
+	   403 => "nosuchchannel",
+	   404 => "cannotsendtochan",
+	   405 => "toomanychannels",
+	   406 => "wasnosuchnick",
+	   407 => "toomanytargets",
+           408 => "nosuchservice",      # UnrealIrcd, Hendrik Frenzel
+	   409 => "noorigin",
+	   411 => "norecipient",
+	   412 => "notexttosend",
+	   413 => "notoplevel",
+	   414 => "wildtoplevel",
+	   416 => "querytoolong",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   421 => "unknowncommand",
+	   422 => "nomotd",
+	   423 => "noadmininfo",
+	   424 => "fileerror",
+           425 => "noopermotd",         # UnrealIrcd, Hendrik Frenzel
+	   431 => "nonicknamegiven",
+	   432 => "erroneusnickname",   # This iz how its speld in thee RFC.
+	   433 => "nicknameinuse",
+           434 => "norules",            # UnrealIrcd, Hendrik Frenzel
+           435 => "serviceconfused",    # UnrealIrcd, Hendrik Frenzel
+	   436 => "nickcollision",
+	   437 => "bannickchange",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   438 => "nicktoofast",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   439 => "targettoofast",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           440 => "servicesdown",           # Bahamut IRCD
+	   441 => "usernotinchannel",
+	   442 => "notonchannel",
+	   443 => "useronchannel",
+	   444 => "nologin",
+	   445 => "summondisabled",
+	   446 => "usersdisabled",
+           447 => "nonickchange",       # UnrealIrcd, Hendrik Frenzel
+	   451 => "notregistered",
+           455 => "hostilename",        # UnrealIrcd, Hendrik Frenzel
+           459 => "nohiding",           # UnrealIrcd, Hendrik Frenzel
+           460 => "notforhalfops",      # UnrealIrcd, Hendrik Frenzel
+	   461 => "needmoreparams",
+	   462 => "alreadyregistered",
+	   463 => "nopermforhost",
+	   464 => "passwdmismatch",
+	   465 => "yourebannedcreep", # I love this one...
+	   466 => "youwillbebanned",
+	   467 => "keyset",
+	   468 => "invalidusername",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           469 => "linkset",            # UnrealIrcd, Hendrik Frenzel
+           470 => "linkchannel",        # UnrealIrcd, Hendrik Frenzel
+	   471 => "channelisfull",
+	   472 => "unknownmode",
+	   473 => "inviteonlychan",
+	   474 => "bannedfromchan",
+	   475 => "badchannelkey",
+	   476 => "badchanmask",
+           477 => "needreggednick",           # Bahamut IRCD
+	   478 => "banlistfull",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           479 => "secureonlychannel",        # pircd
+### TODO: see above todo
+###           479 => "linkfail",               # UnrealIrcd, Hendrik Frenzel
+           480 => "cannotknock",        # UnrealIrcd, Hendrik Frenzel
+	   481 => "noprivileges",
+	   482 => "chanoprivsneeded",
+	   483 => "cantkillserver",
+	   484 => "ischanservice",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           485 => "killdeny",           # UnrealIrcd, Hendrik Frenzel
+           486 => "htmdisabled",        # UnrealIrcd, Hendrik Frenzel
+           489 => "secureonlychan",     # UnrealIrcd, Hendrik Frenzel
+	   491 => "nooperhost",
+	   492 => "noservicehost",
+
+	   501 => "umodeunknownflag",
+	   502 => "usersdontmatch",
+
+	   511 => "silelistfull",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   513 => "nosuchgline",		# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+	   513 => "badping",			# Undernet Extension, Kajetan@Hinner.com, 17/10/98
+           518 => "noinvite",           # UnrealIrcd, Hendrik Frenzel
+           519 => "admonly",            # UnrealIrcd, Hendrik Frenzel
+           520 => "operonly",           # UnrealIrcd, Hendrik Frenzel
+           521 => "listsyntax",         # UnrealIrcd, Hendrik Frenzel
+           524 => "operspverify",       # UnrealIrcd, Hendrik Frenzel
+
+           600 => "rpl_logon",           # Bahamut IRCD
+           601 => "rpl_logoff",           # Bahamut IRCD
+           602 => "rpl_watchoff",       # UnrealIrcd, Hendrik Frenzel
+           603 => "rpl_watchstat",      # UnrealIrcd, Hendrik Frenzel
+           604 => "rpl_nowon",           # Bahamut IRCD
+           605 => "rpl_nowoff",           # Bahamut IRCD
+           606 => "rpl_watchlist",      # UnrealIrcd, Hendrik Frenzel
+           607 => "rpl_endofwatchlist", # UnrealIrcd, Hendrik Frenzel
+           610 => "mapmore",            # UnrealIrcd, Hendrik Frenzel
+           640 => "rpl_dumping",        # UnrealIrcd, Hendrik Frenzel
+           641 => "rpl_dumprpl",        # UnrealIrcd, Hendrik Frenzel
+           642 => "rpl_eodump",         # UnrealIrcd, Hendrik Frenzel
+
+           999 => "numericerror",           # Bahamut IRCD
+
+	  );
+
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Net::IRC::Event - A class for passing event data between subroutines
+
+=head1 SYNOPSIS
+
+None yet. These docs are under construction.
+
+=head1 DESCRIPTION
+
+This documentation is a subset of the main Net::IRC documentation. If
+you haven't already, please "perldoc Net::IRC" before continuing.
+
+Net::IRC::Event defines a standard interface to the salient information for
+just about any event your client may witness on IRC. It's about as close as
+we can get in Perl to a struct, with a few extra nifty features thrown in.
+
+=head1 METHOD DESCRIPTIONS
+
+This section is under construction, but hopefully will be finally written up
+by the next release. Please see the C<irctest> script and the source for
+details about this module.
+
+=head1 LIST OF EVENTS
+
+Net::IRC is an entirely event-based system, which takes some getting used to
+at first. To interact with the IRC server, you tell Net::IRC's server
+connection to listen for certain events and activate your own subroutines when
+they occur. Problem is, this doesn't help you much if you don't know what to
+tell it to look for. Below is a list of the possible events you can pass to
+Net::IRC, along with brief descriptions of each... hope this helps.
+
+=head2 Common events
+
+=over
+
+=item *
+
+nick
+
+The "nick" event is triggered when the client receives a NICK message, meaning
+that someone on a channel with the client has changed eir nickname.
+
+=item *
+
+quit
+
+The "quit" event is triggered upon receipt of a QUIT message, which means that
+someone on a channel with the client has disconnected.
+
+=item *
+
+join
+
+The "join" event is triggered upon receipt of a JOIN message, which means that
+someone has entered a channel that the client is on.
+
+=item *
+
+part
+
+The "part" event is triggered upon receipt of a PART message, which means that
+someone has left a channel that the client is on.
+
+=item *
+
+mode
+
+The "mode" event is triggered upon receipt of a MODE message, which means that
+someone on a channel with the client has changed the channel's parameters.
+
+=item *
+
+topic
+
+The "topic" event is triggered upon receipt of a TOPIC message, which means
+that someone on a channel with the client has changed the channel's topic.
+
+=item *
+
+kick
+
+The "kick" event is triggered upon receipt of a KICK message, which means that
+someone on a channel with the client (or possibly the client itself!) has been
+forcibly ejected.
+
+=item *
+
+public
+
+The "public" event is triggered upon receipt of a PRIVMSG message to an entire
+channel, which means that someone on a channel with the client has said
+something aloud.
+
+=item *
+
+msg
+
+The "msg" event is triggered upon receipt of a PRIVMSG message which is
+addressed to one or more clients, which means that someone is sending the
+client a private message. (Duh. :-)
+
+=item *
+
+notice
+
+The "notice" event is triggered upon receipt of a NOTICE message, which means
+that someone has sent the client a public or private notice. (Is that
+sufficiently vague?)
+
+=item *
+
+ping
+
+The "ping" event is triggered upon receipt of a PING message, which means that
+the IRC server is querying the client to see if it's alive. Don't confuse this
+with CTCP PINGs, explained later.
+
+=item *
+
+other
+
+The "other" event is triggered upon receipt of any number of unclassifiable
+miscellaneous messages, but you're not likely to see it often.
+
+=item *
+
+invite
+
+The "invite" event is triggered upon receipt of an INVITE message, which means
+that someone is permitting the client's entry into a +i channel.
+
+=item *
+
+kill
+
+The "kill" event is triggered upon receipt of a KILL message, which means that
+an IRC operator has just booted your sorry arse offline. Seeya!
+
+=item *
+
+disconnect
+
+The "disconnect" event is triggered when the client loses its
+connection to the IRC server it's talking to. Don't confuse it with
+the "leaving" event. (See below.)
+
+=item *
+
+leaving
+
+The "leaving" event is triggered just before the client deliberately
+closes a connection to an IRC server, in case you want to do anything
+special before you sign off.
+
+=item *
+
+umode
+
+The "umode" event is triggered when the client changes its personal mode flags.
+
+=item *
+
+error
+
+The "error" event is triggered when the IRC server complains to you about
+anything. Sort of the evil twin to the "other" event, actually.
+
+=back
+
+=head2 CTCP Requests
+
+=over
+
+=item *
+
+cping
+
+The "cping" event is triggered when the client receives a CTCP PING request
+from another user. See the irctest script for an example of how to properly
+respond to this common request.
+
+=item *
+
+cversion
+
+The "cversion" event is triggered when the client receives a CTCP VERSION
+request from another client, asking for version info about its IRC client
+program.
+
+=item *
+
+csource
+
+The "csource" event is triggered when the client receives a CTCP SOURCE
+request from another client, asking where it can find the source to its
+IRC client program.
+
+=item *
+
+ctime
+
+The "ctime" event is triggered when the client receives a CTCP TIME
+request from another client, asking for the local time at its end.
+
+=item *
+
+cdcc
+
+The "cdcc" event is triggered when the client receives a DCC request of any
+sort from another client, attempting to establish a DCC connection.
+
+=item *
+
+cuserinfo
+
+The "cuserinfo" event is triggered when the client receives a CTCP USERINFO
+request from another client, asking for personal information from the client's
+user.
+
+=item *
+
+cclientinfo
+
+The "cclientinfo" event is triggered when the client receives a CTCP CLIENTINFO
+request from another client, asking for whatever the hell "clientinfo" means.
+
+=item *
+
+cerrmsg
+
+The "cerrmsg" event is triggered when the client receives a CTCP ERRMSG
+request from another client, notifying it of a protocol error in a preceding
+CTCP communication.
+
+=item *
+
+cfinger
+
+The "cfinger" event is triggered when the client receives a CTCP FINGER
+request from another client. How to respond to this should best be left up
+to your own moral stance.
+
+=item *
+
+caction
+
+The "caction" event is triggered when the client receives a CTCP ACTION
+message from another client. I should hope you're getting the hang of how
+Net::IRC handles CTCP requests by now...
+
+=back
+
+=head2 CTCP Responses
+
+=over
+
+=item *
+
+crping
+
+The "crping" event is triggered when the client receives a CTCP PING response
+from another user. See the irctest script for an example of how to properly
+respond to this common event.
+
+=item *
+
+crversion
+
+The "crversion" event is triggered when the client receives a CTCP VERSION
+response from another client.
+
+=item *
+
+crsource
+
+The "crsource" event is triggered when the client receives a CTCP SOURCE
+response from another client.
+
+=item *
+
+crtime
+
+The "crtime" event is triggered when the client receives a CTCP TIME
+response from another client.
+
+=item *
+
+cruserinfo
+
+The "cruserinfo" event is triggered when the client receives a CTCP USERINFO
+response from another client.
+
+=item *
+
+crclientinfo
+
+The "crclientinfo" event is triggered when the client receives a CTCP
+CLIENTINFO response from another client.
+
+=item *
+
+crfinger
+
+The "crfinger" event is triggered when the client receives a CTCP FINGER
+response from another client. I'm not even going to consider making a joke
+about this one.
+
+=back
+
+=head2 DCC Events
+
+=over
+
+=item *
+
+dcc_open
+
+The "dcc_open" event is triggered when a DCC connection is established between
+the client and another client.
+
+=item *
+
+dcc_update
+
+The "dcc_update" event is triggered when any data flows over a DCC connection.
+Useful for doing things like monitoring file transfer progress, for instance.
+
+=item *
+
+dcc_close
+
+The "dcc_close" event is triggered when a DCC connection closes, whether from
+an error or from natural causes.
+
+=item *
+
+chat
+
+The "chat" event is triggered when the person on the other end of a DCC CHAT
+connection sends you a message. Think of it as the private equivalent of "msg",
+if you will.
+
+=back
+
+=head2 Numeric Events
+
+=over
+
+=item *
+
+There's a whole lot of them, and they're well-described elsewhere. Please see
+the IRC RFC (1495, at http://cs-ftp.bu.edu/pub/irc/support/IRC_RFC ) for a
+detailed description, or the Net::IRC::Event.pm source code for a quick list.
+
+=back
+
+=head1 AUTHORS
+
+Conceived and initially developed by Greg Bacon E<lt>gbacon@adtran.comE<gt> and
+Dennis Taylor E<lt>dennis@funkplanet.comE<gt>.
+
+Ideas and large amounts of code donated by Nat "King" Torkington E<lt>gnat@frii.comE<gt>.
+
+Currently being hacked on, hacked up, and worked over by the members of the
+Net::IRC developers mailing list. For details, see
+http://www.execpc.com/~corbeau/irc/list.html .
+
+=head1 URL
+
+Up-to-date source and information about the Net::IRC project can be found at
+http://netirc.betterbox.net/ .
+
+=head1 SEE ALSO
+
+=over
+
+=item *
+
+perl(1).
+
+=item *
+
+RFC 1459: The Internet Relay Chat Protocol
+
+=item *
+
+http://www.irchelp.org/, home of fine IRC resources.
+
+=back
+
+=cut
+
diff --git a/Net/IRC/EventQueue.pm b/Net/IRC/EventQueue.pm
new file mode 100755
index 0000000000000000000000000000000000000000..fdb7b447bdd27d96f7eca5465feee4239fcd6c39
--- /dev/null
+++ b/Net/IRC/EventQueue.pm
@@ -0,0 +1,73 @@
+package Net::IRC::EventQueue;
+
+use Net::IRC::EventQueue::Entry;
+
+use strict;
+
+sub new {
+  my $class = shift;
+  
+  my $self = {
+    'queue' => {},
+  };
+
+  bless $self, $class;
+}
+
+sub queue {
+  my $self = shift;
+  return $self->{'queue'};
+}
+
+sub enqueue {
+  my $self = shift;
+  my $time = shift;
+  my $content = shift;
+
+  my $entry = new Net::IRC::EventQueue::Entry($time, $content);
+  $self->queue->{$entry->id} = $entry;
+  return $entry->id;
+}
+
+sub dequeue {
+  my $self = shift;
+  my $event = shift;
+  my $result;
+
+  if(!$event) { # we got passed nothing, so return the first event
+    $event = $self->head();
+    delete $self->queue->{$event->id};
+    $result = $event;
+  } elsif(!ref($event)) { # we got passed an id
+    $result = $self->queue->{$event};
+    delete $self->queue->{$event};
+  } else { # we got passed an actual event object
+    ref($event) eq 'Net::IRC::EventQueue::Entry'
+        or die "Cannot delete event type of " . ref($event) . "!";
+
+    $result = $self->queue->{$event->id};
+    delete $self->queue->{$event->id};
+  }
+
+  return $result;
+}
+
+sub head {
+  my $self = shift;
+
+  return undef if $self->is_empty;
+ 
+  no warnings; # because we want to numerically sort strings...
+  my $headkey = (sort {$a <=> $b} (keys(%{$self->queue})))[0];
+  use warnings;
+
+  return $self->queue->{$headkey};
+}
+
+sub is_empty {
+  my $self = shift;
+
+  return keys(%{$self->queue}) ? 0 : 1;
+}
+
+1;
diff --git a/bot.pl b/bot.pl
index a14edff4f4eff1e25acc400ec66028b8decefdfe..908a610d871c41554ef72ca538be6ab6289b18ba 100755
--- a/bot.pl
+++ b/bot.pl
@@ -16,7 +16,12 @@ BEGIN {
 	use Core::Config;
 	use Core::Getpass;
 	use Core::Logging;
-	unshift @INC, "./";
+	
+	# Ça c'est pour utiliser nos librairies avant celles installées sur le système
+	# Ça sert notamment pour Net::IRC, vu que je l'ai patchée (http://coltel.iiens.net/patch_Net_IRC)
+	my $incpath = pop @INC;
+	unshift @INC, $incpath;
+	
 	
 	# On vérifie qu'on n'a pas trop de droits
 	open ID, "id |" or die "Unable to run `id`\n";