#!/usr/bin/perl
#
#  Copyright (C) 2001-2002 MandrakeSoft by Sebastien DUPONT <dupont_s@epita.fr>
#  Updated 2002 by Stew Benedict <sbenedict@mandrakesoft.com>
#  Redistribution of this file is permitted under the terms of the GNU
#  Public License (GPL)
#
#  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, 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.
#
#________________________________________________________________
#
#  Description:
#
#   Drakbackup is used to backup your system.
#   During the configuration you can select 
# 	- System files, 
# 	- Users files, 
# 	- Other files.
# 	or All your system ...  and Other (like windows Partitions)
#
#   Drakbackup allows you to backup your system on:
# 	- Harddrive.
# 	- NFS.
# 	- CD-R (CDRW), DVD-R (with autoboot, rescue and autoinstall.).
# 	- FTP.
# 	- Rsync.
# 	- Webdav.
# 	- Tape.
#
#   Drakbackup allows you to Restore your system on
#   choosen directory.
#
#   Per default all backup will be stored on your
#   /var/lib/drakbackup directory
#
#   Configuration file:
# 	/etc/drakconf/drakbackup/drakbackup.conf
#
#________________________________________________________________
#
#  Backup files formats:
#	
#	no incremental backup:
#			backup_sys_date_hour.tar.*
#			backup_user_toto_date_hour.tar.*
#			backup_other_date_hour.tar.*
#
#	first incremental backup: (if backup_base* does not exist)
#
#			backup_base_sys_date_hour.tar.*
#			backup_base_user_toto_date_hour.tar.*
#			backup_base_other_date_hour.tar.*
#			
#	other incremental backup: (if backup_base* already exist)
#
#			backup_incr_sys_date_hour.tar.*
#			backup_incr_user_toto_date_hour.tar.*
#			backup_incr_other_date_hour.tar.*
#
#	all backup runs will generate:
#
#			drakbackup_date_hour.txt
#
#			this will contain media & hostname	
#________________________________________________________________
# 
# REQUIRE:      cron if daemon
#               cdrecord & mkisofs
#		perl Net::FTP
#		ssh-askpass
#		sitecopy - for webdav
#		rsync
#		perl Expect
	
# BUGS:
#DONE		restore->other_media->next->previous => crash ...
#DONE		selection des sources a inclure dans le backup cd. 
#DONE		help -> ok after install_rpm
#    	sort of fixed - doesn't always land where you would expect
#		but at least it doesn't die
#           
# TODO:
#		1 - print ftp problem for user. 
#	    2 - calcul disk space.
#		   use quota.
#WHY? - Apple can read Joliet - would you really be restoring on MacOS?		
#Or for bootable - PPC is being deprecated anyway ;(
#		4 - write on cd --> ! change Joliet to HFS for Apple
#		6 - total backup.( all partitions wanted, windows partitions for example!)
#		    dump use for total backup.
#		7 - custom deamon
#	    10- backend: --resore_all, --restore_sys, --restore_users
#WHAT IS THIS?
#			  --build_cd_autoinst 	
#		12- cpio use !!
#		13- boot floppy disk (with dialog)
#		14- build autoboot with backup and install cd 
#DONE		15- use .backupignore like on CVS
#		16- afficher les modif dans un fichier texte du meme nom 
#			pour afficher durant le restore.
#		17- futur: could be possible to restore a specific file 
#			or directory at specific date. 
#		18- possible all files each time from directory.
#		               
# DONE TODAY:
#________________________________________________________________


use lib qw(/usr/lib/libDrakX);
use standalone;     #- warning, standalone must be loaded very first, for 'explanations'
use strict;

use interactive;
use common;
use Time::localtime;
use detect_devices;

# Backend Options.
# make this global for status screen      
my ($window1, $my_win);
my $central_widget;
my $previous_widget;
my $current_widget;
my $interactive;
my $up_box;
my $advanced_box;
my $box2;
my $cfg_file_exist = 0;
my @user_list_all;
my $list_other;
my $DEBUG = 0;
my $restore_sys = 1; 
my $restore_user = 1; 
my $restore_other = 1; 
my $restore_step_sys_date = "";
my @user_backuped;
my @sys_backuped;
my $sys_backuped = 0;
my $other_backuped = 0;
my @user_list_to_restore;
my @sys_list_to_restore;
my $cd_device_entry;
my $button_box;
my $button_box_tmp;
my $next_widget;
my $sav_next_widget;
my $system_state;
my $restore_state;
my $save_path_entry;
my $restore_find_path_entry;
my $new_path_entry;
my $pbar;
my $pbar1;
my $pbar2;
my $pbar3;
my $plabel;
my $plabel1;
my $plabel2;
my $plabel3;
my $stext;
my $list_model;
my $iter;
my $the_time;
my @user_list_to_restore2;
my @data_backuped;
my $label_tail;
my @list_to_build_on_cd; 
my $restore_path = "/";
my $restore_other_path = 0;
my $restore_other_src;
my $path_to_find_restore;
my $other_media_hd;
my $backup_bef_restore = 0;
my $table;
my @user_list_backuped;
my @files_corrupted;
#- ack - not a great default - changed 20020814 (SB)
my $remove_user_before_restore = 0;
my @file_list_to_send_by_ftp;
my $results;
my @net_methods = ("ftp", "rsync", "ssh", "webdav");
my @media_types = (translate(N_("hd")), "cd", translate(N_("tape")));
my %cd_devices;
my $std_device;
my @tape_devices;
my $tar_ext = "tar.gz";

# config. FILES -> Default PATH  & Global variables.
my %config;
my @sys_files = "/etc";
my @user_list;
my @list_other;
my $cfg_dir = "/etc/drakxtools/drakbackup/";
my $cfg_file = $cfg_dir . "drakbackup.conf";
my $save_path = "/var/lib/drakbackup";
my $log_file = "/var/log/drakbackup";
my $log_buff;
my $comp_mode = 0;
my $backup_sys = 1;
my $backup_user = 1;
my $backup_daemon = 1;
my $backup_sys_versions = 0;
my $backup_user_versions = 0;
my $backup_other_versions = 0;
my $sys_diff_mode = 0;
my $user_diff_mode = 0;
my $other_diff_mode = 0;
my $what_no_browser = 1;
my $cdrw = 0;
my $dvdr = 0;
my $dvdram = 0;
my $net_proto = '';
my $host_path = '';
my $login_user = '';
my $daemon = 0;
my $backend_only = 0;
my $daemon_media = '';
my $hd_quota = 0;

#- 7/4/2002 SB - consolidate net methods
my $where_use_net = 0;

my $where_net = 0;
my $where_hd = 1;
my $del_hd_files = 0;
my $where_cd = 0;
my $where_tape = 0;
my $cd_time = 650;
my $when_space;
my $custom_cron = 0;
my $cd_with_install_boot = 0;
my $cd_device = '';
my $host_name = '';
my $backupignore = 0; 
my $remember_pass = 0;
my $passwd_user = '';
my $tape_device;
my $media_erase = 0;
my $media_eject = 0;
my $multi_session = 0;
my $session_offset = '';
my $tape_norewind = 0;
my $no_critical_sys = 1;
my $send_mail = 0;
my $user_mail;
my $scp_port = 22;
my $use_expect = 0;
my $xfer_keys = 0;
my $user_keys = 1;
my $user_home = $ENV{HOME};
my $backup_key = $user_home . "/.ssh/identity-drakbackup";
my $nonroot_user = 0;
my $not_warned = 0;
my $media_problem = 0;
my $vol_name = 'Drakbackup';
my $good_restore_path = 1;
my $max_space = 1000.0;
my @no_devices = translate(N_("No devices found"));
my %help;
my $time_string = "* * * * *";
my $exec_string = "export USER=$ENV{USER}; /usr/sbin/drakbackup --daemon > /dev/null 2>&1";

# allow not-root user with own config
if ($ENV{HOME} ne '/root') {
	standalone::explanations("Running as $ENV{USER}...");
	#- doesn't get defined when run from cron
	$user_home = "/home/$ENV{USER}" if $user_home eq '';
	$cfg_dir = "$user_home/.drakbackup/";
	$save_path = $cfg_dir . "backups";
	$log_file = $cfg_dir . "drakbackup.log";
	-d $save_path or mkdir_p $save_path;
	$nonroot_user = 1;
	$not_warned = 1;
	$backup_sys = 0;
	@user_list = $ENV{USER};
}
$cfg_file = $cfg_dir . "drakbackup.conf";

foreach (@ARGV) {

    /--default/ and backend_mode();
    /--daemon/ and daemon_mode();
    /--show-conf/ and show_conf();
	/--config-info/ and explain_conf();
	/--cd-info/ and get_cd_info(), exit(0);
    /--debug/ and $DEBUG = 1, next;
}

sub setup_tooltips() {
	%help = (
		'use_expect' => N("Expect is an extension to the Tcl scripting language that allows interactive sessions without user intervention."),
		'remember_pass' => N("Store the password for this system in drakbackup configuration."),
		'erase_cdrw' => N("For a multisession CD, only the first session will erase the cdrw. Otherwise the cdrw is erased before each backup."),	
		'cdrecord_device' => N("This uses the same syntax as the command line program 'cdrecord'. 'cdrecord -scanbus' would also show you the device number."),
		'use_incr_decr' => N("This option will save files that have changed.  Exact behavior depends on whether incremental or differential mode is used."), 
		'use_incremental' => N("Incremental backups only save files that have changed or are new since the last backup."),
		'use_differential' => N("Differential backups only save files that have changed or are new since the original 'base' backup."),
		'send_mail_to' => N("This should be a comma-separated list of local users or email addresses that you want the backup results sent to. You will need a functioning mail transfer agent setup on your system."),
		'backupignore' => N("Files or wildcards listed in a .backupignore file at the top of a directory tree will not be backed up."),
		'delete_files' => N("For backups to other media, files are still created on the hard drive, then moved to the other media.  Enabling this option will remove the hard drive tar files after the backup."),
		'dir_or_module' => N("Some protocols, like rsync, may be configured at the server end.  Rather than using a directory path, you would use the 'module' name for the service path."),
		'when_space' => N("Custom allows you to specify your own day and time.  The other options use run-parts in /etc/crontab."),
	);
}

sub set_help_tip {
     my ($entry, $key) = @_;
     gtkset_tip(new Gtk2::Tooltips, $entry, formatAlaTeX($help{$key}));
}

sub show_conf() {
    print "DrakBackup configuration:\n\n";
    read_conf_file();
    system_state();
    print "$system_state\n";
    exit(0);
}

sub explain_conf() {
	print "\nConfiguration File Options: \n\n";
	print "Configuration file is located in:\n";
	print "                            Root Mode: /etc/drakxtools/drakbackup/drakbackup.conf.\n";
	print "                            User Mode: ~/.drakbackup/drakbackup.conf.\n\n";
	print "SYS_FILES=                 Space separated list of system directories to backup.\n";
	print "HOME_FILES=                Space separated list of user home directories to backup.\n";
	print "OTHER_FILES=               Space separated list of other files to backup.\n";
	print "PATH_TO_SAVE=              Default Hard Drive path to create backup files in.\n";
	print "                            Root Mode: default is /var/lib/drakbackup.\n";
	print "                            User Mode: default is ~/.drakbackup/backups.\n";
	print "NO_SYS_FILES               Don't backup system files.\n";
	print "NO_USER_FILES              Don't backup user files.\n";
	print "BACKUPIGNORE               Honor .backupignore files in backup directories\n";
	print "OPTION_COMP                Compression option - TAR.GZ or TAR.BZ2 (tar.gz is default).\n";
	print "BROWSER_CACHE              Backup web browser cache also.\n";
	print "CDRW                       Backup media is re-writable CD.\n";
	print "DVDR                       Backup media is recordable DVD (not fully supported yet).\n";
	print "DVDRAM                     Backup media is DVDRAM (not fully supported yet).\n";
	print "NET_PROTO=                 Network protocol to use for remote backups: \n";
	print "                             ftp, rsync, ssh, or webdav.\n";
	print "HOST_NAME=                 Remote backup host.\n";
	print "HOST_PATH=                 Backup storage path or module on remote host.\n";
	print "REMEMBER_PASS              Remember password on remote host in config file.\n";
	print "USER_KEYS                  Ssh keys are already setup for communicating with remote host.\n";
	print "DRAK_KEYS                  Use special drakbackup generated host keys.\n";
	print "                             (requires perl-Expect).\n";
	print "USE_EXPECT                 Use expect to do the whole scp transfer, without keys.\n";
	print "                             (requires perl-Expect).\n";
	print "LOGIN=                     Remote host login name.\n";
	print "PASSWD=                    Password on remote host (if REMEMBER_PASS is enabled).\n";
	print "DAEMON_MEDIA=              Daemon mode backup via given media.\n";
	print "                             (hd, cd, tape, ftp, rsync, ssh, or webdav).\n";
	print "HD_QUOTA                   Use quota to limit hard drive space used for backups.\n";
	print "                             (not supported yet).\n";
	print "USE_HD                     Use Hard Drive for backups (currently all modes use HD also).\n";
	print "MAX_SPACE=                 Maximum Hard Drive Space(MB) to consume for backups. \n";   	
	print "USE_CD                     Use CD for backups.\n";
	print "USE_NET                    Use network for backups (driven by NET_PROTO).\n";
	print "USE_TAPE                   Use tape for backup.\n";
	print "DEL_HD_FILES               Delete local hard drive tar files after backup to other media.\n";
	print "TAPE_NOREWIND              Use non-rewinding tape device.\n";
	print "CD_TIME=                   Length of CD media (not currently utilized).\n";
	print "DAEMON_TIME_SPACE=         Interval between daemon backup runs (hourly, daily, weekly)..\n";
	print "CD_WITH_INSTALL_BOOT       Build a bootable restore CD (currently not utilized).\n";
	print "CD_DEVICE=                 Cdrecord style CD device name (ie: 1,3,0).\n";
	print "USER_MAIL=                 User to send backup results to via email.\n";
	print "SEND_MAIL                  Do send backup results via email.\n";
	print "TAPE_DEVICE                Device to use for tape backup (ie: /dev/st0).\n";
	print "MEDIA_ERASE                Erase media before new backup (applies to tape, CD).\n";
	print "MEDIA_EJECT                Eject media after backup completes.\n";
	print "MULTI_SESSION              Allow muliple sessions to be written to CD media.\n";
	print "SYS_INCREMENTAL_BACKUPS    Do incremental or differential backups of system files.\n";
	print "USER_INCREMENTAL_BACKUPS   Do incremental or differential backups of user files.\n";
	print "OTHER_INCREMENTAL_BACKUPS  Do incremental or differential backups if other files.\n";
	print "SYS_DIFFERENTIAL_BACKUPS   Do differential backups of system files.\n";
	print "USER_DIFFERENTIAL_BACKUPS  Do differential backups of user files.\n";
	print "OTHER_DIFFERENTIAL_BACKUPS Do differential backups if other files.\n";
	print "NO_CRITICAL_SYS            Do not backup critical system files:\n";
	print "                             passwd, fstab, group, mtab\n";
	print "CRITICAL_SYS               Do backup above system files.\n";
	exit(0);
}

sub backend_mode() {
	$backend_only = 1;
    build_backup_files();
    exit(0);
}

sub daemon_mode() {
    $daemon = 1;
    build_backup_files();
    exit(0);
}

if (check_for_xserver()) {
	# I give up, if I don't wrap this somehow, it never comes back when run in 
	# console or daemon mode - just pegs cpu to 100%
	# perl_checker has fits though
	eval { require ugtk2 };
	die "Can't load ugtk2...\n" if $@;
	ugtk2->import(qw(:helpers :wrappers :create));
	interactive_mode();
} else {
	die "Can't run in console mode...";
}

sub all_user_list() {
	if ($nonroot_user) {
		@user_list_all = $ENV{USER};
		return;
	}
    my $passwdfile = "/etc/passwd";
    my $user;
    my $uid;
    @user_list_all = ();

	local *PASSWD;
    open(PASSWD, $passwdfile) or exit 1; 
    while (defined(my $line = <PASSWD>)) {
		chomp($line);
		($user, $uid) = (split(/:/, $line))[0, 2];
		if ($uid >= 500 && $uid < 65000 || $uid == 0) {
	    	push @user_list_all, $user;
		}
    }
    close(PASSWD);
    if ($DEBUG) {
		print "/--  User list  --/ \n";
		print " -> $_\n" foreach @user_list_all;
		print "\n";
    }
}

sub the_time() {
    $the_time = "_";
    $the_time .= localtime->year + 1900;
    if (localtime->mon < 9) { $the_time .= "0" }
    $the_time .= localtime->mon + 1;
    if (localtime->mday < 10) { $the_time .= "0" }
    $the_time .= localtime->mday;
    $the_time .= "_";
    if (localtime->hour < 10) { $the_time .= "0" }
    $the_time .= localtime->hour;
    if (localtime->min < 10) { $the_time .= "0" }
    $the_time .= localtime->min;
    if (localtime->sec < 10) { $the_time .= "0" }
    $the_time .= localtime->sec;    
}

sub get_tape_info() {
	my @line_data;
	my $info = "$ENV{HOME}/tmp/dmesg";
	@tape_devices = ();
	system("dmesg | grep 'st[0-9] at' > $info");

	local *INFO;
	open INFO, $info or warn("Can't open $info\n");
	local $_;
	while (<INFO>) {
		@line_data = split(/[ \t,]+/, $_);
		push @tape_devices, "/dev/" . $line_data[3]; 
	}
 	close INFO;
	unlink($info);
}

sub get_free_space {
	my ($dir) = @_;
	my @line_data;
	my $free = "$ENV{HOME}/tmp/free_space";
	system("df -P $dir | tail -1 > $free");

	local *FREE;
	open FREE, $free or warn("Can't open $free\n");
	local $_;
	while (<FREE>) {
		@line_data = split(/[ \t,]+/, $_); 
	}
 	close FREE;
	unlink($free);
	my $free_space = int($line_data[3] / 1024);
	return $free_space;	
}

sub check_storage_quota {
	my ($dir) = @_;
	my $used = "$ENV{HOME}/tmp/used_space";
	my $used_space;
	system("du $dir > $used");
	
	local *USED;
	open USED, $used or warn("Can't open $used\n");
	local $_;
	while (<USED>) {
		$used_space = $_ / 1024;
	}
	close USED;
	unlink($used);
	if ($used_space > $max_space) {
		return $used_space;
	} else {
		return 0;
	}
}

sub get_cd_info() {
	my @cd_info = cat_("/proc/sys/dev/cdrom/info");
	my @line_data;
	my @drive_names;
	my $i;
	my $info;

	my %data = (
                  "drive speed" => 'speed',
                  "Can change speed" => 'chg_speed',
                  "Can read multisession" => 'multisession',
                  "Can write CD-R" => 'cdr',
                  "Can write CD-RW" => 'cdrw',
                  "Can write DVD-R" => 'dvdr',
                  "Can write DVD-RAM" => 'dvdram'
                  );

	
	#- kind of ugly - I'm sure Pixel could improve this, but it works
	#- parse /proc/sys/dev/cdrom/info and get all the cd device capabilities
 	my $cd_drives;
	foreach (@cd_info) {
	  @line_data = split(/[:\t]+/, $_);
          if ($line_data[0] =~ /drive name/) {
              $cd_drives = @line_data-1;
              chop($line_data[$cd_drives]);
              @drive_names = @line_data;
              print "drives: $cd_drives\n" unless $interactive;
          }
	  chop($line_data[$cd_drives]) if $cd_drives;
          foreach my $key (keys %data) {
              if ($line_data[0] =~ $key) {
                  for ($i = 1; $i <= $cd_drives; $i++) {
                      $cd_devices{$drive_names[$i]}{$data{$key}} = $line_data[$i];
                  }
              }
          }

	}
	
	#- now we know all the capabilities, we need the cdrecord device id
	#- this is scsi-channel, id, lun from /dev/scsi/host*
	#- oops - can't count on devfs - use dmesg

	$info = "$ENV{HOME}/tmp/dmesg";
	system("dmesg | grep sr[0-9] > $info");
	local *INFO;
	open INFO, $info or warn("Can't open $info\n");
 	local $_;
	while (<INFO>) {
		if (/sr[0-9] at/) {
			@line_data = split(/[ \t,]+/, $_);
			chop($line_data[11]);
			$line_data[5] =~ s/scsi//;
			$cd_devices{$line_data[3]}{rec_dev} = $line_data[5] . "," . $line_data[9] . "," . $line_data[11];
		}
    }
    close INFO;
    unlink($info);

	#- should we also try to get the human readable name for display purposes?
	
	#- now just report the data if we called --cd-info from the command line
	if (!$interactive) {
		foreach my $key (keys %cd_devices) {
			print "\n{$key}->{rec_dev} = $cd_devices{$key}->{rec_dev}\n"; 
			print "{$key}->{speed} = $cd_devices{$key}->{speed}\n";
			print "{$key}->{chg_speed} = $cd_devices{$key}->{chg_speed}\n";
			print "{$key}->{multisession} = $cd_devices{$key}->{multisession}\n";
			print "{$key}->{cdr} = $cd_devices{$key}->{cdr}\n";
			print "{$key}->{cdrw} = $cd_devices{$key}->{cdrw}\n";
			print "{$key}->{dvdr} = $cd_devices{$key}->{dvdr}\n";
			print "{$key}->{dvdram} = $cd_devices{$key}->{dvdram}\n"; 
		}
	} else {
		#- in non-interactive mode we just let all the devices through
		#- as a general purpose probe - in reality we want only burners
		foreach my $key (keys %cd_devices) {
			delete $cd_devices{$key} if $cd_devices{$key}{rec_dev} eq ''
   		}
	}
}

sub save_conf_file() {
    write_sitecopyrc() if $net_proto eq 'webdav';
    write_password_file() if $net_proto eq 'rsync' && $passwd_user;
	if (!$backup_daemon) {
		$when_space = "";
		$daemon_media = "";
	}
	if (@user_list == ()) {
		$backup_user = 0;
	} else {
		$backup_user = 1;
	}
    my @cfg_list = ("SYS_FILES=@sys_files\n",
		    "HOME_FILES=@user_list\n", 
		    "OTHER_FILES=@list_other\n",
		    "PATH_TO_SAVE=$save_path\n",
		    "HOST_PATH=$host_path\n",
		    "NET_PROTO=$net_proto\n",
		    "CD_TIME=$cd_time\n",
		    "USER_MAIL=$user_mail\n",		     
		    "CD_DEVICE=$cd_device\n",
		    "LOGIN=$login_user\n",
		    "TAPE_DEVICE=$tape_device\n",
		    "HOST_NAME=$host_name\n"
		    );
	$backup_daemon and push @cfg_list, "DAEMON_TIME_SPACE=$when_space\n";
    $no_critical_sys and push @cfg_list, "NO_CRITICAL_SYS\n"; 
    $no_critical_sys or push @cfg_list, "CRITICAL_SYS\n";
	$backupignore and push @cfg_list, "BACKUPIGNORE\n"; 
    $send_mail and push @cfg_list, "SEND_MAIL\n";
    $backup_sys_versions and push @cfg_list, "SYS_INCREMENTAL_BACKUPS\n"; 
    $backup_user_versions and push @cfg_list, "USER_INCREMENTAL_BACKUPS\n"; 
    $backup_other_versions  and push @cfg_list, "OTHER_INCREMENTAL_BACKUPS\n";
	$sys_diff_mode and $backup_sys_versions and push @cfg_list, "SYS_DIFFERENTIAL_BACKUPS\n"; 
    $backup_user and $user_diff_mode and $backup_user_versions and push @cfg_list, "USER_DIFFERENTIAL_BACKUPS\n"; 
    $other_diff_mode  and $backup_other_versions and push @cfg_list, "OTHER_DIFFERENTIAL_BACKUPS\n"; 
    $media_erase and push @cfg_list, "MEDIA_ERASE\n"; 
    $media_eject and push @cfg_list, "MEDIA_EJECT\n"; 
    $multi_session and push @cfg_list, "MULTI_SESSION\n"; 
    $remember_pass and push @cfg_list, "LOGIN=$login_user\n"; 
    $remember_pass and push @cfg_list, "PASSWD=$passwd_user\n";
    $remember_pass and push @cfg_list, "REMEMBER_PASS\n";
    $user_keys and push @cfg_list, "USER_KEYS\n";
    $xfer_keys and push @cfg_list, "DRAK_KEYS\n";
    $use_expect and push @cfg_list, "USE_EXPECT\n";	
    $cd_with_install_boot and push @cfg_list, "CD_WITH_INSTALL_BOOT\n";
    $daemon_media eq 'ssh' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=ssh\n";
    $daemon_media eq 'ftp' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=ftp\n";
    $daemon_media eq 'hd' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=hd\n";
    $daemon_media eq 'cd' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=cd\n";
    $daemon_media eq 'tape' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=tape\n";
    $daemon_media eq 'webdav' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=webdav\n";
    $daemon_media eq 'rsync' and $backup_daemon and push @cfg_list, "DAEMON_MEDIA=rsync\n";
    $hd_quota and  push @cfg_list, "HD_QUOTA\n";
    $where_hd and  push @cfg_list, "USE_HD\n";
	$where_hd and push @cfg_list, "MAX_SPACE=$max_space\n";
    $where_cd and  push @cfg_list, "USE_CD\n";
    $where_tape and push @cfg_list, "USE_TAPE\n";
    $tape_norewind and push @cfg_list, "TAPE_NOREWIND\n";
    $where_net and  push @cfg_list, "USE_NET\n";
    $cdrw and push @cfg_list, "CDRW\n"; 
    $dvdr and push @cfg_list, "DVDR\n"; 
    $dvdram and push @cfg_list, "DVDRAM\n"; 
    $what_no_browser or push @cfg_list, "BROWSER_CACHE\n";
    $backup_sys or push @cfg_list,  "NO_SYS_FILES\n";
	$backup_user or push @cfg_list, "NO_USER_FILES\n";
    if ($comp_mode) {
		push @cfg_list, "OPTION_COMP=TAR.BZ2\n";
    } else { 
		push @cfg_list, "OPTION_COMP=TAR.GZ\n";   
    }
    $del_hd_files and push @cfg_list, "DEL_HD_FILES\n";
    output_p($cfg_file, @cfg_list);
    chmod(0600, $cfg_file);
    save_cron_files();
}

