[Fedora-directory-commits] ldapserver/ldap/admin/src/scripts DSDialogs.pm, NONE, 1.1 Dialog.pm, NONE, 1.1 DialogManager.pm, NONE, 1.1 Inf.pm, NONE, 1.1 Resource.pm, NONE, 1.1 Setup.pm.in, NONE, 1.1 SetupDialogs.pm, NONE, 1.1 SetupLog.pm, NONE, 1.1 Util.pm, NONE, 1.1 setup-ds.pl.in, NONE, 1.1 setup-ds.res.in, NONE, 1.1

Richard Allen Megginson (rmeggins) fedora-directory-commits at redhat.com
Fri Jun 8 01:09:18 UTC 2007


Author: rmeggins

Update of /cvs/dirsec/ldapserver/ldap/admin/src/scripts
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv20988/ldapserver/ldap/admin/src/scripts

Added Files:
	DSDialogs.pm Dialog.pm DialogManager.pm Inf.pm Resource.pm 
	Setup.pm.in SetupDialogs.pm SetupLog.pm Util.pm setup-ds.pl.in 
	setup-ds.res.in 
Log Message:
Resolves: bug 237356
Description: Move DS Admin Code into Admin Server
Fix Description: This adds the setup related perl modules, scripts, and resource files to the DS base code.  This will allow a user to interactively setup (create an instance of) a directory server.  This will also form the base of the work to add the console and admin server related setup code.
New files/directories:
$libdir/fedora-ds/perl - this is where the perl modules (Setup.pm, etc.) will be installed.
$bindir/setup-ds.pl - the script to use to interactively create an instance of directory server.  This has use lib '$libdir/fedora-ds/perl' hard coded into it at build time, in order to find the "private" setup perl modules.  If you invoke this script in silent mode (setup-ds.pl -s) then it is exactly the same as just using ds_newinst.pl.
$sysconfdir/fedora-ds/property/setup-ds.res - Resources for setup-ds.pl and the associated modules.
I also fixed a problem with the libns-dshttpd linkage.
Platforms tested: RHEL4
Flag Day: no
Doc impact: Yes.  All of these new items will need to be documented.



--- NEW FILE DSDialogs.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

package DSDialogs;

use strict;

use Net::Domain qw(hostname hostfqdn);
use DialogManager;
use Setup;
use Dialog;
use Util;

my $dsport = new Dialog (
    $TYPICAL,
    'dialog_dsport_text',
    sub {
        my $self = shift;
        my $port = $self->{manager}->{inf}->{slapd}->{ServerPort};
        if (!defined($port)) {
            $port = 389;
        }
        if (!portAvailable($port)) {
            $port = getAvailablePort();
        }
        return $port;
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $DialogManager::SAME;
        if ($ans !~ /\d+/) {
            $self->{manager}->alert("dialog_dsport_error", $ans);
        } elsif (!portAvailable($ans)) {
            $self->{manager}->alert("dialog_dsport_error", $ans);
        } else {
            $res = $DialogManager::NEXT;
            $self->{manager}->{inf}->{slapd}->{ServerPort} = $ans;
        }
        return $res;
    },
    ['dialog_dsport_prompt']
);

my $dsserverid = new Dialog (
    $TYPICAL,
    'dialog_dsserverid_text',
    sub {
        my $self = shift;
        my $serverid = $self->{manager}->{inf}->{slapd}->{ServerIdentifier};
        if (!defined($serverid)) {
            $serverid = $self->{manager}->{inf}->{General}->{FullMachineName};
            if (!defined($serverid)) {
                $serverid = hostname;
            } else { # strip out the leftmost domain component
                $serverid =~ s/\..*$//;
            }
        }
        return $serverid;
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $DialogManager::SAME;
        my $path = $self->{manager}->{setup}->{configdir} . "/slapd-" . $ans;
        if ($ans !~ /^[0-9a-zA-Z_-]+$/) {
            $self->{manager}->alert("dialog_dsserverid_error", $ans);
        } elsif (-d $path) {
            $self->{manager}->alert("dialog_dsserverid_inuse", $ans);
        } else {
            $res = $DialogManager::NEXT;
            $self->{manager}->{inf}->{slapd}->{ServerIdentifier} = $ans;
        }
        return $res;
    },
    ['dialog_dsserverid_prompt']
);

my $dssuffix = new Dialog (
    $TYPICAL,
    'dialog_dssuffix_text',
    sub {
        my $self = shift;
        my $suffix = $self->{manager}->{inf}->{slapd}->{Suffix};
        if (!defined($suffix)) {
            $suffix = $self->{manager}->{inf}->{General}->{FullMachineName};
            if (!defined($suffix)) {
                $suffix = hostfqdn;
            }
            # convert fqdn to dc= domain components
            $suffix = "dc=$suffix";
            $suffix =~ s/\./, dc=/g;
        }
        return $suffix;
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $DialogManager::SAME;
        if (!isValidDN($ans)) {
            $self->{manager}->alert("dialog_dssuffix_error", $ans);
        } else {
            $res = $DialogManager::NEXT;
            $self->{manager}->{inf}->{slapd}->{Suffix} = $ans;
        }
        return $res;
    },
    ['dialog_dssuffix_prompt']
);

