diff --git a/apache/apache-lib.pl b/apache/apache-lib.pl index ab7529b2c..35812222d 100755 --- a/apache/apache-lib.pl +++ b/apache/apache-lib.pl @@ -436,6 +436,13 @@ foreach $v (@virt) { return \@get_config_cache; } +# flush_config_cache() +# Delete all in-memory config caches +sub flush_config_cache +{ +undef(@get_config_cache); +} + # get_config_file(filename, [&seen-files]) # Returns a list of config hash refs from some file sub get_config_file @@ -788,6 +795,427 @@ unlink($file); &delete_webfile_link($file); } +# can_manage_vhost_files() +# Returns 1 if this system uses Debian-style available/enabled site dirs +sub can_manage_vhost_files +{ +return 0 if ($gconfig{'os_type'} ne 'debian-linux'); +my $avail = &vhost_available_dir(); +my $enabled = &vhost_enabled_dir(); +return $avail && -d $avail && $enabled && -d $enabled && + &simplify_path(&resolve_links($avail)) ne + &simplify_path(&resolve_links($enabled)); +} + +# vhost_available_dir() +# Returns the configured directory of available Apache virtual host files +sub vhost_available_dir +{ +return $config{'virt_file'} ? &server_root($config{'virt_file'}) : undef; +} + +# vhost_enabled_dir() +# Returns the configured directory of enabled Apache virtual host symlinks +sub vhost_enabled_dir +{ +return $config{'link_dir'} ? &server_root($config{'link_dir'}) : undef; +} + +# get_vhost_available_files() +# Returns real config files from the directory used for new virtual hosts +sub get_vhost_available_files +{ +my @rv; +return @rv if (!&can_manage_vhost_files()); +my $avail = &vhost_available_dir(); +opendir(AVAIL, $avail) || return @rv; +foreach my $f (sort { lc($a) cmp lc($b) } readdir(AVAIL)) { + next if ($f eq "." || $f eq ".."); + my $file = $avail."/".$f; + my $rfile = &simplify_path(&resolve_links($file)); + next if (!$rfile || !-f $rfile || !-r $rfile); + push(@rv, $rfile); + } +closedir(AVAIL); +return &unique(@rv); +} + +# find_virtuals_in_file(file) +# Returns VirtualHost blocks parsed from one config file +sub find_virtuals_in_file +{ +my ($file) = @_; +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +return ( ) if (!-r $rfile); +my @conf = &get_config_file($rfile); +return grep { $_->{'file'} eq $rfile } + &find_directive_struct("VirtualHost", \@conf); +} + +# is_default_vhost(&virt) +# Returns 1 if a VirtualHost looks like a default/catch-all host +sub is_default_vhost +{ +my ($virt) = @_; +return 1 if (!$virt); +return 1 if ($virt->{'value'} =~ /_default_/i); +return 1 if (!&find_directive("ServerName", $virt->{'members'})); +return 0; +} + +# can_manage_vhost_file(file) +# Returns 1 if all virtual hosts in a file are manageable by this user +sub can_manage_vhost_file +{ +my ($file) = @_; +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +return 0 if (!$rfile || !-f $rfile || !-r $rfile); +my @virts = &find_virtuals_in_file($rfile); +return 0 if (!@virts); +foreach my $virt (@virts) { + return 0 if (&is_default_vhost($virt)); + return 0 if (!&can_edit_virt($virt)); + } +return 1; +} + +# can_manage_vhost_state_file(file) +# Returns 1 if a virtual host file can have its enabled state managed here +sub can_manage_vhost_state_file +{ +my ($file) = @_; +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +return 0 if (!$rfile || !-f $rfile); +my %available = map { $_, 1 } &get_vhost_available_files(); +return 0 if (!$available{$rfile}); +return &can_manage_vhost_file($rfile); +} + +# get_virtual_list_rows(&config) +# Returns row hashes for the virtual-host list, preserving sites-available order +sub get_virtual_list_rows +{ +my ($conf) = @_; +my @active = grep { &can_edit_virt($_) } + &find_directive_struct("VirtualHost", $conf); +if (&can_manage_vhost_files()) { + my @rows; + my %active_by_file; + foreach my $v (@active) { + my $file = &simplify_path(&resolve_links($v->{'file'})); + $file ||= $v->{'file'}; + push(@{$active_by_file{$file}}, $v); + } + my %done_virt; + foreach my $file (&get_vhost_available_files()) { + my @filevirts = @{$active_by_file{$file} || [ ]}; + my $active = @filevirts ? 1 : 0; + if (!@filevirts) { + @filevirts = grep { &can_edit_virt($_) } + &find_virtuals_in_file($file); + } + foreach my $v (@filevirts) { + push(@rows, { 'virt' => $v, + 'active' => $active, + 'file' => $file }); + $done_virt{$v}++; + } + } + foreach my $v (@active) { + next if ($done_virt{$v}); + push(@rows, { 'virt' => $v, + 'active' => 1, + 'file' => $v->{'file'} }); + } + return @rows; + } +return map { { 'virt' => $_, 'active' => 1, 'file' => $_->{'file'} } } + @active; +} + +# vhost_file_link(file) +# Returns the enabled symlink path for a virtual host file +sub vhost_file_link +{ +my ($file) = @_; +return undef if (!&can_manage_vhost_files()); +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +my $avail = &vhost_available_dir(); +my $short; +if (opendir(AVAIL, $avail)) { + foreach my $f (sort { lc($a) cmp lc($b) } readdir(AVAIL)) { + next if ($f eq "." || $f eq ".."); + my $afile = $avail."/".$f; + my $rafile = &simplify_path(&resolve_links($afile)); + if ($rafile && $rafile eq $rfile) { + $short = $f; + last; + } + } + closedir(AVAIL); + } +$short ||= $rfile; +$short =~ s/^.*\///; +return &vhost_enabled_dir()."/".$short; +} + +# vhost_file_links(file) +# Returns enabled symlinks for a virtual host file +sub vhost_file_links +{ +my ($file) = @_; +my @rv; +return @rv if (!&can_manage_vhost_files()); +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +my $enabled = &vhost_enabled_dir(); +opendir(LINKDIR, $enabled) || return @rv; +foreach my $f (readdir(LINKDIR)) { + next if ($f eq "." || $f eq ".."); + my $link = $enabled."/".$f; + next if (!-l $link); + my $rlink = &simplify_path(&resolve_links($link)); + if ($rlink && $rlink eq $rfile) { + push(@rv, $link); + } + } +closedir(LINKDIR); +return @rv; +} + +# vhost_file_enabled(file) +# Returns 1 if a virtual host file has an enabled symlink +sub vhost_file_enabled +{ +my ($file) = @_; +return scalar(&vhost_file_links($file)) ? 1 : 0; +} + +# enable_vhost_file(file) +# Enables a virtual host file and rolls back if apache configtest fails +sub enable_vhost_file +{ +my ($file) = @_; +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +return $text{'enable_efile'} if (!&can_manage_vhost_state_file($rfile)); +my $verr = &virtualmin_vhost_file_state_error($rfile, "enable"); +return $verr if ($verr); +my $link = &vhost_file_link($rfile); +$link || return $text{'enable_elinkdir'}; +return undef if (&vhost_file_enabled($rfile)); +if (-e $link || -l $link) { + return &text('enable_elinkexists', "".&html_escape($link).""); + } +&symlink_logged($rfile, $link) || + return &text('enable_elink', "".&html_escape($link)."", + "".&html_escape($!).""); +my $err = &test_config(); +if ($err) { + &unlink_logged($link); + return &text('enable_etest', "".&html_escape($err).""); + } +&flush_config_cache(); +&update_last_config_change(); +return undef; +} + +# disable_vhost_file(file) +# Disables a virtual host file and rolls back if apache configtest fails +sub disable_vhost_file +{ +my ($file) = @_; +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +return $text{'enable_efile'} if (!&can_manage_vhost_state_file($rfile)); +my $verr = &virtualmin_vhost_file_state_error($rfile, "disable"); +return $verr if ($verr); +my @links = &vhost_file_links($file); +return undef if (!@links); +my @restore = map { [ $_, readlink($_) ] } @links; +my @removed; +foreach my $link (@links) { + if (!&unlink_logged($link)) { + foreach my $r (@removed) { + &symlink_logged($r->[1], $r->[0]) + if (defined($r->[1]) && !-e $r->[0] && !-l $r->[0]); + } + return &text('enable_eunlink', + "".&html_escape($link)."", + "".&html_escape($!).""); + } + my ($restore) = grep { $_->[0] eq $link } @restore; + push(@removed, $restore) if ($restore); + } +my $err = &test_config(); +if ($err) { + foreach my $r (@restore) { + &symlink_logged($r->[1], $r->[0]) + if (defined($r->[1]) && !-e $r->[0] && !-l $r->[0]); + } + return &text('enable_etest', "".&html_escape($err).""); + } +&flush_config_cache(); +&update_last_config_change(); +return undef; +} + +# virtualmin_available() +# Returns 1 if Virtualmin is installed and supported on this system +sub virtualmin_available +{ +return $main::apache_virtualmin_available + if (defined($main::apache_virtualmin_available)); +$main::apache_virtualmin_available = &foreign_check("virtual-server"); +return $main::apache_virtualmin_available; +} + +# virtualmin_domain_by_name(name) +# Returns a Virtualmin domain object by domain name, if one exists +sub virtualmin_domain_by_name +{ +my ($name) = @_; +return undef if (!&virtualmin_available()); +return $main::apache_virtualmin_domain_by_name_cache{$name} + if (exists($main::apache_virtualmin_domain_by_name_cache{$name})); +&foreign_require("virtual-server"); +my $d = &virtual_server::get_domain_by("dom", $name); +$main::apache_virtualmin_domain_by_name_cache{$name} = $d; +return $d; +} + +# virtual_names(&virt) +# Returns all hostnames from ServerName and ServerAlias directives +sub virtual_names +{ +my ($virt) = @_; +my @rv; +my $sn = &find_directive("ServerName", $virt->{'members'}); +push(@rv, $sn) if ($sn); +foreach my $sa (&find_directive_struct("ServerAlias", $virt->{'members'})) { + push(@rv, @{$sa->{'words'} || [ ]}); + if (!@{$sa->{'words'} || [ ]} && $sa->{'value'}) { + push(@rv, $sa->{'value'}); + } + } +return grep { $_ && $_ ne "*" } &unique(@rv); +} + +# virtualmin_domain_for_vhost_file(file) +# Returns the Virtualmin domain object for a virtual host file, if any +sub virtualmin_domain_for_vhost_file +{ +my ($file) = @_; +return undef if (!&virtualmin_available()); +my $rfile = &simplify_path(&resolve_links($file)); +$rfile ||= $file; +return $main::apache_virtualmin_domain_for_file_cache{$rfile} + if (exists($main::apache_virtualmin_domain_for_file_cache{$rfile})); +foreach my $virt (&find_virtuals_in_file($file)) { + next if (!&can_edit_virt($virt)); + foreach my $name (&virtual_names($virt)) { + my $d = &virtualmin_domain_by_name($name); + if (!$d && $name =~ /^www\.(\S+)/i) { + $d = &virtualmin_domain_by_name($1); + } + if ($d) { + $main::apache_virtualmin_domain_for_file_cache{$rfile} = $d; + return $d; + } + } + } +$main::apache_virtualmin_domain_for_file_cache{$rfile} = undef; +return undef; +} + +# vhost_file_state(file) +# Returns the effective enabled state for a virtual host file +sub vhost_file_state +{ +my ($file) = @_; +my $d = &virtualmin_domain_for_vhost_file($file); +if ($d) { + return { 'enabled' => $d->{'disabled'} ? 0 : 1, + 'source' => 'virtualmin', + 'domain' => $d }; + } +return { 'enabled' => &vhost_file_enabled($file) ? 1 : 0, + 'source' => 'apache' }; +} + +# vhost_file_toggle_action(file) +# Returns the action needed to toggle a virtual host file's effective state +sub vhost_file_toggle_action +{ +my ($file) = @_; +return &vhost_file_state($file)->{'enabled'} ? "disable" : "enable"; +} + +# virtualmin_domain_state_link(&domain, enabled?) +# Returns a link to the Virtualmin state change form for some domain +sub virtualmin_domain_state_link +{ +my ($d, $enabled) = @_; +my $page = $enabled ? "disable_domain.cgi" : "enable_domain.cgi"; +my $label = $enabled ? $text{'enable_virtualmin_disable_label'} : + $text{'enable_virtualmin_enable_label'}; +my $url = "../virtual-server/".$page."?dom=".&urlize($d->{'id'}); +return &ui_link("e_escape($url), "\"".$label."\""); +} + +# virtualmin_vhost_file_state_error(file, action) +# Returns an error if a Virtualmin-owned site is being enabled or disabled here +sub virtualmin_vhost_file_state_error +{ +my ($file, $action) = @_; +return undef if ($action ne "enable" && $action ne "disable"); +my $state_info = &vhost_file_state($file); +return undef if ($state_info->{'source'} ne "virtualmin"); +my $d = $state_info->{'domain'}; +return undef if (!$d); +my $state = lc($state_info->{'enabled'} ? $text{'index_enabled'} : + $text{'index_disabled'}); +my $dom = "".&html_escape($d->{'dom'}).""; +my $link = &virtualmin_domain_state_link($d, $state_info->{'enabled'}); +return $state_info->{'enabled'} ? + &text('enable_evirtualmin_disable', $dom, $state, $link) : + &text('enable_evirtualmin_enable', $dom, $state, $link); +} + +# delete_virtuals_from_file(file, &virtualhosts...) +# Deletes VirtualHost blocks from one file and removes the file if empty +sub delete_virtuals_from_file +{ +my ($file, @virts) = @_; +return 0 if (!@virts); +my $lref = &read_file_lines($file); +foreach my $virt (sort { $b->{'line'} <=> $a->{'line'} } @virts) { + my $len = $virt->{'eline'} - $virt->{'line'} + 1; + splice(@$lref, $virt->{'line'}, $len); + } +my $empty = 1; +foreach my $line (@$lref) { + if ($line =~ /\S/) { + $empty = 0; + last; + } + } +&flush_file_lines($file); +if ($empty) { + foreach my $link (&vhost_file_links($file)) { + &unlink_logged($link); + } + &unlink_logged($file); + } +&flush_config_cache(); +&update_last_config_change(); +return scalar(@virts); +} + # renumber(&config, line, file, offset) # Recursively changes the line number of all directives from some file # beyond the given line. @@ -1985,16 +2413,16 @@ if ($config{'link_dir'}) { sub delete_webfile_link { local ($file) = @_; +$file = &simplify_path(&resolve_links($file)); if ($config{'link_dir'}) { - local $short = $file; - $short =~ s/^.*\///; opendir(LINKDIR, $config{'link_dir'}); foreach my $f (readdir(LINKDIR)) { - if ($f ne "." && $f ne ".." && - (&simplify_path( - &resolve_links($config{'link_dir'}."/".$f)) eq $file || - $short eq $f)) { - &unlink_logged($config{'link_dir'}."/".$f); + if ($f ne "." && $f ne "..") { + my $link = $config{'link_dir'}."/".$f; + next if (!-l $link); + if (&simplify_path(&resolve_links($link)) eq $file) { + &unlink_logged($link); + } } } closedir(LINKDIR); diff --git a/apache/delete_vservs.cgi b/apache/delete_vservs.cgi index c5901f6d5..19a035b78 100755 --- a/apache/delete_vservs.cgi +++ b/apache/delete_vservs.cgi @@ -3,19 +3,90 @@ require './apache-lib.pl'; &ReadParse(); -&error_setup($text{'delete_err'}); +@d = split(/\0/, $in{'d'}); +$file_action = $in{'toggle'} ? "toggle" : undef; +&error_setup($file_action ? $text{'enable_err'} : $text{'delete_err'}); $access{'vaddr'} || &error($text{'delete_ecannot'}); $conf = &get_config(); -@d = split(/\0/, $in{'d'}); +$can_vhost_files = &can_manage_vhost_files(); @d || &error($text{'delete_enone'}); +if ($file_action) { + &can_manage_vhost_files() || &error($text{'enable_elinkdir'}); + foreach $d (@d) { + if ($d =~ /^file\t([^\t]+)/) { + $file = $1; + } + elsif ($d !~ /^file\t/) { + ($vmembers, $vconf) = &get_virtual_config($d); + next if (!$vconf || !&can_edit_virt($vconf)); + $file = $vconf->{'file'}; + } + else { + next; + } + $rfile = $file ? &simplify_path(&resolve_links($file)) : undef; + $files{$rfile}++ if ($rfile && -f $rfile && + &can_manage_vhost_state_file($rfile)); + } + @files = keys %files; + @files || &error($text{'enable_enone'}); + foreach $file (@files) { + $action = &vhost_file_toggle_action($file); + $err = &virtualmin_vhost_file_state_error($file, $action); + $err && &error($err); + $file_actions{$file} = $action; + } + foreach $file (@files) { + $err = $file_actions{$file} eq "enable" ? + &enable_vhost_file($file) : + &disable_vhost_file($file); + $err && &error($err); + } + &webmin_log($file_action, "vhostfile", scalar(@files)); + &redirect(""); + exit; + } +if (!$in{'delete'}) { + &error($text{'delete_eaction'}); + } + # Get them all foreach $d (@d) { + if ($d =~ /^file\t([^\t]+)\t(\d+)$/) { + push(@{$file_lines{$1}}, $2); + next; + } + elsif ($d =~ /^file\t/) { + next; + } ($vmembers, $vconf) = &get_virtual_config($d); + $vconf || &error($text{'delete_egone'}); &can_edit_virt($vconf) || &error(&text('delete_ecannot2', &virtual_name($vconf))); + $can_vhost_files && &is_default_vhost($vconf) && + &error($text{'delete_edefault'}); push(@virts, $vconf); } +if (%file_lines) { + foreach $file (keys %file_lines) { + $rfile = &simplify_path(&resolve_links($file)); + next if (!$rfile || !-f $rfile || + !&can_manage_vhost_state_file($rfile)); + @fvirts = &find_virtuals_in_file($rfile); + foreach $line (@{$file_lines{$file}}) { + ($vconf) = grep { $_->{'line'} == $line } @fvirts; + $vconf || &error($text{'delete_egone'}); + &can_edit_virt($vconf) || + &error(&text('delete_ecannot2', + &virtual_name($vconf))); + &is_default_vhost($vconf) && + &error($text{'delete_edefault'}); + push(@{$file_virts{$rfile}}, $vconf); + } + } + } +@virts || %file_virts || &error($text{'delete_enone'}); # Delete their structures &before_changing(); @@ -28,6 +99,11 @@ foreach $vconf (@virts) { &unlock_all_files(); &update_last_config_change(); &after_changing(); -&webmin_log("virts", "delete", scalar(@virts)); +foreach $file (keys %file_virts) { + &lock_file($file); + $deleted += &delete_virtuals_from_file($file, @{$file_virts{$file}}); + &unlock_file($file); + } +$deleted += scalar(@virts); +&webmin_log("virts", "delete", $deleted); &redirect(""); - diff --git a/apache/index.cgi b/apache/index.cgi index e5c896e89..f0ccc7efe 100755 --- a/apache/index.cgi +++ b/apache/index.cgi @@ -102,6 +102,10 @@ if (&can_edit_virt()) { push(@vproxy, undef); $sn ||= &get_system_hostname(); push(@vurl, $defport ? "http://$sn:$defport/" : "http://$sn/"); + push(@vfile, undef); + push(@vstatus, ""); + push(@vsel, undef); + push(@vfilemanage, 0); $showing_default++; } @@ -128,16 +132,23 @@ elsif ($httpd_modules{'core'} >= 1.2) { $ba = &find_directive("ServerName", $conf); $nv{&to_ipaddress($ba ? $ba : &get_system_hostname())}++; } -@virt = grep { &can_edit_virt($_) } @virt; +$can_vhost_files = &can_manage_vhost_files(); +@vrows = &get_virtual_list_rows($conf); if ($config{'show_order'} == 1) { # sort by server name - @virt = sort { &server_name_sort($a) cmp &server_name_sort($b) } @virt; + @vrows = sort { &server_name_sort($a->{'virt'}) cmp + &server_name_sort($b->{'virt'}) } @vrows; } elsif ($config{'show_order'} == 2) { # sort by IP address - @virt = sort { &server_ip_sort($a) cmp &server_ip_sort($b) } @virt; + @vrows = sort { &server_ip_sort($a->{'virt'}) cmp + &server_ip_sort($b->{'virt'}) } @vrows; } -foreach $v (@virt) { +@virt = map { $_->{'virt'} } grep { $_->{'active'} } @vrows; +%available_vhost_file = map { $_, 1 } &get_vhost_available_files() + if ($can_vhost_files); +foreach $r (@vrows) { + $v = $r->{'virt'}; $vm = $v->{'members'}; if ($v->{'words'}->[0] =~ /^\[(\S+)\]:(\d+)$/) { # IPv6 address and port @@ -163,7 +174,7 @@ foreach $v (@virt) { $idx = &indexof($v, @$conf); push(@vidx, $idx); push(@vname, $text{'index_virt'}); - push(@vlink, "virt_index.cgi?virt=$idx"); + push(@vlink, $r->{'active'} ? "virt_index.cgi?virt=$idx" : undef); $sname = &find_directive("ServerName", $vm); local $daddr = $addr eq "_default_" || ($addr eq "*" && $httpd_modules{'core'} < 1.2); @@ -225,10 +236,34 @@ foreach $v (@virt) { } $sp = undef if ($sp == 80 && $prot eq "http" || $sp == 443 && $prot eq "https"); - push(@vurl, $sp ? "$prot://$sn:$sp/" : "$prot://$sn/"); + push(@vurl, $r->{'active'} ? + ($sp ? "$prot://$sn:$sp/" : "$prot://$sn/") : undef); + local $rfile = $r->{'file'} ? &simplify_path(&resolve_links($r->{'file'})) + : undef; + push(@vfile, $rfile); + local $status = ""; + if ($can_vhost_files && $rfile && $available_vhost_file{$rfile}) { + local $enabled = &vhost_file_state($rfile)->{'enabled'}; + $status = $enabled ? $text{'index_enabled'} : + $text{'index_disabled'}; + } + push(@vstatus, $status); + local $file_manage = $can_vhost_files && $rfile && + $available_vhost_file{$rfile} && + &can_manage_vhost_state_file($rfile); + push(@vfilemanage, $file_manage ? 1 : 0); + local $sel; + if ($r->{'active'} && (!$can_vhost_files || !&is_default_vhost($v))) { + $sel = $idx; + } + elsif (!$r->{'active'} && $can_vhost_files && $rfile && + $available_vhost_file{$rfile} && $file_manage) { + $sel = "file\t".$rfile."\t".$v->{'line'}; + } + push(@vsel, $sel); } -if (@vlink == 1 && !$access{'global'} && $access{'virts'} ne "*" && +if (@vlink == 1 && $vlink[0] && !$access{'global'} && $access{'virts'} ne "*" && !$access{'create'} && $access{'noconfig'}) { # Can only manage one vhost, so go direct to it &redirect($vlink[0]); @@ -297,7 +332,9 @@ if ($access{'global'}) { # work out select links print &ui_tabs_start_tab("mode", "list"); #print $text{'index_desclist'},"
\n"; -$showdel = $access{'vaddr'} && ($vidx[0] || $vidx[1]); +$showdel = $access{'vaddr'} && + grep { defined($_) && $_ ne "" } @vsel; +$showtoggle = $can_vhost_files && grep { $_ } @vfilemanage; @links = ( ); if ($showdel) { push(@links, &select_all_link("d"), @@ -326,8 +363,10 @@ if ($config{'max_servers'} && @vname > $config{'max_servers'}) { } elsif ($config{'show_list'} && scalar(@vname)) { # as list for people with lots of servers + $list_form = "vhosts_form"; if ($showdel) { - print &ui_form_start("delete_vservs.cgi", "post"); + print &ui_form_start("delete_vservs.cgi", "post", undef, + "id='$list_form'"); } print &ui_links_row(\@links); print &ui_columns_start([ @@ -337,19 +376,23 @@ elsif ($config{'show_list'} && scalar(@vname)) { $text{'index_port'}, $text{'index_name'}, $text{'index_root'}, + $can_vhost_files ? ( $text{'index_status'} ) : ( ), $text{'index_url'} ], 100); for($i=0; $i<@vname; $i++) { local @cols; - push(@cols, &ui_link($vlink[$i], $vname[$i]) ); + push(@cols, $vlink[$i] ? &ui_link($vlink[$i], $vname[$i]) : + $vname[$i] ); push(@cols, &html_escape($vaddr[$i])); push(@cols, &html_escape($vport[$i])); push(@cols, $vserv[$i] || $text{'index_auto'}); push(@cols, &html_escape($vproxy[$i]) || &html_escape($vroot[$i])); - push(@cols, &ui_link($vurl[$i], $text{'index_view'}) ); - if ($showdel && $vidx[$i]) { + push(@cols, $vstatus[$i]) if ($can_vhost_files); + push(@cols, $vurl[$i] ? &ui_link($vurl[$i], $text{'index_view'}) : + "" ); + if ($showdel && defined($vsel[$i]) && $vsel[$i] ne "") { print &ui_checked_columns_row(\@cols, undef, - "d", $vidx[$i]); + "d", $vsel[$i]); } elsif ($showdel) { print &ui_columns_row([ "", @cols ]); @@ -361,13 +404,23 @@ elsif ($config{'show_list'} && scalar(@vname)) { print &ui_columns_end(); print &ui_links_row(\@links); if ($showdel) { - print &ui_form_end([ [ "delete", $text{'index_delete'} ] ]); + if ($showtoggle) { + print &ui_form_end_side_by_side($list_form, + [ [ "delete", $text{'index_delete'} ] ], + [ [ "toggle", $text{'index_toggle'}, undef, + undef, "form=\"$list_form\"" ] ]); + } + else { + print &ui_form_end([ [ "delete", $text{'index_delete'} ] ]); + } } } else { # as icons for niceness + $list_form = "vhosts_form"; if ($showdel) { - print &ui_form_start("delete_vservs.cgi", "post"); + print &ui_form_start("delete_vservs.cgi", "post", undef, + "id='$list_form'"); } print &ui_links_row(\@links); print "
| \n";
print "$vdesc[$i] \n"; @@ -397,12 +451,24 @@ else { print "$text{'index_root'} ", &html_escape($vroot[$i])," | \n";
}
+ if ($can_vhost_files && $vstatus[$i]) {
+ print "|
| $text{'index_status'} ", + $vstatus[$i]," |