#!/usr/bin/perl
#
# makecat = MiniVend catalog configurator
#
# Copyright 1996-1999 by Michael J. Heins <mikeh@minivend.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

sub dontwarn { $FindBin::RealBin; }

BEGIN {
    eval {
        require 5.004;
        require FindBin;
        1 and $VendRoot = "$FindBin::RealBin";
        1 and $VendRoot =~ s/.bin$//;
    };
	($VendRoot = $ENV{MINIVEND_ROOT})
		if defined $ENV{MINIVEND_ROOT};
$VendRoot = $VendRoot || '/home/minivend';
}

## END CONFIGURABLE VARIABLES

use lib "$VendRoot/lib";

$| = 1; select STDERR; 
$| = 1; select STDOUT; 

use Config;
use File::Find;
use File::Copy;
use File::Path;
use Vend::MakeCat;
use Vend::Util;
use Getopt::Long;
use IniConf;

#use strict;

my $Removeconfig;
my $Reconfigure = 0;
my $Configfile;
my $Cfg;
my $Logfile = 'makecat.log';
my $catalog_name;
my %Conf;
my $Inetmode;
my $Windows;
my $pid;
$Windows = 1 if $Config{osname} =~ /win32/i;


my $USAGE = <<EOF;
usage: $0 [options] [catalogname]

options:

    -F    Force make of catalog with defaults
    -f    Configuration file (default is $0.cfg)
    -l    File to log to (default makecat.log)
    -r    Reconfigure defaults

    Defaults:
    --basedir=directory      Base directory for catalogs
    --cgibase=url_fragment   Base URL for link programs
    --documentroot=directory The directory where HTML is based
    --minivendgroup=group    The default group files should be owned by
    --minivenduser=username  The user ID which runs MiniVend
    --serverconf=filename    Location of httpd.conf
    --vendroot=filename      Location of MiniVend software
	--homedir=directory      Use instead of \$HOME to set defaults

    Required:
    --catroot=directory      Directory where MiniVend catalog files go
    --cgidir=directory       The directory the CGI link should go to
    --servername=server      Name of server (www.whatever.domain)
    --cgiurl=url_fragment    The path to the CGI link (no server name)
    --demotype=template      The template catalog (simple is the default)
    --mailorderto=email      Email address to send orders

    Optional:
    --catuser=username       The user files should be owned by (if root)
    --samplehtml=directory   The directory where template HTML goes
    --imagedir=directory     The directory where template images go
    --imageurl=url           The URL to prefix images with
    --nocfg                  Don't add to minivend.cfg
    --nocopy                 Don't actually copy the files, just test
    --norunning              Don't add to running server
    --reference              Return hash of config as string (sets -F, no write)
    --linkprogram=file       Use file as link program instead of vlink/tlink
    --linkmode=mode          UNIX or INET (link program vlink or tlink)
    --sampleurl=url          URL to access HTML for catalog
    --noumask                Don't set umask

EOF

if (scalar @ARGV > 1) {

Getopt::Long::config(qw/permute/);

#Getopt::Long::config(qw/debug/);

my %optctl = (

    'F'                 => \$Vend::MakeCat::Force,
    'aliases'           => \$Conf{aliases},
    'basedir'           => \$Conf{basedir},
    'catalogname'       => \$catalog_name,
    'catroot'           => \$Conf{catroot},
    'catuser'           => \$Conf{catuser},
    'cgibase'           => \$Conf{cgibase},
    'cgidir'            => \$Conf{cgidir},
    'cgiurl'            => \$Conf{cgiurl},
    'demotype'          => \$Conf{demotype},
    'documentroot'      => \$Conf{documentroot},
    'f'                 => \$Configfile,
    'homedir'           => \$Conf{homedir},
    'imagedir'          => \$Conf{imagedir},
    'imageurl'          => \$Conf{imageurl},
    'l'                 => \$Logfile,
    'linkmode'          => \$Conf{linkmode},
    'linkprogram'       => \$Conf{linkprogram},
    'mailorderto'       => \$Conf{mailorderto},
    'minivendgroup'     => \$Conf{minivendgroup},
    'minivenduser'      => \$Conf{minivenduser},
    'nocfg'             => \$Conf{nocfg},
    'nocopy'            => \$Conf{nocopy},
    'norunning'         => \$Conf{norunning},
    'noumask'           => \$Conf{noumask},
    'r'                 => \$Reconfigure,
    'reference'         => \$Conf{reference},
    'samplehtml'        => \$Conf{samplehtml},
    'sampleurl'         => \$Conf{sampleurl},
    'serverconf'        => \$Conf{serverconf},
    'servername'        => \$Conf{servername},
    'vendroot'          => \$Conf{vendroot},
	'<>'				=> sub {
							my $arg = shift;
							return unless $arg =~ /=/;
							my ($opt, $val) = split /=/, $arg, 2;
							$opt = lc $opt;
							die "Can't set \U$opt\E twice.\n$USAGE\n"
								if defined $Conf{$opt};
							$Conf{$opt} = $val;
							return;
							},
);

my @options = ( qw/

	F
    aliases=s
    basedir|base=s
    catalogname|name=s
    catroot|dir=s
    catuser|user=s
    cgibase=s
    cgidir=s
    cgiurl|script=s
    demotype|template=s
    documentroot=s
    f
    i
    homedir=s
    imagedir=s
    imageurl=s
    l=s
    linkmode=s
    linkprogram=s
    mailorderto=s
    minivendgroup|group=s
    minivenduser|mvuser=s
    nocfg
    nocopy
    norunning
    r
    reference
    samplehtml|html=s
    sampleurl=s
    serverconf|conf=s
    servername|server=s
    vendroot|mvdir=s
    <>

/ );

GetOptions(\%optctl, @options)			or die "\n$USAGE\n";

}

$catalog_name = shift unless $catalog_name;
if(@ARGV) {
	die <<EOF . "\n";
Extra command line arguments were found. (Did you specify
both --catalogname=name and one on the command line?)

$USAGE
EOF
}

unless($catalog_name) {
	die "$USAGE\n" if $Vend::MakeCat::Force;
	print <<EOF;

Select a short, mnemonic name for the catalog. This will be
used to set the defaults for naming the catalog, executable,
and directory, so you will have to type in this name frequently.

NOTE: This will be the name of 'vlink' or 'tlink', the link CGI
program. Depending on your CGI setup, it may also have the 
extension .cgi added.

If you are doing the demo for the first time, you might use "simple".

EOF
   $catalog_name = prompt ("Catalog name? ");
}

die "$USAGE\n" unless $catalog_name;

if($Conf{homedir}) {
	die "Directory set with --homedir=$Conf{homedir} is not a directory.\n"
		unless -d $Conf{homedir};
	$ENV{HOME} = $Conf{homedir};
}

if($Conf{'reference'}) {
	$Vend::MakeCat::Force =
	$Conf{nocopy}         =
	$Conf{norunning}      =
	$Conf{nocfg}          = 1;
	$Logfile = $Windows ?  'nul:'	: '/dev/null';
}

