#!/usr/bin/env perl
# BEGIN COPYRIGHT BLOCK
# This Program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; version 2 of the License.
# 
# This Program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along with
# this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA.
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

use lib qw(/usr/lib/i386-linux-gnu/dirsrv/perl);

use strict;

use Setup;
use SetupLog;
use Inf;
use Resource;
use DialogManager;
use DSCreate;
use DSUpdate;
use AdminUtil;
use AdminServer;
use DSUtil;
use Sys::Hostname;

my $res = new Resource("/usr/share/dirsrv/properties/setup-ds.res",
                       "/usr/share/dirsrv/properties/setup-ds-admin.res");

my $setup = new Setup($res);

# see if there is already a configds
my $admConf = AdminUtil::getAdmConf("$setup->{configdir}/admin-serv");

# Set defaults, but don't override settings that were
# defined in a passed in inf file.
if ($admConf && %{$admConf}) {
    unless (defined($setup->{inf}->{General}->{ConfigDirectoryLdapURL})) {
        $setup->{inf}->{General}->{ConfigDirectoryLdapURL} = $admConf->{ldapurl};
    }
    unless (defined($setup->{inf}->{General}->{ConfigDirectoryAdminID})) {
        $setup->{inf}->{General}->{ConfigDirectoryAdminID} = $admConf->{userdn};
    }
    unless (defined($setup->{inf}->{General}->{AdminDomain})) {
        $setup->{inf}->{General}->{AdminDomain} = $admConf->{AdminDomain};
    }
    unless (defined($setup->{inf}->{General}->{SuiteSpotUserID})) {
        $setup->{inf}->{General}->{SuiteSpotUserID} = $admConf->{SuiteSpotUserID};
    }
    unless (defined($setup->{inf}->{General}->{SuiteSpotGroup})) {
        $setup->{inf}->{General}->{SuiteSpotGroup} = $admConf->{SuiteSpotGroup};
    }
    unless (defined($setup->{inf}->{admin}->{SysUser})) {
        $setup->{inf}->{admin}->{SysUser} = $admConf->{sysuser};
    }

    if ($setup->{inf}->{General}->{ConfigDirectoryLdapURL} =~ /^ldaps/) {
        unless (defined($setup->{inf}->{General}->{certdb})) {
            $setup->{inf}->{General}->{certdb} = AdminUtil::getCertDir("$setup->{configdir}/admin-serv");
        }
    }

    # read additional config from config DS
    my $pset = AdminUtil::getPset($admConf);
    if ($pset && %{$pset}) {
        unless (defined($setup->{inf}->{admin}->{Port})) {
            $setup->{inf}->{admin}->{Port} = $pset->{"configuration.nsserverport"};
        }
        $setup->{asorigport} = $pset->{"configuration.nsserverport"}; # save orig. port
        unless (defined($setup->{inf}->{admin}->{ServerIpAddress})) {
            $setup->{inf}->{admin}->{ServerIpAddress} = $pset->{"configuration.nsserveraddress"};
        }
        unless (defined($setup->{inf}->{General}->{FullMachineName})) {
            $setup->{inf}->{General}->{FullMachineName} = $pset->{"serverhostname"};
        }
    }
    my $admpw = AdminUtil::getAdmpw($admConf);
    if ($admpw && %{$admpw}) {
        unless (defined($setup->{inf}->{admin}->{ServerAdminID})) {
            $setup->{inf}->{admin}->{ServerAdminID} = $admpw->{ServerAdminID};
        }
        unless (defined($setup->{inf}->{admin}->{ServerAdminPwd})) {
            $setup->{inf}->{admin}->{ServerAdminPwd} = $admpw->{ServerAdminPwd};
        }
    }

    # default to using the existing config DS
    unless (defined($setup->{inf}->{slapd}->{UseExistingMC})) {
        $setup->{inf}->{slapd}->{UseExistingMC} = 1;
    }
    unless (defined($setup->{inf}->{slapd}->{SlapdConfigForMC})) {
        $setup->{inf}->{slapd}->{SlapdConfigForMC} = 0;
    }
    $setup->{reconfigas} = 1; # allow AS reconfig
} else {
    # default to creating the config DS
    unless (defined($setup->{inf}->{slapd}->{UseExistingMC})) {
        $setup->{inf}->{slapd}->{UseExistingMC} = 0;
    }
    unless (defined($setup->{inf}->{slapd}->{SlapdConfigForMC})) {
        $setup->{inf}->{slapd}->{SlapdConfigForMC} = "yes";
    }
}

