/[irc-logger]/trunk/bin/irc-logger.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/bin/irc-logger.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 97 by dpavlin, Fri Mar 7 15:49:23 2008 UTC revision 133 by dpavlin, Sat Apr 5 21:08:27 2008 UTC
# Line 2  Line 2 
2  use strict;  use strict;
3  $|++;  $|++;
4    
5    use POE qw(Component::IRC Component::Server::HTTP Component::Client::HTTP);
6    use HTTP::Status;
7    use DBI;
8    use Regexp::Common qw /URI/;
9    use CGI::Simple;
10    use POSIX qw/strftime/;
11    use HTML::CalendarMonthSimple;
12    use Getopt::Long;
13    use DateTime;
14    use URI::Escape;
15    use Data::Dump qw/dump/;
16    use DateTime::Format::ISO8601;
17    use Carp qw/confess/;
18    use XML::Feed;
19    use DateTime::Format::Flexible;
20    use Encode;
21    
22  =head1 NAME  =head1 NAME
23    
24  irc-logger.pl  irc-logger.pl
# Line 30  log all conversation on irc channel Line 47  log all conversation on irc channel
47    
48  ## CONFIG  ## CONFIG
49    
50    my $debug = 0;
51    
52    my $irc_config = {
53            nick => 'irc-logger',
54            server => 'irc.freenode.net',
55            port => 6667,
56            ircname => 'Anna the bot: try /msg irc-logger help',
57    };
58    
59  my $HOSTNAME = `hostname -f`;  my $HOSTNAME = `hostname -f`;
60  chomp($HOSTNAME);  chomp($HOSTNAME);
61    
62  my $NICK = 'irc-logger';  
 $NICK .= '-dev' if ($HOSTNAME =~ m/llin/);  
 my $CONNECT =  
   {Server => 'irc.freenode.net',  
    Nick => $NICK,  
    Ircname => "try /msg $NICK help",  
   };  
63  my $CHANNEL = '#razmjenavjestina';  my $CHANNEL = '#razmjenavjestina';
64  $CHANNEL = '#irc-logger' if ($HOSTNAME =~ m/llin/);  
65  my $IRC_ALIAS = "log";  if ( $HOSTNAME =~ m/llin/ ) {
66            $irc_config->{nick} = 'irc-logger-llin';
67    #       $irc_config = {
68    #               nick => 'irc-logger-llin',
69    #               server => 'localhost',
70    #               port => 6668,
71    #       };
72            $CHANNEL = '#irc-logger';
73    } elsif ( $HOSTNAME =~ m/lugarin/ ) {
74            $irc_config->{server} = 'irc.carnet.hr';
75            $CHANNEL = '#riss';
76    }
77    
78    my @channels = ( $CHANNEL );
79    
80    warn "## config = ", dump( $irc_config ) if $debug;
81    
82    my $NICK = $irc_config->{nick} or die "no nick?";
83    
84  my $DSN = 'DBI:Pg:dbname=' . $NICK;  my $DSN = 'DBI:Pg:dbname=' . $NICK;
85    
# Line 62  my $url = "http://$HOSTNAME:$http_port"; Line 99  my $url = "http://$HOSTNAME:$http_port";
99    
100  ## END CONFIG  ## END CONFIG
101    
 use POE qw(Component::IRC Component::Server::HTTP);  
 use HTTP::Status;  
 use DBI;  
 use Regexp::Common qw /URI/;  
 use CGI::Simple;  
 use HTML::TagCloud;  
 use POSIX qw/strftime/;  
 use HTML::CalendarMonthSimple;  
 use Getopt::Long;  
 use DateTime;  
 use URI::Escape;  
 use Data::Dump qw/dump/;  
 use DateTime::Format::ISO8601;  
 use Carp qw/confess/;  
 use XML::Feed;  
 use DateTime::Format::Flexible;  
   
102  my $use_twitter = 1;  my $use_twitter = 1;
103  eval { require Net::Twitter; };  eval { require Net::Twitter; };
104  $use_twitter = 0 if ($@);  $use_twitter = 0 if ($@);
# Line 88  my $log_path; Line 108  my $log_path;
108  GetOptions(  GetOptions(
109          'import-dircproxy:s' => \$import_dircproxy,          'import-dircproxy:s' => \$import_dircproxy,
110          'log:s' => \$log_path,          'log:s' => \$log_path,
111            'debug!' => \$debug,
112  );  );
113    
114  #$SIG{__DIE__} = sub {  #$SIG{__DIE__} = sub {
115  #       confess "fatal error";  #       confess "fatal error";
116  #};  #};
117    
 open(STDOUT, '>', $log_path) || warn "can't redirect log to $log_path: $!";  
   
