/* This file is included from fsck.c */

/* An attempt to keep all the config variables in the Makefile */
#ifdef NC_HEADER
#include <ncurses.h>
#else
#include <curses.h>
#endif

/* From mode_string.c */
void mode_string();

/* Curses variables */
int DATA_START, DATA_END, HOFF;
int VERT, VERT_CENT, VERT_SUPER, VERT_INODE, HOFFPLUS;
int HIGHLIGHT_1, HIGHLIGHT_2, END_HIGHLIGHT;
WINDOW *header, *workspace, *trailer;

unsigned int current_inode = 1;
unsigned int current_block = 1;
int inode_unused = 0;
#define block_unused inode_unused
int max_blocks_this_inode = 0;
char echo_string[150];
struct minix_inode * fake_inode;

#define CURSES_NAME "lde"
#ifndef WIN_COL
#define WIN_COL 80
#endif
#ifndef HEADER_SIZE
#define HEADER_SIZE 2
#endif
#ifndef TRAILER_SIZE
#define TRAILER_SIZE 3
#endif

/* This moves to the bottom of the screen, writes whatever is in coutput,
 * and reads an unsigned int from the user.  It recognizes indicators as to the 
 * type of input for decimal, hex, or octal.  For example if we wanted to
 * input 15, we could enter as hex (0xf, xf, $f), decimal (15), or octal
 * (\017).  sscanf is probably smart enough to recognize these, but 
 * what the hell.  If coutput begins with a space, cinput is returned in
 * coutput and the number processing does not occurr.
 */
unsigned int cread_num(char *coutput)
{
  int i;
  char cinput[80];

#if TRAILER_SIZE>0
#define WINDOW_AVAILABLE trailer
#define LINE_NUMBER TRAILER_SIZE-1
#define HORIZ_WINDOW (COLS-strlen(coutput))/2-5
#else
#define WINDOW_AVAILABLE workspace
#define LINE_NUMBER 0
#define HORIZ_WINDOW (COLS-2*HOFF-strlen(coutput))/2-5
#endif

  wmove(WINDOW_AVAILABLE,LINE_NUMBER,0);
  wclrtoeol(WINDOW_AVAILABLE);
  mvwprintw(WINDOW_AVAILABLE,LINE_NUMBER,
    HORIZ_WINDOW,"%s",coutput);
  wrefresh(WINDOW_AVAILABLE);
  echo();
  wgetstr(WINDOW_AVAILABLE,cinput);
  noecho();
  wmove(WINDOW_AVAILABLE,LINE_NUMBER,0);
  wclrtoeol(WINDOW_AVAILABLE);
  wrefresh(WINDOW_AVAILABLE);

  if (coutput[0]!=' ') {
    if  (strlen(cinput)>0) {
      if ((cinput[0]=='$')||(cinput[0]=='x'))
	sscanf(cinput,"%*1c%x", &i);
      else if (cinput[0]=='\\')
	sscanf(cinput,"%*1c%o", &i);
      else if (cinput[1]=='x')
	sscanf(cinput,"%*2c%x", &i);
      else
	sscanf(cinput,"%d", &i);
      return i;
    }
  } else {
    strncpy(coutput, cinput, 80);
  }

 return 0;
}

/* This fills in the header window -- 
 * things like the program name, current inode, tagged recovered blocks
 */
void update_header()
{
#if HEADER_SIZE>0
  int(j);
  sprintf(echo_string,"Inode: %d (0x%5.5x)",current_inode,current_inode);
  mvwprintw(header,HEADER_SIZE-1,HOFF,"%24s",echo_string);
  sprintf(echo_string,"Block: %d (0x%5.5x)",current_block,current_block);
  mvwprintw(header,HEADER_SIZE-1,HOFF+25,"%24s",echo_string);
  for (j=0;j<9;j++)
    if (fake_inode->i_zone[j]) 
      mvwaddch(header,HEADER_SIZE-1,HOFF+60+j,'-');
    else
      mvwaddch(header,HEADER_SIZE-1,HOFF+60+j,j+'0');
  if (inode_unused) 
      mvwaddch(header,HEADER_SIZE-1,HOFF+70,'U');
  else
      mvwaddch(header,HEADER_SIZE-1,HOFF+70,' ');
  touchwin(header);
  wrefresh(header);
#endif
}