if ($Vend::MakeCat::Force) {
	my $file = $Logfile || 'makecat.log';
	open(LOGOUT, ">>$file") or die "write $file: $!\n";
	select LOGOUT;
}

$Configfile = "$0.cfg" unless $Configfile;
my $Servername;
my $Servers;
my $Done_defaults;

print <<EOF;
makecat -- MiniVend catalog installation program.

*** We will be making a catalog named '$catalog_name'. ***

EOF

READCONFIG: {
	my $cfgfile = "$catalog_name.cfg";

	last READCONFIG unless -f $cfgfile;
	open(READCONFIG, "< $cfgfile") or die "read $cfgfile: $!\n";

	while(<READCONFIG>) {
			next unless /^\s*[A-Z]\w*\s+\S/;
			chomp;
			($var, $val) = split " ", $_, 2;
			$ENV{"MVC_$var"} = $val;
	}
	close READCONFIG;
}

my $CgiDefault		= prefix('CGIDIR')			|| undef;
my $DocrootDefault	= prefix('DOCUMENTROOT')	|| undef;

if ($Windows) {
	$ENV{HOME}		= $ENV{HOME} || $ENV{MINIVEND_ROOT}
						|| prefix('VENDROOT') || '';
	$CgiDefault		=  prefix('CGIDIR') || 'c:/webshare/scripts';
	$CgiUrlDefault	=  prefix('CGIURL')  || '/scripts';
	$DocrootDefault =  prefix('DOCUMENTROOT') || 'c:/webshare/wwwroot';
}

$ENV{MVC_ENCRYPTOR} = prefix('ENCRYPTOR') || 'none';

FINDDOCROOT: {
	last FINDDOCROOT if defined $DocrootDefault;
	for(qw/www html web web-public public_html public-html/) {
		-d "$ENV{HOME}/$_" and -w _
			and $DocrootDefault = "$ENV{HOME}/$_"
		and last FINDDOCROOT;
	}

	for(	glob("$ENV{HOME}/*html*"),
			glob("$ENV{HOME}/*www*"),
			glob("$ENV{HOME}/*web*")
		)
	{
		-d $_ and -w _
			and $DocrootDefault = $_
		and last FINDDOCROOT;
	}

	for(
		 '/usr/local/etc/httpd/htdocs',
		 '/usr/local/apache/htdocs',
		 '/home/httpd/htdocs',
		 glob("/*/httpd/*docs"),
		 glob("/*web*/*docs"),
		 glob("/*/ns-home/docs"),
		 glob("/export/*/ns-home/http*/docs"),
		 glob("/usr/*/ns-home/http*/docs"),
		 glob("/home/*/ns-home/http*/docs")
		)
	{
		-d $_ and -w _
			and $DocrootDefault = $_
		and last FINDDOCROOT;
	}

	$DocrootDefault = '';
}

FINDCGIDIR: {
	last FINDCGIDIR if defined $CgiDefault;
	for(qw/cgi-bin cgi cgibin web-scripts scripts cgiwrap cgi-wrap/) {
		-d "$ENV{HOME}/$_" and -w _
			and $CgiDefault = "$ENV{HOME}/$_"
			and $CgiUrlDefault = "/$_"
		and last FINDCGIDIR;
	}

	for( glob("$ENV{HOME}/*cgi*"), glob("$ENV{HOME}/*scripts*") ) {
		-d $_ and -w _
			and $CgiDefault = $_
			and ($CgiUrlDefault = $_) =~ s:.*/:/:
		and last FINDCGIDIR;
	}

	for(
			 '/usr/local/etc/httpd/cgi-bin',
			 '/usr/local/apache/cgi-bin',
			 '/home/httpd/cgi-bin',
			 glob("/*web*/cgi*"),
			 glob("/*/ns-home/cgi*"),
			 glob("/export/*/ns-home/http*/cgi*"),
			 glob("/usr/*/ns-home/http*/cgi*"),
			 glob("/home/*/ns-home/http*/cgi*"),
		)
	{
		-d $_ and -w _
			and $CgiDefault = $_
			and ($CgiUrlDefault = $_) =~ s:.*/:/:
		and last FINDCGIDIR;
	}

	$CgiDefault = $CgiUrlDefault = '';
}

my $isroot = 0;
if ($< == 0) {
	$isroot = 1 unless $Windows;
}

$Conf{catalogname} = $catalog_name;

my %Initial;

my %IfRoot = (qw( permtype 1 minivenduser 1 minivendgroup 1 catuser 1));

my %Prefix = (
	vendroot     =>  $VendRoot,
	basedir      =>  sub {
							return prefix('basedir', 1) if prefix('basedir', 1);
							return "$Conf{vendroot}/catalogs"
								if $Windows;
							return "$ENV{HOME}/catalogs"
								unless $isroot;
							return "~/catalogs";
							},
	minivenduser =>  sub {  return 'everybody' if $Windows;
							get_id(); },
	minivendgroup=>  '',
    servername	 =>  $Config{myhostname},
    documentroot =>  $ENV{MVC_DOCUMENTROOT} || $DocrootDefault,
	cgidir       =>  $ENV{MVC_CGIDIR} || $CgiDefault,
	cgibase      =>  $ENV{MVC_CGIBASE} || $CgiUrlDefault,
	demotype     =>  $ENV{MVC_DEMOTYPE} || 'simple',
    catuser      =>  sub {
							$ENV{MVC_CATUSER} ||
							($isroot ? '' : $Conf{'minivenduser'})
						},
    mailorderto  => 
						sub {  return 'webmaster' if $Windows;
							if($Conf{servername} =~ s:(/~[^/]+)$:: ) {
								$Tilde = $1;
							}
    						$Conf{catuser} },
	catroot      =>   sub {
							my $dir = prefix('basedir') . "/" . $catalog_name;
							return $dir if $Windows;
							my $userdir = (getpwnam($Conf{catuser}))[7];
							$dir =~ s/^\~/$userdir/;
							return $dir;
							},
	aliases      =>  sub { return "/" . $catalog_name },
	cgiurl       =>  sub {
							return $ENV{MVC_CGIURL} if $ENV{MVC_CGIURL};
							my $url = '';
						 	if ($Windows) {
								$url .= $Conf{cgibase} . '/' .
										$catalog_name  . '.exe';
							}
							elsif ($Conf{cgibase} eq '') {
								$url =	$Tilde if defined $Tilde;
								$url .=	'/' .
										$catalog_name .
										'.cgi';
							}
							else {
								$url .= $Conf{cgibase} . '/' . $catalog_name;
							}
							$url;
						  },
	imagedir     => sub {
							return $ENV{MVC_IMAGEDIR} if $ENV{MVC_IMAGEDIR};
				 			return prefix('samplehtml') . '/' . 'images'
						},
	imageurl     => sub {
							my $url = '';
							return $ENV{MVC_IMAGEURL} if $ENV{MVC_IMAGEURL};
	                        if(defined $Tilde) {
								$url = $Tilde;
							}
							$url .= '/' . $catalog_name . '/' . 'images';
							$url;
						},
	samplehtml   =>  sub {
						return $ENV{MVC_SAMPLEHTML} if $ENV{MVC_SAMPLEHTML};
						$Conf{documentroot} . '/' . $catalog_name;
						},

);

