You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
476 lines
12 KiB
Perl
476 lines
12 KiB
Perl
4 years ago
|
# infobot :: Kevin Lenzo & Patrick Cole (c) 1997
|
||
|
|
||
|
use Socket;
|
||
|
|
||
|
sub srvConnect {
|
||
|
my ($server, $port) = @_;
|
||
|
my ($iaddr, $paddr, $proto);
|
||
|
select(STDOUT);
|
||
|
$| = 1;
|
||
|
|
||
|
$iaddr = inet_aton($server);
|
||
|
$ip_num = inet_ntoa($iaddr);
|
||
|
if (not $ip_num) {
|
||
|
die "can't get the address of $server ($ip_num)!\n";
|
||
|
}
|
||
|
&status("Connecting to port $port of server $server ($ip_num)...");
|
||
|
$paddr = sockaddr_in($port, $iaddr);
|
||
|
$proto = getprotobyname('tcp');
|
||
|
socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "socket failed: $!";
|
||
|
$sockaddr = 'S n a4 x8';
|
||
|
if ($param{'vhost_name'}) {
|
||
|
my $hostname = $param{'vhost_name'};
|
||
|
$this = pack($sockaddr, AF_INET, 0, inet_aton($hostname));
|
||
|
&status("trying to bind as $hostname");
|
||
|
bind(SOCK, $this) || die "bind: $!";
|
||
|
}
|
||
|
connect(SOCK, $paddr) or die "connect failed: $!";
|
||
|
|
||
|
&status(" connected.");
|
||
|
}
|
||
|
|
||
|
sub procservmode {
|
||
|
my ($server, $e, $f) = @_;
|
||
|
my @parts = split (/ /, $f);
|
||
|
$cnt=0;
|
||
|
my $mode="";
|
||
|
my $chan="";
|
||
|
foreach (@parts) {
|
||
|
if ($cnt == 0) {
|
||
|
$chan = $_;
|
||
|
} else {
|
||
|
$mode .= $_;
|
||
|
$mode .= " ";
|
||
|
}
|
||
|
++$cnt;
|
||
|
}
|
||
|
chop $mode;
|
||
|
$mode=~s/://;
|
||
|
|
||
|
if ($server eq $chan) {
|
||
|
if ($params{ansi_control}) {
|
||
|
&status(">>> $b$server$ob sets user mode: $b$mode$ob");
|
||
|
} else {
|
||
|
&status(">>> $server sets mode: $mode");
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
if ($params{ansi_control}) {
|
||
|
&status(">>> $b$server$ob/$b$chan$ob sets server mode: $b$mode$ob");
|
||
|
} else {
|
||
|
&status(">>> $server/$chan sets mode: $mode");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
### added by the xk.
|
||
|
# Usage: &nickServ(text);
|
||
|
sub nickServ {
|
||
|
my $text = shift;
|
||
|
return if !defined $param{'nickServ_pass'};
|
||
|
|
||
|
&status("NickServ: <= '$text'");
|
||
|
|
||
|
if ($text =~ /Password incorrect/i) {
|
||
|
&status("NickServ: ** identify failed.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ($text =~ /Password accepted/i) {
|
||
|
&status("NickServ: ** identify success.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ($nickserv_try) { return; }
|
||
|
|
||
|
&status("NickServ: => Identifying to NickServ.");
|
||
|
rawout("PRIVMSG NickServ :IDENTIFY $param{'nickServ_pass'}");
|
||
|
$nickserv_try++;
|
||
|
}
|
||
|
|
||
|
###
|
||
|
# Usage: &chanServ(text);
|
||
|
sub chanServ {
|
||
|
my $text = shift;
|
||
|
# return if !defined $param{'chanServ_ops'};
|
||
|
&status("chanServ_ops => '$param{'chanServ_ops'}'.");
|
||
|
|
||
|
&status("ChanServ: <= '$text'");
|
||
|
|
||
|
# to be continued...
|
||
|
return;
|
||
|
}
|
||
|
# end of xk functions.
|
||
|
|
||
|
sub procmode {
|
||
|
my ($nick, $user, $host, $e, $f) = @_;
|
||
|
my @parts = split (/ /, $f);
|
||
|
$cnt=0;
|
||
|
my $mode="";
|
||
|
my $chan="";
|
||
|
foreach (@parts) {
|
||
|
if ($cnt == 0) {
|
||
|
$chan = $_;
|
||
|
} else {
|
||
|
$mode .= $_;
|
||
|
$mode .= " ";
|
||
|
}
|
||
|
++$cnt;
|
||
|
}
|
||
|
$mode =~ s/\s$//;
|
||
|
|
||
|
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> mode/$b$chan$ob [$b$mode$ob] by $b$nick$ob");
|
||
|
} else {
|
||
|
&status(">>> mode/$chan [$mode] by $nick");
|
||
|
}
|
||
|
|
||
|
if ($chan =~ /^[\#\&]/) {
|
||
|
my ($modes, $targets) = ($mode =~ /^(\S+)\s+(.*)/);
|
||
|
my @m = ($modes =~ /([+-]*\w)/g);
|
||
|
my @t = split /\s+/, $targets;
|
||
|
if (@m != @t) {
|
||
|
&status("number of modes does not match number of targets: @m / @t");
|
||
|
} else {
|
||
|
my $parity = 0;
|
||
|
foreach (0..$#m) {
|
||
|
if ($m[$_] =~ s/^([-+])//) {
|
||
|
$sign = $1;
|
||
|
if ($sign eq '-') {
|
||
|
$parity = -1;
|
||
|
} else {
|
||
|
$parity = 1;
|
||
|
}
|
||
|
}
|
||
|
if ($parity == 0) {
|
||
|
&status("zero parity mode change... ignored");
|
||
|
} else {
|
||
|
if ($parity > 0) {
|
||
|
$channels{$chan}{$m}{$t} = '+';
|
||
|
} else {
|
||
|
delete $channels{$chan}{$mode}{$t};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub entryEvt {
|
||
|
my ($nick, $user, $host, $type, $chan) = @_;
|
||
|
if ($type=~/PART/) {
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> $nick ($user\@$host) has left $chan");
|
||
|
} else {
|
||
|
&status(">>> $nick ($user\@$host) has left $chan");
|
||
|
}
|
||
|
} elsif ($type=~/JOIN/) {
|
||
|
if ($netsplit) {
|
||
|
foreach (keys(%snick)) {
|
||
|
if ($nick eq $snick{$_}) {
|
||
|
@be = split (/ /);
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> ${b}Netjoined$ob: $be[0] $be[1]");
|
||
|
} else {
|
||
|
&status(">>> ${b}Netjoined$ob: $be[0] $be[1]");
|
||
|
}
|
||
|
$netsplit--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> $nick ($user\@$host) has joined $chan");
|
||
|
} else {
|
||
|
&status(">>> $nick ($user\@$host) has joined $chan");
|
||
|
}
|
||
|
} elsif ($type=~/QUIT/) {
|
||
|
$chan=~s/\r//;
|
||
|
if ($chan=~/^([\d\w\_\-\/]+\.[\.\d\w\_\-\/]+)\s([\d\w\_\-\/]+\.[\.\d\w\_\-\/]+)$/) {
|
||
|
$i=0;
|
||
|
while (0 and ($i < $netsplit || !$netsplit)) {
|
||
|
# while ($i < $netsplit || !$netsplit) {
|
||
|
$i++;
|
||
|
if (($prevsplit1{$i} ne $2) && ($prevsplit2{$i} ne $1)) {
|
||
|
&status("Netsplit: $2 split from $1");
|
||
|
$netsplit++;
|
||
|
$prevsplit1{$netsplit} = $2;
|
||
|
$prevsplit2{$netsplit} = $1;
|
||
|
$snick{"$2 $1"}=$nick;
|
||
|
$schan{"$2 $1"}=$chan;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> $b$nick$ob has signed off IRC ($b$chan$ob)");
|
||
|
} else {
|
||
|
&status(">>> $b$nick$ob has signed off IRC ($b$chan$ob)");
|
||
|
}
|
||
|
}
|
||
|
} elsif ($type=~/NICK/) {
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> ".c($nick,'bold green').
|
||
|
" materializes into ".c($chan,'bold green'));
|
||
|
} else {
|
||
|
&status(">>> $b$nick$ob materializes into $b$chan$ob");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub procevent {
|
||
|
my ($nick, $user, $host, $type, $chan, $msg) = @_;
|
||
|
|
||
|
# support global $nuh, $who
|
||
|
$nuh = "$nick!$user\@$host";
|
||
|
|
||
|
if ($type=~/PRIVMSG/) {
|
||
|
if ($chan =~ /^$ischan/) {
|
||
|
## It's a public message on the channel##
|
||
|
$chan =~ tr/A-Z/a-z/;
|
||
|
|
||
|
if ($msg =~ /\001(.*)\001/ && $msg !~ /ACTION/) {
|
||
|
#### Client To Client Protocol ####
|
||
|
parsectcp($nick, $user, $host, $1, $chan);
|
||
|
} elsif ($msg !~ /ACTION\s(.+)/) {
|
||
|
#### Public Channel Message ####
|
||
|
&IrcMsgHook('public', $chan, $nick, $msg);
|
||
|
} else {
|
||
|
#### Public Action ####
|
||
|
&IrcActionHook($nick, $chan, $1);
|
||
|
}
|
||
|
} else {
|
||
|
## Is Private ##
|
||
|
if ($msg=~/\001(.*)\001/) {
|
||
|
#### Client To Client Protocol ####
|
||
|
parsectcp($nick, $user, $host, $1, $chan);
|
||
|
} else {
|
||
|
#### Is a Private Message ##
|
||
|
&IrcMsgHook('private', $chan, $nick, $msg);
|
||
|
}
|
||
|
}
|
||
|
} elsif ($type=~/NOTICE/) {
|
||
|
if ($chan =~ /^$ischan/) {
|
||
|
$chan =~ tr/A-Z/a-z/;
|
||
|
if ($msg !~ /ACTION (.*)/) {
|
||
|
&status("-$nick/$chan- $msg");
|
||
|
} else {
|
||
|
&status("* $nick/$chan $1");
|
||
|
}
|
||
|
} else {
|
||
|
if ($msg=~/\001([A-Z]*)\s(.*)\001/) {
|
||
|
ctcpReplyParse($nick, $user, $host, $1, $2);
|
||
|
} else {
|
||
|
&status("-$nick($user\@$host)- $msg");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub servmsg {
|
||
|
my $msg=$_[0];
|
||
|
my ($ucount, $uc) = (0, 0);
|
||
|
if ($msg=~/^001/) {
|
||
|
# joinChan(split/\s+/, $param{'join_channels'});
|
||
|
# Line in infobot.config:
|
||
|
# join_channels #chan,key #chan_with_no_key
|
||
|
#
|
||
|
# since , is not allowed in channels, we'll use it to specify keys
|
||
|
# without breaking current join_channels format
|
||
|
for (split /\s+/, $param{'join_channels'}) {
|
||
|
# if it's a keyed chan, replace the comma with a space so it'll
|
||
|
# work as per the RFC (i.e. JOIN #chan key)
|
||
|
s/,/ /;
|
||
|
joinChan ($_);
|
||
|
}
|
||
|
$nicktries=0;
|
||
|
} elsif ($msg=~/^NOTICE ($ident) :(.*)/) {
|
||
|
serverNotice($1,$2);
|
||
|
} elsif ($msg=~/^332 $ident ($ischan) :(.*)/) {
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> topic for $b$1$ob: $2");
|
||
|
} else {
|
||
|
&status(">>> topic for $1: $2");
|
||
|
}
|
||
|
} elsif ($msg=~/^333 $ident $ischan (.*) (.*)$/) {
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> set by $b$1$ob at $b$2$ob");
|
||
|
} else {
|
||
|
&status(">>> set by $1 at $2");
|
||
|
}
|
||
|
} elsif ($msg=~/^433/) {
|
||
|
++$nicktries;
|
||
|
if (length($param{wantNick}) > 9) {
|
||
|
$ident = chop $param{wantNick};
|
||
|
$ident .= $nicktries;
|
||
|
} else {
|
||
|
$ident = $param{wantNick}.$nicktries;
|
||
|
}
|
||
|
if ($param{'opername'}) {
|
||
|
&rawout("OPER $param{opername} $param{operpass}");
|
||
|
}
|
||
|
$param{nick} = $ident;
|
||
|
&status("*** Nickname $param{wantNick} in use, trying $ident");
|
||
|
rawout("NICK $ident");
|
||
|
|
||
|
} elsif ($msg=~/[0-9]+ $ident . ($ischan) :(.*)/) {
|
||
|
my ($chan, $users) = ($1, $2);
|
||
|
&status("NAMES $chan: $users");
|
||
|
my $u;
|
||
|
foreach $u (split /\s+/, $users) {
|
||
|
if (s/\@//) {
|
||
|
$channels{$chan}{o}{$u}++;
|
||
|
}
|
||
|
if (s/\+//) {
|
||
|
$channels{$chan}{v}{$u}++;
|
||
|
}
|
||
|
}
|
||
|
} elsif ($msg=~/[0-9]{3} $ident(\s$ischan)*?\s:(.*)/) {
|
||
|
&status("$2");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub serverNotice {
|
||
|
($type, $msg) = @_;
|
||
|
if ($type=~/AUTH/) {
|
||
|
&status("!$param{server}! $msg");
|
||
|
} else {
|
||
|
$msg =~ s/\*\*\* Notice -- //;
|
||
|
&status("-!$param{server}!- $msg");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub OperWall {
|
||
|
my ($nick, $msg) = @_;
|
||
|
$msg=~s/\*\*\* Notice -- //;
|
||
|
&status("[wallop($nick)] $msg");
|
||
|
}
|
||
|
|
||
|
sub prockick {
|
||
|
my ($kicker, $chan, $knick, $why) = @_;
|
||
|
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> $b$knick$ob was kicked off $b$chan$ob by $b$kicker$ob ($b$why$ob)");
|
||
|
} else {
|
||
|
&status(">>> $b$knick$ob was kicked off $b$chan$ob by $b$kicker$ob ($b$why$ob)");
|
||
|
}
|
||
|
if ($knick eq $ident) {
|
||
|
&status("SELF attempting to rejoin lost channel $chan");
|
||
|
&joinChan($chan);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub prockill {
|
||
|
my ($killer, $knick, $kserv, $killnick, $why) = @_;
|
||
|
if ($knick eq $ident) {
|
||
|
&status("KILLED by $killnick ($why)");
|
||
|
} else {
|
||
|
&status("KILL $knick by $killnick ($why)");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub fhbits {
|
||
|
local (@fhlist) = split(' ',$_[0]);
|
||
|
local ($bits);
|
||
|
for (@fhlist) {
|
||
|
vec($bits,fileno($_),1) = 1;
|
||
|
}
|
||
|
$bits;
|
||
|
}
|
||
|
|
||
|
sub irc {
|
||
|
local ($rin, $rout);
|
||
|
local ($buf, $line);
|
||
|
|
||
|
$nicktries=0;
|
||
|
$connected=1;
|
||
|
while ($connected) {
|
||
|
srvConnect($param{server}, $param{port});
|
||
|
|
||
|
if ($param{server_pass}) { # ksiero++
|
||
|
rawout("PASS $param{server_pass}");
|
||
|
}
|
||
|
|
||
|
rawout("NICK $param{wantNick}");
|
||
|
rawout("USER $param{ircuser} $param{ident} $param{server} :$param{realname}");
|
||
|
if ($param{operator}) {
|
||
|
rawout("OPER $param{operName} $param{operPass}\n");
|
||
|
}
|
||
|
$param{nick} = $param{wantNick};
|
||
|
$ident = $param{wantNick};
|
||
|
|
||
|
$/ = "\015" if $^O eq "MacOS";
|
||
|
|
||
|
$rin = fhbits('SOCK');
|
||
|
while (1) {
|
||
|
($nfound,$timeleft) = select($rout=$rin, undef, undef, 0);
|
||
|
if ($rout & SOCK) {
|
||
|
if (sysread(SOCK,$buf,1) <= 0) {
|
||
|
last;
|
||
|
}
|
||
|
if ($buf=~/\n/) {
|
||
|
$line.=$buf;
|
||
|
sparse($line);
|
||
|
undef $line;
|
||
|
} else {
|
||
|
$line.=$buf;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#Corion++
|
||
|
# Fixed baaaad backdor in server parsing (regexes are a bitch :( )
|
||
|
# /msg infobot :a@b.c PRIVMSG #channel seen <nick>
|
||
|
# can be used to flood a channel witout getting ever caught !
|
||
|
|
||
|
# Affected lines were
|
||
|
# PRIVMSG / NOTICE / TOPIC / KICK
|
||
|
|
||
|
sub sparse {
|
||
|
$_ = $_[0];
|
||
|
s/\r//;
|
||
|
|
||
|
if (/^PING :(\S+)/) { # Pings are important
|
||
|
rawout("PONG :$1");
|
||
|
&status("SELF replied to server PING") if $param{VERBOSITY} > 2;
|
||
|
} elsif (/^:\S+ ([\d]{3} .*)/) {
|
||
|
servmsg($1);
|
||
|
} elsif (/^:([\d\w\_\-\/]+\.[\.\d\w\_\-\/]+) NOTICE ($ident) :(.*)/) {
|
||
|
&status("\-\[$1\]- $3");
|
||
|
} elsif (/^NOTICE (.*) :(.*)/) {
|
||
|
serverNotice($1, $2);
|
||
|
} elsif (/^:NickServ!s\@NickServ NOTICE \S+ :(.*)/i) {
|
||
|
&nickServ($1); # added by the xk.
|
||
|
} elsif (/^:ChanServ!s\@ChanServ NOTICE \S+ :(.*)/i) {
|
||
|
&chanServ($1); # added by the xk.
|
||
|
} elsif (/^:(\S+)!(\S+)@(\S+)\s(PRIVMSG|NOTICE)\s([\#\&]?\S+)\s:(.*)/) {
|
||
|
procevent($1,$2,$3,$4,$5,$6);
|
||
|
} elsif (/^:(\S+)!(\S+)@(\S+)\s(PART|JOIN|NICK|QUIT)\s:?(.*)/) {
|
||
|
entryEvt($1,$2,$3,$4,$5);
|
||
|
} elsif (/^:(.*) WALLOPS :(.*)/) {
|
||
|
OperWall($1,$2);
|
||
|
} elsif (/^:(.*)!(.*)@(.*) (MODE) (.*)/) {
|
||
|
procmode($1,$2,$3,$4,$5);
|
||
|
} elsif (/^:(.*) (MODE) (.*)/) {
|
||
|
procservmode($1,$2,$3);
|
||
|
} elsif (/^:(\S+)!(?:\S+)@(?:\S+) KICK ((\#|&).+) (.*) :(.*)/) {
|
||
|
prockick($1,$2,$4,$5);
|
||
|
} elsif (/^ERROR :(.*)/) {
|
||
|
&status("ERROR $1");
|
||
|
} elsif (/^:([^! ]+)!\S+@\S+ TOPIC (\#.+) :(.*)/) {
|
||
|
if ($param{ansi_control}) {
|
||
|
&status(">>> $1$b\[$ob$2$b\]$ob set the topic: $3");
|
||
|
} else {
|
||
|
&status(">>> $1\[$2\] set the topic: $3");
|
||
|
}
|
||
|
} elsif (/^:(\S+)!\S+@\S+ KILL (.*) :(.*)!(.*) \((.*)\)/) {
|
||
|
prockill($1,$2,$3,$4,$5);
|
||
|
} else {
|
||
|
&status("UNKNOWN $_");
|
||
|
}
|
||
|
#Corion--
|
||
|
}
|
||
|
|
||
|
1;
|