#! /usr/bin/perl -w

# NOTE: this script needs to be run by the news user.
# Debian systems will not allow normal users to run ctlinnd and innxmit
# or rnews.

# Perl version by Blars Blarson, based on sh version by Christophe Le Bars, 
# Brian Mays, Tolleff Fog Heen, and others

use strict;
use File::Copy;
use File::Path;

# defaults, may be overriden in config file or command line
my %var = (
    "batchmode"		=> "-br",
    "bindir"		=> "/usr/bin",
    "etcdir"		=> "/etc/suck",
    "logdir"		=> "/var/log/suck",
    "newsbin"		=> "/usr/sbin",
    "newsspooldir"	=> "/var/spool/news",
    "postfilter"	=> "/usr/lib/suck/put-news",
    "process"		=> "gp",
    "quiet"		=> 0,
    "remoteport" 	=> 119,
    "server"		=> "localhost",
    "servtype"		=> "inn2",   
    "spooldir"		=> "/var/spool/suck",
    "statedir"		=> "/var/lib/suck",
    "timestamp"		=> 0,
    "verbose"		=> 0,	   
);
my @siteoptions = (
    "userid", 
    "password",
    "suckoptions",
    "rpostoptions",
    "remoteport",
    "postfilter",
    "process", 
);
my $site;
my $etcdir = "/etc/suck";
my $getnewsconf = "$etcdir/get-news.conf";
my $exit = 0;