my $dsrootdn = new Dialog (
    $EXPRESS,
    'dialog_dsrootdn_text',
    sub {
        my $self = shift;
        my $index = shift;
        my $rootdn;
        if ($index == 0) { # return undef for password defaults
            $rootdn = $self->{manager}->{inf}->{slapd}->{RootDN};
            if (!defined($rootdn)) {
                $rootdn = "cn=Directory Manager";
            }
        }
        return $rootdn;
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $index = shift;
        my $res = $DialogManager::SAME;
        if ($index == 0) { # verify DN
            if (!isValidDN($ans)) {
                $self->{manager}->alert("dialog_dsrootdn_error", $ans);
            } else {
                $res = $DialogManager::NEXT;
                $self->{manager}->{inf}->{slapd}->{RootDN} = $ans;
            }
        } elsif ($index == 1) { # verify initial password
            my $test = $ans;
            if ($test) {
                $test =~ s/\s//g;
            }
            if (!$ans or (length($ans) < 8)) {
                $self->{manager}->alert("dialog_dsrootpw_tooshort", 8);
            } elsif (length($test) != length($ans)) {
                $self->{manager}->alert("dialog_dsrootpw_invalid");
            } else {
                $res = $DialogManager::NEXT;
                $self->{firstpassword} = $ans; # save for next index
            }
        } elsif ($index == 2) { # verify second password
            if ($ans ne $self->{firstpassword}) {
                $self->{manager}->alert("dialog_dsrootpw_nomatch");
            } else {
                $self->{manager}->{inf}->{slapd}->{RootDNPwd} = $ans;
                $res = $DialogManager::NEXT;
            }
        }
        return $res;
    },
    ['dialog_dsrootdn_prompt'], ['dialog_dsrootpw_prompt1', 1], ['dialog_dsrootpw_prompt2', 1]
);

my $dssample = new DialogYesNo (
    $CUSTOM,
    'dialog_dssample_text',
    0,
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $self->handleResponse($ans);
        if ($res == $DialogManager::NEXT) {
            $self->{manager}->{inf}->{slapd}->{AddSampleEntries} = ($self->isYes() ? 'Yes' : 'No');
        }
        return $res;
    },
    ['dialog_dssample_prompt'],
);

my $dspopulate = new Dialog (
    $CUSTOM,
    'dialog_dspopulate_text',
    sub {
        my $self = shift;
        my $val = $self->{manager}->{inf}->{slapd}->{InstallLdifFile};
        if (!defined($val)) {
            $val = 'none';
        }
        return $val;
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $DialogManager::SAME;
        if ($ans eq 'none') {
            $self->{manager}->{inf}->{slapd}->{InstallLdifFile} = 'none';
            $self->{manager}->{inf}->{slapd}->{AddOrgEntries} = 'No';
            $res = $DialogManager::NEXT;
        } elsif ($ans eq 'suggest') {
            $self->{manager}->{inf}->{slapd}->{InstallLdifFile} = 'suggest';
            $self->{manager}->{inf}->{slapd}->{AddOrgEntries} = 'Yes';
            $res = $DialogManager::NEXT;
        } else { # a file
            if (! -f $ans) {
                $self->{manager}->alert("dialog_dspopulate_error", $ans);
            } else {
                $self->{manager}->{inf}->{slapd}->{InstallLdifFile} = $ans;
                $self->{manager}->{inf}->{slapd}->{AddOrgEntries} = 'No';
                $res = $DialogManager::NEXT;
            }
        }
        return $res;
    },
    ['dialog_dspopulate_prompt']
);

sub getDialogs {
    return ($dsport, $dsserverid, $dssuffix, $dsrootdn, $dssample, $dspopulate);
}

1;


--- NEW FILE Dialog.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

package Dialog;

use DialogManager;

#require    Exporter;
#@ISA       = qw(Exporter);
#@EXPORT    = qw();

# NOTE: This "class" is an "abstract" class.  There are two methods which
# must be provided by subclasses:
# $ans = $dialog->defaultAns($promptindex);
# where $promptindex is the index into the array of prompts given when
# constructing the Dialog object
# The dialog will typically use a default answer either hardcoded in
# or from some key in the setup cache (.inf) file
# 
# $resp = $dialog->handleResponse($ans, $index);
# The dialog uses this method to perform validation of the input, set the value
# in the setup cache, display errors or warnings, and tell the dialog manager
# if the prompt needs to be redisplayed, or if there was an unrecoverable error
# $resp should be $SAME to reprompt, $ERR to abort, or $NEXT to continue
# the $ans and defaultAns should be in the native charset, so the dialog
# may have to convert to/from utf8 as needed.

# a dialog consists of a title, some explanatory text, and one or more prompts
# each prompt has a default value.  An example of a dialog with more than
# one prompt would be a dialog asking the user for the new root DN and password -
# in that case, there would be 3 prompts - one for the DN, one for the password,
# and one to verify the password
# The text and prompts are given as resource keys.  Usually the resource value
# will be a simple string, in which case the resource key is passed in as a simple
# string.  However, if the resource string contains replaceable parameters, the
# resource key is passed as an array ref consisting of the resource key as the
# first element and the parameters to use for replacement as the subsequent
# array elements e.g.
# $foo = new Dialog(['RESOURCE_KEY_CONFIG_LDAP_URL', $secure, $host, $port, $suffix], ...);
# but usually for simple cases like this:
# $foo = new Dialog('RESOURCE_KEY_WELCOME', ...);
# The manager contains the context for all of the dialogs - the setup type, the resource
# file, setup log, other context shared among the dialogs
# the type is the setup type - 1, 2, or 3 for express, typical, or custom
# type is used to say which types use this dialog
sub new {
    my $type = shift;
    my $self = {};

    $self->{type} = shift;
    $self->{text} = shift;
    $self->{defaultAns} = shift;
    $self->{handleResp} = shift;
    $self->{prompts} = \@_;

    $self = bless $self, $type;

    return $self;
}

sub setManager {
    my $self = shift;
    $self->{"manager"} = shift;
}

