/******************************************************************************
 *
 *	Enter program for METAL 1.20a
 *
 *	FILE: MENTER.C version 1.20a of this file
 *
 *			Copyright (c) 1984 Tim Gary
 *			    Delphi Data Systems
 *			    All Rights reserved.
 *
 *
 *	This file gets the users' name/password/etc, and links METAL.COM
 *
 ******************************************************************************
 *
 * 1.20a 11/11/84  Release version.
 * 1.20a 11/07/84  Lastmsg fixes.
 * 1.20a 11/04/84  Wrapping up changes from past few weeks, added new info
 *		  to lastcalr file.
 * 1.10e 11/03/84  Fixed for new pcounters/gcntrs.  Moved writestat to hmlib.
 * 1.10e 10/30/84  Version # changed.
 * 1.10d 10/21/84  First time setup bug created in 1.10a/b (in meinfreq) fixed.
 * 1.10c 10/17/84  Status line support for non i/o mapped terminals.
 * 1.10b 10/01/84  Version change needed to keep track.  Spelling error
 *		  corrected.
 * 1.10a  9/27/84  User # and ID info displayed, help added at name prompt.
 * 1.10a  9/09/84  Fixed last message read bug (for overlays).
 * 1.10a  8/31/84  Overlay version started, this WHOLE file is now and overlay.
 *
 * 1.01a  7/02/84  Multiuser lastcalr file items installed (whew).
 * 1.01a  6/10/84  Fixed for Aztec C 1.06.  Will not function under earlier
 *		  versions of the compiler due to new/changed functions.
 *
 * 1.0b   4/13/84  Modified to allow Upper and Lower case names.
 *
 * 1.0a	  3/16/84  First release version.. fixed jump to cpm bug.
 *
 * 1.0	  2/08/84  Random seek to user # (if entered) implemented.
 * 		  Format for users/messages/summary changed.
 *
 *	 12/13/83  Pre-release Version 3.0 Mconfig operation mods.
 *
 *****************************************************************************/

#define TITLE	"\n\nMetal Enter Version 1.20a\n"

#include "xpm.h"	/* get small cpm i/o routine header file */
#include "hmh.h"	/* get METAL header file */
#include "hmconfg.h"	/* get options/config	*/
#include "ctype.h"	/* isxxxxxxx stuff now defines.. */

static int dead_rec_no=0;	/* for new user, write over old '0' user */
static int dead_user_no=0;	/* dead user #, above is record in file */

static char tpass[PASSLEN+1];

/****************
 * Main routine *
 ****************/

ovmain(argc, argv)
 register int argc;
 register char *argv[];
{
unsigned tlastread;
char tt[TIMELEN+1],td[DATELEN+1];

init();			/* do all the initial stuff */
gcntrs(0);		/* get counters */
getuser();		/* gets user name and other vital info */

/* NOTE::: The users file has been opened in getuser, and all we do now
 * is get the time/date, and write the users info into the files..
 *  remember, they are already open and putuser() closes them..		*/
putchar('\n');
getdate();

send("\n[Updating logs]");

if (O.ASKNULLS) user.parm.nulls=*nulls+'0';  /* setup user nulls for metal */


if (user.parm.calls)
	{
	putlastcaller();	/* write lastcaller info if called before */
	strcpy(td,user.date);
	strcpy(tt,user.time);
	}

strcpy(user.date,date);
strcpy(user.time,time);

if (!user.parm.calls)
	putlastcaller();	/* first time on, lastcalr updated after date/time reset */

tlastread=user.lastread;		/* save real current lastmsg count */
user.lastread=(nextmsg ? nextmsg-1 : 0);	/* new user.lastread msg */
user.parm.calls++;
if (user.parm.width<20 || user.parm.width>132) user.parm.width=O.INITLENGTH;
putuser(0);			/* write to open users file, and close */
user.lastread=tlastread;	/* restore real lastread msg (overlay req.) */
if (user.parm.calls!=1)
	{
	strcpy(user.date,td);
	strcpy(user.time,tt);
	}

/* logoff a TWIT now (timeout=0, then can't get on the system */

#ifndef MULTI_USER
if (O.user_types[user.type].timeout==0) exit();

#endif

++callnum;		/* add to # of callers variable */

putcaller();		/* write caller to callers file or printer (PRTLOG?) */
pcounters(0);		/* write counter info	*/

if (user.parm.jmpcpm==PON)
	{
	height=user.parm.height;
	if (user.parm.expert!=PON) type(CPMINFO);
	*tout=O.user_types[user.type].timeout;
	*maxuser=O.user_types[user.type].maxuser;
	if (O.ZCPR) if (O.user_types[user.type].zcprflag) *O.SECURELOC=255;

#ifndef MULTI_USER
	*(char *)0=0xc3;	/* logs out caller for BYE */
#endif

	sprintf(buffer,"\nYou have access thru user %d.\n\n\
[Entering Operating System]",*maxuser);
	send(buffer);

	exit(0);
	}

/* finish up and execute the main METAL program */

send("\n[Just a minute]\n");

/* NOTE: with overlays, all we do is return, and that'll put us back main */

}	/* main */


