/* EMACS_MODES: !lnumb !fill */

/* to do */
/* Any char aborts pause */
/* Q=quit, P=pending or programmable keys ? */
/*         Key - Sec Lev. - Event */
/* move a file to WWIV area - use external file add program? */

#include <stdio.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <dos.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <dir.h>

#define NAME "fmenu"
#define VERSION "V2.2"
#define ANNOY "UNREGISTERED!"
#define ANNOYKEY "mibPEmgWPbPw7B0jok0jok"

#define AUTHOR "Andrew Gaunt"
#define AUTHORKEY "vvugec.ExvvM00ok00ok"

#define MENUFILE "FMENU.MSG"
#define QUEUE "SENDQUE.BAT"
#define QDATA "QUE.DAT"
#define QUOTE '\042'
#define BELL  '\007'
#define PESTER if(!reg){printf("UNREGISTERED");sleep(1);printf("\b\b\b\b\b\b\b\b\b\b\b\b            \b\b\b\b\b\b\b\b\b\b\b\b");}

#define CONFIGFLE "fmenu.cfg" /* Config file for this program */

#define MAXDIRS  64  /* maximum number of file areas */

#define MAXLINE 128
#define KEYWAIT 120L  /* number of seconds to wait for no keys pressed */
#define PAUSEWARN 30L /* Warn user if paused more than PAUSEWARN secs */

#define OK    0
#define ERROR   1
#define TMOUT 2

#define BREAKON 0
#define NOBREAK 1

#define MAXELM  256          /* Maximum number of elements for temp. array */
#define MAXNODE 128          /* Maximum number of nodes */
#define MAXNAME 81           /* Max number of chars for a BBS's name */
#define NODEFLAG "[NODES]"
#define DIRFLAG  "[DIRS]"
#define KEYFLAG  "[KEYS]"
#define ENDLIST  "[END]"
#define INT       6    /* number of chars needed to represent and integer */
#define MAXREGNO MAXNAME+INT+INT+INT

/* Token definitions */
#define __QUIT 0
#define __FILEXFER 1
#define __SEND 2
#define __RECEIVE 3
#define __LIST 4
#define __DELETE 5
#define __PENDING 6
#define __LNET 7
#define __ARCHIVE 8
#define __VIEW 9
#define __NODELIST 10
#define __REQUEST 11

#define __EXPRESS 12
#define __BBLIST 13
#define __CONLIST 14
#define __NETLIST 15
#define __SUBLIST 16
#define __MODE 17
#define __HELP 18

#define __RANGE 19
#define __SEARCH 20
#define __LOCAL 21

#define __USER0 22
#define __USER1 23
#define __USER2 24
#define __USER3 25
#define __USER4 26
#define __USER5 27
#define __USER6 28
#define __USER7 29
#define __USER8 30
#define __USER9 31

#define MAXKEY  32           /* Max number of key defintions */

#define nl() printf("\n");

void purgkey();
void prompt();
void inline();
int charin();


/* store file area paths in dirlist */
char dirlist[MAXDIRS][MAXPATH];
/* int secure; */
char array[MAXELM][MAXLINE];   /* temp array */
int nodelist[MAXNODE];     /* store nodes here */

typedef struct {
  char   k[10];        /* Key */
  int    sl;           /* Security Level */
  char   prg[MAXLINE]; /* program to run */
} ky;
ky key[MAXKEY];

char work_dir[MAXPATH];
char temp_dir[MAXPATH];
char this_node[INT];               /* BBS's node number */
char bbs_name[MAXNAME];            /* BBS's name */
char reg_key[MAXREGNO];        /* reg. number - calc. from name and node */
short reg; /* Set to true if registered */
char file_minor[INT];
char remote_minor[INT];
static char author[]=AUTHOR;
static char annoy[]=ANNOY;
short bbllo,bblhi,conlo,conhi,netlo,nethi,sublo,subhi,mode;

/* Name of WWIV chain.txt file */
char chainfile[MAXPATH];
char configfile[MAXPATH];

/* From skeleton.c */
#define v407


int    usernum,             /* user number for the user */
       age,                 /* age of the user */
       screenchars,         /* chars/line user has specified */
       screenlines,         /* lines/screen user has specified */
       sl,                  /* sec lev for user (0-255) */
       so,                  /* non-zero if user is sysop (sl=255) */
       cs,                  /* non-zero if user is co-sysop */
       okansi,              /* non-zero if user can support ANSI */
       incom,               /* non-zero if user is calling remotely */
       comport;             /* com port user is on */
char   name[81],            /* name/alias of user */
       realname[81],        /* real name of user */
       callsign[10],        /* amateur radio callsign of user */
       sex,                 /* sex of user, M or F */
       laston[81],          /* date user was last on */
       gfiles[81],          /* directory for text files, ends in \ */
       data[81],            /* directory for non-text files, ends in \ */
       sysoplog[81],        /* full path & filename for sysop log */
       curspeed[81];        /* speed user is on at, "KB" if local */
double gold,                /* gold user has */
       timeallowed,         /* number of seconds before user logged off */
       version;             /* version of WWIV running under */


#ifdef v407

/* function pointers for BBS functions.  ONLY used for 4.07 or later. */
/*
void far interrupt (*inli)(char *, char *, int, int);
void far interrupt (*checka)(int *, int *);
void far interrupt (*pla)(char *, int *);
void far interrupt (*outchr)(char);
void far interrupt (*outstr)(char *);
void far interrupt (*nl)();
void far interrupt (*pl)(char *);
int  far interrupt (*empty)();
char far interrupt (*inkey)();
unsigned char far interrupt (*getkey)();
void far interrupt (*input)(char *, int);
void far interrupt (*inputl)(char *, int);
int  far interrupt (*yn)();
int  far interrupt (*ny)();
void far interrupt (*ansic)(int);
char far interrupt (*onek)(char *);
void far interrupt (*prt)(int, char *);
void far interrupt (*mpl)(int);

void far **funcs;
*/

#endif

