#! /usr/bin/perl
# fixscript will replace this line with code to load INN::Config

# Author:       James Brister <brister@vix.com> -- berkeley-unix --
# Start Date:   Thu May 16 10:32:02 1996 +0200
#
# Description: Take a file of the form generated by innd in the outgoing
#              directory ("Wnm*") and separate it into tape files for innfeed.
#
# Thanks to Clayton O'Neill <coneill@premier.net> for serious speed
# improvements.
#
# Various bug fixes, code and documentation improvements since then
# in 1997-1999, 2004, 2007, 2009, 2011, 2021-2024.

#
#        Hmm, perhaps we should try to read "backlog-directory"
#        from innfeed.conf.  Oh well.
#
use strict;
use warnings;

my $tapeDir = $INN::Config::pathspool . "/innfeed";
my $destDir = $INN::Config::pathtmp;
my $spoolArts = $INN::Config::patharticles;
my $outGoing = $INN::Config::pathoutgoing;

##
## Everything below here should probably be left alone.
##

$0 =~ s!.*/!!;

use Getopt::Std;

# Define variables Getopt::Std uses for --help and --version.
$Getopt::Std::STANDARD_HELP_VERSION = 1;
our $VERSION = $INN::Config::version;
$VERSION =~ s/INN //;

my $usage = "Usage:
  $0 [-hquv] [-c [-s dir]] [-d dir] [-e host] [-m [-t dir]] inn-batchfile

Options:
  -c         to check pathnames of articles before storing them
  -d dir     to put the output file(s) in that directory ($destDir)
  -e host    to process on entries for only that host
  -h         display a short help screen
  -m         to have $0 move the new files to the backlog directory
  -q         quiet mode: only display error messages; good for cron jobs
  -s dir     to specify where the news articles are
             ($spoolArts)
  -t dir     to specify the backlog directory ($tapeDir)
  -u         to unlink the input files when finished
  -v         for verbosity

  $0 will take an INN funnel file (normally a file in
  $outGoing), or an innfeed \"dropped\" file,
  which is presumed to be of the format:

      pathname message-id peer1 peer2 peer3 ...

  and will break it up into files peer1.tmp, peer2.tmp, peer3.tmp...
  Each of these files will be of the format:

      pathname message-id

  that is the same as innfeed's backlog file format.  Simply rename these
  files to peer1, peer2, peer3... in a running innfeed's backlog directory
  and they will be picked up automatically and processed by innfeed.
  Use the '-m' flag and they'll be moved automatically.
";

sub HELP_MESSAGE {
    print $usage;
    exit(0);
}

my (%opt, %hosts);
my $missing = 0;
getopts("cd:e:hmqs:t:uv", \%opt) || die $usage;

HELP_MESSAGE() if $opt{'h'};
die "Cannot specify both -q and -v\n\n" . $usage if ($opt{'q'} && $opt{'v'});

$spoolArts = $opt{'s'} if $opt{'s'};
$destDir = $opt{'d'} if $opt{'d'};
$tapeDir = $opt{'t'} if $opt{'t'};
my $inputFile = shift;

die $usage if !$inputFile;
unless (-f $inputFile) {
    exit if $opt{'q'};
    die "No such file: $inputFile\n\n" . $usage;
}
die "No such directory: $spoolArts\n\n" . $usage
  if (!-d $spoolArts && $opt{'c'});
die "No such directory: $destDir\n\n" . $usage if (!-d $destDir);
die "No such directory: $tapeDir\n\n" . $usage if (!-d $tapeDir && $opt{'m'});
warn "Specifying -s without -c has no effect!" if $opt{'s'} and not $opt{'c'};
warn "Specifying -t without -m has no effect!" if $opt{'t'} and not $opt{'m'};

print "Using $inputFile\n" if $opt{'v'};
open(my $INPUT, '<', $inputFile) || die "$0: open ($inputFile): $!\n";

while (<$INPUT>) {
    chop;
    my @F = split;

    # Check the format of the line vigorously
    next unless (m!^\S+/\d+ <.+@.+> \S+! || m!^@[0-9A-F]+@ <.+@.+> \S+!);

    if ($opt{'c'}) {
        if (!-f "$spoolArts/$F[0]") {
            $missing++;
            print "Dropping file: $spoolArts/$F[0]\n" if $opt{'v'};
            next;
        }
    }

    for (my $i = 2; $i <= $#F; $i++) {
        my $host = $F[$i];
        next if ($opt{'e'} && $opt{'e'} ne $host);

        # Keep out host names with any funny characters (from
        # corrupted files)
        if ($host !~ /^[-\._0-9A-Za-z]+$/) {
            warn "$0: bad site name ignored: \"$host\"\n";
            next;
        }

        if ($hosts{$host}) {
            print { $hosts{$host} } "$F[0] $F[1]\n";
        } else {
            my $outputFile = "$destDir/$host.tmp";
            print "Starting $host\n" if ($opt{'v'});
            open $hosts{$host}, '>>', $outputFile
              or die "open >>$outputFile: $!\n";
            print { $hosts{$host} } "$F[0] $F[1]\n";
        }
    }
}
close $INPUT;

foreach my $host (keys %hosts) {
    close $hosts{$host};
    my $outputFile = "$destDir/$host.tmp";
    my $tmpTape = "$tapeDir/$host.tmp";
    my $tapeFile = "$tapeDir/$host";
    if ($opt{'m'}) {
        if ($outputFile ne $tmpTape) {
            my $cmd = "mv $outputFile $tmpTape";
            system $cmd;
            die "$0: $cmd: failed\n" unless ($? == 0);
        }

        my $cmd
          = "cat $tmpTape | $INN::Config::sort -u"
          . " >> $tapeFile && rm -f $tmpTape";
        system $cmd;
        die "$0: $cmd: failed\n" unless ($? == 0);
    }
}

unlink $inputFile if $opt{'u'};

print "$missing articles dropped\n" if ($opt{'v'} && $missing > 0);