/* This should clear out the old workspace */
void clobber_workspace()
{
  werase(workspace);
  wrefresh(workspace);
  delwin(workspace);
}

/* Redraw everything -- ^L */
void refresh_all()
{
#if TRAILER_SIZE>0
  touchwin(trailer);
  wrefresh(trailer);
#endif
  touchwin(workspace);
  wrefresh(workspace);
#if HEADER_SIZE>0
  werase(header);
  sprintf(echo_string,"%s v%s : %s",CURSES_NAME,VERSION,device_name);
  mvwaddstr(header,0, (COLS-strlen(echo_string))/2-1,echo_string);
  update_header();
#endif
}

/* Format the super block for curses */
void show_super()
{
  clobber_workspace();
  workspace = newwin(VERT_SUPER,COLS/2,VERT_CENT,HOFFPLUS);
  
  mvwprintw(workspace,0,0,"Inodes:        %d (0x%5.5x)",INODES, INODES);
  mvwprintw(workspace,1,0,"Blocks:        %d (0x%5.5x)",ZONES, ZONES);
  mvwprintw(workspace,2,0,"Firstdatazone: %d (%d)",FIRSTZONE,NORM_FIRSTZONE);
  mvwprintw(workspace,3,0,"Zonesize:      %d (0x%4.4x)",
    BLOCK_SIZE<<ZONESIZE, BLOCK_SIZE<<ZONESIZE);
  mvwprintw(workspace,4,0,"Maximum size:  %d (0x%8.8x)",MAXSIZE,MAXSIZE);
  mvwprintw(workspace,6,0,"* Directory entries are %d characters.",namelen);
  mvwprintw(workspace,7,0,"* Inode map occupies %d blocks.",IMAPS);
  mvwprintw(workspace,8,0,"* Zone map occupies %d blocks.",ZMAPS);
  mvwprintw(workspace,9,0,"* Inode table occupies %d blocks.",INODE_BLOCKS);
  wrefresh(workspace);
}

/* I really don't remember why I wrote this, I think it had
 * something to do with the original map_block() writing to 
 * the disk when I really really didn't want it to.
 */
unsigned int cmap_block(struct minix_inode * inode, unsigned int blknr)
{
  unsigned short ind[BLOCK_SIZE>>1];
  unsigned short dind[BLOCK_SIZE>>1];
  unsigned int block, result;

  result = 0;

  if (blknr<7)
    return (inode->i_zone[blknr] < ZONES) ? inode->i_zone[blknr] : 0 ;
  blknr -= 7;
  if (blknr<512) {
    block = inode->i_zone[7];
    if ((block>0)&&(block<ZONES)) {
      read_block(block, (char *) ind);
      result = ind[blknr];
    }
    return result;
  }
  blknr -= 512;
  block = inode->i_zone[8];
  if ((block>0)&&(block<ZONES)) {
    read_block(block, (char *) dind);
    block = dind[blknr/512];
    if ((block>0)&&(block<ZONES)) {
      read_block(block, (char *) ind);
      result = ind[blknr%512];
    }
  }
  return result;

}

/* This will check to see that all bytes which
 * should be recovered are marked unused, i.e.
 * the data is not being used by another file,
 * but it could have been overwritten.
 *
 * Returns 0 if ok, 1 if data space is used.
 */
int check_recover(struct minix_inode * inode)
{
  int i;
  unsigned int nr, j;

  i = j = 0;
  while ((nr=cmap_block(inode,j))) {
    if (zone_in_use(nr))
	i = 1;
    j++;
  }
  return i;
}

/* This is the non-magic undelete.  inode will contain a 
 * possibly bogus inode, only the blocks are looked at --
 * we copy all the blocks (including those indexed indirectly)
 * to the file specified in *fp
 */
void crecover_file(FILE *fp,struct minix_inode * inode)
{
  int i;
  unsigned char dind[BLOCK_SIZE];
  unsigned int nr;
  unsigned int j;

  j = 0;
  while ((nr=cmap_block(inode,j))) {
    read_block(nr,dind);
    for (i=0;i<BLOCK_SIZE;i++) fprintf(fp,"%c",dind[i]);
    j++;
  }
}

/* Dump as much of a block as we can to the screen and format it in a nice 
 * hex mode with ASCII printables off to the right.
 */
