#!/usr/bin/perl

(chdir '/usr/spool/news') || die "Can't cd to /usr/spool/news";
$now = time;
$| = 1;

($dev,$ino,$mode,$nlink) = stat('.');

&dodir('.',$nlink);

exit 0;

###############################################################

sub dodir {
    local($dir,$nlink) = @_;
    local($dev,$ino,$mode,$time,$cutoff);

    $dir =~ s#^\./##;

    # Determine number of days to keep articles in group.

    $time = 14;
    $time = 3   if $dir =~ /^(junk|control)/;
    $time = 8   if $dir =~ /^talk/;
    $time = 8   if $dir =~ /^rec/;
    $time = 28  if $dir =~ /^comp/;
    $time = 10  if $dir =~ /^sci/;
    $time = 50  if $dir =~ /^comp\.sources\.(unix|misc|bugs)/;
    $time = 50  if $dir =~ /^comp\.sys\.(sun|pyramid|amiga)/;
    $time = 50  if $dir =~ /^comp\.windows\.x/;
    $time = 50  if $dir =~ /^comp\.unix\.wizards/;
    $time = 60  if $dir =~ /^comp\.lang\.perl/;
    $time = 50  if $dir =~ /^comp\.bugs/;
    $time = 50  if $dir =~ /^comp\.sources\.bugs/;
    $time = 365 if $dir =~ /^proj/;
    $cutoff = $now - $time * (60 * 60 * 24);

    # Get all the filenames in current directory handy.
    # We use readdir() instead of <*> because it doesn't start
    # a subshell and won't blow up on huge directories.

    opendir(DIR,'.') || die "Can't open $dir";
    local(@filenames) = readdir(DIR);
    closedir(DIR);

    # Separate the sheep from the goats.

    local(@subdirs);
    local(@articles);
    for (@filenames) {
	if (/^\d+$/) {
	    push(@articles,$_); # Possibly a lie, but avoid stat.
	}
	else {
	    push(@subdirs,$_);
	}
    }

    # Look for articles to expire.

    if ($#articles >= 0) {
	@articles = sort bynumber @articles;

	# Now the tricksy part.  Since the @articles array is
	# now in age order, we binary search for articles to
	# expire.  At the end of this loop, $min should be
	# first non-expiring article

	$max = $#articles;
	$min = 0;
	while ($max - $min > 0) {
	    $mid = int(($max + $min) / 2);
	    ($dev,$ino,$mode,$nl,$uid,$gid,$rdev,$size,$atime,
		$mtime,$ctime) = stat($articles[$mid]);
	    if ($dev == 0) {
		$min = -1;
		print STDERR "$dir changed--skipping!\n";
	    }
	    elsif (-d _) {
		push(@subdirs, $mid);   # Oops, a directory.
		$min = -1;             # Punt this time.
	    }
	    elsif ($mtime >= $cutoff) { # $mid is not expiring
		$max = $mid;
	    }
	    else {                      # $mid is expiring
		$min = $mid + 1;
	    }
	}

	# Zap any expired articles.

	if ($min > 0) {
	    print "$dir: $articles[0] .. $articles[$min-1]\n";
	    unlink @articles[ 0 .. $min-1 ];
	}
	else {
	    print "$dir: (none)\n";
	}
    }
    if ($nlink != 2) {          # This dir has subdirectories.
	for (@subdirs) {
	    next if $_ eq '.';
	    next if $_ eq '..';
	    $name = "$dir/$_";

	    ($dev,$ino,$mode,$nlink) = stat($_);
	    next unless -d _;

	    chdir $_ || die "Can't cd to $name";
	    &dodir($name,$nlink);
	    chdir '..';
	}
    }
}

sub bynumber {
    $a <=> $b;
}
