Fixed a bug that causes hosts to be deleted when searching for them!
---- Changes since 1.410 ----
Clashes between hosts with the same IP address, MAC address or hostname are no longer allowed by default - but this can be changed on the DHCP Server access control page in the Webmin User's module.
+---- Changes since 1.420 ----
+Support the new configuration file format for custom options, as used in DHCPd version 3.
$text{'eopt_slpsonly'});
print "</tr>\n";
-# Show custom options
-print "<tr> <td colspan=4><hr></td> </tr>\n";
-@custom = grep { $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
- $_->{'values'}->[1] ne 'code' } @opts;
-push(@custom, undef);
-push(@custom, undef) if (@custom%2 == 1);
-for($i=0; $i<@custom; $i++) {
- $o = $custom[$i];
- print "<tr>\n" if ($i%2 == 0);
- print "<td><b>$text{'eopt_custom'}</b></td>\n";
- print "<td nowrap>$text{'eopt_cnum'}\n";
- local ($ov, @v) = @{$o->{'values'}};
- printf "<input name=cnum_$i size=4 value='%s'>\n",
- $ov =~ /^option-(\S+)$/ ? $1 : '';
- print "$text{'eopt_cval'}\n";
- printf "<input name=cval_$i size=15 value='%s'></td>\n",
- join(" ", @v);
- print "</tr>\n" if ($i%2 != 0);
- }
-
if ($config{'dhcpd_version'} >= 3) {
# Show option definitions
print "<tr> <td colspan=4><hr></td> </tr>\n";
@defs = grep { $_->{'values'}->[1] eq 'code' &&
$_->{'values'}->[3] eq '=' } @opts;
push(@defs, undef);
+ %optdef = ( );
for($i=0; $i<@defs; $i++) {
$o = $defs[$i];
print "<tr>\n";
printf "<input name=dtype_$i size=10 value='%s'>\n",
$o->{'values'}->[4];
print "</td> </tr>\n";
+ $optdef{$o->{'values'}->[0]} = $o if ($o->{'values'}->[0]);
+ }
+
+ # Show values for custom options
+ if (keys %optdef) {
+ @custom = grep { $optdef{$_->{'values'}->[0]} &&
+ $_->{'values'}->[1] ne 'code' } @opts;
+ push(@custom, undef);
+ push(@custom, undef) if (@custom%2 == 1);
+ for($i=0; $i<@custom; $i++) {
+ $o = $custom[$i];
+ print "<tr> <td><b>$text{'eopt_custom'}</b></td>\n";
+ print "<td nowrap colspan=3>$text{'eopt_cname'}\n";
+ local ($ov, @v) = @{$o->{'values'}};
+ print &ui_select("cname_$i", $ov,
+ [ [ "", " " ],
+ sort { $a cmp $b } keys %optdef ],
+ 1, 0, $ov ? 1 : 0);
+ print "$text{'eopt_cval'}\n";
+ print &ui_textbox("cval_$i", join(" ", @v), 40);
+ print "</td> </tr>\n";
+ }
+ }
+ }
+else {
+ # Show custom numeric options
+ print "<tr> <td colspan=4><hr></td> </tr>\n";
+ @custom = grep { $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
+ $_->{'values'}->[1] ne 'code' } @opts;
+ push(@custom, undef);
+ push(@custom, undef) if (@custom%2 == 1);
+ for($i=0; $i<@custom; $i++) {
+ $o = $custom[$i];
+ print "<tr>\n" if ($i%2 == 0);
+ print "<td><b>$text{'eopt_custom'}</b></td>\n";
+ print "<td nowrap>$text{'eopt_cnum'}\n";
+ local ($ov, @v) = @{$o->{'values'}};
+ printf "<input name=cnum_$i size=4 value='%s'>\n",
+ $ov =~ /^option-(\S+)$/ ? $1 : '';
+ print "$text{'eopt_cval'}\n";
+ printf "<input name=cval_$i size=15 value='%s'></td>\n",
+ join(" ", @v);
+ print "</tr>\n" if ($i%2 != 0);
}
}
sopt_edname='$1' is not a valid option name
sopt_ednum='$1' is not a valid option number
sopt_edtype='$1' is not a valid option type
+sopt_ecval=Missing value for custom option '$1'
sshared_faildel=Failed to delete shared network
sshared_failsave=Failed to save shared network
eopt_toffset=Time offset
eopt_custom=Custom option
eopt_cnum=Number
+eopt_cname=Name
eopt_cval=Value
eopt_def=Option definition
eopt_dname=Option name
$ret="edit_shared.cgi?idx=$in{'idx'}";
}
-# save custom options
-@custom = grep { $_->{'name'} eq 'option' &&
- $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
- $_->{'values'}->[1] ne 'code' }
- @{$client->{'members'}};
-for($i=0; defined($in{"cnum_$i"}); $i++) {
- next if (!$in{"cnum_$i"} || !$in{"cval_$i"});
- $in{"cnum_$i"} =~ /^\d+$/ ||
- ($config{'dhcpd_version'} >= 3 && $in{"cnum_$i"} =~ /^\S+$/) ||
- &error(&text('sopt_ednum', $in{"cnum_$i"}));
- local $cv = $in{"cval_$i"};
- $cv = "\"$cv\"" if ($cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/);
- push(@newcustom, { 'name' => 'option',
- 'values' => [ 'option-'.$in{"cnum_$i"},
- $cv ] } );
- }
-&save_directive($client, \@custom, \@newcustom, $indent, 1);
-
if ($config{'dhcpd_version'} >= 3) {
- # save option definitions
+ # Save option definitions
@defs = grep { $_->{'name'} eq 'option' &&
$_->{'values'}->[1] eq 'code' &&
$_->{'values'}->[3] eq '=' }
@{$client->{'members'}};
+ %optdef = map { $_->{'values'}->[0], $_ } @defs;
for($i=0; defined($in{"dname_$i"}); $i++) {
next if (!$in{"dname_$i"} || !$in{"dnum_$i"} ||
!$in{"dtype_$i"});
] } );
}
&save_directive($client, \@defs, \@newdefs, $indent, 1);
+
+ # Save custom options
+ @custom = grep { $_->{'name'} eq 'option' &&
+ $optdef{$_->{'values'}->[0]} &&
+ $_->{'values'}->[1] ne 'code' }
+ @{$client->{'members'}};
+ for($i=0; defined($in{"cname_$i"}); $i++) {
+ next if ($in{"cname_$i"} eq "");
+ local $cv = $in{"cval_$i"};
+ $cv =~ /\S/ || &error(&text('sopt_ecval', $in{"cname_$i"}));
+ $cv = "\"$cv\""
+ if ($cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/);
+ push(@newcustom, { 'name' => 'option',
+ 'values' => [ $in{"cname_$i"}, $cv ] } );
+ }
+ &save_directive($client, \@custom, \@newcustom, $indent, 1);
+ }
+else {
+ # Save custom options
+ @custom = grep { $_->{'name'} eq 'option' &&
+ $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
+ $_->{'values'}->[1] ne 'code' }
+ @{$client->{'members'}};
+ for($i=0; defined($in{"cnum_$i"}); $i++) {
+ next if (!$in{"cnum_$i"} || !$in{"cval_$i"});
+ $in{"cnum_$i"} =~ /^\d+$/ ||
+ ($config{'dhcpd_version'} >= 3 &&
+ $in{"cnum_$i"} =~ /^\S+$/) ||
+ &error(&text('sopt_ednum', $in{"cnum_$i"}));
+ local $cv = $in{"cval_$i"};
+ $cv = "\"$cv\""
+ if ($cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/);
+ push(@newcustom, { 'name' => 'option',
+ 'values' => [ 'option-'.$in{"cnum_$i"},
+ $cv ] } );
+ }
+ &save_directive($client, \@custom, \@newcustom, $indent, 1);
}
&flush_file_lines();