void cdump_block(nr,win_start,win_size)
unsigned short nr;
int win_start, win_size;
{
  int i,j;
  unsigned char dind[BLOCK_SIZE],  c;
  char block_not_used[10]=":NOT:USED:", block_is_used[10] = "::::::::::";
  char *block_status;
 
  clobber_workspace(); 
  workspace = newwin(VERT,(COLS-HOFF),HEADER_SIZE,HOFF);
  
  read_block(nr,dind);
  
  block_status = (zone_in_use(nr)) ? block_is_used : block_not_used; 
  j = 0;

  while ((j<win_size)&&(j*16+win_start<BLOCK_SIZE)) {
    mvwprintw(workspace,j,0,"0x%04x = ",j*16+win_start);
    for (i=0;i<8;i++)
      mvwprintw(workspace,j,9+i*3,"%2.2x",dind[j*16+i+win_start]);
    mvwprintw(workspace,j,34,"%c",block_status[j%10]);
    for (i=0;i<8;i++)
      mvwprintw(workspace,j,37+i*3,"%2.2x",dind[j*16+i+8+win_start]);
    
    for (i=0;i<16;i++) {
      c = dind[j*16+i+win_start];
      c = ((c>31)&&(c<127)) ? c : '.';
      mvwaddch(workspace,j,63+i,c);
    }
    j++;
  }

  wrefresh(workspace);
  update_header();
}

/* This is the curses menu-type system for block mode, displaying a block
 * on the screen, next/previous block, paging this block, etc., etc.
 */
int block_mode() {
  int c,flag;
  unsigned int temp_block;
  int win_start;

#if TRAILER_SIZE>0
  werase(trailer);
  strncpy(echo_string,"UP/DOWN = previous/next block, or '#' to enter block number",150);
  mvwaddstr(trailer,0,(COLS-strlen(echo_string))/2-1,echo_string);
  strncpy(echo_string,"Q to quit",150);
  mvwaddstr(trailer,1,(COLS-strlen(echo_string))/2-1,echo_string);
  wrefresh(trailer);
#endif

  win_start = 0;
  flag = 1; c = ' ';
  while (flag||(c = getch())) {
    flag = 0;
    switch(c) {
      case 'F'-'A'+1: /* ^F */
      case KEY_RIGHT:
        if ( win_start + VERT*16 < BLOCK_SIZE) win_start += VERT*16;
	break;
      case 'B'-'A'+1: /* ^B */
      case KEY_LEFT:
	if (win_start - VERT*16 >= 0)  win_start -= VERT*16;
	break;
      case 'N'-'A'+1: /* ^N */
      case KEY_NPAGE:
      case KEY_DOWN:
        if (block_unused) {
           temp_block = current_block;
           while (temp_block++ < ZONES)
              if (!zone_in_use(temp_block)) {
                 current_block = temp_block;
                 break;
              }
        }
        else
          if (current_block++ > ZONES) current_block = ZONES;
	win_start = 0;
	break;
      case 'P'-'A'+1: /* ^P */
      case KEY_PPAGE:
      case KEY_UP:
        if (block_unused) {
           temp_block = current_block;
           while (temp_block-- > 1)
              if (!zone_in_use(temp_block)) {
                 current_block = temp_block;
                 break;
              }
        }
        else
          if (current_block-- < 1) current_block = 1;
	win_start = 0;
	break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
	fake_inode->i_zone[c-'0'] = current_block;
	break; 
      case 'q':
      case 'Q':
      case 'S':
      case 's':
      case 'I':
      case 'i':
      case 'R':
      case 'r':
	return c;
	break;
      case '#':
	if (temp_block = cread_num("Enter block number (leading 0x or $ indicates hex):"))
              current_block = temp_block;	
	break;
      case 'u':
      case 'U':
        block_unused = 1 - block_unused ;
        break;
      case 'L'-'A'+1: /* ^L */
	refresh_all();
	break;
      default:
	break;
    }

    if (current_block > ZONES)
      current_block=ZONES;
    else if (current_block < 1 ) 
      current_block = 1;
    
    cdump_block(current_block,win_start,VERT);
    wrefresh(workspace);
  }
  return 0;
}