int read_in_data(char *fn)
{
  char buf[1024];
  char *ptr[50],*ss,s[81];
  int i,f,len,i1;
  float fl;

  f=open(fn,O_RDONLY | O_BINARY);
  if (f<0) {
    return(-1);
  }
  i1=1;
  ptr[0]=buf;
  len=read(f,(void *)buf,1024);
  close(f);
  for (i=0; i<len; i++)
    if (buf[i]==13) {
      buf[i]=0;
      ptr[i1++]=&buf[i+2];
    }
  while (*ptr[6]==32)
    ++(ptr[6]);
  while (*ptr[15]==32)
    ++(ptr[15]);
  usernum=atoi(ptr[0]);
  strcpy(name,ptr[1]);
  strcpy(realname,ptr[2]);
  strcpy(callsign,ptr[3]);
  age=atoi(ptr[4]);
  sex=*ptr[5];
  sscanf(ptr[6],"%f",&fl);
  gold=(double)fl;
  strcpy(laston,ptr[7]);
  screenchars=atoi(ptr[8]);
  screenlines=atoi(ptr[9]);
  sl=atoi(ptr[10]);
  so=atoi(ptr[11]);
  cs=atoi(ptr[12]);
  okansi=atoi(ptr[13]);
  incom=atoi(ptr[14]);
  sscanf(ptr[15],"%f",&fl);
  timeallowed=(double)fl;
  strcpy(gfiles,ptr[16]);
  strcpy(data,ptr[17]);
  strcpy(sysoplog,gfiles);
  strcat(sysoplog,ptr[18]);
  strcpy(curspeed,ptr[19]);
  comport=atoi(ptr[20]);
/* 
  version=-1.0;

  funcs=(void far *)getvect(0x6a);
  inli=funcs[0];
  checka=funcs[1];
  pla=funcs[2];
  outchr=funcs[3];
  outstr=funcs[4];
  nl=funcs[5];
  pl=funcs[8];
  empty=funcs[9];
  inkey=funcs[10];
  getkey=funcs[11];
  input=funcs[12];
  inputl=funcs[13];
  yn=funcs[14];
  ny=funcs[15];
  ansic=funcs[16];
  onek=funcs[17];
  prt=funcs[18];
  mpl=funcs[19];
*/
  return(0);
}

/* My stuff */

struct time tm;


void main(int argc, char *argv[])
{
  char s[MAXLINE];
  char outstr[128];
  FILE *fi;
  int i;


  if (argc<2){
    printf("usage: fmenu chain_file [config_file]\n");
    exit(ERROR);
  }
  else {
    strcpy(chainfile,argv[1]);
    strcpy(configfile,CONFIGFLE);
  }
  if (argc==3){
    strcpy(configfile,argv[2]);
  }

  if (read_in_data(chainfile)==-1) {
    fprintf(stderr,"%s: %s not found\n",NAME,chainfile);
    exit(ERROR);
  }


  if(check_regkey(author,"",AUTHORKEY)==ERROR){
    colour(6);
    printf("ERROR: Invalid executable!");
    colour(0);
    nl();
    exit(ERROR); 
  }
  nl();
  colour(4);
  printf(" [%s:%s:%s:%s] Copyright (c) 1991,1992 %s. ",NAME,VERSION,__DATE__,__TIME__,author);
  colour(0);
  nl();



  /* Try to find config file in current directory */
  if ( (fi=fopen(configfile,"r"))==NULL){
    colour(6);
    printf("Can't read config file %s.",configfile);
    exit(ERROR);
    colour(0);
    nl();
  }

  if ( (i=readin_array(fi,MAXELM)) < 17){
    colour(6);
    printf("Config file %s too small, %d items read.",configfile,i);
    colour(0);
    nl();
  }
  fclose(fi);

  /* print_array(); /* DEBUG */
  strcpy(work_dir,array[0]);
  strcpy(temp_dir,array[1]);
  strcpy(this_node,array[2]);
  strcpy(bbs_name,array[3]);
  strcpy(reg_key,array[4]);
  strcpy(file_minor,array[5]);
  strcpy(remote_minor,array[6]);

  bbllo=atoi(array[7]);
  bblhi=atoi(array[8]);
  conlo=atoi(array[9]);
  conhi=atoi(array[10]);
  netlo=atoi(array[11]);
  nethi=atoi(array[12]);
  sublo=atoi(array[13]);
  subhi=atoi(array[14]);

  make_nodelist();
  make_dirlist();
  make_keylist();

  if(check_regkey(annoy,"",ANNOYKEY)==ERROR){
    colour(6);
    printf("ERROR: Invalid executable!");
    colour(0);
    nl();
    exit(ERROR);
  }

  colour(3);
  if(strcmp(reg_key,"-")!=NULL){
    if(check_regkey(bbs_name,this_node,reg_key)!=OK){
      colour(6);
      printf("Check BBS name, BBS node and registration key in fmenu.cfg.");
      sprintf(s,"Invalid Registration Key\n");
      logtosysop(s);        
      colour(0);
      nl();
      exit(ERROR);
    }
    else{
      printf("Registered to: \"%s\", @%s",bbs_name,this_node);
      reg=1;
    } 
  }
  else{
    printf("%s: \"%s\", @%s",ANNOY,bbs_name,this_node);
    reg=0;
  }
  colour(0);
  nl();
  nl();

  menu_main(); 
  exit(OK);
}

menu_main()
{
  char outstr[80];
  char node[10];
  char filename[MAXPATH];
  char ext[MAXEXT];
  char datfile[MAXPATH];
  char s[MAXPATH];
  int i,j;
  FILE *f;
  long T;
  short token;

  colour(2);
  strcpy(node,"0");
  printmenu(9);
  printf("WELCOME ");
  if (sex=='M'){
    printf("MR. ");
  }
  else{
    printf("MS. ");
  }
  printf("%s",name);
  if(strlen(callsign)!=NULL){
    printf(" AND 73's %s",callsign);
  }
  nl();
  nl();
  colour(0);

  printmenu(0);
  while (1) {
    purgkey();
    gettime(&tm);
    colour(3);
    printf("\n%02d:%02d:%02d",tm.ti_hour,tm.ti_min,tm.ti_sec);
    colour(2);
    nl();
    printf("Main Command (h=help) ");
    PESTER
    colour(4);
    strcpy(outstr,"?");
    readf("A",outstr,KEYWAIT);
    colour(0);
    nl();
    token=get_token(outstr,0);
    switch(token) {

      case __QUIT:
        exit(OK);

      case __FILEXFER:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"File xfer sub-menu\n");
        logtosysop(s);
        menu_filexfer();
        break;

      case __EXPRESS:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(2);
        printf("Pathname/file to search: ");
        readf("uuuuuuuuuuuuu^",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(filename,"%s",outstr);
        printf("Expression/Pattern: ");
        readf("???????????????????????????????????????????",outstr,KEYWAIT);
        colour(0);
        nl();
        printf("<< Searching Directories >>");
        colour(0);
        nl();
        for(i=0;i<=MAXDIRS;i++){
          if(dirlist[i][0]=='\0' || mykbhit()){
            break;
          }

          sprintf(s,"%s%s",dirlist[i],filename);
          colour(3);
          printf("< %s >",dirlist[i]);
          colour(0);
          nl();
          if (readable(s)==0){
            colour(5);
            printf("\"%s\" (Y,N,Q) :",filename);
            colour(4);
            readf("u",outstr,KEYWAIT);
            colour(0);
            nl();
            if(outstr[0]=='Y') {
              colour(2);
              if ( (f=fopen(s,"r")) != NULL){
                 find(f,stdout,outstr);
              }
              fclose(f);
              colour(4);
              sprintf(s,"Searched for %s in %s.\n",outstr,filename);
              logtosysop(s);
            }
          }
        }
        colour(2);
        break;

      case __MODE:
        sprintf(s,"Set wildcard on/off\n");
        logtosysop(s);
        mode=askwild();
        break;             

      case __BBLIST:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"BBS list sub-menu\n");
        logtosysop(s);
        menu_bbslist();
        break;

      case __CONLIST:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"Connect list sub-menu\n");
        logtosysop(s);
        menu_connect();
        break;

      case __NETLIST:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"NET list sub-menu\n");
        logtosysop(s);
        menu_netdat();
        break;

      case __SUBLIST:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"SUB's list sub-menu\n");
        logtosysop(s);
        menu_subs();
        break;

      case __USER0:
      case __USER1:
      case __USER2:
      case __USER3:
      case __USER4:
      case __USER5:
      case __USER6:
      case __USER7:
      case __USER8:
      case __USER9:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"%s",key[token].prg);
        system(s);
        break;

     case __HELP:
       if(sec_ok(sl,key[token].sl)!=OK){
         break;
       }
       printmenu(1);
       break;

     default:
       printmenu(0);
       break;
    }
  }
}


