#!/usr/bin/perl # $Id$ use lib '/home/bbs/bin/'; use strict; use Getopt::Std; use LocalVars; use IO::Handle; use Data::Dumper; use BBSFileHeader; use DB_File; use OurNet::FuzzyIndex; sub main { my($fh); die usage() unless( getopts('cdaofn:D:') ); die usage() if( !@ARGV ); builddb($_) foreach( @ARGV ); } sub usage { return ("$0 [-acdfo] [-n NUMBER] [board ...]\n". "\t-a\t\trebuild all files\n". "\t-c\t\tbuild configure\n". "\t-d\t\tprint debug message\n". "\t-f\t\tforce build\n". "\t-o\t\tonly build content(not building link)\n". "\t-n NUMBER\tonly build \#NUMBER article\n". "\t-D DATE\t\tdelete article of DATE\n"); } sub debugmsg($) { print "$_\n" if( $Getopt::Std::opt_d ); } sub builddb($) { my($board) = @_; my(%bh, %ch); debugmsg("building $board"); return if( !getdir("$BBSHOME/man/boards/".substr($board,0,1)."/$board", \%bh, \%ch) ); buildconfigure($board, \%ch) if( $Getopt::Std::opt_c || $Getopt::Std::opt_a ); builddata($board, \%bh, $Getopt::Std::opt_a || '', $Getopt::Std::opt_o || '', $Getopt::Std::opt_n || '', $Getopt::Std::opt_f || '', $Getopt::Std::opt_D,); } sub buildconfigure($$) { my($board, $rch) = @_; my($outdir, $fn, $flag, %config, %attr); $outdir = "$BLOGDATA/$board"; `/bin/rm -rf $outdir; /bin/mkdir -p $outdir`; tie(%config, 'DB_File', "$outdir/config.db", O_CREAT | O_RDWR, 0666, $DB_HASH); tie(%attr, 'DB_File', "$outdir/attr.db", O_CREAT | O_RDWR, 0666, $DB_HASH); for ( 0..($rch->{num} - 1) ){ debugmsg("\texporting ".$rch->{"$_.title"}); if( $rch->{"$_.title"} =~ /^config$/i ){ foreach( split("\n", $rch->{"$_.content"}) ){ $config{$1} = $2 if( !/^\#/ && /(.*?):\s*(.*)/ ); } } else{ my(@ls, $c, $a, $fn); $fn = $rch->{"$_.title"}; if( $fn !~ /\.(css|htm|html|js)$/i ){ print "not supported filetype ". $rch->{"$_.title"}. "\n"; next; } $c = $rch->{"$_.content"}; $c =~ s/$outdir/$fn"; if( $c =~ m|(.*?)\n\s*\s*\n(.*)|s ){ ($a, $c) = ($1, $2); $a =~ s/^\s*\#.*?\n//gm; foreach( split("\n", $a) ){ $attr{"$fn.$1"} = $2 if( /^\s*(\w+):\s+(.*)/ ); } } print FH $c; } } debugmsg(Dumper(\%config)); debugmsg(Dumper(\%attr)); } sub builddata($$$$$$) { my($board, $rbh, $rebuild, $contentonly, $number, $force, $del) = @_; my(%dat, $dbfn, $idxfn, $y, $m, $d, $t, $currid, $idx); $dbfn = "$BLOGDATA/$board.db"; $idxfn = "$BLOGDATA/$board.idx"; if( $rebuild ){ unlink $dbfn; unlink $idxfn; } tie %dat, 'DB_File', $dbfn, O_CREAT | O_RDWR, 0666, $DB_HASH; $idx = OurNet::FuzzyIndex->new($idxfn); if( $del ){ my($delmonth); ($y, $m) = (int($del / 10000), int($del / 100) % 100); $delmonth = 1; foreach( 0..32 ){ $delmonth = 0 if( $d != $_ && exists $dat{sprintf('%04d%02d%02d', $y, $m, $d)} ); } delete $dat{ sprintf('%04d%02d', $y, $m) } if( $delmonth ); $currid = $del; if( $dat{"$currid.prev"} ){ $dat{ $dat{"$currid.prev"}.'.next' } = $dat{"$currid.next"}; } else{ delete $dat{ $dat{"$currid.prev"}.'.next' }; } if( $dat{"$currid.prev"} ){ $dat{ $dat{"$currid.next"}.'.prev' } = $dat{"$currid.prev"}; } else{ delete $dat{ $dat{"$currid.next"}.'.prev' }; } $dat{head} = $dat{"$currid.next"} if( $dat{head} == $currid ); $dat{last} = $dat{"$currid.prev"} if( $dat{last} == $currid ); delete $dat{$currid}; delete $dat{"$currid.next"}; delete $dat{"$currid.prev"}; delete $dat{"$currid.title"}; delete $dat{"$currid.short"}; delete $dat{"$currid.content"}; delete $dat{"$currid.author"}; $idx->delete($currid); goto out; } foreach( $number ? $number : (1..($rbh->{num} - 1)) ){ if( !(($y, $m, $d, $t) = $rbh->{"$_.title"} =~ /(\d+)\.(\d+).(\d+),(.*)/) ){ debugmsg("\terror parsing $_: ".$rbh->{"$_.title"}); } else{ $currid = sprintf('%04d%02d%02d', $y, $m, $d); if( $dat{$currid} && !$force ){ debugmsg("\t$currid is already in db"); next; } debugmsg("\tbuilding $currid content"); $dat{ sprintf('%04d%02d', $y, $m) } = 1; $dat{"$currid.title"} = $t; $dat{"$currid.author"} = $rbh->{"$_.owner"}; # $dat{"$currid.content"} = $rbh->{"$_.content"}; # ugly code for making short my @c = split("\n", $dat{"$currid.content"} = $rbh->{"$_.content"}); $dat{"$currid.short"} = ("$c[0]\n$c[1]\n$c[2]\n$c[3]\n"); $idx->delete($currid) if( $idx->findkey($currid) ); $idx->insert($currid, ($dat{"$currid.title"}. "\n". $rbh->{"$_.content"})); if( !$contentonly ){ debugmsg("\tbuilding $currid linking... "); if( $dat{$currid} ){ debugmsg("\t\talready linked"); } elsif( !$dat{head} ){ # first article $dat{head} = $currid; $dat{last} = $currid; } elsif( $currid < $dat{head} ){ # before head ? $dat{"$currid.next"} = $dat{head}; $dat{"$dat{head}.prev"} = $currid; $dat{head} = $currid; } elsif( $currid > $dat{last} ){ # after last ? $dat{"$currid.prev"} = $dat{last}; $dat{"$dat{last}.next"} = $currid; $dat{last} = $currid; } else{ # inside ? @_@;;; my($p, $c); for( $p = $dat{last} ; $p>$currid ; $p = $dat{"$p.prev"} ){ ; } $c = $dat{"$p.next"}; $dat{"$currid.next"} = $c; $dat{"$currid.prev"} = $p; $dat{"$p.next"} = $currid; $dat{"$c.prev"} = $currid; } $dat{$currid} = 1; } } } out: untie %dat; $idx->sync(); undef $idx; chmod 0666, $idxfn; } sub getdir($$$$$) { my($bdir, $rh_bh, $rh_ch) = @_; my(%h); tie %h, 'BBSFileHeader', "$bdir/"; if( $h{"-1.title"} !~ /blog/i || !$h{"-1.isdir"} ){ debugmsg("blogdir not found"); return; } tie %{$rh_bh}, 'BBSFileHeader', "$bdir/". $h{'-1.filename'}.'/'; if( $rh_bh->{'0.title'} !~ /config/i || !$rh_bh->{'0.isdir'} ){ debugmsg("configure not found"); return; } tie %{$rh_ch}, 'BBSFileHeader', $rh_bh->{dir}. '/'. $rh_bh->{'0.filename'}; return 1; } main(); 1;