my $arg = $3;
if (!defined $arg or $arg =~ /^\s*$/) {
+ # this is fucking ugly but it works :-)
my $x = (&dbRawReturn("SELECT SUM(counter) FROM stats WHERE type=".&dbQuote($type) ))[0];
+ my %hash = &dbGetCol("stats", "nick,counter", "type=".&dbQuote($type).
+ " ORDER BY nick DESC LIMIT 3", 1);
+ my $i;
+ my @top;
+ # unfortunately we have to sort it again!
+ # todo: make dbGetCol return hash and array? too much effort.
+ foreach $i (sort { $b <=> $a } keys %hash) {
+ foreach (keys %{ $hash{$i} }) {
+ push(@top, "$_ - $i");
+ }
+ }
+ my $topstr = "";
+ if (scalar @top) {
+ $topstr = ". Top ".scalar(@top).": ".join(', ', @top);
+ }
if (defined $x) {
- &pSReply("total count of '$type': $x");
+ &pSReply("total count of '$type': $x$topstr");
} else {
&pSReply("zero counter for '$type'.");
}
sub readUserFile {
my $f = "$bot_misc_dir/blootbot.users";
+ if (! -f $f) {
+ &DEBUG("userfile not found; new fresh run detected.");
+ return;
+ }
+
if ( -f $f and -f "$f~") {
my $s1 = -s $f;
my $s2 = -s "$f~";
&msg($who, $reply);
} elsif ($msgType eq 'chat') {
if (!exists $dcc{'CHAT'}{$who}) {
- &WARN("pSR: dcc{'CHAT'}{$who} does not exist.");
+ &VERB("pSR: dcc{'CHAT'}{$who} does not exist.",2);
return;
}
$conn->privmsg($dcc{'CHAT'}{$who}, $reply);
} elsif ($msgType eq 'public') {
&say($reply);
} elsif ($msgType eq 'chat') {
- &dccsay(lc $who,$reply);
+ &dccsay(lc $who, $reply);
} else {
&ERROR("pSR: msgType invalid? ($msgType).");
}
}
sub dccsay {
- my ($who, $reply) = @_;
+ my($who, $reply) = @_;
+
+ if (!defined $reply or $reply =~ /^\s*$/) {
+ &WARN("dccsay: reply == NULL.");
+ return;
+ }
+
if (!exists $dcc{'CHAT'}{$who}) {
- &WARN("pSR: dcc{'CHAT'}{$who} does not exist.");
- return '';
+ &VERB("pSR: dcc{'CHAT'}{$who} does not exist. (2)",2);
+ return;
}
&status("=>$who<= $reply"); # dcc chat.
my @who = grep /^\Q$who\E$/i, keys %{ $dcc{$type} };
next unless (scalar @who);
$who = $who[0];
+ &DEBUG("dcc_close... close $who!");
}
}
}
sub closeDCC {
-### &DEBUG("closeDCC called.");
+# &DEBUG("closeDCC called.");
foreach $type (keys %dcc) {
next if ($type ne uc($type));
foreach $nick (keys %{ $dcc{$type} }) {
next unless (defined $nick);
- &DEBUG("closing DCC $type to $nick (FIXME).");
+ &status("DCC CHAT: closing DCC $type to $nick.");
next unless (defined $dcc{$type}{$nick});
my $ref = $dcc{$type}{$nick};
- &DEBUG("ref => $ref");
-
-# $dcc{$type}{$nick}->close();
+ &dccsay($nick, "bye bye, $nick") if ($type =~ /^chat$/i);
+ $dcc{$type}{$nick}->close();
+ delete $dcc{$type}{$nick};
+ &DEBUG("after close for $nick");
}
+ delete $dcc{$type};
}
}
# modes w/ target affecting nick => cache it.
if ($mode =~ /[bov]/) {
- if ($mode eq "o" and $nick eq "ChanServ" and $target =~ /^\Q$ident\E$/i) {
- &VERB("hookmode: chanserv deopped us! asking",2);
- &chanServCheck($chan);
- }
-
$channels{$chan}{$mode}{$target}++ if $parity;
delete $channels{$chan}{$mode}{$target} if !$parity;
+
+ # lets do some custom stuff.
+ if ($mode eq "o" and $parity) {
+ if ($nick eq "ChanServ" and $target =~ /^\Q$ident\E$/i) {
+ &VERB("hookmode: chanserv deopped us! asking",2);
+ &chanServCheck($chan);
+ }
+
+ &chanLimitVerify($chan);
+ }
}
if ($mode =~ /[l]/) {
return;
}
+# this is basically run on on_join or on_quit
sub chanLimitVerify {
- my($chan) = @_;
+ my($c) = @_;
+ $chan = $c;
my $l = $channels{$chan}{'l'};
- &DEBUG("cLV: netsplitservers: ".scalar(keys %netsplitservers) );
- &DEBUG("cLV: netsplit: ".scalar(keys %netsplit) );
+ return unless (&IsChanConf("chanlimitcheck"));
if (scalar keys %netsplit) {
- &WARN("clV: netsplit active (1); skipping.");
+ &WARN("clV: netsplit active (1, chan = $chan); skipping.");
+ return;
+ }
+
+ if (!defined $l) {
+ &DEBUG("running chanlimitCheck from chanLimitVerify; FIXME! (chan = $chan)");
+ &chanlimitCheck();
return;
}
# only change it if it's not set.
- if (defined $l and &IsChanConf("chanlimitcheck")) {
- my $plus = &getChanConfDefault("chanlimitcheckPlus", 5, $chan);
- my $count = scalar(keys %{ $channels{$chan}{''} });
- my $int = &getChanConfDefault("chanlimitcheckInterval", 10, $chan);
+ my $plus = &getChanConfDefault("chanlimitcheckPlus", 5, $chan);
+ my $count = scalar(keys %{ $channels{$chan}{''} });
+ my $int = &getChanConfDefault("chanlimitcheckInterval", 10, $chan);
- my $delta = $count + $plus - $l;
- $delta =~ s/^\-//;
+ my $delta = $count + $plus - $l;
+# $delta =~ s/^\-//;
- if ($plus <= 3) {
- &WARN("clc: stupid to have plus at $plus, fix it!");
- }
+ if ($plus <= 3) {
+ &WARN("clc: stupid to have plus at $plus, fix it!");
+ }
- if (exists $cache{chanlimitChange}{$chan}) {
- if (time() - $cache{chanlimitChange}{$chan} < $int*60) {
- return;
- }
+ if (exists $cache{chanlimitChange}{$chan}) {
+ if (time() - $cache{chanlimitChange}{$chan} < $int*60) {
+ return;
}
+ }
- &chanServCheck($chan);
+ &chanServCheck($chan);
- ### todo: unify code with chanlimitcheck()
- if ($delta > 5) {
- &status("clc: big change in limit; going for it.");
- &rawout("MODE $chan +l ".($count+$plus) );
- $cache{chanlimitChange}{$chan} = time();
- }
- }
+ ### todo: unify code with chanlimitcheck()
+ return if ($delta > 5);
+
+ &status("clc: big change in limit for $chan ($delta);".
+ "going for it. (was: $l; now: ".($count+$plus).")");
+
+ &rawout("MODE $chan +l ".($count+$plus) );
+ $cache{chanlimitChange}{$chan} = time();
}
sub chanServCheck {
my $crypto = $users{$userHandle}{PASS};
my $success = 0;
+ if ($userHandle eq "_default") {
+ &WARN("DCC CHAT: _default/guest not allowed.");
+ return;
+ }
+
### TODO: prevent users without CRYPT chatting.
if (!defined $crypto) {
&DEBUG("todo: dcc close chat");
# first time run.
if (!exists $users{_default}) {
- &status("First time run... adding _default user.");
+ &status("!!! First time run... adding _default user.");
$users{_default}{FLAGS} = "mrt";
- $users{_default}{HOSTS} = "*!*@*";
+ $users{_default}{HOSTS}{"*!*@*"} = 1;
}
if (scalar keys %users < 2) {
- &status("Ok... now /msg $ident PASS <pass> to get master access through DCC CHAT.");
+ &status("!"x40);
+ &status("!!! Ok. Now type '/msg $ident PASS <pass>' to get master access through DCC CHAT.");
+ &status("!"x40);
}
# end of first time run.
} elsif ($type eq 'GET') { # SEND for us?
&status("DCC: Initializing SEND for $nick.");
$self->new_send($event->args);
+
} elsif ($type eq 'CHAT') {
&status("DCC: Initializing CHAT for $nick.");
$self->new_chat($event);
+
} else {
&WARN("${b_green}DCC $type$ob (1)");
}
} else {
&WARN("${b_green}DCC $type$ob (3)");
-
}
}
if (!exists $users{$userHandle}{HOSTS}) {
&pSReply("you have no hosts defined in my user file; rejecting.");
- ### TODO: $sock->close();
+ $sock->close();
return;
}
my $crypto = $users{$userHandle}{PASS};
$dcc{'CHAT'}{$nick} = $sock;
+ # todo: don't make DCC CHAT established in the first place.
+ if ($userHandle eq "_default") {
+ &dccsay($nick, "_default/guest not allowed");
+ $sock->close();
+ return;
+ }
+
if (defined $crypto) {
+ &status("DCC CHAT: going to use ".$nick."'s crypt.");
&dccsay($nick,"Enter your password.");
} else {
- &dccsay($nick,"Welcome to blootbot DCC CHAT interface, $userHandle.");
+# &dccsay($nick,"Welcome to blootbot DCC CHAT interface, $userHandle.");
}
}
delete $cache{warn}{chanlimit}{$chan};
if (!defined $limit) {
- &status("ChanLimit: setting for first time or from netsplit, for $chan");
+ &status("chanLimit: setting for first time or from netsplit, for $chan");
}
if (exists $cache{chanlimitChange}{$chan}) {
my $delta = time() - $cache{chanlimitChange}{$chan};
if ($delta < $interval*60) {
- &DEBUG("not going to change chanlimit! ($delta<$interval*60)");
+ &DEBUG("chanLimit: not going to change chanlimit! ($delta<$interval*60)");
return;
}
}
&DEBUG("running netsplitCheck... $cache{netsplitCache}");
if (!scalar %netsplit and scalar %netsplitservers) {
- &DEBUG("nsc: FIRST!!! ok hash netsplit is NULL; purging hash netsplitservers");
+ &DEBUG("nsC: !hash netsplit but hash netsplitservers <- removing!");
undef %netsplitservers;
+ return;
}
+ # well... this shouldn't happen since %netsplit code does it anyway.
foreach $s1 (keys %netsplitservers) {
foreach $s2 (keys %{ $netsplitservers{$s1} }) {
my $delta = time() - $netsplitservers{$s1}{$s2};
- if ($delta > 3600) {
+ if ($delta > 60*30) {
&status("netsplit between $s1 and $s2 appears to be stale.");
delete $netsplitservers{$s1}{$s2};
&chanlimitCheck();
# %netsplit hash checker.
my $count = scalar keys %netsplit;
- my(@delete);
+ my $delete = 0;
foreach (keys %netsplit) {
- if (&IsNickInAnyChan($_)) {
- &DEBUG("netsplitC: $_ is in some chan; removing from netsplit list.");
+ if (&IsNickInAnyChan($_)) { # why would this happen?
+# &DEBUG("nsC: $_ is in some chan; removing from netsplit list.");
delete $netsplit{$_};
+ $delete++;
next;
}
- # todo: change time value?
- next unless (time() - $netsplit{$_} > 60*30);
- push(@delete, $_);
+ next unless (time() - $netsplit{$_} > 60*15);
+
+ $delete++;
delete $netsplit{$_};
}
- if (@delete) {
- my $str = scalar(@delete)."/".scalar(keys %netsplit);
- &DEBUG("removed from netsplit list ($str): @delete");
+ if ($delete) {
+ my $j = scalar(keys %netsplit);
+ &DEBUG("nsC: removed from netsplit list: (before: $count; after: $j)");
}
- &DEBUG("nsC: netsplitservers: ".scalar(keys %netsplitservers) );
- &DEBUG("nsC: netsplit: ".scalar(keys %netsplit) );
if (!scalar %netsplit and scalar %netsplitservers) {
- &DEBUG("nsc: ok hash netsplit is NULL; purging hash netsplitservers");
+ &DEBUG("nsC: ok hash netsplit is NULL; purging hash netsplitservers");
undef %netsplitservers;
}
my $backup = 0;
if (! -f $file) {
- &WARN("mkB: file '$file' does not exist.");
+ &VERB("mkB: file '$file' does not exist.",2);
return;
}
my ($type) = @_;
if ($type =~ /^author$/i) {
- my %hash = &dbGetCol("factoids", "factoid_key","created_by");
+ my %hash = &dbGetCol("factoids", "factoid_key,created_by", "created_by IS NOT NULL");
my %author;
foreach (keys %hash) {
} elsif ($type =~ /^broken$/i) {
&status("factstats(broken): starting...");
my $start_time = &timeget();
- my %data = &dbGetCol("factoids", "factoid_key","factoid_value");
+ my %data = &dbGetCol("factoids", "factoid_key,factoid_value", "factoid_value IS NOT NULL");
my @list;
my $delta_time = &timedelta($start_time);
} elsif ($type =~ /^dup(licate|e)$/i) {
&status("factstats(dupe): starting...");
my $start_time = &timeget();
- my %hash = &dbGetCol("factoids", "factoid_key", "factoid_value", 1);
+ my %hash = &dbGetCol("factoids", "factoid_key,factoid_value", "factoid_value IS NOT NULL", 1);
my $refs = 0;
my @list;
my $v;
return &formListReply(1, $prefix, @list);
} elsif ($type =~ /^locked$/i) {
- my %hash = &dbGetCol("factoids", "factoid_key","locked_by");
+ my %hash = &dbGetCol("factoids", "factoid_key,locked_by", "locked_by IS NOT NULL");
my @list = keys %hash;
for (@list) {
return &formListReply(0, $prefix, @list);
} elsif ($type =~ /^new$/i) {
- my %hash = &dbGetCol("factoids", "factoid_key","created_time");
+ my %hash = &dbGetCol("factoids", "factoid_key,created_time", "created_time IS NOT NULL");
my %age;
foreach (keys %hash) {
return &formListReply(1, $prefix, @list);
} elsif ($type =~ /^profanity$/i) {
- my %data = &dbGetCol("factoids", "factoid_key","factoid_value");
+ my %data = &dbGetCol("factoids", "factoid_key,factoid_value", "factoid_value IS NOT NULL");
my @list;
foreach (keys %data) {
return &formListReply(1, $prefix, @newlist);
} elsif ($type =~ /^request(ed)?$/i) {
- my %hash = &dbGetCol("factoids", "factoid_key", "requested_count",1);
+ my %hash = &dbGetCol("factoids", "factoid_key,requested_count", "requested_count IS NOT NULL", 1);
if (!scalar keys %hash) {
return 'sorry, no factoids have been questioned.';
my $prefix = "factoid statistics on $type ";
return &formListReply(0, $prefix, @list);
+ } elsif ($type =~ /^reqrate$/i) {
+ my %hash = &dbGetCol("factoids",
+ "factoid_key,(unix_timestamp() - created_time)/requested_count as rate",
+ "requested_by IS NOT NULL and created_time IS NOT NULL ORDER BY rate LIMIT 15", 1);
+
+ my $rate;
+ my @list;
+ my $total = 0;
+ my $users = 0;
+ foreach $rate (sort { $b <=> $a } keys %hash) {
+ my $f = join(", ", sort keys %{ $hash{$rate} });
+ push(@list, "$f - ".&Time2String($rate));
+ }
+
+ my $prefix = "Rank of top factoid rate (time/req): ";
+ return &formListReply(0, $prefix, @list);
+
} elsif ($type =~ /^requesters?$/i) {
- my %hash = &dbGetCol("factoids", "factoid_key","requested_by");
+ my %hash = &dbGetCol("factoids", "factoid_key,requested_by", "requested_by IS NOT NULL");
my %requester;
foreach (keys %hash) {
}
my $timestr = &::Time2String(time() - $newest);
&::msg($::who, "|= Last updated $timestr ago.");
- &::msg($::who, " \037Num\037 \037Item ".(" "x40)." \037");
+ &::msg($::who, " \037Num\037 \037Item ".(" "x40)." \037");
my $i = 1;
foreach ( &getNewsAll() ) {
my $subtopic = $_;
my $setby = $::news{$chan}{$subtopic}{Author};
+ my $chr = (exists $::News{$chan}{$subtopic}{Text}) ? "" : "*";
if (!defined $subtopic) {
&::DEBUG("news: warn: subtopic == undef.");
}
# todo: show request stats aswell.
- &::msg($::who, sprintf("\002[\002%2d\002]\002 %s",
- $i, $subtopic));
+ &::msg($::who, sprintf("\002[\002%2d\002]\002%s %s",
+ $i, $chr, $subtopic));
$i++;
}
+ my $z = $::newsuser{$::who};
+ if (defined $z) {
+ &::DEBUG("cache $::who: $z");
+ } else {
+ &::DEBUG("cache: $::who doesn't have newscache set.");
+ }
+
&::msg($::who, "|= End of News.");
&::msg($::who, "use 'news read <#>' or 'news read <keyword>'");
}
}
my $t = $::newsuser{$chan}{$who};
+ if (defined $t) {
+ &::DEBUG("newsuser: $chan/$who == $t");
+ } else {
+ &::DEBUG("newsuser: $chan/$who == undefined");
+ }
+
if (defined $t and ($t == 0 or $t == -1)) {
if ($flag) {
&::notice($::who, "if you want to read news, try /msg $::ident news or /msg $::ident news notify");
# !scalar @new, $flag
if (!scalar @new and $flag) {
- &::notice($::who, "no new news for $chan.");
+ &::notice($::who, "no new news for $chan for $who.");
+ # valid to set this?
+ $::newsuser{$chan}{$who} = time();
return;
}
&status("rootwarn: Detected root user; notifying user");
} else {
&status("rootwarn: Detected root user; notifying nick and channel.");
- rawout("PRIVMSG $chan :R".("O" x int(rand 70 + 2))."T has landed!");
+ rawout("PRIVMSG $chan :ROO".("O" x int(rand 68))."T has landed!");
}
if ($_ = &getFactoid("root")) {
if (scalar @args == 1) { # del pass.
if (!&IsFlag("n") and $who !~ /^\Q$verifyUser\E$/i) {
- &pSReply("cannto remove passwd of others.");
+ &pSReply("cannot remove passwd of others.");
return;
}
# 'pass'
if ($msgType =~ /private/ and $message =~ s/^pass//i) {
$message =~ s/^\s+|\s+$//g;
- my @array = split / /, $message;
+ my @array = split ' ', $message;
if ($who =~ /^_default$/i) {
&pSReply("you are too eleet.");
}
# todo: use &getUser()?
- my $first = (scalar keys %users) ? 1 : 0;
+ my $first = (scalar keys %users < 2) ? 1 : 0;
+
if (!exists $users{$who} and !$first) {
&pSReply("nick $who is not in user list.");
return;
}
if ($first) {
- &pSReply("first time user... adding you as master.");
+ &pSReply("First time user... adding you as Master.");
$users{$who}{FLAGS} = "mrsteon";
}
if (!scalar keys %{ $users{$who}{HOSTS} }) {
my $mask = "*!$user@".&makeHostMask($host);
- &pSReply("added mask $mask to $who.");
+ &pSReply("Added hostmask '\002$mask\002' to $who");
$users{$who}{HOSTS}{$mask} = 1;
}
return 0;
}
+ $chan ||= "_default";
+
my $old = $chan;
if ($chan =~ tr/A-Z/a-z/) {
&WARN("IsChanConf: lowercased chan. ($old)");
}
#####
-# Usage: &dbGetCol($table, $primkey, $key, [$type]);
+# Usage: &dbGetCol($table, $select, $where, [$type]);
sub dbGetCol {
- my ($table, $primkey, $key, $type) = @_;
- my $query = "SELECT $primkey,$key FROM $table WHERE $key IS NOT NULL";
+ my ($table, $select, $where, $type) = @_;
+ my $query = "SELECT $select FROM $table";
+ $query .= " WHERE ".$where if ($where);
my %retval;
my $sth = $dbh->prepare($query);
return;
}
- if (defined $type and $type == 1) {
+ if (defined $type and $type == 2) {
+ &DEBUG("dbgetcol: type 2!");
+ while (my @row = $sth->fetchrow_array) {
+ $retval{$row[0]} = join(':', $row[1..$#row]);
+ }
+ &DEBUG("dbgetcol: count => ".scalar(keys %retval) );
+
+ } elsif (defined $type and $type == 1) {
while (my @row = $sth->fetchrow_array) {
# reverse it to make it easier to count.
- $retval{$row[1]}{$row[0]} = 1;
+ if (scalar @row == 2) {
+ $retval{$row[1]}{$row[0]} = 1;
+ } elsif (scalar @row == 3) {
+ $retval{$row[1]}{$row[0]} = 1;
+ }
+ # what to do if there's only one or more than 3?
}
+
} else {
while (my @row = $sth->fetchrow_array) {
$retval{$row[0]} = $row[1];
for ($input) {
s/\n+$//;
- s/\n/<NL>/g;
s/\002|037//g; # bold,video,underline => remove.
}
+ # does this work?
+ if ($input =~ /\n/) {
+ foreach (split(/\n/, $input)) {
+ &status($_);
+ }
+ }
+
# pump up the stats.
$statcount++;