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