# BEGIN COPYRIGHT BLOCK
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details. 
# END COPYRIGHT BLOCK
#

###########################
#
# This perl module provides a way to set up a new installation after
# the binaries have already been extracted.  This is typically after
# using native packaging support to install the package e.g. RPM,
# pkgadd, depot, etc.  This script will show the license, readme,
# dsktune, then run the usual setup pre and post installers.
#
##########################

package Setup;
use Exporter ();
@ISA       = qw(Exporter);
@EXPORT    = qw($SILENT $EXPRESS $TYPICAL $CUSTOM);
@EXPORT_OK = qw($SILENT $EXPRESS $TYPICAL $CUSTOM);

# hostname
use Sys::Hostname; # hostname()

# load perldap
use Mozilla::LDAP::Conn;
use Mozilla::LDAP::Utils qw(normalizeDN);
use Mozilla::LDAP::API qw(ldap_explode_dn);
use Mozilla::LDAP::LDIF;

use Getopt::Long;

use SetupLog;
use DSUtil;
use Inf;

use strict;
use vars qw($EXPRESS $TYPICAL $CUSTOM $SILENT);

# the setup types
$EXPRESS = 1;
$TYPICAL = 2;
$CUSTOM = 3;
$SILENT = 4;

# process command line options
Getopt::Long::Configure(qw(bundling)); # bundling allows -ddddd

sub VersionMessage {
    print "389 Directory Server Setup Program Version 1.4.3.4\n";
}

sub HelpMessage {
    print <<EOF;
Usage: $0 [--options] -- [args]
options:
    --help       This message
    --version    Print the version and exit
    --debug      Turn on debugging
    --silent     Use silent setup - no user input
    --file=name  Use the file 'name' in .inf format to supply the default answers
    --keepcache  Do not delete the temporary .inf file generated by this program
    --logfile    Log setup messages to this file - otherwise, a temp file will be used
    --update     Update an existing installation (e.g. after upgrading packages)
    --continue   (update only) keep going despite errors (also --force)
For all options, you can also use the short name e.g. -h, -d, etc.  For the -d argument,
specifying it more than once will increase the debug level e.g. -ddddd

args:
You can supply default .inf data in this format:
    section.param=value
e.g.
    General.FullMachineName=foo.example.com
or
    "slapd.Suffix=dc=example,dc=com"
Values passed in this manner will override values in an .inf file given with the -f argument.
EOF
}

sub new {
    my $type = shift;
    my $self = {};
    $self = bless $self, $type;
    $self->init(@_);
    return $self;
}

sub init {
    my $self = shift;
    $self->{res} = shift;
    my ($silent, $inffile, $keep, $preonly, $logfile, $update, $force);

    GetOptions('help|h|?' => sub { VersionMessage(); HelpMessage(); exit 0 },
               'version|v' => sub { VersionMessage(); exit 0 },
               'debug|d+' => \$DSUtil::debuglevel,
               'silent|s' => \$silent,
               'file|f=s' => \$inffile,
               'keepcache|k' => \$keep,
               'preonly|p' => \$preonly,
               'logfile|l=s' => \$logfile,
               'update|u' => \$update,
               'continue|force|c' => \$force
               );

    $self->{silent} = $silent;
    $self->{keep} = $keep;
    $self->{preonly} = $preonly;
    $self->{update} = $update;
    $self->{force} = $force;
    $self->{logfile} = $logfile;
    $self->{log} = new SetupLog($self->{logfile});
    DSUtil::setDebugLog($self->{log});
    # if user supplied inf file, use that to initialize
    if (defined($inffile)) {
        $self->{inf} = new Inf($inffile);
        if(!$self->{inf}){
            $self->doExit(1);
        }
    } else {
        $self->{inf} = new Inf;
    }

    # see if user passed in default inf values - also, command line
    # arguments override those passed in via an inf file - this
    # allows the reuse of .inf files with some parameters overridden
    if (!$self->{inf}->updateFromArgs(@ARGV)) {
        HelpMessage();
        exit 1;
    }

    # this is the base config directory - the directory containing
    # the slapd-instance instance specific config directories
    $self->{configdir} = $ENV{DS_CONFIG_DIR} || "/etc/dirsrv";
}

# log only goes the the logfile
sub log {
    my $self = shift;
    my $level = shift;
    $self->{log}->logMessage($level, "Setup", @_);
}

# msg does to the screen and optionally to the log file
# if you use msg like this:
# msg(0, "some message")
# it will go only to the screen
# if you use msg like this:
# msg($WARN, "some message")
# it will go to the screen and to the log at the $WARN level
# all messages are localizable - you must define a resource key
# the first string passed to this method is a resource key
# additional strings are used as "arguments" to that resource key
# if you want to print un-localizable messages, use debug or write
# directly to the log or screen
sub msg {
    my $self = shift;
    my $level = shift;
    my @ary = @_;
    if (!$level && @ary) {
        # e.g. msg(0, "string") - no logging
    } elsif ($level and @ary and grep {/^$level$/} $self->{log}->levels()) {
        # e.g. msg($WARN, "string") - print and log
    } else {
        # log at default INFO level
        unshift @ary, $level;
        $level = $INFO;
    }
    # @text is an array of strings for one message or 
    # an array of array refs, each one is a message
    while (@ary) {
        my @text = shift @ary;

        last if (!@text or !$text[0]);

        # element is an array ref - just pass to getText
        # else is a list of strings
        # NOTE: this will NOT work if ary contains
        # consecutive simple string errors not separated
        # by an array ref e.g. this will work
        # ARRAY, 'errkey', arg, arg, ARRAY
        # this will not work
        # ARRAY, 'errkey', arg, 'errkey2', arg2, ARRAY
        while (@ary and !ref($ary[0])) {
            push @text, shift @ary;
        }
        my $string = $self->{res}->getText(@text);
        if ($level) {
            $self->log($level, $string);
        }
        print $string;
    }
}

sub doExit {
    my $self = shift;
    my $code = shift;
    if (!defined($code)) {
        $code = 1;
    }

    if ($code) {
        $self->msg($FATAL, 'setup_exiting', $self->{log}->{filename});
    } else {
        $self->msg($SUCCESS, 'setup_exiting', $self->{log}->{filename});
    }
	exit $code;
}

# get a list of the directory servers in configdir
sub getDirServers {
    my $self = shift;
    if (!$self->{dirservers}) {
        $self->{dirservers} = [];
        for my $dir (glob("$self->{configdir}/slapd-*")) {
            next if ($dir =~ /\.removed$/); # skip removed instances
            if (-d $dir) {
                $dir =~ s,$self->{configdir}/,,; # strip off dir part
                push @{$self->{dirservers}}, $dir;
            }
        }
    }
    return @{$self->{dirservers}};
}


#############################################################################
# Mandatory TRUE return value.
#
1;

# emacs settings
# Local Variables:
# mode:perl
# indent-tabs-mode: nil
# tab-width: 4
# End:
