#!/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 = "/sites/rockbox.org/logbot/log"; my $today = strftime "%Y%m%d", localtime; my $date = param('date') + 0; if ($date == 0) { print "Location: http://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"; } 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; } if (!open FILE, "<$logdir/$file") { print "

$file: $!\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 = " |"; } 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; } $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; # tag svn revisions $message =~ s!(\b\s)r(\d+)(\b)!$1r$2$3!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 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 = ""; } # remove control codes $message =~ s|[\000-\037]||g; 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"); } } }