#!/usr/bin/perl # # reader.pl - reads irc logs from the Dancer bot and produces pretty HTML # # Copyright 2007 Björn Stenberg # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # use CGI 'escapeHTML', 'param'; use POSIX 'strftime', 'mktime'; # hardcoded log format for dancer irc bot my $logdir = "/home/rockbox/irc-logs"; my $today = strftime "%Y%m%d", localtime; my $date = param('date') + 0; my $year = 0; if ($date == 0) { print "Location: https://www.rockbox.org/irc/log-$today\n\n"; exit; } elsif ($date == $today) { $file = "current.txt"; } else { $file = "rockbox-$date.txt"; } if (open NICKS, ") { if ($line =~ /^([^- ]+)/) { $regular{$1} = 1; $nicks{$1} = 1; } } } if ($date =~ /(\d\d\d\d)(\d\d)(\d\d)/) { $title = "#rockbox $1-$2-$3"; $year = $1; } my $push = 0; #if ($ENV{'HTTP_USER_AGENT'} =~ m|Gecko/2|) { # $push = 1; #} #if ($ENV{'HTTP_USER_AGENT'} =~ m|Firefox/[4-9]|) { # $push = 0; #} #if ($file eq "current.txt" and $push) { # my $delimiter = sprintf("delimiter%x%x%x", rand(2**31), rand(2**31), rand(2**31)); # print "Content-type: multipart/mixed;boundary=$delimiter\n\n"; # print "--$delimiter\n"; # print "Content-type: text/html\n\n"; #} #else { print "Content-type: text/html\n\n"; #} print < $title END ; if ($file =~ /[^\w\d\.\-]/) { print "

$file: Invalid filename\n"; goto foot; } my $realfile; if ($file eq "current.txt") { $realfile = $file; } else { $realfile = "$logdir/$year/$file"; } if (!open FILE, "<$realfile") { print "

$realfile: $! ...\n"; goto foot; } my @lines = ; my $tophour = 0; # pass 1: find all nicks foreach my $line (@lines) { chomp $line; if ($line =~ /^\d\d\.\d\d.\d\d \# + <([^>]+)> /) { $nicks{$1} = 1; } elsif ($line =~ /^\d\d\.\d\d.\d\d (Join|Part|Quit) + ([^ \[]+)/) { $nicks{$2} = 1; } if ($line =~ m/^(\d\d)\./) { $tophour = $1 if ($1 > $tophour); } } # create styles for all nicks print "\n"; my ($prevday, $nextday); if ($file eq "current.txt") { $prevday = sprintf("Previous day", strftime "%Y%m%d", localtime(time - 86400)); $nextday = sprintf("Next day", strftime "%Y%m%d", localtime(time + 86400)); # $autoscroll = " |"; $autoscroll = ""; } else { $file =~ /(\d\d\d\d)(\d\d)(\d\d)/; my ($y, $m, $d) = ($1, $2, $3); $prevtime = mktime( 0, 0, 0, $d-1, $m-1, $y-1900); $nexttime = mktime( 0, 0, 0, $d+1, $m-1, $y-1900); $prevday = sprintf("Previous day", strftime "%Y%m%d", localtime($prevtime)); $nextday = sprintf("Next day", strftime "%Y%m%d", localtime($nexttime)); } my $hourlinks; foreach (1 .. $tophour) { $hourlinks .= sprintf "%02d ", $_, $_; } my $jstime = (stat("reader.js"))[9]; print <
$prevday | Jump to hour: $hourlinks | $nextday

$autoscroll Seconds: Show Hide | Joins: Show Hide | View raw
Font: Serif Sans-Serif Monospace | Size: Small Medium Large

Click in the nick column to highlight everything a person has said.
The Logo icon identifies that the person is a core developer (has commit access).

END ; #if (!$push) { # print "

Notice: Only Gecko based browsers prior to FF4 support the multipart/mixed \"server push\" method used by this log reader to auto-update. Since you do not appear to use such a browser, this page will simply show the current log, and not automatically update.

\n"; #} $date =~ m/(\d\d\d\d)(\d\d)(\d\d)/; print "

#rockbox log for $1-$2-$3

