#!/usr/bin/perl -wT
#----------------------------------------------------------------------
# heading     : Administration
# description : Backup or restore
# navigation  : 4000 4200
# Copyright (C) 2002 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.
#----------------------------------------------------------------------
use strict;
use esmith::FormMagick;
use esmith::ConfigDB;
use esmith::Backup;
use esmith::BackupHistoryDB;
use esmith::BlockDevices;
use esmith::AccountsDB;
use esmith::cgi;
use esmith::util;
use esmith::lockfile;
use File::Find;
use File::Path qw(make_path remove_tree);

$File::Find::dont_use_nlink = 1;  # fix for Windows shares

my $fm = esmith::FormMagick->new();

# These statements _must_ come _after_ the FormMagick constructor. It sets
# POST_MAX and DISABLE_UPLOADS to values that will cause this script to fail
# on restores and verification of files.
$CGI::POST_MAX = -1; # allow any size POST
$CGI::DISABLE_UPLOADS = 0; # need to upload to restore from desktop

$fm->parse_xml();

my $conf = esmith::ConfigDB->open()
	|| die $fm->localise('CANNOT_OPEN').'configuration db';

my $restore = esmith::ConfigDB->open('/etc/e-smith/restore')
	|| die $fm->localise('CANNOT_OPEN').'/etc/e-smith/restore';

my $es_backup = new esmith::Backup or die "Couldn't create Backup object\n";

my @directories = $es_backup->restore_list;
@directories = grep { -e "/$_" } @directories;

my @backup_excludes = $es_backup->excludes;

# Unbuffer standard output so that files and directories are listed as
# they are restored
$| = 1;

# Store away current gid of 'www' group.
my $www_gid = getgrnam("www");

#------------------------------------------------------------
# examine state parameter and display the appropriate form
#------------------------------------------------------------

my $q = $fm->{cgi};

if (! grep (/^state$/, $q->param))
{
    showInitial ($q, '');
}
elsif ($q->param ('state') eq "perform")
{
    performAndShowResult ($q);
}
elsif ($q->param ('state') eq "tape-configure")
{
    updateTapeBackupConfig($q);
}
elsif ($q->param ('state') eq "tape-restore")
{
    performTapeRestore ($q);
}
elsif ($q->param ('state') eq "workstn-configure")
{
    WorkstnBackupConfig1($q);
}
elsif ($q->param ('state') eq "workstn-configure1")
{
    updateWorkstnBackupConfig($q);
}
elsif ($q->param ('state') eq "workstn-verify")
{
    performWorkstnVerify($q);
}
elsif ($q->param ('state') eq "workstn-restore")
{
    performWorkstnRestore ($q);
}
elsif ($q->param ('state') eq "workstn-sel-restore")
{
    performWorkstnSelRestore ($q);
}
elsif ($q->param ('state') eq "workstn-sel-restore2")
{
    performWorkstnSelRestore2 ($q);
}
else
{
    esmith::cgi::genStateError ($q, undef);
}

exit (0);

#------------------------------------------------------------
# subroutine to display initial form
#------------------------------------------------------------

sub showInitial
{
    my ($q, $msg) = @_;

	my $rec = $restore->get('restore');
	if($msg eq '')
	{
		if($rec)
		{
			$msg = $rec->prop('errmsg') || '';
			$rec->delete_prop('errmsg');
		}
	}

    if ($msg eq '')
    {
	esmith::cgi::genHeaderNonCacheable ($q, undef,
		$fm->localise('BACKUP_TITLE'));
    }
    else
    {
	esmith::cgi::genHeaderNonCacheable
	($q, undef, $fm->localise('OPERATION_STATUS_REPORT'));

	print $q->div ({-class => "sme-error"}, $msg);
	print $q->hr;
    }
    print $q->div({-class => 'error'},
	$q->h5('Warning: a reboot is required before proceeding!
	    Failure to reboot now may leave your system in an unknown
	    state!'))
	    if $conf->get_prop('bootstrap-console', 'Run') eq 'yes';

    my ($tarsize, $dumpsize, undef, undef) = &CalculateSizes();

    my $module = $conf->get('backup');
    if ($module)
    {
	$module = $module->prop('Program');
    }

    # The default e-smith backup program is flexbackup.

    unless (defined $module)
    {
	$module = "flexbackup";
    }
    elsif ($module eq '')
    {
	$module = "flexbackup";
    }

    # Hack to evaluate embedded vars
    print eval 'return "'.$fm->localise('BACKUP_DESC_DAR').'\n";';

    if ($tarsize =~ /Tb/ or $tarsize =~ /(\d+)Gb/ and $1 >= 2)
    {
        print $fm->localise("BACKUP_DESKTOP_TOO_BIG"), "\n";
    }

    print $q->h2($fm->localise("BACKUP_CONFIG_STATUS")),"\n";

    my $backup_status = $conf->get('backup');
    if ($backup_status)
    {
	$backup_status = $backup_status->prop('status');
    }

    if (defined $backup_status && $backup_status eq "enabled")
    {
	my $backupTime = $conf->get('backup')->prop('backupTime');
	my $reminderTime = $conf->get('backup')->prop('reminderTime');

	print $q->p ($fm->localise('TAPE_BACKUPS_ENABLED'),
		$fm->localise('BACKUPS_RUN_AT'),$q->b($backupTime),
		$fm->localise('REMINDER_MESSAGE_AT'),$q->b($reminderTime)),
		"\n";
    }
    else
    {
	print $q->p($fm->localise('TAPE_BACKUPS_DISABLED')),"\n";
    }

    my $backupwk_status = $conf->get('backupwk');
    if ($backupwk_status)
    {
	$backupwk_status = $backupwk_status->prop('status');
    }

    if (defined $backupwk_status && $backupwk_status eq "enabled")
    {
	my $backupwkTime = $conf->get('backupwk')->prop('BackupTime');

	print $q->p ($fm->localise('WORKSTN_BACKUPS_ENABLED'),
		$fm->localise('WKBACKUPS_RUN_AT'),$q->b($backupwkTime));
    }
    else
    {
	print $q->p($fm->localise('WORKSTN_BACKUPS_DISABLED'));
    }

    my %labels = (
	    "desktop-backup"    =>  $fm->localise('DESKTOP_BACKUP'),
	    "tape-configure"    =>  $fm->localise('TAPE_CONFIGURE'),
	    "tape-restore"      =>  $fm->localise('TAPE_RESTORE'),
	    "workstn-configure"    =>  $fm->localise('WORKSTN_CONFIGURE'),
	    "workstn-verify"    =>  $fm->localise('WORKSTN_VERIFY'),
	    "workstn-restore"      =>  $fm->localise('WORKSTN_RESTORE'),
	    "workstn-sel-restore"      =>  $fm->localise('WORKSTN_SEL_RESTORE'),
	);

    my @labels = (
	    'desktop-backup',
	    'tape-configure',
	    'tape-restore',
	    'workstn-configure',
	    'workstn-verify',
	    'workstn-restore',
	    'workstn-sel-restore',
	);

    my $default_action = 'desktop-backup';

    my $restore_state;
    if($rec)
    {
	$restore_state = $rec->prop('state');
    }

    unless (defined $restore_state)
    {
	# Undefined, set it to idle
	if ($rec)
	{
	    $rec->reset_props(type=>'status', state=>'idle', finish=>0,
		start=>0);
	}
	else
	{
	    $rec = $restore->new_record('restore',
		{type=>'status', state=>'idle', finish=>0, start=>0});
	}
	$restore_state = 'idle';
    }
    elsif ($restore_state eq 'running')
    {
	my $start = $rec->prop('start');
	$start = scalar localtime($start);

	print $q->p ($fm->localise('RESTORE_IN_PROGRESS_BEGAN_AT')
		. "<b>$start</b>.\n" );

	%labels = (
		"refresh"	=> $fm->localise('REFRESH_THIS_DISPLAY'),
		"tape-configure" => $fm->localise('CONFIGURE_TAPE_BACKUP'),
		"workstn-configure" => $fm->localise('CONFIGURE_WORKSTN_BACKUP'),
	    );

	@labels = (
		'refresh',
		'tape-configure',
		'workstn-configure',
	    );

	$default_action = 'refresh';
    }
    elsif ($restore_state eq 'complete')
    {
        my $start = $rec->prop('start');
        $start = scalar localtime($start);
        my $finish = $rec->prop('finish');
        $finish = scalar localtime($finish);

        print $q->p ($fm->localise('RESTORE_COMPLETED'),$q->br(),
                     $fm->localise('STARTED_AT'),$q->b($start),$q->br(),
                     $fm->localise('FINISHED_AT'),$q->b($finish)),"\n";

        print $q->p (
                     $q->b ($fm->localise('YOU_MUST_REBOOT')
                           )
                    ),"\n";

        $default_action = 'reboot';
    }
    else
    {
	# Unknown state. Reset it to idle

	$rec->set_prop('state', 'idle');
	$restore_state = 'idle';
    }

    print $q->startform(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	),"\n";

    print $q->start_table ({-class => "sme-noborders"}),"\n";

    if ($default_action eq 'reboot')
    {
        print $q->start_table ({width => "100%", -class => "sme-noborders"}),"\n";
        print esmith::cgi::genButtonRow(
                $q,
                $q->submit (-name => 'action', -value =>
                $fm->localise('REBOOT'))
        );
        # Put in a hidden widget to store the reboot value.
        print $q->hidden(
                        -name => 'function',
                        -value => 'reboot'
                        ),"\n";
        print $q->end_table,"\n";
    }
    else
    {
	print $q->Tr(
	    $q->td({-class => "sme-noborders-label"},    
                $fm->localise("SELECT_AN_ACTION")),
	    $q->td({-class => "sme-noborders-content"},    
                $q->popup_menu (
                    -name => 'function',
                    -values => [ @labels ],
                    -default => $default_action,
                    -labels => \%labels
		)
	    )
	),"\n";
	
    }

    print $q->end_table,"\n";

    if ($default_action ne 'reboot')
    {
        print $q->start_table ({width => "100%", -class => "sme-noborders"}),
		"\n";

        print esmith::cgi::genButtonRow(
                $q,
                $q->submit (-name => 'action', -value =>
                $fm->localise('PERFORM'))
        );

	print $q->end_table,"\n";
    }

    print $q->hidden (
	    -name => 'state',
	    -override => 1,
	    -default => 'perform'
	),"\n";

    print $q->endform,"\n";

    esmith::cgi::genFooter($fm);

    return;
}

sub performAndShowResult
{
    my ($q) = @_;

    my $function = $q->param ('function');

    if ($function eq 'refresh')
    {
	showInitial ($q, '');
    }
    elsif ($function eq 'reboot')
    {
	performReboot();
    }
    elsif ($function eq 'desktop-backup')
    {
	desktopBackup();
    }
    elsif ($function eq 'tape-configure')
    {
	TapeBackupConfig ($q);
    }
    elsif ($function eq 'tape-restore')
    {
	tapeRestore();
    }
    elsif ($function eq 'workstn-configure')
    {
	WorkstnBackupConfig ($q);
    }
    elsif ($function eq 'workstn-verify')
    {
	workstnVerify();
    }
    elsif ($function eq 'workstn-restore')
    {
	workstnRestore();
    }
    elsif ($function eq 'workstn-sel-restore')
    {
	workstnSelRestore();
    }
    else
    {
	# Unknown function - refresh the screen anyway
	showInitial ($q, 'unknown');
    }

    return;

    esmith::cgi::genHeaderNonCacheable ($q, undef,
	$fm->localise("X_BACKUP_OR_RESTORE"));
    print $q->p ( $function );
    esmith::cgi::genFooter($fm);
}

sub desktopBackupRecordStatus
{
    my ($backup, $phase, $status) = @_;
    my $now = time();

    warn("Backup terminated: $phase failed - status: $status\n");
    $backup->set_prop('EndEpochTime', "$now");
    $backup->set_prop('Result', "$phase:$status");
}

sub desktopBackup ()
{
    # Generate a header that will trigger a download and send data as
    # an octet stream.

    my $backups = esmith::BackupHistoryDB->open;
    my $now = time();
    my $backup_rec = $backups->new_record($now, {
				type => 'backup_record',
				BackupType => 'desktop',
				StartEpochTime => $now,
			    });
    my $CompressionLevel = $conf->get_prop("backupconsole", "CompressionLevel") || "-6";
    my @exclude = map (" --exclude=$_",@backup_excludes);

    # Dump the current mysql tables so that they are part of the image.
    # The events handle cases where mysqld is not enabled, and/or is
    # not running.

    my $status = system("/sbin/e-smith/signal-event", "pre-backup", "desktop");
    if ($status)
    {
	desktopBackupRecordStatus($backup_rec, 'pre-backup', $status);
	esmith::cgi::genHeaderNonCacheable(
	    $fm->{cgi},
	    undef, $fm->localise('OPERATION_STATUS_REPORT'));
	esmith::cgi::genResult(
	    $fm->{cgi}, $fm->localise('ERR_PRE_BACKUP'));
	return;
    }

    print "Expires: 0\n";
    print "Content-type: application/octet-stream\n";
    print "Content-disposition: attachment; filename=smeserver.tgz\n";
    print "\n";
    setpgrp;
    my $ourpgrp = getpgrp;
    local $SIG{PIPE} = sub
	    {
		local $SIG{HUP} = 'IGNORE';
		warn "Got sigpipe - sending HUP to $ourpgrp\n";
		kill HUP => -$ourpgrp;
		desktopBackupRecordStatus($backup_rec,
		    'send2browser', 'Incomplete');
		exit 1;
	    };

    open(RD,
	    "/bin/tar --directory / --create @directories --file=-"
	    . "@exclude | /usr/bin/gzip $CompressionLevel |"
	);

    while (<RD>)
    {
	print;
    }

    close RD;

    # Remove the dumped tables.

    $status = system("/sbin/e-smith/signal-event", "post-backup", "desktop");
    if ($status)
    {
	desktopBackupRecordStatus($backup_rec, 'post-backup', $status);
	die ($fm->localise('ERR_POST_BACKUP'),"\n");
    }
    $now = time();
    $backup_rec->set_prop('EndEpochTime', "$now");
    $backup_rec->set_prop('Result', "0");
}

sub TapeBackupConfig
{
    my ($q) = @_;
    my $enabledChk = "";
    my $backupAMPM = 'AM';
    my $backupMin;
    my $backupHour;
    my $reminderAMPM = 'AM';
    my $reminderMin;
    my $reminderHour;

    esmith::cgi::genHeaderNonCacheable(
	$q, undef, $fm->localise('ENABLE_DISABLE_TAPE'));

    print $q->p ($fm->localise('TAPE_CONFIG_DESC'));

    # Obtain time for backup from the backup cron template
    my $rec = $conf->get('backup');
    my $backupTime = "2:00";
    if ($rec)
    {
	$backupTime = $rec->prop('backupTime') || "2:00";
    }

    ($backupHour, $backupMin) = split (":", $backupTime, -1);

    if ($backupHour > 11)
    {
	if ($backupHour > 12)
	{
	    $backupHour -= 12;
	}
	$backupAMPM = 'PM';
    }

    # Obtain time for reminder notice from the backup cron template
    my $reminderTime = "14:00";
    if ($rec)
    {
	$reminderTime = $rec->prop('reminderTime') || "14:00";
    }

    ($reminderHour, $reminderMin) = split (":", $reminderTime, -1);

    if ($reminderHour > 12)
    {
	$reminderHour -= 12;
	$reminderAMPM = 'PM';
    }

    print $q->startform(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);

    print $q->start_table ({-class => "sme-noborders"});

    my $backup_status;
    if ($rec)
    {
	$backup_status = $rec->prop('status');
    }

    if (defined $backup_status && $backup_status eq "enabled")
    {
	$enabledChk = "checked";
    }

    print $q->Tr(
	    $q->td(
		    $fm->localise('ENABLE_TAPE_BACKUP')
		    . " <input type=\"checkbox\""
		    . " name=\"tapebackup\""
		    . " $enabledChk"
		    . " value=\"on\">"
		)
	);

    print $q->Tr(
		    esmith::cgi::genCell(
			    $q,$fm->localise('TAPE_BACKUP_TIME')
			),

	esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupHour',
						-override => 1,
						-default => $backupHour,
						-size => 2)),

	esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupMin',
						-override => 1,
						-default => $backupMin,
						-size => 2)),

	esmith::cgi::genCell ($q, "AM/PM:"),

	esmith::cgi::genCell ($q, $q->popup_menu (-name => 'backupAMPM',
						-values => ['AM', 'PM'],
						-default => $backupAMPM)));

    my %timelabels=('AM' => $fm->localise('AM'),'PM' => $fm->localise('PM'));
    print $q->Tr(
		    esmith::cgi::genCell(
			    $q, $fm->localise('LOAD_TAPE_REMINDER_TIME')
			),

	    esmith::cgi::genCell(
		    $q,
		    $q->textfield(
			    -name  => 'reminderHour',
			    -override => 1,
			    -default => $reminderHour,
			    -size => 2
			)
		),

	    esmith::cgi::genCell(
		    $q,
		    $q->textfield(
			    -name  => 'reminderMin',
			    -override => 1,
			    -default => $reminderMin,
			    -size => 2
			)
		),

	    esmith::cgi::genCell($q, $fm->localise("AM/PM").":"),

	    esmith::cgi::genCell(
		    $q,
		    $q->popup_menu(
			    -name => 'reminderAMPM',
			    -values => ['AM', 'PM'],
			    -labels => \%timelabels,
			    -default => $reminderAMPM
			)
		)
	);

    print "</table>\n";
    print $q->start_table ({width => "100%", -class => "sme-noborders"});
    print $q->Tr($q->th({-class => "sme-layout"},
		    $q->submit(
			    -name => 'action',
			    -value => $fm->localise('UPDATE_CONF')
		    )
		)
	);

    print $q->hidden(
	    -name => 'state',
	    -override => 1,
	    -default => 'tape-configure'
	);

    print $q->endform;
    print '</table>';

    esmith::cgi::genFooter($fm);
    return;
}