/*********************************************************************/

readf(format,outstr,maxwait)
char format[];
char outstr[];
long maxwait;
{
  char s[MAXLINE+1];
  int i,j;
  int c,inlen,outlen;

  outlen=0;
  inlen=strlen(format);


/* fprintf(stderr,"format=[%s]\nlen=%d\nmaxwait=%d\n",format,strlen(format),maxwait); */

  inline(inlen);
  i=0;j=0;
  while( j<inlen && ( (c=charin(maxwait)) != TMOUT ) ){
    if (c==TMOUT){
      return(TMOUT);
    }
/*    c=charin(maxwait); */
/* fprintf(stderr,"\nformat[%d]:%c\tc:%c\t",i,format[i],c); */
    if (c=='\r'){
      break;
    }

    if (c=='\b'){
      if(j>0){
        printf("\b_\b");
        i--;
        j--;
        outlen--;
      }
      continue;
    }

    /* Enter or Carrige return */
    if (format[i]=='$') {
      if (!iscntrl(c)){
        prompt("< type enter/<cr> >",inlen,outlen);
        continue;
      }
    }

    /* Control character */
    if (format[i]=='^') {
      if (!iscntrl(c)){
        prompt("< type a control character >",inlen,outlen);
        continue;
      }
    }

    /* Decimal Digit */
    if (format[i]=='#') {
      if (!isdigit(c)){
        prompt("< type a digit >",inlen,outlen);
        continue;
      }
    }


    /* Graph  */
    if (format[i]=='g') {
      if (!isgraph(c)){
        prompt("< type a graphic char >",inlen,outlen);
        continue;
      }
    }

    /* Lower case */
    if (format[i]=='l') {
      if(isupper(c)){
        c=tolower(c);
      }
    }

    /* Upper case */
    if (format[i]=='u') {
      if(islower(c)){
        c=toupper(c);
      }
    }

    /* Printable */
    if (format[i]=='p') {
      if (!isprint(c)){
        prompt("< type a printable char. >",inlen,outlen);
        continue;
      }
    }

    /* Punctuation */
    if (format[i]=='.') {
      if (!ispunct(c)){
        prompt("< use punctuation >",inlen,outlen);
        continue;
      }
    }

    /* White Space */
    if (format[i]==' ') {
      if (!isspace(c)){
        prompt("< type space/tab or enter >",inlen,outlen);
        continue;
      }
    }

    /* Anything ASCII */
    if (format[i]=='?') {
      if (!isascii(c)){
        prompt("< use ascii >",inlen,outlen);
        continue;
      }
    }

    i++;

    outstr[j]=c;
    printf("%c",outstr[j]);
    j++;
    outstr[j]='\0';
    outlen=strlen(outstr);
  }
  return(0);
}

int charin(maxwait)
long maxwait;
{
  long t0,t1;
  time(&t0);
  while (!kbhit()) {
    time(&t1);
    if(t1>t0+maxwait){
      colour(6);
      printf("< Keyboard timeout >");
      colour(0);
      nl();
      exit(TMOUT);
    }
  }
  return(getch());
}


void purgkey()
{
  /* clear out buffer if key(s) has been hit*/
  /* and place cursor at start of line */
  if (kbhit()){
    putchar('\n');
  }
  while(kbhit()) {
    getch();
  }
}

void prompt(s,i,o)
char *s[];
int i,o;
{
  int j;
  colour(6);
  printf("%s",s);
  colour(4);
  while (!kbhit()){
  }
  for(j=0;j<strlen(s);j++){
    printf("\b \b");
  }
  for(j=0;j<(i-o);j++){
    printf("_");
  }
  for(j=0;j<(i-o);j++){
    printf("\b");
  }
}

void inline(l)
int l;
{
  int i;
  for(i=0;i<l;i++){
    printf("_");
  }
  for(i=0;i<l;i++){
    printf("\b");
  }
}


mykbhit()
{
  long i,j;
  int c;
  static short pause;

  if(kbhit()){
    c=getch();
    switch (tolower(c)) {
      case 'p':
        if (pause==0){
          pause=1;
          time(&i);
          while (!kbhit()){
            time(&j);
            /* Warn user if paused more than PAUSEWARN seconds */
            if (j>i+PAUSEWARN){
              printf("\007[PAUSED]\b\b\b\b\b\b\b\b");
              time(&i);
            }
          }
        }
        else{
          pause=0;
        }
        return(0);

      case '\n':
      case ' ':
        if (pause==0){
          return(1);
        }
        pause=0;  

      default:
        return(1);
    }
  }
  return(OK);
}


/* search through def'd menu file and printout appropriate menu */
printmenu(menu)
int menu;
{
  char line[MAXLINE];
  char s[MAXPATH];
  FILE *fi;
  short flag;
  sprintf(s,"%s%s",gfiles,MENUFILE);
  if ( (fi=fopen(s,"r")) == NULL){
    colour(6);
    fprintf(stderr,"FATAL ERROR: can't read menufile, %s.\n",s);
    colour(0);
    exit(ERROR);
  }
  flag=0;
  while (fgets(line, MAXLINE,fi) != NULL){
    if (line[0] == '`'){
      sprintf(s,"`%02d",menu);
      if(strncmp(line,s,3) == NULL){
        flag=1;
        continue;
      }
      else{
        if (flag==1){ /* stop searching, found once */
          break;
        }
        flag=0;
      }
    }
    if (flag==1){
      printf("%s",line);
    }
  }
  fclose(fi);
  return(OK);
}

/* if new is [0-7] then change colour */
colour(code)
short code;
{
  if(!okansi){
    return(0);
  }
  if (code<=7 && code>=0 ){
    printf("%c%d",'\003',code);
  }
  return(OK);
}

int readable(f)
char f[];
{
  FILE *fp;
  if ( (fp=fopen(f,"r")) != NULL){
    fclose(fp);
    return(0);
  }
  fclose(fp);
  return(1);
}

