X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=src%2FModules%2FNews.pl;h=caee5f104751e0fab85324b543997dfecb8f4292;hb=f7cae48a17d6decd0a9bd997188271daa0a885b1;hp=28ca58a933f417d3c6d1f9e57c819164b02f31ff;hpb=34f9ccd5a869f040bf4cb6dc12c55aea16cd25bb;p=infobot.git diff --git a/src/Modules/News.pl b/src/Modules/News.pl index 28ca58a..caee5f1 100644 --- a/src/Modules/News.pl +++ b/src/Modules/News.pl @@ -1,14 +1,14 @@ # # News.pl: Advanced news management # Author: dms -# Version: v0.2 (20010326) +# Version: v0.3 (20010412) # Created: 20010326 # Notes: Testing done by greycat, kudos! # ### structure: -# news{ channel }{ string } { items } +# news{ channel }{ string } { item } # newsuser{ channel }{ user } = time() -### where items is: +### where item is: # Time - when it was added (used for sorting) # Author - Who by. # Expire - Time to expire. @@ -17,34 +17,54 @@ package News; +use strict; + +use vars qw($who $chan); + sub Parse { my($what) = @_; $chan = undef; + $who = lc $::who; - if ($::msgType eq "private") { - # todo: check if the channel exists aswell. - if (defined $what and $what =~ s/^($::mask{chan})\s*//) { - $chan = $1; + if (!keys %::news) { + if (!exists $::cache{newsFirst}) { + &::DEBUG("news: looks like we enabled news option just then; loading up news file just in case."); + $::cache{newsFirst} = 1; } - } else { + + &readNews(); + } + + if ($::msgType ne "private") { $chan = $::chan; } + if (defined $what and $what =~ s/^($::mask{chan})\s*//) { + # todo: check if the channel exists aswell. + $chan = lc $1; + + if (!&::IsNickInChan($who, $chan)) { + &::notice($who, "sorry but you're not on $chan."); + return; + } + } + if (!defined $chan) { - my @chans = &::GetNickInChans($::who); + my @chans = &::getNickInChans($who); if (scalar @chans > 1) { - &::msg($::who, "error: I dunno which channel you are referring to since you're on more than one."); + &::notice($who, "error: I dunno which channel you are referring to since you're on more than one. Try 'news #chan ...' instead"); return; } if (scalar @chans == 0) { - &::msg($::who, "error: I couldn't find you on any chan. This must be a bug!"); + &::notice($who, "error: I couldn't find you on any chan. This must be a bug!"); return; } - $chan = $chans[0]; - &::DEBUG("Guessed $::who being on chan $chan"); + $chan = $chans[0]; + &::VERB("Guessed $who being on chan $chan",2); + $::chan = $chan; # hack for IsChanConf(). } if (!defined $what or $what =~ /^\s*$/) { @@ -54,36 +74,84 @@ 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."); + + } elsif ($what =~ /^(\d+)$/i) { + &::VERB("News: read shortcut called.",2); &read($1); + } elsif ($what =~ /^read(\s+(.*))?$/i) { &read($2); + + } elsif ($what =~ /^(latest|new)(\s+(.*))?$/i) { + &latest($3 || $chan, 1); +# $::cmdstats{'News latest'}++; + + } elsif ($what =~ /^stats?$/i) { + &stats(); + } elsif ($what =~ /^list$/i) { - &::DEBUG("list longcut called."); &list(); + } elsif ($what =~ /^(expire|text|desc)(\s+(.*))?$/i) { # shortcut/link. # nice hack. + my $cmd = $1; my($arg1,$arg2) = split(/\s+/, $3, 2); - &set("$arg1 Text $arg2"); + &set("$arg1 $cmd $arg2"); + } elsif ($what =~ /^help(\s+(.*))?$/i) { - &::help("news$1"); + &::help("news $2"); + + } elsif ($what =~ /^newsflush$/i) { + &::msg($who, "newsflush called... check out the logs!"); + &::newsFlush(); + + } elsif ($what =~ /^(un)?notify$/i) { + my $state = ($1) ? 0 : 1; + + # todo: don't notify even if "news" is called. + if (!&::IsChanConf("newsNotifyAll")) { + &::DEBUG("news: chan => $chan, ::chan => $::chan."); + &::notice($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)) { + &::notice($who, "enabled notify."); + delete $::newsuser{$chan}{$who}; + return; + } + &::notice($who, "already enabled."); + + } else { # state = 0 + my $x = $::newsuser{$chan}{$who}; + if (defined $x and ($x == 0 or $x == -1)) { + &::notice($who, "notify already disabled"); + return; + } + $::newsuser{$chan}{$who} = -1; + &::notice($who, "notify is now disabled."); + } + } else { - &::DEBUG("could not parse '$what'."); - &::msg($::who, "unknown command: $what"); + &::notice($who, "unknown command: $what"); } } sub readNews { my $file = "$::bot_base_dir/blootbot-news.txt"; - if (! -f $file) { + if (! -f $file or -z $file) { return; } @@ -103,9 +171,10 @@ sub readNews { if (/^[\s\t]+(\S+):[\s\t]+(.*)$/) { if (!defined $item) { - &::DEBUG("!defined item, never happen!"); + &::DEBUG("news: !defined item, never happen!"); next; } + $::news{$chan}{$item}{$1} = $2; next; } @@ -125,15 +194,27 @@ sub readNews { } close NEWS; - &::status("News: Read $ci items for ".scalar(keys %::news) - ." chans, $cu users cache"); + my $cn = scalar(keys %::news); + return unless ($ci or $cn or $cu); + + &::status("News: read ". + $ci. &::fixPlural(" item", $ci). " for ". + $cn. &::fixPlural(" chan", $cn). ", ". + $cu. &::fixPlural(" user", $cu), " cache" + ); } sub writeNews { + if (!scalar keys %::news and !scalar keys %::newsuser) { + &::VERB("wN: nothing to write.",2); + return; + } + + # should define this at the top of file. my $file = "$::bot_base_dir/blootbot-news.txt"; if (fileno NEWS) { - &::ERROR("fileno NEWS exists, should never happen."); + &::ERROR("News: write: fileno NEWS exists, should never happen."); return; } @@ -146,6 +227,7 @@ sub writeNews { $c = scalar keys %{ $::news{$chan} }; next unless ($c); $cc++; + my $item; foreach $item (sort keys %{ $::news{$chan} }) { $c = scalar keys %{ $::news{$chan}{$item} }; @@ -153,6 +235,7 @@ sub writeNews { $ci++; print NEWS "$chan $item\n"; + my $what; foreach $what (sort keys %{ $::news{$chan}{$item} }) { print NEWS " $what: $::news{$chan}{$item}{$what}\n"; } @@ -188,31 +271,30 @@ sub add { } if (length $str > 64) { - &::msg($::who, "That's not really an item (>64chars)"); + &::notice($who, "That's not really an item (>64chars)"); return; } if (exists $::news{$chan}{$str}{Time}) { - &::msg($::who, "'$str' for $chan already exists!"); + &::notice($who, "'$str' for $chan already exists!"); return; } $::news{$chan}{$str}{Time} = time(); my $expire = &::getChanConfDefault("newsDefaultExpire",7); $::news{$chan}{$str}{Expire} = time() + $expire*60*60*24; - $::news{$chan}{$str}{Author} = $::who; + $::news{$chan}{$str}{Author} = $::who; # case! my $agestr = &::Time2String($::news{$chan}{$str}{Expire} - time() ); - my $item = &getNewsItem($str); - if ($item eq $str) { - &::DEBUG("item eq str ($item): should never happen."); - } - &::msg($::who, "Added '\037$str\037' at [".localtime(time). + my $item = &newsS2N($str); + &::notice($who, "Added '\037$str\037' at [".gmtime(time). "] by \002$::who\002 for item #\002$item\002."); - &::msg($::who, "Now do 'news text $item '"); - &::msg($::who, "This item will expire at \002". - localtime($::news{$chan}{$str}{Expire})."\002 [$agestr from now] " + &::notice($who, "Now do 'news text $item '"); + &::notice($who, "This item will expire at \002". + gmtime($::news{$chan}{$str}{Expire})."\002 [$agestr from now] " ); + + &writeNews(); } sub del { @@ -227,18 +309,17 @@ sub del { if ($what =~ /^\d+$/) { my $count = scalar keys %{ $::news{$chan} }; if (!$count) { - &::msg($::who, "No news for $chan."); + &::notice($who, "No news for $chan."); return; } if ($what > $count or $what < 0) { - &::msg($::who, "$what is out of range (max $count)"); + &::notice($who, "$what is out of range (max $count)"); return; } - $item = &getNewsItem($what); - &::DEBUG("del: num: item => $item ($what)"); - $what = $item; # hack hack hack. + $item = &getNewsItem($what); + $what = $item; # hack hack hack. } else { $_ = &getNewsItem($what); # hack hack hack. @@ -252,17 +333,17 @@ sub del { } if (!scalar @found) { - &::msg($::who, "could not find $what."); + &::notice($who, "could not find $what."); return; } if (scalar @found > 1) { - &::msg($::who, "too many matches for $what."); + &::notice($who, "too many matches for $what."); return; } $what = $found[0]; - &::DEBUG("del: str: guessed what => $what"); + &::DEBUG("news: del: str: guessed what => $what"); } } @@ -273,55 +354,87 @@ sub del { if (!$auth) { # todo: show when it'll expire. - &::msg($::who, "Sorry, you cannot remove items; just let them expire on their own."); + &::notice($who, "Sorry, you cannot remove items; just let them expire on their own."); return; } - &::msg($::who, "ok, deleted '$what' from \002$chan\002..."); + &::notice($who, "ok, deleted '$what' from \002$chan\002..."); delete $::news{$chan}{$what}; } else { - &::msg($::who, "error: not found $what in news for $chan."); + &::notice($who, "error: not found $what in news for $chan."); } } sub list { if (!scalar keys %{ $::news{$chan} }) { - &::msg($::who, "No News for \002$chan\002."); + &::notice($who, "No news for \002$chan\002."); return; } if (&::IsChanConf("newsKeepRead")) { - $::newsuser{$chan}{$::who} = time(); + my $x = $::newsuser{$chan}{$who}; + + if (defined $x and ($x == 0 or $x == -1)) { + &::DEBUG("news: not updating time for $who."); + } else { + if (!scalar keys %{ $::news{$chan} }) { + &::DEBUG("news: should not add $chan/$who to cache!"); + } + + $::newsuser{$chan}{$who} = time(); + } } - &::msg($::who, "|==== News for \002$chan\002:"); + # ¬ice() breaks OPN :( - using msg() instead! + my $count = scalar keys %{ $::news{$chan} }; + &::msg($who, "|==== News for \002$chan\002: ($count items)"); my $newest = 0; + my $expire = 0; + my $eno = 0; foreach (keys %{ $::news{$chan} }) { my $t = $::news{$chan}{$_}{Time}; + my $e = $::news{$chan}{$_}{Expire}; $newest = $t if ($t > $newest); + if ($e > 1 and $e < $expire) { + $expire = $e; + &::DEBUG("before newsS2N($_)"); + $eno = &newsS2N($_); + &::DEBUG("after newsS2N($_) == $eno"); + } } my $timestr = &::Time2String(time() - $newest); - &::msg($::who, "|= Last updated $timestr ago."); - &::msg($::who, " \037No\037 \037Item ".(" "x40)." \037"); + &::msg($who, "|= Last updated $timestr ago."); + &::msg($who, " \037Num\037 \037Item ".(" "x40)." \037"); + +# &::DEBUG("news: list: expire = $expire"); +# &::DEBUG("news: list: eno = $eno"); my $i = 1; foreach ( &getNewsAll() ) { my $subtopic = $_; my $setby = $::news{$chan}{$subtopic}{Author}; + my $chr = (exists $::News{$chan}{$subtopic}{Text}) ? "" : "*"; if (!defined $subtopic) { - &::DEBUG("warn: subtopic == undef."); + &::DEBUG("news: warn: subtopic == undef."); next; } # 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++; } - &::msg($::who, "|= End of News."); - &::msg($::who, "use 'news read <#>' or 'news read '"); + 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 '"); } sub read { @@ -333,30 +446,62 @@ sub read { } if (!scalar keys %{ $::news{$chan} }) { - &::msg($::who, "No News for \002$chan\002."); + &::notice($who, "No news for \002$chan\002."); return; } -# my $item = (exists $::news{$chan}{$str}) ? $str : &getNewsItem($str); my $item = &getNewsItem($str); if (!defined $item or !scalar keys %{ $::news{$chan}{$item} }) { - &::msg($::who, "No news item called '$str'"); + # todo: numerical check. + if ($str =~ /^(\d+)[-, ](\d+)$/ or + $str =~ /^-(\d+)$/ or + $str =~ /^(\d+)-$/ or 0 + ) { + &::notice($who, "We don't support multiple requests of news items yet. Sorry."); + return; + } + + &::notice($who, "No news item called '$str'"); return; } if (!exists $::news{$chan}{$item}{Text}) { - &::msg($::who, "Someone forgot to add info to this news item"); + &::notice($who, "Someone forgot to add info to this news item"); return; } - # todo: show item number. - # todo: show ago-time aswell? - # todo: show request stats aswell. - my $t = localtime($::news{$chan}{$item}{Time}); - my $a = $::news{$chan}{$item}{Author}; - &::msg($::who, "+- News \002$chan\002 ##, item '\037$item\037':"); - &::msg($::who, "| Added by $a at $t"); - &::msg($::who, $::news{$chan}{$item}{Text}); + my $t = gmtime( $::news{$chan}{$item}{Time} ); + my $a = $::news{$chan}{$item}{Author}; + my $text = $::news{$chan}{$item}{Text}; + my $num = &newsS2N($item); + my $rwho = $::news{$chan}{$item}{Request_By} || $::who; + my $rcount = $::news{$chan}{$item}{Request_Count} || 0; + + if (length $text < $::param{maxKeySize}) { + &::VERB("NEWS: Possible news->factoid redirection.",2); + my $f = &::getFactoid($text); + + if (defined $f) { + &::VERB("NEWS: ok, $text is factoid redirection.",2); + $f =~ s/^\s*//i; # anything else? + $text = $f; + } + } + + $_ = $::news{$chan}{$item}{'Expire'}; + my $e; + if ($_) { + $e = sprintf("\037%s\037 [%s from now]", + scalar(gmtime($_)), + &::Time2String($_ - time()) + ); + } + + &::notice($who, "+- News \002$chan\002 #$num: $item"); + &::notice($who, "| Added by $a at \037$t\037"); + &::notice($who, "| Expire: $e") if (defined $e); + &::notice($who, $text); + &::notice($who, "| Requested \002$rcount\002 times, last by \002$rwho\002") if ($rcount and $rwho); $::news{$chan}{$item}{'Request_By'} = $::who; $::news{$chan}{$item}{'Request_Time'} = time(); @@ -374,7 +519,7 @@ sub mod { my $news = &getNewsItem($item); if (!defined $news) { - &::DEBUG("error: mod: news == undefined."); + &::DEBUG("news: error: mod: news == undefined."); return; } my $nnews = $::news{$chan}{$news}{Text}; @@ -386,7 +531,7 @@ sub mod { my ($delim, $op, $np, $flags) = ($1,$2,$3,$4); if ($flags !~ /^(g)?$/) { - &::msg($::who, "error: Invalid flags to regex."); + &::notice($who, "error: Invalid flags to regex."); return; } @@ -397,23 +542,23 @@ sub mod { if ($flags eq "") { $done++ if (!$done and $mod_news =~ s/\Q$op\E/$np/); $done++ if (!$done and $mod_nnews =~ s/\Q$op\E/$np/); - } elsif ($flags eq "g") { + } elsif ($flags eq "g") { $done++ if ($mod_news =~ s/\Q$op\E/$np/g); $done++ if ($mod_nnews =~ s/\Q$op\E/$np/g); } if (!$done) { - &::msg($::who, "warning: regex not found in news."); + &::notice($who, "warning: regex not found in news."); return; } if ($mod_news ne $news) { # news item. if (exists $::news{$chan}{$mod_news}) { - &::msg($::who, "item '$mod_news' already exists."); + &::notice($who, "item '$mod_news' already exists."); return; } - &::msg($::who, "Moving item '$news' to '$mod_news' with SAR s/$op/$np/."); + &::notice($who, "Moving item '$news' to '$mod_news' with SAR s/$op/$np/."); foreach (keys %{ $::news{$chan}{$news} }) { $::news{$chan}{$mod_news}{$_} = $::news{$chan}{$news}{$_}; delete $::news{$chan}{$news}{$_}; @@ -423,7 +568,7 @@ sub mod { } if ($mod_nnews ne $nnews) { # news Text/Description. - &::msg($::who, "Changing text for '$news' SAR s/$op/$np/."); + &::notice($who, "Changing text for '$news' SAR s/$op/$np/."); if ($mod_news ne $news) { $::news{$chan}{$mod_news}{Text} = $mod_nnews; } else { @@ -433,37 +578,41 @@ sub mod { return; } else { - &::msg($::who, "error: that regex failed ;("); + &::notice($who, "error: that regex failed ;("); return; } - &::msg($::who, "error: Invalid regex. Try s/1/2/, s#3#4#..."); + &::notice($who, "error: Invalid regex. Try s/1/2/, s#3#4#..."); } sub set { my($args) = @_; - $args =~ /^(\S+)\s+(\S+)\s+(.*)$/; - my($item, $what, $value) = ($1,$2,$3); + my($item, $what, $value); - &::DEBUG("set called."); + if (!defined $args) { + &::DEBUG("news: set: args == NULL."); + return; + } + + $item = $1 if ($args =~ s/^(\S+)\s*//); + $what = $1 if ($args =~ s/^(\S+)\s*//); + $value = $args; if ($item eq "") { &::help("news set"); return; } - &::DEBUG("item => '$item'."); my $news = &getNewsItem($item); - &::DEBUG("news => '$news'"); if (!defined $news) { - &::msg($::who, "Could not find item '$item' substring or # in news list."); + &::notice($who, "Could not find item '$item' substring or # in news list."); return; } # list all values for chan. - if (!defined $what) { - &::DEBUG("set: 1"); + if (!defined $what or $what =~ /^\s*$/) { + &::msg($who, "set: you didn't fill me on the arguments! (what and values)"); return; } @@ -477,18 +626,18 @@ sub set { } if (!$ok) { - &::msg($::who, "Invalid set. Try: @elements"); + &::notice($who, "Invalid set. Try: @elements"); return; } # show (read) what. - if (!defined $value) { - &::DEBUG("set: 2"); + if (!defined $value or $value =~ /^\s*$/) { + &::msg($who, "set: you didn't fill me on the arguments! (value)"); return; } if (!exists $::news{$chan}{$news}) { - &::msg($::who, "news '$news' does not exist"); + &::notice($who, "news '$news' does not exist"); return; } @@ -519,21 +668,22 @@ sub set { } if (!$time or ($value and $value !~ /^never$/i)) { - &::DEBUG("set: Expire... need to parse."); + &::DEBUG("news: set: Expire... need to parse."); + &::msg($who, "hrm... couldn't parse that."); return; } if ($time == -1) { - &::msg($::who, "Set never expire for \002$item\002." ); + &::notice($who, "Set never expire for \002$item\002." ); } elsif ($time < -1) { - &::DEBUG("time should never be negative ($time)."); + &::DEBUG("news: time should never be negative ($time)."); return; } else { - &::msg($::who, "Set expire for \002$item\002, to ". - localtime($time) ." [".&::Time2String($time - time())."]" ); + &::notice($who, "Set expire for \002$item\002, to ". + gmtime($time) ." [".&::Time2String($time - time())."]" ); if (time() > $time) { - &::DEBUG("hrm... time() > $time, should expire."); + &::DEBUG("news: hrm... time() > $time, should expire."); } } @@ -544,12 +694,12 @@ sub set { } my $auth = 0; - &::DEBUG("who => '$::who'"); +# &::DEBUG("news: who => '$who'"); my $author = $::news{$chan}{$news}{Author}; $auth++ if ($::who eq $author); $auth++ if (&::IsFlag("o")); if (!defined $author) { - &::DEBUG("news{$chan}{$news}{Author} is not defined! auth'd anyway"); + &::DEBUG("news: news{$chan}{$news}{Author} is not defined! auth'd anyway"); $::news{$chan}{$news}{Author} = $::who; $author = $::who; $auth++; @@ -557,16 +707,156 @@ sub set { if (!$auth) { # todo: show when it'll expire. - &::msg($::who, "Sorry, you cannot set items. (author $author owns it)"); + &::notice($who, "Sorry, you cannot set items. (author $author owns it)"); return; } + # todo: clean this up. my $old = $::news{$chan}{$news}{$what}; if (defined $old) { - &::DEBUG("old => $old."); + &::DEBUG("news: old => $old."); } $::news{$chan}{$news}{$what} = $value; - &::msg($::who, "Setting [$chan]/{$news}/<$what> to '$value'."); + &::notice($who, "Setting [$chan]/{$news}/<$what> to '$value'."); +} + +sub latest { + my ($tchan, $flag) = @_; + + # hack hack hack. fix later. + $chan = $tchan; + $who = $::who; + + # todo: if chan = undefined, guess. +# if (!exists $::news{$chan}) { + if (!exists $::channels{$chan}) { + &::notice($who, "invalid chan $chan") if ($flag); + return; + } + + 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 \002/msg $::ident news $chan\002 or \002/msg $::ident news $chan notify\002"); + } else { + &::DEBUG("news: not displaying any new news for $who"); + return; + } + } + + $::chan = $chan; + my $x = &::IsChanConf("newsNotifyAll"); + return if (!$x); + + # I don't understand this code ;) + $t = 1 if (!defined $t); + + if (!defined $t) { +# &::msg($who, "News is disabled for $chan"); + &::DEBUG("news: $chan: something went really wrong."); + return; + } + + my @new; + foreach (keys %{ $::news{$chan} }) { + next if (!defined $t); + next if ($t > $::news{$chan}{$_}{Time}); + + # don't list new items if they don't have Text. + if (!exists $::news{$chan}{$_}{Text}) { + if (time() - $::news{$chan}{$_}{Time} > 60*60*24*3) { + &::DEBUG("deleting news{$chan}{$_} because it was too old and had no text info."); + delete $::news{$chan}{$_}; + } + + next; + } + + push(@new, $_); + } + + # !scalar @new, $flag + if (!scalar @new and $flag) { + &::notice($who, "no new news for $chan for $who."); + # valid to set this? + $::newsuser{$chan}{$who} = time(); + return; + } + + # scalar @new, !$flag + my $unread = scalar @new; + my $total = scalar keys %{ $::news{$chan} }; + if (!$flag && !&::IsChanConf("newsTellUnread")) { + return; + } + + if (!$flag) { + return unless ($unread); + + # just a temporary measure not to flood ourself off the + # network with news until we get global notice() and msg() + # throttling. + if (time() - ($::cache{newsTime} || 0) < 5) { + &::status("news: not displaying latest notice to $who/$chan."); + return; + } + + $::cache{newsTime} = time(); + my $reply = "There are unread news in $chan ($unread unread, $total total). /msg $::ident news $::chan latest"; + $reply .= " If you don't want further news notification, /msg $::ident news unnotify" if ($unread == $total); + &::notice($who, $reply); + + return; + } + + # scalar @new, $flag + if (scalar @new) { + &::notice($who, "+==== New news for \002$chan\002 ($unread new; $total total):"); + + my $t = $::newsuser{$chan}{$who}; + if (defined $t and $t > 1) { + my $timestr = &::Time2String( time() - $t ); + &::notice($who, "|= Last time read $timestr ago"); + } + + my $i; + my @sorted; + foreach (@new) { + $i = &newsS2N($_); + $sorted[$i] = $_; + } + + for ($i=0; $i<=scalar(@sorted); $i++) { + my $news = $sorted[$i]; + next unless (defined $news); + +# my $age = time() - $::news{$chan}{$news}{Time}; + my $msg = sprintf("\002[\002%2d\002]\002 %s", $i, $news); +### $i, $_, &::Time2String($age) + $::conn->schedule(int((2+$i)/2), sub { + &::notice($who, $msg); + } ); + } + + # todo: implement throttling via schedule into ¬ice() / &msg(). + $::conn->schedule(int((2+$i)/2), sub { + &::notice($who, "|= to read, do \002news $chan read <#>\002 or \002news $chan read \002"); + } ); + + # lame hack to prevent dupes if we just ignore it. + my $x = $::newsuser{$chan}{$who}; + if (defined $x and ($x == 0 or $x == -1)) { + &::DEBUG("news: not updating time for $who. (2)"); + } else { + $::newsuser{$chan}{$who} = time(); + } + } } ### @@ -587,16 +877,45 @@ sub getNewsAll { return @items; } +sub newsS2N { + my($what) = @_; + my $item = 0; + my @items; + my $no; + + my %time; + foreach (keys %{ $::news{$chan} }) { + my $t = $::news{$chan}{$_}{Time}; + + if (!defined $t or $t !~ /^\d+$/) { + &::DEBUG("news: warn: t is undefined for news{$chan}{$_}{Time}; removing item."); + delete $::news{$chan}{$_}; + next; + } + + $time{$t} = $_; + } + + foreach (sort { $a <=> $b } keys %time) { + $item++; + return $item if ($time{$_} eq $what); + } + + &::DEBUG("newsS2N($what): failed..."); +} + sub getNewsItem { my($what) = @_; my $item = 0; + $what =~ s/^\#//; # '#1' for example. + my %time; foreach (keys %{ $::news{$chan} }) { my $t = $::news{$chan}{$_}{Time}; if (!defined $t or $t !~ /^\d+$/) { - &::DEBUG("warn: t is undefined for news{$chan}{$_}{Time}; removing item."); + &::DEBUG("news: warn: t is undefined for news{$chan}{$_}{Time}; removing item."); delete $::news{$chan}{$_}; next; } @@ -613,41 +932,42 @@ sub getNewsItem { } else { # partial string to full string resolution + # in some cases, string->number resolution. my @items; my $no; foreach (sort { $a <=> $b } keys %time) { $item++; - $no = $item if ($time{$_} eq $what); +# $no = $item if ($time{$_} eq $what); +## if ($time{$_} eq $what) { +## $no = $item; +## next; +## } + push(@items, $time{$_}) if ($time{$_} =~ /\Q$what\E/i); } - # since we have so much built into this function, there is so - # many guesses we can make. - # todo: split this command in the future into: - # full_string->number and number->string - # partial_string->full_string - if (defined $no and !@items) { - &::DEBUG("string->number resolution."); - return $no; - } +## if (defined $no and !@items) { +## &::DEBUG("news: string->number resolution: $what->$no."); +## return $no; +## } if (scalar @items > 1) { - &::DEBUG("Multiple matches, not guessing."); - &::msg($::who, "Multiple matches, not guessing."); + &::DEBUG("news: Multiple matches, not guessing."); + &::notice($who, "Multiple matches, not guessing."); return; } if (@items) { - &::DEBUG("gNI: Guessed '$items[0]'."); +# &::DEBUG("news: gNI: part_string->full_string: $what->$items[0]"); return $items[0]; } else { - &::DEBUG("gNI: No match."); + &::DEBUG("news: gNI: No match for '$what'"); return; } } - &::ERROR("getNewsItem: Should not happen (what = $what)"); + &::ERROR("news: gNI: should not happen (what = $what)"); return; } @@ -655,20 +975,57 @@ sub do_set { my($what,$value) = @_; if (!defined $chan) { - &::DEBUG("do_set: chan not defined."); + &::DEBUG("news: do_set: chan not defined."); return; } if (!defined $what or $what =~ /^\s*$/) { - &::DEBUG("what $what is not defined."); + &::DEBUG("news: what $what is not defined."); return; } + if (!defined $value or $value =~ /^\s*$/) { - &::DEBUG("value $value is not defined."); + &::DEBUG("news: value $value is not defined."); return; } - &::DEBUG("do_set: TODO..."); + &::DEBUG("news: do_set: TODO..."); } +sub stats { + &::DEBUG("News: stats called."); + &::msg($who, "check my logs/console."); + my($i,$j) = (0,0); + + # total request count. + foreach $chan (keys %::news) { + foreach (keys %{ $::news{$chan} }) { + $i += $::news{$chan}{$_}{Request_Count}; + } + } + &::DEBUG("news: stats: total request count => $i"); + $i = 0; + + # total user cached. + foreach $chan (keys %::newsuser) { + $i += $::newsuser{$chan}{$_}; + } + &::DEBUG("news: stats: total user cache => $i"); + $i = 0; + + # average latest time read. + my $t = time(); + foreach $chan (keys %::newsuser) { + $i += $t - $::newsuser{$chan}{$_}; + &::DEBUG(" i = $i"); + $j++; + } + &::DEBUG("news: stats: average latest time read: total time: $i"); + &::DEBUG("news: ... count: $j"); + &::DEBUG("news: average: ".sprintf("%.02f", $i/($j||1))." sec/user"); + $i = $j = 0; +} + +sub AUTOLOAD { &::AUTOLOAD(@_); } + 1;