sub updateTapeBackupConfig
{
    my ($q) = @_;

    my $status = $q->param ('tapebackup');
    my $ampm;

    esmith::cgi::genHeaderNonCacheable(
	    $q,
	    undef, $fm->localise('UPDATING_TAPE_CONF')
	);

    if (defined $status && $status eq "on")
    {

    #--------------------------------------------------
    # Untaint parameters and check for validity
    #--------------------------------------------------

	my $backupHour = $q->param ('backupHour');
	if ($backupHour =~ /^(.*)$/) {
	    $backupHour = $1;
	} else {
	    $backupHour = "12";
	}
	if (($backupHour < 1) || ($backupHour > 12))
	{
	    esmith::cgi::genResult(
		    $fm->{cgi}, $fm->localise('ERR_INVALID_HOUR').$backupHour.
			$fm->localise('BETWEEN_1_AND_12')
		);

	    return;
	}

	my $backupMin = $q->param ('backupMin');
    	if ($backupMin =~ /^(.*)$/) {
	    $backupMin = $1;
    	} else {
	    $backupMin = "0";
    	}
	if (($backupMin < 0) || ($backupMin > 59))
    	{
	    esmith::cgi::genResult(
		    $fm->{cgi}, $fm->localise('ERR_INVALID_MINUTE').$backupMin.
			$fm->localise('BETWEEN_0_AND_59')
		);

	    return;
    	}

	$backupMin = sprintf("%02d", $backupMin);

	$ampm = $q->param ('backupAMPM');
	if ($ampm =~ /^(.*)$/) {
	    $ampm = $1;
    	} else {
	    $ampm = "AM";
    	}

    	# convert to 24 hour time

    	$backupHour = $backupHour % 12;
    	if ($ampm eq "PM")
    	{
	    $backupHour = $backupHour + 12;
    	}

    	my $reminderHour = $q->param ('reminderHour');
    	if ($reminderHour =~ /^(.*)$/) {
	    $reminderHour = $1;
    	} else {
	    $reminderHour = "12";
    	}
    	if (($reminderHour < 1) || ($reminderHour > 12))
    	{
	    esmith::cgi::genResult(
			$fm->{cgi}, 
			$fm->localise('ERR_INVALID_REMINDER_HOUR').$reminderHour
			.$fm->localise('BETWEEN_1_AND_12')
		);

	    return;
    	}

    	my $reminderMin = $q->param ('reminderMin');
    	if ($reminderMin =~ /^(.*)$/) {
	    $reminderMin = $1;
    	} else {
	    $reminderMin = "0";
    	}
    	if (($reminderMin < 0) || ($reminderMin > 59))
    	{
	    esmith::cgi::genResult(
		    $fm->{cgi}, $fm->localise('ERR_INVALID_REMINDER_MINUTE').
			$reminderMin.$fm->localise('BETWEEN_0_AND_59')
		);
	    return;
    	}

	$reminderMin = sprintf("%02d", $reminderMin);

    	$ampm = $q->param ('reminderAMPM');
    	if ($ampm =~ /^(.*)$/) {
	    $ampm = $1;
    	} else {
	    $ampm = "AM";
    	}

    	# convert to 24 hour time

	$reminderHour = $reminderHour % 12;
    	if ($ampm eq "PM")
    	{
	    $reminderHour = $reminderHour + 12;
    	}

	# variables passed validity checks, set configuration database values
	my $old = $conf->get('UnsavedChanges')->value;

	my $rec = $conf->get('backup');
	unless (defined $rec)
	{
	    $rec = $conf->new_record('backup', {type=>'service'});
	}

	$rec->set_prop('status', 'enabled');

	my $module = $rec->prop('Program');

	# The default e-smith backup program is flexbackup.

	unless (defined $module)
	{
	    $module = "flexbackup";
	}
	elsif ($module eq '')
	{
	    $module = "flexbackup";
	}

	$rec->set_prop('Program', $module);
	$rec->set_prop('backupTime', "$backupHour:$backupMin");
	$rec->set_prop('reminderTime', "$reminderHour:$reminderMin");

	$conf->get('UnsavedChanges')->set_value($old);

	system("/sbin/e-smith/signal-event", "conf-backup") == 0
	    or die($fm->localise('ERR_CONF_BACKUP'),"\n");

	esmith::cgi::genResult(
		$fm->{cgi}, $fm->localise('SUCCESSFULLY_ENABLED_TAPE').$q->br().
		$fm->localise('WITH_BACKUP_TIME')."$backupHour:$backupMin".
		$q->br().$fm->localise('WITH_REMINDER_TIME').
		"$reminderHour:$reminderMin");
    }
    else
    {
	# set service to disabled
	my $old = $conf->get('UnsavedChanges')->value;

	my $rec = $conf->get('backup');
	unless ($rec)
	{
	    $rec = $conf->new_record('backup', {type=>'service'});
	}

	$rec->set_prop('status', 'disabled');
	$conf->get('UnsavedChanges')->set_value($old);

	system("/sbin/e-smith/signal-event", "conf-backup") == 0
	    or die($fm->localise('ERR_CONF_BACKUP')."\n");

	esmith::cgi::genResult(
		$fm->{cgi}, $fm->localise('SUCCESSFULLY_DISABLED')
	    );
    }

    return;
}

sub tapeRestore ()
{
    esmith::cgi::genHeaderNonCacheable(
	$q, undef, $fm->localise('RESTORE_CONF_FROM_TAPE'));

    print $fm->localise('RESTORE_CONF_FROM_TAPE_DESC');

    print $q->start_multipart_form(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);

    print $q->start_table ({width => "100%", -class => "sme-noborders"});

    print esmith::cgi::genButtonRow(
		    $q,
		    $q->submit (-name => 'action',
                                -value => $fm->localise('RESTORE_FROM_TAPE'))
	);
    print "</table>\n";
	print $q->hidden(
		-name => 'state',
		-override => 1,
		-default => 'tape-restore'
	    );

	print $q->endform;
	esmith::cgi::genFooter($fm);
}