int fgetline(s,max,fp)
char s[];
int max;
FILE *fp;
{
  int i,c;
  short q;
  q=0; /* quote flag */
  i=0;
  while ( (c=fgetc(fp)) != EOF){
    /* Comments begin with # and end with newline */
     if (c=='#'){
      while( (c=fgetc(fp))!='\n' ){
      }
      continue;
    }

    /* Strings enclosed by double quotes treat spaces as any other char */
    if (c==QUOTE ){
      if(q==0){
/*         printf("quote on\n"); /* DEBUG */
        q=1;
      }
      else{
/*        printf("quote off\n"); /* DEBUG */
        q=0;
      }
      continue;
    }
    if ( c==' ' && q==0 ){
/*       printf("FS\n"); /* DEBUG */
      break;
    }

    /* Tabs and newlines are field separators */
    if (c=='\n' || i>=max || c=='\t' ){
/*       printf("FS\n"); /* DEBUG */
      break;
    }
    s[i]=c;
    i++;
  }

  s[i]='\0';
/*   printf("[%s\]\n",s); /* DEBUG */
  return(i);
}

logtosysop(s)
char s[];
{
  FILE *fo;
  char f[MAXPATH];

  /* Don't log if Sysop and not-remote */
  if (incom==0 && sl==255){
    return(0);
  }

  sprintf(f,"%s",sysoplog);
  if ( (fo=fopen(f,"a")) != NULL){
    fprintf(fo,"   %s:%s",NAME,s);
  }
  else{
    colour(6);
    printf("< Can't append to \"%s%s\" >",gfiles,sysoplog);
    colour(0);
    nl();
  }
  fclose(fo);
  return(OK);
}

int type(f,i)
char *f;
int i;
{
  int c;
  FILE *fp;

  if ((fp = fopen(f, "r")) == NULL) {
/*     colour(5); */
/*     printf("\"%s\" is empty or not found.",f); */
/*     colour(0); */
/*     nl(); */
    return(1);
  }
  else {
    /* type out until eof or key is hit */
    while ( (c=fgetc(fp)) != EOF ) {
      fputc(c,stdout);
      if ( (i==0) && mykbhit()){
        break;
      } 
    }
    purgkey();
    fclose(fp);
  }
  return(0);
}

int init_array()
{
  int i;
  i=0;
  for (i=1;i<MAXELM;i++){
    strcpy(array[i],"");
    i++;
  }
  return(OK);
}


/* Read from fi up to max number of items into array */
/* and return number of items read */
int readin_array(fi,max)
FILE *fi;
int max;
{
  int i;
  char s[MAXLINE];

  init_array();
  i=0;
  while ( i<max ){
    if ( fgetline(array[i],MAXLINE,fi) == NULL){
      break;
    }

/*        printf("\t%d:[%s]\n",i,array[i]); /* FOR DEBUG */

    if ( (strcmp(array[i],"")) == NULL){
      break;
    }

    i++;
    if ( i >= MAXELM ){
      colour(6);
      printf(s,"Config file too large, array full: %d\n",MAXELM);
      colour(0);
      nl();
      return(i);
    }
  }
  return(i);
}

int make_dirlist()
{
  char s[MAXLINE];
  int i,j,f;

  f=0,j=0;
  for(i=0;i<MAXELM;i++){
    if (strcmp(array[i],DIRFLAG) == NULL){
      f=1;
      continue;
    }
    if (strcmp(array[i],KEYFLAG) == NULL){
      strcpy(dirlist[j],"");
      break;
    }
    if(f==1){
      if(j>=MAXDIRS){
        colour(6);
        printf("Too many directories: %d.",j);
        colour(0);
                                nl();
        strcpy(dirlist[j],"");
        return(-1);
      }
      strcpy(dirlist[j],array[i]);
/*        printf("dir %d %s\n",j,dirlist[j]); /* DEBUG */
      j++;
    }
  }
  return(j);
}

int make_keylist()
{
  char s[MAXLINE];
  int i,j,f;

  f=0,j=0;
  for(i=0;i<MAXELM;i++){
    if (strcmp(array[i],KEYFLAG) == NULL){
      f=1;
      continue;
    }
    if (strcmp(array[i],ENDLIST) == NULL){
/*       keylist[j]=0; */
      break;
    }
    if(f==1){
      if(j>=MAXKEY){
        colour(6);
        printf("Too many key definitions: %d.",j);
        colour(0);
                                nl();
/*         nodelist[j]=0; */
        return(-1);
      }
      sprintf(key[j].k,"%s",array[i]);
      i++;
      key[j].sl=atoi(array[i]);
      i++;
      sprintf(key[j].prg,"%s",array[i]);

/*       printf("key[%d].k=%s\n",j,key[j].k); /* DEBUG */
/*       printf("key[%d].sl=%d\n",j,key[j].sl); /* DEBUG */
/*       printf("key[%d].prg=%s\n",j,key[j].prg); /* DEBUG */
      j++;
    }
  }
  return(j);
}

int make_nodelist()
{
  char s[MAXLINE];
  int i,j,f;

  f=0,j=0;
  for(i=0;i<MAXELM;i++){
    if (strcmp(array[i],NODEFLAG) == NULL){
      f=1;
      continue;
    }
    if (strcmp(array[i],DIRFLAG) == NULL){
      nodelist[j]=0;
      break;
    }
    if(f==1){
      if(j>=MAXNODE){
        colour(6);
        printf("Too many nodes: %d.",j);
        colour(0);
            nl();
        nodelist[j]=0;
        return(-1);
      }
      nodelist[j]=atoi(array[i]);
/*        printf("node %d %d\n",j,nodelist[j]); /* DEBUG */
      j++;
    }
  }
  return(j);
}

check_node(n)
int n;
{
  int i;
  for(i=0;nodelist[i]>0;i++){
    if(n==nodelist[i]){
      return(OK);
    }
  }
  return(ERROR);
}

print_nodelist()
{
  int i;
  colour(3);
  printf("<< Nodelist >>");
  colour(1);
  nl();
  for (i=0;i<MAXELM;i++){
     if(nodelist[i]==0 ||mykbhit()){
         break;
     }
     printf("%03d. @%-04d\n",i,nodelist[i]);
  }
  colour(3);
  printf("<< END >>");
  colour(0);
  nl();
  return(OK);
}

print_array()
{
  int i;
  nl();
  for (i=0;i<MAXELM;i++){
     if(mykbhit()){
         break;
     }
     printf("%03d. %s\n",i,array[i]);
  }
  nl();
  return(OK);
}

check_filename(f)
char f[];
{
  int i;
  int bad;
  bad=0;
  if(strcmp(f,"LPT1")==NULL)
    bad=1;
  if(strcmp(f,"LPT2")==NULL)
    bad=1;
  if(strcmp(f,"LPT3")==NULL)
    bad=1;
  if(strcmp(f,"COM1")==NULL)
    bad=1;
  if(strcmp(f,"COM2")==NULL)
    bad=1;
  if(strcmp(f,"COM3")==NULL)
    bad=1;
  if(strcmp(f,"COM4")==NULL)
    bad=1;
  if(strcmp(f,"PRN")==NULL)
    bad=1;
  if(strcmp(f,"CLOCK$")==NULL)
    bad=1;
  if(strcmp(f,"NUL")==NULL)
    bad=1;
  if(strcmp(f,"AUX")==NULL)
    bad=1;
  if(strcmp(f,"CON")==NULL)
    bad=1;
  if(bad!=0){
    colour(6);
    printf("Bad filename\t");
    colour(0);
    return(ERROR);
  }

  bad=0;
  for(i=0;i<strlen(f);i++){
    if(iscntrl(f[i])){
      bad=2;
    }
    switch(f[i]) {
      case '.':
        bad++;
        break;
      case ':':
      case '\\':
      case '/':
      case '|':
      case '<':
      case '>':
      case '*':
      case '\'':
      case '\"':
      case '?':
      case ';':
      case '[':
      case ']':
        bad=2;
    }
    
  }
/*
   if (i>(MAXFILE)){
    colour(6);
    printf("Filename too long\t");
    colour(0);
    return(ERROR);
  }
*/
  if(bad>1){
    colour(6);
    printf("Bad Filename\n");
    colour(0);
    return(ERROR);
  }
  return(OK);
}

