# get_zone_form(&in, &zinfo)
# Returns a form for editing a zone
sub get_zone_form
{
local ($in, $zinfo) = @_;
local $form = new Webmin::Form("save_zone.cgi");
$form->set_input($in);
$form->add_hidden("zone", $zinfo->{'name'});
local $section = new Webmin::Section($text{'edit_common'}, 4, undef, "100%");
$form->add_section($section);

$section->add_row($text{'edit_name'}, "<tt>$in{'zone'}</tt>");
$section->add_row($text{'edit_status'}, &nice_status($zinfo->{'status'}));
$section->add_row($text{'edit_zonepath'}, "<tt>$zinfo->{'zonepath'}</tt>");
local $auto = new Webmin::Select("autoboot", $zinfo->{'autoboot'},
				 [ [ "true", $text{'yes'} ],
                                   [ "false", $text{'no'} ] ]);
$section->add_input($text{'edit_autoboot'}, $auto);
local $pool = &pool_object("pool", $zinfo->{'pool'});
$section->add_input($text{'edit_pool'}, $pool);

local @actions = &zone_status_actions($zinfo, 1);
$form->add_button(new Webmin::Submit($text{'save'}, "save"));
$form->add_button_spacer();
foreach my $a (@actions) {
	$form->add_button(new Webmin::Submit($a->[1], $a->[0]));
	}
$form->add_button_spacer() if (@actions);
$form->add_button(new Webmin::Submit($text{'edit_delete'}, "delete"));
return $form;
}

sub pool_object
{
local ($name, $value) = @_;
local $rv = new Webmin::OptTextbox($name, $value, 10, $text{'pool_none'});
$rv->set_validation_regexp('^\S+$', $text{'save_epool'});
return $rv;
}

# get_confirm_page(&in, type, &zinfo, from-list)
sub get_confirm_page
{
local ($in, $action, $zinfo, $list) = @_;
local $p = new Webmin::ConfirmPage(&zone_title($zinfo->{'name'}),
		   $text{$action.'_title'},
		   &text($action.'_rusure', "<tt>$zinfo->{'name'}</tt>"),
		   "save_zone.cgi", $in, $text{'edit_'.$action});
if ($list) {
	$p->add_footer("", $text{'index_return'});
	}
else {
	$p->add_footer("edit_zone.cgi?zone=$zinfo->{'name'}",
		       $text{'edit_return'});
	}
return $p;
}

# get_execute_page(action, &zinfo, from-list, action-args)
sub get_execute_page
{
local ($action, $zinfo, $list, $args) = @_;
local $p = new Webmin::Page(&zone_title($zinfo->{'name'}),
			    $text{$action.'_title'});
local $d = new Webmin::DynamicWait(\&execute_action, [ $action, $zinfo, $args ]);
$p->add_form($d);
$d->set_message($text{$action.'_doing'});
$d->set_wait(1);
if ($list || $action eq "delete") {
	$p->add_footer("", $text{'index_return'});
	}
else {
	$p->add_footer("edit_zone.cgi?zone=$zinfo->{'name'}",
		       $text{'edit_return'});
	}
return $p;
}

sub execute_action
{
my ($d, $action, $zinfo, $args) = @_;
sleep(1);
local ($out, $ex);
if ($action eq "delete") {
	# Halt and un-install before deleting
	if ($zinfo->{'status'} ne 'configured') {
		if ($zinfo->{'status'} ne 'installed') {
			($out, $ex) = &run_zone_command($zinfo, "halt");
			}
		if (!$ex) {
			($out, $ex) = &run_zone_command($zinfo, "uninstall -F");
			}
		}
	if (!$ex) {
		&delete_zone($zinfo);
		}
	}
else {
	# Just run zoneadm to execute action
	($out, $ex) = &run_zone_command($zinfo,
				      $action.($args ? " $args" : ""), 1);
	}
$d->stop();
if ($ex) {
	$p->add_error($text{'reboot_failed'}, $out);
	}
else {
	$p->add_message($text{'reboot_ok'});
	if ($action eq "delete") {
		unlink(&zone_sysidcfg_file($zinfo->{'name'}));
		}
	&webmin_log($action, "zone", $zinfo->{'name'});
	}
}

