#!/usr/bin/perl
########################################################################
# File:           rootfiles/cfedit.pl                                  #
# myLinux Server: Copyright (c) 2004 Michael Oberg                     #
# Version:        0.98                                                 #
# Author:         Michael Oberg <michael.oberg@mylinuxproject.de>      #
#                                                                      #
# This program is free software; you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation; either version 2 of the License, or    #
# (at your option) any later version.                                  #
#                                                                      #
# This program is distributed in the hope that it will be useful,      #
# but WITHOUT ANY WARRANTY; without even the implied warranty of       #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         #
# GNU General Public License for more details.                         #
#                                                                      #
# You should have received a copy of the GNU Public License along      #
# with this package; if not, write to the Free Software Foundation,    #
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.       #
########################################################################

$valuecount = 0;
$menucount = 0;

# global variables:
# menutitle[] - array of menu titles
# menuhelp{} - array of optional help entries, indexed by menu title
# menucheck{} - array of optional check routines, indexed by menu title
# menuentries{} - array of entry counters, indexed by menu title
# menuentry{}[] - array of menu entries, indexed by menu title and
#                 entry number
# entryname{}[] - array of menu entry names,
#		  indexed by menu title and entry number
# entrynumber{}{} - array of menu entry numbers,
#		    indexed by menu title and entry name
# entrystr{}[] - array of menu entry names,
#		 indexed by menu title and entry number
# entryaction{}[] - array of menu actions,
#		    indexed by menu title and entry number
# entryval{}[] - array of menu value names,
#		 indexed by menu title and entry number
# entrykey{}[] - array of optional menu entry keys,
#		 indexed by menu title and entry number
# entrycheck{}[] - array of optional menu ckeck routines,
#		   indexed by menu title and entry number
# valuename[] - array of value (variable) names
# value{} - array of values (content of the variables)
# valuenum{} - array of value (variable) numbers, idexed by name

sub readmenus {
  my ($menufile) = @_;
  if (!(-r $menufile)) {
    die "File '$menufile' does not exist or is not readable\n";
  }

  my $MENUS
     = `cat "$menufile" | sed -e 's/#.*//' -e 's/[ \\t]*\$//' | grep -v "^\$"`;

  my $entry = "";
  foreach my $line (split /\n/, $MENUS) {
    if ($line =~ /[ \t]*\[(.+)\]$/) {
      $entry = $1;	# menu window title
      $menutitle[$menucount++] = $entry;
      $helpmode = 0;	# help screen content is defined behind the entry list
      $menuhelp{$entry} = "";
      $menuentries{$entry} = 0;
    }
    elsif ($helpmode) {
      if (! $entry) {
	die "No menu title defined\n";
      }
      $line =~ s/"/\\"/g;
      $menuhelp{$entry} .= $line . "\n";	# adding line to help content
    }
    else {
      if ($line =~ /[ \t]*:HELP[ \t]*$/) {
	$helpmode = 1;	# after ":HELP" comes the help screen content
      }
      elsif ($line =~ /[ \t]*:CHECK:[ \t]*"(.*)"[ \t]*$/) {
	$menucheck{$entry} = $1;
      }
      elsif (
	$line =~ /[ \t]*([^ \t]*)[ \t]+"([^"]*)"[ \t]*(VAL):([^ \t]+)[ \t]*(CHECK):"([^"]*)"[ \t]*(([^ \t]+))?$/
	|| $line =~ /[ \t]*([^ \t]*)[ \t]+"([^"]*)"[ \t]*(VAL|SUB|KEY):([^ \t]+)[ \t]*(([^ \t]+))?$/
	|| $line =~ /[ \t]*([^ \t]*)[ \t]+"([^"]*)"[ \t]*(RUN):"([^"]+)"[ \t]*(([^ \t]+))?$/
      ) {
	my $num = $menuentries{$entry}++;
	$entryname{$entry}[$num] = $1;
	$entrynumber{$entry}{$1} = $num;
	$entrystr{$entry}[$num] = $2;
	my $action = $3;
	$entryaction{$entry}[$num] = $action;
	my $val = $4;
	$entryval{$entry}[$num] = $val;
	if ($5 eq "CHECK") {
	  $entrycheck{$entry}[$num] = $6;
	  $entrykey{$entry}[$num] = $7;
	}
	else {
	  $entrycheck{$entry}[$num] = "";
	  $entrykey{$entry}[$num] = $5;
	}
	if (($action eq "VAL") || ($action eq "KEY")) {
	  if (defined $valuenum{$val}) {
	    die "$action:$val is already defined";
	  }
	  $valuename[$valuecount] = $val;
	  $valuenum{$val} = $valuecount++;
	}
      }
      else {
	die "Line '$line'\nis not a menu entry definition\n";
      }
    }
  }
}