# returns true if this dialog is to be displayed for the current setup type
# false otherwise
sub isDisplayed {
    my $self = shift;

    return $self->{type} <= $self->{"manager"}->{type};
}

# each prompt looks like this:
# [ 'resource key', is pwd ]
# The resource key is the string key of the resource
# is pwd is optional - if present, the prompt is for a password
# and should not echo the answer
# e.g.
# ['RESOURCE_USERNAME'], ['RESOURCE_PASSWORD', 1], ['RESOURCE_PASSWORD_AGAIN', 1]
sub run {
    my $self = shift;
    my $resp = $DialogManager::SAME;

    # display the dialog text
    if ($self->isDisplayed()) {
        $self->{manager}->showText($self->{text});
    }

    # display each prompt for this dialog
    my $index = 0;
    my @prompts = @{$self->{prompts}};
    for (my $index = 0; $index < @prompts; ++$index) {
        my $prompt = $prompts[$index];
        my $defaultans = $self->{defaultAns}($self, $index);
        my $ans;
        if ($self->isDisplayed()) {
            $ans = $self->{manager}->showPrompt($prompt->[0], $defaultans, $prompt->[1]);
        } else {
            $ans = $defaultans;
        }

        # see if this is the special BACK response, and finish if so
        if ($self->{"manager"}->isBack($ans)) {
            $resp = $DialogManager::BACK;
            last;
        }

        # figure out what action to take based on the users response
        # this will set values in the setup info file
        # this will also validate input, and display errors if the
        # input is not correct - in that case, the resp will be
        # SAME to reprompt, or ERR if unrecoverable
        # NOTE: user cannot BACK from prompt to prompt - BACK
        # always means BACK to the previous dialog
        $resp = $self->{handleResp}($self, $ans, $index);
        if ($resp == $DialogManager::SAME) {
            if (!$self->isDisplayed()) {
                $self->{manager}->alert('dialog_use_different_type');
                $resp = $DialogManager::ERR;
            } else {
                $index--; # reprompt
            }
        } elsif ($resp == $DialogManager::ERR) {
            last;
        }
    }

    return $resp;
}

package DialogYesNo;

@ISA       = qw(Dialog);

sub new {
    my $type = shift;
    my $setuptype = shift;
    my $text = shift;
    my $defaultIsYes = shift;
    my $handler = shift || \&handleResponse;
    my $prompt = shift || ['prompt_yes_no'];
    my $self = Dialog->new($setuptype, $text,
                           \&defaultAns, $handler, $prompt);

    $self->{defaultIsYes} = $defaultIsYes;
    
    $self = bless $self, $type;

    return $self;
}

sub setDefaultYes {
    my $self = shift;
    $self->{default} = $self->{"manager"}->getText("yes");
}

sub setDefaultNo {
    my $self = shift;
    $self->{default} = $self->{"manager"}->getText("no");
}

sub defaultAns {
    my $self = shift;
    if (exists($self->{ans})) {
        return $self->{ans};
    }
    if (!exists($self->{default})) {
        if ($self->{defaultIsYes}) {
            $self->{default} = $self->{"manager"}->getText("yes");
        } else {
            $self->{default} = $self->{"manager"}->getText("no");
        }
    }
    return $self->{default};
}

sub isYes {
    my $self = shift;
    return $self->{ans} eq $self->{"manager"}->getText("yes");
}

sub handleResponse {
    my $self = shift;
    my $ans = shift;
    my $resp = $DialogManager::SAME;
    my $yes = $self->{"manager"}->getText("yes");
    my $nno = $self->{"manager"}->getText("no");

    # the regexp allows us to use y or ye or yes for "yes"
    if ($nno =~ /^$ans/) {
        $resp = $DialogManager::NEXT;
        $self->{ans} = $nno;
    } elsif ($yes =~ /^$ans/) {
        $resp = $DialogManager::NEXT;
        $self->{ans} = $yes;
    } else {
        $self->{"manager"}->alert("yes_no_error");
    }

    return $resp;
}

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


--- NEW FILE DialogManager.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

package DialogManager;
use Exporter ();
@ISA       = qw(Exporter);
@EXPORT    = qw($BACK $SAME $NEXT $ERR);
@EXPORT_OK = qw($BACK $SAME $NEXT $ERR);

use Dialog;
use SetupLog;

# Dialog responses
$BACK = -1;
$SAME = 0;
$NEXT = 1;
$ERR = 2;

# The DialogManager controls the flow of the dialogs and contains context shared
# among all of the dialogs (resources, logs, current setup type, etc.)
# all of these are optional
sub new {
    my $type = shift;
    my $self = {};

    $self->{setup} = shift;
    $self->{res} = shift;
    $self->{type} = shift;

    $self->{log} = $self->{setup}->{log};
    $self->{inf} = $self->{setup}->{inf};

    $self = bless $self, $type;

    return $self;
}

sub getType {
    my $self = shift;
    return $self->{type};
}

sub setType {
    my $self = shift;
    $self->{type} = shift;
}

sub addDialog {
    my $self = shift;
    for my $dialog (@_) {
        $dialog->setManager($self);
        push @{$self->{dialogs}}, $dialog;
    }
}

# see if the user answered with the special BACK answer
sub isBack {
    my $self = shift;
    my $ans = shift;

    # the word "back"
    if ($ans =~ /back/i) {
        return 1;
    }
    # a Ctrl-B sequence
    if ($ans eq '') {
        return 1;
    }

    return 0;
}

sub log {
    my $self = shift;
    if (!$self->{log}) {
        print @_;
    } else {
        $self->{log}->logMessage($INFO, "Setup", @_);
    }
}