check_regkey(name,node,inum)
char name[];
char node[];
char inum[]; /* Input key - to be checked */
{
  char s[81];
  char cnum[MAXREGNO]; /* calculate key - from BBS name & node */
  int chk; /* check sum */
  int i,j,k;

  static char tr[2][255] ={
    {
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
      'p','q','r','s','t','u','v','w','x','y','z',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
      'P','Q','R','S','T','U','V','W','X','Y','Z',
      '!','@','#','$','%','^','&','*','(',')','-','+','-','=',
      '{','}','[',']',':','"',';','\'','<','>','?',',','.','/','\\',
      '~','`','|','0','1','2','3','4','5','6','7','8','9','\007'
    },
    {
      'x','k','h','u','e','c','4','5','v','0','q','l','L','v','R',
      'q','f','g','d','M','v','7','c','3','c','k',
      'v','F','L','w','P','e','E','N','m','z','u','B','H','i','F',
      'J','j','b','g','W','m','o','8','5','B','3',
      '7','n','4','T','U','G','J','K','e','U','K','j','k','f',
      'k','y','h','n','y','6','j','j','6','r','9','h','v','7','h',
      'S','7','s','i','0','j','g','l','o','t','m','k','1','B'
    },
  };

  strcpy(cnum,"");
  chk=0;
  k=0;

  /* encode the name and calulate checksum */
  for(i=0;name[i]!='\0';i++,k++){
    cnum[k]='.';
    for(j=0;j<255;j++){
      if(name[i]==tr[0][j]){
        cnum[k]=tr[1][j];
        chk+=cnum[k];
      }
    }
  }


  sprintf(s,"%d",chk);
/*  printf("Check=%s\n",s); /* DEBUG */
  /* add encoded version checksum so far */
  for(i=0;s[i]!='\0';i++,k++){
    cnum[k]='.';
    for(j=0;j<255;j++){
      if(s[i]==tr[0][j]){
        cnum[k]=tr[1][j];
      }
    }
  }

  /* encode node number and keep adding to check sum */
  for(i=0;node[i]!='\0';i++,k++){
    cnum[k]='.';
    for(j=0;j<255;j++){
      if(node[i]==tr[0][j]){
        cnum[k]=tr[1][j];
        chk+=cnum[k];
      }
    }
  }

  /* add in encoded final value of checksum */

  sprintf(s,"%d",chk);
/*   printf("Check=%s\n",s); /* DEBUG */
  for(i=0;s[i]!='\0';i++,k++){
    cnum[k]='.';
/*     printf("%c",s[i]); /* DEBUG */
    for(j=0;j<255;j++){
      if(s[i]==tr[0][j]){
/*        printf("s[%d]=%c\ttr[1][%d]=%c\n",i,s[i],tr[1][j],j); /* DEBUG */
        cnum[k]=tr[1][j];
/*        printf("cnum[%d]=%c\n",k,cnum[k]); /* DEBUG */
      }
    }
  }
  cnum[k]='\0';

/*  printf("\ncnum=\t\"%s\"\ninum=\t\"%s\"\n",cnum,inum); /* DEBUG */
  if (strcmp(cnum,inum)){
    return(ERROR);
  }
  else{
    return(OK);
  }
}

sec_ok(u,c)
int u; /* User sl */
int c; /* Command sl */
{
  if(u>=c){ 
    return(OK);
  }
  /* If command sl is >255, treat as disabled command */
  if(c>255){
    return(ERROR);
  }
  else{
    colour(6);
    printf("Your security level (%d) is not high enough; you need %d."\
            ,u,c);
    colour(0);
    nl();
    return(ERROR);
  }
}