sub read_cron_files() {
    my $daemon_found = 0;
    foreach (qw(hourly daily weekly monthly)) {
		if (-f "/etc/cron.$_/drakbackup") {
	    	$when_space = $_;	    
	    	$daemon_found = 1;
	    	last;
		}
    }
	if ($when_space ne "custom") {
    	!$daemon_found and $backup_daemon = 0;
	} else {
		$custom_cron = 1;
		my $tmpcron = "$ENV{HOME}/tmp/crontab.tmp";
		system("crontab -l | tail +4 > $tmpcron");
    	my @cronline = grep { /drakbackup/ } cat_($tmpcron);
		if (@cronline) {
			@cronline = split(" ", $cronline[0]);
			my @crondetail = splice(@cronline, 0, 5);			
			$time_string = join(" ", @crondetail);
		}
		unlink($tmpcron);
	} 
}

sub save_cron_files() {
	my $entry_changed = 0;
	my $tmpcron = "$ENV{HOME}/tmp/crontab.tmp";

	if ($nonroot_user && $when_space ne "custom" && $backup_daemon)  {
		show_warning("w", N("Cron not available yet as non-root")) if $not_warned;
		$not_warned = 0;
		$backup_daemon = 0;
		return 1;
	}
    my @cron_file = ("#!/bin/sh\n", "export USER=root\n", "/usr/sbin/drakbackup --daemon > /dev/null 2>&1\n");

    if ($backup_daemon) {
		foreach (qw(hourly daily weekly monthly)) {
	    	-f "/etc/cron.$_/drakbackup" and rm_rf("/etc/cron.$_/drakbackup");
		}
		if ($when_space ne "custom") {
			output_p("/etc/cron.$when_space/drakbackup",  @cron_file);
			system("chmod +x /etc/cron.$when_space/drakbackup");
    	} else {
			my $newdetail = join(" ", $time_string, $exec_string, "\n");
			system("crontab -l | tail +4 > $tmpcron");
			my @cronlines = cat_($tmpcron);
			my $index = 0;
			foreach (@cronlines) {
				if (/$exec_string/) {
					$cronlines[$index] = $newdetail;
					$entry_changed = 1;
				}
				$index++;
			}
			push(@cronlines, $newdetail) if $entry_changed == 0;
			output($tmpcron, @cronlines);
			system("crontab $tmpcron");
			unlink($tmpcron);
		}
	} else {
		foreach (qw(hourly daily weekly monthly)) {
	    	-f "/etc/cron.$_/drakbackup" and rm_rf("/etc/cron.$_/drakbackup");
		}
		system("crontab -l | tail +4 > $tmpcron");
		my @cronlines = cat_($tmpcron);
		if (any { /$exec_string/ } @cronlines) {
			my $index = 0;
			foreach (@cronlines) {
				if (/$exec_string/) {
					splice(@cronlines, $index, 1);
				}
				$index++;
			}
			output($tmpcron, @cronlines);
			system("crontab $tmpcron");
			unlink($tmpcron);
		}
    }
}