sub getvariables {
  my ($str) = @_;
  while ($str =~ /\$([A-Za-z0-9_]+)/) {
    my $var = $1;
    if (defined $value{$var}) {
      $str =~ s/\$$var/$value{$var}/ if defined $value{$var};
    }
    else {
      $str =~ s/\$$var/$var/;
    }
  }
  return $str;
}

sub readvalues {
  my ($valuefile) = @_;
  if (!(-r $valuefile)) {
    die "File '$valuefile' does not exist or is not readable\n";
  }

  my $VALUEFILE
     = `cat "$valuefile" | sed -e 's/#.*//' -e 's/[ \\t]*\$//' | grep -v "^\$"`;
  foreach my $line (split /\n/, $VALUEFILE) {
    if ($line =~ /[ \t]*([^ \t=]*)[ \t]*=[ \t]*"([^"]*)"/) {
      $value{$1} = $2;
    }
  }
}

sub writevalues {
  my ($valuefile) = @_;
  my $VALUEFILE = "";
  for (my $i = 0; $i < $valuecount; $i++) {
    my $name = $valuename[$i];
    $VALUEFILE .= qq|$name="| . $value{$name} . qq|"\n|;
  }
  open (VALFILE, "> $valuefile");
  print VALFILE $VALUEFILE;
  close VALFILE;
}

sub printmenu {
  my ($menu, $cursorpos) = @_;
  my $cmd = "dialog --help-button ";
  my $ret = 0;

  # set cursor position:
  if ((defined $cursorpos) && $cursorpos) {
    $cmd .= "--default-item '$cursorpos' ";
  }
  $cmd .= "--menu '$menu' 25 80 17 ";

  # adding menu entries:
  for ($i = 0; $i < $menuentries{$menu}; $i++) {
#    my $keyval = $value{$entrykey{$menu}[$i]};
#    if (!$keyval || ($keyval =~ /^yes$/i)) {
    my $keyname = $entrykey{$menu}[$i];
    my $keyneg = 0;
    if ($keyname =~ /!(.*)/) {
      $keyname = $1;
      $keyneg = 1;
    }
    my $keyval = $value{$keyname};
    if (!$keyval
	|| (($keyval =~ /^yes$/i) && ($keyneg == 0))
	|| (!($keyval =~ /^yes$/i) && ($keyneg == 1))) {
      $cmd .= "'" . $entryname{$menu}[$i] . "' '";
      if ($entryaction{$menu}[$i] eq "KEY") {
	if ($value{$valuename[$valuenum{$entryval{$menu}[$i]}]} =~ /^yes$/i) {
	  $cmd .= "[*] ";
	}
	else {
	  $cmd .= "[ ] ";
	}
      }
      $cmd .=  $entrystr{$menu}[$i] . "' ";
    }
  }

  # adding exit entry:
  if ($menu eq $menutitle[0]) {
    $cmd .= "'Save & Exit' 'Save changes and exit' ";
  }
  else {
    $cmd .= "'Close' 'Return to calling menu' ";
  }
  $cmd .= "2> /tmp/cfedit.tmp";

  my $sysret = system ($cmd);
  if ($sysret == 0) {
    $ret = `cat /tmp/cfedit.tmp`;
  }
  elsif ($sysret == 512) {
    # 512: return value 2 is shifted 8 bit to the right by "system"
    $ret = "Help";
  }
  else {
    if (system ("dialog --yesno 'Discard changes?' 5 30") == 0) {
      $ret = "Cancel";
    }
    else {
      $ret = "Close";
    }
  }
  `rm -f /tmp/cfedit.tmp`;

  if ($ret eq "Save & Exit") {
    $ret = "Close";
  }

  return $ret;
}