/******************************
 * Initialize the whole works *
 ******************************/

init()
{

#ifndef MULTI_USER
*(char *)0=0xcd;	/* disable ^C for warm boot, uses BYE program method */

#endif

findbye();	/* setup bye, and related, variables */
*maxuser=15;	/* setup maxuser and define variable */
*tout=3;	/* setup 3 minute timeout */

if (!O.ASKNULLS)	/* if bye asked for nulls, don't reset... */
  *nulls=0;		/* no nulls */

send(TITLE);		/* sign-on info */
putchar('\n');

send(O.WHERE);
putchar('\n');

type(BULLETIN);		/* display any recent changes, BULLETIN is a file */

if (O.ZCPR)
	*O.SECURELOC=0;	/* if using ZCPR in secure mode, then make */

} /* init */


/* This is shown should the person type in a name  of one char (like '?') */
/* when prompted for their name or Metal Id. */

login_help()
{
static char *lo_help[] = {
	"\nIf this is your first time on this system,\n",
	"please enter your full name.\n",
	"\nIf you have called this system before, either\n",
	"enter your full name, or your system access\n",
	"code (Metal ID code).  The access code should\n",
	"have been given to you the first time you logged\n",
	"onto the system.  Metal IDs follow the following\n",
	"format:   <user#><password>\n",
	"So, if you are user # 453, and your password is ROCKER\n",
	"you could enter  453ROCKER  in place of your name to speed\n",
	"up the login process.\n",
	"\nUse the '#' command on the BBS to find out what your\n",
	"user # is if you've forgotten it.\n\n",
	0
	};
dis_text(lo_help);
}


/* Getuser gets the users name, and password, or if new user gets info
 * 	to be used in later logons.  A check is made for sysop, and special
 *	parameters are then set-up.
 */

char temp1[64];

