#!/usr/bin/perl --

# $Header: /home/jem/news/xpat_src/local/RCS/fixhist,v 1.4 1997/03/20 02:25:21 jem Exp jem $
#
# $Log: fixhist,v $
# Revision 1.4  1997/03/20 02:25:21  jem
# *** empty log message ***
#
# Revision 1.3  1996/03/04 14:04:14  news
# minor cleanup. -jem
#
# Revision 1.2  1995/12/05 03:12:13  news
# General cleanup for release -jem

# A quick little script to zap bad entries from the history file.
# To add any missing entries, run "makehistory -bun" after this.

# -d runs in debug mode, creating the files, but not make the new
#	database files and moving the new files into place.

# -D is full debug mode, sending most output to the bit bucket.

# -b specifies a different name for the bad entry file.

# However, pre unoff2 makehistory has a memory leak problem, and may
# take days to finish on a Sun machine with a large spool.  For that
# reason, I have not included that step in this program.

# The old history files are not deleted, so you will need to remove
# them manually after confirming that everything works correctly.

# John Milburn   POSTECH, Pohang, Korea      jem@xpat.postech.ac.kr

($prog = $0) =~ s%.*/%%;

# To keep perl -w from complaining
$count = $opt_d = $opt_D = $opt_b = $opt_t = 0;

require Getopt::Std;
Getopt::Std::getopts('Ddtb:');

$debug = 1 if $opt_d;
$DDebug = $debug = 1 if $opt_D;

# ******Configuration Section*********

# The innshellvars file, which contains file path definitions.
#### =()<require '@<_PATH_PERL_SHELLVARS>@';>()=
require '/var/news/etc/innshellvars.pl';

# This is the oldest article which should be in the history database.
# The one year default should be fine, unless you have some really,
# really old stuff hangin around.
$oldest_art = 401;	# minus Days
$newest_art = 2;	# Days
$MAXKEYLEN=255;		# Maximum message-id length

# ******End Configuration Section*********

sub setup {
    $SEC_PER_DAY = 86400;

    $nowtime = time();
    $oldest = $nowtime - ($oldest_art * $SEC_PER_DAY);
    $newest = $nowtime + ($newest_art * $SEC_PER_DAY);

	# Don't use history.n, which is used by expire.
    $newhist = "$history.new";
	# Where to put bad entries
    $badhist = "$history.bad";

    $badhist = "$opt_b" if $opt_b;
    $newhist = "/dev/null" if $DDebug;
    # The directory which contains the history file
    ($newsdir = "$history") =~ s#/history$##;

    # Make sure the directory exists and is readable
    chdir("$newsdir")
	|| die "Cannot change to directory $newsdir";

}

sub parse_hist {

    # Open the files
    open(OLDHIST, "<$history")
	|| die "Cannot open old history file $history";
    open(NEWHIST, ">$newhist")
	|| die "Cannot open new history file $newhist";
    open(BADHIST, ">$badhist")
	|| die "Cannot open bad history file $badhist";

    # This is where all of the significant parsing of the history file
    # is done.  Anything which doesn't exactly match a proper entry is
    # written to the history.bad file.

    while(<OLDHIST>) {

	($msgid,$dates,$arts,$xtra) = ();
	chop;
	($msgid,$dates,$arts,$xtra) = split("\t");
	
	# There must be at most three <TAB> separated fields. If there
	# are more, then entry is trashed.

	if ( $xtra ) {
	    print BADHIST "Extra fields:$_\n";
	    next;
	}

	# First, check for <MESSAGEID><TAB><receivetime~>, which is the
	# minimum entry in the history file (This format is used for
	# already expired articles which have not passed the "remember"
	# flag period.

	# If that is OK, then check the receive time. If it is
	# too early or too late, dump the item into history.bad.

	# Next, check for a <space> in the line.  If there is at least
	# one, the line must end in a decimal number (the article number).
	# If it does not, skip and write to history.bad.

	# Finally, check for dangling <TAB> characters, after the date
	# entries, with no article list. This type of entry give expire fits.

	if ( /^<\S+>\t(\d+)~/ ) {
	    $rectime = $1;
	    if ( $rectime<$oldest || $rectime>$newest ) { # received time
		print BADHIST "Bad time:$_\n";
	    } elsif ( /\ / && ( ! / \S+\/\d+$/ ) ) {      # space and ends in number
		print BADHIST "Bad artlist:$_\n";
	    } elsif ( ! /[\d\-\t]$/ ) {			  # A dangling <TAB>
		print BADHIST "Bad artlist:$_\n";
	    } elsif (length($msgid) > $MAXKEYLEN) {	  # message-id too long
		print BADHIST "Bad MessageID:$_\n";
	    } elsif (/[\000-\010\012-\037\177-\377]/) {   # control chars except tab
		print BADHIST "Bad characters:$_\n";
	    } else {
		print NEWHIST "$_\n";
		$count++;
	    }
	} else {
	    print BADHIST "Bad format:$_\n";
	}
    }

    # Close the files, to be neat
    close(OLDHIST);
    close(NEWHIST);
    close(BADHIST);
}

sub make_dbz {
    # Save the old files
    rename("$history","$history.sav");
    rename("$history.pag","$history.sav.pag");
    rename("$history.dir","$history.sav.dir");

    # Make the new database files
    system("$newsbin/makehistory -r -s $count -f $newhist -i");

    # Move the news files into place
    rename("$newhist","history");
    rename("$newhist.pag","history.pag");
    rename("$newhist.dir","history.dir");
}


# ************* Main program **************
$newsbin = $inn::newsbin;
$history = $inn::history;
&setup;

# Everything is OK, so throttle innd.
system("$newsbin/ctlinnd throttle hist_rebuild") unless ($debug || $opt_t);

&parse_hist;
&make_dbz unless $debug;

# Start it up!
system("$newsbin/ctlinnd go hist_rebuild") unless ($debug || $opt_t);

exit $?;