/* Display current inode */
void cdump_inode(unsigned int nr)
{
  struct minix_inode * inode;
  int j;
  char f_mode[12];
  struct passwd *NC_PASS;
  struct group *NC_GROUP;
  
  inode = Inode + nr;
 
  clobber_workspace(); 
  workspace = newwin(8,(COLS-HOFF),VERT_CENT,HOFF);
  
  mode_string((unsigned short)inode->i_mode,f_mode);
  f_mode[10] = 0; /* Junk from canned mode_string */
  mvwprintw(workspace,0,0,"%10s",f_mode);
  mvwprintw(workspace,0,11,"%3d",inode->i_nlinks);
  if ((NC_PASS = getpwuid(inode->i_uid))!=NULL)
    mvwprintw(workspace,0,15,"%8-s",NC_PASS->pw_name);
  else
    mvwprintw(workspace,0,15,"%8-d",inode->i_uid);
  if ((NC_GROUP = getgrgid(inode->i_gid))!=NULL)
    mvwprintw(workspace,0,24,"%8-s",NC_GROUP->gr_name);
  else
    mvwprintw(workspace,0,24,"%8-d",inode->i_gid);
  mvwprintw(workspace,0,32,"%9d",inode->i_size);
  mvwprintw(workspace,0,42,"%24s",ctime(&(inode->i_time)));

  sprintf(f_mode,"%07o",inode->i_mode);
	
  mvwprintw(workspace,2,0,"TYPE: ");
  if (S_ISREG(inode->i_mode))
    mvwprintw(workspace,2,6,"regular file");
  else if (S_ISDIR(inode->i_mode))
    mvwprintw(workspace,2,6, "directory");
  else if (S_ISLNK(inode->i_mode))
    mvwprintw(workspace,2,6, "symbolic link");
  else if (S_ISCHR(inode->i_mode))
    mvwprintw(workspace,2,6, "char device");
  else if (S_ISBLK(inode->i_mode))
    mvwprintw(workspace,2,6, "block device");
  else if (S_ISFIFO(inode->i_mode))
    mvwprintw(workspace,2,6, "named pipe");
  else if (S_ISSOCK(inode->i_mode))
    mvwprintw(workspace,2,6, "socket");
  
  /* This covers blocks which would give Minix mode not cleared errors */
  if (!inode_in_use(nr)) mvwprintw(workspace,2,25,"(NOT USED)");

  mvwprintw(workspace,3,0,"MODE: \\%4.4s FLAGS: \\%3.3s\n",&f_mode[3],f_mode);
  mvwprintw(workspace,4,0,"UID: %05d(%s)",inode->i_uid, (NC_PASS != NULL) ? NC_PASS->pw_name : "");
  mvwprintw(workspace,4,20,"GID: %05d(%s)",inode->i_gid, (NC_GROUP != NULL) ? NC_GROUP->gr_name : "");
  mvwprintw(workspace,5,0,"TIME: %24s",ctime(&(inode->i_time)));
  mvwprintw(workspace,5,0,"LINKS: %3d SIZE: %-8d \n",inode->i_nlinks,inode->i_size);
  
  if (inode->i_zone[0]) {
    j=-1;
    mvwprintw(workspace,6,0,"BLOCKS=");
    while ((++j<9)&&(inode->i_zone[j])) {
      max_blocks_this_inode = j;
      mvwprintw(workspace,6+j/7,(j%7+1)*10,"0x%7.7x",inode->i_zone[j]);
    }
  }
  
  wrefresh(workspace);
  update_header();
}

