#!/usr/bin/perl -wT

#----------------------------------------------------------------------
# copyright (C) 1999-2003 Mitel Networks Corporation
#
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# 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
#
# Technical support for this program is available from Mitel Networks
# Please visit our web site www.mitel.com/sme/ for details.
#----------------------------------------------------------------------
package esmith::console;

use strict;

use POSIX;
use Locale::gettext;
use Errno;
use esmith::util;
use esmith::util::network qw(:all);
use esmith::ethernet;
use esmith::db;
use esmith::ConfigDB;
use esmith::HostsDB;
use esmith::NetworksDB;
use esmith::I18N;
use esmith::console;
use Net::IPv4Addr qw(ipv4_network);

use constant TRUE  => 1;
use constant FALSE => 0;

my $console = esmith::console->new();
my %menu2object = build_menu();
my $modprobe = '/sbin/modprobe';

# Override STORE and DELETE functions in esmith::config to provide
# UnsavedChanges automatically
{
    package esmith::config::unsaved;
    require esmith::config;
    @esmith::config::unsaved::ISA = qw(esmith::config);

    sub STORE {
        my ($self, $key, $value) = @_;

        # The 'UnsavedChanges' entry is automatically set to 'yes'
        # when a system parameter is changed. This means that there
        # are changes to the main e-smith configuration file which
        # need to be 'saved' (i.e.  all of the e-smith config files
        # must be updated). However, don't do anything automatic if
        # the caller is deliberately trying to set the UnsavedChanges
        # flag. (That's how they can reset it.)

        return undef if ($self->EXISTS($key) and $self->FETCH($key) eq $value);

        if (($self->filename eq '/home/e-smith/configuration')
            && ($key ne 'UnsavedChanges')) {
            $self->SUPER::STORE('UnsavedChanges', 'yes');
        }

        return $self->SUPER::STORE($key, $value);
    }
    # Deleting a record is the same as changing one
    sub DELETE {
        my ($self, $key) = @_;
        if ($self->EXISTS($key)) {
            $self->SUPER::STORE('UnsavedChanges', 'yes');
        }
        return $self->SUPER::DELETE($key);
    }

}

sub displayManager();
sub displaySupport();
sub displayStatus();
sub ethernetManual($);
sub ethernetSelect($$);
sub isValidIP($);
sub rebootShutdown();
sub testInternet();

my $release = esmith::util::determineRelease();
my $release_string = "SME Server ${release}";

BEGIN
{
    # Set PATH explicitly and clear related environment variables so that calls
    # to external programs do not cause results to be tainted. See
    # "perlsec" manual page for details.

    $ENV {'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin';
    $ENV {'SHELL'} = '/bin/bash';
    delete $ENV {'ENV'};
    delete $ENV {'BASH_ENV'};
}

esmith::util::setRealToEffective ();

my $i18n = new esmith::I18N;
$i18n->setLocale("server-console");

my %conf;
tie %conf, 'esmith::config::unsaved';

my $rebootRequired = "no";

#------------------------------------------------------------
# Set stdin, stdout and stderr to console
#------------------------------------------------------------

my $tty = 'tty';

if (defined $ARGV [0])
{
    $ARGV[0] =~ /(console|tty\d*)/ && -c "/dev/$1"
        or die gettext("Bad ttyname:"), " ", $ARGV[0], "\n";
    $tty = $1;
}

open (STDIN,  "</dev/$tty") or die gettext("Can't redirect stdin"),  ": $!\n";
open (STDOUT, ">/dev/$tty") or die gettext("Can't redirect stdout"), ": $!\n";

my $pid = open(STDERR, "|-");
die gettext("Can't fork"), ": $!\n" unless defined $pid;

unless ($pid)
{
    exec qw(/usr/bin/logger -p local1.info -t console);
}

my $rc;
my $choice;

#-------------------------------------------------------------
# If this is not the bootstrap-console, go to the real console
#-------------------------------------------------------------

my $bootstrapConsole =
    db_get_prop(\%conf, "bootstrap-console", "Run") || "no";
unless ($bootstrapConsole eq "yes")
{
    goto INITIAL;
}

#-------------------------------------------------------------
# OK, this is the bootstrap-console - check whether a backup
# in process and incomplete
#-------------------------------------------------------------
my %restore_state;
tie %restore_state, 'esmith::config::unsaved', '/etc/e-smith/restore';

my $restore_state = db_get_prop(\%restore_state, 'restore', 'state')
    || 'idle';

if ($restore_state eq 'running')
{
 INCOMPLETE_RESTORE:
    ($rc, $choice) = $console->message_page
        (
         title => gettext("Inconsistent system state"),
         text  =>
         gettext("********** Inconsistent system state detected ***********") .
         "\n\n" .
         gettext("The restoration of a system backup was running and incomplete at the time of the last reboot. The system should not be used in this state.") .
         "\n\n" .
         gettext("Consult the User Guide for further instructions."),
        );

    ($rc, $choice) = $console->yesno_page
        (
         title => gettext("System will be halted"),
         text  =>
         gettext("The server will now be halted.") .
         "\n\n" .
         gettext("Consult the User Guide for recovery instructions.") .
         "\n\n" .
         gettext("Do you wish to halt the system right now?"),
        );

    goto INITIAL unless ($rc == 0);

    system("/usr/bin/tput", "clear");
    system("/sbin/e-smith/signal-event", "halt");

    # A bit of a hack to avoid the console restarting before the
    # reboot takes effect.

    sleep(600);
}
untie %restore_state;

#---------------------------------------------------------------
# Check whether the password is set, and if so, check for what
# to do next ...
#---------------------------------------------------------------

if ($conf {'PasswordSet'} eq 'yes')
{

    my $forceSave =
        db_get_prop(\%conf, "bootstrap-console", "ForceSave") || "no";

    if ($forceSave eq "yes")
    {
        goto SAVE_CONFIG;
    }
    else
    {
        goto INITIAL;
    }
}

#------------------------------------------------------------
INITIAL_PASSWORD:
#------------------------------------------------------------

{
    my $choice1;
    my $choice2;

    ($rc, $choice1) = $console->password_page
        (
         title => $release_string,
         text  =>
         gettext("Welcome to the server console!") .
         "\n\n" .
         gettext("You will now be taken through a sequence of screens to perform basic networking configuration on this server.") .
         "\n\n" .
         gettext("You can make your selections in each screen using the Arrow and Tab keys. At any point, if you select Back you will be returned to the previous screen.") .
         "\n\n" .
         gettext("Before you start, you must first choose the administrator password for your system and enter it below. You will not see the password as you enter it."),
        );

    unless ($rc == 0)
    {
        ($rc, $choice) = $console->message_page
            (
             title   => gettext("Administrator password not set"),
             text    => gettext("Sorry, you must set the administrator password now."),
            );

        goto INITIAL_PASSWORD;
    }

    unless ($choice1 =~ /^([ -~]+)$/)
    {
        ($rc, $choice) = $console->message_page
            (
             title   => gettext("Unprintable characters in password"),
             text    => gettext("The password must contain only printable characters."),
            );

        goto INITIAL_PASSWORD;
    }


    ($rc, $choice2) = $console->password_page
        (
         title   => $release_string,
         text    => gettext("Please type your administrator password again to verify."),
        );

    unless ($rc == 0)
    {
        ($rc, $choice) = $console->message_page
            (
             title => gettext("Administrator password not set"),
             text  => gettext("Sorry, you must set the administrator password now."),
            );

        goto INITIAL_PASSWORD;
    }

    if ($choice1 ne $choice2)
    {
        ($rc, $choice) = $console->message_page
            (
             title => gettext("Passwords do not match"),
             text  => gettext("The two passwords did not match"),
            );

        goto INITIAL_PASSWORD;
    }

    use Crypt::Cracklib;

    #--------------------------------------------------------
    # These are just to ensure that xgettext knows about the
    # Cracklib strings.
    # Note the extra space here and in the gettext call below. This
    # allows the French localization to properly generate qu'il
    gettext(" it is based on your username");
    gettext(" it is based upon your password entry");
    gettext(" it is derived from your password entry");
    gettext(" it is derivable from your password entry");
    gettext(" it is too short");
    gettext(" it is all whitespace");
    gettext(" it is too simplistic/systematic");
    gettext(" it is based on a dictionary word");
    gettext(" it is based on a (reversed) dictionary word");
    #--------------------------------------------------------

    my $reason = fascist_check($choice1, '/usr/lib/cracklib_dict');
    $reason ||= gettext("Software error: password check failed");
    unless ($reason eq 'ok')
    {
        ($rc, $choice) = $console->yesno_page
            (
             title => gettext("Bad Password Choice"),
             text  =>
             gettext("The password you have chosen is not a good choice, because") .
             gettext( " $reason" ) . "." .
             "\n\n" .
             gettext("Do you wish to choose a better one?"),
            );

        goto INITIAL_PASSWORD if ($rc == 0);
    }

    #--------------------------------------------------
    # Set system password
    #--------------------------------------------------

    esmith::util::setUnixSystemPassword ($choice1);
    esmith::util::setServerSystemPassword ($choice1);

    my $old = $conf {'UnsavedChanges'};
    $conf {'PasswordSet'} = 'yes';
    $conf {'UnsavedChanges'} = $old;

    my $forceSave =
        db_get_prop(\%conf, "bootstrap-console", "ForceSave") || "no";

    if ($forceSave eq "yes")
    {
        # System has been reinstalled from re-install floppy - skip
        # the reconfiguration
        db_set_prop(\%conf, "bootstrap-console", "ForceSave", "no");
        goto SAVE_CONFIG;
    }
    else
    {
        goto CONFIGURE_MAIN;
    }
}

#------------------------------------------------------------
INITIAL:
#------------------------------------------------------------

{
    #----------------------------------------
    # Untie and retie the configuration to force
    # the parameters to be refreshed from the file.
    #----------------------------------------

    untie %conf;
    tie %conf, 'esmith::config::unsaved';

    my @args = ();

    foreach my $key (sort keys %menu2object)
    {
	push @args, $key, gettext($menu2object{$key}->name);
    }

    my $title = gettext("Server console");
    $title .= " ($conf{SystemName}.$conf{DomainName})";

    $title .= " " . gettext("** unsaved changes **")
        if ( $conf {'UnsavedChanges'} eq 'yes' );

    ($rc, $choice) = $console->menu_page
        (
         title => $title,
         text  =>
         gettext("Welcome to the server console!") .
         "\n\n" .
         gettext("Use the Arrow and Tab keys to make your selection, then press Enter."),
         argsref => \@args,
         left    => gettext("Exit"),
        );

    unless ($rc == 0)
    {
        goto QUIT;
    }

    $menu2object{$choice}->doit;

    goto INITIAL;
}

#------------------------------------------------------------
CONFIGURE_INTRO:
#------------------------------------------------------------

{
    #----------------------------------------
    # Untie and retie the configuration to force
    # the parameters to be refreshed from the file.
    #----------------------------------------
    untie %conf;
    tie %conf, 'esmith::config::unsaved';

    my $old = $conf {'UnsavedChanges'};
    db_set_prop(\%conf, 'sysconfig', 'PreviousSystemMode', $conf{SystemMode});
    $conf {'UnsavedChanges'} = $old;

    ($rc, $choice) = $console->yesno_page
        (
         title   => gettext("Configure this server"),
         text =>
         gettext("You will now be taken through a sequence of screens to perform basic networking configuration on this server.") .
         "\n\n" .
         gettext("These configuration steps are usally performed once. Routine system administration tasks such as adding users and printers can then be performed from your desktop using a web browser.") .
         "\n\n" .
         gettext("You can make your selections in each screen using the Arrow and Tab keys. At any point, if you select Back you will be returned to the previous screen.") .
         "\n\n" .
         gettext("Do you wish to proceed?"),
        );

    if ($rc == 0) {
	if($conf{'PasswordSet'} eq 'yes')
	{
            goto CONFIGURE_MAIN;
	}
	else
	{
	    goto INITIAL_PASSWORD;
	}
    }

    goto INITIAL;
}

#------------------------------------------------------------
# The configuration takes the user through a sequence of
# screens. There are several major sections which are visited in
# sequence:
#
# 1. Configure ethernet drivers
# 2. Configure operation mode (Internet access, etc.)
# 3. Configure local network information (DHCP server, IP addresses,
#    clear leases, etc.)
# 4. Configure domain (domain and system name, DNS information), proxy, status
#    reports
#------------------------------------------------------------

#------------------------------------------------------------
CONFIGURE_MAIN:
#------------------------------------------------------------
if (! $console->run_screens( "CONFIGURE_MAIN" ))
{
    goto INITIAL;
}

# Refresh the %conf hash.
untie %conf;
tie %conf, 'esmith::config::unsaved';

#------------------------------------------------------------
DOMAIN_NAME:
#------------------------------------------------------------
{
    ($rc, $choice) = $console->input_page
        (
         title   => gettext("Primary domain name"),
         text    =>
         gettext("Please enter the primary domain name for your server.") .
         "\n\n" .
         gettext("This will be the default domain for your e-mail and web server. Virtual domains can be added later using the server manager."),
         value   => $conf {'DomainName'}
        );

    goto INITIAL unless ($rc == 0);

    if ($choice)
    {
        if ($choice =~ /^[a-zA-Z0-9\-\.]+$/)
        {
            $conf {'DomainName'} = lc($choice);
            goto SYSTEM_NAME;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title  => gettext("Invalid domain name"),
         choice => $choice,
        );

    goto DOMAIN_NAME;
}

#------------------------------------------------------------
SYSTEM_NAME:
#------------------------------------------------------------

{
    my $oldSystemName = $conf{'SystemName'};

    $oldSystemName = '' if ($oldSystemName eq 'server');

    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select system name"),
         text  =>
         gettext("Please enter the system name for your server.") .
         "\n\n" .
         gettext("You should select unique system names for each server.") .
         "\n\n" .
         gettext("The system name must start with a letter and can be composed of  letters, numbers and hyphens."),
         value   => $oldSystemName
        );

    goto DOMAIN_NAME unless ($rc == 0);

    if ($choice)
    {
        if (($choice =~ /^[a-zA-Z][a-zA-Z0-9\-]*$/)
            and ( $choice ne 'server' )) {
            $conf{'SystemName'} =  lc($choice);

            #------------------------------------------------------------
            # Default the SambaServerName to the SystemName, but only
            # change it if someone changes the SystemName here. This allows
            # the default to be overridden in the Workgroup panel.
            #------------------------------------------------------------
            unless ( $conf{'SystemName'} eq $oldSystemName )
            {
                db_set_prop(\%conf, 'smb', 'ServerName', "$choice");

                my $hosts = esmith::HostsDB->open;
                $hosts->propogate_hosts($oldSystemName, $conf{SystemName});
            }
            goto ETHERNET_LOCAL;
        }

    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid system name"),
         choice  => $choice,
        );

    goto SYSTEM_NAME;
}

# Display a dialog about how the module failed to load.
sub failed_to_load
{
    my $driver = shift;
    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("The specified driver failed to load."),
         choice  => $driver
        );
}

