+=back
+
+=head2 Accessor functions (for installer.pl)
+
+=over 4
+
+=cut
+
+=item setlanguage
+
+ setlanguage('en');
+
+Sets the installation language, normally "en" (English).
+In fact, only "en" is supported.
+
+=cut
+
+sub setlanguage ($) {
+ ($language) = @_;
+}
+
+=item setdomainname
+
+ setdomainname('example.org');
+
+Sets the domain name of the host.
+
+The domain name should not contain a leading dot;
+otherwise, the results are undefined.
+
+=cut
+
+sub setdomainname ($) {
+ ($domainname) = @_;
+}
+
+=item setetcdir
+
+ setetcdir('/etc');
+
+Sets the sysconfdir, normally /etc.
+This should be an absolute path; a trailing / is not required.
+
+=cut
+
+sub setetcdir ($) {
+ ($etcdir) = @_;
+}
+
+=item setkohaversion
+
+ setkohaversion('1.3.3RC26');
+
+Sets the Koha version as known by the installer.
+
+=cut
+
+sub setkohaversion ($) {
+ ($kohaversion) = @_;
+}
+
+=item getservername
+
+ my $servername = getservername;
+
+Gets the name of the Koha virtual server as specified by the user.
+
+=cut
+
+sub getservername () {
+ $servername;
+}
+
+=item getopacport
+
+ $port = getopacport;
+
+Gets the port that will run the Koha OPAC virtual server,
+as specified by the user.
+
+=cut
+
+sub getopacport () {
+ $opacport;
+}
+
+=item getintranetport
+
+ $port = getintranetport;
+
+Gets the port that will run the Koha INTRANET virtual server,
+as specified by the user.
+
+=cut
+
+sub getintranetport () {
+ $intranetport;
+}
+
+=back
+
+=head2 Miscellaneous utility functions
+
+=over 4
+
+=cut
+
+=item dirname
+
+ dirname $path;
+
+Does the equivalent of dirname(1). Given a path $path, return the
+parent directory of $path (best guess), except when $path seems to
+be the same as /, in which case $path itself is returned unchanged.
+
+=cut
+
+sub dirname ($;$) {
+ my($path) = @_;
+ if ($path =~ /[^\/]/s) {
+ if ($path =~ /\//) {
+ $path =~ s/\/+[^\/]+\/*$//s;
+ } else {
+ $path = '.';
+ }
+ }
+ return $path;
+}
+
+=item mkdir_parents
+
+ mkdir_parents $path;
+ mkdir_parents $path, $mode;
+
+Does the equivalent of mkdir -p, or mkdir --parents. Given a path $path,
+create the directory $path, recursively creating any intermediate
+directories. If $mode is given, the directory will be created with
+mode $mode.
+
+WARNING: If $path already exists, mkdir_parents will just return
+successfully (just like mkdir -p), whether the mode of $path conforms
+to $mode or not. (This is the behaviour of the mkdir -p command.)
+
+=cut
+
+sub mkdir_parents ($;$) {
+ my($path, $mode) = @_;
+ my $ok = -d($path)? 1: defined $mode? mkdir($path, $mode): mkdir($path);
+
+ if (!$ok && $! == ENOENT) {
+ my $parent = dirname($path);
+ $ok = mkdir_parents($parent, $mode);
+
+ # retry and at the same time make sure that $! is set correctly
+ $ok = defined $mode? mkdir($path, $mode): mkdir($path);
+ }
+ return $ok;
+}
+
+
+=item getmessage
+
+ getmessage($msgid);
+ getmessage($msgid, $variables);
+
+Gets a localized message (format string) with message id $msgid,
+and, if an array reference of variables $variables is given,
+substitutes variables in the format string with @$variables.
+Returns the found message string, with variable substitutions
+if specified.
+
+$msgid must be the message identifier corresponding to a defined
+message string (a valid key to the $messages hash in the Installer
+package). getmessage throws an exception if the message cannot be
+found.
+
+=cut
+
+sub getmessage {
+ my $messagename=shift;
+ my $variables=shift;
+ 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;
+ }
+ return $message;
+}
+
+
+=item showmessage
+
+ showmessage($message, 'none');
+ showmessage($message, 'none', undef, $noclear);
+
+ $result = showmessage($message, 'yn');
+ $result = showmessage($message, 'yn', $defaultresponse);
+ $result = showmessage($message, 'yn', $defaultresponse, $noclear);
+
+ $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');
+
+Shows a message and optionally gets a response from the user.
+
+The first two arguments, the message and the response type,
+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", "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
+significant in the list of allowed characters.) If a response
+type other than the above-listed is specified, the result is
+undefined.
+
+Note that the response type "yn" is equivalent to "restrictchar yn".
+Because "restrictchar" is case-sensitive, the user is expected
+to enter "y" or "n" in lowercase only.
+
+Note that the response type of "email" does not actually
+guarantee that the returned value is a well-formed RFC-822
+email address, nor does it accept all well-formed RFC-822 email
+addresses. What it does is to restrict the returned value to a
+string that is looks reasonably likely to be an email address
+in the "real world", given the premise that the user is trying
+to enter a real email address.
+
+If a response type other than "none" or "PressEnter" is
+specified, a third argument, specifying the default value, can
+be specified: If this default response is not specified, the
+default response is the first allowed character if the response
+type is "restrictchar", otherwise the default response is the
+empty string. This default response is used when the user does
+not specify a value (i.e., presses Enter without typing in
+anything), showmessage will assume that the default response is
+the user's response.
+
+Note that because the response type "yn" is equivalent to
+"restrictchar yn", the default value for response type "yn",
+if unspecified, is "y".
+
+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.
+
+=cut
+#'
+
+sub showmessage {
+ #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) || (print $clear_string);
+ if ($responsetype =~ /^yn$/) {
+ $responsetype='restrictchar ynYN';
+ }
+ print RESET.$message;
+ if ($responsetype =~/^restrictchar (.*)/i) {
+ my $response='\0';
+ my $options=$1;
+ until ($options=~/$response/) {
+ (defined($defaultresponse)) || ($defaultresponse=substr($options,0,1));
+ $response=<STDIN>;
+ chomp $response;
+ (length($response)) || ($response=$defaultresponse);
+ 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 =~/^(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;
+ } elsif ($responsetype =~/^numerical$/i) {
+ (defined($defaultresponse)) || ($defaultresponse='');
+ my $response='';
+ until ($response=~/^\d+$/) {
+ $response=<STDIN>;
+ chomp $response;
+ ($response) || ($response=$defaultresponse);
+ unless ($response=~/^\d+$/) {
+ ($noclear) || (print $clear_string);
+ print RED."Invalid Response ($response). Response must be a number.\n\n";
+ print RESET.$message;
+ }
+ }
+ return $response;
+ } elsif ($responsetype =~/^email$/i) {
+ (defined($defaultresponse)) || ($defaultresponse='');
+ my $response='';
+ until ($response=~/.*\@.*\..*/) {
+ $response=<STDIN>;
+ chomp $response;
+ ($response) || ($response=$defaultresponse);
+ 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;
+ } elsif ($responsetype =~/^PressEnter$/i) {
+ <STDIN>;
+ return;
+ } elsif ($responsetype =~/^none$/i) {
+ return;
+ } else {
+ # FIXME: There are a few places where we will get an undef as the
+ # response type. Should we thrown an exception here, or should we
+ # legitimize this usage and say "none" is the default if not specified?
+ #die "Illegal response type \"$responsetype\"";
+ }
+}
+
+
+=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
+
+=over 4
+
+=cut
+
+=item checkabortedinstall
+
+ checkabortedinstall;