sub performTapeRestore
{
    my ($q) = @_;

    #----------------------------------------
    # restore system from backup tape
    #----------------------------------------

    my $lock_file = "/var/lock/subsys/e-smith-restore";
    my $file_handle = &esmith::lockfile::LockFileOrReturn($lock_file);

    unless ($file_handle)
    {
	esmith::cgi::genHeaderNonCacheable(
		$q,
		undef,
		$fm->localise('UNABLE_TO_RESTORE_CONF')
	    );

	print $q->p (
	    $q->b ($fm->localise('ANOTHER_RESTORE_IN_PROGRESS')
		)
	    );

	esmith::cgi::genFooter($fm);
	return;
    }

    my $rec = $restore->get('restore');
    $rec->set_prop('state', 'running');
    $rec->set_prop('start', time);

	my $sec = 10;
	print "Refresh: $sec; URL=/server-manager/cgi-bin/backup\n";
    esmith::cgi::genHeaderNonCacheable(
	    $q, undef, $fm->localise()
	);

    print $q->p($fm->localise('NOW_RESTORING_FROM_TAPE')
	);

    print $q->p (
	$q->b ($fm->localise('MUST_REBOOT_AFTER_RESTORE'))
	);

	print $q->p($fm->localise('PAGE_REFRESH_IN', {sec=>$sec}));

    my $child;

    if ($child = fork)
    {
	# Parent

	$SIG{'CHLD'} = 'IGNORE';
	&esmith::lockfile::UnlockFile($file_handle);

	esmith::cgi::genFooter($fm);
	return;
    }
    elsif (defined $child)
    {
	# Child

	# Re-establish the lock. Wait till it is relinquished by the parent.

	$file_handle = &esmith::lockfile::LockFileOrWait($lock_file);

	# Close STDOUT so that the web server connection is closed.

	close STDOUT;

	# Now reopen STDOUT for the child. Redirect it to STDERR.

	open(STDOUT, ">&STDERR");

	unless(system("/sbin/e-smith/signal-event", "pre-restore") == 0)
	{
		$rec->set_prop('errmsg', $fm->localise('ERR_PRE_RESTORE'));
		$rec->delete_prop('state');
	    die ($fm->localise('ERR_PRE_RESTORE'),"\n");
	}
	unless(system("/sbin/e-smith/signal-event", "restore-tape") == 0)
	{
		$rec->set_prop('errmsg', $fm->localise('ERR_RESTORING_FROM_TAPE'));
		$rec->delete_prop('state');
	    die ($fm->localise('ERR_RESTORING_FROM_TAPE')."\n");
	}

	#----------------------------------------
	# regenerate configuration files
	#----------------------------------------

	unless(system("/usr/sbin/groupmod", "-g", "$www_gid", "www") == 0)
	{
		$rec->set_prop('errmsg', $rec->prop('errmsg').'<br>'.
		    $fm->localise('ERR_RESTORING_GID'));
	    warn ($fm->localise('ERR_RESTORING_GID')."\n");
	}
	unless(system("/usr/sbin/usermod", "-g", "$www_gid", "www") == 0)
	{
		$rec->set_prop('errmsg', $rec->prop('errmsg').'<br>'.
			$fm->localise('ERR_RESTORING_INITIAL_GRP'));
	    warn ($fm->localise('ERR_RESTORING_INITIAL_GRP')."\n");
	}
	unless(system("/sbin/e-smith/signal-event", "post-upgrade") == 0)
	{
		$rec->set_prop('errmsg', $rec->prop('errmsg').'<br>'.
			$fm->localise('ERR_UPDATING_CONF_AFTER_TAPE_RESTORE'));
		$rec->delete_prop('state');
	    die ($fm->localise('ERR_UPDATING_CONF_AFTER_TAPE_RESTORE'));
	}

	my $finish = time;
	$rec->set_prop('state', 'complete');
	$rec->set_prop('finish', $finish);

	my $start = $rec->prop('start');
	$start = scalar localtime($start);
	$finish = scalar localtime($finish);

	&esmith::lockfile::UnlockFile($file_handle);

	exit;
    }
    else
    {
	# Error

	$rec->delete_prop('state');
	$rec->set_prop('errmsg', $fm->localise('COULD_NOT_FORK'));
	die ($fm->localise("COULD_NOT_FORK")."$!\n");
    }
}

sub WorkstnBackupConfig
{
    my ($q) = @_;
    my $backupwk_status;
    my $enabledIncOnlyTimeout = "";
    my $smbv1 = "";
    my $backupwkLogin = 'backup';
    my $backupwkPassword = 'backup';
    my $backupwkStation = 'host';
    my $backupwkFolder = 'share';
    my $backupwkMount = '/mnt/smb';
    my $setsNumber;
    my $filesinset;
    my $backupwkTime;
    my $backupwkTimeout;
    my $backupwkIncOnlyTimeout;
    my $compression;
    my $VFSType;
    my $dof;
    my @dlabels = split(' ', $fm->localise('DOW'));
    my @VFST = ('cifs', 'nfs', 'usb','mnt');
    my %VFST = ('cifs', $fm->localise('cifs'), 'nfs', $fm->localise('nfs'), 'usb', $fm->localise('local removable disk'), 'mnt', $fm->localise('Mounted disk')); 
        
    # Obtain backup informations from configuration
    my $rec = $conf->get('backupwk');
    if ($rec)
    {
	$backupwkTime = $rec->prop('BackupTime') || '2:00';
	$backupwkLogin = $rec->prop('Login') || 'backup';
	$backupwkPassword = $rec->prop('Password') || 'backup';
	$backupwkStation = $rec->prop('SmbHost') || 'host';
	$backupwkFolder = $rec->prop('SmbShare') || 'share';
	$backupwkMount = $rec->prop('Mount') || '/mnt/smb';
	$setsNumber = $rec->prop('SetsMax') || '1';
	$filesinset = $rec->prop('DaysInSet') || '1';
	$backupwkTimeout = $rec->prop('Timeout') || '12';
	$backupwkIncOnlyTimeout = $rec->prop('IncOnlyTimeout') || 'yes';
	$compression = $rec->prop('Compression') || '0';
	$dof = (defined $rec->prop('FullDay')) ? $rec->prop('FullDay') : '7';
	$smbv1 = ( ($rec->prop('SmbV1') || 'disabled') eq "enabled" ) ? "enabled" : "disabled" ;
	$VFSType = $rec->prop('VFSType') || 'cifs';
	$backupwk_status = $rec->prop('status');
    }

    esmith::cgi::genHeaderNonCacheable($q, undef, $fm->localise('CONFIGURE_WORKSTN_BACKUP'));

    if ($rec) 
    {
        print $fm->localise('WORKSTN_BACKUP_DESC');
        print $fm->localise('WORKSTN_BACKUP_ENABLED'), $q->b(' '.$fm->localise(uc($backupwk_status))), '.<br/>';
        if ($VFSType eq 'usb')
        {
            print $fm->localise('WORKSTN_BACKUP_USB'), ' ', $backupwkFolder, '<br/>';
        }
        elsif ($VFSType eq 'mnt')
        {
            print $fm->localise('WORKSTN_BACKUP_MNT'), ' ', $backupwkMount, '<br/>';
        }
        else
        {
            print $fm->localise('WORKSTN_BACKUP_HOST'), ' ', $backupwkStation;
            print ' ', $fm->localise('WORKSTN_BACKUP_VFSTYPE'), ' ', $VFSType, '<br/>';
            print $fm->localise('WORKSTN_BACKUP_SHARE'), ' ', $backupwkFolder, '<br/>';
        }
        if ($VFSType eq 'cifs')
        {
            print $fm->localise('LOGIN'), ' ', $backupwkLogin, '<br/>';
            print $fm->localise('PASSWORD'), ' ********<br/>';
	    print $fm->localise('SMBV1'), ' ', $smbv1, '<br/>';
        }
        print $fm->localise('WORKSTN_BACKUP_SETSNUM'), ' ', $setsNumber, '<br/>';
        print $fm->localise('WORKSTN_BACKUP_DAYSINSET'), ' ', $filesinset, '<br/>';
        print $fm->localise('WORKSTN_BACKUP_COMPRESSION'), ' ', $compression, '<br/>';
        print $fm->localise('WORKSTN_BACKUP_TOD'), ' ', $backupwkTime, '<br/>';
        print $fm->localise('WORKSTN_BACKUP_TIMEOUT'), ' ', $backupwkTimeout, ' ', $fm->localise('HOURS');
        if ( $backupwkIncOnlyTimeout eq 'yes' ) 
        {
        print $fm->localise('WORKSTN_BACKUP_INCONLY_TIMEOUT')
        }
        print '<br/>';
        if ( $dof eq '7' ) 
        {
            print $fm->localise('WORKSTN_FULL_BACKUP_EVERYDAY', '<br/>');
        }
        else 
        {
            print $fm->localise('WORKSTN_FULL_BACKUP_DAY'), ' ', $dlabels[$dof], '<br/>';
        }
    }
    else { print $fm->localise('WORKSTN_BACKUP_NOT_CONFIGURED'), '<br/>' }

    print $q->startform(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);

    print $q->start_table ({-class => "sme-noborders"});

    print $q->Tr($q->td($q->h3 ($fm->localise('WORKSTATION_BACKUP_SETCONF'))));


    print $q->Tr(
		    esmith::cgi::genCell(
			    $q,
			    $fm->localise('SELECT_VFS_TYPE')
			),

	esmith::cgi::genCell ($q, $q->popup_menu (-name => 'VFSType',
						-values => [ @VFST ],
						-labels => \%VFST,
						-default => $VFSType)));

    print "</table>\n";

    print $q->start_table ({width => "100%", -class => "sme-noborders"});
    print $q->Tr($q->th({-class => "sme-layout"},
		    $q->submit(
			    -name => 'action',
			    -value => $fm->localise('NEXT')
		    )
		)
	);

    print $q->hidden(
	    -name => 'state',
	    -override => 1,
	    -default => 'workstn-configure'
	);
    print '</table>';

    print $q->endform;

    esmith::cgi::genFooter ($q);
    return;
}

