Handle hostnames with upper-case letters
[webmin.git] / smf / wizard.pl
1 #!/usr/local/bin/perl
2 #
3 # Code for a generic cgi wizard. The wizard save
4 # for each stage in the process, provides validation of fields via 
5 # regular expressions, and manages button presses etc. It allows pages
6 # to be used to enter multiple sets of values, all of which are stored.
7 #
8 #       1) create a wizard array. Each array element specifies
9 #       a page in the wizard. Each element should be a comma-separated
10 #       string, containing the following values:
11 #               - "page": the .cgi file for the page
12 #               - "min": the minimum valid number of datafiles
13 #               required for this page
14 #               - "max": the maximum valid number of datafiles
15 #               required for this page.
16 #       An example of a valid entry would be "page=mywizpage.cgi,min=1,max=1".
17 #
18 #       The wizard allows pages to be used to enter multiple sets of
19 #       properties. Each wizard page has an associated data file, and
20 #       where multiple datafiles are valid (i.e. max_datafiles>1),
21 #       they are numbered monotonically.
22 #       2) Create a .cgi file for each wizard page you specified in the
23 #       wizard array. Each wizard page will call wizard_header(),
24 #       wizard_[inputtype]() for each data field and wizard_footer().
25 #       3) Create a submit .cgi script that processes the set of datafiles
26 #       created.
27 #
28 # Appearance:
29 #
30 # Wizard consists of a main table holding 3 subtables
31 #       - the description/image table, taking up the LHS
32 #       - the data table, where fields appear, on the RHS
33 #       - the button table on the bottom
34 # The data table is opened, and rows are added by calls
35 # to wizard_input(). wizard_footer() adds the button table.
36
37
38
39 # This variable is set to 0 whenever an element in the form fails to
40 # validate against its regular expression. This prevents progress, and the
41 # highlighted elements are marked in red.
42 $validation_success = 1;
43
44 # Creates tables/subtables, show image etc.
45 #
46 # Parameters: ref_to_array_of_wizard_element_hashes, pagename, heading,
47 # description, imagename
48 #
49 sub wizard_header()
50 {
51 local ($wizinfo, %wizard, $wizref, $pagename, $heading, $description, $image);
52 ($wizinfo, $pagename, $heading, $description, $image) = @_;
53 %wizard = &read_in_wizard("$wizinfo");
54 $wizref = \%wizard;
55 $pageinst = &wizard_get_pageinst();
56 $submit = &get_wizard_info_by_name($wizref, "submit");
57 print "<form method=\"POST\" action=\"$submit\">\n";
58 print "<table border cellpadding=0 cellspacing=0 width=100%>\n";
59 print "<tr $cb><td>\n";
60 print "<table noborder cellpadding=0 cellspacing=0 width=100% height=15%>\n";
61 print "<tr $tb><td>$heading</td></tr></table></td></tr>\n";
62 print "<tr $cb><td>\n";
63 print "<table border cellpadding=0 cellspacing=0 width=100% height=70%>\n";
64
65 # LHS consists description + optional image.
66 print "<tr $cb><td>\n";
67 print "<table noborder cellpadding=0 cellspacing=0>\n";
68 if ($image =~ /.+/) {
69         print "<tr $cb><td><img src=$image alt=\"\"></td>\n";
70         }
71 print "<td><p>$description</p></td></tr></table></td>\n";
72
73 # RHS contains information supplied by calls to wizard_input(), i.e.
74 # it`s where data is entered. We open this table and close it with
75 # wizard_footer() below...
76
77 print "<td><table noborder cellpadding=0 cellspacing=0>\n";
78 }
79
80 sub wizard_footer()
81 {
82 local ($wizinfo, $pagename, %wizard, $wizref, $min_datafiles, $max_datafiles,
83         $pageinst, $pagenum, $datafile, $back_disabled, $next_disable,
84         $add_disabled, $remove_disabled, $finish_disabled, @wizard_pages,
85         $page, @datafiles);
86 ($wizinfo, $pagename) = @_;
87 %wizard = &read_in_wizard("$wizinfo");
88 $wizref = \%wizard;
89 $pageinst = &wizard_get_pageinst();
90
91 $min_datafiles = &get_wizard_info_by_name($wizref, "min_datafiles", $pagename);
92 $max_datafiles = &get_wizard_info_by_name($wizref, "max_datafiles", $pagename);
93 $pagenum = &get_wizard_info_by_name($wizref, "pagenum", $pagename);
94 $datafile = &wizard_datafile_name($pagename, $pageinst);
95
96 # which buttons do we show?
97
98 $back_disabled = "";
99 # first page, first instance, so no back button
100 if (($pagenum == 0) && ($pageinst == 0)) {
101         $back_disabled="disabled=\"disabled\"";
102         }
103
104 $next_disabled = "disabled=\"disabled\"";
105 # if we have met or exceeded minimum requirement of datafiles for
106 # this page, and are not on last page, or there are subsequent
107 # instances, enable next button
108 @datafiles = &list_wizard_datafiles($pagename);
109 @num_pages = &get_wizard_info_by_name($wizref, "pages");
110 @num_pageinsts = &list_wizard_datafiles($pagename);
111 if ((($pagenum < (@num_pages - 1)) && (@datafiles >= $min_datafiles)) ||
112         (($pageinst < (@num_pageinsts - 1)))) {
113         $next_disabled = "";
114         }
115
116 $add_disabled = "";
117 $update_disabled = "disabled=\"disabled\"";
118 $new_disabled = "disabled=\"disabled\"";
119 $remove_disabled="disabled=\"disabled\"";
120 # if we have data already for page, dont disable remove/clear, disable add,
121 # enable update
122 @thispage_datafiles = &list_wizard_datafiles("$pagename.$pageinst");
123 if (@thispage_datafiles > 0) {
124         $remove_disabled = "";
125         $add_disabled = "disabled=\"disabled\"";
126         $update_disabled = "";
127         # enable new if we can have more instances....
128         if ($pageinst < ($max_datafiles - 1)) {
129                 $new_disabled = "";
130                 }
131         }
132
133 # can we show finish button? if each page has exceeded it`s minimum
134 # amount of datafiles, and each datafile has validation_success == 1, yes.
135 $finish_disabled = "";
136 @wizard_pages = &get_wizard_info_by_name($wizref, "pages");
137 foreach $page (@wizard_pages) {
138         @datafiles = &list_wizard_datafiles("$page->{'pagename'}");
139         foreach $datafile (@datafiles) {
140                 # get instance number...
141                 $datafile =~ /$page->{'pagename'}\.([0-9]*)/;
142                 $inst = $1;
143                 $validated = &wizard_get_data_value($page->{'pagename'},
144                         $inst, "validation_success");
145                 if ($validated != 1) {
146                         # instance not valid!
147                         $finish_disabled = "disabled=\"disabled\"";
148                         }
149                 }
150         $page_min_datafiles = &get_wizard_info_by_name($wizref, "min_datafiles",
151                 "$page->{'pagename'}");
152         if (@datafiles < $page_min_datafiles) {
153                 # haven't got minimum number of instances!
154                 $finish_disabled = "disabled=\"disabled\"";
155                 }
156         }
157 # close data table
158 print "</table></td></tr></table></td></tr>\n";
159
160 # include hidden parameters here. These are:
161 #       - pagename: current pagename
162 #       - pageinst: current pageinst
163 print "<input type=\"hidden\" name=\"pagename\" value=\"$pagename\">";
164 print "<input type=\"hidden\" name=\"pageinst\" value=\"$pageinst\">";
165
166 # open button window
167 print "<tr $cb><td>\n";
168 print "<table noborder cellpadding=0 cellspacing=0 width=100% height=15%>";
169 print "<tr $cb><td>\n";
170 print
171   "<input type=\"submit\" name=\"submit\" value=\"$text{'wizard_back'}\" $back_disabled>\n";
172 print "</td><td>\n";
173 print
174   "<input type=\"submit\" name=\"submit\" value=\"$text{'wizard_new'}\" $new_disabled>\n";
175 print "</td><td>\n";
176 print
177   "<input type=\"submit\" name=\"submit\" value=\"$text{'wizard_add'}\" $add_disabled>\n";
178 print "</td><td>\n";
179 print
180   "<input type=\"submit\" name=\"submit\" value=\"$text{'wizard_update'}\" $update_disabled>\n";
181 print "</td><td>\n";
182 print
183    "<input type=\"submit\" name=\"submit\" value=\"$text{'wizard_remove'}\" $remove_disabled>\n";
184 print "</td><td>\n";
185 print
186   "<input type=\"submit\" name=\"submit\" value=\"$text{'wizard_next'}\" $next_disabled>\n";
187 print "</td><td>\n";
188 print
189  "<input type=\"submit\" name=\"submit\" value=\"$text{'wizard_finish'}\" $finish_disabled>\n";
190 print "</td></tr></table></td></tr></table></form>\n";
191
192 # if we are validating page, ensure that we redirect!
193 if ($validation_success == 1) {
194         # do redirect if next page/inst are defined
195         &wizard_redirect_next($pagename, $pageinst);
196         }
197 }
198
199 sub wizard_input()
200 {
201 local ($pagename, $description, $name, $size, $validation_regexp,
202         $validation_err, $pageinst, $value);
203 ($pagename, $description, $name, $size, $validation_regexp, $validation_err)
204         = @_;
205 $value = &wizard_form_input_header($pagename, $description, $name,
206         $validation_regexp, $validation_err);
207 print "<input size=$size name=\"$name\" value=\"$value\">\n";
208 &wizard_form_input_footer();
209 }
210
211 sub wizard_textarea()
212 {
213 local ($pagename, $description, $name, $rows, $cols, $validation_regexp,
214         $validation_err, $pageinst, $value);
215 ($pagename, $description, $name, $rows, $cols,  $validation_regexp,
216         $validation_err) = @_;
217 $value = &wizard_form_input_header($pagename, $description, $name,
218         $validation_regexp, $validation_err);
219 print "<textarea rows=$rows cols=$cols name=\"$name\" wrap=\"virtual\">\n";
220 print "$value";
221 print "</textarea>\n";
222 &wizard_form_input_footer();
223 }
224
225 sub wizard_select()
226 {
227 local ($pagename, $description, $name, $selection_arrayref, $validation_regexp,
228         $validation_err, $pageinst, $value, @array, $elt, $select);
229 ($pagename, $description, $name, $selection_arrayref, $validation_regexp,
230         $validation_err) = @_;
231 $value = &wizard_form_input_header($pagename, $description, $name,
232         $validation_regexp, $validation_err);
233 print "<select name=\"$name\" size=1>\n";
234 @array = @$selection_arrayref;
235 foreach $elt (@array) {
236         $select = "";
237         if ("$elt" eq "$value") {
238                 $select = "selected";
239                 }
240         print "<option $select>$elt</option>\n";
241         }
242 print "</select>\n";
243 &wizard_form_input_footer();
244 }
245
246 # subfns used for wizard form inputs...
247
248 sub wizard_form_input_header()
249 {
250 local ($pagename, $description, $name, $validation_regexp,
251         $validation_err, $pageinst, $value);
252 ($pagename, $description, $name, $validation_regexp, $validation_err) = @_;
253 $pageinst = &wizard_get_pageinst();
254 $value = &wizard_get_data_value($pagename, $pageinst, $name);
255 &wizard_validate_input($value, $validation_regexp, $validation_err);
256 print "<tr $cb><td><p>$description</p></td></tr><tr $cb><td>\n";
257 return $value;
258 }
259
260 sub wizard_form_input_footer()
261 {
262 print "</td></tr>\n";
263 }
264
265 # Deals with page submission
266 #
267 # Parameters: ref_to_array_of_wizard_element_hashes, pagename, heading,
268 # description, imagename
269 #
270 sub wizard_process_submit()
271 {
272 local ($wizinfo, %wizard, $wizref, $pagename, $heading, $description, $image);
273 ($wizinfo, $pagename, $heading, $description, $image) = @_;
274 %wizard = &read_in_wizard("$wizinfo");
275 $wizref = \%wizard;
276 $pageinst = &wizard_get_pageinst();
277 if (defined($in{'submit'})) {
278         $button_name = $in{'submit'};
279 } else {
280         &error("No button name passed to wizard_process_submit!");
281         }
282 if ($button_name eq "$text{'wizard_finish'}") {
283         # finish is the submit scripts problem!
284         return;
285         }
286 if (defined($in{'pagename'})) {
287         $pagename = $in{'pagename'};
288 } else {
289         &error("No page name passed to wizard_process_submit!");
290         }
291 if (defined($in{'pageinst'})) {
292         $pageinst = $in{'pageinst'};
293 } else {
294         &error("No page instance passed to wizard_process_submit!");
295         }
296 if ($button_name eq "$text{'wizard_back'}") {
297         # find previous page
298         $previous_pagename = $pagename;
299         $previous_pageinst = $pageinst;
300         $pagenum = &get_wizard_info_by_name($wizref, "pagenum",
301                 $pagename);
302         if (($pageinst == 0) && ($pagenum > 0)) {
303                 $previous_pagenum = $pagenum - 1;
304                 $previous_pagename = &get_wizard_info_by_page($wizref,
305                         "pagename", $previous_pagenum);
306                 @num_pageinsts = &list_wizard_datafiles($previous_pagename);
307                 if (@num_pageinsts > 0) {
308                         $previous_pageinst = @num_pageinsts - 1;
309                         }
310         } elsif ($pageinst > 0) {
311                 $previous_pageinst = $pageinst - 1;
312                 }
313         # validation needed? does data already exist for page?
314         $validate_option = "";
315         $previous_datafile = "$previous_pagename.$previous_pageinst";
316         @datafiles =  &list_wizard_datafiles($previous_datafile);
317         if (@datafiles > 0) {
318                 $validate_option = "&validate=1";
319                 }
320         &redirect
321           ("$previous_pagename?pageinst=$previous_pageinst$validate_option");
322         }
323 if ($button_name eq "$text{'wizard_next'}") {
324         # find next page
325         $next_pagename = $pagename;
326         $next_pageinst = $pageinst;
327         @num_pageinsts = &list_wizard_datafiles($pagename);
328         $lastinst = 0;
329         if (@num_pageinsts > 0) {
330                 $lastinst = @num_pageinsts - 1;
331                 }
332         if ($pageinst >= $lastinst) {
333                 $pagenum = &get_wizard_info_by_name($wizref, "pagenum",
334                         $pagename);
335                 @num_pages = &get_wizard_info_by_name($wizref, "pages");
336                 if ($pagenum < (@num_pages - 1)) {
337                         $next_pagenum = $pagenum + 1;
338                         $next_pagename = &get_wizard_info_by_page($wizref,
339                                 "pagename", $next_pagenum);
340                         $next_pageinst = 0;
341                         }
342         } else {
343                 $next_pageinst = $pageinst + 1;
344                 }
345         # validation needed? does data already exist for page?
346         $next_datafile = "$next_pagename.$next_pageinst";
347         @datafiles = &list_wizard_datafiles($next_datafile);
348         $validate_option= "";
349         if (@datafiles > 0) {
350                 $validate_option = "&validate=1";
351                 }
352         &redirect("$next_pagename?pageinst=$next_pageinst$validate_option");
353         }
354 if ($button_name eq "$text{'wizard_new'}") {
355         # for new, if we have less than full complement of instances,
356         # use the last unused instance, otherwise stay here
357         $next_pagename = $pagename;
358         $next_pageinst = $pageinst;
359         @num_pageinsts = &list_wizard_datafiles($pagename);
360         $max_inst = &get_wizard_info_by_name($wizref, "max_datafiles",
361                 $pagename);
362         if (@num_pageinsts <= $max_inst) {
363                 $next_pageinst = @num_pageinsts;
364                 }
365         &redirect("$next_pagename?pageinst=$next_pageinst");
366         }
367 if ($button_name eq "$text{'wizard_remove'}") {
368         &wizard_clear_data($pagename, $pageinst);
369         &redirect("$pagename?pageinst=$pageinst");
370         }
371 if (($button_name eq "$text{'wizard_add'}") ||
372         ($button_name eq "$text{'wizard_update'}")) { 
373         # find next page
374         $next_pagename = $pagename;
375         $next_pageinst = $pageinst;
376         $max_inst = &get_wizard_info_by_name($wizref, "max_datafiles",
377                 $pagename);
378         if ($pageinst < ($max_inst - 1)) {
379                 # in this case, add can move to another instance
380                 $next_pageinst = $pageinst + 1;
381         } else {
382                 # in this case, add moves to next page if possible
383                 $pagenum = &get_wizard_info_by_name($wizref, "pagenum",
384                         $pagename);
385                 @num_pages = &get_wizard_info_by_name($wizref, "pages");
386                 if ($pagenum < (@num_pages - 1)) {
387                         $next_pagenum = $pagenum + 1;
388                         $next_pagename = &get_wizard_info_by_page($wizref,
389                                 "pagename", $next_pagenum);
390                         $next_pageinst = 0;
391                         }
392                 }
393         # save data and reload validation stage (which includes automatic
394         # redirect if no validation errors occur)
395         &wizard_save_data($pagename, $pageinst);
396         $validation_success = 1;
397         &redirect("$pagename?pageinst=$pageinst&validate=1&next_pagename=$next_pagename&next_pageinst=$next_pageinst");
398         }
399
400 # Shouldnt be here!
401 &error("Invalid button name $button_name!");
402 }
403
404 # Return pageinst if defined, 0 otherwise.
405 #
406 # Parameters:
407 #
408 sub wizard_get_pageinst()
409 {
410 local ($pageinst);
411 if (defined($in{'pageinst'})) {
412         $pageinst = $in{'pageinst'};
413 } else {
414         $pageinst = 0;
415         }
416 return $pageinst;
417 }
418
419 # Redirect to next target pagename/pageinst are defined...
420 #
421 # Parameters:
422 #
423 sub wizard_redirect_next()
424 {
425 local ($pagename, $pageinst);
426 ($pagename, $pageinst) = @_;
427 if ((defined($in{'next_pagename'})) && (defined($in{'next_pageinst'}))) {
428         # add validation success value to datafile
429         # add validation result to datafile - used to assess if we can finish
430         &wizard_save_validation_value($pagename, $pageinst);
431         # if validation succeeded, move on...
432         if ($validation_success == 1) {
433                 print <<EOF;
434 <script>
435 location.href = '$in{'next_pagename'}?pageinst=$in{'next_pageinst'}';
436 </script>
437 EOF
438                 }
439         }
440 }
441
442 sub wizard_validate_input()
443 {
444 local ($value, $validation_regexp, $validation_err);
445 ($value, $validation_regexp, $validation_err) = @_;
446 # do we do validation here?
447 if (defined($in{'validate'})) {
448         if ($in{'validate'} == 1) {
449                 if ($value =~ /^$validation_regexp$/) {
450                         # ok, so we can redirect
451                 } else {
452                         print "<tr $cb><td>\n";
453                         print
454                             "<i><font color=#FF0000>$validation_err</font></i>";
455                         print "</td></tr>\n";
456                         # flag global var to indicate validation failed - no
457                         # redirect will occur as a result...
458                         $validation_success = 0;
459                         }
460                 }
461         }
462 }
463
464 # Give appropriate full path to datafile when given pagename/inst
465 #
466 # Parameters: pagename, pageinst
467 #
468 sub wizard_datafile_name()
469 {
470 local ($pagename, $pageinst);
471 ($pagename, $pageinst) = @_;
472 return "$module_config_directory/${pagename}.${pageinst}.wizdata";
473 }
474
475 # Saves data to datafile for page/inst
476 #
477 # Parameters: pagename, pageinst
478 #
479 sub wizard_save_data()
480 {
481 local ($pagename, $pageinst, @inkeys, $datafile);
482 ($pagename, $pageinst) = @_;
483 $datafile = &wizard_datafile_name($pagename, $pageinst);
484 # save webmin's "in" hash to file
485 @inkeys = keys(%in);
486 open(DATAFILE,">$datafile");
487 foreach $inkey (@inkeys) {
488         print DATAFILE "$inkey=$in{$inkey}\n";
489         }
490 close(DATAFILE);
491 }
492
493 sub wizard_save_validation_value()
494 {
495 local ($pagename, $pageinst, $datafile);
496 ($pagename, $pageinst) = @_;
497 $datafile = &wizard_datafile_name($pagename, $pageinst);
498 open(DATAFILE,">>$datafile");
499 print DATAFILE "validation_success=$validation_success";
500 close(DATAFILE);
501 }
502
503 # Removes all datafiles for wizard
504 #
505 # Parameters: wizard_info
506 #
507 sub wizard_clear_all_data()
508 {
509 local ($wizinfo, %wizard, $wizref, @pages, $page, @allinsts, $inst);
510 $wizinfo = $_[0];
511 %wizard = &read_in_wizard("$wizinfo");
512 $wizref = \%wizard;
513 @pages = &get_wizard_info_by_name($wizref, "pages");
514 foreach $page (@pages) {
515         @allinsts = &list_wizard_datafiles("$page->{'pagename'}");
516         foreach $inst (@allinsts) {
517                 unlink($inst);
518                 }
519         }
520 }
521
522 # Removes datafile, moves those above down one instance
523 #
524 # Parameters: pagename, pageinst
525 #
526 sub wizard_clear_data()
527 {
528 local ($pagename, $pageinst, $datafile, @num_inst, $instnum);
529 ($pagename, $pageinst) = @_;
530 $datafile = &wizard_datafile_name($pagename, $pageinst);
531 @num_inst = &list_wizard_datafiles($pagename);
532 unlink($datafile);
533 # move all instances above deleted instance down one to fill gap....
534 for ($instnum = $pageinst + 1; $instnum < @num_inst; $instnum++) {
535         $datafile_old = &wizard_datafile_name($pagename,
536                 $instnum);
537         $datafile_new = &wizard_datafile_name($pagename,
538                 $instnum -1);
539         rename($datafile_old, $datafile_new);
540         }
541 }
542
543 # Reads wizard data file into key-value hash
544 #
545 # Parameters: pagename, pageinst
546 #
547 sub wizard_get_data()
548 {
549 local ($pagename, $pageinst, $datafile, @data, $line, $key, $value, %hash);
550 ($pagename, $pageinst) = @_;
551 $datafile = &wizard_datafile_name($pagename, $pageinst);
552 open(DATAFILE, $datafile);
553 @data = <DATAFILE>;
554 foreach $line (@data) {
555         if ($line =~ /^\s*\#/) {
556                 next;
557                 }
558         if ($line =~ /\s*([^=]+)=(.*)/) {
559                 $key = $1;
560                 $value = $2;
561                 $hash{"$key"} = "$value";
562                 }
563         }
564 return %hash;
565 }
566
567 # Gets data value for particular page/inst
568 #
569 # Parameters: pagename, pageinst, datakey
570 #
571 sub wizard_get_data_value()
572 {
573 local ($pagename, $pageinst, $datakey, %hash);
574 ($pagename, $pageinst, $datakey) = @_;
575 %hash = &wizard_get_data($pagename, $pageinst);
576 return ($hash{"$datakey"});
577 }
578
579 # Gets data values for all page insts associated with a pagename
580 #
581 # Parameters: pagename, datakey
582 #
583 sub wizard_get_data_values()
584 {
585 local ($pagename, $datakey, @allinsts, $instfile, $pageinst, $value);
586 ($pagename, $datakey) = @_;
587 # get all matching instance files...
588 @allinsts = &list_wizard_datafiles($pagename);
589 @values = ();
590 foreach $instfile (@allinsts) {
591         $instfile =~ /${pagename}\.([^\.]*)/;
592         $pageinst = $1;
593         $value = &wizard_get_data_value($pagename, $pageinst, $datakey);
594         push (@values, $value);
595         }
596 return @values;
597 }
598
599 # Read in wizard string, create internal representation (wizard hash).
600 #
601 # Parameters: wizard_string;
602 sub read_in_wizard()
603 {
604 local ($wizard_string, @wizard_array, $pagenum, %wizard, $wiz_elt);
605 $wizard_string = $_[0];
606 @wizard_array = split(/;/, $wizard_string);
607 $pagenum = 0;
608 foreach $wiz_elt (@wizard_array) {
609         if ($wiz_elt =~ /\s*page\s*=\s*([^,\s]*)\s*,\s*min\s*=\s*([^,\s]*)\s*,\s*max\s*=\s*(.+)/) {
610                 # standard wizard element 
611                 $wizard{'pages'}->[$pagenum]->{'pagename'} = $1;
612                 $wizard{'pages'}->[$pagenum]->{'min_datafiles'} = $2;
613                 $wizard{'pages'}->[$pagenum]->{'max_datafiles'} = $3;
614                 $wizard{'pages'}->[$pagenum]->{'pagenum'} = $pagenum;
615                 $pagenum = $pagenum + 1;
616         } elsif ($wiz_elt =~ /\s*submit\s*=\s*(\S+)/) {
617                 # submit cgi script name
618                 $wizard{'submit'} = $1;
619         } else {
620                 &error("Syntax error in wizard specification: $wiz_elt");
621                 }
622         }
623 return %wizard;
624 }
625
626 sub get_wizard_info_by_name()
627 {
628 local ($wizref, $pagename, @wizard_pages, $page);
629 ($wizref, $data, $pagename) = @_;
630 @wizard_pages = @{$wizref->{'pages'}};
631 if ($data eq "pages") {
632         return @wizard_pages;
633 } elsif ($data eq "submit") {
634         return $wizref->{$data};
635         }
636 foreach $page (@wizard_pages) {
637         if ($pagename eq "$page->{'pagename'}") {
638                 return $page->{$data};
639                 }
640         }
641 # not found
642 &error("Data $data not found for wizard. Pagename: $pagename");
643 }
644
645 sub get_wizard_info_by_page()
646 {
647 local ($wizref, $data, $pagenum);
648 ($wizref, $data, $pagenum) = @_;
649 @wizard_pages = @{$wizref->{'pages'}};
650 return $wizard_pages[$pagenum]->{$data};
651 }
652
653 # list all files matching pattern and ending in .wizdata
654 #
655 # Parameters: filematch_pattern
656 #
657 sub list_wizard_datafiles()
658 {
659 local($filematch, $f,@filelist);
660 $filematch = $_[0];
661 opendir(DIR, $module_config_directory);
662 foreach $f (readdir(DIR)) {
663         if ($f =~ /^$filematch.*\.wizdata/) {
664                 push(@filelist, "$module_config_directory/$f");
665                 }
666         }
667 return @filelist;
668 }
669