#------------------------------------------------------------
ETHERNET_LOCAL:
#------------------------------------------------------------

{
    my $selectMode = ethernetSelect('local', 'EthernetDriver1');

    goto ETHERNET_LOCAL     if ($selectMode eq 'CANCEL_MANUAL');

    goto SYSTEM_NAME        if ($selectMode eq 'CANCEL');

    if ($selectMode eq 'NOLOAD')
    {
        failed_to_load($conf{EthernetDriver1});
        goto ETHERNET_LOCAL;
    }

    goto LOCAL_IP           if ($selectMode eq 'CHANGE');

    goto LOCAL_IP           if ($selectMode eq 'KEEP');
}

#------------------------------------------------------------
LOCAL_IP:
#------------------------------------------------------------

{
    unless ($conf{'LocalIP'})
    {
        $conf {'LocalIP'} = '192.168.' . (int(rand(248)) + 2) . '.1';
    }

    ($rc, $choice) = $console->input_page
        (
         title => gettext("Local networking parameters"),
         text  =>
         gettext("Please enter the local IP address for this server.") .
         "\n\n" .
         gettext("If this server is the first machine on your network, we recommend accepting the default value unless you have a specific reason to choose something else.") .
         "\n\n" .
         gettext("If your server is being installed into an existing network, you must choose an address which is not in use by any other computer on this network."),
         value   => $conf {'LocalIP'}
        );

    goto ETHERNET_LOCAL unless ($rc == 0);

    if ($choice)
    {
        if (isValidIP($choice))
        {
            $choice = cleanIP($choice);
            if ($choice ne $conf {'LocalIP'})
            {
                $conf {'LocalIP'} = $choice;
            }
            goto LOCAL_NETMASK;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid local IP address"),
         choice  => $choice,
        );
    goto LOCAL_IP;
}

#------------------------------------------------------------
LOCAL_NETMASK:
#------------------------------------------------------------

{
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select local subnet mask"),
         text  =>
         gettext("Please enter the local subnet mask for this server.") .
         "\n\n" .
         gettext("If this server is the first machine on your network, we recommend using the default unless you have a specific reason to choose something else.") .
         "\n\n" .
         gettext("If your server is being installed into an existing network, you must choose the same subnet mask used by other computers on this network."),
         value   => $conf {'LocalNetmask'}
        );

    goto LOCAL_IP unless ($rc == 0);

    if ($choice)
    {
        if ( isValidIP($choice) )
        {
            $choice = cleanIP($choice);
            # Update primary record
            $conf {'LocalNetmask'} = $choice;
            goto SYSTEM_MODE;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid local subnet mask"),
         choice  => $choice,
        );

    goto LOCAL_NETMASK;
}

#------------------------------------------------------------
SYSTEM_MODE:
#------------------------------------------------------------

{
    my $currentmode;
    my $currentnumber;

    if ($conf {'SystemMode'} eq 'servergateway')
    {
        $currentmode = gettext("Server and gateway");
        $currentnumber = "1.";
    }
    elsif ($conf {'SystemMode'} eq 'servergateway-private')
    {
        $currentmode = gettext("Private server and gateway");
        $currentnumber = "2.";
    }
    else
    {
        $currentmode = gettext("Server-only");
        $currentnumber = "3.";
    }

    my @args = (
                $console->keep_option($currentmode),
                "1.", gettext("Server and gateway"),
                "2.", gettext("Private server and gateway"),
                "3.", gettext("Server-only"),
               );

    ($rc, $choice) = $console->menu_page
        (
         title   => gettext("Select operation mode"),
         text    =>
         gettext("If you want this server to act as a gateway to the Internet, choose one of the server and gateway options. Server and gateway mode acts as a firewall and provides an external web and mail server. Private server and gateway mode also acts as a firewall but disables all incoming services.") .
         "\n\n" .
         gettext("Server-only mode provides services to a local, protected network. If you choose this mode and Internet access is required, the network must be protected by another server configured in server and gateway mode (or another firewall)."),
         argsref => \@args
        );

    goto ETHERNET_LOCAL unless ($rc == 0);

    if ($choice eq gettext("keep"))
    {
        $choice = $currentnumber;
    }

    if ($choice eq "1.")
    {
        $conf {'SystemMode'} = 'servergateway';
        goto SERVER_GATEWAY;
    }

    if ($choice eq "2.")
    {
        $conf {'SystemMode'} = 'servergateway-private';
        goto SERVER_GATEWAY;
    }

    if ($choice eq "3.")
    {
        db_set_prop(\%conf, "pppoe", "status", "disabled");
        db_delete(\%conf, "ExternalIP");
        $conf {'SystemMode'} = 'serveronly';
        $conf{'AccessType'} = "dedicated";
        goto SERVER_ONLY;
    }
}

#------------------------------------------------------------
SERVER_GATEWAY:
#------------------------------------------------------------

{
    my $currentmode;
    my $currentnumber;


    if ($conf {'AccessType'} eq 'dedicated')
    {
        $currentmode = gettext("Server and gateway - dedicated");
        $currentnumber = "1.";
    }
    else
    {
        $currentmode = gettext("Server and gateway - dialup");
        $currentnumber = "2.";
    }

    my @args = (
                $console->keep_option( $currentmode ),
                "1.", gettext("Server and gateway - dedicated"),
                "2.", gettext("Server and gateway - dialup"),
               );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select external access mode"),
         text =>
         gettext("The next step is to select the access mode that your server will use to connect to the Internet.") .
         "\n\n" .
         gettext("Choose the dedicated option if you access the Internet via a router, a cable modem or ADSL. Choose the dialup option if you use a modem or ISDN connection."),
         argsref => \@args
        );

    goto SYSTEM_MODE unless ($rc == 0);

    if ($choice eq gettext("keep"))
    {
        $choice = $currentnumber;
    }

    if ($choice eq  "1.")
    {
        $conf {'AccessType'} = 'dedicated';
        goto ETHERNET_EXTERNAL;
    }

    if ($choice eq  "2.")
    {
        db_set_type(\%conf, 'AccessType', 'dialup');
        db_set_prop(\%conf, "pppoe", "status", "disabled");
        goto DIALUP_MODEM;
    }
}

