]> git.donarmstrong.com Git - infobot.git/blobdiff - src/IRC/Irc.pl
* Add vim formatting comments ( # vim:ts=4:sw=4:expandtab:tw=80 )
[infobot.git] / src / IRC / Irc.pl
index c551a87f3b4f82800290bd581445b9238735dcb2..c89c0db41616a95abce9df3a0a9564d9612d509c 100644 (file)
@@ -6,18 +6,28 @@
 #
 
 use strict;
+
 no strict 'refs';
+no strict 'subs'; # IN/STDIN
 
-use vars qw(%floodjoin %nuh %dcc %cache %channels %param %mask
+use vars qw(%floodjoin %nuh %dcc %cache %conns %channels %param %mask
        %chanconf %orig %ircPort %ircstats %last %netsplit);
-use vars qw($irc $nickserv $ident $conn $msgType $who $talkchannel
-       $addressed);
+use vars qw($irc $nickserv $conn $msgType $who $talkchannel
+       $addressed $postprocess);
 use vars qw($notcount $nottime $notsize $msgcount $msgtime $msgsize
                $pubcount $pubtime $pubsize);
 use vars qw($b_blue $ob);
-use vars qw(@joinchan @ircServers);
+use vars qw(@ircServers);
+
+#use open ':utf8';
+#use open ':std';
 
 $nickserv      = 0;
+# It's probably closer to 510, but let's be cautious until we calculate it extensively.
+my $maxlinelen = 490;
+
+# Keep track of last time we displayed Chans: to avoid spam in logs
+my $lastChansTime = 0;
 
 sub ircloop {
     my $error  = 0;
@@ -66,14 +76,18 @@ loop:;
 sub irc {
     my ($server,$port) = @_;
 
+    $irc = new Net::IRC;
+
+    # TODO: move all this to an sql table
     my $iaddr = inet_aton($server);
     my $paddr = sockaddr_in($port, $iaddr);
     my $proto = getprotobyname('tcp');
 
-    select STDOUT;
-    &status("Connecting to port $port of server $server ...");
+    # why was this here?
+    #select STDOUT;
 
     # host->ip.
+    my $resolve;
     if ($server =~ /\D$/) {
        my $packed = scalar(gethostbyname($server));
 
@@ -82,14 +96,11 @@ sub irc {
            return 0;
        }
 
-       my $resolve = inet_ntoa($packed);
-       &status("  resolved to $resolve.");
+       $resolve = inet_ntoa($packed);
        ### warning in Sys/Hostname line 78???
        ### caused inside Net::IRC?
     }
 
-    $irc = new Net::IRC;
-
     my %args = (
                Nick    => $param{'ircNick'},
                Server  => $server,
@@ -99,22 +110,64 @@ sub irc {
     $args{'LocalAddr'} = $param{'ircHost'} if ($param{'ircHost'});
     $args{'Password'} = $param{'ircPasswd'} if ($param{'ircPasswd'});
 
-    my $conn = $irc->newconn(%args);
-
-    if (!defined $conn) {
-       &ERROR("IRC: connection failed.");
-       &ERROR("add \"set ircHost 0.0.0.0\" to your config. If that does not work");
-       &ERROR("Please check /etc/hosts to see if you have a localhost line like:");
-       &ERROR("127.0.0.1   localhost    localhost");
-       &ERROR("If this is still a problem, please contact the maintainer.");
-       return 1;
-    }
-
-    if ($param{'ircNick2'}) {
-       # prep for real multiple nick/server connects
-       # FIXME: all locations should get nick/server out of self, not config
-       $args{'Nick'} = $param{'ircNick2'};
-       my $conn = $irc->newconn(%args);
+    foreach my $mynick (split ',', $param{'ircNick'}) {
+       &status("Connecting to port $port of server $server ($resolve) as $mynick ...");
+       $args{'Nick'} = $mynick;
+       $conns{$mynick} = $irc->newconn(%args);
+       if (!defined $conns{$mynick}) {
+           &ERROR("IRC: connection failed.");
+           &ERROR("add \"set ircHost 0.0.0.0\" to your config. If that does not work");
+           &ERROR("Please check /etc/hosts to see if you have a localhost line like:");
+           &ERROR("127.0.0.1   localhost    localhost");
+           &ERROR("If this is still a problem, please contact the maintainer.");
+       }
+       $conns{$mynick}->maxlinelen($maxlinelen);
+       # handler stuff.
+       $conns{$mynick}->add_global_handler('caction',  \&on_action);
+       $conns{$mynick}->add_global_handler('cdcc',     \&on_dcc);
+       $conns{$mynick}->add_global_handler('cping',    \&on_ping);
+       $conns{$mynick}->add_global_handler('crping',   \&on_ping_reply);
+       $conns{$mynick}->add_global_handler('cversion', \&on_version);
+       $conns{$mynick}->add_global_handler('crversion',        \&on_crversion);
+       $conns{$mynick}->add_global_handler('dcc_open', \&on_dcc_open);
+       $conns{$mynick}->add_global_handler('dcc_close',        \&on_dcc_close);
+       $conns{$mynick}->add_global_handler('chat',     \&on_chat);
+       $conns{$mynick}->add_global_handler('msg',      \&on_msg);
+       $conns{$mynick}->add_global_handler('public',   \&on_public);
+       $conns{$mynick}->add_global_handler('join',     \&on_join);
+       $conns{$mynick}->add_global_handler('part',     \&on_part);
+       $conns{$mynick}->add_global_handler('topic',    \&on_topic);
+       $conns{$mynick}->add_global_handler('invite',   \&on_invite);
+       $conns{$mynick}->add_global_handler('kick',     \&on_kick);
+       $conns{$mynick}->add_global_handler('mode',     \&on_mode);
+       $conns{$mynick}->add_global_handler('nick',     \&on_nick);
+       $conns{$mynick}->add_global_handler('quit',     \&on_quit);
+       $conns{$mynick}->add_global_handler('notice',   \&on_notice);
+       $conns{$mynick}->add_global_handler('whoischannels', \&on_whoischannels);
+       $conns{$mynick}->add_global_handler('useronchannel', \&on_useronchannel);
+       $conns{$mynick}->add_global_handler('whois',    \&on_whois);
+       $conns{$mynick}->add_global_handler('other',    \&on_other);
+       $conns{$mynick}->add_global_handler('disconnect', \&on_disconnect);
+       $conns{$mynick}->add_global_handler([251,252,253,254,255], \&on_init);
+#      $conns{$mynick}->add_global_handler(302, \&on_init); # userhost
+       $conns{$mynick}->add_global_handler(303, \&on_ison); # notify.
+       $conns{$mynick}->add_global_handler(315, \&on_endofwho);
+       $conns{$mynick}->add_global_handler(422, \&on_endofwho); # nomotd.
+       $conns{$mynick}->add_global_handler(324, \&on_modeis);
+       $conns{$mynick}->add_global_handler(333, \&on_topicinfo);
+       $conns{$mynick}->add_global_handler(352, \&on_who);
+       $conns{$mynick}->add_global_handler(353, \&on_names);
+       $conns{$mynick}->add_global_handler(366, \&on_endofnames);
+       $conns{$mynick}->add_global_handler(376, \&on_endofmotd); # on_connect.
+       $conns{$mynick}->add_global_handler(433, \&on_nick_taken);
+       $conns{$mynick}->add_global_handler(439, \&on_targettoofast);
+       # for proper joinnextChan behaviour
+       $conns{$mynick}->add_global_handler(471, \&on_chanfull);
+       $conns{$mynick}->add_global_handler(473, \&on_inviteonly);
+       $conns{$mynick}->add_global_handler(474, \&on_banned);
+       $conns{$mynick}->add_global_handler(475, \&on_badchankey);
+       $conns{$mynick}->add_global_handler(443, \&on_useronchan);
+       # end of handler stuff.
     }
 
     &clearIRCVars();
@@ -126,53 +179,11 @@ sub irc {
 
     $ircstats{'Server'}        = "$server:$port";
 
-    # handler stuff.
-       $conn->add_global_handler('caction',    \&on_action);
-       $conn->add_global_handler('cdcc',       \&on_dcc);
-       $conn->add_global_handler('cping',      \&on_ping);
-       $conn->add_global_handler('crping',     \&on_ping_reply);
-       $conn->add_global_handler('cversion',   \&on_version);
-       $conn->add_global_handler('crversion',  \&on_crversion);
-       $conn->add_global_handler('dcc_open',   \&on_dcc_open);
-       $conn->add_global_handler('dcc_close',  \&on_dcc_close);
-       $conn->add_global_handler('chat',       \&on_chat);
-       $conn->add_global_handler('msg',        \&on_msg);
-       $conn->add_global_handler('public',     \&on_public);
-       $conn->add_global_handler('join',       \&on_join);
-       $conn->add_global_handler('part',       \&on_part);
-       $conn->add_global_handler('topic',      \&on_topic);
-       $conn->add_global_handler('invite',     \&on_invite);
-       $conn->add_global_handler('kick',       \&on_kick);
-       $conn->add_global_handler('mode',       \&on_mode);
-       $conn->add_global_handler('nick',       \&on_nick);
-       $conn->add_global_handler('quit',       \&on_quit);
-       $conn->add_global_handler('notice',     \&on_notice);
-       $conn->add_global_handler('whoischannels', \&on_whoischannels);
-       $conn->add_global_handler('useronchannel', \&on_useronchannel);
-       $conn->add_global_handler('whois',      \&on_whois);
-       $conn->add_global_handler('other',      \&on_other);
-       $conn->add_global_handler('disconnect', \&on_disconnect);
-       $conn->add_global_handler([251,252,253,254,255], \&on_init);
-#      $conn->add_global_handler(302, \&on_init); # userhost
-       $conn->add_global_handler(303, \&on_ison); # notify.
-       $conn->add_global_handler(315, \&on_endofwho);
-       $conn->add_global_handler(422, \&on_endofwho); # nomotd.
-       $conn->add_global_handler(324, \&on_modeis);
-       $conn->add_global_handler(333, \&on_topicinfo);
-       $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); # 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);
-       $conn->add_global_handler(443, \&on_useronchan);
+    # works? needs to actually do something
+    # should likely listen on a tcp port instead
+    #$irc->addfh(STDIN, \&on_stdin, 'r');
 
-    # end of handler stuff.
+    &status("starting main loop");
 
     $irc->start;
 }
@@ -185,7 +196,7 @@ sub rawout {
     my ($buf) = @_;
     $buf =~ s/\n//gi;
 
-    # slow down a bit if traffic is "high".
+    # slow down a bit if traffic is 'high'.
     # need to take into account time of last message sent.
     if ($last{buflen} > 256 and length($buf) > 256) {
        sleep 1;
@@ -198,39 +209,57 @@ sub rawout {
 
 sub say {
     my ($msg) = @_;
+    my $mynick = $conn->nick();
     if (!defined $msg) {
-       $msg ||= "NULL";
+       $msg ||= 'NULL';
        &WARN("say: msg == $msg.");
        return;
     }
 
-    &status("</$talkchannel> $msg");
-    if (&whatInterface() =~ /IRC/) {
-       $msg    = "zero" if ($msg =~ /^0+$/);
-       my $t   = time();
+    if (&getChanConf('silent', $talkchannel) and not
+      (&IsFlag("s") and &verifyUser($who,$nuh{lc $who}))) {
+       &DEBUG("say: silent in $talkchannel, not saying $msg");
+       return;
+    }
 
-       if ($t == $pubtime) {
-           $pubcount++;
-           $pubsize += length $msg;
+    if ( $postprocess ) {
+       undef $postprocess;
+    } elsif ($postprocess = &getChanConf('postprocess', $talkchannel)) {
+       &DEBUG("say: $postprocess $msg");
+       &parseCmdHook($postprocess . ' ' . $msg);
+       undef $postprocess;
+       return;
+    }
 
-           my $i = &getChanConfDefault("sendPublicLimitLines", 3);
-           my $j = &getChanConfDefault("sendPublicLimitBytes", 1000);
+    &status("<$mynick/$talkchannel> $msg");
 
-           if ( ($pubcount % $i) == 0 and $pubcount) {
-               sleep 1;
-           } elsif ($pubsize > $j) {
-               sleep 1;
-               $pubsize -= $j;
-           }
+    return unless (&whatInterface() =~ /IRC/);
 
-       } else {
-           $pubcount   = 0;
-           $pubtime    = $t;
-           $pubsize    = length $msg;
+    $msg = 'zero' if ($msg =~ /^0+$/);
+
+    my $t = time();
+
+    if ($t == $pubtime) {
+       $pubcount++;
+       $pubsize += length $msg;
+
+       my $i = &getChanConfDefault('sendPublicLimitLines', 3, $chan);
+       my $j = &getChanConfDefault('sendPublicLimitBytes', 1000, $chan);
+
+       if ( ($pubcount % $i) == 0 and $pubcount) {
+           sleep 1;
+       } elsif ($pubsize > $j) {
+           sleep 1;
+           $pubsize -= $j;
        }
 
-       $conn->privmsg($talkchannel, $msg);
+    } else {
+       $pubcount       = 0;
+       $pubtime        = $t;
+       $pubsize        = length $msg;
     }
+
+    $conn->privmsg($talkchannel, $msg);
 }
 
 sub msg {
@@ -241,11 +270,18 @@ sub msg {
     }
 
     if (!defined $msg) {
-       $msg ||= "NULL";
+       $msg ||= 'NULL';
        &WARN("msg: msg == $msg.");
        return;
     }
 
+    # some say() end up here (eg +help)
+    if (&getChanConf('silent', $nick) and not
+       (&IsFlag("s") and &verifyUser($who,$nuh{lc $who}))) {
+       &DEBUG("msg: silent in $nick, not saying $msg");
+       return;
+    }
+
     &status(">$nick< $msg");
 
     return unless (&whatInterface() =~ /IRC/);
@@ -255,8 +291,8 @@ sub msg {
        $msgcount++;
        $msgsize += length $msg;
 
-       my $i = &getChanConfDefault("sendPrivateLimitLines", 3);
-       my $j = &getChanConfDefault("sendPrivateLimitBytes", 1000);
+       my $i = &getChanConfDefault('sendPrivateLimitLines', 3, $chan);
+       my $j = &getChanConfDefault('sendPrivateLimitBytes', 1000, $chan);
        if ( ($msgcount % $i) == 0 and $msgcount) {
            sleep 1;
        } elsif ($msgsize > $j) {
@@ -275,18 +311,25 @@ sub msg {
 
 # Usage: &action(nick || chan, txt);
 sub action {
+    my $mynick = $conn->nick();
     my ($target, $txt) = @_;
     if (!defined $txt) {
        &WARN("action: txt == NULL.");
        return;
     }
 
+    if (&getChanConf('silent', $target) and not
+       (&IsFlag("s") and &verifyUser($who,$nuh{lc $who}))) {
+       &DEBUG("action: silent in $target, not doing $txt");
+       return;
+    }
+
     if (length $txt > 480) {
        &status("action: txt too long; truncating.");
        chop($txt) while (length $txt > 480);
     }
 
-    &status("* $ident/$target $txt");
+    &status("* $mynick/$target $txt");
     $conn->me($target, $txt);
 }
 
@@ -306,8 +349,8 @@ sub notice {
        $notcount++;
        $notsize += length $txt;
 
-       my $i = &getChanConfDefault("sendNoticeLimitLines", 3);
-       my $j = &getChanConfDefault("sendNoticeLimitBytes", 1000);
+       my $i = &getChanConfDefault('sendNoticeLimitLines', 3, $chan);
+       my $j = &getChanConfDefault('sendNoticeLimitBytes', 1000, $chan);
 
        if ( ($notcount % $i) == 0 and $notcount) {
            sleep 1;
@@ -350,6 +393,11 @@ sub performReply {
 
     $reply =~ /([\.\?\s]+)$/;
 
+    # FIXME need real throttling....
+    if (length($reply) > $maxlinelen - 30) {
+       $reply = substr($reply, 0, $maxlinelen - 33);
+       $reply =~ s/ [^ ]*?$/ .../;
+    }
     &checkMsgType($reply);
 
     if ($msgType eq 'public') {
@@ -384,14 +432,15 @@ sub performAddressedReply {
     &performReply(@_);
 }
 
-sub pSReply {
-    &performStrictReply(@_);
-}
-
 # Usage: &performStrictReply($reply);
 sub performStrictReply {
     my ($reply) = @_;
 
+    # FIXME need real throttling....
+    if (length($reply) > $maxlinelen - 30) {
+       $reply = substr($reply, 0, $maxlinelen - 33);
+       $reply =~ s/ [^ ]*?$/ .../;
+    }
     &checkMsgType($reply);
 
     if ($msgType eq 'private') {
@@ -436,31 +485,34 @@ sub dcc_close {
 }
 
 sub joinchan {
-    my ($chan) = @_;
-    my $key    = &getChanConf("chankey", $chan) || "";
+    my ($chan, $key) = @_;
+    $key ||= &getChanConf('chankey', $chan);
+    $key ||= '';
 
     # forgot for about 2 years to implement channel keys when moving
     # over to Net::IRC...
 
     # hopefully validChan is right.
     if (&validChan($chan)) {
-       &status("join: already on $chan");
-    } else {
-       &status("joining $b_blue$chan$ob");
+       &status("join: already on $chan?");
+    }
+    #} else {
+       &status("joining $b_blue$chan $key$ob");
 
        return if ($conn->join($chan, $key));
+       return if (&validChan($chan));
 
        &DEBUG("joinchan: join failed. trying connect!");
        &clearIRCVars();
        $conn->connect();
-    }
+    #}
 }
 
 sub part {
     my $chan;
 
     foreach $chan (@_) {
-       next if ($chan eq "");
+       next if ($chan eq '');
        $chan =~ tr/A-Z/a-z/;   # lowercase.
 
        if ($chan !~ /^$mask{chan}$/) {
@@ -496,23 +548,24 @@ sub mode {
 
 sub op {
     my ($chan, @who) = @_;
-    my $os     = "o" x scalar(@who);
+    my $os     = 'o' x scalar(@who);
 
     &mode($chan, "+$os @who");
 }
 
 sub deop {
     my ($chan, @who) = @_;
-    my $os = "o" x scalar(@who);
+    my $os = 'o' x scalar(@who);
 
     &mode($chan, "-$os ".@who);
 }
 
 sub kick {
     my ($nick,$chan,$msg) = @_;
-    my (@chans) = ($chan eq "") ? (keys %channels) : lc($chan);
+    my (@chans) = ($chan eq '') ? (keys %channels) : lc($chan);
+    my $mynick = $conn->nick();
 
-    if ($chan ne "" and &validChan($chan) == 0) {
+    if ($chan ne '' and &validChan($chan) == 0) {
        &ERROR("kick: invalid channel $chan.");
        return;
     }
@@ -525,7 +578,7 @@ sub kick {
            next;
        }
 
-       if (!exists $channels{$chan}{o}{$ident}) {
+       if (!exists $channels{$chan}{o}{$mynick}) {
            &status("kick: do not have ops on $chan :(");
            next;
        }
@@ -538,6 +591,7 @@ sub kick {
 sub ban {
     my ($mask,$chan) = @_;
     my (@chans) = ($chan =~ /^\*?$/) ? (keys %channels) : lc($chan);
+    my $mynick = $conn->nick();
     my $ban    = 0;
 
     if ($chan !~ /^\*?$/ and &validChan($chan) == 0) {
@@ -546,7 +600,7 @@ sub ban {
     }
 
     foreach $chan (@chans) {
-       if (!exists $channels{$chan}{o}{$ident}) {
+       if (!exists $channels{$chan}{o}{$mynick}) {
            &status("ban: do not have ops on $chan :(");
            next;
        }
@@ -562,12 +616,13 @@ sub ban {
 sub unban {
     my ($mask,$chan) = @_;
     my (@chans) = ($chan =~ /^\*?$/) ? (keys %channels) : lc($chan);
+    my $mynick = $conn->nick();
     my $ban    = 0;
 
     &DEBUG("unban: mask = $mask, chan = @chans");
 
     foreach $chan (@chans) {
-       if (!exists $channels{$chan}{o}{$ident}) {
+       if (!exists $channels{$chan}{o}{$mynick}) {
            &status("unBan: do not have ops on $chan :(");
            next;
        }
@@ -591,45 +646,36 @@ sub quit {
 }
 
 sub nick {
-    my ($nick) = @_;
+    my ($newnick) = @_;
+    my $mynick = $conn->nick();
 
-    if (!defined $nick) {
+    if (!defined $newnick) {
        &ERROR("nick: nick == NULL.");
        return;
     }
 
-    if (defined $ident and $nick eq $ident) {
-       &WARN("nick: nick == ident == '$ident'.");
+    if (!defined $mynick) {
+       &WARN("nick: mynick == NULL.");
        return;
     }
 
-    my $bad     = 0;
-    $bad++ if (exists $nuh{$conn->nick()});
-    $bad++ if (&IsNickInAnyChan($conn->nick()));
+    my $bad = 0;
+    $bad++ if (exists $nuh{$newnick});
+    $bad++ if (&IsNickInAnyChan($newnick));
 
     if ($bad) {
-       &WARN("Nick: not going to try and get my nick back. [".
-               scalar(gmtime). "]");
-# hrm... over time we lose track of our own nick.
-#      return;
+       &WARN("Nick: not going to try to change from $mynick to $newnick. [". scalar(gmtime). "]");
+       # hrm... over time we lose track of our own nick.
+       #return;
     }
 
-    if ($nick =~ /^$mask{nick}$/) {
-       &rawout("NICK ".$nick);
-
-       if (defined $ident) {
-           &status("nick: Changing nick to $nick (from $ident)");
-           # following shouldn't be here :(
-           $ident      = $nick;
-       } else {
-           &DEBUG("first time nick change.");
-           $ident      = $nick;
-       }
-
+    if ($newnick =~ /^$mask{nick}$/) {
+       &status("nick: Changing nick from $mynick to $newnick");
+       # ->nick() will NOT change cause we are using rawout?
+       &rawout("NICK $newnick");
        return 1;
     }
-    &DEBUG("nick: failed... why oh why (nick => $nick)");
-
+    &DEBUG("nick: failed... why oh why (mynick=$mynick, newnick=$newnick)");
     return 0;
 }
 
@@ -646,30 +692,37 @@ sub invite {
 
 # Usage: &joinNextChan();
 sub joinNextChan {
-    if (scalar @joinchan) {
-       my $chan = shift @joinchan;
-       &joinchan($chan);
-
-       if (my $i = scalar @joinchan) {
-           &status("joinNextChan: $i chans to join.");
+    my $joined = 0;
+    foreach (sort keys %conns) {
+       $conn = $conns{$_};
+       my $mynick = $conn->nick();
+       my @join = getJoinChans(1);
+
+       if (scalar @join) {
+           my $chan = shift @join;
+           &joinchan($chan);
+
+           if (my $i = scalar @join) {
+               &status("joinNextChan: $mynick $i chans to join.");
+           }
+           $joined = 1;
        }
-
-       return;
     }
+    return if $joined;
 
-    # !scalar @joinchan:
-    my @c      = &getJoinChans();
-    if (exists $cache{joinTime} and scalar @c) {
+    if (exists $cache{joinTime}) {
        my $delta       = time() - $cache{joinTime} - 5;
        my $timestr     = &Time2String($delta);
-       my $rate        = sprintf("%.1f", $delta / @c);
+       # FIXME: @join should be @in instead (hacked to 10)
+       #my $rate       = sprintf("%.1f", $delta / @in);
+       my $rate        = sprintf("%.1f", $delta / 10);
        delete $cache{joinTime};
 
        &status("time taken to join all chans: $timestr; rate: $rate sec/join");
     }
 
     # chanserv check: global channels, in case we missed one.
-    foreach ( &ChanConfList("chanServ_ops") ) {
+    foreach ( &ChanConfList('chanServ_ops') ) {
        &chanServCheck($_);
     }
 }
@@ -785,51 +838,67 @@ sub clearIRCVars {
     undef %channels;
     undef %floodjoin;
 
-    @joinchan          = &getJoinChans(1);
     $cache{joinTime}   = time();
 }
 
 sub getJoinChans {
-    my($show)  = @_;
-    my @chans;
+    # $show should contain the min number of seconds between display
+    # of the Chans: status line. Use 0 to disable
+    my $show = shift;
+
+    my @in;
     my @skip;
+    my @join;
+
+    # Display "Chans:" only if more than $show seconds since last display
+    if (time() - $lastChansTime > $show) {
+       $lastChansTime = time();
+    } else {
+       $show = 0; # Don't display since < 15min since last
+    }
+
+    # can't join any if not connected
+    return @join if (!$conn);
+
+    my $nick = $conn->nick();
 
     foreach (keys %chanconf) {
-       next if ($_ eq "_default");
+       next if ($_ eq '_default');
 
        my $skip = 0;
        my $val = $chanconf{$_}{autojoin};
 
        if (defined $val) {
-           $skip++ if ($val eq "0");
-           if (($conn) and ($val eq "1")) {
+           $skip++ if ($val eq '0');
+           if ($val eq '1') {
                # convert old +autojoin to autojoin <nick>
-               $val = $conn->nick();
+               $val = lc $nick;
                $chanconf{$_}{autojoin} = $val;
            }
+           $skip++ if (lc $val ne lc $nick);
        } else {
            $skip++;
        }
 
        if ($skip) {
            push(@skip, $_);
-       } elsif (($conn) and ($conn->nick() eq $val)) {
-           push(@chans, $_);
        } else {
-           push(@skip, $_);
+           if (defined $channels{$_} or exists $channels{$_}) {
+               push(@in, $_);
+           } else {
+               push(@join, $_);
+           }
        }
     }
 
     my $str;
-    if (scalar @skip) {
-       $str = "channels not auto-joining: @skip (joining: @chans)";
-    } else {
-       $str = "auto-joining all chans: @chans";
-    }
+    $str .= ' in:' . join(',', sort @in) if scalar @in;
+    $str .= ' skip:' . join(',', sort @skip) if scalar @skip;
+    $str .= ' join:' . join(',', sort @join) if scalar @join;
 
-    &status("Chans: ".$str) if ($show);
+    &status("Chans: ($nick)$str") if ($show);
 
-    return sort @chans;
+    return sort @join;
 }
 
 sub closeDCC {
@@ -858,7 +927,7 @@ sub closeDCC {
 sub joinfloodCheck {
     my($who,$chan,$userhost) = @_;
 
-    return unless (&IsChanConf("joinfloodCheck"));
+    return unless (&IsChanConf('joinfloodCheck') > 0);
 
     if (exists $netsplit{lc $who}) {   # netsplit join.
        &DEBUG("joinfloodCheck: $who was in netsplit; not checking.");
@@ -922,3 +991,5 @@ sub getHostMask {
 }
 
 1;
+
+# vim:ts=4:sw=4:expandtab:tw=80