sub read_conf_file() {
    if (-e $cfg_file) {
		local *CONF_FILE;
        open(CONF_FILE, "<" . $cfg_file) || print "You must be root to read configuration file. \n";
        local $_;
        while (<CONF_FILE>) {
	    	next unless /\S/;
	    	next if /^#/;
	    	chomp;
			if (/^SYS_FILES/)      { s/^SYS_FILES=//gi;    @sys_files = split(' ', $_) }
			if (/^HOME_FILES/)     { s/^HOME_FILES=//gi;   @user_list = split(' ', $_); $backup_user = 1 }
			if (/^OTHER_FILES/)    { s/^OTHER_FILES=//gi;  @list_other = split(' ', $_) }
			if (/^PATH_TO_SAVE/)   { s/^PATH_TO_SAVE=//gi; $save_path = $_ }
			if (/^NO_SYS_FILES/)   { $backup_sys = 0 }
			if (/^NO_USER_FILES/)  { $backup_user = 0 }
			if (/^OPTION_COMP/)    { s/^OPTION_COMP=//gi; /TAR.GZ/ and  $comp_mode = 0; /TAR.BZ2/ and $comp_mode = 1 }
			if (/^BROWSER_CACHE/)  { $what_no_browser = 0 }
			if (/^CDRW/)           { $cdrw = 1 }
			if (/^DVDR/)           { $dvdr = 1 }
			if (/^DVDRAM/)         { $dvdram = 1 }
			if (/^NET_PROTO/)      { s/^NET_PROTO=//gi; $net_proto = $_ }
			if (/^HOST_PATH/)      { s/^HOST_PATH=//gi; $host_path = $_ } 
			if (/^DAEMON_MEDIA/)   { s/^DAEMON_MEDIA=//gi; $daemon_media = $_ }
			if (/^HD_QUOTA/)       { $hd_quota = 1 }
			if (/^USE_HD/)         { $where_hd = 1 }
			if (/^MAX_SPACE/)	   { s/^MAX_SPACE=//gi; $max_space = $_ }
			if (/^USE_CD/)         { $where_cd = 1 }
			if (/^USE_NET/)        { $where_net = 1 }
			if (/^USE_TAPE/)       { $where_tape = 1 }
			if (/^TAPE_NOREWIND/)  { $tape_norewind = 1 }
			if (/^CD_TIME/)        { s/^CD_TIME=//gi; $cd_time = $_ }
			if (/^DAEMON_TIME_SPACE/) { s/^DAEMON_TIME_SPACE=//gi; $when_space = $_; $backup_daemon = 1 }
			if (/^CD_WITH_INSTALL_BOOT/) { $cd_with_install_boot = 1 }
			if (/^CD_DEVICE/)      { s/^CD_DEVICE=//gi; $cd_device = $_ }
			if (/^HOST_NAME/)      { s/^HOST_NAME=//gi; $host_name = $_ } 
			if (/^REMEMBER_PASS/)  { $remember_pass = 1 }
			if (/^USER_KEYS/)      { $user_keys = 1 }
			if (/^DRAK_KEYS/)      { $xfer_keys = 1; $user_keys = 0 }
			if (/^USE_EXPECT/)     { $use_expect = 1; $user_keys = 0 }
			if (/^LOGIN/)          { s/^LOGIN=//gi;  $login_user  = $_ }
			if (/^PASSWD/)         { s/^PASSWD=//gi; $passwd_user = $_; $remember_pass = 1 }
			if (/^USER_MAIL/)      { s/^USER_MAIL=//gi; $user_mail = $_ }		     
			if (/^SEND_MAIL/)      { $send_mail = 1 }
			if (/^TAPE_DEVICE/)    { s/TAPE_DEVICE=//gi; $tape_device = $_ }
			if (/^MEDIA_ERASE/)    { $media_erase = 1 }
			if (/^MEDIA_EJECT/)    { $media_eject = 1 }
			if (/^MULTI_SESSION/)  { $multi_session = 1 }
			if (/^SYS_INCREMENTAL_BACKUPS/)   { $backup_sys_versions = 1 }
			if (/^USER_INCREMENTAL_BACKUPS/)  { $backup_user_versions = 1 }
			if (/^OTHER_INCREMENTAL_BACKUPS/) { $backup_other_versions = 1 }
			if (/^SYS_DIFFERENTIAL_BACKUPS/)   { $sys_diff_mode = 1 }
			if (/^USER_DIFFERENTIAL_BACKUPS/)  { $user_diff_mode = 1 }
			if (/^OTHER_DIFFERENTIAL_BACKUPS/) { $other_diff_mode = 1 }
			if (/^NO_CRITICAL_SYS/) { $no_critical_sys = 1 }
			if (/^CRITICAL_SYS/)   { $no_critical_sys = 0 }
			if (/^BACKUPIGNORE/)   { $backupignore = 1 }
			if (/^DEL_HD_FILES/)   { $del_hd_files = 1 }
	    }
		close(CONF_FILE);
		read_cron_files();
		$cfg_file_exist = 1;
    } else { 
    	$cfg_file_exist = 0;
		#- these were 1 by default, but that made it so the user could never save the 
		#- inverse behavior. this allows incremental as the default if not configured
		$backup_sys_versions = 1;
		$backup_user_versions = 1; 
    }
	# deal with users that may have been deleted from the system
	check_valid_users() if $cfg_file_exist;    
}

sub check_valid_users() {
	all_user_list();
	my @new_user_list = intersection(\@user_list, \@user_list_all);
	if (@user_list != @new_user_list) {
		log::l(N("Valid user list changed, rewriting config file."));
		if ($DEBUG) {
			print N("Old user list:\n");
			print "@user_list\n";
			print N("New user list:\n");
			print "@new_user_list\n";	
		}
		@user_list = @new_user_list;
		save_conf_file();
	}
}

sub write_sitecopyrc() {
	#- FIXME - how to deal with existing sitecopyrc
    my @cfg_list = ("site drakbackup\n",
		     "\tserver $host_name\n",
		     "\tremote /$host_path\n",
		     "\tlocal $save_path\n",
		     "\tusername $login_user\n",
		     "\tpassword $passwd_user\n",
		     "\tprotocol webdav\n"
			);
    output_p("$user_home/.sitecopyrc", @cfg_list);
    chmod(0600, "$user_home/.sitecopyrc");
    -d "$user_home/.sitecopy" or mkdir_p("$user_home/.sitecopy");
    chmod(0700, "$user_home/.sitecopy");
}

sub write_password_file() {
	output_p("$cfg_dir/rsync.user", "$passwd_user\n");
	chmod(0600, "$cfg_dir/rsync.user");
}

my $in;

sub show_warning {
	my ($mode, $warning) = @_;
	$mode = N("WARNING") if $mode eq "w";
	$mode = N("FATAL") if $mode eq "f";
	$mode = N("INFO") if $mode eq "i";
	if ($interactive) {
		$in->ask_warn('', translate($mode).": ".translate($warning));
	} else {
		warn "$mode: $warning\n";
	}
	$log_buff .= "\n$mode: $warning\n";
}
	
sub complete_results() {
    system_state();
    $results .=  "***********************************************************************\n\n";
    $daemon or $results .=  N("\n                      DrakBackup Report \n");
    $daemon and $results .= N("\n                      DrakBackup Daemon Report\n");
	my $datem = `date`;
	$results .=               "                      $datem\n\n";	
    $results .=  "***********************************************************************\n\n";
    $results .= $system_state;
    $results .=  "\n\n***********************************************************************\n\n";
    $results .=             N("\n                    DrakBackup Report Details\n\n\n");
    $results .=  "***********************************************************************\n\n";
}

sub ftp_client() {
    use Net::FTP; 
    my $ftp;

    $DEBUG and print "file list to send: $_\n "  foreach @file_list_to_send_by_ftp;
    if ($DEBUG && $interactive) { $ftp = Net::FTP->new($host_name, Debug => 1) or return 1 }
    elsif ($interactive)  {  $ftp = Net::FTP->new($host_name, Debug => 0) or return 1 }
    else {  $ftp = Net::FTP->new($host_name, Debug => 0) or return 1 }
    $ftp->login($login_user, $passwd_user);
    $ftp->cwd($host_path); 
    foreach (@file_list_to_send_by_ftp) {
		$interactive and $pbar->set_fraction(0);
		$interactive and progress($pbar, $plabel, 0.5, $_);
		$interactive and $pbar->set_text($_);
		#- make perl_checker happy...
		$ftp->put($_, undef, undef);
		$interactive and progress($pbar, $plabel, 0.5, $_);
		$interactive and $pbar->set_text($_);
		$interactive and progress($pbar3, $plabel3, 1/@file_list_to_send_by_ftp, N("Total progress"));
    }
    $ftp->quit; 
    return 0;
}

sub do_expect {

	#- Sort of a general purpose expect routine, we use it to backup files to
	#- a remote server, as well as transfer a key and restore.
	#- Using the key after it is setup is preferred.
	
	my ($mode) = @_;
		
	eval { require Expect };
	
	if ($@) {
		if ($mode eq 'sendkey') {
			destroy_widget();
			check_pkg_needs();
		} else { 
			$log_buff .= "perl-Expect not installed!", 
		}
		return 1;
	}
	
	#- for debugging set to 1
	$Expect::Exp_Internal = 0;
	#- for debugging set to 1
	$Expect::Debug = 0;
	$Expect::Log_Stdout = 0; 

	my $spawn_ok;
	my $no_perm;
	my $bad_passwd;
	my $bad_dir;
	my $timeout  = 20;
	
	my $exp_command;
	my @send_files = "$backup_key.pub";
	
	#- just bypass progress for sendkey for now
	$interactive = 0 if $mode eq "sendkey";
	
	@send_files = @file_list_to_send_by_ftp if $mode eq "backup";
	
	$interactive and $pbar->set_fraction(0);
	$interactive and $pbar3->set_fraction(0);
	$interactive and progress($pbar, $plabel, 0.5, "File Transfer...");

	foreach (@send_files) {
		$exp_command = "scp -P $scp_port $_ $login_user\@$host_name:$host_path" if $mode eq "backup";
		$exp_command = "ssh-copy-id -i $_ $login_user\@$host_name" if $mode eq "sendkey";
	
		if (-e $backup_key && $mode eq "sendkey") {
			if ($in->ask_yesorno('', N("%s exists, delete?\n\nWarning: If you've already done this process you'll probably\n need to purge the entry from authorized_keys on the server.", $backup_key))) {
				unlink($backup_key);
				unlink($backup_key . '.pub');
			} else {
				return 0;
			}
		}
	
		if (!(-e $backup_key) && $mode eq "sendkey") {	
			$in->ask_warn('', N("This may take a moment to generate the keys."));
			cursor_wait();
			#- not using a passphrase for the moment
			system("ssh-keygen -P '' -t dsa -f $backup_key");
			cursor_norm();
		}
		
		my $exp = Expect->spawn($exp_command) or $in->ask_warn('', N("ERROR: Cannot spawn %s.", $exp_command));

		$interactive and progress($pbar3, $plabel3, 1/@send_files, N("Total progress"));
		$interactive and $stext->set_text($_);
	
		#- run scp, look for some common errors and try to track successful progress for GUI
		$exp->expect($timeout,
			[ qr 'password: $', sub { 
				$spawn_ok = 1;
				my $fh = shift;
				$fh->send("$passwd_user\n");
				Expect::exp_continue() } ],
			[ '-re', 'please try again', sub { $bad_passwd = 1; Expect::exp_continue() } ],
			[ '-re', 'Permission denied', sub { $no_perm = 1; Expect::exp_continue() } ],
			[ '-re', 'No such file or directory', sub { $bad_dir = 1; Expect::exp_continue() } ],
#			[ '-re', '%', sub { update_scp_progress(); Expect::exp_continue(); } ],
			[ eof => sub {
					if (!$spawn_ok) { show_warning("f", N("No password prompt on %s at port %s", $host_name, $scp_port)) }					
					if ($bad_passwd) { show_warning("f", N("Bad password on %s", $host_name)) }
					if ($no_perm) { show_warning("f", N("Permission denied transferring %s to %s", $_, $host_name)) }
					if ($bad_dir) { show_warning("f", N("Can't find %s on %s", $host_path, $host_name)) }
				} 
			],
			[ timeout => sub { show_warning("f", N("%s not responding", $host_name)) } ],
		); 

		my $exit_stat = $exp->exitstatus;
		$in->ask_warn('', N("Transfer successful\nYou may want to verify you can login to the server with:\n\nssh -i %s %s\@%s\n\nwithout being prompted for a password.", $backup_key, $login_user, $host_name)) if $exit_stat == 0 && $mode eq "sendkey";
		$log_buff .= "$_\n" if $exit_stat == 0 && $mode eq "backup";
		$exp->hard_close;
	}
	$interactive and progress($pbar, $plabel, 0.5, "Done...");
	$interactive = 1 if $mode eq "sendkey";
}

sub ssh_client() {
    $DEBUG and print "file list to send: $_\n "  foreach @file_list_to_send_by_ftp;
	my $command;
	my $value;
	
    foreach (@file_list_to_send_by_ftp) {
		if ($user_keys) {
			$command = "scp -P $scp_port $_ $login_user\@$host_name:$host_path";
		} else {
			$command = "scp -P $scp_port -i $backup_key $_ $login_user\@$host_name:$host_path";
		}
		$interactive and $pbar->set_fraction(0);
		$interactive and progress($pbar, $plabel, 0.5, "File Transfer...");
		$interactive and $stext->set_text($_);
		$log_buff .= $command . "\n\n";
        local *TMP;
		open TMP, "$command 2>&1 |";
		while ($value = <TMP>) {
			$log_buff .= $value;
		}
		close TMP;
		$log_buff .= "\n";
		$interactive and progress($pbar, $plabel, 0.5, "Done...");
		$interactive and progress($pbar3, $plabel3, 1/@file_list_to_send_by_ftp, N("Total progress"));
    }
    return 0;
}

sub webdav_client() {
    $DEBUG and print "file list to send: $_\n "  foreach @file_list_to_send_by_ftp;
	if (!(-e "$user_home/.sitecopy/drakbackup")) {
		my $command = "sitecopy -f $host_path";
		spawn_progress($command, "Initializing sitecopy");
	}
	my $command = "sitecopy -u drakbackup";
	spawn_progress($command, "Running sitecopy...");
		if ($log_buff =~ /Nothing to do - no changes found/) {
		show_warning("w", N("WebDAV remote site already in sync!"));
		return 1;
	}
	if ($log_buff !~ /Update completed successfully/) {
		show_warning("f", N("WebDAV transfer failed!"));
		return 1;
	}
	return 0;
}

sub rsync_client() {
    $DEBUG and print "file list to send: $_\n "  foreach @file_list_to_send_by_ftp;
	my $rsync_cmd = "rsync -tv $save_path/* ";
	$rsync_cmd = $rsync_cmd . "--password-file=$cfg_dir/rsync.user " if $passwd_user;
	$rsync_cmd = $rsync_cmd . "$login_user\@" if $login_user;
	$rsync_cmd = $rsync_cmd . $host_name . "::" . $host_path;
	spawn_progress($rsync_cmd, "Running rsync");
	return 0;
}

sub check_for_cd() {	
	#- check for a cd
	my $command = "cdrecord dev=$cd_device -atip";
	spawn_progress($command, "Check for media in drive");
	if ($log_buff =~ /No disk/) {
		show_warning("f", N("No CD-R/DVD-R in drive!"));
		return 1;
	}
	if ($log_buff !~ /ATIP info from disk/) {
		show_warning("f", N("Does not appear to be recordable media!"));
		return 1;
	}
	if ($log_buff =~ /Is not erasable/ && $media_erase) {
		show_warning("f", N("Not erasable media!"));
		return 1;
	}
	 
	if ($multi_session) {
		$command = "cdrecord dev=$cd_device -msinfo";
		spawn_progress($command, "Check for previous session status");
		#- if we don't find a previous session, start fresh
		if ($log_buff =~ /Cannot read session offset/) {
			$media_erase = 1;
			return 0;
		} else {
			#- extract the session info from $log_buff
			my $code_loc = rindex($log_buff, "msinfo") + 8;
			if ($code_loc != -1) { 
				my $bufflen = length($log_buff);
				$session_offset = substr($log_buff, $code_loc, $bufflen-$code_loc-1);
				return 0;
			}
			return 1;
		}
	}
}
	
sub write_on_cd() {	
	my $command = "cdrecord -v dev=$cd_device -data ";
	#- only blank if it's the first session
	$command .= "blank=fast " if $media_erase && $session_offset eq '';
	#- multi-session mode
	$command .= "-multi -pad " if $multi_session;
	$command .= "$save_path/drakbackup.iso"; 
	
	spawn_progress($command, "Running cdrecord");
	unlink("$save_path/drakbackup.iso");
}

sub erase_cdrw() {
	#- we can only hit this via interactive
	$interactive = 0;
	$in->ask_warn('', N("This may take a moment to erase the media."));
	cursor_wait();
	my $command = "cdrecord dev=$cd_device -blank=fast";
	spawn_progress($command, "Erasing CDRW...");
	cursor_norm();	
	$interactive = 1;
}

sub spawn_progress {
	my ($command, $descr) = @_;
	my $value;
	my $timer;
	$interactive and progress($pbar3, $plabel3, 0, translate($descr));
	$interactive and $pbar3->set_pulse_step(0.1);
	$interactive and $timer = Glib::Timeout->add(20, sub { $pbar3->pulse });

	$log_buff .= "\n" . $descr . ":\n";
	$log_buff .= $command . "\n\n";
	
	local *TMP;
	open TMP, "$command 2>&1 |";
	while ($value = <TMP>) {
		$log_buff .= $value;
		if ($interactive) {
			$stext->set_text($value);
			gtkflush();
		}			
	}
	close TMP;
	$interactive and Glib::Source->remove($timer);
}

sub get_cd_device() {
	my $check_device = "/dev/cdrom";
	get_cd_info();
	foreach  (keys %cd_devices) {
		if ($cd_devices{$_}{rec_dev} eq $cd_device) {
			s/sr/scd/;
			$check_device = "/dev/" . $_;				
		}
	}
	$check_device;
}

sub get_cd_volname() {
	#- we want the volname for the catalog
	my $check_device = get_cd_device();
     local *TMP;
	open TMP, "volname $check_device 2>&1 |";
     local $_;
	while (<TMP>) {
		$vol_name = $_;		
	}
	close TMP;
	$vol_name =~ s/[ \t]+\n$//;
	$vol_name; 			
}

sub build_iso() {	
	if ($multi_session && $session_offset) {
		$vol_name = get_cd_volname();
	} else {
		$vol_name = "Drakbackup" . $the_time;
	}
	#this is safe to change the volname on rewrites, as is seems to get ignored anyway
	my $command = "mkisofs -r -J -T -v -V '$vol_name' ";
	$command .= "-C $session_offset -M $cd_device " if $multi_session && $session_offset;
	$command .= "-o $save_path/drakbackup.iso @file_list_to_send_by_ftp";
	spawn_progress($command, "Running mkisofs...");
}

sub build_cd() {
	if (!check_for_cd()) {
		build_iso();
		if ($log_buff =~ /Permission denied/) {
			show_warning("f", N("Permission problem accessing CD."));
			$media_problem = 1;
			return 1;
		} else {
			write_on_cd();
		}
	}
}

sub get_tape_label {
	my ($device) = @_;
	cursor_wait();
	system("mt -f $device rewind");
	system("tar -C $cfg_dir -xf $device");
	my @volname = cat_("$cfg_dir/drakbackup.label");
	unlink("$cfg_dir/drakbackup.label");
	$vol_name = $volname[0];
	cursor_norm();
	$vol_name;
}

sub build_tape() {
	my $command;
	#- do we have a tape?
	$command = "mt -f $tape_device status"; 
	spawn_progress($command, "Checking for tape");
	if ($log_buff =~ /DR_OPEN/) {
		show_warning("f", N("No tape in %s!", $tape_device));
		return 1;
	}	
	
	#- try to roll to the end of the data if we're not erasing
	if (!$media_erase) {
		$command = "mt -f $tape_device rewind";
		spawn_progress($command, "Rewind to find tape label");
		$command = "tar -tf $tape_device";
		spawn_progress($command, "Check for label");
		if ($log_buff =~ /drakbackup.label/) {
			if ($tape_norewind) {
				$command = "mt -f $tape_device rewind";
				spawn_progress($command, "Rewind to get tape label");
			}
			$command = "tar -C $cfg_dir -xf $tape_device";
			spawn_progress($command, "Reading tape label");		
			my @volname = cat_("$cfg_dir/drakbackup.label");
			unlink("$cfg_dir/drakbackup.label");
			$vol_name = $volname[0];
		}
		$command = "mt -f $tape_device eod"; 
		spawn_progress($command, "Running mt to find eod");
	} else {
		$command = "mt -f $tape_device rewind"; 
		spawn_progress($command, "Running mt to rewind");		
		# make a tape label for the catalog
		# if we're using the rewinding device, change modes briefly
		if (!$tape_norewind) {
			$tape_device =~ s|/st|/nst|;
		}
		$vol_name = "Drakbackup" . $the_time;
		my $f = "$cfg_dir/drakbackup.label";
		output($f, $vol_name);
		$command = "tar -C $cfg_dir -cf $tape_device drakbackup.label;";
		spawn_progress($command, "Creating tape label");
		unlink $f;
		if (!$tape_norewind) {
			$tape_device =~ s|/nst|/st|;
		}
	}
	
	#- do the backup
	$command = "tar -cvf $tape_device @file_list_to_send_by_ftp";
	spawn_progress($command, "Running tar to tape");
	
	#- eject the tape?
	if ($media_eject) {
		$command = "mt -f $tape_device rewoff";
		spawn_progress($command, "Running mt to eject tape");
	}
}

# share this with logdrake
sub send_mail {
    my ($result) = @_;
    my $datem = `date`;

    local *F;
    open F, "|/usr/sbin/sendmail -f$user_mail $user_mail" or return 1;
    print F "From: drakbackup\n";
    print F "To: $user_mail \n";
    print F "Subject: DrakBackup report on $datem \n";
    print F "\n";
    print F "$result\n";
    close F or  return 1;
    return 0;
}

sub build_backup_files() {
    my $path_name;
    my $tar_cmd;
    my $more_recent;
    my $tar_cmd_sys;
    my $tar_cmd_user;
    my $tar_cmd_other;
    my $base_sys_exist = 0;
    my @dir_content;
	my $incr;
	my $find_args = "! -type d";
	
	local $_;
    $results = "";
	$log_buff = "";
	#- flush this so if the user does 2 runs in a row we don't try to send the same files
	@file_list_to_send_by_ftp = ();
		
	$interactive and cursor_wait();
    read_conf_file();
    the_time();    
    $send_mail and complete_results();
    -d  $save_path or mkdir_p($save_path);
		
    if ($comp_mode) { 
		$DEBUG and $tar_cmd = "tar cv --use-compress-program /usr/bin/bzip2 ";
		$DEBUG or $tar_cmd = "tar c --use-compress-program /usr/bin/bzip2 "; 
		$tar_ext = "tar.bz2";
    } else { 
		$DEBUG and $tar_cmd = "tar cvpz "; 
		$DEBUG or $tar_cmd = "tar cpz "; 
		$tar_ext = "tar.gz"
	}
	my $used_space = check_storage_quota($save_path);
	if ($used_space) {
		my $msg = N("Backup quota exceeded!\n%d MB used vs %d MB allocated.", $used_space, $max_space);
		show_warning("f", $msg);
		$interactive and cursor_norm();
		$results .= $msg;
		$interactive and show_status();
		results_to_logfile();
		return 1; 
	}
	$tar_cmd_sys = $tar_cmd;
    $tar_cmd_user = $tar_cmd;
    $tar_cmd_other = $tar_cmd;
    $no_critical_sys and $tar_cmd_sys .= "--exclude passwd --exclude fstab --exclude group --exclude mtab";
    $what_no_browser and $tar_cmd_user .= "--exclude NewCache --exclude Cache --exclude cache";
	$nonroot_user and $tar_cmd_user .= " --exclude .drakbackup";
	$backupignore && -f "/etc/.backupignore" and $tar_cmd_sys .= " -X /etc/.backupignore";
	
    -d $save_path and @dir_content = all($save_path);
    any { /^backup_base_sys/ } @dir_content and $base_sys_exist = 1;

    if ($where_hd && !$daemon || $daemon) {
	  $interactive and progress($pbar, $plabel, 0.5, N("Backup system files..."));
	  if ($backup_sys) {
	  	my $find_args_sys = $find_args;
	  	if ($backupignore) {
			my @ignore_files = cat_("/etc/.backupignore");
			foreach (@ignore_files) {
				chop;
				$find_args_sys .= " ! -name '" . $_ . "'";
			}
		}
		$find_args_sys .= " -print";	
	    if ($backup_sys_versions) {
			$incr = "incr_sys";
			$incr =~ s/incr/diff/ if $sys_diff_mode;
			#- 8/19/2002 - changed these greps to look at the list, rather than the tar file
			#- we retain the list for other media backups, but the tar file goes away, potentially
 			if ((any { /^list_incr_sys/ } @dir_content) && !$sys_diff_mode) { 
		    	my @more_recent = grep { /^list_incr_sys/ } sort @dir_content; 
		    	$more_recent = pop @more_recent;
		    	$DEBUG and print "more recent file: $more_recent\n";
				system("find @sys_files -cnewer $save_path/$more_recent $find_args_sys > $save_path/list_incr_sys$the_time.txt");
		    	if (!cat_("$save_path/list_incr_sys$the_time.txt")) {
					system("rm $save_path/list_incr_sys$the_time.txt");
		    	} else {
					system("$tar_cmd_sys -f $save_path/backup_incr_sys$the_time.$tar_ext -T $save_path/list_incr_sys$the_time.txt");
					push @file_list_to_send_by_ftp, "$save_path/backup_incr_sys$the_time.$tar_ext";
					push @file_list_to_send_by_ftp, "$save_path/list_incr_sys$the_time.txt";
					$results .= "\nfile: $save_path/backup_incr_sys$the_time.$tar_ext\n";
					$results .= cat_("$save_path/list_incr_sys$the_time.txt");
		    	}
			} elsif (any { /^list_base_sys/ }  @dir_content) { 
		    	my @more_recent = grep { /^list_base_sys/ } sort @dir_content; 
		    	$more_recent = pop @more_recent;
		    	$DEBUG and print "more recent file: $more_recent\n";
  		  		system("find @sys_files -cnewer $save_path/$more_recent $find_args_sys > $save_path/list_$incr$the_time.txt");
		    	if (!cat_("$save_path/list_$incr$the_time.txt")) {
					system("rm $save_path/list_$incr$the_time.txt");
		    	} else {
					system("$tar_cmd_sys -f $save_path/backup_$incr$the_time.$tar_ext -T $save_path/list_$incr$the_time.txt");
					push @file_list_to_send_by_ftp, "$save_path/backup_$incr$the_time.$tar_ext";
					push @file_list_to_send_by_ftp, "$save_path/list_$incr$the_time.txt";
					$results .= "\nfile: $save_path/backup_$incr$the_time.$tar_ext\n";
					$results .= cat_("$save_path/list_$incr$the_time.txt");
		    	}
			} else {
				#- need this for the first pass too, if we're offloading the backups to other media (sb)
				system("find @sys_files $find_args_sys > $save_path/list_base_sys$the_time.txt"); 
				system("$tar_cmd_sys -f $save_path/backup_base_sys$the_time.$tar_ext @sys_files"); 
				push @file_list_to_send_by_ftp, "$save_path/backup_base_sys$the_time.$tar_ext";
				push @file_list_to_send_by_ftp, "$save_path/list_base_sys$the_time.txt";
				$results .= "\nfile: $save_path/backup_base_sys$the_time.$tar_ext\n";
			}
	  	} else {
			system("cd $save_path && rm -f backup_sys* backup_base_sys* backup_incr_sys*");
			system("$tar_cmd_sys -f $save_path/backup_sys$the_time.$tar_ext @sys_files");
			push @file_list_to_send_by_ftp, "$save_path/backup_sys$the_time.$tar_ext";
			$results .= "\nfile: $save_path/backup_sys$the_time.$tar_ext\n";
	  	}
	  }
	  $interactive and progress($pbar, $plabel, 0.5, N("Backup system files..."));
	  $interactive and progress($pbar3, $plabel3, 0.3, N("Hard Disk Backup files..."));
	
	  if ($backup_user) {
	    foreach (@user_list) {
		  my $user = $_;
		  my $tar_cmd_cuser = $tar_cmd_user;
		  $path_name = return_path($user);
		  $backupignore && -f "$path_name/.backupignore" and $tar_cmd_cuser .= " -X $path_name/.backupignore";
		  my $find_args_user = $find_args;
	  	  if ($backupignore) {
			my @ignore_files = cat_("$path_name/.backupignore");
			foreach (@ignore_files) {
				chop;
				$find_args_user .= " ! -name '" . $_ . "'";
			}
		  }
		  $find_args_user .= " -print";	
		  if ($backup_user_versions) {
			$incr = "incr_user_";
			$incr =~ s/incr/diff/ if $user_diff_mode;
			#- 8/19/2002 - changed these greps to look at the list, rather than the tar file
			#- we retain the list for other media backups, but the tar file goes away, potentially
		    if ((any { /^list_incr_user_$user/ } @dir_content) && !$user_diff_mode) { 
				my @more_recent = grep { /^list_incr_user_$user/ } sort @dir_content; 
				$more_recent = pop @more_recent;
				$DEBUG and print "more recent file: $more_recent\n";
				system("find $path_name -cnewer $save_path/$more_recent $find_args_user > $save_path/list_incr_user_$user$the_time.txt");
				if (!cat_("$save_path/list_incr_user_$user$the_time.txt")) {
			    	system("rm $save_path/list_incr_user_$user$the_time.txt");
				} else {
					system("$tar_cmd_cuser -f $save_path/backup_incr_user_$user$the_time.$tar_ext -T $save_path/list_incr_user_$user$the_time.txt");
					push @file_list_to_send_by_ftp, "$save_path/backup_incr_user_$user$the_time.$tar_ext";
					push @file_list_to_send_by_ftp, "$save_path/list_incr_user_$user$the_time.txt";
					$results .= " \nfile: $save_path/backup_incr_user_$user$the_time.$tar_ext\n";
					$results .= cat_("$save_path/list_incr_user_$user$the_time.txt");
				}
		    } elsif (any { /^list_base_user_$user/ } @dir_content) { 
				my @more_recent = grep { /^list_base_user_$user/ } sort @dir_content; 
				$more_recent = pop @more_recent;			
				$DEBUG and print "more recent file: $more_recent\n";
				system("find $path_name -cnewer $save_path/$more_recent $find_args_user > $save_path/list_$incr$user$the_time.txt");
				if (!cat_("$save_path/list_$incr$user$the_time.txt")) {
			    	system("rm $save_path/list_$incr$user$the_time.txt");
				} else {
					system("$tar_cmd_cuser -f $save_path/backup_$incr$user$the_time.$tar_ext -T $save_path/list_$incr$user$the_time.txt");
					push @file_list_to_send_by_ftp, "$save_path/backup_$incr$user$the_time.$tar_ext";
					push @file_list_to_send_by_ftp, "$save_path/list_$incr$user$the_time.txt";
					$results .= "\nfile: $save_path/backup_$incr$user$the_time.$tar_ext\n";
					$results .= cat_("$save_path/list_$incr$user$the_time.txt");
				}
		    } else {
				#- need this for the first pass too, if we're offloading the backups to other media (sb)
				system("find $path_name $find_args_user > $save_path/list_base_user_$user$the_time.txt");
				system("$tar_cmd_cuser -f $save_path/backup_base_user_$user$the_time.$tar_ext $path_name");
				push @file_list_to_send_by_ftp, "$save_path/backup_base_user_$user$the_time.$tar_ext";
				push @file_list_to_send_by_ftp, "$save_path/list_base_user_$user$the_time.txt";
				$results .= "\nfile: $save_path/backup_base_user_$user$the_time.$tar_ext\n";
		    }
		  } else {
		    system("cd $save_path && rm -f backup_user_$_* backup_base_user_$_* backup_incr_user_$_*");
		    system("$tar_cmd_cuser -f $save_path/backup_user_$_$the_time.$tar_ext $path_name");
		    push @file_list_to_send_by_ftp, "$save_path/backup_user_$_$the_time.$tar_ext";
		    $results .= "\nfile: $save_path/backup_user_$user$the_time.$tar_ext\n";
		  }
	    }
	  }
	  $interactive and progress($pbar2, $plabel1, 1, N("Backup User files..."));
	  $interactive and progress($pbar3, $plabel3, 0.4, N("Hard Disk Backup files..."));

	  if (@list_other) {
		my $find_args_other = $find_args;
	  	if ($backupignore) {
			foreach my $dir (@list_other) {
				if (-d $dir) {
					my @ignore_files = cat_("$dir/.backupignore");
					-f "$dir/.backupignore" and $tar_cmd_other .= " -X $dir/.backupignore";
					foreach (@ignore_files) {
						chop;
						$find_args_other .= " ! -name '" . $_ . "'";
					}
				}
			}
		}
		$find_args_other .= " -print";	
		if ($backup_other_versions) {
			$incr = "incr_other";
			$incr =~ s/incr/diff/ if $other_diff_mode;
 			if ((any { /^list_incr_other/ } @dir_content) && !$user_diff_mode) { 
		    	my @more_recent = grep { /^list_incr_other/ } sort @dir_content; 
		    	$more_recent = pop @more_recent;
		    	$DEBUG and print "more recent file: $more_recent\n";
				system("find @list_other -cnewer $save_path/$more_recent $find_args_other > $save_path/list_incr_other$the_time.txt");
		    	if (!cat_("$save_path/list_incr_other$the_time.txt")) {
					system("rm $save_path/list_incr_other$the_time.txt");
		    	} else {
					system("$tar_cmd_other -f $save_path/backup_incr_other$the_time.$tar_ext -T $save_path/list_incr_other$the_time.txt");
					push @file_list_to_send_by_ftp, "$save_path/backup_incr_other$the_time.$tar_ext";
					push @file_list_to_send_by_ftp, "$save_path/list_incr_other$the_time.txt";
					$results .= "\nfile: $save_path/backup_incr_other$the_time.$tar_ext\n";
					$results .= cat_("$save_path/list_incr_other$the_time.txt");
		    	}
			} elsif (any { /^list_base_other/ }  @dir_content) { 
		    	my @more_recent = grep { /^list_base_other/ } sort @dir_content; 
		    	$more_recent = pop @more_recent;
		    	$DEBUG and print "more recent file: $more_recent\n";
  		  		system("find @list_other -cnewer $save_path/$more_recent $find_args_other > $save_path/list_$incr$the_time.txt");
		    	if (!cat_("$save_path/list_$incr$the_time.txt")) {
					system("rm $save_path/list_$incr$the_time.txt");
		    	} else {
					system("$tar_cmd_other -f $save_path/backup_$incr$the_time.$tar_ext -T $save_path/list_$incr$the_time.txt");
					push @file_list_to_send_by_ftp, "$save_path/backup_$incr$the_time.$tar_ext";
					push @file_list_to_send_by_ftp, "$save_path/list_$incr$the_time.txt";
					$results .= "\nfile: $save_path/backup_$incr$the_time.$tar_ext\n";
					$results .= cat_("$save_path/list_$incr$the_time.txt");
		    	}
			} else {
				#- need this for the first pass too, if we're offloading the backups to other media (sb)
				system("find @list_other $find_args_other > $save_path/list_base_other$the_time.txt"); 
				system("$tar_cmd_other -f $save_path/backup_base_other$the_time.$tar_ext @list_other"); 
				push @file_list_to_send_by_ftp, "$save_path/backup_base_other$the_time.$tar_ext";
				push @file_list_to_send_by_ftp, "$save_path/list_base_other$the_time.txt";
				$results .= "\nfile: $save_path/backup_base_other$the_time.$tar_ext\n";
			}
	  	} else {
			system("cd $save_path && rm -f backup_other* backup_base_other* backup_incr_other*");
			system("$tar_cmd_other -f $save_path/backup_other$the_time.$tar_ext @list_other");
			push @file_list_to_send_by_ftp, "$save_path/backup_other$the_time.$tar_ext";
			$results .= "\nfile: $save_path/backup_other$the_time.$tar_ext\n";
	  	}
	  }
	  $interactive and progress($pbar1, $plabel2, 1, N("Backup Other files..."));
	  $interactive and progress($pbar3, $plabel3, 0.3, N("Hard Disk Backup Progress..."));
	}
	  
	my $filecount = @file_list_to_send_by_ftp;
	if (!$filecount) {
		my $msg = N("No changes to backup!");
		show_warning("w", $msg);
		$interactive and cursor_norm();
		$interactive and interactive_mode();
		results_to_logfile();
		return 1;		
	}
		
	#- should hit this block if running daemon mode only
	if ($daemon && $daemon_media) {
#		ftp_client() if $ftp_daemon;
		rsync_client() if $daemon_media eq 'rsync';
		ssh_client() if $daemon_media eq 'ssh' && !$use_expect;
		do_expect("backup") if $daemon_media eq 'ssh' && $use_expect;
		webdav_client() if $daemon_media eq 'webdav';
		build_cd() if $daemon_media eq 'cd';
		build_tape() if $daemon_media eq 'tape';

		$results .= N("\nDrakbackup activities via %s:\n\n", $daemon_media) if $daemon_media ne 'hd';
		$results .= $log_buff;
	}
	
	#- leave this one alone for now - works well
	#- integrate with other methods later
    if (($where_net && !$daemon && $net_proto eq 'ftp') || $daemon && $daemon_media eq 'ftp') {
		$results .= N("file list sent by FTP: %s\n ", $_)  foreach @file_list_to_send_by_ftp;
		$interactive and build_backup_ftp_status();
		if (ftp_client()) { 
	    	$results .= N("\n FTP connection problem: It was not possible to send your backup files by FTP.\n");
	    	$interactive and client_ftp_pb();
		} 
    }
	
	#- consolidate all the other methods under here - interactive and --default should land here
	if (!$daemon) {
	
		if ($where_net && $net_proto && $net_proto ne 'ftp') {
			rsync_client() if $net_proto eq 'rsync';
			ssh_client() if $net_proto eq 'ssh' && !$use_expect;
			do_expect("backup") if $net_proto eq 'ssh' && $use_expect;
			webdav_client() if $net_proto eq 'webdav';
			$results .= N("\nDrakbackup activities via %s:\n\n", $net_proto);
		}
		
		if ($where_cd) {
			build_cd();
			$results .= N("\nDrakbackup activities via CD:\n\n");
		}
	
		if ($where_tape) {
			build_tape();
			$results .= N("\nDrakbackup activities via tape:\n\n");
		}
		$results .= $log_buff;
	}
	
	results_to_logfile();
	
    if ($send_mail) { 
		if (send_mail($results)) { 
	    	$interactive and send_mail_pb();
	    	$interactive or print N(" Error while sending mail. \n");
		} 
    }
	
	#- write our catalog file
	if (!$media_problem) {
		my $catalog = substr($the_time, 1);
		if (!$where_net && !$where_tape && !$where_cd) { 
			$catalog .= ":HD:localhost:$save_path";
			$net_proto = '';
		} 
		$catalog .= ":$net_proto:$login_user\@$host_name:$host_path" if $net_proto;
		$catalog .= ":CD:$vol_name:$cd_device" if $where_cd;
		$catalog .= ":Tape:$vol_name:$tape_device" if $where_tape;
		$catalog .= ":System" if $backup_sys;
		$catalog .= ":I" if $backup_sys_versions && $backup_sys && !$sys_diff_mode;
		$catalog .= ":D" if $backup_sys_versions && $backup_sys && $sys_diff_mode;
		$catalog .= ":F" if !$backup_sys_versions && $backup_sys;
		$catalog .= ":Users=(@user_list)" if $backup_user;
		$catalog .= ":I" if $backup_user_versions && $backup_user && !$user_diff_mode;
		$catalog .= ":D" if $backup_user_versions && $backup_user && $user_diff_mode;
		$catalog .= ":F" if !$backup_user_versions && $backup_user;;
		$catalog .= ":Other=(@list_other)" if @list_other;
		$catalog .= ":I" if $backup_other_versions && @list_other && !$other_diff_mode;
		$catalog .= ":D" if $backup_other_versions && @list_other && $other_diff_mode;
		$catalog .= ":F" if !$backup_other_versions && @list_other;
		$catalog .= "\n";
			
		local *CATALOG;
		open CATALOG, ">> $cfg_dir/drakbackup_catalog" or show_warning("w", N("Can't create catalog!"));
		print CATALOG $catalog;
		close CATALOG;
	}
	
	#- clean up HD files if del_hd_files and media isn't hd
	if ($del_hd_files && ($where_cd || $where_tape || $where_net) && $daemon_media ne 'hd')  {
		foreach (@file_list_to_send_by_ftp) {
			unlink($_) if /$tar_ext$/;
		}
	}
		
	#- if we had a media problem then get rid of the text log of the backed up files too
	if ($media_problem) {
		system("rm $save_path/list*$the_time.txt");
	}
	
	$interactive and cursor_norm();
	$interactive and show_status();
}

my @list_of_rpm_to_install;
sub require_rpm {
    my $all_rpms_found = 1;
    my $res;
    @list_of_rpm_to_install = ();
    foreach my $pkg (@_) {
		$res = system("rpm -q $pkg > /dev/null");
		if ($res == 256) { 
			$all_rpms_found = 0; 
			push @list_of_rpm_to_install, $pkg;
		}
    }
    return $all_rpms_found;
}

sub check_pkg_needs() {
	my $extra_pkg = '';
	if ($where_net) {
		$extra_pkg = 'rsync' if $net_proto eq 'rsync';
		$extra_pkg = 'sitecopy wget' if $net_proto eq 'webdav';
		$extra_pkg = 'perl-Expect' if $net_proto eq 'ssh' && ($use_expect || $xfer_keys);
	}
	$extra_pkg = 'mt-st' if $where_tape;
	if ($extra_pkg) {
		if (require_rpm($extra_pkg)) {
			return 0;
		} else {
			#- this isn't entirely good, but it's the only way we get here currently
			#- was getting strange return behavior before
			#- still a problem, we can also get here from the cron screen
			install_rpm(\&advanced_where);
			return 1;
		}		
	}	
}

sub cursor_wait() {
	# turn the cursor to a watch
	$window1->window->set_cursor(new Gtk2::Gdk::Cursor("GDK_WATCH"));    
	gtkflush();
}

sub cursor_norm() {
	# restore normal cursor
	$window1->window->set_cursor(new Gtk2::Gdk::Cursor("GDK_LEFT_PTR"));
	gtkflush();
}

sub show_status() {
    my $text = new Gtk2::TextView;	
	destroy_widget();
	my $scrolled_window = Gtk2::ScrolledWindow->new;
	$scrolled_window->set_border_width(10);
	$scrolled_window->add_with_viewport($text);
	gtktext_insert(gtkset_editable($text, 0), [ [ $results ] ]);

    gtkpack($advanced_box,
		$table = gtkpack_(new Gtk2::VBox(0,10), 1, $scrolled_window)
	);
    $central_widget = \$table;
    $table->show_all;    
}

sub results_to_logfile() {
		local *LOG;
		open LOG, "> $log_file" or show_warning("w", N("Can't create log file!"));
		print LOG "$results\n";
		close LOG;
}

sub file_ok_sel { 
    my ($file_selection) = @_;     
    my $file_name = $file_selection->get_filename;
    if (!member($file_name, @list_other)) {
		push(@list_other, $file_name);
		$list_model->append_set(undef, $file_name);
    }
}

sub filedialog_where_hd() {
    my $file_dialog;

    $file_dialog = gtksignal_connect(new Gtk2::FileSelection(N("File Selection")), destroy => sub { $file_dialog->destroy });
    $file_dialog->ok_button->signal_connect(clicked => sub { 
	$save_path_entry->set_text($file_dialog->get_filename); 
	$file_dialog->destroy });
    $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy });
    $file_dialog->show;
}

sub filedialog_restore_find_path() {
    my $file_dialog;

    $file_dialog = gtksignal_connect(new Gtk2::FileSelection(N("File Selection")), destroy => sub { $file_dialog->destroy });
    $file_dialog->ok_button->signal_connect(clicked => sub { 
		$restore_find_path_entry->set_text($file_dialog->get_filename);
		$file_dialog->destroy;
	});
    $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy });
    $file_dialog->show;
}

sub filedialog_generic {
	#- a more generic file dialog
	#- a title prompt, the widget to get updated and the variable to update
	my ($prompt, $widget, $set_var) = @_; 
	my $file_dialog;
	
    $file_dialog = gtksignal_connect(new Gtk2::FileSelection(translate($prompt)), destroy => sub { $file_dialog->destroy });
    $file_dialog->ok_button->signal_connect(clicked => sub { 
		$$set_var = $file_dialog->get_filename;
		$$widget->set_text($$set_var); 
		$file_dialog->destroy;
	});
    $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy });
    $file_dialog->show;
}

sub filedialog() {
    my $file_dialog;

    $file_dialog = gtksignal_connect(new Gtk2::FileSelection(N("Select the files or directories and click on 'OK'")), destroy => sub { $file_dialog->destroy });
    $file_dialog->ok_button->signal_connect(clicked => sub { file_ok_sel($file_dialog) });
    $file_dialog->cancel_button->signal_connect(clicked => sub { $file_dialog->destroy });
    $file_dialog->show;
}

################################################  ADVANCED  ################################################  

sub check_list {
    foreach (@_) {
	my $ref = $_->[1];
		gtksignal_connect(gtkset_active($_->[0], $$ref), toggled => sub { 
			invbool $ref; 
			destroy_widget();
			$current_widget->();
		});
	}
}

sub fonction_env {
    ($central_widget, $current_widget, $previous_widget, $next_widget) = @_;
}

sub advanced_what_sys() {
    my $box_what_sys;
    
    gtkpack($advanced_box,
	    $box_what_sys =  gtkpack_(new Gtk2::VBox(0, 15),
		     1, N("\nPlease check all options that you need.\n"),
		     1, N("These options can backup and restore all files in your /etc directory.\n"),
		     0, my $check_what_sys = new Gtk2::CheckButton(N("Backup your System files. (/etc directory)")),
		     0, my $check_what_versions = new Gtk2::CheckButton(N("Use Incremental/Differential Backups  (do not replace old backups)")),
		     0, gtkpack__(new Gtk2::HBox(0,0),	
				my @mode_buttons = gtkradio((N("Use Incremental Backups")) x 2, N("Use Differential Backups")),
			 ),
			 0, my $check_what_critical = new Gtk2::CheckButton(N("Do not include critical files (passwd, group, fstab)")),
		     0, N("With this option you will be able to restore any version\n of your /etc directory."),     
			 1, new Gtk2::VBox(0, 15),
		),
	);
    check_list([$check_what_sys, \$backup_sys], [$check_what_critical, \$no_critical_sys]);
	$check_what_versions->set_active($backup_sys_versions);
	$check_what_versions->signal_connect('toggled' => sub {
		invbool \$backup_sys_versions;
		$mode_buttons[0]->set_sensitive($backup_sys_versions);
		$mode_buttons[1]->set_sensitive($backup_sys_versions);
			
	});
	$mode_buttons[1]->set_active($sys_diff_mode);
	$mode_buttons[0]->signal_connect('toggled' => sub { $sys_diff_mode = $mode_buttons[1]->get_active });
	$mode_buttons[0]->set_sensitive($backup_sys_versions);
	$mode_buttons[1]->set_sensitive($backup_sys_versions);
	set_help_tip($check_what_versions, 'use_incr_decr');
	set_help_tip($mode_buttons[0], 'use_incremental');
	set_help_tip($mode_buttons[1], 'use_differential');
    fonction_env(\$box_what_sys, \&advanced_what_sys, \&advanced_what);
    $up_box->show_all;
}

sub advanced_what_user {
    my ($previous_function) = @_;
    my $box_what_user;
    my %check_what_user;
    
    all_user_list();
    gtkpack($advanced_box,
	    $box_what_user = gtkpack_(new Gtk2::VBox(0, 15),
			0, N("Please check all users that you want to include in your backup."),
			0, new Gtk2::HSeparator,
			1, create_scrolled_window( 
				gtkpack__(new Gtk2::VBox(0,0),
					map { my $name = $_;
						my @user_list_tmp;
						my $b = new Gtk2::CheckButton($name); 
						if (any { /^$name$/ } @user_list) {
							$check_what_user{$_}[1] = 1;
							gtkset_active($b, 1);
						} else {
							$check_what_user{$_}[1] = 0;
							gtkset_active($b, 0);
						}
						$b->signal_connect(toggled => sub { 
							if ($check_what_user{$name}[1]) {
								$check_what_user{$name}[1] = 0;
								@user_list_tmp = grep { !/^$name$/ } @user_list;
								@user_list = @user_list_tmp;
							} else { 
								$check_what_user{$name}[1] = 1;
								if (!member($name, @user_list)) { push @user_list, $name }
							}
						});
					$b } (@user_list_all) 
				),
			),
			0, my $check_what_browser = new Gtk2::CheckButton(N("Do not include the browser cache")),
			0, my $check_what_user_versions = new Gtk2::CheckButton(N("Use Incremental/Differential Backups  (do not replace old backups)")), 
		    0, gtkpack__(new Gtk2::HBox(0,0),	
				my @mode_buttons = gtkradio((N("Use Incremental Backups")) x 2, N("Use Differential Backups")),
			),
		),
	);
    check_list([$check_what_browser, \$what_no_browser]);
	$check_what_user_versions->set_active($backup_user_versions);
	$check_what_user_versions->signal_connect('toggled' => sub {
		invbool \$backup_user_versions; 
		$mode_buttons[0]->set_sensitive($backup_user_versions);
		$mode_buttons[1]->set_sensitive($backup_user_versions);	
	});
	$mode_buttons[1]->set_active($user_diff_mode);
	$mode_buttons[0]->signal_connect('toggled' => sub { $user_diff_mode = $mode_buttons[1]->get_active });
	$mode_buttons[0]->set_sensitive($backup_user_versions);
	$mode_buttons[1]->set_sensitive($backup_user_versions);
	set_help_tip($check_what_user_versions, 'use_incr_decr');
	set_help_tip($mode_buttons[0], 'use_incremental');
	set_help_tip($mode_buttons[1], 'use_differential');

    if ($previous_function) { fonction_env(\$box_what_user, \&advanced_what_user, \&$previous_function, \&$previous_function) }
    else { fonction_env(\$box_what_user, \&advanced_what_user, \&advanced_what) }
    $up_box->show_all;
}

sub advanced_what_other() {
    my $box_what_other;
	my $file_iter;
	my $other_file;
			
	$list_model = Gtk2::ListStore->new("Glib::String");
	my $list_others = Gtk2::TreeView->new_with_model($list_model);
	$list_others->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0));
	$list_others->set_headers_visible(0);	
		
	foreach (@list_other) {
    	$list_model->append_set(undef, $_);		
	}
	
	$list_others->get_selection->signal_connect(changed => sub {
    	my ($model, $iter) = $_[0]->get_selected;
    	$model && $iter or return;
    	$other_file = $model->get($iter, 0);
		$file_iter = $iter;
	});
	    
    gtkpack($advanced_box,
	    $box_what_other = gtkpack_(new Gtk2::VBox(0, 15),
			1, gtkpack_(new Gtk2::HBox(0,4),
				1, create_scrolled_window($list_others),
			),
			0, gtkadd(gtkset_layout(new Gtk2::HButtonBox, 'spread'),
				gtksignal_connect(Gtk2::Button->new(N("Add")), clicked => sub { filedialog() }),
				gtksignal_connect(Gtk2::Button->new(N("Remove Selected")), clicked => sub { 
					$list_model->remove($file_iter) if $file_iter; 
					my $iindex = 0; 
					foreach (@list_other) {
						if ($list_other[$iindex] eq $other_file) {
							splice(@list_other, $iindex, 1); 
							last;
						}
						$iindex++;
					}
				}),
			),
			0, my $check_what_other_versions = new Gtk2::CheckButton(N("Use Incremental/Differential Backups  (do not replace old backups)")),
			0, gtkpack__(new Gtk2::HBox(0,0),	
				my @mode_buttons = gtkradio((N("Use Incremental Backups")) x 2, N("Use Differential Backups")),
			),
		),
		
	);
	$check_what_other_versions->set_active($backup_other_versions);
	$check_what_other_versions->signal_connect('toggled' => sub {
		invbool \$backup_other_versions; 
		$mode_buttons[0]->set_sensitive($backup_other_versions);
		$mode_buttons[1]->set_sensitive($backup_other_versions);	
	});
	$mode_buttons[1]->set_active($other_diff_mode);
	$mode_buttons[0]->signal_connect('toggled' => sub { $other_diff_mode = $mode_buttons[1]->get_active });
	$mode_buttons[0]->set_sensitive($backup_other_versions);
	$mode_buttons[1]->set_sensitive($backup_other_versions);
	set_help_tip($check_what_other_versions, 'use_incr_decr');
	set_help_tip($mode_buttons[0], 'use_incremental');
	set_help_tip($mode_buttons[1], 'use_differential');

    fonction_env(\$box_what_other, \&advanced_what_other, \&advanced_what);
    $up_box->show_all;			
}

sub advanced_what_entire_sys() {
    my $box_what;
    
    gtkpack($advanced_box,
	    $box_what = gtkpack_(new Gtk2::HBox(0, 15),
		     1, new Gtk2::VBox(0, 5),
		     1, gtkpack_(new Gtk2::VBox(0, 15),	
				 1, new Gtk2::VBox(0, 5),
				 1, gtksignal_connect(my $button_what_other = Gtk2::Button->new, 
						      clicked => sub { destroy_widget(); message_underdevel() }),
				 1, gtksignal_connect(my $button_what_all = Gtk2::Button->new, 
						      clicked => sub { destroy_widget(); message_underdevel() }),
				 1, new Gtk2::VBox(0, 5),
				 ),
		     1, new Gtk2::VBox(0, 5),	
		     ),
	    );
    $button_what_other->add(gtkpack(new Gtk2::HBox(0,10),
				    gtkcreate_img("bootloader"),
				    new Gtk2::Label(N("Linux")),
				    new Gtk2::HBox(0, 5)
				    ));
    $button_what_all->add(gtkpack(new Gtk2::HBox(0,10),
				  gtkcreate_img("user"),
				  new Gtk2::Label(N("Windows (FAT32)")),
				  new Gtk2::HBox(0, 5)
				  ));
    fonction_env(\$box_what, \&advanced_what_entire_sys, \&advanced_what);
    $up_box->show_all;
}

sub advanced_what() {
    my $box_what;    

    gtkpack($advanced_box,
	    $box_what =  gtkpack_(new Gtk2::HBox(0, 15),
		     1, new Gtk2::VBox(0, 5),
		     1, gtkpack_(new Gtk2::VBox(0, 15),	
				 1, new Gtk2::VBox(0, 5),
				 1, gtksignal_connect(my $button_what_sys = Gtk2::Button->new, 
						      clicked => sub { $box_what->destroy; advanced_what_sys() }),
				 1, gtksignal_connect(my $button_what_user = Gtk2::Button->new, 
						      clicked => sub { destroy_widget(); advanced_what_user() }),
				 1, gtksignal_connect(my $button_what_other = Gtk2::Button->new, 
						      clicked => sub { destroy_widget(); advanced_what_other() }),
#				 1, gtksignal_connect(my $button_what_all = Gtk2::Button->new, 
#						  clicked => sub { destroy_widget(); advanced_what_entire_sys(); }),
				 1, new Gtk2::VBox(0, 5),
				 ),
		     1, new Gtk2::VBox(0, 5),	
				 ),
	    );
    $button_what_sys->add(gtkpack(new Gtk2::HBox(0,10),
				    gtkcreate_img("ic82-system-40"),
				    new Gtk2::Label(N("System")),
				    new Gtk2::HBox(0, 5)
				    ));
    $button_what_user->add(gtkpack(new Gtk2::HBox(0,10),
				    gtkcreate_img("ic82-users-40"),
				    new Gtk2::Label(N("Users")),
				    new Gtk2::HBox(0, 5)
				    ));
    $button_what_other->add(gtkpack(new Gtk2::HBox(0,10),
				    gtkcreate_img("ic82-others-40"),
				    new Gtk2::Label(N("Other")),
				    new Gtk2::HBox(0, 5)
				    ));
#     $button_what_all->add(gtkpack(new Gtk2::HBox(0,10),
# 				    gtkcreate_img("ic82-systemeplus-40"),
# 				    new Gtk2::Label(N("An Entire System")),
# 				    new Gtk2::HBox(0, 5)
# 				    ));

    fonction_env(\$box_what, \&advanced_what, \&advanced_box);
    $up_box->show_all;
}

sub advanced_where_net_types {
    my ($previous_function) = @_;
    my $box_where_net;
	        
    gtkpack($advanced_box,
	    $box_where_net = gtkpack_(new Gtk2::VBox(0, 10),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	 			0, my $check_where_use_net = new Gtk2::CheckButton(N("Use network connection to backup")),
				1, new Gtk2::HBox(0,10),
	 			0, new Gtk2::Label(N("Net Method:")),
	 			0, gtkset_sensitive(my $entry_net_type = new Gtk2::OptionMenu(), $where_net),
	 		),	 
	 		0, gtkpack_(new Gtk2::HBox(0,5),
	   			0, gtkset_sensitive(my $check_use_expect = new Gtk2::CheckButton(N("Use Expect for SSH")), ($where_net && $net_proto eq 'ssh')),
	   			0, gtkset_sensitive(my $check_xfer_keys = new Gtk2::CheckButton(N("Create/Transfer backup keys for SSH")), ($where_net && $net_proto eq 'ssh')),
				1, new Gtk2::HBox(0,10),
				0, gtkset_sensitive(my $button_xfer_keys = Gtk2::Button->new(N("Transfer Now")), $xfer_keys),
			),
			0, gtkset_sensitive(my $check_user_keys = new Gtk2::CheckButton(N("Other (not drakbackup) keys in place already")), ($where_net && $net_proto eq 'ssh')),
	 		0, new Gtk2::HSeparator,
	 		0, gtkpack_(new Gtk2::HBox(0,10),
		    	0, gtkset_sensitive(new Gtk2::Label(N("Host name or IP.")), $where_net),
		    	1, new Gtk2::HBox(0,10),
		    	0, gtkset_sensitive(my $host_name_entry = new Gtk2::Entry(), $where_net),
		    ),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	 			0, gtkset_sensitive(new Gtk2::Label(N("Directory (or module) to put the backup on this host.")), $where_net),
		     	1, new Gtk2::HBox(0,10),
		     	0, gtkset_sensitive(my $host_path_entry = new Gtk2::Entry(), $where_net), 
		    ),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
		    	0, gtkset_sensitive(new Gtk2::Label(N("Login name")), $where_net),
				1, new Gtk2::HBox(0,10),
				0, gtkset_sensitive(my $login_user_entry = new Gtk2::Entry(), $where_net),
			),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Password")),  $where_net),
				1, new Gtk2::HBox(0,10),
				0, gtkset_sensitive(my $check_remember_pass = new Gtk2::CheckButton(N("Remember this password")), $where_net),
				1, new Gtk2::HBox(0,10),
				0, gtkset_sensitive(my $passwd_user_entry = new Gtk2::Entry(), $where_net),
			),
	 	),   
	);
	$entry_net_type->set_popdown_strings(@net_methods);
	$entry_net_type->entry->set_text($net_proto);
	$button_xfer_keys->signal_connect('clicked', sub { 
		if ($passwd_user && $login_user && $host_name) {
			do_expect("sendkey");
		} else {
			$in->ask_warn('', N("Need hostname, username and password!"));
		}
	}); 	
    $passwd_user_entry->set_visibility(0);
    $passwd_user_entry->set_text($passwd_user);
    $passwd_user_entry->signal_connect('changed', sub { $passwd_user = $passwd_user_entry->get_text });
    $host_path_entry->set_text($host_path);
    $host_name_entry->set_text($host_name);
    $login_user_entry->set_text($login_user);
    $host_name_entry->signal_connect('changed', sub { $host_name = $host_name_entry->get_text });
    $host_path_entry->signal_connect('changed', sub { $host_path = $host_path_entry->get_text });
    $login_user_entry->signal_connect('changed', sub { $login_user = $login_user_entry->get_text });
    $entry_net_type->entry->signal_connect('changed', sub { 
		$net_proto = $entry_net_type->entry->get_text;
		my $sensitive = 0;
		$sensitive = 1 if $net_proto eq 'ssh';
		$check_use_expect->set_sensitive($sensitive);
		$check_xfer_keys->set_sensitive($sensitive);
		$button_xfer_keys->set_sensitive($sensitive);
		$check_user_keys->set_sensitive($sensitive);
	});
    check_list([$check_remember_pass, \$remember_pass]);
    gtksignal_connect(gtkset_active($check_where_use_net, $where_net), toggled => sub { 
		invbool \$where_net;
 		#- assure other methods disabled
		if ($where_net == 1) {
			$where_cd = 0;
			$where_tape = 0;
		}
		$net_proto = '' if $where_net == 0; 
		destroy_widget();
 		$current_widget->();
    });
	gtksignal_connect(gtkset_active($check_use_expect, $use_expect), toggled => sub { 
		invbool \$use_expect;
 		#- assure other methods disabled
		if ($use_expect == 1) {
			$xfer_keys = 0;
			$user_keys = 0;
		}
		destroy_widget();
 		$current_widget->();
    });
	gtksignal_connect(gtkset_active($check_xfer_keys, $xfer_keys), toggled => sub { 
		invbool \$xfer_keys;
		#- assure other methods disabled
		if ($xfer_keys == 1) {
			$use_expect = 0;
			$user_keys = 0;
		}
		destroy_widget();
 		$current_widget->();
    });
	gtksignal_connect(gtkset_active($check_user_keys, $user_keys), toggled => sub { 
		invbool \$user_keys;
 		#- assure other methods disabled
		if ($user_keys == 1) {
			$xfer_keys = 0;
			$use_expect = 0;
		}
		destroy_widget();
 		$current_widget->();
    });
	set_help_tip($check_use_expect, 'use_expect');
	set_help_tip($check_remember_pass, 'remember_pass');
	set_help_tip($host_path_entry, 'dir_or_module');
    if ($previous_function) { 
		fonction_env(\$box_where_net, \&advanced_where_net_types, \&$previous_function);
    } else { 
		fonction_env(\$box_where_net, \&advanced_where_net_types, \&advanced_where);
	}
    $up_box->show_all;
}

sub advanced_where_cd {
    my ($previous_function) = @_;
    my $box_where_cd;
	
	get_cd_info();
	
	my $combo_where_cd_device = new Gtk2::OptionMenu();
	if (keys %cd_devices) {
    	$combo_where_cd_device->set_popdown_strings(sort keys %cd_devices);
	} else {
		$combo_where_cd_device->set_popdown_strings(@no_devices);
	}  
	
    my $combo_where_cd_time = new Gtk2::OptionMenu();
    $combo_where_cd_time->set_popdown_strings("650 MB", "700 MB", "750 MB", "800 MB");    
 
	my $combo_where_cdrecord_device = new Gtk2::Combo();
	my @dev_codes;
	
	foreach my $key (keys %cd_devices) {
		push(@dev_codes, $cd_devices{$key}{rec_dev}); 
	}
	
    $combo_where_cdrecord_device->set_popdown_strings(@dev_codes) if keys %cd_devices;  	 

    gtkpack($advanced_box,
		$box_where_cd = gtkpack_(new Gtk2::VBox(0, 6),
			0, my $check_where_cd = new Gtk2::CheckButton(N("Use CD-R/DVD-R to backup")),
			0, new Gtk2::HSeparator,
			0, gtkpack_(new Gtk2::HBox(0,10),
			0, gtkset_sensitive(new Gtk2::Label(N("Choose your CD/DVD device")), $where_cd),
				1, new Gtk2::VBox(0, 5),
				0, gtkset_sensitive($combo_where_cd_device, $where_cd),
			),
			0, gtkpack_(new Gtk2::HBox(0,10),
			0, gtkset_sensitive(new Gtk2::Label(N("Choose your CD/DVD media size (MB)")), $where_cd),
				1, new Gtk2::VBox(0, 5),
				0, gtkset_sensitive($combo_where_cd_time, $where_cd),
			),
			0, new Gtk2::VBox(0, 5),
			0, gtkpack_(new Gtk2::HBox(0,10),
				1, new Gtk2::VBox(0, 5),
				0, gtkset_sensitive(new Gtk2::Label(N("Multisession CD")), $where_cd),
				0, gtkset_sensitive(my $check_multisession = new Gtk2::CheckButton(), $where_cd),
				0, gtkset_sensitive(new Gtk2::Label(N("CDRW media")), $where_cd),
				0, gtkset_sensitive(my $check_cdrw = new Gtk2::CheckButton(), $where_cd),
			),
			0, new Gtk2::VBox(0, 5),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	 			0, gtkset_sensitive(new Gtk2::Label(N("Erase your RW media (1st Session)")), $cdrw && $where_cd),
				0, gtkset_sensitive(my $button_erase_now = Gtk2::Button->new(N(" Erase Now ")), $cdrw),			
	    		1, new Gtk2::VBox(0, 5),
	    		0, gtkset_sensitive(my $check_cdrw_erase = new Gtk2::CheckButton(), $cdrw && $where_cd),
			),
			0, new Gtk2::VBox(0, 5),
			0, gtkpack_(new Gtk2::HBox(0,10),
				1, new Gtk2::VBox(0, 5),
				0, gtkset_sensitive(new Gtk2::Label(N("DVD-R device")), $where_cd),
				0, gtkset_sensitive(my $check_dvdr = new Gtk2::CheckButton(), $where_cd),
				0, gtkset_sensitive(new Gtk2::Label(N("DVDRAM device")), $where_cd),
				0, gtkset_sensitive(my $check_dvdram = new Gtk2::CheckButton(), $where_cd),
			),
# don't know what this is about - hold off for now (SB)
#			0, new Gtk2::VBox(0, 5),
#			0, gtkpack_(new Gtk2::HBox(0,10),
#				0, gtkset_sensitive(new Gtk2::Label(N("Please check if you want to include\n install boot on your CD.")),  $where_cd),
#				1, new Gtk2::VBox(0, 5),
#				0, gtkset_sensitive(my $check_cd_with_install_boot = new Gtk2::CheckButton(), $where_cd),
#			),
			0, new Gtk2::VBox(0, 5),
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Enter your CD Writer device name\n ex: 0,1,0")),  $where_cd),
				1, new Gtk2::VBox(0, 5),
#				0, gtkset_size_request(gtkset_sensitive($cd_device_entry = new Gtk2::Entry(), $where_cd), 200, 20),
				0, gtkset_sensitive(gtkset_size_request($combo_where_cdrecord_device, 200, 20), $where_cd),
			),
		),
	);

#    foreach ([$check_cdrw_erase, \$media_erase], [$check_cd_with_install_boot, \$cd_with_install_boot ]) {
    foreach ([$check_cdrw_erase, \$media_erase], [$check_dvdr, \$dvdr], [$check_dvdram, \$dvdram], [$check_multisession, \$multi_session]) {
		my $ref = $_->[1];
		gtksignal_connect(gtkset_active($_->[0], $$ref), toggled => sub { $$ref = $$ref ? 0 : 1 })
	}
    gtksignal_connect(gtkset_active($check_where_cd, $where_cd), toggled => sub { 
		$where_cd = $where_cd ? 0 : 1;
		#- toggle where_net, where_tape off
		if ($where_cd == 1) {
			$where_net = 0;
			$where_tape = 0;
		}
		destroy_widget();
		$current_widget->();
    });
    gtksignal_connect(gtkset_active($check_cdrw, $cdrw), toggled => sub { 
		$cdrw = $cdrw ? 0 : 1;
		$check_cdrw_erase->set_sensitive($cdrw);
		destroy_widget();
		$current_widget->();
    });
	$button_erase_now->signal_connect('clicked', sub { 
		if ($cd_device) {
			erase_cdrw();
		} else {
			$in->ask_warn('', N("No CD device defined!"));
		}
	}); 	
    $combo_where_cdrecord_device->entry->set_text($cd_device);
    $combo_where_cdrecord_device->entry->signal_connect('changed', sub { $cd_device = $combo_where_cdrecord_device->entry->get_text });
    
	$combo_where_cd_time->entry->set_text($cd_time);
    $combo_where_cd_time->entry->signal_connect('changed', sub { $cd_time = $combo_where_cd_time->entry->get_text });

	#- this one drives changes in the other entries
	#- still not getting quite the desired behavior, but combo box signals seem to be limited
	#- tried to trigger from the selection, but it either does nothing or crashes!
	
#-	$combo_where_cd_device->entry->set_text($std_device);
	$combo_where_cd_device->entry->signal_connect('activate', sub {
		$std_device = $combo_where_cd_device->entry->get_text;
		$combo_where_cdrecord_device->entry->set_text($cd_devices{$std_device}{rec_dev});
		$check_dvdr->set_active($cd_devices{$std_device}{dvdr});
		$check_dvdram->set_active($cd_devices{$std_device}{dvdram});
		#- do this one last or the widget destory mucks up the others
		$check_cdrw->set_active($cd_devices{$std_device}{cdrw});			
	});
	
	set_help_tip($button_erase_now, 'erase_cdrw');
	set_help_tip($combo_where_cdrecord_device, 'cdrecord_device');
	
    if ($previous_function) { 
		fonction_env(\$box_where_cd, \&advanced_where_cd, \&$previous_function); 
	} else { 
		fonction_env(\$box_where_cd, \&advanced_where_cd, \&advanced_where); 
	}
    $up_box->show_all;
}

sub advanced_where_tape {
    my ($previous_function) = @_;

	#- look for tape devices;
	get_tape_info();

	my $combo_where_tape_device = new Gtk2::OptionMenu();
    if (@tape_devices) {  
		$combo_where_tape_device->set_popdown_strings(@tape_devices) 
	} else {
		$combo_where_tape_device->set_popdown_strings(@no_devices);
	}
	
    my $box_where_tape;
    local $_;
	
    gtkpack($advanced_box,
		$box_where_tape = gtkpack_(new Gtk2::VBox(0, 6),
			0, new Gtk2::HSeparator,
		 	0, my $check_where_tape = new Gtk2::CheckButton(N("Use tape to backup")),
		 	0, new Gtk2::HSeparator,
		 	0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Device name to use for backup")), $where_tape),
				1, new Gtk2::VBox(0, 6),
				#0, gtkset_sensitive(gtkset_size_request($combo_where_tape_device, 200, 20), $where_tape),
				0, gtkset_sensitive($combo_where_tape_device, $where_tape),

			),
			0, new Gtk2::VBox(0, 5),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	    		0, gtkset_sensitive(new Gtk2::Label(N("Don't rewind tape after backup")), $where_tape),
	    		1, new Gtk2::VBox(0, 5),
	    		0, gtkset_sensitive(my $check_tape_rewind = new Gtk2::CheckButton(), $where_tape),
			),
			0, new Gtk2::VBox(0, 5),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	    		0, gtkset_sensitive(new Gtk2::Label(N("Erase tape before backup")), $where_tape),
	    		1, new Gtk2::VBox(0, 5),
	    		0, gtkset_sensitive(my $check_tape_erase = new Gtk2::CheckButton(), $where_tape),
			),
			0, new Gtk2::VBox(0, 5),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	    		0, gtkset_sensitive(new Gtk2::Label(N("Eject tape after the backup")), $where_tape),
	    		1, new Gtk2::VBox(0, 5),
	    		0, gtkset_sensitive(my $check_tape_eject = new Gtk2::CheckButton(), $where_tape),
			),
			0, new Gtk2::VBox(0, 6),
# not appropriate - disable
#			0, gtkpack_(new Gtk2::HBox(0,10),
#				0, gtkset_sensitive(new Gtk2::Label(N("Please enter the maximum size\n allowed for Drakbackup (MB)")), $where_tape),
#				1, new Gtk2::VBox(0, 6),
#				0, gtkset_size_request(gtkset_sensitive($spinner = new Gtk2::SpinButton($adj, 0, 0), $where_tape), 200, 20),
#			),
			0, gtkpack_(new Gtk2::HBox(0,10),),
		),
	);
    gtksignal_connect(gtkset_active($check_where_tape, $where_tape), toggled => sub { 
		$where_tape = $where_tape ? 0 : 1;
		#- assure other methods are off
		if ($where_tape == 1) {
			$where_net = 0;
			$where_cd = 0;
		}
		destroy_widget();
		$current_widget->();
    });
	gtksignal_connect(gtkset_active($check_tape_rewind, $tape_norewind), toggled => sub { 
		$tape_norewind = $tape_norewind ? 0 : 1;
		$_ = $tape_device;
		if ($tape_norewind) {
			$tape_device =~ s|/st|/nst|;
		} else {
			$tape_device =~ s|/nst|/st|;
		}
		$combo_where_tape_device->entry->set_text($tape_device);
		destroy_widget();
		$current_widget->();

    });
	gtksignal_connect(gtkset_active($check_tape_erase, $media_erase), toggled => sub { 
		$media_erase = $media_erase ? 0 : 1;
		destroy_widget();
		$current_widget->();
    });
	gtksignal_connect(gtkset_active($check_tape_eject, $media_eject), toggled => sub { 
		$media_eject = $media_eject ? 0 : 1;
		destroy_widget();
		$current_widget->();
    });
    $combo_where_tape_device->entry->set_text($tape_device);
	$combo_where_tape_device->entry->signal_connect('changed', sub {
		$tape_device = $combo_where_tape_device->entry->get_text;
	}); 
    if ($previous_function) { 
		fonction_env(\$box_where_tape, \&advanced_where_tape, \&$previous_function); 
	} else { 
		fonction_env(\$box_where_tape, \&advanced_where_tape, \&advanced_where); 
	}
    $up_box->show_all;
}