sub getText {
    my $self = shift;
    return $self->{res}->getText(@_);
}

sub handleError {
    my $self = shift;
    my $msg = $self->{res}->getText('setup_err_exit');
    $self->{log}->logMessage($FATAL, "Setup", $msg);
}

sub showText {
    my $self = shift;
    my $msg = shift;
    my $text = $self->getText($msg);
    print "\n", ("=" x 78), "\n";
    # display it,
    print $text;
    # log it
    $self->log($text);
}

sub showPrompt {
    my $self = shift;
    my $msg = shift;
    my $defaultans = shift;
    my $ispwd = shift;

    my $text = $self->getText($msg);
    # display it,
    print $text;
    # log it
    $self->log($text . "\n");
    # display the default answer
    if ($defaultans) {
        print " [$defaultans]";
    }
    print ": ";
    # if we are prompting for a password, disable console echo
    if ($ispwd) {
        system("stty -echo");
    }
    # read the answer
    my $ans = <STDIN>;
    # if we are prompting for a password, enable console echo
    if ($ispwd) {
        system("stty echo");
        print "\n";
    }
    chop($ans); # trim trailing newline

    # see if this is the special BACK response, and finish if so
    if ($self->isBack($ans)) {
        $self->log("BACK\n");
        return $ans;
    }

    if (!length($ans)) {
        $ans = $defaultans;
    }

    # log the response, if not a password
    if (!$ispwd) {
        $self->log($ans . "\n");
    }

    return $ans;
}

sub alert {
    my $self = shift;
    my $msg = $self->{res}->getText(@_);
    print $msg;
    $self->{log}->logMessage($WARN, "Setup", $msg);
}

sub run {
    my $self = shift;
    my $done;
    my $index = 0;
    my $incr = 1;
    my $rc = 0;

    while (!$done) {
        my $dialog = $self->{dialogs}->[$index];
        my $resp = $NEXT;
        $resp = $dialog->run();
        if ($resp == $BACK) {
            $incr = -1;
        } elsif ($resp == $NEXT) {
            $incr = 1;
        } elsif ($resp == $SAME) {
            $incr = 0;
        } else {
            $self->handleError($resp);
            $done = 1;
            $rc = 1;
        }
        $index += $incr;
        if ($index < 0) {
            $index = 0;
        } elsif ($index >= @{$self->{dialogs}}) {
            $done = 1;
        }
    }

    return $rc;
}

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


--- NEW FILE Inf.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

# manages inf files - gets values
# given keys

package Inf;

#require    Exporter;
#@ISA       = qw(Exporter);
#@EXPORT    = qw();

sub new {
    my $type = shift;
    my $self = {};

    $self->{filename} = shift;

    $self = bless $self, $type;

    if ($self->{filename}) {
        $self->read();
    }

    return $self;
}

sub read {
# each key in the table is a section name
# the value is a hash ref of the items in that section
#   in that hash ref, each key is the config param name,
#   and the value is the config param value
    my $self = shift;
    my $filename = shift;
    my $curSection;

    if ($filename) {
        $self->{filename} = $filename;
    } else {
        $filename = $self->{filename};
    }

    open INF, $filename or die "Error: could not open inf file $filename: $!";
    while (<INF>) {
        # e.g. [General]
        if (/^\[(.*?)\]/) {
            $curSection = $1;
        } elsif (/^\s*$/) {
            next; # skip blank lines
        } elsif (/^\s*\#/) {
            next; # skip comment lines
        } elsif (/^\s*(.*?)\s*=\s*(.*?)\s*$/) {
            $self->{$curSection}->{$1} = $2;
        }
	}
    close INF;
}

sub section {
    my $self = shift;
    my $key = shift;

    if (!exists($self->{$key})) {
        print "Error: unknown inf section $key\n";
        return undef;
    }

    return $self->{$key};
}

sub writeSection {
    my $self = shift;
    my $name = shift;
    my $fh = shift;
    my $section = $self->{$name};
    if (ref($section) eq 'HASH') {
        print $fh "[$name]\n";
        for my $key (keys %{$section}) {
            if (defined($section->{$key})) {
                print $fh "$key = ", $section->{$key}, "\n";
            }
        }
    }
}

sub write {
    my $self = shift;
    my $filename = shift;

    if ($filename) {
        $self->{filename} = $filename;
    } else {
        $filename = $self->{filename};
    }

    open INF, ">$filename" or die "Error: could not write inf file $filename: $!";
    # write General section first
    $self->writeSection('General', \*INF);
    print INF "\n";
    for my $key (keys %{$self}) {
        next if ($key eq 'General');
        $self->writeSection($key, \*INF);
        print INF "\n";
    }
    close INF;
}

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


--- NEW FILE Resource.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

# manages resource bundle files - gets values
# given keys

package Resource;

use strict;

#require    Exporter;
#@ISA       = qw(Exporter);
#@EXPORT    = qw();

sub new {
    my $type = shift;
    my $self = {};

    $self->{filename} = shift;

    $self = bless $self, $type;

    if ($self->{filename}) {
        $self->read();
    }

    return $self;
}