sub WorkstnBackupConfig1
{
    my ($q) = @_;
    my $enabledChk = "";
    my $enabledIncOnlyTimeout = "";
    my $backupwkAMPM = 'AM';
    my $backupwkMin;
    my $backupwkHour;
    my $backupwkLogin = 'backup';
    my $backupwkPassword = 'backup';
    my $backupwkStation = 'host';
    my $backupwkFolder = 'share';
    my $backupwkMount = '';
    my $setsNumber;
    my $filesinset;
    my $backupwkTimeout;
    my $backupwkIncOnlyTimeout;
    my $compression;
    my $VFSType = $q->param ('VFSType');
    my $error="";
    my $dof;
    my $smbv1 = '';
    my @usbdisks;
    my %dlabels = ();
    my @dlabels = split(' ', $fm->localise('DOW'));
    my $i = 0;
    foreach (@dlabels) {
	$dlabels{$i} = $_;
	$i++;
	}
        
    # Obtain backup informations from configuration
    my $rec = $conf->get('backupwk');
    my $backupwkTime = '2:00';
    if ($rec)
    {
	$backupwkTime = $rec->prop('BackupTime') || '2:00';
	$backupwkLogin = $rec->prop('Login') || 'backup';
	$backupwkPassword = $rec->prop('Password') || 'backup';
	$backupwkStation = $rec->prop('SmbHost') || 'host';
	$backupwkFolder = $rec->prop('SmbShare') || 'share';
	$backupwkMount = $rec->prop('Mount') || '';
	$setsNumber = $rec->prop('SetsMax') || '1';
	$filesinset = $rec->prop('DaysInSet') || '1';
	$backupwkTimeout = $rec->prop('Timeout') || '12';
	$backupwkIncOnlyTimeout = $rec->prop('IncOnlyTimeout') || 'yes';
	$compression = $rec->prop('Compression') || '0';
	$dof = (defined $rec->prop('FullDay')) ? $rec->prop('FullDay') : '7';
	$smbv1 = ( ($rec->prop('SmbV1') || 'disabled') eq "enabled" ) ? "checked" : "" ;
    }

    ($backupwkHour, $backupwkMin) = split (':', $backupwkTime, -1);

    if ($backupwkHour > 12)
    {
	$backupwkHour -= 12;
	$backupwkAMPM = 'PM';
    }

    my $backupwk_status;
    if ($rec)
    {
	$backupwk_status = $rec->prop('status');
    }

    if (defined $backupwk_status && $backupwk_status eq 'enabled')
    {
	$enabledChk = 'checked';
    }

    if (defined $backupwkIncOnlyTimeout && $backupwkIncOnlyTimeout eq 'yes')
    {
	$enabledIncOnlyTimeout = 'checked';
    }

    esmith::cgi::genHeaderNonCacheable(
	$q, undef, $fm->localise('CONFIGURE_WORKSTN_BACKUP'));

    if ( $VFSType eq 'usb' ) {
        my $devices = esmith::BlockDevices->new ('allowmount' => 'disabled');
        my ($valid, $invalid) = $devices->checkBackupDrives(0);

        if ( ${$valid}[0] ) {
            foreach ( @{$valid} ) {
                push @usbdisks, $devices->label($_);
            }
        }
        else
        {
            push @usbdisks, $fm->localise('ERR_NO_USB_DISK');
            $error='nousb';
        }
        $devices->destroy;
    }
    if ( $VFSType eq 'mnt' ) 
    {
        @usbdisks = findmnt ();
        unless ($usbdisks[0]){
            push @usbdisks, $fm->localise('ERR_NO_MOUNTED_DISK');
            $error='nomnt';
        }
    }


    print $q->startform(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);

    print $fm->localise('CONFIGURE_WORKSTN_BACKUP_DESC');

    print $q->start_table ({-class => "sme-noborders"});

    print $q->Tr(
	    $q->td(
		    $fm->localise('ENABLE_WORKSTN_BACKUP')
		    . " <input type=\"checkbox\""
		    . " name=\"workstnbackup\""
		    . " $enabledChk"
		    . " value=\"on\">"
		)
	);

    print $q->Tr($q->td($q->h3 ($fm->localise('WORKSTATION_BACKUP_DEST'))));

    if ( $VFSType =~ m/cifs|nfs/s )
    {
        print $q->Tr(esmith::cgi::genCell($q,$fm->localise('WORKSTN_NAME')),
            esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupwkStation',
            -override => 1,
            -default => $backupwkStation,
            -size => 20)),
        );
    }

    if ( $VFSType eq 'usb' )
    {
        print $q->Tr(esmith::cgi::genCell($q,$fm->localise('local removable disk')),
            esmith::cgi::genCell ($q, $q->popup_menu (-name  => 'backupwkFolder',
            -values => [ @usbdisks ],
            -default => $backupwkFolder,)),
        );
    }
    elsif ($VFSType eq 'mnt')
    {
        print $q->Tr(esmith::cgi::genCell($q,$fm->localise('Mounted disk')),
            esmith::cgi::genCell ($q, $q->popup_menu (-name  => 'backupwkFolder',
            -values => [ @usbdisks ],
            -default => $backupwkMount,)),
        );
    }
    else 
    {
        print $q->Tr(esmith::cgi::genCell($q,$fm->localise('SHARED_FOLDER_NAME')),
            esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupwkFolder',
            -override => 1,
            -default => $backupwkFolder,
            -size => 20)),
        );
    }

    if ( $VFSType eq 'cifs' ) {
	print $q->Tr(
		    esmith::cgi::genCell(
			    $q,
			    $fm->localise('WORKSTN_LOGIN')
			),

	    esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupwkLogin',
						-override => 1,
						-default => $backupwkLogin,
						-size => 12)),
	    );

	print $q->Tr(
		    esmith::cgi::genCell(
			    $q,
			    $fm->localise('PASSWORD')
			),

	    esmith::cgi::genCell ($q, $q->password_field (-name  => 'backupwkPassword',
						-override => 1,
						-default => $backupwkPassword,
						-size => 20)),
	    );
#smbv1
        print $q->Tr(
                    esmith::cgi::genCell(
                            $q,
                            $fm->localise('SMBV1')
                        ),

        	     esmith::cgi::genCell (
                    $q,
                    " <input type=\"checkbox\""
                    . " name=\"smbv1\""
                    . " $smbv1"
                    . " value=\"on\">"
            ),

            );

	}

    print '</table>';

    print $q->table ({border => 0, cellspacing => 1, cellpadding => 4});

    print $q->Tr($q->td({-colspan=>4},$q->h3 ($fm->localise('WORKSTN_BACKUP_SETTINGS'))));

    print $q->Tr(
		    esmith::cgi::genCell(
			    $q,
			    $fm->localise('NUMBER_OF_SETS')
			),

	esmith::cgi::genCell ($q, $q->textfield (-name  => 'setsNumber',
						-override => 1,
						-default => $setsNumber,
						-size => 3)),

	esmith::cgi::genCell ($q, $fm->localise('NUMBER_OF_FILES_IN_SET')),
	esmith::cgi::genCell ($q, $q->textfield (-name  => 'filesinset',
						-override => 1,
						-default => $filesinset,
						-size => 3))
	);

    print $q->Tr(
		    esmith::cgi::genCell(
			    $q,
			    $fm->localise('WORKSTN_BACKUP_TIME')
			),

	esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupwkHour',
						-override => 1,
						-default => $backupwkHour,
						-size => 2)),

	esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupwkMin',
						-override => 1,
						-default => $backupwkMin,
						-size => 2)),

	esmith::cgi::genCell ($q, $q->popup_menu (-name => 'backupwkAMPM',
						-values => ['AM', 'PM'],
						-default => $backupwkAMPM)));

    print $q->Tr(
		    esmith::cgi::genCell(
			    $q,
			    $fm->localise('WORKSTN_TIMEOUT')
			),

	esmith::cgi::genCell ($q, $q->textfield (-name  => 'backupwkTimeout',
						-override => 1,
						-default => $backupwkTimeout,
						-size => 2)),

        esmith::cgi::genCell(
			    $q,
			    $fm->localise('INC_ONLY_TIMEOUT')
			),

	esmith::cgi::genCell (
		    $q,
		    " <input type=\"checkbox\""
		    . " name=\"incOnlyTimeout\""
		    . " $enabledIncOnlyTimeout"
		    . " value=\"on\">"
	    ),
	);

    print $q->Tr(
		    esmith::cgi::genCell(
			    $q,
			    $fm->localise('COMPRESSION_LEVEL')
			),

	esmith::cgi::genCell ($q, $q->textfield (-name  => 'compression',
						-override => 1,
						-default => $compression,
						-size => 1)),

        esmith::cgi::genCell(
			    $q,
			    $fm->localise('FULL_ONLY_ON')
			),

	esmith::cgi::genCell (
		    $q,
	        $q->popup_menu (
		    -name => 'dof',
		    -values => [ '7', '0', '1', '2', '3', '4', '5', '6' ],
		    -labels => \%dlabels,
		    -default => $dof))
	);

    print "</table>\n";

    if ($error =~ m/nousb|nomnt/s) {$VFSType = $error;}
    print $q->start_table ({width => "100%", -class => "sme-noborders"});
    print $q->Tr($q->th({-class => "sme-layout"},
		    $q->submit(
			    -name => 'action',
			    -value => $fm->localise('UPDATE_CONF')
		    )
		)
	);

    print $q->hidden(
	    -name => 'state',
	    -override => 1,
	    -default => 'workstn-configure1'
	);
    print $q->hidden(
	    -name => 'VFSType',
	    -override => 1,
	    -default => $VFSType
	);
    print '</table>';

    print $q->endform;

    esmith::cgi::genFooter ($q);
    return;
}