sub strip_trailing_slash {
	my $url = shift;
	$url =~ s:/+\s*$::;
	return $url;
}

my %Postprocess = (

	cgibase			=> \&strip_trailing_slash,
	documentroot	=> \&strip_trailing_slash,
	imagedir		=> \&strip_trailing_slash,
	samplehtml		=> \&strip_trailing_slash,
	catroot			=> \&strip_trailing_slash,

);

sub prefix {
	my ($parm, $nodefault) = @_;
	$parm = lc $parm;
	return $Conf{$parm} if $Conf{$parm};
	return $ENV{"MVC_\U$parm"} if $ENV{"MVC_\U$parm"};
	return undef if $nodefault;
	if(ref $Prefix{$parm}) { 
		return &{ $Prefix{$parm} };
	}
	else {
		return $Prefix{$parm};
	}
}

my %History = (
    demotype =>  sub {
						return('simple', 'flycat');
					},

    documentroot =>  sub {
						if(defined $Servers->{$Servername}) {
							return $Servers->{$Servername}->{documentroot}
							 if defined $Servers->{$Servername}->{documentroot};
						}
						else {
							return (@_);
						}
					},

	cgidir       =>  sub {
						if(	defined $Servers->{$Servername} and
							$Servers->{$Servername}->{scriptalias}
							 ) {
							my @return;
							@return = values %{$Servers->{$Servername}{scriptalias}};
							unshift @return, $ENV{MVC_CGIDIR} if $ENV{MVC_CGIDIR};
							return @return;
						}
						return (@_);
					},

	cgibase      =>  sub {
						if(defined $Servers->{$Servername}) {
							my $ref = $Servers->{$Servername}{scriptalias};
							return @_ unless defined $ref;
							if($Conf{cgidir}) {
								my ($k,$v);
								for (keys %$ref) {
									$k = $_;
									$v = $ref->{$_};
									$v =~ s:[/\s]+$::;
									next unless $v eq $Conf{cgidir};
									$k =~ s:[/\s]+$::;
									return $k;
								}
							}
							else {
								return keys %$ref;
							}
						}
						return (@_);
					},
    mailorderto  =>	 sub {
						my(@return) = @_;
						if(defined $Servers->{$Servername}) {
							push(@return, $Servers->{$Servername}->{serveradmin})
							 if defined $Servers->{$Servername}->{serveradmin};
						}
						return @return;
					},
	imagedir     =>   sub {
						my (@return) = @_;
						if(defined $Servers->{$Servername}) {
							push (@return,
								values %{$Servers->{$Servername}->{alias}})
							 if defined $Servers->{$Servername}->{alias};
						}
						return @return;
					},

	permtype     =>   sub {
						my (@return) = @_;
						push(@return, 'G', 'M', 'U');
						return @return;
					},

	imageurl     =>   sub {
						my (@return) = @_;
						if(defined $Servers->{$Servername}) {
							push (@return,
								keys %{$Servers->{$Servername}->{alias}})
							 if defined $Servers->{$Servername}->{alias};
						}
						return @return;
					},

	catuser  =>   sub {
						return 'everybody' if $Windows;
						my @return = (@_);
						my $u;
						if(defined $Servers->{$Servername}) {
							$nogood = $Servers->{$Servername}->{'user'}
							 if defined $Servers->{$Servername}->{'user'};
						}
						my @out;
						while($u = getpwent) {
							next if $u eq 'root';
							next if $u eq $nogood;
							push(@out, $u);
						}
						return (@return, sort @out);
					},

	minivenduser  =>   sub {
						return 'everybody' if $Windows;
						my @return = (@_);
						my $u;
						if(defined $Servers->{$Servername}) {
							$nogood = $Servers->{$Servername}->{'user'}
							 if defined $Servers->{$Servername}->{'user'};
						}
						my @out;
						while($u = getpwent) {
							next if $u eq 'root';
							next if $u eq $nogood;
							push(@out, $u);
						}
						return (@return, sort @out);
					},

	minivendgroup  =>   sub {
						return 'nogroup' if $Windows;
						my (@return) = @_;
						my $u;
						if(defined $Servers->{$Servername}) {
							$nogood = $Servers->{$Servername}->{'group'}
							 if defined $Servers->{$Servername}->{'group'};
						}
						my @out;
						while($u = getgrent) {
							next if $u eq 'root';
							next if $u eq $nogood;
							push(@out, $u);
						}
						return (@return, sort @out);
					},

);

unless($isroot) {
	@Prefix{qw(minivenduser minivendgroup)} = get_ids();
	$Prefix{catuser} = $Prefix{minivenduser};
	$Prefix{basedir} = "$ENV{HOME}/catalogs";
}

my($ask,$param);

unless (-f $Configfile) {
	$Removeconfig = 1 if prefix('nocopy');
	open(CFGFILE, ">$Configfile")	or die "Can't write $Configfile: $!\n";
	while(<DATA>) {
		print CFGFILE $_;
	}
	close(CFGFILE)					or die "Can't close $Configfile: $!\n";
	print "\nNew configuration file '$Configfile'\n" ;
	$Reconfigure = 1;
}

$Cfg = new IniConf -file => $Configfile, -nocase => 1;

die "Can't read config file $Configfile: $!\n" unless defined $Cfg;
my @parms;

unless($Reconfigure or $Cfg->val('base', 'vendroot')) {
	$Reconfigure = 1;
}

CHECKEXIST: {

	if(grep /^catalog $catalog_name$/i, $Cfg->Sections()) {
		@parms = $Cfg->Parameters("catalog $catalog_name");
	}
	else {
		@parms = ();
	}
	unless(@parms) {
		@parms = $Cfg->Parameters('legalconfig');
		undef $Cfg;
		open(CFGFILE, ">>$Configfile")	or die "Can't write $Configfile: $!\n";
		print CFGFILE <<EOF;

# New catalog definition '$catalog_name' written by makecat
[catalog $catalog_name]
EOF
		for(@parms) {
			printf CFGFILE "%-19s =\n", $_;
		}
		close(CFGFILE)					or die "Can't close $Configfile: $!\n";
		$Cfg = new IniConf -file => $Configfile, -nocase => 1;
		die "Can't read config file $Configfile: $!\n" unless defined $Cfg;
		redo CHECKEXIST;
	}
		
}

my @conf;
my @Servers;