#------------------------------------------------------------
ETHERNET_EXTERNAL:
#------------------------------------------------------------
{
    my $selectMode = ethernetSelect('external', 'EthernetDriver2');

    goto ETHERNET_EXTERNAL  if ($selectMode eq 'CANCEL_MANUAL');

    goto SERVER_GATEWAY     if ($selectMode eq 'CANCEL');

    if ($selectMode eq 'NOLOAD')
    {
        failed_to_load($conf{EthernetDriver2});
        goto ETHERNET_EXTERNAL;
    }

    if ($conf{'EthernetDriver1'} eq $conf{'EthernetDriver2'})
    {
        goto ETHERNET_SWAP
    }
    else
    {
        $conf {'EthernetAssign'} = "normal";
    }

    goto SERVER_GATEWAY_DEDICATED;
}

#------------------------------------------------------------
ETHERNET_SWAP:
#------------------------------------------------------------

{

    my @args = (
                $console->keep_option( gettext($conf{'EthernetAssign'}) ),
                gettext("normal"),  gettext("eth0 is local, eth1 is external"),
                gettext("swapped"), gettext("eth1 is local, eth0 is external")
               );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select ethernet card assignment"),
         text  =>
         gettext("You have two Ethernet cards which use the same driver. The server will automatically designate one for your local network (called eth0) and one for your external Internet connection (called eth1). If this default assignment is not appropriate for your situation, you can select the opposite assignment using swapped mode. Most installations can accept the default setting of normal.") .
         "\n\n" .
         gettext("Please select whether you want to operate in normal or swapped mode.") ,
         argsref => \@args
        );

    goto ETHERNET_EXTERNAL unless ($rc == 0);

    unless ($choice eq gettext("keep"))
    {
        $conf {'EthernetAssign'} = ($choice eq gettext("swapped")) ? "swapped"
            : "normal";
    }

    goto SERVER_GATEWAY_DEDICATED;
}

#------------------------------------------------------------
SERVER_GATEWAY_DEDICATED:
#------------------------------------------------------------
{
    unless ($conf {'DHCPClient'})
    {
        $conf {'DHCPClient'} = 'dhi';
    }

    my $currentmode;
    my $currentnumber;
    my $shortmode;

    if ($conf {'ExternalDHCP'} eq 'on')
    {
        if ($conf {'DHCPClient'} eq 'dhi')
        {
            $currentmode = gettext("use DHCP (send account name as client identifier)");
            $shortmode = gettext("DHCP with account name");
            $currentnumber = "1.";
        }
        else
        {
            $currentmode =
                gettext("use DHCP (send ethernet address as client identifier)");
            $shortmode = gettext("DHCP with ethernet address");
            $currentnumber = "2.";
        }
    }
    elsif (db_get_prop(\%conf, "pppoe", "status") eq "enabled")
    {
        $currentmode = gettext("use PPP over Ethernet (PPPoE)");
        $shortmode = gettext("PPPoE");
        $currentnumber = "3.";

    }
    else
    {
        $currentmode = gettext("use static IP address (do not use DHCP or PPPoE)");
        $shortmode = gettext("static IP");
        $currentnumber = "4.";
    }

    my @args = (
                $console->keep_option( $shortmode ),
                "1.", gettext("Use DHCP (send account name as client identifier)"),
                "2.", gettext("Use DHCP (send ethernet address as client identifier)"),
                "3.", gettext("Use PPP over Ethernet (PPPoE)"),
                "4.", gettext("Use static IP address"),
               );

    ($rc, $choice) = $console->menu_page
        (
         title   => gettext("External Interface Configuration"),
         text    =>
         gettext("Next, specify how to configure the external ethernet adapter.") .
         "\n\n" .
         gettext("For cable modem connections, select DHCP. If your ISP has assigned a system name for your connection, use the account name option. Otherwise use the ethernet address option. For residential ADSL, use PPPoE. For most corporate connections, use a static IP address."),
         argsref => \@args
        );

    goto SERVER_GATEWAY unless ($rc == 0);

    if ($choice eq gettext("keep"))
    {
        $choice = $currentnumber;
    }

    if ($choice eq  "3.")
    {
        $conf {'ExternalDHCP'} = 'off';

        db_set_prop(\%conf, "pppoe", "status", "enabled");
        db_set_prop(\%conf, "pppoe", "DemandIdleTime", "no");
        db_set_prop(\%conf, "pppoe", "SynchronousPPP", "no");
        # Delete GatewayIP, as Gateway is via ppp link
        db_delete(\%conf, 'GatewayIP');
        goto PPPoE_ACCOUNT;
    }
    else
    {
        db_set_prop(\%conf, "pppoe", "status", "disabled");
        if ($choice eq  "1.")
        {
            # Delete GatewayIP, as Gateway is via DHCP
            db_delete(\%conf, 'GatewayIP');
            $conf {'ExternalDHCP'} = 'on';
            $conf {'DHCPClient'} = 'dhi';
            goto DHCP_ACCOUNT;
        }

        if ($choice eq  "2.")
        {
            # Delete GatewayIP, as Gateway is via DHCP
            db_delete(\%conf, 'GatewayIP');
            $conf {'ExternalDHCP'} = 'on';
            $conf {'DHCPClient'} = 'd';
            goto DYNAMIC_DNS_SERVICE;
        }

        if ($choice eq  "4.")
        {
            $conf {'ExternalDHCP'} = 'off';
            db_set_prop(\%conf, 'DynDNS', 'status', 'disabled');
            goto STATIC_IP;
        }
    }
}

#------------------------------------------------------------
DHCP_ACCOUNT:
#------------------------------------------------------------
{
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Enter ISP assigned hostname"),
         text  =>
         gettext("You have selected DHCP (send account name). Please enter the account name assigned by your ISP. You must enter the account name exactly as specified by your ISP."),
         value   => $conf {'DialupUserAccount'}
        );

    goto SERVER_GATEWAY_DEDICATED unless ($rc == 0);

    if ($choice)
    {
        $conf {'DialupUserAccount'} = $choice;
    }
    else
    {
        $conf {'DialupUserAccount'} = '';
    }

    goto DYNAMIC_DNS_SERVICE;
}

#------------------------------------------------------------
PPPoE_ACCOUNT:
#------------------------------------------------------------
{
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select PPPoE user account"),
         text  =>
         gettext("Please enter the user account name for your PPPoE Internet connection. Most PPPoE service providers use an account name and e-mail domain. For example, ") . "fredfrog\@frog.pond",
         value   => $conf {'DialupUserAccount'}
        );

    goto SERVER_GATEWAY_DEDICATED unless ($rc == 0);

    if ($choice)
    {
        $conf {'DialupUserAccount'} = $choice;
    }
    else
    {
        $conf {'DialupUserAccount'} = '';
    }

    goto PPPoE_PASSWORD;
}

#------------------------------------------------------------
PPPoE_PASSWORD:
#------------------------------------------------------------

{
    ($rc, $choice) = $console->input_page
        (
         title  => gettext("Select PPPoE password"),
         text   =>
         gettext("Please enter the password for your PPPoE Internet connection."),
         value   => $conf {'DialupUserPassword'}
        );

    goto PPPoE_ACCOUNT unless ($rc == 0);

    if ($choice)
    {
        $conf {'DialupUserPassword'} = $choice;
    }
    else
    {
        $conf {'DialupUserPassword'} = '';
    }

    goto DYNAMIC_DNS_SERVICE;
}

#------------------------------------------------------------
DYNAMIC_DNS_SERVICE:
#------------------------------------------------------------
goto OTHER_PARAMETERS unless (-d "/sbin/e-smith/dynamic-dns");

{
    unless (opendir (DIR, "/sbin/e-smith/dynamic-dns"))
    {
        warn gettext("Cannot read directory"),
            " /sbin/e-smith/dynamic-dns", "\n";
        db_set_prop(\%conf, 'DynDNS', 'status', 'disabled');
        goto OTHER_PARAMETERS;

    }
    my @scripts = grep (!/^(\.\.?|custom)$/, readdir (DIR));
    closedir (DIR);

    foreach my $script (@scripts)
    {
        # Grab description from script contents
    }

    my $currentnumber;

    my $status = db_get_prop(\%conf, 'DynDNS', 'status') || "disabled";
    my $service = db_get_prop(\%conf, 'DynDNS', 'Service');
    if ($status eq "disabled")
    {
        $service = "off";
        $currentnumber = "1.";
    }
    else
    {
        if ($service eq 'yi')
        {
            $currentnumber = "2.";
        }

        if ($service eq 'dyndns')
        {
            $currentnumber = "3.";
        }

        if ($service eq 'dyndns.org')
        {
            $currentnumber = "4.";
        }

        if ($service eq 'tzo')
        {
            $currentnumber = "5.";
        }

        if ($service eq 'custom')
        {
            $currentnumber = "6.";
        }
    }

    my @args = (
                $console->keep_option( $service ),
                "1.", gettext("Do not use a dynamic DNS service"),
                "2.", "www.yi.org"     . " - " . gettext("free service"),
                "3.", "www.dyndns.com" . " - " . gettext("commercial service"),
                "4.", "www.dyndns.org" . " - " . gettext("free service"),
                "5.", "www.tzo.com"    . " - " . gettext("commercial service"),
               );

    ($rc, $choice) = $console->menu_page
        (
         title   => gettext("Select dynamic DNS service"),
         text    =>
         gettext("Please specify whether you wish to subscribe to a dynamic DNS service. Such services allow you to have a domain name without a static IP address, and are available from various organizations for free or for a reasonable charge. A notification must be sent to the dynamic DNS service whenever your IP address changes. Your server can automatically do this for some dynamic DNS services.") .
         "\n\n" .
         gettext("Choose which dynamic DNS service you would like to use."),
         argsref => \@args
        );

    goto SERVER_GATEWAY_DEDICATED unless ($rc == 0);

    if ($choice eq gettext("keep"))
    {
        $choice = $currentnumber;
    }

    if ($choice eq  "1.")
    {
        db_set_prop(\%conf, 'DynDNS', 'status', 'disabled');
        goto OTHER_PARAMETERS;
    }
    db_set_prop(\%conf, 'DynDNS', 'status', 'enabled');
    if ($choice eq  "2.")
    {
        db_set_prop(\%conf, 'DynDNS', 'Service', 'yi');
        goto DYNAMIC_DNS_ACCOUNT;
    }

    if ($choice eq  "3.")
    {
        db_set_prop(\%conf, 'DynDNS', 'Service', 'dyndns');
        goto DYNAMIC_DNS_ACCOUNT;
    }

    if ($choice eq  "4.")
    {
        db_set_prop(\%conf, 'DynDNS', 'Service', 'dyndns.org');
        goto DYNAMIC_DNS_ACCOUNT;
    }

    if ($choice eq  "5.")
    {
        db_set_prop(\%conf, 'DynDNS', 'Service', 'tzo');
        goto DYNAMIC_DNS_ACCOUNT;
    }

    if ($choice eq  "6.")
    {
        db_set_prop(\%conf, 'DynDNS', 'Service', 'custom');
        goto DYNAMIC_DNS_ACCOUNT;
    }
}

