/*********************************************************************
 *
 *   This is ADT, a user friendly frontend for Aminet FTP sites.
 *
 *   To re-setup adt, start it using adt -n
 *
 *********************************************************************/

/* Include files */

#include <stdlib.h>
#ifdef ultrix
#include <cursesX.h>
#include <term.h>
#else
#include <curses.h>
#endif
#include <string.h>
#include <varargs.h>
#include <signal.h>
#ifdef SYSV
#include <netdb.h>
#include <term.h>
#else
#include <sys/param.h>
#endif
#include "adt.h"
#include "version.h"

/* Function protos  */

void
  cur_init(),
  cur_main(),
  cur_status(),
  cur_command(),
  cur_total_refresh(),
  cur_refresh_top(),
  cur_refresh_bot(),
  cur_more(),
  cur_refresh(),
#ifdef SIGINT
  cur_sigexit(),
#endif
  cur_exit(),
  cur_t_server(),
  cur_st_server(),
  cur_e_server(),
  cur_t_help(),
  cur_st_help(),
  cur_e_help(),
  cur_t_tag(),
  cur_st_tag(),
  cur_e_tag(),
  cur_t_new(),
  cur_e_entry(),
  cur_st_entry(),
  cur_t_recent(),
  cur_t_all(),
  cur_name(),
  cur_view(),
  cur_center(),
  cur_cd(),
  cur_download(),
  cur_gotoline();

int
  cur_getch(),
  cur_sort(),
  cur_scale(),
  cur_get_string(),
  cur_get_number();

/* external functions */

extern void
  (* adt_quit)(),
  (* adt_status)(),
  (* adt_more)(),
  (* adt_refresh)(),
  (* adt_refresh_list)(),
  adt_exit(),
  adt_sort(),
  adt_goto_line(),
  adt_goto_start(),
  adt_set_mode(),
  adt_xit(),
  adt_info(),
  adt_Quit(),
  adt_download(),
  adt_mode_long(),
  adt_readme(),
  adt_nocr(),
  adt_cd(),
  adt_tag();

extern int
  adt_select();

/* external variables */

extern int
  Save,
  Window,
  NumVisible,
  NumTagged,
  Mode,
  Offset,
  OldOffset,
  KeepResult,
  SortMode,
  Long,
  gotall,
  OldHelpMode;

extern TAG
  *Active,
  *Page,
  *OldActive,
  *OldPage,
  *Visible,
  *Tag;

extern char
  Result[],
  GBuf[];

extern struct {
  int (*func)();
  char *text;
} Sort[];

/* Constant's #define */

#define TITLE    0
#define SUBTITLE 2
#define WINSIZE (LINES-9)
#define OPTIONS (LINES-5)
#define COMMAND (LINES-3)
#define STATUS  (LINES-1)

#define SKEY_UP     300
#define SKEY_DOWN   301
#define SKEY_RIGHT  302
#define SKEY_LEFT   303
#define SKEY_BS     304

/* Function's #define */

#define cur_ungetch(c) (UnGot=c)
#define wait4key() (cur_ungetch(cur_getch()))
#define left(rows,cols,str) (mvaddstr(rows,(cols-strlen(str)),str))

/* option strings */

static char cur_o_server[] = "s)ave       u)se";
static char cur_o_help[]   = "<i> to exit help";
static char cur_o_tag[]    = "d)ownload i)nfo l)ong n)ame r)eadme s)ort q)uit";
static char cur_o_entry[]  = "d)ownload i)nfo l)ong n)ame r)eadme s)ort v)iew q)uit";

struct {
  void (* cur_title)();
  void (* cur_subtitle)();
  void (* cur_entry)();
  char *cur_options;
} cur_modes[] = {
  { cur_t_server , cur_st_server , cur_e_server , cur_o_server },
  { cur_t_help   , cur_st_help   , cur_e_help   , cur_o_help   },
  { cur_t_tag    , cur_st_tag    , cur_e_tag    , cur_o_tag    },
  { cur_t_new    , cur_st_entry  , cur_e_entry  , cur_o_entry  },
  { cur_t_recent , cur_st_entry  , cur_e_entry  , cur_o_entry  },
  { cur_t_all    , cur_st_entry  , cur_e_entry  , cur_o_entry  }
};