FINDCONF: {

	last FINDCONF if $Windows;
	last FINDCONF if $Vend::MakeCat::Force;
	last FINDCONF if $ENV{MVC_SERVERNAME};
	my $httpdconf;
	print <<EOF unless @conf;

If you are using the Apache or NCSA web server, MiniVend can set
some of the default parameters for you by reading the file.

If you use the Netscape Enterprise server or other non-NCSA HTTP server,
enter 'none' -- the information, if any, will not be useful.

EOF
	if (defined $Vend::MakeCat::Prompt_sub) {
		print <<EOF;

Try using the UP arrow at some of the prompts -- you have the
Term::ReadLine module installed, and MiniVend may find some
default values in your HTTP server configuration file.  You can
cycle among them with the UP and DOWN arrows.

EOF
	}
	else {
		print <<EOF;

This information may not be that useful to you, since you don't
have the Term::ReadLine module installed. If the default setting
presented is not correct, you will have to know the information.
C'est la vie.

EOF
	}

	if(@conf) {
		# Skip doing this again
	}
	elsif($param = prefix('serverconf') || $Cfg->val('base', 'serverconf')) {
		last FINDCONF if $param =~ /^none$/i;
		@conf = split /\s+/, $param;
	}
	else {
		if(findexe('locate')) {
			@conf = findfiles('httpd.conf');
			$Cfg->setval('base', 'serverconf', join(" ", @conf));
		}
		else {
			print <<EOF;

MiniVend can look for Apache or NCSA HTTP server configuration
files for you by a slow method (using the system find
command). This may take as many as several minutes.

EOF
			$ask = prompt("Find httpd.conf files? ", 'y');
			@conf = findfiles('httpd.conf') if $ask =~ /^\s*y/i;
			$Cfg->setval('base', 'serverconf', join(" ", @conf));
		}
	}
	sethistory(@conf);
	$httpdconf = prompt("Enter path to httpd.conf file: ", $conf[0]);

	last FINDCONF if $httpdconf =~ /^none$/i;
	if($httpdconf) {
		$Servers = conf_parse_http($httpdconf);
		unless (defined $Servers) {
			print <<EOF;

The file '$httpdconf' was not parsed properly.

Error: $Vend::MakeCat::Error

You can edit the file and try again if you wish. (Don't worry if it
didn't work, you will have the opportunity to enter all of the proper
information manually.)

EOF
			$ask = prompt("Try again? ", 'y');
			last FINDCONF if $ask =~ /^\s*n/i;
			redo FINDCONF;
		}
		else {
			@Servers = sort keys %{$Servers};
		}
	}
}

##############
SETDEFAULTS: {
	last SETDEFAULTS if $Done_defaults;
	$Done_defaults = 1;
	unless ($Reconfigure) {
		my @parms = $Cfg->Parameters('base');
		for(@parms) {
			next if $Conf{$_} = prefix($_, 1);
			$Conf{$_} = $Cfg->val('base', $_) || undef;
		}
		last SETDEFAULTS;
	}

	PERMS: {

		unless ($isroot) {
			print <<EOF unless $Windows;

This demo configuration sometimes requires root permissions,
depending on your ISP.  It needs to copy a few files to the CGI
and HTML directories.

You must either have your own CGI directory, or be able to run
a CGI with an extension like '.cgi'.

If you will be operating only on directories owned by the
user you are running this as, you will be able to do
everything.

EOF

		}
		else {
			last PERMS if prefix('permtype', 1);
			print <<EOF;

You are the super-user. You can set the permissions to GROUP, MULTIPLE
GROUP, or USER mode for catalogs on this server.

MULTIPLE GROUP or GROUP is appropriate when multiple users will be running
catalogs on the same server.

MULTIPLE GROUP is the best way. Put each user in their own group, and
place the MiniVend user in that group.  In this mode, only the user of
each catalog and the MiniVend server may read database and error files --
files that may contain sensitive information. If the user's default UMASK
is 2 on a UNIX system, then this the most troublefree mode of operation.

GROUP mode causes all files to be owned by the MiniVend user, with group
ownership set to the group the user belongs to. This allows the MiniVend
user and each individual user to read and write the files associated with
a catalog, but others in that group may read files from a catalog. This
may not be secure, and may cause problems when the user creates new
files that must be read/write to the MiniVend user.

USER mode is appropriate when only one user owns all catalogs running
on this server, and the MiniVend daemon is run by the same user.

  M) MULTIPLE GROUP
  G) GROUP
  U) USER

EOF
			sethistory("MULTIPLE GROUP", "GROUP", "USER");
			$Conf{permtype} = prompt("Permission Mode? ", "M");
			unless($Conf{permtype} =~ s/^\s*([mgu]).*/uc $1/ie) {
				print "Must be one of M(ULTIPLE), G(ROUP), or U(SER).\n";
				redo PERMS;
			}
			$Cfg->setval('base', 'permtype', $Conf{permtype});

		}

	} # END PERMS

	print <<EOF;

Since there was no master configuration file, we will ask
some questions to help set initial defaults for making this
and future catalogs.

EOF


	##############
	DEFSERVER: {

	last DEFSERVER unless @Servers;

	print <<EOF if defined $Vend::MakeCat::Prompt_sub;

MiniVend can set many of the defaults for you if it knows the server
name that is going to be used.

Enter the default server that should be used. This is only a default, to
determine the *first* one that will be looked at -- you will be given
a choice of all available servers.

There is a "history" mechanism that will allow you to use the up
and down arrows on your terminal (assuming you have a standard terminal)
to cycle between possible choices.  This should contain the available
servers.

EOF

	sethistory(@Servers);
	$Conf{servername} = prompt('Default server? ', $Servers[0]);
	$Servername = $Conf{servername};
	$Cfg->setval('base', 'servername', $Servername);

	}
	############

	my @ask = $Cfg->val('global', 'askbase');

	for('cgidir') {
		next if $Conf{$_};
		print <<EOF;


We need to know if all of your CGI programs are run as a file ending
in .cgi or some other extension, or whether you have your own personal
CGI directory.

EOF
		$ask = prompt ("Do you have a CGI directory? ", 'y');
		last if is_yes($ask);
		$Prefix{cgidir} = prefix('documentroot');
	}

	my ($p, $i);

	for ($i = 0; $i < scalar @ask; $i++) {
		$p = $ask[$i];
		my $hval;
		$hval = prefix($p);
		if (defined $History{$p}) {
			@history = &{$History{$p}}(prefix($p));
			$hval = $history[0];
			sethistory(@history);
		}
		$val = prefix($p, 1) || $Cfg->val("base", $p) || $hval;
		print "\n";
		print description($p);
		print "\n\n";
		my $msg = pretty($p) . "? ";
		$Conf{$p} = prompt ($msg, $val);
		if($Conf{$p} eq '@') {
			$i--;
			$i = 0 if $i < 0;
			redo;
		}
		if(defined $Postprocess{$p}) {
			$Conf{$p} = &{$Postprocess{$p}}($Conf{$p});
		}
	}

	for(@ask) {
		$Cfg->setval('base', $_, $Conf{$_});
	}

	$Cfg->WriteConfig("$Configfile.new")
		and rename "$Configfile.new", $Configfile;

	print "#########     END BASE CONFIGURATION      #########\n\n";

}
#############

	my $serv = prefix('servername') || 'www.yourdomain'; 

# Set server

print "######### BEGINNING CATALOG CONFIGURATION #########\n";
print <<EOF if defined $Vend::MakeCat::Prompt_sub;

During many of the following operations, defaults are placed in
a buffer for you.  You may use the up and down arrows to toggle
between the defaults.

