Adding test for Event module
[koha.git] / misc / Install.pm
index 1886c87..8bf7b76 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);
@@ -63,6 +72,8 @@ $VERSION = 0.01;
                &restartapache
                &finalizeconfigfile
                &loadconfigfile
+               &backupmycnf
+               &restoremycnf
                );
 
 use vars qw( $kohaversion );                   # set in installer.pl
@@ -76,7 +87,6 @@ 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
@@ -88,34 +98,46 @@ 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\n"; #MJR: was $terminal->Tputs('cl');
+
 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`;
+
 my $messages;
 $messages->{'continuing'}->{en}="Great!  Continuing setup.\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.
+basic information about your desired setup, then install Koha for you.
+
+If you want to install the Koha configuration file somewhere other than /etc
+(eg for non-root installation, or multiple Koha versions on one system), you
+should set the etcdir and prefix environment variables.  If this is your
+only koha installation on this machine and you are running this as root, the
+default should be OK.
+
+To accept the default value for any question, simply hit Enter at the prompt.
 
 Please be sure to read the documentation, or visit the Koha website at
 http://www.koha.org for more information.
 
-Are you ready to begin the installation? (Y/[N]): |;
+Are you ready to begin the installation? ([Y]/N): |;
 $messages->{'ReleaseCandidateWarning'}->{en} =
    heading('RELEASE CANDIDATE') . qq|
 WARNING WARNING WARNING WARNING WARNING
@@ -146,8 +168,11 @@ perl -MCPAN -e 'install Net::Z3950'
 
 IMPORTANT NOTE : If you use PERL5.8.0 (RedHat 8.0 or Mandrake 9.x), you MUST install 
 manually the Net::Z3950 and edit Makefile.PL and yazwrap/Makefile.PL to include:
-    'DEFINES' => '-D_GNU_SOURCE',
-
+    '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 the following line in yazwrap/ywpriv.h :
+   #include "XSUB.h"
 
 Press the <ENTER> key to continue: |;  #'
 
@@ -214,6 +239,7 @@ Congratulations ... your Koha installation is complete!
 You will be able to connect to your Librarian interface at:
 
    http://%s\:%s/
+   use mysql login and password to connect to this interface. Then, go to admin page, and create whatever fits your needs.
 
 and the OPAC interface at :
 
@@ -420,7 +446,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;
     }
@@ -439,6 +465,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');
@@ -450,7 +477,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
@@ -492,16 +519,18 @@ screen-clearing is not done.
 #'
 
 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 = 0 unless defined $noclear; # defaults to "clear"
-    ($noclear) || (system('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;
@@ -511,22 +540,24 @@ sub showmessage {
            chomp $response;
            (length($response)) || ($response=$defaultresponse);
             if ( $response=~/.*[\:\(\)\^\$\*\!\\].*/ ) {
-                ($noclear) || (system('clear'));
-                print "Response contains invalid characters.  Choose from [$options].\n\n";
-                print $message;
+                ($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) || (system('clear'));
-                    print "Invalid Response.  Choose from [$options].\n\n";
-                    print $message;
+                    ($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;
@@ -538,9 +569,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;
@@ -551,10 +582,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;
@@ -572,6 +603,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
@@ -636,6 +683,7 @@ sub checkperlmodules {
     unless ($] >= 5.006001) {                  # Bug 179
        die getmessage('PerlVersionFailure', ['5.6.1']);
     }
+       startsysout();
 
     my @missing = ();
     unless (eval {require DBI})              { push @missing,"DBI" };
@@ -646,11 +694,16 @@ sub checkperlmodules {
     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 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) { # XXX why only when $#missing >= 0?
-           push @missing, "Net::Z3950";
-       }
+               if ($#missing>=0) { # see above note
+                   push @missing, "Net::Z3950";
+               }
     }
 
 #
@@ -670,6 +723,7 @@ sub checkperlmodules {
     }
 
 
+       startsysout();
     unless (-x "/usr/bin/perl") {
        my $realperl=`which perl`;
        chomp $realperl;
@@ -679,6 +733,7 @@ sub checkperlmodules {
        }
        my $response=showmessage(getmessage('ConfirmPerlExecutableSymlink', $realperl), 'yn', 'y', 1);
        unless ($response eq 'n') {
+               startsysout();
            system("ln -s $realperl /usr/bin/perl");
        }
     }
@@ -700,6 +755,12 @@ The Koha scripts will _not_ work without a symlink from %s to /usr/bin/perl
 May I create this symlink? ([Y]/N):
 : |;
 
+$messages->{'DirFailed'}->{en} = RED.qq|
+We could not create %s, but continuing anyway...
+
+|;
+
+
 
 =item getinstallationdirectories
 
@@ -714,8 +775,9 @@ function does not return any values.
 =cut
 
 sub getinstallationdirectories {
-    $opacdir = '/usr/local/koha/opac';
-    $intranetdir = '/usr/local/koha/intranet';
+       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
@@ -736,26 +798,26 @@ You must specify different directories for the OPAC and INTRANET files!
            $getdirinfo=0;
        }
     }
-    $kohalogdir='/var/log/koha';
+    $kohalogdir=$ENV{prefix}.'/koha/log';
     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);
@@ -763,9 +825,9 @@ 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");
     }
 }
@@ -786,7 +848,8 @@ 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.
+Please provide the name that you wish to give your koha database.
+It must not exist already on the database server.
 
 Database name [%s]: |;
 
@@ -797,7 +860,7 @@ another machine this will 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
+Please provide the name of the user who will have full administrative rights
 to the %s database, when authenticating from %s.
 
 This user will also be used to access Koha's INTRANET interface.
@@ -812,7 +875,7 @@ This password will also be used to access Koha's INTRANET interface.
 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: 
 |;
@@ -907,6 +970,8 @@ sub getapacheinfo {
                          /usr/local/etc/apache/httpd.conf
                          /usr/local/etc/apache/apache.conf
                          /var/www/conf/httpd.conf
+                         /etc/apache2/httpd.conf
+                         /etc/apache2/apache.conf
                          /etc/apache/conf/httpd.conf
                          /etc/apache/conf/apache.conf
                          /etc/apache-ssl/conf/apache.conf
@@ -945,7 +1010,7 @@ sub getapacheinfo {
        $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;
     }
 
@@ -956,12 +1021,9 @@ sub getapacheinfo {
     }
     close(HTTPDCONF);
 
-
-
-
-    unless ($httpduser) {
+    unless (defined($httpduser)) {
        my $message=getmessage('EnterApacheUser', [$etcdir]);
-       until (length($httpduser) && getpwnam($httpduser)) {
+       until (defined($httpduser) && length($httpduser) && getpwnam($httpduser)) {
            $httpduser=showmessage($message, "free", '');
            if (length($httpduser)>0) {
                unless (getpwnam($httpduser)) {
@@ -971,7 +1033,6 @@ sub getapacheinfo {
            } else {
            }
        }
-       print "AU: $httpduser\n";
     }
 }
 
@@ -991,13 +1052,18 @@ function does not return any values.
 
 $messages->{'ApacheConfigIntroduction'}->{en} =
    heading('APACHE CONFIGURATION') . qq|
-Koha needs to setup your Apache configuration file for the
+Koha needs to write an 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
 for the virtual hosts.  There are other ways to set this up,
-and the installer will leave comments in httpd.conf detailing
+and the installer will leave comments in
+%s/koha-httpd.conf detailing
 what these other options are.
 
+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: |;
 
@@ -1010,13 +1076,14 @@ 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.
+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|
 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
+if you are already serving web content from this host, you should change it
 to a different port (8000 might be a good choice).
 
 Enter the OPAC Port [%s]: |;
@@ -1037,7 +1104,7 @@ sub getapachevhostinfo {
     $opacport=80;
     $intranetport=8080;
 
-    showmessage(getmessage('ApacheConfigIntroduction'), 'PressEnter');
+    showmessage(getmessage('ApacheConfigIntroduction',[$etcdir,$etcdir]), 'PressEnter');
 
     $svr_admin=showmessage(getmessage('GetVirtualHostEmail', [$svr_admin]), 'email', $svr_admin);
     $servername=showmessage(getmessage('GetServerName', [$servername]), 'free', $servername);
@@ -1077,17 +1144,11 @@ $messages->{'StartUpdateApache'}->{en} =
 Checking for modules that need to be loaded...
 |;
 
-$messages->{'LoadingApacheModuleModEnv'}->{en}="Loading SetEnv Apache module.\n";
-
-$messages->{'LoadingApacheModuleModInc'}->{en}="Loading Includes Apache module.\n";
-
-$messages->{'ApacheConfigBackupFailed'}->{en} =
-   heading('APACHE CONFIGURATION BACKUP FAILED') . qq|
-An error occurred while trying to make a backup copy of %s.
-
-  %s
-
-No changes will be made to the apache configuration file at this time.
+$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 statements for them in your config.  Please
+make sure that they are enabled for your Koha host.
 
 Press <ENTER> to continue: |;
 
@@ -1096,65 +1157,36 @@ $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
+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';
-    }
-
+    my $logfiledir=$kohalogdir;
+    my $httpdconf = $etcdir."/koha-httpd.conf";
+   
     showmessage(getmessage('StartUpdateApache'), 'none');
+       # to be polite about it: I don't think this should touch the main httpd.conf
 
-    my $httpdconf;
+       # 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 'VirtualHost $servername' "$httpdconf"`) {
+       showmessage(getmessage('ApacheAlreadyConfigured', [$httpdconf, $httpdconf]), 'PressEnter');
        return;
     } else {
        my $includesdirectives='';
@@ -1162,7 +1194,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";
@@ -1174,8 +1206,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
 
@@ -1190,6 +1223,7 @@ $intranetlisten
    ErrorLog $logfiledir/opac-error_log
    TransferLog $logfiledir/opac-access_log
    SetEnv PERL5LIB "$intranetdir/modules"
+   SetEnv KOHA_CONF "$etcdir/koha.conf"
    $includesdirectives
 </VirtualHost>
 
@@ -1202,6 +1236,7 @@ $intranetlisten
    ErrorLog $logfiledir/koha-error_log
    TransferLog $logfiledir/koha-access_log
    SetEnv PERL5LIB "$intranetdir/modules"
+   SetEnv KOHA_CONF "$etcdir/koha.conf"
    $includesdirectives
 </VirtualHost>
 
@@ -1253,6 +1288,7 @@ $messages->{'BasicAuthPasswordWasBlank'}->{en}="\nYou cannot use a blank passwor
 sub basicauthentication {
     my $message=getmessage('IntranetAuthenticationQuestion');
     my $answer=showmessage($message, 'yn', 'y');
+    my $httpdconf = $etcdir."/koha-httpd.conf";
 
     my $apacheauthusername='librarian';
     my $apacheauthpassword='';
@@ -1271,7 +1307,7 @@ sub basicauthentication {
        $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";
+       open(SITE,">>$httpdconf") or warn "Insufficient priveleges to open $realhttpdconf for writing.\n";
        print SITE <<EOP
 
 <Directory $intranetdir>
@@ -1311,24 +1347,39 @@ $messages->{'CopyingFiles'}->{en}="Copying %s to %s.\n";
 
 sub installfiles {
 
+       #MJR: preserve old files, just in case
+       sub neatcopy {
+               my $desc = shift;
+               my $src = shift;
+               my $tgt = shift;
+               
+               if (-d $tgt) {
+               print getmessage('CopyingFiles', ["old ".$desc,$tgt.".old"]);
+                       startsysout;
+                       system("mv ".$tgt." ".$tgt.".old");
+               }
+
+       print getmessage('CopyingFiles', [$desc,$tgt]);
+       startsysout;
+           system("cp -R ".$src." ".$tgt);
+       }
 
     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/");
+
+    neatcopy("admin templates", 'intranet-html', "$intranetdir/htdocs");
+    neatcopy("admin interface", 'intranet-cgi', "$intranetdir/cgi-bin");
+    neatcopy("main scripts", 'scripts', "$intranetdir/scripts");
+    neatcopy("perl modules", 'modules', "$intranetdir/modules");
+    neatcopy("OPAC templates", 'opac-html', "$opacdir/htdocs");
+    neatcopy("OPAC interface", 'opac-cgi', "$opacdir/cgi-bin");
+       startsysout();
     system("touch $opacdir/cgi-bin/opac");
 
-    system("chown -R $httpduser:$httpduser $opacdir");
-    system("chown -R $httpduser:$httpduser $intranetdir");
+       #MJR: is this necessary?
+       if ($> == 0) {
+           system("chown -R $httpduser:$httpduser $opacdir $intranetdir");
+    }
+       system("chmod -R a+rx $opacdir $intranetdir");
 
     # Create /etc/koha.conf
 
@@ -1351,15 +1402,18 @@ opachtdocs=$opacdir/htdocs/opac-tmpl
     close(SITES);
     umask($old_umask);
 
-    chown((getpwnam($httpduser)) [2,3], "$etcdir/koha.conf.tmp") or warn "can't chown koha.conf: $!";
+       startsysout();
+       #MJR: can't help but this be broken, can we?
     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: $!";
-
+       
+       #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";
+
+       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: FIXME: Should report that we haven't chown()d.
 }
 
 
@@ -1374,12 +1428,10 @@ then create the Koha database structure and MySQL permissions.
 
 $messages->{'MysqlRootPassword'}->{en} =
    heading('MYSQL ROOT USER PASSWORD') . qq|
-To allow us to create the koha database please supply your
+To allow us 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...
@@ -1424,14 +1476,6 @@ $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 {
     $mysqluser = 'root';
@@ -1463,44 +1507,27 @@ EOP
 #'
        }
     }
-
-
-    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");
+    # we must not put the mysql root password on the command line
+       $mysqlpass=     showmessage(getmessage('MysqlRootPassword'),'silentfree');
+       
+       showmessage(getmessage('CreatingDatabase'),'none');
+       # 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 ('%','$dbname','$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", "$dbname");
        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 $dbname < 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 {
-       # Create the database structure
-       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");
-
-
-
-
-
-    }
 
 }
 
@@ -1516,9 +1543,10 @@ 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 a symlink to
-do this and to also at the same time faciliate detection of
-ahorted installs. (See checkabortedinstall.)
+$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
 
@@ -1530,7 +1558,7 @@ You can import marc parameters for :
   2 UNIMARC
   N none
 
-Please choose which parameter you want to install. Note if you choose 3,
+Please choose which parameter you want to install. Note if you choose N,
 nothing will be added, and it can be a BIG job to manually create those tables
 
 Choose MARC definition [1]: |;
@@ -1554,29 +1582,35 @@ Which language do you choose? |;
 
 sub updatedatabase {
     # At this point, $etcdir/koha.conf must exist, for C4::Context
+    $ENV{"KOHA_CONF"}=$etcdir.'/koha.conf.tmp';
+       startsysout();  
        my $result=system ("perl -I $intranetdir/modules scripts/updater/updatedatabase");
        if ($result) {
+               restoremycnf();
                print "Problem updating database...\n";
                exit;
        }
 
        my $response=showmessage(getmessage('UpdateMarcTables'), 'restrictchar 12N', '1');
 
+       startsysout();
        if ($response eq '1') {
-               system("cat scripts/misc/marc_datas/marc21_en/structure_def.sql | $mysqldir/bin/mysql -u$mysqluser $mysqlpass_quoted $dbname");
+               system("cat scripts/misc/marc_datas/marc21_en/structure_def.sql | $mysqldir/bin/mysql -u$user $dbname");
        }
        if ($response eq '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");
+               system("cat scripts/misc/marc_datas/unimarc_fr/structure_def.sql | $mysqldir/bin/mysql -u$user $dbname");
+               system("cat scripts/misc/lang-datas/fr/stopwords.sql | $mysqldir/bin/mysql -u$user $dbname");
        }
 
        $result = system ("perl -I $intranetdir/modules scripts/marc/updatedb2marc.pl");
        if ($result) {
                print "Problem updating database to MARC...\n";
+               restoremycnf();
                exit;
        }
+       delete($ENV{"KOHA_CONF"});
 
-       print "\n\nFinished updating of database. Press <ENTER> to continue...";
+       print RESET."\n\nFinished updating of database. Press <ENTER> to continue...";
        <STDIN>;
 }
 
@@ -1591,15 +1625,19 @@ sample data, install them.
 =cut
 
 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);