/***********************************************************************/
menu_filexfer()
{
  char outstr[80];
  char node[10];
  char filename[MAXPATH];
  char ext[MAXEXT];
  char datfile[MAXPATH];
  char s[MAXPATH];
  int i,j;
  FILE *f;
  long T;
  short token;

  colour(2);
  strcpy(node,"0");

  printmenu(60);
  while (1) {
    colour(2);
    printf("\nFile Transfer ");
    PESTER
    colour(4);
    strcpy(outstr,"?");
    readf("A",outstr,KEYWAIT);
    colour(0);
    nl();
    token=get_token(outstr,1);
    switch(token) {
      case __HELP:
        printmenu(61);
        break;

      case __QUIT:
        return(0);

      case __SEND:
        putchar(BELL);
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(2);
        printf("Enter filename send: ");
        colour(4);
        readf("uuuuuuuuuuuu$",outstr,KEYWAIT);
        colour(0);
        nl();
        if(check_filename(outstr)==ERROR){
          sprintf(s,"Send; Bad filename \"%s\" to @%s.\n",outstr,node);
          logtosysop(s);
          break;
        }
        strcpy(filename,outstr);
        colour(3);
        printf("<< Searching Directories >>");
        colour(0);
        nl();
        for(i=0;i<=MAXDIRS;i++){
          if(dirlist[i][0]=='\0' || mykbhit()){
            break;
          }

          sprintf(s,"%s%s",dirlist[i],filename);
          colour(3);
          printf("< %s >",dirlist[i]);
          colour(0);
          nl();
          if (readable(s)==0){
            colour(5);
            printf("\"%s\" (Y,N,Q) :",filename);
            colour(4);
            readf("u",outstr,KEYWAIT);
            colour(0);
            nl();
            if(outstr[0]=='Y') {
              colour(2);
              printf("Node number to send to [%s] :",node);
              colour(4);
              printf("@");
              strcpy(outstr,node);
              readf("#####$",outstr,KEYWAIT);
              strcpy(node,outstr);
              colour(0);
              nl();
              if ( check_node(atoi(node))==ERROR){
                 colour(6);
                 printf("Node @%s not in list.",node);
                 colour(0);
                 nl();
                 if(sl<key[token].sl){
                     continue;
                 }
              }
              if(atoi(node)<1){
                colour(6);
                printf("Ooooops!");
                colour(0);
                nl();
                continue;
              }
              nl();
              colour(5);
              strcpy(outstr,"Y");
              printf("Send file now [Y] ? ");
              colour(4);
              readf("u",outstr,KEYWAIT);
              colour(0);
              nl();
              if(outstr[0]=='Y') {
                colour(5);
                sprintf(s,"Send file %s%s to %s",dirlist[i],filename,node);
                printf("\n%s\n",s);
                sprintf(s,"%s %s %s %s %s%s %s 1",key[token].prg,node,this_node,file_minor,dirlist[i],filename,data);
                system(s);
                sprintf(s,"Sent \"%s\" to @%s.\n",filename,node);
                logtosysop(s);
                strcpy(outstr,"Y");
                colour(0);
              }
              else{
                sprintf(datfile,"%s%s",work_dir,QUEUE);
                if( (f=fopen(datfile,"a")) == NULL ){
                  colour(6);
                  printf("Can't create batch file queue, \"%s\".");
                  colour(0);
                  nl();
                  sprintf(s,"Error creating que file\n");
                  logtosysop(s);        
                }
                else{
      fprintf(f,"REM %s #%d\n",name,usernum);
                  fprintf(f,"fsend %s %s %s %s%s %s 1\n",node,this_node,file_minor,dirlist[i],filename,data);
                  fprintf(f,"REM\n");
                  colour(3);
                  printf("<< Queueing file \"%s\" >>\n",filename);
                  sprintf(s,"File %s queued.\n",filename);
                  logtosysop(s);
                }
                fclose(f);
                sprintf(datfile,"%s%s",work_dir,QDATA);
                if( (f=fopen(datfile,"a")) == NULL ){
                  colour(6);
                  printf("Can't create queue data file, \"%s\".\n");
                  sprintf(s,"Error creating queue data file\n");
                  logtosysop(s);        
                }
                else{
                  time(&T);
                  printf("%s%s\t%d\t%s\t%lu\n",dirlist[i],filename,usernum,node,T);
                  fprintf(f,"%s%s\t%d\t%s\t%lu\n",dirlist[i],filename,usernum,node,T);
                  colour(0);
                  fclose(f);
                }
              }
            }
            if(outstr[0]=='N') {
              continue;
            }
            if(outstr[0]=='Q') {
              break;
            }
          }
        }
        colour(3);
        printf("<< Directory Search Complete >>");
        colour(0);
        nl();        
        break;

      case __RECEIVE:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"Receive file minor type %s.\n",file_minor);
        logtosysop(s);
        sprintf(s,"%sexternal.net",data);
        if(readable(s)!=0){
          sprintf(s,"Nothing to receive.\n");
          logtosysop(s);
          printf("%s",s);
          break;
        }    
        colour(5);
        nl();
        printf("%s",s);
        sprintf(s,"%s %s %sexternal.net %sexternal.net %s",key[token].prg,file_minor,data,temp_dir,work_dir);
        system(s);
        colour(0);
        break;

      case __LIST:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        sprintf(s,"List files in work area.\n");
        colour(0);
        logtosysop(s);
        sprintf(s,"%s %s",key[token].prg,work_dir);
        system(s);
        break;

      case __DELETE:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(2);
        printf("File to delete in work area : ");
        strcpy(outstr,"");
        colour(4);
        readf("uuuuuuuuuuuuu",outstr,KEYWAIT);
        colour(0);
        nl();
        if(check_filename(outstr)==ERROR || strcmp(outstr,"")==NULL){
          sprintf(s,"Tried to delete \"%s\"\n",outstr);
          logtosysop(s);
          break;
        }
        strcpy(filename,outstr);
        if(strcmp(filename,"")==NULL){
          break;
        }
        sprintf(s,"%s%s",work_dir,filename);

        if(readable(s)==0){
/*           system(s); */
          unlink(s);
          sprintf(s,"Deleted \"%s\" in work area.\n",filename);
          colour(3);
          nl();
          printf(s);
          colour(0);
          logtosysop(s);
        }
        else{
          colour(6);
          sprintf(s,"Failed to delete \"%s\" in work area\n",filename);
          printf(s);
          logtosysop(s);
        }
        colour(0);
        break;

      case __PENDING:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(0);
        sprintf(s,"%s%s",work_dir,QDATA);
        colour(3);
        printf("< Send Queue %s >",s);
        colour(0);
        nl();
        type(s,BREAKON);
        colour(3);
        printf("< END >");
        colour(0);
        nl();
        sprintf(s,"Viewed queue file.\n");
        logtosysop(s);
        break;
    
      case __LNET:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(2);
        printf("File to view with LNET [EXTERNAL.NET] : ");
        strcpy(outstr,"EXTERNAL.NET");
        colour(4);
        readf("uuuuuuuuuuuuu",outstr,KEYWAIT);
        colour(0);
        nl();
        strcpy(filename,outstr);
        sprintf(s,"LNET %s\n",filename);
        logtosysop(s);
        sprintf(s,"%s %s",key[token].prg,filename);
        colour(2);
        system(s);
        colour(0);
        break;

      case __ARCHIVE:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(2);
        printf("Archive to view in work area : ");
        colour(4);
        readf("uuuuuuuuuuuuu",outstr,KEYWAIT);
        colour(0);
        nl();
        strcpy(filename,outstr);
        sprintf(s,"Archive view %s\n",filename);
        logtosysop(s);
        sprintf(s,"%s %s %s",key[token].prg,work_dir,filename);
        colour(0);
        system(s);
        colour(0);
        break;

      case __VIEW:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(2);
        printf("Enter filename mask [*.*] : ");
        colour(4);
        strcpy(outstr,"*.*");
        readf("uuuuuuuuuuuu$",outstr,KEYWAIT);
        colour(0);
        nl();
        strcpy(filename,outstr);
        colour(3);
        printf("<< Searching Directories >>");
        colour(0);
        nl();
        sprintf(s,"View filenames, mask=%s\n",filename);
        logtosysop(s);
        for(i=2;i<=MAXDIRS;i++){
          if(dirlist[i][0]=='\0' || mykbhit()){
            break;
          }
          colour(3);
          printf("< %s >",dirlist[i]);
          colour(0);
          nl();
          sprintf(s,"%s %s %s",key[token].prg,dirlist[i],filename);
          system(s);
        }
        colour(3);
        printf("<< Search Complete >>");
        colour(0);
        nl();
        break;

      case __NODELIST:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        print_nodelist();
        sprintf(s,"Nodelist\n");
        logtosysop(s);
        break;


      case __REQUEST:
        if(sec_ok(sl,key[token].sl)!=OK){
          break;
        }
        colour(2);
        printf("Enter filename to request: ");
        colour(4);
        readf("uuuuuuuuuuuu$",outstr,KEYWAIT);
        colour(0);
        nl();
        if(check_filename(outstr)==ERROR || strcmp(outstr,"")==NULL){
          sprintf(s,"Request; Bad or null filename \"%s\" to @%s.\n",outstr,node);
          logtosysop(s);
          break;
        }
        strcpy(filename,outstr);
        colour(2);
        printf("Node number to request file from [%s] :",node);
        colour(4);
        printf("@");
        strcpy(outstr,node);
        readf("#####$",outstr,KEYWAIT);
        strcpy(node,outstr);
        colour(0);
        nl();      
        if ( check_node(atoi(node))==ERROR){
           colour(6);
           printf("Node @%s not in list.",node);
           colour(0);
           nl();
           break;
        }
        nl();
        sprintf(datfile,"%s%s.req",work_dir,this_node);
        if( (f=fopen(datfile,"a")) == NULL ){
           colour(6);
           printf("Can't create request data file, \"%s.req\".\n",this_node);
           sprintf(s,"Error creating request data file %s.req\n",this_node);
           logtosysop(s);        
        }
        else{
           printf("Get %s from %s\n",filename,node);
           fprintf(f,"%s\t%s\n",this_node,filename);
        }
        sprintf(s,"Requested %s from @%s\n",filename,node);
        logtosysop(s);        
        colour(0);
        fclose(f);

  sprintf(s,"%s%s.req",work_dir,this_node);
  if(readable(s)==0){
    colour(5);
    printf("Sending file requests.");
    colour(0);
    nl();
          sprintf(s,"%s %s %s %s %s%s.req %s 0",key[token].prg,node,this_node,remote_minor,work_dir,this_node,data);
    system(s);
    sprintf(s,"%s%s.req",work_dir,this_node);
    unlink(s);
    colour(0);
  }
  break;


      default:
        printmenu(60);
    }
  }
}