If you made a mistake on a *previous* entry and realize that
in a later one, if you enter ONLY an @ sign and press return you
should be returned to the previous step.

EOF
SETSERVER: {
	sethistory(@Servers);
	print description('servername');
 	$Servername = prefix('servername', 1)  			|| 
				  $Cfg->val('base', 'servername')	||
				  prefix('servername');
	$Servername =
		$Conf{servername} =
			prompt("Server name? ", ($Servername || $Servers[0]));
	$Cfg->setval("catalog $catalog_name", 'servername', $Conf{servername});
}

	@ask = $Cfg->val('global', 'askconfig');


	for ($i = 0; $i < scalar @ask; $i++) {
		$p = $ask[$i];
		if (defined $History{$p}) {
			@history = &{$History{$p}}(prefix($p));
			sethistory(@history);
			$val =	prefix($p,1)							||
					$Cfg->val("catalog $catalog_name", $p)	||
					$history[0]								||
					prefix($p);
		}
		else {
			$val =	prefix($p,1)							||
					$Cfg->val("catalog $catalog_name", $p)	||
					prefix($p);
		}
		if (! $isroot and defined $IfRoot{$p}) {
			$Conf{$p} = $val;
			next;
		}
		print "\n";
		print description($p);
		print "\n\n";
		my $msg = pretty($p) . "? ";
		$Conf{$p} = prompt ($msg, $val);
		if($Conf{$p} eq '@') {
			$Conf{$p} = $val;
			$i--;
			$i = 0 if $i < 0;
			redo;
		}
		$Cfg->setval("catalog $catalog_name", $p, $Conf{$p});
	}

if($Removeconfig) {
	unlink $Configfile;
}
elsif ( ! prefix('nocopy') ) {
	$Cfg->WriteConfig("$Configfile.new")
		and rename "$Configfile.new", $Configfile;
}

undef $Cfg;

# Try and get the URL we will use to access the catalog
GUESS: {

 	if( $Conf{samplehtml} =~ /^\s*none\s*$/i ) {
		$Conf{sampleurl} = 'NONE';
		last GUESS;
	}

	my $tempurl;
    $guessdir = $Conf{samplehtml};

    unless( $guessdir =~ s/^$Conf{documentroot}// ) {
        print <<EOF;

The specified HTML directory, $Conf{samplehtml},
is not a subdirectory of DocumentRoot. This will make it
hard for us to guess the URL needed to access pages from
the catalog. Please re-specify your HTML document root.

# The base directory for HTML for the catalog, the DocumentRoot.
# This is a file name, not a URL.

EOF
        $val = '';
		my $msg = pretty('documentroot');
        $Conf{documentroot} = prompt ("\n$msg? ", '');
        redo GUESS;
    }

    $guessdir =~ s:^/+::;
    $guessdir = "$Tilde/$guessdir" if defined $Tilde;
    $guessdir =~ s:^/+::;
    $tempurl = "http://$Conf{servername}/$guessdir";
    if (defined $Conf{sampleurl} and $Conf{sampleurl} ne $tempurl) {
		print <<EOF;

We were given a previous value for the URL that will run the catalog
(from the catalog configuration file $Configfile):

    $Conf{sampleurl}

This conflicts with what we guess from what you have just
entered:

   	$tempurl

EOF

	$tempurl  = prompt ("\nPlease re-enter or confirm: ",
						"http://$Conf{servername}/$guessdir");

	}

	$Conf{sampleurl} = $tempurl;

}

$mvuid = $Windows ? 'everybody' : (getpwnam($Conf{minivenduser}))[2];
unless (defined $mvuid) {
	die "$Conf{minivenduser} is not a valid user name on this machine.\n";
}

# Fix supplied by Paul V. Shevtsov
if($isroot) {
	chown ($mvuid, $mvgid, $Configfile)
		or warn "\nCouldn't set ownership of $Configfile: $!\n";
}

if ($Conf{minivendgroup}) {
	$mvgid = $Windows ? 'nogroup' : getgrnam($Conf{minivendgroup});
	unless (defined $mvgid) {
		die "$Conf{minivendgroup} is not a valid group name on this machine.\n";
	}
}
else {
	$mvgid = $Windows ? 'nogroup' : (getpwnam($Conf{minivenduser}))[3];
}

if($Windows) {
	($catuid,$catgid) = ('everybody', 'nogroup');
}
else {
	($catuid,$catgid) = (getpwnam($Conf{catuser}))[2,3];
	unless (defined $catuid) {
		die "$Conf{catuser} is not a valid user name on this machine.\n";
	}
}

# Find the perl path
$Conf{'perl'} = $Config{perlpath};

# Now change to the directory defined as VendRoot
chdir $Conf{vendroot}
	or die "Couldn't change directory to $Conf{vendroot}: $!\n";

$warn = 0;
$msg = q# supposed to be a directory, not a file. Can't continue.#;
for ( $Conf{catroot}, $Conf{documentroot}, $Conf{basedir},
	$Conf{samplehtml}, $Conf{imagedir} ) {
	next unless -f $_;
	print "$_ $msg\n";
	$warn++;
}
die "\n" if $warn;

my $prog;
use vars qw/$CGIwrap/;

SETLINKMODE: {
	if($prog = prefix('linkprogram')) {
		last SETLINKMODE;
	}
	if ($Windows) {
		$Conf{linkmode} = 'INET';
		$prog = "$VendRoot/bin/tlink.exe";
		last SETLINKMODE;
	}
	print <<EOF;

MiniVend can use either UNIX- or internet-domain sockets.
Most ISPs would prefer UNIX mode, and it is more secure.

If you already have a program there, or use a common program
and the FullURL directive, select NONE. You will then need
to copy the program by hand or otherwise ensure its presence.

EOF
	print "(You can use the up/down arrows to toggle).\n"
		if $Vend::MakeCat::Prompt_sub;

	sethistory("NONE", "UNIX", "INET");

	unless ( $default = prefix('linkmode') ) {
		$default = ($Config{osname} =~ /bsd/i and $Config{osvers} gt '3')
				? 'INET' : 'UNIX';
	}
	
	$ask = prompt("INET or UNIX mode? ", $default);

	$prog = "$VendRoot/bin/vlink";

	if($ask =~ /^\s*i/i) {
		$prog = "$VendRoot/bin/tlink";
		$Inetmode = 1;
	}
	elsif($ask =~ /^\s*n/i) {
		$prog = "NONE";
	}
	else {
		$ask = prompt("Do you use CGIWRAP? ", 'n');
		$CGIwrap = $ask =~ /^\s*y/i;
	}

}

FINDPROG: {
	last FINDPROG if $prog eq 'NONE';
	unless (-x "$prog" and -f _) {
		my @history = ();
		$prog =~ s:.*bin/::;
		print <<EOF;
	Couldn't find the executable file '$prog'.

	Please give the complete path to the link program.

EOF
		if($Config{osname} =~ /win32/i) {
			# do nothing
		}
		elsif(findexe('locate')) {
			@history = findfiles($prog);
		}
		else {
			@history = `find . -name \*[vt]link\* -print`;
			chomp @history;
		}
		sethistory(@history);
		$prog = prompt("Link program? ", $history[0]);
	}
}

