#!/usr/bin/perl -w use lib qw(/home/blech/perllib/perl5 /home/blech/perllib/share/perl/5.8.4 /home/blech/perllib/lib/perl/5.8.4 /home/blech/perllib/lib/home/blech/perllib/); use strict; use CGI qw/:standard/; use File::Spec; use File::Find; use File::Grep qw(fgrep fmap fdo); use Time::Local; use Data::Dumper; use XML::XPath; use XML::Simple; use XML::LibXML; use XML::LibXSLT; # set up globals for nav stuff my ($dates, $seen); # decide mode and do despatch my ($mode, $arg) = get_mode(); # print STDERR "to do '$mode' with '$arg'\n"; # um, why isn't this in (a renamed) get_mode ? if ($mode eq 'index') { do_index($arg); } elsif ($mode eq 'file') { do_file($arg); } elsif ($mode eq 'month') { do_month($arg); } elsif ($mode eq 'rss') { do_rss($arg); } elsif ($mode eq 'search') { do_search($arg); } else { error("Mode or argument not recognised.\n"); } ### subs sub wanted { return if ($File::Find::dir =~ m/.AppleDouble/); return unless $_ =~ m/.xml$/; # return if ($_ =~ m/index.html/); my ($n, $y, $m, $d) = File::Spec->splitdir($File::Find::name); $dates->{'year'}{'name'} = $y; if (!exists $seen->{$y.$m}) { push (@{ $dates->{'year'}{'month'} }, { 'href' => "/bots/$y/$m/", 'content' => "$y-$m", }); $seen->{$y.$m} = 'yes'; } #$dates->{'year'}{'month'}{'href'} = "/bots/$y/$m/"; #$dates->{'year'}{'month'}{'content'} = "$y-$m"; $d =~ s/\.xml//; push @{ $dates->{'recent'} }, { 'content' => "$y-$m-$d", 'href' => "/bots/$y/$m/$d/" }; my $offset = (scalar @{ $dates->{'recent'} })-6; splice (@{ $dates->{'recent'} }, 0, $offset); # $dates->{$y}{$m}{$d} = $_; } sub get_nav { # this will need fixing at year end find(\&wanted, 'botd/2002', 'botd/2003'); my $nav = XMLout($dates, rootname => 'nav'); } sub get_root { return "/home/blech/web/husk.org/botd/"; } sub get_mode { my $path_info = path_info; if (!$path_info || $path_info eq '/') { return ('index', 'index.xml'); } if ($path_info =~ m/rss/) { return ('rss', 'index.xml'); } if ($path_info =~ m/\.html?$/) { return ('file', $path_info); } if ($path_info =~ m!^[\d/]+$!) { # some kind of date my ($null, $year, $mon, $day) = split (/\//, $path_info); if ($day) { # three args, day my $file = sprintf("%04d/%02d/%02d/%04d-%02d-%02d.xml", $year, $mon, $day, $year, $mon, $day); return ('index', $file); } elsif ($mon) { # two args, month my $month = sprintf("%04d/%02d", $year, $mon); return ('month', $month); } } if ($path_info =~ m!^/search/!) { (my $search = $path_info) =~ s!^/search/!!; $search =~ s/ .*$//; return ('search', $search) if $search; } my $q = new CGI; my $search = $q->param('search'); $search =~ s/ .*$//; return ('search', $search) if $search; return ('error', 'whoopsie'); # error is handled back up there ^^ } sub error { print CGI::header(); print shift; exit; } sub do_index { my $date_file = shift; my $root = get_root(); my $xml = $root.$date_file; my $xsl = $root.'scriborg.xsl'; my $nav = get_nav(); # read in data XML my $blog; open (SOURCE, $xml) or error("Can't open XML: $!\n"); while () { s!(!$1"/>!; $blog .= $_; } $blog =~ s!!$nav\n!; render ($blog, $xsl, 'html'); } sub do_file { my $file = shift; my $nav = get_nav(); my $root = get_root(); local $/ = undef; open (FILE, $root.'files'.$file) or error ("Can't open file '$file'.\n"); my $xml = ; close (FILE); $xml = qq{$nav\n}; my $xsl = $root.'files/files.xsl'; render ($xml, $xsl, 'html'); } sub do_search { my $search = shift; my $nav = get_nav(); my $root = get_root(); my @files = glob "botd/20*/*/*/*.xml"; my ($xml, $matches); # debug- print files # print STDERR join ("\n", @files); # print CGI::header('text/xml'); my @matches = fgrep { m/$search/i } @files; foreach my $matchref (@matches) { if ($matchref->{count}) { (my $link = $matchref->{filename}) =~ s!botd/!/bots/!; $link =~ s![\d-]*.xml!!; # initialise XML if necessary $xml = xml_header("search for '$search'") unless $xml; # add link item $xml .= "\n$link\n"; foreach my $line (keys %{ $matchref->{'matches'} }) { $xml .= $matchref->{'matches'}->{$line}; } $xml .= "\n"; # housekeeping $matches++; } } unless ($xml) { $xml = xml_no_results("search for '$search'", $nav); } else { $xml .= "$nav\n\n"; $xml =~ s//$matches/; } #print $xml; my $xsl = $root.'files/search.xsl'; render ($xml, $xsl, 'html'); } sub xml_header { my $title = shift; my $time = localtime; my $date = scalar localtime; return < $date $title EOX } sub xml_no_results { my $title = shift; my $nav = shift; my $time = localtime; my $date = scalar localtime; return < $date $title scriborg No matches found. Sorry. $nav EOX } sub do_month { my $date = shift; my ($year, $mon) = split(/\//, $date); my $nav = get_nav(); my $root = get_root(); opendir(DIR, $root.$date) or error ("Can't make month index: $date\n"); my @days = readdir(DIR); closedir(DIR); my $days; foreach my $day (reverse sort @days) { next if ($day !~ m/^\d+$/); # get topic (and as a sideeffect check we have an arch) my $file = sprintf("%04d/%02d/%02d/%04d-%02d-%02d.xml", $year, $mon, $day, $year, $mon, $day); my $xp = XML::XPath->new(filename => $root.$file) or next; my $topic = $xp->find('/churn/topic'); # this bit fixes both no topic and stringifies the XPath object $topic = ($topic !~ m/^\s*$/) ? $topic.'' : 'no topic set'; # build data structure my $href = sprintf("/bots/%04d/%02d/%02d", $year, $mon, $day); push @{ $days->{days} }, { 'content' => $topic, 'day' => $day, 'href' => $href, }; } # build XML from DS my $month = XMLout($days, rootname => 'month'); $month =~ s!!!; $month =~ s!!$nav!; # print STDERR "$month\n"; my $xsl = $root."sb_month.xsl"; render($month, $xsl, 'html'); } sub do_rss { my $date_file = shift; my $root = get_root(); my $xml = $root.$date_file; my $xsl = $root.'scrirss.xsl'; # my $nav = get_nav(); # read in data XML my $blog; open (SOURCE, $xml) or error("Can't open XML: $!\n"); while () { s!(!$1"/>!; $blog .= $_; } # $blog =~ s!!$nav\n!; render ($blog, $xsl, 'xml'); } sub do_year { error("Not implemented\n"); } sub render { my ($xml, $xsl, $type) = @_; my $parser = XML::LibXML->new(); my $xslt = XML::LibXSLT->new(); my $source = $parser->parse_string($xml); my $style = $parser->parse_file($xsl); my $stylesheet = $xslt->parse_stylesheet($style); my $results = $stylesheet->transform($source); print CGI::header() if ($type eq 'html'); print CGI::header('text/xml') if ($type eq 'xml'); print $stylesheet->output_string($results); }