#!/usr/local/bin/perl5 -w
## =================================================================
## rebatch: resend nntplink files
##
## Usage: 
##    rebatch -d[n] -r 
##      -d   --- tell the user what we are doing in detail
##      -n   --- -d plus don't run any commands or touch any files
##      -r   --- remove status files when a site finishes
##
## By R Street <r.street@auckland.ac.nz>
##
## 21/04/94 RS --- Version II written
## 15/09/94 RS --- Added estimated time of completion
## 20/01/95 RS --- Version III written 
## 03/02/95 RS --- Allowed for aliases in the sitename portion
## 04/02/95 RS --- Added timeout to innxmit invocations
##                 More cleaning, polishing and documentation
## =================================================================

## -----------------------------------------------------------------
## Where to find the configuration files and common subroutines
## -----------------------------------------------------------------
## =()<push(@INC, "@<_PATH_NEWSBIN>@");>()=
push(@INC, "/usr/local/news/bin");

## -----------------------------------------------------------------
## These variables are undef'd here to stop perl -w from
## complaining.
## -----------------------------------------------------------------
undef $ctlinnd;
undef $log;
undef $nntplink_link_suffix;
undef $nntplink_tmp_suffix;
undef $opt_d;
undef $opt_n;
undef $opt_r;
undef $rebatch_batch_suffix;
undef $rebatch_lockfile_prefix;
undef $rebatch_status_prefix;
undef $remove_status;
undef @addresses;
undef @sites;


## -----------------------------------------------------------------
## All of the configuration variables in held in a seperate file
## -----------------------------------------------------------------
require "rebatch.conf";


## -----------------------------------------------------------------
## Load common code
## -----------------------------------------------------------------
require "rebatch.common";


## -----------------------------------------------------------------
## General Perl library code
## -----------------------------------------------------------------
require "ctime.pl";
require "getopts.pl";


## -----------------------------------------------------------------
## Parse command line options. 
## -----------------------------------------------------------------

&Getopts("rdn");
if (defined($opt_d)) {
    $debug = 1;
}

if (defined($opt_n)) {
    $debug = 2;
}

if (defined($opt_r)) {
    $remove_status = 1;
}



## -----------------------------------------------------------------
## Logging... if not debugging, reopen stdout and stderr into 
## a log file.  Do not buffer stdout/stderr
## -----------------------------------------------------------------

if ($debug) {
} else {
    open(STDOUT, ">>$log");
    open(STDERR, ">&STDOUT");
}

select STDOUT; $| = 1;	# No buffering
select STDERR; $| = 1;
	
## -----------------------------------------------------------------
## Idenfiy ourself and print a start up message
## Move to the right place and start work
## -----------------------------------------------------------------
$proc = "rebatch";

print "------------------------------------------------------------\n";
print "$proc\[$$\]: starting at ".&ctime(time);

chdir $path_batchdir  || die "could not chdir to $path_batchdir";

## Only one rebatch process should be run at once
&do_lock();

## Read the sites and hosts from the newsfeeds file into the
## linear arrays
##     ???
## and ???
&read_newsfeeds();


## Examine each site/address pair

for $i (0 .. $#sites) {
    $the_site = $sites[$i];
    $the_address = $addresses[$i];
    $the_batchfile =  "$the_address.$rebatch_batch_suffix";

    print "$proc\[$$\]: have site '$the_site' address '$the_address'\n" if $debug;
    
    next if ! &do_site_flush($the_site, $the_address);
    &rebatch_files($the_site, $the_address, $the_batchfile);
    &send_batch($the_site, $the_address, $the_batchfile);

    print "$proc\[$$\]: \n" if $debug;
}



## Release the rebatch lock
print "$proc\[$$\]: removing rebatch lock file '$rebatch_lockfile'\n"
    if $debug;
unlink($rebatch_lockfile);

print "$proc\[$$\]: finished: ".&ctime(time)."\n";
print "------------------------------------------------------------\n";
exit 0;




## -----------------------------------------------------------------
## sub do_lock --- shlock style locking 
## -----------------------------------------------------------------

sub do_lock {
    print "$proc\[$$\]: rebatch lock file ('$rebatch_lockfile')\n" if $debug;

    if (open(LOCK, $rebatch_lockfile)) {
	print "$proc\[$$\]: ... lock file exists\n" if $debug;

	# It exists. Read the pid and send a signal to that process
	$pid = <LOCK>;
	chop $pid;
	close(LOCK);

	kill 0, $pid;

	# Did it succeed? Then there is another copy of us running
	# and we should STOP

	print "$proc\[$$\]: ... kill of pid $pid went '$!'\n" if $debug;

	if ( $! ne "No such process" ) {
	    print "$proc\[$$\]: ... already running (pid $pid): exiting";
	    exit 0;
	} else {
	    print "$proc\[$$\]: ... breaking lock on $pid\n";
	    unlink($rebatch_lockfile);
	}
    }

    # Otherwise make a lock file
    open(LOCK, "> $rebatch_lockfile")
	|| die "Could not make lock file '$rebatch_lockfile: $!";
    print LOCK "$$\n";
    close(LOCK);

    print "$proc\[$$\]: ... made lock file\n" if $debug;
    print "$proc\[$$\]: end of lock file section\n" if $debug;
    print "$proc\[$$\]: \n" if $debug;
}