sub setvalue {
  my ($varname) = @_;

  my $name = $valuename[$valuenum{$varname}];
  my $val = $value{$name};

  my $cmd = qq|dialog --inputbox "$name" 8 40 "$val" 2> /tmp/cfedit.tmp|;

  if (system ($cmd) == 0) {
    $value{$name} = `cat /tmp/cfedit.tmp`;
  }
  else {
    $ret = "Cancel";
  }
  `rm -f /tmp/cfedit.tmp`;
}

sub menuwrapper {
  my ($menu) = @_;
  my $ret = &printmenu ($menu);
  while (!($ret eq "Close")) {
    if ($ret eq "Cancel") {
      system ("clear");
      die "Aborted\n";
    }
    elsif ($ret eq "Help") {
      my $helptext = $menuhelp{$menu};
      $helptext = "No help available" if (!$helptext);
      `dialog --msgbox "$helptext" 25 80`;
    }
    else {
      my $num = $entrynumber{$menu}{$ret};
      my $action = $entryaction{$menu}[$num];
      if ($action eq "VAL") {
	&setvalue ($entryval{$menu}[$num]);
	if ($entrycheck{$menu}[$num]) {
	  while (system (&getvariables ($entrycheck{$menu}[$num]))) {
	    `dialog --msgbox "Invalid value" 5 20`;
	    &setvalue ($entryval{$menu}[$num]);
	  }
	}
      }
      elsif ($action eq "SUB") {
	&menuwrapper ($entryval{$menu}[$num]);
	if ($menucheck{$entryval{$menu}[$num]}) {
	  while (system (&getvariables ($menucheck{$entryval{$menu}[$num]}))) {
            `dialog --msgbox "Invalid value combination" 5 20`;
	    &menuwrapper ($entryval{$menu}[$num]);
	  }
	}
      }
      elsif ($action eq "KEY") {
	my $key = $valuename[$valuenum{$entryval{$menu}[$num]}];
	if ($value{$key} =~ /^yes$/i) {
	  $value{$key} = "no";
	}
	else {
	  $value{$key} = "yes";
	}
      }
      elsif ($action eq "RUN") {
	my $cmd = $entryval{$menu}[$num];
	system ("clear");
	system ($cmd);
	print "Press <Enter> to return to the menu\n";
	$cmd = <STDIN>;
      }
      else {
	system ("clear");
	die "Invalid menu entry action: $action\n";
      }
    }
    $ret = &printmenu ($menu, $ret);
  }
}

########################################################################
# Main program                                                         #
########################################################################

if (@ARGV < 2) {
  die ("Usage: cfedit.pl <menufile> <valuefile>\n");
}

$menufile = $ARGV[0];
$valuefile = $ARGV[1];

# reading initial values
&readmenus ($menufile);
&readvalues ($valuefile);

# print main menu
&menuwrapper ($menutitle[0]);
if ($menucheck{$menutitle[0]}) {
  while (system (&getvariables ($menucheck{$menutitle[0]}))) {
    `dialog --msgbox "Invalid value combination" 5 20`;
    &menuwrapper ($menutitle[0]);
  }
}

# writing values
&writevalues ($valuefile);
system ("clear");