# do not allow reconfig (setup -r) if no setup has been done
if (! $setup->{reconfigas}) {
    delete $setup->{update};
}

if (!$setup->{silent}) {
    my $dialogmgr = new DialogManager($setup, $res, $TYPICAL);

    require SetupDialogs;
    require DSDialogs;
    require ConfigDSDialogs;
    require ASDialogs;

    my @dialogs;
    if ($setup->{update}) {
        push @dialogs, ConfigDSDialogs->getUpdateDialogs();
    } else {
        push @dialogs, SetupDialogs->getDialogs();
        push @dialogs, ConfigDSDialogs->getDialogs();
        push @dialogs, DSDialogs->getDialogs();
        push @dialogs, ASDialogs->getDialogs();
    }

    my $readytoproceed = new DialogYesNo (
        $EXPRESS,
        'dialog_readytoproceed_text',
        1,
        sub {
            my $self = shift;
            my $ans = shift;
            my $resp = $self->handleResponse($ans);
            if ($resp == $DialogManager::NEXT) {
                if (!$self->isYes()) {
                    $resp = $DialogManager::BACK;
                }
            }
            return $resp;
        },
        ['dialog_readytoproceed_prompt'],
    );
    push @dialogs, $readytoproceed;

    $dialogmgr->addDialog(@dialogs);

    my $rc = $dialogmgr->run();
    if ($rc) {
        $setup->doExit($rc);
    }
}


# set default values
if (!defined($setup->{inf}->{General}->{FullMachineName})) {
    $setup->{inf}->{General}->{FullMachineName} = hostname();
}

if (!defined($setup->{inf}->{slapd}->{ServerPort})) {
    my $port = 389;
    if (!portAvailable($port)) {
        $port = getAvailablePort();
    }
    $setup->{inf}->{slapd}->{ServerPort} = $port;
}

my $createconfigds;
if ((defined($setup->{inf}->{slapd}->{SlapdConfigForMC}) and
     ("yes" =~ /^$setup->{inf}->{slapd}->{SlapdConfigForMC}/i)) or
    (defined($setup->{inf}->{slapd}->{UseExistingMC}) and
     !$setup->{inf}->{slapd}->{UseExistingMC})) {
    # if user has chosen to create the config ds, we must set
    # the url appropriately, before writing the inf for ds_newinst
    $setup->{inf}->{General}->{ConfigDirectoryLdapURL} = 
        "ldap://" . $setup->{inf}->{General}->{FullMachineName} .
        ":" . $setup->{inf}->{slapd}->{ServerPort} .
        "/o=NetscapeRoot";
    $createconfigds = 1;
}

if (!defined($setup->{inf}->{General}->{ConfigDirectoryAdminID})) {
    $setup->{inf}->{General}->{ConfigDirectoryAdminID} = "admin";
}

if (!defined($setup->{inf}->{General}->{AdminDomain})) {
    my $admindomain = $setup->{inf}->{General}->{FullMachineName} ||
        hostname();
    $admindomain =~ s/^[^\.]*\.//; # just the domain part
    $setup->{inf}->{General}->{AdminDomain} = $admindomain;
}

if (!defined($setup->{inf}->{General}->{SuiteSpotGroup})) {
    $setup->{inf}->{General}->{SuiteSpotGroup} = "nogroup";
}

# for admin server too, since ServerAdminID is used by AdminUtil code
AdminServer::setDefaults($setup);

my @errs;