/* This is the parser for inode_mode: previous/next inode, etc. */
int inode_mode() {
  int c, flag, cb;
  unsigned int temp_inode;
  struct minix_inode * inode;
  
  cb = 0;

#if TRAILER_SIZE>0
  werase(trailer);
  strncpy(echo_string,"UP/DOWN = previous/next inode, or '#' to enter inode number",150);
  mvwaddstr(trailer,0,(COLS-strlen(echo_string))/2-1,echo_string);
  strncpy(echo_string,"Q to quit",150);
  mvwaddstr(trailer,1,(COLS-strlen(echo_string))/2-1,echo_string);
  wrefresh(trailer);
#endif
  
  flag = 1; c = ' ';
  while (flag||(c = getch())) {
    flag = 0;
    switch (c) {
      case 'N'-'A'+1: /* ^N */
      case KEY_NPAGE:
      case KEY_DOWN:
        if (inode_unused) {
           temp_inode = current_inode;
           while (temp_inode++ < INODES)
              if (!inode_in_use(temp_inode)) {
                 current_inode = temp_inode;
                 break;
              }
        }
        else
          if (current_inode++ > INODES) current_inode = INODES;
	cb = 0;
	break;
      case 'P'-'A'+1: /* ^P */
      case KEY_PPAGE:
      case KEY_UP:
        if (inode_unused) {
           temp_inode = current_inode;
           while (temp_inode-- > 1 )
              if (!inode_in_use(temp_inode)) {
                 current_inode = temp_inode;
                 break;
          }
        }
        else
          if (current_inode-- < 1) current_inode = 1;
	cb = 0;
	break;
      case 'F'-'A'+1: /* ^F */
      case KEY_RIGHT:
	if (++cb > max_blocks_this_inode) cb--;
	break;
      case 'B'-'A'+1: /* ^B */
      case KEY_LEFT:
	if (--cb < 0 ) cb=0;
	break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
	inode = Inode + current_inode;
	if (inode->i_zone[c-'0']) {
	  current_block = inode->i_zone[c-'0'];
	  return 'b';
	}
	break;
      case 'u':
      case 'U':
        inode_unused = 1 - inode_unused ;
        break;
      case 'R':
	inode = Inode + current_inode;
	for (cb=0;cb<9;cb++)
	  fake_inode->i_zone[cb] = inode->i_zone[cb];
	return c;
	break;
      case 'B':
	inode = Inode + current_inode;
	if (inode->i_zone[cb]) current_block = inode->i_zone[cb];
      case 'b':
      case 'q':
      case 'Q':
      case 'S':
      case 's':
      case 'r':
	return c;
	break;
      case '#':
	if (temp_inode = cread_num("Enter inode number (leading 0x or $ indicates hex):"))
            current_inode = temp_inode;	
	break;
      case 'L'-'A'+1: /* ^L */
	refresh_all();
	break;
    }
    if (current_inode > INODES) 
      current_inode = INODES;
    else if (current_inode < 1 ) 
      current_inode = 1;
    
    cdump_inode(current_inode);
    wmove(workspace,6+cb/7,(cb%7+1)*10);
    wrefresh(workspace);
  }
  return 0;
}

int recover_mode()
{
  FILE *fp;
  int j,c,flag;
  char recover_file_name[80];
  unsigned int temp_block;
 
  clobber_workspace(); 
  workspace = newwin(9,(COLS-HOFF),VERT_CENT,HOFFPLUS);
  
#if TRAILER_SIZE>0
  werase(trailer);
  strncpy(echo_string,"Enter number corresponding to block to modify values",150);
  mvwaddstr(trailer,0,(COLS-strlen(echo_string))/2-1,echo_string);
  strncpy(echo_string,"Q to quit, R to dump to file",150);
  mvwaddstr(trailer,1,(COLS-strlen(echo_string))/2-1,echo_string);
  wrefresh(trailer);
#endif

  flag=1; c = ' ';
  while (flag||(c = getch())) {
    switch (c) {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
        if ( (temp_block = cread_num("Enter block number (leading 0x or $ indicates hex):")) )
           fake_inode->i_zone[c-'0'] = temp_block;
        break;
      case 'B':
      case 'b':
      case 'q':
      case 'Q':
      case 'S':
      case 's':
      case 'I':
      case 'i':
	return c;
	break;
      case 'c':
      case 'C':
#       if TRAILER_SIZE>0
           if (check_recover(fake_inode))
	      sprintf(echo_string,"Dataspace is used by another file, things don't look good.");
           else
              sprintf(echo_string,"Good chance for file recovery.");
	   mvwaddstr(trailer,TRAILER_SIZE-1,(COLS-strlen(echo_string))/2-1,
	   	  echo_string);
	   wrefresh(trailer);
	   wmove(trailer,TRAILER_SIZE-1,0);
	   wclrtoeol(trailer);
           /* Still has to be refreshed by someone */
#       endif
        break;
      case 'L'-'A'+1: /* ^L */
	refresh_all();
	break;
      case 'R':
      case 'r':
	sprintf(recover_file_name," Write data to file:");
	(void) cread_num(recover_file_name);
	if (strlen(recover_file_name)<1)
	  strcpy(recover_file_name,"RECOVERED.file");
	if ((fp = fopen(recover_file_name,"w")) != NULL) {
	  crecover_file(fp, fake_inode);
	  fclose(fp);
	}
#if TRAILER_SIZE>0
	sprintf(echo_string,"Recovered data written to '%s'",
		recover_file_name);
	if (fp==NULL)
	  sprintf(echo_string,"Cannot open file '%s'\n",recover_file_name);
	mvwaddstr(trailer,TRAILER_SIZE-1,(COLS-strlen(echo_string))/2-1,
		  echo_string);
	wrefresh(trailer);
	wmove(trailer,TRAILER_SIZE-1,0);
	wclrtoeol(trailer);
	/* Still has to be refreshed by someone */
#endif
	break;
    }

    mvwprintw(workspace,0,0,"DIRECT BLOCKS:" );
    for (j=0; j<7; j++)
      mvwprintw(workspace,j,20," %d : %7.7x",j,fake_inode->i_zone[j]);
    mvwprintw(workspace,7,0,"INDIRECT BLOCK:" );
    mvwprintw(workspace,7,20," %d : %7.7x",7,fake_inode->i_zone[7]);
    mvwprintw(workspace,8,0,"2x INDIRECT BLOCK:" );
    mvwprintw(workspace,8,20," %d : %7.7x",8,fake_inode->i_zone[8]);
    wrefresh(workspace);
    flag = 0;
  }	
  return 0;
}