sub updateWorkstnBackupConfig
{
    my ($q) = @_;

    my $status = $q->param ('workstnbackup') || "";
    my $inconly = $q->param ('incOnlyTimeout');
    my $smbv1 = $q->param ('smbv1');
    my $dof = $q->param('dof');
    my $ampm;
    my $incOnlyTimeout;

    esmith::cgi::genHeaderNonCacheable(
	    $q,
	    undef, $fm->localise('UPDATING_WORKSTN_CONF')
	);
	
    my $rec = $conf->get('backupwk');
    unless (defined $rec)
    {
        $rec = $conf->new_record('backupwk', {type=>'service'});
    }
    my $backupwkMount = $rec->prop('Mount') || '/mnt/smb';

    unless ( $status eq 'on') 
    {
        # set service to disabled
        my $old = $conf->get('UnsavedChanges')->value;

        $rec->set_prop('status', 'disabled');
        $conf->get('UnsavedChanges')->set_value($old);

        system("/sbin/e-smith/signal-event", "conf-backup") == 0
            or die($fm->localise('ERR_CONF_BACKUP')."\n");

        esmith::cgi::genResult($q, $fm->localise('SUCCESSFULLY_DISABLED_WORKSTN'));
        return;
    }
    
    #--------------------------------------------------
    # Untaint parameters and check for validity
    #--------------------------------------------------

    my $VFSType = $q->param ('VFSType');
    if ( $VFSType eq 'nousb') 
    {
        esmith::cgi::genResult($q, $fm->localise('ERR_NO_USB_DISK'));
        return;
    }
    if ( $VFSType eq 'nomnt') 
    {
        esmith::cgi::genResult($q, $fm->localise('ERR_NO_MOUNTED_DISK'));
        return;
    }

    my $backupwkStation = $q->param ('backupwkStation');
    if ( $VFSType =~ m/usb|mnt/s) { $backupwkStation = 'localhost' }
    if ($backupwkStation =~ /^\s*(\S+)\s*$/) {
	$backupwkStation = $1;
    } else {
        $backupwkStation = "";
    }
    if ( $backupwkStation eq "" )
    {
        esmith::cgi::genResult(
	    $q, $fm->localise('ERR_INVALID_WORKSTN')
	);
    return;
    }

    my $backupwkFolder = $q->param ('backupwkFolder');
    if ($backupwkFolder =~ /^(.*)$/)
    {
        $backupwkFolder = $1;
    }
    else 
    {
        $backupwkFolder = '';
    }
    if ( $VFSType eq 'usb' )
    {
        $backupwkFolder = 'media/' . $backupwkFolder;
    }
    if ( $VFSType eq 'mnt' )
    {
        $backupwkMount  = $backupwkFolder;
        if (checkMount ($backupwkMount)){$backupwkFolder = '';}
    }
    else
    {
        $backupwkFolder =~ s/^\///; # remove leading /
    } 
    if ( $backupwkFolder eq '')
    {
        esmith::cgi::genResult($q, $fm->localise('ERR_INVALID_FOLDER'));
        return;
    }

    my $backupwkLogin = $q->param ('backupwkLogin') || '';
    if ($backupwkLogin =~ /^(.*)$/) {
        $backupwkLogin = $1;
    } else {
        $backupwkLogin = "";
    }
    if ( ( $backupwkLogin eq "" ) && ( $VFSType eq 'cifs' ) )
    {
        esmith::cgi::genResult(
    	    $q, $fm->localise('ERR_INVALID_LOGIN')
    	);
        return;
    }

    my $backupwkPassword = $q->param ('backupwkPassword') || '';
    if ($backupwkPassword =~ /^(.*)$/) {
        $backupwkPassword = $1;
    } else {
        $backupwkPassword = "";
    }
    if ( ( $backupwkPassword eq "" ) && ( $VFSType eq 'cifs' ) )
    {
        esmith::cgi::genResult(
    	    $q, $fm->localise('ERR_INVALID_PASSWORD')
    	);
        return;
    }

    my $setsNumber = $q->param ('setsNumber');
    unless ( $setsNumber > 0 )
    {
        esmith::cgi::genResult(
    	    $q, $fm->localise('ERR_INVALID_SETS_NUMBER')
    	);
        return;
    }

    my $filesinset = $q->param ('filesinset');
    unless ( $filesinset > 0 )
    {
        esmith::cgi::genResult(
    	    $q, $fm->localise('ERR_INVALID_FILES_IN_SET_NUMBER')
    	);
        return;
    }

    my $timeout = $q->param ('backupwkTimeout');
    if (( $timeout eq '') || ( $timeout == 0 )) {$timeout = 24 }
    if  (( $timeout < 1 ) || ( $timeout > 24 ))
    {
        esmith::cgi::genResult(
    	    $q, $fm->localise('ERR_INVALID_TIMEOUT')
    	);
        return;
    }

    if (defined $inconly && $inconly eq 'on')
    {
	$incOnlyTimeout = 'yes';
    }
    else
    {
	$incOnlyTimeout = 'no';
    }

    if (defined $smbv1 && $smbv1 eq 'on')
    {
        $smbv1 = 'enabled';
    }
    else
    {
        $smbv1 = 'disabled';
    }

    my $compression = $q->param ('compression');
    if  (( $compression < 0 ) || ( $compression > 9 ))
    {
        esmith::cgi::genResult(
    	    $q, $fm->localise('ERR_INVALID_COMPRESSION')
    	);
        return;
    }

    $rec->set_prop('SmbHost', $backupwkStation);
    $rec->set_prop('SmbShare', $backupwkFolder);
    $rec->set_prop('SmbV1', $smbv1);
    $rec->set_prop('Mount', $backupwkMount);
    $rec->set_prop('Login', $backupwkLogin);
    $rec->set_prop('Password', $backupwkPassword);
    $rec->set_prop('SetsMax', $setsNumber);
    $rec->set_prop('DaysInSet', $filesinset);
    $rec->set_prop('Timeout', $timeout);
    $rec->set_prop('IncOnlyTimeout', $incOnlyTimeout);
    $rec->set_prop('Compression', $compression);
    $rec->set_prop('FullDay', $dof);
    $rec->set_prop('VFSType', $VFSType);
    
    my $module = $rec->prop('Program');

    # The default workstation backup program is dar.

    unless (defined $module)
    {
        $module = 'dar';
    }
    elsif ($module eq '')
    {
        $module = 'dar';
    }

    $rec->set_prop('Program', $module);

	my $backupwkHour = $q->param ('backupwkHour');
	if ($backupwkHour =~ /^(.*)$/) {
	    $backupwkHour = $1;
	} else {
	    $backupwkHour = '12';
	}
	if (($backupwkHour < 0) || ($backupwkHour > 12))
	{
	    esmith::cgi::genResult(
		    $q, $fm->localise('ERR_INVALID_HOUR').$backupwkHour.
			$fm->localise('BETWEEN_0_AND_12')
		);

	    return;
	}

	my $backupwkMin = $q->param ('backupwkMin');
    	if ($backupwkMin =~ /^(.*)$/) {
	    $backupwkMin = $1;
    	} else {
	    $backupwkMin = '0';
    	}
	if (($backupwkMin < 0) || ($backupwkMin > 59))
    	{
	    esmith::cgi::genResult(
		    $q, $fm->localise('ERR_INVALID_MINUTE').$backupwkMin.
			$fm->localise('BETWEEN_0_AND_59')
		);

	    return;
    	}

	$backupwkMin = sprintf("%02d", $backupwkMin);

	$ampm = $q->param ('backupwkAMPM');
	if ($ampm =~ /^(.*)$/) {
	    $ampm = $1;
    	} else {
	    $ampm = 'AM';
    	}

    	# convert to 24 hour time

    	$backupwkHour = $backupwkHour % 12;
    	if ($ampm eq 'PM')
    	{
	    $backupwkHour = $backupwkHour + 12;
    	}


	# variables passed validity checks, set configuration database values
	my $old = $conf->get('UnsavedChanges')->value;

	$rec->set_prop('status', 'enabled');

	$rec->set_prop('BackupTime', "$backupwkHour:$backupwkMin");

	$conf->get('UnsavedChanges')->set_value($old);

	system("/sbin/e-smith/signal-event", "conf-backup") == 0
	    or die($fm->localise('ERR_CONF_BACKUP'),"\n");

    # we test if the remote host is reachable, else we simply display a warning
    if ( $VFSType =~ m/cifs|nfs/s )
    {
    my $error_message = vmount($backupwkStation,$backupwkFolder,$backupwkMount,$VFSType,$smbv1);
    if (! $error_message)
        {
        bunmount($backupwkMount,$VFSType);
        }
    elsif ($error_message)
        {
        esmith::cgi::genResult($q, $fm->localise('ERROR_WHEN_TESTING_REMOTE_SERVER').$q->br() . "$error_message");
        return;
        }
    }

	esmith::cgi::genResult(
		$q, $fm->localise('SUCCESSFULLY_ENABLED_WORKSTN').$q->br().
		$fm->localise('WITH_BACKUP_TIME')."$backupwkHour:$backupwkMin");

    return;
}

sub workstnVerify ()
{

    my $rec = $conf->get('backupwk');
    
    esmith::cgi::genHeaderNonCacheable ($q, undef,
	$fm->localise('VERIFY_WORKSTN_BACKUP_FILE'));

    unless ($rec)
    {
	esmith::cgi::genResult(
	    $q, $fm->localise('CONFIGURATION_TO_BE_DONE'));
	return;
    }

    my %backupfiles = ();
    my $mntdir = $rec->prop('Mount') || '/mnt/smb';
    my $mntbkdir;
    my $key;
    my $id = $rec->prop('Id') || $conf->get('SystemName')->value . "." . $conf->get('DomainName')->value;
    my $smbhost = $rec->prop('SmbHost');
    my $smbshare = $rec->prop('SmbShare');
    my $smbv1 = $rec->prop('SmbV1') || 'disabled';
    my $VFSType = $rec->prop('VFSType') || 'cifs';
    my $err;
    $mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
    
    my $setbackuplist = sub {
	if ( $_ =~ /\.dar/ ) {
	    my $dir = $File::Find::dir;
	    my $backupref;
	    $dir =~ s/$mntbkdir\///;
            $_ =~ s/\..*\.dar//;
	    $backupref = $_;
	    $_ =~ s/.*-//;
    	    @{$backupfiles{$_}}[0] = $dir;
    	    @{$backupfiles{$_}}[1] =  $backupref;	
	}
    };
    
    # Mounting backup shared folder
    my $error_message = bmount($mntdir,$smbhost,$smbshare,$VFSType,$smbv1);
    if ($error_message)
    {
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }
    
    # Test if backup subdirectory for our server
    $mntbkdir = $mntdir . "/$id";
    unless (-d $mntbkdir) 
    {
        $error_message  = $fm->localise('ERR_NO_HOST_DIR')."\n";
        $error_message .= bunmount($mntdir,$VFSType);
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Finding existing backups
    
    find { wanted => \&$setbackuplist, untaint => 1, untaint_pattern => qr|^([-+@\w\s./]+)$|}, $mntbkdir ;

    my %blabels = ();
    my @blabels;
    my $backups = 0;
    
    foreach $key (sort keys %backupfiles) {
	my $labkey = $mntbkdir . '/' . $backupfiles{$key}[0] . '/' . $backupfiles{$key}[1];
	$blabels{$labkey} = $backupfiles{$key}[1] . " (" . $backupfiles{$key}[0] . ")";
	$backups = push @blabels, $labkey;
	}

    $error_message = bunmount($mntdir,$VFSType);
    die($error_message) if $error_message;

    # Stops here if no backups 
    
    if ( $backups == 0 ) {
	esmith::cgi::genResult(
	    $q, $fm->localise('NO_BACKUPS_TO_RESTORE'));
	return;
    }

    print $q->p ($fm->localise('VERIFY_WORKSTN_BACKUP_DESC') . ' ' . "$smbhost/$smbshare/$id");
    print $q->p;
    
    print $q->start_multipart_form(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);

    print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},

	esmith::cgi::genWidgetRow(
		$q,
	        $fm->localise('SELECT_BACKUP_FILE'),
	        $q->popup_menu (
		    -name => 'backupset',
		    -values => [ @blabels ],
		    -labels => \%blabels
		)
	)
    );

    print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},

        esmith::cgi::genWidgetRow(
	    $q,
	    $fm->localise('CHECK_TO_VERIFY_FULL_RESTORE'),
	    $q->checkbox (
		-name => 'verifyall',
		-checked=>0,
		-label=>''
	    )
	), 
	$q->Tr(
            esmith::cgi::genTextRow(
		    $q, 
    	        $fm->localise('CHECK_INTEGRITY_WARNING') 
    	    )
    	)
    ),"\n";
    
    print $q->table ({width => "100%", -class => "sme-noborders"},
	    esmith::cgi::genButtonRow(
		    $q,
		    $q->submit(
			    -name => 'action',
			    -value => $fm->localise('VERIFY')
			)
		)
	),"\n";
    
    print $q->hidden(
	    -name => 'state',
	    -override => 1,
	    -default => 'workstn-verify'
	);

    print $q->endform;

    esmith::cgi::genFooter ($q);
}