umask(022) unless $Conf{noumask};

$warn = 0;
print do_msg("Checking directories");

$msg = q#directory exists!#;
for($Conf{catroot}, $Conf{samplehtml}) {
	next unless -d $_;
	print "\n$_: $msg\n";
	$warn++;
}

if($warn) {
	$ask = prompt "The above directories already exist. Overwrite files? ", 'n';
	unless($Vend::MakeCat::Force) {
		exit 2 unless is_yes($ask);
	}
}

$warn = 0;
for($Conf{documentroot}, $Conf{basedir}) {
	next if /^\s*none\s*$/i;
	next if -d $_;
	$warn++;
}

for($Conf{catroot}, $Conf{samplehtml}, $Conf{imagedir}) {
	next if /^\s*none\s*$/i;
	next if -d $_;
	$warn++;
}

if($warn) {
	for(qw(catroot samplehtml imagedir)) {
		$dir = $Conf{$_};

		# Allow nocopy
		next if $dir =~ /^\s*none\s*$/i;

		(warn "\n$_ is empty, skipping.\n", next)
			unless $dir =~ /\S/;
		unless(-d $dir or prefix('nocopy') ) {
			File::Path::mkpath([$dir], 0, 0775)
				or die "Couldn't make directory $dir: $!\n";
		}
	}
}

for(qw(catroot samplehtml imagedir)) {
	$dir = $Conf{$_};

	# Allow nocopy
	next if $dir =~ /^\s*none\s*$/i;

	if (prefix('nocopy')) {
		next if -w $dir;
		my $parent = $dir;
		do {
			$parent =~ s:/[^/]+$::;
		} until ! $parent or -d $parent;
		warn "Directory $dir (or parents) not writable, could be problems.\n"
			unless -w $dir || -w $parent;
		next;
	}

	die "Directory $dir not writable, can't continue.\n"
		unless -w $dir or $dir =~ /^\s*none\s*$/i;
	set_owner($dir);
}
print "done.\n";

# Now change to the directory defined as VendRoot if the checks
# have left us elsewhere
chdir $Conf{vendroot}
	or die "Couldn't change directory to $Conf{vendroot}: $!\n";

print do_msg("Copying demo files");
unless (-d $Conf{'demotype'}) {
	print "No $Conf{vendroot}/$Conf{'demotype'} directory is present,\n";
	$dir = prompt("where should the files come from? ", '');
}
else {
	$dir = $Conf{'demotype'};
}

# Do some additional configuration if the additional_fields
# file is found

ADDITIONAL: {
	last ADDITIONAL unless -f "$dir/config/additional_fields";
	open(ADDL, "< $dir/config/additional_fields") 
		or last ADDITIONAL;
	my %help;
	local ($/) = "";
	if(open(ADDLHELP, "< $dir/config/additional_help") ) {
		while(<ADDLHELP>) {
			my($parm,$help) = split /\n/, $_, 2;
			$help =~ s/\s*$/\n\n/;
			$help{uc $parm} = $help;
		}
		close ADDLHELP;
	}
	print "found more to ask.\n\n";
	while(<ADDL>) {
		s/\s+$//;
		s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
		my ($var, $prompt, $default) = split /\n/, $_, 3;
		$var =~ s/\s+//g;
		$var = lc $var;
		my $ucvar = uc $var;
		if (defined $help{$ucvar}) {
			$help{$ucvar} =~ s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
			print $help{$ucvar};
		}
		$Conf{$var} = prompt( do_msg("$prompt: ", 40),
							 (delete $ENV{"MVC_$ucvar"} || $Conf{$var} || $default) ) ;
	}
	close ADDL;
}

PRECMD: {
	last PRECMD unless -f "$dir/config/precopy_commands";
	open(ADDL, "< $dir/config/precopy_commands") 
		or last PRECMD;
	print "\nFound system commands to run.\n\n";
	local ($/) = "";
	while(<ADDL>) {
		s/\s+$//;
		s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
		my ($command, $prompt) = split /\n/, $_, 2;
		$command =~ s/^\s+//;
		$command =~ s/\s+$//;
		print $prompt;
		my $ans = prompt( do_msg(qq{run "$command"? }, 40), 'y' );
		if($ans =~ /^\s*y/i) {
			system $command;
			if($?) {
				print "\nCommand returned error code " . ($? >> 8) . ": $!\n";
			}
		}
		else {
			print "\nskipping '$command'\n";
		}
	}
	close ADDL;
}