118  sub _log {  sub _log {
119          print strftime($TIMESTAMP,localtime()) . ' ' . join(" ",@_) . $/;          print strftime($TIMESTAMP,localtime()) . ' ' . join(" ",map { ref($_) ? dump( $_ ) : $_ } @_) . $/;
120  }  }
121    
122    open(STDOUT, '>', $log_path) && warn "log to $log_path: $!\n";
123    
124    
125  # HTML formatters  # HTML formatters
126    
127  my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;');  my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;');
128  my $escape_re  = join '|' => keys %escape;  my $escape_re  = join '|' => keys %escape;
129    
130  my $tag_regex = '\b([\w-_]+)//';  my $tag_regex = '\b([\w\-_]+)//';
131    
132  my %nick_enumerator;  my %nick_enumerator;
133  my $max_color = 0;  my $max_color = 0;
# Line 117  my $filter = { Line 139  my $filter = {
139                  # protect HTML from wiki modifications                  # protect HTML from wiki modifications
140                  sub e {                  sub e {
141                          my $t = shift;                          my $t = shift;
142                          return 'uri_unescape{' . uri_escape($t) . '}';                          return 'uri_unescape{' . uri_escape($t, '^a-zA-Z0-9') . '}';
143                  }                  }
144    
145                  $m =~ s/($escape_re)/$escape{$1}/gs;                  $m =~ s/($escape_re)/$escape{$1}/gs;
146                  $m =~ s#($RE{URI}{HTTP})#e(qq{<a href="$1">$1</a>})#egs ||                  $m =~ s#($RE{URI}{HTTP})#e(qq{<a href="$1">$1</a>})#egs;
147                  $m =~ s#\/(\w+)\/#<i>$1</i>#gs;                  $m =~ s#\/(\w+)\/#<i>$1</i>#gs;
148                  $m =~ s#$tag_regex#e(qq{<a href="$url?tag=$1" class="tag">$1</a>})#egs;                  $m =~ s#$tag_regex#e(qq{<a href="$url?tag=$1" class="tag">$1</a>})#egs;
149                  $m =~ s#\*(\w+)\*#<b>$1</b>#gs;                  $m =~ s#\*(\w+)\*#<b>$1</b>#gs;
# Line 142  my $filter = { Line 164  my $filter = {
164          },          },
165  };  };
166    
167    # POE IRC
168    my $poe_irc = POE::Component::IRC->spawn( %$irc_config ) or
169            die "can't start ", dump( $irc_config ), ": $!";
170    
171    my $irc = $poe_irc->session_id();
172    _log "IRC session_id $irc";
173    
174  my $dbh = DBI->connect($DSN,"","", { RaiseError => 1, AutoCommit => 1 }) || die $DBI::errstr;  my $dbh = DBI->connect($DSN,"","", { RaiseError => 1, AutoCommit => 1 }) || die $DBI::errstr;
175  $dbh->do( qq{ set client_encoding = 'UTF-8' } );  $dbh->do( qq{ set client_encoding = 'UTF-8' } );
176    
# Line 339  sub get_from_log { Line 368  sub get_from_log {
368    
369          my @where;          my @where;
370          my @args;          my @args;
371            my $msg;
372    
373          if (my $search = $args->{search}) {          if (my $search = $args->{search}) {
374                  $search =~ s/^\s+//;                  $search =~ s/^\s+//;
375                  $search =~ s/\s+$//;                  $search =~ s/\s+$//;
376                  push @where, 'message ilike ? or nick ilike ?';                  push @where, 'message ilike ? or nick ilike ?';
377                  push @args, ( ( '%' . $search . '%' ) x 2 );                  push @args, ( ( '%' . $search . '%' ) x 2 );
378                  _log "search for '$search'";                  $msg = "Search for '$search'";
379          }          }
380    
381          if ($args->{tag} && $tags->{ $args->{tag} }) {          if ($args->{tag} && $tags->{ $args->{tag} }) {
382                  push @where, 'id in (' . join(',', @{ $tags->{ $args->{tag} } }) . ')';                  push @where, 'id in (' . join(',', @{ $tags->{ $args->{tag} } }) . ')';
383                  _log "search for tags $args->{tag}";                  $msg = "Search for tags $args->{tag}";
384          }          }
385    
386          if (my $date = $args->{date} ) {          if (my $date = $args->{date} ) {
387                  $date = check_date( $date );                  $date = check_date( $date );
388                  push @where, 'date(time) = ?';                  push @where, 'date(time) = ?';
389                  push @args, $date;                  push @args, $date;
390                  _log "search for date $date";                  $msg = "search for date $date";
391          }          }
392    
393          $sql .= " where " . join(" and ", @where) if @where;          $sql .= " where " . join(" and ", @where) if @where;
# Line 371  sub get_from_log { Line 401  sub get_from_log {
401          eval { $sth->execute( @args ) };          eval { $sth->execute( @args ) };
402          return if $@;          return if $@;
403    
404            my $nr_results = $sth->rows;
405    
406          my $last_row = {          my $last_row = {
407                  date => '',                  date => '',
408                  time => '',                  time => '',
# Line 391  sub get_from_log { Line 423  sub get_from_log {
423    
424          return @rows if ($args->{full_rows});          return @rows if ($args->{full_rows});
425    
426          my @msgs = (          $msg .= ' produced ' . (
427                  "Showing " . ($#rows + 1) . " messages..."                  $nr_results == 0 ? 'no results' :
428                    $nr_results == 0 ? 'one result' :
429                            $nr_results . ' results'
430          );          );
431    
432            my @msgs = ( $msg );
433    
434          if ($context) {          if ($context) {
435                  my @ids = @rows;                  my @ids = @rows;
436                  @rows = ();                  @rows = ();
# Line 451  sub get_from_log { Line 487  sub get_from_log {
487  #                       $row->{nick} = $nick;  #                       $row->{nick} = $nick;
488  #               }  #               }
489    
490                    $append = 0 if $row->{me};
491    
492                  if ($last_row->{nick} ne $nick) {                  if ($last_row->{nick} ne $nick) {
493                          # obfu way to find format for me_nick if needed or fallback to default                          # obfu way to find format for me_nick if needed or fallback to default
494                          my $fmt = $row->{me} ? ( $args->{fmt}->{me_nick} || $args->{fmt}->{nick} ) : $args->{fmt}->{nick};                          my $fmt = $row->{me} ? ( $args->{fmt}->{me_nick} || $args->{fmt}->{nick} ) : $args->{fmt}->{nick};
# Line 487  sub get_from_log { Line 525  sub get_from_log {
525    
526  # tags support  # tags support
527    
528  my $cloud = HTML::TagCloud->new;  my $cloud = TagCloud->new;
529    $cloud->seed_tags;
 =head2 add_tag  
   
  add_tag( id => 42, message => 'irc message', nick => 'foobar' [, me => 1 ] );  
   
 =cut  
   
 my @last_tags;  
   
 sub add_tag {  
         my $arg = {@_};  
   
         return unless ($arg->{id} && $arg->{message});  
   
         my $m = $arg->{message};  
   
         my @tags;  
   
         while ($m =~ s#$tag_regex##s) {  
                 my $tag = $1;  
                 next if (! $tag || $tag =~ m/https?:/i);  
                 push @{ $tags->{$tag} }, $arg->{id};  
                 #warn "+tag $tag: $arg->{id}\n";  
                 $cloud->add($tag, "$url?tag=$tag", scalar @{$tags->{$tag}} + 1);  
                 push @tags, $tag;  
   
         }  
   
         if ( @tags ) {  
                 pop @last_tags if $#last_tags == $last_x_tags;  
                 unshift @last_tags, { tags => [ @tags ], %$arg };  
         }  
   
 }  
   
 =head2 seed_tags  
   
 Read all tags from database and create in-memory cache for tags  
   
 =cut  
   
 sub seed_tags {  
         my $sth = $dbh->prepare(qq{ select id,message,nick,me,time from log where message like '%//%' order by time asc });  
         $sth->execute;  
         while (my $row = $sth->fetchrow_hashref) {  
                 add_tag( %$row );  
         }  
   
         foreach my $tag (keys %$tags) {  
                 $cloud->add($tag, "$url?tag=$tag", scalar @{$tags->{$tag}} + 1);  
         }  
 }  
   
 seed_tags;  
   
530    
531  =head2 save_message  =head2 save_message
532    
# Line 566  sub save_message { Line 550  sub save_message {
550          $a->{me} ||= 0;          $a->{me} ||= 0;
551          $a->{time} ||= strftime($TIMESTAMP,localtime());          $a->{time} ||= strftime($TIMESTAMP,localtime());
552    
553          _log          _log "ARCHIVE",
554                  $a->{channel}, " ",                  $a->{channel}, " ",
555                  $a->{me} ? "***" . $a->{nick} : "<" . $a->{nick} . ">",                  $a->{me} ? "***" . $a->{nick} : "<" . $a->{nick} . ">",
556                  " " . $a->{message};                  " " . $a->{message};
557    
558          $sth_insert_log->execute($a->{channel}, $a->{me}, $a->{nick}, $a->{message}, $a->{time});          eval { $sth_insert_log->execute($a->{channel}, $a->{me}, $a->{nick}, $a->{message}, $a->{time}); };
559          add_tag( id => $dbh->last_insert_id(undef,undef,"log",undef), %$a );          _log "ERROR: can't archive ", $a->{message} if $@;
560            $cloud->add_tag( id => $dbh->last_insert_id(undef,undef,"log",undef), %$a );
561  }  }
562    
563    
# Line 614  if ($import_dircproxy) { Line 599  if ($import_dircproxy) {
599  # RSS follow  # RSS follow
600  #  #
601    
602  my $_rss;  my $_stat;
603    
604    POE::Component::Client::HTTP->spawn(
605            Alias   => 'rss-fetch',
606            Timeout => 30,
607    );
608    
609    =head2 rss_parse_xml
610    
611      rss_parse_xml({
612            url => 'http://www.example.com/rss',
613            send_rss_msgs => 42,
614      });
615    
616    =cut
617    
618  sub rss_fetch {  sub rss_parse_xml {
619          my ($args) = @_;          my ($kernel,$args) = @_;
620    
621            warn "## rss_parse_xml ",dump( $args ) if $debug;
622    
623          # how many messages to send out when feed is seen for the first time?          # how many messages to send out when feed is seen for the first time?
624          my $send_rss_msgs = 1;          my $send_rss_msgs = $args->{send_rss_msgs};
625            $send_rss_msgs = 1 if ! defined $send_rss_msgs;
626    
627          _log "RSS fetch", $args->{url};          warn "## RSS fetch first $send_rss_msgs items from", $args->{url} if $debug;
628    
629          my $feed = XML::Feed->parse(URI->new( $args->{url} ));          my $feed = XML::Feed->parse( \$args->{xml} );
630          if ( ! $feed ) {          if ( ! $feed ) {
631                  _log("can't fetch RSS ", $args->{url});                  _log "can't fetch RSS ", $args->{url}, XML::Feed->errstr;
632                  return;                  return;
633          }          }
634    
635            $_stat->{rss}->{url2link}->{ $args->{url} } = $feed->link;
636    
637          my ( $total, $updates ) = ( 0, 0 );          my ( $total, $updates ) = ( 0, 0 );
638          for my $entry ($feed->entries) {          for my $entry ($feed->entries) {
639                  $total++;                  $total++;
640    
641                    my $seen_times = $_stat->{rss}->{seen}->{$args->{channel}}->{$feed->link}->{$entry->id}++;
642                  # seen allready?                  # seen allready?
643                  next if $_rss->{$args->{channel}}->{$feed->link}->{$entry->id}++ > 0;                  warn "## $seen_times ",$entry->id if $debug;
644                    next if $seen_times > 0;
645    
646                  sub prefix {                  sub prefix {
647                          my ($txt,$var) = @_;                          my ($txt,$var) = @_;
# Line 655  sub rss_fetch { Line 660  sub rss_fetch {
660                  } elsif ( $link !~ m!^http! ) {                  } elsif ( $link !~ m!^http! ) {
661                          $link = $args->{url} . $link;                          $link = $args->{url} . $link;
662                  }                  }
                 $link =~ s!//+!/!g;  
663    
664                  my $msg;                  my $msg;
665                  $msg .= prefix( 'From: ' , $args->{name} || $feed->title );                  $msg .= prefix( 'From: ' , $args->{name} || $feed->title );
# Line 663  sub rss_fetch { Line 667  sub rss_fetch {
667                  $msg .= prefix( ' | ' , $entry->title );                  $msg .= prefix( ' | ' , $entry->title );
668                  $msg .= prefix( ' | ' , $link );                  $msg .= prefix( ' | ' , $link );
669  #               $msg .= prefix( ' id ' , $entry->id );  #               $msg .= prefix( ' id ' , $entry->id );
670                    my @categories = $entry->category;
671                    warn "## category = ", dump( @categories ) if $debug;
672                    if ( my $tags = $entry->category ) {
673                            $tags = join(' ', @$tags) if ref($tags) eq 'ARRAY';
674                            $tags =~ s!^\s+!!;
675                            $tags =~ s!\s*$! !;
676                            $tags =~ s!,?\s+!// !g;
677                            $msg .= prefix( ' ' , $tags );
678                    }
679    
680                  if ( $args->{kernel} && $send_rss_msgs ) {                  if ( $seen_times == 0 && $send_rss_msgs ) {
681                          $send_rss_msgs--;                          $send_rss_msgs--;
682                          $sth_insert_log->execute( $args->{channel}, 1, $NICK, $msg, 'now()' );                          if ( ! $args->{private} ) {
683                                    # FIXME bug! should be save_message
684                                    save_message( channel => $args->{channel}, me => 1, nick => $NICK, message => $msg );
685    #                               $sth_insert_log->execute( $args->{channel}, 1, $NICK, $msg, 'now()' );
686                            }
687                          my ( $type, $to ) = ( 'notice', $args->{channel} );                          my ( $type, $to ) = ( 'notice', $args->{channel} );
688                          ( $type, $to ) = ( 'privmsg', $args->{nick} ) if $args->{private};                          ( $type, $to ) = ( 'privmsg', $args->{nick} ) if $args->{private};
689                          _log(">> $type $to |", $msg);  
690                          $args->{kernel}->post( $IRC_ALIAS => $type => $to, $msg );                          _log(">> RSS $type to $to:", $msg);
691                            $kernel->post( $irc => $type => $to => $msg );
692    
693                          $updates++;                          $updates++;
694                  }                  }
695          }          }
# Line 680  sub rss_fetch { Line 699  sub rss_fetch {
699          $sql .= qq{where id = } . $args->{id};          $sql .= qq{where id = } . $args->{id};
700          eval { $dbh->do( $sql ) };          eval { $dbh->do( $sql ) };
701    
702          _log "RSS got $total items of which $updates new";          _log "RSS $updates/$total new items from", $args->{url};
703    
704          return $updates;          return $updates;
705  }  }
706    
707  sub rss_fetch_all {  sub rss_fetch_all {
708          my $kernel = shift;          my ( $kernel, $send_rss_msgs )  = @_;
709            warn "## rss_fetch_all -- send_rss_msgs: $send_rss_msgs\n" if $debug;
710          my $sql = qq{          my $sql = qq{
711                  select id, url, name, channel, nick, private                  select id, url, name, channel, nick, private
712                  from feeds                  from feeds
713                  where active is true                  where active is true
714          };          };
715          # limit to newer feeds only if we are not sending messages out          # limit to newer feeds only if we are not sending messages out
716          $sql .= qq{     and last_update + delay < now() } if $kernel;          $sql .= qq{     and last_update + delay < now() } if defined ( $_stat->{rss}->{fetch} );
717          my $sth = $dbh->prepare( $sql );          my $sth = $dbh->prepare( $sql );
718          $sth->execute();          $sth->execute();
719          warn "# ",$sth->rows," active RSS feeds\n";          warn "# ",$sth->rows," active RSS feeds\n";
720          my $count = 0;          my $count = 0;
721          while (my $row = $sth->fetchrow_hashref) {          while (my $row = $sth->fetchrow_hashref) {
722                  $row->{kernel} = $kernel if $kernel;                  $row->{send_rss_msgs} = $send_rss_msgs if defined $send_rss_msgs;
723                  $count += rss_fetch( $row );                  $_stat->{rss}->{fetch}->{ $row->{url} } = $row;
724                    $kernel->post(
725                            'rss-fetch',
726                            'request',
727                            'rss_response',
728                            HTTP::Request->new( GET => $row->{url} ),
729                    );
730                    warn "## queued rss-fetch ", dump( $row ) if $debug;
731          }          }
732          return "OK, fetched $count posts from " . $sth->rows . " feeds";          return "OK, scheduled " . $sth->rows . " feeds for refresh";
733  }  }
734    
735    
736  sub rss_check_updates {  sub rss_check_updates {
737          my $kernel = shift;          my $kernel = shift;
738          $_rss->{last_poll} ||= time();          $_stat->{rss}->{last_poll} ||= time();
739          my $dt = time() - $_rss->{last_poll};          my $dt = time() - $_stat->{rss}->{last_poll};
         warn "## rss_check_updates $dt > $rss_min_delay\n";  
740          if ( $dt > $rss_min_delay ) {          if ( $dt > $rss_min_delay ) {
741                  $_rss->{last_poll} = time();                  warn "## rss_check_updates $dt > $rss_min_delay\n";
742                    $_stat->{rss}->{last_poll} = time();
743                  _log rss_fetch_all( $kernel );                  _log rss_fetch_all( $kernel );
744          }          }
745  }  }
746    
747  # seed rss seen cache so we won't send out all items on startup  sub process_command {
748  _log rss_fetch_all;          my ( $kernel, $nick, $channel, $msg ) = @_;
749    
750  #          my $res = "unknown command '$msg', try /msg $NICK help!";
751  # POE handing part  
752  #          if ($msg =~ m/^help/i) {
753    
754                    $res = "usage: /msg $NICK comand | commands: stat - user/message stat | last - show backtrace | grep foobar - find foobar";
755    
756            } elsif ($msg =~ m/^(privmsg|notice)\s+(\S+)\s+(.*)$/i) {
757    
758                    _log ">> /$1 $2 $3";
759                    $kernel->post( $irc => $1 => $2, $3 );
760                    $res = '';
761    
762  my $ping;                                               # ping stats          } elsif ($msg =~ m/^stat.*?\s*(\d*)/i) {
763    
764                    my $nr = $1 || 10;
765    
766                    my $sth = $dbh->prepare(qq{
767                            select
768                                    trim(both '_' from nick) as nick,
769                                    count(*) as count,
770                                    sum(length(message)) as len
771                            from log
772                            group by trim(both '_' from nick)
773                            order by len desc,count desc
774                            limit $nr
775                    });
776                    $sth->execute();
777                    $res = "Top $nr users: ";
778                    my @users;
779                    while (my $row = $sth->fetchrow_hashref) {
780                            push @users,$row->{nick} . ': ' . $row->{count} . '/' . $row->{len} . '=' . sprintf("%.2f", $row->{len}/$row->{count});
781                    }
782                    $res .= join(" | ", @users);
783            } elsif ($msg =~ m/^last.*?\s*(\d*)/i) {
784    
785                    my $limit = $1 || meta( $nick, $channel, 'last-size' ) || 10;
786    
787                    foreach my $res (get_from_log( limit => $limit )) {
788                            _log "last: $res";
789                            $kernel->post( $irc => privmsg => $nick, $res );
790                    }
791    
792                    $res = '';
793    
794            } elsif ($msg =~ m/^(search|grep)\s+(.*)\s*$/i) {
795    
796                    my $what = $2;
797    
798                    foreach my $res (get_from_log(
799                                    limit => 20,
800                                    search => $what,
801                            )) {
802                            _log "search [$what]: $res";
803                            $kernel->post( $irc => privmsg => $nick, $res );
804                    }
805    
806                    $res = '';
807    
808            } elsif ($msg =~ m/^(?:count|poll)\s+(.*)(?:\s+(\d+))?\s*$/i) {
809    
810                    my ($what,$limit) = ($1,$2);
811                    $limit ||= 100;
812    
813                    my $stat;
814    
815                    foreach my $res (get_from_log(
816                                    limit => $limit,
817                                    search => $what,
818                                    full_rows => 1,
819                            )) {
820                            while ($res->{message} =~ s/\Q$what\E(\+|\-)//) {
821                                    $stat->{vote}->{$1}++;
822                                    $stat->{from}->{ $res->{nick} }++;
823                            }
824                    }
825    
826                    my @nicks;
827                    foreach my $nick (sort { $stat->{from}->{$a} <=> $stat->{from}->{$b} } keys %{ $stat->{from} }) {
828                            push @nicks, $nick . ( $stat->{from}->{$nick} == 1 ? '' :
829                                    "(" . $stat->{from}->{$nick} . ")"
830                            );
831                    }
832    
833                    $res =
834                            "$what ++ " . ( $stat->{vote}->{'+'} || 0 ) .
835                            " : " . ( $stat->{vote}->{'-'} || 0 ) . " --" .
836                            " from " . ( join(", ", @nicks) || 'nobody' );
837    
838                    $kernel->post( $irc => notice => $nick, $res );
839    
840            } elsif ($msg =~ m/^ping/) {
841                    $res = "ping = " . dump( $_stat->{ping} );
842            } elsif ($msg =~ m/^conf(?:ig)*\s*(last-size|twitter)*\s*(.*)/) {
843                    if ( ! defined( $1 ) ) {
844                            my $sth = $dbh->prepare(qq{ select name,value,changed from meta where nick = ? and channel = ? });
845                            $sth->execute( $nick, $channel );
846                            $res = "config for $nick on $channel";
847                            while ( my ($n,$v) = $sth->fetchrow_array ) {
848                                    $res .= " | $n = $v";
849                            }
850                    } elsif ( ! $2 ) {
851                            my $val = meta( $nick, $channel, $1 );
852                            $res = "current $1 = " . ( $val ? $val : 'undefined' );
853                    } else {
854                            my $validate = {
855                                    'last-size' => qr/^\d+/,
856                                    'twitter' => qr/^\w+\s+\w+/,
857                            };
858    
859                            my ( $op, $val ) = ( $1, $2 );
860    
861                            if ( my $regex = $validate->{$op} ) {
862                                    if ( $val =~ $regex ) {
863                                            meta( $nick, $channel, $op, $val );
864                                            $res = "saved $op = $val";
865                                    } else {
866                                            $res = "config option $op = $val doesn't validate against $regex";
867                                    }
868                            } else {
869                                    $res = "config option $op doesn't exist";
870                            }
871                    }
872            } elsif ($msg =~ m/^rss-update/) {
873                    $res = rss_fetch_all( $kernel );
874            } elsif ($msg =~ m/^rss-list/) {
875                    my $sth = $dbh->prepare(qq{ select url,name,last_update,active,channel,nick,private from feeds });
876                    $sth->execute;
877                    while (my @row = $sth->fetchrow_array) {
878                            $kernel->post( $irc => privmsg => $nick, join(' | ',@row) );
879                    }
880                    $res = '';
881            } elsif ($msg =~ m!^rss-(add|remove|stop|start|clean)(?:-(private))?\s+(http://\S+)\s*(.*)!) {
882                    my ( $command, $sub, $url, $arg ) = ( $1,$2,$3,$4 );
883    
884                    my $channel = $1 if ( $arg =~ s/\s*(#\S+)\s*// );
885                    $channel = $nick if $sub eq 'private';
886    
887                    my $sql = {
888                            add     => qq{ insert into feeds (url,name,channel,nick,private) values (?,?,?,?,?) },
889                            remove  => qq{ delete from feeds                                where url = ? and nick = ? },
890                            start   => qq{ update feeds set active = true   where url = ? },
891                            stop    => qq{ update feeds set active = false  where url = ? },
892                            clean   => qq{ update feeds set last_update = now() - delay where url = ? },
893                    };
894    
895                    if ( $command eq 'add' && ! $channel ) {
896                            $res = "ERROR: got '$msg' which doesn't have #channel in it, ignoring!";
897                    } elsif (my $q = $sql->{$command} ) {
898                            my $sth = $dbh->prepare( $q );
899                            my @data = ( $url );
900                            if ( $command eq 'add' ) {
901                                    push @data, ( $arg, $channel, $nick, $sub eq 'private' ? 1 : 0 );
902                            } elsif ( $command eq 'remove' ) {
903                                    push @data, $nick;
904                            }
905                            warn "## $command SQL $q with ",dump( @data ),"\n";
906                            eval { $sth->execute( @data ) };
907                            if ($@) {
908                                    $res = "ERROR: $@";
909                            } else {
910                                    $res = "OK, RSS executed $command" .
911                                            ( $sub ? "-$sub " : ' ' ) .
912                                            ( $channel ? "on $channel " : '' ) .
913                                            "url $url";
914                                    if ( $command eq 'clean' ) {
915                                            my $seen = $_stat->{rss}->{seen} || die "no seen?";
916                                            my $want_link = $_stat->{rss}->{url2link}->{$url} || warn "no url2link($url)";
917                                            foreach my $c ( keys %$seen ) {
918                                                    my $c_hash = $seen->{$c} || die "no seen->{$c}";
919                                                    die "not HASH with rss links but ", dump($c_hash) unless ref($c_hash) eq 'HASH';
920                                                    foreach my $link ( keys %$c_hash ) {
921                                                            next unless $link eq $want_link;
922                                                            _log "RSS removed seen $c $url $link";
923                                                    }
924                                            }
925                                    } elsif ( $command eq 'add' ) {
926                                            rss_fetch_all( $kernel );
927                                    }
928                            }
929                    } else {
930                            $res = "ERROR: don't know what to do with: $msg";
931                    }
932            } elsif ($msg =~ m/^rss-clean/) {
933                    # this makes sense because we didn't catch rss-clean http://... before!
934                    $_stat->{rss} = undef;
935                    $dbh->do( qq{ update feeds set last_update = now() - delay } );
936                    $res = rss_fetch_all( $kernel );
937            }
938    
939  POE::Component::IRC->new($IRC_ALIAS);          return $res;
940    }
941    
942  POE::Session->create( inline_states => {  POE::Session->create( inline_states => {
943          _start => sub {                _start => sub {      
944                  $_[KERNEL]->post($IRC_ALIAS => register => 'all');                  $_[KERNEL]->post( $irc => register => 'all' );
945                  $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);                  $_[KERNEL]->post( $irc => connect => {} );
     },  
     irc_255 => sub {    # server is done blabbing  
                 $_[KERNEL]->post($IRC_ALIAS => join => $CHANNEL);  
                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );  
946      },      },
947            irc_001 => sub {
948                    my ($kernel,$sender) = @_[KERNEL,SENDER];
949                    my $poco_object = $sender->get_heap();
950                    _log "connected to",$poco_object->server_name();
951                    $kernel->post( $sender => join => $_ ) for @channels;
952                    # seen RSS cache, so don't send out messages
953                    _log rss_fetch_all( $kernel, 0 );
954                    undef;
955            },
956    #       irc_255 => sub {        # server is done blabbing
957    #               $_[KERNEL]->post( $irc => join => $CHANNEL);
958    #       },
959      irc_public => sub {      irc_public => sub {
960                  my $kernel = $_[KERNEL];                  my $kernel = $_[KERNEL];
961                  my $nick = (split /!/, $_[ARG0])[0];                  my $nick = (split /!/, $_[ARG0])[0];
# Line 767  POE::Session->create( inline_states => { Line 986  POE::Session->create( inline_states => {
986      },      },
987          irc_ping => sub {          irc_ping => sub {
988                  _log( "pong ", $_[ARG0] );                  _log( "pong ", $_[ARG0] );
989                  $ping->{ $_[ARG0] }++;                  $_stat->{ping}->{ $_[ARG0] }++;
990                  rss_check_updates( $_[KERNEL] );                  rss_check_updates( $_[KERNEL] );
991          },          },
992          irc_invite => sub {          irc_invite => sub {
# Line 777  POE::Session->create( inline_states => { Line 996  POE::Session->create( inline_states => {
996    
997                  _log "invited to $channel by $nick";                  _log "invited to $channel by $nick";
998    
999                  $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, "how nice of you to invite me to $channel, I'll be right there..." );                  $_[KERNEL]->post( $irc => privmsg => $nick, "how nice of you to invite me to $channel, I'll be right there..." );
1000                  $_[KERNEL]->post($IRC_ALIAS => join => $channel);                  $_[KERNEL]->post( $irc => 'join' => $channel );
1001    
1002          },          },
1003          irc_msg => sub {          irc_msg => sub {
1004                  my $kernel = $_[KERNEL];                  my $kernel = $_[KERNEL];
1005                  my $nick = (split /!/, $_[ARG0])[0];                  my $nick = (split /!/, $_[ARG0])[0];
                 my $msg = $_[ARG2];  
1006                  my $channel = $_[ARG1]->[0];                  my $channel = $_[ARG1]->[0];
1007                    my $msg = $_[ARG2];
1008                  my $res = "unknown command '$msg', try /msg $NICK help!";                  warn "# ARG = ",dump( @_[ARG0,ARG1,ARG2] ) if $debug;
                 my @out;  
1009    
1010                  _log "<< $msg";                  _log "<< $msg";
1011    
1012                  if ($msg =~ m/^help/i) {                  my $res = process_command( $_[KERNEL], $nick, $channel, $msg );
   
                         $res = "usage: /msg $NICK comand | commands: stat - user/message stat | last - show backtrace | grep foobar - find foobar";  
   
                 } elsif ($msg =~ m/^msg\s+(\S+)\s+(.*)$/i) {  
   
                         _log ">> /msg $1 $2";  
                         $_[KERNEL]->post( $IRC_ALIAS => privmsg => $1, $2 );  
                         $res = '';  
   
                 } elsif ($msg =~ m/^stat.*?\s*(\d*)/i) {  
   
                         my $nr = $1 || 10;  
   
                         my $sth = $dbh->prepare(qq{  
                                 select  
                                         trim(both '_' from nick) as nick,  
                                         count(*) as count,  
                                         sum(length(message)) as len  
                                 from log  
                                 group by trim(both '_' from nick)  
                                 order by len desc,count desc  
                                 limit $nr  
                         });  
                         $sth->execute();  
                         $res = "Top $nr users: ";  
                         my @users;  
                         while (my $row = $sth->fetchrow_hashref) {  
                                 push @users,$row->{nick} . ': ' . $row->{count} . '/' . $row->{len} . '=' . sprintf("%.2f", $row->{len}/$row->{count});  
                         }  
                         $res .= join(" | ", @users);  
                 } elsif ($msg =~ m/^last.*?\s*(\d*)/i) {  
   
                         my $limit = $1 || meta( $nick, $channel, 'last-size' ) || 10;  
   
                         foreach my $res (get_from_log( limit => $limit )) {  
                                 _log "last: $res";  
                                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );  
                         }  
   
                         $res = '';  
   
                 } elsif ($msg =~ m/^(search|grep)\s+(.*)\s*$/i) {  
   
                         my $what = $2;  
   
                         foreach my $res (get_from_log(  
                                         limit => 20,  
                                         search => $what,  
                                 )) {  
                                 _log "search [$what]: $res";  
                                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );  
                         }  
   
                         $res = '';  
   
                 } elsif ($msg =~ m/^(?:count|poll)\s+(.*)(?:\s+(\d+))?\s*$/i) {  
   
                         my ($what,$limit) = ($1,$2);  
                         $limit ||= 100;  
   
                         my $stat;  
   
                         foreach my $res (get_from_log(  
                                         limit => $limit,  
                                         search => $what,  
                                         full_rows => 1,  
                                 )) {  
                                 while ($res->{message} =~ s/\Q$what\E(\+|\-)//) {  
                                         $stat->{vote}->{$1}++;  
                                         $stat->{from}->{ $res->{nick} }++;  
                                 }  
                         }  
   
                         my @nicks;  
                         foreach my $nick (sort { $stat->{from}->{$a} <=> $stat->{from}->{$b} } keys %{ $stat->{from} }) {  
                                 push @nicks, $nick . ( $stat->{from}->{$nick} == 1 ? '' :  
                                         "(" . $stat->{from}->{$nick} . ")"  
                                 );  
                         }  
   
                         $res =  
                                 "$what ++ " . ( $stat->{vote}->{'+'} || 0 ) .  
                                 " : " . ( $stat->{vote}->{'-'} || 0 ) . " --" .  
                                 " from " . ( join(", ", @nicks) || 'nobody' );  
   
                         $_[KERNEL]->post( $IRC_ALIAS => notice => $nick, $res );  
   
                 } elsif ($msg =~ m/^ping/) {  
                         $res = "ping = " . dump( $ping );  
                 } elsif ($msg =~ m/^conf(?:ig)*\s*(last-size|twitter)*\s*(.*)/) {  
                         if ( ! defined( $1 ) ) {  
                                 my $sth = $dbh->prepare(qq{ select name,value,changed from meta where nick = ? and channel = ? });  
                                 $sth->execute( $nick, $channel );  
                                 $res = "config for $nick on $channel";  
                                 while ( my ($n,$v) = $sth->fetchrow_array ) {  
                                         $res .= " | $n = $v";  
                                 }  
                         } elsif ( ! $2 ) {  
                                 my $val = meta( $nick, $channel, $1 );  
                                 $res = "current $1 = " . ( $val ? $val : 'undefined' );  
                         } else {  
                                 my $validate = {  
                                         'last-size' => qr/^\d+/,  
                                         'twitter' => qr/^\w+\s+\w+/,  
                                 };  
   
                                 my ( $op, $val ) = ( $1, $2 );  
   
                                 if ( my $regex = $validate->{$op} ) {  
                                         if ( $val =~ $regex ) {  
                                                 meta( $nick, $channel, $op, $val );  
                                                 $res = "saved $op = $val";  
                                         } else {  
                                                 $res = "config option $op = $val doesn't validate against $regex";  
                                         }  
                                 } else {  
                                         $res = "config option $op doesn't exist";  
                                 }  
                         }  
                 } elsif ($msg =~ m/^rss-update/) {  
                         $res = rss_fetch_all( $_[KERNEL] );  
                 } elsif ($msg =~ m/^rss-clean/) {  
                         $_rss = undef;  
                         $dbh->do( qq{ update feeds set last_update = now() - delay } );  
                         $res = "OK, cleaned RSS cache";  
                 } elsif ($msg =~ m/^rss-list/) {  
                         my $sth = $dbh->prepare(qq{ select url,name,last_update,active,channel,nick,private from feeds });  
                         $sth->execute;  
                         while (my @row = $sth->fetchrow_array) {  
                                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, join(' | ',@row) );  
                         }  
                         $res = '';  
                 } elsif ($msg =~ m!^rss-(add|remove|stop|start)(?:-(private))?\s+(http://\S+)\s*(.*)!) {  
                         my ( $command, $sub, $url, $arg ) = ( $1,$2,$3,$4 );  
   
                         my $channel = $1 if ( $arg =~ s/\s*(#\S+)\s*// );  
                         $channel = $nick if $sub eq 'private';  
   
                         my $sql = {  
                                 add             => qq{ insert into feeds (url,name,channel,nick,private) values (?,?,?,?,?) },  
 #                               remove  => qq{ delete from feeds                                where url = ? and name = ? },  
                                 start   => qq{ update feeds set active = true   where url = ? },  
                                 stop    => qq{ update feeds set active = false  where url = ? },  
                         };  
   
                         if (my $q = $sql->{$command} ) {  
                                 my $sth = $dbh->prepare( $q );  
                                 my @data = ( $url );  
                                 if ( $command eq 'add' ) {  
                                         push @data, ( $arg, $channel, $nick, $sub eq 'private' ? 1 : 0 );  
                                 }  
                                 warn "## $command SQL $q with ",dump( @data ),"\n";  
                                 eval { $sth->execute( @data ) };  
                                 if ($@) {  
                                         $res = "ERROR: $@";  
                                 } else {  
                                         $res = "OK, RSS [$command|$sub|$url|$arg]";  
                                 }  
                         } else {  
                                 $res = "ERROR: don't know what to do with: $msg";  
                         }  
   
                 }  
1013    
1014                  if ($res) {                  if ($res) {
1015                          _log ">> [$nick] $res";                          _log ">> [$nick] $res";
1016                          $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );                          $_[KERNEL]->post( $irc => privmsg => $nick, $res );
1017                  }                  }
1018    
1019                  rss_check_updates( $_[KERNEL] );                  rss_check_updates( $_[KERNEL] );
1020          },          },
1021            irc_372 => sub {
1022                    _log "<< motd",$_[ARG0],$_[ARG1];
1023            },
1024            irc_375 => sub {
1025                    _log "<< motd", $_[ARG0], "start";
1026            },
1027            irc_376 => sub {
1028                    _log "<< motd", $_[ARG0], "end";
1029            },
1030    #       irc_433 => sub {
1031    #               print "# irc_433: ",$_[ARG1], "\n";
1032    #               warn "## indetify $NICK\n";
1033    #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "IDENTIFY $NICK" );
1034    #       },
1035    #       irc_451 # please register
1036          irc_477 => sub {          irc_477 => sub {
1037                  _log "# irc_477: ",$_[ARG1];                  _log "<< irc_477: ",$_[ARG1];
1038                  $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "register $NICK" );                  _log ">> IDENTIFY $NICK";
1039                    $_[KERNEL]->post( $irc => privmsg => 'NickServ', "IDENTIFY $NICK" );
1040          },          },
1041          irc_505 => sub {          irc_505 => sub {
1042                  _log "# irc_505: ",$_[ARG1];                  _log "<< irc_505: ",$_[ARG1];
1043                  $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "register $NICK" );                  _log ">> register $NICK";
1044  #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "set hide email on" );                  $_[KERNEL]->post( $irc => privmsg => 'NickServ', "register $NICK" );
1045  #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "set email dpavlin\@rot13.org" );  #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "IDENTIFY $NICK" );
1046    #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "set hide email on" );
1047    #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "set email dpavlin\@rot13.org" );
1048          },          },
1049          irc_registered => sub {          irc_registered => sub {
1050                  _log "## registrated $NICK";                  _log "<< registered $NICK";
                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );  
1051          },          },
1052          irc_disconnected => sub {          irc_disconnected => sub {
1053                  _log "## disconnected, reconnecting again";                  _log "## disconnected.. sleeping for $sleep_on_error seconds and reconnecting again";
1054                  $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);                  sleep($sleep_on_error);
1055                    $_[KERNEL]->post( $irc => connect => {} );
1056          },          },
1057          irc_socketerr => sub {          irc_socketerr => sub {
1058                  _log "## socket error... sleeping for $sleep_on_error seconds and retry";                  _log "## socket error... sleeping for $sleep_on_error seconds and retry";
1059                  sleep($sleep_on_error);                  sleep($sleep_on_error);
1060                  $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);                  $_[KERNEL]->post( $irc => connect => {} );
1061            },
1062            irc_notice => sub {
1063                    _log "<< notice from ", $_[ARG0], $_[ARG1], $_[ARG2];
1064                    my $m = $_[ARG2];
1065                    if ( $m =~ m!/msg.*(NickServ).*(IDENTIFY)!i ) {
1066                            _log ">> suggested to $1 $2";
1067                            $_[KERNEL]->post( $irc => privmsg => $1, "$2 $NICK" );
1068                    } elsif ( $m =~ m!\Q$NICK\E.*registered!i ) {
1069                            _log ">> registreted, so IDENTIFY";
1070                            $_[KERNEL]->post( $irc => privmsg => 'nickserv', "IDENTIFY $NICK" );
1071                    } else {
1072                            warn "## ignore $m\n" if $debug;
1073                    }
1074            },
1075            irc_snotice => sub {
1076                    _log "<< snotice", $_[ARG0]; #dump( $_[ARG0],$_[ARG1], $_[ARG2] );
1077                    if ( $_[ARG0] =~ m!/(QUOTE)\s+(PASS\s+\d+)!i ) {
1078                            warn ">> $1 | $2\n";
1079                            $_[KERNEL]->post( $irc => lc($1) => $2);
1080                    }
1081          },          },
 #       irc_433 => sub {  
 #               print "# irc_433: ",$_[ARG1], "\n";  
 #               warn "## indetify $NICK\n";  
 #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );  
 #       },  
1082      _child => sub {},      _child => sub {},
1083      _default => sub {      _default => sub {
1084                  _log sprintf "sID:%s %s %s",                  _log '_default SID:', $_[SESSION]->ID, $_[ARG0], dump( $_[ARG1] );
1085                          $_[SESSION]->ID, $_[ARG0],                  0; # false for signals
                         ref($_[ARG1]) eq "ARRAY"        ?       join(",", map { ref($_) eq "ARRAY" ? join(";", @{$_}) : $_ } @{ $_[ARG1] })     :  
                         $_[ARG1]                                        ?       $_[ARG1]                                        :  
                         "";  
       0;                        # false for signals  
1086      },      },
1087            rss_response => sub {
1088                    my ($request_packet, $response_packet) = @_[ARG0, ARG1];
1089                    my $request_object  = $request_packet->[0];
1090                    my $response_object = $response_packet->[0];
1091    
1092                    my $row = delete( $_stat->{rss}->{fetch}->{ $request_object->uri } );
1093                    if ( $row ) {
1094                            $row->{xml} = $response_object->content;
1095                            rss_parse_xml( $_[KERNEL], $row );
1096                    } else {
1097                            warn "## can't find rss->fetch for ", $request_object->uri;
1098                    }
1099            },
1100     },     },
1101    );    );
1102    
1103  # http server  # http server
1104    
1105    _log "WEB archive at $url";
1106    
1107  my $httpd = POE::Component::Server::HTTP->new(  my $httpd = POE::Component::Server::HTTP->new(
1108          Port => $http_port,          Port => $http_port,
1109          PreHandler => {          PreHandler => {
# Line 1052  foreach my $c (@cols) { Line 1150  foreach my $c (@cols) {
1150          $style .= ".col-${max_color} { background: $c }\n";          $style .= ".col-${max_color} { background: $c }\n";
1151          $max_color++;          $max_color++;
1152  }  }
1153  warn "defined $max_color colors for users...\n";  _log "WEB defined $max_color colors for users...";
1154    
1155  sub root_handler {  sub root_handler {
1156          my ($request, $response) = @_;          my ($request, $response) = @_;
# Line 1074  sub root_handler { Line 1172  sub root_handler {
1172          }          }
1173    
1174          my $search = $q->param('search') || $q->param('grep') || '';          my $search = $q->param('search') || $q->param('grep') || '';
1175            my $r_url = $request->url;
1176    
1177            my @commands = qw( tags last-tag follow stat );
1178            my $commands_re = join('|',@commands);
1179    
1180          if ($request->url =~ m#/rss(?:/(tags|last-tag|follow.*)\w*(?:=(\d+))?)?#i) {          if ($r_url =~ m#/rss(?:/($commands_re.*)\w*(?:=(\d+))?)?#i) {
1181                  my $show = lc($1);                  my $show = lc($1);
1182                  my $nr = $2;                  my $nr = $2;
1183    
# Line 1084  sub root_handler { Line 1186  sub root_handler {
1186                  $response->content_type( 'application/' . lc($type) . '+xml' );                  $response->content_type( 'application/' . lc($type) . '+xml' );
1187    
1188                  my $html = '<!-- error -->';                  my $html = '<!-- error -->';
1189                  #warn "create $type feed from ",dump( @last_tags );                  #warn "create $type feed from ",dump( $cloud->last_tags );
1190    
1191                  my $feed = XML::Feed->new( $type );                  my $feed = XML::Feed->new( $type );
1192                  $feed->link( $url );                  $feed->link( $url );
1193    
1194                    my $rc = RC_OK;
1195    
1196                  if ( $show eq 'tags' ) {                  if ( $show eq 'tags' ) {
1197                          $nr ||= 50;                          $nr ||= 50;
1198                          $feed->title( "tags from $CHANNEL" );                          $feed->title( "tags from $CHANNEL" );
# Line 1116  sub root_handler { Line 1220  sub root_handler {
1220                          $feed->title( "last $nr tagged messages from $CHANNEL" );                          $feed->title( "last $nr tagged messages from $CHANNEL" );
1221                          $feed->description( "collects messages which have tags// in them" );                          $feed->description( "collects messages which have tags// in them" );
1222    
1223                          foreach my $m ( @last_tags ) {                          foreach my $m ( $cloud->last_tags ) {
1224  #                               warn dump( $m );  #                               warn dump( $m );
1225                                  #my $tags = join(' ', @{$m->{tags}} );                                  #my $tags = join(' ', @{$m->{tags}} );
1226                                  my $feed_entry = XML::Feed::Entry->new($type);                                  my $feed_entry = XML::Feed::Entry->new($type);
# Line 1158  sub root_handler { Line 1262  sub root_handler {
1262                                  $feed->add_entry( $feed_entry );                                  $feed->add_entry( $feed_entry );
1263                          }                          }
1264    
1265                    } elsif ( $show =~ m/^stat/ ) {
1266    
1267                          my $feed_entry = XML::Feed::Entry->new($type);                          my $feed_entry = XML::Feed::Entry->new($type);
1268                          $feed_entry->title( "Internal stats" );                          $feed_entry->title( "Internal stats" );
1269                          $feed_entry->content(                          $feed_entry->content(
1270                                  '<![CDATA[<pre>' . dump( $_rss ) . '</pre>]]>'                                  '<![CDATA[<pre>' . dump( $_stat ) . '</pre>]]>'
1271                          );                          );
1272                          $feed->add_entry( $feed_entry );                          $feed->add_entry( $feed_entry );
1273    
1274                  } else {                  } else {
1275                          _log "unknown rss request ",$request->url;                          _log "WEB unknown rss request $r_url";
1276                          return RC_DENY;                          $feed->title( "unknown $r_url" );
1277                            foreach my $c ( @commands ) {
1278                                    my $feed_entry = XML::Feed::Entry->new($type);
1279                                    $feed_entry->title( "rss/$c" );
1280                                    $feed_entry->link( "$url/rss/$c" );
1281                                    $feed->add_entry( $feed_entry );
1282                            }
1283                            $rc = RC_DENY;
1284                  }                  }
1285    
1286                  $response->content( $feed->as_xml );                  $response->content( $feed->as_xml );
1287                  return RC_OK;                  return $rc;
1288          }          }
1289    
1290          if ( $@ ) {          if ( $@ ) {
# Line 1262  sub root_handler { Line 1375  sub root_handler {
1375          <p>See <a href="/history">history</a> of all messages.</p>          <p>See <a href="/history">history</a> of all messages.</p>
1376          </body></html>};          </body></html>};
1377    
1378          $response->content( $html );          $response->content( decode('utf-8',$html) );
1379          warn "<< ", $request->method, " ", $request->uri, " created ", length($html), " bytes\n";          warn "<< ", $request->method, " ", $request->uri, " created ", length($html), " bytes\n";
1380          return RC_OK;          return RC_OK;
1381  }  }
1382    
1383  POE::Kernel->run;  POE::Kernel->run;
1384    
1385    =head1 TagCloud
1386    
1387    Extended L<HTML::TagCloud>
1388    
1389    =cut
1390    
1391    package TagCloud;
1392    use warnings;
1393    use strict;
1394    use HTML::TagCloud;
1395    use base 'HTML::TagCloud';
1396    use Data::Dump qw/dump/;
1397    
1398    =head2 html
1399    
1400    Generate html with number of tags in title of link
1401    
1402    =cut
1403    
1404    sub html {
1405            my($self, $limit) = @_;
1406            my @tags=$self->tags($limit);
1407    
1408            my $ntags = scalar(@tags);
1409            if ($ntags == 0) {
1410                    return "";
1411    #       } elsif ($ntags == 1) {
1412    #               my $tag = $tags[0];
1413    #               return qq{<div id="htmltagcloud"><span class="tagcloud1"><a href="}.
1414    #               $tag->{url}.qq{">}.$tag->{name}.qq{</a></span></div>\n};
1415            }
1416    
1417      my $html = qq{<div id="htmltagcloud">};
1418      foreach my $tag (@tags) {
1419        $html .=  sprintf(qq{<span class="tag tagcloud%d"><a href="%s" title="%s">%s</a></span>\n},
1420                    $tag->{level}, $tag->{url}, $tag->{count}, $tag->{name}
1421            );
1422      }
1423      $html .= qq{</div>};
1424      return $html;
1425    }
1426    
1427    =head2 last_tags
1428    
1429      my @tags = $cloud->last_tags;
1430    
1431    =cut
1432    
1433    my @last_tags;
1434    sub last_tags {
1435            return @last_tags;
1436    }
1437    
1438    =head2 add_tag
1439    
1440     $cloud->add_tag( id => 42, message => 'irc message', nick => 'foobar' [, me => 1 ] );
1441    
1442    =cut
1443    
1444    
1445    sub add_tag {
1446            my $self = shift;
1447            my $arg = {@_};
1448    
1449            return unless ($arg->{id} && $arg->{message});
1450    
1451            my $m = $arg->{message};
1452    
1453            my @tags;
1454    
1455            while ($m =~ s#$tag_regex##s) {
1456                    my $tag = $1;
1457                    next if (! $tag || $tag =~ m/https?:/i);
1458                    push @{ $tags->{$tag} }, $arg->{id};
1459                    #warn "+tag $tag: $arg->{id}\n";
1460                    $self->add($tag, "$url?tag=$tag", scalar @{$tags->{$tag}});
1461                    push @tags, $tag;
1462    
1463            }
1464    
1465            if ( @tags ) {
1466                    pop @last_tags if $#last_tags == $last_x_tags;
1467                    unshift @last_tags, { tags => [ @tags ], %$arg };
1468            }
1469    
1470    }
1471    
1472    =head2 seed_tags
1473    
1474    Read all tags from database and create in-memory cache for tags
1475    
1476    =cut
1477    
1478    sub seed_tags {
1479            my $self = shift;
1480            my $sth = $dbh->prepare(qq{ select id,message,nick,me,time from log where message like '%//%' order by time asc });
1481            $sth->execute;
1482            while (my $row = $sth->fetchrow_hashref) {
1483                    $self->add_tag( %$row );
1484            }
1485    
1486            foreach my $tag (keys %$tags) {
1487                    $self->add($tag, "$url?tag=$tag", scalar @{$tags->{$tag}});
1488            }
1489    }
1490    

Legend:
Removed from v.97  
changed lines
  Added in v.133

  ViewVC Help
Powered by ViewVC 1.1.26