{
   Main menu for sample client

   $Id: menu.mgl,v 1.11 2006/11/19 14:30:29 gkminix Exp $
}

{
   Set latin1 character set for this source file
}
{$C3}

program sample_menu;


const
  BOOTP_FLASH = 130;		// BOOTP tag for flash programming password


type
  nLabel    = string[20];
  pMenuItem = ^sMenuItem;
  sMenuItem = record
                num    : integer;
                name   : nLabel;
                file   : string;
                server : ipaddr;
                gw     : ipaddr;
                next   : pMenuItem;
              end;


var
  MainMenu : pMenuItem;



{
   Add new item to menu list
}
procedure AddItem (const itemnum : integer; const name, file : string;
						const server, gw : ipaddr);
var
  NewItem   : pMenuItem;
  cur, prev : pMenuItem;
begin
  new(NewItem);
  NewItem^.num := itemnum;
  NewItem^.name := name;
  NewItem^.file := file;
  NewItem^.next := nil;
  NewItem^.server := server;
  NewItem^.gw := gw;
  cur := MainMenu;
  prev := nil;
  while cur <> nil do
    begin
      prev := cur;
      cur := cur^.next;
    end;
  if prev = nil then
    MainMenu := NewItem
  else
    prev^.next := NewItem
end;



{
   Load a menu item
}
procedure LoadItem (const itemnum, line : integer);
var
  cur : pMenuItem;
begin
  cur := MainMenu;
  while (cur <> nil) and (cur^.num <> itemnum) do
    cur := cur^.next;
  if cur <> nil then
    begin
      if cur^.file[1,5] <> "/dev/" then
        begin
          print "Loading ", cur^.name, " from ", cur^.server at [0, line];
          print at [0,24];
          load cur^.file from cur^.server with gateway cur^.gw
        end
      else
        begin
          print "Loading ", cur^.name, " from local disk" at [0, line];
          print at [0, line + 1];
          load cur^.file
        end
    end
end;



{
   Print menu items
}
function PrintMenu (FirstLine : integer) : integer;
var
  cur  : pMenuItem;
  line : integer;
begin
  cur := MainMenu;
  line := FirstLine;
  while (cur <> nil) and (line < 20) do
    begin
      print at [15, line];
      print cur^.num, " - ", cur^.name;
      if cur^.file[1,5] = "/dev/" then
        print " from local disk"
      else
        print " from server ", cur^.server;
      cur := cur^.next;
      line := succ(line)
    end;
  PrintMenu := line
end;



{
   Clear the screen
}
procedure cls;
begin
  print "\033[J"
end;



{
   Read in a password. Since we don't want to let the user input appear
   on the screen while typing the password we have to do reading it ourselves
   instead of using a runtime routine (which echos the input data)
}
function getpasswd (bootp, x, y : integer) : boolean;

const
  pwdlen = 20;

var
  s     : string[pwdlen];
  x1, i : integer;
  ch    : char; 

begin
  i  := 0;
  s  := "";
  x1 := x;

  // Read in the password
  while i < 20 do
    begin
      get ch at [x1, y];
      if (ch = '\b') and (i > 0) then
        begin
          x1 := pred(x1);
          i  := pred(i);
          s.len := pred(s.len);
          print ' ' at [x1, y]
        end
      else if (ch >= ' ') and (ch <= chr(127)) then
        begin
          print '*' at [x1, y];
          x1 := succ(x1);
          i  := succ(i);
          s  := s + ch
        end
      else if (ch = '\r') then
        break
    end;

  // Check that the password is correct
  getpasswd := true;
  if s <> string($[bootp]) then
    begin
      cls;
      print "\033[41mInvalid password\033[40m" at [20, 12];
      print "Press any key to continue..." at [20, 15];
      get ch;
      getpasswd := false
    end
end;



{
   Main procedure which prints and handles the menu
}
procedure main;
var
  i       : integer;
  root    : string;
  doflash : boolean;
  server  : ipaddr;
  line    : integer;
label
  redo_select;
begin
  // Set default parameters
  root := string($[BOOTP_ROOTPATH]);
  if root.len = 0 then
	root := "/tftpboot/root-" + hostname;
  doflash := (string($[BOOTP_FLASH]) <> "");
  server := tftpaddr;

  // Generate menu
  if MainMenu = nil then
    begin
      AddItem(1, "Linux", root + "/bootImage-linux", server, 0.0.0.0);
      AddItem(2, "MS-DOS", root + "/bootImage-msdos", server, 0.0.0.0);
      AddItem(3, "OpenDOS", root + "/bootImage-opendos", server, 0.0.0.0);
      AddItem(4, "FreeDOS", root + "/bootImage-freedos", server, 0.0.0.0);
      AddItem(5, "FreeBSD", "/tftpboot/freebsd/base/boot/pxeboot", server, 0.0.0.0);
      AddItem(6, "LTSP", "/tftpboot/ltsp/bootImage-ltsp", server, 0.0.0.0);
      AddItem(7, "Windows", "/dev/hda1", 0.0.0.0, 0.0.0.0);
      if doflash then
        AddItem(9, "Flash Programmer", root + "/bootImage-flash", server, 0.0.0.0)
    end;

  // Print menu header
  cls;
  print "\033[44m";
  print chr(201) + chr(205)*50 + chr(187)    at [10,2];
  for i := 3 to 7 do
    print chr(186) + chr(32)*50  + chr(186)  at [10,i];
  print chr(200) + chr(205)*50 + chr(188)    at [10,8];
  print "Boot menu for " + hostname          at [20,5];
  print "\033[40m";

  // Print menu itself
  line := PrintMenu(11) + 1;

  // Let the user enter his/her selection
redo_select:
  print "Enter selection:" at [15, line];
  select at [32, line] with timeout 10 of

    0:		begin
		  print at [0,24];
		  return
		end;

    1,2,3,4,5,6,7:
		begin
		  LoadItem(selectnumber, line + 2);
		  restart
		end;

    9:		begin
		  if doflash then
		    begin
		      print "Enter password:" at [15, line + 1];
		      if getpasswd(BOOTP_FLASH, 31, line + 1) then
		        LoadItem(9, line + 3);
		      restart
		    end;
		  goto redo_select
		end;

    else	begin
		  LoadItem(7, line + 2);
		  restart
		end
  end;
end;



{
   Just call the main screen
}
begin
  MainMenu := nil;
  try
    main
  except
    if exception < 256 then
      raise
    else
      print "Runtime Error ", exception at [0,24]
  end
end.

