# $Id: faqfile.pl,v 1.13 1993/01/25 00:09:26 jik Exp $
# 
# Copyright (c) 1992 Jonathan I. Kamens.  See the GNU Public License
# (any version) for terms of distribution.

package faqfile;

$default_interval = 0;
$default_sigfile = "none";
$default_force = 0;
$check_duplicates = 1;
$; = "\034";

sub parse_faq {
    # The format of an individual FAQ specification line in the config
    # file is as follows:
    # 
    # idname file timestamp interval sigfile force parent
    # 
    # The fields are separated by blank space, which means, of course,
    # that the contents of the fields cannot contain spaces or tabs.
    # To specify an empty field (for fields that are allowed to be
    # empty -- timestamp, interval, sigfile, force, parent), use a
    # single period.  The meaning of each field is as follows:
    # 
    # idname -- The string to use as the unique name of the FAQ in the
    #   Message ID of the posted article.
    # file -- The file containing the text of the FAQ.  This should be
    # 	readable from the current directory.
    # timestamp -- The timestamp of when the article was last posted.
    # 	If unspecified, the article is assumed not to have been
    #   posted.  This field is filled in automatically by the program
    #   when it rewrites the config file after doing a set of
    #   postings.
    # interval -- The number of days to wait after the last posting
    #   before posting the FAQ again.  Defaults to the interval
    #   hard-coded into the program, or to the interval specified with
    #   the "-interval" command-line option.
    # sigfile -- The signature file to append to the bottom of the
    #   message, with "-- \n" prepended to it.  If unspecified,
    #   defaults to the hard-coded path or to the file specified with
    #   "-sigfile".  If "none", don't include a signature file.  So,
    #   you can't have a signature file named "none" in the current
    #   working directory; use "./none". So sue me.
    # force -- If specified, then treat the contents as a number.  If
    #   it is 0, then never force the posting of this article.  If it
    #   is a 1, then force the posting of this article just once, and
    #   replace the 1 with an empty field ('.') when done doing so.
    #   If it is a 2, then always force the posting of this article.
    #   If it is a -1, then force the article NOT to be posted, no
    #   matter what.  Any other values are illegal.  If not specified,
    #   the hard-coded force parameter or the presence or absence of
    #   "-force" on the command line is used to decide whether or not
    #   to force.
    # parent -- The ID name of the parent article of this one, if any.
    # 	The parent's FAQ specification must appear earlier in the
    #   config file than the child's.  If a parent is specified, then
    #   the child article will not be posted unless the parent was
    #   posted successfully.  Note that *if* the parent posts
    #   successfully, the child won't post unless its interval has
    #   expired, so if you want the child to post whenever the parent
    #   did, make sure to use "force" (see above).
    # 
    # Blank lines, lines with only whitespace, and lines starting with
    # '#' in the config file are ignored.

    return undef if (($_[0] =~ /^[ \t]*$/) || ($_[0] =~ /^\#/));

    local(@fields) = split(' ', $_[0]);
    if (@fields != 7) {
	warn "Wrong number of fields in FAQ specification \"$_[0]\".  Ignoring FAQ.\n";
	return undef;
    }

    local($idname) = shift @fields;

    if ($idname eq "") {
	warn "No ID name specified in FAQ specification \"$_[0]\".  Ignoring FAQ.\n";
	return undef;
    }

    if ($check_duplicates && $faqs{$idname,"file"}) {
	warn "Duplicate ID name $idname.  Ignoring FAQ.\n";
	return undef;
    }
    local($file) = shift @fields;

    if ($file eq "") {
	warn "No file specified in FAQ specification in \"$_[0]\".  Ignoring FAQ.\n";
	return undef;
    }

    local($timestamp) = shift @fields;
    if ($timestamp eq ".") {
	$timestamp = undef;
    }
    elsif ($timestamp !~ /^[0-9]+$/) {
	warn "Timestamp in FAQ specification \"$_[0]\" is invalid.  Ignoring FAQ.\n";
	return undef;
    }

    local($interval) = shift @fields;
    if ($interval eq ".") {
	$interval = undef;
    }
    elsif ($interval !~ /^[0-9.]+$/) {
	warn "Interval in FAQ specification \"$_[0]\" is invalid.  Ignoring FAQ.\n";
	return undef;
    }

    local($sigfile) = shift @fields;
    ($sigfile = undef) if ($sigfile eq ".");

    local($force) = shift @fields;
    if ($force eq ".") {
	$force = undef;
    }
    else {
	$force += 0;		# force it to be a number
	if ((int($force) != $force) || ($force < -1) || ($force > 2)) {
	    warn "Force parameter in FAQ specification \"$_[0]\" is invalid.  Ignoring FAQ.\n";
	    return undef;
	}
    }

    local($parent) = shift @fields;
    if ($parent eq ".") {
	$parent = undef;
    }
    elsif (! $faqs{$parent,"file"}) {
	warn "FAQ specification \"$_[0]\" has unknown parent.  Ignoring FAQ.\n";
	return undef;
    }

    $faqs{$idname,"file"} = $file;
    $faqs{$idname,"timestamp"} = $timestamp;
    $faqs{$idname,"interval"} = $interval;
    $faqs{$idname,"sigfile"} = $sigfile;
    $faqs{$idname,"force"} = $force;
    $faqs{$idname,"parent"} = $parent;
    $faqs{$idname,"configline"} = $_[0];

    return($idname, eval "\"$file\"", $timestamp, 
	   $interval ? $interval : $default_interval,
	   $sigfile ? $sigfile : $default_sigfile,
	   $force ? $force : $default_force, $parent);
}

sub get_file {
    $faqs{$_[0],"file"};
}

sub get_timestamp {
    $faqs{$_[0],"timestamp"};
}

sub get_interval {
    if ($faqs{$_[0],"file"}) {
	$faqs{$_[0],"interval"} || $default_interval;
    }
    else {
	undef;
    }
}

sub get_sigfile {
    if ($faqs{$_[0],"file"}) {
	$faqs{$_[0],"sigfile"} || $default_sigfile;
    }
    else {
	undef;
    }
}

sub get_force {
    if ($faqs{$_[0],"file"}) {
	$faqs{$_[0],"force"} || $default_force;
    }
    else {
	undef;
    }
}

sub get_parent {
    $faqs{$_[0],"parent"};
}

sub set_posted {
    $faqs{$_[0],"posted"}++;
}

sub set_name {
    local($old, $new) = @_;

    for ("file", "timestamp", "interval", "sigfile", "force", "parent",
	 "configline") {
	$faqs{$new,$_} = $faqs{$old,$_};
    }
    &delete($old);
}

sub set_file {
    return if (! $_[1]);
    $faqs{$_[0],"file"} = $_[1];
}

sub set_timestamp {
    local($idname, $timestamp) = @_;
    ($timestamp = ".") if (! $timestamp);
    $faqs{$idname,"timestamp"} = $timestamp;
}

sub set_interval {
    local($idname, $interval) = @_;
    ($interval = ".") if (! $interval);
    $faqs{$idname,"interval"} = $interval;
}

sub set_sigfile {
    local($idname, $sigfile) = @_;
    ($sigfile = ".") if (! $sigfile);
    $faqs{$_[0],"sigfile"} = $sigfile;
}

sub set_force {
    local($idname, $force) = @_;
    ($force = ".") if (! $force);
    $faqs{$idname,"force"} = $force;
}

sub set_parent {
    local($idname, $parent) = @_;
    ($parent = ".") if (! $parent);
    $faqs{$idname,"parent"} = $parent;
}

sub configline {
    local($id) = $_[0];
    local($fi, $t, $i, $s, $fo, $p) = 
	($faqs{$id,"file"}, $faqs{$id,"timestamp"}, $faqs{$id,"interval"},
	 $faqs{$id,"sigfile"}, $faqs{$id,"force"}, $faqs{$id,"parent"});

    $t = "." if (! $t);
    $i = "." if (! $i);
    $s = "." if (! $s);
    $fo = "." if (! $fo);
    $p = "." if (! $p);

    if ($faqs{$id,"configline"} !~ s/^(\s*)[^\s]+(\s+)[^\s]+(\s+)[^\s]+(\s+)[^\s]+(\s+)[^\s]+(\s+)[^\s]+(\s+)[^\s]+(\s*)$/$1$id$2$fi$3$t$4$i$5$s$6$fo$7$p$8/) {
	die sprintf("possible internal error in faqfile'configline\n(For archive name %s, configline is\n%s", $id, $faqs{$id,"configline"});
    }

    $faqs{$_[0],"configline"};
}
    
sub was_posted {
    $faqs{$_[0],"posted"};
}

sub timestamp {
    $faqs{$_[0],"timestamp"};
}

sub new_configline {
    local($idname, $file, $timestamp, $interval, $sigfile, $force, $parent) =
	@_;

    sprintf("%s\t%s\t%s\t%s\t%s\t%s\t%s", $idname, $file,
	    $timestamp ? $timestamp : ".", $interval ? $interval : ".",
	    $sigfile ? $sigfile : ".", $force ? $force : ".",
	    $parent ? $parent : ".");
}

sub delete {
    local($name) = @_;

    for ("file", "timestamp", "interval", "sigfile", "force", "parent",
	 "configline") {
	delete $faqs{$name,$_};
    }
}

1;