sub read {
    my $self = shift;
    my $filename = shift;

    if ($filename) {
        $self->{filename} = $filename;
    } else {
        $filename = $self->{filename};
    }

    open RES, $filename or die "Error: could not open resource file $filename: $!";
    while (<RES>) {
        next if (/^\s*$/); # skip blank lines
        next if (/^\s*\#/); # skip comment lines
        # read name = value pairs like this
        # bol whitespace* name whitespace* '=' whitespace* value eol
        # the value will include any trailing whitespace
        if (/^\s*(.*?)\s*=\s*(.*?)$/) {
            $self->{res}->{$1} = $2;
            # replace \n with real newline
            $self->{res}->{$1} =~ s/\\n/\n/g;
        }
	}
    close RES;
}

# given a resource key and optional args, return the value
# $text = $res->getText('key');
# or
# $text = $res->getText('key', @args);
# or
# $text = $res->getText($arrayref)
# where $arrayref is ['key', @args]
sub getText {
    my $self = shift;
    my $key = shift;
    my @args = @_;

    if (ref($key) eq 'ARRAY') {
        my $tmpkey = shift @{$key};
        @args = @{$key};
        $key = $tmpkey;
    }

    if (!exists($self->{res}->{$key})) {
        print "Error: unknown resource key $key\n";
        return undef;
    }

    if (!defined($self->{res}->{$key})) {
        print "Error: resource key $key has no value\n";
        return undef;
    }

    # see if the args themselves are resource keys
    for (my $ii = 0; $ii < @args; ++$ii) {
        if (exists($self->{res}->{$args[$ii]})) {
            $args[$ii] = $self->{res}->{$args[$ii]};
        }
    }

    my $text = sprintf $self->{res}->{$key}, @args;

    return $text;
}

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


--- NEW FILE Setup.pm.in ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# 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);

# tempfiles
use File::Temp qw(tempfile tempdir);

# hostname
use Net::Domain qw(hostfqdn);

# 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 File::Temp qw(tempfile tempdir);

use SetupLog;

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

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

sub VersionMessage {
    print "@capbrand@ Directory Server Setup Program Version @PACKAGE_VERSION@\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
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 = {};
    my ($debuglevel, $silent, $inffile, $keep, $preonly, $logfile);
    my @otherargs;

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

    $self->{debuglevel} = $debuglevel;
    $self->{silent} = $silent;
    $self->{inffile} = $inffile;
    $self->{keep} = $keep;
    $self->{preonly} = $preonly;
    $self->{logfile} = $logfile;
    $self->{log} = new SetupLog($self->{logfile});
    if (!$self->{inffile}) {
        my ($fh, $filename) = tempfile("setupXXXXXX", UNLINK => !$keep,
                                       SUFFIX => ".inf", OPEN => 0,
                                       DIR => File::Spec->tmpdir);
        $self->{inffile} = $filename;
        $self->{inf} = new Inf;
        $self->{inf}->{filename} = $self->{inffile};
    } else {
        $self->{inf} = new Inf($self->{inffile});
        $self->{keep} = 1; # do not delete user supplied inf file
    }

    # 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
    for (@ARGV) {
        if (/^(\w+).(\w+)=(.*)$/) { # e.g. section.param=value
            $self->{inf}->{$1}->{$2} = $3;
        } else { # error
            print STDERR "Error: unknown command line option $_\n";
            usage();
            exit 1;
        }
    }

    $self->{configdir} = $ENV{DS_CONFIG_DIR} || "@instconfigdir@";

    $self = bless $self, $type;
    return $self;
}

# 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
sub msg {
    my $self = shift;
    my $level = shift;
    my @text = @_;
    if (!$level && @text) {
        # e.g. msg(0, "string") - no logging
    } elsif ($level and @text and grep {/^$level$/} $self->{log}->levels()) {
        # e.g. msg($WARN, "string") - print and log
    } else {
        # log at default INFO level
        unshift @text, $level;
        $level = $INFO;
    }
    if ($level) {
        $self->log($level, @text);
    }
    print @text;
}

sub doExit {
    my $self = shift;
    $self->msg($FATAL, "Exiting . . .\n");
    $self->msg("Log file is " . $self->{log}->{filename} . "\n");
	exit 1;
}

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


--- NEW FILE SetupDialogs.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

package SetupDialogs;

use strict;

use DialogManager;
use Setup;
use Dialog;
use Net::Domain qw(hostfqdn);

my $welcome = new DialogYesNo (
    $EXPRESS,
    ['dialog_welcome_text', 'brand', 'brand'],
    1,
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $self->handleResponse($ans);
        if ($res == $DialogManager::NEXT) {
            $res = $DialogManager::ERR if (!$self->isYes());
        }
        return $res;
    },
    ['dialog_welcome_prompt'],
);

my $license = new DialogYesNo (
    $EXPRESS,
    'dialog_license_text',
    0,
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $self->handleResponse($ans);
        if ($res == $DialogManager::NEXT) {
            $res = $DialogManager::ERR if (!$self->isYes());
        }
        return $res;
    },
    ['dialog_license_prompt']
);

my $setuptype = new Dialog (
    $EXPRESS,
    'dialog_setuptype_text',
    sub {
        my $self = shift;
        return $self->{manager}->getType();
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $DialogManager::SAME;
        if ($ans < $EXPRESS or $ans > $CUSTOM) {
            $self->{manager}->alert("dialog_setuptype_error");
        } else {
            $res = $DialogManager::NEXT;
            $self->{manager}->setType($ans);
        }
        return $res;
    },
    ['dialog_setuptype_prompt']
);

my $hostdlg = new Dialog (
    $TYPICAL,
    'dialog_hostname_text',
    sub {
        my $self = shift;
        return $self->{manager}->{inf}->{General}->{FullMachineName} ||
            hostfqdn;
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $res = $DialogManager::NEXT;
        if ($ans !~ /\./) {
            $self->{manager}->alert("dialog_hostname_warning", $ans);
        }
        $self->{manager}->{inf}->{General}->{FullMachineName} = $ans;
        return $res;
    },
    ['dialog_hostname_prompt']
);

