582 lines
19 KiB
Perl
Executable File
582 lines
19 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
#
|
|
# TWiki Enterprise Collaboration Platform, http://TWiki.org/
|
|
#
|
|
# Copyright (C) 2000-2007 TWiki Contributors.
|
|
#
|
|
# 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. For
|
|
# more details read LICENSE in the root of this distribution.
|
|
#
|
|
# 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.
|
|
#
|
|
# As per the GPL, removal of this notice is prohibited.
|
|
#
|
|
# Configuration script for TWiki. Once you have a basic webserver
|
|
# configuration that lets you access this script, the rest of the
|
|
# configuration process is done from here.
|
|
#
|
|
# The script works from the top down, by checking features of the
|
|
# environment before moving on. The sequence is:
|
|
# 1. Check the version of perl
|
|
# 2. Check we have the modules to run this script
|
|
# 3. Check the environment
|
|
# 4. Check we have the modules to load the rest of configure
|
|
# ... and so on. At any stage, the script reports any errors in the
|
|
# best way it can given the environment established so far.
|
|
# When the basic checks are complete, the script moves into the
|
|
# real configuration steps; setting configuration variables.
|
|
#
|
|
# This phase of the configure environment follows a Model-View-
|
|
# Controller pattern.
|
|
#
|
|
# Controller
|
|
# This script is the controller; it handles communication with the
|
|
# browser (and thus the user). Communication is very simple; this script
|
|
# is re-invoked with different 'action' parameters to determine what it does.
|
|
#
|
|
# Model
|
|
# The Model consists of a simple node tree, where each node represents a
|
|
# structural element in the *presentation* of the configuration (this may
|
|
# not be consistent with the structure of $TWiki:cfg, so beware). Each
|
|
# leaf node has an associated Type (in the Types subdirectory) that has
|
|
# collected model and view behaviours for the basic types.
|
|
# The Model is independent of the language used to represent the
|
|
# configuration. There is one parser/generator provided, TWikiCfg, but it
|
|
# would be trivial to add others.
|
|
#
|
|
# The View is a DOM document, generated as HTML by a set of UI classes.
|
|
# Because of some convoluted history, there are actually three sets of classes
|
|
# that generate views. They are all subclasses of TWiki::Configure::UI
|
|
# UIs - are top-level and pluggable UI components. All the main screens are
|
|
# implemented here.
|
|
# Checkers - are specialised UIs designed to give checking support for
|
|
# variable values. Checkers also include the read-only checking
|
|
# UIs used for checking environment.
|
|
# Types - provide some UI support in the form of type-specific prompters.
|
|
# this is really an abuse of the Model, but it saves creating
|
|
# decorator classes for all the Model types.
|
|
# HTML is generated for the model using Visitor pattern. Each node in the tree
|
|
# is visited in depth-first order.
|
|
#
|
|
use strict;
|
|
use warnings;
|
|
|
|
# This is absolutely essential for error reporting. We load it using
|
|
# an eval so we can report the problem.
|
|
eval "use CGI::Carp qw(fatalsToBrowser)";
|
|
if ($@) {
|
|
print <<"REPORT";
|
|
Content-type: text/plain
|
|
|
|
Could not load CGI::Carp. Please install this module before continuing.
|
|
It can be downloaded from http://www.cpan.org
|
|
|
|
The error seen was:
|
|
$@
|
|
REPORT
|
|
exit 1;
|
|
}
|
|
|
|
###########################################################
|
|
# VERY basic stuff required for configure to work. Any errors
|
|
# during this phase will throw a die, which will be picked up
|
|
# using CGI::Carp fatalsToBrowser
|
|
|
|
|
|
# Warnings are fatal
|
|
$SIG{'__WARN__'} = sub { die @_ };
|
|
|
|
eval 'require 5.008';
|
|
die $@ if $@;
|
|
|
|
my $localLibFailure;
|
|
|
|
sub _loadBasicModule {
|
|
my $module = shift;
|
|
|
|
eval "use $module";
|
|
if ($@) {
|
|
my $reason = <<HERE;
|
|
Could not load $module. Please ensure this module is installed
|
|
and available on the perl \@INC path before continuing. If the
|
|
module is already installed, but can't be found, you may need
|
|
to adjust your perl path, for example by setting PERL5LIB.
|
|
|
|
The error seen was:
|
|
$@
|
|
HERE
|
|
if ($localLibFailure) {
|
|
$reason .= <<HERE;
|
|
|
|
NOTE that I was unable to load LocalLib.cfg because of the following error:
|
|
|
|
$localLibFailure
|
|
HERE
|
|
}
|
|
die $reason;
|
|
}
|
|
}
|
|
|
|
foreach my $module ('FindBin',
|
|
'File::Spec',
|
|
'Config',
|
|
'CGI qw(:any)'
|
|
) {
|
|
_loadBasicModule($module);
|
|
}
|
|
|
|
# Capture DIE for stack *when debugging*
|
|
#$SIG{__DIE__} = sub { Carp::confess( $_[0] || '' ) };
|
|
|
|
###########################################################
|
|
# Establish the path to the TWiki library
|
|
|
|
# Set the working dir to the bin dir
|
|
no warnings;
|
|
$FindBin::Bin =~ /^(.*)$/;
|
|
use warnings;
|
|
chdir($1);
|
|
my @root = File::Spec->splitdir($1);
|
|
pop(@root);
|
|
my @script = File::Spec->splitdir($0);
|
|
my $scriptName = pop(@script);
|
|
|
|
# Try to load the LocalLib.cfg optional overload
|
|
|
|
# Paths from LocalLib.cfg (preferred)
|
|
use vars qw( $twikiLibPath @localPerlLibPath );
|
|
|
|
eval 'require "setlib.cfg"';
|
|
|
|
if ($@) {
|
|
# No joy. Remember the failure so we can report it later.
|
|
$localLibFailure = $@;
|
|
# Stick the root/lib on the path; there's a high probability we'll be
|
|
# able to find the bits of TWiki::Configure that way. We will report
|
|
# the setlib error later.
|
|
unshift(@INC, File::Spec->catfile(@root, 'lib'));
|
|
}
|
|
|
|
# Load all the bits of the configure module that we use
|
|
foreach my $module (
|
|
'TWiki::Configure::Checker',
|
|
'TWiki::Configure::JS',
|
|
'TWiki::Configure::CSS',
|
|
'TWiki::Configure::UI',
|
|
'TWiki::Configure::Root',
|
|
'TWiki::Configure::Valuer',
|
|
'TWiki::Configure::TWikiCfg',
|
|
'TWiki::Configure::Load',
|
|
) {
|
|
_loadBasicModule($module);
|
|
}
|
|
|
|
$| = 1; # no buffering
|
|
|
|
###########################################################
|
|
# From this point on we shouldn't have any more "fatal" (to configure)
|
|
# errors, so we can report errors in the browser (i.e. without using die)
|
|
|
|
# We are configuring $TWiki::cfg, so we need to be in package TWiki from
|
|
# now on.
|
|
package TWiki;
|
|
|
|
# We keep the actual config, and the default from TWiki.cfg, separate
|
|
use vars qw( %cfg $defaultCfg);
|
|
|
|
# Declared in TWiki to support checkers
|
|
use vars qw( $query );
|
|
|
|
# 'constants' used in TWiki.cfg
|
|
use vars qw( $TRUE $FALSE );
|
|
$TRUE = 1;
|
|
$FALSE = 0;
|
|
|
|
# Remember what we detected previously, for use by Checkers
|
|
if( $scriptName =~ /(\.\w+)$/ ) {
|
|
$TWiki::cfg{DETECTED}{ScriptExtension} = $1;
|
|
}
|
|
|
|
# very basic tool
|
|
sub findFileOnPath {
|
|
my $file = shift;
|
|
|
|
$file =~ s(::)(/)g;
|
|
|
|
foreach my $dir ( @INC ) {
|
|
if ( -e "$dir/$file" ) {
|
|
return "$dir/$file";
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
###########################################################
|
|
# Grope the OS. This duplicates a bit of code in TWiki.pm,
|
|
# but it has to be duplicated because we don't want to deal
|
|
# with loading TWiki just yet.
|
|
|
|
unless( $TWiki::cfg{DetailedOS} ) {
|
|
$TWiki::cfg{DetailedOS} = $^O;
|
|
unless( $TWiki::cfg{DetailedOS} ) {
|
|
require Config;
|
|
$TWiki::cfg{DetailedOS} = $Config::Config{osname};
|
|
}
|
|
}
|
|
unless( $TWiki::cfg{OS} ) {
|
|
if ($TWiki::cfg{DetailedOS} =~ /darwin/i) { # MacOS X
|
|
$TWiki::cfg{OS} = 'UNIX';
|
|
} elsif ($TWiki::cfg{DetailedOS} =~ /Win/i) {
|
|
$TWiki::cfg{OS} = 'WINDOWS';
|
|
} elsif ($TWiki::cfg{DetailedOS} =~ /vms/i) {
|
|
$TWiki::cfg{OS} = 'VMS';
|
|
} elsif ($TWiki::cfg{DetailedOS} =~ /bsdos/i) {
|
|
$TWiki::cfg{OS} = 'UNIX';
|
|
} elsif ($TWiki::cfg{DetailedOS} =~ /dos/i) {
|
|
$TWiki::cfg{OS} = 'DOS';
|
|
} elsif ($TWiki::cfg{DetailedOS} =~ /^MacOS$/i) { # MacOS 9 or earlier
|
|
$TWiki::cfg{OS} = 'MACINTOSH';
|
|
} elsif ($TWiki::cfg{DetailedOS} =~ /os2/i) {
|
|
$TWiki::cfg{OS} = 'OS2';
|
|
} else {
|
|
$TWiki::cfg{OS} = 'UNIX';
|
|
}
|
|
}
|
|
|
|
$query = new CGI;
|
|
|
|
my $url = $query->url();
|
|
my $action = $query->param('action') || 'Configure';
|
|
|
|
# Handle serving an image embedded in the configure page, before generating
|
|
# any other output
|
|
if( $action eq 'image' ) {
|
|
# SMELL: this call is correct, but causes a perl error
|
|
# on some versions of CGI.pm
|
|
# print $query->header(-type => $query->param('type'));
|
|
# So use this instead:
|
|
print 'Content-type: '.$query->param('type')."\n\n";
|
|
if( open(F, 'logos/'.$query->param('image' ))) {
|
|
local $/ = undef;
|
|
print <F>;
|
|
close(F);
|
|
}
|
|
exit 0;
|
|
}
|
|
|
|
my @meta = (
|
|
CGI::meta({ 'http-equiv'=>'Pragma', content=>'no-cache' }),
|
|
CGI::meta({ 'http-equiv'=>'Cache-Control', content=>'no-cache' }),
|
|
CGI::meta({ 'http-equiv'=>'Expires', content=>0 }),
|
|
CGI::meta({ name=>'robots', content=>'noindex' }),
|
|
CGI::Link( { -rel=>'icon',
|
|
-href=>$scriptName.'?action=image;image=favicon.ico;type=image/x-icon',
|
|
-type=>'image/x-icon' } ),
|
|
CGI::Link(
|
|
{ -rel=>'shortcut icon',
|
|
-href=>$scriptName.'?action=image;image=logos/favicon.ico;type=image/x-icon',
|
|
-type=>'image/x-icon' } ),
|
|
CGI::script( { language => 'JavaScript',
|
|
type => 'text/javascript' }, TWiki::Configure::JS::js1() ),
|
|
CGI::style( { -type=>'text/css' }, TWiki::Configure::CSS::css()),
|
|
CGI::script( { language => 'JavaScript',
|
|
type => 'text/javascript' },
|
|
TWiki::Configure::JS::js2() ),
|
|
);
|
|
|
|
# Generate standard page header
|
|
my $hdr = CGI::start_html(
|
|
-title => 'TWiki Configuration',
|
|
-head => \@meta,
|
|
-class => 'patternNoViewPage');
|
|
|
|
# XML header confuses IE, so strip it out. This is fixed in CGI.pm 3.06
|
|
# (and IE 7, but who's counting?)
|
|
if ($CGI::VERSION < 3.06) {
|
|
$hdr =~ s/^<\?xml.*?>//s;
|
|
}
|
|
print CGI::header('text/html'). $hdr;
|
|
|
|
print <<'HERE';
|
|
<div id="patternScreen">
|
|
<div id="patternPageShadow">
|
|
<div id="patternPage">
|
|
<div id="patternOuter">
|
|
<div id="patternFloatWrap">
|
|
<div id="patternMain">
|
|
<div id="patternMainContents">
|
|
HERE
|
|
|
|
# use this script recursively to serve the icon image
|
|
print CGI::img({src=>$scriptName.'?action=image;image=T-logo-140x40-t.gif;type=image/gif', class=>'logo', alt=>'TWiki', width=>'140', height=>'40'});
|
|
|
|
my $stub = new TWiki::Configure::Item();
|
|
my $sanityUI = TWiki::Configure::UI::loadChecker('BasicSanity', $stub);
|
|
print $sanityUI->ui();
|
|
|
|
# This is the dispatcher; $action is the name of the action to perform,
|
|
# this is concatenated to _action to determine the name of the procedure.
|
|
# Dispatcher methods return a boolean to indicate whether to generate a
|
|
# link back to the main page at the end.
|
|
unless ($sanityUI->insane() || $query->param('abort')) {
|
|
|
|
$action =~ s/\W//g;
|
|
my $method = '_action'.$action;
|
|
|
|
die "Undefined action $action" unless defined(&$method);
|
|
|
|
no strict 'refs';
|
|
my $reroute = &$method();
|
|
use strict 'refs';
|
|
|
|
if ($reroute) {
|
|
print '<div>';
|
|
print CGI::a( { href=>$TWiki::query->url().'?t='.time(),
|
|
rel => 'nofollow' },
|
|
'Return to configuration');
|
|
print CGI::br();
|
|
print "</div>\n";
|
|
}
|
|
}
|
|
|
|
print <<'HERE';
|
|
</div><!--/patternMainContents-->
|
|
</div><!--/patternMain-->
|
|
</div><!--/patternFloatWrap-->
|
|
<div class="clear"> </div>
|
|
</div><!--/patternOuter-->
|
|
</div><!--/patternPage-->
|
|
</div><!--/patternPageShadow-->
|
|
</div><!--/patternScreen-->
|
|
HERE
|
|
|
|
print CGI::end_html(),"\n";
|
|
|
|
###########################################################
|
|
# End of the main program; the rest is all subs
|
|
|
|
sub _checkLoadUI {
|
|
my ($uiname, $root) = @_;
|
|
my $ui = TWiki::Configure::UI::loadUI($uiname, $root);
|
|
unless ($ui) {
|
|
print "Could not load $uiname UI. Error was: <pre>$@</pre>";
|
|
if ($@ =~ /Can't locate (\S+)/) {
|
|
print <<HERE
|
|
You may be able to correct this error by installing the missing $1 module.
|
|
HERE
|
|
}
|
|
}
|
|
return $ui;
|
|
}
|
|
|
|
# Action invoked by 'Next' button on the main screen
|
|
sub _actionNext {
|
|
my $valuer = new TWiki::Configure::Valuer(
|
|
$TWiki::defaultCfg, \%TWiki::cfg);
|
|
my %updated;
|
|
my $modified = $valuer->loadCGIParams($TWiki::query, \%updated);
|
|
|
|
# create the root of the UI
|
|
my $root = new TWiki::Configure::Root();
|
|
my $ui;
|
|
if (!TWiki::Configure::UI::authorised()) {
|
|
print CGI::h2('Authorisation is required to save.');
|
|
print CGI::div($modified.' configuration item'.
|
|
($modified==1?' was':'s were').' changed');
|
|
if ($modified) {
|
|
print CGI::div(join(' ', keys %updated));
|
|
}
|
|
$ui = _checkLoadUI('AUTH', $root);
|
|
return 1 unless $ui;
|
|
print $ui->ui(1, 'Save');
|
|
} else {
|
|
# Load the specs from the .spec files and generate the UI template
|
|
TWiki::Configure::TWikiCfg::load($root);
|
|
|
|
$ui = _checkLoadUI('UPDATE', $root);
|
|
return 1 unless $ui;
|
|
print $ui->ui($root, $valuer, \%updated);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
# Invoked by "find more extensions" button in the Extensions section
|
|
sub _actionFindMoreExtensions {
|
|
print CGI::h1( 'Find TWiki Extensions');
|
|
print '<div class="patternContent"><div class="patternTopic">';
|
|
|
|
my $ui = _checkLoadUI('EXTENSIONS');
|
|
return 1 unless $ui;
|
|
|
|
print $ui->ui();
|
|
return 1;
|
|
}
|
|
|
|
# Invoked when an extension is to be installed
|
|
sub _actionInstallExtension {
|
|
my $root = new TWiki::Configure::Root();
|
|
my $ui;
|
|
if (!TWiki::Configure::UI::authorised()) {
|
|
$ui = _checkLoadUI('AUTH', $root);
|
|
return 1 unless $ui;
|
|
print $ui->ui(0, 'Install '.($query->param('extension')||''));
|
|
} else {
|
|
$ui = _checkLoadUI('EXTEND', $root);
|
|
return 1 unless $ui;
|
|
print $ui->ui();
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
# This is the default screen
|
|
sub _actionConfigure {
|
|
|
|
$TWiki::Configure::UI::toterrors = 0;
|
|
$TWiki::Configure::UI::totwarnings = 0;
|
|
|
|
print CGI::h1( 'Configuration');
|
|
|
|
# The first three sections go without a root
|
|
my $stub = new TWiki::Configure::Item();
|
|
my $eui = TWiki::Configure::UI::loadChecker('Environment', $stub);
|
|
|
|
# See if this platform has special detection or checking requirements
|
|
# (most don't)
|
|
$stub = new TWiki::Configure::Item();
|
|
my $osui = TWiki::Configure::UI::loadChecker(
|
|
$Config::Config{osname}, $stub);
|
|
|
|
$stub = new TWiki::Configure::Item();
|
|
my $cgiui = TWiki::Configure::UI::loadChecker('CGISetup', $stub);
|
|
|
|
# Use a separate root for the _saveable_ sections
|
|
my $root = new TWiki::Configure::Root();
|
|
my $valuer = new TWiki::Configure::Valuer(
|
|
$TWiki::defaultCfg, \%TWiki::cfg);
|
|
|
|
# Load the config structures.
|
|
TWiki::Configure::TWikiCfg::load($root);
|
|
|
|
print <<HERE;
|
|
<div class="patternContent">
|
|
<div class="patternTopic">
|
|
<p><strong>Use this page to set the configuration options for TWiki.
|
|
Fill in the settings, and then press 'Next'.</strong></p>
|
|
<div class="explanation">
|
|
<div class="specialRemark">
|
|
<b>If you are installing TWiki for the first time</b><br />
|
|
If you just want to get up and running, the only section you need to
|
|
worry about below is
|
|
<a rel="nofollow" href="#" onclick="foldBlock('GeneralPathSettings'); return false;">
|
|
General path settings</a>. You can always come back and configure other
|
|
settings later.
|
|
</div>
|
|
<ul>
|
|
<li><b>If your TWiki site is already working</b>, continue to
|
|
<a rel="nofollow" href="$TWiki::cfg{ScriptUrlPath}/view$TWiki::cfg{ScriptSuffix}/$TWiki::cfg{SystemWebName}/WebHome">
|
|
browse to the TWiki WebHome</a>.
|
|
<ul>
|
|
<li>You will now need to consider how you are going to manage
|
|
authentication and access control. See the reference manual
|
|
sections on <a rel="nofollow" href="$TWiki::cfg{ScriptUrlPath}/view$TWiki::cfg{ScriptSuffix}/$TWiki::cfg{SystemWebName}/TWikiUserAuthentication">
|
|
authentication</a>
|
|
and
|
|
<a rel="nofollow" href="$TWiki::cfg{ScriptUrlPath}/view$TWiki::cfg{ScriptSuffix}/$TWiki::cfg{SystemWebName}/TWikiAccessControl">
|
|
access control</a>, and the
|
|
<a rel="nofollow" href="#" onclick="foldBlock('SecuritySetup'); return false;">Security Setup</a>
|
|
section below.
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<b>If you are on an odd platform</b> there are a lot of topics on
|
|
TWiki.org describing
|
|
<a href="http://twiki.org/cgi-bin/view/Codev/CategoryCookbook">how to
|
|
configure TWiki for different platforms</a>.</li>
|
|
<li>
|
|
<b>If you get stuck</b> there is a lot of support available on
|
|
<a href="http://twiki.org/cgi-bin/view/Codev/TWikiIRC">TWikiIRC</a>
|
|
(irc.freenode.net, channel #twiki) and at
|
|
<a href="http://twiki.org/cgi-bin/view/Support/WebHome">TWiki:Support</a>.
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<div class="remark">Explanation of colours and symbols:
|
|
<ul style="margin-top:0;">
|
|
<li>Settings marked <span class='mandatory'>like this</span> are required
|
|
(they must have a value).</li>
|
|
<li>Any <span class='error'>errors</span> in your configuration will be
|
|
highlighted.</li>
|
|
<li><span class='warn'>Warnings</span> are non-fatal, but are often a good
|
|
indicator that something that is wrong.</li>
|
|
<li>The little <span class='twikiAlert' title="Not here, stupid. In the table below!">δ</span> after an entry means that the current value is <b>not</b> the same as the default value. If you hover the cursor over the <span class='twikiAlert' title="Not here, stupid. In the table below!">δ</span>, a popup will show you what the default value is.</li>
|
|
<li><b><font color="#f00">EXPERT</font></b> means a setting is for expert use only. You should not fiddle with it unless you know what you are doing, or at least have read all the documentation!</lib>
|
|
</ul>
|
|
</div><!-- remark-->
|
|
</div><!--explanation-->
|
|
HERE
|
|
|
|
print CGI::start_form({ name=>'update',
|
|
action=>$scriptName,
|
|
method=>"post" });
|
|
# use time to make sure we never allow cacheing
|
|
print CGI::hidden( 'time', time() );
|
|
|
|
print '<div class="options" id="options">';
|
|
print CGI::div(
|
|
{ class => 'optionHeader'},
|
|
CGI::span(
|
|
{ class => 'twikiLeft' },
|
|
'Settings' .
|
|
CGI::span(
|
|
{ class => 'twikiSmall' },
|
|
'Click the buttons below to open each section')).
|
|
CGI::span(
|
|
{ class => 'twikiSmall twikiRight' },
|
|
CGI::a(
|
|
{ href => '#', rel => 'nofollow',
|
|
onclick => 'toggleAllOptions(true); return false;'},
|
|
'Open all options')).
|
|
CGI::br());
|
|
|
|
print $eui->ui();
|
|
print $osui->ui() if $osui;
|
|
print $cgiui->ui() if $cgiui;
|
|
|
|
# Load the UI for the configuration and whack it out
|
|
my $ui = _checkLoadUI('Root', $root);
|
|
return 1 unless $ui;
|
|
|
|
print $ui->ui($root, $valuer);
|
|
|
|
print "</div><!-- options -->\n";
|
|
|
|
if ($TWiki::Configure::UI::toterrors || $TWiki::Configure::UI::totwarnings) {
|
|
my $mess = 'Total: '.$TWiki::Configure::UI::toterrors.' error'.
|
|
($TWiki::Configure::UI::toterrors==1?'':'s').', '.
|
|
$TWiki::Configure::UI::totwarnings.' warning'.
|
|
($TWiki::Configure::UI::totwarnings==1?'':'s');
|
|
print CGI::div($mess);
|
|
}
|
|
|
|
print CGI::p(CGI::submit(-class=>'twikiSubmit',
|
|
-name=>'action',
|
|
-value=>'Next',
|
|
-accesskey=>'N'));
|
|
print CGI::end_form();
|
|
|
|
print <<DIVS;
|
|
</div><!--/patternTopic-->
|
|
</div><!--/patternContent-->
|
|
DIVS
|
|
return 0;
|
|
}
|
|
|
|
1;
|
|
|