if (&IsParam("useStrict")) { use strict; }
+use vars qw($nickserv);
+$nickserv = 0;
+
# static scalar variables.
$mask{ip} = '(\d+)\.(\d+)\.(\d+)\.(\d+)';
$mask{host} = '[\d\w\_\-\/]+\.[\.\d\w\_\-\/]+';
-$mask{chan} = '[\#\&\+]\S*';
+$mask{chan} = '[\#\&]\S*|_default';
my $isnick1 = 'a-zA-Z\[\]\{\}\_\`\^\|\\\\';
my $isnick2 = '0-9\-';
$mask{nick} = "[$isnick1]{1}[$isnick1$isnick2]*";
+$mask{nuh} = '\S*!\S*\@\S*';
sub ircloop {
my $error = 0;
my $lastrun = 0;
- while (1) {
+loop:;
+ while (my $host = shift @ircServers) {
# JUST IN CASE. irq was complaining about this.
if ($lastrun == time()) {
+ &DEBUG("ircloop: hrm... lastrun == time()");
$error++;
- sleep 1;
+ sleep 10;
next;
}
- foreach (@ircServers) {
- if (!defined $_) {
- &DEBUG("ircloop: ircServers[x] = NULL.");
- $lastrun = time();
- next;
- }
- &DEBUG("ircloop: _ => '$_'.");
- next unless (exists $ircPort{$_});
+ if (!defined $host) {
+ &DEBUG("ircloop: ircServers[x] = NULL.");
+ $lastrun = time();
+ next;
+ }
+ next unless (exists $ircPort{$host});
- my $retval = &irc($_, $ircPort{$_});
- next unless (defined $retval and $retval == 0);
- $error++;
- if ($error % 3 == 0 and $error != 0) {
- &ERROR("CANNOT connect to this server; next!");
- next;
- }
+ my $retval = &irc($host, $ircPort{$host});
+ &DEBUG("ircloop: after irc()");
- if ($error >= 3*3) {
- &ERROR("CANNOT connect to any irc server; stopping.");
- exit 1;
- }
+ next unless (defined $retval and $retval == 0);
+
+ $error++;
+
+ if ($error % 3 == 0 and $error != 0) {
+ &ERROR("CANNOT connect to this server; next!");
+ next;
+ }
+
+ if ($error >= 3*3) {
+ &ERROR("CANNOT connect to any irc server; stopping.");
+ exit 1;
}
}
+
+ &DEBUG("ircloop: end... going back.");
+ &loadIRCServers();
+ goto loop;
}
sub irc {
select STDOUT;
&status("Connecting to port $port of server $server ...");
- sleep 3; # lame hack.
# host->ip.
if ($server =~ /\D$/) {
my $resolve = inet_ntoa($packed);
&status(" resolved to $resolve.");
+ ### warning in Sys/Hostname line 78???
+ ### caused inside Net::IRC?
}
$irc = new Net::IRC;
return 1;
}
+ &clearIRCVars();
+
# change internal timeout value for scheduler.
$irc->{_timeout} = 10; # how about 60?
- # clear out hashes before connecting...
- &clearIRCVars();
-
- $ident = $param{'ircNick'};
- ### IRCSTATS.
- $ircstats{'ConnectTime'} = time();
- $ircstats{'ConnectCount'}++;
- $ircstats{'Server'} = "$server:$port";
+ $ircstats{'Server'} = "$server:$port";
# handler stuff.
$conn->add_handler('caction', \&on_action);
$conn->add_handler('cping', \&on_ping);
$conn->add_handler('crping', \&on_ping_reply);
$conn->add_handler('cversion', \&on_version);
-
+ $conn->add_handler('crversion', \&on_crversion);
$conn->add_handler('dcc_open', \&on_dcc_open);
$conn->add_handler('dcc_close', \&on_dcc_close);
$conn->add_handler('chat', \&on_chat);
$conn->add_global_handler(352, \&on_who);
$conn->add_global_handler(353, \&on_names);
$conn->add_global_handler(366, \&on_endofnames);
- $conn->add_global_handler(376, \&on_endofmotd);
+ $conn->add_global_handler(376, \&on_endofmotd); # on_connect.
$conn->add_global_handler(433, \&on_nick_taken);
$conn->add_global_handler(439, \&on_targettoofast);
+ # for proper joinnextChan behaviour
+ $conn->add_global_handler(471, \&on_chanfull);
+ $conn->add_global_handler(473, \&on_inviteonly);
+ $conn->add_global_handler(474, \&on_banned);
+ $conn->add_global_handler(475, \&on_badchankey);
+
# end of handler stuff.
$irc->start;
sub say {
my ($msg) = @_;
- if (!defined $msg or $msg eq $noreply) {
+ if (!defined $msg) {
$msg ||= "NULL";
- &DEBUG("say: msg == $msg.");
- return;
- }
-
- if ($msg eq $last{say} and length($msg) > 256) {
- &status("say: detected repeated message; skipping.");
+ &WARN("say: msg == $msg.");
return;
}
- $last{say} = $msg;
&status("</$talkchannel> $msg");
if (&whatInterface() =~ /IRC/) {
- $msg = "zero" if ($msg =~ /^0+$/);
+ $msg = "zero" if ($msg =~ /^0+$/);
+ my $t = time();
+
+ if ($t == $pubtime) {
+ $pubcount++;
+ $pubsize += length $msg;
+
+ if ( ($pubcount % 4) == 0 and $pubcount) {
+ sleep 1;
+ } elsif ($pubsize > 1500) {
+ sleep 1;
+ $pubsize -= 1500;
+ }
+
+ } else {
+ $pubcount = 0;
+ $pubtime = $t;
+ $pubsize = length $msg;
+ }
$conn->privmsg($talkchannel, $msg);
}
return;
}
- if (!defined $msg or $msg eq $noreply) {
+ if (!defined $msg) {
$msg ||= "NULL";
- &DEBUG("msg: msg == $msg.");
- return;
- }
-
- if ($msg eq $last{msg} and length($msg) > 256) {
- &status("msg: detected repeated message; skipping.");
+ &WARN("msg: msg == $msg.");
return;
}
- $last{msg} = $msg;
&status(">$nick< $msg");
- $conn->privmsg($nick, $msg) if (&whatInterface() =~ /IRC/);
+
+ if (&whatInterface() =~ /IRC/) {
+ my $t = time();
+
+ if ($t == $msgtime) {
+ $msgcount++;
+ $msgsize += length $msg;
+
+ if ( ($msgcount % 4) == 0 and $msgcount) {
+ sleep 1;
+ } elsif ($msgsize > 1000) {
+ sleep 1;
+ $msgsize -= 1000;
+ }
+
+ } else {
+ $msgcount = 0;
+ $msgtime = $t;
+ $msgsize = length $msg;
+ }
+
+ $conn->privmsg($nick, $msg);
+ }
}
# Usage: &action(nick || chan, txt);
sub action {
my ($target, $txt) = @_;
if (!defined $txt) {
- &DEBUG("action: txt == NULL.");
+ &WARN("action: txt == NULL.");
return;
}
rawout($rawout);
}
-# Usage: &action(nick || chan, txt);
-sub notice{
+# Usage: ¬ice(nick || chan, txt);
+sub notice {
my ($target, $txt) = @_;
if (!defined $txt) {
- &DEBUG("action: txt == NULL.");
+ &WARN("notice: txt == NULL.");
return;
}
&status("-$target- $txt");
+ my $t = time();
+
+ if ($t == $nottime) {
+ $notcount++;
+ $notsize += length $txt;
+
+ if ( ($notcount % 4) == 0 and $notcount) {
+ sleep 1;
+ } elsif ($notsize > 1500) {
+ sleep 1;
+ $notsize -= 1500;
+ }
+
+ } else {
+ $notcount = 0;
+ $nottime = $t;
+ $notsize = length $txt;
+ }
+
$conn->notice($target, $txt);
}
sub DCCBroadcast {
- my ($txt) = @_;
+ my ($txt,$flag) = @_;
- foreach (keys %{$dcc{'CHAT'}}) {
+ ### FIXME: flag not supported yet.
+
+ foreach (keys %{ $dcc{'CHAT'} }) {
$conn->privmsg($dcc{'CHAT'}{$_}, $txt);
}
}
&performReply(@_);
}
+sub pSReply {
+ &performStrictReply(@_);
+}
+
# Usage: &performStrictReply($reply);
sub performStrictReply {
my ($reply) = @_;
} elsif ($msgType eq 'public') {
&say($reply);
} elsif ($msgType eq 'chat') {
- if (!exists $dcc{'CHAT'}{$who}) {
- &WARN("pSR: dcc{'CHAT'}{$who} does not exist.");
- return;
- }
- $conn->privmsg($dcc{'CHAT'}{$who}, $reply);
+ &dccsay(lc $who,$reply);
} else {
&ERROR("pSR: msgType invalid? ($msgType).");
}
+}
+
+sub dccsay {
+ my ($who, $reply) = @_;
+ if (!exists $dcc{'CHAT'}{$who}) {
+ &WARN("pSR: dcc{'CHAT'}{$who} does not exist.");
+ return '';
+ }
+
+ &status("=>$who<= $reply"); # dcc chat.
+ $conn->privmsg($dcc{'CHAT'}{$who}, $reply);
+}
+
+sub dcc_close {
+ my($who) = @_;
+ my $type;
- return '';
+ foreach $type (keys %dcc) {
+ &FIXME("dcc_close: $who");
+ my @who = grep /^\Q$who\E$/i, keys %{ $dcc{$type} };
+ next unless (scalar @who);
+ $who = $who[0];
+ }
}
sub joinchan {
if (&validChan($chan)) {
&status("join: already on $chan");
} else {
- $conn->join($chan);
+ if (!$conn->join($chan)) {
+ &DEBUG("joinchan: join failed. trying connect!");
+ $conn->connect();
+ }
}
}
return;
}
- &DEBUG("MODE $chan $modes");
+ &DEBUG("mode: MODE $chan $modes");
rawout("MODE $chan $modes");
}
my ($chan, @who) = @_;
my $os = "o" x scalar(@who);
- &mode($chan, "+$os ".@who);
+ &mode($chan, "+$os @who");
}
sub deop {
sub ban {
my ($mask,$chan) = @_;
- my (@chans) = ($chan eq "") ? (keys %channels) : lc($chan);
+ my (@chans) = ($chan =~ /^\*?$/) ? (keys %channels) : lc($chan);
+ my $ban = 0;
- if ($chan ne "" and &validChan($chan) == 0) {
+ if ($chan !~ /^\*?$/ and &validChan($chan) == 0) {
&ERROR("ban: invalid channel $chan.");
return;
}
- $nick =~ tr/A-Z/a-z/;
-
foreach $chan (@chans) {
- if (!&IsNickInChan($nick,$chan) and scalar @chans == 1) {
- &status("Ban: $nick is not on $chan.");
- next;
- }
-
if (!exists $channels{$chan}{o}{$ident}) {
&status("Ban: do not have ops on $chan :(");
next;
&status("Banning $mask from $chan.");
&rawout("MODE $chan +b $mask");
+ $ban++;
}
+
+ return $ban;
+}
+
+sub unban {
+ my ($mask,$chan) = @_;
+ my (@chans) = ($chan =~ /^\*?$/) ? (keys %channels) : lc($chan);
+ my $ban = 0;
+
+ &DEBUG("unban: mask = $mask, chan = @chans");
+
+ foreach $chan (@chans) {
+ if (!exists $channels{$chan}{o}{$ident}) {
+ &status("unBan: do not have ops on $chan :(");
+ next;
+ }
+
+ &status("Removed ban $mask from $chan.");
+ &rawout("MODE $chan -b $mask");
+ $ban++;
+ }
+
+ return $ban;
}
sub quit {
my ($nick) = @_;
if ($nick =~ /^$mask{nick}$/) {
+ &DEBUG("nick: Changing nick to $nick (from $ident)");
rawout("NICK ".$nick);
return 1;
}
+ &DEBUG("nick: failed... why oh why (nick => $nick)");
return 0;
}
# Usage: &joinNextChan();
sub joinNextChan {
+ &DEBUG("joinNextChan called.");
+
if (scalar @joinchan) {
- my $chan = shift @joinchan;
+ $chan = shift @joinchan;
&joinchan($chan);
if (my $i = scalar @joinchan) {
&status("joinNextChan: $i chans to join.");
}
- } else {
- return unless (&IsParam("chanServ_ops"));
- if (!$nickserv) {
- &DEBUG("jNC: nickserv/chanserv not up?");
- }
- my @chans = split(/[\s\t]+/, $param{'chanServ_ops'});
- foreach $chan (keys %channels) {
- next unless (grep /^$chan$/i, @chans);
+ # chanserv check: channel specific.
+ &chanServCheck($chan);
+
+ } else {
+ # chanserv check: global channels, in case we missed one.
- if (!exists $channels{$chan}{'o'}{$ident}) {
- &status("ChanServ ==> Requesting ops for $chan.");
- &rawout("PRIVMSG ChanServ :OP $chan $ident");
- }
+ foreach ( &ChanConfList("chanServ_ops") ) {
+ &chanServCheck($_);
}
}
}
my @array;
foreach (keys %channels) {
- next unless (grep /^\Q$nick\E$/i, keys %{$channels{$_}{''}});
+ next unless (grep /^\Q$nick\E$/i, keys %{ $channels{$_}{''} });
push(@array, $_);
}
return @array;
}
+# Usage: &GetNicksInChan($chan);
+sub GetNicksInChan {
+ my ($chan) = @_;
+ my @array;
+
+ return keys %{ $channels{$chan}{''} };
+}
+
sub IsNickInChan {
my ($nick,$chan) = @_;
return 0;
}
- if (grep /^\Q$nick\E$/i, keys %{$channels{$chan}{''}}) {
+ if (grep /^\Q$nick\E$/i, keys %{ $channels{$chan}{''} }) {
return 1;
} else {
+ foreach (keys %channels) {
+ next unless (/[A-Z]/);
+ &DEBUG("iNIC: hash channels contains mixed cased chan!!!");
+ }
return 0;
}
}
my ($nick) = @_;
foreach $chan (keys %channels) {
- next unless (grep /^\Q$nick\E$/i, keys %{$channels{$chan}{''}});
+ next unless (grep /^\Q$nick\E$/i, keys %{ $channels{$chan}{''} });
return 1;
}
return 0;
my ($mode,$chan);
foreach $chan (@chans) {
- foreach $mode (keys %{$channels{$chan}}) {
+ foreach $mode (keys %{ $channels{$chan} }) {
# use grep here?
next unless (exists $channels{$chan}{$mode}{$nick});
}
sub clearIRCVars {
- &DEBUG("clearIRCVars() called!");
- %channels = ();
- @joinchan = split /[\t\s]+/, $param{'join_channels'};
+### &DEBUG("clearIRCVars() called!");
+ undef %channels;
+ undef %floodjoin;
+
+ @joinchan = &getJoinChans();
}
-sub makeChanList {
- my ($str) = @_;
- my $inverse = 0;
+sub getJoinChans {
my @chans;
+ my @skip;
- if ($str eq "ALL") {
- return(keys %channels);
- } elsif ($str =~ s/^ALL but //i) {
- @chans = keys %channels;
- foreach (split /[\s\t\,]+/, lc $str) {
- @chans = grep !/^$_$/, @chans;
+ foreach (keys %chanconf) {
+ next if ($_ eq "_default");
+
+ my $val = $chanconf{$_}{autojoin};
+ my $skip = 0;
+
+ if (defined $val) {
+ $skip++ if ($val eq "0");
+ } else {
+ $skip++;
}
- } else {
- foreach (split /[\s\t\,]+/, lc $str) {
- next unless (&validChan($_));
- push(@chans, $_);
+
+ if ($skip) {
+ push(@skip, $_);
+ next;
}
+
+ push(@chans, $_);
}
- @chans;
+ if (scalar @skip) {
+ &status("gJC: channels not auto-joining: @skip");
+ } else {
+ &status("gJC: auto-joining all chans.");
+ }
+
+ return @chans;
}
sub closeDCC {
+### &DEBUG("closeDCC called.");
+
foreach $type (keys %dcc) {
- foreach (keys %{$dcc{$type}}) {
- &DEBUG("closing DCC $type to $_ (FIXME).");
-### $irc->removeconn($dcc{$type}{$_});
+ next if ($type ne uc($type));
+
+ foreach $nick (keys %{ $dcc{$type} }) {
+ next unless (defined $nick);
+ &DEBUG("closing DCC $type to $nick (FIXME).");
+ next unless (defined $dcc{$type}{$nick});
+
+ my $ref = $dcc{$type}{$nick};
+ &DEBUG("ref => $ref");
+
+# $dcc{$type}{$nick}->close();
}
}
}
+sub joinfloodCheck {
+ my($who,$chan,$userhost) = @_;
+
+ return unless (&IsChanConf("joinfloodCheck"));
+
+ if (exists $netsplit{lc $who}) { # netsplit join.
+ &DEBUG("joinfloodCheck: $who was in netsplit; not checking.");
+ }
+
+ if (exists $floodjoin{$chan}{$who}{Time}) {
+ &WARN("floodjoin{$chan}{$who} already exists?");
+ }
+
+ $floodjoin{$chan}{$who}{Time} = time();
+ $floodjoin{$chan}{$who}{Host} = $userhost;
+
+ ### Check...
+ foreach (keys %floodjoin) {
+ my $c = $_;
+ my $count = scalar keys %{ $floodjoin{$c} };
+ next unless ($count > 5);
+ &DEBUG("joinflood: count => $count");
+
+ my $time;
+ foreach (keys %{ $floodjoin{$c} }) {
+ $time += $floodjoin{$c}{$_}{Time};
+ }
+ &DEBUG("joinflood: time => $time");
+ $time /= $count;
+
+ &DEBUG("joinflood: new time => $time");
+ }
+
+ ### Clean it up.
+ my $delete = 0;
+ foreach $chan (keys %floodjoin) {
+ foreach $who (keys %{ $floodjoin{$chan} }) {
+ my $time = time() - $floodjoin{$chan}{$who}{Time};
+ next unless ($time > 10);
+ delete $floodjoin{$chan}{$who};
+ $delete++;
+ }
+ }
+
+ &DEBUG("joinfloodCheck: $delete deleted.") if ($delete);
+}
+
+sub getHostMask {
+ my($n) = @_;
+
+ &FIXME("getHostMask...");
+}
+
1;