#------------------------------------------------------------
DYNAMIC_DNS_ACCOUNT:
#------------------------------------------------------------

{
    my $account = db_get_prop(\%conf, 'DynDNS', 'Account') || '';
    my $service = db_get_prop(\%conf, 'DynDNS', 'Service');
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select dynamic DNS account"),
         text  => gettext("Please enter the account name for your dynamic DNS service"),
         value   => $account
        );

    goto DYNAMIC_DNS_SERVICE unless ($rc == 0);

    if ($choice)
    {
        db_set_prop(\%conf, 'DynDNS', 'Account', $choice);
    }
    else
    {
        db_set_prop(\%conf, 'DynDNS', 'Account', '');
    }

    goto DYNAMIC_DNS_PASSWORD;
}

#------------------------------------------------------------
DYNAMIC_DNS_PASSWORD:
#------------------------------------------------------------

{
    my $account = db_get_prop(\%conf, 'DynDNS', 'Account');
    my $password = db_get_prop(\%conf, 'DynDNS', 'Password') || '';
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select dynamic DNS password"),
         text  => gettext("Please enter the password for your dynamic DNS service"),
         value   => $password
        );

    goto DYNAMIC_DNS_ACCOUNT unless ($rc == 0);

    if ($choice)
    {
        db_set_prop(\%conf, 'DynDNS', 'Password', $choice);
    }
    else
    {
        db_set_prop(\%conf, 'DynDNS', 'Password', '');
    }

    goto OTHER_PARAMETERS;
}

#------------------------------------------------------------
STATIC_IP:
#------------------------------------------------------------

{
    # Need to do this now, since we delete ExternalIP and
    # the console will throw an uninitialized variable error
    # that you'll never see, but will make rc == 0.

    my $externalIP = $conf {'ExternalIP'} || "";
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select static IP address"),
         text  =>
         gettext("You have chosen to configure your external Ethernet connection with a static IP address. Please enter the IP address which should be used for the external interface on this server.") .
         "\n\n" .
         gettext("Please note, this is not the address of your external gateway."),
         value   => $externalIP
        );

    goto SERVER_GATEWAY_DEDICATED unless ($rc == 0);

    if ($choice)
    {
        if (isValidIP($choice) )
        {
            $conf {'ExternalIP'} = cleanIP($choice);
            goto STATIC_NETMASK;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid external IP address"),
         choice  => $choice,
        );

    goto STATIC_IP;
}

#------------------------------------------------------------
STATIC_NETMASK:
#------------------------------------------------------------

{
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select subnet mask"),
         text  =>
         gettext("Please enter the subnet mask for your Internet connection. A typical subnet mask is 255.255.255.0."),
         value   => $conf {'ExternalNetmask'}
        );

    goto STATIC_IP unless ($rc == 0);

    if ($choice)
    {
        if ( isValidIP($choice) )
        {
            $conf {'ExternalNetmask'} = cleanIP($choice);
            goto STATIC_GATEWAY;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid external subnet mask"),
         choice  => $choice,
        );

    goto STATIC_NETMASK;
}

#------------------------------------------------------------
STATIC_GATEWAY:
#------------------------------------------------------------

{
    my $netmaskBits = esmith::util::IPquadToAddr ($conf{'ExternalNetmask'});
    my $gateway_ip = $conf{'GatewayIP'} || "";
    unless ((esmith::util::IPquadToAddr($conf{'ExternalIP'}) & $netmaskBits) ==
            (esmith::util::IPquadToAddr($conf{'GatewayIP'}) & $netmaskBits)) {
        $gateway_ip =
            esmith::util::IPaddrToQuad(
                                       (esmith::util::IPquadToAddr($conf{'ExternalIP'}) & $netmaskBits)
                                       + 1);
    }
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select gateway IP address"),
         text  =>
         gettext("Please enter the gateway IP address for your Internet connection."),
         value   => $gateway_ip
        );

    goto STATIC_NETMASK unless ($rc == 0);

    if ($choice)
    {
        if (isValidIP($choice) )
        {
            $conf {'GatewayIP'} = cleanIP($choice);
            goto OTHER_PARAMETERS;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid gateway IP address"),
         choice  => $choice,
        );

    goto STATIC_GATEWAY;
}

#------------------------------------------------------------
DIALUP_MODEM:
#------------------------------------------------------------

{
    my @args = (
                $console->keep_option( $conf{'DialupModemDevice'} ),
                "COM1", gettext("Set modem port to") . " COM1 (/dev/ttyS0)",
                "COM2", gettext("Set modem port to") . " COM2 (/dev/ttyS1)",
                "COM3", gettext("Set modem port to") . " COM3 (/dev/ttyS2)",
                "COM4", gettext("Set modem port to") . " COM4 (/dev/ttyS3)",
                gettext("ISDN"), gettext("Set modem port to") . " " .
                gettext("internal ISDN card") . " (/dev/ttyI0)",
               );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select modem/ISDN port"),
         text  =>
         gettext("Please specify which serial port your modem or ISDN terminal adapter is connected to. Select ISDN if you wish to use an internal ISDN card."),
         argsref => \@args
        );

    goto SERVER_GATEWAY unless ($rc == 0);

    if ($choice eq  "COM1")
    {
        db_set(\%conf, 'DialupModemDevice', '/dev/ttyS0');
    }

    if ($choice eq  "COM2")
    {
        db_set(\%conf, 'DialupModemDevice', '/dev/ttyS1');
    }

    if ($choice eq  "COM3")
    {
        db_set(\%conf, 'DialupModemDevice', '/dev/ttyS2');
    }

    if ($choice eq  "COM4")
    {
        db_set(\%conf, 'DialupModemDevice', '/dev/ttyS3');
    }
    if ($choice eq gettext("ISDN"))
    {
        db_set(\%conf, 'DialupModemDevice', '/dev/ttyI0');
    }

    if (db_get(\%conf, 'DialupModemDevice') eq '/dev/ttyI0')
    {
        db_set_prop(\%conf, 'ippp', 'status', 'enabled');
        db_set_prop(\%conf, 'isdn', 'status', 'enabled');
        goto HISAX_OPTIONS
    }
    db_set_prop(\%conf, 'ippp', 'status', 'disabled');
    db_set_prop(\%conf, 'isdn', 'status', 'disabled');
    goto MODEM_INIT_STRING;
}

#------------------------------------------------------------
HISAX_OPTIONS:
#------------------------------------------------------------