# get_net_form(&in, &zinfo, &net)
sub get_net_form
{
local ($in, $zinfo, $net) = @_;
local ($new, $active, $address, $netmask);
local $form = new Webmin::Form("save_net.cgi", "post");
$form->add_hidden("zone", $zinfo->{'name'});
if ($net->{'address'}) {
	$active = &get_active_interface($net);
	($address, $netmask) = &get_address_netmask($net, undef);
	$form->add_hidden("old", $net->{'address'});
	}
else {
	$net = { 'physical' => &get_default_physical() };
	$new = 1;
	$form->add_hidden("new", 1);
	}
$form->set_input($in);
local $section = new Webmin::Section($text{'net_header'}, 2);
$form->add_section($section);

local $ainput = new Webmin::Textbox("address", $address, 20);
$ainput->set_mandatory(1);
$ainput->set_validation_func(\&validate_address);
$section->add_input($text{'net_address'}, $ainput);

local $pinput = &physical_object("physical", $net->{'physical'});
$section->add_input($text{'net_physical'}, $pinput);

local $ninput = new Webmin::OptTextbox("netmask", $netmask, 20,
				       $text{'default'});
$ninput->set_validation_func(\&validate_netmask);
$section->add_input($text{'net_netmask'}, $ninput);

if ($active) {
	$section->add_row($text{'net_broadcast'},
                          "<tt>$active->{'broadcast'}</tt>");
	}

if ($new) {
	$form->add_button(new Webmin::Submit($text{'create'}, "create"));
	}
else {
	$form->add_button(new Webmin::Submit($text{'save'}, "save"));
	$form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
	}
return $form;
}

# physical_object(name, value)
# Returns an input for selecting a real interface
sub physical_object
{
local ($name, $value) = @_;
return new Webmin::Select($name, $value,
       [ map { [ $_->{'name'} ] } grep { $_->{'virtual'} eq '' }
	     &net::active_interfaces() ], 0, $value ? 1 : 0);
}

sub validate_address
{
return &check_ipaddress($_[0]) ? undef : $text{'net_eaddress'};
}

sub validate_netmask
{
return &check_ipaddress($_[0]) ? undef : $text{'net_enetmask'};
}

# get_pkg_form(&in, &zinfo, &pkg)
sub get_pkg_form
{
local ($in, $zinfo, $pkg) = @_;
local ($new);
local $form = new Webmin::Form("save_pkg.cgi", "post");
$form->set_input($in);
$form->add_hidden("zone", $zinfo->{'name'});
if ($pkg->{'dir'}) {
	$form->add_hidden("old", $pkg->{'dir'});
	}
else {
	$new = 1;
	$form->add_hidden("new", 1);
	}
local $section = new Webmin::Section($text{'pkg_header'}, 2);
$form->add_section($section);

local $dinput = new Webmin::File("dir", $pkg->{'dir'}, 50, 1);
$dinput->set_mandatory(1);
$dinput->set_validation_func(\&validate_dir);
$section->add_input($text{'pkg_dir'}, $dinput);

if ($new) {
	$form->add_button(new Webmin::Submit($text{'create'}, "create"));
	}
else {
	$form->add_button(new Webmin::Submit($text{'save'}, "save"));
	$form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
	}
return $form;
}

sub validate_dir
{
return -d $_[0] ? undef : $text{'pkg_edir'};
}

# get_attr_form(&in, &zinfo, &attr)
sub get_attr_form
{
local ($in, $zinfo, $pkg) = @_;
local ($new);
local $form = new Webmin::Form("save_attr.cgi", "post");
$form->set_input($in);
$form->add_hidden("zone", $zinfo->{'name'});
if ($attr->{'name'}) {
	$form->add_hidden("old", $attr->{'name'});
	}
else {
	$new = 1;
	$form->add_hidden("new", 1);
	}
local $section = new Webmin::Section($text{'attr_header'}, 2);
$form->add_section($section);

local $ninput = new Webmin::Textbox("name", $attr->{'name'}, 30);
$ninput->set_mandatory(1);
$ninput->set_validation_regexp('^\S+$', $text{'attr_ename'});
$section->add_input($text{'attr_name'}, $ninput);

local $tinput = new Webmin::Select("type", $attr->{'type'} || "string",
		       [ map { [ $_, $text{'attr_'.$_} ] }
			     &list_attr_types() ], 0, 1);
$section->add_input($text{'attr_type'}, $tinput);

local $vinput = new Webmin::Textbox("value", $attr->{'value'}, 30);
$vinput->set_validation_func(\&validate_value);
$vinput->set_mandatory(1);
$section->add_input($text{'attr_value'}, $vinput);

if ($new) {
	$form->add_button(new Webmin::Submit($text{'create'}, "create"));
	}
else {
	$form->add_button(new Webmin::Submit($text{'save'}, "save"));
	$form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
	}
return $form;
}