\n"; my $lasthour = 0; my $houranchor; print "\n"; # pass 2: output html #if ($file eq "current.txt" and $push) { # # go into tail chase mode # # # start auto-scrolling # print < # # #END #; # # my $needtodie = 0; # $SIG{PIPE} = $SIG{HUP} = $SIG{INT} = $SIG{TERM} = sub { $needtodie = 1 }; # # Pipe isn't bad? # #$SIG{PIPE} = 'IGNORE'; # # $SIG{__DIE__} = sub { # printf STDERR "Program ending: @_\n"; # }; # # $| = 1; # autoflush # # my $keepalive = 0; # seek(FILE,0,0); # back to the beginning # for (;;) { # seek(LOG, 0, 1); # @lines = ; # if (scalar @lines) { # &parsechunk(\@lines); # $keepalive = 0; # } # exit if ($needtodie); # sleep 1; # # if (++$keepalive > 15) { # print "\n"; # $keepalive = 0; # } # # # check the time, abort tail chase if clock_hour < $lasthour # last if ((localtime())[2] < $lasthour); # } #} #else { # just parse the lines &parsechunk(\@lines); #} close FILE; print "
\n"; foot: print <$prevday | $nextday END ; sub parsechunk { my $lines = shift @_; foreach my $line (@{$lines}) { next unless ($line =~ /^(\d\d)\.(\d\d).(\d\d) ([^ ]+) +(.*)/); my ($hour, $minute, $second, $action, $string) = ($1, $2, $3, $4, $5); last if ($hour > 0 and param('test')); # print "$line"; if ($hour > $lasthour) { printf "%02d:00\n", $hour, $hour, $hour; $lasthour = $hour; } # This seems to be intended to strip out control characters # but ropes in other stuff too... # $string =~ s|[-]||g; if ($action eq "#") { my ($nick, $message); if ($string =~ /^<([^>]+)> (.*)/) { ($nick, $message) = ($1, $2); } elsif ($string =~ /^\* (.*)/) { $nick = "*"; $message = $1; } $message = escapeHTML($message); # tag URLs if ($message =~ m!((http|https|ftp)://[^\)\s,]+)!) { my $url = $1; my $showurl = $url; $showurl =~ s|([/&])|$1|g; $message =~ s|\Q$url\E|$showurl|; } # tag flyspray $message =~ s!FS *\#(\d+)!FS \#$1!g; $message =~ s!fs*\#(\d+)!fs\#$1!g; # tag svn revisions # $message =~ s!(\b\s)r(\d+)(\b)!$1r$2$3!g; # tag git revisions (WIP) $message =~ s!Revision (\w+)(\b)!Revision $1$3!g; # tag gerrit ids $message =~ s!\s*g\#(\d+)! g\#$1!g; # escape text that looks like the multipart delimiter $message =~ s!--!−−!g; # break long lines. max 60 chars if (0 and $message =~ /([^ ]{60,})/) { my $substr_orig = $1; my $substr = $1; unless ($substr =~ s/,([^ ])/, $1/g) { unless ($substr =~ s/\.([^ ])/\. $1/g) { unless ($substr =~ s/-([^ ])/- $1/) { unless ($substr =~ s|/([^ ])|/ $1|) { } } } } $message =~ s/\Q$substr_orig\E/$substr/; #print STDERR "wrapped: $substr_orig ==> $substr\n"; } # tag all nicks foreach my $nick (keys %nicks) { if (index($message, $nick) > -1) { $message =~ s|\b\Q$nick\E\b|$nick|g; } } # remove color codes $message =~ s|\x03\d+||g; # remove control codes $message =~ s|[\x00-\x1f]||g; # remove any nick-highlightning inside hrefs if ($message =~ /href=\"([^\"]+)/) { my $url = $1; my $broken_url = $url; if ($url =~ /$nick|$nick|g; $message =~ s|$broken_url|$url|g; } } my $class = "nick"; my $realnick = $nick; if (defined $regular{lc $nick}) { $class = "regular"; } elsif (($nick eq "*") and ($message =~ /^"; my $n2 = ""; if ($nick =~ /[^\w\d_\-]/) { $n1 = $n2 = ""; } print("", "$hour:$minute", ":$second", "$n1$nick$n2", "$message", "\n"); $houranchor = ""; } elsif ($action =~ /^(Join|Quit|Part|Nick)/) { my ($nick, $message); if ($string =~ /^([^ ]+) *(.*)/) { ($nick, $message) = ($1, $2); $message = escapeHTML($message); } print("", "$hour:$minute", ":$second", " ", "$action ", "$nick ", "$message", "\n"); } else { print("", "$hour:$minute", ":$second", "$action", "$string", "\n"); } } }