{
    # See http://ibiblio.org/pub/Linux/distributions/caldera/eServer/\
    # 2.3.1/live/etc/hwprobe.config for a pciid list - we cover most of
    # the cards listed there
    my %isdn_cards = (
                      '1133e001' =>
                      { type => "11",
                        description => "Eicon|DIVA 20PRO" },
                      '1133e002' =>
                      { type => "11",
                        description => "Eicon|DIVA 20" },
                      '1133e003' =>
                      { type => "11",
                        description => "Eicon|DIVA 20PRO_U" },
                      '1133e004' =>
                      { type => "11",
                        description => "Eicon|DIVA 20_U" },
                      '1133e005' =>
                      { type => "11",
                        description => "Eicon|DIVA 2.01 PCI or PCI_LP" },
                      '1133e010' =>
                      { type => "11",
                        description => "Eicon|DIVA Server BRI-2M" },
                      '1133e012' =>
                      { type => "11",
                        description => "Eicon|DIVA Server BRI-8M" },
                      '1133e014' =>
                      { type => "11",
                        description => "Eicon|DIVA Server PRO-30M" },
                      '1133e018' =>
                      { type => "11",
                        description => "Eicon|DIVA Server BRI-2M/-2F" },
                      'e1590002' =>
                      { type => "15",
                        description => "Sedlbauer Speed PCI ISDN" },
                      '10481000' =>
                      { type => "18",
                        description => "Elsa AG|QuickStep 1000" },
                      '10483000' =>
                      { type => "18",
                        description => "Elsa AG|QuickStep 3000" },
                      'e1590001' =>
                      { type => "20",
                        description => "Netjet|Tigerjet 300|320" },
                      '11de6057' =>
                      { type => "21",
                        description => "Teles PCI ISDN network controller" },
                      '11de6120' =>
                      { type => "21",
                        description => "Teles PCI ISDN network controller" },
                      '12671016' =>
                      { type => "24",
                        description => "Dr Neuhaus Niccy PCI" },
                      '12440a00' =>
                      { type => "27",
                        description => "AVM Fritz PCI" },
                      '10b51030' =>
                      { type => "34",
                        description => "Gazel/PLX R685" },
                      '10b51151' =>
                      { type => "34",
                        description => "Gazel/PLX DJINN_ITOO" },
                      '10b51152' =>
                      { type => "34",
                        description => "Gazel/PLX R753" },
                      '13972bd0' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b000' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b006' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b007' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b008' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b009' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b00a' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b00b' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b00c' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '1397b100' =>
                      { type => "35",
                        description => "ISDN network controller [HFC-PCI]" },
                      '15b02bd0' =>
                      { type => "35",
                        description => "Zoltrix ISDN network controller [HFC-PCI]" },
                      '10430675' =>
                      { type => "35",
                        description => "Asuscom ISDNLINK 128K [HFC-PCI]" },
                      '06751700' =>
                      { type => "36",
                        description => "Dynalink IS64PH ISDN network controller" },
                      '06751702' =>
                      { type => "36",
                        description => "Dynalink IS64PH ISDN network controller" },
                      '06751704' =>
                      { type => "36",
                        description => "Dynalink IS64PH ISDN network controller" },
                      '10506692' =>
                      { type => "36",
                        description => "Winbond 6692 ISDN network controller" },
                      '15ad0710' =>
                      { type => "FF",
                        description =>
                        "Test thingy to check detection (actually VMWare display)" },
                     );

    my $card;
    open (PCI, "/proc/bus/pci/devices");
    while (my $pci_data = <PCI>)
    {
        my $id = (split(/\s+/, $pci_data))[1];
        $card = $isdn_cards{$id};
        last if defined $card;
    }
    close (PCI);
    if (defined $card)
    {
        my $description = $$card{'description'};
        ($rc, $choice) = $console->yesno_page
            (
             title => gettext("ISDN card detected"),
             text  =>
             gettext("Do you wish to use the following ISDN card for your Internet connection?") .
             "\n\n" .
             $description,
            );

        if ($rc == 0)
        {
            my $type = $$card{'type'};
            db_set_prop(\%conf, 'isdn', 'Type', "$type");
            goto DIALUP_ACCESS_NUMBER;
        }
    }

    my $hisax_options = db_get_prop(\%conf, 'isdn', 'HisaxOptions') || "";
    ($rc, $choice) = $console->input_page
        (
         title => gettext("ISDN driver options"),
         text  =>
         gettext("You have selected an internal ISDN card.") .
         "\n\n" .
         gettext("The ISDN software will need to be told what ISDN hardware you have. It may also need to be told what protocol number to use and may need to be given some additional information about your hardware such as the I/O address and interrupt settings.") .
         "\n\n" .
         gettext("This information is provided via an options string. An example is") .
         " " .  qq("type=27 protocol=2") . " " .
         gettext("which would be used to set the") .
         " " . qq("AVM Fritz!PCI") . " " .
         gettext("to EURO-ISDN."),
         value   => $hisax_options
        );

    goto DIALUP_MODEM unless ($rc == 0);

    if ($choice)
    {
        db_set_prop(\%conf, 'isdn', 'HisaxOptions', $choice);
    }
    else
    {
        db_delete_prop(\%conf, 'isdn', 'HisaxOptions');
    }
}

#------------------------------------------------------------
ISDN_MSN:
#------------------------------------------------------------
goto MODEM_INIT_STRING;         # Skip this page - only for dial-in

{
    my $msn = db_get_prop(\%conf, 'isdn', 'Msn');
    $msn = "" unless (defined $msn);
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Multiple Subscriber Numbering"),
         text  =>
         gettext("Your ISDN line may have more than one number associated with it known as Multiple Subscriber Numbering (MSN). In order to receive an incoming ISDN call from an ISP or a remote site, you may need to configure your ISDN card with its MSN so that ISDN calls are routed correctly. If you do not know this number, you can leave this value blank."),
         value   => $msn
        );

    goto HISAX_OPTIONS unless ($rc == 0);

    unless ($choice eq "" or $choice =~ /^[-,0-9]+$/)
    {
        ($rc, $choice) = $console->tryagain_page
            (
             title   => gettext("Invalid Multiple Subscriber Numbering (MSN)"),
             choice  => $choice,
            );

        goto ISDN_MSN;
    }
    db_set_prop(\%conf, 'isdn', 'Msn', "$choice");
    goto DIALUP_ACCESS_NUMBER;
}
#------------------------------------------------------------
MODEM_INIT_STRING:
#------------------------------------------------------------

{
    my $modem_init = db_get(\%conf, 'ModemInit') || "";
    my $modem = db_get(\%conf, 'DialupModemDevice') || "";

    my $isdn_msg =
        gettext("You have selected an internal ISDN card.") .
            "\n\n" .
        gettext("The driver for this card includes modem emulation software, and modem control commands are used by the networking software to configure and control the ISDN interface card.") .
                    "\n\n" .
        gettext("The precise behavior of your ISDN card can be modified by using a specific modem initialization string, to adjust the settings of the card, or to modify its default behavior. Most cards should work correctly with the default settings, but you may enter a modem initialization string here if required.");

    my $modem_msg =
        gettext("You have selected a modem device.") .
            "\n\n" .
        gettext("The precise behavior of your modem can be modified by using a specific modem initialization string, to adjust the settings of your modem, or to modify its default behavior. You may enter a modem initialization string here.") .
                    "\n\n" .
        gettext("Many modems will work correctly without any special settings. If you leave this field blank, the default string of") .
                            " " . qw("L0M0") . " " .
        gettext("will be used. This turns the modem speaker off, so that you will not be bothered by the noises that a modem makes when it starts a connection.");

    my $msg = ($modem eq '/dev/ttyI0') ? $isdn_msg : $modem_msg;

    ($rc, $choice) = $console->input_page
        (
         title   => gettext("Modem initialization string"),
         text    => $msg,
         value   => $modem_init
        );

    unless ($rc == 0)
    {
        if ($conf{'DialupModemDevice'} eq '/dev/ttyI0')
        {
            goto HISAX_OPTIONS;
        }
        else
        {
            goto DIALUP_MODEM;
        }
    }

    if ($choice)
    {
        $conf {'ModemInit'} = $choice;
    }
    else
    {
        delete $conf {'ModemInit'};
    }
    goto DIALUP_ACCESS_NUMBER;
}

#------------------------------------------------------------
DIALUP_ACCESS_NUMBER:
#------------------------------------------------------------

{
    my $title = gettext("Select access phone number");

    my $msg =
        gettext("Please enter the access phone number for your Internet connection. Long distance numbers can be entered. The phone number must not contain spaces, but may contain dashes for readability. Commas may be inserted where a delay is required. For example, if you need to dial 9 first, then wait, then dial a phone number, you could enter") . " "
            . qq("9,,,123-4567");

    ($rc, $choice) = $console->input_page
        (
         title   => $title,
         text    => $msg,
         value   => $conf {'DialupPhoneNumber'}
        );

    goto MODEM_INIT_STRING unless ($rc == 0);

    if ($choice)
    {
        if ($choice =~ /^[-,0-9]+$/)
        {
            db_set(\%conf, 'DialupPhoneNumber', "$choice");
            goto DIALUP_ACCOUNT;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid access phone number"),
         choice  => $choice,
        );

    goto DIALUP_ACCESS_NUMBER;
}

#------------------------------------------------------------
DIALUP_ACCOUNT:
#------------------------------------------------------------

{
    my $msg = gettext("Please enter the user account name for your Internet connection.")
        . "\n\n" .
            gettext("Please note that account names are usually case sensitive.");

    ($rc, $choice) = $console->input_page
        (
         title   => gettext("Select dialup user account"),
         text    => $msg,
         value   => $conf {'DialupUserAccount'}
        );

    goto DIALUP_ACCESS_NUMBER unless ($rc == 0);

    if ($choice)
    {
        $conf {'DialupUserAccount'} = $choice;
    }
    else
    {
        $conf {'DialupUserAccount'} = '';
    }

    goto DIALUP_PASSWORD;
}

#------------------------------------------------------------
DIALUP_PASSWORD:
#------------------------------------------------------------

{
    my $msg = gettext("Please enter the password for your Internet connection.")
        . "\n\n" .
            gettext("Please note that passwords are usually case sensitive.");

    ($rc, $choice) = $console->input_page
        (
         title   => gettext("Select dialup password"),
         text    => $msg,
         value   => $conf {'DialupUserPassword'}
        );

    goto DIALUP_ACCOUNT unless ($rc == 0);

    if ($choice)
    {
        $conf {'DialupUserPassword'} = $choice;
    }
    else
    {
        $conf {'DialupUserPassword'} = '';
    }

    goto INITIALIZE_CONNECT_TIMES;
}

#------------------------------------------------------------
INITIALIZE_CONNECT_TIMES:
#------------------------------------------------------------
my %policy2string =
    (
     "never"        => "No connection",
     "short"        => "Short connect times to minimize minutes off-hook",
     "medium"       => "Medium connect times",
     "long"     => "Long connect times to minimize dialing delays",
     "continuous"   => "Continuous connection",
    );

my @connect_options;
my %gettext2policy;

goto DIALUP_OFFICE if scalar @connect_options;

foreach (keys %policy2string)
{
    push @connect_options, gettext($_), gettext($policy2string{$_});
    $gettext2policy{gettext($_)} = $_;
}

#------------------------------------------------------------
DIALUP_OFFICE:
#------------------------------------------------------------
{
    unless ($conf {'DialupConnOffice'})
    {
        $conf {'DialupConnOffice'} = 'medium';
    }

    my @args = (
                $console->keep_option( gettext($conf{'DialupConnOffice'}) ),
                @connect_options,
               );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select connect policy"),
         text  =>
         gettext("Select the dialup connect policy that you would like to use during office hours (8:00 AM to 6:00 PM) on weekdays."),

         argsref => \@args
        );

    goto DIALUP_PASSWORD unless ($rc == 0);

    $conf {'DialupConnOffice'} = $choice eq gettext("keep")
        ? $conf {'DialupConnOffice'}
            : $gettext2policy{$choice};

    goto DIALUP_OUTSIDE;
}

#------------------------------------------------------------
DIALUP_OUTSIDE:
#------------------------------------------------------------