sub validate_value
{
local ($value, $name, $form) = @_;
if ($form->get_value("type") eq 'int') {
	$value =~ /^\-?\d+$/ || return $text{'attr_eint'};
	}
elsif ($form->get_value("type") eq 'uint') {
	$value =~ /^\d+$/ || return $text{'attr_euint'};
	}
elsif ($form->get_value("type") eq 'boolean') {
	$value eq "true" || $value eq "false" ||
		return $text{'attr_uboolean'};
	}
return undef;
}

# get_fs_form(in, &zinfo, &fs, type)
sub get_fs_form
{
local ($in, $zinfo, $fs, $type) = @_;
local ($new, $mount);
local $form = new Webmin::Form("save_fs.cgi", "post");
$form->set_input($in);
$form->add_hidden("zone", $zinfo->{'name'});
if ($fs->{'dir'}) {
	$form->add_hidden("old", $fs->{'dir'});
	$mount = &get_active_mount($zinfo, $fs);
	}
else {
	$new = 1;
	$form->add_hidden("new", 1);
	$form->add_hidden("type", $type);
	}
local $section = new Webmin::Section($text{'fs_header'}, 2);
$form->add_section($section);

$section->add_row($text{'fs_type'},
                  &mount::fstype_name($type)." (".uc($type).")");

if (!$new) {
	if ($mount) {
		($total, $free) = &mount::disk_space($mount->[2], $mount->[0]);
		$section->add_row($text{'fs_status'},
			$total ? &text('fs_mountedsp', &nice_size($total*1024),
						       &nice_size($free*1024)) :
			         $text{'fs_mounted'});
		}
	else {
		$section->add_row($text{'fs_status'}, $text{'fs_unmounted'});
		}
	}
else {
	$section->add_row($text{'fs_mount'},
		      &ui_yesno_radio("mount", $zinfo->{'status'} eq 'running' ?
					       1 : 0));
	}

local $dinput = new Webmin::File("dir", $fs->{'dir'}, 50);
$dinput->set_mandatory(1);
$dinput->set_validation_func(\&validate_fsdir);
$section->add_input($text{'fs_dir'}, $dinput);

if (&indexof($type, &mount::list_fstypes()) >= 0) {
	# A supported filesystem, which means we can show nice options
	local $shtml = 
	    "<table border width=100%><tr><td><table>".
	    &capture_function_output(\&mount::generate_location, $type,
				     $fs->{'special'}).
	    "</table></td></tr></table>";
	$section->add_row($text{'fs_special'}, $shtml);

	&mount::parse_options($type, $fs->{'options'});
	local $ohtml =
	    "<table border width=100%><tr><td><table>".
	    &capture_function_output(\&mount::generate_options, $type,
				     $new ? 1 : 0).
	    "</table></td></tr></table>";
	$section->add_row($text{'fs_options'}, $ohtml);
	}
else {
	# Un-supported, so show just text fields
	local $sinput = new Webmin::Textboc("special", $fs->{'special'}, 40);
	$sinput->set_mandatory(1);
	$sinput->set_validation_func(\&validate_special);
	$section->add_input($text{'fs_special'}, $sinput);

	local $oinput = new Webmin::Textboc("options", $fs->{'options'}, 40);
	$oinput->set_mandatory(1);
	$oinput->set_validation_func(\&validate_options);
	$section->add_input($text{'fs_options'}, $oinput);
	}

if ($new) {
	$form->add_button(new Webmin::Submit($text{'create'}, "create"));
	}
else {
	$form->add_button(new Webmin::Submit($text{'save'}, "save"));
	$form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
	}
return $form;
}

sub validate_fsdir
{
return $_[0] =~ /^\/\S/ ? undef : $text{'fs_edir'};
}

sub validate_special
{
return $_[0] =~ /\S/ ? undef : $text{'fs_especial'};
}

sub validate_options
{
return $_[0] =~ /^\S*$/ ? undef : $text{'fs_eoptions'};
}