# must verify that the user or uid specified by the user to run the server as
# is a valid uid
sub verifyUserChoice {
    my $self = shift;
    my $ans = shift;
    my $res = $DialogManager::NEXT;
    # convert numeric uid to string
    my $strans = $ans;
    if ($ans =~ /^\d/) { # numeric - convert to string
        $strans = getpwuid $ans;
        if (!$strans) {
            $self->{manager}->alert("dialog_ssuser_error", $ans);
            return $DialogManager::SAME;
        }
    }
    if ($> != 0) { # if not root, the user must be our uid
        my $username = getlogin;
        if ($strans ne $username) {
            $self->{manager}->alert("dialog_ssuser_must_be_same", $username);
            return $DialogManager::SAME;
        }
    } else { # user is root - verify id
        my $nuid = getpwnam $strans;
        if (!defined($nuid)) {
            $self->{manager}->alert("dialog_ssuser_error", $ans);
            return $DialogManager::SAME;
        }
        if (!$nuid) {
            $self->{manager}->alert("dialog_ssuser_root_warning");
        }
    }
    $self->{manager}->{inf}->{General}->{SuiteSpotUserID} = $ans;
    return $res;
}

# must verify that the given group is one of the groups the given user
# belongs to
sub verifyGroupChoice {
    my $self = shift;
    my $ans = shift;
    my $res = $DialogManager::NEXT;
    my ($dummy, $memstr);
    my $strgrp;
    my $numgrp;
    if ($ans =~ /^\d/) { # numeric
        $numgrp = $ans;
        ($strgrp, $dummy, $dummy, $memstr) = getgrgid $ans;
    } else {
        $strgrp = $ans;
        ($dummy, $dummy, $numgrp, $memstr) = getgrnam $ans;
    }

    if (!defined($strgrp) or !defined($numgrp)) {
        $self->{manager}->alert("dialog_ssgroup_error", $ans);
        return $DialogManager::SAME;
    }

    # get the user id, and then get the user's default group id
    my $uid = $self->{manager}->{inf}->{General}->{SuiteSpotUserID};
    my $usergid;
    if ($uid =~ /^\d/) { # numeric
        ($uid, $dummy, $dummy, $usergid, $dummy) = getpwuid $uid;
    } else { # string
        ($uid, $dummy, $dummy, $usergid, $dummy) = getpwnam $uid;
    }

    if ($numgrp == $usergid) {
        $self->{manager}->{inf}->{General}->{SuiteSpotGroup} = $ans;
    } elsif ($memstr) { # see if the user is in the member list
        if ($memstr =~ /\b$uid\b/) { # uid exactly matches one of the users in the member string
            $self->{manager}->{inf}->{General}->{SuiteSpotGroup} = $ans;
        } else { # no match
            $self->{manager}->alert("dialog_ssgroup_no_match",
                                   $self->{manager}->{inf}->{General}->{SuiteSpotUserID},
                                   $ans, $memstr);
            $res = $DialogManager::SAME;
        }
    } else { # user not in group
        $self->{manager}->alert("dialog_ssgroup_no_user",
                                $self->{manager}->{inf}->{General}->{SuiteSpotUserID},
                                $ans);
        $res = $DialogManager::SAME;
    }
    return $res;
}

