#!/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 = <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 ; 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';
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 '
'; print CGI::a( { href=>$TWiki::query->url().'?t='.time(), rel => 'nofollow' }, 'Return to configuration'); print CGI::br(); print "
\n"; } } print <<'HERE';
 
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:
$@
"; if ($@ =~ /Can't locate (\S+)/) { print <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 '
'; 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 <

Use this page to set the configuration options for TWiki. Fill in the settings, and then press 'Next'.

If you are installing TWiki for the first time
If you just want to get up and running, the only section you need to worry about below is General path settings. You can always come back and configure other settings later.
Explanation of colours and symbols:
  • Settings marked like this are required (they must have a value).
  • Any errors in your configuration will be highlighted.
  • Warnings are non-fatal, but are often a good indicator that something that is wrong.
  • The little δ after an entry means that the current value is not the same as the default value. If you hover the cursor over the δ, a popup will show you what the default value is.
  • EXPERT 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!
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 '
'; 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 "
\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 return 0; } 1;