#!/usr/bin/perl # # TWiki Enterprise Collaboration Platform, http://TWiki.org/ # # Copyright (C) 2000-2006 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. This script replaces # the old "testenv" script. # # The script works by accepting values into a CGI form, and then # submitting those values back to itself with a parameter (update) # set to 1. This causes it to write config changes to LocalSite.cfg. # Note that changes are only written if there is a real change in the # value. # # The values available to configuration are determined by parsing # TWiki.cfg. Special full-line comments guide the parse: # Any comment of the form #---+ Some text # is taken as a foldable block, and following comments are dragged in too. # ---++ is H3, ---+++ is H4 etc # Comments of the form # **TYPE opts** # where TYPE is one of URL, PATH, URLPATH, BOOLEAN, STRING, REGEX, SELECT, PASSWORD # are used to indicate that a following cfg var is configurable through # the interface. All intermediate comments are taken as documentation for # the value. # package TWiki; # BASIC checks. Without these, nothing works. use strict; use warnings; $SIG{__DIE__} = sub { Carp::confess( $_[0] || '' ) }; $SIG{'__WARN__'} = sub { die @_ }; use vars qw( %cfg $perlver $perlvernum $perlverRequired $perlverRequiredString $perlverRecommended $perlVerPreferred $ActivePerlRecommendedBuild $GUESSED $cgiModVerRecommended $modPerlVersionRecommended $rcsverRequired ); # Constants $perlvernum = $]; $perlverRequired = 5.00503; # Oldest supported version of Perl $perlverRequiredString = '5.005_03'; $perlverRecommended = '5.6.1'; $perlVerPreferred = 5.006; # 5.6 or higher has [:lower:] etc $ActivePerlRecommendedBuild = 631; # Fixes PERL5SHELL bugs $GUESSED = <<'HERE'; I guessed this setting. You are advised to confirm this setting (and any other guessed settings) and hit 'Next' to save before changing any other settings. HERE # CGI.pm version, on some platforms - actually need CGI 2.93 for mod_perl # 2.0 and CGI 2.90 for Cygwin Perl 5.8.0. See # http://perl.apache.org/products/apache-modules.html#Porting_CPAN_modules_to_mod_perl_2_0_Status $cgiModVerRecommended = '2.93'; # Recommended mod_perl version if using mod_perl 2.0 # (see Support.RegistryCookerBadFileDescriptor) $modPerlVersionRecommended = '1.99_12'; $rcsverRequired = 5.7; # constants used in TWiki.cfg use vars qw($TRUE $FALSE ); use vars qw( $basicMods $requiredMods $requiredModsNonUnix $optionalMods $I18Mods $I18Mods_perl56 $I18Mods_perl58 ); BEGIN { $TRUE = 1; $FALSE = 0; # Set default current working directory if( $ENV{SCRIPT_FILENAME} && $ENV{SCRIPT_FILENAME} =~ /^(.+)\/[^\/]+$/ ) { chdir $1; } # Get Perl version if (defined $^V) { $perlver = $^V; # New in Perl 5.6.1, one byte per part $perlver = ord(substr($perlver,0)) . "." . ord(substr($perlver,1)) . "." . ord(substr($perlver,2)); } else { $perlver = $perlvernum } # Required for configure to work $basicMods = { 'CGI' => "basic TWiki", 'CGI::Carp' => "basic TWiki", 'Error' => 'basic TWiki', }; $requiredMods = { 'File::Copy' => 'basic TWiki', 'File::Spec' => 'basic TWiki', 'FileHandle' => 'basic TWiki', 'Algorithm::Diff' => 'basic TWiki', }; # Required on non-Unix platforms (mainly Windows) $requiredModsNonUnix = { 'MIME::Base64' => "SHA1 password encoding", 'Net::SMTP' => "registration emails and mailnotify", }; # Optional modules on all platforms $optionalMods = { 'Digest::SHA1' => "SHA1 password encoding", 'MIME::Base64' => "HTTP Authentication to proxies, and SHA1 password encoding", 'POSIX' => "I18N (core module) and Security", 'Digest::MD5' => "MD5 encoded passwords", 'Text::Diff' => 'UpgradeTWiki', 'CGI::Cookie' => "sessions", 'CGI::Session' => "sessions", }; $I18Mods = { 'Locale::Maketext::Lexicon' => "I18N translations", }; $I18Mods_perl56 = { 'Unicode::String' => 'I18N conversions', 'Unicode::MapUTF8' => "I18N conversions", 'Unicode::Map' => "I18N conversions", 'Unicode::Map8' => "I18N conversions", 'Jcode' => "I18N conversions", }; $I18Mods_perl58 = { 'Encode' => "I18N conversions (core module in Perl 5.8)", }; }; ######################################################################## ##################### GLOBAL VARIABLES ################################# ######################################################################## use CGI qw( :any ); use vars qw( $cygwinRcsVerNum $perltype $query $action ); $query = new CGI; $action = $query->param('action') || ''; if( $action eq 'image' ) { _serveImage( $query->param('type'), $query->param('image' )); exit 0; } use vars qw( $errors $toterrors $warnings $totwarnings $url $nextid ); $errors = 0; # reset for each block $toterrors = 0; $warnings = 0; # reset for each block $totwarnings = 0; $url = $query->url(); $nextid = 0; ######################################################################## ########################## FORMATTING ################################## ######################################################################## # a note sub NOTE { return CGI::p({class=>"info"}, join("\n",@_)); } # a warning sub WARN { $warnings++; $totwarnings++; return CGI::div(CGI::span({class=>'warn'}, CGI::strong('Warning: ').join("\n",@_))); } # an error sub ERROR { $errors++; $toterrors++; return CGI::div(CGI::span({class=>'error'}, CGI::strong('Error: ').join("\n",@_))); } # Generate a foldable block (twisty). This is a DIV with a table in it # that contains the settings and doc rows. sub _foldableBlock { my( $head, $attr, $body ) = @_; my $headText = $head . CGI::span({ class => 'blockLinkAttribute' }, $attr); $body = CGI::start_table({width => '100%', -border => 0, -cellspacing => 0, -cellpadding => 0}).$body.CGI::end_table(); my $mess = ''; my $errorsMess = ($errors > 1) ? ' errors' : ' error'; my $warningsMess = ($warnings > 1) ? ' warnings' : ' warning'; $mess .= CGI::span({class=>'error'}, $errors . $errorsMess) if $errors; if ($errors && $warnings) { $mess .= ' '; } $mess .= CGI::span({class=>'warn'}, $warnings . $warningsMess) if $warnings; $errors = $warnings = 0; my $anchor = _makeAnchor( $head ); my $id = $anchor; my $blockId = $id; my $linkId = 'blockLink'.$id; my $linkAnchor = $anchor.'link'; return CGI::a({ name => $linkAnchor }). CGI::a( {id => $linkId, class => 'blockLink blockLinkOff', href => '#'.$linkAnchor, rel => 'nofollow', onclick => 'foldBlock(\'' . $id . '\'); return false;'}, $headText.$mess). CGI::div( { id => $blockId, class=> 'foldableBlock foldableBlockClosed' }, $body ). "\n"; } # Generate an ordinary inline headedblock sub _ordinaryBlock { my( $depth, $head, $attr, $body ) = @_; $head .= CGI::span({ class => 'blockLinkAttribute' }, $attr) if $attr; if( $depth == 2 ) { $head = CGI::h2( $head ); } elsif( $depth == 3 ) { $head = CGI::h3( $head ); } elsif( $depth == 4 ) { $head = CGI::h4( $head ); } elsif( $depth == 5 ) { $head = CGI::h5( $head ); } elsif( $depth == 6 ) { $head = CGI::h6( $head ); } else { $head = CGI::h6( $head ); } return CGI::Tr(CGI::td( { colspan => 2 } , $head)). $body; } # Generate a sub-heading table row sub _subHead { my $text = shift; return CGI::Tr(CGI::Td({class=>'subHead', colspan=>2}, $text)). "\n"; } # Generate a variable - prompt row sub _setting { my $key = shift; return CGI::Tr(CGI::td({class=>'firstCol'}, $key). CGI::td({class=>'secondCol'}, join(' ', @_))); } # generate a documentation table row sub _docBlock { my $desc = shift || ''; my $hidden = shift; if (length($desc) == 0 || $desc =~ /\A\s\Z/) { return ''; } if ($hidden) { return CGI::Tr( {class => 'hiddenRow' }, CGI::td( { colspan => 2, class=>'docdata info' }, $desc )). "\n"; } return CGI::Tr( CGI::td( { colspan => 2, class=>'docdata info' }, $desc )). "\n"; } # encode a string to make an HTML anchor sub _makeAnchor { my $str = shift; $str =~ s/\s(\w)/uc($1)/ge; $str =~ s/\W//g; return $str; } ######################################################################## ################### CHECKING SUPPORT ################################### ######################################################################## # Since Windows (without Cygwin) makes it hard to capture stderr # ('2>&1' works only on Win2000 or higher), and Windows will usually have # GNU tools in any case (installed for TWiki since there's no built-in # diff, grep, patch, etc), we only check for these tools on Unix/Linux # and Cygwin. sub _checkGnuProgram { my $prog = shift; my $n = ''; if( $TWiki::cfg{OS} eq 'UNIX' || $TWiki::cfg{OS} eq 'WINDOWS' && $perltype eq 'Cygwin' ) { $prog =~ s/^\s*(\S+)\s.*$/$1/; $prog =~ /^(.*)$/; $prog = $1; # check for taintedness die "$prog is tainted" unless eval { $n = $prog, kill 0; 1 }; my $diffOut = ( `$prog --version 2>&1` || ""); my $notFound = ( $? == -1 ); if( $notFound ) { $n = WARN("'$prog' program was not found on the", "current PATH."); } elsif ( $diffOut !~ /\bGNU\b/ ) { # Program found on path, complain if no GNU in version output $n = WARN("'$prog' program was found on the PATH", "but is not GNU $prog - this may cause", "problems. $diffOut"); } else { $diffOut =~ /(\d+(\.\d+)+)/; $n = "($prog is version $1)."; } } return $n; } sub _checkRCSProgram { my $key = shift; return 'Not used in this configuration.' unless $TWiki::cfg{StoreImpl} eq 'RcsWrap'; my $mess = ''; my $err = ''; my $prog = $TWiki::cfg{RCS}{$key} || ''; $prog =~ s/^\s*(\S+)\s.*$/$1/; $prog =~ /^(.*)$/; $prog = $1; if( !$prog ) { $err .= $key.' is not set'; } else { my $version = `$prog -V` || ''; if( $@ ) { $err .= ERROR($prog.' returned an error: '.$@ ); } elsif ( $version ne '' ) { $version =~ /(\d+(\.\d+)+)/; $version = $1; $mess .= " ($prog is version $version)"; } else { $err .= ERROR($prog.' did not return a version number (or might not exist..)'); } if( defined( $cygwinRcsVerNum )) { $mess .= " (Cygwin package rcs-$cygwinRcsVerNum)"; } if( $version && $version < $rcsverRequired ) { # RCS too old $err .= $prog.' is too old, upgrade to version '. $rcsverRequired.' or higher.'; } } if( $err ) { $mess .= ERROR( $err .<$name" ) || return 'Could not create test file '. $name; print FILE $txt1; close( FILE); open( IN_FILE, "<$name" ) || return 'Could not read test file '. $name; my $txt2 = ; close( IN_FILE ); unlink $name if( -e $name ); unless ( $txt2 eq $txt1 ) { return 'Could not write and then read '.$name; } return ''; } sub _checkTreePerms { my( $path, $perms, $filter ) = @_; return '' if( defined($filter) && $path !~ $filter && !-d $path); #lets ignore Subversion directories return '' if( $path !~ /_svn/ ); return '' if( $path !~ /.svn/ ); my $errs = ''; return $path. ' cannot be found'.CGI::br() unless( -e $path ); if( $perms =~ /r/ && !-r $path) { $errs .= ' readable'; } if( $perms =~ /w/ && !-d $path && !-w $path) { $errs .= ' writable'; } if( $perms =~ /x/ && !-x $path) { $errs .= ' executable'; } return $path.' is not '.$errs.CGI::br() if $errs; return '' unless -d $path; opendir(D, $path) || return 'Directory '.$path.' is not readable.'.CGI::br(); foreach my $e ( grep { !/^\./ } readdir( D )) { my $p = $path.'/'.$e; $errs .= _checkTreePerms( $p, $perms, $filter ); } closedir(D); return $errs; } sub _findFileOnPath { my $file = shift; $file =~ s(::)(/)g; foreach my $dir ( @INC ) { if ( -e "$dir/$file" ) { return "$dir/$file"; } } return undef; } # Try and locate a required directory sub _findMajorDir { my( $cfg, $dir ) = @_; return '' if( $TWiki::cfg{$cfg} && $TWiki::cfg{$cfg} ne 'NOT SET'); my $guess = $ENV{SCRIPT_FILENAME}; unless( $guess ) { return WARN("This web server does not set SCRIPT_FILENAME so I can't guess a value for this"); } $guess =~ s(bin/*configure$)(); $guess .= $dir; $TWiki::cfg{$cfg} = $guess; return WARN($GUESSED); } sub _warnAboutWindowsBackSlashes { my ( $path ) = @_; if ( $path =~ /\\/ ) { return WARN('You should use c:/path style slashes, not c:\path in "'.$path.'"'); } } ######################################################################## ##################### PROMPT GENERATORS ################################ ######################################################################## # generate an input field for password types sub _PROMPT_FOR_PASSWORD { my( $id, $opts, $value, $keys ) = @_; my $size = "55%"; if( $opts =~ /\s(\d+)\s/ ) { $size = $1; # These numbers are somewhat arbitrary.. if($size>25) { $size="55%"; } } # support upgrade from old configuration, where LowerNational and UpperNational # were stored as REGEX'es (now they are STRING's): if ( $id eq "LowerNational" || $id eq "UpperNational" ) { if ($value =~ /^\(\?-xism:(.*)\)$/) { $value = $1; } } return CGI::password_field( -name => $id, -size=>$size, -default=>'--------' ); } # generate an input field for string types sub _PROMPT_FOR_STRING { my( $id, $opts, $value, $keys ) = @_; my $size = "55%"; if( $opts =~ /\s(\d+)\s/ ) { $size = $1; # These numbers are somewhat arbitrary.. if($size>25) { $size="55%"; } } # support upgrade from old configuration, where LowerNational and UpperNational # were stored as REGEX'es (now they are STRING's): if ( $id eq "LowerNational" || $id eq "UpperNational" ) { if ($value =~ /^\(\?-xism:(.*)\)$/) { $value = $1; } } return CGI::textfield( -name => $id, -size=>$size, -default=>$value ); } # generate an input field for URL types # This has its own type in case someone wants to add javascript validation sub _PROMPT_FOR_URL { my( $id, $opts, $value, $keys ) = @_; return CGI::textfield( -name => $id, -size=>"55%", -default=>$value ); } # generate an input field for URLPATH types # This has its own type in case someone wants to add javascript validation sub _PROMPT_FOR_URLPATH { my( $id, $opts, $value, $keys ) = @_; return CGI::textfield( -name => $id, -size=>"55%", -default=>$value ); } # generate an input field for PATH types # This has its own type in case someone wants to add javascript validation sub _PROMPT_FOR_PATH { my( $id, $opts, $value, $keys ) = @_; return CGI::textfield( -name => $id, -size=>"55%", -default=>$value ); } # generate an input field for BOOLEAN types sub _PROMPT_FOR_BOOLEAN { my( $id, $opts, $value, $keys ) = @_; return CGI::checkbox( -name => $id, -checked => ( $value ? 1 : 0), -value => 1, -label => '' ); } # generate an input field for REGEX types # This has its own type in case someone wants to add javascript validation sub _PROMPT_FOR_REGEX { my( $id, $opts, $value, $keys ) = @_; $value =~ s/[[\x01-\x09\x0b\x0c\x0e-\x1f"%&'*<=>@[_\|]/'&#'.ord($&).';'/ge; return ''; } # generate an input field for COMMAND types # This has its own type in case someone wants to add javascript validation sub _PROMPT_FOR_COMMAND { my( $id, $opts, $value, $keys ) = @_; return CGI::textfield( -name => $id, -size=>"55%", -default=>$value ); } # generate an input field for NUMBER types # This has its own type in case someone wants to add javascript validation sub _PROMPT_FOR_NUMBER { my( $id, $opts, $value, $keys ) = @_; return CGI::textfield( -name => $id, -size=>20, -default=>$value ); } # generate an input field for OCTAL number types (protections) sub _PROMPT_FOR_OCTAL { my( $id, $opts, $value, $keys ) = @_; return CGI::textfield( -name => $id, -size=>20, -default=>sprintf('0%o',$value) ); } # generate an input field for SELECT types sub _PROMPT_FOR_SELECT { my( $id, $opts, $value, $keys ) = @_; $opts =~ s/^\s+//; $opts =~ s/\s.*$//; my $sopts = ''; if ( defined($value) ) { $sopts .= ''; } foreach my $opt (split( /\s*,\s*/, $opts)) { if( $opt ne $value ) { $sopts .= ''; } } return CGI::Select({ name => $id, size=>1 }, $sopts); } # generate an input field for SELECTCLASS types # Takes a comma-separated list of options # Each option must be either 'none' or a wildcard expression that matches classes e.g. # TWiki::Plugins::*Plugin # * is the only wildcard supported # Finds all classes that match in @INC sub _PROMPT_FOR_SELECTCLASS { my( $id, $opts, $value, $keys ) = @_; $opts =~ s/^\s*(.*)\s*$/$1/; my $sopts = ''; if ( defined($value) ) { $sopts .= ''; } foreach my $opt (split( /\s*,\s*/, $opts)) { if ($opt eq 'none') { $sopts .= ''; } else { foreach my $class (_findClasses($opt)) { $sopts .= '' unless $class eq $value; } } } return CGI::Select({ name => $id, size=>1 }, $sopts); } # $pattern is a wildcard expression that matches classes e.g. # TWiki::Plugins::*Plugin # * is the only wildcard supported # Finds all classes that match in @INC sub _findClasses { my $pattern = shift; $pattern =~ s/^\s+//; $pattern =~ s/\s+$//; $pattern =~ s/\*/.*/g; my @path = split(/::/, $pattern); my $places = \@INC; while (scalar(@path) > 1 && @$places) { my $pathel = shift(@path); eval "\$pathel = qr/^$pathel\$/"; my @newplaces; foreach my $place (@$places) { if( opendir( DIR, $place ) ) { foreach my $subplace ( readdir DIR ) { next unless $subplace =~ $pathel; push(@newplaces, $place.'/'.$subplace); } } } $places = \@newplaces; } my @list; my $leaf = shift(@path); eval "\$leaf = qr/$leaf\.pm\$/"; my %known; foreach my $place (@$places) { if (opendir( DIR, $place )) { foreach my $file ( readdir DIR ) { next unless $file =~ $leaf; $file =~ /^(.*)\.pm$/; my $module = "$place/$1"; $module =~ s./.::.g; $module =~ /($pattern)$/; push(@list, $1) unless $known{$1}; $known{$1} = 1; } } } return @list; } ######################################################################## ###################### VARIABLE CHECKERS ############################### ######################################################################## sub _CHECKVAR_DefaultUrlHost { my $keys = shift; if( $TWiki::cfg{DefaultUrlHost} && $TWiki::cfg{DefaultUrlHost} ne 'NOT SET' ) { my $host = $ENV{HTTP_HOST}; if( $host && $TWiki::cfg{DefaultUrlHost} !~ /$host/ ) { return WARN('Current setting does not match HTTP_HOST ', $ENV{HTTP_HOST}); } } else { my $protocol = $url || 'http://'.$ENV{HTTP_HOST}; $protocol =~ s(^(.*?://.*?)/.*$)($1); $TWiki::cfg{DefaultUrlHost} = $protocol; return ERROR($GUESSED); } return ''; } sub _CHECKVAR_ScriptUrlPath { # Check Script URL Path against REQUEST_URI my $n; my $val = $TWiki::cfg{ScriptUrlPath}; my $guess = $ENV{REQUEST_URI} || $ENV{SCRIPT_NAME} || ''; $guess =~ s(/+configure\b.*$)(); if( $val && $val ne 'NOT SET' ) { unless( $guess ) { return WARN(<Go to "pub" directory'; } sub _CHECKVAR_PubDir { my $e = _findMajorDir('PubDir', 'pub'); $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{PubDir}); my $e2 = _checkTreePerms( $TWiki::cfg{PubDir}, 'rw' ); $e .= WARN($e2) if $e2; return $e; } sub _CHECKVAR_TemplateDir { my $e = _findMajorDir('TemplateDir', 'templates'); $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{TemplateDir}); my $e2 = _checkTreePerms( $TWiki::cfg{TemplateDir}, 'r' ); $e .= ERROR($e2) if $e2; return $e; } sub _CHECKVAR_DataDir { my $e = _findMajorDir('DataDir', 'data'); my $e2 = _checkTreePerms( $TWiki::cfg{DataDir}, "r" ); $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{DataDir}); $e2 = _checkTreePerms( $TWiki::cfg{DataDir}, "w", qr/\.txt$/ ) unless $e2; $e .= WARN($e2) if $e2; return $e; } sub _CHECKVAR_LocalesDir { my $e = _findMajorDir('LocalesDir', 'locale'); my $e2 = _checkTreePerms( $TWiki::cfg{LocalesDir}, "r" ); $e .= _warnAboutWindowsBackSlashes($TWiki::cfg{LocalesDir}); $e .= ERROR($e2) if $e2; return $e; } sub _CHECKVAR_MailProgram { eval "use Net::SMTP"; my $n; if ($@) { $n = "Net::SMTP is not installed in this environment. "; my $val = $TWiki::cfg{MailProgram} || ''; $val =~ s/\s.*$//g; if( ! ( -e $val ) ) { return WARN("$val was not found. Check the path."); } } else { $n = 'Net::SMTP is installed in this environment, so this setting will not be used.'; } return $n; } sub _CHECKVAR_LogFileName { my $logFile = $TWiki::cfg{LogFileName} || ""; $logFile =~ s/%DATE%/DATE/; my $e = _checkCanCreateFile( $logFile ); $e = ERROR($e) if $e; return $e; } sub _CHECKVAR_ConfigurationLogName { my $logFile = $TWiki::cfg{ConfigurationLogName} || ""; $logFile =~ s/%DATE%/DATE/; my $e = _checkCanCreateFile( $logFile ); $e = ERROR($e) if $e; return $e; } sub _CHECKVAR_WarningFileName { my $logFile = $TWiki::cfg{WarningFileName} || ""; $logFile =~ s/%DATE%/DATE/; my $e = _checkCanCreateFile( $logFile ); $e = ERROR($e) if $e; return $e; } sub _CHECKVAR_DebugFileName { my $logFile = $TWiki::cfg{DebugFileName} || ""; $logFile =~ s/%DATE%/DATE/; my $e = _checkCanCreateFile( $logFile ); $e = ERROR($e) if $e; return $e; } sub _CHECKVAR_MimeTypesFileName { my $e = _checkTreePerms($TWiki::cfg{MimeTypesFileName}, 'r'); $e = ERROR($e) if $e; return $e; } sub _CHECKVAR_Htpasswd_FileName { my $e = _checkTreePerms($TWiki::cfg{Htpasswd}{FileName}, 'r'); $e = ERROR($e) if $e; return $e; } sub _CHECKVAR_RegistrationApprovals { my $file = $TWiki::cfg{RegistrationApprovals}; my $e = _checkTreePerms( $file, 'rw' ); $e = WARN($e) if $e; return $e; } sub _CHECKVAR_UseLocale { my $on = $TWiki::cfg{UseLocale}; my $n = ''; if( $TWiki::cfg{OS} eq 'WINDOWS' ) { # Warn re known broken locale setup $n .= WARN(<= 5.008 and not ( exists $Config::Config{useperlio} and $Config::Config{useperlio} eq 'define' ) ) { $n .= WARN(<Perl's Unicode Model in 'perldoc perluniintro') - re-compilation of Perl will be required before it can be used to enable TWiki's experimental UTF-8 support. HERE ); } # Check for d_setlocale in Config (same as 'perl -V:d_setlocale') eval "use Config"; if ( !( exists $Config::Config{d_setlocale} && $Config::Config{d_setlocale} eq 'define' ) ) { $n .= WARN(<$forUpperNat HERE ); } } return ''; } sub _CHECKVAR_LowerNational { if( $perlvernum < $perlVerPreferred || 1) { # Locales are off/broken, or using pre-5.6 Perl, so have to # explicitly list the accented characters (but not if using UTF-8) my $forLowerNat = join '', grep { uc($_) ne $_ and m/[^a-z]/ } map { chr($_) } 1..255; if ($forLowerNat) { return WARN( <$forLowerNat HERE ); } } return ''; } sub _CHECKVAR_Site_Locale { my $e = ''; my $locale = $TWiki::cfg{Site}{Locale}; setlocale(&LC_CTYPE, $locale); my $currentLocale = setlocale(&LC_CTYPE); if ( $currentLocale ne $locale ) { $e .= WARN(<path_info() =~ /$TWiki::cfg{ScriptSuffix}$/ ) { return ERROR('this script ('.$query->pather_info().') called with different ScriptSuffix setting'.$TWiki::cfg{ScriptSuffix}); } } return ''; } sub _CHECKVAR_RCS_EgrepCmd { return _checkGnuProgram($TWiki::cfg{RCS}{EgrepCmd}); } sub _CHECKVAR_RCS_FgrepCmd { return _checkGnuProgram($TWiki::cfg{RCS}{FgrepCmd}); } sub _CHECKVAR_RCS_initTextCmd { return _checkRCSProgram('initTextCmd'); } sub _CHECKVAR_RCS_initBinaryCmd { return _checkRCSProgram('initBinaryCmd'); } sub _CHECKVAR_RCS_tmpBinaryCmd { return _checkRCSProgram('tmpBinaryCmd'); } sub _CHECKVAR_RCS_ciCmd { return _checkRCSProgram('ciCmd'); } sub _CHECKVAR_RCS_ciDateCmd { return _checkRCSProgram('ciDateCmd'); } sub _CHECKVAR_RCS_coCmd { return _checkRCSProgram('coCmd'); } sub _CHECKVAR_RCS_histCmd { return _checkRCSProgram('histCmd'); } sub _CHECKVAR_RCS_infoCmd { return _checkRCSProgram('infoCmd'); } sub _CHECKVAR_RCS_rlogDateCmd { return _checkRCSProgram('rlogDateCmd'); } sub _CHECKVAR_RCS_diffCmd { return _checkRCSProgram('diffCmd'); } sub _CHECKVAR_RCS_lockCmd { return _checkRCSProgram('lockCmd'); } sub _CHECKVAR_RCS_unlockCmd { return _checkRCSProgram('unlockCmd'); } sub _CHECKVAR_RCS_delRevCmd { return _checkRCSProgram('delRevCmd'); } sub _CHECKVAR_StoreImpl { my $mess = ''; if( $TWiki::cfg{StoreImpl} eq 'RcsWrap') { # Check that GNU diff is found in PATH; used by rcsdiff $mess .= NOTE( "Note: The 'diff' program found on the path is used by RcsWrap to compare revisions ". _checkGnuProgram( "diff")); } return $mess; }; sub _CHECKVAR_UseClientSessions { my $mess = ''; if (!eval "use CGI::Cookie; 1") { $mess .= <$class}, $prompter) if $mandatory; use strict 'refs'; $keys = CGI::span({class=>'mandatory'}, $keys) if $mandatory; my $hidden = 0; if (length($desc) == 0 || $desc =~ /\A\s\Z/) { $hidden = 1; } return _docBlock( $output.$desc, $hidden )._setting( $keys, $prompter ); } sub _showPlugins { my %modules; my @classes = _findClasses('TWiki::Plugins::*Plugin'); foreach my $module ( @classes ) { $module =~ s/^.*::([^:]*)/$1/; $TWiki::cfg{Plugins}{$module}{Enabled} ||= 0; # only add the first instance of any plugin, as only # the first can get loaded from @INC. unless( $modules{$module} ) { $modules{$module} = 1; } } my $block = ''; foreach my $m ( sort keys %modules ) { $block .= _checkAndBuildValueGrabber ( 'BOOLEAN', '', #SMELL - i'm assuming that the Plugin topic is in the SystemWeb :( "$m", '{Plugins}{'.$m.'}{Enabled}' ); } return $block; } sub _showLanguages { opendir( DIR, $TWiki::cfg{LocalesDir}) or return 'Couldn\'t read TWiki {LocalesDir}!'; my $block = ''; foreach my $file ( grep { /^.*\.po$/ } readdir DIR ) { $file =~ m/^(.*)\.po$/; my $lang = $1; $lang = "'$lang'" if $lang =~ /\W/; $block .= _checkAndBuildValueGrabber ( 'BOOLEAN', '', 'Enable the language ' . $lang . '', '{Languages}{' . $lang . '}{Enabled}' ); } closedir( DIR ); return $block; } ######################################################################## ##################### WRITING NEW VALUES ############################### ######################################################################## sub setConfig { my ($path, $updates) = @_; my $txt = ''; if( open(F, "<$path")) { undef $/; $txt = ; close(F); } $txt =~ s/^\s*1;\s*$//gm; open(F, ">$path") || die "Failed to open $path for write"; foreach my $config ( keys %$updates ) { # kill the old settings if any are there $txt =~ s/\$TWiki::cfg$config\s*=.*?;\s*\n//s; $txt .= '$TWiki::cfg'.$config.' = '.$updates->{$config}.";\n"; } print F $txt,"1;\n"; close(F); if( defined( $TWiki::cfg{ConfigurationLogName} ) && open(F, '>>'.$TWiki::cfg{ConfigurationLogName} )) { my $date = gmtime(); my $user = $query->remote_user() || 'guest'; foreach my $config ( keys %$updates ) { print F '| ',$date,' | ',$user,' | ',$config,' | ', $updates->{$config}," |\n"; } close(F); } } # Convert value to a canonical perl representation suitable for writing # to LocalSite.cfg sub _perlifyType { my ($val,$type) = @_; if ($type eq 'BOOLEAN') { return ($val ? 1 : 0); } elsif ($type eq 'NUMBER') { $val ||= 0; return 0+$val; } elsif ($type eq 'OCTAL') { $val ||= 0; $val = '0'.$val unless $val =~ /^0/; return $val; } else { $val ||= ''; $val =~ s/'/\\'/g; return "'".$val."'"; } } sub _perlModulesCheck { # Suppress "Subroutine TWiki::O_CREAT redefined" warnings - see Bugs:Item2433 no warnings qw(redefine); my $mods = shift; my $e = ''; foreach my $mod (keys %$mods) { my $n = ''; eval "use $mod"; if ($@) { $n = WARN('not installed. May be required for ', $mods->{$mod}); } else { my $mod_version; no strict 'refs'; eval '$mod_version = ${'.$mod.'::VERSION}'; use strict 'refs'; $n = $mod_version || 'unknown'; } $e .= _setting($mod, $n); } return $e; } ######################################################################## #################### MAIN ACTION ENTRY POINTS ########################## ######################################################################## sub _serveImage { my($type, $image )= @_; print "Content-type: $type\n\n"; if( open(F, "logos/$image")) { local $/ = undef; print ; close(F); } } sub handleUpdate { my $path = shift; my $pass = $query->param( 'cfgAccess' ); my $param; my $output = ''; unless( defined( $pass )) { $output .= CGI::start_form({ action=>$ENV{SCRIPT_NAME}, method=>"post" }); # Pass all URL params through foreach $param ( $query->param ) { $output .= CGI::hidden( $param, $query->param( $param )); $output .= "\n"; } my $changed = calculateChanges(); my $itemText = ($changed == 1) ? 'item' : 'items'; $output .= CGI::div({ class => ''}, CGI::strong( 'Changing ' . $changed. ' configuration ' . $itemText. '.'). (($changed == 0) ? CGI::br() . CGI::a( { href=>$url.'?t='.time(), rel => 'nofollow' }, 'Return to configuration') : CGI::br() . 'Proceed with the steps below to save your changes.')); # and add a few more my $password = ""; my $passwordtitle = CGI::h3('Enter the configuration password'); my $passwordinput = ""; if ($TWiki::cfg{Password} ne '') { $passwordinput .= CGI::h3(CGI::strong("Your Password:")); $passwordinput .= CGI::p(CGI::password_field( 'cfgAccess', '', 20, 80 ) . ' ' . CGI::submit(-class=>'twikiSubmit', -value=>'Save changes')); } else { $passwordinput .= CGI::hidden( 'cfgAccess', '' ); } my $passwordforgot = ""; if ($TWiki::cfg{Password} ne '') { $passwordforgot .= CGI::p( CGI::strong("Forgot your password?")) . CGI::p('To reset the password, log in to the server and delete the $TWiki::cfg{Password} = \'...\'; line in lib/LocalSite.cfg'); } my $passwordforgothelp = CGI::img({width=>'16', height=>'16', src=>$ENV{SCRIPT_NAME}.'?action=image;image=warning.gif;type=image/gif', alt=>''}) . ' '; $passwordforgothelp .= CGI::span({ class=>'twikiAlert' }, CGI::strong("Notes on Security")); $passwordforgothelp .= "
  • If you don't set a password, or the password is cracked, then configure could be used to do very nasty things to your server.
  • If you are running TWiki on a public website, you are strongly advised to disable saving from configure by making lib/LocalSite.cfg readonly once you are happy with your configuration.
