#/usr/bin/perl
#Copyright (C) 2003 Erik Fears
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program; if not, write to the Free Software
#
# Foundation, Inc.
# 59 Temple Place - Suite 330
# Boston, MA 02111-1307, USA.
use strict;
use Socket;
#Options
my %BOPM = (
NICK => 'bopm', #Our bopm's nick
TS_GRACE => 30, #Delta allowed above LAST_SCAN in seconds
LAST => time, #TS of last scan
);
my %IRC = (
NAME => 'bopm.blitzed.org', #Your server name
HOST => 'localhost', #Remote server we're linking to
PORT => '6667', #Port of remote server we're linking to
PASS => 'link', #Link password from C/N
);
#Bahamut
my %PROTOCOL = (
CAPAB => 'TS3 NOQUIT SSJOIN BURST UNCONNECT NICKIP TSMODE',
);
my %NICKFORMAT = (
NICK => 1,
TS => 3,
USERNAME => 5,
HOSTNAME => 6,
SERVER => 7,
IP => 9,
REALNAME => 10,
);
###### END CONFIGURATION ######
my %IRC_FUNCTIONS = (
'PING' => \&m_ping,
'NICK' => \&m_nick,
);
my $IRC_SOCKET;
my $IRC_DATA;
main();
# main
#
# Main connects to the IRC server
# and handles the main daemon loop.
sub main #()
{
my $read;
irc_init();
irc_connect();
while(1) {
if($IRC_SOCKET)
{
irc_read();
}
irc_reconnect();
}
}
# do_log
#
# Log!
sub do_log #($data)
{
my $data = $_[0];
print STDOUT "[" . scalar localtime() . "] " . $data . "\n";
}
# init
#
# Initialize IRC socket
#
sub irc_init #()
{
if(!socket($IRC_SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')))
{
do_log(sprintf('IRC -> Error initializing IRC socket: %s', $!));
die;
}
}
# irc_connect
#
# Connect to IRC and send registration data
#
sub irc_connect #()
{
if(!connect($IRC_SOCKET, sockaddr_in($IRC{PORT}, inet_aton($IRC{HOST}))))
{
do_log(sprintf('IRC -> Error connecting to IRC host: %s', $!));
return;
}
irc_send(sprintf('PASS %s', $IRC{PASS}));
irc_send(sprintf('CAPAB %s',$PROTOCOL{CAPAB}));
irc_send(sprintf('SERVER %s', $IRC{NAME}));
}
# irc_reconnect
#
# Reconnct to IRC server
#
sub irc_reconnect #()
{
do_log('IRC -> Reconnecting to server in 30 seconds..');
close($IRC_SOCKET);
sleep(30);
if(!socket($IRC_SOCKET, PF_INET, SOCK_STREAM, getprotobyname('tcp')))
{
do_log(sprintf('IRC -> Error initializing IRC socket: %s', $!));
die;
}
irc_connect();
}
# irc_send
#
# Send data to IRC server
#
# $_[0] IRC Data to send
sub irc_send #($data)
{
my $data = $_[0];
do_log(sprintf('IRC SEND -> %s', $data));
$data .= "\n\n";
if(!send($IRC_SOCKET, $data, 0))
{
do_log(sprintf('IRC -> send() error: %s', $!));
irc_reconnect();
}
}
# irc_read
#
# Read data from IRC server
#
sub irc_read #()
{
while(<$IRC_SOCKET>)
{
chomp;
irc_parse($_);
}
}
sub irc_parse #($line)
{
my $line = $_[0];
my @parv;
my $command;
my $message;
my %source;
chomp $line;
do_log(sprintf('IRC READ -> %s', $line));
if(index($line, ':', 1) != -1)
{
@parv = split(/\s+/, substr($line, 0, index($line, ':', 1)));
$message = substr($line, index($line, ':', 1) + 1, length($line));
}
else
{
@parv = split(/\s+/, $line);
}
push @parv, $message;
if($parv[0] =~ /:/)
{
$parv[0] = substr($parv[0], 1, length($parv[0]));
}
else
{
unshift @parv, $IRC{HOST};
}
#parse the nick!user@host if it exists
if($parv[0] =~ /([^!]+)!([^@]+)@(.*)/)
{
$source{nickname} = $1;
$source{username} = $2;
$source{hostname} = $3;
$source{is_user} = 1;
}
else { $source{is_user} = 0; }
if(exists($IRC_FUNCTIONS{$parv[1]}))
{
$IRC_FUNCTIONS{$parv[1]}(\@parv, \%source);
}
}
# m_ping
#
# PING from server.
#
# parv[0] = SOURCE
# parv[1] = PING
# parv[2] = PACKAGE
#
sub m_ping # \@parv, \%source
{
my $parv = $_[0];
irc_send(sprintf('PONG :%s', $$parv[2]));
}
# m_nick
#
sub m_nick
{
my $parv = $_[0];
my $conn;
if(@$parv <= 3)
{
return;
}
shift @$parv;
#Check if the NICK TS is older than last scan time, give TS_GRACE seconds grace
if($$parv[$NICKFORMAT{TS}] < ($BOPM{LAST} + $BOPM{TS_GRACE}))
{
do_log(sprintf('BOPM -> Not scanning %s due to old TS (%d < %d + %d)',
$$parv[$NICKFORMAT{NICK}], $$parv[$NICKFORMAT{TS}], $BOPM{LAST} , $BOPM{TS_GRACE}));
return;
}
$conn = sprintf('*** Notice -- Client connecting: %s (%s@%s) [%s] {class}',
$$parv[$NICKFORMAT{NICK}],
$$parv[$NICKFORMAT{USERNAME}],
$$parv[$NICKFORMAT{HOSTNAME}],
inet_ntoa(pack("N", $$parv[$NICKFORMAT{IP}])),
);
#send hybrid connection notice
irc_send(sprintf(':%s NOTICE %s :%s', $IRC{NAME}, $BOPM{NICK}, $conn));
$BOPM{LAST} = time;
}
syntax highlighted by Code2HTML, v. 0.9.1