/******************************************************************************
 *
 *	Enter program for METAL/Z-MSG System
 *
 *	FILE: MENTER.C
 *
 *		   Copyright (c) 1984, 1985, 1986 Tim Gary
 *			    All Rights reserved.
 *
 *
 *	This file gets the users' name/password/etc..
 *
 ******************************************************************************
 *
 * 1.50xx 08/04/86 Ask for phone number (or other field)
 * 1.50xx 07/04/86 Type bulletins AFTER login!
 * 1.50xx 04/10/86 z3_init() call changed to overlay call, etc..
 * 1.50xx 03/10/86 Init group flags if user.group_flags==0..
 * 1.40xx 02/04/86 Hashed user file support added..
 * 1.40xx 01/28/86 City/state back in users structure..
 * 1.40xx 01/26/86 time/user stuff changed...
 * 1.31a  10/13/85 Release version.  Changes:
 *		   z3_init()/custom init support added.  Help changed..
 * 1.31xx 8/06/85  Start on TurnKey bbs version..
 * 1.30xx 6/23/85  wustat routine moved here..
 * 1.30xx 6/19/85  Askdate routine moved here.. g_restore stuff done in main.
 * 1.30xx 6/19/85  Putuser routine not used anymore..  user saved directly..
 * 1.30xx 6/12/85  <BBSNAME> + <password> can be typed on one OS command line
 *		  for a quicker sysop toggle..
 * 1.30xx 6/09/85  New bye save stuff deleted, change for new save stuff.. 
 * 1.30xx 6/01/85  rsvstk reserves more space.... 512 more..
 * 1.30xx 5/30/85  rsvstk called to make sure 'msg' array don't get clobbered.
 * 1.30xx 5/25/85  msg pointer gets setup here for Z3..  (top of memory)
 * 1.30xx 5/19/85  Read clock before getting user stuff if RTC != NOCLOCK.
 * 1.30xx 5/12/85  Things should be working better..
 * 1.30xx 5/11/85  Uh..  hopefully works with bye..
 * 1.30xx 5/09/85  Protect mode works fine!!!
 * 1.30xx 5/08/85  Fix bug in saving cmdline..
 * 1.30xx 5/05/85  Path stuff changed, protection stuff added.
 * 1.30xx 5/03/85  Path stuff added for aliases.
 * 1.30xx 5/02/85  Z3BUG turned off, Z3MSG_OFFSET added, last_date/time
 *		  put in g_save..
 * 1.30xx 5/01/85  Message buffer pointers fixed/Saved buffers locs corrected.
 * 1.30xx 4/28/85  Debug (Z3) stuff added..
 * 1.30xx 4/26/85  Restoration of command buffer added for Z3.
 * 1.30xx 3/13/85  Return from OS bug fixed..
 * 1.30xx 3/07/85  BYE link stuff added, and also BBSNAME define.
 * 1.30xx 2/21/85  Start Z3 additions.
 * 1.20b 01/18/85  Last time called bug fixed..
 * 1.20b 01/11/85  User.time/date saved in different order.
 * 1.20b 01/05/85  Fast status change if 'METAL +' issued..  Password length
 *		  bug fixed.  Log twit calls IF default user type is TWIT.
 * 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.
 *
 *****************************************************************************/

#include "xpm.h"	/* CPMIO header file for i/o operations.*/
#include "megen.h"	/* general defines		*/
#include "meglob.h"	/* global variable definitions	*/
#include "meovfn.h"	/* overlay function numbers	*/
#include "mefiles.h"	/* file names			*/

#include "ctype.h"

static char tpass[PASSLEN+1];

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