"; $passwordforgot .= CGI::div({ class => 'explanation'}, $passwordforgothelp); $password .= CGI::div({ class=>'twikiFormStep' }, $passwordtitle) unless $passwordtitle eq ''; $password .= CGI::div({ class=>'twikiFormStep' }, $passwordinput) unless $passwordinput eq ''; $password .= CGI::div({ class=>'twikiFormStep' }, $passwordforgot) unless $passwordforgot eq ''; $output .= CGI::div({ id =>'twikiPassword'}, CGI::div({class=>'twikiFormSteps'}, $password)) unless $changed == 0; my $changepassword = ""; my $changepasswordtitle = ""; if ($TWiki::cfg{Password} ne '') { $changepasswordtitle .= CGI::h3( "You may change your password here:" ); } my $changepasswordnew = ""; $changepasswordnew .= CGI::strong("New Password:"); $changepasswordnew .= CGI::p( CGI::password_field( 'newCfgP', '', 20, 80 ) ); my $changepasswordconfirm = ""; $changepasswordconfirm .= CGI::strong("Confirm Password:"); $changepasswordconfirm .= CGI::p( CGI::password_field( 'confCfgP', '', 20, 80 ) ); my $changepasswordsubmit = CGI::p( CGI::submit(-class=>'twikiSubmit', -value=>'Set Password and Save changes') ); $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordtitle) unless $changepasswordtitle eq ''; $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordnew) unless $changepasswordnew eq ''; $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordconfirm) unless $changepasswordconfirm eq ''; $changepassword .= CGI::div({ class=>'twikiFormStep' }, $changepasswordsubmit) unless $changepasswordsubmit eq ''; $output .= CGI::div({ id =>'twikiPasswordChange'}, CGI::div({class=>'twikiFormSteps'}, $changepassword)); $output .= CGI::end_form(); return $output; } unless( crypt( $pass, $TWiki::cfg{Password}) eq $TWiki::cfg{Password} || $TWiki::cfg{Password} eq '') { $output .= CGI::span( {class => 'error' }, "Incorrect password" ); return $output; } my $changed = 0; my %updates; if( $query->param( 'newCfgP' )) { if( $query->param( 'newCfgP' ) eq $query->param( 'confCfgP' )) { my @saltchars = ( 'a'..'z', 'A'..'Z', '0'..'9', '.', '/' ); my $salt = $saltchars[int(rand($#saltchars+1))] . $saltchars[int(rand($#saltchars+1)) ]; $updates{'{Password}'} = _perlifyType( crypt( $query->param( 'newCfgP' ), $salt ), 'STRING' ); $changed++; $output .= "Password changed"; } else { $output .= "New password and confirmation do not match"; return $output; } } $output .= CGI::h2('Updating configuration'); my $languageChanged=0; foreach $param ( $query->param ) { next unless $param =~ /$TYPEOF/os; my $keys = $1; my $type = $query->param( $param ); my $var = '$TWiki::cfg'.$keys; my $val = $query->param( $keys ); my $def; eval "\$def = defined( $var );"; if( $type ) { eval "\$def = $var;" if $def; next if( $type eq 'OCTAL' && sprintf('0%o', $def) =~ /^0*$val$/ ); next if( $type eq 'NUMBER' && $val + 1 == $def + 1 ); next if( $type eq 'BOOLEAN' && ($val && $def || !$val && !$def)); next if( $type eq 'PASSWORD' && ($val eq '--------')); next if( $val eq $def ); $output .= CGI::h3($var). CGI::strong('old '). CGI::code($def||' '). CGI::br(). CGI::strong('new '). CGI::code($val||' '); $updates{$keys} = _perlifyType($val, $type); #SMELL: Not elegant, but works if ($keys=~/\{Languages\}/) { $languageChanged=1; } $changed++; } } $output .= CGI::p(); setConfig($path, \%updates); if ($languageChanged) { if ( -f "$TWiki::cfg{LocalesDir}/languages.cache" ) { unlink "$TWiki::cfg{LocalesDir}/languages.cache"; } } my $itemText = ($changed == 1) ? 'item' : 'items'; $output .= CGI::hr(); $output .= CGI::p(CGI::strong($changed.' configuration ' . $itemText . ' changed. ')); $output .= CGI::p(CGI::a({ rel => 'nofollow', href=>$url.'?t='.time() }, 'Return to configuration')); return $output; } sub calculateChanges { my $param; my $changed = 0; foreach $param ( $query->param ) { next unless $param =~ /$TYPEOF/os; my $keys = $1; my $type = $query->param( $param ); my $var = '$TWiki::cfg'.$1; my $val = $query->param( $keys ); my $def; eval "\$def = defined( $var );"; if( $type ) { eval "\$def = $var;" if $def; next if( $type eq 'OCTAL' && sprintf('0%o', $def) =~ /^0*$val$/ ); next if( $type eq 'NUMBER' && $val + 1 == $def + 1 ); next if( $type eq 'BOOLEAN' && ($val && $def || !$val && !$def)); next if( $type eq 'PASSWORD' && ($val eq '--------')); next if( $val eq $def ); $changed++; } } return $changed; } sub performSanityChecks { my( $brokenTWikiCfgError, $brokenLocalSiteError ) = @_; my $output = ''; if ($brokenTWikiCfgError) { $output .= CGI::h2('WARNING:'). CGI::p('TWiki.cfg is unreadable or has a configuration problem that is causing a Perl error - the following message(s) should help locate the problem.'); $output .= $brokenTWikiCfgError; # EARLY EXIT $output .= CGI::end_html(); return $output; } if ($brokenLocalSiteError) { $output .= CGI::h2('WARNING:'). ERROR('LocalSite.cfg is unreadable or has a configuration problem that is causing a Perl error - the following message(s) was generated:'). CGI::pre($brokenLocalSiteError). 'The @INC path is '. CGI::pre(join(":", @INC)). NOTE('This may be because this is the first time you have run configure. In this case you can simply ignore this error until you have filled in your General path settings. Otherwise, check that the file exists, and the webserver user is allowed to read it.'); } # Check whether basic CGI modules exist (some broken installations of # Perl don't have this, even though they are standard modules), and warn user my $modMissing = 0; foreach my $mod (keys %$basicMods) { eval "use $mod"; if ($@) { unless ($modMissing) { $output .= ERROR( 'Perl Module(s) missing'); } $modMissing = 1; $output .= ERROR( 'Essential Perl Module \'',$mod, '\' not installed - please check the setting ', 'of @INC.' ); } } # If any critical modules missing, display @INC and give up if ($modMissing) { $output .= NOTE( '@INC = ', join( ' ', @INC )); return $output; } return $output; } sub presentReadOnlyInfo { # use strict; # Recommended for mod_perl, enable for Perl 5.6.1 only # Doesn't work well here, due to 'do "TWiki.cfg"' # use diagnostics; # Debug only # Load CGI modules (run-time, after checking they are accessible) require CGI; import CGI qw( -any ); require CGI::Carp; import CGI::Carp qw( fatalsToBrowser ); $errors = 0; $warnings = 0; my $output = ''; my $block = ''; for my $key ( sort keys %ENV ) { $block .= _setting($key, $ENV{$key}); } $output .= _foldableBlock(CGI::em( 'Environment variables' ), '(read only) ', $block); $block = ''; # Make %ENV safer for CGI (should reflect TWiki.pm) my $originalPath = $ENV{PATH} || ''; if( $TWiki::cfg{SafeEnvPath} ) { # SMELL: this untaint probably isn't needed my $ut = $TWiki::cfg{SafeEnvPath}; $ut =~ /^(.*)$/; $ENV{PATH} = $1; } delete @ENV{ qw( IFS CDPATH ENV BASH_ENV ) }; my $perlverMsg = $perlver; # Default version message # Load Config module - used here and elsewhere require Config; # Set $TWiki::cfg{DetailedOS} if not using later versions of TWiki.cfg for BeijingRelease # - this code enables the latest testenv to be used with Dec 2001 and # earlier releases. if ( !defined $TWiki::cfg{DetailedOS} ) { $TWiki::cfg{DetailedOS} = $Config::Config{'osname'}; } # Detect Perl flavour on Windows, and Cygwin Perl/RCS package versions if ($TWiki::cfg{DetailedOS} eq 'cygwin') { $perltype = 'Cygwin'; # Cygwin Perl only my ($pkg, $pkgName); # Get Cygwin perl's package version number $pkgName = 'perl'; $pkg = `/bin/cygcheck -c $pkgName | /bin/grep $pkgName 2>/dev/null`; if ($?) { $pkg = " [Cannot identify package - cygcheck or grep not installed]"; $perlverMsg = $perlver . $pkg } else { $pkg = (split ' ', $pkg)[1]; # Package version $perlverMsg = $pkg; } # Get Cygwin RCS's package version number $pkgName = 'rcs'; $pkg = `/bin/cygcheck -c $pkgName | /bin/grep $pkgName 2>/dev/null`; if ($?) { $pkg = " [Cannot identify package - cygcheck or grep not installed]"; $cygwinRcsVerNum = $pkg; } else { $pkg = (split ' ', $pkg)[1]; # Package version $cygwinRcsVerNum = $pkg; } } elsif ($TWiki::cfg{DetailedOS} =~ /win/i && $TWiki::cfg{DetailedOS} !~ /darwin/i ) { # Windows Perl - try ActivePerl-only function: returns number if # successful, otherwise treated as a literal (bareword). my $isActivePerl= eval 'Win32::BuildNumber !~ /Win32/'; if( $isActivePerl ) { $perltype = 'ActiveState'; $perlverMsg = $perlver . ", build " . Win32::BuildNumber(); } else { # Could be SiePerl or some other Win32 port of Perl $perltype = 'SiePerl or other Windows Perl'; } } else { $perltype = 'generic'; } # Detect executable name suffix, e.g. .exe on Windows or '' on Unix # Avoid testing for .exe suffixes on Cygwin, since the built-in # grep and ls don't end in '.exe', even though Perl's '_exe' setting # indicates they should. my $exeSuffix=''; if ( $Config::Config{'_exe'} and ($TWiki::cfg{OS} eq 'WINDOWS' and $perltype ne 'Cygwin') ) { if ( ! $ENV{INTERIX_ROOT} ) { #this is set is we are using UnixServicesForWindows (or INTERIX funnily enough) and they don't use .exe either $exeSuffix = $Config::Config{'_exe'}; } } # Detect whether mod_perl was loaded into Apache my $modPerlLoaded = ( exists $ENV{SERVER_SOFTWARE} && ( $ENV{SERVER_SOFTWARE} =~ /mod_perl/ )); # Detect whether we are actually running under mod_perl # - test for MOD_PERL alone, which is enough. my $usingModPerl = ( exists $ENV{MOD_PERL} ); my $modPerlVersion; # Get the version of mod_perl if it's being used if ( $usingModPerl ) { $modPerlVersion = eval 'use mod_perl; return $mod_perl::VERSION'; $block .= _setting('', WARN(<configure with mod_perl. This is risky because mod_perl will remember old values of configuration variables. You are *highly* recommended not to run configure under mod_perl (though the rest of TWiki can be run with mod_perl, of course) HERE )); } my $n = ucfirst(lc($TWiki::cfg{OS})); $n .= " ($TWiki::cfg{DetailedOS})" if ( $TWiki::cfg{DetailedOS} ne '' ); # OS $block .= _setting("Operating system", $n); # Perl version and type $perlverMsg .= " ($perltype)" if $perltype ne 'generic'; $block .= _setting("Perl version", $perlverMsg); if ( $perlvernum < $perlverRequired ) { $block .= _setting('', WARN(<twiki/lib and check that LocalSite.cfg is present and readable"); } else { $twikiFound = 1; my $mod_version = eval '$TWiki::wikiversion || $TWiki::VERSION'; $mod_version ||= 'unknown'; $mess = 'OK, TWiki.pm found (Version: '.$mod_version.')'; } $block .= _setting('TWiki module in @INC path', $mess); #add in the basic Modules so that we list their versions in the UI map { $requiredMods->{$_} = $basicMods->{$_} } keys %$basicMods; if ( defined $TWiki::cfg{DetailedOS} and ($TWiki::cfg{DetailedOS} =~ /darwin/i or $TWiki::cfg{OS} ne 'UNIX') ) { map { $requiredMods->{$_} = $requiredModsNonUnix->{$_} } keys %$requiredModsNonUnix; } else { # these are optional on Unix map { $optionalMods->{$_} = $requiredModsNonUnix->{$_} } keys %$requiredModsNonUnix; } # Check that each of the required Perl modules can be loaded, and # print its version number. my $set = ''; foreach my $mod (keys %$requiredMods) { eval "use $mod"; if ($@) { $set .= _setting($mod, ERROR("not installed. Required for ", $requiredMods->{$mod})); } else { my $mod_version; no strict 'refs'; eval '$mod_version = ${'.$mod.'::VERSION}'; use strict 'refs'; $n = $mod_version || 'unknown'; # Check for potential CGI.pm module upgrade if( $mod eq 'CGI' and $mod_version < $cgiModVerRecommended ) { if ( $perltype eq 'Cygwin' and $perlver eq '5.8.0' ) { # Recommend CGI.pm upgrade if using Cygwin Perl 5.8.0 $n .= WARN( "CGI.pm version $cgiModVerRecommended or higher", "is recommended to avoid problems with attachment", "uploads on Cygwin Perl $perlver."); } elsif ( $usingModPerl and $modPerlVersion >= 1.99 ) { # Recommend CGI.pm upgrade if using mod_perl 2.0, which # is reported as version 1.99 and implies Apache 2.0 $n .= WARN("CGI.pm version $cgiModVerRecommended or higher is", "recommended to avoid problems with mod_perl version", "$modPerlVersion on Apache 2.0 or higher."); } } $set .= _setting( $mod, $n ); } } $block .= _setting("Required Perl modules", CGI::start_table({width=>'100%'}). $set.CGI::end_table()); # Check that each of the optional Perl modules can be loaded, and # print its version number. $set = _perlModulesCheck( $optionalMods ); $set .= _perlModulesCheck( $I18Mods ); $set .= _perlModulesCheck( $] >= 5.008 ? $I18Mods_perl58 : $I18Mods_perl56 ); $block .= _setting("Optional Perl Modules", CGI::start_table({width=>'100%'}). $set.CGI::end_table()); # All module checks done, OK to enable fatalsToBrowser import CGI::Carp qw( fatalsToBrowser ); # PATH_INFO $block .= _setting(CGI::a({name=>'PATH_INFO'},'PATH_INFO'), $query->path_info(). NOTE(<$url/foo/bar, the correct PATH_INFO is /foo/bar, without any prefixed path components. Click here to test this - particularly if you are using mod_perl, Apache or IIS, or are using a web hosting provider. Look at the new path info here. It should be /foo/bar. HERE )); # mod_perl if( $usingModPerl ) { $n = "Used for this script"; } else { $n = "Not used for this script"; } $n .= NOTE( 'mod_perl is ', $modPerlLoaded ? '' : 'not', ' loaded into Apache' ); if ( $modPerlVersion ) { $n .= NOTE( 'mod_perl version ', $modPerlVersion ); } # Check for a broken version of mod_perl 2.0 if ( $usingModPerl && $modPerlVersion =~ /1\.99_?11/ ) { # Recommend mod_perl upgrade if using a mod_perl 2.0 version # with PATH_INFO bug (see Support.RegistryCookerBadFileDescriptor # and Bugs:Item82) $n .= ERROR(<) ); # Unix/Cygwin Perl - effective UID $grp = join(',', map { lc(getgrgid( $_ )) } split( " ", $( ) ); } else { # ActiveState or other Win32 Perl $usr = lc( getlogin ); # Try to use Cygwin's 'id' command - may be on the path, since Cygwin # is probably installed to supply ls, egrep, etc - if it isn't, give up. # Run command without stderr output, to avoid CGI giving error. # Get names of primary and other groups. $grp = lc(qx(sh -c '( id -un ; id -gn) 2>/dev/null' 2>nul )); if ($?) { $grp = "[Cannot identify groups - no Cygwin 'id' or 'sh' command on path]"; } } $block .= _setting('CGI user', 'userid = '.$usr.' groups = '. $grp.''. NOTE('Your CGI scripts are executing as this user.')); $block .= _setting("Original PATH", $originalPath. NOTE(<recommended if Cygwin is installed).

