    /*
    Pirate Bulletin Board System
    Copyright (C) 1990, Edward Luke

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 1, or (at your option)
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


    Email address:
    lush@Athena.EE.MsState.EDU
*/
#include "bbs.h"
#include "io.h"

#include <sys/file.h>


jmp_buf byebye ;

FILE *ufp ;
long ti ;
int talkrequest = NA ;

struct user_info uinfo ;

extern char *boardmargin() ;

char fromhost[STRLEN] ;
char BoardName[STRLEN] ;

int utmpent = -1 ;
u_enter()
{
    uinfo.active = NA ;
	uinfo.active = YEA ;
	uinfo.pid    = getpid() ;
	uinfo.invisible = NA ;
	uinfo.sockactive = NA ;
	uinfo.sockaddr = 0 ;
	uinfo.destuid = 0 ;
	uinfo.mode = IDLE ;
    uinfo.uid = usernum ;
    strncpy(uinfo.from,fromhost,STRLEN) ;
    utmpent = getnewutmpent(&uinfo) ;
}

u_exit()
{
	uinfo.active = NA ;
	uinfo.pid = 0 ;
	uinfo.invisible = YEA ;
	uinfo.sockactive = NA ;
	uinfo.sockaddr = 0 ;
	uinfo.destuid = 0 ;
	substitute_record(ULIST,&uinfo,sizeof(uinfo),utmpent) ;
}

int
cmpuids(uid,up)
char *uid ;
struct user *up ;
{
    return !ci_strncmp(uid,up->userid,USERIDSIZE) ;
}


int
dosearchuser(userid)
char *userid ;
{
	return usernum = search_record(PASSFILE,&currentuser,sizeof(currentuser),
                                   cmpuids,userid) ;
}

int started = 0;

void
talk_request(status)
int status ;
{
	signal(SIGUSR1,talk_request); /* Linux/GCC - eats signal handler vectors */
	talkrequest = YEA ;
/*	fprintf(stderr,"talkrequest set to true\n") ;*/
	bell() ;
	return ;
}

void
abort_bbs(status)
int status ;
{
	if (started)
	  if((ufp = fopen("usies","a")) != NULL) {
		  ti = time(0) ;
		  fprintf(ufp,"AXXED %-10s %-20s %s",currentuser.userid,currentuser.username,ctime(&ti)) ;
		  fflush(ufp) ;
		  u_exit() ;
		  fclose(ufp) ;
	  }
	exit(0) ;
}

generic_abort()
{
    abort_bbs() ;
}

#include <sys/file.h>
#include <signal.h>

