removing .po in the wrong place (is in po/ now)
[koha.git] / misc / Install.pm
index 251628c..2f3649c 100644 (file)
@@ -2,6 +2,7 @@ package Install; #assumes Install.pm
 
 
 # Copyright 2000-2002 Katipo Communications
+# Contains parts Copyright 2003 MJ Ray
 #
 # This file is part of Koha.
 #
@@ -17,9 +18,17 @@ package Install; #assumes Install.pm
 # You should have received a copy of the GNU General Public License along with
 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
 # Suite 330, Boston, MA  02111-1307 USA
+#
+# Recent Authors
+# MJR: my.cnf, etcdir, prefix, new display, apache conf, copying fixups
 
 use strict;
 use POSIX;
+#MJR: everyone will have these modules, right?
+# They look like part of perl core to me
+use Term::Cap;
+use Term::ANSIColor qw(:constants);
+use Text::Wrap;
 require Exporter;
 
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
@@ -45,8 +54,10 @@ to perform an actual installation.
 $VERSION = 0.01;
 
 @ISA = qw(Exporter);
-@EXPORT = qw(  &checkperlmodules
-                &checkabortedinstall
+@EXPORT = qw(
+               &read_autoinstall_file
+               &checkperlmodules
+               &checkabortedinstall
                &getmessage
                &showmessage
                &releasecandidatewarning
@@ -61,11 +72,14 @@ $VERSION = 0.01;
                &updatedatabase
                &populatedatabase
                &restartapache
+               &backupkoha
                &finalizeconfigfile
                &loadconfigfile
+               &backupmycnf
+               &restoremycnf
                );
 
-use vars qw( $kohaversion );                   # set in installer.pl
+use vars qw( $kohaversion $newversion );                       # set in loadconfigfile and installer.pl
 use vars qw( $language );                      # set in installer.pl
 use vars qw( $domainname );                    # set in installer.pl
 
@@ -76,10 +90,7 @@ use vars qw( $servername $svr_admin $opacport $intranetport );
 use vars qw( $mysqldir );
 use vars qw( $database $mysqluser );
 use vars qw( $mysqlpass );                     # normally should not be used
-use vars qw( $mysqlpass_quoted );              # quoted, contains -p as needed
-use vars qw( $dbname $hostname $user $pass );  # virtual hosting
-
-use vars qw( $newversion );                    # XXX this seems to be unused
+use vars qw( $hostname $user $pass );  # virtual hosting
 
 =item heading
 
@@ -88,42 +99,75 @@ use vars qw( $newversion );                 # XXX this seems to be unused
 
 The heading function takes one string, the text to be displayed as
 the heading, and returns a formatted heading (currently formatted
-in the "traditional Koha installer" style, i.e., surrounded by a
-box of equal signs).
+with ANSI colours).
 
 This reduces the likelihood of pod2man(1) etc. misinterpreting
 a line of equal signs as illegal POD directives.
 
 =cut
 
+my $termios = POSIX::Termios->new();
+$termios->getattr();
+my $terminal = Term::Cap->Tgetent({OSPEED=>$termios->getospeed()});
+my $clear_string = "\n";
+
 sub heading ($) {
-   my($s) = @_;
-   my $n = length($s) + 4;
-   my $line = ('=' x $n) . "\n";
-   "\n$line= $s =\n$line\n";
+  my $title = shift;
+  my $bal = 5;
+  return($clear_string.ON_BLUE.WHITE.BOLD." "x$bal.uc($title)." "x$bal.RESET."\n\n");
 }
 
+my $mycnf = $ENV{HOME}."/.my.cnf";
+my $mytmpcnf = `mktemp my.cnf.koha.XXXXXX`;
+chomp($mytmpcnf);
+
 my $messages;
-$messages->{'continuing'}->{en}="Great!  Continuing setup.\n\n";
+$messages->{'continuing'}->{en}="Great!  Continuing...\n\n";
 $messages->{'WelcomeToKohaInstaller'}->{en} =
    heading('Welcome to the Koha Installer') . qq|
-Welcome to the Koha install script!  This script will prompt you for some
-basic information about your desired setup, then install Koha according to
-your specifications.  To accept the default value for any question, simply hit
-Enter at the prompt.
+This program will ask some questions and try to install koha for you.
+You need to know: 
+* where most koha files should be stored (you can set the prefix environment variable for this);
+* the username and password of a mysql superuser; 
+* Details of your library setup. 
+* Details of your Apache setup.
+
+If you want to install the Koha configuration files somewhere other than
+/etc (for multiple Koha versions on one system, for example), you should
+set the etcdir environment variable.  Please look at your manuals for
+details of how to set that.
+
+Recommended answers are given in brackets after each question.  To accept
+the default value for any question (indicated by []), simply hit Enter
+at the prompt.
+
+Note that you also can define an auto_install_file, that will answer every question automatically.
+To use this feature, run ./installer.pl -i /path/to/auto_install_file 
+
+Are you ready to begin the installation? ([Y]/N): |;
+
+$messages->{'WelcomeToUpgrader'}->{en} =
+   heading('Welcome to the Koha Upgrader') . qq|
+You are attempting to upgrade from Koha %s to %s.
+
+We recommend that you do a complete backup of all your files before upgrading.
+This upgrade script will make a backup copy of your files for you.
+
+Would you like to proceed?  (Y/[N]):|;
 
-Please be sure to read the documentation, or visit the Koha website at
-http://www.koha.org for more information.
+$messages->{'AbortingInstall'}->{en} =
+   heading('ABORTING') . qq|
+Aborting as requested.  Please rerun when you are ready.
+|;
 
-Are you ready to begin the installation? (Y/[N]): |;
 $messages->{'ReleaseCandidateWarning'}->{en} =
    heading('RELEASE CANDIDATE') . qq|
-WARNING WARNING WARNING WARNING WARNING
+WARNING: You are about to install Koha version %s.  This is a
+release candidate, It is NOT bugfree.
+However, it works, and has been declared stable enough to
+be released.
 
-You are about to install Koha version %s.  This version of Koha is a
-release candidate.  It is not intended to be installed on production systems.
-It is being released so that users can test it before we release a final
-version.
+Most people should answer Yes here.
 
 Are you sure you want to install Koha %s? (Y/[N]): |;
 $messages->{'WatchForReleaseAnnouncements'}->{en}=qq|
@@ -137,39 +181,51 @@ $messages->{'NETZ3950Missing'}->{en}=qq|
 
 The Net::Z3950 module is missing.  This module is necessary if you want to use
 Koha's Z39.50 client to download bibliographic records from other libraries.
+
 To install this module, you will need the yaz client installed from
 http://www.indexdata.dk/yaz/ and then you can install the perl module with the
 command:
 
 perl -MCPAN -e 'install Net::Z3950'
 
-Press the <ENTER> key to continue: |;
+...or by installing packages for your distribution, if available.
+
+IMPORTANT NOTE : If you use Perl 5.8.0, you might need to 
+edit NET::Z3950's Makefile.PL and yazwrap/Makefile.PL to include:
+
+    'DEFINE' => '-D_GNU_SOURCE',
+
+Also note that some installations of Perl on Red Hat will generate a lot of
+"'my_perl' undeclared" errors when running make in Net-Z3950.  This is fixed by
+inserting in yazwrap/ywpriv.h a line saying #include "XSUB.h"
 
-$messages->{'CheckingPerlModules'}->{en} = heading('PERL & MODULES') . qq|
+Press the <ENTER> key to continue: |;  #'
+
+$messages->{'CheckingPerlModules'}->{en} = heading('PERL MODULES') . qq|
 Checking perl modules ...
 |;
 
 $messages->{'PerlVersionFailure'}->{en}="Sorry, you need at least Perl %s\n";
 
 $messages->{'MissingPerlModules'}->{en} = heading('MISSING PERL MODULES') . qq|
-You are missing some Perl modules which are required by Koha.
-Once these modules have been installed, rerun this installer.
-They can be installed by running (as root) the following:
+You are missing some Perl modules required by Koha.
+Please run this again after installing them.
+They may be installed by finding packages from your operating system supplier, or running (as root) the following commands:
 
 %s
 |;
 
 $messages->{'AllPerlModulesInstalled'}->{en} =
-   heading('ALL PERL MODULES INSTALLED') . qq|
-All mandatory perl modules are installed.
+   heading('PERL MODULES AVAILABLE') . qq|
+All required perl modules are installed.
 
 Press <ENTER> to continue: |;
 $messages->{'KohaVersionInstalled'}->{en}="You currently have Koha %s on your system.";
 $messages->{'KohaUnknownVersionInstalled'}->{en}="I am not able to determine what version of Koha is installed now.";
 $messages->{'KohaAlreadyInstalled'}->{en} =
    heading('Koha already installed') . qq|
-It looks like Koha is already installed on your system (%s/koha.conf exists
-already).  If you would like to upgrade your system to %s, please use
+It looks like Koha is already installed on your system (%s/koha.conf exists).
+If you would like to upgrade your system to %s, please use
 the koha.upgrade script in this directory.
 
 %s
@@ -179,46 +235,53 @@ $messages->{'GetOpacDir'}->{en} = heading('OPAC DIRECTORY') . qq|
 Please supply the directory you want Koha to store its OPAC files in.  This
 directory will be auto-created for you if it doesn't exist.
 
-OPAC Directory [%s]: |;
+OPAC Directory [%s]: |;        #'
 
 $messages->{'GetIntranetDir'}->{en} =
-   heading('INTRANET/LIBRARIANS DIRECTORY') . qq|
-Please supply the directory you want Koha to store its Intranet/Librarians
+   heading('LIBRARIAN DIRECTORY') . qq|
+Please supply the directory you want Koha to store its Librarian interface
 files in.  This directory will be auto-created for you if it doesn't exist.
 
-Intranet Directory [%s]: |;
+Intranet Directory [%s]: |;    #'
 
-$messages->{'GetKohaLogDir'}->{en} = heading('KOHA LOG DIRECTORY') . qq|
-Specify a log directory where any Koha daemons can create log files.
+$messages->{'GetKohaLogDir'}->{en} = heading('LOG DIRECTORY') . qq|
+Specify a directory where log files will be written.
 
 Koha Log Directory [%s]: |;
 
 $messages->{'AuthenticationWarning'}->{en} = heading('Authentication') . qq|
-This release of Koha has a new authentication module.  If you are not already
-using basic authentication on your intranet, you will be required to log in to
-access some of the features of the intranet.  You can log in using the userid
-and password from the %s/koha.conf configuration file at any time.  Use the
-"Members" module to add passwords for other accounts and set their permissions.
+This release of Koha has a new authentication module.
+You will be required to log in to
+access some features.
+
+IMPORTANT: You can log in using the userid and password from the %s/koha.conf configuration file at any time.
+Use the "Members" screen to add passwords for other accounts and set their flags.
 
 Press the <ENTER> key to continue: |;
 
-$messages->{'Completed'}->{en} = heading('KOHA INSTALLATION COMPLETE') . qq|
+$messages->{'Completed'}->{en} = heading('INSTALLATION COMPLETE') . qq|
 Congratulations ... your Koha installation is complete!
-
 You will be able to connect to your Librarian interface at:
-
    http://%s\:%s/
-
-and the OPAC interface at :
-
+   use the koha admin mysql login and password to connect to this interface.
+and the OPAC interface at:
    http://%s\:%s/
+   
+NOTE: You need to add lines to your main httpd.conf to include
+/etc/koha-httpd.conf and to make sure it is listening on the right ports
+(using the Listen directive). Then, restart Apache.
+
+Please read the Hints file and visit http://www.koha.org (in english) or www.koha-fr.org (in french)
+Press <ENTER> to exit the installer: |;
 
-Be sure to read the INSTALL, and Hints files.
+$messages->{'UpgradeCompleted'}->{en} = heading('UPGRADE COMPLETE') . qq|
+Congratulations ... your Koha upgrade is finished!
 
-For more information visit http://www.koha.org
+Please report any problems you encounter through http://bugs.koha.org/
 
 Press <ENTER> to exit the installer: |;
 