{
    unless ($conf {'DialupConnOutside'})
    {
        $conf {'DialupConnOutside'} = 'medium';
    }


    my @args = (
                $console->keep_option( gettext($conf{'DialupConnOutside'}) ),
                @connect_options
               );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select connect policy"),
         text  =>
         gettext("Please select the dialup connect policy that you would like to use outside office hours (6:00 PM to 8:00 AM) on weekdays."),
         argsref => \@args
        );

    goto DIALUP_OFFICE unless ($rc == 0);

    $conf {'DialupConnOutside'} = $choice eq gettext("keep")
        ? $conf {'DialupConnOutside'}
            : $gettext2policy{$choice};

    goto DIALUP_WEEKEND;
}

#------------------------------------------------------------
DIALUP_WEEKEND:
#------------------------------------------------------------

{
    unless ($conf {'DialupConnWeekend'})
    {
        $conf {'DialupConnWeekend'} = 'medium';
    }

    my @args = (
                $console->keep_option( gettext($conf{'DialupConnWeekend'}) ),
                @connect_options
               );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select connect policy"),
         text  =>
         gettext("Please select the dialup connect policy that you would like to use during the weekend."),
         argsref => \@args
        );

    goto DIALUP_OUTSIDE unless ($rc == 0);

    $conf {'DialupConnWeekend'} = $choice eq gettext("keep")
        ? $conf {'DialupConnWeekend'}
            : $gettext2policy{$choice};

    goto DYNAMIC_DNS_SERVICE;
}


#------------------------------------------------------------
SERVER_ONLY:
#------------------------------------------------------------

{
    goto OTHER_PARAMETERS unless ($conf{'AccessType'} eq 'dedicated');

    my $gateway_ip = $conf {'GatewayIP'} || "";
    my $netmaskBits = esmith::util::IPquadToAddr ($conf{'LocalNetmask'});
    unless ((esmith::util::IPquadToAddr($conf{'LocalIP'}) & $netmaskBits) ==
            (esmith::util::IPquadToAddr($conf{'GatewayIP'}) & $netmaskBits)) {
        $gateway_ip =
            esmith::util::IPaddrToQuad(
                                       (esmith::util::IPquadToAddr($conf{'LocalIP'}) & $netmaskBits)
                                       + 1);
    }

    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select gateway IP address"),
         text  =>
         gettext("In server-only mode, this server will use only one ethernet adapter connected to your local network. If you have a firewall and wish to use this server as your e-mail/web server, you should consult the firewall documentation for networking details.") .
         "\n\n" .
         gettext("Please specify the gateway IP address that this server should use to access the Internet. Leave blank if you have no Internet access."),
         value   => $gateway_ip
        );

    goto SYSTEM_MODE unless ($rc == 0);

    if ($choice eq "")
    {
        delete $conf {'GatewayIP'};
        $conf{'AccessType'} = "off";
        goto OTHER_PARAMETERS;
    }

    if ( isValidIP($choice) )
    {
        $conf {'GatewayIP'} = cleanIP($choice);
        $conf{'AccessType'} = "dedicated";
        goto OTHER_PARAMETERS;
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid gateway IP address"),
         choice  => $choice,
        );

    goto SERVER_ONLY;
}

#------------------------------------------------------------
OTHER_PARAMETERS:
#------------------------------------------------------------
# Sample UnsavedChanges at this point - nothing after here
# should require a reboot - and we don't require a reboot first time
# through
#------------------------------------------------------------
if ($bootstrapConsole eq "no")
{
    $rebootRequired = $conf{'UnsavedChanges'};
}
#------------------------------------------------------------

DHCP_SERVER:
{
    my $start = db_get_prop(\%conf, "dhcpd", "start") || '0.0.0.65';
    my $end = db_get_prop(\%conf, "dhcpd", "end") || '0.0.0.250';
    my $priv_ip = db_get(\%conf, 'LocalIP');
    my $priv_mask = db_get(\%conf, 'LocalNetmask');
    my $priv_net = ipv4_network($priv_ip, $priv_mask);
    my $localip = esmith::util::IPquadToAddr($priv_ip);
    my $netmask = esmith::util::IPquadToAddr($priv_mask);
    $start      = esmith::util::IPquadToAddr($start);
    $end        = esmith::util::IPquadToAddr($end);
    # AND-out the network bits, and OR that with our current dhcp values.
    my $localnet = $localip & $netmask;
    # Delete the current DHCP leases file if we are changing networks
    unless ((($start & $netmask) == $localnet) &&
	    (($end & $netmask) == $localnet))
    {
	my $dhcpLeases = "/var/lib/dhcp/dhcpd.leases";
	open (WR, ">$dhcpLeases")
	    or die gettext("Can't open output file"),
		" $dhcpLeases", ": $!\n";
	close WR;
    }
    # AND-out the host bits from the start and end ips.
    # And, OR our local network with our start and end host values.
    $start = $localnet | ($start & ~$netmask);
    $end = $localnet | ($end & ~$netmask);
    # Make sure that $start is less than $end (might not be if netmask has changed
    if ($start > $end)
    {
	my $temp = $start;
	$start = $end;
	$end = $temp;
    }
    $start = esmith::util::IPaddrToQuad($start);
    $end   = esmith::util::IPaddrToQuad($end);
    # That's it. Set them back. These will hopefully be reasonable defaults.
    db_set_prop(\%conf, "dhcpd", "start", $start);
    db_set_prop(\%conf, "dhcpd", "end", $end);
    my $DHCPServer = (db_get_prop(\%conf, 'dhcpd', 'status') eq 'enabled') ?
        gettext("On") : gettext("Off");

    my @args =
        (
         $console->keep_option( $DHCPServer ),
         gettext("On"),  gettext("Provide DHCP service to local network"),
         gettext("Off"), gettext("Do not provide DHCP service to local network"),
        );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select DHCP server configuration"),
         text  =>
         gettext("Please specify whether you would like this server to provide DHCP service to your local network. This will let you assign IP addresses to your other network computers automatically by configuring them to obtain their IP information using DHCP.") .
         "\n\n" .
         gettext("We strongly advise that all clients are configured using DHCP."),
         argsref => \@args
        );

    goto SYSTEM_MODE unless ($rc == 0);

    if ($choice eq gettext("On")
        || ($choice eq gettext("keep") && $DHCPServer eq "On")) {
        db_set_prop(\%conf, 'dhcpd', 'status', 'enabled');
        # Initialise Samba DomainMaster setting if it isn't already set
        # default to yes if DHCP is enabled
        unless (defined db_get_prop(\%conf, 'smb', 'DomainMaster') )
        {
            db_set_prop(\%conf, 'smb', 'DomainMaster', 'yes');
        }
        goto DHCP_SERVER_BEGIN;
    }

    if ($choice eq gettext("Off"))
    {
        db_set_prop(\%conf, 'dhcpd', 'status', 'disabled');
        # default to no if DHCP is disabled
        unless (defined db_get_prop(\%conf, 'smb', 'DomainMaster') )
        {
            db_set_prop(\%conf, 'smb', 'DomainMaster', 'no');
        }
        goto PROXY;
    }

    goto PROXY;
}

#------------------------------------------------------------
DHCP_SERVER_BEGIN:
#------------------------------------------------------------

{
    my $start = db_get_prop(\%conf, "dhcpd", "start") || '0.0.0.65';
    my $priv_ip = db_get(\%conf, 'LocalIP');
    my $priv_mask = db_get(\%conf, 'LocalNetmask');
    my $priv_net = ipv4_network($priv_ip, $priv_mask);

    my $errmsg = "";

    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select beginning of DHCP host number range"),
         text  =>
         gettext("You must reserve a range of host numbers for the DHCP server to use.") .
         "\n\n" .
         gettext("Please enter the first host number in this range. If you are using the standard server defaults and have no particular preference, you should keep the default values."),
         value   => $start
        );

    goto DHCP_SERVER unless ($rc == 0);

    if ($choice)
    {
        if ( isValidIP($choice) )
        {
	    my $dhcp_net = ipv4_network($choice, $priv_mask);
	    if ($dhcp_net eq $priv_net)
	    {
		# need to check for valid range as well.
		unless ($choice eq $start)
		{
		    db_set_prop(\%conf, 'dhcpd', 'start', cleanIP($choice));
		}
		goto DHCP_SERVER_END;
	    }
	    else
	    {   
		$errmsg = gettext("That address is not on the local network.");
	    }
	}
	else
	{   
	    $errmsg = gettext("Invalid IP address for DHCP start");
	}
    }
    else
    {
        $choice = '';
	$errmsg = gettext("You must provide an IP address for the start of the DHCP range.");
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => $errmsg,
         choice  => $choice,
        );

    goto DHCP_SERVER_BEGIN;
}

#------------------------------------------------------------
DHCP_SERVER_END:
#------------------------------------------------------------

{
    my $serverStart = db_get_prop(\%conf, 'dhcpd', 'start');
    my $serverEnd   = db_get_prop(\%conf, 'dhcpd', 'end');
    my $priv_ip = db_get(\%conf, 'LocalIP');
    my $priv_mask = db_get(\%conf, 'LocalNetmask');
    my $priv_net = ipv4_network($priv_ip, $priv_mask);
    my $errmsg = "";

    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select end of DHCP host number range"),
         text  =>
         gettext("Please enter the last host address in this range. If you are using the standard server defaults and have no particular preference, you should keep the default value."),
         value   => $serverEnd
        );

    goto DHCP_SERVER_BEGIN unless ($rc == 0);

    if ($choice)
    {
        if ( isValidIP($choice) )
        {
	    my $dhcp_net = ipv4_network($choice, $priv_mask);
	    if ($dhcp_net eq $priv_net)
	    {
		# There are a few additional things to confirm here. We now
		# know that the chosen range is on the same network as the
		# private interface. We should ensure that it does not overlap
		# the private interface, and that the end is larger than the
		# beginning. 
		if (cmpIP($serverStart, $choice) < 0)
		{
		    if ((cmpIP($priv_ip, $serverStart) < 0) ||
			(cmpIP($choice, $priv_ip) < 0))
		    {
			# need to check for valid range as well.
			unless ($choice eq $serverEnd)
			{
			    db_set_prop(\%conf, 'dhcpd', 'end', cleanIP($choice));
			}
			goto PROXY;
		    }
		    else
		    {
			$errmsg = gettext("The IP range cannot include our private network address.");
			$choice = $priv_ip;
		    }
		}
		else
		{
		    $errmsg = gettext("The end of the range must be larger than the start.");
		    $choice = $serverStart;
		}
	    }
	    else
	    {
		$errmsg = gettext("That address is not on the local network.");
	    }
        }
	else
	{
	    $errmsg = gettext("Invalid IP address for DHCP start");
	}
    }
    else
    {
        $choice = '';
	$errmsg = gettext("You must provide an IP address for the end of the DHCP range.");
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => $errmsg,
         choice  => $choice,
        );

    goto DHCP_SERVER_END;
}

