~vcs-imports/ipfire/ipfire-2.x

« back to all changes in this revision

Viewing changes to html/cgi-bin/dhcp.cgi

  • Committer: ipfire
  • Date: 2006-02-15 21:15:54 UTC
  • Revision ID: git-v1:cd1a2927226c734d96478e12bb768256fb64a06a


git-svn-id: http://svn.ipfire.org/svn/ipfire/IPFire/source@16 ea5c0bd1-69bd-2848-81d8-4f18e57aeed8

Show diffs side-by-side

added added

removed removed

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