+#'
 sub releasecandidatewarning {
     my $message=getmessage('ReleaseCandidateWarning', [$newversion, $newversion]);
     my $answer=showmessage($message, 'yn', 'n');
@@ -226,12 +289,48 @@ sub releasecandidatewarning {
     if ($answer =~ /y/i) {
        print getmessage('continuing');
     } else {
-       my $message=getmessage('WatchForReleaseAnnouncements');
-       print $message;
+       my $message=getmessage('WatchForReleaseAnnouncements','');
+       print $message."\n";
        exit;
     };
 }
 
+sub read_autoinstall_file
+{
+       my $fname = shift;      # Config file to read
+       my $retval = {};        # Return value: ref-to-hash holding the
+                               # configuration
+
+       open (CONF, $fname) or return undef;
+
+       while (<CONF>)
+       {
+               my $var;                # Variable name
+               my $value;              # Variable value
+
+               chomp;
+               s/#.*//;                # Strip comments
+               next if /^\s*$/;        # Ignore blank lines
+
+               # Look for a line of the form
+               #       var = value
+               if (!/^\s*(\w+)\s*=\s*(.*?)\s*$/)
+               {
+                       next;
+               }
+
+               # Found a variable assignment
+               # variable that was already set.
+               $var = $1;
+               $value = $2;
+               $retval->{$var} = $value;
+       }
+       close CONF;
+       if ($retval->{MysqlRootPassword} eq "XXX") {
+               print "ERROR : the root password is XXX. It is NOT valid. Edit your auto_install_file\n";
+       }
+       return $retval;
+}
 
 =back
 
@@ -282,6 +381,18 @@ sub setetcdir ($) {
     ($etcdir) = @_;
 }
 
+=item getkohaversion
+
+    getkohaversion();
+
+Gets the Koha version as known by the previous config file.
+
+=cut
+
+sub getkohaversion () {
+    return($kohaversion);
+}
+
 =item setkohaversion
 
     setkohaversion('1.3.3RC26');
@@ -291,7 +402,7 @@ Sets the Koha version as known by the installer.
 =cut
 
 sub setkohaversion ($) {
-    ($kohaversion) = @_;
+    ($newversion) = @_;
 }
 
 =item getservername
@@ -378,7 +489,7 @@ to $mode or not. (This is the behaviour of the mkdir -p command.)
 
 =cut
 
-sub mkdir_parents ($;$) {
+sub mkdir_parents {
     my($path, $mode) = @_;
     my $ok = -d($path)? 1: defined $mode? mkdir($path, $mode): mkdir($path);
 
@@ -414,7 +525,7 @@ found.
 sub getmessage {
     my $messagename=shift;
     my $variables=shift;
-    my $message=$messages->{$messagename}->{$language} || $messages->{$messagename}->{en} || "Error: No message named $messagename in Install.pm\n";
+    my $message=$messages->{$messagename}->{$language} || $messages->{$messagename}->{en} || RED.BOLD."Error: No message named $messagename in Install.pm\n";
     if (defined($variables)) {
        $message=sprintf $message, @$variables;
     }
@@ -433,6 +544,7 @@ sub getmessage {
 
     $result = showmessage($message, 'restrictchar CHARS');
     $result = showmessage($message, 'free');
+    $result = showmessage($message, 'silentfree');
     $result = showmessage($message, 'numerical');
     $result = showmessage($message, 'email');
     $result = showmessage($message, 'PressEnter');
@@ -444,7 +556,7 @@ are mandatory.  The message must be the actual string to
 display; the caller is responsible for calling getmessage if
 required.
 
-The response type must be one of "none", "yn", "free",
+The response type must be one of "none", "yn", "free", "silentfree"
 "numerical", "email", "PressEnter", or a string consisting
 of "restrictchar " followed by a list of allowed characters
 (space can be specified). (Case is not significant, but case is
@@ -482,52 +594,49 @@ The screen is normally cleared before the message is displayed;
 if a fourth argument is specified and is nonzero, this
 screen-clearing is not done.
 
-FIXME: A response type of "yn" should allow the user to specify
-"y" or "n" in either uppercase or lowercase. This is especially
-true since the message shown to the user will contain uppercase
-characters as valid choices.
-
-FIXME: If the response type is "free", the user cannot specify
-an empty string; showmessage will return "1" as the result.
-
-FIXME: A default response of "0" cannot be specified. This is
-wrong; the default response should be checked for undef, not
-for 0.
-
-FIXME: If $noclear is not specified or specified as undef, we
-just test it for a non-zero value without testing it for being
-undef first.
-
 =cut
+#'
 
 sub showmessage {
-    my $message=shift;
+    #MJR: Maybe refactor to use anonymous functions that
+    # check the responses instead of RnP branching.
+    my $message=join('',fill('','',(shift)));
     my $responsetype=shift;
     my $defaultresponse=shift;
     my $noclear=shift;
-    ($noclear) || (system('clear'));
+    $noclear = 0 unless defined $noclear; # defaults to "clear"
+    ($noclear) || (print $clear_string);
     if ($responsetype =~ /^yn$/) {
-       $responsetype='restrictchar yn';
+       $responsetype='restrictchar ynYN';
     }
-    print $message;
+    print RESET.$message;
     if ($responsetype =~/^restrictchar (.*)/i) {
        my $response='\0';
        my $options=$1;
        until ($options=~/$response/) {
-           ($defaultresponse) || ($defaultresponse=substr($options,0,1));
+           (defined($defaultresponse)) || ($defaultresponse=substr($options,0,1));
            $response=<STDIN>;
            chomp $response;
            (length($response)) || ($response=$defaultresponse);
-           unless ($options=~/$response/) {
-               ($noclear) || (system('clear'));
-               print "Invalid Response.  Choose from [$options].\n\n";
-               print $message;
-           }
+            if ( $response=~/.*[\:\(\)\^\$\*\!\\].*/ ) {
+                ($noclear) || (print $clear_string);
+                print RED."Response contains invalid characters.  Choose from [$options].\n\n";
+                print RESET.$message;
+                $response='\0';
+            } else {
+                unless ($options=~/$response/) {
+                    ($noclear) || (print $clear_string);
+                    print RED."Invalid Response.  Choose from [$options].\n\n";
+                    print RESET.$message;
+                }
+            }
        }
        return $response;
-    } elsif ($responsetype =~/^free$/i) {
+    } elsif ($responsetype =~/^(silent)?free$/i) {
        (defined($defaultresponse)) || ($defaultresponse='');
+       if ($responsetype =~/^(silent)/i) { setecho(0) }; 
        my $response=<STDIN>;
+       if ($responsetype =~/^(silent)/i) { setecho(1) }; 
        chomp $response;
        ($response) || ($response=$defaultresponse);
        return $response;
@@ -539,9 +648,9 @@ sub showmessage {
            chomp $response;
            ($response) || ($response=$defaultresponse);
            unless ($response=~/^\d+$/) {
-               ($noclear) || (system('clear'));
-               print "Invalid Response ($response).  Response must be a number.\n\n";
-               print $message;
+               ($noclear) || (print $clear_string);
+               print RED."Invalid Response ($response).  Response must be a number.\n\n";
+               print RESET.$message;
            }
        }
        return $response;
@@ -552,10 +661,10 @@ sub showmessage {
            $response=<STDIN>;
            chomp $response;
            ($response) || ($response=$defaultresponse);
-           unless ($response=~/.*\@.*\..*/) {
-               ($noclear) || (system('clear'));
-               print "Invalid Response ($response).  Response must be a valid email address.\n\n";
-               print $message;
+           if ($response!~/.*\@.*\..*/) {
+                       ($noclear) || (print $clear_string);
+                       print RED."Invalid Response ($response).  Response must be a valid email address.\n\n";
+                       print RESET.$message;
            }
        }
        return $response;
@@ -573,6 +682,22 @@ sub showmessage {
 }
 
 
+=back
+
+=item startsysout
+
+       startsysout;
+
+Changes the display to show system output until the next showmessage call.
+At the time of writing, this means using red text.
+
+=cut
+
+sub startsysout {
+       print RED."\n";
+}
+
+
 =back
 
 =head2 Subtasks of doing an installation
@@ -615,6 +740,72 @@ database is already created.
     }
 }
 
+=item checkpaths
+
+       checkpaths;
+
+Make sure that we loaded the right dirs from an old koha.conf
+
+=cut
+
+#FIXME: update to use Install.pm
+sub checkpaths {
+if ($opacdir && $intranetdir) {
+    print qq|
+
+I believe that your old files are located in:
+
+  OPAC:      $opacdir
+  LIBRARIAN: $intranetdir
+
+
+Does this look right?  ([Y]/N):
+|;
+    my $answer = <STDIN>;
+    chomp $answer;
+
+    if ($answer =~/n/i) {
+       $intranetdir='';
+       $opacdir='';
+    } else {
+       print "Great! continuing upgrade... \n";
+    }
+}
+
+if (!$opacdir || !$intranetdir) {
+    $intranetdir='';
+    $opacdir='';
+    while (!$intranetdir) {
+       print "Please specify the location of your LIBRARIAN files: ";
+
+       my $answer = <STDIN>;
+       chomp $answer;
+
+       if ($answer) {
+           $intranetdir=$answer;
+       }
+       if (! -e "$intranetdir/htdocs") {
+           print "\nCouldn't find the htdocs directory here.  That doesn't look right.\nPlease enter another location.\n\n";
+           $intranetdir='';
+       }
+    }
+    while (!$opacdir) {
+       print "Please specify the location of your OPAC files: ";  
+
+       my $answer = <STDIN>;
+       chomp $answer;
+
+       if ($answer) {
+           $opacdir=$answer;
+       }
+       if (! -e "$opacdir/htdocs") {
+           print "\nCouldn't find the htdocs directory here.  That doesn't look right.\nPlease enter another location.\n\n";
+           $opacdir='';
+       }
+    }
+}
+
+}
 
 =item checkperlmodules
 
@@ -630,29 +821,40 @@ sub checkperlmodules {
 #
 # Test for Perl and Modules
 #
+       my ($auto_install) = @_;
+       my $message = getmessage('CheckingPerlModules');
+       showmessage($message, 'none');
 
-    my $message = getmessage('CheckingPerlModules');
-    showmessage($message, 'none');
-
-    # FIXME: Perl 5.6 is BUGGY!!! IT SHOULD NOT BE USED in production!!!
-    unless (eval "require 5.006_000") {
-       die getmessage('PerlVersionFailure', ['5.6.0']);
-    }
-
-    my @missing = ();
-    unless (eval {require DBI})               { push @missing,"DBI" };
-    unless (eval {require Date::Manip})       { push @missing,"Date::Manip" };
-    unless (eval {require DBD::mysql})        { push @missing,"DBD::mysql" };
-    unless (eval {require HTML::Template})          { push @missing,"HTML::Template" };
-    unless (eval {require Set::Scalar})       { push @missing,"Set::Scalar" };
-    unless (eval {require Digest::MD5})       { push @missing,"Digest::MD5" };
-    unless (eval {require MARC::Record})       { push @missing,"MARC::Record" };
-    unless (eval {require Net::Z3950})        {
-       my $message = getmessage('NETZ3950Missing');
-       showmessage($message, 'PressEnter', '', 1);
-       if ($#missing>=0) {
-           push @missing, "Net::Z3950";
+       unless ($] >= 5.006001) {                       # Bug 179
+               die getmessage('PerlVersionFailure', ['5.6.1']);
        }
+       startsysout();
+
+       my @missing = ();
+       unless (eval {require DBI})              { push @missing,"DBI" };
+       unless (eval {require Date::Manip})      { push @missing,"Date::Manip" };
+       unless (eval {require DBD::mysql})       { push @missing,"DBD::mysql" };
+       unless (eval {require HTML::Template})   { push @missing,"HTML::Template" };
+       unless (eval {require Digest::MD5})      { push @missing,"Digest::MD5" };
+       unless (eval {require MARC::Record})     { push @missing,"MARC::Record" };
+       unless (eval {require Mail::Sendmail})   { push @missing,"Mail::Sendmail" };
+       unless (eval {require PDF::API2})   { push @missing,"PDF::API2" };
+# The following modules are not mandatory, depends on how the library want to use Koha
+       unless (eval {require Net::LDAP})       {
+               if ($#missing>=0) { # only when $#missing >= 0 so this isn't fatal
+                               push @missing, "Net::LDAP";
+                       }
+    }
+       unless (eval {require Event})       {
+               if ($#missing>=0) { # only when $#missing >= 0 so this isn't fatal
+                               push @missing, "Event";
+                       }
+    }
+    unless (eval {require Net::Z3950})       {
+               showmessage(getmessage('NETZ3950Missing'), 'PressEnter', '', 1);
+               if ($#missing>=0) { # see above note
+                       push @missing, "Net::Z3950";
+               }
     }
 
 #
@@ -661,17 +863,22 @@ sub checkperlmodules {
 
     if (@missing > 0) {
        my $missing='';
+       if (POSIX::setlocale(LC_ALL) ne "C") {
+               $missing.="   export LC_ALL=C\n";  
+       }
        foreach my $module (@missing) {
            $missing.="   perl -MCPAN -e 'install \"$module\"'\n";
        }
        my $message=getmessage('MissingPerlModules', [$missing]);
        showmessage($message, 'none');
+       print "\n";
        exit;
     } else {
-       showmessage(getmessage('AllPerlModulesInstalled'), 'PressEnter', '', 1);
+       showmessage(getmessage('AllPerlModulesInstalled'), 'PressEnter', '', 1) unless $auto_install->{NoPressEnter};
     }
 
 
+       startsysout();
     unless (-x "/usr/bin/perl") {
        my $realperl=`which perl`;
        chomp $realperl;
@@ -681,6 +888,7 @@ sub checkperlmodules {
        }
        my $response=showmessage(getmessage('ConfirmPerlExecutableSymlink', $realperl), 'yn', 'y', 1);
        unless ($response eq 'n') {
+               startsysout();
            system("ln -s $realperl /usr/bin/perl");
        }
     }
@@ -689,18 +897,25 @@ sub checkperlmodules {
 }
 
 $messages->{'NoUsrBinPerl'}->{en} =
-   heading('Perl is not located in /usr/bin/perl') . qq|
-The Koha perl scripts expect to find the perl executable in the /usr/bin
+   heading('No /usr/bin/perl') . qq|
+Koha expects to find the perl executable in the /usr/bin
 directory.  It is not there on your system.
 
 |;
 
-$messages->{'AskLocationOfPerlExecutable'}->{en}=qq|Location of Perl Executable: [%s]: |;
+$messages->{'AskLocationOfPerlExecutable'}->{en}=qq|Location of Perl Executable [%s]: |;
 $messages->{'ConfirmPerlExecutableSymlink'}->{en}=qq|
-The Koha scripts will _not_ work without a symlink from %s to /usr/bin/perl
+Some Koha scripts will _not_ work without a symlink from %s to /usr/bin/perl
+
+Most users should answer Y here.
+
+May I try to create this symlink? ([Y]/N):|;
+
+$messages->{'DirFailed'}->{en} = RED.qq|
+We could not create %s, but continuing anyway...
+
+|;
 
-May I create this symlink? ([Y]/N):
-: |;
 
 
 =item getinstallationdirectories
@@ -716,17 +931,28 @@ function does not return any values.
 =cut
 
 sub getinstallationdirectories {
-    $opacdir = '/usr/local/koha/opac';
-    $intranetdir = '/usr/local/koha/intranet';
+       my ($auto_install) = @_;
+       if (!$ENV{prefix}) { $ENV{prefix} = "/usr/local"; } #"
+    $opacdir = $ENV{prefix}.'/koha/opac';
+    $intranetdir = $ENV{prefix}.'/koha/intranet';
     my $getdirinfo=1;
     while ($getdirinfo) {
        # Loop until opac directory and koha directory are different
-       my $message=getmessage('GetOpacDir', [$opacdir]);
-       $opacdir=showmessage($message, 'free', $opacdir);
-
-       $message=getmessage('GetIntranetDir', [$intranetdir]);
-       $intranetdir=showmessage($message, 'free', $intranetdir);
-
+       my $message;
+       if ($auto_install->{GetOpacDir}) {
+               $opacdir=$auto_install->{GetOpacDir};
+               print ON_YELLOW.BLACK."auto-setting OpacDir to : $opacdir".RESET."\n";
+       } else {
+               $message=getmessage('GetOpacDir', [$opacdir]);
+               $opacdir=showmessage($message, 'free', $opacdir);
+       }
+       if ($auto_install->{GetIntranetDir}) {
+               $intranetdir=$auto_install->{GetIntranetDir};
+               print ON_YELLOW.BLACK."auto-setting IntranetDir to : $intranetdir".RESET."\n";
+       } else {
+               $message=getmessage('GetIntranetDir', [$intranetdir]);
+               $intranetdir=showmessage($message, 'free', $intranetdir);
+       }
        if ($intranetdir eq $opacdir) {
            print qq|
 
@@ -738,26 +964,31 @@ You must specify different directories for the OPAC and INTRANET files!
            $getdirinfo=0;
        }
     }
-    $kohalogdir='/var/log/koha';
-    my $message=getmessage('GetKohaLogDir', [$kohalogdir]);
-    $kohalogdir=showmessage($message, 'free', $kohalogdir);
+    $kohalogdir=$ENV{prefix}.'/koha/log';
+       if ($auto_install->{GetOpacDir}) {
+               $kohalogdir=$auto_install->{KohaLogDir};
+               print ON_YELLOW.BLACK."auto-setting log dir to : $kohalogdir".RESET."\n";
+       } else {
+           my $message=getmessage('GetKohaLogDir', [$kohalogdir]);
+       $kohalogdir=showmessage($message, 'free', $kohalogdir);
+       }
 
 
-    # FIXME: Missing error handling for all mkdir calls here
+    # FIXME: Need better error handling for all mkdir calls here
     unless ( -d $intranetdir ) {
-       mkdir_parents (dirname($intranetdir), 0775);
-       mkdir ($intranetdir,                  0770);
-       chown (oct(0), (getgrnam($httpduser))[2], "$intranetdir");
-       chmod (oct(770), "$intranetdir");
+       mkdir_parents (dirname($intranetdir), 0775) || print getmessage('DirFailed',['parents of '.$intranetdir]);
+       mkdir ($intranetdir,                  0770) || print getmessage('DirFailed',[$intranetdir]);
+       if ($>==0) { chown (oct(0), (getgrnam($httpduser))[2], "$intranetdir"); }
+       chmod 0770, "$intranetdir";
     }
     mkdir_parents ("$intranetdir/htdocs",    0750);
     mkdir_parents ("$intranetdir/cgi-bin",   0750);
     mkdir_parents ("$intranetdir/modules",   0750);
     mkdir_parents ("$intranetdir/scripts",   0750);
     unless ( -d $opacdir ) {
-       mkdir_parents (dirname($opacdir),     0775);
-       mkdir ($opacdir,                      0770);
-       chown (oct(0), (getgrnam($httpduser))[2], "$opacdir");
+       mkdir_parents (dirname($opacdir),     0775) || print getmessage('DirFailed',['parents of '.$opacdir]);
+       mkdir ($opacdir,                      0770) || print getmessage('DirFailed',[$opacdir]);
+       if ($>==0) { chown (oct(0), (getgrnam($httpduser))[2], "$opacdir"); }
        chmod (oct(770), "$opacdir");
     }
     mkdir_parents ("$opacdir/htdocs",        0750);
@@ -765,14 +996,47 @@ You must specify different directories for the OPAC and INTRANET files!
 
 
     unless ( -d $kohalogdir ) {
-       mkdir_parents (dirname($kohalogdir),  0775);
-       mkdir ($kohalogdir,                   0770);
-       chown (oct(0), (getgrnam($httpduser))[2,3], "$kohalogdir");
+       mkdir_parents (dirname($kohalogdir),  0775) || print getmessage('DirFailed',['parents of '.$kohalogdir]);
+       mkdir ($kohalogdir,                   0770) || print getmessage('DirFailed',[$kohalogdir]);
+       if ($>==0) { chown (oct(0), (getgrnam($httpduser))[2,3], "$kohalogdir"); }
        chmod (oct(770), "$kohalogdir");
     }
 }
 
+=item getmysqldir
 
+       getmysqldir;
+
+Get the MySQL database server installation directory, automatically if possible.
+
+=cut
+
+$messages->{'WhereIsMySQL'}->{en} = heading('MYSQL LOCATION').qq|
+Koha can't find the MySQL command-line tools. If you installed a MySQL package, you may need to install an additional package containing mysqladmin.
+If you compiled mysql yourself,
+please give the value of --prefix when you ran configure.
+The file mysqladmin should be in bin/mysqladmin under the directory that you give here.
+
+MySQL installation directory: |;
+#'
+sub getmysqldir {
+    foreach my $mysql (qw(/usr/local/mysql
+                         /opt/mysql
+                         /usr/local
+                         /usr
+                         )) {
+       if ( -d $mysql  && -f "$mysql/bin/mysqladmin") { #"
+           $mysqldir=$mysql;
+       }
+    }
+    if (!$mysqldir){
+       for (;;) {
+           $mysqldir = showmessage(getmessage('WhereIsMySQL'),'free');
+           last if -f "$mysqldir/bin/mysqladmin";
+       }
+    }
+    return($mysqldir);
+}
 
 =item getdatabaseinfo
 
@@ -787,69 +1051,91 @@ function does not return any values.
 
 =cut
 
-$messages->{'DatabaseName'}->{en} = heading('Name of MySQL database') . qq|
-Please provide the name of the mysql database for your koha installation.
+$messages->{'DatabaseName'}->{en} = heading('Database Name') . qq|
+Please provide the name that you wish to give your koha database.
+It must not exist already on the database server.
+
+Most users give a short single-word name for their library here.
 
 Database name [%s]: |;
 
 $messages->{'DatabaseHost'}->{en} = heading('Database Host') . qq|
-Please provide the hostname for mysql.  Unless the database is located on
-another machine this will be "localhost".
+Please provide the mysql server name.  Unless the database is stored on
+another machine, this should be "localhost".
 
 Database host [%s]: |;
 
 $messages->{'DatabaseUser'}->{en} = heading('Database User') . qq|
-Please provide the name of the user, who will have full administrative rights
-to the %s database, when authenticating from %s.
+We are going to create a new mysql user for Koha. This user will have full administrative rights
+to the database called %s when they connect from %s.
+This is also the name of the Koha librarian superuser.
 
-This user will also be used to access Koha's INTRANET interface.
+Most users give a single-word name here.
 
 Database user [%s]: |;
 
 $messages->{'DatabasePassword'}->{en} = heading('Database Password') . qq|
 Please provide a good password for the user %s.
 
-This password will also be used to access Koha's INTRANET interface.
+IMPORTANT: You can log in using this user and password at any time.
 
-Database Password: |;
+Password for database user %s: |;
 
 $messages->{'BlankPassword'}->{en} = heading('BLANK PASSWORD') . qq|
-You must not use a blank password for your MySQL user!
+You must not use a blank password for your MySQL user.
 
 Press <ENTER> to try again: 
 |;
 
 sub getdatabaseinfo {
-
-    $dbname = 'Koha';
+       my ($auto_install) = @_;
+    $database = 'Koha';
     $hostname = 'localhost';
     $user = 'kohaadmin';
     $pass = '';
 
 #Get the database name
-
-    my $message=getmessage('DatabaseName', [$dbname]);
-    $dbname=showmessage($message, 'free', $dbname);
-
+       my $message;
+       
+       if ($auto_install->{database}) {
+               $database=$auto_install->{database};
+               print ON_YELLOW.BLACK."auto-setting database to : $database".RESET."\n";
+       } else {
+               $message=getmessage('DatabaseName', [$database]);
+               $database=showmessage($message, 'free', $database);
+       }
 #Get the hostname for the database
     
-    $message=getmessage('DatabaseHost', [$hostname]);
-    $hostname=showmessage($message, 'free', $hostname);
-
+       if ($auto_install->{DatabaseHost}) {
+               $hostname=$auto_install->{DatabaseHost};
+               print ON_YELLOW.BLACK."auto-setting database host to : $hostname".RESET."\n";
+       } else {
+               $message=getmessage('DatabaseHost', [$hostname]);
+               $hostname=showmessage($message, 'free', $hostname);
+       }
 #Get the username for the database
 
-    $message=getmessage('DatabaseUser', [$dbname, $hostname, $user]);
-    $user=showmessage($message, 'free', $user);
-
+       if ($auto_install->{DatabaseUser}) {
+               $user=$auto_install->{DatabaseUser};
+               print ON_YELLOW.BLACK."auto-setting DB user to : $user".RESET."\n";
+       } else {
+               $message=getmessage('DatabaseUser', [$database, $hostname, $user]);
+               $user=showmessage($message, 'free', $user);
+       }
 #Get the password for the database user
 
     while ($pass eq '') {
-       my $message=getmessage('DatabasePassword', [$user]);
-       $pass=showmessage($message, 'free', $pass);
-       if ($pass eq '') {
-           my $message=getmessage('BlankPassword');
-           showmessage($message,'PressEnter');
-       }
+               my $message=getmessage('DatabasePassword', [$user, $user]);
+               if ($auto_install->{DatabasePassword}) {
+                       $pass=$auto_install->{DatabasePassword};
+                       print ON_YELLOW.BLACK."auto-setting database password to : $pass".RESET."\n";
+               } else {
+                               $pass=showmessage($message, 'free', $pass);
+               }
+               if ($pass eq '') {
+                       my $message=getmessage('BlankPassword');
+                       showmessage($message,'PressEnter');
+               }
     }
 }
 
@@ -869,112 +1155,126 @@ function does not return any values.
 =cut
 
 $messages->{'FoundMultipleApacheConfFiles'}->{en} = 
-   heading('MULTIPLE APACHE CONFIG FILES') . qq|
+   heading('MULTIPLE APACHE CONFIG FILES FOUND') . qq|
 I found more than one possible Apache configuration file:
 
 %s
 
-Choose the correct file [1]: |;
+Enter number of the file to read [1]: |;
 
 $messages->{'NoApacheConfFiles'}->{en} =
    heading('NO APACHE CONFIG FILE FOUND') . qq|
 I was not able to find your Apache configuration file.
 
-The file is usually called httpd.conf or apache.conf.
+The file is usually called httpd.conf, apache.conf or similar.
 
-Please specify the location of your config file: |;
+Please enter the full name, starting with /: |;
 
 $messages->{'NotAFile'}->{en} = heading('FILE DOES NOT EXIST') . qq|
 The file %s does not exist.
 
 Please press <ENTER> to continue: |;
 
-$messages->{'EnterApacheUser'}->{en} = heading('NEED APACHE USER') . qq|
-I was not able to determine the user that Apache is running as.  This
-information is necessary in order to set the access privileges correctly on
-%s/koha.conf.  This user should be set in one of the Apache configuration
-files using the "User" directive.
+$messages->{'EnterApacheUser'}->{en} = heading('NEED APACHE USER') . qq\
+The installer could not find the User setting in the Apache configuration file.
+This is used to set up access permissions for
+%s/koha.conf.  This user should be set in one of the Apache configuration.
+Please try to find it and enter the user name below.  You might find
+that "ps u|grep apache" will tell you.  It probably is NOT "root".
 
-Enter the Apache userid: |;
+Enter the Apache userid: \;
 
-$messages->{'InvalidUserid'}->{en} = heading('INVALID USERID') . qq|
+$messages->{'InvalidUserid'}->{en} = heading('INVALID USER') . qq|
 The userid %s is not a valid userid on this system.
 
 Press <ENTER> to continue: |;
 
 sub getapacheinfo {
+       my ($auto_install) = @_;
     my @confpossibilities;
 
     foreach my $httpdconf (qw(/usr/local/apache/conf/httpd.conf
                          /usr/local/etc/apache/httpd.conf
                          /usr/local/etc/apache/apache.conf
                          /var/www/conf/httpd.conf
+                         /etc/apache2/httpd.conf
+                         /etc/apache2/apache2.conf
                          /etc/apache/conf/httpd.conf
                          /etc/apache/conf/apache.conf
+                         /etc/apache/httpd.conf
                          /etc/apache-ssl/conf/apache.conf
                          /etc/apache-ssl/httpd.conf
                          /etc/httpd/conf/httpd.conf
-                         /etc/httpd/httpd.conf)) {
-       if ( -f $httpdconf ) {
-           push @confpossibilities, $httpdconf;
-       }
+                         /etc/httpd/httpd.conf
+                         /etc/httpd/2.0/conf/httpd2.conf
+                         )) {
+               if ( -f $httpdconf ) {
+                       push @confpossibilities, $httpdconf;
+               }
     }
 
     if ($#confpossibilities==-1) {
-       my $message=getmessage('NoApacheConfFiles');
-       my $choice='';
-       until (-f $realhttpdconf) {
-           $choice=showmessage($message, "free", 1);
-           if (-f $choice) {
-               $realhttpdconf=$choice;
-           } else {
-               showmessage(getmessage('NotAFile', [$choice]),'PressEnter', '', 1);
-           }
-       }
+               my $message=getmessage('NoApacheConfFiles');
+               my $choice='';
+               $realhttpdconf='';
+               until (-f $realhttpdconf) {
+                       $choice=showmessage($message, "free", 1);
+                       if (-f $choice) {
+                       $realhttpdconf=$choice;
+                       } else {
+                       showmessage(getmessage('NotAFile', [$choice]),'PressEnter', '', 1);
+                       }
+               }
     } elsif ($#confpossibilities>0) {
-       my $conffiles='';
-       my $counter=1;
-       my $options='';
-       foreach (@confpossibilities) {
-           $conffiles.="   $counter: $_\n";
-           $options.="$counter";
-           $counter++;
-       }
-       my $message=getmessage('FoundMultipleApacheConfFiles', [$conffiles]);
-       my $choice=showmessage($message, "restrictchar $options", 1);
-       $realhttpdconf=$confpossibilities[$choice-1];
+               my $conffiles='';
+               my $counter=1;
+               my $options='';
+               foreach (@confpossibilities) {
+                       $conffiles.="   $counter: $_\n";
+                       $options.="$counter";
+                       $counter++;
+               }
+               my $message=getmessage('FoundMultipleApacheConfFiles', [$conffiles]);
+               my $choice=showmessage($message, "restrictchar $options", 1);
+               $realhttpdconf=$confpossibilities[$choice-1];
     } else {
-       $realhttpdconf=$confpossibilities[0];
+               $realhttpdconf=$confpossibilities[0];
     }
     unless (open (HTTPDCONF, "<$realhttpdconf")) {
-       warn "Insufficient privileges to open $realhttpdconf for reading.\n";
+       warn RED."Insufficient privileges to open $realhttpdconf for reading.\n";
        sleep 4;
     }
 
     while (<HTTPDCONF>) {
-       if (/^\s*User\s+"?([-\w]+)"?\s*$/) {
-           $httpduser = $1;
-       }
+               if (/^\s*User\s+"?([-\w]+)"?\s*$/) {
+                       $httpduser = $1;
+               }
     }
     close(HTTPDCONF);
 
-
-
-
-    unless ($httpduser) {
-       my $message=getmessage('EnterApacheUser', [$etcdir]);
-       until (length($httpduser) && getpwnam($httpduser)) {
-           $httpduser=showmessage($message, "free", '');
-           if (length($httpduser)>0) {
-               unless (getpwnam($httpduser)) {
-                   my $message=getmessage('InvalidUserid', [$httpduser]);
-                   showmessage($message,'PressEnter');
+    unless (defined($httpduser)) {
+               my $message;
+               if ($auto_install->{EnterApacheUser}) {
+                       $message = $auto_install->{EnterApacheUser};
+                       print ON_YELLOW.BLACK."auto-setting Apache User to : $message".RESET."\n";
+               } else {
+                       $message=getmessage('EnterApacheUser', [$etcdir]);
+               }
+               until (defined($httpduser) && length($httpduser) && getpwnam($httpduser)) {
+                       if ($auto_install->{EnterApacheUser}) {
+                               $httpduser = $auto_install->{EnterApacheUser};
+                       } else {
+                               $httpduser=showmessage($message, "free", '');
+                       }
+                       if (length($httpduser)>0) {
+                               unless (getpwnam($httpduser)) {
+                                       my $message=getmessage('InvalidUserid', [$httpduser]);
+                                       showmessage($message,'PressEnter');
+                               }
+                       } else {
+                       }
                }
-           } else {
-           }
        }
-       print "AU: $httpduser\n";
-    }
 }
 
 
@@ -993,146 +1293,157 @@ function does not return any values.
 
 $messages->{'ApacheConfigIntroduction'}->{en} =
    heading('APACHE CONFIGURATION') . qq|
-Koha needs to setup your Apache configuration file for the
-OPAC and LIBRARIAN virtual hosts.  By default this installer
-will do this by using one ip address and two different ports
+Koha needs to write an Apache configuration file for the
+OPAC and Librarian sites.  By default this installer
+will do this by using one name and two different ports
 for the virtual hosts.  There are other ways to set this up,
-and the installer will leave comments in httpd.conf detailing
-what these other options are.
+and the installer will leave comments in
+%s/koha-httpd.conf about them.
 
+NOTE: You will need to add lines to your main httpd.conf to
+include %s/koha-httpd.conf
+and to make sure it is listening on the right ports
+(using the Listen directive).
 
 Press <ENTER> to continue: |;
 
 $messages->{'GetVirtualHostEmail'}->{en} =
-   heading('WEB SERVER E-MAIL CONTACT') . qq|
-Enter the e-mail address to be used as a contact for the virtual hosts (this
-address is displayed if any errors are encountered).
+   heading('WEB E-MAIL CONTACT') . qq|
+Enter the e-mail address to be used as a contact for Koha.  This
+address is displayed if fatal errors are encountered.
 
 E-mail contact [%s]: |;
 
 $messages->{'GetServerName'}->{en} =
-   heading('WEB SERVER HOST NAME OR IP ADDRESS') . qq|
-Please enter the domain name or ip address of your computer.
+   heading('WEB HOST NAME OR IP ADDRESS') . qq|
+Please enter the host name or IP address that you wish to use for koha.
+Normally, this should be a name or IP that belongs to this machine.
 
 Host name or IP Address [%s]: |;
 
-$messages->{'GetOpacPort'}->{en} = heading('OPAC VIRTUAL HOST PORT') . qq|
+$messages->{'GetOpacPort'}->{en} = heading('OPAC PORT') . qq|
 Please enter the port for your OPAC interface.  This defaults to port 80, but
-if you are already serving web content from this server, you should change it
-to a different port (8000 might be a good choice).
+if you are already serving web content with this hostname, you should change it
+to a different port (8000 might be a good choice, but check any firewalls).
 
 Enter the OPAC Port [%s]: |;
 
 $messages->{'GetIntranetPort'}->{en} =
-   heading('INTRANET VIRTUAL HOST PORT') . qq|
-Please enter the port for your Intranet interface.  This must be different from
+   heading('LIBRARIAN PORT') . qq|
+Please enter the port for your Librarian interface.  This must be different from
 the OPAC port (%s).
 
 Enter the Intranet Port [%s]: |;
 
 
 sub getapachevhostinfo {
-
+       my ($auto_install) = @_;
     $svr_admin = "webmaster\@$domainname";
     $servername=`hostname`;
     chomp $servername;
     $opacport=80;
     $intranetport=8080;
 
-    showmessage(getmessage('ApacheConfigIntroduction'), 'PressEnter');
+       if ($auto_install->{GetVirtualHostEmail}) {
+               $svr_admin=$auto_install->{GetVirtualHostEmail};
+               print ON_YELLOW.BLACK."auto-setting VirtualHostEmail to : $svr_admin".RESET."\n";
+       } else {
+               showmessage(getmessage('ApacheConfigIntroduction',[$etcdir,$etcdir]), 'PressEnter');
+               $svr_admin=showmessage(getmessage('GetVirtualHostEmail', [$svr_admin]), 'email', $svr_admin);
+       }
+       if ($auto_install->{servername}) {
+               $servername=$auto_install->{servername};
+               print ON_YELLOW.BLACK."auto-setting server name to : $servername".RESET."\n";
+       } else {
+       $servername=showmessage(getmessage('GetServerName', [$servername]), 'free', $servername);
+       }
+       if ($auto_install->{opacport}) {
+               $opacport=$auto_install->{opacport};
+               print ON_YELLOW.BLACK."auto-setting opac port to : $opacport".RESET."\n";
+       } else {
+           $opacport=showmessage(getmessage('GetOpacPort', [$opacport]), 'numerical', $opacport);
+       }
+       if ($auto_install->{intranetport}) {
+               $intranetport=$auto_install->{intranetport};
+               print ON_YELLOW.BLACK."auto-setting intranet port to : $intranetport".RESET."\n";
+       } else {
+           $intranetport=showmessage(getmessage('GetIntranetPort', [$opacport, $intranetport]), 'numerical', $intranetport);
+       }
 
-    $svr_admin=showmessage(getmessage('GetVirtualHostEmail', [$svr_admin]), 'email', $svr_admin);
-    $servername=showmessage(getmessage('GetServerName', [$servername]), 'free', $servername);
+}
 
 
-    $opacport=showmessage(getmessage('GetOpacPort', [$opacport]), 'numerical', $opacport);
-    $intranetport=showmessage(getmessage('GetIntranetPort', [$opacport, $intranetport]), 'numerical', $intranetport);
+=item updateapacheconf
 
-}
+    updateapacheconf;
 
-$messages->{'StartUpdateApache'}->{en} =
-   heading('UPDATING APACHE CONFIGURATION') . qq|
-Checking for modules that need to be loaded...
-|;
+Updates the Apache config file according to parameters previously
+specified by the user.
+
+It will append fully-commented directives at the end of the original
+Apache config file.  The old config file is renamed with an extension
+of .prekoha.
 
-$messages->{'LoadingApacheModuleModEnv'}->{en}="Loading SetEnv Apache module.\n";
+If you need to uninstall Koha for any reason, the lines between
 
-$messages->{'LoadingApacheModuleModInc'}->{en}="Loading Includes Apache module.\n";
+    # Ports to listen to for Koha
 
-$messages->{'ApacheConfigBackupFailed'}->{en} =
-   heading('APACHE CONFIGURATION BACKUP FAILED') . qq|
-An error occurred while trying to make a backup copy of %s.
+and the block of comments beginning with
 
-  %s
+    # If you want to use name based Virtual Hosting:
 
-No changes will be made to the apache configuration file at this time.
+must be removed.
+
+=cut
+
+$messages->{'StartUpdateApache'}->{en} =
+   heading('UPDATING APACHE CONFIGURATION') . qq|
+Checking for modules that need to be loaded...
+|;
+
+$messages->{'ApacheConfigMissingModules'}->{en} =
+   heading('APACHE CONFIGURATION NEEDS UPDATE') . qq|
+Koha uses the mod_env and mod_include apache features, but the
+installer did not find them in your config.  Please
+make sure that they are enabled for your Koha site.
 
 Press <ENTER> to continue: |;
 
 
 $messages->{'ApacheAlreadyConfigured'}->{en} =
    heading('APACHE ALREADY CONFIGURED') . qq|
-%s appears to already have an entry for Koha
-Virtual Hosts.  You may need to edit %s
-f anything has changed since it was last set up.  This
+%s appears to already have an entry for Koha.  You may need to edit %s
+if anything has changed since it was last set up.  This
 script will not attempt to modify an existing Koha apache
 configuration.
 
 Press <ENTER> to continue: |;
 
 sub updateapacheconf {
-    my $logfiledir=`grep ^ErrorLog "$realhttpdconf"`;
-    chomp $logfiledir;
-
-    if ($logfiledir) {
-       $logfiledir=~m#ErrorLog (.*)/[^/]*$#
-           or die "Can't parse ErrorLog directive\n";
-       $logfiledir=$1;
-    }
-
-    unless ($logfiledir) {
-       $logfiledir='logs';
-    }
-
-    showmessage(getmessage('StartUpdateApache'), 'none');
-
-    my $httpdconf;
+       my ($auto_install)=@_;
+    my $logfiledir=$kohalogdir;
+    my $httpdconf = $etcdir."/koha-httpd.conf";
+   
+    showmessage(getmessage('StartUpdateApache'), 'none') unless $auto_install->{NoPressEnter};
+       # to be polite about it: I don't think this should touch the main httpd.conf
+
+       # QUESTION: Should we warn for includes_module too?
     my $envmodule=0;
     my $includesmodule=0;
     open HC, "<$realhttpdconf";
     while (<HC>) {
        if (/^\s*#\s*LoadModule env_module /) {
-           s/^\s*#\s*//;
-           showmessage(getmessage('LoadingApacheModuleModEnv'));
+           showmessage(getmessage('ApacheConfigMissingModules'));
            $envmodule=1;
        }
-       if (/^\s*#\s*LoadModule includes_module /) {
-           s/^\s*#\s*//;
-           showmessage(getmessage('LoadingApacheModuleModInc'));
-       }
        if (/\s*LoadModule includes_module / ) {
            $includesmodule=1;
        }
-       $httpdconf.=$_;
     }
 
-    my $backupfailed=0;
-    $backupfailed=`cp -f $realhttpdconf $realhttpdconf\.prekoha`;
-    if ($backupfailed) {
-       showmessage(getmessage('ApacheConfigBackupFailed', [$realhttpdconf,$backupfailed ]), 'PressEnter');
-       return;
-    }
-
-    if ($envmodule || $includesmodule) {
-       open HC, ">$realhttpdconf";
-       print HC $httpdconf;
-       close HC;
-    }
-
-
-    
-    if (`grep 'VirtualHost $servername' "$realhttpdconf"`) {
-       showmessage(getmessage('ApacheAlreadyConfigured', [$realhttpdconf, $realhttpdconf]), 'PressEnter');
+       startsysout;
+    if (`grep -q 'VirtualHost $servername' "$httpdconf" 2>/dev/null`) {
+       showmessage(getmessage('ApacheAlreadyConfigured', [$httpdconf, $httpdconf]), 'PressEnter');
        return;
     } else {
        my $includesdirectives='';
@@ -1140,7 +1451,7 @@ sub updateapacheconf {
            $includesdirectives.="Options +Includes\n";
            $includesdirectives.="   AddHandler server-parsed .html\n";
        }
-       open(SITE,">>$realhttpdconf") or warn "Insufficient priveleges to open $realhttpdconf for writing.\n";
+       open(SITE,">$httpdconf") or warn "Insufficient priveleges to open $httpdconf for writing.\n";
        my $opaclisten = '';
        if ($opacport != 80) {
            $opaclisten="Listen $opacport";
@@ -1152,8 +1463,9 @@ sub updateapacheconf {
        print SITE <<EOP
 
 # Ports to listen to for Koha
-$opaclisten
-$intranetlisten
+# uncomment these if they aren't already in main httpd.conf
+#$opaclisten
+#$intranetlisten
 
 # NameVirtualHost is used by one of the optional configurations detailed below
 
@@ -1168,6 +1480,7 @@ $intranetlisten
    ErrorLog $logfiledir/opac-error_log
    TransferLog $logfiledir/opac-access_log
    SetEnv PERL5LIB "$intranetdir/modules"
+   SetEnv KOHA_CONF "$etcdir/koha.conf"
    $includesdirectives
 </VirtualHost>
 
@@ -1180,6 +1493,7 @@ $intranetlisten
    ErrorLog $logfiledir/koha-error_log
    TransferLog $logfiledir/koha-access_log
    SetEnv PERL5LIB "$intranetdir/modules"
+   SetEnv KOHA_CONF "$etcdir/koha.conf"
    $includesdirectives
 </VirtualHost>
 
@@ -1200,61 +1514,97 @@ EOP
     }
 }
 
-$messages->{'IntranetAuthenticationQuestion'}->{en} =
-   heading('INTRANET AUTHENTICATION') . qq|
-I can set it up so that the Intranet/Librarian site is password protected using
-Apache's Basic Authorization.
-
-This is going to be phased out very soon. However, setting this up can provide
-an extra layer of security before the new authentication system is completely
-in place.
-
-Would you like to do this ([Y]/N): |;
-
-$messages->{'BasicAuthUsername'}->{en}="Please enter a userid for intranet access [%s]: ";
-$messages->{'BasicAuthPassword'}->{en}="Please enter a password for %s: ";
-$messages->{'BasicAuthPasswordWasBlank'}->{en}="\nYou cannot use a blank password!\n\n";
-
-sub basicauthentication {
-    my $message=getmessage('IntranetAuthenticationQuestion');
-    my $answer=showmessage($message, 'yn', 'y');
-
-    my $apacheauthusername='librarian';
-    my $apacheauthpassword='';
-    if ($answer=~/^y/i) {
-       ($apacheauthusername) = showmessage(getmessage('BasicAuthUsername', [ $apacheauthusername]), 'free', $apacheauthusername, 1);
-       $apacheauthusername=~s/[^a-zA-Z0-9]//g;
-       while (! $apacheauthpassword) {
-           ($apacheauthpassword) = showmessage(getmessage('BasicAuthPassword', [ $apacheauthusername]), 'free', 1);
-           if (!$apacheauthpassword) {
-               ($apacheauthpassword) = showmessage(getmessage('BasicAuthPasswordWasBlank'), 'none', '', 1);
-           }
-       }
-       open AUTH, ">$etcdir/kohaintranet.pass";
-       my $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
-       my $salt=substr($chars, int(rand(length($chars))),1);
-       $salt.=substr($chars, int(rand(length($chars))),1);
-       print AUTH $apacheauthusername.":".crypt($apacheauthpassword, $salt)."\n";
-       close AUTH;
-       open(SITE,">>$realhttpdconf") or warn "Insufficient priveleges to open $realhttpdconf for writing.\n";
-       print SITE <<EOP
 
-<Directory $intranetdir>
-    AuthUserFile $etcdir/kohaintranet.pass
-    AuthType Basic
-    AuthName "Koha Intranet (for librarians only)"
-    Require  valid-user
-</Directory>
-EOP
-    }
-    close(SITE);
-}
+=item basicauthentication
+
+    basicauthentication;
+
+Asks the user whether HTTP basic authentication is wanted, and,
+if so, the user name and password for the basic authentication.
+
+These pieces of information are saved to global variables; the
+function does not return any values.
+
+=cut
+
+# $messages->{'IntranetAuthenticationQuestion'}->{en} =
+#    heading('LIBRARIAN AUTHENTICATION') . qq|
+# The Librarian site can be password protected using
+# Apache's Basic Authorization instead of Koha user details.
+# 
+# This method going to be phased out very soon.  Most users should answer N here.
+# 
+# Would you like to do this (Y/[N]): |;        #'
+# 
+# $messages->{'BasicAuthUsername'}->{en}="Please enter a username for librarian access [%s]: ";
+# $messages->{'BasicAuthPassword'}->{en}="Please enter a password for %s: ";
+# $messages->{'BasicAuthPasswordWasBlank'}->{en}="\nYou cannot use a blank password!\n\n";
+# 
+# sub basicauthentication {
+#     my $message=getmessage('IntranetAuthenticationQuestion');
+#     my $answer=showmessage($message, 'yn', 'n');
+#     my $httpdconf = $etcdir."/koha-httpd.conf";
+# 
+#     my $apacheauthusername='librarian';
+#     my $apacheauthpassword='';
+#     if ($answer=~/^y/i) {
+#      ($apacheauthusername) = showmessage(getmessage('BasicAuthUsername', [ $apacheauthusername]), 'free', $apacheauthusername, 1);
+#      $apacheauthusername=~s/[^a-zA-Z0-9]//g;
+#      while (! $apacheauthpassword) {
+#          ($apacheauthpassword) = showmessage(getmessage('BasicAuthPassword', [ $apacheauthusername]), 'free', 1);
+#          if (!$apacheauthpassword) {
+#              ($apacheauthpassword) = showmessage(getmessage('BasicAuthPasswordWasBlank'), 'none', '', 1);
+#          }
+#      }
+#      open AUTH, ">$etcdir/kohaintranet.pass";
+#      my $chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+#      my $salt=substr($chars, int(rand(length($chars))),1);
+#      $salt.=substr($chars, int(rand(length($chars))),1);
+#      print AUTH $apacheauthusername.":".crypt($apacheauthpassword, $salt)."\n";
+#      close AUTH;
+#      open(SITE,">>$httpdconf") or warn "Insufficient priveleges to open $realhttpdconf for writing.\n";
+#      print SITE <<EOP
+# 
+# <Directory $intranetdir>
+#     AuthUserFile $etcdir/kohaintranet.pass
+#     AuthType Basic
+#     AuthName "Koha Intranet (for librarians only)"
+#     Require  valid-user
+# </Directory>
+# EOP
+#     }
+#     close(SITE);
+# }
+
+
+=item installfiles
+
+    installfiles
+
+Install the Koha files to the specified OPAC and INTRANET
+directories (usually in /usr/local/koha).
+
+The koha.conf file is created, but as koha.conf.tmp. The
+caller is responsible for calling finalizeconfigfile when
+installation is completed, to rename it back to koha.conf.
+
+=cut
 
 $messages->{'InstallFiles'}->{en} = heading('INSTALLING FILES') . qq|
 Copying files to installation directories:
 
 |;
 
+$messages->{'OldFiles'}->{en} = heading('OLD FILES') . qq|
+Any files from the previous edition of Koha have been
+copied to a dated backup directory alongside the new
+installation. You should move any custom files that you
+want to keep (such as your site templates) into the new
+directories and then move the backup off of the live
+server.
+
+Press ENTER to continue:|;
+
 
 $messages->{'CopyingFiles'}->{en}="Copying %s to %s.\n";
 
@@ -1262,65 +1612,101 @@ $messages->{'CopyingFiles'}->{en}="Copying %s to %s.\n";
 
 sub installfiles {
 
+       my ($is_first_install,$auto_install) = @_;
+       # $is_install is set if it's a fresh install and not an upgrade. If it's an upgrade, copy old files.
+       
+       sub neatcopy {
+               my $desc = shift;
+               my $src = shift;
+               my $tgt = shift;
+               my $auto_install = shift;
+               my $is_first_install = shift;
+               if (!$is_first_install && -e $tgt) {
+               print getmessage('CopyingFiles', ["old ".$desc,$tgt.strftime("%Y%m%d%H%M",localtime())]) unless ($auto_install->{NoPressEnter});
+                       system("mv ".$tgt." ".$tgt.strftime("%Y%m%d%H%M",localtime()));
+                       system("mkdir ".$tgt);   ##New line 
+               }
+               print getmessage('CopyingFiles', [$desc,$tgt]) unless ($auto_install->{NoPressEnter});
+               system("cp -R ".$src."/* ".$tgt);
+       }
+
+#      my ($auto_install) = @_;
+       showmessage(getmessage('InstallFiles'),'none') unless ($auto_install->{NoPressEnter});
+
+       neatcopy("admin templates", 'intranet-html', "$intranetdir/htdocs",$auto_install,$is_first_install);
+       neatcopy("admin interface", 'intranet-cgi', "$intranetdir/cgi-bin",$auto_install,$is_first_install);
+       neatcopy("main scripts", 'scripts', "$intranetdir/scripts",$auto_install,$is_first_install);
+       neatcopy("perl modules", 'modules', "$intranetdir/modules",$auto_install,$is_first_install);
+       neatcopy("OPAC templates", 'opac-html', "$opacdir/htdocs",$auto_install,$is_first_install);
+       neatcopy("OPAC interface", 'opac-cgi', "$opacdir/cgi-bin",$auto_install,$is_first_install);
+       startsysout();
+       system("touch $opacdir/cgi-bin/opac");
+
+       #MJR: is this necessary?
+       if ($> == 0) {
+               my $httpdgrp = getgrnam($httpduser);
+               system("chown -R $httpduser:$httpdgrp $opacdir $intranetdir");
+       }
+       system("chmod -R a+rx $opacdir $intranetdir");
+
+       # Create /etc/koha.conf
 
-    showmessage(getmessage('InstallFiles'),'none');
-    print getmessage('CopyingFiles', ['intranet-html', "$intranetdir/htdocs" ]);
-    system("cp -R intranet-html/* $intranetdir/htdocs/");
-    print getmessage('CopyingFiles', ['intranet-cgi', "$intranetdir/cgi-bin" ]);
-    system("cp -R intranet-cgi/* $intranetdir/cgi-bin/");
-    print getmessage('CopyingFiles', ['stand-alone scripts', "$intranetdir/scripts" ]);
-    system("cp -R scripts/* $intranetdir/scripts/");
-    print getmessage('CopyingFiles', ['perl modules', "$intranetdir/modules" ]);
-    system("cp -R modules/* $intranetdir/modules/");
-    print getmessage('CopyingFiles', ['opac-html', "$opacdir/htdocs" ]);
-    system("cp -R opac-html/* $opacdir/htdocs/");
-    print getmessage('CopyingFiles', ['opac-cgi', "$opacdir/cgi-bin" ]);
-    system("cp -R opac-cgi/* $opacdir/cgi-bin/");
-    system("touch $opacdir/cgi-bin/opac");
-
-    system("chown -R root:$httpduser $opacdir");
-    system("chown -R root:$httpduser $intranetdir");
-
-    # Create /etc/koha.conf
-
-    my $old_umask = umask(027); # make sure koha.conf is never world-readable
-    open(SITES,">$etcdir/koha.conf.tmp") or warn "Couldn't create file at $etcdir. Must have write capability.\n";
-    print SITES qq|
-database=$dbname
+       my $old_umask = umask(027); # make sure koha.conf is never world-readable
+       open(SITES,">$etcdir/koha.conf.tmp") or warn "Couldn't create file at $etcdir. Must have write capability.\n";
+       print SITES qq|
+database=$database
 hostname=$hostname
 user=$user
 pass=$pass
-includes=$opacdir/htdocs/includes
 intranetdir=$intranetdir
 opacdir=$opacdir
 kohalogdir=$kohalogdir
-kohaversion=$kohaversion
+kohaversion=$newversion
 httpduser=$httpduser
 intrahtdocs=$intranetdir/htdocs/intranet-tmpl
 opachtdocs=$opacdir/htdocs/opac-tmpl
 |;
-    close(SITES);
-    umask($old_umask);
+       close(SITES);
+       umask($old_umask);
+
+       startsysout();
+       #MJR: can't help but this be broken, can we?
+       chmod 0440, "$etcdir/koha.conf.tmp";
+       
+       #MJR: does this contain any passwords?
+       chmod 0755, "$intranetdir/scripts/z3950daemon/z3950-daemon-launch.sh", "$intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh", "$intranetdir/scripts/z3950daemon/processz3950queue";
+
+       open(FILE,">$intranetdir/scripts/z3950daemon/z3950-daemon-options");
+       print FILE "RunAsUser=$httpduser\nKohaZ3950Dir=$intranetdir/scripts/z3950daemon\nKohaModuleDir=$intranetdir/modules\nLogDir=$kohalogdir\nKohaConf=$etcdir/koha.conf";
+       close(FILE);
+
+       if ($> == 0) {
+           chown((getpwnam($httpduser)) [2,3], "$etcdir/koha.conf.tmp") or warn "can't chown koha.conf: $!";
+               chown(0, (getpwnam($httpduser)) [3], "$intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh") or warn "can't chown $intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh: $!";
+               chown(0, (getpwnam($httpduser)) [3], "$intranetdir/scripts/z3950daemon/processz3950queue") or warn "can't chown $intranetdir/scripts/z3950daemon/processz3950queue: $!";
+       } #MJR: report that we haven't chown()d.
+       else {
+               print "Please check permissions in $intranetdir/scripts/z3950daemon\n";
+       }
+       showmessage(getmessage('OldFiles'),'PressEnter') unless ($auto_install->{NoPressEnter} or $is_first_install);
+}
 
-    chown((getpwnam($httpduser)) [2,3], "$etcdir/koha.conf.tmp") or warn "can't chown koha.conf: $!";
-    chmod 0440, "$etcdir/koha.conf.tmp";
 
-    chmod 0750, "$intranetdir/scripts/z3950daemon/z3950-daemon-launch.sh";
-    chmod 0750, "$intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh";
-    chmod 0750, "$intranetdir/scripts/z3950daemon/processz3950queue";
-    chown(0, (getpwnam($httpduser)) [3], "$intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh") or warn "can't chown $intranetdir/scripts/z3950daemon/z3950-daemon-shell.sh: $!";
-    chown(0, (getpwnam($httpduser)) [3], "$intranetdir/scripts/z3950daemon/processz3950queue") or warn "can't chown $intranetdir/scripts/z3950daemon/processz3950queue: $!";
+=item databasesetup
 
-}
+    databasesetup;
+
+Finds out where the MySQL utitlities are located in the system,
+then create the Koha database structure and MySQL permissions.
+
+=cut
 
 $messages->{'MysqlRootPassword'}->{en} =
    heading('MYSQL ROOT USER PASSWORD') . qq|
-To allow us to create the koha database please supply your
+To create the koha database, please enter your
 mysql server's root user password:
 
-Enter MySQL root user password: |;
-
-$messages->{'InvalidMysqlRootPassword'}->{en}="Invalid Password.  Please try again.";
+Password: |;   #'
 
 $messages->{'CreatingDatabase'}->{en} = heading('CREATING DATABASE') . qq|
 Creating the MySQL database for Koha...
@@ -1330,18 +1716,18 @@ Creating the MySQL database for Koha...
 $messages->{'CreatingDatabaseError'}->{en} =
    heading('ERROR CREATING DATABASE') . qq|
 Couldn't connect to the MySQL server for the reason given above.
-This is a serious problem, the database will not get installed.\a
+This is a serious problem, the database will not get installed.
 
-Press <ENTER> to continue: |;
+Press <ENTER> to continue: |;  #'
 
 $messages->{'SampleData'}->{en} = heading('SAMPLE DATA') . qq|
-If you are installing Koha for evaluation purposes,  I have a batch of sample
-data that you can install now.
+If you are installing Koha for evaluation purposes,
+you can install some sample data now.
 
-If you are installing Koha with the intention of populating it with your own
+If you are installing Koha to use your own
 data, you probably don't want this sample data installed.
 
-Would you like to install the sample data? Y/[N]: |;
+Would you like to install the sample data? Y/[N]: |;   #'
 
 $messages->{'SampleDataInstalled'}->{en} =
    heading('SAMPLE DATA INSTALLED') . qq|
@@ -1349,7 +1735,7 @@ Sample data has been installed.  For some suggestions on testing Koha, please
 read the file doc/HOWTO-Testing.  If you find any bugs, please submit them at
 http://bugs.koha.org/.  If you need help with testing Koha, you can post a
 question through the koha-devel mailing list, or you can check for a developer
-online at +irc.katipo.co.nz:6667 channel #koha.
+online at irc.katipo.co.nz:6667 channel #koha.
 
 You can find instructions for subscribing to the Koha mailing lists at:
 
@@ -1359,214 +1745,417 @@ You can find instructions for subscribing to the Koha mailing lists at:
 Press <ENTER> to continue: |;
 
 $messages->{'AddBranchPrinter'}->{en} = heading('Add Branch and Printer') . qq|
-Would you like to install an initial branch and printer? [Y]/N: |;
+Would you like to describe an initial branch and printer? [Y]/N: |;
 
 $messages->{'BranchName'}->{en}="Branch Name [%s]: ";
 $messages->{'BranchCode'}->{en}="Branch Code (4 letters or numbers) [%s]: ";
 $messages->{'PrinterQueue'}->{en}="Printer Queue [%s]: ";
 $messages->{'PrinterName'}->{en}="Printer Name [%s]: ";
-$messages->{'BlankMysqlPassword'}->{en} = heading('Blank MySQL Password') . qq|
-Do not leave your MySQL root password blank unless you know exactly what you
-are doing.  To change your MySQL root password use the mysqladmin command:
-
-mysqladmin password NEWPASSWORDHERE
-
-Press <ENTER> to continue:
-|;
 
 sub databasesetup {
+       my ($auto_install) = @_;
     $mysqluser = 'root';
     $mysqlpass = '';
+       my $mysqldir = getmysqldir();
 
-    foreach my $mysql (qw(/usr/local/mysql
-                         /opt/mysql
-                         /usr
-                         )) {
-       if ( -d $mysql  && -f "$mysql/bin/mysqladmin") {
-           $mysqldir=$mysql;
-       }
-    }
-    if (!$mysqldir){
-       print "I don't see mysql in the usual places.\n";
-       for (;;) {
-           print "Where have you installed mysql? ";
-           chomp($mysqldir = <STDIN>);
-           last if -f "$mysqldir/bin/mysqladmin";
-       print <<EOP;
-
-I can't find it there either. If you compiled mysql yourself,
-please give the value of --prefix when you ran configure.
-
-The file mysqladmin should be in bin/mysqladmin under the directory that you
-provide here.
-
-EOP
+       if ($auto_install->{MysqlRootPassword}) {
+               $mysqlpass=$auto_install->{MysqlRootPassword};
+       } else {
+       # we must not put the mysql root password on the command line
+               $mysqlpass=     showmessage(getmessage('MysqlRootPassword'),'silentfree');
        }
-    }
-
-
-    my $needpassword=1;
-    while ($needpassword) {
-       $mysqlpass=showmessage(getmessage('MysqlRootPassword'), 'free');
-       $mysqlpass_quoted = $mysqlpass;
-       $mysqlpass_quoted =~ s/"/\\"/g;
-       $mysqlpass_quoted="-p\"$mysqlpass_quoted\"";
-       $mysqlpass eq '' and $mysqlpass_quoted='';
-       my $result=system("$mysqldir/bin/mysqladmin -u$mysqluser $mysqlpass_quoted proc > /dev/null 2>&1");
+       
+       showmessage(getmessage('CreatingDatabase'),'none') unless ($auto_install->{NoPressEnter});
+       # set the login up
+       setmysqlclipass($mysqlpass);
+       # Set up permissions
+       startsysout();
+       print system("$mysqldir/bin/mysql -u$mysqluser mysql -e \"insert into user (Host,User,Password) values ('$hostname','$user',password('$pass'))\"\;");#"
+       system("$mysqldir/bin/mysql -u$mysqluser mysql -e \"insert into db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv, index_priv, alter_priv) values ('%','$database','$user','Y','Y','Y','Y','Y','Y','Y','Y')\"");
+       system("$mysqldir/bin/mysqladmin -u$mysqluser reload");
+       # Change to admin user login
+       setmysqlclipass($pass);
+       my $result=system("$mysqldir/bin/mysqladmin", "-u$user", "create", "$database");
        if ($result) {
-           print getmessage('InvalidMysqlRootPassword');
+               showmessage(getmessage('CreatingDatabaseError'),'PressEnter', '', 1);
        } else {
-           if ($mysqlpass eq '') {
-               showmessage(getmessage('BlankMysqlPassword'), 'PressEnter');
-           }
-           $needpassword=0;
+               # Create the database structure
+               startsysout();
+               system("$mysqldir/bin/mysql -u$user $database < koha.mysql");
        }
-    }
 
-    showmessage(getmessage('CreatingDatabase'),'none');
+}
 
-    my $result=system("$mysqldir/bin/mysqladmin", "-u$mysqluser", "-p$mysqlpass", "create", "$dbname");
-    if ($result) {
-       showmessage(getmessage('CreatingDatabaseError'),'PressEnter', '', 1);
-    } else {
-       # Populate the Koha database
-       system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname < koha.mysql");
-       # Set up permissions
-       system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted mysql -e \"insert into user (Host,User,Password) values ('$hostname','$user',password('$pass'))\"\;");
-       system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted mysql -e \"insert into db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv, index_priv, alter_priv) values ('%','$dbname','$user','Y','Y','Y','Y','Y','Y','Y','Y')\"");
-       system("$mysqldir/bin/mysqladmin -u$mysqluser $mysqlpass_quoted reload");
 
+=item updatedatabase
 
+    updatedatabase;
 
+Updates the Koha database structure, including the addition of
+MARC tables.
 
+The MARC tables are also populated in addition to being created.
 
-    }
+Because updatedatabase calls scripts/updater/updatedatabase to
+do the actual update, and that script uses C4::Context,
+$etcdir/koha.conf must exist at this point. We use the KOHA_CONF
+environment variable to do this.
 
-}
+FIXME: (See checkabortedinstall as it depends on old symlink way.)
+
+=cut
 
 $messages->{'UpdateMarcTables'}->{en} =
-   heading('UPDATING MARC FIELD DEFINITION TABLES') . qq|
-You can import marc parameters for :
+   heading('MARC FIELD DEFINITIONS') . qq|
+You can import MARC settings for:
 
   1 MARC21
   2 UNIMARC
-  3 none
+  N none
+
+NOTE: If you choose N,
+nothing will be added, and you must create them all yourself.
+Only choose N if you want to use a MARC format not listed here,
+such as DANMARC.  We would like to hear from you if you do.
 
-Please choose which parameter you want to install. Note if you choose 3,
-nothing will be added, and it can be a BIG job to manually create those tables
+UPGRADE : If you UPGRADE your version from a previous 2.x.x, the right choice here is N (None) to preserve your local MARC setup.
 
 Choose MARC definition [1]: |;
 
-$messages->{'Language'}->{en} = heading('CHOOSE LANGUAGES') . qq|
+$messages->{'Language'}->{en} = heading('CHOOSE LANGUAGE') . qq|
 This version of koha supports a few languages.
-Enter you languages preferences : either en, fr, es or pl.
-Note that the en is always choosen when the system does not finds the
-language you choose in a specific screen.
-fr : opac is translated (except pictures)
-es : a few intranet is translated (including pictures)
-pl : opac is translated (UNTESTED in this release)
-|;
+
+  en : default language, all pages available
+  fr : complete translation (except pictures)
+  es : partial librarian site translation (including pictures)
+  pl : complete OPAC and partial librarian translation
+  zh_TW : partial translation
+
+en is used when a screen is not available in your language
+
+If you specify a language here, you can still
+change it from the system preferences screen in the librarian sit.
+
+Which language do you choose? |;
 
 sub updatedatabase {
+       my ($auto_install) = @_;
     # At this point, $etcdir/koha.conf must exist, for C4::Context
-    # We must somehow temporarily enable $etcdir/koha.conf. A symlink can
-    # do this & at the same time facilitate detection of aborted installs.
-       my $result=system ("perl -I $intranetdir/modules scripts/updater/updatedatabase");
+    $ENV{"KOHA_CONF"}=$etcdir.'/koha.conf';
+    if (! -e $ENV{"KOHA_CONF"}) { $ENV{"KOHA_CONF"}=$etcdir.'/koha.conf.tmp'; }
+       startsysout();  
+       my $result=system ("perl -I $intranetdir/modules scripts/updater/updatedatabase -s");
        if ($result) {
+               restoremycnf();
                print "Problem updating database...\n";
                exit;
        }
-
-       my $response=showmessage(getmessage('UpdateMarcTables'), 'restrictchar 123', '1');
-
-       if ($response == 1) {
-               system("cat scripts/misc/marc_datas/marc21_en/structure_def.sql | $mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname");
+       my $response;
+       if ($auto_install->{UpdateMarcTables}) {
+               $response=$auto_install->{UpdateMarcTables};
+               print ON_YELLOW.BLACK."auto-setting UpdateMarcTable to : $response".RESET."\n";
+       } else {
+               $response=showmessage(getmessage('UpdateMarcTables'), 'restrictchar 12Nn', '1');
        }
-       if ($response == 2) {
-               system("cat scripts/misc/marc_datas/unimarc_fr/structure_def.sql | $mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname");
-               system("cat scripts/misc/lang-datas/fr/stopwords.sql | $mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname");
+       startsysout();
+       if ($response eq '1') {
+               system("cat scripts/misc/marc_datas/marc21_en/structure_def.sql | $mysqldir/bin/mysql -u$user $database");
        }
-
-       $result = system ("perl -I $intranetdir/modules scripts/marc/updatedb2marc.pl");
-       if ($result) {
-               print "Problem updating database to MARC...\n";
-               exit;
+       if ($response eq '2') {
+               system("cat scripts/misc/marc_datas/unimarc_fr/structure_def.sql | $mysqldir/bin/mysql -u$user $database");
        }
+       delete($ENV{"KOHA_CONF"});
 
-       print "\n\nFinished updating of database. Press <ENTER> to continue...";
-       <STDIN>;
+       print RESET."\nFinished updating of database. Press <ENTER> to continue..." unless ($auto_install->{NoPressEnter});
+       <STDIN> unless ($auto_install->{NoPressEnter});
 }
 
+
+=item populatedatabase
+
+    populatedatabase;
+
+Populate the non-MARC tables. If the user wants to install the
+sample data, install them.
+
+=cut
+
+$messages->{'ConfirmFileUpload'}->{en} = qq|
+Confirm loading of this file into Koha  [Y]/N: |;
+
 sub populatedatabase {
-       my $response=showmessage(getmessage('SampleData'), 'yn', 'n');
-       if ($response =~/^y/i) {
-               system("gunzip -d < sampledata-1.2.gz | $mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname");
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into branches (branchcode,branchname,issuing) values ('MAIN', 'Main Library', 1)\"");
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'IS')\"");
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'CU')\"");
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into printers (printername,printqueue,printtype) values ('Circulation Desk Printer', 'lp', 'hp')\"");
-               showmessage(getmessage('SampleDataInstalled'), 'PressEnter','',1);
+       my ($auto_install) = @_;
+       my $input;
+       my $response;
+       my $branch='MAIN';
+       if ($auto_install->{BranchName}) {
+               $branch=$auto_install->{BranchName};
+               print ON_YELLOW.BLACK."auto-setting a branch : $branch".RESET."\n";
        } else {
-               my $input;
-               my $response=showmessage(getmessage('AddBranchPrinter'), 'yn', 'y');
-
+               $response=showmessage(getmessage('AddBranchPrinter'), 'yn', 'y');
                unless ($response =~/^n/i) {
-               my $branch='Main Library';
-               $branch=showmessage(getmessage('BranchName', [$branch]), 'free', $branch, 1);
-               $branch=~s/[^A-Za-z0-9\s]//g;
-
+                       $branch=showmessage(getmessage('BranchName', [$branch]), 'free', $branch, 1);
+                       $branch=~s/[^A-Za-z0-9\s]//g;
+               }
+       }
+       if ($branch) {
                my $branchcode=$branch;
                $branchcode=~s/[^A-Za-z0-9]//g;
                $branchcode=uc($branchcode);
                $branchcode=substr($branchcode,0,4);
-               $branchcode=showmessage(getmessage('BranchCode', [$branchcode]), 'free', $branchcode, 1);
+               if ($auto_install->{BranchCode}) {
+                       $branchcode=$auto_install->{BranchCode};
+                       print ON_YELLOW.BLACK."auto-setting branch code : $branchcode".RESET."\n";
+               } else {
+                       $branchcode=showmessage(getmessage('BranchCode', [$branchcode]), 'free', $branchcode, 1);
+               }
                $branchcode=~s/[^A-Za-z0-9]//g;
                $branchcode=uc($branchcode);
                $branchcode=substr($branchcode,0,4);
                $branchcode or $branchcode='DEF';
 
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into branches (branchcode,branchname,issuing) values ('$branchcode', '$branch', 1)\"");
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'IS')\"");
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'CU')\"");
-
-               my $printername='Library Printer';
-               $printername=showmessage(getmessage('PrinterName', [$printername]), 'free', $printername, 1);
-               $printername=~s/[^A-Za-z0-9\s]//g;
-
-               my $printerqueue='lp';
-               $printerqueue=showmessage(getmessage('PrinterQueue', [$printerqueue]), 'free', $printerqueue, 1);
-               $printerqueue=~s/[^A-Za-z0-9]//g;
-               system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"insert into printers (printername,printqueue,printtype) values ('$printername', '$printerqueue', '')\"");
+               startsysout();
+               system("$mysqldir/bin/mysql -u$user $database -e \"insert into branches (branchcode,branchname,issuing) values ('$branchcode', '$branch', 1)\"");
+               system("$mysqldir/bin/mysql -u$user $database -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'IS')\"");
+               system("$mysqldir/bin/mysql -u$user $database -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'CU')\"");
+
+               my $printername='lp';
+               my $printerqueue='/dev/lp0';
+               if ($auto_install->{PrinterName}) {
+                       $printername=$auto_install->{PrinterName};
+                       print ON_YELLOW.BLACK."auto-setting a printer : $printername".RESET."\n";
+               } else {
+                       $printername=showmessage(getmessage('PrinterName', [$printername]), 'free', $printername, 1);
+                       $printername=~s/[^A-Za-z0-9\s]//g;
+               }
+               if ($auto_install->{PrinterQueue}) {
+                       $printerqueue=$auto_install->{PrinterQueue};
+                       print ON_YELLOW.BLACK."auto-setting printer queue to : $printerqueue".RESET."\n";
+               } else {
+                       $printerqueue=showmessage(getmessage('PrinterQueue', [$printerqueue]), 'free', $printerqueue, 1);
+                       $printerqueue=~s/[^A-Za-z0-9]//g;
+               }
+               startsysout();  
+               system("$mysqldir/bin/mysql -u$user $database -e \"insert into printers (printername,printqueue,printtype) values ('$printername', '$printerqueue', '')\"");
+       }
+       my $language;
+       if ($auto_install->{Language}) {
+               $language=$auto_install->{Language};
+               print ON_YELLOW.BLACK."auto-setting language to : $language".RESET."\n";
+       } else {
+               $language=showmessage(getmessage('Language'), 'free', 'en');
+       }
+       startsysout();  
+       system("$mysqldir/bin/mysql -u$user $database -e \"update systempreferences set value='$language' where variable='opaclanguages'\"");
+       my @dirs;
+       if (-d "scripts/misc/sql-datas") {
+               # ask for directory to look for files to append
+               my @directories;
+               push @directories,"FINISHED";
+               if (-d "scripts/misc/sql-datas") {
+                       opendir D, "scripts/misc/sql-datas";
+                       foreach my $dir (readdir D) {
+                               next if ($dir =~ /^\./);
+                               push @directories, $dir;
+                       }
+               }
+               my $loopend=0;
+               while (not $loopend) {
+                       print heading("SELECT SQL DIRECTORY");
+                       print qq|
+Select a directory. You will see every file included in this directory and be able to choose file(s) to import into Koha
+This is a VERY important feature. By selecting the proper options, you can get a pre-setup Koha, almost ready to be put in production.
+Choose wisely.
+|;
+                       for (my $i=0;$i<=$#directories;$i++) {
+                               print "$i => ".$directories[$i]."\n";
+                       }
+                       my $sqluploaddir =<STDIN>;
+                       if ($sqluploaddir==0) {
+                               $loopend = 1;
+                       } else {
+                               $sqluploaddir = $directories[$sqluploaddir];
+                               # CHECK for any other file to append...
+                               my @sql;
+                               push @sql,"FINISHED";
+                               if (-d "scripts/misc/sql-datas/$sqluploaddir") {
+                                       opendir D, "scripts/misc/sql-datas/$sqluploaddir";
+                                       foreach my $sql (readdir D) {
+                                               next unless ($sql =~ /.txt$/);
+                                               push @sql, $sql;
+                                       }
+                               }
+                               $loopend=0;
+                               while (not $loopend) {
+                                       print heading("SELECT SQL FILE");
+                                       print qq|
+Select a file to append to the Koha DB.
+enter a number. A detailled explanation of the file will be given
+if you confirm, the file will be added to the DB
+|;
+                                       for (my $i=0;$i<=$#sql;$i++) {
+                                               print "$i => ".$sql[$i]."\n";
+                                       }
+                                       my $response =<STDIN>;
+                                       if ($response==0) {
+                                               $loopend = 1;
+                                       } else {
+                                               # show the content of the file
+                                               my $FileToUpload = $sql[$response];
+                                               open FILE,"scripts/misc/sql-datas/$sqluploaddir/$FileToUpload";
+                                               my $content = <FILE>;
+                                               print heading("INSERT $sqluploaddir/$FileToUpload ?")."$content\n";
+                                               # ask confirmation
+                                               $response=showmessage(getmessage('ConfirmFileUpload'), 'yn', 'y');
+                                               # if confirmed, upload the file in the DB
+                                               unless ($response =~/^n/i) {
+                                                       $FileToUpload =~ s/\.txt/\.sql/;
+                                                       system("$mysqldir/bin/mysql -u$user $database <scripts/misc/sql-datas/$sqluploaddir/$FileToUpload");
+                                               }
+                                       }
+                               }
+                               $loopend=0;
+                       }
                }
-       my $language=showmessage(getmessage('Language'), 'free', 'en');
-       system("$mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname -e \"update systempreferences set value='$language' where variable='opaclanguages'\"");
        }
 }
 
+=item restartapache
+
+    restartapache;
+
+Asks the user whether to restart Apache, and restart it if the user
+wants so.
+
+=cut
+
 $messages->{'RestartApache'}->{en} = heading('RESTART APACHE') . qq|
-Apache needs to be restarted to load the new configuration for Koha.
+The web server daemon needs to be restarted to load the new configuration for Koha.
+The installer can do this if you are using Apache and give the root password.
 
-Would you like to restart Apache now?  [Y]/N: |;
+Would you like to try to restart Apache now?  [Y]/N: |;
 
 sub restartapache {
+       my ($auto_install)=@_;
+       my $response;
+    $response=showmessage(getmessage('RestartApache'), 'yn', 'y') unless ($auto_install->{NoPressEnter});
+    $response='y' if ($auto_install->{NoPressEnter});
+
+    unless ($response=~/^n/i) {
+               startsysout();
+               # Need to support other init structures here?
+               if (-e "/etc/rc.d/init.d/httpd") {
+                       system('su root -c "/etc/rc.d/init.d/httpd restart"');
+               } elsif (-e "/etc/init.d/apache") {
+                       system('su root -c "/etc/init.d/apache restart"');
+               } elsif (-e "/etc/init.d/apache-ssl") {
+                       system('su root -c "/etc/init.d/apache-ssl restart"');
+               }
+       }
+}
 
-    my $response=showmessage(getmessage('RestartApache'), 'yn', 'y');
+=item backupkoha
 
+   backupkoha;
 
+This function attempts to back up all koha's details.
 
-    unless ($response=~/^n/i) {
-       # Need to support other init structures here?
-       if (-e "/etc/rc.d/init.d/httpd") {
-           system('/etc/rc.d/init.d/httpd restart');
-       } elsif (-e "/etc/init.d/apache") {
-           system('/etc//init.d/apache restart');
-       } elsif (-e "/etc/init.d/apache-ssl") {
-           system('/etc/init.d/apache-ssl restart');
+=cut
+
+$messages->{'BackupDir'}->{en} = heading('BACKUP STORAGE').qq|
+The upgrader will now try to backup your old files.
+
+Please specify a directory to store the backup in [%s]: |;
+
+$messages->{'BackupSummary'}->{en} = heading('BACKUP SUMMARY').qq|
+Backed up:
+
+%6d biblio entries
+%6d biblioitems entries
+%6d items entries
+%6d borrowers
+
+File Listing
+---------------------------------------------------------------------
+%s
+---------------------------------------------------------------------
+
+Does this look right? ([Y]/N): |;
+
+#FIXME: rewrite to use Install.pm
+sub backupkoha {
+if (!$ENV{prefix}) { $ENV{prefix} = "/usr/local"; }
+my $backupdir=$ENV{prefix}.'/backups';
+
+my $answer = showmessage(getmessage('BackupDir',[$backupdir]),'free',$backupdir);
+$backupdir = $answer; 
+
+if (! -e $backupdir) {
+       my $result=mkdir ($backupdir, oct(770));
+       if ($result==0) {
+               my @dirs = split(m#/#, $backupdir);
+               my $checkdir='';
+               foreach (@dirs) {
+                       $checkdir.="$_/";
+                       unless (-e "$checkdir") {
+                               mkdir($checkdir, 0775);
+                       }
+               }
        }
-    }
+}
+
+chmod 0770, $backupdir;
+
+# Backup MySql database
+#
+#
+my $mysqldir = getmysqldir();
+
+my ($sec, $min, $hr, $day, $month, $year) = (localtime(time))[0,1,2,3,4,5];
+$month++;
+$year+=1900;
+my $date= sprintf "%4d-%02d-%02d_%02d:%02d:%02d", $year, $month, $day,$hr,$min,$sec;
 
+open (MD, "$mysqldir/bin/mysqldump --user=$user --password=$pass --host=$hostname $database|");
+
+(open BF, ">$backupdir/Koha.backup_$date") || (die "Error opening up backup file $backupdir/Koha.backup_$date: $!\n");
+
+my $itemcounter=0;
+my $bibliocounter=0;
+my $biblioitemcounter=0;
+my $membercounter=0;
+
+while (<MD>) {
+       (/insert into items /i) && ($itemcounter++);
+       (/insert into biblioitems /i) && ($biblioitemcounter++);
+       (/insert into biblio /i) && ($bibliocounter++);
+       (/insert into borrowers /i) && ($membercounter++);
+       print BF $_;
 }
 
+close BF;
+close MD;
+
+my $filels=`ls -hl $backupdir/Koha.backup_$date`;
+chomp $filels;
+$answer = showmessage(getmessage('BackupSummary',[$bibliocounter, $biblioitemcounter, $itemcounter, $membercounter, $filels]),'yn');
+
+if ($answer=~/^n/i) {
+    print qq|
+
+Aborting.  The database dump is located in:
+
+       $backupdir/Koha.backup_$date
+
+|;
+    exit;
+} else {
+       print "Great! continuing upgrade... \n";
+};
+
+
+
+}
 
 =item finalizeconfigfile
 
@@ -1580,6 +2169,7 @@ Currently, failure to rename the file results only in a warning.
 =cut
 
 sub finalizeconfigfile {
+       restoremycnf();
    rename "$etcdir/koha.conf.tmp", "$etcdir/koha.conf"
       || showmessage(<<EOF, 'PressEnter', undef, 1);
 An unexpected error, $!, occurred
@@ -1590,6 +2180,7 @@ Couldn't rename file at $etcdir. Must have write capability.
 
 Press Enter to continue.
 EOF
+#'
 }
 
 
@@ -1608,6 +2199,8 @@ the file is silently ignored.
 sub loadconfigfile {
     my %configfile;
 
+       #MJR: reverted to r1.53.  Please call setetcdir().  Do NOT hardcode this.
+       #FIXME: make a dated backup
     open (KC, "<$etcdir/koha.conf");
     while (<KC>) {
      chomp;
@@ -1624,6 +2217,7 @@ sub loadconfigfile {
      }
     }
 
+       #MJR: Reverted this too. You do not mess with my privates. Please ask for new functions if required.
     $intranetdir=$configfile{'intranetdir'};
     $opacdir=$configfile{'opacdir'};
     $kohaversion=$configfile{'kohaversion'};
@@ -1636,12 +2230,52 @@ sub loadconfigfile {
 
 END { }       # module clean-up code here (global destructor)
 
+### These things may move
+
+sub setecho {
+my $state=shift;
+my $t = POSIX::Termios->new;
+
+$t->getattr();
+if ($state) {
+  $t->setlflag(($t->getlflag) | &POSIX::ECHO);
+  }
+else {
+  $t->setlflag(($t->getlflag) & !(&POSIX::ECHO));
+  }
+$t->setattr();
+}
+
+sub setmysqlclipass {
+       my $pass = shift;
+       open(MYCNF,">$mycnf");
+       chmod(0600,$mycnf);
+       print MYCNF "[client]\npassword=$pass\n";
+       close(MYCNF);
+}
+
+sub backupmycnf {
+       if (-e $mycnf) {
+               rename $mycnf,$mytmpcnf;
+       }
+}
+
+sub restoremycnf {
+       if (defined $mycnf && -e $mycnf) {
+               unlink($mycnf);
+       }
+       if (defined $mytmpcnf && -e $mytmpcnf) {
+               rename $mytmpcnf,$mycnf;
+       }
+}
+
 =back
 
 =head1 SEE ALSO
 
-buildrelease.pl,
+buildrelease.pl
 installer.pl
+koha.upgrade
 
 =cut