# read the configuration file
open CONF, "<$getnewsconf" or die "Could not open $getnewsconf: $!";
while ($_ = <CONF>) {
    if (/^([a-z0-9\-\_\.]+)\:\s+(.*)$/) {
        $var{$1} = $2;
    } else {
	die "Unknown line in $getnewsconf:\n$_" unless (/^\s*(?:$|\#)/);
    }
}
close CONF;

my $quiet = $var{'quiet'};
my $verbose = $var{'verbose'};
my $timestamp = $var{'timestamp'};

unless (defined $var{'rnews'}) {
    if (-x "/usr/lib/news/input/rnews") {
	$var{'rnews'} = "/usr/lib/news/input/rnews";
    } elsif (-x '/usr/bin/rnews') {
	$var{'rnews'} = '/usr/bin/rnews';
    } else {
	die "rnews not found\n";
    }
}

my $defserver = $var{'remoteserver'};

if (exists $var{"outgoingfile"}) {
    $site = $var{"outgoingfile"};
} else {
    $site = $var{"remoteserver"};
}

# see if site is on the command line
if (scalar(@ARGV) && $ARGV[0] !~ /^-/) {
    $site = shift @ARGV;
    $var{"remoteserver"} = $site;
}

foreach my $opt (@siteoptions) {
    if (exists $var{"${site}_${opt}"}) {
        $var{$opt} = $var{"${site}_${opt}"};
    }
}

# process the rest of the command line
while ($_ = shift @ARGV) {
    if (/^-outgoingfile$/) {
        $site = shift @ARGV;
	foreach my $opt (@siteoptions) {
	    if (exists $var{"${site}_${opt}"}) {
		$var{$opt} = $var{"${site}_${opt}"};
	    }
	}
    } elsif (/^-server$/) {
        $var{"server"} = shift @ARGV;
    } elsif (/^-get(?:only)?$/) {
        $var{"process"} = "g";
    } elsif (/^-post(?:only)?$/) {
        $var{"process"} = "p";
    } elsif (/^-user(?:id)?$/) {
        $var{"userid"} = shift @ARGV;
    } elsif (/^-password$/) {
        $var{"password"} = shift @ARGV;
    } elsif (/^-noauth$/) {
        delete $var{"userid"};
	delete $var{"password"};
    } elsif (/^-port$/) {
        $var{"remoteport"} = shift @ARGV;
    } elsif (/^-q(?:iet)?$/) {
        $quiet++;
    } elsif (/^-v(?:erbose)?$/) {
	$verbose++;
    } elsif (/^-timestamp$/) {
	$timestamp++;
    } elsif (/^-h(?:elp)?$/) {
	print "Usage: $0 [<sitename>] [-option parm]...\n\n".
	    "    <sitename>		The NNTP server you will connect to.\n".
	    "\n".
	    "Options:\n".
	    "    -outgoingfile	<filename>  	The file of your remote server\n".
	    "					outgoing articles.\n".
	    "                            		(default = the remote server name)\n".
	    "    -userid		<userid>	The userid to send to the remote\n".
	    "					server.\n".
	    "    -password		<password>	The password to send to the remote\n".
	    "					server.\n".
	    "    -noauth				Do not send userid and password.\n".
	    "					(even if they are specified in\n".
	    "					${getnewsconf})\n".
	    "    -port               <port>          Set remote port number.\n".
	    "    -server    		<sitename>  	Your local NNTP server.\n".
	    "                            		(default = \"$var{'server'}\")\n".
	    "    -q                                  Do not display the BPS and article\n".
	    "                                        count messages during download.  \n".
	    "                                        Multiple -q to suppress message\n".
	    "    -getonly                            Only get new messages, do not post\n".
	    "    -postonly                           Only post outgoing messages, do not get\n".
	    "                                        new ones\n".
	    "    -timestamp                          put timestamps in log\n".
	    "    -verbose                            Display more messages about process.\n".
	    "                                        Use multiple times for debugging.\n".
	    "\n";
	exit 0;
    } else {
        die "Unknown option: $_ (use -h for help)";
    }
}

if ($verbose > 1) {
    print "Options:\n";
    foreach (keys %var) {
	print "$_: $var{$_}\n";
    }
    print "\n";
}

my $authopts = '';
if (exists $var{'userid'}) {
    $authopts = '-Q';
    $ENV{'NNTP_USER'} = $var{'userid'};
    $ENV{'NNTP_PASS'} = $var{'password'};
}

if ($var{'servtype'} =~ /^inn/) {
    if (system("$var{'bindir'}/testhost $var{'server'} -s -e") != 0) {
	die "Bad status for the $var{'server'} local NNTP news server: $?";
    }
}

my $lastdir = "$var{'logdir'}/$var{'remoteserver'}";
if (! -d $lastdir) {
    die "could not create $lastdir" unless mkdir($lastdir);
}

sub ts {
    return "" unless($timestamp);
    my @now = localtime();
    return sprintf("%02d:%02d:%02d ", $now[2], $now[1], $now[0]);
}

my $getnewslog = "$var{'logdir'}/get-news.log";
open LOG, ">>", $getnewslog or die "Could not open $getnewslog: $!";
print LOG "\n".scalar(localtime())."\n";

if ($var{'process'} =~ /g/) {
    my $batchfile = "$var{'statedir'}/batch.$var{'remoteserver'}.$$";
    my $msgdir = "$var{'spooldir'}/$var{'remoteserver'}";
    my $errlog = "$var{'logdir'}/errlog";
    my $suffix = '';
    my $popt = '';

    if($defserver ne $var{'remoteserver'}) {
	$suffix = ".$var{'remoteserver'}";
	$popt = "-p $suffix";
    }
    if($quiet && $var{'suckoptions'} !~ /-q/) {
	$var{'suckoptions'} .= ' -q';
    }

    print LOG ts()."getnews: download articles\n" unless($quiet > 1);
    my $suckcmd = "$var{bindir}/suck $var{'remoteserver'} $var{'suckoptions'}"
	." $authopts $var{'batchmode'} $batchfile -dt $var{'statedir'}"
	." -dm $msgdir -dd $var{'etcdir'} $popt -N $var{'remoteport'}"
	." -E $errlog";
    print ts()."$suckcmd\n" if($verbose);
    open SUCK, "-|", $suckcmd or die "Could not start $suckcmd: $!";
    while (my $l = <SUCK>) {
	print LOG ts().$l;
	print ts().$l if($verbose);
    }
    close SUCK;
    if ($? == 0 || $? == 256) {
	print ts()."Downloaded Articles\n" unless($quiet > 1);
	if (-f "$var{'statedir'}/suck.newrc$suffix") {	
	    rename("$var{'etcdir'}/sucknewsrc$suffix",
		   "$var{'etcdir'}/sucknewsrc$suffix.old");
	    move("$var{'statedir'}/suck.newrc$suffix",
		 "$var{'etcdir'}/sucknewsrc$suffix");
	}
	move("$var{'statedir'}/suck.sorted$suffix",$lastdir)
	    if (-f "$var{'statedir'}/suck.sorted$suffix");
	move("$var{'statedir'}/suck.killog$suffix",$lastdir)
	    if (-f "$var{'statedir'}/suck.killog$suffix");
	move("$var{'etcdir'}/suckothermsgs$suffix",$lastdir)
	    if (-f "$var{'etcdir'}/suckothermsgs$suffix");
	if (-f $batchfile) {
	    my $batchcmd = "NNTPSERVER=$var{'server'} $var{'rnews'} <$batchfile";
	    print ts()."$batchcmd\n" if ($verbose);
	    if (system($batchcmd)) {
		print STDERR "Local posting error\n";
		$exit = 255;
	    } else {
		print ts()."Posted Articles Locally\n" unless($quiet > 1);
		rmtree($msgdir);
		unlink($batchfile);
	    }
	}
    } else {
	print STDERR "Error getting articles, see $errlog\n";
	$exit = 1;
    }
}

if (! $exit && $var{'process'} =~ /p/) {
    my $outgoing = $var{'newsspooldir'};
    foreach my $a ('.outgoing', 'out.going', 'outgoing') {
	if (-d "$outgoing/$a") {
	    $outgoing .= "/$a";
	    last;
	}
    }
    $outgoing .= "/$site";
    my $artdir = $var{'newsspooldir'};
    $artdir .= "/articles" if (-d "$artdir/articles");
    my $outgoingnew = "${outgoing}.new";
    foreach my $o ($outgoingnew, $outgoing) {
	if (-s $o) {
	    if ($o ne $outgoingnew) {
		rename($outgoing,$outgoingnew);
		if ($var{'servtype'} =~ /^inn/) {
		    my $flushcmd = "$var{'newsbin'}/ctlinnd flush $site";
		    print ts()."$flushcmd\n" if ($verbose);
		    if (system($flushcmd) != 0) {
			print STDERR "Problem running $flushcmd: $!\n";
		    }
		}
	    }
	    my $outfile = "$var{'statedir'}/rpost.$var{'remoteserver'}.$$";

	    my $postcmd = "$var{'bindir'}/rpost $var{'remoteserver'}"
		." -N $var{'remoteport'} $authopts -E $var{'logdir'}/errlog"
		." $var{'rpostoptions'} -b $outgoingnew -p $artdir"
		." -f $var{'postfilter'} \\\$\\\$o=$outfile"
		." \\\$\\\$i $outfile";
	    print LOG ts()."Posting outgoing articles\n";
	    print ts()."$postcmd\n" if ($verbose);
	    if (system($postcmd) != 0) {
		print STDERR "Error remote posting\n";
		$exit = 2;
		last;
	    } else {
		print ts()."Remotely posted articles\n" unless($quiet > 1);
		unlink($outfile);
		unlink($outgoingnew);
	    }
	}
    }
}
print ts()."get-news processing complete\n" unless($quiet > 1);    

close LOG;

exit($exit);