# get_rctl_form(&in, &zinfo, &rctl)
sub get_rctl_form
{
local ($in, $zinfo, $rctl) = @_;
local ($new, $mount);
local $form = new Webmin::Form("save_rctl.cgi", "post");
$form->set_input($in);
$form->add_hidden("zone", $zinfo->{'name'});
if ($rctl->{'name'}) {
	$form->add_hidden("old", $rctl->{'name'});
	}
else {
	$new = 1;
	$form->add_hidden("new", 1);
	}
local $section = new Webmin::Section($text{'rctl_header'}, 2);
$form->add_section($section);

local $ninput = new Webmin::Select("name", $rctl->{'name'},
                [ map { [ $_ ] } grep { /^zone\./ } &list_rctls() ],
                0, $in{'new'} ? 0 : 1);
$section->add_input($text{'rctl_name'}, $ninput);

local $table = new Webmin::InputTable([ $text{'rctl_priv'},
				        $text{'rctl_limit'},
				        $text{'rctl_action'} ]);
$form->add_section($table);
local $pinput = new Webmin::Select("priv", undef,
		   [ [ "", "&nbsp;" ],
		     [ "privileged", $text{'rctl_privileged'} ] ]);
local $linput = new Webmin::Textbox("limit", undef, 20);
$linput->set_mandatory(1);
$linput->set_validation_func(\&validate_limit);
local $ainput = new Webmin::Select("action", undef,
			   [ [ "none", $text{'rctl_none'} ],
			     [ "deny", $text{'rctl_deny'} ] ]);
$table->set_inputs([ $pinput, $linput, $ainput ]);
local @values = split(/\0/, $rctl->{'value'});
foreach my $v (@values, "") {
	($priv, $limit, $action) = &get_rctl_value($v);
	($actionn, $actionv) = split(/=/, $action);
	$table->add_values([ $priv, $limit, $actionn ]);
	}
$table->set_emptymsg("No RCTLs defined yet");
$table->set_all_sortable(0);
$table->set_control(0);

if ($new) {
	$form->add_button(new Webmin::Submit($text{'create'}, "create"));
	}
else {
	$form->add_button(new Webmin::Submit($text{'save'}, "save"));
	$form->add_button(new Webmin::Submit($text{'delete'}, "delete"));
	}
return $form;
}

sub validate_limit
{
return $_[0] =~ /^\d+$/ ? undef : $text{'rctl_elimit'};
}

