Gro├čes Update:
[ipfire-2.x.git] / html / cgi-bin / base.cgi
CommitLineData
ac1cfefa
MT
1#!/usr/bin/perl
2#
78331e30 3# IPFire CGI's - base.cgi
ac1cfefa
MT
4#
5# This code is distributed under the terms of the GPL
6#
7# (c) place a name here
8#
9# $Id: base.cgi,v 1.1.2.10 2005/11/03 19:20:50 franck78 Exp $
10#
11#
12
13
14# This file is a starting base for writting a new GUI screen using the three box model
15# Box 1 : global settings for the application
16# Box 2 : line editor for multiple data line
17# Box 3 : the list of data line, with edit/remove buttons
18#
19# This example do the following
20# Read global settings:
21# a NAME and an interface (IT)
22# Lines of data composed of:
23# an ipaddress (IP), an enabled/disabled options (CB), a comment (CO)
24#
25#
26# All you need to do is
27# replace 'XY' with your app name
28# define your global $settings{'var name'}
29# define your strings
30# write validation code for Settings1 and Settings2
31# write HTML box Settings1 and Settings2
32# adapt the sort function
33# write the correct configuration file
34#
35#
36# to fully troubleshot your code, uncomment diagnostics, Carp and cluck lines
37# use diagnostics; # need to add the file /usr/lib/perl5/5.8.x/pods/perldiag.pod before to work
38# next look at /var/log/httpd/error_log , http://www.perl.com/pub/a/2002/05/07/mod_perl.html may help
39#use warnings;
40use strict;
41#use Carp ();
42#local $SIG{__WARN__} = \&Carp::cluck;
43
78331e30
MT
44require '/var/ipfire/general-functions.pl'; # Replace all occurences of </var/ipfire> with CONFIG_ROOT
45 # before updating cvs IPFire file.
ac1cfefa
MT
46require "${General::swroot}/lang.pl";
47require "${General::swroot}/header.pl";
48
49# Files used
50our $setting = "${General::swroot}/XY/settings"; # particular settings
51my $datafile = "${General::swroot}/XY/data"; # repeted settings (multilines)
52our $conffile = "${General::swroot}/XY/XY.conf"; # Config file for application XY
53
54# strings to add to languages databases or in addon language file
55$Lang::tr{'XY title'} = 'XY service';
56$Lang::tr{'XY settings'} = 'XY setup';
57$Lang::tr{'XY add data'} = 'add data';
58$Lang::tr{'XY edit data'} = 'edit data';
59$Lang::tr{'XY data'} = 'XY data';
60
61# informationnal & log strings, no translation required
62my $msg_added = 'XY added';
63my $msg_modified = 'XY modified';
64my $msg_deleted = 'XY removed';
65my $msg_datafileerror = 'XY data file error';
66our $msg_configfileerror = 'XY configuration file error';
67
68my %settings=();
69
70# Settings1
71$settings{'NAME'} = ''; # a string field than must be 'GOOD' or 'good'
72$settings{'IT'} = ''; # a 'choose' field for color interface
73$settings{'TURBO'} = 'off'; # a checkbox field to enable something
74
75# Settings2 for editing the multi-line list
76# Must not be saved by writehash !
77$settings{'IP'} = ''; # datalines are: IPaddress,enable,comment
78$settings{'CB'} = 'off'; # Every check box must be set to off
79$settings{'COMMENT'} = '';
80my @nosaved=('IP','CB','COMMENT'); # List here ALL setting2 fields. Mandatory
81
82$settings{'ACTION'} = ''; # add/edit/remove....
83$settings{'KEY1'} = ''; # point record for ACTION
84
85# Define each field that can be used to sort columns
86my $sortstring='^IP|^COMMENT';
87my $errormessage = '';
88my $warnmessage = '';
89
90&Header::showhttpheaders();
91
92# Read needed Ipcop settings (exemple)
93my %mainsettings=();
94&General::readhash("${General::swroot}/main/settings", \%mainsettings);
95
96# Get GUI values
97&Header::getcgihash(\%settings);
98
99# Load multiline data. Do it before use in save action
100our $f = new Multilines (filename => $datafile,
101 fields => ['IP','CB','COMMENT'],
102 comment => 1
103 );
104
105##
106## SAVE Settings1
107##
108# Remove if no Settings1 needed
109if ($settings{'ACTION'} eq $Lang::tr{'save'}) {
110
111 #
112 #Validate static Settings1 here
113 #
114 if (($settings{"NAME"} ne "GOOD") &&
115 ($settings{"NAME"} ne "good")) {
116 $errormessage = 'Enter good or GOOD in Name field';
117 }
118
119 unless ($errormessage) { # Everything is ok, save settings
120 map (delete ($settings{$_}) ,(@nosaved,'ACTION','KEY1'));# Must never be saved
121 &General::writehash($setting, \%settings); # Save good settings
122 $settings{'ACTION'} = $Lang::tr{'save'}; # Recreate 'ACTION'
123 map ($settings{$_}= '',(@nosaved,'KEY1')); # and reinit var to empty
124
125 # Rebuild configuration file if needed
126 &BuildConfiguration;
127 }
128
129 ERROR: # Leave the faulty field untouched
130} else {
131 &General::readhash($setting, \%settings); # Get saved settings and reset to good if needed
132}
133
134##
135## Now manipulate the multiline list with Settings2
136##
137
138# Basic actions are:
139# toggle the check box
140# add/update a new line
141# begin editing a line
142# remove a line
143# $KEY1 contains the index of the line manipulated
144
145##
146## Toggle CB field.
147##
148if ($settings{'ACTION'} eq $Lang::tr{'toggle enable disable'}) {
149
150 $f->togglebyfields($settings{'KEY1'},'CB'); # toggle checkbox
151 $settings{'KEY1'} = ''; # End edit mode
152
153 &General::log($msg_modified);
154
155 # save changes
156 $f->savedata || die "$msg_datafileerror";
157
158 # Rebuild configuration file
159 &BuildConfiguration;
160}
161
162##
163## ADD/UPDATE a line of configuration from Settings2
164##
165if ($settings{'ACTION'} eq $Lang::tr{'add'}) {
166 # Validate inputs
167 if (! &General::validip($settings{'IP'})) {$errormessage = "Specify an IP value !"};
168 if (! $settings{'COMMENT'} ) {$warnmessage = "no comment specified"};
169
170 unless ($errormessage) {
171 if ($settings{'KEY1'} eq '') { #add or edit ?
172 # insert new data line
173 $f->writedata(-1, $settings{'IP'},$settings{'CB'},$settings{'COMMENT'});
174 &General::log($msg_added);
175 } else {
176 # modify data line
177 $f->writedata($settings{'KEY1'}, $settings{'IP'},$settings{'CB'},$settings{'COMMENT'});
178 $settings{'KEY1'} = ''; # End edit mode
179 &General::log($msg_modified);
180 }
181 # save changes
182 $f->savedata || die "$msg_datafileerror";
183
184 # Rebuild configuration file
185 &BuildConfiguration;
186
187 # if entering data line is a repetitive task, choose here to not erase fields between each addition
188 map ($settings{$_}='' ,@nosaved);
189 }
190}
191
192##
193## begin EDIT: move data fields to Settings2 controls
194##
195if ($settings{'ACTION'} eq $Lang::tr{'edit'}) {
196 $f->readdata ($settings{'KEY1'},
197 $settings{'IP'},
198 $settings{'CB'},
199 $settings{'COMMENT'});
200}
201##
202## REMOVE: remove selected line
203##
204if ($settings{'ACTION'} eq $Lang::tr{'remove'}) {
205 $f->deleteline ($settings{'KEY1'});
206 $settings{'KEY1'} = ''; # End remove mode
207 &General::log($msg_deleted);
208
209 # save changes
210 $f->savedata || die "$msg_datafileerror";
211
212 # Rebuild configuration file
213 &BuildConfiguration;
214}
215
216
217##
218## Check if sorting is asked
219##
220if ($ENV{'QUERY_STRING'} =~ /$sortstring/ ) {
221 my $newsort=$ENV{'QUERY_STRING'};
222 my $actual=$settings{'SORT_XY'};
223
224 # Reverse actual sort or choose new column ?
225 if ($actual =~ $newsort) {
226 $f->setsortorder ($newsort ,rindex($actual,'Rev'));
227 $newsort .= rindex($actual,'Rev')==-1 ? 'Rev' : '';
228 } else {
229 $f->setsortorder ($newsort ,1);
230 }
231 $f->savedata; # Synchronise file & display
232 $settings{'SORT_XY'} = $newsort;
233 map (delete ($settings{$_}) ,(@nosaved,'ACTION','KEY1')); # Must never be saved
234 &General::writehash($setting, \%settings);
235 $settings{'ACTION'} = 'SORT'; # Recreate an 'ACTION'
236 map ($settings{$_}= '',(@nosaved,,'KEY1')); # and reinit var to empty
237}
238
239##
240## Remove if no Setting1 needed
241##
242if ($settings{'ACTION'} eq '' ) { # First launch from GUI
243 # Place here default value when nothing is initialized
244
245}
246
247&Header::openpage($Lang::tr{'XY title'}, 1, '');
248&Header::openbigbox('100%', 'left', '', $errormessage);
249my %checked =(); # Checkbox manipulations
250
251if ($errormessage) {
252 &Header::openbox('100%', 'left', $Lang::tr{'error messages'});
253 print "<font class='base'>$errormessage&nbsp;</font>";
254 &Header::closebox();
255}
256
257##
258## First box Settings1. Remove if not needed
259##
260$warnmessage = "<font color=${Header::colourred}><b>$Lang::tr{'capswarning'}</b></font>: $warnmessage" if ($warnmessage);
261
262&Header::openbox('100%', 'left', $Lang::tr{'XY settings'});
263print "<form method='post' action='$ENV{'SCRIPT_NAME'}'>";
264$checked{'IT'}{'RED'} = '';
265$checked{'IT'}{'GREEN'} = '';
266$checked{'IT'}{'ORANGE'} = '';
267$checked{'IT'}{'BLUE'} = '';
268$checked{'IT'}{$settings{'IT'}} = "checked='checked'";
269$checked{'TURBO'} = ($settings{'TURBO'} eq 'on') ? "checked='checked'" : '';
270
271print<<END
272<table width='100%'>
273<tr>
274 <td class='base'>Name:</td>
275 <td><input type='text' name='NAME' value='$settings{'NAME'}' /></td>
276 <td align='right'>INTERFACE</td>
277 <td align='right'>red<input type='radio' name='IT' value='RED' $checked{'IT'}{'RED'} /></td>
278</tr><tr>
279 <td>Turbo:</td>
280 <td><input type='checkbox' name='TURBO' $checked{'TURBO'}' /></td>
281 <td></td>
282 <td align='right'>green<input type='radio' name='IT' value='GREEN' $checked{'IT'}{'GREEN'} /></td>
283</tr><tr>
284 <td></td>
285 <td></td>
286 <td></td>
287 <td align='right'>blue<input type='radio' name='IT' value='BLUE' $checked{'IT'}{'BLUE'} /></td>
288</tr><tr>
289 <td></td>
290 <td></td>
291 <td></td>
292 <td align='right'>orange<input type='radio' name='IT' value='ORANGE' $checked{'IT'}{'ORANGE'} /></td>
293</tr>
294</table>
295<br />
296END
297;
298
299print<<END
300<table width='100%'>
301<hr />
302<tr>
303 <td class='base' width='25%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'this field may be blank'}</td>
304 <td class='base' width='25%'>$warnmessage</td>
305 <td width='50%' align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' /></td>
306</tr>
307</table>
308</form>
309END
310;
311&Header::closebox(); # end of Settings1
312
313##
314## Second box is for editing the an item of the list
315##
316$checked{'CB'} = ($settings{'CB'} eq 'on') ? "checked='checked'" : '';
317
318my $buttontext = $Lang::tr{'add'};
319if ($settings{'KEY1'} ne '') {
320 $buttontext = $Lang::tr{'update'};
321 &Header::openbox('100%', 'left', $Lang::tr{'XY edit data'});
322} else {
323 &Header::openbox('100%', 'left', $Lang::tr{'XY add data'});
324}
325
326# Edited line number (KEY1) passed until cleared by 'save' or 'remove' or 'new sort order'
327print <<END
328<form method='post' action='$ENV{'SCRIPT_NAME'}'>
329<input type='hidden' name='KEY1' value='$settings{'KEY1'}' />
330<table width='100%'>
331<tr>
332 <td class='base'>$Lang::tr{'ip address'}:</td>
333 <td><input type='text' name='IP' value='$settings{'IP'}' /></td>
334 <td class='base'>$Lang::tr{'enabled'}</td>
335 <td><input type='checkbox' name='CB' $checked{'CB'} /></td>
336 <td class='base'>$Lang::tr{'remark'}:&nbsp;<img src='/blob.gif' alt='*' /></td>
337 <td><input type 'text' name='COMMENT' value='$settings{'COMMENT'}' /></td>
338</tr>
339</table>
340<hr />
341<table width='100%'>
342<tr>
343 <td class='base' width='50%'><img src='/blob.gif' align='top' alt='*' />&nbsp;$Lang::tr{'this field may be blank'}</td>
344 <td width='50%' align='center'><input type='hidden' name='ACTION' value='$Lang::tr{'add'}' /><input type='submit' name='SUBMIT' value='$buttontext' /></td>
345</tr>
346</table>
347</form>
348END
349;
350&Header::closebox();
351
352##
353## Third box shows the list
354##
355
356# Columns headers may be a sort link. In this case it must be named in $sortstring
357&Header::openbox('100%', 'left', $Lang::tr{'XY data'});
358print <<END
359<table width='100%'>
360<tr>
361 <td width='20%' align='center'><a href='$ENV{'SCRIPT_NAME'}?IP'><b>$Lang::tr{'ip address'}</b></a></td>
362 <td width='70%' align='center'><a href='$ENV{'SCRIPT_NAME'}?COMMENT'><b>$Lang::tr{'remark'}</b></a></td>
363 <td width='10%' colspan='3' class='boldbase' align='center'><b>$Lang::tr{'action'}</b></td>
364</tr>
365END
366;
367
368##
369## Print each line of @current list
370##
371my $key = 0;
372$f->readreset; # beginning of data
373for ($key=0; $key<$f->getnumberofline; $key++) {
374
375 my($cb,$comment,$ip) = $f->readbyfieldsseq($key,'CB','COMMENT','IP');
376
377 #Choose icon for checkbox
378 my $gif = '';
379 my $gdesc = '';
380 if ($cb eq "on") {
381 $gif = 'on.gif';
382 $gdesc = $Lang::tr{'click to disable'};
383 } else {
384 $gif = 'off.gif';
385 $gdesc = $Lang::tr{'click to enable'};
386 }
387
388 #Colorize each line
389 if ($settings{'KEY1'} eq $key) {
390 print "<tr bgcolor='${Header::colouryellow}'>";
391 } elsif ($key % 2) {
392 print "<tr bgcolor='${Header::table2colour}'>";
393 } else {
394 print "<tr bgcolor='${Header::table1colour}'>";
395 }
396
397 print <<END
398<td align='center'>$ip</td>
399<td align='center'>$comment</td>
400
401<td align='center'>
402<form method='post' action='$ENV{'SCRIPT_NAME'}'>
403<input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
404<input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif' alt='$gdesc' title='$gdesc' />
405<input type='hidden' name='KEY1' value='$key' />
406</form>
407</td>
408
409<td align='center'>
410<form method='post' action='$ENV{'SCRIPT_NAME'}'>
411<input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
412<input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif' alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
413<input type='hidden' name='KEY1' value='$key' />
414</form>
415</td>
416
417<td align='center'>
418<form method='post' action='$ENV{'SCRIPT_NAME'}'>
419<input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
420<input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif' alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
421<input type='hidden' name='KEY1' value='$key' />
422</form>
423</td>
424</tr>
425END
426;
427} print "</table>";
428
429# If table contains entries, print 'Key to action icons'
430if ($key) {
431print <<END
432<table>
433<tr>
434 <td class='boldbase'>&nbsp;<b>$Lang::tr{'legend'}:&nbsp;</b></td>
435 <td><img src='/images/on.gif' alt='$Lang::tr{'click to disable'}' /></td>
436 <td class='base'>$Lang::tr{'click to disable'}</td>
437 <td>&nbsp;&nbsp;</td>
438 <td><img src='/images/off.gif' alt='$Lang::tr{'click to enable'}' /></td>
439 <td class='base'>$Lang::tr{'click to enable'}</td>
440 <td>&nbsp;&nbsp;</td>
441 <td><img src='/images/edit.gif' alt='$Lang::tr{'edit'}' /></td>
442 <td class='base'>$Lang::tr{'edit'}</td>
443 <td>&nbsp;&nbsp;</td>
444 <td><img src='/images/delete.gif' alt='$Lang::tr{'remove'}' /></td>
445 <td class='base'>$Lang::tr{'remove'}</td>
446</tr>
447</table>
448END
449;
450}
451
452&Header::closebox();
453&Header::closebigbox();
454&Header::closepage();
455
456## Ouf it's the end !
457
458##
459## Build the configuration file for application XY
460##
461sub BuildConfiguration {
462 open(FILE, ">/$conffile") or die "$msg_configfileerror";
463 flock(FILE, 2);
464
465 #Global settings
466 print FILE "#\n# Configuration file for application XY\n#\n\n";
467 print FILE "# do not edit manually\n";
468 print FILE "# build for Ipcop:$mainsettings{'HOSTNAME'}\n\n\n";
469 print FILE "service=$settings{'NAME'}\n";
470 print FILE "activate-turbo\n" if $settings{'TURBO'} eq 'on';
471 print FILE "interface=$settings{'IT'}\n\n\n";
472 #write data line
473 {
474 my ($IP,$CB,$COMMENT);
475 $f->readreset;
476 while (defined ($f->readdataseq($IP,$CB,$COMMENT))) {
477 if ($CB eq "on") {
478 print FILE "$IP\t\t\t\t\t#$COMMENT\n";
479 } else {
480 print FILE "#DISABLED $IP\t\t\t\t#$COMMENT\n";
481 }
482 }
483 }
484 close FILE;
485
486 # Restart service
487 #system '/usr/local/bin/restartyourhelper';
488}