# Here we actually do the file copy unless --nocopy is set
DOCOPY: {

	if (prefix('nocopy')) {
		print "not copying.\n";
		last DOCOPY;
	}

	chdir $dir || die "Couldn't change directory to $dir: $!\n";

	# This is what we used to do
	#system "tar -cf - * | (cd $Conf{catroot}; tar -xf -)";

	umask(07) unless $Conf{noumask};

	eval {
		copy_current_to_dir($Conf{catroot});
	};

	umask(022) unless $Conf{noumask};

	if($@) {
		die <<EOF . "\n";
There were errors in copying the demo files.  Cannot
continue.  Check to see if permissions are correct.

EOF
	}

	unless($prog eq 'NONE') {
		File::Copy::copy( $prog, "$Conf{catroot}/executable")
			or die "Couldn't copy link program from $prog: $!\n";
	}

	print "done.\n";

chdir $Conf{catroot} 
 	|| die "Couldn't change directory to $Conf{catroot}: $!\n";

%Xfile = ( qw(
                reconfig        1
                report_problem  1
            ) );

my ($umode, $gmode);

if($Conf{permtype} =~ /^[mg]/i) {
	$umode = 0; $gmode = 1;
}
else {
	$umode = 1; $gmode = 0;
}


%MacroString = qw(

    __MVC_CGIURL        cgiurl
    __MVC_CGIDIR        cgidir
    __MVC_MAILORDERTO   mailorderto
    __MVC_IMAGEURL      imageurl
    __MVC_SAMPLEURL     sampleurl
    __MVC_SERVERNAME    servername

);

sub set_owner {
	my($file) = @_;
	return unless $isroot;
	my ($user, $group) = ($mvuid, $mvgid);
	if($Conf{permtype} =~ /^m/i) { $user = $catuid; $group = $catgid; }
	elsif($Conf{permtype} =~ /^g/i) { $group = $catgid; }
	chown($user, $group, $file)
		or die "Couldn't set ownership to UID=$user GID=$group for $file: $!\n";
}

sub substitute {
	my($parm,$new) = @_;

	return $ENV{"MVC_$parm"} if defined $ENV{"MVC_$parm"};

	if($new) {
		return $Conf{lc $parm} || '';
	}
	else {
		return $Conf{$MacroString{"__MVC_$parm"}}
			if defined $MacroString{"__MVC_$parm"};
	}
	return "__MVC_${parm}__";
}

sub wanted {

	my ($mode,$file);
	$file = $_;
	my $name = $File::Find::name;
	EDIT: {
     	return if        (-l $file);

		# Ugly, but necessary on BSDI
		$File::Find::prune = 1 if -f _;

        last EDIT unless (-f _);
        last EDIT unless (-T _);
  
		open(IN, "< $file") or die "Couldn't open $file: $!\n";
		open(OUT, ">$file.new") or die "Couldn't create $name.new: $!\n";
		while(<IN>) {
			s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
			print OUT $_;
		}
		close OUT;
		close IN;
		unlink ($file)
			or die "Couldn't unlink $name: $!\n";
		rename ("$file.new", $file)
			or die "Couldn't rename $name.new to $name: $!\n";
	}
	if($Windows) {
		# None of this stuff applies for Windows, I don't think.
		# Put Win-specific stuff here.
	}
	else {
		set_owner($file);
		$mode = (stat($file))[2];
		if ($Xfile{$file}) {
			$mode |= 0550;
		}
		else {
			$mode |= 060 if $gmode;
			$mode |= 02010 if $gmode and -d $file;
		}
		chmod ($mode, $file)
			or die "\nCouldn't set permissions on $name: $!\n";
	}
}
	
	$File::Find::dont_use_nlink = 1;
	set_owner($Conf{catroot});
	File::Find::find(\&wanted, $Conf{catroot});

	$cginame = $Conf{cgiurl};
	$cginame =~ s:.*/::;
	$Conf{cgifile} = $cginame = "$Conf{cgidir}/$cginame";
	
	umask(022) unless $Conf{noumask};

	unless ($prog eq 'NONE') {
		my $ask_cgi = 'y';
		print do_msg("Moving link program to $cginame");
		if(-f $cginame) {
			$ask_cgi = prompt ("$cginame exists, overwrite? ", 'n');
		}

		if(is_yes($ask_cgi)) {
			File::Copy::copy("$Conf{catroot}/executable", $cginame)
				or die
				"\nCouldn't copy link executable from $prog to $cginame: $!\n";
			chmod 0755, $cginame   
					or die "\nCouldn't make $cginame executable: $!\n";
			unlink "$Conf{catroot}/executable";
		}

		if($isroot) {
			chown ($mvuid, $mvgid, $cginame)
				or die "\nCouldn't set ownership of $cginame: $!\n";
		}

		unless ($Windows or $Inetmode or $CGIwrap) {
			unless ($isroot or can_do_suid()) {
				print <<EOF;

My test indicates you can't change vlink to SUID mode.
This will cause big problems -- you can make MiniVend work anyway
by changing the ReadPermission and WritePermission directives in
all of your catalogs to 'world', but this is not secure. If you can,
you should run this as root, or su to root and do:

	chmod 4755 $cginame

EOF
				$ask = prompt("Continue? ", 'n');
				unless($Vend::MakeCat::Force) {
					exit 2 unless is_yes($ask);
				}
			}

			chmod 04755, $cginame
				or warn "\nCouldn't set permissions on $cginame: $!\n";
		}

		print "done.\n";
	}

	my $chg_to_catuser = sub {
							next if -l $_;
							$File::Find::prune = 1 if -f _;
							my $mode = (stat(_))[2];
							$mode |= 044;
							$mode |= 011 if -d $_;
							chmod( $mode, $_)
								or die "\nchmod $_ to $mode: $!\n";
							chown($catuid, $catgid, $_)
								or die "\nchown $_: $!\n";
							
						 };
	my $ok = 0;
	unless($Conf{samplehtml} eq 'NONE') {
		print do_msg("Moving HTML files to $Conf{samplehtml}");
		eval {
			chdir 'html' or ++$ok and die "\nchdir html: $!\n";
			copy_current_to_dir($Conf{samplehtml});
			chdir '..';
			File::Path::rmtree('html'); 
		};


		if($@ and !$ok) {
			die "\nCouldn't move HTML files to $Conf{samplehtml}: $@\n";
		}
		elsif ($ok) {
			warn "\nHTML dir copy error: $!\nTrying to continue.\n";
		}
		else {
			File::Find::find( $chg_to_catuser, $Conf{samplehtml})
				if $isroot;
		}


		print "done.\n";
	}

	unless($Conf{imagedir} eq 'NONE') {
		print do_msg("Moving image files to $Conf{imagedir}");
		eval {
			chdir 'images' or ++$ok and die "chdir images: $!\n";
			copy_current_to_dir($Conf{imagedir});
			chdir '..';
			File::Path::rmtree('images');
		};
			
		if($@ and !$ok) {
			die "\nCouldn't move image files $Conf{imagedir}: $@\n";
		}   
		elsif ($ok) {
			warn "\nImage dir copy error: $!\nTrying to continue.\n";
		}
		else {
			File::Find::find($chg_to_catuser, $Conf{imagedir})
				if $isroot;
		}
 
		print "done.\n";
	}

	chdir $Conf{vendroot}
		or die "\nCouldn't change directory to $VendRoot: $!\n";

	my $pidfile = 'etc/minivend.pid';
	PID: {
		local ($/);
		open(PID,"+<$pidfile") or last PID;

		# If we get lock we are not running
		unless($Windows) {
			lockfile(\*PID,1,0)  and last PID;
		}
		
		$pid = <PID>;
		$pid =~ /(\d+)/;
		$pid = $1;
	}

}

