From bb9e3127fe594248efa7d4733e0be24dba8e579e Mon Sep 17 00:00:00 2001 From: dms Date: Fri, 13 Apr 2001 15:23:27 +0000 Subject: [PATCH] news: can make news compulsory (chanset +newsNotifyAll) and opt-out (news unnotify) irchooks: splitted into IrcHelpers.pl so we can reload it on the fly. factoids: added debugging for short factoids that may be botched up references git-svn-id: https://svn.code.sf.net/p/infobot/code/trunk/blootbot@438 c11ca15a-4712-0410-83d8-924469b57eb5 --- src/IRC/IrcHelpers.pl | 280 ++++++++++++++++++++++++++++++++++++++++ src/IRC/IrcHooks.pl | 267 -------------------------------------- src/IRC/Schedulers.pl | 2 +- src/Modules/Factoids.pl | 5 + src/Modules/News.pl | 70 +++++++++- 5 files changed, 352 insertions(+), 272 deletions(-) create mode 100644 src/IRC/IrcHelpers.pl diff --git a/src/IRC/IrcHelpers.pl b/src/IRC/IrcHelpers.pl new file mode 100644 index 0000000..c4e4530 --- /dev/null +++ b/src/IRC/IrcHelpers.pl @@ -0,0 +1,280 @@ +# +# IrcHooks.pl: IRC Hooks stuff. +# Author: dms +# Version: 20010413 +# Created: 20010413 +# NOTE: Based on code by Kevin Lenzo & Patrick Cole (c) 1997 +# + +if (&IsParam("useStrict")) { use strict; } + +####################################################################### +####### IRC HOOK HELPERS IRC HOOK HELPERS IRC HOOK HELPERS ######## +####################################################################### + +##### +# Usage: &hookMode($chan, $modes, @targets); +sub hookMode { + my ($chan, $modes, @targets) = @_; + my $parity = 0; + + $chan = lc $chan; # !!!. + + my $mode; + foreach $mode (split(//, $modes)) { + # sign. + if ($mode =~ /[-+]/) { + $parity = 1 if ($mode eq "+"); + $parity = 0 if ($mode eq "-"); + next; + } + + # mode with target. + if ($mode =~ /[bklov]/) { + my $target = shift @targets; + + if ($parity) { + $chanstats{$chan}{'Op'}++ if ($mode eq "o"); + $chanstats{$chan}{'Ban'}++ if ($mode eq "b"); + } else { + $chanstats{$chan}{'Deop'}++ if ($mode eq "o"); + $chanstats{$chan}{'Unban'}++ if ($mode eq "b"); + } + + # modes w/ target affecting nick => cache it. + if ($mode =~ /[bov]/) { + $channels{$chan}{$mode}{$target}++ if $parity; + delete $channels{$chan}{$mode}{$target} if !$parity; + } + + if ($mode =~ /[l]/) { + $channels{$chan}{$mode} = $target if $parity; + delete $channels{$chan}{$mode} if !$parity; + } + } + + # important channel modes, targetless. + if ($mode =~ /[mt]/) { + $channels{$chan}{$mode}++ if $parity; + delete $channels{$chan}{$mode} if !$parity; + } + } +} + +sub hookMsg { + ($msgType, $chan, $who, $message) = @_; + my $skipmessage = 0; + $addressed = 0; + $addressedother = 0; + $orig{message} = $message; + $orig{who} = $who; + $addrchar = 0; + + $message =~ s/[\cA-\c_]//ig; # strip control characters + $message =~ s/^\s+//; # initial whitespaces. + $who =~ tr/A-Z/a-z/; # lowercase. + + &showProc(); + + # addressing. + if ($msgType =~ /private/) { + # private messages. + $addressed = 1; + } else { + # public messages. + # addressing revamped by the xk. + ### below needs to be fixed... + if (&IsParam("addressCharacter")) { + if ($message =~ s/^$param{'addressCharacter'}//) { + $addrchar = 1; + $addressed = 1; + } + } + + if ($message =~ /^($mask{nick})([\;\:\>\, ]+) */) { + my $newmessage = $'; + if ($1 =~ /^\Q$ident\E$/i) { + $message = $newmessage; + $addressed = 1; + } else { + # ignore messages addressed to other people or unaddressed. + $skipmessage++ if ($2 ne "" and $2 !~ /^ /); + } + } + } + + # Determine floodwho. + my $c = "_default"; + if ($msgType =~ /public/i) { # public. + $floodwho = $c = lc $chan; + } elsif ($msgType =~ /private/i) { # private. + $floodwho = lc $who; + } else { # dcc? + &DEBUG("FIXME: floodwho = ???"); + } + + my $val = &getChanConfDefault("floodRepeat", "2:10", $c); + my ($count, $interval) = split /:/, $val; + + # flood repeat protection. + if ($addressed) { + my $time = $flood{$floodwho}{$message} || 0; + + if ($msgType eq "public" and (time() - $time < $interval)) { + ### public != personal who so the below is kind of pointless. + my @who; + foreach (keys %flood) { + next if (/^\Q$floodwho\E$/); + next if (defined $chan and /^\Q$chan\E$/); + + push(@who, grep /^\Q$message\E$/i, keys %{ $flood{$_} }); + } + + return if ($lobotomized); + + if (scalar @who) { + &msg($who, "you already said what ". + join(' ', @who)." have said."); + } else { + &msg($who,"Someone already said that ". (time - $time) ." seconds ago" ); + } + + ### TODO: delete old floodwarn{} keys. + my $floodwarn = 0; + if (!exists $floodwarn{$floodwho}) { + $floodwarn++; + } else { + $floodwarn++ if (time() - $floodwarn{$floodwho} > $interval); + } + + if ($floodwarn) { + &status("FLOOD repetition detected from $floodwho."); + $floodwarn{$floodwho} = time(); + } + + return; + } + + if ($addrchar) { + &status("$b_cyan$who$ob is short-addressing me"); + } elsif ($msgType eq "private") { # private. + &status("$b_cyan$who$ob is /msg'ing me"); + } else { # public? + &status("$b_cyan$who$ob is addressing me"); + } + + $flood{$floodwho}{$message} = time(); + } elsif ($msgType eq "public" and &IsChanConf("kickOnRepeat")) { + # unaddressed, public only. + + ### TODO: use a separate "short-time" hash. + my @data; + @data = keys %{ $flood{$floodwho} } if (exists $flood{$floodwho}); + } + + $val = &getChanConfDefault("floodMessages", "5:30", $c); + ($count, $interval) = split /:/, $val; + + # flood overflow protection. + if ($addressed) { + foreach (keys %{$flood{$floodwho}}) { + next unless (time() - $flood{$floodwho}{$_} > $interval); + delete $flood{$floodwho}{$_}; + } + + my $i = scalar keys %{$flood{$floodwho}}; + if ($i > $count) { + &msg($who,"overflow of messages ($i > $count)"); + &status("FLOOD overflow detected from $floodwho; ignoring"); + + my $expire = $param{'ignoreAutoExpire'} || 5; + &ignoreAdd("*!$uh", $chan, $expire, "flood overflow auto-detected."); + return; + } + + $flood{$floodwho}{$message} = time(); + } + + my @ignore; + if ($msgType =~ /public/i) { # public. + $talkchannel = $chan; + &status("<$orig{who}/$chan> $orig{message}"); + push(@ignore, keys %{ $ignore{$chan} }) if (exists $ignore{$chan}); + } elsif ($msgType =~ /private/i) { # private. + &status("[$orig{who}] $orig{message}"); + $talkchannel = undef; + $chan = "_default"; + } else { + &DEBUG("unknown msgType => $msgType."); + } + push(@ignore, keys %{ $ignore{"*"} }) if (exists $ignore{"*"}); + + if ((!$skipmessage or &IsChanConf("seenStoreAll")) and + &IsChanConf("seen") and + $msgType =~ /public/ + ) { + $seencache{$who}{'time'} = time(); + $seencache{$who}{'nick'} = $orig{who}; + $seencache{$who}{'host'} = $uh; + $seencache{$who}{'chan'} = $talkchannel; + $seencache{$who}{'msg'} = $orig{message}; + $seencache{$who}{'msgcount'}++; + } + + return if ($skipmessage); + return unless (&IsParam("minVolunteerLength") or $addressed); + + foreach (@ignore) { + s/\*/\\S*/g; + + next unless (eval { $nuh =~ /^$_$/i }); + + &status("IGNORE <$who> $message"); + return; + } + + if (defined $nuh) { + if (!defined $userHandle) { + &DEBUG("line 1074: need verifyUser?"); + &verifyUser($who, $nuh); + } + } else { + &DEBUG("hookMsg: 'nuh' not defined?"); + } + +### For extra debugging purposes... + if ($_ = &process()) { +# &DEBUG("IrcHooks: process returned '$_'."); + } + + return; +} + +sub chanLimitVerify { + my($chan) = @_; + my $l = $channels{$chan}{'l'}; + + # 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}{''} }); + &DEBUG("plus = $plus, count = $count"); + my $delta = $count + $plus - $l; + $delta =~ s/^\-//; + &DEBUG(" delta => $delta"); + + if ($plus <= 3) { + &WARN("clc: stupid to have plus at $plus, fix it!"); + } + + ### todo: check if we have ops. + ### todo: if not, check if nickserv/chanserv is avail. + ### todo: unify code with chanlimitcheck() + if ($delta > 5) { + &status("clc: big change in limit; changing."); + &rawout("MODE $chan +l ".($count+$plus) ); + } + } +} + +1; diff --git a/src/IRC/IrcHooks.pl b/src/IRC/IrcHooks.pl index 461d9de..d217fc5 100644 --- a/src/IRC/IrcHooks.pl +++ b/src/IRC/IrcHooks.pl @@ -941,271 +941,4 @@ sub on_whoisuser { $nuh{lc $args[1]} = $args[1]."!".$args[2]."\@".$args[3]; } -####################################################################### -####### IRC HOOK HELPERS IRC HOOK HELPERS IRC HOOK HELPERS ######## -####################################################################### - -##### -# Usage: &hookMode($chan, $modes, @targets); -sub hookMode { - my ($chan, $modes, @targets) = @_; - my $parity = 0; - - $chan = lc $chan; # !!!. - - my $mode; - foreach $mode (split(//, $modes)) { - # sign. - if ($mode =~ /[-+]/) { - $parity = 1 if ($mode eq "+"); - $parity = 0 if ($mode eq "-"); - next; - } - - # mode with target. - if ($mode =~ /[bklov]/) { - my $target = shift @targets; - - if ($parity) { - $chanstats{$chan}{'Op'}++ if ($mode eq "o"); - $chanstats{$chan}{'Ban'}++ if ($mode eq "b"); - } else { - $chanstats{$chan}{'Deop'}++ if ($mode eq "o"); - $chanstats{$chan}{'Unban'}++ if ($mode eq "b"); - } - - # modes w/ target affecting nick => cache it. - if ($mode =~ /[bov]/) { - $channels{$chan}{$mode}{$target}++ if $parity; - delete $channels{$chan}{$mode}{$target} if !$parity; - } - - if ($mode =~ /[l]/) { - $channels{$chan}{$mode} = $target if $parity; - delete $channels{$chan}{$mode} if !$parity; - } - } - - # important channel modes, targetless. - if ($mode =~ /[mt]/) { - $channels{$chan}{$mode}++ if $parity; - delete $channels{$chan}{$mode} if !$parity; - } - } -} - -sub hookMsg { - ($msgType, $chan, $who, $message) = @_; - my $skipmessage = 0; - $addressed = 0; - $addressedother = 0; - $orig{message} = $message; - $orig{who} = $who; - $addrchar = 0; - - $message =~ s/[\cA-\c_]//ig; # strip control characters - $message =~ s/^\s+//; # initial whitespaces. - $who =~ tr/A-Z/a-z/; # lowercase. - - &showProc(); - - # addressing. - if ($msgType =~ /private/) { - # private messages. - $addressed = 1; - } else { - # public messages. - # addressing revamped by the xk. - ### below needs to be fixed... - if (&IsParam("addressCharacter")) { - if ($message =~ s/^$param{'addressCharacter'}//) { - $addrchar = 1; - $addressed = 1; - } - } - - if ($message =~ /^($mask{nick})([\;\:\>\, ]+) */) { - my $newmessage = $'; - if ($1 =~ /^\Q$ident\E$/i) { - $message = $newmessage; - $addressed = 1; - } else { - # ignore messages addressed to other people or unaddressed. - $skipmessage++ if ($2 ne "" and $2 !~ /^ /); - } - } - } - - # Determine floodwho. - my $c = "_default"; - if ($msgType =~ /public/i) { # public. - $floodwho = $c = lc $chan; - } elsif ($msgType =~ /private/i) { # private. - $floodwho = lc $who; - } else { # dcc? - &DEBUG("FIXME: floodwho = ???"); - } - - my $val = &getChanConfDefault("floodRepeat", "2:10", $c); - my ($count, $interval) = split /:/, $val; - - # flood repeat protection. - if ($addressed) { - my $time = $flood{$floodwho}{$message} || 0; - - if ($msgType eq "public" and (time() - $time < $interval)) { - ### public != personal who so the below is kind of pointless. - my @who; - foreach (keys %flood) { - next if (/^\Q$floodwho\E$/); - next if (defined $chan and /^\Q$chan\E$/); - - push(@who, grep /^\Q$message\E$/i, keys %{ $flood{$_} }); - } - - return if ($lobotomized); - - if (scalar @who) { - &msg($who, "you already said what ". - join(' ', @who)." have said."); - } else { - &msg($who,"Someone already said that ". (time - $time) ." seconds ago" ); - } - - ### TODO: delete old floodwarn{} keys. - my $floodwarn = 0; - if (!exists $floodwarn{$floodwho}) { - $floodwarn++; - } else { - $floodwarn++ if (time() - $floodwarn{$floodwho} > $interval); - } - - if ($floodwarn) { - &status("FLOOD repetition detected from $floodwho."); - $floodwarn{$floodwho} = time(); - } - - return; - } - - if ($addrchar) { - &status("$b_cyan$who$ob is short-addressing me"); - } elsif ($msgType eq "private") { # private. - &status("$b_cyan$who$ob is /msg'ing me"); - } else { # public? - &status("$b_cyan$who$ob is addressing me"); - } - - $flood{$floodwho}{$message} = time(); - } elsif ($msgType eq "public" and &IsChanConf("kickOnRepeat")) { - # unaddressed, public only. - - ### TODO: use a separate "short-time" hash. - my @data; - @data = keys %{ $flood{$floodwho} } if (exists $flood{$floodwho}); - } - - $val = &getChanConfDefault("floodMessages", "5:30", $c); - ($count, $interval) = split /:/, $val; - - # flood overflow protection. - if ($addressed) { - foreach (keys %{$flood{$floodwho}}) { - next unless (time() - $flood{$floodwho}{$_} > $interval); - delete $flood{$floodwho}{$_}; - } - - my $i = scalar keys %{$flood{$floodwho}}; - if ($i > $count) { - &msg($who,"overflow of messages ($i > $count)"); - &status("FLOOD overflow detected from $floodwho; ignoring"); - - my $expire = $param{'ignoreAutoExpire'} || 5; - &ignoreAdd("*!$uh", $chan, $expire, "flood overflow auto-detected."); - return; - } - - $flood{$floodwho}{$message} = time(); - } - - my @ignore; - if ($msgType =~ /public/i) { # public. - $talkchannel = $chan; - &status("<$orig{who}/$chan> $orig{message}"); - push(@ignore, keys %{ $ignore{$chan} }) if (exists $ignore{$chan}); - } elsif ($msgType =~ /private/i) { # private. - &status("[$orig{who}] $orig{message}"); - $talkchannel = undef; - $chan = "_default"; - } else { - &DEBUG("unknown msgType => $msgType."); - } - push(@ignore, keys %{ $ignore{"*"} }) if (exists $ignore{"*"}); - - if ((!$skipmessage or &IsChanConf("seenStoreAll")) and - &IsChanConf("seen") and - $msgType =~ /public/ - ) { - $seencache{$who}{'time'} = time(); - $seencache{$who}{'nick'} = $orig{who}; - $seencache{$who}{'host'} = $uh; - $seencache{$who}{'chan'} = $talkchannel; - $seencache{$who}{'msg'} = $orig{message}; - $seencache{$who}{'msgcount'}++; - } - - return if ($skipmessage); - return unless (&IsParam("minVolunteerLength") or $addressed); - - foreach (@ignore) { - s/\*/\\S*/g; - - next unless (eval { $nuh =~ /^$_$/i }); - - &status("IGNORE <$who> $message"); - return; - } - - if (defined $nuh) { - if (!defined $userHandle) { - &DEBUG("line 1074: need verifyUser?"); - &verifyUser($who, $nuh); - } - } else { - &DEBUG("hookMsg: 'nuh' not defined?"); - } - -### For extra debugging purposes... - if ($_ = &process()) { -# &DEBUG("IrcHooks: process returned '$_'."); - } - - return; -} - -sub chanLimitVerify { - my($chan) = @_; - my $l = $channels{$chan}{'l'}; - - # only change it if it's not set. - if (defined $l and &IsChanConf("chanlimitcheck")) { - my $plus = &getChanConfDefault("chanlimitcheckPlus", 5, $chan); - my $nowl = scalar(keys %{ $channels{$chan}{''} }); - my $delta = $nowl - $l; - $delta =~ s/^\-//; - - if ($plus <= 3) { - &WARN("clc: stupid to have plus at $plus, fix it!"); - } - - ### todo: check if we have ops. - ### todo: if not, check if nickserv/chanserv is avail. - ### todo: unify code with chanlimitcheck() - if ($delta > 5) { - &status("clc: big change in limit; changing."); - &rawout("MODE $chan +l ".($nowl+$plus) ); - } - } -} - 1; diff --git a/src/IRC/Schedulers.pl b/src/IRC/Schedulers.pl index b9d4623..e3e224c 100644 --- a/src/IRC/Schedulers.pl +++ b/src/IRC/Schedulers.pl @@ -324,7 +324,7 @@ sub newsFlush { foreach $chan (keys %::newsuser) { foreach (keys %{ $::newsuser{$chan} }) { my $t = $::newsuser{$chan}{$_}; - if (!defined $t or $t < 1000) { + if (!defined $t or ($t > 2 and $t < 1000)) { &DEBUG("something wrong with newsuser{$chan}{$_} => $t"); next; } diff --git a/src/Modules/Factoids.pl b/src/Modules/Factoids.pl index d6c20b4..46cbf8d 100644 --- a/src/Modules/Factoids.pl +++ b/src/Modules/Factoids.pl @@ -316,6 +316,11 @@ sub CmdFactStats { $match++ if ($val =~ /\s{3,}/); next unless ($match); + my $v = &getFactoid($val); + if (defined $v) { + &DEBUG("key $key => $val => $v"); + } + $key =~ s/\,/\037\,\037/g; push(@list, $key); } diff --git a/src/Modules/News.pl b/src/Modules/News.pl index ab274d3..6a4d30f 100644 --- a/src/Modules/News.pl +++ b/src/Modules/News.pl @@ -63,30 +63,68 @@ sub Parse { if ($what =~ /^add(\s+(.*))?$/i) { &add($2); + } elsif ($what =~ /^del(\s+(.*))?$/i) { &del($2); + } elsif ($what =~ /^mod(\s+(.*))?$/i) { &mod($2); + } elsif ($what =~ /^set(\s+(.*))?$/i) { &set($2); + } elsif ($what =~ /^(\d)$/i) { &::DEBUG("read shortcut called."); &read($1); + } elsif ($what =~ /^read(\s+(.*))?$/i) { &read($2); + } elsif ($what =~ /^(latest|new)(\s+(.*))?$/i) { &::DEBUG("latest called... hrm"); &latest($3 || $chan, 1); + } elsif ($what =~ /^list$/i) { &::DEBUG("list longcut called."); &list(); + } elsif ($what =~ /^(expire|text|desc)(\s+(.*))?$/i) { # shortcut/link. # nice hack. my($arg1,$arg2) = split(/\s+/, $3, 2); &set("$arg1 $1 $arg2"); + } elsif ($what =~ /^help(\s+(.*))?$/i) { &::help("news$1"); + + } elsif ($what =~ /^(un)?notify$/i) { + my $state = ($1) ? 0 : 1; + + # todo: don't notify even if "news" is called. + if (!&::IsChanConf("newsNotifyAll")) { + &::msg($::who, "not available for this channel or disabled altogether."); + return; + } + + my $t = $::newsuser{$chan}{$::who}; + if ($state) { # state = 1 + if (defined $t and ($t == 0 or $t == -1)) { + &::msg($::who, "enabled notify."); + delete $::newsuser{$chan}{$::who}; + return; + } + &::msg($::who, "already enabled."); + + } else { # state = 0 + my $x = $::newsuser{$chan}{$::who}; + if (defined $x and ($x == 0 or $x == -1)) { + &::msg($::who, "notify already disabled"); + return; + } + $::newsuser{$chan}{$::who} = -1; + &::msg($::who, "notify is now disabled."); + } + } else { &::DEBUG("could not parse '$what'."); &::msg($::who, "unknown command: $what"); @@ -307,7 +345,13 @@ sub list { } if (&::IsChanConf("newsKeepRead")) { - $::newsuser{$chan}{$::who} = time(); + my $x = $::newsuser{$chan}{$::who}; + + if (defined $x and ($x == 0 or $x == -1)) { + &::DEBUG("not updating time for $::who."); + } else { + $::newsuser{$chan}{$::who} = time(); + } } &::msg($::who, "|==== News for \002$chan\002:"); @@ -610,9 +654,19 @@ sub latest { return; } + my $t = $::newsuser{$chan}{$::who}; + if (defined $t and ($t == 0 or $t == -1)) { + &::DEBUG("not displaying any new news for $::who"); + return; + } + my @new; foreach (keys %{ $::news{$chan} }) { - my $t = $::newsuser{$chan}{$::who}; + if (&::IsChanConf("newsNotifyAll") and !defined $t) { + &::DEBUG("setting time for $::who to 1..."); + $::newsuser{$chan}{$::who} = 1; + $t = 1; + } next if (!defined $t); next if ($t > $::news{$chan}{$_}{Time}); @@ -627,7 +681,10 @@ sub latest { if (!$flag) { my $unread = scalar @new; my $total = scalar keys %{ $::news{$chan} }; - &::msg($::who, "There are unread news in $chan ($unread unread, $total, total). /msg $::ident news latest"); + return unless ($unread); + + &::msg($::who, "There are unread news in $chan ($unread unread, $total total). /msg $::ident news latest. If you don't want further news notification, /msg $::ident news unnotify"); + return; } @@ -649,7 +706,12 @@ sub latest { &::msg($::who, "|= to read, do 'news read <#>' or 'news read '"); # lame hack to prevent dupes if we just ignore it. - $::newsuser{$chan}{$::who} = time(); + my $x = $::newsuser{$chan}{$::who}; + if (defined $x and ($x == 0 or $x == -1)) { + &::DEBUG("not updating time for $::who. (2)"); + } else { + $::newsuser{$chan}{$::who} = time(); + } } } -- 2.39.2