ovmain(argc, argv)
 register int argc;
 register char *argv[];
{
unsigned tlastread,temp_hp;
char **m_buff;
usr *up;

if (argc>=2 && (!strcmp(argv[1],"+") || !strcmp(argv[1],"!")) )
	/* check for quick sysop status */
	{
	if (argc==3) strcpy(buffer,argv[2]);
	  else ask("Prove it!",buffer,PASSLEN+1,UP|NOECHO|NOTOS);
	if (!strcmp(buffer,O.SOPASS))
		{
		user.status=SYSOP;
		user.type_ptr=get_tp(SYSOP);
		send("[Sysop Toggle ON]\n");
#ifdef Z3
		if (O.ZCPR==3) ovovloader(OVZ3,INITZ3,NULL);	/* load sys segs, etc.. */
#endif
		findbye();
		go_os(NO);
		}
	  else {
		send("[Sorry...]");
		exit(0);		/* (any os) don't change a thing */
		}
	}

  init();
  gcntrs(0);		/* get counters */

  if (O.RTC) readclock();	/* get time here if RTC being used */

  if ((users=open(USERFILE,1))!=NULL)
	getuser();		/* gets user name and other vital info */
    else
	{
	send("\nERROR: Unable to open/create users file..");
	go_os(NO);
	}

  up=bufloc(users);

  /* 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');

  if (!O.RTC) askdate();	/* get date now if no clock */

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

  if (O.ASKNULLS) user.nulls=*nulls;  /* setup user nulls */
     else *nulls=user.nulls;

  if (!user.calls)
	{
	movmem(date,user.date,3);
	movmem(time,user.time,2);
	}

  movmem(user.date,last_date,3);
  movmem(user.time,last_time,2);	/* putlastcaller writes these */

  movmem(date,user.date,3);		/* setup current login date/time */
  movmem(time,user.time,2);

  temp_hp=up->number;

  if (!user.group_flags) user.group_flags=O.INIT_G_FLAGS;

  putlastcaller();

  user.number=temp_hp;
  tlastread=user.lastread;		/* save real current lastmsg count */
  user.lastread=(nextmsg ? nextmsg-1 : 0);	/* new user.lastread msg */
  user.calls++;
  if (user.width<20 || user.width>132) user.width=O.INITLENGTH;
  movmem(&user,bufloc(users),128);   /* write to open users file, and close */
  user.number=getrec(users);
  write(users,0);
  close(users);
  user.lastread=tlastread;	/* restore real lastread msg (overlay req.) */
  user.type_ptr=get_tp(user.status);

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

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

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

#ifndef MULTI_USER
  if (user.type_ptr->timeout==0)
	hangup(NO);
#endif

#ifdef Z3
  if (O.ZCPR==3) ovovloader(OVZ3,INITZ3,NULL);
#endif

  cust_init();		/* do custom user init stuff (MEINIT) */

  if (user.login)
	go_os(YES);	/* setup parms and goto Op Sys */

type(BULLETIN);		/* display this */

/* NOTE: with overlays, all we do is return, and that'll put us back main */
return argc;	/* tells whether or not to be quiet or not */

}	/* main */


/* Custom user init code caller.. passes if bye present, user struct and
   user status table address..	*/

cust_init()
{
int (*initloc)()=0x390;		/* location of actual code */
char *bye_flag=0x385;		/* flag if bye there.. */
usr **up=0x386;			/* pointer to pointer to user struct */
u_types **usp=0x388;		/* pointer to pointer to user status stuff */

if ( ! (*(bye_flag-1)) ) return;	/* not installed, ignore */

if (bye) *bye_flag=0xff;
*up=&user;
*usp=user.type_ptr;

(*initloc)();		/* call routine */
}


/* get date from keyboard (for those without a clock) */

askdate()
{
int temp;
char tdate[9];

setmem(time,2,0);

if (!strloc || tolower(glbstr[strloc])!='y')
   {
   printf("\nIs %s today's date [y/n]? ",ascdate(date));

   do temp=tolower(getd());
	while (temp!='y' && temp!='n');

   if (temp=='y')
	send("[yes]\n");
     else {	/* no need for this really */
	send("[no]\n");
	do  ask("What's todays date (mm/dd/yy)? ",tdate,9,UP|NOTOS);
	  while (strlen(tdate)!=8 && tdate[2]!='/' && tdate[5]!='/');
	dateasc(tdate,&date);	/* convert.. */
	}
   }
   else if (strloc) ask("",buffer,1,UPLOW);	/* kill 'y' */

return date;

} /* askdate */


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

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

#endif

/* done in main code: findbye();   */ /* setup bye, and related, variables */
*maxuser=1;	/* setup maxuser */
*tout=3;	/* setup 3 minute timeout */
if (!O.ASKNULLS)	/* if bye asked for nulls, don't reset... */
  *nulls=0;		/* no nulls */

printf("\n\nEnter %s\n%s\n",O.VERSION,O.WHERE);

if (msg==(char *)0)	/* message allocated by settop in main */
	{
	send("\nAllocation ERROR: Memory full.\n");
	if (user.status==SYSOP)
		{
		send("\n** Use the Configuration program and decrease total # of msgs **\n");
		go_os(NO);
		}
  	else send("\n** Sorry, but the BBS is in need of repair.  Please try it later! **");
	hangup(YES);	
	}

if (O.ZCPR)
 if (O.ZCPR!=3) *O.SECURELOC=0;	/* if using ZCPR in secure mode, then make */
  else *(z3env->wheel)=0;

} /* init */


/* 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;
char name[NAMELEN+1];	/* temp name */
char temp[MAXLINE+1];
int match;

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

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

*tpass='\0';	/* no temp password yet */