sub get_create_form
{
local ($in) = @_;
local $form = new Webmin::Form("create_zone.cgi", "post");
$form->set_input($in);
local $section = new Webmin::Section($text{'create_header'}, 2);
$form->add_section($section);
&foreign_require("time", "time-lib.pl");

local $name = new Webmin::Textbox("name", undef, 20);
$name->set_mandatory(1);
$name->set_validation_func(\&validate_zone_name);
$section->add_input($text{'edit_name'}, $name);

local $path = new Webmin::OptTextbox("path", undef, 30,
		&text('create_auto', $config{'base_dir'}),
		$text{'create_sel'});
$path->set_validation_func(\&validate_zone_path);
$section->add_input($text{'create_path'}, $path);

local $address = new Webmin::OptTextbox("address", undef, 20,
					$text{'create_noaddress'});
$address->set_validation_func(\&validate_address);
$section->add_input($text{'create_address'}, $address);

local $physical = &physical_object("physical", &get_default_physical());
$section->add_input($text{'net_physical'}, $physical);

local $install = new Webmin::Radios("install", 0, [ [ 1, $text{'yes'} ],
						    [ 0, $text{'no'} ] ]);
$section->add_input($text{'create_install'}, $install);

local $webmin = new Webmin::Radios("webmin", 0, [ [ 1, $text{'yes'} ],
						    [ 0, $text{'no'} ] ]);
$section->add_input($text{'create_webmin'}, $webmin);

local $pkgs = new Webmin::Multiline("pkgs", undef, 5, 50);
$section->add_input($text{'create_pkgs'}, $pkgs);

$section->add_separator();

local $cfg = new Webmin::Radios("cfg", 1, [ [ 1, $text{'create_cfgyes'} ],
                                          [ 0, $text{'create_cfgno'} ] ]);
$section->add_input($text{'create_cfg'}, $cfg);

local $hostname = new Webmin::OptTextbox("hostname", undef, 20,
					 $text{'create_samehost'});
$hostname->set_validation_func(\&validate_zone_hostname);
$section->add_input($text{'create_hostname'}, $hostname);

local $root = new Webmin::OptTextbox("root", undef, 20,
					 $text{'create_same'});
$section->add_input($text{'create_root'}, $root);

local $currtz = &time::get_current_timezone();
local $timezone = new Webmin::OptTextbox("timezone", undef, 25,
					 &text('create_same2', $currtz));
$timezone->set_validation_func(\&validate_zone_timezone);
$section->add_input($text{'create_timezone'}, $timezone);

local $currlc = &get_global_locale();
local $locale = new Webmin::OptTextbox("locale", undef, 25,
					 &text('create_same2', $currlc));
$locale->set_validation_func(\&validate_zone_locale);
$section->add_input($text{'create_locale'}, $locale);

local $terminal = new Webmin::OptTextbox("terminal", undef, 25,
					 $text{'create_vt100'});
$terminal->set_validation_func(\&validate_zone_terminal);
$section->add_input($text{'create_terminal'}, $terminal);

local $dns = &net::get_dns_config();
local ($resolv) = grep { $_ ne "files" } split(/\s+/, $dns->{'order'});
$resolv ||= "none";
local $rinput = new Webmin::Radios("resolv", $resolv,
				  [ [ "none", $text{'create_none'} ],
                                    [ "dns", $text{'create_dns'} ],
                                    [ "nis", $text{'create_nis'} ],
                                    [ "nis+", $text{'create_nis+'} ] ]);
$section->add_input($text{'create_name'}, $rinput);

local $domain = $resolv eq "dns" ? $dns->{'domain'}->[0] :
	  $resolv eq "nis" || $resolv eq "nis+" ? &net::get_domainname()
						: undef;
local $dinput = new Webmin::Textbox("domain", $domain, 20);
$dinput->set_validation_func(\&validate_zone_domain);
$dinput->set_disable_code("form.resolv[0].checked");
$section->add_input($text{'create_domain'}, $dinput);

local (@servers, $server);
if ($resolv eq "dns") {
	@servers = map { gethostbyaddr(inet_aton($_), AF_INET) || $_ }
			 @{$dns->{'nameserver'}};
	$server = join(" ", @servers);
	}
elsif ($resolv eq "nis" || $resolv eq "nis+") {
	$server = `ypwhich`;
	chop($server);
	}
local $server = new Webmin::Textbox("server", $server, 40);
$server->set_validation_func(\&validate_zone_server);
$server->set_disable_code("form.resolv[0].checked");
$section->add_input($text{'create_server'}, $server);

local ($router) = &net::get_default_gateway();
if (!$router) {
	# Use active settings
	foreach my $r (&net::list_routes()) {
		$router = $r->{'gateway'} if ($r->{'dest'} eq '0.0.0.0');
		}
	}
local $rinput = new Webmin::OptTextbox("router", $router, 20,
				       $text{'create_none'});
$rinput->set_validation_func(\&validate_zone_router);
$section->add_input($text{'create_router'}, $rinput);

$form->add_button(new Webmin::Submit($text{'create_ok'}));
return $form;
}

sub validate_zone_name
{
return $text{'create_ename'} if ($_[0] !~ /^[a-z0-9\.\-\_]+$/i);
my ($clash) = grep { $_->{'name'} eq $in{'name'} } &list_zones();
return $text{'create_eclash'} if ($clash);
return undef;
}

sub validate_zone_root
{
return $_[0] =~ /^\// ? undef : $text{'create_epath'};
}

sub validate_zone_pkgs
{
my @pkgs = split(/[\r\n]+/, $in{'pkgs'});
foreach my $p (@pkgs) {
        $p =~ /^\/\S/ || return &text('create_epkg', $p);
        }
return undef;
}

sub validate_zone_hostname
{
return $_[0] =~ /^[a-z0-9\.\-\_]+$/ ? undef : $text{'create_ehostname'};
}

sub validate_zone_timezone
{
return $_[0] =~ /^\S+$/ ? undef : $text{'create_etimezone'};
}

sub validate_zone_locale
{
return $_[0] =~ /^\S+$/ ? undef : $text{'create_elocale'};
}

sub validate_zone_domain
{
return undef if ($_[2]->get_value("resolv") eq "none");
return $_[0] =~ /^[a-z0-9\.\-\_]+$/ ? undef : $text{'create_edomain'};
}

sub validate_zone_server
{
return undef if ($_[2]->get_value("resolv") eq "none");
local @servers = split(/\s+/, $in{'server'});
foreach my $n (@servers) {
	return &text('create_eserver', $n) if (!&to_ipaddress($n));
	}
return @servers ? undef : $text{'create_eservers'};
}

sub validate_zone_router
{
return &check_ipaddress($_[0]) ? undef : $text{'create_erouter'};
}