main(argc, argv)
int argc ;
char **argv ;
{
	char uid[STRLEN] ;
	char *pass, *getpass() ;
    char passbuf[PASSLEN] ;
	int cmd, nu = 0 ;
    int fd ;
    int getin ;
    extern char *genpasswd() ;
#ifdef SINGLE
    { char c[256] ;
      gethostname(c,256) ;
      if(strcmp(c,SINGLE)) {
          printf("Not on a valid machine!\n") ;
          exit(-1) ;
      } }
#endif
    getin = NA ;
	
	if(argc == 2) {
		switch(*argv[1]) {
		  case 'U':
		  case 'u':
			/* User status check */
			UserStatus() ;
			exit(0) ;
		  case 's':
		  case 'S':
            getin = YEA ;
            break ;
		  case 'l':
		  case 'L':
            dumb_user_list() ;
			exit(0) ;
          case 'a':
            list_all_users() ;
            exit(0) ;
          case 'd':
            if((cmd = atoi(argv[1]+1)) > 0) {
                prints("deleting %d day old users\n",cmd) ;
                auto_clean(cmd) ;
                oflush() ;
            }
            exit(0) ;
		  default:
			fprintf(stderr,"UNKNOWN OPTION\n") ;
			exit(0) ;
		}
	}
    if(argc == 3)
      strncpy(fromhost,argv[2],STRLEN) ;
    else
      fromhost[0] = '\0' ;

#ifndef lint
	signal(SIGHUP,abort_bbs) ;
	signal(SIGINT,SIG_IGN) ;
	signal(SIGQUIT,SIG_IGN) ;
	signal(SIGPIPE,SIG_IGN) ;
	signal(SIGALRM,SIG_IGN) ;
	signal(SIGTERM,SIG_IGN) ;
	signal(SIGURG,SIG_IGN) ;
	signal(SIGTSTP,SIG_IGN) ;
	signal(SIGTTIN,SIG_IGN) ;
	signal(SIGTTOU,SIG_IGN) ;
	signal(SIGUSR1,talk_request) ;
	signal(SIGUSR2,SIG_IGN) ;
#endif

    if(!getin && num_active_users() >= MAXACTIVE) {
        if((ufp = fopen("boot.off","r")) == NULL) {
          fprintf(stderr,"\nSorry, BBS system is full.\nCall again later.\n");
        } else {
            while(fgets(genbuf,256,ufp) != NULL)
              fprintf(stderr,"%s",genbuf) ;
        }
        exit(-1) ;
    }

	if(setjmp(byebye)) {
		if (started)
		  if((ufp = fopen("usies","a")) != NULL) {
			  ti = time(0) ;
			  fprintf(ufp,"ABORT %-10s %-20s %s",currentuser.userid,currentuser.username,ctime(&ti)) ;
			  fflush(ufp) ;
			  u_exit() ;
			  fclose(ufp) ;
		  }
		printf("goodbye\n") ;
		exit(0) ;
	}
    get_tty() ;
    init_tty() ;
    init_alarm() ;
    if((fd = open(NAMEFILE,O_RDONLY)) > 0) {
        char *t, *index() ;
        int cc = read(fd,BoardName,STRLEN) ;
        BoardName[cc] = '\0' ;
        if(t = index(BoardName,'\n'))
          *t = '\0' ;
        close(fd) ;
    } else
      strcpy(BoardName,"The UNKNOWN BBS") ;
  grok:
	prints("\n\n\nWelcome to %s\n\n",BoardName) ; 
	prints("Enter userid, 'new' for new user.\n") ;
	getdata(0,0,"\n\nuser id: ",uid,USERIDSIZE,DOECHO,NULL) ;
	if(uid[0] == '\0')
	  goto grok ;
	if(!strcmp(uid,"new")) {
		struct user newuser ;
		char *s ;
		int allocid ;

		nu = 1 ;
		allocid = getnewuserid()  ;
		if(allocid >= MAXUSERS*2 || allocid <= 0) {
			prints("No space for new users on the system!\n") ;
            oflush() ;
			sleep(1) ;
			exit(1) ;
		}
	  redo:
		prints("Welcome! New user, Please enter your user id \n(a single word nickname or call sign)\n") ;
		getdata(0,0,"Enter user id: ",newuser.userid,USERIDSIZE,DOECHO,NULL) ;
		if(*newuser.userid == '\0') {
			prints("Invalid user id.\n") ;
			goto redo ;
		}
		for(s=newuser.userid;*s != '\0';s++)
		  if(!isalpha(*s)) {
			  prints("Invalid user id (Use letters only)\n") ;
			  goto redo ;
		  }
		if(dosearchuser(newuser.userid)) {
			prints("Userid already exists\n") ;
			goto redo ;
		}
      dopassagain:
        getdata(0,0,"Enter Passwd: ",passbuf,PASSLEN,NOECHO,NULL) ;
        if(passbuf[0] == '\0') {
            prints("You must enter a passwd\n") ;
            goto dopassagain ;
        }
		strncpy(newuser.passwd,passbuf,PASSLEN) ;
		getdata(0,0,"Renter Passwd: ",passbuf,PASSLEN,NOECHO,NULL) ;
		if(strncmp(passbuf,newuser.passwd,PASSLEN)) {
			prints("Error entering passwd\n") ;
			goto dopassagain ;
		}
        newuser.passwd[8] = '\0' ;
        strncpy(newuser.passwd,genpasswd(newuser.passwd),PASSLEN) ;
		getdata(0,0,"Name: ",newuser.username,USERNAMESZ,ECHO,NULL) ;
	  getterm:
		getdata(0,0,"Termtype (vt100,xterm,...): ",
                newuser.termtype,TERMTYPESZ,ECHO,NULL) ;
		if(!term_init(newuser.termtype)) {
			prints("Invalid terminal type, please enter termcap termtype\n") ;
			goto getterm ;
		}
		newuser.userlevel = 0 ;
		newuser.lastlogin = time(NULL) ;
		newuser.protocol = 0 ;
		if(substitute_record(PASSFILE,&newuser,sizeof(newuser),allocid) == -1) {
			fprintf(stderr,"too much, good bye!\n") ;
			exit(1) ;
		}
        touchnew() ;
		if(!dosearchuser(newuser.userid)) {
			fprintf(stderr,"User failed to create\n") ;
			exit(1) ;
		}
	} else {
		if(!dosearchuser(uid)) {
			prints("Bad userid\n") ;
			goto grok ;
		}
		getdata(0,0,"Enter Passwd: ",passbuf,PASSLEN,NOECHO,NULL) ;
        passbuf[8] = '\0' ;
		if(!checkpasswd(currentuser.passwd,passbuf)) {
			prints("invalid passwd\n") ;
            oflush() ;
			exit(1) ;
		}
		currentuser.lastlogin = time(NULL) ;
		substitute_record(PASSFILE,&currentuser,sizeof(currentuser),usernum) ;
        if(!term_init(currentuser.termtype)) {
            prints("Bad terminal type.  Defaulting to 'dumb'\n") ;
            term_init("dumb") ;
        }
	}
	if(!strcmp(currentuser.userid,"SYSOP"))
	  currentuser.userlevel = 255 ;
    bbssetenv("TERM",currentuser.termtype) ;
    bbssetenv("LOGNAME",currentuser.userid) ;
    bbssetenv("USER",currentuser.userid) ;
    bbssetenv("USERNAME",currentuser.username) ;
	if((ufp = fopen("usies","a")) != NULL) {
        fromhost[16] = '\0' ;
		ti = time(0) ;
		fprintf(ufp,"ENTER %-10s %-20s %-16s %s",currentuser.userid,currentuser.username,
                fromhost,ctime(&ti)) ;
		u_enter() ;
		if(nu) {
			uinfo.mode = NEW ;
			substitute_record(ULIST,&uinfo,sizeof(uinfo),utmpent) ;
		}
		fflush(ufp) ;
		fclose(ufp) ;
	}
	report("Enter") ;
	started = 1 ;
	initscr() ;
	scrint = 1 ;
	clear() ;
	move(0,0) ;
    more("Welcome", YEA) ;

	m_init() ;

	if(nu)
	  cmd = 'h' ;
	else
	  cmd = 'n' ;
	if(chkmail())
	  cmd = 'm' ;

	docmd(BoardName,"Enter Command: ",cmd,cmdlist,boardmargin) ;
		
	exit(0) ;
}