int
  Status,
  Options,
  Command,
  FastRefresh = 0,
  NoStandOut = 0,   /* 1 = terminal cannot do standout */
  UnGot,
  cur_s_off1,
  cur_s_off2,
  cur_s_off3,
  cur_e_off1,
  cur_e_off2,
  cur_e_off3,
  cur_h_off1;

void cur_init()
{
#ifdef SIGINT
  signal(SIGINT, cur_sigexit);
#endif
  initscr();
  adt_quit=cur_exit;
  nonl();
  noecho();
  cbreak();
  clear();

  /* Check for minimum display size */
  
  if (LINES < 10 || COLS < 80 )
    (* adt_quit)("incompatible display size");
  
#if defined(SYSV) || defined (ultrix)   /* I hope I'm doing this right */
  if (!enter_standout_mode) {
#else    /* BSD */
  if (!SO || !*SO) {
#endif
    NoStandOut = 1;
    FastRefresh = 1;
  }
  
  adt_status = cur_status;
  adt_more = cur_more;
  adt_refresh = cur_total_refresh;
  adt_refresh_list = cur_refresh_top;
  Window = WINSIZE;
  Status = STATUS;
  Options = OPTIONS;
  Command = COMMAND;
  cur_s_off1 = cur_scale(15,3,0);
  cur_s_off2 = cur_scale(40,3,1);
  cur_s_off3 = COLS-cur_s_off1-cur_s_off2-2;
  cur_e_off1 = cur_scale(20,2,0);
  cur_e_off2 = cur_scale(39,2,0);
  /*  cur_e_off3 = cur_scale(38,2,0); */
  cur_h_off1 = 13;
}

void cur_main()
{
  int ch;
  
  for(;;) {
    ch = cur_getch();
    switch(ch)
      {
      case 'q':
	cur_command("Command: Quit");
	adt_Quit();
	break;
      case 'Q':
	cur_command("Command: Exit");
	adt_xit();
	break;
      case 13:
      case 10:
	if (adt_select())
	  cur_refresh_top(0);
	break;
      case SKEY_DOWN:
      case 'N'-64:
      case 'k':
	if (Mode != M_HELP) {
	  adt_goto_line(Offset+1);
	  cur_refresh_top(0);
	}
	break;
      case SKEY_UP:
      case 'P'-64:
      case 'j':
	if (Mode != M_HELP) {
	  adt_goto_line(Offset-1);
	  cur_refresh_top(0);
	}
	break;
      case SKEY_RIGHT:
      case 'V'-64:
      case ' ':
	adt_goto_line (Offset+Window);
	cur_refresh_top(0);
	break;
      case SKEY_BS:
      case SKEY_LEFT:
	adt_goto_line(Offset-Window);
	cur_refresh_top(0);
	break;
      case '<':
	adt_goto_start();
	cur_refresh_top(0);
	break;
      case '>':
	adt_goto_line(NumVisible);
	cur_refresh_top(0);
	break;
      case 'i':
	if (MULTI_MODE && Visible)
	  adt_info(Active->entry);
	else if (Mode == M_HELP) {
	  strcpy(Result,GBuf);
	  adt_set_mode(OldHelpMode);
	}
	wait4key();
	break;
      case 'c':
	if (Mode != M_HELP)
	  cur_cd();
	break;
      case 'd':
	if (MULTI_MODE && Visible)
	  cur_download(0);
	break;
      case 'D':
	if (MULTI_MODE && Visible)
	  cur_download(1);
	break;
      case 'h':
	if (Mode != M_HELP)
	  adt_set_mode(M_HELP);
	break;
      case 'l':
	if (MULTI_MODE && Visible) {
	  cur_command("Command: Long");
	  adt_mode_long();
	  cur_refresh_top(1);
	}
	break;
      case 'n':
	if (MULTI_MODE && Visible)
	  cur_name();
	break;
      case 'o':
	if (MULTI_MODE)
	  adt_set_mode(M_SERVER);
	break;
      case 'r':    /* Readme, std option */
	if (MULTI_MODE && Visible) {
	  cur_command("Command: Readme");
	  adt_readme(0);
	  wait4key();
	}
	break;
      case 'R':    /* Readme, Force status line */
	if (MULTI_MODE && Visible) {
	  cur_command("Command: Readme");
	  adt_readme(1);
	  wait4key();
	}
	break;
      case 's':
	if (Mode == M_SERVER) {
	  Save = 1;
	  adt_select();
	}
	else if (MULTI_MODE && Visible)
	  if (cur_sort()) {
	    adt_goto_start();
	    cur_total_refresh();
	  }
	break;
    case 'u':
	if (Mode == M_SERVER) {
	  Save = 0;
	  adt_select();
	}
	break;
      case 'v':
	cur_view();
	break;
      case 'I':
	if (!NoStandOut) {
	  FastRefresh ^= 1;
	  cur_refresh_top(1);
	}
	break;
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
	if (Mode != M_HELP) {
	  cur_ungetch(ch);
	  cur_gotoline();
	}
	break;
      }
    cur_refresh_bot(1);
  }
}

/* default ^C handler */

void
  cur_sigexit()
{
  (* adt_quit)(NULL);
}

/* cur_exit handles exiting adt: quiting curses, getting rid of /tmp files,
   and printing of the 'str' text on stderr, if it exists */

void cur_exit(str)
     char *str;
{
  noraw();
  nl();
  endwin();
  
  adt_exit(str);
}

void cur_total_refresh()
{
  cur_refresh_top(1);
  cur_refresh_bot(1);
}

/* Refreshed the title and entries on a list. If flag is not zero forces */
/* the redrawing of the entire list, otherwise, only the needed entries  */
/* are refreshed */

void cur_refresh_top(flag)
     int flag;
{
  char buf[40];
  int i;
  TAG
    *entry;
  
  move(TITLE,0);
  clrtoeol();
  sprintf(buf,"Aminet Download Tool %s",VERSION);
  mvaddstr(TITLE,(COLS-strlen(buf))/2,buf); /* don't want center's refresh */
  
  (* cur_modes[Mode].cur_title)();
  
  entry = Page;

  move(SUBTITLE,0);
  clrtoeol();

  (* cur_modes[Mode].cur_subtitle)();

  if(OldPage != Page || flag) {
    OldPage = Page;       /* to optimize refresh later */
    OldActive = NULL;     /* to prevent wrong refresh */
    for (i = 0 ; i < Window ; i++) {
      move(i+3,0);
      clrtoeol();
      if (entry) {
	(* cur_modes[Mode].cur_entry)(entry,i+3);
	entry = entry->next;
      }
    }
  } else {     /* OldPage == Page ==> cut down on refresh overhead */
    if (OldActive) {
      i = OldOffset % Window;
      if (i == 0)
        i = Window;
      move(i+2,0);
      clrtoeol();
      (* cur_modes[Mode].cur_entry)(OldActive,i+2);
    }
    if (Active) {
      i = Offset % Window;
      if (i == 0)
	i = Window;
      move(i+2,0);
      clrtoeol();
      (* cur_modes[Mode].cur_entry)(Active,i+2);
    }
  }
  refresh();
}

/* refreshes the bottom part of the display (options + status */
/* if 'flag' is non-zero, redraws the command prompt */

void cur_refresh_bot(flag)
     int flag;
{
  if (cur_modes[Mode].cur_options) {
    move(Options,0);
    clrtoeol();
    cur_center(Options,cur_modes[Mode].cur_options);
  }
  cur_status(Result); /* does refresh */
  if (!KeepResult)
    *Result = '\0';
  if (flag)
    cur_command("Command: "); /* does refresh */
}

/* Puts 'str' at command line */

void cur_command(str)
     char *str;
{
  move(Command,0);
  clrtoeol();
  mvaddstr(Command,0,str);
  refresh();
}

/* Displays file named 'file', using 'title' as a title */

void cur_more(file, title)
     char
       *file,
       *title;
{
  FILE
    *in;
  
  int
    i,
    eof=0,
    ch,
    cnt;
  
  if(!(in=fopen(file,"r")))
    return;
  
  while( !eof ) {
    clear();
    cur_center(TITLE,title);
    for( i=2; i<LINES-2; i++ ) {
      cnt = 0;
      if( !eof ) {
	GBuf[0] = '\0';
	while(!eof && cnt < COLS+1 ) {
	  if ((ch = fgetc(in)) == EOF) {
	    eof = 1;
	    break;
	  }
	  if (ch == 13 || ch == 10)
	    break;
	  GBuf[cnt++]=ch;
	  GBuf[cnt]='\0';
	}
      }
      if( !eof || cnt != 0)
	mvaddstr(i,0,GBuf);
    }
    standout();
    if( !eof )
      cur_status("More - press space or i/q to return");
    else
      cur_status("End of file - press space to return");
    standend();
    
    switch(cur_getch())
      {
      case 'q':
      case 'i':
	eof=1;
	break;
      }
  }
  fclose(in);
  clear();
  cur_total_refresh();
}

int
  cur_getch()
{
  int
    c,
    c1;
  
  if( UnGot ) {
    c=UnGot;
    UnGot=0;
    return c;
  }
  for(;;) {
    c=getchar();
    switch (c)
      {
      case 'L'-64:           /* ^L Force a screen refresh */
	wrefresh(curscr);
	break;
      case 8:
      case 127:
	return SKEY_BS;
      case 27:
	if ((c1=getchar()) != '[')
	  return c1;
      case 155:
	switch(c1=getchar())
	  {
	  case 'A':
	    return SKEY_UP;
	  case 'B':
	    return SKEY_DOWN;
	  case 'C':
	    return SKEY_RIGHT;
	  case 'D':
	    return SKEY_LEFT;
	  default:
	    return c;
	  }
      default:
	return c;
      }
  }
}

void cur_name()
{
  char
    buf2[50],
    *buf;
  TAG
    *tag,
    *start;
  int
    len=0,
    begin,
    i, c;
  
  bzero(buf2,40);
  strcpy(buf2,"name-i-search: ");
  buf = &buf2[15]; /* right after prompt */
  start = Active;
  begin = Offset;
  KeepResult = 0;
  
  for(;;) {
    cur_refresh_bot(0);
    cur_command(buf2);
    
    switch( c=cur_getch() )
      {
      case 10:
      case 13:
	goto exit;
      case SKEY_BS:
	if( len > 0 ) {
	  buf[--len]='\0';
	  cur_command(buf2);
	  i = begin;
	  for(tag=start ;
	      tag && strnicmp(tag->entry->file,buf,len);
	      tag = tag->next ) i++;
	  if (tag) {
	    adt_goto_line(i);
	    cur_refresh_top(0);
	  }
	  else strcpy(Result,"No match");
	}
	break;
      case 'N'-64:
	if(len > 0) {
	  i = Offset+1;
	  for(tag=Active->next;
	      tag && strnicmp(tag->entry->file,buf,len);
	      tag = tag->next ) i++;
	  if (tag) {
	    adt_goto_line(i);
	    cur_refresh_top(0);
	  }
	  else strcpy(Result,"No match");
	}
	break;
      case 'P'-64:
	if(len > 0) {
	  i= Offset-1;
	  for(tag=Active->prev;
              tag && tag != start->prev && strnicmp(tag->entry->file,buf,len);
              tag = tag->prev) i--;
	  if (tag && tag != start->prev ) {
	    adt_goto_line(i);
            cur_refresh_top(0);
          }
	  else strcpy(Result,"No match");
        }
        break;
      default:
	if(c<' ' || c>'z')
	  goto exit;
	if (len > 30 )
	  break;
	buf[len++]=c;
	cur_command(buf2);
	i = Offset;
	for(tag=Active;
	    tag && strnicmp(tag->entry->file,buf,len);
	    tag = tag->next ) i++;
	if (tag) {
	  adt_goto_line(i);
	  cur_refresh_top(0);
	}
	else strcpy(Result,"No match");
      }
  }
  
 exit:
  if( c!=10 && c!=13 )
    cur_ungetch(c);
  cur_refresh_bot(1);
}

/* Generic curses display routines */

/* center the string 'str' in row number 'rows' */

void cur_center(rows,str)
     int rows;
     char *str;
{
  mvaddstr(rows,(COLS-strlen(str))/2,str);
  refresh();
}

/* Center the string 'str' in the status line */

void cur_status(va_alist)
     va_dcl
{
  va_list args;
  char *fmt, buf[256];
  
  *buf = '\0';
  move(Status,0);
  clrtoeol();
  
  va_start(args);
  fmt = va_arg(args, char *);
  if (fmt)
    vsprintf(buf,fmt,args);
  va_end(args);
  
  if (*buf != '\0')
    cur_center(Status,buf);
  refresh();
}

/* scale size */

int cur_scale(base,div,mod)
     int base,div,mod;
{
  int rem, divd;
  
  rem = (COLS % 80 ) % div;
  divd = (COLS % 80 ) / div;
  
  if (mod == 0 )
    return base + divd;
  if ( rem > mod )
    return base + divd;
  return base + divd + 1;
}

/* title for M_SERVER */

void cur_t_server()
{
  mvprintw(TITLE,0,"Servers: %d/%d",Offset,NumVisible);
  sprintf(GBuf,"Page: %d/%d",Offset/Window+1,NumVisible/Window+1);
  left(TITLE,COLS,GBuf);
}

/* title for M_NEW */

void cur_t_new()
{
  if(NumVisible)
    mvprintw(TITLE,0,"New files: %d/%d",Offset,NumVisible);
  else
    mvaddstr(TITLE,0,"No new files");
  sprintf(GBuf,"Page: %d/%d",Offset/Window+1,NumVisible/Window+1);
  left(TITLE,COLS,GBuf);
}

void cur_t_all()
{
  if(NumVisible)
    mvprintw(TITLE,0,"All files: %d/%d",Offset,NumVisible);
  else
    mvaddstr(TITLE,0,"No files");
  sprintf(GBuf,"Page: %d/%d",Offset/Window+1,NumVisible/Window+1);
  left(TITLE,COLS,GBuf);
}

void cur_t_recent()
{
  if(NumVisible)
    mvprintw(TITLE,0,"Recent files: %d/%d",Offset,NumVisible);
  else
    mvaddstr(TITLE,0,"No recent files");
  sprintf(GBuf,"Page: %d/%d",Offset/Window+1,NumVisible/Window+1);
  left(TITLE,COLS,GBuf);
}

/* title for M_HELP */

void cur_t_help() /* stub */
{
}

/* title for M_TAG */

void cur_t_tag()
{
  mvprintw(TITLE,0,"Tagged: %d/%d",Offset,NumTagged);
  sprintf(GBuf,"Page: %d/%d",Offset/Window+1,NumTagged/Window+1);
  left(TITLE,COLS,GBuf);
}

/* Subtitle for M_SERVER */

void cur_st_server()
{
  int mod = 0;
  
  if (FastRefresh)
    mod = 1;
  mvaddstr(SUBTITLE,mod,"Country");
  mvaddstr(SUBTITLE,mod+cur_s_off1+1,"Site");
  mvaddstr(SUBTITLE,mod+cur_s_off1+cur_s_off2+2,"Directory");
}

/* Subtitle for M_ENTRY */

void cur_st_entry()
{
  int mod = 0;
  
  if (FastRefresh)
    mod = 1;
  if (Long) {
    mvprintw(SUBTITLE,mod+1,"File (by %s)",Sort[SortMode].text);
    mvaddstr(SUBTITLE,mod+cur_e_off1+2,"Description");
  }
  else {
    mvprintw(SUBTITLE,mod+1,"File (by %s)",Sort[SortMode].text);
    mvaddstr(SUBTITLE,mod+cur_e_off1+2,"Dir");
    mvaddstr(SUBTITLE,mod+cur_e_off1+14,"Size");
    mvaddstr(SUBTITLE,mod+cur_e_off1+19,"Description");
  }
  left(SUBTITLE,COLS,"Readme");
}

/* Subtitle for M_HELP */

void cur_st_help()
{
  mvaddstr(SUBTITLE,0,"Command");
  mvaddstr(SUBTITLE,cur_h_off1,"Description");
}

/* Subtitle for M_TAG */

void cur_st_tag()
{
  int mod = 0;
  
  if (FastRefresh)
    mod = 1;
  if (Long) {
    mvprintw(SUBTITLE,mod+1,"File (by %s)",Sort[SortMode].text);
    mvaddstr(SUBTITLE,mod+cur_e_off1+2,"Description");
  }
  else {
    mvprintw(SUBTITLE,mod+1,"File (by %s)",Sort[SortMode].text);
    mvaddstr(SUBTITLE,mod+cur_e_off1+2,"Dir");
    mvaddstr(SUBTITLE,mod+cur_e_off1+14,"Size");
    mvaddstr(SUBTITLE,mod+cur_e_off1+19,"Description");
  }
  left(SUBTITLE,COLS,"Readme");
}

/* Entry for M_SERVER */

void cur_e_server(tag,line)
     TAG *tag;
     int line;
{
  SERVER *show;
  int mod = 0;
  
  if(FastRefresh)
    mod = 1;
  
  if (tag == Active)
    if (FastRefresh)
      mvaddch(line,0,'>');
    else
      standout();
  
  show = (SERVER *)tag->entry;
  
  mvprintw(line,mod,"%-*.*s %-*.*s %-*.*s",
	   cur_s_off1,cur_s_off1,show->country,
	   cur_s_off2,cur_s_off2,show->host,
	   cur_s_off3,cur_s_off3,show->dir);
  if (tag == Active && !FastRefresh)
    standend();
}

/* Entry for M_ENTRY */

void cur_e_entry(tag,line)
     TAG *tag;
     int line;
{
  int size, mod =0;
  ENTRY *show;
  
  if (FastRefresh)
    mod = 1;
  if (tag == Active)
    if (FastRefresh)
      mvaddch(line,0,'>');
    else
      standout();

  show = tag->entry;
  
  size = show->size;
  if (size == -1)
    strcpy(GBuf,"Read");
  else if (size < 1024)
    sprintf(GBuf,"%dB",size);
  else if ((size = (size+512)/1024) < 1024)
    sprintf(GBuf,"%dK",size);
  else sprintf(GBuf,"%d.%dM",size/1024,(size*10/1024)%10);
  
  if (Long)
    mvprintw(line,mod,"%c%-*.*s %-*.*s%c",
	     (IS_TAGGED(show)) ? '+' : ' ',
	     cur_e_off1,cur_e_off1,show->file,
	     cur_e_off2+18-mod,cur_e_off2+18-mod,show->desc,
	     (HAS_README(show)) ? '*' : ' ');
  else
    mvprintw(line,mod,"%c%-*.*s %-10.10s %5.5s %-*.*s%c",
	     (IS_TAGGED(show)) ? '+' : ' ',
	     cur_e_off1,cur_e_off1,show->file,
             show->dir,
             GBuf,
             cur_e_off2-mod+1,cur_e_off2-mod+1,show->desc,
             (HAS_README(show)) ? '*' : ' ');

  if (tag == Active && !FastRefresh)
    standend();
}

/* Entry for M_HELP */

void cur_e_help(tag,line)
     TAG *tag;
     int line;
{
  HELP *show;
  
  show = (HELP *)tag->entry;
  
  mvaddstr(line,0,show->command);
  mvaddstr(line,cur_h_off1,show->desc);
}

/* Entry for M_TAG */

void cur_e_tag(entry,line)
     TAG *entry;
     int line;
{
  cur_e_entry(entry,line);
}

/* handle View command */

void cur_view()
{
  if (!MULTI_MODE)
    return;
  cur_command("View: a)ll n)ew r)ecent t)agged");
  switch(cur_getch()) {
  case 'a':
    if (Mode == M_ALL) return;
    adt_set_mode(M_ALL);
    break;
  case 'n':
    if (Mode == M_NEW) return;
    adt_set_mode(M_NEW);
    break;
  case 'r':
    if (Mode == M_RECENT) return;
    adt_set_mode(M_RECENT);
    break;
  case 't':
    if (Mode == M_TAG) return;
    adt_set_mode(M_TAG);
    break;
  }
}

/* returns 0 if no refreshing is needed. 1 if it's needed */

int cur_sort()
{
  int oldsort = SortMode;
  
  cur_command("Sort by: a)ge d)ir n)ame s)ize");
  switch(cur_getch())
    {
    case 'a':
      cur_status("Sorting...");
      adt_sort(SORT_NAME,Visible);
      adt_sort(SORT_AGE,Visible);
      break;
    case 'A':
      cur_status("Sorting...");
      adt_sort(REV_SORT_NAME,Visible);
      adt_sort(REV_SORT_AGE,Visible);
      break;
    case 'd':
      cur_status("Sorting...");
      adt_sort(SORT_NAME,Visible);
      adt_sort(SORT_DIR,Visible);
      break;
    case 'D':
      cur_status("Sorting...");
      adt_sort(REV_SORT_NAME,Visible);
      adt_sort(REV_SORT_DIR,Visible);
      break;
    case 'n':
      cur_status("Sorting...");
      adt_sort(SORT_NAME,Visible);
      break;
    case 'N':
      cur_status("Sorting...");
      adt_sort(REV_SORT_NAME,Visible);
      break;
    case 's':
      cur_status("Sorting...");
      adt_sort(SORT_SIZE,Visible);
      break;
    case 'S':
      cur_status("Sorting...");
      adt_sort(REV_SORT_SIZE,Visible);
      break;
    }
  if (oldsort != SortMode)
    return 1;
  return 0;
}

void cur_cd()
{
  char path[40];
  
  strcpy(path,"Cd: ");
  if (cur_get_string(path,4,35))
    adt_cd(path+4);
}

/* returns zero on text entry aborted. Non-Zero (text len) if text  */
/* is returned */

int cur_get_string(buf,offset,len)
     char buf[];
     int
       offset,
       len;
{
  int 
    size,
    ch;
  
  char *ptr;

  ptr = buf+offset;
  bzero(ptr,len+1);
  
  size = 0;
  
  for(;;)
    {
      cur_command(buf);
      
      switch(ch = cur_getch())
	{
	case SKEY_BS:
	  if (size > 0)
	    ptr[--size]='\0';
	  break;
	case 10:
	case 13:
	  return size;
	default:
	  if (size < len)
	    ptr[size++]=ch;  /* no need to put NULL char here */
	}
    }
}

void cur_download(readme)
     int readme;
{
  if (!Tag)
    adt_tag(Active);         /* Nothing tagged, tag  <- traps adt_download() */
  
  adt_set_mode(M_TAG);       /* Traps adt_download() screen refresh */

  cur_command("Command: Download");

  adt_download(readme);
}

/* returns zero on text entry aborted. Non-Zero (text len) if text  */
/* is returned */

int cur_get_number(buf,offset,len)
     char buf[];
     int
       offset,
       len;
{
  int
    size,
    ch;
  
  char *ptr;
  
  ptr = buf+offset;
  bzero(ptr,len+1);
  
  size = 0;
  
  for(;;)
    {
      cur_command(buf);
      
      switch(ch = cur_getch())
        {
        case SKEY_BS:
          if (size > 0)
            ptr[--size]='\0';
          break;
        case 10:
        case 13:
          return size;
	case '0':
	  if (size > 0 && size < len)
	    ptr[size++]=ch;
	  break;
	case '1':
	case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          if (size < len)
            ptr[size++]=ch;  /* no need to put NULL char here */
        }
    }
}

void cur_gotoline()
{
  char num[20];
  int line;
  
  strcpy(num,"Goto-line: ");
  if (cur_get_number(num,11,5)) {
    line = atoi(&num[11]);
    if(line <= NumVisible) {
      adt_goto_line(line);
      cur_refresh_top(1);
    }
  }
}