#------------------------------------------------------------
PROXY:
#------------------------------------------------------------

{
    my $currentSetting =
        ($conf{'SquidParent'} &&
         ($conf{'SquidParent'} ne '')) ? gettext("Yes") : gettext("No");

    my @args =
        (
         $console->keep_option( $currentSetting ),
         gettext("No"),  gettext("Normal operation"),
         gettext("Yes"), gettext("Use outside proxy server"),
        );


    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select proxy server"),
         text =>
         gettext("Some Internet Service Providers require that you use a proxy server outside your local network. In such cases, you will need to specify that the server fetch all web pages from your ISP\'s proxy server.  You should select No unless you have reason to do otherwise."),
         argsref => \@args
        );

    goto DHCP_SERVER unless ($rc == 0);

    if ($choice eq gettext("keep"))
    {
        $choice = $currentSetting;
    }

    if ($choice eq gettext("No"))
    {
        $conf {'SquidParent'} = '';
        $conf {'SquidParentPort'} = '';
        goto CONSOLE_MODE;
    }

    goto PROXY_IP;
}

#------------------------------------------------------------
PROXY_IP:
#------------------------------------------------------------

{
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select outside proxy server IP address"),
         text  => gettext("Please specify the name or IP address of the outside proxy server"),
         value   => $conf {'SquidParent'}
        );

    goto PROXY unless ($rc == 0);

    if ($choice)
    {
        if ( isValidIP($choice) )
        {
            $conf {'SquidParent'} = cleanIP($choice);
            goto PROXY_PORT;
        }

        if ($choice =~ /^[a-zA-Z0-9\-\.]+$/)
        {
            $conf {'SquidParent'} = $choice;
            goto PROXY_PORT;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid proxy server address"),
         choice  => $choice,
        );

    goto PROXY_IP;
}

#------------------------------------------------------------
PROXY_PORT:
#------------------------------------------------------------

{
    ($rc, $choice) = $console->input_page
        (
         title => gettext("Select outside proxy server port number"),
         text  => gettext("Please specify the port number of your outside proxy server."),
         value   => $conf {'SquidParentPort'}
        );

    goto PROXY_IP unless ($rc == 0);

    if ($choice)
    {
        if ($choice =~ /^[0-9]+$/)
        {
            $conf {'SquidParentPort'} = $choice;
            goto CONSOLE_MODE;
        }
    }
    else
    {
        $choice = '';
    }

    ($rc, $choice) = $console->tryagain_page
        (
         title   => gettext("Invalid proxy server port number"),
         choice  => $choice,
        );

    goto PROXY_PORT;
}

#------------------------------------------------------------
CONSOLE_MODE:
#------------------------------------------------------------

{
    unless ($conf {'ConsoleMode'})
    {
        $conf {'ConsoleMode'} = 'auto';
    }

    my @args =
        (
         $console->keep_option( gettext($conf{'ConsoleMode'}) ),
         gettext("auto"),  gettext("Display server console at all times"),
         gettext("login"), gettext("Log in as") . " admin " .
         gettext("to access server console"),
        );


    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Select console mode"),
         text  =>
         gettext("By default the server console (which you are now using) can be used without requiring a username or password. As an additional security precaution, you can configure this server to display a login prompt instead. In this case, you must log in as") .
         " admin " .
         gettext("with the current system password to access the console.") .
         "\n\n" .
         gettext("Please select your preferred console mode."),
         argsref => \@args
        );

    goto PROXY unless ($rc == 0);

    unless ($choice eq gettext("keep"))
    {
        $conf {'ConsoleMode'} = $choice eq gettext("auto") ? "auto" : "login";
    }
    goto QUERY_SAVE_CONFIG;
}

#------------------------------------------------------------
QUERY_SAVE_CONFIG:
#------------------------------------------------------------

{
    if ($conf{'UnsavedChanges'} eq "no")
    {
        my $old = $conf {'UnsavedChanges'};
        $conf {'UnsavedChanges'} = $old;

        ($rc, $choice) = $console->message_page
            (
             title => gettext("No unsaved changes"),
             text  =>
             gettext("No changes were made during the configuration process") .
             "\n\n" .
             gettext("Press ENTER to proceed."),
             right => gettext("Finish"),
            );

        goto INITIAL;
    }
    else
    {
        if ($rebootRequired eq "yes")
        {
            db_set_prop(\%conf, "bootstrap-console", "Run", "yes");
            db_set_prop(\%conf, "bootstrap-console", "ForceSave", "yes");
	    ($rc, $choice) = $console->yesno_page
		(
		 title   => gettext("Changes will take effect after reboot"),
		     text =>
			 gettext("The new configuration will take effect when you reboot the server.") .
			 "\n\n" .
			 gettext("Do you wish to reboot right now?"),
		);

	    goto INITIAL unless ($rc == 0);

	    system("/usr/bin/tput", "clear");
	    system("/sbin/e-smith/signal-event", "reboot");

	    # A bit of a hack to avoid the console restarting before the
	    # reboot takes effect.

	    sleep(600);
        }
        ($rc, $choice) = $console->yesno_page
            (
             title => gettext("Activate configuration changes"),
             text  =>
             gettext("Your configuration changes will now be activated. The configuration files on this server will be changed to reflect your new settings. This may take a few minutes.") .
             "\n\n" .
             gettext("Do you wish to activate your changes?"),
            );
    }
    goto INITIAL unless ($rc == 0);

    #------------------------------------------------------------
 SAVE_CONFIG:
    #------------------------------------------------------------
    # After saving config we don't need to run it again on the next reboot.
    db_set_prop(\%conf, "bootstrap-console", "ForceSave", "no");
    db_set_prop(\%conf, "bootstrap-console", "Run", "no");
    untie %conf;

    # XXX-FIXME
    # We call whiptail directly (rather than through the screen function)
    # as we don't want the --clear parameter passed by screen().
    # Appropriate magic can clean this up.

    system(
           "/usr/bin/whiptail",
           "--backtitle",
	   "$release_string",
           "--title", gettext("Activating configuration settings"),
           "--infobox", gettext("Please standby while your configuration settings are activated ..."),
           8, SCREEN_COLUMNS,
          );


    if ($bootstrapConsole eq "yes")
    {
        system("/sbin/e-smith/signal-event", "bootstrap-console-save");
        goto QUIT1;
    }
    else
    {
        system("/sbin/e-smith/signal-event", "console-save");
        tie %conf, 'esmith::config::unsaved';

	my $current_mode = (getppid() == 1) ? "auto" : "login";
	if ($current_mode ne $conf{ConsoleMode})
	{
	    # If we switch from login to auto or vv, then we
	    # need to quite here
	    goto QUIT1;
	}
	goto INITIAL;
    }
}

#------------------------------------------------------------
QUIT:
#------------------------------------------------------------
{
    if ( $conf {'UnsavedChanges'} eq 'no' )
    {
        goto QUIT1
    }

    ($rc, $choice) = $console->yesno_page
        (
         title   => gettext("*** THERE ARE UNACTIVATED CHANGES - QUIT ANYWAY? ***"),
         text =>
         gettext("Your configuration changes have been saved but have not yet been activated. This may result in unpredictable system behavior. We recommend that you complete the configuration process and activate the changes before exiting the console.") .
         "\n\n" .
         gettext("Are you sure you want to quit with unactivated changes?"),
        );

    goto INITIAL unless ($rc == 0);

}

QUIT1:

system("/usr/bin/tput", "clear");
exit (0);

#------------------------------------------------------------
# ethernetSelect()
# Choose appropriate Ethernet driver for the given interface
# Returns the selection method
#------------------------------------------------------------
sub ethernetSelect($$)
{
    my ($ifName, $confEntry) = @_;
    my $item = 0;
    my @adapters = split(/\n/, esmith::ethernet::probeAdapters());
    my $adapterList;

    if (  ($confEntry eq "EthernetDriver2") ) {
        my ($parameter, $driver, $chipset) = split (/\s+/, $adapters[0], 3);
        if ($driver eq $conf{"EthernetDriver1"})
        {
            @adapters = reverse @adapters;
        }
    }

    if ( scalar @adapters == 0 )
    {
        $adapterList = "    (none)";
    }
    else
    {
        foreach my $adapter ( @adapters )
        {
            my ($parameter, $driver, $chipset) = split (/\s+/, $adapter, 3);
            chomp $chipset;

            $adapterList .= "    " .
                substr("${chipset} (driver ${driver})", 0, 72) . "\n";
        }
    }

    my %tag2driver;
    my @args;

    if ($conf{$confEntry} ne "unknown" && $conf{$confEntry} ne "")
    {
        $tag2driver{keep} = $conf{$confEntry};
        push(@args, $console->keep_option( $conf{$confEntry} ) );
    }

    foreach my $adapter ( @adapters )
    {
        my ($parameter, $driver, $chipset) = split (/\s+/, $adapter, 3);
        chomp($chipset);

        unless ($driver eq $conf{$confEntry})
        {
            my $tag = ++$item . ".";

            $tag2driver{$tag} = $driver;

            my $display_name = gettext("Use") . " " . ${driver} . " " .
                gettext("for chipset") . " " . ${chipset};

            push(@args, $tag, substr($display_name, 0, 65));
        }
    }

    push( @args,
          ++$item . ".",
          sprintf(gettext("Manually select driver for %s ethernet adapter"),
                  $ifName),
        );


    ($rc, $choice) = $console->menu_page
        (
         title => sprintf(gettext("Select %s network ethernet driver"),
                          $ifName),
         text  =>
         sprintf(gettext("You now need to select the proper driver for your %s network ethernet adapter. The server can attempt to do this automatically, or you can do it manually - either by specifying the model of your ethernet adapter or by directly choosing a driver."),
                 $ifName) .
         "\n\n" .
         gettext("The server has detected these ethernet adapters:") .
         "\n\n" .
         $adapterList,
         argsref => \@args,
        );

    return 'CANCEL' unless ($rc == 0);

    my $newDriver = $conf{$confEntry};

    if ( $choice =~ /^${item}/ )
    {
        $newDriver = ethernetManual($ifName);
        return 'CANCEL_MANUAL' if ($newDriver eq 'CANCEL_MANUAL');
    }
    elsif (defined($tag2driver{$choice}) )
    {
        $newDriver = $tag2driver{$choice};
    }

    if ( $newDriver eq $conf{$confEntry} )
    {
        return 'KEEP';
    }

    # Try to load the driver before accepting it.
    system($modprobe, $newDriver) == 0
        or return 'NOLOAD';

    $conf{$confEntry} = $newDriver;
    return 'CHANGE';
}