char *
boardmargin()
{
	static char buf[STRLEN] ;
	if(selboard)
	  sprintf(buf,"Current Board = '%s'",currboard) ;
	else
	  sprintf(buf,"No Board Currently Selected") ;
	return buf ;
}

int refscreen = NA ;

int
egetch()
{
	char c ;
	int rval ;

	if(talkrequest) {
		talkreply() ;
		refscreen = YEA ;
		return -1 ;
	}
  egetagain:
    c = igetch() ;
    if(talkrequest) {
        talkreply() ;
        refscreen = YEA ;
        return -1 ;
    }
    if(!isprint(c)) {
        switch(c) {
          case '\r':
          case '\n':
          case '\010':
          case '\177':
            break ;
          case 0x0c: /* CTRL(L) */
            redoscr() ;
          default:
            goto egetagain ;
        }
    }
	rval = c ;
	refscreen = NA ;
	return rval ;
}
			
docmd(cmdtitle,cmdprompt,firstcmd,cmdtable,marginnote)
char *cmdtitle,*cmdprompt ;
int firstcmd ;
struct commands cmdtable[] ;
char *(*marginnote)() ;
{
	int cmd, lastcmdptr ;
    int cmdplen ;
    int reprint ;

    cmdplen = strlen(cmdprompt) ;
  grok:
	clear() ;
    reprint = YEA ;
	prints("%s ",cmdtitle) ;
    move(0,26) ;
	if(chkmail())
      prints("(You have mail.)") ;
	else
      prints("                ") ;
	move(0,44) ;
	prints("%s\n",(*marginnote)()) ;
	move(1,0) ;
	prints("%s",cmdprompt) ;
	cmd = firstcmd ;
    lastcmdptr = 0 ;
	do {
        extern int dumb_term ;
		int i=0 ;
		int err ;
	
		if(cmd == '\n' || cmd == '\r') {
            if(dumb_term)
              prints("\n") ;
            else {
                move(1,cmdplen) ;
                clrtoeol() ;
                refresh() ;
            }
            clrstandout() ;
			if((err = (*cmdtable[lastcmdptr].cmdfunc)()) == QUIT)
		      return ;
			move(0,0) ;
            reprint = YEA ;
            prints("%s ",cmdtitle) ;
            move(0,26) ;
	        if(chkmail())
              prints("(You have mail.)") ;
	        else
              prints("                ") ;
	        move(0,44) ;
	        prints("%s\n",(*marginnote)()) ;
	        move(1,0) ;
	        prints("%s",cmdprompt) ;
			clrtoeol() ;
			if(err)
			  cmd = *(cmdtable[lastcmdptr].errorcmd) ;
			else
			  cmd = *(cmdtable[lastcmdptr].nextcmd) ;
		}
		while(i != 100) {
			if(cmdtable[i].cmdname == NULL)
			  break ;
			if((*(cmdtable[i].cmdname) & ~0x20) == (cmd & ~0x20))
			  break ;
			i++ ;
		}
		if(cmdtable[i].cmdname == NULL) {
			bell() ;
			continue ;
		}
		if(cmdtable[i].level > currentuser.userlevel) {
			bell() ;
			continue ;
		}
        if(dumb_term) {
            int lastcmdlen ;
            int newcmdlen ;
            register int j ;

            if(reprint) {
                reprint = NA ;
                prints("%s",cmdtable[i].cmdname) ;
                lastcmdptr = i ;
                continue ;
            }
            if(lastcmdptr == i)
              continue ;
            if(lastcmdptr == 0) {
                prints("%s",cmdtable[i].cmdname) ;
                lastcmdptr = i ;
                continue ;
            }
            lastcmdlen = strlen(cmdtable[lastcmdptr].cmdname) ;
            newcmdlen = strlen(cmdtable[i].cmdname) ;
            for(j=0;j<lastcmdlen;j++)
              ochar(0x08) ; /* CTRL(H) */
            prints("%s",cmdtable[i].cmdname) ;
            if(lastcmdlen > newcmdlen) {
                register int k = lastcmdlen - newcmdlen ;
                for(j=0;j<k;j++)
                  ochar(' ') ;
                for(j=0;j<k;j++)
                  ochar(0x08) ; /* CTRL(H) */
            }
            lastcmdptr = i ;
        } else {
            lastcmdptr = i ;
            move(1,cmdplen) ;
            standout() ;
            prints("%s",cmdtable[i].cmdname) ;
            standend() ;
            clrtoeol() ;
        }
	} while ((cmd = egetch()) != EOF) ;
	if(refscreen)
	  goto grok ;
	abort_bbs() ;
}