## -----------------------------------------------------------------
## sub do_site_flush
##
## See if this site has any INN written spool files or nntplink
## temporary files.  If it does, the site needs to be flushed before
## processing.  We take care only to do *one* flush.
##
## At the end of this all the files we are interested in will 
## match:
##         $nntphost\.\d+
## -----------------------------------------------------------------


sub do_site_flush {
    local($sitename, $nntphost) = @_;

    print "$proc\[$$\]: ... start do_site_flush for ($sitename, $nntphost)\n"
	if $debug;

    local($do_flush) = 0;
    local($found_files) = 0;

    # Check for INN written batch file. 
    # Rename it to look like an nntplink batch file
    if ( -e $sitename ) {
	print "$proc\[$$\]: ... ... INN batchfile exists\n" if $debug;
	
	$do_flush = 1;

	$dest = "$nntphost.0";
	while ( -e $dest ) {
	    $dest = $dest."0";
	}
	
	print "$proc\[$$\]: ... ... do rename($sitename, $dest)\n" if $debug;
	rename($sitename, $dest) if $debug < 2;
    }


    # Look for all files of the form 
    #   $nntphost.*  (shell wildcard)
    # We ignore .link files, and remember to flush if .tmp files exist
    
    foreach $file ( <$nntphost.*>, <$sitename.*> ) {
	next if ! -r $file;
	next if ($file =~ /^$nntphost\.$nntplink_link_suffix/) ;

	print "$proc\[$$\]: ... ... found $file\n" if $debug;

	$found_files = 1;

	if ( $file =~ /$nntplink_tmp_suffix$/ ) {
	    $do_flush = 1;
	    print "$proc\[$$\]: ... ... nntplink temp $file exists\n"
		if $debug;
	}
    }

    # If we are need to flush the site do it now
    if ($do_flush) {
	print "$proc\[$$\]: ... ... ctlinnd -s flush $sitename\n" if $debug;
	system("$ctlinnd -s flush $sitename") if $debug < 2;
	sleep 10 if $debug < 2;
    }

    print "$proc\[$$\]: ... end do_site_flush for ($sitename, $nntphost)\n"
	if $debug;
    print "$proc\[$$\]: ... no files found\n" if $debug && !$found_files;
    return $found_files;
}




## -----------------------------------------------------------------
## sub rebatch_files
##
## Collect all the rogue batchfiles for a site into one.
## -----------------------------------------------------------------

sub rebatch_files {
    local($site, $nntphost, $resend_batch) = @_;
    local($file);

    print "$proc\[$$\]: ... into rebatch_files \n" if $debug;

    foreach $file (<$nntphost.*>, <$site.*>) {

	# Skip irregular files and those that don't conform
	next if ! -r $file;
	next if ! ( ($file =~ /^$nntphost.\d+$/) 
		   || ($file =~ /^$site.\d+$/) );

	print "$proc\[$$\]: ... ... cat $file >> $resend_batch\n" if $debug;
	system("cat $file >> $resend_batch") if $debug < 2;
	unlink($file) if $debug < 2;
    }

    print "$proc\[$$\]: ... out of rebatch_files \n" if $debug;
}    ## sub rebatch_files


## -----------------------------------------------------------------
## sub send_batch --- send a batch of news to a remote host
##
## Uses shlock style locking to ensure we are only going to run
## one innxmit process to a site.
## -----------------------------------------------------------------

sub send_batch {
    local($rb_site, $rb_host, $rb_file) = @_;
    local($progress) = "$rebatch_status_prefix.$rb_site";

    print "$proc\[$$\]: ... into send_batch\n" if $debug;

    ## Check for a valid lock file for this host

    $hostlock = "$rebatch_lockfile_prefix.$rb_site";

    if (open(HOSTLOCK, "$hostlock")) {
	print "$proc\[$$\]: ... ... lock file exists\n" if $debug;
	
	# It exists. Read the pid and send a signal to that process
	$pid = <HOSTLOCK>;
	chop $pid;
	close(HOSTLOCK);

	kill 0, $pid;

	# Did it succeed? 

	print "$proc\[$$\]: ... ... kill of pid $pid went '$!'\n" if $debug;

	if ( $! ne "No such process" ) {
	    print "$proc\[$$\]: $rb_site already running (pid $pid)\n";
	    return;
	} else {
	    print "$proc\[$$\]: $rb_site breaking lock on $pid\n";
	    unlink($hostlock);
	}
    }



    if ( ($child = fork) == 0) 
    {
	# CHILD

	# Otherwise make a lock file
	open(HOSTLOCK, "> $hostlock") || die "Could not make lock file: $!";
	print HOSTLOCK "$$\n";
	close(HOSTLOCK);
	
	print "$proc\[$$\]: ... ... made lock file $hostlock\n" if $debug;
	print "$proc\[$$\]: ... ... running '$innxmit -d $rb_host $rb_file > $progress'\n"
	    if $debug;

	if (($child = fork) == 0) {
	    # grandchild

	    open(STDOUT, ">$progress"); $| = 1;
	    open(STDERR, ">&STDOUT");   $| = 1;
	    print time, "\n";
	    exec "$innxmit -d $rb_host $rb_file" if $debug < 2;
	    exit;
	}

	waitpid($child, 0);

	unlink($progress) if ($remove_status);

	print "$proc\[$$\]: ... ... removing lock file $hostlock\n" if $debug;
	unlink($hostlock);

	exit;
    } else { 
	# PARENT
	sleep 5 if $debug < 2;
    }

    print "$proc\[$$\]: ... out of send_batch\n" if $debug;
}

## End of file: rebatch
## =================================================================