sub performWorkstnVerify
{
    my ($q) = @_;

    my $backupwkrec = $conf->get('backupwk');
    my $smbhost = $backupwkrec->prop('SmbHost');
    my $smbshare = $backupwkrec->prop('SmbShare');
    my $smbv1 = $backupwkrec->prop('SmbV1') || 'disabled';
    my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
    my $key;
    my $error_message;
    my $id = $backupwkrec->prop('Id') ||
	$conf->get('SystemName')->value . "." . $conf->get('DomainName')->value;
    my $err;
    my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
    my $verifyref = $q->param ('backupset');
    $mntdir = "/$smbshare" if ( $VFSType eq 'usb' );

    # Mounting backup shared folder
    $error_message = bmount($mntdir,$smbhost,$smbshare,$VFSType,$smbv1);
    if ($error_message)
    {
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Test if backup subdirectory for our server
    my $mntbkdir = $mntdir . "/$id";
    unless (-d $mntbkdir) 
    {
        $error_message  = $fm->localise('ERR_NO_HOST_DIR')."\n";
        $error_message .= bunmount($mntdir,$VFSType);
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    my $fullverify = $q->param('verifyall') || '';

    if ( $fullverify eq "on" ) 
    {
	# Test all backups needed to full restore
    
        my %backupsetfiles = ();
	my @restorefiles;
        my $set = $verifyref;
        $set =~ s/\/[^\/]*$//;
        my $backupsetlist = sub {
		if ( $_ =~ /\.dar/ )
	    {
		my $backupref = $File::Find::name;
        	$backupref =~ s/\.[0-9]+\.dar//;
        	$_ =~ s/\..*\.dar//;
		$_ =~ s/.*-//;
    		$backupsetfiles{$_} = $backupref;
	    }
	};

	# find list of available backups and verify
	# it contains all backups needed for full restore

	find { wanted => \&$backupsetlist, untaint => 1, untaint_pattern => qr|^([-+@\w\s./]+)$| }, $set ;
    
	my $key;
	my $num = 0;
	foreach $key (sort keys %backupsetfiles)
	{
	    push @restorefiles, $backupsetfiles{$key};
	    if ( $num == 0 )
	    {
		unless ( $backupsetfiles{$key} =~ /\/full-/ ) 
		{
		    esmith::cgi::genHeaderNonCacheable(
			$q,
			undef, $fm->localise('VERIFY_WORKSTN_BACKUP_FILE')
		    );
	    	    esmith::cgi::genResult(
			$q, $fm->localise('ERR_NO_FULL_BACKUP')
			);
		    return;
		}
	    }
	    else
	    {
		my $numf = sprintf("%03d", $num);
		unless ( $backupsetfiles{$key} =~ /\/inc-$numf-/ )
		{
	    	    esmith::cgi::genHeaderNonCacheable(
		 	$q,
			undef, $fm->localise('VERIFY_WORKSTN_BACKUP_FILE')
		    );

		    esmith::cgi::genResult(
			$q, $fm->localise('ERR_NO_INC_BACKUP') . " " . $numf
		    );
		    return;
		}

	    }
	    $num++;	
	    last if ( $backupsetfiles{$key} eq $verifyref );
	}
	
	# and test them 
	
        $| = 1;

	if (open(RD, "-|"))
	{
	    esmith::cgi::genHeaderNonCacheable ($q, undef, 
		$fm->localise('VERIFY_WORKSTN_BACKUP_FILE'));

	    print $q->p (
		$q->b ($fm->localise('TESTING_NEEDED_BACKUPS_FOR_RESTORE') )
		);
	    print '<UL>';
	    
	    while (<RD>)
	    {
		print "<li>$_</li>\n";
	    }

	    print '</UL>';
	    my $message;
	    if (!close RD)
	    {
		print $q->p ($q->b ( $fm->localise('RESTORE_VERIFY_FAILED') ));
	    }
	    else
	    {
		print $q->p ($q->b ( $fm->localise('VERIFY_COMPLETE') ));
	    }

	    esmith::cgi::genFooter ($q);
    }
    else
    {
        select(STDOUT);
        $| = 1;

        my $file;
        foreach $file (@restorefiles)
        {
            if ($file =~ /^(.*)$/)
            {
                $file = $1;
            }
            else
            {
                $error_message  = "Unsecure data :  $file\n";
                $error_message .= bunmount($mntdir,$VFSType);
                die ($error_message);
            }
            print $q->p($fm->localise('TESTED_BACKUP') . "  " . $file);
            system ("/usr/bin/dar", "-Q", "--test", "$file", "--noconf");
        }

        $error_message = bunmount($mntdir,$VFSType);
        die($error_message) if $error_message;

        exit(0);
    }
    return;

    }
    else 
    {
        # verify selected backup only
        # and display files saved in the backup

        my $backupkey = $verifyref;
        if ($backupkey =~ /^(.*)$/)
        {
            $backupkey = $1;
        }
        else
        {
            $error_message  = "Unsecure data :  $backupkey\n";
            $error_message .= bunmount($mntdir,$VFSType);
            die ($error_message);
        }

	if (open(RD, "-|"))
	{
	    esmith::cgi::genHeaderNonCacheable ($q,
		undef, $fm->localise('VERIFY_WORKSTN_BACKUP_FILE'));
	    print $q->p($fm->localise('FILES_IN_BACKUP'));
	    
	    print '<UL>';

	    my $complete = 0;
	    while (<RD>)
	    {
		$complete++ if /etc\/samba\/smbpasswd$/;
		print "<li>$_</li>\n";
	    }

	    print '</UL>';
	    my $status = close RD ?
			($complete ?
			    $fm->localise('VERIFY_COMPLETE') :
			    $fm->localise('BACKUP_FILE_INCOMPLETE'))
			: ($fm->localise('ERROR_READING_FILE').' : '.$backupkey);
	    print $q->p ($q->b ($status));

	    esmith::cgi::genFooter ($q);

        }
        else
        {
            select(STDOUT);
            $| = 1;

            system ("/usr/bin/dar", "-Q", "--list", "$backupkey", "--noconf") == 0
                or die ($fm->localise('ERR_EXTRACT')." : ".$!);

            $error_message = bunmount($mntdir,$VFSType);
            die($error_message) if $error_message;
            exit(0);
        }
    }

    return;
}

sub workstnRestore ()
{

    my $rec = $conf->get('backupwk');

    esmith::cgi::genHeaderNonCacheable(
	$q, undef, $fm->localise('RESTORE_CONF_FROM_WORKSTN'));

    unless ($rec)
    {
	esmith::cgi::genResult(
	    $q, $fm->localise('CONFIGURATION_TO_BE_DONE'));
	return;
    }

    my $mntdir = $rec->prop('Mount') || '/mnt/smb';
    my $mntbkdir;
    my %backupfiles = ();
    my $key;
    my $id = $rec->prop('Id') ||
	$conf->get('SystemName')->value . "." . $conf->get('DomainName')->value;
    my $VFSType = $rec->prop('VFSType') || 'cifs';
    my $smbhost = $rec->prop('SmbHost');
    my $smbshare = $rec->prop('SmbShare');
    my $smbv1 = $rec->prop('SmbV1') || 'disabled';
    my $err;
    $mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
        
    my $setbackupflist = sub {
	if ( $_ =~ /\.dar/ )
	{
	    my $dir = $File::Find::dir;
	    my $backupref;
	    $dir =~ s/$mntbkdir\///;
            $_ =~ s/\..*\.dar//;
	    $backupref = $_;
	    $_ =~ s/.*-//;
    	    @{$backupfiles{$_}}[0] = $dir;
    	    @{$backupfiles{$_}}[1] =  $backupref;	
 	}
    };
    
    # Mounting backup shared folder
    my $error_message = bmount($mntdir,$smbhost,$smbshare,$VFSType,$smbv1);
    if ($error_message)
    {
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Test if backup subdirectory for our server
    $mntbkdir = $mntdir . "/$id";
    unless (-d $mntbkdir) 
    {
        $error_message  = $fm->localise('ERR_NO_HOST_DIR')."\n";
        $error_message .= bunmount($mntdir,$VFSType);
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Finding existing backups
    
    find { wanted => \&$setbackupflist, untaint => 1, untaint_pattern => qr|^([-+@\w\s./]+)$| }, $mntbkdir ;

    my %blabels = ();
    my @blabels;
    my $backups = 0;
    
    foreach $key (sort keys %backupfiles)
    {
	my $labkey = $mntbkdir . '/' . $backupfiles{$key}[0] . '/' . $backupfiles{$key}[1];
	$blabels{$labkey} = $backupfiles{$key}[1] . ' (' . $backupfiles{$key}[0] . ')';
	$backups = push @blabels, $labkey;
    }

    $error_message = bunmount($mntdir,$VFSType);
    die($error_message) if $error_message;

    if ( $backups == 0 )
    {
	esmith::cgi::genResult(
	    $q, $fm->localise('NO_BACKUPS_TO_RESTORE'));
	return;
    }

    print $q->p ($fm->localise('RESTORE_CONF_FROM_WORKSTN_DESC') . ' ' . "$smbhost/$smbshare/$id");
    print $q->p;
    
    print $q->start_multipart_form(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);

    print $q->table ( {border => 0, cellspacing => 0, cellpadding => 4},
        esmith::cgi::genTextRow(
                $q,
                $q->b($fm->localise('DO_NOT_RESTORE_BIN_SBIN_LIB_LIB64_FROM_SME9')),
                ),

	    esmith::cgi::genWidgetRow(
		    $q,
		    $fm->localise('SELECT_BACKUP_FILE'),
		    $q->popup_menu (
			    -name => 'backuptorestore',
			    -values => [ @blabels ],
			    -labels => \%blabels
			)
		)
	);

    print $q->table ( {width => "100%", -class => "sme-noborders"},
	    esmith::cgi::genButtonRow(
		    $q,
		    $q->submit(
			    -name => 'action',
			    -value => $fm->localise('RESTORE_FROM_WORKSTN')
			)
		)
	);

    print $q->hidden(
    	-name => 'state',
	-override => 1,
	-default => 'workstn-restore'
    );

    print $q->endform;

    esmith::cgi::genFooter ($q);
}

sub performWorkstnRestore
{
    my ($q) = @_;
    my $restoreref = $q->param ('backuptorestore');
    my $set = $restoreref;
    $set =~ s/\/[^\/]*$//;
    my %backupsetfiles = ();
    my @restorefiles;
    
    my $backupsetlist = sub {
	if ( $_ =~ /\.dar/ )
	{
	    my $backupref = $File::Find::name;
            $backupref =~ s/\.[0-9]+\.dar//;
            $_ =~ s/\..*\.dar//;
	    $_ =~ s/.*-//;
    	    $backupsetfiles{$_} = $backupref;
	}
    };
    

    my $lock_file = "/var/lock/subsys/e-smith-restore";
    my $file_handle = &esmith::lockfile::LockFileOrReturn($lock_file);

    unless ($file_handle)
    {
	esmith::cgi::genHeaderNonCacheable(
		$q,
		undef, $fm->localise('RESTORE_CANNOT_PROCEED')
	    );

	print $q->p (
	    $q->b ($fm->localise('ANOTHER_RESTORE_IN_PROGRESS')
		)
	    );

	esmith::cgi::genFooter ($q);
	return;
    }

    my $backupwkrec = $conf->get('backupwk');
    my $id = $backupwkrec->prop('Id')
	|| $conf->get('SystemName')->value . "." . $conf->get('DomainName')->value;
    my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
    my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
    my $smbhost = $backupwkrec->prop('SmbHost');
    my $smbshare = $backupwkrec->prop('SmbShare');
    my $smbv1 = $backupwkrec->prop('SmbV1') || 'disabled';
    $mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
    my $err;
    my $error_message;

    # Mounting backup shared folder
    $error_message = bmount($mntdir,$smbhost,$smbshare,$VFSType,$smbv1);
    if ($error_message)
    {
        esmith::cgi::genHeaderNonCacheable($q,undef, $fm->localise('RESTORE_CANNOT_PROCEED'));
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Test if backup subdirectory for our server
    my $mntbkdir = $mntdir . "/$id";
    unless (-d $mntbkdir) 
    {
        $error_message  = $fm->localise('ERR_NO_HOST_DIR')."\n";
        $error_message .= bunmount($mntdir,$VFSType);
        esmith::cgi::genHeaderNonCacheable($q,undef, $fm->localise('RESTORE_CANNOT_PROCEED'));
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

     # finding list of available backups
    # and verifying all needed backup files are available
    
    find { wanted => \&$backupsetlist, untaint => 1, untaint_pattern => qr|^([-+@\w\s./]+)$| }, $set ;
    
    my $key;
    my $num = 0;
    foreach $key (sort keys %backupsetfiles)
    {
	push @restorefiles, $backupsetfiles{$key};
	if ( $num == 0 )
	{
	    unless ( $backupsetfiles{$key} =~ /\/full-/ ) 
	    {
		esmith::cgi::genHeaderNonCacheable(
			$q,
			undef, $fm->localise('RESTORE_CANNOT_PROCEED')
		);
	        esmith::cgi::genResult(
		    $q, $fm->localise('ERR_NO_FULL_BACKUP')
		    );
		return;
	    }
	}
	else
	{
	    my $numf = sprintf("%03d", $num);
	    unless ( $backupsetfiles{$key} =~ /\/inc-$numf-/ )
	    {
	    	esmith::cgi::genHeaderNonCacheable(
		 	$q,
		    undef, $fm->localise('RESTORE_CANNOT_PROCEED')
		);

		esmith::cgi::genResult(
		    $q, $fm->localise('ERR_NO_INC_BACKUP') . $numf
		);
		return;
	    }

	}
	$num++;	
	last if ( $backupsetfiles{$key} eq $restoreref );
    }

    # backup is online, restoring now

    my $rec = $restore->get('restore');
    $rec->set_prop('state','running');
    $rec->set_prop('start', time);
    $conf->get('bootstrap-console')->set_prop('Run', 'yes');

    unless (system("/sbin/e-smith/signal-event", "pre-restore") == 0)
    {
	esmith::cgi::genHeaderNonCacheable(
	    $fm->{cgi},
	    undef, $fm->localise('OPERATION_STATUS_REPORT'));
	esmith::cgi::genResult(
	    $fm->{cgi}, $fm->localise('ERR_PRE_RESTORE'));
	return;
    }

    $| = 1;

    if (open(RD, "-|"))
    {

	#-----------------------------------------------------
	# restore system from uploaded workstation backup file
	#-----------------------------------------------------

	esmith::cgi::genHeaderNonCacheable ($q, undef, 
	    $fm->localise('RESTORE_IN_PROGRESS'));

	print $q->p (
	    $q->b ($fm->localise('RESTORE_IN_PROGRESS_DESC')
		)
	    );

	print $q->p($fm->localise('FILES_HAVE_BEEN_RESTORED'));

	print '<UL>';
	my $complete = 0;
	while (<RD>)
	{
	    $complete++ if /etc\/samba\/smbpasswd$/;
	    print "<li>$_</li>\n";
	}

	print '</UL>';
	my $message;
	if (!close RD)
	{
	    $message = $fm->localise('RESTORE_FAILED_MSG');
	}
	else
	{
	    #-----------------------------------------------------
	    # if restore completed, regenerate configuration files
	    #-----------------------------------------------------
	    if ($complete)
	    {

		$message = $fm->localise('RESTORE_COMPLETE');
		system("/usr/sbin/groupmod", "-g", "$www_gid", "www") == 0
		    or warn ($fm->localise('ERR_RESTORING_GID')."\n");
		system("/usr/sbin/usermod", "-g", "$www_gid", "www") == 0
		    or warn ($fm->localise('ERR_RESTORING_INITIAL_GRP')."\n");
		system("/sbin/e-smith/signal-event", "post-upgrade") == 0
		    or die ($fm->localise('ERROR_UPDATING_CONFIGURATION')."\n");
	    }
	    else
	    {
		$message = $fm->localise('RESTORE_FAILED');
	    }
	}

	$rec->set_prop('state', 'complete');
	$rec->set_prop('finish', time);

	&esmith::lockfile::UnlockFile($file_handle);

	print $q->p ($q->b ($message));

        print $q->startform(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);
        print $q->p($q->b ($fm->localise('YOU_MUST_REBOOT'))),"\n";
        print $q->start_table ({width => "100%", -class => "sme-noborders"}),"\n";
        print esmith::cgi::genButtonRow(
                $q,
                $q->submit (-name => 'action', -value =>
                $fm->localise('REBOOT'))
        );
        # Put in a hidden widget to store the reboot value.
        print $q->hidden(
                        -name => 'function',
                        -value => 'reboot'
                        ),"\n";
        print $q->hidden (
	    -name => 'state',
	    -override => 1,
	    -default => 'perform'
	),"\n";
        print $q->end_table,"\n";
	print $q->endform;

	esmith::cgi::genFooter ($q);
    }
    else
    {
	select(STDOUT);
	$| = 1;
	
	my $file;
	foreach $file (@restorefiles)
	{
	    if ($file =~ /^(.*)$/)
	    {
		$file = $1;
	    }
	    else
	    {
            $error_message  = "Unsecure data :  $file\n";
            $error_message .= bunmount($mntdir,$VFSType);
            die ($error_message);
	    }
	    # because CentOS 7/SME 10  has now links in place of folder for bin lib lib64 and sbin, we need to exclude them to avoid to trash the server
	    # if restoring from a previous SME version. An alternative or complement to exclud directories would be to add this rule :  '-/{!T&~D}[Pp];Oo' : do not replace symlink by dir, otherwise replace. 
	    system ("/usr/bin/dar", "-Q", "-x", "$file", "-v", "-N", "-R", "/", "-wa", '-P', 'bin', '-P', 'lib', '-P', 'lib64', '-P', 'sbin', '-P', 'var/run', '-P', 'var/lock');
	    # However if one has added element to backup to this location; we need to resore them to their new location
	    # TODO condition to execute or not the following ....
	    # something like dar -l full-20210309124352 -g bin -g lib -g lib64 -g sbin  -/'{T}[Pp]'|grep -E '(sbin|bin|lib)'|wc -l ; if result > to 4
	    # or with a loop accross the 4 locations
	    system ("/usr/bin/dar", "-Q", "-x", "$file", "-v", "-N", "-R", "/usr/", "-wa", '-g', 'bin', '-g', 'lib', '-g', 'lib64', '-g', 'sbin', '-D');
	}

    $error_message = bunmount($mntdir,$VFSType);
    die($error_message) if $error_message;

	exit(0);
    }
    return;
}

sub workstnSelRestore()
{
    my $rec = $conf->get('backupwk');

    esmith::cgi::genHeaderNonCacheable ($q, undef,
	$fm->localise('WORKSTN_SELECTIVE_RESTORE'));

    unless ($rec)
    {
	esmith::cgi::genResult(
	    $q, $fm->localise('CONFIGURATION_TO_BE_DONE'));
	return;
    }

    my %backupfiles = ();
    my $mntdir = $rec->prop('Mount') || '/mnt/smb';
    my $mntbkdir;
    my $key;
    my $id = $rec->prop('Id') ||
	$conf->get('SystemName')->value . '.' . $conf->get('DomainName')->value;
    my %blabels = ();
    my @blabels;
    my $backups = 0;
    my $filterexp;
    my $VFSType = $rec->prop('VFSType') || 'cifs';
    my $smbhost = $rec->prop('SmbHost');
    my $smbshare = $rec->prop('SmbShare');
    my $smbv1 = $rec->prop('SmbV1') || 'disabled';
    $mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
    my $err;
    my $error_message;

    my $setbackuplist = sub {
	if ( $_ =~ /\.dar/ )
	{
	    my $dir = $File::Find::dir;
	    my $backupref;
	    $dir =~ s/$mntbkdir\///;
            $_ =~ s/\..*\.dar//;
	    $backupref = $_;
	    $_ =~ s/.*-//;
    	    @{$backupfiles{$_}}[0] = $dir;
    	    @{$backupfiles{$_}}[1] =  $backupref;	
	}
    };

    # Mounting backup shared folder
    $error_message = bmount($mntdir,$smbhost,$smbshare,$VFSType,$smbv1);
    if ($error_message)
    {
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Test if backup subdirectory for our server
    $mntbkdir = $mntdir . "/$id";
    unless (-d $mntbkdir) 
    {
        $error_message  = $fm->localise('ERR_NO_HOST_DIR')."\n";
        $error_message .= bunmount($mntdir,$VFSType);
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    my $catalog = "$mntbkdir/dar-catalog";
    my $i = 0;
    my $j = 0;
    my @bknum;
    my @setd;
    my @bkname;

        
    # update backups list from current catalog    
    
    open(DAR_LIST, "/usr/bin/dar_manager -B $catalog -l |") ;

    $i = 0;
    while (<DAR_LIST>)
    {
	next unless m/set/;
	chomp;
	($bknum[$i], $setd[$i], $bkname[$i]) = split(' ', $_, 3);
	$i++;
    }
    close (DAR_LIST);

    # set drop down list of backups
    
    push @blabels, "0";
    $blabels{"0"} = $fm->localise('ALL_BACKUPS');
    $j = 0;
    while ($j < $i)
    {
	push @blabels, $bknum[$j];
	$blabels{$bknum[$j]} = $bkname[$j];
	$j++
    }  

    print $q->p ($fm->localise('WORKSTN_SEL_REST_DESC') . " $smbhost/$smbshare/$id");

    print $q->h2 ($fm->localise('BACKUP_CHOICE'));
    
    print $q->start_multipart_form(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);


    print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},

	esmith::cgi::genWidgetRow(
		$q,
	        $q->b($fm->localise('SELECT_BACKUP_FILE')),
	        $q->popup_menu (
		    -name => 'backupset',
		    -values => [ @blabels ],
		    -labels => \%blabels)
		),

	esmith::cgi::genNameValueRow(
		$q,
		$fm->localise('FILTER_EXPRESSION'),
		'filterexp',
		$filterexp
		)
	);


    print $q->table ({width => "100%", -class => "sme-noborders"},
	    esmith::cgi::genButtonRow(
		    $q,
		    $q->submit(
			    -name => 'action',
			    -value => $fm->localise('PERFORM')
			)
		)
	),"\n";

    print $q->hidden(
	    -name => 'state',
	    -override => 1,
	    -default => 'workstn-sel-restore'
	);

    print $q->endform;


    esmith::cgi::genFooter ($q);

    $error_message = bunmount($mntdir,$VFSType);
    die($error_message) if $error_message;
}

sub performWorkstnSelRestore
{
    my ($q) = @_;

    my $rgfilter;
    my $filterexp = $q->param ('filterexp');
    if ($filterexp =~ /^(.*)$/)
    {
	$filterexp = $1;
	$rgfilter = qr/$filterexp/;
    }
    else
    {
        $filterexp = "";
    }
    my $seldatebf;

    esmith::cgi::genHeaderNonCacheable ($q,
        undef, $fm->localise('WORKSTN_SELECTIVE_RESTORE'));
	
    my $backupwkrec = $conf->get('backupwk');
    my $smbhost = $backupwkrec->prop('SmbHost');
    my $smbshare = $backupwkrec->prop('SmbShare');
    my $smbv1 = $backupwkrec->prop('SmbV1') || 'disabled';
    my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
    my $key;
    my $id = $backupwkrec->prop('Id') ||
	$conf->get('SystemName')->value . "." . $conf->get('DomainName')->value;
    my @flabels;
    my %flabels = ();
    my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
    my $err;
    my $error_message;
    $mntdir = "/$smbshare" if ( $VFSType eq 'usb' );
    
    my $backupkey = $q->param ('backupset');
    if ($backupkey =~ /^(.*)$/)
    {
	$backupkey = $1;
    }
    else
    {
	die('Unsecure data : ' . $backupkey);
    }

    # Mounting backup shared folder
    $error_message = bmount($mntdir,$smbhost,$smbshare,$VFSType,$smbv1);
    if ($error_message)
    {
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Test if backup subdirectory for our server
    my $mntbkdir = $mntdir . "/$id";
    unless (-d $mntbkdir) 
    {
        $error_message  = $fm->localise('ERR_NO_HOST_DIR')."\n";
        $error_message .= bunmount($mntdir,$VFSType);
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Read wanted file list from selected backup

    if (open(RD, "-|"))
    {
	my $regex = qr/\[.*\] */;
	while (<RD>)
	{
        chomp;
	    $_ =~ s/$regex//;
	    next if m/^(sbin|bin|lib|lib64|var\/run|var\/lock)$/;
	    if ($filterexp) {next unless m/$rgfilter/};
	    push @flabels, $_;
	}

	my $status = close RD ?
			$fm->localise('READ_COMPLETE')
			: ($fm->localise('ERROR_READING_FILE').' : '.$backupkey);
	print $q->p ($status);

    }
    else
    {
        select(STDOUT);
        $| = 1;

        system ("/usr/bin/dar_manager", "-B", "$mntbkdir/dar-catalog", "-u", "$backupkey") == 0
            or die ($fm->localise('ERR_EXTRACT')." : ".$!);

        $error_message = bunmount($mntdir,$VFSType);
        die($error_message) if $error_message;
        exit(0);
    }

    print $q->start_multipart_form(
	    -method => 'POST',
	    -action => $q->url (-absolute => 1)
	);

    print $q->table ({border => 0, cellspacing => 0, cellpadding => 4},

        esmith::cgi::genTextRow(
                $q,
                $q->b($fm->localise('DO_NOT_RESTORE_BIN_SBIN_LIB_LIB64_FROM_SME9')),
	        ),

	esmith::cgi::genWidgetRow(
		$q,
	        $q->b($fm->localise('SELECT_FILES_TO_RESTORE')),
	        $q->scrolling_list (
		    -name => 'restorefiles',
		    -values => [ @flabels ],
		    -size => 15,
		    -multiple => 'true')
		),

	esmith::cgi::genNameValueRow(
		$q,
		$fm->localise('SELECT_DATE_BEFORE'),
		'seldatebefore',
		$seldatebf
		)
	);

    print $q->table ({width => "100%", -class => "sme-noborders"},
	    esmith::cgi::genButtonRow(
		    $q,
		    $q->submit(
			    -name => 'action',
			    -value => $fm->localise('PERFORM')
			)
		)
	),"\n";

    print $q->hidden(
	    -name => 'state',
	    -override => 1,
	    -default => 'workstn-sel-restore2'
	);

    print $q->hidden(
	    -name => 'when',
	    -override => 1,
	    -value => $seldatebf
	);

    print $q->endform;

    esmith::cgi::genFooter ($q);

}

sub performWorkstnSelRestore2
{
    my ($q) = @_;

    esmith::cgi::genHeaderNonCacheable ($q, undef, 
        $fm->localise('RESTORE_IN_PROGRESS'));

    my @restorelist;
    my $when = $q->param ('seldatebefore');
    if ($when =~ /^(.*)$/)
    {
	$when = $1;
    }
    else
    {
	die('Unsecure data : ' . $when);
    }
    my $tymd =
	qr/((19|20)\d\d\/(?=\d\d\/\d\d-))?((0?[1-9]|1[0-2])\/(?=\d\d-))?((31|[123]0|[012]?[1-9])-)?/;
    my $thms =
	qr/([01]?[0-9]|2[0-3]):([0-5][0-9])(:[0-5][0-9])?/;

    unless (($when =~ m/^$tymd$thms$/) || ($when eq ""))
    {
        esmith::cgi::genResult(
	    $q, "$when : " . $fm->localise('ERR_INVALID_SELDATE')
    	    );
    	return;
    }

    my @restorefiles = $q->param ('restorefiles');
    my $f;
    foreach $f (@restorefiles)
    {
        if ($f =~ /^(.*)$/)
	{
	    push @restorelist, "\"".$1."\"";
	}
    }
	
    my $backupwkrec = $conf->get('backupwk');
    my $id = $backupwkrec->prop('Id') ||
	$conf->get('SystemName')->value . "." . $conf->get('DomainName')->value;
    my $mntdir = $backupwkrec->prop('Mount') || '/mnt/smb';
    my $VFSType = $backupwkrec->prop('VFSType') || 'cifs';
    my $smbhost = $backupwkrec->prop('SmbHost');
    my $smbshare = $backupwkrec->prop('SmbShare');
    my $smbv1 = $backupwkrec->prop('SmbV1') || 'disabled';
    my $err;
    my $error_message;
    $mntdir = "/$smbshare" if ( $VFSType eq 'usb' );    

    # Mounting backup shared folder
    $error_message = bmount($mntdir,$smbhost,$smbshare,$VFSType,$smbv1);
    if ($error_message)
    {
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # Test if backup subdirectory for our server
    my $mntbkdir = $mntdir . "/$id";
    unless (-d $mntbkdir) 
    {
        $error_message  = $fm->localise('ERR_NO_HOST_DIR')."\n";
        $error_message .= bunmount($mntdir,$VFSType);
        esmith::cgi::genResult($q, $error_message, $id);
        return;
    }

    # backup is online, restoring now

    $| = 1;
    my $restorerr;

    if (open(RD, "-|"))
    {

	#-----------------------------------------------------
	# restore system from uploaded workstation backup file
	#-----------------------------------------------------

	print $q->p($fm->localise('FILES_HAVE_BEEN_RESTORED'));

	print '<UL>';
	while (<RD>)
	{
	    print "<li>$_</li>\n";
	}

	print '</UL>';
	my $message;
	if (!close RD)
	{
	    $message = $fm->localise('RESTORE_FAILED_MSG');
	}
	else
	{
	    if ($restorerr)
	    {
		$message = $fm->localise('RESTORE_FAILED');
	    }
	    else
	    {
		$message = $fm->localise('RESTORE_COMPLETE');
	    }
	}

	print $q->p ($q->b ($message));

	esmith::cgi::genFooter ($q);
    }
    else
    {
	select(STDOUT);
	$| = 1;
	# we could add this filter here -/{!T&~D}[Pp];Oo to prevent symlinks to be transformed as folder, but it would lead to $?=4 or 5 or 1024.... thus marking as failed	
	if ($when) 
	{
	    $restorerr = system ("/usr/bin/dar_manager -B \"$mntbkdir/dar-catalog\" -Q -w $when -e '-v -N -R / -w -P sbin -P bin -P lib64 -P lib -P var/run -P var/lock' -r @restorelist");
	}
	else 
	{
	    $restorerr = system ("/usr/bin/dar_manager -B \"$mntbkdir/dar-catalog\" -Q -k -e '-v -N -R / -w -P sbin -P bin -P lib64 -P lib -P var/run -P var/lock' -r @restorelist");
	}

    $error_message = bunmount($mntdir,$VFSType);
    die($error_message) if $error_message;
    exit(0);
    }
    return;
}

sub performReboot ()
{
    esmith::cgi::genHeaderNonCacheable ($q, undef,
	$fm->localise('SERVER_REBOOT'));

    print $q->p (
	    $q->b ($fm->localise('SERVER_WILL_REBOOT'))
	);

    esmith::cgi::genFooter($fm);

    esmith::util::backgroundCommand(
	    5,
	    "/sbin/e-smith/signal-event",
	    "reboot"
	);
}

sub CalculateSizes ()
{
    #------------------------------------------------------------
    # figure out the size of the tar file.
    #------------------------------------------------------------

    my $tarsize = 0;

    # It takes way too much time to do a du on /home/e-smith. So we'll
    # estimate the current size.
    # We do this by checking the quota used by each user on the system.

    use Quota;
    use esmith::AccountsDB;
    my $accounts = esmith::AccountsDB->open;

    # Get a $dev value appropriate for use in Quota::query call.
    my $dev = Quota::getqcarg("/home/e-smith/files");

    foreach my $user ($accounts->users())
    {
	my $name = $user->key;
	my $uid = getpwnam($name);
	unless ($uid)
	{
	    warn ($fm->localise('NO_UID_FOR_NAME').$name."\n");
	    # We shouldn't ever get here. If we do, we can't get
	    # the quota value for this user, so we just skip to
	    # the next one.
	    next;
	}

	# Get current quota settings.
	my ($blocks) = Quota::query($dev, $uid, 0);
	$tarsize += $blocks;
    }

    # We add to this the size of root owned firectories, estimated using du.
    # If this takes too long, then the admin only has his or
    # herself to blame!

    # Remove /home/e-smith from backup list, and make paths absolute
    my @list = map { "/$_" } grep { !/home\/e-smith/ } @directories;
    open(DU, "-|")
	or exec '/usr/bin/du', '-s', @list;

    while (<DU>)
    {
	my ($du) = split(/\s+/);
	$tarsize += $du;
    }
    close DU;

    $tarsize = &showSize($tarsize);

    #------------------------------------------------------------
    # figure out the size of the dump files
    #------------------------------------------------------------

    my $dumpsize = 0;

    open(DF, "-|")
	or exec '/bin/df', '-P', '-t', 'ext3', '-t', 'ext4', '-t', 'xfs';

    while (<DF>)
    {
	next unless (/^\//);

	(undef, undef, my $s, undef) = split(/\s+/, $_);

	$dumpsize += $s;
    }

    # increase size by 10% to cope with dump overhead.

    $dumpsize *= 1.1;

    close DF;

    $dumpsize = &showSize($dumpsize);

    #------------------------------------------------------------
    # how much free space is in /tmp
    #------------------------------------------------------------

    my $tmpfree = 0;
    my $halffree = 0;

    open(DF, "-|")
	or exec '/bin/df', '-P', '-t', 'ext3', '-t', 'ext4', '-t', 'xfs', '/tmp';

    while (<DF>)
    {
	next unless (/^\//);

	(undef, undef, undef, my $s) = split(/\s+/, $_);

	$tmpfree += $s;
    }

    close DF;

    $halffree = $tmpfree / 2;

    $tmpfree = &showSize($tmpfree);
    $halffree = &showSize($halffree);

    return ($tarsize, $dumpsize, $tmpfree, $halffree);
}

sub showSize
{
    # convert size to Mb or Gb or Tb :) Remember, df reports in kb.

    my $size = shift;

    my $Mb = 1024;
    my $Gb = $Mb * $Mb;
    my $Tb = $Mb * $Mb * $Mb;

    if ($size >= $Tb)
    {
	$size /= $Tb;
	$size = int($size) . "Tb";
    }
    elsif ($size >= $Gb)
    {
	$size /= $Gb;
	$size = int($size) . "Gb";
    }
    elsif ($size >= $Mb)
    {
	$size /= $Mb;
	$size = int($size) . "Mb";
    }
    else
    {
	$size .= "kb";
    }

    return $size;
}

sub dmount
{
    # mount dar unit according to dar-workstation configuration
    # return nothing if mount successfull

    my ($host,$share,$mountdir,$login,$password,$VFSType,$smbv1) = @_;
    
    if ($VFSType eq 'cifs')
    {
	my $opt= ($smbv1 eq "enabled")? ",vers=1.0": "";
	return ( qx(/bin/mount -t cifs "//$host/$share" $mountdir -o credentials=/etc/dar/CIFScredentials,nounix$opt 2>&1) );
    }
    elsif ($VFSType eq 'nfs')
    {
	return ( qx(/bin/mount -t nfs -o nolock "$host:/$share" $mountdir 2>&1) );
    }
    elsif ($VFSType eq 'usb')
    {
        my $device = "";
        my $vollbl = "";

        my $devices = esmith::BlockDevices->new ('allowmount' => 'disabled');
        my ($valid, $invalid) = $devices->checkBackupDrives(0);

        if ( ${$valid}[0] ) {
            foreach ( @{$valid} ) {
                $vollbl = $devices->label($_);
                if ( $share eq "media/$vollbl" ) {
                    $device = "/dev/$_";
                }
            }
        }
        $devices->destroy;
        return ( qx (mount $device /$share 2>&1) );
    }
    else
    {
	return ("Error while mounting $host/$share : $VFSType not supported.\n");
    }
}   

sub checkMount
{
    # check if $mountdir is mounted
    my $mountdir = shift;
    $|=1; # Auto-flush

    my @res = qx( findmnt $mountdir );
    return ( !@res );
}

sub bmount
{
    my ($mntdir,$host,$share,$VFSType,$smbv1) = @_;
    # verify backup directory not already mounted

    if (!checkMount ($mntdir))
    {
        return if ($VFSType eq 'mnt');
        return ($fm->localise('ERR_ALREADY_MOUNTED'));
    }
    else
    {
        if ($VFSType eq 'mnt')
        {
            return ($fm->localise('ERR_NOT_MOUNTED'));
        }
    }

    # create the directory mount point if it does not exist
    my $err = createTree ($mntdir);
    return ($fm->localise('ERR_MOUNTING_SMBSHARE') . "<//$host/$share>\n" . $err) if $err;
    
    # mount the backup directory
    $err = dmount($host,$share,$mntdir,'','',$VFSType,$smbv1);
    return ($fm->localise('ERR_MOUNTING_SMBSHARE') . "<//$host/$share>\n" . $err) if $err;

    # verify $mntdir is mounted
    if (checkMount ($mntdir))
    {
        # The mount should have suceeded, but sometimes it needs more time, 
        # so sleep and then check again.
        sleep 5;
        if (checkMount ($mntdir))
        {
            return ($fm->localise('ERR_NOT_MOUNTED'));
        }
    }
    return;
}

sub bunmount
{
    my ($mount,$type) = @_;
    return if ($type eq 'mnt'); # Don't unmount for type 'mnt'

    if (!checkMount ($mount))
    {
        system('/bin/umount', '-f', $mount) == 0
            or return ($fm->localise('ERR_WHILE_UNMOUNTING'));
    }
    return;
}

sub findmnt
{
    my @mntin  = qx( findmnt -n -l -o TARGET );
    my @mntout;

    foreach my $mount (@mntin)
    {
        next if ($mount =~ m/^\/proc|^\/dev|^\/sys|^\/boot/s);
        chomp $mount;
        next if ($mount eq '/');
        push @mntout, $mount;
    }

    return @mntout;
}

sub createTree
{
    my $tree = shift;
    if (! -d "$tree")
    {
        eval {make_path("$tree")};
        return ("Error while creating $tree : $@. Maybe insufficient rights directory.\n") if $@;
    }
    return;
}

#Used to test if the remote share is mountable when you save settings in database
sub vmount
{
    # mount dar unit according to dar-workstation configuration in order to test the remote host
    # return nothing if mount successfull
    my ($host,$share,$mountdir,$VFSType,$smbv1) = @_;
    if ($VFSType eq 'cifs')
    {
    my $opt= ($smbv1 eq "enabled")? ",vers=1.0": "";
    return ( qx(/bin/mount -t cifs "//$host/$share" $mountdir -o credentials=/etc/dar/CIFScredentials,nounix$opt 2>&1) );
    }
    elsif ($VFSType eq 'nfs')
    {
    return ( qx(/bin/mount -t nfs -o nolock,timeo=30,retrans=1,retry=0 "$host:/$share" $mountdir 2>&1) );
    }

}

__DATA__
<form>
</form>