menu_bbslist()
{
  FILE *fi;
  char s[MAXLINE];
  char outstr[80];
  static int lo, hi;
  char pattern[20];
  int i,j;
  short token;

  hi=bblhi;
  lo=bbllo;
  printmenu(20);
  while (1) {
    colour(2);
    printf("\nBBS Lists [%d-%d] ",lo,hi);
    PESTER
    colour(4);
    strcpy(outstr,"?");
    readf("A",outstr,KEYWAIT);
    colour(0);
    nl();
    token=get_token(outstr,1);
    switch(token) {
      case __HELP:
        printmenu(21);
        break;
      case __RANGE:
        hi=bblhi;lo=bbllo;
        range(&lo,&hi,lo,hi);
        break;

      case __SEARCH:
        colour(2);
        printf("Search pattern :");
        colour(4);
        strcpy(outstr,"");
        readf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(pattern,"%s",outstr);
        sprintf(s,"  Range [%d-%d], Pattern \"%s\"\n",lo,hi,pattern);
        logtosysop(s);

        for(i=lo;i<=hi;i++){
          sprintf(s,"%sbbslist.%d",data,i);
          if (mykbhit()){
            purgkey();
            break;
          }
          if ( (fi=fopen(s,"r")) == NULL){
            colour(6);
            printf("< No bbslist.%d >\n",i);
            colour(0);
          }
          else{
            colour(3);
            printf("< Searching bbslist.%d >\n",i,i);
            colour(0);
            find(fi,stdout,pattern);
            fclose(fi);
          }
        }
        break;


      case __LOCAL:
        colour(2);
        nl();
        printf("Search pattern :");
        colour(4);
        strcpy(outstr,"");
        readf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(pattern,"%s",outstr);
        sprintf(s,"  Local, Pattern \"%s\"\n",pattern);
        logtosysop(s);
        sprintf(s,"%sbbslist.msg",gfiles,i);
        if ( (fi=fopen(s,"r")) == NULL){
          colour(6);
          printf("< No bbslist.msg >\n");
          colour(0);
        }
        else{
          colour(3);
          printf("< Searching bbslist.msg >\n");
          colour(0);
          find(fi,stdout,pattern);
          fclose(fi);
        }
        break;

      case __QUIT:
        return(0);

      default:
        printmenu(20);
    }
  }
}

menu_connect()
{
  FILE *fi;
  char s[MAXLINE];
  char outstr[80];
  static int lo, hi;
  char pattern[20];
  int i;
  short token;

  lo=conlo;
  hi=conhi;
  printmenu(30);
  while (1) {
    colour(2);
    printf("\nConnections [%d-%d] ",lo,hi);
    PESTER
    colour(4);
    strcpy(outstr,"?");
    readf("A",outstr,KEYWAIT);
    colour(0);
    nl();
    token=get_token(outstr,1);
    switch(token) {
      case __HELP:
        printmenu(31);
        break;

      case __RANGE:
        lo=conlo;hi=conhi;
        range(&lo,&hi,conlo,conhi);
        break;

      case __SEARCH:
        colour(2);
        nl();
        printf("Search pattern :");
        colour(4);
        strcpy(outstr,"");
        readf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(pattern,"%s",outstr);
        sprintf(s,"  Range [%d-%d], Pattern \"%s\"\n",lo,hi,pattern);
        logtosysop(s);
        for(i=lo;i<=hi;i++){
          sprintf(s,"%sconnect.%d",data,i);
          if (mykbhit()){
            purgkey();
            break;
          }
          if ( (fi=fopen(s,"r")) == NULL){
            colour(6);
            printf("< No connect.%d >\n",i);
            colour(0);
          }
          else{
            colour(3);
            printf("< Searching connect.%d >\n",i);
            colour(0);
            find(fi,stdout,pattern);
            fclose(fi);
          }
        }
        break;


      case __QUIT:
        return(0);

      default:
        printmenu(30);
    }
  }
}

menu_netdat()
{
  FILE *fi;
  char s[MAXLINE];
  char outstr[80];
  static int lo, hi;
  char pattern[20];
  int i;
  short token;

  lo=netlo;
  hi=nethi;
  printmenu(40);
  while (1) {
    colour(2);
    printf("\nNetdats [%d-%d] ",lo,hi);
    PESTER
    colour(4);
    strcpy(outstr,"?");
    readf("A",outstr,KEYWAIT);
    colour(0);
    nl();
    token=get_token(outstr,1);
    switch(token) {
      case __HELP:
        printmenu(41);
        break;

      case __RANGE:
        lo=netlo;hi=nethi;
        range(&lo,&hi,netlo,nethi);
        break;

      case __SEARCH:
        colour(2);
        nl();
        printf("Search pattern :");
        colour(4);
        strcpy(outstr,"");
        readf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(pattern,"%s",outstr);
        sprintf(s,"  Range [%d-%d], Pattern \"%s\"\n",lo,hi,pattern);
        logtosysop(s);
        for(i=lo;i<=hi;i++){
          sprintf(s,"%snetdat%d.log",gfiles,i);
          if (mykbhit()){
            purgkey();
            break;
          }
          if ( (fi=fopen(s,"r")) == NULL){
            colour(6);
            printf("< No netdat%d.log >\n",i);
            colour(0);
          }
          else{
            colour(3);
            printf("< Searching netdat%d.log >\n",i);
            colour(0);
            find(fi,stdout,pattern);
            fclose(fi);
          }
        }
        break;


      case __LOCAL:
        colour(2);
        nl();
        printf("Search pattern :");
        colour(4);
        strcpy(outstr,"");
        readf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(pattern,"%s",outstr);
        sprintf(s,"  NET.LOG, Pattern \"%s\"\n",pattern);
        logtosysop(s);
        sprintf(s,"%snet.log",gfiles);
        if ( (fi=fopen(s,"r")) == NULL){
          colour(6);
          printf("< No net.log >\n",i);
          colour(0);
        }
        else{
          colour(3);
          printf("< Searching net.log >\n");
          colour(0);
          find(fi,stdout,pattern);
          fclose(fi);
        }
        break;
    
      case __QUIT:
        return(0);

      default:
        printmenu(40);
    }
  }
}

