/* 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 __SEND 1
#define __RECEIVE 2
#define __LIST 3
#define __DELETE 4
#define __PENDING 5
#define __LNET 6
#define __ARCHIVE 7
#define __VIEW 8
#define __NODELIST 9
#define __REQUEST 10
#define __HELP 11

#define __EXPRESS 12
#define __BBLIST 13
#define __CONLIST 14
#define __NETLIST 15
#define __SUBLIST 16
#define __MODE 17

#define __RANGE 18
#define __SEARCH 19
#define __LOCAL 20

#define __USER0 21
#define __USER1 22
#define __USER2 23
#define __USER3 24
#define __USER4 25
#define __USER5 26
#define __USER6 27
#define __USER7 28
#define __USER8 29
#define __USER9 30

#define MAXKEY  31           /* 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 __SEND:
	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;

      case __EXPRESS:
	if(sec_ok(sl,key[token].sl)!=OK){
		break;
        }
        colour(2);
        printf("Pathname/file to search: ");
        readf("uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(filename,"%s",outstr);
        sprintf(outstr,"Y");
	colour(2);
	printf("%s\n",work_dir);
        printf("In work directory ([y],n) ? ");
        colour(4);
        readf("u",outstr,KEYWAIT);
        colour(0);
        nl();
        sprintf(s,"%s",filename);
        if(outstr[0]=='Y') {
	        sprintf(s,"%s%s",work_dir,filename);
	}
       	if ( (f=fopen(s,"r")) == NULL){
		colour(6);
		printf("< No such file: %s >\n",s);
	        sprintf(s,"Couldn't search for %s in %s.\n",outstr,filename);
		logtosysop(s);
		colour(0);
		break;
	}
	printf("Expression/Pattern: ");
        readf("???????????????????????????????????????????",outstr,KEYWAIT);
        colour(0);
        nl();
	find(f,stdout,outstr);
	fclose(f);
        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);
/*   printf("s=%s\n",s); */
  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);
/*       printf("line=%s s=%s\n",line,s); */
      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);
/*   printf("End\n") */
  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 find_dirs()
{
  FILE *fp;
  char line[MAXPATH];
  int i,j;
  i=0;

  sprintf(line,"%s%s",data,dirfile);
  if ( (fp=fopen(line,"r")) == NULL) {
     colour(6);
     printf("< No \"%s\" >\n",data,line);
     colour(0);
     fclose(fp);
     return(-1);
     }
       else{
       colour(3);
       printf("< Reading directories in \"%s\" >",line);
       colour(0);
       nl();
      while (fgetline(dirlist[i],MAXLINE,fp) != NULL){
        if ( (strcmp(dirlist[i],"")) == NULL){
           break;
        }
        i++;
        if ( i >= MAXDIRS ){
          colour(6);
          printf("Too many directories, buffer full: %d lines",MAXDIRS);
          colour(0);
          nl();
          break;
        }
      }
      fclose(fp);
      return(0);
   }
}
*/

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){
/*     putchar(c); /* DEBUG */
    /* 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_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);
}
