]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - html/cgi-bin/dhcp.cgi
rootfiles: replace x86_64 with MACHINE
[people/pmueller/ipfire-2.x.git] / html / cgi-bin / dhcp.cgi
CommitLineData
ac1cfefa 1#!/usr/bin/perl
70df8302
MT
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2007 Michael Tremer & Christian Schmidt #
6# #
7# This program is free software: you can redistribute it and/or modify #
8# it under the terms of the GNU General Public License as published by #
9# the Free Software Foundation, either version 3 of the License, or #
10# (at your option) any later version. #
11# #
12# This program is distributed in the hope that it will be useful, #
13# but WITHOUT ANY WARRANTY; without even the implied warranty of #
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15# GNU General Public License for more details. #
16# #
17# You should have received a copy of the GNU General Public License #
18# along with this program. If not, see <http://www.gnu.org/licenses/>. #
19# #
20###############################################################################
21
ac1cfefa 22use strict;
5653e551 23use ecperimental 'smartmatch';
ac1cfefa
MT
24
25# enable only the following on debugging purpose
cb5e9c6c
CS
26#use warnings;
27#use CGI::Carp 'fatalsToBrowser';
ac1cfefa 28
986e08d9 29require '/var/ipfire/general-functions.pl';
ac1cfefa
MT
30require "${General::swroot}/lang.pl";
31require "${General::swroot}/header.pl";
32#workaround to suppress a warning when a variable is used only once
33my @dummy = ( ${Header::colouryellow} );
34undef (@dummy);
35
36our %dhcpsettings=();
37our %netsettings=();
38my %mainsettings=();
39my %timesettings=();
40my $setting = "${General::swroot}/dhcp/settings";
41our $filename1 = "${General::swroot}/dhcp/advoptions"; # Field separator is TAB in this file (comma is standart)
d1883e28 42 # because we need commas in the some data
ac1cfefa 43our $filename2 = "${General::swroot}/dhcp/fixleases";
d1883e28 44our $filename3 = "${General::swroot}/dhcp/advoptions-list"; # Describe the allowed syntax for dhcp options
ac1cfefa
MT
45my $errormessage = '';
46my $warnNTPmessage = '';
47my @nosaved=();
fe6cda92 48my %color = ();
ac1cfefa
MT
49
50#Basic syntax allowed for new Option definition. Not implemented: RECORDS & array of RECORDS
51our $OptionTypes = 'boolean|((un)?signed )?integer (8|16|32)|ip-address|text|string|encapsulate \w+|array of ip-address';
52
53&Header::showhttpheaders();
541d93f0
CS
54our @ITFs=('GREEN');
55if (&Header::blue_used()){push(@ITFs,'BLUE');}
ac1cfefa
MT
56
57#Settings1 for the first screen box
58foreach my $itf (@ITFs) {
59 $dhcpsettings{"ENABLE_${itf}"} = 'off';
60 $dhcpsettings{"ENABLEBOOTP_${itf}"} = 'off';
61 $dhcpsettings{"START_ADDR_${itf}"} = '';
62 $dhcpsettings{"END_ADDR_${itf}"} = '';
63 $dhcpsettings{"DOMAIN_NAME_${itf}"} = '';
64 $dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} = '';
65 $dhcpsettings{"MAX_LEASE_TIME_${itf}"} = '';
66 $dhcpsettings{"WINS1_${itf}"} = '';
67 $dhcpsettings{"WINS2_${itf}"} = '';
68 $dhcpsettings{"DNS1_${itf}"} = '';
69 $dhcpsettings{"DNS2_${itf}"} = '';
70 $dhcpsettings{"NTP1_${itf}"} = '';
71 $dhcpsettings{"NTP2_${itf}"} = '';
d1883e28
MT
72 $dhcpsettings{"NEXT_${itf}"} = '';
73 $dhcpsettings{"FILE_${itf}"} = '';
f5fb9a04
MT
74 $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} = '';
75 $dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"} = '';
76 $dhcpsettings{"DNS_UPDATE_KEY_ALGO_${itf}"} = '';
ac1cfefa
MT
77}
78
79$dhcpsettings{'SORT_FLEASELIST'} = 'FIPADDR';
80$dhcpsettings{'SORT_LEASELIST'} = 'IPADDR';
81
f5fb9a04
MT
82# DNS Update settings
83$dhcpsettings{'DNS_UPDATE_ENABLED'} = 'off';
84
ac1cfefa
MT
85#Settings2 for editing the multi-line list
86#Must not be saved with writehash !
87$dhcpsettings{'FIX_MAC'} = '';
88$dhcpsettings{'FIX_ADDR'} = '';
89$dhcpsettings{'FIX_ENABLED'} = 'off';
90$dhcpsettings{'FIX_NEXTADDR'} = '';
91$dhcpsettings{'FIX_FILENAME'} = '';
92$dhcpsettings{'FIX_ROOTPATH'} = '';
93$dhcpsettings{'FIX_REMARK'} = '';
94$dhcpsettings{'ACTION'} = '';
95$dhcpsettings{'KEY1'} = '';
96$dhcpsettings{'KEY2'} = '';
97@nosaved=('FIX_MAC','FIX_ADDR','FIX_ENABLED','FIX_NEXTADDR',
98 'FIX_FILENAME','FIX_ROOTPATH','FIX_REMARK');
99
100$dhcpsettings{'ADVOPT_ENABLED'} = '';
101$dhcpsettings{'ADVOPT_NAME'} = '';
102$dhcpsettings{'ADVOPT_DATA'} = '';
103unshift (@nosaved,'ADVOPT_ENABLED','ADVOPT_NAME','ADVOPT_DATA');
104foreach my $itf (@ITFs) {
105 $dhcpsettings{"ADVOPT_SCOPE_${itf}"} = 'off';
106 unshift (@nosaved, "ADVOPT_SCOPE_${itf}");
107}
108
109# Read Ipcop settings
110&General::readhash("${General::swroot}/ethernet/settings", \%netsettings);
111&General::readhash("${General::swroot}/main/settings", \%mainsettings);
112&General::readhash("${General::swroot}/time/settings", \%timesettings);
fe6cda92 113&General::readhash("/srv/web/ipfire/html/themes/".$mainsettings{'THEME'}."/include/colors.txt", \%color);
ac1cfefa
MT
114
115#Get GUI values
116&Header::getcgihash(\%dhcpsettings);
117
118open(FILE, "$filename1") or die 'Unable to open dhcp advanced options file.';
119our @current1 = <FILE>;
120close(FILE);
121# Extract OptionDefinition
122foreach my $line (@current1) {
123 #chomp($line); # remove newline #don't know why, but this remove newline in @current1 .... !
124 my @temp = split(/\t/,$line);
125 AddNewOptionDefinition ($temp[1] . ' ' . $temp[2]);
126}
127
128open(FILE, "$filename2") or die 'Unable to open fixed leases file.';
129our @current2 = <FILE>;
130close(FILE);
131
132# Check Settings1 first because they are needed by &buildconf
133if ($dhcpsettings{'ACTION'} eq $Lang::tr{'save'}) {
134 foreach my $itf (@ITFs) {
135 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on' ) {
136 # "Start" is defined, need "End" and vice versa
137 if ($dhcpsettings{"START_ADDR_${itf}"}) {
138 if (!(&General::validip($dhcpsettings{"START_ADDR_${itf}"}))) {
139 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
140 goto ERROR;
141 }
142 if (!$dhcpsettings{"END_ADDR_${itf}"}) {
143 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
144 goto ERROR;
145 }
146 if (! &General::IpInSubnet ( $dhcpsettings{"START_ADDR_${itf}"},
147 $netsettings{"${itf}_NETADDRESS"},
148 $netsettings{"${itf}_NETMASK"})) {
149 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
150 goto ERROR;
151 }
152 }
153
154 if ($dhcpsettings{"END_ADDR_${itf}"}) {
155 if (!(&General::validip($dhcpsettings{"END_ADDR_${itf}"}))) {
156 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
157 goto ERROR;
158 }
159 if (!$dhcpsettings{"START_ADDR_${itf}"}) {
160 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid start address'};
161 goto ERROR;
162 }
163 if (! &General::IpInSubnet ( $dhcpsettings{"END_ADDR_${itf}"},
164 $netsettings{"${itf}_NETADDRESS"},
165 $netsettings{"${itf}_NETMASK"})) {
166 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid end address'};
167 goto ERROR;
168 }
169 #swap if necessary! (support 255.255.0.0 range, I doubt we need more) GE
170 my @startoct = split (/\./, $dhcpsettings{"START_ADDR_${itf}"});
171 my @endoct = split (/\./, $dhcpsettings{"END_ADDR_${itf}"});
172 if ( $endoct[2]*256+$endoct[3] < $startoct[2]*256+$startoct[3] ) {
173 ($dhcpsettings{"START_ADDR_${itf}"},$dhcpsettings{"END_ADDR_${itf}"}) =
174 ($dhcpsettings{"END_ADDR_${itf}"},$dhcpsettings{"START_ADDR_${itf}"});
175 }
176 }
177
178 if (!($dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} =~ /^\d+$/)) {
179 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid default lease time'} . $dhcpsettings{'DEFAULT_LEASE_TIME_${itf}'};
180 goto ERROR;
181 }
182
183 if (!($dhcpsettings{"MAX_LEASE_TIME_${itf}"} =~ /^\d+$/)) {
184 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid max lease time'} . $dhcpsettings{'MAX_LEASE_TIME_${itf}'};
185 goto ERROR;
186 }
187
188 if ($dhcpsettings{"DNS1_${itf}"}) {
189 if (!(&General::validip($dhcpsettings{"DNS1_${itf}"}))) {
190 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid primary dns'};
191 goto ERROR;
192 }
193 }
194 if ($dhcpsettings{"DNS2_${itf}"}) {
195 if (!(&General::validip($dhcpsettings{"DNS2_${itf}"}))) {
196 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid secondary dns'};
197 goto ERROR;
198 }
199 if (! $dhcpsettings{"DNS1_${itf}"}) {
200 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary dns without specifying primary'};
201 goto ERROR;
202 }
203 }
204
205 if ($dhcpsettings{"WINS1_${itf}"}) {
206 if (!(&General::validip($dhcpsettings{"WINS1_${itf}"}))) {
207 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid wins address'};
208 goto ERROR;
209 }
210 }
211 if ($dhcpsettings{"WINS2_${itf}"}) {
212 if (!(&General::validip($dhcpsettings{"WINS2_${itf}"}))) {
213 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid wins address'};
214 goto ERROR;
215 }
216 if (! $dhcpsettings{"WINS1_${itf}"} ) {
217 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary wins without specifying primary'};
218 goto ERROR;
219 }
220 }
d1883e28
MT
221 if ($dhcpsettings{"NEXT_${itf}"}) {
222 if (!(&General::validip($dhcpsettings{"NEXT_${itf}"}))) {
223 $errormessage = "next-server on ${itf}: " . $Lang::tr{'invalid ip'};
224 goto ERROR;
225 }
226 }
ac1cfefa
MT
227 if ($dhcpsettings{"NTP1_${itf}"}) {
228 if (!(&General::validip($dhcpsettings{"NTP1_${itf}"}))) {
229 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid primary ntp'};
230 goto ERROR;
231 }
232 if ($dhcpsettings{"NTP1_${itf}"} eq $netsettings{"${itf}_ADDRESS"} && ($timesettings{'ENABLECLNTP'} ne 'on')) {
233 $warnNTPmessage = "DHCP on ${itf}: " . $Lang::tr{'local ntp server specified but not enabled'};
234 #goto ERROR;
235 }
236 }
237 if ($dhcpsettings{"NTP2_${itf}"}) {
238 if (!(&General::validip($dhcpsettings{"NTP2_${itf}"}))) {
239 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'invalid secondary ntp'};
240 goto ERROR;
241 }
242 if ($dhcpsettings{"NTP2_${itf}"} eq $netsettings{"${itf}_ADDRESS"} && ($timesettings{'ENABLECLNTP'} ne 'on')) {
243 $warnNTPmessage = "DHCP on ${itf}: " . $Lang::tr{'local ntp server specified but not enabled'};
244 #goto ERROR;
245 }
246 if (! $dhcpsettings{"NTP1_${itf}"}) {
247 $errormessage = "DHCP on ${itf}: " . $Lang::tr{'cannot specify secondary ntp without specifying primary'};
248 goto ERROR;
249 }
250 }
251 } # enabled
252 }#loop interface verify
253
a1468f66 254 map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2','q'); # Must not be saved
ac1cfefa
MT
255 &General::writehash($setting, \%dhcpsettings); # Save good settings
256 $dhcpsettings{'ACTION'} = $Lang::tr{'save'}; # create an 'ACTION'
257 map ($dhcpsettings{$_} = '',@nosaved,'KEY1','KEY2'); # and reinit vars to empty
258 &buildconf;
259 ERROR: # Leave the faulty field untouched
260} else {
261 &General::readhash($setting, \%dhcpsettings); # Get saved settings and reset to good if needed
262}
263
264## Sorting of fixed leases
265if ($ENV{'QUERY_STRING'} =~ /^FETHER|^FIPADDR/ ) {
266 my $newsort=$ENV{'QUERY_STRING'};
267 my $act=$dhcpsettings{'SORT_FLEASELIST'};
268 #Reverse actual sort ?
269 if ($act =~ $newsort) {
270 my $Rev='';
271 if ($act !~ 'Rev') {
272 $Rev='Rev';
273 }
274 $newsort.=$Rev;
275 }
276 $dhcpsettings{'SORT_FLEASELIST'}=$newsort;
a1468f66 277 map (delete ($dhcpsettings{$_}) ,@nosaved,'ACTION','KEY1','KEY2', 'q'); # Must never be saved
ac1cfefa
MT
278 &General::writehash($setting, \%dhcpsettings);
279 &sortcurrent2;
280 $dhcpsettings{'ACTION'} = 'SORT'; # create an 'ACTION'
281 map ($dhcpsettings{$_} = '',@nosaved,'KEY1','KEY2');# and reinit vars to empty
282}
283
284#Sorting of allocated leases
285&Header::CheckSortOrder;
286
287
288## Now manipulate the two multi-line list with Settings2.
289# '1' suffix is for ADVANCED OPTIONS
290# '2' suffix is for FIXED LEASES
291
292# Toggle enable/disable field on specified options.
293
294if ($dhcpsettings{'ACTION'} eq $Lang::tr{'toggle enable disable'}.'1') {
295 #move out new line
296 chomp(@current1[$dhcpsettings{'KEY1'}]);
297 my @temp = split(/\t/,@current1[$dhcpsettings{'KEY1'}]); #use TAB separator !
298 $temp[0] = $temp[0] eq 'on' ? '' : 'on'; # Toggle the field
299 @current1[$dhcpsettings{'KEY1'}] = join ("\t",@temp)."\n";
300 $dhcpsettings{'KEY1'} = ''; # End edit mode
301 &General::log($Lang::tr{'dhcp advopt modified'});
302 open(FILE, ">$filename1") or die 'Unable to open dhcp advanced options file.';
303 print FILE @current1;
304 close(FILE);
305
306 #Write changes to dhcpd.conf.
307 &buildconf;
308}
309
310
311
312if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'1' &&
313 $dhcpsettings{'SUBMIT'} ne $Lang::tr{'dhcp advopt help'}) {
314 $dhcpsettings{'ADVOPT_NAME'} =~ s/[^ \w-]//g; # prevent execution of code by removing everything except letters/space
315 $dhcpsettings{'ADVOPT_DATA'} =~ s/`//g; # back tik ` ? not allowed !
316
317 if ($dhcpsettings{'ADVOPT_DATA'} eq '') {
318 $errormessage=$Lang::tr{'dhcp advopt blank value'};
319 }
320
321 # Test for a new option definition string (join field name & data)
322 if (ExistNewOptionDefinition ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
323 #only edit permitted if option definition exists
324 $errormessage = $Lang::tr{'dhcp advopt definition exists'} if ($dhcpsettings{'KEY1'} eq '');
325 $dhcpsettings{'ADVOPT_ENABLED'} = 'on'; # force active
326 map ($dhcpsettings{"ADVOPT_SCOPE_$_"} = 'off', @ITFs); # force global
327 } elsif (AddNewOptionDefinition ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
328 #was a new option definition
329 $dhcpsettings{'ADVOPT_ENABLED'} = 'on'; # force active
330 map ($dhcpsettings{"ADVOPT_SCOPE_$_"} = 'off', @ITFs); # force global
331 } elsif (ValidNewOption ($dhcpsettings{'ADVOPT_NAME'} . ' ' . $dhcpsettings{'ADVOPT_DATA'})) {
332 #was a new option
333 } elsif (! `grep "\$option $dhcpsettings{'ADVOPT_NAME'} " $filename3`) {
334 $errormessage=$Lang::tr{'dhcp advopt unknown'}.': '.$dhcpsettings{'ADVOPT_NAME'};
335 }
336
337 unless ($errormessage) {
338
339 my $scope = '';
340 foreach my $itf (@ITFs) { # buils "RED,GREEN,ORANGE,... based on selection
341 $scope .= $dhcpsettings{"ADVOPT_SCOPE_${itf}"} eq 'on' ? "\t$itf" : "\toff" ;
342 }
343 if ($dhcpsettings{'KEY1'} eq '') { #add or edit ? TAB separator !
344 unshift (@current1, "$dhcpsettings{'ADVOPT_ENABLED'}\t$dhcpsettings{'ADVOPT_NAME'}\t$dhcpsettings{'ADVOPT_DATA'}$scope\n");
345 &General::log($Lang::tr{'dhcp advopt added'});
346 } else {
347 @current1[$dhcpsettings{'KEY1'}] = "$dhcpsettings{'ADVOPT_ENABLED'}\t$dhcpsettings{'ADVOPT_NAME'}\t$dhcpsettings{'ADVOPT_DATA'}$scope\n";
348 $dhcpsettings{'KEY1'} = ''; # End edit mode
349 &General::log($Lang::tr{'dhcp advopt modified'});
350 }
351
352 #Write changes to dhcpd.conf.
353 &sortcurrent1; # sort newly added/modified entry
354 &buildconf; # before calling buildconf which use fixed lease file !
355 }
356}
357
358if ($dhcpsettings{'ACTION'} eq $Lang::tr{'edit'}.'1') {
359 #move out new line
360 my $line = @current1[$dhcpsettings{'KEY1'}];
361 chomp($line);
362 my @temp = split(/\t/, $line);
363 $dhcpsettings{'ADVOPT_ENABLED'}=$temp[0];
364 $dhcpsettings{'ADVOPT_NAME'}=$temp[1];
365 $dhcpsettings{'ADVOPT_DATA'}=$temp[2];
366
367 # read next fields which are the name (color) of an interface if this interface is scoped
368 for (my $key=0; $key<@ITFs; $key++) {
369 my $itf = $temp[3+$key];
370 if ($itf ne 'off') # Only is an interface name is read
371 {
372 $dhcpsettings{"ADVOPT_SCOPE_${itf}"} = 'on';
373 }
374 }
375}
376
377if ($dhcpsettings{'ACTION'} eq $Lang::tr{'remove'}.'1') {
378 splice (@current1,$dhcpsettings{'KEY1'},1);
379 open(FILE, ">$filename1") or die 'Unable to open dhcp advanced options file.';
380 print FILE @current1;
381 close(FILE);
382 $dhcpsettings{'KEY1'} = ''; # End remove mode
383 &General::log($Lang::tr{'dhcp advopt removed'});
384 #Write changes to dhcpd.conf.
385 &buildconf;
386}
387#end KEY1
388
389
390# Toggle enable/disable field on specified lease.
391if ($dhcpsettings{'ACTION'} eq $Lang::tr{'toggle enable disable'}.'2') {
392 #move out new line
393 chomp(@current2[$dhcpsettings{'KEY2'}]);
394 my @temp = split(/\,/,@current2[$dhcpsettings{'KEY2'}]);
395 $temp[2] = $temp[2] eq 'on' ? '' : 'on'; # Toggle the field
396 @current2[$dhcpsettings{'KEY2'}] = join (',',@temp)."\n";
397 $dhcpsettings{'KEY2'} = ''; # End edit mode
398 &General::log($Lang::tr{'fixed ip lease modified'});
399 open(FILE, ">$filename2") or die 'Unable to open fixed leases file.';
400 print FILE @current2;
401 close(FILE);
402
403 #Write changes to dhcpd.conf.
404 &buildconf;
405}
406
407if ($dhcpsettings{'ACTION'} eq $Lang::tr{'add'}.'2') {
408 $dhcpsettings{'FIX_MAC'} =~ tr/-/:/;
409 unless(&General::validip($dhcpsettings{'FIX_ADDR'})) { $errormessage = $Lang::tr{'invalid fixed ip address'}; }
410 unless(&General::validmac($dhcpsettings{'FIX_MAC'})) { $errormessage = $Lang::tr{'invalid fixed mac address'}; }
411 if ($dhcpsettings{'FIX_NEXTADDR'}) {
412 unless(&General::validip($dhcpsettings{'FIX_NEXTADDR'})) { $errormessage = $Lang::tr{'invalid fixed ip address'}; }
413 }
414
415 my $key = 0;
416 CHECK:foreach my $line (@current2) {
417 my @temp = split(/\,/,$line);
418 if($dhcpsettings{'KEY2'} ne $key) {
419 # same MAC is OK on different subnets. This test is not complete because
420 # if ip are not inside a known subnet, I don't warn.
421 # Also it may be needed to put duplicate fixed lease in their right subnet definition..
422 foreach my $itf (@ITFs) {
423 my $scoped = &General::IpInSubnet($dhcpsettings{'FIX_ADDR'},
424 $netsettings{"${itf}_NETADDRESS"},
425 $netsettings{"${itf}_NETMASK"}) &&
426 $dhcpsettings{"ENABLE_${itf}"} eq 'on';
427 if ( $scoped &&
428 (lc($dhcpsettings{'FIX_MAC'}) eq lc($temp[0])) &&
429 &General::IpInSubnet($temp[1],
430 $netsettings{"${itf}_NETADDRESS"},
431 $netsettings{"${itf}_NETMASK"})) {
432 $errormessage = "$Lang::tr{'mac address in use'} $dhcpsettings{'FIX_MAC'}";
433 last CHECK;
434 }
435 }
436 }
437 $key++;
438 }
439
440 unless ($errormessage) {
441 $dhcpsettings{'FIX_REMARK'} = &Header::cleanhtml($dhcpsettings{'FIX_REMARK'});
442 $dhcpsettings{'FIX_NEXTADDR'} = &Header::cleanhtml($dhcpsettings{'FIX_NEXTADDR'});
443 $dhcpsettings{'FIX_FILENAME'} = &Header::cleanhtml($dhcpsettings{'FIX_FILENAME'});
444 $dhcpsettings{'FIX_ROOTPATH'} = &Header::cleanhtml($dhcpsettings{'FIX_ROOTPATH'});
445 if ($dhcpsettings{'KEY2'} eq '') { #add or edit ?
446 unshift (@current2, "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n");
e4f9ea3c
BB
447 open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
448 print FILE @current2;
449 close(FILE);
ac1cfefa 450 &General::log($Lang::tr{'fixed ip lease added'});
91fc3030
MT
451
452 # Enter edit mode
31672dc8 453 $dhcpsettings{'KEY2'} = 0;
ac1cfefa
MT
454 } else {
455 @current2[$dhcpsettings{'KEY2'}] = "$dhcpsettings{'FIX_MAC'},$dhcpsettings{'FIX_ADDR'},$dhcpsettings{'FIX_ENABLED'},$dhcpsettings{'FIX_NEXTADDR'},$dhcpsettings{'FIX_FILENAME'},$dhcpsettings{'FIX_ROOTPATH'},$dhcpsettings{'FIX_REMARK'}\n";
456 $dhcpsettings{'KEY2'} = ''; # End edit mode
457 &General::log($Lang::tr{'fixed ip lease modified'});
31672dc8
MT
458
459 # sort newly added/modified entry
460 &sortcurrent2;
ac1cfefa
MT
461 }
462
463 #Write changes to dhcpd.conf.
ac1cfefa
MT
464 &buildconf; # before calling buildconf which use fixed lease file !
465 }
466}
467
468if ($dhcpsettings{'ACTION_ALL'} eq '+') {
469 my $news = 0;
470 foreach (keys %dhcpsettings) {
471 if (/^(\d+\.\d+\.\d+\.\d+)-([0-9a-fA-F:]+)$/) { # checked names are index of the line
472 my $ip=$1;
473 my $mac=$2;
474 if (!grep (/$2/,@current2)) {
475 unshift (@current2, "$mac,$ip,on,,,,imported\n");
476 $news++;
477 }
478 }
479 }
480 if ($news) {
481 #Write changes to dhcpd.conf.
482 $warnNTPmessage = $Lang::tr{'fixed ip lease added'}."($news)";
483 &General::log($warnNTPmessage);
484 &sortcurrent2; # sort newly added/modified entry
485 &buildconf; # before calling buildconf which use fixed lease file !
486 }
487}
488
489if ($dhcpsettings{'ACTION'} eq $Lang::tr{'edit'}.'2') {
490 #move out new line
491 my $line = @current2[$dhcpsettings{'KEY2'}];
492 chomp($line);
493 my @temp = split(/\,/, $line);
494 $dhcpsettings{'FIX_MAC'}=$temp[0];
495 $dhcpsettings{'FIX_ADDR'}=$temp[1];
496 $dhcpsettings{'FIX_ENABLED'}=$temp[2];
497 $dhcpsettings{'FIX_NEXTADDR'}=$temp[3];
498 $dhcpsettings{'FIX_FILENAME'}=$temp[4];
499 $dhcpsettings{'FIX_ROOTPATH'}=$temp[5];
500 $dhcpsettings{'FIX_REMARK'}=$temp[6];
501}
502
503if ($dhcpsettings{'ACTION'} eq $Lang::tr{'remove'}.'2') {
504 splice (@current2,$dhcpsettings{'KEY2'},1);
505 open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
506 print FILE @current2;
507 close(FILE);
508 $dhcpsettings{'KEY2'} = ''; # End remove mode
509 &General::log($Lang::tr{'fixed ip lease removed'});
510 #Write changes to dhcpd.conf.
511 &buildconf;
512}
513#end KEY2 defined
514
515
516
517
518if ($dhcpsettings{'ACTION'} eq '' ) { # First launch from GUI
519
520 # Set default DHCP values only if blank and disabled
521 foreach my $itf (@ITFs) {
522 if ($dhcpsettings{"ENABLE_${itf}"} ne 'on' ) {
523 $dhcpsettings{"DNS1_${itf}"} = $netsettings{"${itf}_ADDRESS"};
524 $dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} = '60';
525 $dhcpsettings{"MAX_LEASE_TIME_${itf}"} = '120';
526 $dhcpsettings{"DOMAIN_NAME_${itf}"} = $mainsettings{'DOMAINNAME'};
527 }
528 }
529 $dhcpsettings{'FIX_ENABLED'} = 'on';
530}
531
532&Header::openpage($Lang::tr{'dhcp configuration'}, 1, '');
533&Header::openbigbox('100%', 'left', '', $errormessage);
534
535if ($errormessage) {
536 &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
537 print "<font class='base'>$errormessage&nbsp;</font>\n";
538 &Header::closebox();
539}
540if ($warnNTPmessage) {
541 $warnNTPmessage = "<font color=${Header::colourred}><b>$Lang::tr{'capswarning'}</b></font>: $warnNTPmessage";
542}
543
544&Header::openbox('100%', 'left', 'DHCP');
545print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>";
546
547foreach my $itf (@ITFs) {
548 my %checked=();
549 $checked{'ENABLE'}{'on'} = ( $dhcpsettings{"ENABLE_${itf}"} ne 'on') ? '' : "checked='checked'";
550 $checked{'ENABLEBOOTP'}{'on'} = ( $dhcpsettings{"ENABLEBOOTP_${itf}"} ne 'on') ? '' : "checked='checked'";
551
552 if ($netsettings{"${itf}_DEV"} ne '' ) { # Show only defined interface
553 my $lc_itf=lc($itf);
554print <<END
555<table width='100%'>
556<tr>
557 <td width='25%' class='boldbase'><b><font color='${lc_itf}'>$Lang::tr{"$lc_itf interface"}</font></b></td>
558 <td class='base'>$Lang::tr{'enabled'}
559 <input type='checkbox' name='ENABLE_${itf}' $checked{'ENABLE'}{'on'} /></td>
9c100957 560 <td width='25%' class='base'>$Lang::tr{'ip address'}<br />$Lang::tr{'netmask'}:</td><td><b>$netsettings{"${itf}_ADDRESS"}<br />$netsettings{"${itf}_NETMASK"}</b></td>
ac1cfefa 561</tr><tr>
e3edceeb 562 <td width='25%' class='base'>$Lang::tr{'start address'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 563 <td width='25%'><input type='text' name='START_ADDR_${itf}' value='$dhcpsettings{"START_ADDR_${itf}"}' /></td>
e3edceeb 564 <td width='25%' class='base'>$Lang::tr{'end address'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa
MT
565 <td width='25%'><input type='text' name='END_ADDR_${itf}' value='$dhcpsettings{"END_ADDR_${itf}"}' /></td>
566</tr><tr>
e3edceeb 567 <td class='base'>$Lang::tr{'default lease time'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 568 <td><input type='text' name='DEFAULT_LEASE_TIME_${itf}' value='$dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"}' /></td>
e3edceeb 569 <td class='base'>$Lang::tr{'max lease time'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa
MT
570 <td><input type='text' name='MAX_LEASE_TIME_${itf}' value='$dhcpsettings{"MAX_LEASE_TIME_${itf}"}' /></td>
571</tr><tr>
e3edceeb 572 <td class='base'>$Lang::tr{'domain name suffix'}</td>
ac1cfefa
MT
573 <td><input type='text' name='DOMAIN_NAME_${itf}' value='$dhcpsettings{"DOMAIN_NAME_${itf}"}' /></td>
574 <td>$Lang::tr{'dhcp allow bootp'}:</td>
575 <td><input type='checkbox' name='ENABLEBOOTP_${itf}' $checked{'ENABLEBOOTP'}{'on'} /></td>
576</tr><tr>
e3edceeb 577 <td class='base'>$Lang::tr{'primary dns'}&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 578 <td><input type='text' name='DNS1_${itf}' value='$dhcpsettings{"DNS1_${itf}"}' /></td>
e3edceeb 579 <td class='base'>$Lang::tr{'secondary dns'}</td>
ac1cfefa
MT
580 <td><input type='text' name='DNS2_${itf}' value='$dhcpsettings{"DNS2_${itf}"}' /></td>
581</tr><tr>
e3edceeb 582 <td class='base'>$Lang::tr{'primary ntp server'}:</td>
ac1cfefa 583 <td><input type='text' name='NTP1_${itf}' value='$dhcpsettings{"NTP1_${itf}"}' /></td>
e3edceeb 584 <td class='base'>$Lang::tr{'secondary ntp server'}:</td>
ac1cfefa
MT
585 <td><input type='text' name='NTP2_${itf}' value='$dhcpsettings{"NTP2_${itf}"}' /></td>
586</tr><tr>
e3edceeb 587 <td class='base'>$Lang::tr{'primary wins server address'}:</td>
ac1cfefa 588 <td><input type='text' name='WINS1_${itf}' value='$dhcpsettings{"WINS1_${itf}"}' /></td>
e3edceeb 589 <td class='base'>$Lang::tr{'secondary wins server address'}:</td>
ac1cfefa 590 <td><input type='text' name='WINS2_${itf}' value='$dhcpsettings{"WINS2_${itf}"}' /></td>
d1883e28 591</tr><tr>
e3edceeb 592 <td class='base'>next-server:</td>
d1883e28 593 <td><input type='text' name='NEXT_${itf}' value='$dhcpsettings{"NEXT_${itf}"}' /></td>
e3edceeb 594 <td class='base'>filename:</td>
d1883e28 595 <td><input type='text' name='FILE_${itf}' value='$dhcpsettings{"FILE_${itf}"}' /></td>
ac1cfefa
MT
596</tr>
597</table>
598<hr />
599END
600;
601 }# Show only defined interface
602}#foreach itf
603print <<END
604<table width='100%'>
605<tr>
e3edceeb 606 <td class='base' width='25%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'required field'}</td>
ac1cfefa 607 <td class='base' width='30%'>$warnNTPmessage</td>
e084eea0 608 <td width='40%' align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
ac1cfefa
MT
609</tr>
610</table>
b510e12a
SS
611END
612;
613&Header::closebox();
614
615# DHCP DNS update support (RFC2136)
616&Header::openbox('100%', 'left', $Lang::tr{'dhcp dns update'});
617
618my %checked = ();
619$checked{'DNS_UPDATE_ENABLED'}{'on'} = ( $dhcpsettings{'DNS_UPDATE_ENABLED'} ne 'on') ? '' : "checked='checked'";
620
621print <<END
622<table width='100%'>
623 <tr>
624 <td width='25%' class='boldbase'>$Lang::tr{'dhcp dns enable update'}</td>
625 <td class='base'><input type='checkbox' name='DNS_UPDATE_ENABLED' $checked{'DNS_UPDATE_ENABLED'}{'on'}>
626 </td>
627 <tr>
628</table>
629
630<table width='100%'>
631END
632;
633 my @domains = ();
634
635 # Print options for each interface.
636 foreach my $itf (@ITFs) {
637 # Check if DHCP for this interface is enabled.
638 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on') {
639 # Check for same domain name.
640 next if ($dhcpsettings{"DOMAIN_NAME_${itf}"} ~~ @domains);
641 my $lc_itf = lc($itf);
642
643 # Select previously configured update algorithm.
644 my %selected = ();
645 $selected{'DNS_UPDATE_ALGO_${inf}'}{$dhcpsettings{'DNS_UPDATE_ALGO_${inf}'}} = 'selected';
646
647print <<END
648 <tr>
649 <td colspan='6'>&nbsp;</td>
650 </tr>
651 <tr>
652 <td colspan='6' class='boldbase'><b>$dhcpsettings{"DOMAIN_NAME_${itf}"}</b></td>
653 </tr>
654 <tr>
655 <td width='10%' class='boldbase'>$Lang::tr{'dhcp dns key name'}:</td>
656 <td width='20%'><input type='text' name='DNS_UPDATE_KEY_NAME_${itf}' value='$dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"}'></td>
657 <td width='10%' class='boldbase' align='right'>$Lang::tr{'dhcp dns update secret'}:&nbsp;&nbsp;</td>
28fee676 658 <td width='20%'><input type='password' name='DNS_UPDATE_KEY_SECRET_${itf}' value='$dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"}'></td>
b510e12a
SS
659 <td width='10%' class='boldbase' align='right'>$Lang::tr{'dhcp dns update algo'}:&nbsp;&nbsp;</td>
660 <td width='20%'>
28fee676 661 <select name='DNS_UPDATE_KEY_ALGO_${itf}'>
a057a976 662 <!-- <option value='hmac-sha1' $selected{'DNS_UPDATE_KEY_ALGO_${itf}'}{'hmac-sha1'}>HMAC-SHA1</option> -->
28fee676 663 <option value='hmac-md5' $selected{'DNS_UPDATE_KEY_ALGO_${itf}'}{'hmac-md5'}>HMAC-MD5</option>
b510e12a
SS
664 </select>
665 </td>
666 </tr>
667END
668;
669 }
670
671 # Store configured domain based on the interface
672 # in the temporary variable.
673 push(@domains, $dhcpsettings{"DOMAIN_NAME_${itf}"});
674}
675print <<END
676</table>
677<hr>
678<table width='100%'>
679 <tr>
680 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
681 </tr>
682</table>
ac1cfefa
MT
683</form>
684END
685;
686
687&Header::closebox();
688
689&Header::openbox('100%', 'left', $Lang::tr{'dhcp advopt list'});
690# DHCP Advanced options settings
691my %checked=();
692$checked{'ADVOPT_ENABLED'}{'on'} = ($dhcpsettings{'ADVOPT_ENABLED'} ne 'on') ? '' : "checked='checked'";
693
694print "<form method='post' action='$ENV{'SCRIPT_NAME'}'><table width='100%'>";
695my $buttontext = $Lang::tr{'add'};
696if ($dhcpsettings{'KEY1'} ne '') {
697 $buttontext = $Lang::tr{'update'};
698 print "<tr><td class='boldbase'><b>$Lang::tr{'dhcp advopt edit'}</b></td></tr>";
699} else {
700 print "<tr><td class='boldbase'><b>$Lang::tr{'dhcp advopt add'}</b></td></tr>"
701}
702
703#search if the 'option' is in the list and print the syntax model
704my $opt = `grep "\$option $dhcpsettings{'ADVOPT_NAME'} " $filename3`;
705if ($opt ne '') {
706 $opt =~ s/option $dhcpsettings{'ADVOPT_NAME'}/Syntax:/; # "option xyz abc" => "syntax: abc"
707 $opt =~ s/;//;
708 $opt = "<tr><td></td><td></td><td colspan='2'>$opt</td></tr>";
709}
710print <<END
711<tr>
e3edceeb 712 <td class='base'>$Lang::tr{'dhcp advopt name'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 713 <td><input type='text' name='ADVOPT_NAME' value='$dhcpsettings{'ADVOPT_NAME'}' size='18' /></td>
e3edceeb 714 <td class='base'>$Lang::tr{'dhcp advopt value'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa
MT
715 <td><input type='text' name='ADVOPT_DATA' value='$dhcpsettings{'ADVOPT_DATA'}' size='40' /></td>
716</tr>$opt<tr>
717 <td class='base'>$Lang::tr{'enabled'}</td><td><input type='checkbox' name='ADVOPT_ENABLED' $checked{'ADVOPT_ENABLED'}{'on'} /></td>
e3edceeb 718 <td class='base'>$Lang::tr{'dhcp advopt scope'}:</td>
ac1cfefa
MT
719 <td>
720END
721;
722
723# Put a checkbox for each interface. Checkbox visible disabled if interface is disabled
724foreach my $itf (@ITFs) {
725 my $lc_itf=lc($itf);
726 $checked{'ADVOPT_SCOPE_${itf}'}{'on'} = $dhcpsettings{"ADVOPT_SCOPE_${itf}"} ne 'on' ? '' : "checked='checked'";
727 print "$Lang::tr{\"${lc_itf}\"} <input type='checkbox' name='ADVOPT_SCOPE_${itf}' $checked{'ADVOPT_SCOPE_${itf}'}{'on'} ";
728 print $dhcpsettings{"ENABLE_${itf}"} eq 'on' ? "/>" : "disabled='disabled' />";
729 print "&nbsp; &nbsp;";
730}
731
732print <<END
733 </td>
734</tr>
735</table>
736<hr />
737<table width='100%'>
738<tr>
e3edceeb 739 <td class='base' width='50%'>$Lang::tr{'dhcp advopt scope help'}</td>
e084eea0 740 <td width='50%' align='right'>
ac1cfefa
MT
741 <input type='hidden' name='ACTION' value='$Lang::tr{'add'}1' />
742 <input type='submit' name='SUBMIT' value='$buttontext' />
743 <input type='submit' name='SUBMIT' value='$Lang::tr{'dhcp advopt help'}' />
744 <input type='hidden' name='KEY1' value='$dhcpsettings{'KEY1'}' />
745 </td>
746</tr>
747</table>
748</form>
749END
750;
751#Edited line number (KEY1) passed until cleared by 'save' or 'remove' or 'new sort order'
752
753# print help taken from the file describing options
754if ($dhcpsettings{'SUBMIT'} eq $Lang::tr{'dhcp advopt help'}) {
755 print "<hr />";
756 print "<table width='100%'>";
757 print "<tr><td width='30%'><b>$Lang::tr{'dhcp advopt name'}</b></td><td width='70%'><b>$Lang::tr{'dhcp advopt value'}</b></td>";
758 open(FILE, "$filename3");
759 my @current3 = <FILE>;
760 close(FILE);
761 foreach my $line (@current3) {
762 $line =~ /option ([a-z0-9-]+) (.*);/;
763 print "<tr><td>$1</td><td>$2</td></tr>\n";
764 }
765 print "<tr><td colspan='2'><hr /></td></tr>\n";
766 print '<tr><td>string type</td><td>"quoted string" or 00:01:FF...</td></tr>';
767 print '<tr><td>ip-address type </td><td>10.0.0.1 | www.dot.com</td></tr>';
768 print '<tr><td>int,uint types</td><td>numbers</td></tr>';
769 print '<tr><td>flag type</td><td>on | off</td></tr>';
770 print '</table>';
771 print "<hr />";
772 print "<table width='100%'>";
773 print "<tr><td width='30%'><b>$Lang::tr{'dhcp advopt custom definition'}</b></td><td width='70%'><b>$Lang::tr{'dhcp advopt value'}</b></td>";
774 print "<tr><td>any-name </td><td> code NNN=$OptionTypes</td></tr>";
775 print '<tr><td>a-string</td><td>code 100=string</td></tr>';
776 print '<tr><td>a-number</td><td>code 101=signed integer 8</td></tr>';
777 print '<tr><td>wpad</td><td>code 252=text</td></tr>';
778 print '<tr><td>wpad</td><td>"http://www.server.fr/path-to/proxy.pac"</td></tr>';
779 print '</table>';
780
781}
782
783print <<END
784<hr />
785<table width='100%'>
786<tr>
787 <td width='30%' class='boldbase' align='center'><b>$Lang::tr{'dhcp advopt name'}</b></td>
788 <td width='50%' class='boldbase' align='center'><b>$Lang::tr{'dhcp advopt value'}</b></td>
789 <td width='20%' class='boldbase' align='center'><b>$Lang::tr{'dhcp advopt scope'}</b></td>
790 <td colspan='3' class='boldbase' align='center'><b>$Lang::tr{'action'}</b></td>
791</tr>
792END
793;
794my $key = 0;
795foreach my $line (@current1) {
796 my $gif = '';
797 my $gdesc = '';
798 chomp($line); # remove newline
799 my @temp = split(/\t/,$line);
800
801 if ($temp[0] eq "on") {
802 $gif = 'on.gif';
803 $gdesc = $Lang::tr{'click to disable'};
804 } else {
805 $gif = 'off.gif';
806 $gdesc = $Lang::tr{'click to enable'};
807 }
808
809 if ($dhcpsettings{'KEY1'} eq $key) {
810 print "<tr bgcolor='${Header::colouryellow}'>";
811 } elsif ($key % 2) {
fe6cda92 812 print "<tr bgcolor='$color{'color22'}'>";
ac1cfefa 813 } else {
fe6cda92 814 print "<tr bgcolor='$color{'color20'}'>";
ac1cfefa
MT
815 }
816
817 print <<END
818<td align='center'>$temp[1]</td>
819<td align='center'>$temp[2]</td>
820<td align='center'>
821END
822;
823 # Prepare a global flag to make easy reading
824 my $global = '';
825 my $disabledTogle = '';
826 my $disabledEditRemove = '';
827 if ( ExistNewOptionDefinition ($temp[1] . ' ' . $temp[2]) ) {
828 $global = $Lang::tr{'dhcp advopt definition'};
829 $disabledTogle = "disabled='disabled'";
830 # Search if it is a used NewOptionDefinition to also disable edit & delete
831 $disabledEditRemove = "disabled='disabled'" if (IsUsedNewOptionDefinition ($temp[1], $temp[2]));
832 } else {
833 $global = $Lang::tr{'dhcp advopt scope global'};
834 }
835
836
837 # Print each checked interface
838 for (my $key=0; $key<@ITFs; $key++) {
839 my $itf = $temp[3+$key];
840 if ($itf ne 'off') { # Only if an interface name is read
841 print "$itf";
842 $global=''; # fall to local scope !
843 }
844 }
845 print <<END
846$global</td>
847<td align='center'>
848<form method='post' action='$ENV{'SCRIPT_NAME'}'>
849<input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}1' />
850<input $disabledTogle type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
851<input type='hidden' name='KEY1' value='$key' />
852</form>
853</td>
854
855<td align='center'>
856<form method='post' action='$ENV{'SCRIPT_NAME'}'>
857<input type='hidden' name='ACTION' value='$Lang::tr{'edit'}1' />
858<input $disabledEditRemove type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
859<input type='hidden' name='KEY1' value='$key' />
860</form>
861</td>
862
863<td align='center'>
864<form method='post' action='$ENV{'SCRIPT_NAME'}'>
865<input type='hidden' name='ACTION' value='$Lang::tr{'remove'}1' />
866<input $disabledEditRemove type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
867<input type='hidden' name='KEY1' value='$key' />
868</form>
869</td>
870</tr>
871END
872;
873 $key++;
874}
875
876print "</table>";
877
878# If there are dhcp options, print Key to action icons
879if ($key) {
880print <<END
881<table>
882<tr>
883 <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
884 <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
885 <td class='base'>$Lang::tr{'click to disable'}</td>
886 <td>&nbsp;&nbsp;</td>
887 <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
888 <td class='base'>$Lang::tr{'click to enable'}</td>
889 <td>&nbsp;&nbsp;</td>
890 <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
891 <td class='base'>$Lang::tr{'edit'}</td>
892 <td>&nbsp;&nbsp;</td>
893 <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
894 <td class='base'>$Lang::tr{'remove'}</td>
895</tr>
896</table>
897END
898;
899}
900&Header::closebox();
901
902&Header::openbox('100%', 'left', $Lang::tr{'current fixed leases'});
903# Fixed leases screens
904$checked{'FIX_ENABLED'}{'on'} = ($dhcpsettings{'FIX_ENABLED'} ne 'on') ? '' : "checked='checked'";
905
906$buttontext = $Lang::tr{'add'};
907print "<form method='post' action='$ENV{'SCRIPT_NAME'}'><table width='100%'>";
908
909if ($dhcpsettings{'KEY2'} ne '') {
910 $buttontext = $Lang::tr{'update'};
911 print "<tr><td class='boldbase' colspan='3'><b>$Lang::tr{'edit an existing lease'}</b></td></tr>";
912} else {
913 print "<tr><td class='boldbase' colspan='3'><b>$Lang::tr{'add new lease'}</b></td></tr>"
914}
915print <<END
916<tr>
e3edceeb 917 <td class='base'>$Lang::tr{'mac address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 918 <td><input type='text' name='FIX_MAC' value='$dhcpsettings{'FIX_MAC'}' size='18' /></td>
e3edceeb 919 <td class='base'>$Lang::tr{'ip address'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
ac1cfefa 920 <td><input type='text' name='FIX_ADDR' value='$dhcpsettings{'FIX_ADDR'}' size='18' /></td>
e3edceeb 921 <td class='base'>$Lang::tr{'remark'}:</td>
ac1cfefa
MT
922 <td><input type='text' name='FIX_REMARK' value='$dhcpsettings{'FIX_REMARK'}' size='18' /></td>
923</tr><tr>
924 <td class='base'>$Lang::tr{'enabled'}</td><td><input type='checkbox' name='FIX_ENABLED' $checked{'FIX_ENABLED'}{'on'} /></td>
925</tr><tr>
926 <td colspan = '3'><b>$Lang::tr{'dhcp bootp pxe data'}</b></td>
927</tr><tr>
e3edceeb 928 <td class='base'>next-server:</td>
ac1cfefa 929 <td><input type='text' name='FIX_NEXTADDR' value='$dhcpsettings{'FIX_NEXTADDR'}' size='18' /></td>
e3edceeb 930 <td class='base'>filename:</td>
ac1cfefa 931 <td><input type='text' name='FIX_FILENAME' value='$dhcpsettings{'FIX_FILENAME'}' size='18' /></td>
e3edceeb 932 <td class='base'>root path:</td>
ac1cfefa
MT
933 <td><input type='text' name='FIX_ROOTPATH' value='$dhcpsettings{'FIX_ROOTPATH'}' size='18' /></td>
934</tr>
935</table>
936<hr />
937<table width='100%'>
938<tr>
e3edceeb 939 <td class='base' width='50%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'required field'}</td>
e084eea0 940 <td width='50%' align='right'>
ac1cfefa
MT
941 <input type='hidden' name='ACTION' value='$Lang::tr{'add'}2' />
942 <input type='submit' name='SUBMIT' value='$buttontext' />
943 <input type='hidden' name='KEY2' value='$dhcpsettings{'KEY2'}' /></td>
944</tr>
945</table>
946</form>
947END
948;
949#Edited line number (KEY2) passed until cleared by 'save' or 'remove' or 'new sort order'
950
1554e8a3
MT
951# Search for static leases
952my $search_query = $dhcpsettings{'q'};
953
954if (scalar @current2 >= 10) {
955 print <<END;
956 <form method="POST" action="#search">
957 <a name="search"></a>
958 <table width='100%'>
959 <tr>
960 <td>
961 <input type="text" name="q" value="$search_query">
962 <input type="submit" value="$Lang::tr{'search'}">
963 </td>
964 </tr>
965 </table>
966 </form>
967END
968}
969
ac1cfefa 970print <<END
52ca3c80 971<table width='100%' class='tbl'>
ac1cfefa 972<tr>
52ca3c80
AM
973 <th width='20%' align='center'><a href='$ENV{'SCRIPT_NAME'}?FETHER'><b>$Lang::tr{'mac address'}</b></a></th>
974 <th width='20%' align='center'><a href='$ENV{'SCRIPT_NAME'}?FIPADDR'><b>$Lang::tr{'ip address'}</b></a></th>
975 <th width='15%' align='center'><b>$Lang::tr{'remark'}</b></th>
976 <th width='15%' class='boldbase' align='center'><b>next-server</b></th>
977 <th width='15%' class='boldbase' align='center'><b>filename</b></th>
978 <th width='15%' class='boldbase' align='center'><b>root path</b></th>
979 <th colspan='3' class='boldbase' align='center'><b>$Lang::tr{'action'}</b></th>
ac1cfefa
MT
980</tr>
981END
982;
983my $ipdup = 0;
984my %ipinuse = ();
985my %macdupl = (); # Duplicate MACs have to be on different subnets
986my %ipoutside = ();
987
988# mark duplicate ip or duplicate MAC
989foreach my $line (@current2) {
990 my @temp = split(/\,/,$line);
991 $macdupl{$temp[0]} += 1;
992 if ($macdupl{$temp[0]} > 1) {
993 $ipdup = 1; # Flag up duplicates for use later
994 }
995 $ipinuse{$temp[1]} += 1;
996 if ($ipinuse{$temp[1]} > 1) {
997 $ipdup = 1; # Flag up duplicates for use later
998 }
999 # Mark IP addresses outwith known subnets
1000 $ipoutside{$temp[1]} = 1;
1001 foreach my $itf (@ITFs) {
1002 if ( &General::IpInSubnet($temp[1],
1003 $netsettings{"${itf}_NETADDRESS"},
1004 $netsettings{"${itf}_NETMASK"})) {
1005 $ipoutside{$temp[1]} = 0;
1006 }
1007 }
1008}
1009
1010$key = 0;
52ca3c80 1011my $col="";
ac1cfefa
MT
1012foreach my $line (@current2) {
1013 my $gif = '';
1014 my $gdesc = '';
1015 chomp($line); # remove newline
1016 my @temp = split(/\,/,$line);
1017
1018 if ($temp[2] eq "on") {
1019 $gif = 'on.gif';
1020 $gdesc = $Lang::tr{'click to disable'};
1021 } else {
1022 $gif = 'off.gif';
1023 $gdesc = $Lang::tr{'click to enable'};
1024 }
1025
1554e8a3
MT
1026 # Skip all entries that do not match the search query
1027 if ($search_query ne "") {
e353470a
MT
1028 if (!grep(/$search_query/, @temp)) {
1029 $key++;
1030 next;
1031 }
1554e8a3
MT
1032 }
1033
ac1cfefa 1034 if ($dhcpsettings{'KEY2'} eq $key) {
52ca3c80
AM
1035 print "<tr>";
1036 $col="bgcolor='${Header::colouryellow}'";
ac1cfefa 1037 } elsif ($key % 2) {
52ca3c80
AM
1038 print "<tr>";
1039 $col="bgcolor='$color{'color20'}'";
ac1cfefa 1040 } else {
52ca3c80
AM
1041 print "<tr>";
1042 $col="bgcolor='$color{'color22'}'";
ac1cfefa
MT
1043 }
1044 my $TAG0 = '';
1045 my $TAG1 = '';
1046 my $TAG2 = '';
1047 my $TAG3 = '';
1048 my $TAG4 = '';
1049 if ($ipinuse{$temp[1]} > 1) {
1050 $TAG0 = '<b>';
1051 $TAG1 = '</b>';
1052 }
1053 if ($macdupl{$temp[0]} > 1) {
1054 $TAG2 = '<b>';
1055 $TAG3 = '</b>';
1056 }
1057 if ($ipoutside{$temp[1]} > 0) {
1058 $TAG4 = "bgcolor='orange'" if ($dhcpsettings{'KEY2'} ne $key);
1059 }
1060
1061 print <<END
52ca3c80
AM
1062<td align='center' $col>$TAG2$temp[0]$TAG3</td>
1063<td align='center' $col $TAG4>$TAG0$temp[1]$TAG1</td>
1064<td align='center' $col>$temp[6]&nbsp;</td>
1065<td align='center' $col>$temp[3]&nbsp;</td>
1066<td align='center' $col>$temp[4]&nbsp;</td>
1067<td align='center' $col>$temp[5]&nbsp;</td>
1068
1069<td align='center' $col>
ac1cfefa
MT
1070<form method='post' action='$ENV{'SCRIPT_NAME'}'>
1071<input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}2' />
1072<input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
1073<input type='hidden' name='KEY2' value='$key' />
1074</form>
1075</td>
1076
52ca3c80 1077<td align='center' $col>
ac1cfefa
MT
1078<form method='post' action='$ENV{'SCRIPT_NAME'}'>
1079<input type='hidden' name='ACTION' value='$Lang::tr{'edit'}2' />
1080<input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
1081<input type='hidden' name='KEY2' value='$key' />
1082</form>
1083</td>
1084
52ca3c80 1085<td align='center' $col>
ac1cfefa
MT
1086<form method='post' action='$ENV{'SCRIPT_NAME'}'>
1087<input type='hidden' name='ACTION' value='$Lang::tr{'remove'}2' />
1088<input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
1089<input type='hidden' name='KEY2' value='$key' />
1090</form>
1091</td>
1092</tr>
1093END
1094;
1095 $key++;
1096}
1097print "</table>";
1098
1099# If the fixed lease file contains entries, print Key to action icons
1100if ($key) {
1101my $dup = $ipdup ? "<td class='base'>$Lang::tr{'duplicate ip bold'}</td>" :'';
1102print <<END
1103<table>
1104<tr>
1105 <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
1106 <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
1107 <td class='base'>$Lang::tr{'click to disable'}</td>
1108 <td>&nbsp;&nbsp;</td>
1109 <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
1110 <td class='base'>$Lang::tr{'click to enable'}</td>
1111 <td>&nbsp;&nbsp;</td>
1112 <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
1113 <td class='base'>$Lang::tr{'edit'}</td>
1114 <td>&nbsp;&nbsp;</td>
1115 <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
1116 <td class='base'>$Lang::tr{'remove'}</td>
1117</tr>
1118<tr>
1119 <td>&nbsp;</td>
1120 <td bgcolor='orange'>&nbsp;</td>
1121 <td class='base'>$Lang::tr{'ip address outside subnets'}</td>
1122 <td>&nbsp;</td>
1123 <td>&nbsp;</td>
1124 $dup
1125</tr>
1126</table>
1127END
1128;
1129}
1130
1131&Header::closebox();
1132
ac1cfefa
MT
1133foreach my $itf (@ITFs) {
1134 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on') {
1135 # display leases with a list of actions to do with the global select checkbox.
1136 &Header::PrintActualLeases("+"); # "+" => create fixed leases from nodeaddress
1137 last; #Print one time only for all interfaces
1138 };
1139}
1140
1141&Header::closebigbox();
1142&Header::closepage();
1143
1144## Ouf it's the end !
1145
1146sub sortcurrent1 # by now, do not sort, just write
1147{
1148 open(FILE, ">$filename1") or die 'Unable to open dhcp advanced options file.';
1149 print FILE @current1;
1150 close(FILE);
1151}
1152
1153
1154# Sort the "current2" array according to choices
1155sub sortcurrent2
1156{
1157 our %entries = ();
1158
1159 sub fixedleasesort {
1160 my $qs='';
1161 if (rindex ($dhcpsettings{'SORT_FLEASELIST'},'Rev') != -1) {
1162 $qs=substr ($dhcpsettings{'SORT_FLEASELIST'},0,length($dhcpsettings{'SORT_FLEASELIST'})-3);
1163 if ($qs eq 'FIPADDR') {
1164 my @a = split(/\./,$entries{$a}->{$qs});
1165 my @b = split(/\./,$entries{$b}->{$qs});
1166 ($b[0]<=>$a[0]) ||
1167 ($b[1]<=>$a[1]) ||
1168 ($b[2]<=>$a[2]) ||
1169 ($b[3]<=>$a[3]);
1170 } else {
1171 $entries{$b}->{$qs} cmp $entries{$a}->{$qs};
1172 }
1173 } else { #not reverse
1174 $qs=$dhcpsettings{'SORT_FLEASELIST'};
1175 if ($qs eq 'FIPADDR') {
1176 my @a = split(/\./,$entries{$a}->{$qs});
1177 my @b = split(/\./,$entries{$b}->{$qs});
1178 ($a[0]<=>$b[0]) ||
1179 ($a[1]<=>$b[1]) ||
1180 ($a[2]<=>$b[2]) ||
1181 ($a[3]<=>$b[3]);
1182 } else {
1183 $entries{$a}->{$qs} cmp $entries{$b}->{$qs};
1184 }
1185 }
1186 }
1187
1188 #Use an associative array (%entries)
1189 foreach my $line (@current2) {
1190 chomp( $line); #remove newline because can be on field 5 or 6 (addition of REMARK)
1191 my @temp = split (',',$line);
1192 my @record = ('FETHER',$temp[0],'FIPADDR',$temp[1],'DATA',join(',',@temp[2..6]));
1193 my $record = {}; # create a reference to empty hash
1194 %{$record} = @record; # populate that hash with @record
1195 # use combination of ether & IP as key to allow duplicates in either but not both
1196 $entries{$record->{FETHER} . $record->{FIPADDR}} = $record; # add this to a hash of hashes
1197 }
1198
1199 open(FILE, ">$filename2") or die 'Unable to open fixed lease file.';
1200 foreach my $entry ( sort fixedleasesort keys %entries) {
1201 print FILE "$entries{$entry}->{FETHER},$entries{$entry}->{FIPADDR},$entries{$entry}->{DATA}\n";
1202 }
1203 close(FILE);
1204
1205 # Reload sorted @current2
1206 open (FILE, "$filename2");
1207 @current2 = <FILE>;
1208 close (FILE);
1209 undef (%entries); #This array is reused latter. Clear it.
1210}
1211
1212# Build the configuration file mixing settings, fixed leases and advanced options
1213sub buildconf {
1214 open(FILE, ">/${General::swroot}/dhcp/dhcpd.conf") or die "Unable to write dhcpd.conf file";
1215 flock(FILE, 2);
1216
1217 # Global settings
ac1cfefa
MT
1218 print FILE "deny bootp; #default\n";
1219 print FILE "authoritative;\n";
f5fb9a04
MT
1220
1221 # DNS Update settings
1222 if ($dhcpsettings{'DNS_UPDATE_ENABLED'} eq 'on') {
1223 print FILE "ddns-updates on;\n";
1224 print FILE "ddns-update-style interim;\n";
5fd7e84c 1225 print FILE "ddns-ttl 60; # 1 min\n";
f5fb9a04
MT
1226 print FILE "ignore client-updates;\n";
1227 print FILE "update-static-leases on;\n";
1228 } else {
1229 print FILE "ddns-update-style none;\n";
1230 }
ac1cfefa
MT
1231
1232 # Write first new option definition
1233 foreach my $line (@current1) {
1234 chomp($line); # remove newline
1235 my @temp = split(/\t/,$line);
1236 if (ExistNewOptionDefinition ($temp[1] . ' ' . $temp[2])) {
1237 print FILE "option $temp[1] $temp[2];\n";
1238 }
1239 }
1240 # Write other global options
1241 foreach my $line (@current1) {
1242 chomp($line); # remove newline
1243 my @temp = split(/\t/,$line);
1244
1245 if ($temp[0] eq 'on' && !ExistNewOptionDefinition ($temp[1] . ' ' . $temp[2])){ # active & !definition
1246 my $global=1;
1247 for (my $key=0; $key<@ITFs; $key++) {
1248 my $itf = $temp[3+$key];
1249 if ($itf ne 'off') # Only if an interface name is read
1250 {
1251 $global=0;
1252 }
1253 }
1254 if ($global) {
1255 print FILE "option $temp[1] $temp[2];\n";
1256 }
1257 }# on
1258 }# foreach line
28fee676 1259 print FILE "\n";
ac1cfefa
MT
1260
1261 #Subnet range definition
1262 foreach my $itf (@ITFs) {
1263 my $lc_itf=lc($itf);
1264 if ($dhcpsettings{"ENABLE_${itf}"} eq 'on' ){
28fee676 1265 print FILE "subnet " . $netsettings{"${itf}_NETADDRESS"} . " netmask ". $netsettings{"${itf}_NETMASK"} . " #$itf\n";
ac1cfefa
MT
1266 print FILE "{\n";
1267 print FILE "\trange " . $dhcpsettings{"START_ADDR_${itf}"} . ' ' . $dhcpsettings{"END_ADDR_${itf}"}.";\n" if ($dhcpsettings{"START_ADDR_${itf}"});
1268 print FILE "\toption subnet-mask " . $netsettings{"${itf}_NETMASK"} . ";\n";
1269 print FILE "\toption domain-name \"" . $dhcpsettings{"DOMAIN_NAME_${itf}"} . "\";\n";
1270 print FILE "\toption routers " . $netsettings{"${itf}_ADDRESS"} . ";\n";
1271 print FILE "\toption domain-name-servers " . $dhcpsettings{"DNS1_${itf}"} if ($dhcpsettings{"DNS1_${itf}"});
1272 print FILE ", " . $dhcpsettings{"DNS2_${itf}"} if ($dhcpsettings{"DNS2_${itf}"});
1273 print FILE ";\n" if ($dhcpsettings{"DNS1_${itf}"});
1274 print FILE "\toption ntp-servers " . $dhcpsettings{"NTP1_${itf}"} if ($dhcpsettings{"NTP1_${itf}"});
1275 print FILE ", " . $dhcpsettings{"NTP2_${itf}"} if ($dhcpsettings{"NTP2_${itf}"});
1276 print FILE ";\n" if ($dhcpsettings{"NTP1_${itf}"});
1277 print FILE "\toption netbios-name-servers " . $dhcpsettings{"WINS1_${itf}"} if ($dhcpsettings{"WINS1_${itf}"});
1278 print FILE ", " . $dhcpsettings{"WINS2_${itf}"} if ($dhcpsettings{"WINS2_${itf}"});
1279 print FILE ";\n" if ($dhcpsettings{"WINS1_${itf}"});
d1883e28 1280 print FILE "\tnext-server " . $dhcpsettings{"NEXT_${itf}"} . ";\n" if ($dhcpsettings{"NEXT_${itf}"});
820ab96c 1281 print FILE "\tfilename \"" . &EscapeFilename($dhcpsettings{"FILE_${itf}"}) . "\";\n" if ($dhcpsettings{"FILE_${itf}"});
ac1cfefa
MT
1282 print FILE "\tdefault-lease-time " . ($dhcpsettings{"DEFAULT_LEASE_TIME_${itf}"} * 60). ";\n";
1283 print FILE "\tmax-lease-time " . ($dhcpsettings{"MAX_LEASE_TIME_${itf}"} * 60) . ";\n";
1284 print FILE "\tallow bootp;\n" if ($dhcpsettings{"ENABLEBOOTP_${itf}"} eq 'on');
1285
1286
1287
1288 # Write scoped options
1289 foreach my $line (@current1) {
1290 chomp($line); # remove newline
1291 my @temp = split(/\t/,$line); # Use TAB separator !
1292
1293 if ($temp[0] eq 'on'){
1294 for (my $key=0; $key<@ITFs; $key++) {
1295 if ($itf eq $temp[3+$key]) # Only is an interface name is read
1296 {
1297 print FILE "\toption $temp[1] $temp[2];\n";
1298 }
1299 }
1300 }# on
1301 }# foreach line
28fee676 1302 print FILE "} #$itf\n\n";
ac1cfefa 1303
f5fb9a04 1304 if (($dhcpsettings{"DNS_UPDATE_ENABLED"} eq "on") && ($dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} ne "")) {
28fee676 1305 print FILE "key " . $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} . " {\n";
f5fb9a04
MT
1306 print FILE "\talgorithm " . $dhcpsettings{"DNS_UPDATE_KEY_ALGO_${itf}"} . ";\n";
1307 print FILE "\tsecret \"" . $dhcpsettings{"DNS_UPDATE_KEY_SECRET_${itf}"} . "\";\n";
1308 print FILE "};\n\n";
1309
1310 print FILE "zone " . $dhcpsettings{"DOMAIN_NAME_${itf}"} . ". {\n";
1311 print FILE "\tkey " . $dhcpsettings{"DNS_UPDATE_KEY_NAME_${itf}"} . ";\n";
1312 print FILE "}\n\n";
1313 }
ac1cfefa 1314
9833e7d8 1315 system ('/usr/bin/touch', "${General::swroot}/dhcp/enable_${lc_itf}");
ac1cfefa
MT
1316 &General::log("DHCP on ${itf}: " . $Lang::tr{'dhcp server enabled'})
1317 } else {
1318 unlink "${General::swroot}/dhcp/enable_${lc_itf}";
1319 &General::log("DHCP on ${itf}: " . $Lang::tr{'dhcp server disabled'})
1320 }
1321 }
1322
1323 #write fixed leases if any. Does not handle duplicates to write them elsewhere than the global scope.
1324 my $key = 0;
1325 foreach my $line (@current2) {
1326 chomp($line);
1327 my @temp = split(/\,/,$line);
1328 if ($temp[2] eq "on") {
1329 print FILE "\nhost fix$key # $temp[6]\n";
1330 print FILE "{\n";
1331 print FILE "\thardware ethernet $temp[0];\n";
1332 print FILE "\tfixed-address $temp[1];\n";
1333 print FILE "\tnext-server $temp[3];\n" if ($temp[3]);
820ab96c 1334 print FILE "\tfilename \"" . &EscapeFilename($temp[4]) . "\";\n" if ($temp[4]);
ac1cfefa
MT
1335 print FILE "\toption root-path \"$temp[5]\";\n" if ($temp[5]);
1336 print FILE "}\n";
1337 $key++;
1338 }
1339 }
55b2f2eb 1340 print FILE "include \"${General::swroot}/dhcp/dhcpd.conf.local\";\n";
ac1cfefa 1341 close FILE;
32ab16de
CS
1342 if ( $dhcpsettings{"ENABLE_GREEN"} eq 'on' || $dhcpsettings{"ENABLE_BLUE"} eq 'on' ) {system '/usr/local/bin/dhcpctrl enable >/dev/null 2>&1';}
1343 else {system '/usr/local/bin/dhcpctrl disable >/dev/null 2>&1';}
4eb23a91 1344 system '/usr/local/bin/dhcpctrl restart >/dev/null 2>&1 &';
ac1cfefa
MT
1345}
1346
1347#
1348# Receive a string and if it match model for a new option,
1349# add it to the list %newOptions
1350#
1351my %NewOptions = ();
1352
1353sub AddNewOptionDefinition {
1354 my ($line) = @_;
1355 if ( $line =~ /^([-\w]+)( code \d+=($OptionTypes))/ ) {
1356 $NewOptions{$1} = $2;
1357 #&General::log ("new:<$1><$2>");
1358 return 1;
1359 }
1360 return 0;
1361}
1362
1363#
1364# Check existence of definition for a new option
1365#
1366sub ExistNewOptionDefinition {
1367 my ($line) = @_;
1368
1369 if ( $line =~ /^([-\w]+)( code \d+=($OptionTypes))/ ) {
1370 return defined $NewOptions{$1};
1371 }
1372 return 0;
1373}
1374
1375#
1376# Check if it is a new option (definition must exist)
1377# "code=" test eliminate a false response when definition exists
1378# but this string is a definition with bad $OptionTypes.
1379sub ValidNewOption {
1380 my ($line) = @_;
1381 if ($line =~ /^([-\w]+) (.*)/ ) {
1382 return defined ( $NewOptions{$1} ) && $2 !~ /code=/;
1383 }
1384 return 0;
1385}
1386
1387#
1388# Check if the new option $opt is used, except the definition of itself!
1389#
1390sub IsUsedNewOptionDefinition {
1391 my ($opt,$val) = @_;
1392
1393 foreach my $line (@current1) {
1394 #chomp($line); # remove newline #don't know why, but this remove newline in @current1 .... !
1395 my @temp = split(/\t/,$line);
1396 # if we find something "opt value" & value != "code nnn=" it's ok.
1397 return 1 if ( ($opt eq $temp[1]) && ($temp[2] !~ /code \d+=/) );
1398 }
1399 return 0;
1400}
820ab96c
MT
1401
1402sub EscapeFilename($) {
1403 my $filename = shift;
1404
1405 # Replace all single / by \/
1406 $filename =~ s/\//\\\//g;
1407
1408 return $filename;
1409}