if (!$setup->{update}) {
    $setup->msg('create_dirserver');

    # create a directory server instance
    # if we are not creating the config DS instance, 
    # create but do not start the server - start
    # after createSubDS so the pta plugin will take effect
    my $start_server_after_reg = 1; # default - start server after registration
    if (!$createconfigds) {
        if (exists($setup->{inf}->{slapd}->{start_server}) &&
            defined($setup->{inf}->{slapd}->{start_server})) {
            # user explicitly set this value
            $start_server_after_reg = $setup->{inf}->{slapd}->{start_server};
        }
        $setup->{inf}->{slapd}->{start_server} = 0; # create server un-started
    }

    @errs = createDSInstance($setup->{inf});
    if (@errs) {
        $setup->msg(@errs);
        $setup->msg($FATAL, 'error_creating_dsinstance', $setup->{inf}->{slapd}->{ServerIdentifier});
        $setup->doExit(1);
    } else {
        $setup->msg('created_dsinstance', $setup->{inf}->{slapd}->{ServerIdentifier});
    }

    # setup directory server instance to be the configuration DS
    if ($createconfigds) {
        $setup->msg('create_configds');
        if (!createConfigDS($setup->{inf}, \@errs)) {
            $setup->msg($FATAL, @errs);
            $setup->msg($FATAL, 'error_create_configds');
            $setup->doExit(1);
        }
    } else {
        # set up directory server instance to be managed by the console/adminserver
        $setup->msg('create_subds');
        if (!createSubDSNoConn($setup->{inf}, \@errs)) {
            $setup->msg($FATAL, @errs);
            $setup->msg($FATAL, 'error_create_configds');
            $setup->doExit(1);
        }
        if ($start_server_after_reg) {
            delete $setup->{inf}->{slapd}->{start_server}; # remove to start server
            if (@errs = DSCreate::startServer($setup->{inf})) {
                $setup->msg(@errs);
                $setup->doExit(1);
            }
            # add the aci that allows the admin user to administer the server
            if (!addConfigACIsToSubDS($setup->{inf}, \@errs)) {
                $setup->msg(@errs);
                $setup->doExit(1);
            }
        }
    }
}

if (!$setup->{update}) {
    # register ds instances with config DS
    if (!registerDSWithConfigDS($setup->{inf}->{slapd}->{ServerIdentifier},
                                \@errs,
                                $setup->{inf})) {
        $setup->msg(@errs);
        $setup->msg($FATAL, 'error_register_dirserver');
        $setup->doExit(1);
    }
} else {
    doUpdate($setup, \@errs);
    if (@errs) {
        $setup->msg(@errs);
        if (!$setup->{force}) {
            $setup->msg($FATAL, 'error_reconfig_adminserver');
            $setup->doExit(1);
        }
    }
}


# configure and register the admin server instance
if (!$setup->{reconfigas}) {
    if (!createAdminServer($setup)) {
        $setup->msg($FATAL, 'error_create_adminserver');
        $setup->doExit(1);
    }
} else {
    if (!reconfigAdminServer($setup)) {
        $setup->msg($FATAL, 'error_reconfig_adminserver');
        $setup->doExit(1);
    }
}

$setup->doExit(0);

END {
    if ($setup and $setup->{keep}) {
        $setup->{inf}->write("__temp__");
    }
}

sub doUpdate {
    my ($setup, $errs) = @_;

    my $inf = $setup->{inf};

    # first, acquire a connection to the config DS
    my $conn = getConfigDSConn($inf->{General}->{ConfigDirectoryLdapURL},
                               $inf->{General}->{ConfigDirectoryAdminID},
                               $inf->{General}->{ConfigDirectoryAdminPwd},
                               $setup->{configdir} . "/admin-serv", $errs);

    if (!$conn) {
        return;
    }

    # update DS first
    # use the admin DN + password to update the DS - requires
    # the servers are online
    unless(defined($setup->{inf}->{General}->{UpdateMode})) {
        $setup->{inf}->{General}->{UpdateMode} = 'online';
    }
    # this assumes all of the directory servers are already registered with
    # the config ds and being managed by them
    # a nice enhancement would be to detect if the instance is being managed
    # if not, shut it down, configure it for registration, then register it
    for my $inst ($setup->getDirServers()) {
        unless(defined($setup->{inf}->{$inst}->{RootDN})) {
            # adminbinddn set as a side effect of a successful getConfigDSConn
            $setup->{inf}->{$inst}->{RootDN} = $conn->{adminbinddn};
        }
        unless(defined($setup->{inf}->{$inst}->{RootDNPwd})) {
            $setup->{inf}->{$inst}->{RootDNPwd} = $setup->{inf}->{General}->{ConfigDirectoryAdminPwd};
        }
    }

    # stuff the config ds conn in the inf for update use
    $setup->{inf}->{configdsconn} = $conn;

    my @localerrs;
    if (@localerrs = updateDS($setup, ["/usr/share/dirsrv/updates-admin"])) {
        push @{$errs}, @localerrs;
        if (!$setup->{force}) {
            return;
        }
    }
    
    $conn->close();

    # register all instances
    $setup->msg('registering_dirserver_instances');
    if (!registerManyDSWithConfigDS($setup->{inf}, $errs,
                                    $setup->{configdir},
                                    $setup->getDirServers())) {
        if (!$setup->{force}) {
            return;
        }
    }

    return;
}

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