-       } else {
+#      my $response=showmessage(getmessage('SampleData'), 'yn', 'n');
+#      if ($response =~/^y/i) {
+#
+# FIXME: These calls are now unsafe and should either be removed
+# or updated to use -u$user and no mysqlpass_quoted
+#
+#              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);
+#      } else {
                my $input;
                my $response=showmessage(getmessage('AddBranchPrinter'), 'yn', 'y');
 
@@ -1618,9 +1656,10 @@ sub populatedatabase {
                $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')\"");
+               startsysout();
+               system("$mysqldir/bin/mysql -u$user $dbname -e \"insert into branches (branchcode,branchname,issuing) values ('$branchcode', '$branch', 1)\"");
+               system("$mysqldir/bin/mysql -u$user $dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'IS')\"");
+               system("$mysqldir/bin/mysql -u$user $dbname -e \"insert into branchrelations (branchcode,categorycode) values ('MAIN', 'CU')\"");
 
                my $printername='Library Printer';
                $printername=showmessage(getmessage('PrinterName', [$printername]), 'free', $printername, 1);
@@ -1629,10 +1668,12 @@ sub populatedatabase {
                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 $dbname -e \"insert into printers (printername,printqueue,printtype) values ('$printername', '$printerqueue', '')\"");
+#              }
        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'\"");
+       startsysout();  
+       system("$mysqldir/bin/mysql -u$user $dbname -e \"update systempreferences set value='$language' where variable='opaclanguages'\"");
        }
 }
 