To use 'bash' with ActiveState or other Win32 Perl you should set the PERL5SHELL environment variable to something like c:/YOURCYGWINDIR/bin/bash.exe -c This should be set in the System Environment, and ideally set directly in the web server (e.g. using the Apache SetEnv directive). HERE ); if( $perltype eq 'ActiveState' ) { $n .= WARN(<highly recommended not to use this particular configuration on a public server (one exposed to the internet) HERE ); if( Win32::BuildNumber() < $ActivePerlRecommendedBuild ) { $n .= WARN(< $ActivePerlRecommendedBuild if you are going to use PERL5SHELL, which was broken in earlier builds. HERE ); } } $block .= _setting("PERL5SHELL", $n); }; $output .= _foldableBlock(CGI::em( 'CGI Setup' ), '(read only) ', $block); return $output; }; sub presentEditableInfo { # "Parse" TWiki.cfg and LocalSite.cfg my $output = ''; my @blocks; my @heads; my $depth = 0; for my $file ( 'TWiki.cfg', 'LocalSite.cfg' ) { my $cfgfile = _findFileOnPath($file); next unless $cfgfile; open(F, $cfgfile) || next; undef $/; my $text = ; close(F); $text =~ s/^# //gm; my $type = ''; my $descr; my $opts; foreach (split(/\r?\n/, $text)) { if( m/^\*\*([A-Z]+)(\s*.*?)\*\*/ ) { if( $type eq '_HELP' ) { $blocks[$depth] .= _docBlock( $descr ); } $type = $1; $opts = $2 || ''; $opts .= ' '; # to simplify parsing $descr = ''; } elsif ($type && /\$(TWiki::)?cfg(.*?)\s*=/) { if( $type eq '_HELP' ) { $blocks[$depth] .= _docBlock( $descr ); } else { $blocks[$depth] .= _checkAndBuildValueGrabber($type, $opts, $descr, $2); } $type = ''; $descr = ''; } elsif( m/^#---(\++) *(.*?)$/ ) { my $ndepth = length($1); my $nhead = $2; while( $depth >= $ndepth ) { if ($depth <= 1) { $output .= _foldableBlock($heads[$depth], '', $blocks[$depth]); } else { $blocks[$depth - 1] .= _ordinaryBlock($depth, $heads[$depth], '', $blocks[$depth]); } $depth--; } $depth = $ndepth; $heads[$depth] = $nhead; $blocks[$depth] = ''; $type = '_HELP'; } elsif( m/^\*PLUGINS\*/ ) { if( $type eq '_HELP' ) { $blocks[$depth] .= _docBlock( $descr ); $descr = ''; } $blocks[$depth] .= _showPlugins(); } elsif ( m/\*LANGUAGES\*/ ) { if ( $type eq '_HELP' ) { $blocks[$depth] .= _docBlock( $descr ); $descr = ''; } $blocks[$depth] .= _showLanguages(); } elsif( $type ) { $descr .= "$_ "; } } } while( $depth && $blocks[$depth]) { if ($depth <= 1) { $output .= _foldableBlock($heads[$depth], '', $blocks[$depth]); } else { $blocks[ $depth - 1] .= _ordinaryBlock($depth, $heads[$depth], '', $blocks[$depth]); } $depth--; } return $output; } ###################################################################### ################# MAIN PROGRAM ####################################### ###################################################################### $| = 1; # no buffering - FIXME: mod_perl issue? eval "use CGI::Carp qw( fatalsToBrowser )"; use vars qw ( $setlibAvail $brokenLocalSiteError $brokenTWikiCfgError $js1 $css ); # Set library paths in @INC, read TWiki.cfg and set locale, at compile time # Try to use setlib.cfg, use default path if missing if ( -r './setlib.cfg' ) { require './setlib.cfg'; $setlibAvail = 1; } elsif ( -r '../conf/setlib.cfg' ) { require '../conf/setlib.cfg'; $setlibAvail = 1; } else { unshift @INC, '../lib'; $setlibAvail = 0; } 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'; } } # if this fails, ignore the problem, but we have to do it unless( eval 'do "LocalSite.cfg"' ) { # Capture the Perl error(s) $brokenLocalSiteError = 'require failed: '. ( $! ? $! : '') . ( $@ ? $@ : ''); } # Read the configuration file now in order to set locale; # includes checking for broken syntax etc. Need 'require' # to get the $!/$@ to work. unless( eval 'require "TWiki.cfg" ' ) { # Capture the Perl error(s) $brokenTWikiCfgError = 'require failed: '. ( $! ? $! : '') . ( $@ ? $@ : ''); } # and again eval 'do "LocalSite.cfg"'; # Do a dynamic 'use locale' for this script if( $TWiki::cfg{UseLocale} ) { require locale; import locale (); } $js1 = <<'HERE'; // HERE $css = <<'HERE'; /* Basic layout derived from http://www.positioniseverything.net/articles/pie-maker/pagemaker_form.php. I've changed many so things that I won't put a full copyright notice. However all hacks (and comments!) are far beyond my knowledge and this deserves full credits: Original copyright notice: Parts of these notes are (c) Big John @ www.positioniseverything.net and (c) Paul O'Brien @ www.pmob.co.uk, all of whom contributed significantly to the design of the css and html code. Reworked for TWiki: (c) Arthur Clemens @ visiblearea.com */ html, body { margin:0; /*** Do NOT set anything other than a left margin for the page as this will break the design ***/ padding:0; border:0; /* \*/ height:100%; /* Last height declaration hidden from Mac IE 5.x */ } body { background:#fff; min-width:100%; /*** This is needed for moz. Otherwise, the header and patternBottomBar will slide off the left side of the page if the screen width is narrower than the design. Not seen by IE. Left Col + Right Col + Center Col + Both Inner Borders + Both Outer Borders ***/ text-align:center; /*** IE/Win (not IE/MAC) alignment of page ***/ } .clear { clear:both; /*** these next attributes are designed to keep the div height to 0 pixels high, critical for Safari and Netscape 7 ***/ height:0px; overflow:hidden; line-height:1%; font-size:0px; } #patternWrapper { height:100%; /*** moz uses this to make full height design. As this #patternWrapper is inside the #patternPage which is 100% height, moz will not inherit heights further into the design inside this container, which you should be able to do with use of the min-height style. Instead, Mozilla ignores the height:100% or min-height:100% from this point inwards to the center of the design - a nasty bug. If you change this to height:100% moz won't expand the design if content grows. Aaaghhh. I pulled my hair out over this for days. ***/ /* \*/ height:100%; /* Last height declaration hidden from Mac IE 5.x */ /*** Fixes height for non moz browsers, to full height ***/ } #patternWrapp\65 r{ /*** for Opera and Moz (and some others will see it, but NOT Safari) ***/ height:auto; /*** For moz to stop it fixing height to 100% ***/ } /* \*/ * html #patternWrapper{ height:100%; } #patternPage { margin-left:auto; /*** Mozilla/Opera/Mac IE 5.x alignment of page ***/ margin-right:auto; /*** Mozilla/Opera/Mac IE 5.x alignment of page ***/ text-align:left; /*** IE Win re-alignment of page if page is centered ***/ position:relative; width:100%; /*** Needed for Moz/Opera to keep page from sliding to left side of page when it calculates auto margins above. Can't use min-width. Note that putting width in #patternPage shows it to IE and causes problems, so IE needs a hack to remove this width. Left Col + Right Col + Center Col + Both Inner Border + Both Outer Borders ***/ /* \*/ height:100%; /* Last height declaration hidden from Mac IE 5.x */ /*** Needed for Moz to give full height design if page content is too small to fill the page ***/ } /* Last style with height declaration hidden from Mac IE 5.x */ /*** Fixes height for IE, back to full height, from esc tab hack moz min-height solution ***/ #patternOuter { z-index:1; /*** Critical value for Moz/Opera Background Column colors fudge to work ***/ position:relative; /*** IE needs this or the contents won't show outside the parent container. ***/ height:100%; /* Last height declaration hidden from Mac IE 5.x */ /*** Needed for full height inner borders in Win IE ***/ } #patternFloatWrap { width:100%; float:left; display:inline; } #patternLeftBar { /* Left bar width is defined in viewleftbar.pattern.tmpl */ float:left; display:inline; position:relative; /* IE needs this or the contents won't show outside the parent container. */ overflow:hidden; } #patternLeftBarContents { left:-1px; position:relative; /* for margins and paddings use style.css */ } #patternMain { width:100%; float:right; display:inline; } #patternTopBar { /* Top bar height is defined in viewtopbar.pattern.tmpl */ z-index:1; /*** Critical value for Moz/Opera Background Column colors fudge to work ***/ position:absolute; top:0px; width:100%; } #patternTopBarContents { height:1%; /* or Win IE won't display a background */ /* for margins/paddings use style.css */ } #patternBottomBar { z-index:1; /* Critical value for Moz/Opera Background Column colors fudge to work */ clear:both; width:100%; } /* Pages that are not view */ .patternNoViewPage #patternOuter { /* no left bar, margin at both sides */ margin-left:4%; margin-right:4%; } /* edit.pattern.tmpl */ .patternEditPage #patternOuter, .patternPreviewPage #patternOuter { margin-left:0; margin-right:0; } .twikiLeft { float:left; position:relative; } .twikiRight { position:relative; float:right; display:inline; margin:0; } .twikiClear { /* to clean up floats */ margin:0; padding:0; height:0; line-height:0px; clear:both; display:block; } .twikiHidden { display:none; } .twikiLast, .patternTopic .twikiLast { border-bottom:0px; } /* ----------------------------------------------------------- STYLE Appearance: margins, padding, fonts, borders ----------------------------------------------------------- */ /* --------------------------------------------------------------------------------------- CONSTANTS Sizes ---------------------------------------- S1 line-height 1.4em S2 somewhat smaller font size 94% S3 small font size, twikiSmall font-size:86%; line-height:110%; S4 horizontal bar padding (h2, patternTop) 5px S5 form and attachment padding 20px S6 left margin left bar 1em --------------------------------------------------------------------------------------- */ /* GENERAL HTML ELEMENTS */ html body { font-size:104%; /* to change the site's font size, change #patternPage below */ voice-family:"\"}\""; voice-family:inherit; font-size:small; } html>body { /* Mozilla */ font-size:small; } p { margin:1em 0 0 0; } table { border-collapse:separate; } th { line-height:1.15em; } strong, b { font-weight:bold; } hr { height:1px; border:none; } /* put overflow pre in a scroll area */ pre { width:100%; margin:1em 0; /* Win IE tries to make this bigger otherwise */ } html>body pre { /* hide from IE */ /*\*/ overflow:auto !important; /* */ overflow:scroll; width:auto; /* for Mac Safari */ } /* IE behavior for pre is defined in twiki.pattern.tmpl in conditional comment */ ol li, ul li { line-height:1.4em; /*S1*/ } /* Text */ h1, h2, h3, h4, h5, h6 { line-height:104%; padding:0em; margin:1em 0 .1em 0; font-weight:normal; } h1 { margin:0 0 .5em 0; } h1 { font-size:210%; } h2 { font-size:160%; } h3 { font-size:135%; } h4 { font-size:122%; } h5 { font-size:110%; } h6 { font-size:95%; } h2, h3, h4, h5, h6 { display:block; /* give header a background color for easy scanning:*/ padding:.1em 5px; margin:1em -5px .35em -5px; border-width:0 0 1px 0; border-style:solid; height:auto; } h1.patternTemplateTitle { font-size:175%; text-align:center; } h2.patternTemplateTitle { text-align:center; } /* Links */ /* somehow the twikiNewLink style have to be before the general link styles */ .twikiNewLink { border-width:0 0 1px 0; border-style:solid; } .twikiNewLink a { text-decoration:none; margin-left:1px; } .twikiNewLink a sup { text-align:center; padding:0 2px; vertical-align:baseline; font-size:100%; text-decoration:none; } .twikiNewLink a:link sup, .twikiNewLink a:visited sup { border-width:1px; border-style:solid; text-decoration:none; } .twikiNewLink a:hover sup { text-decoration:none; } :link:focus, :visited:focus, :link, :visited, :link:active, :visited:active { text-decoration:underline; } :link:hover, :visited:hover { text-decoration:none; } img { vertical-align:text-bottom; border:0; } /* Form elements */ form { display:inline; margin:0em; padding:0em; } textarea, input, select { vertical-align:middle; border-width:1px; border-style:solid; } textarea { padding:1px; } input, select option { padding:1px; } .twikiSubmit, .twikiButton, .twikiCheckbox { border-width:1px; border-style:solid; padding:.15em .25em; font-size:94%; font-weight:bold; vertical-align:middle; } .twikiCheckbox, .twikiRadioButton { margin:0 .3em 0 0; border:0; } .twikiInputField { border-width:1px; border-style:solid; padding:.15em .25em; font-size:94%; /*S2*/ } .patternFormButton { border:0; margin:0 0 0 2px; } textarea { font-size:100%; } /* LAYOUT ELEMENTS */ /* for specific layout sub-elements see further down */ #patternPage { font-family:arial, "Lucida Grande", verdana, sans-serif; line-height:1.4em; /*S1*/ /* change font size here */ font-size:105%; } #patternTopBar { border-width:0 0 1px 0; border-style:solid; overflow:hidden; } #patternTopBarContents { padding:0 1.5em 0 1em; } #patternBottomBar { border-width:1px 0 0 0; border-style:solid; } #patternBottomBarContents { padding:1em; font-size:86%; line-height:110%; /*S3*/ text-align:center; } #patternMainContents { padding:0 1.5em 3em 3em; } #patternLeftBarContents { margin:0 1em 1em 1em; } /* ----------------------------------------------------------- Plugin elements ----------------------------------------------------------- */ /* EditTablePlugin */ .editTable .twikiTable { margin:0 0 2px 0; } .editTableInput, .editTableTextarea { font-family:monospace; } .editTableEditImageButton { border:none; } /* TablePlugin */ .twikiTable { } .twikiTable td, .twikiTable th { } .twikiTable th { padding:4px; } .twikiTable td { padding:2px 4px; } .twikiTable th a:link, .twikiTable th a:visited, .twikiTable th a font { text-decoration:none; } .twikiTable th a:hover, .twikiTable th a:hover font { text-decoration:none; border-width:0 0 1px 0; border-style:solid; } /* TablePlugin - sorting of table columns */ th.twikiSortedAscendingCol a:link, th.twikiSortedAscendingCol a:link font, th.twikiSortedAscendingCol a:visited, th.twikiSortedAscendingCol a:visited font { border-width:1px 0 0 0; border-style:solid; } th.twikiSortedDescendingCol a:link, th.twikiSortedDescendingCol a:link font, th.twikiSortedDescendingCol a:visited, th.twikiSortedDescendingCol a:visited font { border-width:0 0 1px 0; border-style:solid; } th.twikiSortedAscendingCol a:hover, th.twikiSortedAscendingCol a:hover font { border-width:0 0 1px 0; border-style:solid; text-decoration:none; } th.twikiSortedDescendingCol a:hover, th.twikiSortedDescendingCol a:hover font { border-width:1px 0 0 0; border-style:solid; text-decoration:none; } .twikiEditForm { margin:0 0 .5em 0; } .twikiEditForm .twikiFormTable { text-align:center; } /* TipsContrib */ .tipsOfTheDayContents .tipsOfTheDayTitle { font-weight:bold; } .patternTopic .tipsOfTheDayHeader { display:block; padding:3px 5px; } .patternTopic .tipsOfTheDayText { padding:0 5px 5px 5px; } .patternTopic .tipsOfTheDayText a:link, .patternTopic .tipsOfTheDayText a:visited { text-decoration:none; } /* TipsContrib - in left bar */ #patternLeftBar .tipsOfTheDayHeader img { /* hide lamp icon */ display:none; } #patternLeftBar .tipsOfTheDayContents { padding:.25em .25em .5em .25em; height:1%; /* or Win IE won't display a background */ overflow:hidden; } #patternLeftBar .tipsOfTheDayHeader { display:block; font-weight:normal; } /* TwistyContrib */ a:link.twistyTrigger, a:visited.twistyTrigger { text-decoration:none; } a:link .twistyLinkLabel, a:visited .twistyLinkLabel { text-decoration:underline; } /* ----------------------------------------------------------- TWiki styles ----------------------------------------------------------- */ #twikiLogin { width:40em; margin:0 auto; text-align:center; } #twikiLogin .twikiFormSteps { border-width:5px; } .twikiAttachments, .twikiForm { margin:1em 0; padding:1px; /* fixes disappearing borders because of overflow:auto; in twikiForm */ } .twikiForm h1, .twikiForm h2, .twikiForm h3, .twikiForm h4, .twikiForm h5, .twikiForm h6 { margin-top:0; } .patternContent .twikiAttachments, .patternContent .twikiForm { /* form or attachment table inside topic area */ font-size:94%; /*S2*/ padding:.5em 20px; /*S5*/ /* top:use less padding for the toggle link; bottom:use less space in case the table is folded in */ border-width:1px 0 0 0; border-style:solid; margin:0; } .twikiAttachments table, table.twikiFormTable { margin:5px 0 10px 0; /* bottom:create extra space in case the table is folded out */ border-collapse:collapse; padding:0px; border-spacing:0px; empty-cells:show; border-style:solid; border-width:1px; } .twikiAttachments table { line-height:1.4em; /*S1*/ width:auto; voice-family:"\"}\""; /* hide the following for Explorer 5.x */ voice-family:inherit; width:100%; } .twikiAttachments td, .twikiAttachments th { border-style:solid; border-width:1px; } .twikiAttachments th, table.twikiFormTable th.twikiFormTableHRow { padding:3px 6px; height:2.5em; vertical-align:middle; } table.twikiFormTable th.twikiFormTableHRow { text-align:center; } .twikiEditForm .twikiFormTable th, .twikiEditForm .twikiFormTable td { padding:.25em .5em; vertical-align:middle; border-width:0 0 1px 0; border-style:solid; } .twikiAttachments th a:link, .twikiAttachments th a:visited { text-decoration:none; } /* don't show any of those ugly sort icons */ .twikiAttachments th img, .twikiAttachments th a:link img, .twikiAttachments th a:visited img { display:none; } .twikiAttachments td, table.twikiFormTable td { padding:3px 6px; height:1.4em; /*S1*/ text-align:left; vertical-align:top; } .twikiAttachments td { /* don't show column lines in attachment listing */ border-width:0 0 1px 0; } .twikiAttachments th.twikiFirstCol, .twikiAttachments td.twikiFirstCol { /* make more width for the icon column */ width:26px; text-align:center; } .twikiAttachments caption { display:none; } table.twikiFormTable th.twikiFormTableHRow a:link, table.twikiFormTable th.twikiFormTableHRow a:visited { text-decoration:none; } .twikiFormSteps { text-align:left; padding:.25em 0 0 0; border-width:1px 0; border-style:solid; } .twikiFormStep { line-height:140%; padding:1em 20px; /*S5*/ border-width:0 0 1px 0; border-style:solid; } .twikiFormStep h3, .twikiFormStep h4 { font-size:115%; border:none; margin:0; padding:0; } .twikiFormStep h3 { font-weight:bold; } .twikiFormStep h4 { font-weight:normal; } .twikiFormStep p { margin:.3em 0; } .twikiToc { margin:1em 0; padding:.3em 0 .6em 0; } .twikiToc ul { list-style:none; padding:0 0 0 .5em; margin:0em; } .twikiToc li { margin-left:1em; padding-left:1em; background-repeat:no-repeat; background-position:0 .5em; } .twikiToc .twikiTocTitle { margin:0em; padding:0em; font-weight:bold; } .twikiSmall { font-size:86%; line-height:110%; /*S3*/ } .twikiSmallish { font-size:94%; /*S2*/ } .twikiNew { } .twikiSummary { font-size:86%; line-height:110%; /*S3*/ } .twikiEmulatedLink { text-decoration:underline; } .twikiPageForm table { border-width:1px; border-style:solid; } .twikiPageForm table { width:100%; margin:0 0 2em 0; } .twikiPageForm th, .twikiPageForm td { border:0; padding:.15em 1em; } .twikiPageForm td {} .twikiPageForm td.first { padding-top:1em; } .twikiBroadcastMessage { padding:.25em .5em; margin:0 0 1em 0; } .twikiHelp { padding:1em; margin:0 0 1em 0; border-width:1px 0; border-style:solid; } .twikiHelp ul, .twikiHelp li { margin:0; } .twikiHelp ul { padding-left:2em; } .twikiAccessKey { text-decoration:none; border-width:0 0 1px 0; border-style:solid; } a:hover .twikiAccessKey { text-decoration:none; border:none; } .twikiWebIndent { margin:0 0 0 1em; } a.twikiLinkInHeaderRight { float:right; display:block; margin:0 0 0 5px; } /* ----------------------------------------------------------- Pattern skin specific elements ----------------------------------------------------------- */ .patternTopic { margin:1em 0 2em 0; } #patternLeftBarContents { font-size:94%; /*S2*/ padding:0 0 .5em 0; } #patternLeftBarContents a img { margin:1px 0 0 0; } #patternLeftBarContents a:link, #patternLeftBarContents a:visited { text-decoration:none; } #patternLeftBarContents ul { padding:0; margin:.5em 0 1em 0; list-style:none; } #patternLeftBarContents li { width:100%; margin:0 1.1em 0 0; overflow:hidden; } #patternLeftBarContents .patternWebIndicator { margin:0 -1em; /*S6*/ padding:.55em 1em; /*S6*/ line-height:1.4em; text-align:center; } #patternLeftBarContents .patternWebIndicator a:link, #patternLeftBarContents .patternWebIndicator a:visited { text-decoration:none; } #patternLeftBarContents .patternLeftBarPersonal { margin:0 -1em; /*S6*/ padding:.55em 1em; /*S6*/ width:100%; border-width:0 0 1px 0; border-style:solid; } #patternLeftBarContents .patternLeftBarPersonal ul { margin:0; padding:0; } #patternLeftBarContents .patternLeftBarPersonal li { padding-left:1em; background-repeat:no-repeat; } #patternLeftBarContents .patternLeftBarPersonal a:hover { text-decoration:none; } .patternTop { font-size:94%; /*S2*/ } /* Button tool bar */ .patternToolBar { margin:.4em 0 0 0; padding:0 .5em 0 0; height:1%; /* for Win IE */ } .patternToolBarButtons { float:right; } .patternToolBarButtons .twikiSeparator { display:none; } .patternToolBar .patternButton { float:left; } .patternToolBar .patternButton s, .patternToolBar .patternButton strike, .patternToolBar .patternButton a:link, .patternToolBar .patternButton a:visited { display:block; margin:0 0 -1px 4px; border-width:1px; border-style:solid; /* relative + z-index removed due to buggy Win/IE redrawing problems */ /* position:relative; z-index:0; */ padding:.15em .45em; } .patternToolBar .patternButton a:link, .patternToolBar .patternButton a:visited { text-decoration:none; } .patternToolBar .patternButton s, .patternToolBar .patternButton strike { text-decoration:none; } .patternToolBar .patternButton a:hover { text-decoration:none; /*z-index:3;*/ } .patternToolBarBottom { position:relative; border-width:1px 0 0 0; border-style:solid; z-index:2; clear:both; } .patternMetaMenu input, .patternMetaMenu select, .patternMetaMenu select option { font-size:.86em; /* use em instead of % for consistent size */ margin:0; width:8em; } .patternMetaMenu select option { padding:1px 0 0 0; } .patternMetaMenu ul { padding:0; margin:0; list-style:none; } .patternMetaMenu ul li { padding:0 .1em 0 .1em; display:inline; } /* breadcrumb */ .patternHomePath { font-size:94%; /*S2*/ margin:.3em 0; } .patternHomePath a:link, .patternHomePath a:visited { text-decoration:none; } .patternRevInfo { margin:0 0 0 .15em; font-size:94%; } .patternTopicAction { line-height:1.5em; padding:.4em 20px; /*S5*/ border-width:1px 0; border-style:solid; } .patternViewPage .patternTopicAction { font-size:94%; /*S2*/ } .patternActionButtons a:link, .patternActionButtons a:visited { padding:1px 1px 2px 1px; } .patternTopicAction .patternActionButtons a:link, .patternTopicAction .patternActionButtons a:visited { text-decoration:none; } .patternTopicAction .patternSaveOptions { margin-bottom:.5em; } .patternTopicAction .patternSaveOptions .patternSaveOptionsContents { padding:.2em 0; } .patternMoved { font-size:94%; /*S2*/ margin:1em 0; } .patternMoved i, .patternMoved em { font-style:normal; } /* WebSearch, WebSearchAdvanced */ table#twikiSearchTable { background:none; border-bottom:0; } table#twikiSearchTable th, table#twikiSearchTable td { padding:.5em; border-width:0 0 1px 0; border-style:solid; } table#twikiSearchTable th { width:20%; text-align:right; } table#twikiSearchTable td { width:80%; } table#twikiSearchTable td.first { padding:1em; } /* ----------------------------------------------------------- Search results styles and overridden styles used in search.pattern.tmpl ----------------------------------------------------------- */ .patternSearchResults { /* no longer used in search.pattern.tmpl, but remains in rename templates */ margin:0 0 1em 0; } .patternSearchResults blockquote { margin:1em 0 1em 5em; } h3.patternSearchResultsHeader, h4.patternSearchResultsHeader { display:block; border-width:0 0 1px 0; border-style:solid; height:1%; /* or WIN/IE wont draw the backgound */ font-weight:bold; } .patternSearchResults h3 { font-size:115%; /* same as twikiFormStep */ margin:0; padding:.5em 20px; font-weight:bold; } h4.patternSearchResultsHeader { font-size:100%; padding-top:.3em; padding-bottom:.3em; font-weight:normal; } .patternSearchResult .twikiTopRow { padding-top:.2em; } .patternSearchResult .twikiBottomRow { padding-bottom:.25em; border-width:0 0 1px 0; border-style:solid; } .patternSearchResult .twikiAlert { font-weight:bold; } .patternSearchResult .twikiSummary .twikiAlert { font-weight:normal; } .patternSearchResult .twikiNew { border-width:1px; border-style:solid; font-size:85%; /*S3*/ padding:0 1px; font-weight:bold; } .patternSearchResults .twikiHelp { display:block; width:auto; padding:.1em 5px; margin:1em -5px .35em -5px; } .patternSearchResult .twikiSRAuthor { width:15%; text-align:left; } .patternSearchResult .twikiSRRev { width:30%; text-align:left; } .patternSearchResultCount { margin:1em 0 3em 0; } .patternSearched { } /* Search results in book view format */ .patternBookView { border-width:0 0 2px 2px; border-style:solid; /* border color in cssdynamic.pattern.tmpl */ margin:.5em 0 1.5em -5px; padding:0 0 0 5px; } .patternBookView .twikiTopRow { padding:.25em 5px .15em 5px; /*S4*/ margin:1em -5px .15em -5px; /*S4*/ } .patternBookView .twikiBottomRow { font-size:100%; padding:1em 0 1em 0; width:auto; border:none; } /* pages that are not view */ .patternNoViewPage #patternMainContents { padding-top:1.5em; } /* oopsmore.pattern.tmpl */ table.patternDiffOptions { margin:.5em 0; border:none; } table.patternDiffOptions td { border:none; text-align:center; } table.patternDiffOptions img { padding:0 10px; border-width:1px; border-style:solid; } /* edit.pattern.tmpl */ .patternEditPage .twikiForm h1, .patternEditPage .twikiForm h2, .patternEditPage .twikiForm h3 { /* same as twikiFormStep */ font-size:120%; font-weight:bold; } .twikiEditboxStyleMono { font-family:"Courier New", courier, monaco, monospace; } .twikiEditboxStyleProportional { font-family:"Lucida Grande", verdana, arial, sans-serif; } .twikiChangeFormButtonHolder { margin:.5em 0; float:right; } .twikiChangeFormButton .twikiButton, .twikiChangeFormButtonHolder .twikiButton { padding:0em; margin:0em; border:none; text-decoration:underline; font-weight:normal; } .patternFormHolder { /* constrains the textarea */ width:100%; } .patternSigLine { margin:.25em 0 .5em 0; padding:0 .5em 0 0; } .patternAccessKeyInfo { margin:1em 0 .5em 0; padding:.25em .5em; border-width:1px 0; border-style:solid; } .patternAccessKeyInfo a:link, .patternAccessKeyInfo a:visited { text-decoration:underline; } .patternAccessKeyInfo a:hover { text-decoration:none; } /* preview.pattern.tmpl */ .patternPreviewArea { border-width:1px; border-style:solid; margin:0em -.5em 2em -.5em; padding:.5em; } /* attach.pattern.tmpl */ .patternAttachPage .twikiAttachments table { width:auto; } .patternAttachPage .patternTopicAction { margin-top:-1px; } .patternAttachPage .twikiAttachments { margin-top:0; } .patternAttachForm { margin:0 0 3.5em 0; } .patternMoveAttachment { margin:.5em 0 0 0; text-align:right; } /* rdiff.pattern.tmpl */ .patternDiff { /* same as patternBookView */ border-width:0 0 2px 2px; border-style:solid; margin:.5em 0 1.5em -5px; padding:0 0 0 5px; } .patternDiffPage .patternRevInfo ul { padding:0; margin:2em 0 0 0; list-style:none; } .patternDiffPage .twikiDiffTable { margin:2em 0; } .patternDiffPage .twikiDiffTable th, .patternDiffPage .twikiDiffTable td { padding:.2em; } tr.twikiDiffDebug td { border-width:1px; border-style:solid; } .patternDiffPage td.twikiDiffDebugLeft { border-bottom:none; } .twikiDiffLineNumberHeader { padding:.3em 0; } /* ----------------------------------------------------------- COLOR Appearance: text colors, background colors, border colors ----------------------------------------------------------- */ /* --------------------------------------------------------------------------------------- CONSTANTS Text colors ---------------------------------------- T1 text color #000 T2 link color #06c T3 link hover text color #FBF7E8 T4 link action button color (red) (same as BG2) #D6000F T5 header color #a00 T6 code text, left bar text #7A4707 T7 muted (dark gray) text #666 T8 grayed out text #8E9195 T9 alert #f00 T10 green 'new' #049804 T11 dark gray #333 Background colors ---------------------------------------- BG1 white; attachment, form table background #fff BG2 link hover background color (red) #D6000F BG3 light gray #efefef BG4 active form field (not implemented yet) #ffc BG5 info background very light blue (placeholder for background image) #ECF4FB BG6 patternTopicAction light yellow (same as T3) #FBF7E8 BG7 header background (very light yellow) #FDFAF1 BG8 accent on sorted table column #ccc BG9 light yellow; attachment, form background #FEFBF3 BG10 light green 'new' #ECFADC BG11 dark gray; diff header background (same as T8) #8E9195 BG12 dark yellow, submit button #FED764 BG13 light blue: form steps #F6FAFD BG14 lighter blue: left bar #F9FCFE Border colors ---------------------------------------- BO1 light gray #efefef BO2 submit button border blue ('active') #88B6CF BO3 info light blue border #D5E6F3 BO4 border color beige, header h2 bottom border #E2DCC8 BO5 header h3..h6 bottom border (75% of BO4) #E9E4D2 BO6 darker gray #aaa BO7 neutral gray border #ccc BO8 light neutral gray #ddd BO9 alert border #f00 BO10 dark gray (same as BG11) #8E9195 --------------------------------------------------------------------------------------- */ /* LAYOUT ELEMENTS */ #patternTopBar{ background-color:#fff; border-color:#ccc; } #patternMain { /* don't set a background here; use patternOuter */ } #patternOuter { background-color:#fff; /*** Sets background of center col***/ border-color:#ccc; } #patternLeftBar, #patternLeftBarContents { /* don't set a background here; use patternWrapper */ } #patternWrapper { background-color:#F6FAFD; /*BG13*/ } #patternBottomBar { background-color:#fff; border-color:#ccc; } #patternBottomBarContents, #patternBottomBarContents a:link, #patternBottomBarContents a:visited { color:#8E9195; /*T8*/ } /* GENERAL HTML ELEMENTS */ html body { background-color:#fff; /*BG1*/ color:#000; /*T1*/ } /* be kind to netscape 4 that doesn't understand inheritance */ body, p, li, ul, ol, dl, dt, dd, acronym, h1, h2, h3, h4, h5, h6 { background-color:transparent; } hr { color:#ccc; /*BO7*/ background-color:#ccc; /*BO7*/ } pre, code, tt { color:#7A4707; /*T6*/ } h1, h2, h3, h4, h5, h6 { color:#a00; /*T5*/ } h1 a:link, h1 a:visited { color:#a00; /*T5*/ } h1 a:hover { color:#FBF7E8; /*T3*/ } h2 { background-color:#FDFAF1; border-color:#E2DCC8; /*BO4*/ } h3, h4, h5, h6 { border-color:#E9E4D2; /*BO5*/ } /* to override old Render.pm coded font color style */ .twikiNewLink font { color:inherit; } .twikiNewLink a:link sup, .twikiNewLink a:visited sup { color:#666; /*T7*/ border-color:#ddd; /*BO8*/ } .twikiNewLink a:hover sup { background-color:#D6000F; /*BG2*/ color:#FBF7E8; /*C3*/ border-color:#D6000F; /*BG2*/ /* (part of bg) */ } .twikiNewLink { border-color:#ddd; /*BO8*/ } :link:focus, :visited:focus, :link, :visited, :link:active, :visited:active { color:#06c; /*T2*/; background-color:transparent; } :link:hover, :visited:hover { color:#FBF7E8; /*C3*/ background-color:#D6000F; /*BG2*/ } :link:hover img, :visited:hover img { background:#fff; /*BG1*/ } .patternTopic a:visited { color:#666; /*T7*/ } .patternTopic a:hover { color:#FBF7E8; /*C3*/ } /* Form elements */ textarea, input, select { border-color:#aaa; /*BO6*/ } .twikiSubmit, .twikiButton { border-color:#ddd #aaa #aaa #ddd; color:#333; background-color:#fff; /*BG1*/ } .twikiSubmit:active, .twikiButton:active { border-color:#999 #ccc #ccc #999; color:#000; } .twikiInputField, .twikiSelect { border-color:#aaa #ddd #ddd #aaa; color:#000; background-color:#fff; /*BG1*/ } /* ----------------------------------------------------------- Plugin elements ----------------------------------------------------------- */ /* TablePlugin */ .twikiTable, .twikiTable td, .twikiTable th { border-color:#ccc; /*BO8*/ } .twikiTable th a:link, .twikiTable th a:visited, .twikiTable th a font { color:#06c; /*T2*/ } .twikiTable th a:hover, .twikiTable th a:hover font { background-color:transparent; color:#D6000F; /*T4*/ border-color:#D6000F; /*T4*/ } /* TablePlugin - sorting of table columns */ .patternTopic th.twikiSortedAscendingCol, .patternTopic th.twikiSortedDescendingCol { background-color:#ccc; /*BG8*/ } th.twikiSortedAscendingCol a:link, th.twikiSortedAscendingCol a:link font, th.twikiSortedAscendingCol a:visited, th.twikiSortedAscendingCol a:visited font, th.twikiSortedDescendingCol a:link, th.twikiSortedDescendingCol a:link font, th.twikiSortedDescendingCol a:visited, th.twikiSortedDescendingCol a:visited font { border-color:#666; /*T7*/ } th.twikiSortedAscendingCol a:hover, th.twikiSortedAscendingCol a:hover font, th.twikiSortedDescendingCol a:hover, th.twikiSortedDescendingCol a:hover font { border-color:#D6000F; /*T4*/ } /* TwistyContrib */ .twistyPlaceholder { color:#8E9195; /*T8*/ } a:hover.twistyTrigger { color:#FBF7E8; /*T3*/ } /* TipsContrib */ .tipsOfTheDay { background-color:#ECF4FB; /*BG5*/ } .patternTopic .tipsOfTheDayHeader { color:#333; /*T11*/ } /* TipsContrib - in left bar */ #patternLeftBar .tipsOfTheDay a:link, #patternLeftBar .tipsOfTheDay a:visited { color:#a00; /*T5*/ } #patternLeftBar .tipsOfTheDay a:hover { color:#FBF7E8; /*T3*/ } /* ----------------------------------------------------------- TWiki styles ----------------------------------------------------------- */ .twikiGrayText { color:#8E9195; /*T8*/ } .twikiGrayText a:link, .twikiGrayText a:visited { color:#8E9195; /*T8*/ } .twikiGrayText a:hover { color:#FBF7E8; /*C3*/ } table.twikiFormTable th.twikiFormTableHRow, table.twikiFormTable td.twikiFormTableRow { color:#666; /*T7*/ } .twikiEditForm { color:#000; /*T1*/ } .twikiEditForm .twikiFormTable th, .twikiEditForm .twikiFormTable td { border-color:#ddd; /*BO8*/ } .twikiEditForm .twikiFormTable td { background-color:#F6F8FC; } .twikiEditForm .twikiFormTable th { background-color:#ECF4FB; /*BG5*/ } .patternContent .twikiAttachments, .patternContent .twikiForm { background-color:#FEFBF3; /*BG9*/ border-color:#E2DCC8; /*BO4*/ } .twikiAttachments table, table.twikiFormTable { border-color:#ccc; /*BO7*/ background-color:#fff; /*BG1*/ } .twikiAttachments table { background-color:#fff; /*BG1*/ } .twikiAttachments td, .twikiAttachments th { border-color:#ccc; } .twikiAttachments th/*, table.twikiFormTable th.twikiFormTableHRow*/ { background-color:#fff; /*BG1*/ } .twikiAttachments td { background-color:#fff; /*BG1*/ } .twikiAttachments th a:link, .twikiAttachments th a:visited, table.twikiFormTable th.twikiFormTableHRow a:link, table.twikiFormTable th.twikiFormTableHRow a:visited { color:#06c; /*T2*/ } .twikiAttachments th font, table.twikiFormTable th.twikiFormTableHRow font { color:#06c; /*T2*/ } .twikiAttachments th a:hover, table.twikiFormTable th.twikiFormTableHRow a:hover { border-color:#06c; /*T2*/ background-color:transparent; } .twikiAttachments th.twikiSortedAscendingCol, .twikiAttachments th.twikiSortedDescendingCol { background-color:#efefef; /*BG3*/ } .twikiFormSteps { background-color:#F6FAFD; /*BG13*/ border-color:#E2DCC8; } .twikiFormStep { border-color:#E2DCC8; } .twikiFormStep h3, .twikiFormStep h4 { background-color:transparent; } .twikiToc .twikiTocTitle { color:#666; /*T7*/ } .twikiBroadcastMessage { background-color:yellow; } .twikiBroadcastMessage b, .twikiBroadcastMessage strong { color:#f00; /*T9*/ } .twikiAlert, .twikiAlert code { color:#f00; /*T9*/ } .twikiEmulatedLink { color:#06c; /*T2*/ } .twikiPageForm table { border-color:#ddd; /*BO8*/ background:#fff; /*BG1*/ } .twikiPageForm hr { border-color:#efefef; /*BO1*/ background-color:#efefef; /*BO1*/ color:#efefef; /*BO1*/ } .twikiHelp { background-color:#ECF4FB; /*BG5*/ border-color:#D5E6F3; /*BO3*/ } .twikiAccessKey { color:inherit; border-color:#8E9195; /*T8*/ } a:link .twikiAccessKey, a:visited .twikiAccessKey, a:hover .twikiAccessKey { color:inherit; } /* ----------------------------------------------------------- Pattern skin specific elements ----------------------------------------------------------- */ #patternPage { background-color:#fff; /*BG1*/ } /* Left bar */ #patternLeftBarContents { color:#666; /*T7*/ } #patternLeftBarContents .patternWebIndicator { color:#000; /*T1*/ } #patternLeftBarContents .patternWebIndicator a:link, #patternLeftBarContents .patternWebIndicator a:visited { color:#000; /*T1*/ } #patternLeftBarContents .patternWebIndicator a:hover { color:#FBF7E8; /*T3*/ } #patternLeftBarContents hr { color:#E2DCC8; /*BO4*/ background-color:#E2DCC8; /*BO4*/ } #patternLeftBarContents a:link, #patternLeftBarContents a:visited { color:#7A4707; /*T6*/ } #patternLeftBarContents a:hover { color:#FBF7E8; /*C3*/ } #patternLeftBarContents b, #patternLeftBarContents strong { color:#333; /*T11*/ } #patternLeftBarContents .patternChangeLanguage { color:#8E9195; /*T8*/ } #patternLeftBarContents .patternLeftBarPersonal { border-color:#D9EAF6; } #patternLeftBarContents .patternLeftBarPersonal a:link, #patternLeftBarContents .patternLeftBarPersonal a:visited { color:#06c; /*T2*/; } #patternLeftBarContents .patternLeftBarPersonal a:hover { color:#FBF7E8; /*C3*/ background-color:#D6000F; /*BG2*/ } .patternSeparator { font-family:monospace; } .patternTopicAction { color:#666; /*T7*/ border-color:#E2DCC8; /*BO4*/ background-color:#FBF7E8; } .patternTopicAction .twikiSeparator { color:#aaa; } .patternActionButtons a:link, .patternActionButtons a:visited { color:#D6000F; /*T4*/ } .patternActionButtons a:hover { color:#FBF7E8; /*C3*/ } .patternTopicAction .twikiAccessKey { border-color:#C75305; } .patternTopicAction label { color:#000; /*T1*/ } .patternHelpCol { color:#8E9195; /*T8*/ } .patternFormFieldDefaultColor { /* input fields default text color (no user input) */ color:#8E9195; /*T8*/ } .patternToolBar .patternButton s, .patternToolBar .patternButton strike, .patternToolBar .patternButton a:link, .patternToolBar .patternButton a:visited { border-color:#E2DCC8; /*BO4*/ background-color:#fff; /*BG1*/ } .patternToolBar .patternButton a:link, .patternToolBar .patternButton a:visited { color:#666; /*T7*/ } .patternToolBar .patternButton s, .patternToolBar .patternButton strike { color:#ccc; border-color:#e0e0e0; background-color:#fff; /*BG1*/ } .patternToolBar .patternButton a:hover { background-color:#D6000F; /*BG2*/ color:#FBF7E8; /*C3*/ border-color:#D6000F; /*T4*/ } .patternToolBar .patternButton img { background-color:transparent; } .patternToolBarBottom { border-color:#E2DCC8; /*BO4*/ } .patternToolBar a:link .twikiAccessKey, .patternToolBar a:visited .twikiAccessKey { color:inherit; border-color:#666; /*T7*/ } .patternToolBar a:hover .twikiAccessKey { background-color:transparent; color:inherit; } .patternRevInfo, .patternRevInfo a:link, .patternRevInfo a:visited { color:#8E9195; /*T8*/ } .patternRevInfo a:hover { color:#FBF7E8; /*C3*/ } .patternMoved, .patternMoved a:link, .patternMoved a:visited { color:#8E9195; /*T8*/ } .patternMoved a:hover { color:#FBF7E8; /*T3*/ } /* WebSearch, WebSearchAdvanced */ table#twikiSearchTable th, table#twikiSearchTable td { background-color:#fff; /*BG1*/ border-color:#ddd; /*BO8*/ } table#twikiSearchTable th { color:#8E9195; /*T8*/ } table#twikiSearchTable td.first { background-color:#efefef; /*BG3*/ } /* ----------------------------------------------------------- Search results styles and overridden styles used in search.pattern.tmpl ----------------------------------------------------------- */ h3.patternSearchResultsHeader, h4.patternSearchResultsHeader { background-color:#FEFBF3; /*BG9*/ border-color:#ccc; /*BO7*/ } h4.patternSearchResultsHeader { color:#000; } .patternNoViewPage h4.patternSearchResultsHeader { color:#a00; /*T5*/ } .patternSearchResult .twikiBottomRow { border-color:#ddd; /*BO8*/ } .patternSearchResult .twikiAlert { color:#f00; /*T9*/ } .patternSearchResult .twikiSummary .twikiAlert { color:#900; /*C5*/ } .patternSearchResult .twikiNew { background-color:#ECFADC; /*BG10*/ border-color:#049804; /*T10*/ color:#049804; /*T10*/ } .patternViewPage .patternSearchResultsBegin { border-color:#ddd; /*BO8*/ } /* Search results in book view format */ .patternBookView .twikiTopRow { background-color:transparent; /* set to WEBBGCOLOR in css.pattern.tmpl */ color:#666; /*T7*/ } .patternBookView .twikiBottomRow { border-color:#ddd; /*BO8*/ } .patternBookView .patternSearchResultCount { color:#8E9195; /*T8*/ } /* oopsmore.pattern.tmpl */ table.patternDiffOptions img { border-color:#ccc; /*BO7*/ } /* edit.pattern.tmpl */ .patternEditPage textarea#topic { background-color:#fff; /*BG1*/ } .twikiChangeFormButton .twikiButton, .twikiChangeFormButtonHolder .twikiButton { color:#06c; /*T2*/ background:none; } .patternSig input { color:#8E9195; /*T8*/ background-color:#fff; /*BG1*/ } .patternAccessKeyInfo { color:#666; /*T7*/ background-color:#ECF4FB; /*BG5*/ border-color:#D5E6F3; /*BO3*/ } .patternAccessKeyInfo a:link, .patternAccessKeyInfo a:visited { color:#06c; /*T2*/ } .patternAccessKeyInfo a:hover { color:#FBF7E8; /*T3*/ } /* preview.pattern.tmpl */ .patternPreviewArea { border-color:#f00; /*BO9*/ background-color:#fff; /*BG1*/ } /* rdiff.pattern.tmpl */ .patternDiff { border-color:#ccc; } .patternDiff h4.patternSearchResultsHeader { background-color:#ccc; } tr.twikiDiffDebug td { border-color:#ddd; /*BO8*/ } .patternDiffPage .twikiDiffTable th { background-color:#eee; } tr.twikiDiffDebug .twikiDiffChangedText, tr.twikiDiffDebug .twikiDiffChangedText { background:#99ff99; /* green */ } /* Deleted */ tr.twikiDiffDebug .twikiDiffDeletedMarker, tr.twikiDiffDebug .twikiDiffDeletedText { background-color:#f99; } /* Added */ tr.twikiDiffDebug .twikiDiffAddedMarker, tr.twikiDiffDebug .twikiDiffAddedText { background-color:#ccf; } /* Unchanged */ tr.twikiDiffDebug .twikiDiffUnchangedText { color:#8E9195; /*T8*/ } /* Headers */ .twikiDiffChangedHeader, .twikiDiffDeletedHeader, .twikiDiffAddedHeader { background-color:#ccc; } /* Unchanged */ .twikiDiffUnchangedTextContents { } .twikiDiffLineNumberHeader { background-color:#eee; } /* CONFIGURE SPECIFIC */ #twikiPassword, #twikiPasswordChange { width:40em; margin:1em auto; text-align:center; } #twikiPassword .twikiFormSteps, #twikiPasswordChange .twikiFormSteps { border-width:5px; } ul { margin-top:0; margin-bottom:0; } .logo { margin:1em 0 1.5em 0; } .formElem { background-color:#F3EDE7; margin:0.5em 0; padding:0.5em 1em; } .blockLinkAttribute { margin-left:0.35em; } .blockLinkAttribute a:link, .blockLinkAttribute a:visited { text-decoration:none; } a.blockLink { display:block; padding:0.25em 1em; border-bottom:1px solid #aaa; text-decoration:none; } a:link.blockLink, a:visited.blockLink { text-decoration:none; } a:link:hover.blockLink { text-decoration:none; } a:link.blockLinkOff, a:visited.blockLinkOff { background-color:#F3EDE7; color:#333; font-weight:normal; } a:link.blockLinkOn, a:visited.blockLinkOn { background-color:#b4d5ff; color:#333; font-weight:bold; } a.blockLink:hover { background-color:#1559B3; color:white; } div.explanation { background-color:#ECF4FB; padding:0.5em 1em; margin:0.5em 0; } div.specialRemark { background-color:#fff; border:1px solid #ccc; margin:0.5em; padding:0.5em 1em; } div.options { margin:1em 0; } div.options div.optionHeader { padding:0.25em 1em; background-color:#666; color:white; font-weight:bold; } div.options div.optionHeader a { color:#bbb; text-decoration:underline; } div.options div.optionHeader a:link:hover, div.options div.optionHeader a:visited:hover { color:#b4d5ff; /* King's blue */ background-color:#666; text-decoration:underline; } div.options .twikiSmall { margin-left:0.5em; color:#bbb; } div.foldableBlock { border-bottom:1px solid #ccc; border-left:1px solid #ddd; border-right:1px solid #ddd; height:auto; width:auto; overflow:auto; padding:0.25em 0 0.5em 0; } .foldableBlockOpen { display:block; } .foldableBlockClosed { display:block; } div.foldableBlock table { margin-bottom:1em; } div.foldableBlock td { padding:0.15em 1em; border-top:1px solid #ddd; } .info { color:#666; /*T7*/ /* gray */ background-color:#ECF4FB; margin-bottom:0.25em; padding:0.25em 0; } .warn { color:#f60; /* orange */ background-color:#FFE8D9; /* light orange */ border-bottom:1px solid #f60; } a.info, a.warn, a.error { text-decoration:none; } .error { color:#f00; /*T9*/ /*red*/ background-color:#FFD9D9; /* pink */ border-bottom:1px solid #f00; } .mandatory, .mandatory input { color:green; background-color:#ECFADC; font-weight: bold; } .mandatory { border-bottom:1px solid green; } .mandatory input { font-weight:normal; } .docdata { padding-top: 1ex; vertical-align: top; } .keydata { font-weight: bold; background-color:#FOFOFO; vertical-align: top; } .subHead { font-weight: bold; font-style: italic; } .firstCol { width: 30%; font-weight: bold; vertical-align: top; } .secondCol { } .hiddenRow { display:none; } HERE my $js2 = <<'HERE'; // HERE my $hdr = CGI::start_html( -title => 'TWiki Configuration', -head => [ 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=>$ENV{SCRIPT_NAME}.'?action=image;image=favicon.ico;type=image/x-icon', -type=>'image/x-icon' } ), CGI::Link( { -rel=>'shortcut icon', -href=>$ENV{SCRIPT_NAME}.'?action=image;image=logos/favicon.ico;type=image/x-icon', -type=>'image/x-icon' } ), CGI::script( { language => 'JavaScript', type => 'text/javascript' }, $js1 ), CGI::style( { -type=>'text/css' }, $css), CGI::script( { language => 'JavaScript', type => 'text/javascript' }, $js2 ), ], -class => 'patternNoViewPage'); # XML confuses IE, so strip it out. This is fixed in CGI.pm 3.06. $hdr =~ s/^<\?xml.*?>//s; print CGI::header('text/html'), $hdr; my $body = "

"; $body .= CGI::img({src=>$ENV{SCRIPT_NAME}.'?action=image;image=T-logo-140x40-t.gif;type=image/gif', class=>'logo', alt=>'TWiki', width=>'140', height=>'40'}); $body .= CGI::h1( 'Configuration'); $body .= "
"; my $update_disabled = 0; my $path_to_localsite_cfg = _findFileOnPath('LocalSite.cfg'); unless( $path_to_localsite_cfg ) { $path_to_localsite_cfg = _findFileOnPath('TWiki.cfg') || ''; $path_to_localsite_cfg =~ s/TWiki\.cfg/LocalSite.cfg/; } my $errs; if( !$path_to_localsite_cfg || ( $errs = _checkCanCreateFile( $path_to_localsite_cfg ))) { $errs ||= 'Cannot locate LocalSite.cfg. Is your setting for $twikiLibPath correct in bin/LocalLib.cfg?'; $body .= CGI::p(WARN('Save is disabled; '.$errs)); $update_disabled = "Cannot create $path_to_localsite_cfg - are permissions correct?"; } if( $action eq 'update' ) { if( $update_disabled ) { die ERROR( "Update is disabled $update_disabled" ); } $body .= handleUpdate( $path_to_localsite_cfg ); } else { $body .= "

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

"; $body .= "
"; $body .= CGI::img({height=>'16', width=>'16', src=>$ENV{SCRIPT_NAME}.'?action=image;image=info.gif;type=image/gif', alt=>''}) . ' '; $TWiki::cfg{ScriptUrlPath} ||= ''; $TWiki::cfg{ScriptSuffix} ||= ''; $TWiki::cfg{SystemWebName} ||= ''; $body .= <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 color codes:
  • 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.
HERE $body .= performSanityChecks( $brokenTWikiCfgError, $brokenLocalSiteError ); my $options = ''; unless( $update_disabled ) { $body .= CGI::start_form({ action=>$ENV{SCRIPT_NAME},method=>"post" }); # use time to make sure we never allow cacheing $options .= CGI::hidden( 'action', 'update' ); $options .= CGI::hidden( 'time', time() ); } $options .= 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()); $options .= presentReadOnlyInfo(); $options .= presentEditableInfo(); $body .= CGI::div({class=>'options', id=>'options'}, $options); my $totwarningsMess = ($totwarnings > 1) ? ' warnings' : ' warning'; $body .= CGI::div('Total: '.CGI::span( {class=>'warn'}, $totwarnings . $totwarningsMess)) if $totwarnings; my $toterrorsMess = ($toterrors > 1) ? ' errors' : ' error'; $body .= CGI::div('Total: ' . CGI::span( {class=>'error'}, $toterrors . $toterrorsMess)) if $toterrors; if( $update_disabled) { $body .= CGI::em("Update is disabled - $update_disabled"); } else { $body .= CGI::p(CGI::submit(-class=>'twikiSubmit', -value=>'Next', -accesskey=>'N')); $body .= CGI::end_form(); } } $body .= "
 
"; print $body; print CGI::end_html(); 1;