1#!/usr/bin/perl
2##!~_~perlpath~_~
3#
4# Interchange catalog configurator
5#
6# $Id: makecat.PL,v 2.27 2007-08-09 13:40:57 pajamian Exp $
7#
8# Copyright (C) 2002-2007 Interchange Development Group
9# Copyright (C) 1996-2002 Red Hat, Inc.
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public
22# License along with this program; if not, write to the Free
23# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
24# MA  02110-1301  USA.
25
26use lib '/usr/local/interchange/lib';
27#use lib '~_~INSTALLPRIVLIB~_~';
28use lib '/usr/local/interchange';
29#use lib '~_~INSTALLARCHLIB~_~';
30
31#use strict;
32use Config;
33use File::Find;
34use File::Copy;
35use File::Path;
36use Sys::Hostname;
37use Vend::MakeCat;
38use Vend::Util;
39use Getopt::Long;
40use IniConf;
41use Cwd;
42use vars qw/$CGIwrap/;
43
44Getopt::Long::config(qw/permute/);
45#Getopt::Long::config(qw/debug/);
46
47BEGIN {
48
49	($Global::VendRoot = $ENV{MINIVEND_ROOT})
50		if defined $ENV{MINIVEND_ROOT};
51	$Global::VendRoot = $Global::VendRoot || '/usr/local/interchange';
52#	$Global::VendRoot = $Global::VendRoot || '~_~INSTALLARCHLIB~_~';
53
54	$Global::ProgRoot = '/usr/local/interchange';
55#	$Global::ProgRoot = '~_~INSTALLARCHLIB~_~';
56
57	if(-f "$Global::VendRoot/interchange.cfg") {
58		$Global::ExeName = 'interchange';
59		$Global::ConfigFile = 'interchange.cfg';
60	}
61	elsif(-f "$Global::VendRoot/minivend.cfg") {
62		$Global::ExeName = 'minivend';
63		$Global::ConfigFile = 'minivend.cfg';
64	}
65	else {
66		$Global::ExeName = 'interchange';
67		$Global::ConfigFile = 'interchange.cfg';
68	}
69
70}
71
72### END CONFIGURATION VARIABLES
73
74$| = 1; select STDERR;
75$| = 1; select STDOUT;
76
77my $Removeconfig;
78my $Reconfigure = 0;
79my $Configfile;
80my $Cfg;
81my $Logfile = 'makecat.log';
82my $catalog_name;
83use vars qw( %Conf );
84my $Inetmode;
85my $Windows;
86my $pid;
87$Windows = 1 if $Config{osname} =~ /win32/i;
88
89
90my $USAGE = <<EOF;
91usage: $0 [options] [catalogname]
92
93options:
94
95    -F    Force make of catalog with defaults
96    -c    Configuration file (default is etc/makecat.cfg)
97    -l    File to log to (default makecat.log)
98    -r    Reconfigure defaults
99
100    [catalogname] must contain alphanumerics and hyphens only.
101
102    Defaults:
103    --basedir=directory        Base directory for catalogs
104    --cgibase=url_fragment     Base URL for link programs
105    --documentroot=directory   The directory where HTML is based
106    --interchangegroup=group   The default group files should be owned by
107    --interchangeuser=username The user ID which runs Interchange
108    --serverconf=filename      Location of httpd.conf
109    --vendroot=filename        Location of Interchange software
110    --homedir=directory        Use instead of \$HOME to set defaults
111
112    Required:
113    --catroot=directory        Directory where Interchange catalog files go
114    --cgidir=directory         The directory the CGI link should go to
115    --servername=server        Name of server (www.whatever.domain)
116    --cgiurl=url_fragment      The path to the CGI link (no server name)
117    --demotype=template        The template catalog (standard is the default)
118    --mailorderto=email        Email address to send orders
119
120    Optional:
121    --catalogconf=file         Specify separate configuration file for catalogs
122    --catuser=username         The user files should be owned by (if root)
123    --sharedir=directory       The directory where shared admin images go
124    --shareurl=url             The URL to prefix shared admin images with
125    --imagedir=directory       The directory where template images go
126    --imageurl=url             The URL to prefix images with
127    --linkmode=mode            UNIX or INET (link program vlink or tlink)
128    --linkprogram=file         Use file as link program instead of vlink/tlink
129    --nocfg                    Don't add to $Global::ConfigFile
130    --nocopy                   Don't actually copy the files, just test
131    --norunning                Don't add to running server
132    --noumask                  Don't set umask
133    --permtype=[M|G|U]         Set permission type (Multi, Group, User)
134    --reference                Return hash of config as string
135                               (sets -F, no write)
136    --relocate=dir             Directory to relocate files to (for RPM and such)
137    --samplehtml=directory     The directory where template HTML goes
138    --sampleurl=url            URL to access HTML for catalog
139
140EOF
141
142if (scalar @ARGV > 1) {
143	my %optctl = (
144	    'F'                 => \$Vend::MakeCat::Force,
145	    'aliases'           => \$Conf{aliases},
146	    'basedir'           => \$Conf{basedir},
147	    'catalogconf'       => \$Conf{catalogconf},
148	    'catalogname'       => \$catalog_name,
149	    'catroot'           => \$Conf{catroot},
150	    'catuser'           => \$Conf{catuser},
151	    'cgibase'           => \$Conf{cgibase},
152	    'cgidir'            => \$Conf{cgidir},
153	    'cgiurl'            => \$Conf{cgiurl},
154	    'configfile'        => \$Global::ConfigFile,
155	    'demotype'          => \$Conf{demotype},
156	    'documentroot'      => \$Conf{documentroot},
157	    'c'                 => \$Configfile,
158	    'homedir'           => \$Conf{homedir},
159	    'imagedir'          => \$Conf{imagedir},
160	    'imageurl'          => \$Conf{imageurl},
161	    'l'                 => \$Logfile,
162	    'linkmode'          => \$Conf{linkmode},
163	    'linkhost'          => \$Conf{linkhost},
164	    'linkport'          => \$Conf{linkport},
165	    'linkprogram'       => \$Conf{linkprogram},
166	    'mailorderto'       => \$Conf{mailorderto},
167	    'interchangegroup'  => \$Conf{interchangegroup},
168	    'interchangeuser'   => \$Conf{interchangeuser},
169	    'nocfg'             => \$Conf{nocfg},
170	    'nocopy'            => \$Conf{nocopy},
171	    'norunning'         => \$Conf{norunning},
172	    'noumask'           => \$Conf{noumask},
173	    'permtype'          => \$Conf{permtype},
174	    'r'                 => \$Reconfigure,
175	    'reference'         => \$Conf{reference},
176	    'relocate'          => \$Conf{relocate},
177	    'samplehtml'        => \$Conf{samplehtml},
178	    'sampleurl'         => \$Conf{sampleurl},
179	    'sharedir'          => \$Conf{sharedir},
180	    'shareurl'          => \$Conf{shareurl},
181	    'serverconf'        => \$Conf{serverconf},
182	    'servername'        => \$Conf{servername},
183	    'linkfile'          => \$Conf{linkfile},
184	    'vendroot'          => \$Conf{vendroot},
185	    '<>'                => sub {
186                            my $arg = shift;
187                            return unless $arg =~ /=/;
188                            my ($opt, $val) = split /=/, $arg, 2;
189                            $opt = lc $opt;
190                            die "Can't set \U$opt\E twice.\n$USAGE\n"
191                                if defined $Conf{$opt};
192                            $Conf{$opt} = $val;
193                            return;
194                            },
195	);
196
197	my @options = ( qw/
198	    F
199	    aliases=s
200	    basedir|base=s
201	    catalogconf=s
202	    catalogname|name=s
203	    catroot|dir=s
204	    catuser|user=s
205	    cgibase=s
206	    cgidir=s
207	    cgiurl|script=s
208	    configfile=s
209	    demotype|template=s
210	    documentroot=s
211	    c=s
212	    homedir=s
213	    imagedir=s
214	    imageurl=s
215	    l=s
216	    linkmode=s
217	    linkfile=s
218	    linkhost=s
219	    linkport=s
220	    linkprogram=s
221	    mailorderto=s
222	    interchangegroup|minivendgroup|group=s
223	    interchangeuser|minivenduser|mvuser=s
224	    nocfg
225	    nocopy
226	    norunning
227	    permtype=s
228	    r
229	    reference
230	    relocate=s
231	    samplehtml|html=s
232	    sampleurl=s
233	    serverconf|conf=s
234	    servername|server=s
235	    sharedir=s
236	    shareurl:s
237	    vendroot|mvdir=s
238	    <>
239	/);
240
241	GetOptions(\%optctl, @options)			or die "\n$USAGE\n";
242}
243elsif ($ARGV[0] =~ /^(--help|-h(elp)?)$/i) {
244	die "\n$USAGE\n";
245}
246
247$catalog_name = shift unless $catalog_name;
248if(@ARGV) {
249	die <<EOF . "\n";
250Extra command line arguments were found. (Did you specify
251both --catalogname=name and one on the command line?)
252
253$USAGE
254EOF
255}
256
257unless($catalog_name) {
258	die "$USAGE\n" if $Vend::MakeCat::Force;
259	print <<EOF;
260
261Select a short, mnemonic name for the catalog. This will be
262used to set the defaults for naming the catalog, executable,
263and directory, so you will have to type in this name frequently.
264
265NOTE: This will be the name of 'vlink' or 'tlink', the link CGI
266program. Depending on your CGI setup, it may also have the
267extension .cgi added.
268
269Only the characters [-a-zA-Z0-9_] are allowed, and it is strongly suggested
270that the catalog name be all lower case.
271
272If you are doing the demo for the first time, you might use "standard".
273
274EOF
275   $catalog_name = prompt ("Catalog name? ");
276}
277
278die "$catalog_name -- $USAGE\n" unless $catalog_name =~ /^[-\w]+$/;
279
280if($Conf{homedir}) {
281	die "Directory set with --homedir=$Conf{homedir} is not a directory.\n"
282		unless -d $Conf{homedir};
283	$ENV{HOME} = $Conf{homedir};
284}
285
286if($Conf{'reference'}) {
287	$Vend::MakeCat::Force =
288	$Conf{nocopy}         =
289	$Conf{norunning}      =
290	$Conf{nocfg}          = 1;
291	$Logfile = $Windows ?  'nul:'	: '/dev/null';
292}
293
294if ($Vend::MakeCat::Force) {
295	my $file = $Logfile || 'makecat.log';
296	open(LOGOUT, ">>$file") or die "write $file: $!\n";
297	select LOGOUT;
298}
299
300$Configfile = "$Global::VendRoot/etc/makecat.cfg" unless $Configfile;
301my $Servername;
302my $Servers;
303my $Done_defaults;
304
305print <<EOF;
306makecat -- Interchange catalog installation program.
307
308*** We will be making a catalog named '$catalog_name'. ***
309
310EOF
311
312READCONFIG: {
313	my $cfgfile = "etc/$catalog_name.makecat.cfg";
314
315	last READCONFIG unless -f $cfgfile;
316	open(READCONFIG, "< $cfgfile") or die "read $cfgfile: $!\n";
317
318	while(<READCONFIG>) {
319			next unless /^\s*[A-Z]\w*\s+\S/;
320			chomp;
321			($var, $val) = split " ", $_, 2;
322			$ENV{"MVC_$var"} = $val;
323	}
324	close READCONFIG;
325}
326
327my $CgiDefault		= prefix('CGIDIR')			|| undef;
328my $DocrootDefault	= prefix('DOCUMENTROOT')	|| undef;
329
330if ($Windows) {
331	$ENV{HOME}		= $ENV{HOME} || $ENV{MINIVEND_ROOT}
332						|| prefix('VENDROOT') || '';
333	$CgiDefault		=  prefix('CGIDIR') || 'c:/webshare/scripts';
334	$CgiUrlDefault	=  prefix('CGIURL')  || '/scripts';
335	$DocrootDefault =  prefix('DOCUMENTROOT') || 'c:/webshare/wwwroot';
336}
337
338$ENV{MVC_ENCRYPTOR} = prefix('ENCRYPTOR') || 'none';
339
340FINDDOCROOT: {
341	last FINDDOCROOT if defined $DocrootDefault;
342	for(qw/www html web web-public public_html public-html htdocs/) {
343		-d "$ENV{HOME}/$_" and -w _
344			and $DocrootDefault = "$ENV{HOME}/$_"
345		and last FINDDOCROOT;
346	}
347
348	for(	glob("$ENV{HOME}/*html*"),
349			glob("$ENV{HOME}/*www*"),
350			glob("$ENV{HOME}/*web*")
351		)
352	{
353		-d $_ and -w _
354			and $DocrootDefault = $_
355		and last FINDDOCROOT;
356	}
357
358	for(
359		 '/home/httpd/html',
360		 '/var/www/html',
361		 '/usr/local/etc/httpd/htdocs',
362		 '/usr/local/apache/htdocs',
363		 '/home/httpd/htdocs',
364		 glob("/*/httpd/*docs"),
365		 glob("/*web*/*docs"),
366		 glob("/*/ns-home/docs"),
367		 glob("/export/*/ns-home/http*/docs"),
368		 glob("/usr/*/ns-home/http*/docs"),
369		 glob("/home/*/ns-home/http*/docs")
370		)
371	{
372		-d $_ and -w _
373			and $DocrootDefault = $_
374		and last FINDDOCROOT;
375	}
376
377	$DocrootDefault = '';
378}
379
380FINDCGIDIR: {
381	last FINDCGIDIR if defined $CgiDefault;
382	for(qw/cgi-bin cgi cgibin web-scripts scripts cgiwrap cgi-wrap/) {
383		-d "$ENV{HOME}/$_" and -w _
384			and $CgiDefault = "$ENV{HOME}/$_"
385			and $CgiUrlDefault = "/$_"
386		and last FINDCGIDIR;
387	}
388
389	for( glob("$ENV{HOME}/*cgi*"), glob("$ENV{HOME}/*scripts*") ) {
390		-d $_ and -w _
391			and $CgiDefault = $_
392			and ($CgiUrlDefault = $_) =~ s:.*/:/:
393		and last FINDCGIDIR;
394	}
395
396	for(
397			 '/home/httpd/cgi-bin',
398			 '/var/www/cgi-bin',
399			 '/usr/local/etc/httpd/cgi-bin',
400			 '/usr/local/apache/cgi-bin',
401			 glob("/*web*/cgi*"),
402			 glob("/*/ns-home/cgi*"),
403			 glob("/export/*/ns-home/http*/cgi*"),
404			 glob("/usr/*/ns-home/http*/cgi*"),
405			 glob("/home/*/ns-home/http*/cgi*"),
406		)
407	{
408		-d $_ and -w _
409			and $CgiDefault = $_
410			and ($CgiUrlDefault = $_) =~ s:.*/:/:
411		and last FINDCGIDIR;
412	}
413
414	$CgiDefault = $CgiUrlDefault = '';
415}
416
417my $isroot = 0;
418if ($< == 0) {
419	$isroot = 1 unless $Windows or $Conf{relocate};
420}
421
422$Conf{catalogname} = $catalog_name;
423
424my %Initial;
425
426my %IfRoot = (qw( permtype 1 interchangeuser 1 interchangegroup 1 catuser 1 linkmode 1));
427
428my %Prefix = (
429	vendroot     =>  $Global::VendRoot,
430	basedir      =>  sub {
431							return prefix('basedir', 1) if prefix('basedir', 1);
432							return "$Conf{vendroot}/catalogs"
433								if $Windows;
434							return "$ENV{HOME}/catalogs"
435								unless $isroot;
436							return "~/catalogs";
437							},
438	interchangeuser =>  sub {  return 'everybody' if $Windows;
439							get_id(); },
440	interchangegroup=>  '',
441    servername => sub {
442						return Sys::Hostname::hostname() || $Config{myhostname};
443					},
444    linkmode     =>  'UNIX',
445    documentroot =>  $ENV{MVC_DOCUMENTROOT} || $DocrootDefault,
446	cgidir       =>  $ENV{MVC_CGIDIR} || $CgiDefault,
447	cgibase      =>  $ENV{MVC_CGIBASE} || $CgiUrlDefault,
448	demotype     =>  $ENV{MVC_DEMOTYPE} || 'standard',
449    catuser      =>  sub {
450							$ENV{MVC_CATUSER} ||
451							($isroot ? '' : $Conf{'interchangeuser'})
452						},
453    mailorderto  =>
454						sub {  return 'webmaster' if $Windows;
455							if($Conf{servername} =~ s:(/~[^/]+)$:: ) {
456								$Tilde = $1;
457							}
458    						$Conf{catuser} },
459	catroot      =>   sub {
460							my $dir = prefix('basedir') . "/" . $catalog_name;
461							return $dir if $Windows;
462							my $userdir = (getpwnam($Conf{catuser}))[7];
463							$dir =~ s/^\~/$userdir/;
464							return $dir;
465							},
466	cgiurl       =>  sub {
467							return $ENV{MVC_CGIURL} if $ENV{MVC_CGIURL};
468							my $url = '';
469							if ($Conf{cgibase} eq '') {
470								$url =	$Tilde if defined $Tilde;
471								$url .=	'/' .
472										$catalog_name .
473										'.cgi';
474							}
475							else {
476								$url .= $Conf{cgibase} . '/' . $catalog_name;
477							}
478							$url;
479						  },
480	imagedir     => sub {
481							return $ENV{MVC_IMAGEDIR} if $ENV{MVC_IMAGEDIR};
482				 			return prefix('samplehtml') . '/' . 'images'
483						},
484	imageurl     => sub {
485							my $url = '';
486							return $ENV{MVC_IMAGEURL} if $ENV{MVC_IMAGEURL};
487	                        if(defined $Tilde) {
488								$url = $Tilde;
489							}
490							$url .= '/' . $catalog_name . '/' . 'images';
491							$url;
492						},
493	samplehtml   =>  sub {
494						return $ENV{MVC_SAMPLEHTML} if $ENV{MVC_SAMPLEHTML};
495						$Conf{documentroot} . '/' . $catalog_name;
496						},
497	sharedir	 => sub {
498							return $ENV{MVC_SHAREDIR} if $ENV{MVC_SHAREDIR};
499							return prefix('documentroot');
500						},
501	shareurl	 => sub {
502							return $ENV{MVC_SHAREURL} if $ENV{MVC_SHAREURL};
503							my $url = '';
504							$url = $Tilde if defined $Tilde;
505							return $url;
506						},
507
508);
509
510sub strip_trailing_slash {
511	my $url = shift;
512	$url =~ s:[/\s]+$::;
513	return $url;
514}
515
516sub directory_process {
517    my $dir = shift;
518    $dir =~ s:[/\s]+$::;
519    if($Conf{catuser} and $dir =~ /^~/) {
520        my $userdir = ( getpwnam( $Conf{catuser} ) )[7];
521		$dir =~ s/^~/$userdir/ if $userdir;
522    }
523    return $dir;
524}
525
526my %Postprocess = (
527
528	cgibase			=> \&strip_trailing_slash,
529	cgidir			=> \&strip_trailing_slash,
530	basedir			=> \&strip_trailing_slash,
531	documentroot	=> \&directory_process,
532	imagedir		=> \&directory_process,
533	samplehtml		=> \&directory_process,
534	catroot			=> \&directory_process,
535	relocate		=> \&strip_trailing_slash,
536	shareurl		=> \&strip_trailing_slash,
537	sharedir		=> \&strip_trailing_slash,
538
539);
540
541sub sum_it {
542	my ($file) = @_;
543	open(IT, "<$file")
544		or return undef;
545	my $data = '';
546	$data .= $_ while (<IT>);
547	close IT;
548	return unpack("%32c*", $data);
549}
550
551sub prefix {
552	my ($parm, $nodefault) = @_;
553	$parm = lc $parm;
554	return $Conf{$parm} if $Conf{$parm};
555	return $ENV{"MVC_\U$parm"} if $ENV{"MVC_\U$parm"};
556	return undef if $nodefault;
557	if(ref $Prefix{$parm}) {
558		return &{ $Prefix{$parm} };
559	}
560	else {
561		return $Prefix{$parm};
562	}
563}
564
565my %History = (
566    demotype =>  sub {
567						my @dir;
568						@dir = sort map { s:(.*)/.*:$1:; $_ } glob("*/catalog.cfg");
569						@dir = grep $_ ne 'standard', @dir;
570						unshift(@dir, 'standard') if -f 'standard/catalog.cfg';
571						unshift(@dir, 'foundation')
572							if  -f 'foundation/catalog.cfg'
573							and $catalog_name =~ /^foundation/;
574						unshift(@dir, 'construct')
575							if  -f 'construct/catalog.cfg'
576							and $catalog_name =~ /^construct/;
577						unshift(@dir, 'barry')
578							if  -f 'barry/catalog.cfg'
579							and $catalog_name =~ /^barry/;
580						unshift(@dir, 'art')
581							if  -f 'art/catalog.cfg'
582							and $catalog_name =~ /^art/;
583						my %seen;
584						@dir = grep !$seen{$_}++, @dir;
585						return @dir;
586					},
587
588	linkmode => sub { return ('UNIX', 'INET') },
589    documentroot =>  sub {
590						if(defined $Servers->{$Servername}) {
591							return $Servers->{$Servername}->{documentroot}
592							 if defined $Servers->{$Servername}->{documentroot};
593						}
594						else {
595							return (@_);
596						}
597					},
598
599	cgidir       =>  sub {
600						if(	defined $Servers->{$Servername} and
601							$Servers->{$Servername}->{scriptalias}
602							 ) {
603							my @return;
604							@return = values %{$Servers->{$Servername}{scriptalias}};
605							unshift @return, $ENV{MVC_CGIDIR} if $ENV{MVC_CGIDIR};
606							return @return;
607						}
608						return (@_);
609					},
610
611	cgibase      =>  sub {
612						if(defined $Servers->{$Servername}) {
613							my $ref = $Servers->{$Servername}{scriptalias};
614							return @_ unless defined $ref;
615							if($Conf{cgidir}) {
616								my ($k,$v);
617								for (keys %$ref) {
618									$k = $_;
619									$v = $ref->{$_};
620									$v =~ s:[/\s]+$::;
621									next unless $v eq $Conf{cgidir};
622									$k =~ s:[/\s]+$::;
623									return $k;
624								}
625							}
626							else {
627								return keys %$ref;
628							}
629						}
630						return (@_);
631					},
632    mailorderto  =>	 sub {
633						my(@return) = @_;
634						if(defined $Servers->{$Servername}) {
635							push(@return, $Servers->{$Servername}->{serveradmin})
636							 if defined $Servers->{$Servername}->{serveradmin};
637						}
638						return @return;
639					},
640
641	sharedir	 =>	  sub {
642						my (@return) = @_;
643						if(defined $Servers->{$Servername}) {
644							push (@return,
645								values %{$Servers->{$Servername}->{alias}})
646							 if defined $Servers->{$Servername}->{alias};
647						}
648						return @return;
649					},
650
651	shareurl     =>   sub {
652						my (@return) = @_;
653						if(defined $Servers->{$Servername}) {
654							push (@return,
655								keys %{$Servers->{$Servername}->{alias}})
656							 if defined $Servers->{$Servername}->{alias};
657						}
658						return @return;
659					},
660
661	imagedir     =>   sub {
662						my (@return) = @_;
663						if(defined $Servers->{$Servername}) {
664							push (@return,
665								values %{$Servers->{$Servername}->{alias}})
666							 if defined $Servers->{$Servername}->{alias};
667						}
668						return @return;
669					},
670
671	permtype     =>   sub {
672						my (@return) = @_;
673						push(@return, 'G', 'M', 'U');
674						return @return;
675					},
676
677	imageurl     =>   sub {
678						my (@return) = @_;
679						if(defined $Servers->{$Servername}) {
680							push (@return,
681								keys %{$Servers->{$Servername}->{alias}})
682							 if defined $Servers->{$Servername}->{alias};
683						}
684						return @return;
685					},
686
687	catuser  =>   sub {
688						return 'everybody' if $Windows;
689						my @return = (@_);
690						my $u;
691						if(defined $Servers->{$Servername}) {
692							$nogood = $Servers->{$Servername}->{'user'}
693							 if defined $Servers->{$Servername}->{'user'};
694						}
695						my @out;
696						while($u = getpwent) {
697							next if $u eq 'root';
698							next if $u eq $nogood;
699							push(@out, $u);
700						}
701						return (@return, sort @out);
702					},
703
704	interchangeuser  =>   sub {
705						return 'everybody' if $Windows;
706						my @return = (@_);
707						my $u;
708						if(defined $Servers->{$Servername}) {
709							$nogood = $Servers->{$Servername}->{'user'}
710							 if defined $Servers->{$Servername}->{'user'};
711						}
712						my @out;
713						while($u = getpwent) {
714							next if $u eq 'root';
715							next if $u eq $nogood;
716							push(@out, $u);
717						}
718						return (@return, sort @out);
719					},
720
721	interchangegroup  =>   sub {
722						return 'nogroup' if $Windows;
723						my (@return) = @_;
724						my $u;
725						if(defined $Servers->{$Servername}) {
726							$nogood = $Servers->{$Servername}->{'group'}
727							 if defined $Servers->{$Servername}->{'group'};
728						}
729						my @out;
730						while($u = getgrent) {
731							next if $u eq 'root';
732							next if $u eq $nogood;
733							push(@out, $u);
734						}
735						return (@return, sort @out);
736					},
737
738);
739
740unless($isroot) {
741	@Prefix{qw(interchangeuser interchangegroup)} = get_ids();
742	$Prefix{catuser} = $Prefix{interchangeuser};
743	$Prefix{basedir} = "$ENV{HOME}/catalogs";
744}
745
746my($ask,$param);
747
748unless (-f $Configfile) {
749	$Removeconfig = 1 if prefix('nocopy');
750	open(CFGFILE, ">$Configfile")	or die "Can't write $Configfile: $!\n";
751	while(<DATA>) {
752		print CFGFILE $_;
753	}
754	close(CFGFILE)					or die "Can't close $Configfile: $!\n";
755	print "\nNew configuration file '$Configfile'\n" ;
756	$Reconfigure = 1;
757}
758
759$Cfg = new IniConf -file => $Configfile;
760unless ($Cfg) {
761	if (@IniConf::errors) {
762		print join("\n", @IniConf::errors, '');
763	}
764	die "Can't parse config file $Configfile\n";
765}
766
767my @parms;
768
769unless($Reconfigure or $Cfg->val('base', 'vendroot')) {
770	$Reconfigure = 1;
771}
772
773CHECKEXIST: {
774
775	if(grep /^catalog $catalog_name$/i, $Cfg->Sections()) {
776		@parms = $Cfg->Parameters("catalog $catalog_name");
777	}
778	else {
779		@parms = ();
780	}
781	unless(@parms) {
782		@parms = $Cfg->Parameters('legalconfig');
783		undef $Cfg;
784		my $user_time = "run by ";
785		$user_time .= scalar getpwuid($>);
786		$user_time .= " at ";
787		$user_time .= scalar localtime();
788
789		open(CFGFILE, ">>$Configfile")	or die "Can't write $Configfile: $!\n";
790		print CFGFILE <<EOF;
791
792# New catalog definition '$catalog_name' written by makecat
793# $user_time
794[catalog $catalog_name]
795EOF
796		for(@parms) {
797			printf CFGFILE "%-19s =\n", $_;
798		}
799		close(CFGFILE)					or die "Can't close $Configfile: $!\n";
800		$Cfg = new IniConf -file => $Configfile;
801		die "Can't read config file $Configfile: $!\n" unless defined $Cfg;
802		redo CHECKEXIST;
803	}
804
805}
806
807my @conf;
808my @Servers;
809
810FINDCONF: {
811
812	last FINDCONF if $Windows;
813	last FINDCONF if $Vend::MakeCat::Force;
814	last FINDCONF if $ENV{MVC_SERVERNAME};
815	my $httpdconf;
816	if($param = prefix('serverconf') || $Cfg->val('base', 'serverconf')) {
817		last FINDCONF if $param =~ /^none$/i;
818		@conf = split /\s+/, $param;
819	}
820	print <<EOF unless @conf;
821
822If you are using the Apache or NCSA web server, Interchange can set
823some of the default parameters for you by reading the file.
824
825If you use the Netscape Enterprise server or other non-NCSA HTTP server,
826enter 'none' -- the information, if any, will not be useful.
827
828EOF
829	if (defined $Vend::MakeCat::Prompt_sub) {
830		print <<EOF;
831
832Try using the UP arrow at some of the prompts -- you have the
833Term::ReadLine module installed, and Interchange may find some
834default values in your HTTP server configuration file.  You can
835cycle among them with the UP and DOWN arrows.
836
837EOF
838	}
839	else {
840		print <<EOF unless @conf;
841
842This information may not be that useful to you, since you don't
843have the Term::ReadLine module installed. If the default setting
844presented is not correct, you will have to know the information.
845C'est la vie.
846
847EOF
848	}
849
850	my $not_set;
851	if(! scalar @conf) {
852		$not_set = 1;
853		if(findexe('locate')) {
854			@conf = findfiles('httpd.conf');
855		}
856		else {
857			print <<EOF;
858
859Interchange can look for Apache or NCSA HTTP server configuration
860files for you by a slow method (using the system find
861command). This may take as many as several minutes.
862
863EOF
864			$ask = prompt("Find httpd.conf files? ", 'y');
865			@conf = findfiles('httpd.conf') if $ask =~ /^\s*y/i;
866		}
867	}
868
869	sethistory(@conf);
870	if ($not_set) {
871		$httpdconf = prompt("Enter path to httpd.conf file: ", $conf[0]);
872		$Cfg->setval('base', 'serverconf', $httpdconf);
873	}
874	else {
875		$httpdconf = shift @conf;
876	}
877	last FINDCONF if $httpdconf =~ /^none$/i;
878
879	if($httpdconf) {
880		$Servers = conf_parse_http($httpdconf);
881		unless (defined $Servers) {
882			print <<EOF;
883
884The file '$httpdconf' was not parsed properly.
885
886Error: $Vend::MakeCat::Error
887
888You can edit the file and try again if you wish. (Don't worry if it
889didn't work, you will have the opportunity to enter all of the proper
890information manually.)
891
892EOF
893			$ask = prompt("Try again? ", 'y');
894			last FINDCONF if $ask =~ /^\s*n/i;
895			redo FINDCONF;
896		}
897		else {
898			@Servers = sort keys %{$Servers};
899		}
900	}
901}
902
903##############
904SETDEFAULTS: {
905	last SETDEFAULTS if $Done_defaults;
906	$Done_defaults = 1;
907	unless ($Reconfigure) {
908		my @parms = $Cfg->Parameters('base');
909		for(@parms) {
910			next if $Conf{$_} = prefix($_, 1);
911			$Conf{$_} = $Cfg->val('base', $_) || undef;
912		}
913		last SETDEFAULTS;
914	}
915
916	PERMS: {
917
918		unless ($isroot) {
919			print <<EOF unless $Windows;
920
921This demo configuration sometimes requires root permissions,
922depending on your ISP. It needs to copy a few files to the CGI
923and HTML directories.
924
925You must either have your own CGI directory, or be able to run
926a CGI with an extension like '.cgi'.
927
928If you will be operating only on directories owned by the
929user you are running this as, you will be able to do
930everything.
931
932EOF
933
934		}
935		else {
936			last PERMS if prefix('permtype', 1);
937			print <<EOF;
938
939You are the super-user. You can set the permissions to GROUP, MULTIPLE
940GROUP, or USER mode for catalogs on this server.
941
942MULTIPLE GROUP or GROUP is appropriate when multiple users will be running
943catalogs on the same server.
944
945MULTIPLE GROUP is the best way. Put each user in their own group, and
946place the Interchange user in that group. In this mode, only the user of
947each catalog and the Interchange server may read database and error files --
948files that may contain sensitive information. If the user's default UMASK
949is 2 on a UNIX system, then this the most troublefree mode of operation.
950
951GROUP mode causes all files to be owned by the Interchange user, with group
952ownership set to the group the user belongs to. This allows the Interchange
953user and each individual user to read and write the files associated with
954a catalog, but others in that group may read files from a catalog. This
955may not be secure, and may cause problems when the user creates new
956files that must be read/write to the Interchange user.
957
958USER mode is appropriate when only one user owns all catalogs running
959on this server, and the Interchange daemon is run by the same user.
960
961  M) MULTIPLE GROUP
962  G) GROUP
963  U) USER
964
965EOF
966			sethistory("MULTIPLE GROUP", "GROUP", "USER");
967			$Conf{permtype} = prompt("Permission Mode? ", "M");
968			unless($Conf{permtype} =~ s/^\s*([mgu]).*/uc $1/ie) {
969				print "Must be one of M(ULTIPLE), G(ROUP), or U(SER).\n";
970				redo PERMS;
971			}
972			$Cfg->setval('base', 'permtype', $Conf{permtype});
973
974		}
975
976	} # END PERMS
977
978	print <<EOF;
979
980Since there was no master configuration file, we will ask
981some questions to help set initial defaults for making this
982and future catalogs.
983
984EOF
985
986
987	##############
988	DEFSERVER: {
989
990	last DEFSERVER unless @Servers;
991
992	print <<EOF if defined $Vend::MakeCat::Prompt_sub;
993
994Interchange can set many of the defaults for you if it knows the server
995name that is going to be used.
996
997Enter the default server that should be used. This is only a default, to
998determine the *first* one that will be looked at -- you will be given
999a choice of all available servers.
1000
1001There is a "history" mechanism that will allow you to use the up
1002and down arrows on your terminal (assuming you have a standard terminal)
1003to cycle between possible choices. This should contain the available
1004servers.
1005
1006EOF
1007
1008	sethistory(@Servers);
1009	$Conf{servername} = prompt('Default server? ', $Servers[0]);
1010	$Servername = $Conf{servername};
1011	$Cfg->setval('base', 'servername', $Servername);
1012
1013	}
1014	############
1015
1016	my @ask = $Cfg->val('global', 'askbase');
1017
1018	for('cgidir') {
1019		next if $Conf{$_};
1020		print <<EOF;
1021
1022
1023We need to know if all of your CGI programs are run as a file ending
1024in .cgi or some other extension, or whether you have your own personal
1025CGI directory.
1026
1027EOF
1028		$ask = prompt ("Do you have a CGI directory? ", 'y');
1029		last if is_yes($ask);
1030		$Prefix{cgidir} = prefix('documentroot');
1031	}
1032
1033	my ($p, $i);
1034
1035	for ($i = 0; $i < scalar @ask; $i++) {
1036		$p = $ask[$i];
1037		my $hval;
1038		$hval = prefix($p);
1039		if (defined $History{$p}) {
1040			@history = &{$History{$p}}(prefix($p));
1041			$hval = $history[0];
1042			sethistory(@history);
1043		}
1044		$val = prefix($p, 1) || $Cfg->val("base", $p) || $hval;
1045		if (! $isroot and defined $IfRoot{$p}) {
1046			$Conf{$p} = $val;
1047			next;
1048		}
1049		print "\n";
1050		print description($p);
1051		print "\n\n";
1052		my $msg = pretty($p) . "? ";
1053		$Conf{$p} = prompt ($msg, $val);
1054		if($Conf{$p} eq '@') {
1055			$i--;
1056			$i = 0 if $i < 0;
1057			redo;
1058		}
1059		if(defined $Postprocess{$p}) {
1060			$Conf{$p} = $Postprocess{$p}->($Conf{$p});
1061		}
1062	}
1063
1064	for(@ask) {
1065		$Cfg->setval('base', $_, $Conf{$_});
1066	}
1067
1068	$Cfg->WriteConfig("$Configfile.new")
1069		and File::Copy::copy "$Configfile.new", $Configfile;
1070
1071	print "#########     END BASE CONFIGURATION      #########\n\n";
1072
1073}
1074#############
1075
1076	my $serv = prefix('servername') || 'www.yourdomain';
1077
1078# Set server
1079
1080print "######### BEGINNING CATALOG CONFIGURATION #########\n";
1081print <<EOF if defined $Vend::MakeCat::Prompt_sub;
1082
1083During many of the following operations, defaults are placed in
1084a buffer for you. You may use the up and down arrows to toggle
1085between the defaults.
1086
1087If you made a mistake on a *previous* entry and realize that
1088in a later one, if you enter ONLY an @ sign and press return you
1089should be returned to the previous step.
1090
1091EOF
1092SETSERVER: {
1093	sethistory(@Servers);
1094	print description('servername');
1095 	$Servername = prefix('servername', 1)  			||
1096				  $Cfg->val('base', 'servername')	||
1097				  prefix('servername');
1098	$Servername =
1099		$Conf{servername} =
1100			prompt("Server name? ", ($Servername || $Servers[0]));
1101	$Cfg->setval("catalog $catalog_name", 'servername', $Conf{servername});
1102}
1103
1104	@ask = $Cfg->val('global', 'askconfig');
1105
1106	my $redid;
1107	my $next_force;
1108	for ($i = 0; $i < scalar @ask; $i++) {
1109		$p = $ask[$i];
1110		if ($redid) {
1111#print("###redo###\n");
1112			# Handle the &-d option, don't want to force first time
1113			if (defined $next_force and ! $next_force) {
1114#print("###force next###\n");
1115				$next_force = 1;
1116			}
1117			$val = $Conf{$p};
1118		}
1119		elsif (defined $History{$p}) {
1120			@history = &{$History{$p}}(prefix($p));
1121			sethistory(@history);
1122			$val =	prefix($p,1)							||
1123					$Cfg->val("catalog $catalog_name", $p)	||
1124					$history[0]								||
1125					prefix($p);
1126		}
1127		else {
1128			$val =	prefix($p,1)							||
1129					$Cfg->val("catalog $catalog_name", $p)	||
1130					prefix($p);
1131		}
1132		if (! $isroot and defined $IfRoot{$p}) {
1133			$Conf{$p} = $val;
1134			next;
1135		}
1136		print "\n";
1137
1138		unless($redid) {
1139			print description($p);
1140			print "\n\n";
1141		}
1142		else {
1143			undef $redid;
1144		}
1145
1146		my $msg = pretty($p) . "? ";
1147		$Conf{$p} = prompt ($msg, $val);
1148#print("###force=$Vend::MakeCat::Force###\n");
1149		if(defined $Postprocess{$p}) {
1150			$Conf{$p} = $Postprocess{$p}->($Conf{$p});
1151		}
1152		if($Conf{$p} eq '@') {
1153			$Conf{$p} = $val;
1154			$redid = 1;
1155			$next_force = 0 if $next_force;
1156			$i--;
1157			$i = 0 if $i < 0;
1158			redo;
1159		}
1160		elsif ($Conf{$p} eq '&-d') {
1161			print "OK, I will run with defaults after this prompt.\n";
1162			$Conf{$p} = $val;
1163			$redid = 1;
1164			$next_force = 0;
1165			redo;
1166		}
1167
1168		if ($next_force) {
1169#print("###force now###\n");
1170			$Vend::MakeCat::Force = 1;
1171		}
1172
1173		$Cfg->setval("catalog $catalog_name", $p, $Conf{$p});
1174	}
1175
1176if($Removeconfig) {
1177	unlink $Configfile;
1178}
1179elsif ( ! prefix('nocopy') ) {
1180	$Cfg->WriteConfig("$Configfile.new")
1181		and File::Copy::copy "$Configfile.new", $Configfile;
1182}
1183
1184undef $Cfg;
1185
1186# Try and get the URL we will use to access the catalog
1187GUESS: {
1188
1189 	if( $Conf{samplehtml} =~ /^\s*none\s*$/i ) {
1190		$Conf{sampleurl} = 'NONE';
1191		last GUESS;
1192	}
1193
1194	my $tempurl;
1195    $guessdir = $Conf{samplehtml};
1196
1197    unless( $guessdir =~ s/^$Conf{documentroot}// ) {
1198        print <<EOF;
1199
1200The specified HTML directory, $Conf{samplehtml},
1201is not a subdirectory of DocumentRoot. This will make it
1202hard for us to guess the URL needed to access pages from
1203the catalog. Please re-specify your HTML document root.
1204
1205# The base directory for HTML for the catalog, the DocumentRoot.
1206# This is a file name, not a URL.
1207
1208EOF
1209        $val = '';
1210		my $msg = pretty('documentroot');
1211        $Conf{documentroot} = prompt ("\n$msg? ", '');
1212        redo GUESS;
1213    }
1214
1215    $guessdir =~ s:^/+::;
1216    $guessdir = "$Tilde/$guessdir" if defined $Tilde;
1217    $guessdir =~ s:^/+::;
1218    $tempurl = "http://$Conf{servername}/$guessdir";
1219    if (defined $Conf{sampleurl} and $Conf{sampleurl} ne $tempurl) {
1220		print <<EOF;
1221
1222We were given a previous value for the URL that will run the catalog
1223(from the catalog configuration file $Configfile):
1224
1225    $Conf{sampleurl}
1226
1227This conflicts with what we guess from what you have just
1228entered:
1229
1230   	$tempurl
1231
1232EOF
1233
1234		if ($Vend::MakeCat::Force) {
1235			$tempurl = $Conf{sampleurl};
1236		} else {
1237			$tempurl  = prompt ("\nPlease re-enter or confirm: ",
1238						"http://$Conf{servername}/$guessdir");
1239		}
1240	}
1241
1242	$Conf{sampleurl} = $tempurl;
1243
1244}
1245
1246if ($Windows) {
1247	$mvuid = $catuid = 'everybody';
1248	$mvgid = $catgid = 'nogroup';
1249}
1250elsif ($Conf{relocate}) {
1251	$mvuid = $catuid = $mvgid = $catgid = 'nobody';
1252}
1253else {
1254	$mvuid = (getpwnam($Conf{interchangeuser}))[2];
1255	die "$Conf{interchangeuser} is not a valid user name on this machine.\n"
1256		unless defined $mvuid;
1257
1258	if ($Conf{interchangegroup}) {
1259		$mvgid = getgrnam($Conf{interchangegroup});
1260		die "$Conf{interchangegroup} is not a valid group name on this machine.\n"
1261			unless defined $mvgid;
1262	}
1263	else {
1264		$mvgid = (getpwnam($Conf{interchangeuser}))[3];
1265		$Conf{interchangegroup} = getgrgid($mvgid)
1266	}
1267
1268	($catuid, $catgid) = (getpwnam($Conf{catuser}))[2,3];
1269	die "$Conf{catuser} is not a valid user name on this machine.\n"
1270		unless defined $catuid;
1271}
1272
1273if($isroot) {
1274	chown ($mvuid, $mvgid, $Configfile)
1275		or warn "\nCouldn't set ownership of $Configfile: $!\n";
1276	if(! $Conf{permtype} or $Conf{permtype} =~ /^[MUmu]/) {
1277		$Conf{catgroup} = getgrgid($catgid);
1278	}
1279	else {
1280		$Conf{catgroup} = getgrgid($mvgid);
1281	}
1282}
1283
1284# Final substitution
1285for(keys %Conf) {
1286	next unless $Conf{$_} =~ /__MVC_/;
1287	$Conf{$_} =~ s/__MVC_([A-Z]+)__/$Conf{lc $1}/g;
1288}
1289
1290# Find the perl path
1291$Conf{'perl'} = $Config{perlpath};
1292
1293# Now change to the directory defined as Global::VendRoot
1294chdir "$Conf{relocate}$Conf{vendroot}"
1295	or die "Couldn't change directory to $Conf{relocate}$Conf{vendroot}: $!\n";
1296
1297$warn = 0;
1298$msg = q# supposed to be a directory, not a file. Can't continue.#;
1299for ( $Conf{catroot}, $Conf{documentroot}, $Conf{basedir},
1300	$Conf{samplehtml}, $Conf{imagedir} ) {
1301	next unless -f "$Conf{relocate}$_";
1302	print "$_ $msg\n";
1303	$warn++;
1304}
1305die "\n" if $warn;
1306
1307my $prog;
1308my ($lh, $lp);
1309
1310SETLINKMODE: {
1311	if($prog = prefix('linkprogram')) {
1312		last SETLINKMODE;
1313	}
1314	if ($Windows) {
1315		$Conf{linkmode} = 'INET';
1316		$prog = "$Conf{relocate}$Conf{vendroot}/src/tlink.pl";
1317		last SETLINKMODE;
1318	}
1319	print <<EOF;
1320
1321Interchange can use either UNIX- or internet-domain sockets.
1322Most ISPs would prefer UNIX mode, and it is more secure.
1323
1324If you already have a program there, or use a common program
1325and the FullURL directive, select NONE. You will then need
1326to copy the program by hand or otherwise ensure its presence.
1327
1328EOF
1329	print "(You can use the up/down arrows to toggle).\n"
1330		if $Vend::MakeCat::Prompt_sub;
1331
1332	sethistory("NONE", "UNIX", "INET");
1333
1334	unless ( $default = prefix('linkmode') ) {
1335		$default = ($Config{osname} =~ /bsd/i and $Config{osvers} gt '3')
1336				? 'INET' : 'UNIX';
1337	}
1338
1339	$ask = prompt("INET or UNIX mode? ", $default);
1340
1341	$prog = "$Conf{relocate}$Conf{vendroot}/src/vlink";
1342
1343	if($ask =~ /^\s*i/i) {
1344		$lm = "i";
1345		$Conf{linkmode} = 'INET';
1346		$Inetmode = 1;
1347
1348		my $defport;
1349		my $defhost;
1350
1351	  INETASK: {
1352		my (@hosts);
1353		my (@ports);
1354		$prog = "$Conf{relocate}$Conf{vendroot}/src/tlink";
1355		my $the_one = sum_it($prog);
1356
1357		my @poss = glob("$Conf{relocate}$Conf{vendroot}/src/tlink.*.*");
1358		for (@poss) {
1359			my $name = $_;
1360			/tlink\.(.*)\.(\d+)$/
1361				or next;
1362			my ($h, $p) = ($1, $2);
1363			push @hosts, $h;
1364			push @ports, $p;
1365			my $one = sum_it($_);
1366			next unless $one eq $the_one;
1367			$defhost = $h;
1368			$defport = $p;
1369		}
1370
1371		my %seen;
1372		sethistory(grep !$seen{$_}++, @ports);
1373		$default = $defport || $Conf{linkport} || 7786;
1374		$lp = $lh = '';
1375		while(! $lp) {
1376			$lp = prompt("TCP socket to use? ", $default);
1377			redo INETASK if $lp eq '@';
1378			if($lp !~ /^\d+$/ or $lp < 1024) {
1379				print "Looking for an integer number > 1024 here.\n";
1380				undef $lp;
1381			}
1382		}
1383
1384		sethistory(grep !$seen{$_}++, @hosts);
1385		$default = $defhost || $Conf{linkhost} || '127.0.0.1';
1386		while(! $lh) {
1387			$lh = prompt("Link host? ", $default);
1388			redo INETASK if $lh eq '@';
1389		}
1390		$Conf{linkport} = $lp;
1391		$Conf{linkhost} = $lh;
1392		unlink $prog unless $lh eq $defhost && $lp eq $defport;
1393	  } # END INETASK
1394	}
1395	elsif($ask =~ /^\s*n/i) {
1396		$Conf{linkmode} = $prog = "NONE";
1397	}
1398	else {
1399		$lm = 'u';
1400		$Conf{linkmode} = "UNIX";
1401		my $def = -u '/usr/bin/suexec' ? 'y' : 'n';
1402		$ask = prompt("Do you use CGIWRAP or SUEXEC? ", $def);
1403		$Conf{cgiwrap} = $CGIwrap = $ask =~ /^\s*y/i;
1404	}
1405
1406}
1407
1408my $tried_compile;
1409
1410FINDPROG: {
1411	last FINDPROG if $prog eq 'NONE';
1412	unless (-x $prog and -f _) {
1413		if(! $tried_compile) {
1414			my $cmd = 'bin/compile_link ';
1415			$cmd .= "-$lm " if $lm;
1416			$cmd .= "-s $Conf{linkfile} " if $Conf{linkfile};
1417			$cmd .= "-p $lp " if $lp;
1418			$cmd .= "-h $lh " if $lh;
1419			if ($Conf{relocate}) {
1420                        	$cmd .= "--source $Conf{relocate}/$Conf{vendroot}/src ";
1421            		}
1422			system $cmd;
1423			$tried_compile = 1;
1424			redo FINDPROG;
1425		}
1426		my @history = ();
1427		$prog =~ s:.*src/::;
1428		print <<EOF;
1429	Couldn't find the executable file '$prog'.
1430
1431	Please give the complete path to the link program.
1432
1433EOF
1434		if($Config{osname} =~ /win32/i) {
1435			# do nothing
1436		}
1437		elsif (@history = glob("$Global::VendRoot/src/?link.???*")) {
1438			# do nothing
1439		}
1440		elsif (@history = glob("$Global::ProgRoot/src/?link.???*")) {
1441			# do nothing
1442		}
1443		elsif(findexe('locate')) {
1444			@history = findfiles($prog);
1445		}
1446		else {
1447			@history = `find . -name \*[vt]link\* -print`;
1448			chomp @history;
1449		}
1450		sethistory(@history);
1451		$prog = prompt("Link program? ", $history[0]);
1452	}
1453}
1454
1455umask(022) unless $Conf{noumask};
1456
1457$warn = 0;
1458print do_msg("Checking directories");
1459
1460$msg = q#directory exists!#;
1461for($Conf{catroot}, $Conf{samplehtml}) {
1462	next unless -d $_;
1463	print "\n$_: $msg\n";
1464	$warn++;
1465}
1466
1467if($warn) {
1468	$ask = prompt "The above directories already exist. Overwrite files? ", 'n';
1469	unless($Vend::MakeCat::Force) {
1470		exit 2 unless is_yes($ask);
1471	}
1472}
1473
1474$warn = 0;
1475for($Conf{documentroot}, $Conf{basedir}) {
1476	next if /^\s*none\s*$/i;
1477	next if -d $_;
1478	$warn++;
1479}
1480
1481for($Conf{catroot}, $Conf{samplehtml}, $Conf{imagedir}) {
1482	next if /^\s*none\s*$/i;
1483	next if -d $_;
1484	$warn++;
1485}
1486
1487if($warn) {
1488	for(qw(catroot samplehtml imagedir)) {
1489		$dir = "$Conf{relocate}$Conf{$_}";
1490#print "doing dir=$dir\n";
1491		# Allow nocopy
1492		next if $dir =~ /^\s*none\s*$/i;
1493
1494		(warn "\n$_ is empty, skipping.\n", next)
1495			unless $dir =~ /\S/;
1496		unless(-d $dir or prefix('nocopy') ) {
1497			File::Path::mkpath([$dir], 1, 0775)
1498				or die "Couldn't make directory $dir: $!\n";
1499		}
1500	}
1501}
1502
1503for(qw(catroot samplehtml imagedir)) {
1504    my $userdir;
1505    if($dir =~ /^~/ and $userdir = (getpwnam($Conf{catuser}))[7] ) {
1506		$dir =~ s/^~/$userdir/;
1507    }
1508	$dir = "$Conf{relocate}$Conf{$_}";
1509
1510	# Allow nocopy
1511	next if $dir =~ /^\s*none\s*$/i;
1512
1513	if (prefix('nocopy')) {
1514		next if -w $dir;
1515		my $parent = $dir;
1516		do {
1517			$parent =~ s:/[^/]+$::;
1518		} until $parent !~ m{/} or -d $parent;
1519		warn "Directory $dir (or parents) not writable, could be problems.\n"
1520			unless -w $dir || -w $parent;
1521		next;
1522	}
1523
1524	die "Directory $dir not writable, can't continue.\n"
1525		unless -w $dir or $dir =~ /^\s*none\s*$/i;
1526	set_owner($dir);
1527}
1528print "done.\n";
1529
1530# Now change to the directory defined as Global::VendRoot if the checks
1531# have left us elsewhere
1532chdir "$Conf{relocate}$Conf{vendroot}"
1533		or die "Couldn't change directory to $Conf{relocate}$Conf{vendroot}: $!\n";
1534
1535print do_msg("Copying demo files");
1536unless (-d "$Conf{relocate}$Conf{vendroot}/$Conf{demotype}") {
1537	print "No $Conf{relocate}$Conf{vendroot}/$Conf{demotype} directory is present,\n";
1538	$dir = prompt("where should the files come from? ", "$Conf{relocate}$Conf{catroot}");
1539}
1540else {
1541	$dir = "$Conf{relocate}$Conf{vendroot}/$Conf{demotype}";
1542}
1543
1544# Do some additional configuration if the additional_fields
1545# file is found
1546
1547ADDITIONAL: {
1548	last ADDITIONAL unless -f "$dir/config/additional_fields";
1549	open(ADDL, "< $dir/config/additional_fields")
1550		or last ADDITIONAL;
1551	my %help;
1552	local ($/) = "";
1553	if(open(ADDLHELP, "< $dir/config/additional_help") ) {
1554		while(<ADDLHELP>) {
1555			my($parm,$help) = split /\n/, $_, 2;
1556			$help =~ s/\s*$/\n\n/;
1557			$help =~ s/^[.\t ]+$//mg;
1558			$help{uc $parm} = $help;
1559		}
1560		close ADDLHELP;
1561	}
1562	my $said = 0;
1563	my $redid;
1564	my $next_force;
1565	while(<ADDL>) {
1566		my $noprompt = '';
1567		my $grp;
1568		s/\s+$//;
1569		s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
1570		my ($var, $prompt, $default) = split /\n/, $_, 3;
1571		$var =~ s/\t(.*)//;
1572		next unless $var;
1573		$grp = $1 || $var;
1574
1575		if ($redid) {
1576#print("###redo###\n");
1577			# Handle the &-d option, don't want to force first time
1578			if (defined $next_force and ! $next_force) {
1579#print("###force next###\n");
1580				$next_force = 1;
1581			}
1582			$val = $Conf{$p};
1583		}
1584		if($var =~ s/{\s*([A-Z0-9]+)(\s*\S.*?)?\s*}\s*//) {
1585			my $param = $1;
1586			my $test = $2;
1587			my $v = $Conf{lc $param};
1588			$v = "q{$v}";
1589			my $true;
1590			eval {
1591				$true = eval "$v$test";
1592			};
1593			next unless $true;
1594		}
1595		$var =~ s/\s+//g;
1596		$var =~ s:^!::
1597			and $noprompt = 1;
1598		$var = lc $var;
1599		my $ucvar = uc $var;
1600		if($default =~ /\t/) {
1601			my (@history);
1602			(@history)  = split /\t/, $default;
1603			$default = $history[0];
1604			sethistory(@history);
1605		}
1606		unless ($noprompt) {
1607			if (defined $help{$ucvar} and ! $redid) {
1608				$help{$ucvar} =~ s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
1609				print $help{$ucvar};
1610			}
1611			print "found more to ask.\n\n" unless $said++;
1612			$Conf{$var} = prompt(
1613							do_msg("$prompt: ", 50),
1614									 ( delete $ENV{"MVC_$ucvar"}
1615										|| $Conf{$var}
1616										|| $default)
1617									);
1618			if ($Conf{$var} eq '&-d') {
1619				print "OK, I will run with defaults after this prompt.\n";
1620				$Conf{$var} = $default;
1621				$redid = 1;
1622				$next_force = 0;
1623				redo;
1624			}
1625		}
1626		else {
1627			$Conf{$var} = delete $ENV{"MVC_$ucvar"} || $Conf{$var} || $default;
1628		}
1629
1630		if ($next_force) {
1631#print("###force now###\n");
1632			$Vend::MakeCat::Force = 1;
1633		}
1634
1635	}
1636	close ADDL;
1637}
1638
1639CRYPTPW: {
1640	my $pw = substitute('CRYPTPW', '__');
1641	last CRYPTPW unless $pw;
1642	last CRYPTPW if substitute('ALREADYCRYPT', '__');
1643	my @letters = ('A' .. 'Z', 'a' .. 'z');
1644	my $salt = $letters[ int rand(scalar @letters) ];
1645	$salt .= $letters[ int rand(scalar @letters) ];
1646	$ENV{MVC_CRYPTPW} = crypt($pw, $salt);
1647}
1648
1649PRECMD: {
1650	last PRECMD unless -f "$dir/config/precopy_commands";
1651	open(ADDL, "< $dir/config/precopy_commands")
1652		or last PRECMD;
1653	print "\nFound system commands to run.\n\n";
1654	local ($/) = "";
1655	while(<ADDL>) {
1656		my $unprompted;
1657		s/\s+$//;
1658		s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
1659		my ($command, $prompt) = split /\n/, $_, 2;
1660		$command =~ s/^\s+//;
1661		$command =~ s/\s+$//;
1662		$command =~ s/^!// and $unprompted = 1;
1663		if($command =~ s/{\s*([A-Z0-9]+)(\s*\S.*?)?\s*}\s*//) {
1664			my $param = $1;
1665			my $test = $2;
1666			my $v = $Conf{lc $param};
1667			$v = "q{$v}";
1668			my $true;
1669			eval {
1670				$true = eval "$v$test";
1671			};
1672			next unless $true;
1673		}
1674		print "$prompt\n\n";
1675		print "Running: $command\n" if $unprompted;
1676		my $ans = $unprompted ? 'y' : prompt( qq{run "$command"? }, 'y' );
1677		if($ans =~ /^\s*y/i) {
1678			system $command;
1679			if($?) {
1680				print "\nCommand returned error code " . ($? >> 8) . ": $!\n";
1681			}
1682		}
1683		else {
1684			print "\nskipping '$command'\n";
1685		}
1686	}
1687	close ADDL;
1688}
1689
1690# Here we actually do the file copy unless --nocopy is set
1691DOCOPY: {
1692
1693	if (prefix('nocopy')) {
1694		print "not copying.\n";
1695		last DOCOPY;
1696	}
1697
1698	chdir $dir || die "Couldn't change directory to $dir: $!\n";
1699
1700
1701	# This is what we used to do
1702	#system "tar -cf - * | (cd $Conf{catroot}; tar -xf -)";
1703
1704	umask(07) unless $Conf{noumask};
1705
1706	# remove any existing symbolic links in target directory
1707	File::Find::find( sub {
1708								return if ! -l $_;
1709								unlink $_
1710									or die "couldn't unlink $File::Find::name: $!\n";
1711							},
1712					 "$Conf{relocate}$Conf{catroot}",
1713					 );
1714
1715	eval {
1716		copy_current_to_dir("$Conf{relocate}$Conf{catroot}");
1717	};
1718
1719	umask(022) unless $Conf{noumask};
1720
1721	if($@) {
1722		die <<EOF . "\n";
1723There were errors in copying the demo files.  Cannot
1724continue.  Check to see if permissions are correct.
1725The problem was:
1726
1727	$@
1728EOF
1729	}
1730
1731	unless($prog eq 'NONE') {
1732		File::Copy::copy( $prog, "$Conf{relocate}$Conf{catroot}/executable")
1733			or die "Couldn't copy link program from $prog: $!\n";
1734	}
1735
1736	print "done.\n";
1737
1738chdir "$Conf{relocate}$Conf{catroot}"
1739 	|| die "Couldn't change directory to $Conf{relocate}$Conf{catroot}: $!\n";
1740
1741my ($umode, $gmode);
1742
1743if($Conf{permtype} =~ /^[mg]/i) {
1744	$umode = 0; $gmode = 1;
1745}
1746else {
1747	$umode = 1; $gmode = 0;
1748}
1749
1750
1751%MacroString = qw(
1752
1753    __MVC_CGIURL        cgiurl
1754    __MVC_CGIDIR        cgidir
1755    __MVC_MAILORDERTO   mailorderto
1756    __MVC_IMAGEURL      imageurl
1757    __MVC_SAMPLEURL     sampleurl
1758    __MVC_SERVERNAME    servername
1759
1760);
1761
1762sub set_owner {
1763	return unless $> == 0;
1764	my($file) = @_;
1765	my ($user, $group) = ($mvuid, $mvgid);
1766	if($Conf{permtype} =~ /^m/i) { $user = $catuid; $group = $catgid; }
1767	elsif($Conf{permtype} =~ /^g/i) { $group = $catgid; }
1768	chown($user, $group, $file)
1769		or die "Couldn't set ownership to UID=$user GID=$group for $file: $!\n";
1770}
1771
1772sub substitute {
1773	my($parm,$new) = @_;
1774
1775	return $ENV{"MVC_$parm"} if defined $ENV{"MVC_$parm"};
1776
1777	if($new) {
1778		return $Conf{lc $parm} || '';
1779	}
1780	else {
1781		return $Conf{$MacroString{"__MVC_$parm"}}
1782			if defined $MacroString{"__MVC_$parm"};
1783	}
1784	return "__MVC_${parm}__";
1785}
1786
1787sub wanted {
1788
1789	my ($mode,$file);
1790	$file = $_;
1791	my $name = $File::Find::name;
1792	EDIT: {
1793     	return if        (-l $file);
1794
1795		# Ugly, but necessary on BSDI
1796		$File::Find::prune = 1 if -f _;
1797
1798        last EDIT unless (-f _);
1799        last EDIT unless (-T _);
1800
1801		open(IN, "< $file") or die "Couldn't open $name: $!\n";
1802		open(OUT, ">$file.new") or die "Couldn't create $name.new: $!\n";
1803		while(<IN>) {
1804			( (print OUT $_), next) unless /__MV[CR]/;
1805            s/^#>>(.*)(__MVR_(\w+)__.*)\n\1.*/#>>$1$2/g;
1806            s/^#>>(.*__MVR_(\w+)__.*)/#>>$1\n$1/g;
1807            1 while s/\n([^#].*)__MVR_(.*)/\n$1__MVC_$2/g;
1808            s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
1809            print OUT $_;
1810		}
1811		close OUT;
1812		close IN;
1813		unlink ($file)
1814			or die "Couldn't unlink $name: $!\n";
1815		rename ("$file.new", $file)
1816			or die "Couldn't rename $name.new to $name: $!\n";
1817	}
1818	my %Xfile;
1819	if($Windows) {
1820		# None of this stuff applies for Windows, I don't think.
1821		# Put Win-specific stuff here.
1822	}
1823	else {
1824		set_owner($file);
1825		$mode = (stat($file))[2];
1826		if ($Xfile{$file}) {
1827			$mode |= 0550;
1828		}
1829		else {
1830			$mode |= 060 if $gmode;
1831			$mode |= 02010 if $gmode and -d $file;
1832		}
1833		chmod ($mode, $file)
1834			or die "\nCouldn't set permissions on $name: $!\n";
1835	}
1836}
1837
1838	$File::Find::dont_use_nlink = 1;
1839	set_owner("$Conf{relocate}$Conf{catroot}");
1840	File::Find::find(\&wanted, "$Conf{relocate}$Conf{catroot}");
1841
1842	$cginame = $Conf{cgiurl};
1843	$cginame =~ s:.*/::;
1844	$Conf{cgifile} = $cginame = "$Conf{relocate}$Conf{cgidir}/$cginame";
1845
1846	umask(022) unless $Conf{noumask};
1847
1848	unless ($prog eq 'NONE') {
1849		my $ask_cgi = 'y';
1850		if(-f $cginame) {
1851            $ask_cgi = prompt (
1852                            do_msg("Moving link, $cginame exists, overwrite? "),
1853                            'n',
1854                            );
1855        }
1856        else {
1857            print do_msg("Moving link program to $cginame");
1858        }
1859
1860		if(is_yes($ask_cgi)) {
1861			File::Copy::copy("$Conf{relocate}$Conf{catroot}/executable", $cginame)
1862				or die
1863				"\nCouldn't copy link executable from $prog to $cginame: $!\n";
1864			chmod 0755, $cginame
1865					or die "\nCouldn't make $cginame executable: $!\n";
1866			unlink "$Conf{relocate}$Conf{catroot}/executable";
1867		}
1868
1869		if($isroot) {
1870			chown ($mvuid, $mvgid, $cginame)
1871				or die "\nCouldn't set ownership of $cginame: $!\n";
1872		}
1873
1874		unless ($Windows or $Inetmode or $CGIwrap) {
1875			unless ($isroot or can_do_suid()) {
1876				print <<EOF;
1877
1878My test indicates you can't change vlink to SUID mode.
1879This will cause big problems -- you can make Interchange work anyway
1880by changing the ReadPermission and WritePermission directives in
1881all of your catalogs to 'world', but this is not secure. If you can,
1882you should run this as root, or su to root and do:
1883
1884	chmod 4755 $cginame
1885
1886EOF
1887				$ask = prompt("Continue? ", 'n');
1888				unless($Vend::MakeCat::Force) {
1889					exit 2 unless is_yes($ask);
1890				}
1891			}
1892
1893			chmod 04755, $cginame
1894				or warn "\nCouldn't set permissions on $cginame: $!\n";
1895		}
1896
1897		print "done.\n";
1898
1899		if($CGIwrap and $isroot) {
1900			print <<EOF;
1901Since you selected the SUEXEC/CGIwrap option and are root, we aren't sure
1902which user and group you intended to own the link program. We have selected
1903the catalog user's UID/GID ($catuid/$catgid), but this may not match your
1904server definition. If you get a server error, change the ownership to its
1905proper value and ensure that the SUID bit is turned off on the link
1906program ($cginame).
1907
1908EOF
1909			chown($catuid, $catgid, $cginame) or die "\nchown $cginame: $!\n";
1910			prompt("Press <ENTER> to continue....");
1911		}
1912	}
1913
1914	my $chg_to_catuser = sub {
1915							next if -l $_;
1916							$File::Find::prune = 1 if -f _;
1917							my $mode = (stat(_))[2];
1918							$mode |= 044;
1919							$mode |= 011 if -d $_;
1920							chmod( $mode, $_)
1921								or die "\nchmod $_ to $mode: $!\n";
1922							chown($catuid, $catgid, $_)
1923								or die "\nchown $_: $!\n";
1924
1925						 };
1926
1927	unless ($Conf{sharedir} eq 'NONE') {
1928		print do_msg("Copying share/ files to $Conf{relocate}$Conf{sharedir}");
1929		my $oldpwd = cwd();
1930		my @sharedirs;
1931		eval {
1932			chdir "$Conf{relocate}$Conf{vendroot}"
1933				or die "\nchdir $Conf{relocate}$Conf{vendroot}: $!\n";
1934			# remember directories so we can chown below
1935			chdir "share" or die "error.\nchdir 'share': $!\n";
1936			map { push @sharedirs, $_ if -d $_ } glob('*');
1937			chdir "..";
1938			copy_dir("share", "$Conf{relocate}$Conf{sharedir}") or die;
1939		};
1940		if (! @sharedirs) {
1941			print "none found.\n";
1942		}
1943		elsif ($@) {
1944			print "error.\nError installing share/ files: $@\n";
1945		} else {
1946			File::Find::find(
1947				$chg_to_catuser,
1948				map { "$Conf{relocate}$Conf{sharedir}/$_" } @sharedirs
1949			) if $isroot;
1950			print "done.\n";
1951		}
1952		chdir $oldpwd;
1953	}
1954
1955	my $ok = 0;
1956	unless($Conf{samplehtml} eq 'NONE') {
1957		print do_msg("Moving HTML files to $Conf{samplehtml}");
1958		eval {
1959			chdir 'html' or ++$ok and die "\nchdir html: $!\n";
1960			copy_current_to_dir("$Conf{relocate}$Conf{samplehtml}");
1961			chdir '..';
1962			File::Path::rmtree('html');
1963		};
1964
1965		if($@ and !$ok) {
1966			die "\nCouldn't move HTML files to $Conf{relocate}$Conf{samplehtml}: $@\n";
1967		}
1968		elsif ($ok) {
1969			warn "\nHTML dir copy error: $!\nTrying to continue.\n";
1970		}
1971		else {
1972			File::Find::find( $chg_to_catuser, "$Conf{relocate}$Conf{samplehtml}")
1973				if $isroot;
1974		}
1975
1976		print "done.\n";
1977	}
1978
1979	$ok = 0;
1980	unless($Conf{imagedir} eq 'NONE') {
1981		print do_msg("Moving image files to $Conf{imagedir}");
1982		eval {
1983			chdir 'images' or ++$ok and die "chdir images: $!\n";
1984			copy_current_to_dir("$Conf{relocate}$Conf{imagedir}");
1985			chdir '..';
1986			File::Path::rmtree('images');
1987		};
1988
1989		if($@ and !$ok) {
1990			die "\nCouldn't move image files $Conf{relocate}$Conf{imagedir}: $@\n";
1991		}
1992		elsif ($ok) {
1993			warn "\nImage dir copy error: $!\nTrying to continue.\n";
1994		}
1995		else {
1996			File::Find::find($chg_to_catuser, "$Conf{relocate}$Conf{imagedir}")
1997				if $isroot;
1998		}
1999
2000		print "done.\n";
2001	}
2002
2003	chdir "$Conf{relocate}$Conf{vendroot}"
2004		or die "\nCouldn't change directory to $Conf{relocate}$Conf{vendroot}: $!\n";
2005
2006	my $pidfile;
2007	for(qw! etc/interchange.pid etc/minivend.pid etc/interchange.pid !) {
2008		$pidfile = $_;
2009		last if -f $_;
2010	}
2011
2012	PID: {
2013		local ($/);
2014		open(PID,"+<$pidfile") or last PID;
2015
2016		# If we get lock we are not running
2017		unless($Windows) {
2018			lockfile(\*PID,1,0)  and last PID;
2019		}
2020
2021		$pid = <PID>;
2022		$pid =~ /(\d+)/;
2023		$pid = $1;
2024	}
2025
2026}
2027
2028POSTCMD: {
2029	last POSTCMD unless -f "$dir/config/postcopy_commands";
2030	open(ADDL, "< $dir/config/postcopy_commands")
2031		or last POSTCMD;
2032	print "\nFound additional system commands to run.\n\n";
2033	local ($/) = "";
2034	while(<ADDL>) {
2035		my $unprompted;
2036		s/\s+$//;
2037		s/__MVC_([A-Z0-9]+)(__)?/substitute($1,$2)/eg;
2038		my ($command, $prompt) = split /\n/, $_, 2;
2039		$command =~ s/^\s+//;
2040		$command =~ s/\s+$//;
2041		$command =~ s/^!// and $unprompted = 1;
2042		if($command =~ s/{\s*([A-Z0-9]+)(\s*\S.*?)?\s*}\s*//) {
2043			my $param = $1;
2044			my $test = $2;
2045			my $v = $Conf{lc $param};
2046			$v = "q{$v}";
2047			my $true;
2048			eval {
2049				$true = eval "$v$test";
2050			};
2051			next unless $true;
2052		}
2053		print "$prompt\n\n";
2054		print "Running: $command\n" if $unprompted;
2055		my $ans = $unprompted ? 'y' : prompt( qq{run "$command"? }, 'y' );
2056		if($ans =~ /^\s*y/i) {
2057			system $command;
2058			if($?) {
2059				print "\nCommand returned error code " . ($? >> 8) . ": $!\n";
2060			}
2061		}
2062		else {
2063			print "\nskipping '$command'\n";
2064		}
2065	}
2066	close ADDL;
2067}
2068	my $add;
2069	my $add_tcp;
2070	my $add_inet;
2071
2072	umask(07) unless $Conf{noumask};
2073
2074	$add = prefix('nocfg') ? 'n' : 'y';
2075	if ($Conf{catalogconf}) {
2076		$yes = prompt "Add catalog to $Conf{catalogconf}? ", $add;
2077	} else {
2078		$yes = prompt "Add catalog to $Global::ConfigFile? ", $add;
2079	}
2080	$add = prefix('norunning') ? 'n' : 'y';
2081
2082	if($yes and $Inetmode) {
2083		$add_tcp = prompt "Add port $lp to TcpMap in interchange.cfg if necessary? ", $add;
2084		$add_tcp = is_yes($add_tcp);
2085		$add_inet = prompt "Set Interchange to run in INET mode if necessary? ", $add;
2086		$add_inet = is_yes($add_inet);
2087	}
2088
2089	if($pid) {
2090		$add_to_running = prompt "Add catalog to server running on PID $pid? ", $add;
2091		$add_to_running = is_yes($add_to_running);
2092	}
2093
2094	my $full = '';
2095	my $newcfgline;
2096	my $tcpmark;
2097
2098	$newcfgline = sprintf "%-10s %s %s %s %s\n", 'Catalog',
2099				$catalog_name, $Conf{catroot}, $full . $Conf{cgiurl}, $Conf{aliases};
2100
2101	if( is_yes($yes) ) {
2102		my ($newcfgline, $mark, @out);
2103		my $tmpfile;
2104
2105		if ($Conf{catalogconf}) {
2106			$tmpfile = "$Conf{catalogconf}.$$";
2107			File::Copy::copy ($Conf{catalogconf}, $tmpfile)
2108					or die "\nCouldn't copy $Conf{catalogconf}: $!\n";
2109        } else {
2110        	$tmpfile= "$Global::ConfigFile.$$";
2111			if (-f $Global::ConfigFile) {
2112				File::Copy::copy ($Global::ConfigFile, $tmpfile)
2113					or die "\nCouldn't copy $Global::ConfigFile: $!\n";
2114			}
2115			else {
2116				my @cf = ("$Global::ConfigFile.dist", "$Global::VendRoot/interchange.cfg.dist");
2117				my $cf;
2118				for(@cf) {
2119					$cf = $_ if -f $_;
2120				}
2121
2122				File::Copy::copy($cf, $tmpfile)
2123					or die "\nCouldn't copy $cf: $!\n";
2124			}
2125		}
2126
2127		open(CFG, "< $tmpfile")
2128			or die "\nCouldn't open $tmpfile: $!\n";
2129		while(<CFG>) {
2130			$mark = $. if /^#?catalog\s+/i;
2131			print "\nDeleting old configuration $catalog_name.\n"
2132				if s/^(catalog\s+$catalog_name\s+)/#$1/io;
2133			$full = is_yes($1)
2134				if /^\s*fullurl\s+(.*)/i;
2135			if ($add_tcp and /^tcpmap\s+/i and $_ !~ /\b$lh:$lp\b/) {
2136				$tcpmark = /^tcpmap\s+[^<]+$/i ? $. : $. + 1;
2137				$tcpmark-- if $mark;
2138			}
2139			push @out, $_;
2140		}
2141		close CFG;
2142
2143		if($full) {
2144			$full = $Conf{servername};
2145		}
2146
2147		if ($Conf{catalogconf}) {
2148			open(NEWCFG, ">$Conf{catalogconf}")
2149				or die "\nCouldn't write $Conf{catalogconf}: $!\n";
2150		} else {
2151			open(NEWCFG, ">$Global::ConfigFile")
2152				or die "\nCouldn't write $Global::ConfigFile: $!\n";
2153		}
2154
2155		$newcfgline = sprintf "%-13s %s %s %s %s\n", 'Catalog',
2156				$catalog_name, $Conf{catroot}, $full . $Conf{cgiurl}, $Conf{aliases};
2157
2158		if($tcpmark) {
2159			$out[$tcpmark] =~ s/\s*$/ $lh:$lp -\n/;
2160		}
2161
2162		if($add_inet) {
2163			my $found_inetmode;
2164			for(@out) {
2165				next unless /^\s*inet_mode\s+/i;
2166				$_ = "Inet_Mode Yes\n";
2167				$found_inetmode = 1;
2168				last;
2169			}
2170			if(! $found_inetmode) {
2171				push @out, "Inet_Mode Yes\n";
2172			}
2173		}
2174
2175		if (defined $mark) {
2176			print NEWCFG @out[0..$mark-1];
2177			print NEWCFG $newcfgline;
2178			print NEWCFG @out[$mark..$#out];
2179		}
2180		else {
2181			$newconfig = 1;
2182			print "\nNo catalog previously defined. Adding $catalog_name at top.\n";
2183			print NEWCFG $newcfgline;
2184			print NEWCFG @out;
2185		}
2186
2187		close NEWCFG || die "close: $!\n";
2188		unlink $tmpfile;
2189		if($isroot) {
2190			chown ($mvuid, $mvgid, $Global::ConfigFile)
2191				or warn "Couldn't set ownership of '$Global::ConfigFile': $!\n";
2192		}
2193	}
2194	else {
2195		print <<EOF;
2196You will need to add the following line to your $Global::ConfigFile file
2197to activate the catalog.
2198
2199$newcfgline
2200
2201EOF
2202	}
2203
2204	$newcfgline = sprintf "%-13s %s %s %s %s\n", 'Catalog',
2205				$catalog_name, $Conf{catroot}, $full . $Conf{cgiurl}, $Conf{aliases};
2206
2207	if($add_to_running) {
2208		my $fn = 'etc/restart';
2209		open(RESTART, ">>$fn") or
2210				die "Couldn't write $fn to add catalog: $!\n";
2211		Vend::Util::lockfile(\*RESTART, 1, 1) 	or die "lock $fn: $!\n";
2212		printf RESTART $newcfgline;
2213		Vend::Util::unlockfile(\*RESTART) 		or die "unlock $fn: $!\n";
2214		close RESTART;
2215		if($isroot) {
2216			chown ($mvuid, $mvgid, $fn)
2217				or warn "\nCouldn't set ownership of $fn: $!\n";
2218		}
2219		unless ($Windows) {
2220			kill 'HUP', $pid;
2221			sleep 1;
2222		}
2223		$fn = 'etc/reconfig';
2224		open(RESTART, ">>$fn") or
2225				die "Couldn't write $fn to add catalog: $!\n";
2226		Vend::Util::lockfile(\*RESTART, 1, 1) 	or die "lock $fn: $!\n";
2227		printf RESTART $full . $Conf{cgiurl} . "\n";
2228		if($isroot) {
2229			chown ($mvuid, $mvgid, $fn)
2230				or warn "\nCouldn't set ownership of $fn: $!\n";
2231		}
2232		Vend::Util::unlockfile(\*RESTART) 		or die "unlock $fn: $!\n";
2233		close RESTART;
2234		unless ($Windows) {
2235			kill 'HUP', $pid;
2236		}
2237	}
2238
2239    my $start_string = $> == 0
2240				? qq(su -c "$Conf{vendroot}/bin/interchange -r" $Conf{interchangeuser})
2241				: "$Conf{vendroot}/bin/interchange -r";
2242
2243	print <<EOF;
2244
2245Done with installation. If my reading of your input is correct, you
2246should be able to access the demo catalog with the following URL:
2247
2248	$Conf{sampleurl}
2249
2250In any case, you should get direct access at:
2251
2252	http://$Conf{servername}$Conf{cgiurl}
2253
2254That is, after you START or RESTART the Interchange server.  8-)
2255It is best done with:
2256
2257	$start_string
2258
2259EOF
2260	CHECKEXPIRE: {
2261		my $dbm;
2262		my $message;
2263		eval { require GDBM_File; $dbm = 1; };
2264		eval { require DB_File;   $dbm = 1; };
2265
2266		if(! $Windows and $dbm) {
2267
2268			print <<EOF;
2269For session expiration, you might want to place a line like this in your
2270crontab:
2271
227244 4 * * * $Conf{vendroot}/bin/expireall -r
2273
2274It will prevent the session databases from getting too large.
2275
2276EOF
2277
2278		}
2279		else {
2280			print <<EOF;
2281Remember to expire your session databases on a regular basis (see
2282the documentation for details).
2283
2284EOF
2285		}
2286	}
2287
2288	print "Good luck with Interchange!\n" if defined $newconfig;
2289
2290	if($Conf{'reference'}) {
2291		$Data::Dumper::Terse = 1;
2292		$Data::Dumper::Indent = 3;
2293		print STDOUT Vend::Util::uneval(\%Conf);
2294	}
2295
2296=head1 NAME
2297
2298makecat - Build an Interchange catalog from a template
2299
2300=head1 SYNOPSIS
2301
2302makecat [--options] name
2303
2304=head1 VERSION
2305
2306# $Id: makecat.PL,v 2.27 2007-08-09 13:40:57 pajamian Exp $
2307
2308=head1 INTRODUCTION
2309
2310The makecat program builds a Interchange catalog from a template based on your
2311server configuration.  It interrogates for parameters like the directories to
2312use, URL to base the catalog in, HTTP server definitions, and file ownership.
2313It is self-documenting in that it asks verbose questions and gives relevant
2314examples.
2315
2316On UNIX, if you want to check on something during the process you can
2317usually hit <CTRL-Z> to suspend the program and do something and then
2318type C<fg> to return to <makecat>. Also, if your input begins with
2319an exclamation mark (C<!>), it will be interpreted as a shell command.
2320An exclamation mark (C<!>) alone should drop you into a shell.
2321
2322If you have the C<Term::ReadLine::Perl> and C<Term::ReadKey> modules
2323installed, the <UP> and <DOWN> arrows will cycle between suggested defaults;
2324and the following features will be in place:
2325
2326    TAB       Completes file name
2327    <UP>      Cycle suggestion up
2328    <DOWN>    Cycle suggestion down
2329    <CTRL-P>  Cycle suggestion up
2330    <CTRL-N>  Cycle suggestion down
2331    <CTRL-B>  Go back one question (if possible)
2332    <CTRL-U>  Erase line
2333    <LEFT>    Command-line editing left
2334    <RIGHT>   Command-line editing left
2335
2336Also, if you make a mistake at some stage of the interrogation, you can
2337often hit the <CTRL-B> key to return to the previous query. If you don't
2338have Term::ReadLine installed, then you can enter an at sign (C<@>) by
2339itself on the line.
2340
2341=head1 OPTIONS
2342
2343usage: makecat [options] [catalogname]
2344
2345The makecat program can build a catalog based completely on a command line
2346description. An example is in eg/makecat.sh.
2347
2348There are just a few flag-based options:
2349
2350=over 4
2351
2352=item C<-F>
2353
2354Force make of catalog with defaults supplied on command line.
2355
2356=item C<-c>
2357
2358Configuration file -- default is makecat.cfg in Interchange Confdir (etc) directory.
2359
2360=item C<-l>
2361
2362File to log to (default makecat.log)
2363
2364=item C<-r>
2365
2366Reconfigure defaults normally set in makecat.cfg; this is done automatically
2367the first time the program is run.
2368
2369=back
2370
2371The remainder of the options are supplied on the command line as named
2372parameters followed by an C<=> sign, followed by the value, i.e.
2373
2374  --parameter=value
2375
2376Normally, if C<makecat> supplies a default you might guess at that. It
2377is fairly intelligent if you have an Apache server and it has found the
2378httpd.conf file. If you are on a Netscape or other web server, it is
2379less likely to be right.
2380
2381The options set at reconfig time, i.e. the first time the program is run:
2382
2383=over 4
2384
2385=item --basedir=directory
2386
2387Base directory for catalogs. This defaults to C<catalogs> in the home
2388directory of the catalog user.
2389
2390=item --cgibase=url_fragment
2391
2392Base URL for link programs. This is normally either blank (your programs
2393are made with .cgi extension) or C</cgi-bin> (you have a CGI directory).
2394
2395=item --documentroot=directory
2396
2397The directory where HTML is based. This is the root directory of the
2398web server, i.e. DocumentRoot.
2399
2400=item --interchangegroup=group
2401
2402The default group files should be owned by.
2403
2404=item --interchangeuser=username
2405
2406The user ID which runs Interchange.
2407
2408=item --serverconf=filename
2409
2410Location of httpd.conf; you will be queried otherwise.
2411
2412=item --vendroot=filename
2413
2414Location of Interchange software.
2415
2416=item --homedir=directory
2417
2418Use instead of \$HOME to set defaults
2419
2420=back
2421
2422These are options which are required to be set for any catalog; the
2423default will often be correct if you have set the above options correctly.
2424
2425=over 4
2426
2427=item --catroot=directory
2428
2429Directory where Interchange catalog files go. This is the base directory
2430for this catalog.
2431
2432=item --cgidir=directory
2433
2434The directory the CGI link should go to. This is the CGI directory; if
2435your CGI programs all end in C<.cgi> then this would normally be the same
2436as C<documentroot>; if you have a C<cgi bin> directory it should be used.
2437
2438=item --servername=server
2439
2440Name of server (www.whatever.domain). You can supply a port:
2441
2442    www.foo.com:8080
2443
2444or a username:
2445
2446    www.foo.com/~bar
2447
2448For testing on your local machine, just use C<localhost>.
2449
2450=item --cgiurl=url_fragment
2451
2452The path to the CGI link (no server name). For a catalog named
2453C<standard>, this would normally be one of:
2454
2455    --cgiurl=/cgi-bin/standard
2456
2457or
2458
2459    --cgiurl=/standard.cgi
2460
2461
2462=item --demotype=template
2463
2464The template catalog. The default is <standard>.
2465
2466=item --mailorderto=email
2467
2468Email address to send orders
2469
2470=item --catuser=username
2471
2472The user files should be owned by (option only operative if C<root>).
2473
2474=back
2475
2476The rest of the parameters need not be supplied on the
2477command line as intelligent defaults can be derived from
2478the above parameters.
2479
2480=over 4
2481
2482=item --samplehtml=directory
2483
2484The directory where template HTML goes.
2485
2486=item --imagedir=directory
2487
2488The directory where template images go.
2489
2490=item --imageurl=url
2491
2492The URL to prefix images with.
2493
2494=item --sharedir=directory
2495
2496The directory where shared admin images go.
2497
2498=item --shareurl=url
2499
2500The URL to prefix shared admin images with.
2501
2502=item --nocfg
2503
2504Don't add to interchange.cfg.
2505
2506=item --nocopy
2507
2508Don't actually copy the files, just test.
2509
2510=item --norunning
2511
2512Don't add to running server.
2513
2514=item --reference
2515
2516Return hash of config as string (sets C<-F>, no write). This is for
2517passing back to the makecat program in a autobuild environment.
2518
2519=item --linkprogram=file
2520
2521Use file as link program instead of vlink/tlink.
2522
2523=item --linkmode=mode
2524
2525UNIX or INET (link program vlink or tlink).
2526
2527=item --sampleurl=url
2528
2529URL to access HTML for catalog.
2530
2531=item --noumask
2532
2533Don't set umask to the value implied by mode.
2534
2535=item --catalogconf=file
2536
2537Use file as configuration file for catalog definitions. This option
2538has been designed for the use with Debian installations.
2539
2540=back
2541
2542=head1 DESCRIPTION
2543
2544C<makecat> needs a template catalog to operate on. The I<Foundation
2545Store> demo template is distributed with Interchange. You can
2546also look for additional demo catalogs (mostly for ideas) at
2547http://www.icdevgroup.org/
2548
2549B<IMPORTANT NOTE:> You only make a catalog once. All further configuration
2550is done by editing the files within the I<catalog directory>.
2551
2552A catalog template contains an image of a configured catalog. The best
2553way to see what the makecat program does is to configure the 'standard'
2554demo and then run a recursive C<diff> on the template and configured
2555catalog directories:
2556
2557  diff -r interchange/standard catalogs/standard
2558
2559You will see that the files are mostly the same, except that certain
2560macro strings have been replaced with the answers you gave to the script.
2561For example, if you answered C<www.mydomain.com> at the prompt
2562for server name, then you would see this difference in the catalog.cfg file:
2563
2564    # template
2565    Variable SERVER_NAME  __MVC_SERVERNAME__
2566
2567    # configured catalog
2568    Variable SERVER_NAME  www.mydomain.com
2569
2570The macro string __MVC_SERVERNAME__ was substituted with the answer to
2571the question about server name.  In the same way, other variables are
2572substituted, and include (at least):
2573
2574    MVC_BASEDIR      MVC_IMAGEDIR
2575    MVC_CATROOT      MVC_IMAGEURL
2576    MVC_CATUSER      MVC_MAILORDERTO
2577    MVC_CGIBASE      MVC_MINIVENDGROUP
2578    MVC_CGIDIR       MVC_MINIVENDUSER
2579    MVC_CGIURL       MVC_SAMPLEHTML
2580    MVC_DEMOTYPE     MVC_SAMPLEURL
2581    MVC_DOCUMENTROOT MVC_VENDROOT
2582    MVC_ENCRYPTOR
2583
2584(Not all of these are present in the standard template, and
2585quite a few more may be defined.)  In fact, any environment variable that
2586is set and begins with MVC_ will be substituted for by the C<makecat>
2587script. So if you wanted to set up a configurable parameter to customize
2588the COMPANY variable in catalog.cfg, you could run a pre-qualifying
2589script that set the environment variable MVC_COMPANY and then place in
2590the catalog.cfg file:
2591
2592    Variable   COMPANY   __MVC_COMPANY__
2593
2594All files within a template directory are substituted for macros,
2595not just the catalog.cfg file. There are two special directories
2596named C<html> and C<images>. These will be recursively copied to
2597the directories defined as SampleHTML and ImageDir.
2598
2599B<IMPORTANT NOTE:> The template directory is located in the Interchange
2600software directory, i.e. where C<interchange.cfg> resides. You normally do
2601not edit files in the template directory.  If you want to try creating
2602your own template, it is recommended that you name it something besides
2603standard and copy the C<standard> demo directory to it as a starting point.
2604Templates are normally placed in the Interchange base directory, but can
2605be located anywhere -- the script will prompt you for location if it
2606cannot find a template.
2607
2608In addition to the standard parameters prompted for by Interchange, and
2609the standard catalog creation procedure, you may define four other
2610files in the C<config> directory of the template:
2611
2612    additional_fields  -- file with more parameters for macro substitution
2613    additional_help    -- extended description for the additional_fields
2614    precopy_commands   -- commands passed to the system prior to catalog copy
2615    postcopy_commands  -- commands passed to the system after catalog copy
2616
2617All files are paragraph-based; in other words, a blank line (with no spaces)
2618terminates the individual setting.
2619
2620The I<additional_fields> file contains:
2621
2622    PARAM
2623    The prompt. Set PARAM to?
2624    The default value of PARAM
2625
2626This would cause a question during makecat:
2627
2628    The prompt. Set PARAM to?.....[The default value of PARAM]
2629
2630If the I<additional_help> file is present, you can give additional
2631instructions for PARAM.
2632
2633    PARAM
2634    These are additional instructions for PARAM, and they
2635    may span multiple lines up to the first blank line.
2636
2637The prompt would now be:
2638
2639    These are additional instructions for PARAM, and they
2640    may span multiple lines up to the first blank line.
2641
2642    The prompt. Set PARAM to?.....[The default value of PARAM]
2643
2644If the file I<config/precopy_commands> exists, it will be read as
2645a command followed by the prompt/help value.
2646
2647    mysqladmin create __MVC_CATALOGNAME__
2648    We need to create an SQL database for your Interchange
2649    database tables.
2650
2651This will cause the prompt:
2652
2653    We need to create an SQL database for your Interchange
2654    database tables.
2655
2656    Run command "mysqladmin create test_standard"?
2657
2658If the response is "y" or "yes", then the command will be run
2659by passing it through the Perl system() function. As with any
2660of the additional configuration files, MVC_PARAM macro substitution
2661is done on the command and help. Obviously you must have proper
2662permissions for the command.
2663
2664The file I<config/postcopy_commands> is exactly the same as I<precopy_commands>
2665except you are prompted I<after> the catalog files are copied and
2666macro substitution is performed on all files.
2667
2668=head1 ABOUT INTERCHANGE IN GENERAL
2669
2670Interchange has many, many, functions and features; they are too numerous
2671to describe in this venue. Complete information can be found at
2672its web site:
2673
2674        http://www.icdevgroup.org/
2675
2676Interchange requires Perl 5.6.0 or higher; more information on Perl can
2677be seen at:
2678
2679        http://www.perl.com/
2680
2681=head1 SEE ALSO
2682
2683interchange(1)
2684
2685=head1 LICENSE
2686
2687Interchange comes with ABSOLUTELY NO WARRANTY. This is free software, and
2688you are welcome to redistribute and modify it under the terms of the
2689GNU General Public License.
2690
2691=head1 COPYRIGHT
2692
2693Copyright 2002-2007 Interchange Development Group.
2694Copyright 1995-2002, Red Hat, Inc.
2695All rights reserved except as in the license.
2696
2697=cut
2698
2699=head1 AUTHOR
2700
2701Mike Heins, <mike@perusion.com>. Please do not contact the author for
2702direct help with the system. Use the Interchange mail list:
2703
2704    interchange-users
2705
2706Information on subscribing to the list, and general information and
2707documentation for Interchange is at:
2708
2709    http://www.icdevgroup.org/
2710
2711=cut
2712
2713__END__
2714
2715[catalog standard]
2716basedir         =
2717catroot         =
2718catuser         =
2719cgibase         =
2720cgibin          =
2721cgidir          =
2722cgiurl          =
2723demotype        = standard
2724documentroot    =
2725imagedir        =
2726imageurl        =
2727mailorderto     =
2728interchangegroup=
2729interchangeuser =
2730samplehtml      =
2731sampleurl       =
2732servername      =
2733vendroot        =
2734
2735[base]
2736permtype=
2737basedir=
2738cgidir=
2739cgibase=
2740documentroot=
2741sharedir=
2742shareurl=
2743interchangegroup=
2744interchangeuser=
2745serverconf=
2746servername=
2747vendroot=
2748linkmode=
2749
2750# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2751#
2752# DO NOT EDIT BELOW HERE
2753#
2754# These are global parameters used by the program
2755# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
2756
2757[global]
2758#
2759# All params allowed
2760#
2761params=<<EOF
2762aliases
2763basedir
2764catroot
2765catuser
2766cgibase
2767cgibin
2768cgidir
2769cgiurl
2770demotype
2771documentroot
2772imagedir
2773imageurl
2774linkmode
2775mailorderto
2776interchangegroup
2777interchangeuser
2778samplehtml
2779sampleurl
2780serverconf
2781servername
2782sharedir
2783shareurl
2784vendroot
2785EOF
2786
2787catparams=<<EOF
2788aliases
2789catroot
2790catuser
2791cgidir
2792cgiurl
2793demotype
2794documentroot
2795imagedir
2796imageurl
2797mailorderto
2798interchangegroup
2799interchangeuser
2800samplehtml
2801sampleurl
2802servername
2803EOF
2804
2805#
2806# Default (base) parameters to ask about, in order
2807#
2808askbase=<<EOF
2809cgidir
2810cgibase
2811documentroot
2812sharedir
2813shareurl
2814vendroot
2815basedir
2816interchangeuser
2817linkmode
2818EOF
2819
2820#
2821# Catalog parameters to ask about, in order
2822#
2823askconfig=<<EOF
2824demotype
2825permtype
2826interchangeuser
2827catuser
2828interchangegroup
2829mailorderto
2830catroot
2831cgidir
2832cgiurl
2833aliases
2834documentroot
2835samplehtml
2836imagedir
2837imageurl
2838EOF
2839
2840######## END GLOBAL SECTION ########
2841
2842# Simple test to make sure legal for config file
2843[legalconfig]
2844aliases=1
2845cgidir=1
2846cgiurl=1
2847catuser=1
2848demotype=1
2849imagedir=1
2850imageurl=1
2851mailorderto=1
2852interchangeuser=1
2853interchangegroup=1
2854permtype=1
2855samplehtml=1
2856sampleurl=1
2857servername=1
2858catroot=1
2859
2860# Simple test to make sure legal for base file
2861[legalbase]
2862basedir=1
2863cgidir=1
2864cgibase=1
2865documentroot=1
2866interchangegroup=1
2867interchangeuser=1
2868serverconf=1
2869servername=1
2870sharedir=1
2871shareurl=1
2872vendroot=1
2873linkmode=1
2874