@@ -1652,8 +1693,9 @@ asks the question.
 
 $messages->{'RestartApache'}->{en} = heading('RESTART APACHE') . qq|
 Apache needs to be restarted to load the new configuration for Koha.
+This requires 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 {
 
@@ -1662,13 +1704,14 @@ sub restartapache {
 
 
     unless ($response=~/^n/i) {
+       startsysout();
        # Need to support other init structures here?
        if (-e "/etc/rc.d/init.d/httpd") {
-           system('/etc/rc.d/init.d/httpd restart');
+           system('su root -c /etc/rc.d/init.d/httpd restart');
        } elsif (-e "/etc/init.d/apache") {
-           system('/etc//init.d/apache restart');
+           system('su root -c /etc/init.d/apache restart');
        } elsif (-e "/etc/init.d/apache-ssl") {
-           system('/etc/init.d/apache-ssl restart');
+           system('su root -c /etc/init.d/apache-ssl restart');
        }
     }
 
@@ -1687,6 +1730,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
@@ -1744,6 +1788,45 @@ 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 (-e $mycnf) {
+               unlink($mycnf);
+       }
+       if (-e $mytmpcnf) {
+               rename $mytmpcnf,$mycnf;
+       }
+}
+
 =back
 
 =head1 SEE ALSO