my $usergroup = new Dialog (
    $TYPICAL,
    'dialog_ssuser_text',
    sub {
        my $self = shift;
        my $index = shift;
        if ($index == 0) {
            my $username = $self->{manager}->{inf}->{General}->{SuiteSpotUserID};
            if (!$username) {
                if ($> == 0) { # if root, use the default user
                    $username = "\@defaultuser\@";
                } else { # if not root, use the user's uid
                    $username = getlogin;
                }
            }
            return $username;
        } else { # group
            my $groupname = $self->{manager}->{inf}->{General}->{SuiteSpotGroup};
            if (!$groupname) {
                if ($> == 0) { # if root, use the default group
                    $groupname = "\@defaultgroup\@";
                } else { # if not root, use the user's gid
                    $groupname = getgrgid $(;
                }
            }
            return $groupname;
        }
    },
    sub {
        my $self = shift;
        my $ans = shift;
        my $index = shift;
        if ($index == 0) {
            return verifyUserChoice($self, $ans);
        } else {
            return verifyGroupChoice($self, $ans);
        }
    },
    ['dialog_ssuser_prompt'], ['dialog_ssgroup_prompt']
);


sub getDialogs {
    return ($welcome, $license, $setuptype, $hostdlg, $usergroup);
}

1;


--- NEW FILE SetupLog.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#
# This implements SetupLog from setuputil InstallLog in perl
#
package SetupLog;
use Exporter ();
@ISA       = qw(Exporter);
@EXPORT    = qw($FATAL $START $SUCCESS $WARN $INFO $DEBUG);
@EXPORT_OK = qw($FATAL $START $SUCCESS $WARN $INFO $DEBUG);

use POSIX qw(strftime);

# tempfiles
use File::Temp qw(tempfile tempdir);

# exported variables
$FATAL    = "Fatal";
$START    = "Start";
$SUCCESS  = "Success";
$WARN     = "Warning";
$INFO     = "Info";
$DEBUG    = "Debug";

sub new {
    my $type = shift;
    my $filename = shift;
    my $self = {};
    my $fh;

    if (!$filename) {
        ($fh, $filename) = tempfile("setupXXXXXX", UNLINK => 0,
                                    SUFFIX => ".log", DIR => File::Spec->tmpdir);
    } else {
        open LOGFILE, ">$filename" or die "Error: could not open logfile $filename: $!";
        $fh = \*LOGFILE;
    }
    $self->{fh} = $fh;
    $self->{filename} = $filename;
    $self = bless $self, $type;

    return $self;
}

sub logMessage {
    my ($self, $level, $who, $msg, @rest) = @_;
    if (!$self->{fh}) {
        return;
    }

    my $string = strftime "[%y/%m/%d:%H:%M:%S] - ", localtime;
    $string .= "[$who] $level ";
    $string .= sprintf $msg, @rest;
    print { $self->{fh} } $string;
}

sub levels {
    my $self = shift;
    return ($FATAL, $START, $SUCCESS, $WARN, $INFO, $DEBUG);
}

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


--- NEW FILE Util.pm ---
# 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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

package Util;
require Exporter;
@ISA       = qw(Exporter);
@EXPORT    = qw(portAvailable getAvailablePort isValidDN);
@EXPORT_OK = qw(portAvailable getAvailablePort isValidDN);

use strict;

use Socket;

# return true if the given port number is available, false otherwise
sub portAvailable {
    my $port = shift;
    my $proto = getprotobyname('tcp');
    my $rc = socket(SOCK, PF_INET, SOCK_STREAM, $proto);
    if ($rc == 1) {
        $rc = bind(SOCK, sockaddr_in($port, INADDR_ANY));
    }
    close(SOCK);
    return $rc and ($rc == 1);
}

# returns a randomly assigned port number, or -1
# if not able to find an available port
sub getAvailablePort {
    my $MINPORT = 1024;
    my $MAXPORT = 65535;

    srand( time() ^ ($$ + ($$ << 15)) );
    while (1) {
        my $port = $MINPORT + int(rand($MAXPORT-$MINPORT));

        if (portAvailable($port)) {
            return $port;
        }
    }
}

sub isValidDN {
    my $dn = shift;
    return ($dn =~ /^[0-9a-zA-Z_-]+=.*$/);
}

1;


--- NEW FILE setup-ds.pl.in ---
#!/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.
# 
# In addition, as a special exception, Red Hat, Inc. gives You the additional
# right to link the code of this Program with code not covered under the GNU
# General Public License ("Non-GPL Code") and to distribute linked combinations
# including the two, subject to the limitations in this paragraph. Non-GPL Code
# permitted under this exception must only link to the code of this Program
# through those well defined interfaces identified in the file named EXCEPTION
# found in the source code files (the "Approved Interfaces"). The files of
# Non-GPL Code may instantiate templates or use macros or inline functions from
# the Approved Interfaces without causing the resulting work to be covered by
# the GNU General Public License. Only Red Hat, Inc. may make changes or
# additions to the list of Approved Interfaces. You must obey the GNU General
# Public License in all respects for all of the Program code and other code used
# in conjunction with the Program except the Non-GPL Code covered by this
# exception. If you modify this file, you may extend this exception to your
# version of the file, but you are not obligated to do so. If you do not wish to
# provide this exception without modification, you must delete this exception
# statement from your version and license this file solely under the GPL without
# exception. 
# 
# 
# Copyright (C) 2007 Red Hat, Inc.
# All rights reserved.
# END COPYRIGHT BLOCK
#

use lib '@perldir@';

use strict;

use Setup;
use Inf;
use Resource;
use DialogManager;

my $setup = new Setup;

if (!$setup->{silent}) {
    my $res = new Resource("@propertydir@/setup-ds.res");
    my $dialogmgr = new DialogManager($setup, $res, $TYPICAL);

    require SetupDialogs;
    require DSDialogs;

    my @dialogs = SetupDialogs->getDialogs();
    push @dialogs, DSDialogs->getDialogs();

    $dialogmgr->addDialog(@dialogs);

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

system("@bindir@/ds_newinst.pl $setup->{inffile}");
if (!$setup->{keep}) {
    unlink $setup->{inffile};
}

$setup->doExit();


--- NEW FILE setup-ds.res.in ---
# ------------ Global Resources -----------
brand = @capbrand@
yes = yes
no = no
yes_no_error = Please answer "yes" or "no"\n\n
setup_err_exit = Setup cannot proceed.  Exiting.\n\n
dialog_use_different_type = When using Silent or Express mode, some of the\ndialogs are skipped, but validation is still performed\non the default or given answers.  You should run this program again and\nchoose Typical or Custom mode in order to provide a valid input\nfor the problem dialog.\n\n

# ------------ Welcome Dialog Resource ------------
dialog_welcome_text = This program will setup the %s Directory Server.\n\nIt is recommended that you have "root" privilege to setup the software.\nTips for using this  program:\n  - Press "Enter" to choose the default and go to the next screen\n  - Type "Control-B" then "Enter" to go back to the previous screen\n  - Type "Control-C" to cancel the setup program\n  - You can enter multiple items using commas to separate them.\n    For example: 1, 2, 3 \n\n
# %s -> brand

dialog_welcome_prompt = Would you like to continue with setup?

# ----------- License Dialog Resource  -----------
dialog_license_text = BY SETTING UP AND USING THIS SOFTWARE YOU ARE CONSENTING TO BE BOUND BY\nAND ARE BECOMING A PARTY TO THE AGREEMENT FOUND IN THE\nLICENSE.TXT FILE. IF YOU DO NOT AGREE TO ALL OF THE TERMS\nOF THIS AGREEMENT, PLEASE DO NOT SETUP OR USE THIS SOFTWARE.\n\n

dialog_license_prompt = Do you agree to the license terms?


# ----------- Setup Type Dialog Resource  ----------------
dialog_setuptype_text = Choose a setup type:\n\n   1. Express\n       Allows you to quickly setup the servers using the most\n       common options and pre-defined defaults. Useful for quick\n       evaluation of the products.\n\n   2. Typical\n       Allows you to specify common defaults and options.\n\n   3. Custom\n       Allows you to specify more advanced options. This is \n       recommended for experienced server administrators only.\n\nTo accept the default shown in brackets, press the Enter key.\n\n

dialog_setuptype_prompt = Choose a setup type

dialog_setuptype_error = Invalid setup type\n\n


# ----------- HostName Dialog Resource  ----------------
dialog_hostname_text = Enter the fully qualified domain name of the computer\non which you're setting up server software. Using the form\n<hostname>.<domainname>\nExample: eros.example.com.\n\nTo accept the default shown in brackets, press the Enter key.\n\n

dialog_hostname_prompt = Computer name

dialog_hostname_warning = The hostname %s does not look like a\nfully qualified host and domain name.\nIf you feel you have made a mistake,\nplease go back to this dialog and enter another name.\n\n

# ----------- SSUser Dialog Resource  ----------------
dialog_ssuser_text = The server must run as a specific user in a specific group.\nIt is strongly recommended that this user should have no privileges\non the computer (i.e. a non-root user).  The Administration Server\nwill give this user/group some permissions in specific paths/files\nto perform server-specific operations.\n\nIf you have not yet created a user and group for the server,\ncreate this user and group using your native operating\nsystem utilities.\n\n

dialog_ssuser_prompt = System User
dialog_ssuser_error = The user '%s' is invalid.\n\n
dialog_ssuser_must_be_same = Since you are not running setup as root, the System User must be the same as your userid '%s'.\n\n
dialog_ssuser_root_warning = You are strongly discouraged to use a non-root user for the server uid.\nIf you feel you have made a mistake,\nplease go back to this dialog and enter another system user.\n\n
dialog_ssgroup_prompt = System Group
dialog_ssgroup_error = The group '%s' is invalid.\n\n
dialog_ssgroup_no_match = The system user '%s' does not belong to the group '%s'.\n\nThis is the list of users of the given group: %s\n\n
dialog_ssgroup_no_user = The system user '%s' does not belong to the group '%s'.\n\n

# ----------- DS port Dialog Resource  ----------------
dialog_dsport_text = The standard directory server network port number is 389.  However, if\nyou are not logged as the superuser, or port 389 is in use, the\ndefault value will be a random unused port number greater than 1024.\nIf you want to use port 389, make sure that you are logged in as the\nsuperuser, that port 389 is not in use.\n\n
dialog_dsport_prompt = Directory server network port
dialog_dsport_error = The port %s is in use or not available.  Please choose another port.\n\n

# ----------- DS server ID Dialog Resource  ----------------
dialog_dsserverid_text = Each instance of a directory server requires a unique identifier.\nThis identifier is used to name the various\ninstance specific files and directories in the file system,\nas well as for other uses as a server instance identifier.\n\n
dialog_dsserverid_prompt = Directory server identifier
dialog_dsserverid_error = The server identifier '%s' is not valid.  Please choose another one.\n\n
dialog_dsserverid_inuse = The server identifier '%s' is already in use.  Please choose another one.\n\n

# ----------- DS suffix Dialog Resource  ----------------
dialog_dssuffix_text = The suffix is the root of your directory tree.  The suffix must be a valid DN.\nIt is recommended that you use the dc=domaincomponent suffix convention.\nFor example, if your domain is example.com,\nyou should use dc=example,dc=com for your suffix.\nSetup will create this initial suffix for you,\nbut you may have more than one suffix.\nUse the directory server utilities to create additional suffixes.\n\n
dialog_dssuffix_prompt = Suffix
dialog_dssuffix_error = The suffix '%s' is not a valid DN.  Please choose another one.\n\n

# ----------- DS Root DN and password Dialog Resource  ----------------
dialog_dsrootdn_text = Certain directory server operations require an administrative user.\nThis user is referred to as the Directory Manager and typically has a\nbind Distinguished Name (DN) of cn=Directory Manager.\nYou will also be prompted for the password for this user.  The password must\nbe at least 8 characters long, and contain no spaces.\n\n
dialog_dsrootdn_prompt = Directory Manager DN
dialog_dsrootdn_error = The input '%s' is not a valid DN.  Please choose another one.\n\n
dialog_dsrootpw_prompt1 = Password
dialog_dsrootpw_prompt2 = Password (again)
dialog_dsrootpw_invalid = The password contains invalid characters.  Please choose another one.\n\n
dialog_dsrootpw_tooshort = The password must be at least %s characters long.  Please choose another one.\n\n
dialog_dsrootpw_nomatch = The passwords do not match.  Please try again.\n\n

# ----------- DS Sample Data Dialog Resource  ----------------
dialog_dssample_text = You may install some sample entries in this directory instance.  These\nentries will be installed in a separate suffix and will not interfere\nwith the normal operation of the directory server.\n\n
dialog_dssample_prompt = Do you want to install the sample entries?

# ----------- DS Populate Data Dialog Resource  ----------------
dialog_dspopulate_text = You may wish to populate your new directory instance with some data.\n"You may already have a file in LDIF format to use or some suggested\nentries can be added.  If you want to import entries from an LDIF\nfile, you may type in the full path and filename at the prompt.  If\nyou want the setup program to add the suggested entries, type the\nword suggest at the prompt.  The suggested entries are common\ncontainer entries under your specified suffix, such as ou=People and\nou=Groups, which are commonly used to hold the entries for the persons\nand groups in your organization.  If you do not want to add any of\nthese entries, type the word none at the prompt.\n\n
dialog_dspopulate_prompt = Type the full path and filename, the word suggest, or the word none
dialog_dspopulate_error = The file '%s' was not found.  Please choose another one.\n\n




More information about the Fedora-directory-commits mailing list