#------------------------------------------------------------
# Manually choose Ethernet driver for given adapter
#------------------------------------------------------------
sub ethernetManual($)
{
    my ($ifName) = @_;

    my $driver = gettext("unknown");

    my @args =
        (
         "1.",  gettext("Choose driver by specifying ethernet adapter model"),
         "2.",  gettext("Choose driver directly"),
        );

    my ($rc, $choice) = $console->menu_page
        (
         title   => sprintf(gettext("Select %s adapter manually"), $ifName),
         text    => gettext("Please select one of the following:"),
         argsref => \@args
        );

    return 'CANCEL_MANUAL' unless ($rc == 0);

    if ($choice eq "1.")
    {
        # Choose driver by specifying ethernet adapter model
        my @args;

        my $adapters = esmith::ethernet::listAdapters();

        while ( $adapters =~ s/^\s*"([^"]*)"// ) # )"...Keep Emacs happy
        {
            push @args, substr $1, 0, 60;
        }

        my ($rc, $choice) = $console->menu_page
            (
             title => sprintf(gettext("Specify %s adapter and driver"),
                              $ifName),
             text  => sprintf(gettext("Please specify your %s ethernet adapter and corresponding driver"), $ifName),
             argsref => \@args
            );

        return 'CANCEL_MANUAL' unless ($rc == 0);

        $driver = $choice;
    }
    else
    {
        # Choose driver directly

        my @args;

        my $drivers = esmith::ethernet::listDrivers;

        while ($drivers =~ s/^\s*"([^"]*)"//)
        {
            push @args, substr $1, 0, 60;
        }

        my ($rc, $choice) = $console->menu_page
            (
             title   => sprintf(gettext("Specify %s ethernet driver"), $ifName),
             text    => sprintf(gettext("Please specify the driver to use for the %s ethernet adapter"), $ifName),
             argsref => \@args
            );

        return 'CANCEL_MANUAL' unless ($rc == 0);

        $driver = $choice;
    }

    return $driver;
}



#------------------------------------------------------------
# SUPPORT:
#------------------------------------------------------------

sub displaySupport()
{
    my $licenses = esmith::util::getLicenses();

    ($rc, $choice) =
        $console->screen ("--title", gettext("Support and licensing information"),
                          "--scrolltext",
                          "--msgbox",
                          "**********************************************************************" .
                          "\n" .
                          gettext("You can scroll through this document using the up and down arrow keys or the Page Up and Page Down keys.") .
                          "\n" .
                          "**********************************************************************" .
                          "\n\n" .
                          $licenses,
                          SCREEN_ROWS, SCREEN_COLUMNS
                         );

}

#------------------------------------------------------------
# MANAGER:
#------------------------------------------------------------

sub displayManager()
{
    untie %conf;
    tie %conf, 'esmith::config::unsaved';

    ($rc, $choice) = $console->yesno_page
        (
         title => gettext("Access server manager"),
         text  =>
         gettext("This option will start a text-mode browser to access the server manager from this console.  Normally you would access the server manager from a web browser at the following url:") .
         "\n\n" .
         "http://$conf{'SystemName'}/server-manager/" .
         "\n\n" .
         gettext("You should only proceed if you are comfortable using a text-mode browser.  Note that you will be prompted for the administrator password in order to access the server manager.") .
         "\n\n" .
         gettext("NOTE: The 'q' key is used to quit from the text-mode browser.") .
         "\n\n" .
         gettext("Do you wish to proceed?"),
        );

    if ($rc == 0)
    {

        ($rc, $choice) = $console->password_page
            (
             title => gettext("Access server manager with text-mode browser"),
             text  => gettext("Enter the administrator password"),
            );

        if ($rc == 0)
        {
            $ENV{'LYNX_TEMP_SPACE'} = "/tmp";
            system(
                   "/usr/bin/lynx",
                   "-auth=admin:$choice",
                   "-localhost",
                   "-nopause",
                   "-restrictions=all",
                   "-rlogin",
                   "-telnet",
                   "https://localhost/common/noframes"
                  );
        }
    }

    untie %conf;
}

#------------------------------------------------------------
# STATUS:
#------------------------------------------------------------
sub displayStatus()
{
    my $today = `/bin/date '+%A %B %-d, %Y'`;
    chomp ($today);

    my $seconds = `/bin/awk '{ print \$1 }' < /proc/uptime`;
    chomp ($seconds);

    my $days = int ($seconds / 86400);
    $seconds = $seconds % 86400;

    my $hours = int ($seconds / 3600);
    $seconds = $seconds % 3600;

    my $minutes = int ($seconds / 60);
    $seconds = $seconds % 60;

    ($rc, $choice) = $console->screen
        (
         "--title",  gettext("Status of this server as of") . " " . $today,

         "--msgbox", gettext("This server has been running for") . " " .
         $days    . " " . gettext("days")  . ", " .
         $hours   . " " . gettext("hours") . ", " .
         $minutes . " " . gettext("minutes"),
         7, SCREEN_COLUMNS
        );
}

#------------------------------------------------------------
# REBOOT_SHUTDOWN:
#------------------------------------------------------------
sub rebootShutdown()
{
    my @args =
        (
         gettext("Reboot"),     gettext("Reboot this server"),
         gettext("Shutdown"),   gettext("Shutdown this server"),
        );

    ($rc, $choice) = $console->menu_page
        (
         title => gettext("Reboot or shutdown this server"),
         text  =>
         gettext("Please select whether you wish to reboot or shutdown. The process will start as soon as you make your selection.") .
         "\n\n" .
         gettext("If you have an older computer without power management, the shutdown process will perform a clean halt of all system services, but will not actually power off your computer. In this case, wait for the power down message and then shut off the power manually.") .
         "\n\n" .
         gettext("If you have changed your mind and do not want to reboot or shutdown, use the Tab key to select Cancel, then press Enter."),
         argsref => \@args,
         left => gettext("Cancel"),
         right => gettext("OK"),
        );

    return unless ($rc == 0);

    if ($choice eq gettext('Shutdown'))
    {
        system("/usr/bin/tput", "clear");
        system("/sbin/e-smith/signal-event", "halt");
    }
    else
    {
        system("/usr/bin/tput", "clear");
        system("/sbin/e-smith/signal-event", "reboot");
    }

    # A bit of a hack to avoid the console restarting before the
    # reboot takes effect.

    sleep(600);
}

#------------------------------------------------------------
# TEST:
#------------------------------------------------------------
sub testInternet()
{
    use LWP;
    use HTTP::Request::Common;

    ($rc, $choice) = $console->yesno_page
        (
         title => gettext("Test Internet access"),
         text  =>
         gettext("After your Internet connection is operational and your server has been connected and configured, this test will verify that your server can communicate with the Internet.") .
         "\n\n" .
         gettext("Do you wish to run the test?"),
        );

    return unless ($rc == 0);

    # get system parameters (filter out accounts and passwords)

    my @results = ();
    foreach my $key (keys %conf)
    {
        unless (($key =~ /Account$/) || ($key =~ /Password$/))
        {
            push @results, $key;
        }
    }

    use constant SERVERTEST => 'http://www.google.com/';

    my $ua = LWP::UserAgent->new;

    # add proxy arguments if appropriate
    if ($conf{'SquidParent'} && ($conf{'SquidParent'} ne ''))
    {
        my $parent = $conf{'SquidParent'};
        my $port = $conf{'SquidParentPort'} || "3128";
        $ua->proxy(['http', 'ftp'], "http://$parent:$port/");
    }

    print '-' x 75 . "\n";
    print gettext("Attempting to test Internet connection.") . "\n";
    print gettext("If this test takes too long, please halt it by typing Ctrl-C.") . "\n";
    print '-' x 75 . "\n";

    my $response = $ua->get(SERVERTEST);

    if ($response->is_success)
    {
        ($rc, $choice) = $console->message_page
            (
             title => gettext("Internet connection successful"),
             text  =>
             gettext("The test was successful! Your server was able to communicate."),
            );
    }
    else
    {
        warn gettext("Response to Internet test was"), ": ",
            $response->message,
                "\n";

        ($rc, $choice) = $console->message_page
            (
             title => "Internet connection failed",
             text  =>
             gettext("The test failed. Your server was unable to establish contact with the Internet.") .
             "\n\n" .
             gettext("Please check that your server is correctly configured. A reboot may be required if certain settings are modified and the configuration process will advise you if this is required.") .
             "\n\n" .
             gettext("You might also want to check with your Internet provider to make sure that your Internet connection is working properly.")
            );
    }
}

sub build_menu
{
    my @items = ();

    my $menu_dir = "/sbin/e-smith/console-menu-items";

    opendir(ITEMS, $menu_dir);

    while (defined(my $item = readdir(ITEMS)))
    {
	next unless -f "$menu_dir/$item";

	if ($item =~ /([\w\.]+)/)
	{
	    $item = $1;
	}
	else
	{
	    warn "Don't know what to do with $menu_dir/$item\n";
	    next;
	}

	my $obj = require "$menu_dir/$item";

	push @items, $obj;
    }

    close ITEMS;

    my $number = 1;

    my %menu2object;

    foreach my $item (sort { $a->order <=> $b->order } @items)
    {
	next if ($item->order < 0);

	$menu2object{$number++ . "."} = $item;
    }
     
    return %menu2object;
}