/* Not too exciting main parser with superblock on screen */
void interactive_main()
{
int c;
static int flag;

fake_inode = malloc(INODE_SIZE);

/* Curses junk */
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
scrollok(stdscr, TRUE);
if (has_colors()) {
  start_color();
  init_pair(1,COLOR_BLUE,COLOR_BLACK);
  init_pair(2,COLOR_WHITE,COLOR_BLUE);
  HIGHLIGHT_1 = COLOR_PAIR(1);
  HIGHLIGHT_2 = COLOR_PAIR(2);
}
else {
  HIGHLIGHT_1 = HIGHLIGHT_2 = A_REVERSE;
}
HOFF = ( COLS - 80 ) / 2;
HOFFPLUS = COLS>40 ? (COLS-50)/2 : 0;
VERT = LINES - HEADER_SIZE - TRAILER_SIZE ; 
VERT_INODE = VERT>7  ? 7 : VERT;
VERT_SUPER = VERT>10 ? 10 : VERT;
VERT_CENT = (VERT - VERT_SUPER)/2 + HEADER_SIZE;

/* These are the three curses windows */
#if HEADER_SIZE>0
header = newwin(HEADER_SIZE,COLS,0,0);
#endif
workspace = newwin(VERT_SUPER,COLS/2,VERT_CENT,HOFFPLUS);
#if TRAILER_SIZE>0
trailer = newwin(TRAILER_SIZE,COLS,LINES-TRAILER_SIZE,0);
#endif

#if HEADER_SIZE>0
wattron(header,HIGHLIGHT_2);
werase(header);
sprintf(echo_string,"%s v%s : %s",CURSES_NAME,VERSION,device_name);
mvwaddstr(header,0, (COLS-strlen(echo_string))/2-1,echo_string);
wrefresh(header);
#endif

/* flag is used so that the user can switch between modes without
 * getting stuck here.  Flag indicates no keypress is required, so
 * getch() is not called.
 */
flag = 1; c = ' ';
while (flag || (c = getch())) {
  switch (c|flag) {
    case 'B':
    case 'b':
      c = flag = block_mode();
      break;
    case 'I':
    case 'i':
      c = flag = inode_mode();
      break;
    case 'R':
    case 'r':
      c = flag = recover_mode();
      break;
    case 'q':
    case 'Q':
      endwin();
      free(fake_inode);
      return;
      break;
    case 'L'-'A'+1: /* ^L */
      refresh_all();
      break;
    default:
      flag=0;
      break;
    }

  show_super();
  update_header();
#if TRAILER_SIZE>0
  werase(trailer);
  strncpy(echo_string,"I)node, B)locks, R)ecover File",150);
  mvwaddstr(trailer,0, (COLS-strlen(echo_string))/2-1,echo_string);
  wrefresh(trailer);
#endif
}

/* No way out here -- have to use Q key */
}

