#!/usr/local/bin/perl
use strict;
use warnings;
my $rcs_id = q$Id$;
use Config;
use File::Basename;
use Getopt::Long;
use Pod::Usage;
use POE qw(Kernel);
use YAML ();
use NetHirc::Adventurer;
use NetHirc::Database;
use NetHirc::Debug;
use NetHirc::Inventory;
use NetHirc::Terminal;
use NetHirc::Server;
my $progname = basename($0);
my @personal_info = getpwuid($<);
my $nick = $ENV{'IRCNICK'};
my $ircname = $ENV{'IRCNAME'};
my $homedir = $personal_info[7];
my $port = 6667;
my $database = undef;
my $debug = undef;
my $help = undef;
my $rcfile = "$homedir/.nethirc";
my $username = undef;
my $hostname = undef;
my $localport = undef;
my $dump_database = undef;
my $server = undef;
my @channels = ();
my %options = (
'database|b=s' => \$database,
'debug|d=s' => \$debug,
'hostname|h=s' => \$hostname,
'rc-file|f=s' => \$rcfile,
'ircname|i=s' => \$ircname,
'join|j=s' => \@channels,
'local-port|l=i' => \$localport,
'dump-database|m' => \$dump_database,
'nick|n=s' => \$nick,
'port|p=i' => \$port,
'server|s=s' => \$server,
'username|u=s' => \$username,
'help|?' => \$help,
);
my $rc = GetOptions(%options);
if (not $rc or $help)
{
pod2usage(-exitval => 1, -verbose => 0);
}
my $rcdb;
my $commands;
eval {
my $x = YAML::LoadFile($rcfile);
die "$rcfile must have nethirc: section" unless exists $x->{'nethirc'};
$rcdb = $x->{'nethirc'};
$commands = $x->{'commands'};
$database ||= $x->{'database'};
};
my $db = NetHirc::Database->new($database);
if ($dump_database)
{
print YAML::Dump($db);
exit(0);
}
if ($@)
{
warn sprintf("%s: Can't load %s: %s\n", $progname, $rcfile, $@->{'msg'});
}
$rcdb->[0]->{'Server'} = $server if $server;
$rcdb->[0]->{'Nick'} = $nick if $nick;
$rcdb->[0]->{'Port'} = $port if $port;
$rcdb->[0]->{'LocalAddr'} = $hostname if $hostname;
$rcdb->[0]->{'LocalPort'} = $localport if $localport;
$rcdb->[0]->{'Username'} = $username if $username;
$rcdb->[0]->{'Ircname'} = $ircname if $ircname;
$rcdb->[0]->{'channels'} = \@channels if @channels;
bless $rcdb, 'NetHirc::Inventory';
map {
$_->{'channels'} ||= [];
$_->{'_joined'} ||= [];
bless $_, 'NetHirc::Server';
} @$rcdb;
NetHirc::Debug->new($debug) if $debug;
NetHirc::Terminal->new($db, $rcdb);
NetHirc::Adventurer->new($db, $rcdb, $commands);
$poe_kernel->run();
__END__
=pod
=head1 NAME
nethirc - A nethack-flavored IRC client
=head1 SYNOPSIS
B<nethirc>
[B<-m?>]
[B<-b> I<dbfile>]
[B<-f> I<rcfile>]
[B<-h> I<hostname>]
[B<-i> I<ircname>]
[B<-j> I<channel>]
[B<-l> I<localport>]
[B<-n> I<nick>]
[B<-p> I<port>]
[B<-s> I<server>]
[B<-u> I<username>]
[B<--dump-database>]
[B<--help>]
[B<--database>=I<dbfile>]
[B<--hostname>=I<hostname>]
[B<--rc-file>=I<rcfile>]
[B<--join>=I<channel>]
[B<--local-port>=I<localport>]
[B<--nick>=I<nick>]
[B<--port>=I<port>]
[B<--server>=I<server>]
[B<--username>=I<username>]
=head1 DESCRIPTION
B<nethirc> is an IRC client written almost entirely in Perl, with
the help of the C<POE::Component::IRC> module from CPAN. It is
named B<nethirc> because of the influence of B<nethack>, which is
the theme behind many of the things that B<nethirc> displays on
your screen.
=head2 Switches
B<nethirc>'s command line interface is intentionally a bit different
than that of B<ircII>, arguably the standard IRC client.
=over 4
=item B<-b> I<dbfile>
=item B<--database>=I<dbfile>
Use a database of quips, quotes, and other text found in I<dbfile>.
This file can be created with the B<-m> or B<--dump-database>
switches, and modified with a text editor. This is a YAML file.
=item B<-f> I<rcfile>
=item B<--rc-file>=I<rcfile>
Use the named file for initialization instead of the default
C<~/.nethirc>. This is also a YAML file.
=item B<-h> I<hostname>
=item B<--hostname>=I<hostname>
Assert a particular hostname to IRC servers. They may not always
like it. This switch can be used to pick an interface to which to
bind on a multi-homed host.
=item B<-i> I<ircname>
=item B<--ircname>=I<ircname>
Use the indicated witty comment as your "real name" on IRC. The
default may be less than flattering, if you do not set the C<IRCNAME>
environment variable.
=item B<-j> I<channel>
=item B<--join>=I<channel>
For the first server which you specify, join the indicated channel.
You may specify this switch more than once. By default, you join
no channels.
=item B<-l> I<localport>
=item B<--local-port>=I<localport>
Use the indicated port for your client instead of letting the
operating system pick one for you.
=item B<-m>
=item B<--dump-database>
Dump I<NetHirc>'s internal database to the standard output. You
can feed this back into later invocations with B<-b> or B<--database>.
=item B<-n> I<nick>
=item B<--nick>=I<nick>
Use the indicated nick. If not specified, the environment variable
C<IRCNICK> will be consulted. If that's empty, you will get your
login name, or something worse.
=item B<-p> I<port>
=item B<--port>=I<port>
Connect to the indicated port on the remote server instead of the
default. The default is usually what you want.
=item B<-s> I<server>
=item B<--server>=I<server>
Connect to the named server. If you do not have a startup file
(see B<-f> and B<--rc-file>), you must specify this switch.
=item B<-u> I<username>
=item B<--username>=I<username>
Use the indicated user name, instead of choosing a default (probably
your login name).
=item B<-?>
=item B<--help>
Ask for help.
=back
=head2 The Initialization File
The initialization file (see the B<-f> and B<--rc-file> switches)
is a YAML file that has at least one top-level section, called
C<nethirc>. Inside it are several servers to which to connect, and
how to do it. A minimal example would be:
nethirc:
- Server: irc.example.com
There can also be a section called C<commands>, which are executed
after the first IRC server greets you. They are executed just as
if they were typed. For your own safety, please do not put anything
that causes network traffic in the C<commands> section.
A more complex example of an initialization file:
nethirc:
- Server: irc.example.com
Nick: Eggplant
- Server: irc.freenode.net
Nick: Aubergine
Ircname: le plante du egg
channels:
- "#nethirc"
- "#perl"
- Server: irc.example.dal.net
Nick: Nasu-chan
Hostname: I.know.stupid.DNS.tricks
LocalPort: 23456
Port: 12345
Username: notvegan
channels:
- "#lasagna"
commands:
- "/bigbrother on"
- "/count start nethirc.counts"
If it's not obvious what this file attempts to do, keep reading it
until it makes sense. :-)
Note that the file is case-sensitive, and whitespace is important.
Switches specified on the command line override things only for the
first server specified.
=head2 The Database File
The database file (see B<-b>, B<--database>, B<-m>, and B<--dump-database>)
is also full of YAML, and is arguably more interesting than the
initialization file.
If you see an interesting message appear on your screen, look for
its counterpart in the database file. Note that a lot of things
in here may not make sense to you unless you know the source somewhat.
But don't let it stop you from trying. :-) Perhaps the most
interesting portions of the file are the C<channel_mode_comments>,
C<complaints>, B<formats>, and C<self_mode_comments>.
=head1 USAGE
Start the client. Have fun. Yell at people. There is a full
command set at your disposal. Those used to ircII should have little
problem with the default command set.
=head1 EXIT STATUS
Does it really matter?
=head1 FILES
C<$HOME/.nethirc>
=head1 ENVIRONMENT
The C<IRCNAME> and C<IRCNICK> variables retain their usual meaning.
=head1 SEE ALSO
RFC1459, L<perl(1)>, L<nethack(6)>, L<fortune(6)>, L<POE::Component::IRC>,
L<YAML>.
=head1 BUGS
The command set is not complete yet.
The event set is not complete yet. Need to generate more error-type
events.
This client is not very oper-friendly.
DCC support is nonexistent. This may actually be a feature.
Should provide various files for i18n/l10n, based on locale, LC_LANG,
whatever. The mechanism we use should support this...once we write
it. (Probably based on various database files.)
=head1 AUTHOR
Tony Monroe E<lt>tmonroe plus perl at nog dot netE<gt>, sometimes
known as Eggplant on EFnet.
=head1 HISTORY
B<nethirc> was written in a fit of experimentation and madness and
frustration with a previous creation known as hoserchat. The main
idea was, of course, "Wouldn't a Nethack-like IRC client be cool?
Or at least amusing?" And so, several months of on-and-off development
time later, I felt that the world won't wince too much at the sight
of version 0.01 of this program. So it was released.
It went through a few revisions after that, but it suffered because
its internal architecture was rather stinky. Starting with version
0.7, its code layout made much more sense, though it lost a good
deal of its dynamic-reload capability (which was a gross hack
anyway). However, it added some random amusements, to increase the
appalling factor.
Version 0.9 was a complete rewrite to be even cleaner than version
0.7, gratuitously interface-incompatible, yet somehow cleaner and
more willing to play nicely with multiple servers. And to take
advantage of POE, which is insanely cool. (Yes, both insane and
cool.)
Version 0.91 takes advantage of new features in C<POE::Component::IRC>
3.0 and later.
Version 0.92 uses the "new way" to create C<POE::Component::IRC>
objects, as presented in version 3.4 and later.
syntax highlighted by Code2HTML, v. 0.9.1