getuser()
{
register int cfast;		/* fast c variable	*/
register int tries,usernum;
int dir;		/* search direction */
char first[FNAMELEN+1],last[LNAMELEN+1];	/* temp name	*/
char temp[MAXLINE+1];


tries=0;	/* number of unsuccessful tries (wrong password tries) */

do {		/* main input name/etc loop */

usernum=-1;	/* no user number yet, if ever */
*tpass='\0';	/* no temp password yet */


/* PRIVATE SYSTEM ONLY STUFF */

if (O.PRIVATE)
 {
do {
   ask("SYSTEM ID CODE (not personal ID): ",temp,PASSLEN,UP);
   if (!strcmp(O.PRIVPASS,temp)) break;
   } while (++tries<O.MAXTRIES);

   if (tries>=O.MAXTRIES)
	{
	type(SYSINFO);	/* info about this private system before quiting */
	exit();
	}
   else tries=0;	/* reset to 0 for name test */
 } /* private */


/* Here we actually get the name of the person.. can give both first and
   last names on a line, or seperately, or a user id..	*/

getfirst:
    do {
	*last='\0';	/* terminate last name initially */
	/* get first name or user # and password, TRUE says convert to upper */
	sepstr=' ';	/* seperator char is space for first/last name sep */
	ask("\nWhat's your name (or Metal ID)? ",first,FNAMELEN,UPLOW);
	sepstr='\0';
	capstr(first);	/* capitalize first name */
	if (!isdigit(*first) && strlen(first)<2)
		login_help();	/* print login help msg */
 	} while(!isdigit(*first) && strlen(first)<2);

   if (ustrcmp(first,"SYSOP")==0) *last='\0';
	else if ( ( !isdigit(*first)) && (*last=='\0') )
		{
		ask("\nWhat's your LAST name? ",last,LNAMELEN,UPLOW);
		if (*last=='\0') goto getfirst;
			/* if return pressed, start over */
		}
    capstr(last);

/* check for sysop */

   if ( ((ustrcmp(first,"SYSOP")==0) && (*last=='\0')) ||
	 ( (ustrcmp(first,O.SOFIRST)==0) && (ustrcmp(last,O.SOLAST)==0) )
	  || (atoi(first)==1) )
	{
	ask("\nSysop Pass? ",tpass,PASSLEN,UP+NOECHO);	/* get sysop pass */
	if (strcmp(tpass,O.SOPASS)!=0)	/* not sysop? */
		{
		tries+=2;	/* double penalty for false sysop try */
		continue;	/* bad practice I think */
		}
	send("\n[Ok]");		/* say your ok so far */
	*tpass='\0';		/* user num, not entered */
	strcpy(first,O.SOFIRST); strcpy(last,O.SOLAST);	/* for sysop respons */
	}

/* if user # was entered, get password if any, or pass through */

  if (isdigit(*first))
	{
	usernum=atoi(first);	/* if #, then get it all */
	for (cfast=0; isdigit(first[cfast]); ++cfast);
	if (first[cfast]!='\0')
	  	strcpy(tpass,&first[cfast]);	/* else get password */
	dir=1;	/* set flag for user number entered */
	} else dir=0;

  if ((users=open(USERFILE,1))!=NULL)
     {					/* open users file, and create it
	 				if it doesn't exist now */
	if (dir) setarec(users,usernum-1);	/* skip to a place */

if (O.PRIVATE) send("\n[Verifying ID]");
	else send("\n[Checking for previous login]\n[.");

/* NOTE: you can't successfully delete the sysop (first user actually)
  using the following method... */


dead_user_number=dead_rec_no=0;

cfast=read(users,0);	/* get first record */
if (cfast!=128) if (dir)
	{
	dir=-1;
	toeof(users);
	setrrec(users,-1);	/* backup one */
	cfast=read(users,0);	/* re-read */
	}

  do	{
	if (cfast!=128) break;		/* exit loop if eof */

	/* let user know things are still being looked into */
	if ((getrec(users)%25)==0) putchar('.');

	/* get desired info from users file... */

	if (dead_rec_no==0) dead_user_no=user.number;

	movmem(bufloc(users),&user,128);	/* get vars, now src,dest */

	if (user.number==0 && dead_rec_no==0)
		{
		dead_user_no++;		/* get user after last since this one
					  is 0 right now... */
		dead_rec_no=getrec(users);
		}

	/* see if past user number */

	if (dir && user.number)	/* if user number entered, and this ain't 0  */
		{		/* check for past user, and exit if so */
		if ( (dir==-1) && (usernum>user.number) ) break;
		  else if (usernum<user.number) break;
		}

	/* see if a match of either name or user number */

	if ((user.number) && ( (usernum==user.number) ||
		(!ustrcmp(first,user.first) && !ustrcmp(last,user.last)) ) )
		{
		putchar(']');		/* cosmetic */
		if (*tpass!='\0')
		    if (ustrcmp(tpass,user.pass)==0)
			goto itshim;   /* it's him! that's all getuser needs */

		/* didn't enter user number, so get password */

		if (*tpass=='\0')
			{
			ask("\nEnter password? ",tpass,PASSLEN,UP+NOECHO+NUMBER);
			if (strcmp(tpass,user.pass)==0)
				{
	itshim:			movmem(bufloc(users),&user,128);
				putchar('\n');
				return;
				}
			}
		send("\n[Wrong!]\n");
		break;		/* exit this loop and ask for name again */
		}
	setrrec(users,dir==-1 ? -1 : 1);	/* forward or backward */
	cfast=read(users,0);				/* and read record */

	} while (cfast==128);	/* read do loop ends */

	close(users);	/* close it... */
    }	/* good open loop */

	if (cfast!=128)
	   if (usernum==-1)		/* if entered name */
if (O.PRIVATE)
	break;	/* print system info, for address of where to get account */
  else
	if (newuser(first,last,user.number)!=ERROR)   /* newuser or bad name */
		return;		/* was new user, so return to main */

} while (++tries<O.MAXTRIES);	/* get name, etc.. for MAXTRIES */

if (O.PRIVATE) type(SYSINFO);
  else send("\n[* Access Denied *]");

exit();

}	/* getuser .... should never ever get here */


/**/
/* this routine checks if mistaken name, or gets new user's info	*/
/**/

