/**
 * File:	clients/bootfloppy.ycp
 *
 * Package:	yast2-bootloader
 *
 * Summary:	Boot floppy creation
 *
 * Authors:	Michael Hager <mike@suse.de>
 *		Johannes Buchhold <jbuch@suse.de>
 *		Jiri Srain <jsrain@suse.cz>
 *
 * $Id: bootfloppy.ycp 22318 2005-03-07 14:13:13Z jsrain $
 *
 * This module create boot floppies and module floppies.
 * You can use a new boot/install floppy to boot either
 * the installed  system or the rescue system from CD.
 */

{

    textdomain "bootloader";

    import "Arch";
    import "Label";
    import "PackageCallbacksInit";
    import "Popup";
    import "Report";
    import "Sequencer";
    import "Wizard";

    Wizard::CreateDialog();
    Wizard::SetDesktopIcon("bootfloppy");
    PackageCallbacksInit::InitPackageCallbacks ();

    integer boot_floppy_count = 6;

    string file_image = "bootdsk1"; //default
    string filename = "";
    string dirname = "";
    string url = "";
    string user = "";
    string pass = "";

    integer source_id = 0;
    boolean source_mounted = false;

    string floppy_device = "/dev/fd0"; // default
    boolean format_floppy = false; // default
    boolean images_created = false;
    string imagedir = "";
    map floppymount = nil;

    // This is the headline of the bootfloppy module
    string dialog_header = _("Create boot or rescue floppies");

    map<string,string> image_creating_labels = $[
	// image text - label
	"rescuefloppy" : _("Creating rescue floppy"),
	// image text - label
	"modules1": _("Creating USB modules floppy"),
	// image text - label
	"modules2" : _("Creating IDE/RAID/SCSI modules floppy"),
	// image text - label
	"modules3" : _("Creating network modules floppy"),
	// image text - label
	"modules4" : _("Creating PCMCIA, old (non-ATAPI) CDROM,
FireWire and file systems modules floppy"),
	// image text - label
	"modules5" : _("Creating IDE/RAID/SCSI modules floppy"),
    ];

    integer index = -1;
    while (index < boot_floppy_count)
    {
	index = index + 1;
	string image = sformat ("bootdsk%1", index);
	image_creating_labels[image] = sformat (
	    // image text - label
	    // %1 is index of the floppy
	    // %2 is total count of the floppies
	    _("Creating Standard Boot Floppy--Part %1 of %2"),
	    index,
	    boot_floppy_count);
    }

    map<string,string> image_selection_labels = $[
	// radiobutton - disk image name
	"rescuefloppy" : _("&Rescue Floppy"),
	// radiobutton - disk image name
	"__modules" : _("&Module Floppies"),
	// radiobutton - disk image name
	"__other" : _("&Other Installation Disk"),
	// radiobutton - disk image name
	"__custom" : _("&Custom Floppy"),
	// radiobutton - disk image name
	"__url" : _("&Download Floppy Image"),
    ];
    index = 0;
    while (index < boot_floppy_count)
    {
	index = index + 1;
	string image = sformat ("bootdsk%1", index);
	image_selection_labels[image] = sformat (
	    // image text - label
	    // %1 is index of the floppy
	    // %2 is total count of the floppies
	    _("Standard Boot Floppy--Part %1 of %2"),
	    index,
	    boot_floppy_count);
    }

    /**
      * Get strnig to show while writing the image to floppy
      * @param image string image name
      * @return string label to show
      */
    define string getImageWritingLabel (string image) ``{
	// image text - label
	return image_creating_labels[image]:_("Creating Specified Floppy");
    }

    /**
      * Show popup with a custom message
      * @param label string message to show
      */
    define void showPopup (string label) ``{
	UI::OpenDialog (`Label (label));
    }

    /**
      * Hide shown popup window
      */
    define void hidePopup () ``{
	UI::CloseDialog ();
    }

define string createFloppyImage (string file_image) {
    if (! images_created)
    {
	// first download the mkbootfloppy script
	string script = Pkg::SourceProvideFile(source_id, 1,
	    "/boot/mkbootdisk");
	// build command to build the images
	string tmpdir = (string)SCR::Read (.target.tmpdir);
	imagedir = sformat ("%1/floppy", tmpdir);
	string srcdir = sformat ("%1/src", tmpdir);
	SCR::Execute (.target.mkdir, imagedir);
	SCR::Execute (.target.mkdir, srcdir);
	// get the list of files
	string filelist_str = Pkg::SourceProvideFile (source_id, 1,
	    "/boot/loader/directory.yast");
	filelist_str = (string)SCR::Read (.target.string, filelist_str);
	list<string> filelist = splitstring (filelist_str, "\n");
	filelist = filter (string f, filelist, {return f != "";});
	y2milestone ("Filelist: %1", filelist);
	// copy all files to the local disk
	foreach (string f, filelist, {
	    f = Pkg::SourceProvideFile (source_id, 1,
		sformat ("/boot/loader/%1", f));
	    SCR::Execute (.target.bash, sformat ("/bin/cp %1 %2",
		f, srcdir));
	});
	string image_pattern
	    = substring (file_image, 0, size (file_image) - 1);
	string command = sformat ("cd %1; /usr/bin/perl %2 %5 --out %3 %4",
	    imagedir,
	    script,
	    image_pattern,
	    srcdir,
	    Arch::x86_64 () ? "--64" : "--32");
	y2milestone ("Command to execute: %1", command);
	SCR::Execute (.target.bash, command);
	images_created = true;
    }
    file_image = sformat ("%1/%2", imagedir, file_image);
    y2milestone ("Image selected: %1", file_image);
    return file_image;
}


    /**
      * Try to mount source medium e.g. CD1 or a directory on the harddisk.
      * If no source medium is found, the user can select
      * a new source medium like in the module software selection.
      */
    define void floppyMountSource() ``{
	if (source_mounted)
	    return;
	list<integer> sources = Pkg::SourceStartCache (true);
	source_id = sources[0]:0;
	source_mounted = true;
    }


    /**
      * Read /proc/mounts and return a list with all mounted devices
      * @param floppy string device name of floppy to check
      * @return map floppy mountpoint info
      */
    define map isFloppyMounted (string floppy) ``{
	list<map> mounts = (list<map>)SCR::Read(.proc.mounts);

	mounts = filter (map mount, mounts, ``(
	    issubstring (mount["spec"]:"", floppy)));

	return (map)(mounts[0]:nil);
    }

    /**
      * Helptext for the define floppySelectImage.
      * Called from the floppySelectImage.
      * @param modules boolean if true then shows a list of modules instead
      *  of main dialog
      * @return string help text
      */
    define string floppyHelpSelectImage(boolean modules) ``{
	if (modules)
	{
	    // help text 1/1
	    string help_text = _("<p>Depending on the modules needed, select the
appropriate floppy from the list of module floppies then click <b>Next</b>
to continue.</p>
");

	    return help_text;
	}
	else
	{
	    // help text 1/5
	    string help_text = _("<p>
To create a boot, modules, or rescue floppy,
select the appropriate item from the list and
click <b>Next</b> to continue.</p>");

	    // help text 2/5
	    help_text = help_text + _("<p><b>Boot Floppies</b><br>
These boot floppies can be used to boot your installed system or a rescue system
(from the first CD-ROM or the rescue floppy).</p>");

	    if (Arch::i386 ())
	    {
		// help text 3/5
		help_text = help_text + _("<p><b>Rescue Floppy:</b><br>
To start the rescue system, boot from the boot floppy or the SuSE CD-ROM
and select <i>Manual installation</i> -> <i>Start installation / system</i>
-> <i>Rescue system</i>. You will be prompted for the rescue floppy.</p>");
	    }

if (false)
	    // help text - former 4/5 - is skipped now
	    help_text = help_text + _("<p><b>Module Floppies</b><br>
All SuSE kernels are modularized. This means that most drivers
are loaded as kernel modules on demand. Because the space on one single floppy
is not sufficient for all kernel modules, consider creating one
of the <b>module floppies</b>.</p>");

	    // help text 4/5
	    help_text = help_text + _("<p><b>Custom Floppy</b><br>
To create a floppy from another image, select <b>Custom Floppy</b>. You will
be prompted for the file containing the floppy image.</p>");

	    // help text 5/5
	    help_text = help_text + _("<p><b>Download Floppy Image</b><br>
To create a floppy from an image located on the network, select
<b>Download Floppy Image</b>. You are then prompted for the location
of the floppy image.</p>
");

	    return help_text;
	}
    }

    /**
      * Helptext for the define floppyInsertDisk.
      * Called from the floppyInsertDisk.
      * @return string help text
      */
    define string floppyHelpInsertDisk() ``{
	// help text 1/4
	string help_text = _("<p><b><big>Create a Boot, Rescue
or Module Floppy:</big></b><br>
Insert a floppy disk (1.44 MB) into the floppy drive
and press <b>Next</b> to continue.</p>
");

	// help text 2/4
	help_text = help_text + _("<p><b><big>Floppy Device:</big></b><br>
If your computer has multiple floppy drives, select the correct device.</p>
");

	// help text 3/4
	help_text = help_text + _("<p><b><big>Format Floppy Disk:</big></b><br>
Before a floppy image is saved on the floppy, it must be formatted.
If the floppy is not preformatted, check
<b>Format Floppy Disk</b>.</p>
");

	// help text 4/4
	help_text = help_text + _("<p><b><big>Attention:</big></b><br>
All data on the floppy will be deleted.</p>");

	return help_text;
    }

    /**
      * Helptext for the define floppyCopyImage.
      * Called from the  floppyCopyImage.
      * @return string help text
      */
    define string floppyHelpCopyImage() ``{
	// help text 1/1
	return _("<p><b><big>Creating Floppy Disk:</big></b><br>
YaST2 is copying the image to the floppy disk. Please wait.</p>
");
    }

    /**
      * Helptext for the define floppySelectFile.
      * Called from the  floppySelectFile.
      * @return string help text
      */
    define string floppyHelpSelectFile() ``{
	// help text 1/1
	return _("<p><b><big>Select Floppy Image:</big></b><br>
Select the file containing the image of the floppy to create.</p>
");
    }

    /**
      * Helptext for the define floppySelectURL.
      * Called from the  floppySelectURL.
      * @return string help text
      */
    define string floppyHelpSelectURL() ``{
        // help text 1/1
        return _("<p><b><big>Select Floppy Image:</big></b><br>
Enter the URL from which to download the floppy image.
If necessary, also specify the user name and password for authentication.</p>
");
    }

    /**
      * Display a dialog that lets the user choose among different images.
      * Save the selected image in the global variable file_image.
      * Called from the sequencer.
      * @param modules boolean if true then shows a list of modules instead
      *  of main dialog
      * @return symbol wizard sequencer symbol
      */
    define symbol floppySelectImage(boolean modules) ``{
	term images_term = nil;

	if (modules)
	{
	    images_term = `VBox (
		`VSpacing (2),
		`Left (`RadioButton (`id ("modules1"),
		    // radiobutton - disk image name
		    _("&USB (modules disk 1)"))),
		`VSpacing (0.4),
		`Left (`RadioButton (`id ("modules2"),
		    // radiobutton - disk image name
		    _("&IDE/RAID/SCSI (modules disk 2)"))),
		`VSpacing (0.4),
		`Left (`RadioButton (`id ("modules3"),
		    // radiobutton - disk image name
		    _("&Network (modules disk 3)"))),
		`VSpacing (0.4),
		`Left (`RadioButton (`id ("modules4"),
		    // radiobutton - disk image name
                   _("&PCMCIA, Old (non-ATAPI) CD-ROM, FireWire,
and File Systems (modules disk 4)"))),
		`VSpacing (0.4),
		`Left (`RadioButton (`id ("modules5"),
		    // radiobutton - disk image name
		    _("&More IDE, RAID, and SCSI (modules disk 5)"))),
		`VSpacing (2)
	    );
	}
	else
	{
	    list<string> images = [];
	    integer index = 0;
	    while (index < boot_floppy_count)
	    {
		index = index + 1;
		images = add (images, sformat ("bootdsk%1", index));
	    }
	    if (Arch::i386 ())
		images = add (images, "rescuefloppy");
	    images = (list<string>)merge (images, [
//		"rescuefloppy",
//		"__modules",
//		"__other",
		"__custom",
		"__url"
	    ]);
	    images_term = `VBox ();
	    boolean first = true;
	    foreach (string i, images, {
		images_term = add (images_term, `VSpacing (first ? 2 : 0.4));
		first = false;
		images_term = add (images_term, `Left (`RadioButton (`id (i),
		    `opt (`autoShortcut),
		    image_selection_labels[i]:i)));
	    });
	    images_term = add (images_term, `VSpacing (2));
	}

	term contents = `HBox (`HStretch (),
	    `VBox (
		`VSpacing (2),
		// frame label
		`Frame (_("Floppy Image"), `HBox (`HSpacing (3),
		    `RadioButtonGroup (`id (`images), images_term),
		    `HSpacing (3)
		)),
		`VSpacing (2)
	    ), `HStretch ()
	);

	// Screen title for the first interactive dialog
	any dlg = Wizard::SetContents( dialog_header, contents,
	    floppyHelpSelectImage(modules), true, true);

	if (modules)
	{
	    Wizard::RestoreBackButton ();
	    Wizard::RestoreAbortButton ();
	    UI::SetFocus (`id ("modules1"));
	    if (substring (file_image, 0, 7) != "modules")
		file_image = "modules1";
	    UI::SetFocus (`id (file_image));
	    UI::ChangeWidget(`id(`images), `CurrentButton, file_image);
	}
	else
	{
	    Wizard::HideBackButton();
	    Wizard::SetAbortButton(`abort, Label::CancelButton () );
	    UI::SetFocus (`id ("bootdsk1"));
	    string image_item = file_image;
	    if (substring (image_item, 0, 7) == "modules")
		image_item = "__modules";
	    UI::ChangeWidget(`id(`images), `CurrentButton, image_item);
	}

	any ret = nil;
	while (ret == nil)
	{
	    ret = UI::UserInput ();
	    if (ret == `next)
	    {
		string backup_file_image = file_image;
		file_image = (string)
		    UI::QueryWidget (`id (`images), `CurrentButton);
		if (file_image == "__modules")
		{
		    file_image = backup_file_image;
		    return `select_module;
		}
		if (file_image != "__custom" && file_image != "__url")
		{
		    if (file_image == "__other")
		    {
			floppyMountSource ();
			filename = "";
			dirname = Pkg::SourceProvideDir (source_id, 1, "boot");
		    }
		    else
		    {
			// label in a popup informing about currently
			// processed action
			showPopup (_("Getting the floppy disk image..."));
			floppyMountSource ();
			if (substring (file_image, 0, 7) == "bootdsk")
			{
			    filename = createFloppyImage (file_image);
			}
			else
			{
			    string pth = sformat ("boot/%1", file_image);
			    filename = Pkg::SourceProvideFile(source_id,
								1, pth);
			}
			hidePopup ();
			if (filename == nil)
			{
			    // error report
			    Report::Error (_("The selected image does not exist on the installation medium."));
			    ret = nil;
			}
		    }
		}
		else
		{
		    filename = "";
		    dirname = "";
		}
		if (file_image == "__other" || file_image == "__custom")
		{
		    ret = `select_file;
		}
		else if (file_image == "__url")
		{
		    ret = `select_url;
		}

	    }
	    else if (ret != `abort && ret != `cancel && ret != `back)
	    {
		ret = nil;
	    }
	}
	return (symbol)ret;
    };

    /**
      * Display a dialog that lets the select file with floppy image.
      * Save the selected file name in the global variable filename.
      * Called from the sequencer.
      * @return symbol wizard sequencer symbol
      */
    define symbol floppySelectFile () ``{
        term contents = `HBox (`HStretch (),
            `VBox (
                `VStretch (),
		`HBox (
			// text entry label
		    `TextEntry (`id (`filename), _("&File Name"), ""),
		    `VBox (
			`Label (" "),
			// push button
			`PushButton (`id (`browse), _("&Browse..."))
		    )
		),
                `VStretch ()
            ), `HStretch ()
        );

	Wizard::SetContents (dialog_header, contents,
            floppyHelpSelectFile(), true, true);

	Wizard::RestoreBackButton ();
	Wizard::RestoreAbortButton ();

	if (filename != "" && filename != nil)
	    UI::ChangeWidget (`id (`filename), `Value, filename);

	symbol ret = nil;

	while (ret == nil)
	{
	    ret = (symbol)UI::UserInput ();
	    if (ret == `cancel)
		ret = `abort;
	    if (ret == `browse)
	    {
		string name = (string)UI::QueryWidget (`id (`filename), `Value);
		name = UI::AskForExistingFile (name, "",
		    // popup header
		    _("Select Floppy Image"));
		if (name != "" && name != nil)
		    UI::ChangeWidget (`id (`filename), `Value, name);
		ret = nil;
	    }
	    else if (ret == `next)
	    {
		string name = (string)UI::QueryWidget (`id (`filename), `Value);
		if ((integer)SCR::Read (.target.size, name) > 0)
		    filename = name;
		else
		{
		    ret = nil;
		    Report::Error (
			// error report
			_("The specified file does not exist or is empty."));
		}

	    }
	}

	return ret;
    }

    /**
      * Display a dialog that lets the select URL with floppy image.
      * Save the URL and downloaded file name in the global variable filename.
      * Called from the sequencer.
      * @return symbol wizard sequencer symbol
      */
    define symbol floppySelectURL () ``{
	term contents = `HBox (`HStretch (),
	    `VBox (
		`VStretch (),
		// text entry label
		`TextEntry (`id (`url), _("&URL"), ""),
		`VSpacing (2),
		`HBox (
		    // text entry label
		    `TextEntry (`id (`user), _("&User"), user),
		    `HSpacing (2),
		    // text entry label
		    `Password (`id (`pass), Label::Password (), pass)
		),
		`VStretch ()
	    ), `HStretch ()
	);

	Wizard::SetContents (dialog_header, contents,
	    floppyHelpSelectURL(), true, true);

	Wizard::RestoreBackButton ();
	Wizard::RestoreAbortButton ();

	if (url != "" && url != nil)
	    UI::ChangeWidget (`id (`url), `Value, url);

	symbol ret = nil;

	while (ret == nil)
	{
	    ret = (symbol)UI::UserInput ();
	    if (ret == `cancel)
		ret = `abort;
	    if (ret == `next)
	    {
		url = (string)UI::QueryWidget (`id (`url), `Value);
		user = (string)UI::QueryWidget (`id (`user), `Value);
		pass = (string)UI::QueryWidget (`id (`pass), `Value);
		string file = (string)SCR::Read (.target.tmpdir) + "/image";
		// label in a popup informing about currently processed action
		showPopup (_("Downloading image..."));
		if (user != "" && pass != "")
		{
		    string userpass = sformat ("%1:%2", user, pass);
		    SCR::Execute(.curl.setUserPassword, userpass, $[]);
		}
		else if (user != "")
		{
		    // error report
		    Report::Error (_("Set the password."));
		    ret = nil;
		    continue;
		}
		map response = (map)SCR::Execute (.curl.get, url,
		    $["output": file]);
		hidePopup ();
		y2error ("Response: %1", response);
		if (response["dsize"]:0 == 0)
		{
		    Report::Error (
// error report
_("An error occurred while downloading the floppy image.
Verify the URL, user name, 
and password.
"));
		    ret = nil;
		    continue;
		}
		filename = file;
	    }
	}

	return ret;
    }


    /**
      * Display a dialog that prompts for a floppy.
      * @return system
      */
    define symbol floppyInsertDisk() ``{
	list<map> floppies_m = (list<map>)SCR::Read (.probe.floppy);
	list<string> floppies = (list<string>)maplist (map f, floppies_m,
	    ``(f["dev_name"]:nil));
	floppies = filter (string f, floppies, ``(f != nil));

	term contents = `HSquash (
	    `VBox (
		`VSpacing (1),
		`Label (
		    // Main window contents when the floppy
		    // is about to be written.
		    // Translators: Try not to make this much longer
		    // than the English version, please...
		    _("Insert a floppy disk (1.44 MB)
into the floppy drive.

All data on this floppy will be deleted.
")),
		`VSpacing (3),
		`HSquash (
		    `ComboBox (`id (`device), `opt (`editable),
			// combo box label
			_("Floppy &Device"), floppies)
		),
		`VSpacing (3),
		`HSquash (
		    // checkbox
		    `CheckBox (`id (`format), _("&Format Floppy Disk"),
			format_floppy)
		),
		`VSpacing (1)
	    )
	);

	Wizard::SetContents( dialog_header, contents, floppyHelpInsertDisk(),
	    true, true);

	Wizard::RestoreBackButton ();
	Wizard::RestoreAbortButton ();
	UI::ChangeWidget (`id (`device), `Value, floppy_device);

	any ret = nil;
	while (ret == nil)
	{
	    ret = UI::UserInput ();
	    if (ret == `cancel)
		ret = `abort;
	    if (ret == `next)
	    {
		floppy_device = (string)UI::QueryWidget (`id (`device), `Value);
		format_floppy = (boolean)
		    UI::QueryWidget (`id (`format), `Value);

		map floppymount_tmp = isFloppyMounted (floppy_device);

		if ( floppymount_tmp != nil)
		{
		    floppymount = floppymount_tmp;
		     //floppy is mounted -- popup
		    if( ! Popup::ContinueCancel(sformat(_("
Your floppy device %1 is currently mounted on
%2. To create a new boot floppy,
the floppy device must be unmounted.

Unmount the floppy?
"), floppymount["spec"]:"", floppymount["file"]:"")))
		    {
			ret = nil;
		    }
		    else
		    {
			SCR::Execute (.target.bash, sformat ("/bin/umount %1",
			    floppymount["spec"]:""));
		    }
		}
	    }
	}
	return (symbol)ret;
    }

define void OfferFloppyRemount () {
    if (floppymount == nil)
	return;
    // yes-no popup
    if (Popup::YesNo (_("The floppy device was unmounted before creating
the floppy image. Mount it again?")))
    {
	// try according to fstab
	integer ret = (integer)SCR::Execute (.target.bash,
	    sformat ("/bin/mount %1", floppymount["spec"]:""));
	if (ret == 0)
	    return;
	ret = (integer)SCR::Execute (.target.bash,
	    sformat ("/bin/mount %1 %2 %3 %4",
		floppymount["mntops"]:"" == ""
		    ? ""
		    : sformat ("-o %1", floppymount["mntops"]:""),
		floppymount["vfstype"]:"" == ""
		    ? ""
		    : sformat ("-t %1", floppymount["vfstype"]:""),
		floppymount["spec"]:"",
		floppymount["file"]:""));
	if (ret == 0)
	    return;
	// error report;
	Report::Error (_("Failed to mount the floppy. Do it manually
after finishing YaST."));
    }
}

    /**
      * Copy the selected image to the floppy.
      * Called from the  sequenser.
      * @return symbol wizard sequencer symbol
      */
    define symbol floppyCopyImage() ``{
	term contents = `VBox(
	    `VSpacing (2),
	    `Left(`Heading ( getImageWritingLabel (file_image))),
	    // progress bar status
	    `HVCenter(`ReplacePoint (`id (`bar_rp),
		// progress bar
		`ProgressBar(`id(`bar), _("Copying...")))),
	    `VSpacing (2)
	);

	Wizard::SetContents( dialog_header, contents, floppyHelpCopyImage(),
	    true, true);

	string command   = "";
	string begin_str = "";
	string diff_str  = "";

	if (format_floppy)
	{
	    // label in a popup informing about currently processed action
	    showPopup (_("Formatting the floppy..."));
	    integer fd_ret = (integer)SCR::Execute
		(.target.bash, sformat ("/usr/bin/fdformat %1", floppy_device));
	    hidePopup ();
	    if (fd_ret != 0)
	    {
		Report::Error(
		    // error report
		    _("An error occurred while formatting the floppy disk.
Verify that a valid floppy medium is
in the drive and that you have root permissions 
then try again.
"));
		OfferFloppyRemount ();
		return `select_image;
	    }
	}

	begin_str = sformat ("/bin/dd if=%1 of=%2 bs=512",
	    filename, floppy_device);
	diff_str = sformat (" %1 %2", filename, floppy_device);

	integer image_size = (integer)SCR::Read (.target.size, filename);
	integer count = 0;
	integer ignore = 0;
	integer value = 0;
	integer ret_command = 1;
	boolean failed = false;

	while(count < 2880)
	{
	    UI::ChangeWidget(`id(`bar), `Value, value );
	    count = count + 288;
	    command = begin_str
		+ sformat (" count=288 skip=%1 seek=%1", ignore)
		+ ">/dev/null 2>&1";
	    ignore  = ignore + 288;
	    value   = value  + 10;

	    ret_command = (integer)SCR::Execute(.target.bash , command );
	    if (ret_command != 0)
	    {
		failed = true;
		break;
	    }
	}
	if (failed)
	{
	    // error report
	    Report::Error(_("An error occurred while copying the image file
to the floppy disk. Verify that a valid floppy 
medium is in the drive and that you have
root permissions then try again.
"));
	    OfferFloppyRemount ();
	    return `select_image;
	}

	count = 0;
	ignore = 0;
	value = 0;
	failed = false;

	UI::ReplaceWidget (`id (`bar_rp),
	    // progress bar
	    `ProgressBar(`id(`bar), _("Verifying...")));

	while (count < 2880)
	{
	    UI::ChangeWidget(`id(`bar), `Value, value );
	    count = count + 288;
	    integer check_size = 512 * 288;
	    if (512 * ignore + check_size > image_size)
	    {
		check_size = image_size - 512 * ignore;
		if (check_size < 0)
		    check_size = 0;
	    }
	    command = sformat ("/usr/bin/cmp -i %1:%1 -n %2",
		512 * ignore, check_size ) + diff_str + ">/dev/null 2>&1";
	    ignore  = ignore + 288;
	    value   = value  + 10;

	    ret_command = (integer)SCR::Execute(.target.bash , command );
	    if (ret_command != 0)
	    {
		failed = true;
		break;
	    }
	}
        if (failed)
        {
	    // error report
            Report::Error(_("An error occurred while verifying the floppy disk.
Try again with another floppy.
"));
	    OfferFloppyRemount ();
            return `back;
        }
	// popup
	Popup::Message(_("

The requested floppy disk was successfully created.

"));
	OfferFloppyRemount ();
	return `next;
    }


    // ===== define the sequences =======================================

    map aliases = $[
	"select_image" :  ``(floppySelectImage (false)),
	"select_module":  ``(floppySelectImage (true)),
	"select_file"  :  ``(floppySelectFile ()),
	"select_url"   :  ``(floppySelectURL ()),
	"insert_disk"  :  ``(floppyInsertDisk ()),
	"copy_image"   :  ``(floppyCopyImage ())
    ];

    map main_sequence = $[
	"ws_start": "select_image",
	"select_image":	$[
	    `abort: `abort,
	    `next : "insert_disk",
	    `select_file : "select_file",
	    `select_url : "select_url",
	    `select_module : "select_module",
	],
	"select_module": $[
	    `abort: `abort,
	    `next : "insert_disk",
	],
	"select_file" : $[
	    `abort: `abort,
	    `next : "insert_disk",
	],
	"select_url" : $[
	    `abort: `abort,
	    `next : "insert_disk",
	],
	"insert_disk" : $[
	    `abort: `abort,
	    `next : "copy_image",
	],
	"copy_image"  : $[
	    `abort: `abort ,
	    `next : `abort,
	    `select_image: "select_image"
	],
    ];

    // ===== Start the sequence =======================================

    any ret = Sequencer::Run(aliases, main_sequence);

    //  ===== umount CD  ================================================
    UI::CloseDialog();
    return ret;

/* EOF */
}