menu_subs()
{
  FILE *fi;
  char s[MAXLINE];
  char outstr[80];
  static int lo, hi;
  char pattern[20];
  int i;
  short token;

  lo=sublo;
  hi=subhi;
  printmenu(50);
  while (1) {
    colour(2);
    printf("\nSUBS Lists [%d-%d] ",lo,hi);
    PESTER
    colour(4);
    strcpy(outstr,"?");
    readf("A",outstr,KEYWAIT);
    colour(0);
    nl();
    token=get_token(outstr,1);
    switch(token) {
      case __HELP:
        printmenu(51);
        break;

      case __RANGE:
        lo=sublo;hi=subhi;
        range(&lo,&hi,sublo,subhi);
        break;

      case __SEARCH:
        colour(2);
        printf("Search pattern :");
        colour(4);
        strcpy(outstr,"");
        readf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(pattern,"%s",outstr);
        sprintf(s,"  Range [%d-%d], Pattern \"%s\"\n",lo,hi,pattern);
        logtosysop(s);

        /* Hack in subs.lst for subs.0 */
        for(i=lo;i<=hi;i++){
          sprintf(s,"%ssubs.%d",data,i);
          if (i==0){
            sprintf(s,"%ssubs.lst",data);
          }
          if (mykbhit()){
            purgkey();
            break;
          }
          if ( (fi=fopen(s,"r")) == NULL){
            colour(6);
            printf("< No %s >\n",s);
            colour(0);
          }
          else{
            colour(3);
            if(i==0){
              printf("< Searching subs.lst >\n",i);
            }
            else{
              printf("< Searching subs.%d >\n",i);
            }
            colour(0);
            find(fi,stdout,pattern);
            fclose(fi);
          }
        }
        break;


      case __QUIT:
        return(0);

      default:
        printmenu(50);

    }
  }
}

range(lo,hi,min,max)
int *lo,*hi,min,max;
{
  char outstr[4];

  do {
    printf("Low number (>=%d,<=%d): ",min,max);
    colour(4);
    strcpy(outstr,"");
    readf("###",outstr,KEYWAIT);
    colour(0);
    *lo=atoi(outstr);
    nl();
  } while(*lo<min || *lo>max);

  do {
    printf("High number (>=%d,<=%d): ",*lo,max);
    colour(4);
    readf("###",outstr,KEYWAIT);
    colour(0);
    *hi=atoi(outstr);
    nl();
  } while(*hi>max || *hi<*lo);
  colour(3);
  printf("< Range is [%d-%d] >\n",*lo,*hi);
  colour(0);
  return(OK);
}

askwild()
{
  char outstr[2];

  while (1) {
    printf("Use wildcards (y,[n],?=help) :");
    colour(4);
    sprintf(outstr,"n");
    readf("A",outstr,KEYWAIT);
    colour(0);
    nl();
    switch (outstr[0]){
      case '?':
        printmenu(8);
        break;
      case 'y':
      case 'Y':
        return(1);
      case 'n':
      case 'N':
        return(0);
      default:
        break;
    }
  }
  colour(0);
  nl();
  return(0);
}

/* The below code has been imported for the wildcard matching features */
/*
**  Do shell-style pattern matching for ?, \, [], and * characters.
**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
**  could cause a segmentation violation.  It is 8bit clean.
**
**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
**  Rich $alz is now <rsalz@bbn.com>.
**  Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
**  This can greatly speed up failing wildcard patterns.  For example:
**  pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
**  text 1:   -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
**  text 2:   -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
**  the ABORT, then it takes 22310 calls to fail.  Ugh.
*/

#define TRUE    1
#define FALSE    0
#define ABORT    -1

#define NEGATE_CLASS  '^'

/* Forward declaration. */
static int  DoMatch();

/*
**  See if the text matches the p, which has an implied leading asterisk.
*/
static int
Star(text, p)
    register char  *text;
    register char  *p;
{
    register int  ret;

    do
  ret = DoMatch(text++, p);
    while (ret == FALSE);
    return ret;
}


/*
**  Match text and p, return TRUE, FALSE, or ABORT.
*/
static int
DoMatch(text, p)
    register char  *text;
    register char  *p;
{
    register int    last;
    register int    matched;
    register int    reverse;

    for ( ; *p; text++, p++) {
  if (*text == '\0' && *p != '*')
      return ABORT;
  switch (*p) {
  case '\\':
      /* Literal match with following character. */
      p++;
      /* FALLTHROUGH */
  default:
      if (*text != *p)
    return FALSE;
      continue;
  case '?':
      /* Match anything. */
      continue;
  case '*':
      /* Trailing star matches everything. */
      return *++p ? Star(text, p) : TRUE;
  case '[':
      if (reverse = p[1] == NEGATE_CLASS)
    /* Inverted character class. */
    p++;
      for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
    /* This next line requires a good C compiler. */
    if (*p == '-' ? *text <= *++p && *text >= last : *text == *p)
        matched = TRUE;
      if (matched == reverse)
    return FALSE;
      continue;
  }
    }

    return *text == '\0';
}


/*
**  User-level routine.  Returns TRUE or FALSE.
*/
int wildmat(text, p)
    char  *text;
    char  *p;
{
    return DoMatch(text, p) == TRUE;
}

/* Look for a token, begin at defintion indexed by m */
get_token(s,m)
char s[];
short m;
{
  int i,j;
  int token;
  token=-1;
  if(m==1){
      for(i=0;i<=MAXKEY;i++){
        for(j=0;key[i].k[j]!='\0';j++){
          if(s[0]==key[i].k[j]){
            token=i;
            break;
          }
        }
      }
  }
  else{
      for(i=MAXKEY;i>=0;i--){
        for(j=0;key[i].k[j]!='\0';j++){
          if(s[0]==key[i].k[j]){
            token=i;
            break;
          }
        }
      }
  }
  return(token);
}
find(fi,fo,pattern)
FILE *fi,*fo;
char pattern[];
{
  int i,j;
  char line[MAXLINE];
  while ( (fgets(line, MAXLINE,fi) != NULL) && !mykbhit()){
    if (mode==0){
      if ( (j=index(line,pattern)) >= 0){
        colour(0);
        for (i=0;i<j;i++){
          fprintf(fo,"%c",line[i]);
        }
        colour(3);
        fprintf(fo,"%s",pattern);
        colour(0);
        i+=strlen(pattern);
        for (i=i;i<strlen(line);i++){
          fprintf(fo,"%c",line[i]);
        }
      }
    }
    else{
      if ( (j=wildmat(line,pattern)) != 0){
         fprintf(fo,"%s", line);
      }
    }
  }
}

index(s, t)
char s[], t[];
{
     int i, j, k;

     for (i = 0; s[i]  != '\0'; i++) {
          for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++)
               ;
          if (t[k] == '\0')
               return(i);
     }
     return(-1);
}
