/[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 83 by dpavlin, Fri Feb 29 22:11:07 2008 UTC revision 126 by dpavlin, Fri Mar 14 16:06:57 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 HTML::TagCloud;
11    use POSIX qw/strftime/;
12    use HTML::CalendarMonthSimple;
13    use Getopt::Long;
14    use DateTime;
15    use URI::Escape;
16    use Data::Dump qw/dump/;
17    use DateTime::Format::ISO8601;
18    use Carp qw/confess/;
19    use XML::Feed;
20    use DateTime::Format::Flexible;
21    use Encode;
22    
23  =head1 NAME  =head1 NAME
24    
25  irc-logger.pl  irc-logger.pl
# Line 20  Import log from C<dircproxy> to C<irc-lo Line 38  Import log from C<dircproxy> to C<irc-lo
38    
39  =item --log=irc-logger.log  =item --log=irc-logger.log
40    
 Name of log file  
   
41  =back  =back
42    
43  =head1 DESCRIPTION  =head1 DESCRIPTION
# Line 32  log all conversation on irc channel Line 48  log all conversation on irc channel
48    
49  ## CONFIG  ## CONFIG
50    
51    my $debug = 0;
52    
53    my $irc_config = {
54            nick => 'irc-logger',
55            server => 'irc.freenode.net',
56            port => 6667,
57            ircname => 'Anna the bot: try /msg irc-logger help',
58    };
59    
60  my $HOSTNAME = `hostname -f`;  my $HOSTNAME = `hostname -f`;
61  chomp($HOSTNAME);  chomp($HOSTNAME);
62    
63  my $NICK = 'irc-logger';  
 $NICK .= '-dev' if ($HOSTNAME =~ m/llin/);  
 my $CONNECT =  
   {Server => 'irc.freenode.net',  
    Nick => $NICK,  
    Ircname => "try /msg $NICK help",  
   };  
64  my $CHANNEL = '#razmjenavjestina';  my $CHANNEL = '#razmjenavjestina';
 $CHANNEL = '#irc-logger' if ($HOSTNAME =~ m/llin/);  
 my $IRC_ALIAS = "log";  
65    
66  my %FOLLOWS =  if ( $HOSTNAME =~ m/llin/ ) {
67    (          $irc_config->{nick} = 'irc-logger-llin';
68     ACCESS => "/var/log/apache/access.log",  #       $irc_config = {
69     ERROR => "/var/log/apache/error.log",  #               nick => 'irc-logger-llin',
70    );  #               server => 'localhost',
71    #               port => 6668,
72    #       };
73            $CHANNEL = '#irc-logger';
74    } elsif ( $HOSTNAME =~ m/lugarin/ ) {
75            $irc_config->{server} = 'irc.carnet.hr';
76            $CHANNEL = '#riss';
77    }
78    
79    my @channels = ( $CHANNEL );
80    
81    warn "## config = ", dump( $irc_config ) if $debug;
82    
83    my $NICK = $irc_config->{nick} or die "no nick?";
84    
85  my $DSN = 'DBI:Pg:dbname=' . $NICK;  my $DSN = 'DBI:Pg:dbname=' . $NICK;
86    
 my $ENCODING = 'ISO-8859-2';  
87  my $TIMESTAMP = '%Y-%m-%d %H:%M:%S';  my $TIMESTAMP = '%Y-%m-%d %H:%M:%S';
88    
89  my $sleep_on_error = 5;  my $sleep_on_error = 5;
# Line 62  my $sleep_on_error = 5; Line 91  my $sleep_on_error = 5;
91  # number of last tags to keep in circular buffer  # number of last tags to keep in circular buffer
92  my $last_x_tags = 50;  my $last_x_tags = 50;
93    
94    # don't pull rss feeds more often than this
95    my $rss_min_delay = 60;
96    
97  my $http_port = $NICK =~ m/-dev/ ? 8001 : 8000;  my $http_port = $NICK =~ m/-dev/ ? 8001 : 8000;
98    
99  my $url = "http://$HOSTNAME:$http_port";  my $url = "http://$HOSTNAME:$http_port";
100    
101  ## END CONFIG  ## END CONFIG
102    
   
   
 use POE qw(Component::IRC Wheel::FollowTail Component::Server::HTTP);  
 use HTTP::Status;  
 use DBI;  
 use Encode qw/from_to is_utf8/;  
 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;  
   
103  my $use_twitter = 1;  my $use_twitter = 1;
104  eval { require Net::Twitter; };  eval { require Net::Twitter; };
105  $use_twitter = 0 if ($@);  $use_twitter = 0 if ($@);
# Line 97  my $log_path; Line 109  my $log_path;
109  GetOptions(  GetOptions(
110          'import-dircproxy:s' => \$import_dircproxy,          'import-dircproxy:s' => \$import_dircproxy,
111          'log:s' => \$log_path,          'log:s' => \$log_path,
112            'debug!' => \$debug,
113  );  );
114    
115  $SIG{__DIE__} = sub {  #$SIG{__DIE__} = sub {
116          confess "fatal error";  #       confess "fatal error";
117  };  #};
   
 open(STDOUT, '>', $log_path) || warn "can't redirect log to $log_path: $!";  
118    
119  sub _log {  sub _log {
120          print strftime($TIMESTAMP,localtime()), ' ', join(" ",@_), $/;          print strftime($TIMESTAMP,localtime()) . ' ' . join(" ",map { ref($_) ? dump( $_ ) : $_ } @_) . $/;
121  }  }
122    
123    open(STDOUT, '>', $log_path) && warn "log to $log_path: $!\n";
124    
125    
126  # HTML formatters  # HTML formatters
127    
128  my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;');  my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;');
# Line 126  my $filter = { Line 140  my $filter = {
140                  # protect HTML from wiki modifications                  # protect HTML from wiki modifications
141                  sub e {                  sub e {
142                          my $t = shift;                          my $t = shift;
143                          return 'uri_unescape{' . uri_escape($t) . '}';                          return 'uri_unescape{' . uri_escape($t, '^a-zA-Z0-9') . '}';
144                  }                  }
145    
146                  $m =~ s/($escape_re)/$escape{$1}/gs;                  $m =~ s/($escape_re)/$escape{$1}/gs;
147                  $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;
148                  $m =~ s#\/(\w+)\/#<i>$1</i>#gs;                  $m =~ s#\/(\w+)\/#<i>$1</i>#gs;
149                  $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;
150                  $m =~ s#\*(\w+)\*#<b>$1</b>#gs;                  $m =~ s#\*(\w+)\*#<b>$1</b>#gs;
# Line 151  my $filter = { Line 165  my $filter = {
165          },          },
166  };  };
167    
168    # POE IRC
169    my $poe_irc = POE::Component::IRC->spawn( %$irc_config ) or
170            die "can't start ", dump( $irc_config ), ": $!";
171    
172    my $irc = $poe_irc->session_id();
173    _log "IRC session_id $irc";
174    
175  my $dbh = DBI->connect($DSN,"","", { RaiseError => 1, AutoCommit => 1 }) || die $DBI::errstr;  my $dbh = DBI->connect($DSN,"","", { RaiseError => 1, AutoCommit => 1 }) || die $DBI::errstr;
176    $dbh->do( qq{ set client_encoding = 'UTF-8' } );
177    
178  my $sql_schema = {  my $sql_schema = {
179          log => '          log => qq{
180  create table log (  create table log (
181          id serial,          id serial,
182          time timestamp default now(),          time timestamp default now(),
# Line 168  create table log ( Line 190  create table log (
190  create index log_time on log(time);  create index log_time on log(time);
191  create index log_channel on log(channel);  create index log_channel on log(channel);
192  create index log_nick on log(nick);  create index log_nick on log(nick);
193          ',          },
194          meta => '          meta => q{
195  create table meta (  create table meta (
196          nick text not null,          nick text not null,
197          channel text not null,          channel text not null,
198          name text not null,          name text not null,
199          value text,          value text,
200          changed timestamp default now(),          changed timestamp default 'now()',
201          primary key(nick,channel,name)          primary key(nick,channel,name)
202  );  );
203          ',          },
204            feeds => qq{
205    create table feeds (
206            id serial,
207            url text not null,
208            name text,
209            delay interval not null default '5 min',
210            active boolean default true,
211            channel text not null,
212            nick text not null,
213            private boolean default false,
214            last_update timestamp default 'now()',
215            polls int default 0,
216            updates int default 0
217    );
218    create unique index feeds_url on feeds(url);
219    insert into feeds (url,name,channel,nick) values ('http://wiki.razmjenavjestina.org/feed/workspace/razmjenavjestina?category=Recent%20Changes','wiki','$CHANNEL','dpavlin');
220            },
221  };  };
222    
223  foreach my $table ( keys %$sql_schema ) {  foreach my $table ( keys %$sql_schema ) {
# Line 221  sub meta { Line 260  sub meta {
260                  if ( $@ || ! $sth->rows ) {                  if ( $@ || ! $sth->rows ) {
261                          $sth = $dbh->prepare(qq{ insert into meta (value,nick,channel,name,changed) values (?,?,?,?,now()) });                          $sth = $dbh->prepare(qq{ insert into meta (value,nick,channel,name,changed) values (?,?,?,?,now()) });
262                          $sth->execute( $value, $nick, $channel, $name );                          $sth->execute( $value, $nick, $channel, $name );
263                          _log "created $nick/$channel/$name = $value";                          warn "## created $nick/$channel/$name = $value\n";
264                  } else {                  } else {
265                          _log "updated $nick/$channel/$name = $value ";                          warn "## updated $nick/$channel/$name = $value\n";
266                  }                  }
267    
268                  return $value;                  return $value;
# Line 233  sub meta { Line 272  sub meta {
272                  my $sth = $dbh->prepare(qq{ select value,changed from meta where nick = ? and channel = ? and name = ? });                  my $sth = $dbh->prepare(qq{ select value,changed from meta where nick = ? and channel = ? and name = ? });
273                  $sth->execute( $nick, $channel, $name );                  $sth->execute( $nick, $channel, $name );
274                  my ($v,$c) = $sth->fetchrow_array;                  my ($v,$c) = $sth->fetchrow_array;
275                  _log "fetched $nick/$channel/$name = $v [$c]";                  warn "## fetched $nick/$channel/$name = $v [$c]\n";
276                  return ($v,$c) if wantarray;                  return ($v,$c) if wantarray;
277                  return $v;                  return $v;
278    
# Line 242  sub meta { Line 281  sub meta {
281    
282    
283    
284  my $sth = $dbh->prepare(qq{  my $sth_insert_log = $dbh->prepare(qq{
285  insert into log  insert into log
286          (channel, me, nick, message, time)          (channel, me, nick, message, time)
287  values (?,?,?,?,?)  values (?,?,?,?,?)
# Line 330  sub get_from_log { Line 369  sub get_from_log {
369    
370          my @where;          my @where;
371          my @args;          my @args;
372            my $msg;
373    
374          if (my $search = $args->{search}) {          if (my $search = $args->{search}) {
375                  $search =~ s/^\s+//;                  $search =~ s/^\s+//;
376                  $search =~ s/\s+$//;                  $search =~ s/\s+$//;
377                  push @where, 'message ilike ? or nick ilike ?';                  push @where, 'message ilike ? or nick ilike ?';
378                  push @args, ( ( '%' . $search . '%' ) x 2 );                  push @args, ( ( '%' . $search . '%' ) x 2 );
379                  _log "search for '$search'";                  $msg = "Search for '$search'";
380          }          }
381    
382          if ($args->{tag} && $tags->{ $args->{tag} }) {          if ($args->{tag} && $tags->{ $args->{tag} }) {
383                  push @where, 'id in (' . join(',', @{ $tags->{ $args->{tag} } }) . ')';                  push @where, 'id in (' . join(',', @{ $tags->{ $args->{tag} } }) . ')';
384                  _log "search for tags $args->{tag}";                  $msg = "Search for tags $args->{tag}";
385          }          }
386    
387          if (my $date = $args->{date} ) {          if (my $date = $args->{date} ) {
388                  $date = check_date( $date );                  $date = check_date( $date );
389                  push @where, 'date(time) = ?';                  push @where, 'date(time) = ?';
390                  push @args, $date;                  push @args, $date;
391                  _log "search for date $date";                  $msg = "search for date $date";
392          }          }
393    
394          $sql .= " where " . join(" and ", @where) if @where;          $sql .= " where " . join(" and ", @where) if @where;
# Line 362  sub get_from_log { Line 402  sub get_from_log {
402          eval { $sth->execute( @args ) };          eval { $sth->execute( @args ) };
403          return if $@;          return if $@;
404    
405            my $nr_results = $sth->rows;
406    
407          my $last_row = {          my $last_row = {
408                  date => '',                  date => '',
409                  time => '',                  time => '',
# Line 382  sub get_from_log { Line 424  sub get_from_log {
424    
425          return @rows if ($args->{full_rows});          return @rows if ($args->{full_rows});
426    
427          my @msgs = (          $msg .= ' produced ' . (
428                  "Showing " . ($#rows + 1) . " messages..."                  $nr_results == 0 ? 'no results' :
429                    $nr_results == 0 ? 'one result' :
430                            $nr_results . ' results'
431          );          );
432    
433            my @msgs = ( $msg );
434    
435          if ($context) {          if ($context) {
436                  my @ids = @rows;                  my @ids = @rows;
437                  @rows = ();                  @rows = ();
# Line 442  sub get_from_log { Line 488  sub get_from_log {
488  #                       $row->{nick} = $nick;  #                       $row->{nick} = $nick;
489  #               }  #               }
490    
491                    $append = 0 if $row->{me};
492    
493                  if ($last_row->{nick} ne $nick) {                  if ($last_row->{nick} ne $nick) {
494                          # 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
495                          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 494  sub add_tag { Line 542  sub add_tag {
542          return unless ($arg->{id} && $arg->{message});          return unless ($arg->{id} && $arg->{message});
543    
544          my $m = $arg->{message};          my $m = $arg->{message};
         from_to('UTF-8', 'iso-8859-2', $m) if (is_utf8($m));  
545    
546          my @tags;          my @tags;
547    
# Line 558  sub save_message { Line 605  sub save_message {
605          $a->{me} ||= 0;          $a->{me} ||= 0;
606          $a->{time} ||= strftime($TIMESTAMP,localtime());          $a->{time} ||= strftime($TIMESTAMP,localtime());
607    
608          _log          _log "ARCHIVE",
609                  $a->{channel}, " ",                  $a->{channel}, " ",
610                  $a->{me} ? "***" . $a->{nick} : "<" . $a->{nick} . ">",                  $a->{me} ? "***" . $a->{nick} : "<" . $a->{nick} . ">",
611                  " " . $a->{message};                  " " . $a->{message};
612    
613          from_to($a->{message}, 'UTF-8', $ENCODING);          $sth_insert_log->execute($a->{channel}, $a->{me}, $a->{nick}, $a->{message}, $a->{time});
   
         $sth->execute($a->{channel}, $a->{me}, $a->{nick}, $a->{message}, $a->{time});  
614          add_tag( id => $dbh->last_insert_id(undef,undef,"log",undef), %$a );          add_tag( id => $dbh->last_insert_id(undef,undef,"log",undef), %$a );
615  }  }
616    
# Line 604  if ($import_dircproxy) { Line 649  if ($import_dircproxy) {
649          exit;          exit;
650  }  }
651    
   
652  #  #
653  # POE handing part  # RSS follow
654  #  #
655    
656  my $SKIPPING = 0;               # if skipping, how many we've done  my $_stat;
657  my $SEND_QUEUE;                 # cache  
658  my $ping;                                               # ping stats  POE::Component::Client::HTTP->spawn(
659            Alias   => 'rss-fetch',
660  POE::Component::IRC->new($IRC_ALIAS);          Timeout => 30,
661    );
662  POE::Session->create( inline_states =>  
663     {_start => sub {        =head2 rss_parse_xml
664                  $_[KERNEL]->post($IRC_ALIAS => register => 'all');  
665                  $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);    rss_parse_xml({
666      },          url => 'http://www.example.com/rss',
667      irc_255 => sub {    # server is done blabbing          send_rss_msgs => 42,
668                  $_[KERNEL]->post($IRC_ALIAS => join => $CHANNEL);    });
669                  $_[KERNEL]->post($IRC_ALIAS => join => '#logger');  
670                  $_[KERNEL]->yield("heartbeat"); # start heartbeat  =cut
671  #               $_[KERNEL]->yield("my_add", $_) for keys %FOLLOWS;  
672                  $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );  sub rss_parse_xml {
673            my ($kernel,$args) = @_;
674    
675            warn "## rss_parse_xml ",dump( @_ ) if $debug;
676    
677            # how many messages to send out when feed is seen for the first time?
678            my $send_rss_msgs = $args->{send_rss_msgs};
679            $send_rss_msgs = 1 if ! defined $send_rss_msgs;
680    
681            warn "## RSS fetch first $send_rss_msgs items from", $args->{url} if $debug;
682    
683            my $feed = XML::Feed->parse( \$args->{xml} );
684            if ( ! $feed ) {
685                    _log "can't fetch RSS ", $args->{url}, XML::Feed->errstr;
686                    return;
687            }
688    
689            $_stat->{rss}->{url2link}->{ $args->{url} } = $feed->link;
690    
691            my ( $total, $updates ) = ( 0, 0 );
692            for my $entry ($feed->entries) {
693                    $total++;
694    
695                    my $seen_times = $_stat->{rss}->{seen}->{$args->{channel}}->{$feed->link}->{$entry->id}++;
696                    # seen allready?
697                    warn "## $seen_times ",$entry->id if $debug;
698                    next if $seen_times > 0;
699    
700                    sub prefix {
701                            my ($txt,$var) = @_;
702                            $var =~ s/\s+/ /gs;
703                            $var =~ s/^\s+//g;
704                            $var =~ s/\s+$//g;
705                            return $txt . $var if $var;
706                    }
707    
708                    # fix absolute and relative links to feed entries
709                    my $link = $entry->link;
710                    if ( $link =~ m!^/! ) {
711                            my $host = $args->{url};
712                            $host =~ s!^(http://[^/]+).*$!$1!;      #!vim
713                            $link = "$host/$link";
714                    } elsif ( $link !~ m!^http! ) {
715                            $link = $args->{url} . $link;
716                    }
717    
718                    my $msg;
719                    $msg .= prefix( 'From: ' , $args->{name} || $feed->title );
720                    $msg .= prefix( ' by ' , $entry->author );
721                    $msg .= prefix( ' | ' , $entry->title );
722                    $msg .= prefix( ' | ' , $link );
723    #               $msg .= prefix( ' id ' , $entry->id );
724                    if ( my $tags = $entry->category ) {
725                            $tags =~ s!^\s+!!;
726                            $tags =~ s!\s*$! !;
727                            $tags =~ s!,?\s+!// !g;
728                            $msg .= prefix( ' ' , $tags );
729                    }
730    
731                    if ( $seen_times == 0 && $send_rss_msgs ) {
732                            $send_rss_msgs--;
733                            if ( ! $args->{private} ) {
734                                    # FIXME bug! should be save_message
735                                    save_message( channel => $args->{channel}, me => 1, nick => $NICK, message => $msg );
736    #                               $sth_insert_log->execute( $args->{channel}, 1, $NICK, $msg, 'now()' );
737                            }
738                            my ( $type, $to ) = ( 'notice', $args->{channel} );
739                            ( $type, $to ) = ( 'privmsg', $args->{nick} ) if $args->{private};
740    
741                            _log(">> RSS $type to $to:", $msg);
742                            $kernel->post( $irc => $type => $to => $msg );
743    
744                            $updates++;
745                    }
746            }
747    
748            my $sql = qq{ update feeds set last_update = now(), polls = polls + 1 };
749            $sql .= qq{, updates = updates + $updates } if $updates;
750            $sql .= qq{where id = } . $args->{id};
751            eval { $dbh->do( $sql ) };
752    
753            _log "RSS $updates/$total new items from", $args->{url};
754    
755            return $updates;
756    }
757    
758    sub rss_fetch_all {
759            my ( $kernel, $send_rss_msgs )  = @_;
760            warn "## rss_fetch_all -- send_rss_msgs: $send_rss_msgs\n" if $debug;
761            my $sql = qq{
762                    select id, url, name, channel, nick, private
763                    from feeds
764                    where active is true
765            };
766            # limit to newer feeds only if we are not sending messages out
767            $sql .= qq{     and last_update + delay < now() } if defined ( $_stat->{rss}->{fetch} );
768            my $sth = $dbh->prepare( $sql );
769            $sth->execute();
770            warn "# ",$sth->rows," active RSS feeds\n";
771            my $count = 0;
772            while (my $row = $sth->fetchrow_hashref) {
773                    $row->{send_rss_msgs} = $send_rss_msgs if defined $send_rss_msgs;
774                    $_stat->{rss}->{fetch}->{ $row->{url} } = $row;
775                    $kernel->post(
776                            'rss-fetch',
777                            'request',
778                            'rss_response',
779                            HTTP::Request->new( GET => $row->{url} ),
780                    );
781                    warn "## queued rss-fetch ", dump( $row ) if $debug;
782            }
783            return "OK, scheduled " . $sth->rows . " feeds for refresh";
784    }
785    
786    
787    sub rss_check_updates {
788            my $kernel = shift;
789            $_stat->{rss}->{last_poll} ||= time();
790            my $dt = time() - $_stat->{rss}->{last_poll};
791            if ( $dt > $rss_min_delay ) {
792                    warn "## rss_check_updates $dt > $rss_min_delay\n";
793                    $_stat->{rss}->{last_poll} = time();
794                    _log rss_fetch_all( $kernel );
795            }
796    }
797    
798    POE::Session->create( inline_states => {
799            _start => sub {      
800                    $_[KERNEL]->post( $irc => register => 'all' );
801                    $_[KERNEL]->post( $irc => connect => {} );
802      },      },
803            irc_001 => sub {
804                    my ($kernel,$sender) = @_[KERNEL,SENDER];
805                    my $poco_object = $sender->get_heap();
806                    _log "connected to",$poco_object->server_name();
807                    $kernel->post( $sender => join => $_ ) for @channels;
808                    # seen RSS cache, so don't send out messages
809                    _log rss_fetch_all( $kernel, 0 );
810                    undef;
811            },
812    #       irc_255 => sub {        # server is done blabbing
813    #               $_[KERNEL]->post( $irc => join => $CHANNEL);
814    #       },
815      irc_public => sub {      irc_public => sub {
816                  my $kernel = $_[KERNEL];                  my $kernel = $_[KERNEL];
817                  my $nick = (split /!/, $_[ARG0])[0];                  my $nick = (split /!/, $_[ARG0])[0];
# Line 635  POE::Session->create( inline_states => Line 820  POE::Session->create( inline_states =>
820    
821                  save_message( channel => $channel, me => 0, nick => $nick, message => $msg);                  save_message( channel => $channel, me => 0, nick => $nick, message => $msg);
822                  meta( $nick, $channel, 'last-msg', $msg );                  meta( $nick, $channel, 'last-msg', $msg );
823                    rss_check_updates( $kernel );
824      },      },
825      irc_ctcp_action => sub {      irc_ctcp_action => sub {
826                  my $kernel = $_[KERNEL];                  my $kernel = $_[KERNEL];
# Line 655  POE::Session->create( inline_states => Line 841  POE::Session->create( inline_states =>
841    
842      },      },
843          irc_ping => sub {          irc_ping => sub {
844                  warn "pong ", $_[ARG0], $/;                  _log( "pong ", $_[ARG0] );
845                  $ping->{ $_[ARG0] }++;                  $_stat->{ping}->{ $_[ARG0] }++;
846                    rss_check_updates( $_[KERNEL] );
847          },          },
848          irc_invite => sub {          irc_invite => sub {
849                  my $kernel = $_[KERNEL];                  my $kernel = $_[KERNEL];
850                  my $nick = (split /!/, $_[ARG0])[0];                  my $nick = (split /!/, $_[ARG0])[0];
851                  my $channel = $_[ARG1];                  my $channel = $_[ARG1];
852    
853                  warn "invited to $channel by $nick";                  _log "invited to $channel by $nick";
854    
855                  $_[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..." );
856                  $_[KERNEL]->post($IRC_ALIAS => join => $channel);                  $_[KERNEL]->post( $irc => 'join' => $channel );
857    
858          },          },
859          irc_msg => sub {          irc_msg => sub {
# Line 674  POE::Session->create( inline_states => Line 861  POE::Session->create( inline_states =>
861                  my $nick = (split /!/, $_[ARG0])[0];                  my $nick = (split /!/, $_[ARG0])[0];
862                  my $msg = $_[ARG2];                  my $msg = $_[ARG2];
863                  my $channel = $_[ARG1]->[0];                  my $channel = $_[ARG1]->[0];
864                  from_to($msg, 'UTF-8', $ENCODING);                  warn "# ARG = ",dump( @_[ARG0,ARG1,ARG2] ) if $debug;
865    
866                  my $res = "unknown command '$msg', try /msg $NICK help!";                  my $res = "unknown command '$msg', try /msg $NICK help!";
867                  my @out;                  my @out;
# Line 685  POE::Session->create( inline_states => Line 872  POE::Session->create( inline_states =>
872    
873                          $res = "usage: /msg $NICK comand | commands: stat - user/message stat | last - show backtrace | grep foobar - find foobar";                          $res = "usage: /msg $NICK comand | commands: stat - user/message stat | last - show backtrace | grep foobar - find foobar";
874    
875                  } elsif ($msg =~ m/^msg\s+(\S+)\s+(.*)$/i) {                  } elsif ($msg =~ m/^(privmsg|notice)\s+(\S+)\s+(.*)$/i) {
876    
877                          _log ">> /msg $1 $2";                          _log ">> /$1 $2 $3";
878                          $_[KERNEL]->post( $IRC_ALIAS => privmsg => $1, $2 );                          $_[KERNEL]->post( $irc => $1 => $2, $3 );
879                          $res = '';                          $res = '';
880    
881                  } elsif ($msg =~ m/^stat.*?\s*(\d*)/i) {                  } elsif ($msg =~ m/^stat.*?\s*(\d*)/i) {
# Line 718  POE::Session->create( inline_states => Line 905  POE::Session->create( inline_states =>
905    
906                          foreach my $res (get_from_log( limit => $limit )) {                          foreach my $res (get_from_log( limit => $limit )) {
907                                  _log "last: $res";                                  _log "last: $res";
908                                  from_to($res, $ENCODING, 'UTF-8');                                  $_[KERNEL]->post( $irc => privmsg => $nick, $res );
                                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );  
909                          }                          }
910    
911                          $res = '';                          $res = '';
# Line 733  POE::Session->create( inline_states => Line 919  POE::Session->create( inline_states =>
919                                          search => $what,                                          search => $what,
920                                  )) {                                  )) {
921                                  _log "search [$what]: $res";                                  _log "search [$what]: $res";
922                                  from_to($res, $ENCODING, 'UTF-8');                                  $_[KERNEL]->post( $irc => privmsg => $nick, $res );
                                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );  
923                          }                          }
924    
925                          $res = '';                          $res = '';
# Line 769  POE::Session->create( inline_states => Line 954  POE::Session->create( inline_states =>
954                                  " : " . ( $stat->{vote}->{'-'} || 0 ) . " --" .                                  " : " . ( $stat->{vote}->{'-'} || 0 ) . " --" .
955                                  " from " . ( join(", ", @nicks) || 'nobody' );                                  " from " . ( join(", ", @nicks) || 'nobody' );
956    
957                          $_[KERNEL]->post( $IRC_ALIAS => notice => $nick, $res );                          $_[KERNEL]->post( $irc => notice => $nick, $res );
958    
959                  } elsif ($msg =~ m/^ping/) {                  } elsif ($msg =~ m/^ping/) {
960                          $res = "ping = " . dump( $ping );                          $res = "ping = " . dump( $_stat->{ping} );
961                  } elsif ($msg =~ m/^conf(?:ig)*\s*(last-size|twitter)*\s*(.*)/) {                  } elsif ($msg =~ m/^conf(?:ig)*\s*(last-size|twitter)*\s*(.*)/) {
962                          if ( ! defined( $1 ) ) {                          if ( ! defined( $1 ) ) {
963                                  my $sth = $dbh->prepare(qq{ select name,value,changed from meta where nick = ? and channel = ? });                                  my $sth = $dbh->prepare(qq{ select name,value,changed from meta where nick = ? and channel = ? });
# Line 803  POE::Session->create( inline_states => Line 988  POE::Session->create( inline_states =>
988                                          $res = "config option $op doesn't exist";                                          $res = "config option $op doesn't exist";
989                                  }                                  }
990                          }                          }
991                    } elsif ($msg =~ m/^rss-update/) {
992                            $res = rss_fetch_all( $_[KERNEL] );
993                    } elsif ($msg =~ m/^rss-list/) {
994                            my $sth = $dbh->prepare(qq{ select url,name,last_update,active,channel,nick,private from feeds });
995                            $sth->execute;
996                            while (my @row = $sth->fetchrow_array) {
997                                    $_[KERNEL]->post( $irc => privmsg => $nick, join(' | ',@row) );
998                            }
999                            $res = '';
1000                    } elsif ($msg =~ m!^rss-(add|remove|stop|start|clean)(?:-(private))?\s+(http://\S+)\s*(.*)!) {
1001                            my ( $command, $sub, $url, $arg ) = ( $1,$2,$3,$4 );
1002    
1003                            my $channel = $1 if ( $arg =~ s/\s*(#\S+)\s*// );
1004                            $channel = $nick if $sub eq 'private';
1005    
1006                            my $sql = {
1007                                    add     => qq{ insert into feeds (url,name,channel,nick,private) values (?,?,?,?,?) },
1008    #                               remove  => qq{ delete from feeds                                where url = ? and name = ? },
1009                                    start   => qq{ update feeds set active = true   where url = ? },
1010                                    stop    => qq{ update feeds set active = false  where url = ? },
1011                                    clean   => qq{ update feeds set last_update = now() - delay where url = ? },
1012                            };
1013    
1014                            if ( $command eq 'add' && ! $channel ) {
1015                                    $res = "ERROR: got '$msg' which doesn't have #channel in it, ignoring!";
1016                            } elsif (my $q = $sql->{$command} ) {
1017                                    my $sth = $dbh->prepare( $q );
1018                                    my @data = ( $url );
1019                                    if ( $command eq 'add' ) {
1020                                            push @data, ( $arg, $channel, $nick, $sub eq 'private' ? 1 : 0 );
1021                                    }
1022                                    warn "## $command SQL $q with ",dump( @data ),"\n";
1023                                    eval { $sth->execute( @data ) };
1024                                    if ($@) {
1025                                            $res = "ERROR: $@";
1026                                    } else {
1027                                            $res = "OK, RSS executed $command" . ( $sub ? "-$sub" : '' ) ." on $channel url $url";
1028                                            if ( $command eq 'clean' ) {
1029                                                    my $seen = $_stat->{rss}->{seen} || die "no seen?";
1030                                                    my $want_link = $_stat->{rss}->{url2link}->{$url} || warn "no url2link($url)";
1031                                                    foreach my $c ( keys %$seen ) {
1032                                                            my $c_hash = $seen->{$c} || die "no seen->{$c}";
1033                                                            die "not HASH with rss links but ", dump($c_hash) unless ref($c_hash) eq 'HASH';
1034                                                            foreach my $link ( keys %$c_hash ) {
1035                                                                    next unless $link eq $want_link;
1036                                                                    _log "RSS removed seen $c $url $link";
1037                                                            }
1038                                                    }
1039                                            } elsif ( $command eq 'add' ) {
1040                                                    rss_fetch_all( $_[KERNEL] );
1041                                            }
1042                                    }
1043                            } else {
1044                                    $res = "ERROR: don't know what to do with: $msg";
1045                            }
1046                    } elsif ($msg =~ m/^rss-clean/) {
1047                            # this makes sense because we didn't catch rss-clean http://... before!
1048                            $_stat->{rss} = undef;
1049                            $dbh->do( qq{ update feeds set last_update = now() - delay } );
1050                            $res = rss_fetch_all( $_[KERNEL] );
1051                  }                  }
1052    
1053                  if ($res) {                  if ($res) {
1054                          _log ">> [$nick] $res";                          _log ">> [$nick] $res";
1055                          from_to($res, $ENCODING, 'UTF-8');                          $_[KERNEL]->post( $irc => privmsg => $nick, $res );
                         $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );  
1056                  }                  }
1057    
1058                    rss_check_updates( $_[KERNEL] );
1059            },
1060            irc_372 => sub {
1061                    _log "<< motd",$_[ARG0],$_[ARG1];
1062            },
1063            irc_375 => sub {
1064                    _log "<< motd", $_[ARG0], "start";
1065          },          },
1066            irc_376 => sub {
1067                    _log "<< motd", $_[ARG0], "end";
1068            },
1069    #       irc_433 => sub {
1070    #               print "# irc_433: ",$_[ARG1], "\n";
1071    #               warn "## indetify $NICK\n";
1072    #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "IDENTIFY $NICK" );
1073    #       },
1074    #       irc_451 # please register
1075          irc_477 => sub {          irc_477 => sub {
1076                  _log "# irc_477: ",$_[ARG1];                  _log "<< irc_477: ",$_[ARG1];
1077                  $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "register $NICK" );                  _log ">> IDENTIFY $NICK";
1078                    $_[KERNEL]->post( $irc => privmsg => 'NickServ', "IDENTIFY $NICK" );
1079          },          },
1080          irc_505 => sub {          irc_505 => sub {
1081                  _log "# irc_505: ",$_[ARG1];                  _log "<< irc_505: ",$_[ARG1];
1082                  $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "register $NICK" );                  _log ">> register $NICK";
1083  #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "set hide email on" );                  $_[KERNEL]->post( $irc => privmsg => 'NickServ', "register $NICK" );
1084  #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "set email dpavlin\@rot13.org" );  #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "IDENTIFY $NICK" );
1085    #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "set hide email on" );
1086    #               $_[KERNEL]->post( $irc => privmsg => 'nickserv', "set email dpavlin\@rot13.org" );
1087          },          },
1088          irc_registered => sub {          irc_registered => sub {
1089                  _log "## registrated $NICK";                  _log "<< registered $NICK";
                 $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );  
1090          },          },
1091          irc_disconnected => sub {          irc_disconnected => sub {
1092                  _log "## disconnected, reconnecting again";                  _log "## disconnected.. sleeping for $sleep_on_error seconds and reconnecting again";
1093                  $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);                  sleep($sleep_on_error);
1094                    $_[KERNEL]->post( $irc => connect => {} );
1095          },          },
1096          irc_socketerr => sub {          irc_socketerr => sub {
1097                  _log "## socket error... sleeping for $sleep_on_error seconds and retry";                  _log "## socket error... sleeping for $sleep_on_error seconds and retry";
1098                  sleep($sleep_on_error);                  sleep($sleep_on_error);
1099                  $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);                  $_[KERNEL]->post( $irc => connect => {} );
1100            },
1101            irc_notice => sub {
1102                    _log "<< notice from ", $_[ARG0], $_[ARG1], $_[ARG2];
1103                    my $m = $_[ARG2];
1104                    if ( $m =~ m!/msg.*(NickServ).*(IDENTIFY)!i ) {
1105                            _log ">> suggested to $1 $2";
1106                            $_[KERNEL]->post( $irc => privmsg => $1, "$2 $NICK" );
1107                    } elsif ( $m =~ m!\Q$NICK\E.*registered!i ) {
1108                            _log ">> registreted, so IDENTIFY";
1109                            $_[KERNEL]->post( $irc => privmsg => 'nickserv', "IDENTIFY $NICK" );
1110                    } else {
1111                            warn "## ignore $m\n" if $debug;
1112                    }
1113            },
1114            irc_snotice => sub {
1115                    _log "<< snotice", $_[ARG0]; #dump( $_[ARG0],$_[ARG1], $_[ARG2] );
1116                    if ( $_[ARG0] =~ m!/(QUOTE)\s+(PASS\s+\d+)!i ) {
1117                            warn ">> $1 | $2\n";
1118                            $_[KERNEL]->post( $irc => lc($1) => $2);
1119                    }
1120          },          },
 #       irc_433 => sub {  
 #               print "# irc_433: ",$_[ARG1], "\n";  
 #               warn "## indetify $NICK\n";  
 #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );  
 #       },  
1121      _child => sub {},      _child => sub {},
1122      _default => sub {      _default => sub {
1123                  _log sprintf "sID:%s %s %s",                  _log sprintf "sID:%s %s %s",
# Line 849  POE::Session->create( inline_states => Line 1127  POE::Session->create( inline_states =>
1127                          "";                          "";
1128        0;                        # false for signals        0;                        # false for signals
1129      },      },
1130      my_add => sub {          rss_response => sub {
1131        my $trailing = $_[ARG0];                  my ($request_packet, $response_packet) = @_[ARG0, ARG1];
1132        my $session = $_[SESSION];                  my $request_object  = $request_packet->[0];
1133        POE::Session->create                  my $response_object = $response_packet->[0];
1134            (inline_states =>  
1135             {_start => sub {                  my $row = delete( $_stat->{rss}->{fetch}->{ $request_object->uri } );
1136                $_[HEAP]->{wheel} =                  if ( $row ) {
1137                  POE::Wheel::FollowTail->new                          $row->{xml} = $response_object->content;
1138                      (                          rss_parse_xml( $_[KERNEL], $row );
1139                       Filename => $FOLLOWS{$trailing},                  } else {
1140                       InputEvent => 'got_line',                          warn "## can't find rss->fetch for ", $request_object->uri;
1141                      );                  }
1142              },          },
             got_line => sub {  
               $_[KERNEL]->post($session => my_tailed =>  
                                time, $trailing, $_[ARG0]);  
             },  
            },  
           );  
       
     },  
     my_tailed => sub {  
       my ($time, $file, $line) = @_[ARG0..ARG2];  
       ## $time will be undef on a probe, or a time value if a real line  
   
       ## PoCo::IRC has throttling built in, but no external visibility  
       ## so this is reaching "under the hood"  
       $SEND_QUEUE ||=  
         $_[KERNEL]->alias_resolve($IRC_ALIAS)->get_heap->{send_queue};  
   
       ## handle "no need to keep skipping" transition  
       if ($SKIPPING and @$SEND_QUEUE < 1) {  
         $_[KERNEL]->post($IRC_ALIAS => privmsg => $CHANNEL =>  
                          "[discarded $SKIPPING messages]");  
         $SKIPPING = 0;  
       }  
   
       ## handle potential message display  
       if ($time) {  
         if ($SKIPPING or @$SEND_QUEUE > 3) { # 3 msgs per 10 seconds  
           $SKIPPING++;  
         } else {  
           my @time = localtime $time;  
           $_[KERNEL]->post($IRC_ALIAS => privmsg => $CHANNEL =>  
                            sprintf "%02d:%02d:%02d: %s: %s",  
                            ($time[2] + 11) % 12 + 1, $time[1], $time[0],  
                            $file, $line);  
         }  
       }  
   
       ## handle re-probe/flush if skipping  
       if ($SKIPPING) {  
         $_[KERNEL]->delay($_[STATE] => 0.5); # $time will be undef  
       }  
   
     },  
     my_heartbeat => sub {  
       $_[KERNEL]->yield(my_tailed => time, "heartbeat", "beep");  
       $_[KERNEL]->delay($_[STATE] => 10);  
     }  
1143     },     },
1144    );    );
1145    
1146  # http server  # http server
1147    
1148    _log "WEB archive at $url";
1149    
1150  my $httpd = POE::Component::Server::HTTP->new(  my $httpd = POE::Component::Server::HTTP->new(
1151          Port => $http_port,          Port => $http_port,
1152          PreHandler => {          PreHandler => {
# Line 960  foreach my $c (@cols) { Line 1193  foreach my $c (@cols) {
1193          $style .= ".col-${max_color} { background: $c }\n";          $style .= ".col-${max_color} { background: $c }\n";
1194          $max_color++;          $max_color++;
1195  }  }
1196  warn "defined $max_color colors for users...\n";  _log "WEB defined $max_color colors for users...";
1197    
1198  sub root_handler {  sub root_handler {
1199          my ($request, $response) = @_;          my ($request, $response) = @_;
# Line 982  sub root_handler { Line 1215  sub root_handler {
1215          }          }
1216    
1217          my $search = $q->param('search') || $q->param('grep') || '';          my $search = $q->param('search') || $q->param('grep') || '';
1218            my $r_url = $request->url;
1219    
1220          if ($request->url =~ m#/rss(?:/(tags|last-tag)\w*(?:=(\d+))?)?#i) {          my @commands = qw( tags last-tag follow stat );
1221            my $commands_re = join('|',@commands);
1222    
1223            if ($r_url =~ m#/rss(?:/($commands_re.*)\w*(?:=(\d+))?)?#i) {
1224                  my $show = lc($1);                  my $show = lc($1);
1225                  my $nr = $2;                  my $nr = $2;
1226    
# Line 995  sub root_handler { Line 1232  sub root_handler {
1232                  #warn "create $type feed from ",dump( @last_tags );                  #warn "create $type feed from ",dump( @last_tags );
1233    
1234                  my $feed = XML::Feed->new( $type );                  my $feed = XML::Feed->new( $type );
1235                    $feed->link( $url );
1236    
1237                    my $rc = RC_OK;
1238    
1239                  if ( $show eq 'tags' ) {                  if ( $show eq 'tags' ) {
1240                          $nr ||= 50;                          $nr ||= 50;
# Line 1021  sub root_handler { Line 1261  sub root_handler {
1261                          $nr = $last_x_tags if $nr > $last_x_tags;                          $nr = $last_x_tags if $nr > $last_x_tags;
1262    
1263                          $feed->title( "last $nr tagged messages from $CHANNEL" );                          $feed->title( "last $nr tagged messages from $CHANNEL" );
                         $feed->link( $url );  
1264                          $feed->description( "collects messages which have tags// in them" );                          $feed->description( "collects messages which have tags// in them" );
1265    
1266                          foreach my $m ( @last_tags ) {                          foreach my $m ( @last_tags ) {
# Line 1036  sub root_handler { Line 1275  sub root_handler {
1275                                  my $message = $filter->{message}->( $m->{message} );                                  my $message = $filter->{message}->( $m->{message} );
1276                                  $message .= "<br/>\n" unless $message =~ m!<(/p|br/?)>!;                                  $message .= "<br/>\n" unless $message =~ m!<(/p|br/?)>!;
1277  #                               warn "## message = $message\n";  #                               warn "## message = $message\n";
                                 from_to( $message, $ENCODING, 'UTF-8' );  
1278    
1279                                  #$feed_entry->summary(                                  #$feed_entry->summary(
1280                                  $feed_entry->content(                                  $feed_entry->content(
# Line 1050  sub root_handler { Line 1288  sub root_handler {
1288    
1289                          }                          }
1290    
1291                    } elsif ( $show =~ m/^follow/ ) {
1292    
1293                            $feed->title( "Feeds which this bot follows" );
1294    
1295                            my $sth = $dbh->prepare( qq{ select * from feeds order by last_update desc } );
1296                            $sth->execute;
1297                            while (my $row = $sth->fetchrow_hashref) {
1298                                    my $feed_entry = XML::Feed::Entry->new($type);
1299                                    $feed_entry->title( $row->{name} );
1300                                    $feed_entry->link( $row->{url}  );
1301                                    $feed_entry->issued( DateTime::Format::Flexible->build( $row->{last_update} ) );
1302                                    $feed_entry->content(
1303                                            '<![CDATA[<pre>' . dump( $row ) . '</pre>]]>'
1304                                    );
1305                                    $feed->add_entry( $feed_entry );
1306                            }
1307    
1308                    } elsif ( $show =~ m/^stat/ ) {
1309    
1310                            my $feed_entry = XML::Feed::Entry->new($type);
1311                            $feed_entry->title( "Internal stats" );
1312                            $feed_entry->content(
1313                                    '<![CDATA[<pre>' . dump( $_stat ) . '</pre>]]>'
1314                            );
1315                            $feed->add_entry( $feed_entry );
1316    
1317                  } else {                  } else {
1318                          warn "!! unknown rss request for $show\n";                          _log "WEB unknown rss request $r_url";
1319                          return RC_DENY;                          $feed->title( "unknown $r_url" );
1320                            foreach my $c ( @commands ) {
1321                                    my $feed_entry = XML::Feed::Entry->new($type);
1322                                    $feed_entry->title( "rss/$c" );
1323                                    $feed_entry->link( "$url/rss/$c" );
1324                                    $feed->add_entry( $feed_entry );
1325                            }
1326                            $rc = RC_DENY;
1327                  }                  }
1328    
1329                  $response->content( $feed->as_xml );                  $response->content( $feed->as_xml );
1330                  return RC_OK;                  return $rc;
1331          }          }
1332    
1333          if ( $@ ) {          if ( $@ ) {
1334                  warn "$@";                  warn "$@";
1335          }          }
1336    
1337          $response->content_type("text/html; charset=$ENCODING");          $response->content_type("text/html; charset=UTF-8");
1338    
1339          my $html =          my $html =
1340                  qq{<html><head><title>$NICK</title><style type="text/css">$style}                  qq{<html><head><title>$NICK</title><style type="text/css">$style}
# Line 1114  sub root_handler { Line 1385  sub root_handler {
1385                          }                          }
1386                          $cal->setcontent($dd, qq[                          $cal->setcontent($dd, qq[
1387                                  <a href="$url?date=$row->{date}">$row->{nr}</a><br/>$row->{len}                                  <a href="$url?date=$row->{date}">$row->{nr}</a><br/>$row->{len}
1388                          ]);                          ]) if $cal;
1389                                                    
1390                  }                  }
1391                  $html .= qq{<td valign="top">} . $cal->as_HTML() . qq{</td></tr></table>};                  $html .= qq{<td valign="top">} . $cal->as_HTML() . qq{</td></tr></table>};
# Line 1147  sub root_handler { Line 1418  sub root_handler {
1418          <p>See <a href="/history">history</a> of all messages.</p>          <p>See <a href="/history">history</a> of all messages.</p>
1419          </body></html>};          </body></html>};
1420    
1421          $response->content( $html );          $response->content( decode('utf-8',$html) );
1422          warn "<< ", $request->method, " ", $request->uri, " created ", length($html), " bytes\n";          warn "<< ", $request->method, " ", $request->uri, " created ", length($html), " bytes\n";
1423          return RC_OK;          return RC_OK;
1424  }  }

Legend:
Removed from v.83  
changed lines
  Added in v.126

  ViewVC Help
Powered by ViewVC 1.1.26