sub advanced_where_hd {
    my ($previous_function) = @_;
    my $box_where_hd;
    my $button;
	if ($max_space == 1000.0) {
		$max_space = int(0.8 * get_free_space($save_path)) if -d $save_path;
    }
	my $adj = new Gtk2::Adjustment($max_space, 0.0, $max_space, 10.0, 5.0, 0.0);
    my $spinner;
	
    gtkpack($advanced_box,
	    $box_where_hd = gtkpack_(new Gtk2::VBox(0, 6),
			0, new Gtk2::HSeparator,
#	 0, my $check_where_hd = new Gtk2::CheckButton( N("Use Hard Disk to backup")),
#	 0, new Gtk2::HSeparator,
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Enter the directory to save to:")), $where_hd),
				1, new Gtk2::VBox(0, 6),
				0, gtkset_size_request(gtkset_sensitive($save_path_entry = new Gtk2::Entry(), $where_hd), 152, 20),
				0, gtkset_sensitive($button = gtksignal_connect(Gtk2::Button->new,  clicked => sub {
					filedialog_where_hd() 
				}), $where_hd),
			),
			0, new Gtk2::VBox(0, 6),
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Maximum size\n allowed for Drakbackup (MB)")),  $where_hd),
				1, new Gtk2::VBox(0, 6),
				0, gtkset_size_request(gtkset_sensitive($spinner = new Gtk2::SpinButton($adj, 0, 0), $where_hd), 200, 20),
			),
# just disable for now - doesn't do anything anyway (sb)
#			0, gtkpack_(new Gtk2::HBox(0,10),
#				1, new Gtk2::VBox(0, 6),
#	   			0, gtkset_sensitive(my $check_where_hd_quota = new Gtk2::CheckButton(N("Use quota for backup files.")), $where_hd),
#		    	0, new Gtk2::VBox(0, 6),
#			),
		),
	);