/* PRIVATE SYSTEM ONLY STUFF */

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

   if (tries>=O.MAXTRIES)
	{
	type(SYSINFO);	/* info about this private system before quiting */
	hangup(NO);
	}
   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 {
	*name='\0';	/* terminate last name initially */
	/* get first name or user # and password, TRUE says convert to upper */
	ask("\nWhat is your FULL name? ",name,NAMELEN,UPLOW|NOTOS);
	if (strlen(name)<2) type(SYSINFO);	/* print login help msg */
 	} while (strlen(name)<2);

   if (!ustrcmp(name,"SYSOP") || !index(name,' ') )
		{
		char tlast[NAMELEN+1],temp_name[NAMELEN+NAMELEN+3];
		ask("\nWhat is your LAST name? ",tlast,NAMELEN,UPLOW|NOTOS);
		if (*tlast=='\0') goto getfirst;
			/* if return pressed, start over */
		sprintf(temp_name,"%s %s",name,tlast);
		strncpy(name,temp_name,NAMELEN);
		name[NAMELEN]='\0';	/* make sure it's terminated */
		}

capstr(name);

/* check for sysop */

   if (  (!ustrcmp(name,"SYSOP")) ||
	 (ustrcmp(name,O.SONAME)==0) || (atoi(name)==1) )
	{
	ask("\nSysop Pass? ",tpass,PASSLEN,UP|NOECHO|NOTOS);
	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(name,O.SONAME);	/* for sysop respons */
	}


/* New stuff too fast for these!
	if (O.PRIVATE) send("\n[Verifying ID]");
	  else send("\n[Checking for previous login]\n[.");	*/


	/* see if name match */

	if ( (match=find_user(name))>=0 )
		{
		movmem(bufloc(users),&user,128);	/* get user */
		user.number=getrec(users);
		tpass[PASSLEN]='\0';	/* make sure it's terminated here */
		if (*tpass!='\0')
		    if (ustrcmp(tpass,user.pass)==0)
			goto itshim;   /* it's him! that's all getuser needs */

		/* get password */

		if (*tpass=='\0')
			{
			ask("\nEnter password? ",tpass,PASSLEN,UP|NOECHO|NUMBER|NOTOS);
			if (strcmp(tpass,user.pass)==0)
				{
	itshim:			movmem(bufloc(users),&user,128);
			/*	putchar('\n');	*/
				return;
				}
			}
		send("\n[Wrong!]\n");
		}

if (match<0)
  if (O.PRIVATE)
	break;	/* print system info, for address of where to get account */
     else
	if (newuser(name)!=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 *]");

hangup(NO);

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


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

newuser(name)
char *name;
{
register int cfast;
char temp[MAXLINE+1];

setmem(&user,128,0);

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

  ask("\nWhere are you calling from (city,state)? ",user.city,CITYLEN,UPLOW|NOTOS);
  if (user.city[0]=='\0') return ERROR;
  capstr(user.city);

  printf("\nYou are %s from %s",name,user.city);
  ask("\nIs that correct? ",temp,1,UP|NOTOS);
  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|NOTOS);
	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|NOTOS);
	if (strcmp(temp,&temp[PASSLEN+10])==0) break;
	send("\n[* Incorrect *]");
	send("\n  Try again.");
	} while (1);

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


  if (O.QUESTION[0]!='\0')
	{
	while (1) {
	   putchar('\n');
	   ask(O.QUESTION,user.phone,12,UPLOW);
	   if (O.QUESTION[0]=='!' && user.phone[0]=='\0')
		{
		send("\nYou must answer this question if you wish to use this system.");
		continue;
		}
	   break;
	   } 
	}

  strcpy(user.name,name);
  strcpy(user.pass,temp);
  user.flags=O.INITPARMS;			/* initial user parms.. */
  user.lastread=user.calls=0;
  user.status=O.DSTATUS;
  user.height=24;
  user.width=O.INITLENGTH;

  user.number=add_user(&user);
  type(NEWUSER);

  return NULL;		/* got a new usr ok.. */

}	/* newuser */


putlastcaller()
{
FILE *lastcalr;
register unsigned *uptr;
register char *sp;

#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 on %s%s%s\r\n\032",
	user.name,ascdate(date),O.RTC ? " at " : "",
	O.RTC ? asctime(time) : "");

sp=index(bufloc(lastcalr),0x1a)+1;	/* find ^Z and skip  */
uptr=sp;				/* point to values.. */
uptr[0]=getrec(users);
uptr[1]=user.lastread;
strcpy(sp+4,ascdate(last_date));
strcpy(sp+14,asctime(last_time));

/* sprintf(bufloc(lastcalr),"%s on %s%s%s\r\n\032%u %u %s %s",
	user.name,date,O.RTC ? " at " : "",
	O.RTC ? time : "",getrec(users),user.lastread,
	last_date,last_time);					*/

write(lastcalr,0);
close(lastcalr);
}


/* update callers log..  */

putcaller()
{
FILE *callers;
char td[9];

strncpy(td,ascdate(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\n\032",
		O.RTC ? asctime(time) : "",td,user.name);

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 */


/* Write user status line info (name, stat, time called, city).. */

wustat(s)
 char *s;
{
char buf[128];
sprintf(buf,"%8s -- %s - '%c' %s -- %s",s ? s : "",user.name,
	user.status,asctime(time),user.city);
writestat(buf);
}


/* EOF: menter.c */