POSTCMD: {
	last POSTCMD unless -f "$dir/config/postcopy_commands";
	open(ADDL, "< $dir/config/postcopy_commands") 
		or last POSTCMD;
	print "\nFound additional system commands to run.\n\n";
	local ($/) = "";
	while(<ADDL>) {
		s/\s+$//;
		s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
		my ($command, $prompt) = split /\n/, $_, 2;
		$command =~ s/^\s+//;
		$command =~ s/\s+$//;
		print $prompt;
		my $ans = prompt( do_msg(qq{run "$command"? }, 40), 'y' );
		if($ans =~ /^\s*y/i) {
			system $command;
			if($?) {
				print "\nCommand returned error code " . ($? >> 8) . ": $!\n";
			}
		}
		else {
			print "\nskipping '$command'\n";
		}
	}
	close ADDL;
}
	my $add;

	umask(07) unless $Conf{noumask};

	$add = prefix('nocfg') ? 'n' : 'y';
	$yes = prompt "Add catalog to minivend.cfg? ", $add;

	$add = prefix('norunning') ? 'n' : 'y';

	if($pid) {
		$add_to_running = prompt "Add catalog to server running on PID $pid? ", $add;
		$add_to_running = is_yes($add_to_running);
	}

	my $full = '';
	my $newcfgline;

	$newcfgline = sprintf "%-10s %s %s %s %s\n", 'Catalog',
				$catalog_name, $Conf{catroot}, $full . $Conf{cgiurl}, $Conf{aliases};

	if( is_yes($yes) ) {
		my ($newcfgline, $mark, @out);
		my ($tmpfile) = "minivend.cfg.$$";
		if (-f 'minivend.cfg') {
			rename ("minivend.cfg", $tmpfile)
				or die "\nCouldn't rename minivend.cfg: $!\n";
		}
		else {
			File::Copy::copy('minivend.cfg.dist', $tmpfile);
		}
		open(CFG, "< $tmpfile")
			or die "\nCouldn't open $tmpfile: $!\n";
		while(<CFG>) {
			$mark = $. if /^#?catalog\s+/i;
			print "\nDeleting old configuration $catalog_name.\n"
				if s/^(catalog\s+$catalog_name\s+)/#$1/io;
			$full = is_yes($1)
				if /^\s*fullurl\s+(.*)/i;
			push @out, $_;
		}
		close CFG;

		if($full) {
			$full = $Conf{servername};
		}
		open(NEWCFG, ">minivend.cfg")
			or die "\nCouldn't write minivend.cfg: $!\n";

		$newcfgline = sprintf "%-13s %s %s %s %s\n", 'Catalog',
				$catalog_name, $Conf{catroot}, $full . $Conf{cgiurl}, $Conf{aliases};
		if (defined $mark) {
			print NEWCFG @out[0..$mark-1];
			print NEWCFG $newcfgline;
			print NEWCFG @out[$mark..$#out];
		}
		else { 
			$newconfig = 1;
			print "\nNo catalog previously defined. Adding $catalog_name at top.\n";
			print NEWCFG $newcfgline;
			print NEWCFG @out;
		}
		close NEWCFG || die "close: $!\n";
		unlink $tmpfile;
		if($isroot) {
			chown ($mvuid, $mvgid, 'minivend.cfg')
				or warn "Couldn't set ownership of 'minivend.cfg': $!\n";
		}
	}
	else {
		print <<EOF;
You will need to add the following line to your minivend.cfg file
to activate the catalog.

$newcfgline

EOF
	}

	$newcfgline = sprintf "%-13s %s %s %s %s\n", 'Catalog',
				$catalog_name, $Conf{catroot}, $full . $Conf{cgiurl}, $Conf{aliases};

	if($add_to_running) {
		my $fn = 'etc/restart';
		open(RESTART, ">>$fn") or
				die "Couldn't write $fn to add catalog: $!\n";
		Vend::Util::lockfile(\*RESTART, 1, 1) 	or die "lock $fn: $!\n";
		printf RESTART $newcfgline;
		Vend::Util::unlockfile(\*RESTART) 		or die "unlock $fn: $!\n";
		close RESTART;
		if($isroot) {
			chown ($mvuid, $mvgid, $fn)
				or warn "\nCouldn't set ownership of $fn: $!\n";
		}
		unless ($Windows) {
			kill 'HUP', $pid;
			sleep 1;
		}
		$fn = 'etc/reconfig';
		open(RESTART, ">>$fn") or
				die "Couldn't write $fn to add catalog: $!\n";
		Vend::Util::lockfile(\*RESTART, 1, 1) 	or die "lock $fn: $!\n";
		printf RESTART $full . $Conf{cgiurl} . "\n";
		if($isroot) {
			chown ($mvuid, $mvgid, $fn)
				or warn "\nCouldn't set ownership of $fn: $!\n";
		}
		Vend::Util::unlockfile(\*RESTART) 		or die "unlock $fn: $!\n";
		close RESTART;
		unless ($Windows) {
			kill 'HUP', $pid;
		}
	}
	
    my $start_string = $Windows	? "$Conf{vendroot}\\minivend"
								: "$Conf{vendroot}/bin/restart";

	print <<EOF;

Done with installation. If my reading of your input is correct, you
should be able to access the demo catalog with the following URL:

	$Conf{sampleurl}

In any case, you should get direct access at:

	http://$Conf{servername}$Conf{cgiurl}

That is, after you START or RESTART the MiniVend server.  8-)
It is best done with:

	$start_string

EOF
	CHECKEXPIRE: {
		my $dbm;
		my $message;
		eval { require GDBM_File; $dbm = 1; };
		eval { require DB_File;   $dbm = 1; };

		if(! $Windows and $dbm) {

			print <<EOF;
For session expiration, you might want to place a line like this in your
crontab:

44 4 * * * $Conf{vendroot}/bin/expireall -r

It will prevent the session databases from getting too large.

EOF

		}
		else {
			print <<EOF;
Remember to expire your session databases on a regular basis (see
the documentation for details).

EOF
		}
	}

	print "Good luck with MiniVend!\n" if defined $newconfig;

	if($Conf{'reference'}) {
		$Data::Dumper::Terse = 1;
		$Data::Dumper::Indent = 3;
		print STDOUT Vend::Util::uneval(\%Conf);
	}

__END__

# Sample catalog definition
[catalog sample]
basedir      =
catroot      =
catuser      =
cgibase      =
cgibin       =
cgidir       =
cgiurl       =
demotype     = sample
documentroot =
imagedir     =
imageurl     =
mailorderto  =
minivendgroup=
minivenduser =
samplehtml   =
sampleurl    =
servername   =
vendroot     =

# Simple catalog definition
[catalog simple]
basedir      =
catroot      =
catuser      =
cgibase      =
cgibin       =
cgidir       =
cgiurl       =
demotype     = simple
documentroot =
imagedir     =
imageurl     =
mailorderto  =
minivendgroup=
minivenduser =
samplehtml   =
sampleurl    = 
servername   =
vendroot     =

[base]
permtype=
basedir=
cgidir=
cgibase=
documentroot=
minivendgroup=
minivenduser=
serverconf=
servername=
vendroot=

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# DO NOT EDIT BELOW HERE
#
# These are global parameters used by the program
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

[global]
# 
# All params allowed
#
params=<<EOF
aliases
basedir
catroot
catuser
cgibase
cgibin     
cgidir
cgiurl
demotype
documentroot
imagedir
imageurl
mailorderto
minivendgroup
minivenduser
samplehtml
sampleurl
serverconf
servername
vendroot
EOF

catparams=<<EOF
aliases
catroot
catuser
cgidir
cgiurl
demotype
documentroot
imagedir
imageurl
mailorderto
minivendgroup
minivenduser
samplehtml
sampleurl
servername
EOF

# 
# Default (base) parameters to ask about, in order
#
askbase=<<EOF
cgidir
cgibase
documentroot
vendroot
basedir
minivenduser
EOF

# 
# Catalog parameters to ask about, in order
#
askconfig=<<EOF
demotype
permtype
minivenduser
catuser
minivendgroup
mailorderto
catroot
cgidir
cgiurl
aliases
documentroot
samplehtml
imagedir
imageurl
EOF

######## END GLOBAL SECTION ########

# Simple test to make sure legal for config file
[legalconfig]
aliases=1
cgidir=1
cgiurl=1
catuser=1
demotype=1
imagedir=1
imageurl=1
mailorderto=1
minivenduser=1
minivendgroup=1
permtype=1
samplehtml=1
sampleurl=1
servername=1
catroot=1

# Simple test to make sure legal for base file
[legalbase]
basedir=1
cgidir=1
cgibase=1
documentroot=1
minivendgroup=1
minivenduser=1
serverconf=1
servername=1
vendroot=1