#    foreach ([$check_where_hd_quota, \$hd_quota]) {
#		my $ref = $_->[1];
#		gtksignal_connect(gtkset_active($_->[0], $$ref), toggled => sub { $$ref = $$ref ? 0 : 1 })
#	}
    $button->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-dossier-32")));
    $save_path_entry->set_text($save_path);
	$spinner->signal_connect('changed', sub { $max_space = $spinner->get_text });
    $save_path_entry->signal_connect('changed', 
		sub { 
			$save_path = $save_path_entry->get_text;
			if (-d $save_path) { 
				$max_space = int(0.8 * get_free_space($save_path));
				# seems to be the easiest way to avoid the widgets fighting over values
				# and getting grabage in $max_value
				destroy_widget();
				if ($previous_function) {
					advanced_where_hd(\&$previous_function);
				} else {
					advanced_where_hd();
				}
			}
		});
    if ($previous_function) { 
		fonction_env(\$box_where_hd, \&advanced_where_hd, \&$previous_function); 
	} else { 
		fonction_env(\$box_where_hd, \&advanced_where_hd, \&advanced_where); 
	}
    $up_box->show_all;
}

sub advanced_where() {
    my $box_where;

    gtkpack($advanced_box,
	    $box_where = gtkpack_(new Gtk2::HBox(0, 15),
				  1, new Gtk2::VBox(0, 5),
				  1, gtkpack_(new Gtk2::VBox(0, 15),	
					  1, new Gtk2::VBox(0, 5),
					  1, gtksignal_connect(my $button_where_net = Gtk2::Button->new, clicked => sub { 
					      destroy_widget();
					      advanced_where_net_types(); 
					  }),
					  1, gtksignal_connect(my $button_where_cd = Gtk2::Button->new,  clicked => sub { 
					      destroy_widget(); 
					      if (require_rpm("mkisofs", "cdrecord")) { 
					      	advanced_where_cd();
					      } else { 
						  	destroy_widget();
						  	install_rpm(\&advanced_where);
						  }
					  }),
					  1, gtksignal_connect(my $button_where_hd = Gtk2::Button->new,  clicked => sub { 
					      destroy_widget(); 
					      advanced_where_hd();
					  }),
					  1, gtksignal_connect(my $button_where_tape = Gtk2::Button->new,  clicked => sub { 
					      destroy_widget(); 
						  advanced_where_tape() }),
					  1, new Gtk2::VBox(0, 5),
					     ),
				  1, new Gtk2::VBox(0, 5),	
				  ),
	    );
    $button_where_net->add(gtkpack(new Gtk2::HBox(0,10),
		gtkcreate_img("ic82-network-40"),
		new Gtk2::Label(N("Network")),
		new Gtk2::HBox(0, 5)
	));
    $button_where_cd->add(gtkpack(new Gtk2::HBox(0,10),
		gtkcreate_img("ic82-CD-40"),
		new Gtk2::Label(N("CD-R / DVD-R")),
		new Gtk2::HBox(0, 5)
	));
    $button_where_hd->add(gtkpack(new Gtk2::HBox(0,10),
		gtkcreate_img("ic82-discdurwhat-40"),
		new Gtk2::Label(N("HardDrive / NFS")),
		new Gtk2::HBox(0, 5)
	));
    $button_where_tape->add(gtkpack(new Gtk2::HBox(0,10),
 		gtkcreate_img("ic82-tape-40"),
 		new Gtk2::Label(N("Tape")),
 		new Gtk2::HBox(0, 5)
 	));
    fonction_env(\$box_where, \&advanced_where, \&advanced_box); 
    $up_box->show_all;
}

sub advanced_when() {
    my $box_when;
	my $allow_custom = $backup_daemon && $custom_cron; 
    my $combo_when_space = new Gtk2::OptionMenu();
    my %trans = (N("hourly") => 'hourly',
		 N("daily") => 'daily',
		 N("weekly") => 'weekly',
		 N("monthly") => 'monthly',
		 N("custom") => 'custom');
    my %trans2 = ('hourly' => N("hourly"),
		  'daily' => N("daily"),
		  'weekly' => N("weekly"),
		  'monthly' => N("monthly"),
		  'custom' => N("custom"));
    $combo_when_space->set_popdown_strings("", N("hourly"), N("daily"), N("weekly"), N("monthly"), N("custom"));    
	set_help_tip($combo_when_space, 'when_space');

	#- custom setup - let user specify month, day of month, day of week, hour, minute
	my $combo_month_when = new Gtk2::OptionMenu();
	my @months = ("*", N("January"), N("February"), N("March"),
		N("April"), N("May"), N("June"), N("July"), N("August"), N("September"),
		N("October"), N("November"), N("December"));
	$combo_month_when->set_popdown_strings(@months);
	my $combo_day_when = new Gtk2::OptionMenu();
	$combo_day_when->set_popdown_strings("*", (1..31));
	my $combo_weekday_when = new Gtk2::OptionMenu();
	my @weekdays = ("*", N("Sunday"), N("Monday"), N("Tuesday"), 
		N("Wednesday"), N("Thursday"), N("Friday"), N("Saturday")); 
	$combo_weekday_when->set_popdown_strings(@weekdays);
	my $combo_hour_when = new Gtk2::OptionMenu();
	$combo_hour_when->set_popdown_strings("*", (0..23));
	my $combo_minute_when = new Gtk2::OptionMenu();
	$combo_minute_when->set_popdown_strings("*", (0..59));
	
	my $entry_crontab = new Gtk2::Entry();
	gtkset_editable($entry_crontab, 0);

	my @time_list = split(" ", $time_string);
	$combo_minute_when->entry->set_text($time_list[0]);
	$combo_hour_when->entry->set_text($time_list[1]);
	$combo_day_when->entry->set_text($time_list[2]);
	if ($time_list[3] =~ /\*/) {
		$combo_month_when->entry->set_text($time_list[3]);
	} else {
		$combo_month_when->entry->set_text($months[$time_list[3]]);
	}
	if ($time_list[4] =~ /\*/) {
		$combo_weekday_when->entry->set_text($time_list[4]);
	} else {
		$combo_weekday_when->entry->set_text($weekdays[$time_list[4] + 1]);
	}
#	my $button_apply = new Gtk2::Button(N("Apply"));
	
	#- drop down list of possible media - default to config value
    my $entry_media_type = new Gtk2::OptionMenu();
    $entry_media_type->set_popdown_strings("", @media_types, @net_methods);
	$entry_media_type->entry->set_text($daemon_media);
	
    gtkpack($advanced_box,
		$box_when = gtkpack_(new Gtk2::VBox(0, 10),
			0, gtkpack_(new Gtk2::HBox(0,10),
				1, new Gtk2::HBox(0,10),
				1, gtkcreate_img("ic82-when-40"),
				0, my $check_when_daemon  = new Gtk2::CheckButton(N("Use daemon")), 
				1, new Gtk2::HBox(0,10),
			),
			0, new Gtk2::HSeparator,
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Please choose the time interval between each backup")),  $backup_daemon),
				1, new Gtk2::HBox(0,10),
				0, gtkset_sensitive($combo_when_space, $backup_daemon),
			),
			0, new Gtk2::HSeparator,
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Custom setup/crontab entry:")), $allow_custom),
				1, gtkset_sensitive($entry_crontab, $allow_custom),
			),
			0, gtkpack_(new Gtk2::HBox(0,10),
				1, gtkpack_(new Gtk2::VBox(0,10),
					0, gtkset_sensitive(new Gtk2::Label(N("Minute")), $allow_custom),
					0, gtkset_sensitive($combo_minute_when, $allow_custom),
				),
				1, gtkpack_(new Gtk2::VBox(0,10),
					0, gtkset_sensitive(new Gtk2::Label(N("Hour")), $allow_custom),
					0, gtkset_sensitive($combo_hour_when, $allow_custom),
				),
				1, gtkpack_(new Gtk2::VBox(0,10),
					0, gtkset_sensitive(new Gtk2::Label(N("Day")), $allow_custom),
					0, gtkset_sensitive($combo_day_when, $allow_custom),
				),
				1, gtkpack_(new Gtk2::VBox(0,10),
					0, gtkset_sensitive(new Gtk2::Label(N("Month")), $allow_custom),			
					0, gtkset_sensitive($combo_month_when, $allow_custom),
				),
				1, gtkpack_(new Gtk2::VBox(0,10),
					0, gtkset_sensitive(new Gtk2::Label(N("Weekday")), $allow_custom),
					0, gtkset_sensitive($combo_weekday_when, $allow_custom),
				),
#				1,gtkpack_(new Gtk2::VBox(0,10),
#					0, new Gtk2::HBox(0,10),
#					0, gtkset_sensitive($button_apply, $allow_custom),	
#				),
			),
			0, new Gtk2::HSeparator,
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Please choose the media for backup.")), $backup_daemon),
				1, new Gtk2::HBox(0,10),
				0, gtkpack_(new Gtk2::VBox(0,10),
					0, gtkset_sensitive($entry_media_type, $backup_daemon),
				),
			),
			0, new Gtk2::HSeparator,
			0, gtkset_sensitive(new Gtk2::Label(N("Please be sure that the cron daemon is included in your services.")), $backup_daemon), 
			0, gtkset_sensitive(new Gtk2::Label(N("Note that currently all 'net' media also use the hard drive.")),  $backup_daemon),
		),
	);

    gtksignal_connect(gtkset_active($check_when_daemon, $backup_daemon), toggled => sub { 
		$backup_daemon = $backup_daemon ? 0 : 1;
		destroy_widget();
		advanced_when();
    });
    $combo_when_space->entry->set_text($trans2{$when_space});
    $combo_when_space->entry->signal_connect('changed', sub { 
		$when_space = $trans{$combo_when_space->entry->get_text}; 
		$custom_cron = $when_space eq "custom" ? 1 : 0;
		destroy_widget();
		advanced_when();		
	});
	if ($custom_cron) {
		$entry_crontab->set_text("$time_string $exec_string")
	}
	
	$combo_minute_when->entry->signal_connect('changed', sub { combo_to_cron_string($combo_minute_when->get_history - 1, 0) });
	$combo_hour_when->entry->signal_connect('changed', sub { combo_to_cron_string($combo_hour_when->get_history - 1, 1) });
	$combo_day_when->entry->signal_connect('changed', sub {	combo_to_cron_string($combo_day_when->get_history, 2) });	
	$combo_month_when->entry->signal_connect('changed', sub { combo_to_cron_string($combo_month_when->get_history, 3) });
	$combo_weekday_when->entry->signal_connect('changed', sub {	combo_to_cron_string($combo_weekday_when->get_history - 1, 4) });
	
	$entry_media_type->entry->signal_connect('changed', sub { $daemon_media = $entry_media_type->entry->get_text });
    fonction_env(\$box_when, \&advanced_when, \&advanced_box);
    $up_box->show_all;
}

sub combo_to_cron_string {
	my ($field, $location) = @_;
	$field = "*" if $field == 0 && $location > 1 && $location < 4;
	$field = "*" if $field == -1 && ($location < 2 || $location == 4);
	my @time_list = split(" ", $time_string);
	splice(@time_list, $location, 1, $field);
	$time_string = join(" ", @time_list);
	destroy_widget();
	advanced_when();				
}

sub advanced_options() {
    my $box_options;
    
	gtkpack($advanced_box,
		$box_options = gtkpack_(new Gtk2::VBox(0, 15),
# 				 0, gtkpack_(new Gtk2::HBox(0,10),
# 					     1, new Gtk2::VBox(0,10),
# 					     1, gtkcreate_img("ic82-moreoption-40"),
# 					     1, N("Please choose correct options to backup."),
# 					     1, new Gtk2::VBox(0,10),
# 					     ),
# 				 0, new Gtk2::HSeparator,
# 				 0, gtkpack_(new Gtk2::VBox(0,10),
# 					     0, gtkset_sensitive(my $check_tar_bz2  = new Gtk2::CheckButton( N("Use Tar and bzip2 (very slow) [Please be careful if you\n (un)select this option, as all your old backups will be deleted.]")), 0),
 			0, my $check_backupignore = new Gtk2::CheckButton(N("Use .backupignore files")),
#			0, new Gtk2::VBox(0,10),
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, my $check_mail = new Gtk2::CheckButton(N("Send mail report after each backup to:")),
				1, new Gtk2::HBox(0,10),
				0, my $mail_entry = new Gtk2::Entry(),
			),
#					     ),
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, my $check_del_hd_files = new Gtk2::CheckButton(N("Delete Hard Drive tar files after backup to other media.")),
			),
		),
	);
    check_list([$check_mail, \$send_mail], [$check_del_hd_files, \$del_hd_files], [$check_backupignore, \$backupignore]);
#    check_list([$check_mail, \$send_mail], [$check_tar_bz2, \$comp_mode], [$check_backupignore, \$backupignore]);
    $mail_entry->set_text($user_mail);
    $mail_entry->signal_connect('changed', sub { $user_mail = $mail_entry->get_text });
	set_help_tip($check_backupignore, 'backupignore');
	set_help_tip($check_mail, 'send_mail_to');
	set_help_tip($check_del_hd_files, 'delete_files');
    fonction_env(\$box_options, \&advanced_options, \&advanced_box);
    $up_box->show_all;
}

sub advanced_box() {
    my $box_adv;

    gtkpack($advanced_box,
		$box_adv = gtkpack_(new Gtk2::HBox(0, 15),
			1, new Gtk2::VBox(0, 5),	
			1, gtkpack_(new Gtk2::VBox(0, 15),	
				1, new Gtk2::VBox(0, 5),	
				1, gtksignal_connect(my $button_what = Gtk2::Button->new, clicked => sub { 
				    destroy_widget(); advanced_what() }),
				1, gtksignal_connect(my $button_where = Gtk2::Button->new, clicked => sub { 
				    destroy_widget();  advanced_where() }),
				1, gtksignal_connect(my $button_when = Gtk2::Button->new, clicked => sub { 
				    destroy_widget();  advanced_when() }),
				1, gtksignal_connect(my $button_options = Gtk2::Button->new, clicked => sub {
					destroy_widget(); advanced_options() }),
				1, new Gtk2::VBox(0, 5),	
			),
			1, new Gtk2::VBox(0, 5),	
		),
	);
    $button_what->add(gtkpack(new Gtk2::HBox(0,10),
		gtkcreate_img("ic82-discdurwhat-40"),
		new Gtk2::Label(N("What")),
		new Gtk2::HBox(0, 5)
	));
    $button_where->add(gtkpack(new Gtk2::HBox(0,10),
	    gtkcreate_img("ic82-where-40"),
	    new Gtk2::Label(N("Where")),
	    new Gtk2::HBox(0, 5)
	));
    $button_when->add(gtkpack(new Gtk2::HBox(0,10),
	    gtkcreate_img("ic82-when-40"),
	    new Gtk2::Label(N("When")),
	    new Gtk2::HBox(0, 5)
	));
    $button_options->add(gtkpack(new Gtk2::HBox(0,10),
	    gtkcreate_img("ic82-moreoption-40"),
	    new Gtk2::Label(N("More Options")),
	    new Gtk2::HBox(0, 5)
	));
    fonction_env(\$box_adv, \&advanced_box, \&interactive_mode_box);
    $up_box->show_all;
}

################################################  WIZARD  ################################################  

sub wizard_step3() {
    my $box2;    
    my $text = new Gtk2::TextView;
	save_conf_file();
    read_conf_file();
    system_state();
    gtktext_insert($text, [ [ $system_state ] ]);
    button_box_restore_main();

    gtkpack($advanced_box,
		$box2 =  gtkpack_(new Gtk2::HBox(0, 15),	
			1, gtkpack_(new Gtk2::VBox(0,10),
				0, N("Drakbackup Configuration"),
				1, create_scrolled_window($text),
			),
		),
	);
    fonction_env(\$box2, \&wizard_step3, \&wizard_step2);
    button_box_wizard_end();
    $up_box->show_all;
}

sub wizard_step2() {
    my $box2;    	
    gtkpack($advanced_box,
		$box2 =  gtkpack_(new Gtk2::HBox(0, 15),	
			1, new Gtk2::VBox(0, 5),	
			1, gtkpack_(new Gtk2::VBox(0, 15),	
				1, new Gtk2::VBox(0, 5),
				0, N("Please choose where you want to backup"),
				0, gtkpack_(new Gtk2::HBox(0, 15),	      
					0, my $check_wizard_hd = new Gtk2::CheckButton(N("On Hard Drive")),
					1, new Gtk2::VBox(0, 5),
					0, gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("Configure")), clicked => sub {
						destroy_widget();
						to_ok();
						advanced_where_hd(\&wizard_step2);
						to_normal();
					}), $where_hd),
				),
				0, gtkpack_(new Gtk2::HBox(0, 15),
					0, my $check_wizard_net = new Gtk2::CheckButton(N("Across Network")),
					1, new Gtk2::VBox(0, 5),
					0, gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("Configure")), clicked => sub {
						destroy_widget();
						to_ok();
						advanced_where_net_types(\&wizard_step2);
						to_normal();
					}), $where_net),
				),
 				0, gtkpack_(new Gtk2::HBox(0, 15),	      
 					0, my $check_wizard_cd = new Gtk2::CheckButton(N("On CD-R")),
 					1, new Gtk2::VBox(0, 5),	
 					0, gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("Configure")), clicked => sub {
 						destroy_widget();
						to_ok();
 						advanced_where_cd(\&wizard_step2);
						to_normal();
 					}), $where_cd),
 				),
 				0, gtkpack_(new Gtk2::HBox(0, 15),	      
 					0, my $check_wizard_tape = new Gtk2::CheckButton(N("On Tape Device")),
 					1, new Gtk2::VBox(0, 5),
 					0, gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("Configure")), clicked => sub {
 						destroy_widget();
						to_ok();
 						advanced_where_tape(\&wizard_step2);
						to_normal();
 					}), $where_tape),
 				),
				1, new Gtk2::VBox(0, 5),
			),
			1, new Gtk2::VBox(0, 5),
		),
	);
	gtksignal_connect(gtkset_active($check_wizard_cd, $where_cd), toggled => sub {
		invbool \$where_cd; 
		if ($where_cd) { $where_tape = 0; $where_net = 0 };
		refresh_wizard_step2();
	});
	gtksignal_connect(gtkset_active($check_wizard_net, $where_net), toggled => sub {
		invbool \$where_net;
		if ($where_net) { $where_tape = 0; $where_cd = 0 };
		refresh_wizard_step2();
	});
	gtksignal_connect(gtkset_active($check_wizard_tape, $where_tape), toggled => sub {
		invbool \$where_tape;
		if ($where_tape) { $where_cd = 0; $where_net = 0 };
		refresh_wizard_step2();
	});
	gtksignal_connect(gtkset_active($check_wizard_hd, $where_hd), toggled => sub {
		refresh_wizard_step2();
	});
	if (!$where_hd && !$where_cd && !$where_net) { fonction_env(\$box2, \&wizard_step2, \&wizard, \&message_noselect_box) }
    else { fonction_env(\$box2, \&wizard_step2, \&wizard, \&wizard_step3) }
    button_box_wizard();
    $up_box->show_all;
}

sub refresh_wizard_step2() {
	$where_hd = 1;
	if (!$where_hd && !$where_cd && !$where_net) {  
		$next_widget = \&message_noselect_box
	} else { 
		$next_widget = \&wizard_step3 
	}
	destroy_widget();
	wizard_step2();
}

sub wizard()   {
	my $box2;    
    my $user_string = N("Backup Users");
	$user_string .= N(" (Default is all users)") if !$nonroot_user;
	if ($backup_user) {
		@user_list = @user_list_all;
	} else {
		@user_list = ();
	}

	gtkpack($advanced_box,
		$box2 =  gtkpack_(new Gtk2::HBox(0, 15),	
			1, new Gtk2::VBox(0, 5),	
			1, gtkpack_(new Gtk2::VBox(0, 15),	
				1, new Gtk2::VBox(0, 5),
				0, N("Please choose what you want to backup"),
				0, my $check_wizard_sys = new Gtk2::CheckButton(N("Backup System")),
				0, my $check_wizard_user = new Gtk2::CheckButton($user_string),
				0, gtksignal_connect(Gtk2::Button->new(N("Select user manually")), clicked => sub {
					destroy_widget();
					advanced_what_user(\&wizard);
				}),
				1, new Gtk2::VBox(0, 5),	
			),
			1, new Gtk2::VBox(0, 5),	
		),
	);
    foreach ([$check_wizard_sys, \$backup_sys], [$check_wizard_user, \$backup_user]) {
		my $ref = $_->[1];
		gtksignal_connect(gtkset_active($_->[0], $$ref), toggled => sub { 
			$$ref = $$ref ? 0 : 1;
			if ($backup_sys || $backup_user && @user_list) { 
				$next_widget = \&wizard_step2; 
			} else { 
				$next_widget = \&message_noselect_what_box; 
			}
			if ($backup_user) {
				@user_list = @user_list_all;
			} else {
				@user_list = ();
			}
		})
	}
    if ($backup_sys || $backup_user && @user_list) { fonction_env(\$box2, \&wizard, \&interactive_mode_box, \&wizard_step2) } 
    else { fonction_env(\$box2, \&wizard, \&interactive_mode_box, \&message_noselect_what_box) } 
    button_box_wizard();
    $up_box->show_all;
}

################################################  RESTORE  ################################################  

sub find_backup_to_restore() {
    my @list_backup;
    my @list_backup_tmp2;
    my $to_put;
    @sys_backuped = ();
	local $_;
	
    @user_backuped = ();
    -d $path_to_find_restore and @list_backup_tmp2 = all($path_to_find_restore);
    	
	foreach (@list_backup_tmp2) {
		s/_base//gi;
		s/_incr//gi;
		push @list_backup , $_;
    }
    if (any { /^backup_other/ } @list_backup) { $other_backuped = 1 }
    if (any { /^backup_sys/ } @list_backup) { $sys_backuped = 1 }
    foreach (grep { /^backup_sys_/ } @list_backup) {
		chomp;
		s/^backup_sys_//gi;
		s/.tar.gz$//gi;
		s/.tar.bz2$//gi;
 		my ($date, $heure) = /^(.*)_([^_]*)$/; 
		my $year = substr($date, 0, 4);
		my $month = substr($date, 4,  2);
		my $day =  substr($date, 6, 2);
		my $hour = substr($heure, 0,  2);
		my $min =  substr($heure, 2, 2);
		$to_put = "$day/$month/$year $hour:$min                   $_";
 		push @sys_backuped , $to_put;
    }
    $restore_step_sys_date  = $to_put;
    foreach (grep { /^backup_user_/ } @list_backup) {
		chomp;
		s/^backup_user_//gi;
		s/.tar.gz$//gi;
		s/.tar.bz2$//gi;
		my ($nom, $date, $heure) = /^(.*)_([^_]*)_([^_]*)$/;
		my $year = substr($date, 0, 4);
		my $month = substr($date, 4,  2);
		my $day =  substr($date, 6, 2);
		my $hour = substr($heure, 0,  2);
		my $min =  substr($heure, 2, 2);
#	my $to_put = "  $nom,  (date: $date, hour: $heure)";
		$to_put = "$_       user: $nom,   date: $day/$month/$year,   hour: $hour:$min";
		push @user_backuped , $to_put;
		any { /^$nom$/ } @user_list_backuped or push @user_list_backuped, $nom;
    }
}