newuser(first,last,un)
char *first,*last;
unsigned un;
{
register int cfast;
char temp[MAXLINE+1];

setmem(&user,128,0);
user.number=un;

  ask("] [no record]\nAre you new to this system? ",temp,1,UP);	/* mistake? */
  if (*temp!='Y') return ERROR;	/* not new user then return to getuser */

  ask("\nWhere are you calling from (city,state)? ",user.city,CITYLEN,UPLOW);
  if (user.city[0]=='\0') return ERROR;	/* not entered, get name again */
  capstr(user.city);

  printf("\nYou are %s %s from %s", first,last,user.city);
  ask("\nIs that correct? ",temp,1,UP);
  if (*temp=='N') return ERROR;

  send("\nPlease enter a password of 8 characters or less.");
  send("\nYou will need it EVERY time you login to this system!");
  send("\nSpaces and control characters are not allowed, and the first\ncharacter must not be numeric. ");
  do	{
 	ask("\nEnter password? ",temp,PASSLEN,UP+NOECHO+NUMBER);
	if (*temp=='\0') return ERROR;
	if (isspc(temp)) {
			 send("\nSpaces aren't allowed in passwords!!\n");
			 continue;	/* ask again... */
			 }
	if (isdigit(*temp))
			{
			send("\nThe first character must NOT be numeric!!\n");
			continue;
			}
	ask("\nNow re-enter it to make sure it's correct ? ",&temp[PASSLEN+10],
		PASSLEN,UP+NOECHO+NUMBER);
	if (strcmp(temp,&temp[PASSLEN+10])==0) break;
	send("\n[* Incorrect *]");
	send("\n  Try again.");
	} while (1);

if (dead_rec_no!=0) user.number=dead_user_no;
  else user.number++;	/* either use previously deleted user, or next one */

  send("\nGreat!  Now just make sure that you remember it!\n\
        You won't be able to login later without it.\n");

  printf("\nYou are user #%u.",user.number);
  printf("\n\nYour Metal ID is: %u%s",user.number,temp);

  send("\n\nEntering it instead of your name will\
\ntremendously speed up the login process,\
\nthough this is not required.");

  strcpy(user.first,first);
  strcpy(user.last,last);
  strcpy(user.pass,temp);
  strcpy(&user.parm.ulcase,"0000110");     /* initial user parms.. */
  user.lastread=user.parm.calls=0;
  user.status=O.DSTATUS;
  user.type=get_type(user.status);
  user.parm.height=24;
  user.parm.width=O.INITLENGTH;

  users=open(USERFILE,1);	/* open for r/w */

if (dead_rec_no!=0)
	setarec(users,dead_rec_no);
  else toeof(users);	/* set random record to eof for append */

 type(NEWUSER);
 return NULL;		/* got a new usr ok.. */

}	/* newuser */


putlastcaller()
{

#ifdef MULTI_USER
 register unsigned crec;
#endif

lastcalr=open(LASTCALR,1);

#ifdef MULTI_USER

#ifdef MPM
  crec=bdos(153,0);	/* get MP/M console # */
#else
  crec=*(id_loc+3);	/* Id number from counters file.. */
#endif   /* mp/m */

  toeof(lastcalr);	/* seek to end, and then write junk til positioned */
  while (getrec(lastcalr)<crec) write(lastcalr,1);
  setarec(lastcalr,crec);

#endif	 /* Multi_User */

sprintf(bufloc(lastcalr),"%s %s on %s%s%s\r\n\032%u %u %s %s",
	user.first,user.last,date,O.RTC!=NOCLOCK ? " at " : "",
	O.RTC!=NOCLOCK ? time : "",getrec(users),user.lastread,
	user.date,O.RTC==NOCLOCK ? "00:00:00" : user.time);
write(lastcalr,0);
close(lastcalr);
}


/* update callers log..  */

putcaller()
{
char tt[TIMELEN+1],td[DATELEN+1];

if (O.RTC!=NOCLOCK)
	{
	strcpy(tt,time);
	timefix(tt);
	}
   else	strcpy(tt,"");

strncpy(td,date,5);  td[5]='\0';

if (!O.PRTLOG)
	{
	callers=open(CALLERS,1);	/* output to file */
	toeof(callers);
	if (getrec(callers)!=0)
		{
		setrrec(callers,-1);	/* backup one */
		read(callers,0);
		while(gchar(callers)!=26);	/* test eof */
		setbuf(callers,getbuf(callers)-1);	/* backup a char */
		}
	}
	sprintf(buffer,"%s %s %s %s from %s\n\032",
			tt,td,user.first,
			user.last,user.city);
if (!O.PRTLOG)
	{
	fputs(buffer,callers);	/* write it out there.. */
	if (getbuf(callers)!=0) write(callers,0);
	close(callers);
	}
    else print(buffer);
  
wustat(0);	/* write user info, etc to status line */

}	/* pcaller */


/******************************************************************
 * initialize the bye variable to point to location if BYE active */

findbye()
{
register char *p;

bye=(*(char *)2)*256+*(char *)1-2;
bye=(*(char *)(bye+1))*256+*(char *)bye+6;

/* bye keeps mucking everyone up by changing the locations of strings */
for (p=bye; p<=bye+35; p++)
	if (!ustrncmp("bye",p,3)) break;

if (p>=bye+25) bye=nothing;

/* now for the values that we use the bye variable for.. */
maxuser=bye;
tout=bye+2;
nulls=bye+3;
}

/* EOF: menter.c */