sub system_state() {
#    $system_state;

    if ($cfg_file_exist) { 
		$system_state = N("\nBackup Sources: \n");
        $backup_sys and $system_state .= N("\n- System Files:\n"); 
        $backup_sys and $system_state .= "\t\t$_\n" foreach @sys_files; 
        $backup_user and $system_state .= N("\n- User Files:\n");
        $backup_user and $system_state .= "\t\t$_\n" foreach @user_list;
        @list_other and $system_state .= N("\n- Other Files:\n"); 
        @list_other and $system_state .= "\t\t$_\n" foreach @list_other;
        $where_hd and $system_state .= N("\n- Save on Hard drive on path: %s\n", $save_path);
		$where_hd and $system_state .= N("\tLimit disk usage to %s MB\n", $max_space);

		if ($del_hd_files && ($where_cd || $where_tape || $where_net) && $daemon_media ne 'hd')  {
			$system_state .= N("\n- Delete hard drive tar files after backup.\n");	
		}
		
		#- tape and CDRW share some features
		my $erase_media = N("NO");
		$erase_media = N("YES") if $media_erase && ($where_cd || $where_tape); 
		$where_cd and $system_state .= N("\n- Burn to CD");
		$where_cd and $cdrw and $system_state .= N("RW");
		$where_cd and $system_state .= N(" on device: %s", $cd_device);
		$where_cd and $multi_session and $system_state .= N(" (multi-session)");
		$where_tape and $system_state .= N("\n- Save to Tape on device: %s", $tape_device);
		(($where_cd || $where_tape) && $media_erase) and $system_state .= N("\t\tErase=%s", $erase_media);
		$where_cd || $where_tape and $system_state .= "\n";
		
		$where_net and $system_state .= N("\n- Save via %s on host: %s\n", $net_proto, $host_name);
		$where_net and $system_state .= N("\t\t user name: %s\n\t\t on path: %s \n", $login_user, $host_path);
		$system_state .= N("\n- Options:\n");
		$backup_sys or $system_state .= N("\tDo not include System Files\n");
		
		if ($comp_mode) { 
			$system_state .= N("\tBackups use tar and bzip2\n"); 
		} else { 
			$system_state .= N("\tBackups use tar and gzip\n");
		}   

		$system_state .= N("\tUse .backupignore files\n") if $backupignore;
		$system_state .= N("\tSend mail to %s\n", $user_mail) if $user_mail;
		
		$daemon_media and $system_state .= N("\n- Daemon, %s via:\n", $when_space);
		$daemon_media eq 'hd' and $system_state .= N("\t-Hard drive.\n");    
		$daemon_media eq 'cd' and $system_state .= N("\t-CD-R.\n");
		$daemon_media eq 'tape' and $system_state .= N("\t-Tape \n");    
		$daemon_media eq 'ftp' and $system_state .= N("\t-Network by FTP.\n");    
		$daemon_media eq 'ssh' and $system_state .= N("\t-Network by SSH.\n");    
		$daemon_media eq 'rsync' and $system_state .= N("\t-Network by rsync.\n");    
		$daemon_media eq 'webdav' and $system_state .= N("\t-Network by webdav.\n");    
    } else {
    	$system_state = N("No configuration, please click Wizard or Advanced.\n");
    }
}

sub restore_state() {
    my @tmp = split(' ', $restore_step_sys_date);
    $restore_state = N("List of data to restore:\n\n");
    if ($restore_sys) { $restore_state .= "- Restore System Files.\n";
			$restore_state .= "   - from date: $tmp[0] $tmp[1]\n";
	}
    if ($restore_user) { 
		$restore_state .= "- Restore User Files: \n";
		$restore_state .= "\t\t$_\n" foreach @user_list_to_restore2;
		push @user_list_to_restore, (split(',', $_))[0] foreach @user_list_to_restore2;
    }
    if ($restore_other) { 
		$restore_state .= "- Restore Other Files: \n";
		-f "$path_to_find_restore/list_other" and $restore_state .= "\t\t$_\n" foreach split("\n", cat_("$path_to_find_restore/list_other"));  
    }
    if ($restore_other_path) {
		$restore_state .= "- Path to Restore: $restore_path \n";
    }
}

sub select_most_recent_selected_of {
    my ($user_name) = @_;
    my @list_tmp2;
	local $_;
    my @tmp = sort @user_list_to_restore2;
    foreach (grep { /$user_name/ } sort @tmp) { push @list_tmp2 , $_ }
    return pop @list_tmp2;
}

sub select_user_data_to_restore() {
    my $var_eq = 1;
    my @list_backup;
    my @list_tmp;
    my @list_tmp2;
    @user_list_to_restore = ();
	local $_;

    -d $path_to_find_restore and my @list_backup_tmp2 = grep { /^backup/ } all($path_to_find_restore);
    @list_tmp2 = @list_backup_tmp2;
    foreach (@list_backup_tmp2) {
		s/_base//gi;
		s/_incr//gi;
		push @list_backup , $_;
    }
    foreach my $var_tmp (@user_list_backuped) {
		$var_eq = 1;
		my $more_recent = (split(' ', select_most_recent_selected_of($var_tmp)))[0]; 
		foreach (grep { /^backup_user_$var_tmp/ } sort @list_backup) {
	    	s/.tar.gz//gi;
	    	s/.tar.bz2//gi;
	    	if ($more_recent) {
				if (/$more_recent/) {
		    		push @list_tmp , $_;
		    		$var_eq = 0;    
				} else {
					#- only if user asked for it - previously this was restoring everything (SB)
					my $tmp_name = $_;
					s/backup_user_//gi;
					foreach my $buff (@user_list_to_restore2) {
						if (index($buff, $_) >= 0) { 
							$var_eq and push @list_tmp , $tmp_name;
						}
					}
				}
	    	}
		}
    }
	foreach my $var_to_restore (@list_tmp) {
		$var_to_restore =~ s/backup_//gi;
		foreach my $var_exist (sort @list_tmp2) {
	    	if ($var_exist =~ /$var_to_restore/) {
				push @user_list_to_restore, $var_exist;
	    	}
		}
    }
    $DEBUG and print "real user list to restore:  $_ \n" foreach @user_list_to_restore;
}

sub select_sys_data_to_restore() {
    my $var_eq = 1;
    my @list_tmp;
	local $_;
	
    -d $path_to_find_restore and @list_tmp = grep { /^backup/ } all($path_to_find_restore);
    my @more_recent = split(' ', $restore_step_sys_date); 
    my $more_recent = pop @more_recent;
    foreach my $var_exist (grep { /_sys_/ } sort @list_tmp) {
		if ($var_exist =~ /$more_recent/) {
	    	push @sys_list_to_restore, $var_exist;
	    	$var_eq = 0; 
	    } else {  
	    	$var_eq and push @sys_list_to_restore, $var_exist; 
	    }
    }
    $DEBUG and print "sys list to restore: $_\n " foreach @sys_list_to_restore;
}

sub show_backup_details {
	my ($function, $mode, $name) = @_;
	my $archive_file_detail;
	my $value;
# dies in gtk2
#	my $fixed_font = Gtk2::Gdk::Font->load("-misc-fixed-medium-r-*-*-*-100-*-*-*-*-*-*");
	my $command2;
	my $tarfile;
	
	# FIXME - only tar.gz at the moment	
	my $extension = ".tar.gz";
		    
	if ($mode eq "user") {
		#- we've only got a partial filename in this case
		$tarfile = "$path_to_find_restore/backup_*" . $name . $extension;
	}
	if ($mode eq "sys") {
		#- funky string here we need to use to reconstruct the filename
		my @flist = split(/[ \t,]+/, $name);
		$tarfile = "$path_to_find_restore/backup_*" .  $flist[2] . $extension;
	}
	my $command1 = "stat " . $tarfile;
	$command2 = "tar -tzvf " . $tarfile;
	
     local *TMP;
	open TMP, "$command1 2>&1 |";
	while ($value = <TMP>) {
		$archive_file_detail .= $value;			
	}
	close TMP;
	$archive_file_detail .= "\n\n";
	open TMP, "$command2 2>&1 |";
	while ($value = <TMP>) {
		#- drop the permissions display for the sake of readability	
		$archive_file_detail .= substr($value, 11);
	}
	close TMP;	

    my $text = new Gtk2::TextView;
    my $advanced_box_archive;
    gtktext_insert(gtkset_editable($text, 0), $archive_file_detail);
    gtkpack($advanced_box,
	    $advanced_box_archive = gtkpack_(new Gtk2::VBox(0,10),
			1, gtkpack_(new Gtk2::HBox(0,0),
				1, create_scrolled_window($text), 
			),
			0, gtkadd(gtkset_layout(new Gtk2::HButtonBox, 'spread'),
				gtksignal_connect(Gtk2::Button->new(N("Done")), clicked => sub { 
					destroy_widget(); 
					$function->() }),
			),
		)
	);
    $central_widget = \$advanced_box_archive;
    $up_box->show_all;
}

sub valid_backup_test {
    my (@files_list) = @_;
    @files_corrupted = ();
    my $is_corrupted = 0;
    foreach (@files_list) {
		#- let's quiet this down (SB)
		if (system("gzip -l $path_to_find_restore/$_ > /dev/null 2>&1") > 1) {
	    	push @files_corrupted, $_;
	    	$is_corrupted = -1;
		}
    }
    return $is_corrupted;
}

sub restore_aff_backup_problems() {
    my $do_restore;
    my $text = new Gtk2::TextView;
    my $restore_pbs_state = N("List of data corrupted:\n\n");
    $restore_pbs_state .= "\t\t$_\n" foreach @files_corrupted;
    $restore_pbs_state .= N("Please uncheck or remove it on next time.");
    gtktext_insert($text, [ [ $restore_pbs_state ] ]);
    button_box_restore_main();    

    gtkpack($advanced_box,
	    $do_restore = gtkpack_(new Gtk2::VBox(0,10),
			0, new Gtk2::VBox(0,10),
			1, gtkpack_(new Gtk2::HBox(0, 15),	
				1, new Gtk2::VBox(0, 5),	
				0, gtkcreate_img('warning'),
				0, N("Backup files are corrupted"),
				1, new Gtk2::VBox(0, 5),	
			),
			0, new Gtk2::VBox(0,10),
			1, create_scrolled_window($text),
		),
	);
    button_box_restore_pbs_end();
    fonction_env(\$do_restore, \&restore_aff_backup_problems, "restore_pbs");
    $up_box->show_all;
}

sub restore_aff_result() {
    my $do_restore;
    my $text = new Gtk2::TextView;
    gtktext_insert($text, [ [ $restore_state ] ]);
    button_box_restore_main();
    
    gtkpack($advanced_box,
		$do_restore = gtkpack_(new Gtk2::VBox(0,10),
			1, new Gtk2::VBox(0,10),
			0, N("          All of your selected data have been          "),
			0, N("          Successfuly Restored on %s       ", $restore_path),
			1, new Gtk2::VBox(0,10),
		),
	);
    button_box_build_backup_end();
    $central_widget = \$do_restore;
    $up_box->show_all;

}

sub return_path {
    my ($username) = @_;
    my $usr;
    my $home_dir;
    my $passwdfile = "/etc/passwd";
	local *PASSWD;
    open(PASSWD, $passwdfile) or exit 1; 
    while (defined(my $line = <PASSWD>)) {
		chomp($line);
		($usr, $home_dir) = (split(/:/, $line))[0,5];
		last if $usr eq $username; 
    }
    close(PASSWD);
    return $home_dir;
}

sub restore_backend() {
    my $untar_cmd;
    my $exist_problem = 0;
    my $user_dir;
	my $tnom;
	my $username;
	my $theure2;
	local $_;
	-d $restore_path or mkdir_p $restore_path;
	
    if (any { /tar.gz$/ } all($path_to_find_restore)) { 
    	$untar_cmd = 0; 
    } else { 
    	$untar_cmd = 1; 
    }
    
	if ($restore_user)  {
		select_user_data_to_restore();
	    if (valid_backup_test(@user_list_to_restore) == -1) {
			$exist_problem = 1;
			restore_aff_backup_problems();
	    } else { 
	    	foreach (@user_list_to_restore) {
		    	if ($backup_user_versions) {
					($tnom, $username, $theure2) = /^(\w+_\w+_user_)(.*)_(\d+_\d+.*)$/;
				} else {
					($tnom, $username, $theure2) = /^(\w+_user_)(.*)_(\d+_\d+.*)$/;
				}

				$user_dir = return_path($username);
				-d $user_dir and rm_rf($user_dir) if $remove_user_before_restore;

		    	$DEBUG and print "user name to restore: $username, user directory: $user_dir\n";		    
		    	$untar_cmd or system(" tar xfz  $path_to_find_restore/$_ -C $restore_path");
		    	$untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/$_ | tar xf -C $restore_path ");
			}
			#- flush this out for another cycle (SB)
			@user_list_to_restore2 = ();
	    }
		
    }
    
	if ($restore_sys)   { 
		if ($backup_sys_versions) {
			select_sys_data_to_restore();
	    	if (valid_backup_test(@sys_list_to_restore) == -1) {
				$exist_problem = 1;
				restore_aff_backup_problems();
	    	} else {
				$untar_cmd or system("tar xfz $path_to_find_restore/$_  -C $restore_path ") foreach @sys_list_to_restore;
				$untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/$_  | tar xf -C $restore_path ") foreach @sys_list_to_restore;
			}
		} else {
			$untar_cmd or system("tar xfz $path_to_find_restore/backup_sys.tar.gz  -C $restore_path ");
			$untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/backup_sys.tar.bz2  | tar xf -C $restore_path ");
		}	    
    }
    if ($restore_other) { 
		$untar_cmd or system("tar xfz $path_to_find_restore/backup_other.tar.gz  -C $restore_path ");
		$untar_cmd and system("/usr/bin/bzip2 -cd $path_to_find_restore/backup_other.tar.bz2  | tar xf -C $restore_path ");
    }
    $exist_problem or restore_aff_result();
}

sub restore_do() {
    if ($backup_bef_restore) {
		if ($restore_sys) { 
			$backup_sys = 1;
		} else { 
			$backup_sys = 0;
		}
		if ($restore_user) { 
	    	$backup_user = 1;
	    	@user_list = @user_list_to_restore;
		} else { 
			$backup_user = 0;
		}
		build_backup_status();
		read_conf_file();
		build_backup_files();
		$table->destroy;
    }
    restore_do2();
}

sub restore_do2() {
    my $do_restore;
    my $text = new Gtk2::TextView;
    restore_state();
    gtktext_insert($text, [ [ $restore_state ] ]);
    button_box_restore_main();
    
	gtkpack($advanced_box,
		$do_restore = gtkpack_(new Gtk2::VBox(0,10),
			0, N("         Restore Configuration       "),
			1, create_scrolled_window($text),
		),
	);
    button_box_restore_end();
    fonction_env(\$do_restore, \&restore_do2, \&restore_box);
    $up_box->show_all;
}

sub restore_step_other() {
    my $retore_step_other;
    my $text = new Gtk2::TextView;
    my $other_rest = cat_("$path_to_find_restore/list_other");
    gtktext_insert($text, [ [ $other_rest ] ]); 
    gtkpack($advanced_box,
		$retore_step_other = gtkpack_(new Gtk2::VBox(0,10),
			1, new Gtk2::VBox(0,10),
			1, create_scrolled_window($text),
			0, my $check_restore_other_sure = new Gtk2::CheckButton(N("OK to restore the other files.")),
			1, new Gtk2::VBox(0,10),
		),
	);
    check_list([$check_restore_other_sure, \$restore_other]);
    fonction_env(\$retore_step_other, \&restore_step_other, \&restore_step2, \&restore_do);
    $up_box->show_all;
}

my %check_user_to_restore;
sub restore_step_user() {
    my $retore_step_user;
    my @tmp_list = sort @user_backuped;
    @user_backuped = @tmp_list;
    gtkpack($advanced_box,
		$retore_step_user = gtkpack_(new Gtk2::VBox(0,10),
			0, new Gtk2::VBox(0,10),
			0, N("User list to restore (only the most recent date per user is important)"),
			1, create_scrolled_window(gtkpack__(new Gtk2::VBox(0,0),
				map { my $name;
					my $var2;
					my $name_complet = $_;
					$name = (split(' ', $name_complet))[0];
					my @user_list_tmp;
					my $restore_row = new Gtk2::HBox(0,5);
					my $b = new Gtk2::CheckButton($name_complet);
					my $details = Gtk2::Button->new(" Details ");
					
					$restore_row->pack_start($b, 1, 1, 0);
					$restore_row->pack_end(new Gtk2::VBox(1,5), 0, 0, 0);
					$restore_row->pack_end($details, 0, 0, 0);
					
# this doesn't work - I don't understand why - but you end up with
# everything selected when you hit the screen a second time, after selecting one				
#					if (grep $name_complet, @user_list_to_restore2)  {
#						gtkset_active($b, 1);
#						$check_user_to_restore{$name_complet}[1] = 1;
#					} else {
#						gtkset_active($b, 0);
#						$check_user_to_restore{$name_complet}[1] = 0;
#					}

# this doesn't work right either - returning to the screen only 1 is selected
# yet several are scheduled to be restored
					foreach (@user_list_to_restore2) {
						if ($name_complet eq $_) {
							gtkset_active($b, 1);
							$check_user_to_restore{$name_complet}[1] = 1;
						} else {
							gtkset_active($b, 0);
							$check_user_to_restore{$name_complet}[1] = 0;
						}
					}
					$b->signal_connect(toggled => sub { 
						if (!$check_user_to_restore{$name_complet}[1]) {
							$check_user_to_restore{$name_complet}[1] = 1;
							if (!any { /$name/ } @user_list_to_restore2) {
								push @user_list_to_restore2, $name_complet 
							}
						} else {
							$check_user_to_restore{$name_complet}[1] = 0;
							foreach (@user_list_to_restore2) {
								$var2 =  (split(' ', $_))[0];
								if ($name ne $var2) {
									push @user_list_tmp, $_;
								}
							}
							@user_list_to_restore2 = @user_list_tmp;
						}
					});
					$details->signal_connect('clicked', sub { 
						#- we're only passing a portion of the filename to
						#- the subroutine so we need to let it know this
						destroy_widget();
						show_backup_details(\&restore_step_user, "user", $name);
					}); 	
					$restore_row } (@user_backuped) 
				),
			),
		),
	);
    if ($restore_other) { fonction_env(\$retore_step_user, \&restore_step_user, "", \&restore_step_other) }
	elsif ($restore_sys) { fonction_env(\$retore_step_user, \&restore_step_user, \&restore_step_sys, \&restore_step_other) }
    else { fonction_env(\$retore_step_user, \&restore_step_user, \&restore_step2, \&restore_do) }
    $up_box->show_all;
}

sub restore_step_sys() {
    my $restore_step_sys;
	my $check_backup_before;
    my $combo_restore_step_sys = new Gtk2::OptionMenu();
    $combo_restore_step_sys->set_popdown_strings(@sys_backuped);
    gtkpack($advanced_box,
		$restore_step_sys = gtkpack_(new Gtk2::VBox(0,10),
			1, new Gtk2::VBox(0,10),
			0, $check_backup_before = new Gtk2::CheckButton(N("Backup the system files before:")),
			0, gtkpack_(new Gtk2::HBox(0,10),
				1, N("please choose the date to restore"),
				0, $combo_restore_step_sys,
				0, my $details = Gtk2::Button->new(" Details "),
				0, new Gtk2::HBox(0,10),
			),
			1, new Gtk2::VBox(0,10),
			
		),
	);
    $combo_restore_step_sys->entry->signal_connect('changed', sub {
		$restore_step_sys_date = $combo_restore_step_sys->entry->get_text;
	});
	$details->signal_connect('clicked', sub { 
		#- we're only passing a portion of the filename to
		#- the subroutine so we need to let it know this
		my $backup_date = $combo_restore_step_sys->entry->get_text;
		destroy_widget();
		show_backup_details(\&restore_step_sys, "sys", $backup_date);
	}); 	
    $combo_restore_step_sys->entry->set_text($restore_step_sys_date);
    fonction_env(\$restore_step_sys, \&restore_step_sys,  \&restore_step2, "restore");
    if ($restore_user) { fonction_env(\$restore_step_sys, \&restore_step_sys,  \&restore_step2, \&restore_step_user) }
    elsif ($restore_other) { fonction_env(\$restore_step_sys, \&restore_step_sys,  \&restore_step2, \&restore_step_other) }
    else { fonction_env(\$restore_step_sys, \&restore_step_sys,  \&restore_step2, \&restore_do) }
    $up_box->show_all;
}

sub restore_other_media_hd {
    my ($previous_function) = @_;
    my $box_where_hd;
    my $button;
    my $adj = new Gtk2::Adjustment(550.0, 10.0, 10000.0, 10.0, 5.0, 0.0);
    my $spinner;
	 
    gtkpack($advanced_box,
	    $box_where_hd = gtkpack_(new Gtk2::VBox(0, 6),
			0, new Gtk2::HSeparator,
			0, my $check_where_hd = new Gtk2::CheckButton(N("Use Hard Disk to backup")),
			0, new Gtk2::HSeparator,
			0, gtkpack_(new Gtk2::HBox(0,10),
		    	0, gtkset_sensitive(new Gtk2::Label(N("Enter the directory to save:")), $where_hd),
		    	1, new Gtk2::VBox(0, 6),
		    	0, gtkset_size_request(gtkset_sensitive($save_path_entry = new Gtk2::Entry(), $where_hd), 152, 20),
		    	0, gtkset_sensitive($button = gtksignal_connect(Gtk2::Button->new,  clicked => sub {
				filedialog_where_hd() }), $where_hd),
			),
	 		0, new Gtk2::VBox(0, 6),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	    		0, gtkset_sensitive(new Gtk2::Label(N("Enter the maximum size\n allowed for Drakbackup (MB)")),  $where_hd),
	    		1, new Gtk2::VBox(0, 6),
	    		0, gtkset_size_request(gtkset_sensitive($spinner = new Gtk2::SpinButton($adj, 0, 0), $where_hd), 200, 20),
			),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
	    		1, new Gtk2::VBox(0, 6),
	    		0, gtkset_sensitive(my $check_where_hd_quota = new Gtk2::CheckButton(N("Use quota for backup files.")), $where_hd),
	    		0, new Gtk2::VBox(0, 6),
			),
	 	),
	);
    check_list([$check_where_hd_quota, \$hd_quota]);
    gtksignal_connect(gtkset_active($check_where_hd, $where_hd), toggled => sub { 
		$where_hd = $where_hd ? 0 : 1;
		destroy_widget();
		$current_widget->();
    });
    $button->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-dossier-32")));
    $save_path_entry->set_text($save_path);
    $save_path_entry->signal_connect('changed', sub { $save_path = $save_path_entry->get_text });
    if ($previous_function) { fonction_env(\$box_where_hd, \&advanced_where_hd, \&$previous_function) }
    else { fonction_env(\$box_where_hd, \&advanced_where_hd, \&advanced_where) }
    $up_box->show_all;
}

sub restore_other_media() {
    my $box_find_restore;
    my $button;
    
    gtkpack($advanced_box,
		$box_find_restore = gtkpack_(new Gtk2::VBox(0, 6),
			0, new Gtk2::HSeparator,
			0, my $check_other_media_hd = new Gtk2::CheckButton(N("Restore from Hard Disk.")),
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, gtkset_sensitive(new Gtk2::Label(N("Enter the directory where backups are stored")), $other_media_hd),
				1, new Gtk2::VBox(0, 6),
				0, gtkset_size_request(gtkset_sensitive($restore_find_path_entry = new Gtk2::Entry(), $other_media_hd), 152, 20),
				0, gtkset_sensitive($button = gtksignal_connect(Gtk2::Button->new,  clicked => sub {
				     filedialog_restore_find_path(); 
				}), $other_media_hd),
			),
			1, new Gtk2::VBox(0, 6),
#					 0, new Gtk2::HSeparator,
# 					 0, my $check_other_media_net = new Gtk2::CheckButton( N("Restore from Network")),
# 					 0, new Gtk2::VBox(0, 6),
# 					 1, gtkpack(new Gtk2::HBox(0,10),
# 						    new Gtk2::VBox(0, 6),
# 						    gtkset_sensitive(gtksignal_connect(Gtk2::Button->new("Network"),  clicked => sub {
# 							destroy_widget();
# 							restore_find_net(\&restore_other_media);}), !$other_media_hd),
# 						    new Gtk2::VBox(0, 6),
# 						    ),
# 					 1, new Gtk2::VBox(0, 6),
# 					 0, new Gtk2::HSeparator,
			0, new Gtk2::VBox(0, 6),
		),
	);
	gtksignal_connect(gtkset_active($check_other_media_hd, $other_media_hd), toggled => sub { 
		$other_media_hd = $other_media_hd ? 0 : 1;
		destroy_widget();
		$current_widget->();
    });
#     gtksignal_connect(gtkset_active($check_other_media_net, !$other_media_hd), toggled => sub { 
# 	$other_media_hd = $other_media_hd ? 0 : 1;
# 	destroy_widget();
# 	$current_widget->();
#    });
    $button->add(gtkpack(new Gtk2::HBox(0,10), gtkcreate_img("ic82-dossier-32")));
    $restore_find_path_entry->set_text($path_to_find_restore);
    $restore_find_path_entry->signal_connect('changed', sub { $path_to_find_restore = $restore_find_path_entry->get_text });
#- not sure if this was the original intent - address the crash at "Next"
    fonction_env(\$box_find_restore, \&restore_other_media, \&restore_step2, \&restore_do);
    $up_box->show_all;
}

sub restore_step2() {
    my $retore_step2;
    my $other_exist;
    my $sys_exist;
    my $user_exist;
	local $_;
	
	my $restore_info_path = $save_path;
	$restore_info_path = $path_to_find_restore if $where_hd || $where_cd;
	my $info_prefix = "backup";
	$info_prefix = "list" if $where_net || $where_tape;
	
    if (-f "$restore_info_path/$info_prefix" . "_other*") { $other_exist = 1 } 
    else { $other_exist = 0; $restore_other = 0 }
    if (any  { /_sys_/ } grep { /^$info_prefix/ } all("$restore_info_path/")) { $sys_exist = 1 } 
    else { $sys_exist = 0; $restore_sys = 0 }
    if (any { /_user_/ } grep { /^$info_prefix/ } all("$restore_info_path/")) { $user_exist = 1 } 
    else { $user_exist = 0; $restore_user = 0 }

# disabling this (sb) - very nicely wipes out your backup media if the user isn't very careful
# cycling through the GUI turns it back on for you!!!
#    $backup_sys_versions || $backup_user_versions and $backup_bef_restore = 1;

    gtkpack($advanced_box,
		$retore_step2 = gtkpack_(new Gtk2::VBox(0,10),
			1, new Gtk2::VBox(0,10),
			1, new Gtk2::VBox(0,10),
			0, gtkpack_(new Gtk2::HBox(0,10),
				0, my $check_restore_other_src = new Gtk2::CheckButton(N("Select another media to restore from")),
				1, new Gtk2::HBox(0,10),
				0, gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("Other Media")), clicked => sub {
					destroy_widget();
					restore_other_media();
				}), $restore_other_src),
			),
	 		0, gtkset_sensitive(my $check_restore_sys = new Gtk2::CheckButton(N("Restore system")), $sys_exist),
	 		0, gtkset_sensitive(my $check_restore_user = new Gtk2::CheckButton(N("Restore Users")), $user_exist),
	 		0, gtkset_sensitive(my $check_restore_other = new Gtk2::CheckButton(N("Restore Other")), $other_exist),
	 		0, gtkpack_(new Gtk2::HBox(0,10),
		     	0, my $check_restore_other_path = new Gtk2::CheckButton(N("select path to restore (instead of /)")),
		     	1, new Gtk2::HBox(0,10),
		    	0, gtkset_sensitive(my $restore_path_entry = new Gtk2::Entry(), $restore_other_path),
			),
	 		0, gtkset_sensitive(my $check_backup_bef_restore = new Gtk2::CheckButton(N("Do new backup before restore (only for incremental backups.)")), 
				$backup_sys_versions || $backup_user_versions),
	 		0, gtkset_sensitive(my $check_remove_user_dir = new Gtk2::CheckButton(N("Remove user directories before restore.")), $user_exist),
	 		1, new Gtk2::VBox(0,10),
	 	),
	);
	
	foreach  ([$check_restore_sys, \$restore_sys], 
	      [$check_backup_bef_restore, \$backup_bef_restore],
	      [$check_restore_user, \$restore_user],
	      [$check_remove_user_dir, \$remove_user_before_restore],
	      [$check_restore_other, \$restore_other]) {
			my $ref = $_->[1];
			gtksignal_connect(gtkset_active($_->[0], $$ref), toggled => sub { 
	    		$$ref = $$ref ? 0 : 1;
	    		if (!$restore_sys && !$restore_user && !$restore_other) { $next_widget = \&message_norestore_box }
	    		elsif ($restore_sys && $backup_sys_versions) { $next_widget = \&restore_step_sys }
	    		elsif ($restore_user) { $next_widget = \&restore_step_user }
	    		elsif ($restore_other) { $next_widget = \&restore_step_other }
	    		else { $next_widget = \&restore_do }
			})
	}
    gtksignal_connect(gtkset_active($check_restore_other_path, $restore_other_path), toggled => sub {
		$restore_other_path = $restore_other_path ? 0 : 1;
		destroy_widget();
		$current_widget->();
    });
    gtksignal_connect(gtkset_active($check_restore_other_src, $restore_other_src), toggled => sub {
		$restore_other_src = $restore_other_src ? 0 : 1;
		destroy_widget();
		$current_widget->();
    });
	$central_widget = \$retore_step2;
    fonction_env(\$retore_step2, \&restore_step2, \&restore_box);
    if (!$restore_sys && !$restore_user && !$restore_other) { $next_widget = \&message_norestore_box }
    elsif ($restore_sys && $backup_sys_versions) { $next_widget = \&restore_step_sys }
    elsif ($restore_user) { $next_widget = \&restore_step_user }
    elsif ($restore_other) { $next_widget = \&restore_step_other }
    else { $next_widget = \&restore_do }
    $restore_path_entry->set_text($restore_path); 
    $restore_path_entry->signal_connect('changed', sub { $restore_path = $restore_path_entry->get_text });
    $up_box->show_all;
}

sub find_files_to_restore() {
	local $_;
	my $file_restore;
	my $start_restore;
	my @possible_sources;
	my $file_to_restore;
	my $cat_entry;
	my @catalog = cat_("$cfg_dir/drakbackup_catalog");
	
	#- file info in tree view
	my $model = Gtk2::TreeStore->new("Glib::String");
    my $file_list = Gtk2::TreeView->new_with_model($model);
	$file_list->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0));
	$file_list->set_headers_visible(0);
	$file_list->get_selection->set_mode('single');

	my $file_wildcard_entry = new Gtk2::Entry();
	
    gtkpack($advanced_box,
		$file_restore = gtkpack_(new Gtk2::VBox(0,10),
		    0, new Gtk2::Label(N("Filename text to search for:")),
			0, gtkpack_(new Gtk2::HBox(0,10),
				1, $file_wildcard_entry,
				0, gtksignal_connect(new Gtk2::Button(N("Search Backups")), clicked => sub {
					my $wildcard = $file_wildcard_entry->get_text;
					@possible_sources = glob "$save_path/list*";
					foreach my $list (@possible_sources) {
						my @listing = cat_($list);
						my @matches = grep { /$wildcard/ } @listing;
						if (@matches) {
							my $list_entry = $model->append_set(undef, [ 0 => $list ]);
							foreach (@matches) {
								chop;
								$model->append_set($list_entry, [ 0 => $_ ]);
							}
						}
					}
				}),
			),
			1, create_scrolled_window($file_list),
			0, gtkset_sensitive(gtksignal_connect($start_restore = new Gtk2::Button(N("Restore Selected")), clicked => sub {
				my $media_check = restore_catalog_entry($cat_entry, $file_to_restore);
				if (! $media_check) {
					destroy_widget();
					find_files_to_restore();
				} 
			}), 0),
		),
	);

	$file_list->get_selection->signal_connect(changed => sub {
		my ($lmodel, $iter) = $_[0]->get_selected;
		$lmodel && $iter or return;
 		my $s = $lmodel->get($iter, 0);
		if (! any { /$s/ } @possible_sources) {
			$file_to_restore = $s;
			my $parent_iter = Gtk2::TreeModel::iter_parent($lmodel, $iter);
			my $parent_name = $lmodel->get($parent_iter, 0);
			$cat_entry = substr($parent_name, -19, 15);
			my @full_cat_entry = grep { /^$cat_entry/ } @catalog;
			$cat_entry = $full_cat_entry[0];
			gtkset_sensitive($start_restore, 1);			
		} else {
			gtkset_sensitive($start_restore, 0);
		}
	});

	$central_widget = \$file_restore;
}

sub catalog_restore() {
	my $catalog_box;
	my $cat_entry;
	my @restore_files;
	my $restore_path_entry;
		
	#- catalog info in tree view
	my $model = Gtk2::TreeStore->new("Glib::String");
	my $tree_catalog = Gtk2::TreeView->new_with_model($model);
	$tree_catalog->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0));
    
	$tree_catalog->set_headers_visible(0);
	$tree_catalog->get_selection->set_mode('single');
	
	# file details in list widget	
	my $lmodel = Gtk2::ListStore->new("Glib::String");
    my $tree_files = Gtk2::TreeView->new_with_model($lmodel);
    $tree_files->append_column(Gtk2::TreeViewColumn->new_with_attributes(undef, Gtk2::CellRendererText->new, 'text' => 0));
    
	$tree_files->set_headers_visible(0);
    $tree_files->get_selection->set_mode('multiple');

	#- read the catalog
	my @catalog = cat_("$cfg_dir/drakbackup_catalog");
	
	foreach (@catalog) {
		chop;
		my @line_data = split(':', $_);
		my $t = $line_data[0];
		
		my $t_catalog = $model->append_set(undef, [ 0 => $t ]);
		
		my $indexer = 0;
		foreach (@line_data) {
			if ($indexer != 0) {
				my $m;
				$m = "Media: " if $indexer == 1;
				$m = "Label or Host: " if $indexer == 2;
				$m = "Device or Path: " if $indexer == 3;
				$m = "Type: Incremental" if $_ eq "I";
				$m = "Type: Differential" if $_ eq "D";
				$m = "Type: Full" if $_ eq "F";
				$m .= $_ if $_ ne "I" && $_ ne "F" && $_ ne "D";
				$model->append_set($t_catalog, [ 0 => $m ]);
			}
			$indexer++;
		}
	}	

	$tree_catalog->get_selection->signal_connect(changed => sub {			
		my ($model, $iter) = $_[0]->get_selected;
        $model && $iter or return;
		$cat_entry = $model->get($iter, 0);
		my $parent_iter = Gtk2::TreeModel::iter_parent($model, $iter);
		if ($parent_iter) {
			$cat_entry = '';
			return;
		}
		cursor_wait();
		@restore_files = ();
		$lmodel->clear;
		foreach my $filename (glob("$save_path/list*$cat_entry.txt")) {
			my @contents = cat_($filename);
			foreach (@contents) {
				chop;
				my $s = $_;
				$lmodel->append_set(undef, $s);
			}
		}
		cursor_norm();
		my @full_cat_entry = grep { /^$cat_entry/ } @catalog;
		$cat_entry = $full_cat_entry[0];
	});

	$tree_files->get_selection->signal_connect(changed => sub {
		my (@what) = $_[0]->get_selected_rows;
		@restore_files = ();
		foreach (@what) {
			my $iter = $lmodel->get_iter($_);
    		my $s = $lmodel->get($iter, 0);
			push @restore_files, $s;
		}
	});
		
	gtkpack($advanced_box,
		$catalog_box = gtkpack_(new Gtk2::HBox(0,10),
			0, new Gtk2::VBox(0,10),
			1, gtkpack_(new Gtk2::VBox(0,5),
				1, gtkpack_(new Gtk2::VBox(0, 10),
					1, create_scrolled_window($tree_catalog),
					1, create_scrolled_window($tree_files),
				),
				0, gtkpack_(new Gtk2::HBox(1, 10),
					1, gtksignal_connect(Gtk2::Button->new(N("Restore Selected\nCatalog Entry")), clicked => sub { 
						if ($cat_entry) {
							my $media_check = restore_catalog_entry($cat_entry, ());
							if (! $media_check) {
								destroy_widget();
								interactive_mode_box();
							} 
						} 
					}),
					1, gtksignal_connect(Gtk2::Button->new(N("Restore Selected\nFiles")), clicked => sub { 							
						my $files = @restore_files;
						#- grab the array before the widget clears it 
						my @passed_files = @restore_files;
						if ($cat_entry && $files) {
							my $media_check = restore_catalog_entry($cat_entry, @passed_files);
							if (! $media_check) {
								destroy_widget();
								interactive_mode_box();
							} 
						}
					}),
					1, gtkpack_(new Gtk2::VBox(0, 5),
						0, new Gtk2::Label("Restore To Path"),
		    			0, $restore_path_entry = new Gtk2::Entry(),
					),
					1, gtksignal_connect(Gtk2::Button->new(N("Change\nRestore Path")), clicked => sub { 							
						filedialog_generic("Path To Restore To", \$restore_path_entry, \$restore_path);
					}),						
				),
				0, new Gtk2::VBox(0,10),
			),
			0, new Gtk2::VBox(0,10),
		),
	);		
	
	$restore_path_entry->set_text($restore_path);
	gtksignal_connect($restore_path_entry, changed => sub { $restore_path = $restore_path_entry->get_text });
	
	button_box_restore();		
	fonction_env(\$catalog_box, \&catalog_restore, \&restore_find_media_box, \&catalog_restore);
	$central_widget = \$catalog_box;	
    $up_box->show_all;
}

sub restore_catalog_entry {
	#FIXME
	# we're working from a catalog entry, which means we know the
	# the tar file wildcards and some info on where the backup was stored
	# if it's a local device (HD, tape, CD) - prompt for the media
	# for tape, find how many other catalog entries had the same 
	# label and calculate the record offset
	# if it's remote storage, display what we know of the connection
	# parameters and get the user's verification, then connect
	
	restore_status();
	
	my ($cat_entry, @restore_files) = @_;
	my $username;
	my $userpass = $passwd_user;
	my $restore_result = 1;
		
	my @line_data = split(':', $cat_entry);
	my $backup_time = $line_data[0];
	
	#- use our own variables here so we don't trash a saved config accidentally
	my $media = $line_data[1];
	
	#- can be a volume name or a host name
	my $vol_host = $line_data[2];
	
	#- see if we have a username embedded in the host
	if (index($vol_host, "@")) {
		my @user_host = split("@", $vol_host);
		$username = $user_host[0];
		$vol_host = $user_host[1];
	} else {
		$username = $login_user;
	}
	
	#- create a restore work directory if we don't have one
	-d "$cfg_dir/restores" or mkdir_p "$cfg_dir/restores";

	#- can be a device name or a path
	my $dev_path = $line_data[3];
	
	if ($media eq 'HD') {
		#- shouldn't really happen, should have just browsed 
		#- to the $save_path in the previous step - deal with it anyway
		my @restore_tar_files = glob("$dev_path/*$backup_time*$tar_ext");
		my $matches = @restore_tar_files;
		if ($matches == 0) {
			show_warning("f", N("Backup files not found at %s.", $dev_path));
			return 0;
		} else {
			my $save_path_org = $save_path;
			$save_path = $dev_path;
			$restore_result = restore_hd_or_cd($cat_entry, $dev_path, @restore_files);
			$save_path = $save_path_org;
		}			
	}
	
	if ($media eq 'CD') {
		#- we know the cdrecord device, and the label
		#- prompt the user for the right CD
		$in->ask_okcancel(N("Restore From CD"), N("Insert the CD with volume label %s\n in the CD drive under mount point /mnt/cdrom", $vol_host) ,1) ? ($vol_name = get_cd_volname()) : return 0;
		if ($vol_name ne $vol_host) {
			show_warning("f", N("Not the correct CD label. Disk is labelled %s.", $vol_name));
			return 0;
		} else {
			$restore_result = restore_hd_or_cd($cat_entry, '/mnt/cdrom', @restore_files);
		}	
	}
	
	if ($media eq 'Tape') {
		#- a little more complicated, we need to check if other backups
		#- were done on this tape, and try to find the offset to this one
		$in->ask_okcancel(N("Restore From Tape"), N("Insert the tape with volume label %s\n in the tape drive device %s", $vol_host, $dev_path) ,1) ? ($vol_name = get_tape_label($dev_path)) : return 0;
		if ($vol_name ne $vol_host) {
			show_warning("f", N("Not the correct tape label. Tape is labelled %s.", $vol_name));
			return 0;
		} else {
			$restore_result = restore_tape($cat_entry, $dev_path, @restore_files);
		}			
	}
	
	if ($media eq 'ftp' || $media eq 'webdav' || $media eq 'ssh' || $media eq 'rsync') { 
		#- show the user what we know of the connection from the catalog 
		#- and the config file, let them override if necessary
		
		#- the various protocols are going to have different requirements
		#- webdav - it should already be in sitecopyrc - compare it?
		#- ssh - the only method we have enabled at the moment is with keys 
		#-	- no passwd needed
		#-  - if we use expect, it is needed
		#-  - if we use drackbackup keys, then a different ssh call is needed
		#- rsync - uses a config file with username - rsync.user
		#- ftp needs all parameters entered
		
		$in->ask_from(N("Restore Via Network"), N("Restore Via Network Protocol: %s", $media),
			      [ { label => N("Host Name"), val => \$vol_host },
				{ label => N("Host Path or Module"), val => \$dev_path },
				{ label => N("Username"), val => \$username },
				{ label => N("Password"), val => \$userpass, hidden => 1  },
				]) or goto return 0;
		
		if ($media eq 'ftp' || $media eq 'rsync') {
			if ($userpass eq '') {
				show_warning("f", N("Password required")); 
				return 0;
			}
		} 
		if ($media eq 'ftp' || $media eq 'rsync' || $media eq 'ssh') {
			if ($username eq '') {
				show_warning("f", N("Username required"));
				return 0; 
			} elsif ($vol_host eq '') {
				show_warning("f", N("Hostname required")); 
				return 0;
			}
		}
		if ($dev_path eq '') {
			show_warning("f", N("Path or Module required")); 
			return 0;
		}
			
		$restore_result = restore_ftp($cat_entry, $vol_host, $dev_path, $username, $userpass, @restore_files) if $media eq 'ftp';
		$restore_result = restore_rsync_ssh_webdav($cat_entry, $vol_host, $dev_path, $username, $media, @restore_files) 
			if $media eq 'rsync' || $media eq 'ssh' || $media eq 'webdav';
	}

	# cleanup our restore dir - unlink fails here?
	system("rm -f $cfg_dir/restores/*");

	if (!$restore_result) {
		show_warning("i", N("Files Restored..."));
		return 0;
	} else {
		show_warning("f", N("Restore Failed..."));
		return 1;
	}

}

sub restore_hd_or_cd {
	my ($cat_entry, $tarfile_dir, @restore_files) = @_;
	my $indv_files = @restore_files;
	my $command;
		
	my $wild_card = catalog_to_wildcard($cat_entry);
		
	if ($indv_files == 0) {
		#- full catalog specified
		foreach (wildcard_to_tarfile($wild_card)) {
			$command = "tar -C $restore_path -xzf $tarfile_dir/$_";
			spawn_progress($command, "Untarring from \n$_ \nto $restore_path.");
		}
	} else {
		#- individual files - pull from appropriate catalog
		foreach (@restore_files) {
			my $tarfile = file_to_tarfile($_, $wild_card);
			$_ = substr($_, 1);
			$command = "tar -C $restore_path -xzf $tarfile_dir/$tarfile $_";
			spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path.");
		}
	}
    return 0;
}

sub restore_tape {
	my ($cat_entry, $dev_path, @restore_files) = @_;
	my $indv_files = @restore_files;
	my $command;
		
	my $wild_card = catalog_to_wildcard($cat_entry);
	$dev_path =~ s|/st|/nst|;
		
	if ($indv_files == 0) {
		#- full catalog specified
		foreach (wildcard_to_tarfile($wild_card)) {
			my $offset = find_tape_offset($cat_entry);
			$command = "mt -f $dev_path rewind";
			spawn_progress($command, "Rewinding tape on $dev_path.");
			$command = "mt -f $dev_path fsf $offset";
			spawn_progress($command, "Moving forward $offset file records.");
			$command = "tar -C cfg_dir/restores -xf $dev_path";
			spawn_progress($command, "Untarring from $dev_path to work directory.");
			if (-e "$cfg_dir/restores/$_") {
				$command = "tar -C $restore_path -xzf $cfg_dir/restores/$_";
				spawn_progress($command, "Untarring \n$_ \nto $restore_path.");
			} else {
				return 1;
			}
		}
	} else {
		#- individual files - pull from appropriate catalog
		foreach (@restore_files) {
			my $tarfile = file_to_tarfile($_, $wild_card);
			$_ = substr($_, 1);
			if (!-e "$cfg_dir/restores/$tarfile") {
				my $offset = find_tape_offset($cat_entry);
				$command = "mt -f $dev_path rewind";
				spawn_progress($command, "Rewinding tape on $dev_path.");
				$command = "mt -f $dev_path fsf $offset";
				spawn_progress($command, "Moving forward $offset file records.");
				$command = "tar -C cfg_dir/restores -xf $dev_path";
				spawn_progress($command, "Untarring from $dev_path to work directory.");
			}
			if (-e "$cfg_dir/restores/$tarfile") {
				$command = "tar -C $restore_path -xzf $cfg_dir/restores/$tarfile $_";
				spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path.");
			} else {
				return 1;
			}
		}
	}
    return 0;
}

sub restore_ftp {
    use Net::FTP; 
    my $ftp;
	my ($cat_entry, $hostname, $hostpath, $username, $userpass, @restore_files) = @_;
	my $indv_files = @restore_files;
	my $command;
		
    $DEBUG and print "file list to retrieve: $cat_entry\n ";
    if ($DEBUG && $interactive) { $ftp = Net::FTP->new($hostname, Debug => 1) or return 1 }
    elsif ($interactive)  {  $ftp = Net::FTP->new($hostname, Debug => 0) or return 1 }
    else {  $ftp = Net::FTP->new($hostname, Debug => 0) or return 1 }
    $ftp->login($username, $userpass);
    $ftp->cwd($hostpath);

	my $wild_card = catalog_to_wildcard($cat_entry);
		
	if ($indv_files == 0) {
		#- full catalog specified
		foreach (wildcard_to_tarfile($wild_card)) {
			$ftp->get($_, "$cfg_dir/restores/$_");
			$command = "tar -C $restore_path -xzf $cfg_dir/restores/$_";
			spawn_progress($command, "Untarring \n$_ \nto $restore_path.");
		}
	} else {
		#- individual files - pull from appropriate catalog
		foreach (@restore_files) {
			my $tarfile = file_to_tarfile($_, $wild_card);
			$_ = substr($_, 1);
			if (!-e "$cfg_dir/restores/$tarfile") {
				$ftp->get($tarfile, "$cfg_dir/restores/$tarfile");
			}
			$command = "tar -C $restore_path -xzf $cfg_dir/restores/$tarfile $_";
			spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path.");
		}
	}
    $ftp->quit; 
    return 0;
}

sub restore_rsync_ssh_webdav {
	my ($cat_entry, $hostname, $hostpath, $username, $mode, @restore_files) = @_;
	my $indv_files = @restore_files;
	my $command;
	my $wild_card = catalog_to_wildcard($cat_entry);
	if ($indv_files == 0) {
		#- full catalog specified
		foreach (wildcard_to_tarfile($wild_card)) {
			if ($mode eq 'ssh') {
				$command = "scp $username\@$hostname:$hostpath/$_ $cfg_dir/restores/";
			} elsif ($mode eq 'rsync') {
				$command = "rsync --password-file=$cfg_dir/rsync.user $username\@$hostname" . "::" . "$hostpath/$_ $cfg_dir/restores/";
			} else {
				$command = "wget http://$hostname/$hostpath/$_ -P $cfg_dir/restores/";
			}
			spawn_progress($command, "Retrieving backup file \n$_ \nvia $mode.");
			if (-e "$cfg_dir/restores/$_") {
				$command = "tar -C $restore_path -xzf $cfg_dir/restores/$_";
				spawn_progress($command, "Untarring \n$_ \nto $restore_path.");
			} else {
				return 1;
			}
		}
	} else {
		#- individual files - pull from appropriate catalog
		foreach (@restore_files) {
			my $tarfile = file_to_tarfile($_, $wild_card);
			$_ = substr($_, 1);
			if (!-e "$cfg_dir/restores/$tarfile") {
				if ($mode eq 'ssh') {
					$command = "scp $username\@$hostname:$hostpath/$tarfile $cfg_dir/restores/";
				} elsif ($mode eq 'rsync') {
					$command = "rsync --password-file=$cfg_dir/rsync.user $username\@$hostname" . "::" . "$hostpath/$tarfile $cfg_dir/restores/";
				} else {
					$command = "wget http://$hostname/$hostpath/$tarfile -P $cfg_dir/restores/";
				}
				spawn_progress($command, "Retrieving backup file \n$tarfile \nvia $mode.");
			}
			if (-e "$cfg_dir/restores/$tarfile") {
				$command = "tar -C $restore_path -xzf $cfg_dir/restores/$tarfile $_";
				spawn_progress($command, "Untarring \n$_ from \n$tarfile \nto $restore_path.");
			} else {
				return 1;
			}
		}
	}
    return 0;
}

sub catalog_to_wildcard {
	my ($cat_entry) = @_;
	my @line_data = split(':', $cat_entry);
	my $wildcard = $line_data[0];
	$wildcard;
}

sub wildcard_to_tarfile {
	my ($wildcard) = @_;
	my (@tarfile) = glob("$save_path/*$wildcard.txt");
	foreach (@tarfile) {
		$_ = basename($_);
		s/txt/$tar_ext/;
		s/list/backup/;
	}
	@tarfile;
}

sub file_to_tarfile {
	my ($restore_file, $wildcard) = @_;
	my $tarfile = `grep -l $restore_file $save_path/*$wildcard.txt`;
	chop $tarfile;
	$tarfile = basename($tarfile);
	$tarfile =~ s/txt/$tar_ext/;
	$tarfile =~ s/list/backup/;
	$tarfile;
}

sub find_tape_offset {
	my ($cat_entry) = @_;
	my @line_data = split(':', $cat_entry);
	my $label = $line_data[2];
	my @catalog = cat_("$cfg_dir/drakbackup_catalog");
	# always off by 1 for tape label.
	my $offset = 1;
	foreach (@catalog) {
		if (index($_, $label)) {
			if (!index($_, $cat_entry)) {
				# tar seems to need 2 of these to get located
				$offset++;
				$offset++;
			} else {
				return $offset;
			}
		} 
	}	
}

sub restore_box() {
    my $retore_box;
    
	if ($good_restore_path) {
		$path_to_find_restore = $save_path if $where_hd;
		$path_to_find_restore = "/mnt/cdrom" if $where_cd;
	}
	
    find_backup_to_restore();
    button_box_restore_main();

    if ($other_backuped || $sys_backuped || @user_backuped) {
		gtkpack($advanced_box,
			$retore_box = gtkpack_(new Gtk2::HBox(0,1),
				1, new Gtk2::VBox(0,10),
				1, gtkpack_(new Gtk2::VBox(0,10),
					1, new Gtk2::VBox(0,10),
					1, new Gtk2::VBox(0,10),
					1, gtksignal_connect(Gtk2::Button->new(N("Search for files to restore")), clicked => sub { 
						$retore_box->destroy;
						button_box_file_restore();
						find_files_to_restore() 
					}),
					1, gtksignal_connect(Gtk2::Button->new(N("Restore all backups")), clicked => sub { 
						$retore_box->destroy;
						button_box_restore();
						@user_list_to_restore2 = sort @user_backuped; 
						$restore_sys = 1;
						$restore_other = 1;
						$restore_user = 1;
						restore_do() 
					}),
					1, gtksignal_connect(Gtk2::Button->new(N("Custom Restore")), clicked => sub { 
						$retore_box->destroy;
						button_box_restore(); 
						restore_step2();
					}),
					1, new Gtk2::VBox(0,10),
					1, new Gtk2::VBox(0,10),
				),
				1, new Gtk2::HBox(0,10),
			),
		);
    } else {
		destroy_widget();
		restore_find_media_box(),
	}
    fonction_env(\$retore_box, \&restore_box, \&interactive_mode_box);
    $central_widget = \$retore_box;
	$up_box->show_all;
}

sub restore_find_media_box() {
    my $mount_media = 1;
    $good_restore_path = 0;
    my $message = N("Unable to find backups to restore...\n");
    $message .= N("Verify that %s is the correct path", $path_to_find_restore) if $where_hd && $where_cd;
    $message .= N(" and the CD is in the drive") if $where_cd;
    if ($where_tape || $net_proto) {
		$message .= N("Backups on unmountable media - Use Catalog to restore");
		$mount_media = 0;
    }
    $message .= ".";
    
    gtkpack($advanced_box,
		$box2 = gtkpack_(new Gtk2::VBox(0, 5),	
			1, gtkpack(new Gtk2::HBox(0, 15),	
				new Gtk2::VBox(0, 5),	
				gtkcreate_img('warning'), 
				translate($message),
				new Gtk2::VBox(0, 5),	
			),
			1, gtkpack(new Gtk2::HBox(0, 15),
				new Gtk2::VBox(0, 5),
				gtkpack(new Gtk2::VBox(0, 10),
					gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("CD in place - continue.")), clicked => sub {  
						$good_restore_path = 1;
						interactive_mode_box("restore");
					}), $mount_media),
					$new_path_entry = gtkset_sensitive(new Gtk2::Entry(), $mount_media),
					gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("Browse to new restore repository.")), clicked => sub {  
						filedialog_generic("Directory To Restore From", \$new_path_entry, \$path_to_find_restore);
					}), $mount_media),
					gtksignal_connect(Gtk2::Button->new(N("Restore From Catalog")), clicked => sub {  
						$box2->destroy;
						catalog_restore();
					}),
					gtksignal_connect(Gtk2::Button->new(N("Search for files to restore")), clicked => sub { 
						$box2->destroy;
						button_box_file_restore();
						find_files_to_restore() 
					}),
				),
				new Gtk2::VBox(0, 5),
			),
			1, new Gtk2::VBox(0, 5),	
		),
	);
	$new_path_entry->set_text($path_to_find_restore);
	$central_widget = \$box2;
	
	button_box_find_media($mount_media);  
    $up_box->show_all;
}

sub restore_status() {
	destroy_widget();
	$pbar3 =  new Gtk2::ProgressBar;
	$stext = new Gtk2::Label("");
	gtkpack($advanced_box,
		$table = gtkpack(new Gtk2::VBox(0, 5),
			new Gtk2::HBox(0,5),
	    	create_packtable({ col_spacings => 10, row_spacings => 5 },
				[""],
				[""],
				[""],
				[""], 
				[N("Restore Progress")],
				[""],
				[""],
				[$pbar3],
				[""],
				[""],
				[$plabel3 = new Gtk2::Label(' ')],
				[""],
			),
			$stext,
		),
	);
    $central_widget = \$table;
    $up_box->show_all;
    gtkflush();
}

################################################  BUTTON_BOX  ################################################  

sub button_box_adv() {
    $button_box_tmp->destroy;
    gtkpack($button_box,
		$button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			0, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub { 
				adv_help();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				interactive_mode_box();
			}),
			1, new Gtk2::HBox(0, 1),	
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub { 
				destroy_widget();
				$previous_widget->();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Save")), clicked => sub { 
				destroy_widget();
				unless (check_pkg_needs()) {
					save_conf_file();
					$previous_widget->();
				}
			}),
		),
	);
}

sub button_box_restore_main() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(gtkpack_(new Gtk2::HButtonBox, 
			0, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub {
				adv_help();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box();
			}),
			1, new Gtk2::HBox(0, 1),	
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box() 
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box() }),
			),
		),
	);
}

sub button_box_file_restore() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(gtkpack_(new Gtk2::HButtonBox, 
			0, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub {
				adv_help();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget(); 
				restore_box();
			}),
			1, new Gtk2::HBox(0, 1),	
			),
		),
	);
}

sub button_box_log_main() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(gtkpack_(new Gtk2::HButtonBox, 
			1, new Gtk2::HBox(0, 1),	
			0, gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box() }),
			),
		),
	);
}


sub button_box_backup_end() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			0, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub { 
				adv_help() 
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box() 
			}),
			1, new Gtk2::HBox(0, 1),	
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub { 
				destroy_widget(); 
				$previous_widget->() 
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Build Backup")), clicked => sub { 
				destroy_widget();
				build_backup_status();
				build_backup_files(); 
			}),
		),
	);
}

sub button_box_wizard_end() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
		$button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			0, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub { 
				adv_help();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget();
				interactive_mode_box();
			}),
			1, new Gtk2::HBox(0, 1),	
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub { 
				destroy_widget(); 
				$previous_widget->();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Save")), clicked => sub { 
				destroy_widget();
				save_conf_file();
				interactive_mode_box();
			}),
		),
	);
}

sub button_box_restore_end() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			0, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub { 
				adv_help();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget();
				interactive_mode_box();
			}),
			1, new Gtk2::HBox(0, 1),	
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub { 
				destroy_widget();
				$previous_widget->();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Restore")), clicked => sub { 
 				destroy_widget();
				restore_backend(); 
			}),
		),
	);
}

sub button_box_build_backup_end() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 
			1, new Gtk2::HBox(0, 5),	
			1, new Gtk2::HBox(0, 5),	
			0, gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { 
#				destroy_widget();
				interactive_mode_box();  
			}),
		),
	);
}

sub button_box_restore_pbs_end() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
		$button_box_tmp = gtkpack_(new Gtk2::HButtonBox, 
			1, new Gtk2::HBox(0, 5),	
			1, new Gtk2::HBox(0, 5),	
			1, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub {
				adv_help();
			}),
			0, gtksignal_connect(Gtk2::Button->new(N("Ok")), clicked => sub { 
				destroy_widget();
				interactive_mode_box();
			}),
		),
	);
}

sub button_box_build_backup() {
    $button_box_tmp->destroy;

	gtkpack($button_box,
		$button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			1, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub {
				adv_help(); 
			}),
			1, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box();
			}),
			1, new Gtk2::HBox(0, 0),
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub { 
				destroy_widget();
				$previous_widget->();
			}),
			1, gtksignal_connect(Gtk2::Button->new(N("Next ->")), clicked => sub {
				destroy_widget();
				$next_widget->();
			}),
		),
	);
}

sub button_box_restore() {

    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			1, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub {
				adv_help();
			}),
			1, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box();  
			}),
			1, new Gtk2::HBox(0, 0),
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub { 
				destroy_widget(); 
				$previous_widget->(); 
			}),
			1, gtksignal_connect(Gtk2::Button->new(N("Next ->")), clicked => sub {
				destroy_widget(); 
				$next_widget->();
			}),
		),
	);
}

sub button_box_find_media {

	my ($mount_media) = @_;
	
	#- $central_widget is not known yet?
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			1, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub {
				$central_widget = \$box2; 
				adv_help();
			}),
			1, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				$central_widget = \$box2;
				interactive_mode_box();  
			}),
			1, new Gtk2::HBox(0, 0),
			0, gtksignal_connect(Gtk2::Button->new(N("<- Previous")), clicked => sub {
				$central_widget = \$box2;
				interactive_mode_box();  
			}),
			1, gtkset_sensitive(gtksignal_connect(Gtk2::Button->new(N("Next ->")), clicked => sub {
				interactive_mode_box("restore"); 
			}), $mount_media),
		),
	);
}

sub button_box_wizard() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack_(new Gtk2::HButtonBox,
			1, gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub {
				adv_help() 
			}),
			1, gtksignal_connect(Gtk2::Button->new(N("Cancel")), clicked => sub { 
				destroy_widget(); 
				interactive_mode_box() 
			}),
			1, new Gtk2::HBox(0, 0),
			0, gtksignal_connect(Gtk2::Button->new($next_widget ? N("<- Previous") : N("Ok")), clicked => sub { 
				destroy_widget();
				$previous_widget ? $previous_widget->() : $next_widget->();
			}),
			if_($next_widget, 1, gtksignal_connect(Gtk2::Button->new(N("Next ->")), clicked => sub {
				destroy_widget();
				$next_widget ? $next_widget->() : $previous_widget->();
			})),
		),
	);
}

sub button_box_main() {
    $button_box_tmp->destroy;

    gtkpack($button_box,
	    $button_box_tmp = gtkpack(Gtk2::HButtonBox->new,
			gtksignal_connect(Gtk2::Button->new(N("Help")), clicked => sub { 
				adv_help() 
			}),
			gtksignal_connect(Gtk2::Button->new(N("Close")), clicked => sub { ugtk2->exit(0) }),
		),
	);
}

################################################  MESSAGES  ################################################  

sub dialog_one {
	destroy_widget();
    my ($label) = @_;
    
    gtkadd($advanced_box,
           $box2 = gtkpack_(new Gtk2::HBox(0, 15),	
                            1, new Gtk2::VBox(0, 5),	
                            0, gtkpack_(new Gtk2::HBox(0, 15),	
                                        0, new Gtk2::VBox(0, 5),	
                                        0, gtkcreate_img('warning'),
                                        0, $label),
                            0, new Gtk2::VBox(0, 5),	
                            1, new Gtk2::VBox(0, 5),	
                            ),
           );
    button_box_restore_main();
    $central_widget = \$box2;
    $up_box->show_all;    
}

sub send_mail_pb() {
    dialog_one(N("Error during sendmail.
  Your report mail was not sent.
  Please configure sendmail"));
}

sub client_ftp_pb() {
    dialog_one(N("Error during sending file via FTP.
 Please correct your FTP configuration."));
}

sub install_rpm {
    my ($previous_function) = @_;
	#- catch a crash when calling help
	#- this GUI control technique is kind of funky
	if ($previous_function eq '') {
		$previous_function = \&advanced_where;
	}
    my $box_what_user;
    gtkpack($advanced_box,
	    $box_what_user = gtkpack_(new Gtk2::VBox(0, 15),
			0, N("The following packages need to be installed:\n") . join(' ', @list_of_rpm_to_install),
				0, new Gtk2::HSeparator,
				0, gtksignal_connect(Gtk2::Button->new(N("Install")), clicked => sub {  
					system("/usr/sbin/urpmi --X @list_of_rpm_to_install"); 
					destroy_widget();
					$previous_widget->();		  
				}),
		),
	);
    fonction_env(\$box_what_user, \&install_rpm, \&$previous_function);
    $up_box->show_all;
}


sub message_norestore_box() {
    $box2->destroy;
    
    gtkadd($advanced_box,
		$box2 = gtkpack_(new Gtk2::HBox(0, 15),	
			1, new Gtk2::VBox(0, 5),	
			1, gtkpack(new Gtk2::HBox(0, 15),	
				new Gtk2::VBox(0, 5),	
				gtkcreate_img('warning'),
				N("Please select data to restore..."),
				new Gtk2::VBox(0, 5),	
			),
			1, new Gtk2::VBox(0, 5),	
		),
	);
    button_box_restore_main();
    $central_widget = \$box2;
    $up_box->show_all;    
}


sub message_common_box {
    $box2->destroy;
    my ($label) = @_;
    
    gtkadd($advanced_box,
           $box2 = gtkpack_(new Gtk2::HBox(0, 15),	
                            1, new Gtk2::VBox(0, 5),	
                            1, gtkpack(new Gtk2::HBox(0, 15),	
                                       new Gtk2::VBox(0, 5),	
                                       gtkcreate_img('warning'),
                                       $label,
                                       new Gtk2::VBox(0, 5),	
                                       ),
                            1, new Gtk2::VBox(0, 5),	
                            ),
           );
    $previous_widget = \&wizard;
    $next_widget = \&wizard;
    $central_widget = \$box2;
    $up_box->show_all;    
}

sub message_noselect_box() {
    message_common_box(N("Please select media for backup..."));
    $previous_widget = \&wizard_step2;
    $next_widget = \&wizard_step2;
    $central_widget = \$box2;
    $up_box->show_all;    
}

sub message_noselect_what_box() {
    message_common_box(N("Please select data to backup..."));
    $previous_widget = \&wizard;
    $next_widget = \&wizard;
    $central_widget = \$box2;
    $up_box->show_all;    
}

sub message_common_box_2 {
    my ($label, $restore_main) = @_;

    $box2->destroy;

    gtkadd($advanced_box,
		$box2 = gtkpack_(new Gtk2::HBox(0, 15),	
			1, new Gtk2::VBox(0, 5),	
			1, gtkpack(new Gtk2::HBox(0, 15),	
				new Gtk2::VBox(0, 5),	
				gtkcreate_img('warning'),
				N("%s", $label),
				new Gtk2::VBox(0, 5),	
			),
			1, new Gtk2::VBox(0, 5),	
		),
	);
    button_box_restore_main() if $restore_main;
    $central_widget = \$box2;
    $up_box->show_all;    
}
sub message_noconf_box() {
    message_common_box_2(N("No configuration file found \nplease click Wizard or Advanced."), 1);
}

sub message_underdevel() {
    message_common_box_2(N("Under Devel ... please wait."), 1);
}

################################################  BUILD_BACKUP  ################################################  

sub progress {
    my ($progressbar, $plabel, $incr, $label_text) = @_;
    my ($new_val) = $progressbar->get_fraction;
    $new_val += $incr;
    if ($new_val > 1) { $new_val = 1 }
    $progressbar->set_fraction($new_val);
    $plabel->set_text($label_text);
    gtkflush();
}

sub find_backup_to_put_on_cd() {
    @data_backuped = ();
	local $_;
	
    -d $save_path and my @list_backup = all($save_path);
    foreach (grep { /^backup_other/ } @list_backup) {
		$other_backuped = 1;
		chomp;
		my $tail  = (split(' ', `du $save_path/$_`))[0];
		s/^backup_other//gi;
		s/.tar.gz$//gi;
		s/.tar.bz2$//gi;
		my @user_date = split /_20/;
		my @user_date2 = split(/_/, $user_date[1]);
		my $to_put = "  other_data,          (tail: $tail ko, date: 20$user_date2[0], hour: $user_date2[1])";
		push @data_backuped , $to_put;
    }
    foreach (grep { /_sys_/ } @list_backup) {
		$sys_backuped = 1;
		chomp;
		my $tail  = (split(' ', `du $save_path/$_`))[0];
		s/^backup_other//gi;
		s/.tar.gz$//gi;
		s/.tar.bz2$//gi;
		my @user_date = split /_20/;
		my @user_date2 = split(/_/, $user_date[1]);
		my $to_put = "  system,          (tail: $tail ko, date: 20$user_date2[0], hour: $user_date2[1])";
		push @data_backuped , $to_put;
    }
    foreach (grep { /user_/ } @list_backup) {
		chomp;
		my $tail  = (split(' ', `du $save_path/$_`))[0];
		s/^backup_user_//gi;
		s/.tar.gz$//gi;
		s/.tar.bz2$//gi;
		my @user_date = split /_20/;
		my @user_date2 = split(/_/, $user_date[1]);
		my $to_put = "  $user_date[0],          (tail: $tail ko, date: 20$user_date2[0], hour: $user_date2[1])";
		push @data_backuped , $to_put;
    }
}

sub build_backup_status() {
    $pbar =   new Gtk2::ProgressBar;
    $pbar1 =  new Gtk2::ProgressBar;
    $pbar2 =  new Gtk2::ProgressBar;
    $pbar3 =  new Gtk2::ProgressBar;
	$plabel = new Gtk2::Label(" ");
	$plabel1 = new Gtk2::Label(" ");
	$plabel2 = new Gtk2::Label(" ");
	$plabel3 = new Gtk2::Label(" ");
	
    $stext = new Gtk2::Label("");
	button_box_build_backup_end();

	my $table = Gtk2::Table->new(10, 2, 1);
	$table->set_row_spacings(5);
	$table->set_col_spacings(10);
	
	$table->attach_defaults(new Gtk2::Label(N("Backup system files")), 0, 1, 0, 1);
	$table->attach_defaults($pbar, 0, 1, 1, 2);
	$table->attach_defaults($plabel, 1, 2, 1, 2);	
	$table->attach_defaults(new Gtk2::Label(N("Backup user files")), 0, 1, 2, 3);
	$table->attach_defaults($pbar1, 0, 1, 3, 4);
	$table->attach_defaults($plabel1, 1, 2, 3, 4);	
	$table->attach_defaults(new Gtk2::Label(N("Backup other files")), 0, 1, 4, 5);
	$table->attach_defaults($pbar2, 0, 1, 5, 6);
	$table->attach_defaults($plabel2, 1, 2, 5, 6);	
	$table->attach_defaults(new Gtk2::Label(N("Total Progress")), 0, 1, 6, 7);
	$table->attach_defaults($pbar3, 0, 1, 7, 8);
	$table->attach_defaults($plabel3, 1, 2, 7, 8);	

    gtkpack($advanced_box,
		my $tbox = gtkpack(new Gtk2::VBox(0, 5),
			$table,
			$stext,
		),
	);

    $central_widget = \$tbox;
    $up_box->show_all;
    gtkflush();
}


sub build_backup_ftp_status() {
    $pbar =   new Gtk2::ProgressBar;
    $pbar3 =  new Gtk2::ProgressBar;
	destroy_widget();
    button_box_build_backup_end();
    $pbar->set_fraction(0);
    $pbar3->set_fraction(0);


    gtkpack($advanced_box,
		$table =  gtkpack_(new Gtk2::VBox(0, 15),
			1, N("Sending files by FTP"),
			1, new Gtk2::VBox(0, 15),
			1, create_packtable ({ col_spacings => 10, row_spacings => 5 },
				[N("Sending files...")],
				[""], 
				[ $plabel = new Gtk2::Label(' ') ],
				[ $pbar ],
				[""], 
				[N("Total Progress")],
				[ $plabel3 = new Gtk2::Label(' ') ],
				[$pbar3],
			),
			1, new Gtk2::VBox(0, 15),
		),
	);
    $central_widget = \$table;
    $up_box->show_all;
    gtkflush();
}

sub build_backup_box_see_conf {
	my ($caller) = @_;
    my $box2;
    my $text = new Gtk2::TextView;
	read_conf_file();
    system_state();
    gtktext_insert($text, [ [ $system_state ] ]);
    button_box_restore_main();

    gtkpack($advanced_box,
	    $box2 = gtkpack_(new Gtk2::HBox(0, 15),	
			1, gtkpack_(new Gtk2::VBox(0,10),
				0, N("Drakbackup Configuration"),
				1, create_scrolled_window($text),
			),
		),
	);
    button_box_backup_end();
    $central_widget = \$box2;
    $current_widget = \&build_backup_box_see_conf;
	if ($caller eq "interactive") {
		$previous_widget = \&interactive_mode_box;
	} else {
    	$previous_widget = \&build_backup_box;
    }
	$up_box->show_all;
}

sub build_backup_box_progress() {
#    build_backup_files(); 
}

sub aff_total_tail() {
    my @toto;
    my $total = 0;
    push @toto, (split(",", $_))[1] foreach @list_to_build_on_cd;
    foreach (@toto) {
	s/\s+\(tail://gi;
	s/\s+//gi;
	s/ko//gi;
	$total += $_; 
	}
    $label_tail->set("total tail: $total ko");
}

sub build_backup_box() {
	destroy_widget();

    gtkadd($advanced_box,
		$box2 = gtkpack_(new Gtk2::HBox(0, 15),	
			1, new Gtk2::VBox(0, 5),	
			1, gtkpack_(new Gtk2::VBox(0, 15),	
				1, new Gtk2::VBox(0, 5),	
				1, gtksignal_connect(my $button_from_conf_file = Gtk2::Button->new, clicked => sub { 
					destroy_widget();
					build_backup_box_see_conf();
				}),
 				0, new Gtk2::VBox(0, 5),	
				1, gtksignal_connect(my $button_see_conf = Gtk2::Button->new, clicked => sub { 
					destroy_widget();
					build_backup_box_see_conf();
				}),
				1, new Gtk2::VBox(0, 5),	
			),
			1, new Gtk2::VBox(0, 5),	
		),
	 );

    $button_from_conf_file->add(gtkpack(new Gtk2::HBox(0,10),
		gtkcreate_img("ic82-discdurwhat-40"),
		new Gtk2::Label(N("Backup Now from configuration file")),
		new Gtk2::HBox(0, 5)
	));
    $button_see_conf->add(gtkpack(new Gtk2::HBox(0,10),
		gtkcreate_img("ic82-moreoption-40"),
		new Gtk2::Label(N("View Backup Configuration.")),
		new Gtk2::HBox(0, 5)
	));

    button_box_restore_main();
    fonction_env(\$box2, \&build_backup_box, \&interactive_mode_box);
    $up_box->show_all;
}

################################################  INTERACTIVE  ################################################  

sub interactive_mode_box {

	my ($mode) = @_;
	if ($mode eq "restore") {
    	$central_widget = \$box2;
		restore_box();
		return 0;
	}
	    
	destroy_widget();
    gtkadd($advanced_box,
		$box2 = gtkpack_(new Gtk2::HBox(0, 15),	
			1, new Gtk2::VBox(0, 5),	
			1, gtkpack_(new Gtk2::VBox(0, 5),	
				1, new Gtk2::VBox(0, 5),	
				0, gtksignal_connect(Gtk2::Button->new(N("Wizard Configuration")), clicked => sub { 
					destroy_widget();
					read_conf_file();
					wizard(); 
				}),
				0, gtksignal_connect(Gtk2::Button->new(N("Advanced Configuration")), clicked => sub { 
					button_box_adv();
					destroy_widget();
					advanced_box(); 
				}),
				0, gtksignal_connect(Gtk2::Button->new(N("View Configuration")), clicked => sub { 
					destroy_widget();
					build_backup_box_see_conf("interactive");
				}),
				0, gtksignal_connect(Gtk2::Button->new(N("View Last Log")), clicked => sub { 
					$results = cat_($log_file);
					button_box_log_main();
					show_status();
				}),				
				0, gtksignal_connect(Gtk2::Button->new(N("Backup Now")), clicked => sub { 
					if ($cfg_file_exist) { 
						build_backup_box();
					} else { 
						message_noconf_box();
					}
				}),
				0, gtksignal_connect(Gtk2::Button->new(N("Restore")), clicked => sub {
					destroy_widget(); 
					restore_box();
				}),
				1, new Gtk2::VBox(0, 5),	
			),
			1, new Gtk2::VBox(0, 5),	
		),
	);
    $central_widget = \$box2;
    button_box_main();
    $up_box->show_all;
}

sub interactive_mode() {
    $interactive = 1;

    $in = 'interactive'->vnew;

    my $box;
	my $winht = 440;
	$winht = 320 if $::isEmbedded;
	my $winwidth = 540;
	$winwidth = 500 if $::isEmbedded;
	my $darea;
	
    $my_win = ugtk2->new('drakbackup');
    $window1 = $my_win->{window};
    unless ($::isEmbedded) {
		$my_win->{rwindow}->set_position('center');
		$my_win->{rwindow}->set_title(N("Drakbackup"));
		$window1->set_size_request($winwidth, $winht);
		my $pixbuf_icon = gtkcreate_pixbuf("ic82-back-up-48");
		$darea = Gtk2::DrawingArea->new;
		$darea->set_size_request($winwidth, 60);
		$darea->modify_font(Gtk2::Pango::FontDescription->from_string('Sans Italic 24'));
		my $layout = $darea->create_pango_layout(N("Drakbackup"));
    	$darea->signal_connect(realize => sub { 
			set_back_pixbuf($darea, gtkcreate_pixbuf('title-tile')) 
		});
    	$darea->signal_connect(expose_event => sub {
			my (undef, undef, $dx, $dy) = $darea->allocation->values;
			$darea->window->draw_pixbuf($darea->style->white_gc, $pixbuf_icon, 0, 0, $dx - $pixbuf_icon->get_width, $dy - $pixbuf_icon->get_height, -1, -1, 'none', 0, 0);
			my ($lx, $ly) = $layout->get_pixel_size;
			$darea->window->draw_layout($darea->style->white_gc, ($dx-$lx)/2, ($dy-$ly)/2, $layout);
			0;
		});
    }
    $my_win->{rwindow}->signal_connect(delete_event => sub { ugtk2->exit(0) });
    read_conf_file();     

    gtkadd($window1,
		gtkpack(new Gtk2::VBox(0,0),
			gtkpack(gtkset_size_request($up_box = new Gtk2::VBox(0, 5), $winwidth, $winht),
				$box = gtkpack_(new Gtk2::VBox(0, 3),
					if_(!$::isEmbedded, 0, $darea),
					1, gtkpack_(new Gtk2::HBox(0, 3),
				  		1, gtkpack_(new Gtk2::HBox(0, 15),	
							0, new Gtk2::HBox(0, 5),	
					    	1, $advanced_box = gtkpack_(new Gtk2::HBox(0, 15),	
							),
					    	0, new Gtk2::HBox(0, 5),	
						),
					),
					0, new Gtk2::HSeparator,
					0, $button_box = gtkpack(new Gtk2::VBox(0, 15),	
						$button_box_tmp = gtkpack(new Gtk2::VBox(0, 0),),
					),
				),
			),
		),
	);
	setup_tooltips();
    interactive_mode_box();
    button_box_main();
    $central_widget = \$box2;
    $window1->show_all;
    $window1->realize;
    $window1->show_all;    
    $my_win->main;
    $my_win->exit(0);
}

################################################  HELP & ABOUT  ################################################  

sub adv_help() {
	exec("drakhelp --id drakbackup") unless fork();
}

sub to_ok() {
    $sav_next_widget = $next_widget;
    $next_widget = undef;
    button_box_wizard();
}

sub to_normal() {
    $next_widget = $sav_next_widget;
}

sub destroy_widget() {
	if ($central_widget ne '') {
		$$central_widget->destroy;
		$central_widget = '';
	}
}