/************************************************************************
 * This file contains infrequently used (or used once) routines for the
 * overlay version of The Metal Message System.
 *
 *	Name: MEINFREQ.C
 *	Version 1.20a
 *
 *			Copyright (c) 1984  Tim Gary
 *			     Delphi Data Systems
 *			     All rights reserved.
 *
 ************************************************************************
 *
 *  1.20a   11/11/84  Ok, final cosmetic touches and release for this
 *		     series of changes.
 *  1.20<test c> 11/09/84  Version message changed for new mes.c file.
 *  1.20<test b> 11/07/84  Lastread fixed.
 *  1.20<test a> 11/04/84  Version change, and additions to lastcalr file info.
 *  1.10e   11/03/84  Added more info to the '#' command.
 *  1.10e   11/02/84  Msg number=parent thing deleted. New put/get counters.
 *  1.10e   11/01/84  Untypo'd a typo.
 *  1.10e   10/31/84  Added stuff for private message counts/width stuff.
 *  1.10d   10/21/84  First time system setup bug (from 1.10a/b/c) fixed.
 *  1.10c   10/12/84  Routines added to verify parent/replys to msgs.
 *		     if not found in the table, then zero'd.
 *  1.10b   10/04/84  Message table build from message file corrected.
 *  1.10b   10/03/84  Version change, touch-ups, height properly initialized.
 *  1.10a   09/27/84  Cosmetic fixes (U command).
 *  1.10a   09/09/84  Cosmetic fixes.
 *  1.10a   08/31/84  Created.
 *
 ************************************************************************/

#include "xpm.h"
#include "hmh.h"
#include "hmconfg.h"
#include "ctype.h"

#define TITLE "\nMetal Message System..(A Heavy BBS)\nVersion 1.20a\n"


/**********************************************************
 * Overlay main program, dispatches to contained routines.
 **********************************************************/

ovmain(routine,parm)
 int routine,parm;
{
switch(routine)
	{
	case INIT:
		return init(parm);
	case MSGALERT:
		return msg_alert(parm);
	case READUSERS:
		return readusers(parm);
	case SAVEUSER:
		return saveuser(parm);
	case CALLS:
		return calls(parm);
	case STATS:
		return stats(parm);
	default:
		send("\nUnknown routine called for.\n");
		break;
	}
} /* ovmain */


/***************************
 * INITIALIZE EVERYTHING   *
 ***************************/

/* flag is argc and is used to tell if menter was run or not for getlastcalr */

init(flag)
 register int flag;
{
if (O.ZCPR) *O.SECURELOC=0;	/* turn of all cp/m hazzards */

msg=malloc(O.MAXTOTMSGS*8+1);	/* alloc message array */

if (msg==0)
	{
	send("\nFatal ERROR: Unable to allocate message table space.");
	exit();
	}

#ifdef MULTI_USER
#ifdef MPM
 if (strncmp(id_loc,ID_STR,3))
	{
	send("\n[Please wait]\n");
/* 	ovloader(OVMENTER,(char *)0,0);	won't work here..*//* not setup with lastcalr.. */
	}
#endif
#endif

send(TITLE);	/* display banner identifing the system */

/* done only if menter not used */

if (flag<=1) {
	gcntrs(0);
	getlastcaller();	/* get lastcalr file saved in menter.c */
	}

height=user.parm.height;	/* reset height */

if (O.RTC!=NOCLOCK) getdate();	/* get time and date from clock board */

/*
 * Find out if BYE is active and setup BYE parms..
 */

findbye();	/* Get bye, maxuser,tout, etc.. variables */
*maxuser=15;	/* initialy so BYE lets us get to bbs files */

/*	setup timeout values for different people (different stats)  */
*tout=O.user_types[user.type].timeout;

*nulls=user.parm.nulls-'0';		/* setup users nulls	*/

stats(0);	/* display user number/message stats */

*(char *)O.RESETDRIVE;

flag=msg_alert(0);	/* check for msgs/build index */
putchar('\n');
return flag;
}	/* init */


/************************
 *  Get user from lastcalr file, file was created with menter
 ************************/

getlastcaller()
{
unsigned trec,tlast;
char td[DATELEN+1],tt[TIMELEN+1];

if ((lastcalr=open(LASTCALR,F_RD | F_UNLOCK))==NULL) 	/* open for read only */
	{
	send("\nSerious ERROR:  No LASTCALLER FILE!");
	exit();		/* exit to cpm in case it's sysop and can be fixed.. */
	}

#ifdef MULTI_USER

#ifdef MPM
  trec=bdos(153,0)%16;	/* get mp/m user console id */
#else
  trec=id_num;
#endif	 /* MP/M */

  setarec(lastcalr,trec);	/* seek to console position to get caller */

#endif	 /* Multi_User */

read(lastcalr,0);
sscanf(bufloc(lastcalr),"%*[^\032] %*1s %d %d %s %s",
	&trec,&tlast,td,tt);
close(lastcalr);

users=open(USERFILE,F_RD | F_UNLOCK);		/* open for read */
setarec(users,trec);		/* seek to user */
read(users,0);			/* get the record */
movmem(bufloc(users),&user,128);	/* copy the record into our variable */
close(users);
user.lastread=tlast;		/* get lastread back */
height=user.parm.height;	/* get height setup  */
strcpy(user.time,tt);
strcpy(user.date,td);
}


/************************************************
 * All new and improved msg summary builder...	*
 * Will use messages file alone and skip bad	*
 * sectors that it finds...			*
 ************************************************/

msg_alert(n)
{
msg_record *mptr;	/* for easy access to values in the field */
register int flag;
int fileflag;		/* summary or message index build	  */
int lines;		/* line count of message */

flag=msgcount=totalmsgs=privmsgs=mindex=fmsg=lmsg=0;
fileflag=TRUE;

if (!n) send("\n[Checking for Mail]\n"); 

if ((summary=open(SUMMARY,F_RD | F_UNLOCK))!=NULL)
 	{	/* summary file opened.. */
	toeof(summary);
	if (getrec(summary)<=1) close(summary);
	  else	{
		setarec(summary,1);
		fileflag=FALSE;
		}
	}
	else {		/* create summary to keep things happy */
		summary=open(SUMMARY,F_RW);
		sprintf(bufloc(summary),"0   \n");
		write(summary,1);
		close(summary);
		}

if (fileflag)	/* summary file not opened correctly, try messages */
	summary=open(MESSAGES,F_RD | F_UNLOCK);

#ifdef DEBUG
printf("\nBuilding message index from %s file.\n",fileflag ? "message" : "summary");
#endif

mptr=bufloc(summary);	/* setup buffer pointer	*/
while (summary && read(summary,1)==128)
	{
	msg[mindex].number=mptr->number;
	msg[mindex].seek=mptr->seek;
	msg[mindex].parent=mptr->parent;
	msg[mindex].reply=mptr->reply;
	if (mptr->status==DEADMSG) msg[mindex].parent=msg[mindex].reply=0;

#ifdef DEBUG
printf("\nnum %u   seek %u   parent %u   reply %u",mptr->number,mptr->seek,
	mptr->parent,mptr->reply);
#endif

	if (mptr->lines && fileflag)
		{		/* message file skip text */
		if ( (mptr->status!=PRIVMSG && mptr->status!=NORMMSG
		    && mptr->status!=DEADMSG)
	    	    || mptr->seek!=(getrec(summary)-1) )
			{	/* not valid record, skip till one found.. */
			send("\n[Bad records found, skipping..]\n");
#ifdef DEBUG
printf("\nFile seek=%u, Message stat='%c' %x hex.",getrec(summary)-1,mptr->status,mptr->status);
#endif
			do lines=read(summary,1);
			  while (lines==128 && (mptr->status!=NORMMSG &&
				 mptr->status!=PRIVMSG && 
				 mptr->status!=DEADMSG) ||
				 mptr->lines>O.MLINES ||
				mptr->seek!=(getrec(summary)-1) );
			setrrec(summary,-1);
			if (lines==128) continue;	/* don't increment mindex, etc.. */		   else break;
			}
		}

	if ( /* mptr->status!=DEADMSG && */ mptr->number)
		{
		lmsg=mptr->number;
		if (!fmsg) fmsg=lmsg;
		}

	if (mptr->status==PRIVMSG) privmsgs++;	/* count # of private msgs */

	if (!n && mptr->status!=DEADMSG && thisis(mptr->receiver))
		{	/* if message active and addressed to them */
		if (!flag)
			{
			send("\n[You have Mail!]\n\nNumber:  From:\n");
			++flag;
			}
		printf("%5u    %s %s%s%s\n",
			mptr->number,
			mptr->fsend,mptr->lsend,
			mptr->number>user.lastread ? "  [new]" : " ",
			mptr->status==PRIVMSG ? " [private]" : "");
		}

	if (mptr->status!=DEADMSG) {
			++msgcount;
			++totalmsgs;
			}

	if (mptr->lines && fileflag)
		{
		lines=mptr->lines+1;
		read(summary,1);
		while (lines--) while (getc(summary)!='\n');  /* flush line */
		}

	++mindex;	/* killed msg in table too, for upcoming unkill,etc. */

	if (mindex>=O.MAXTOTMSGS)
		{
		printf("\nTo many msgs, (%d is max, including deleted ones)\n",
			O.MAXTOTMSGS);
		close(summary);
		return ERROR;
		}
	}	/* while */

if (!n && !flag) send("\n[Sorry, no Mail]\n");

if (summary && fileflag)
	{
	send("\n[One moment please.  Be sure to do a message purge before anything else!]\n");
	for (flag=0; flag<mindex; flag++)	/* fix reply/parent conficts */
		{
		if (getindex(msg[flag].parent)==ERROR) msg[flag].parent=0;
		if (getindex(msg[flag].reply)==ERROR) msg[flag].reply=0;
		}
	}

close(summary);
nextmsg=lmsg+1;

return NULL;
} /* build index */


/********************************
 * display users of the system	*
 ********************************/

readusers(n)
 register int n;
{
char temp[FNAMELEN+LNAMELEN+CITYLEN+3];
ask("\nEnter full or partial User Name or City,\nor user number to start listing at? ",
temp,FNAMELEN+LNAMELEN+CITYLEN+2,UP);
if ((users=open(USERFILE,F_RD | F_UNLOCK))!=NULL)
	while (showuser(temp,n)!=ERROR) *(char *)O.RESETDRIVE;

if (users!=NULL) close(users);
}


showuser(sstr,mode)
register char *sstr,mode;
{
char temp[120],temptime[TIMELEN+1];
char tb[FNAMELEN+LNAMELEN+CITYLEN+3];
usr *up;

up=bufloc(users);
if (read(users,1)!=128) return ERROR;

if (breakkey()) return ERROR;		/* stop? */
if (up->number==0) return NULL;

sprintf(tb,"%s %s %s",up->first,up->last,up->city);
upcase(tb);		/* make upper case only */

if (isdigit(*sstr))
	{
 	if (atoi(sstr) > up->number) return NULL;
	}
  else if (!sindex(sstr,tb) && *sstr!='\0') return NULL; /* no match-no show */

if (user.status==SYSOP)
	sprintf(temp," -- '%c' (%s) pw=%s",up->status,
	up->status==SYSOP ? "sysop" :
		up->status==SPECIAL ? "special" :
			up->status==NORMAL ? "normal" :
				up->status==NOCPM ? "NO CP/M" :
					up->status==TWIT ? "*TWIT*" :
						"OTHER",up->pass);
   else { mode=NOPRINT; *temp='\0'; }
sprintf(buffer,"\n%-5u %s %s%s  from %s",up->number,up->first,up->last,
	temp,up->city);

if (send(buffer)==ERROR) return ERROR;
if (mode==PRINT) {
		print(buffer);		/* send to list device */
		print("\r");
		}

strcpy(temptime,up->time);
timefix(temptime);

sprintf(buffer,"\n\\---- Called %u time(s).  Last message was %u on %s %s%s\n",
	up->parm.calls,up->lastread,up->date,
	O.RTC!=NOCLOCK ? "at " : "",O.RTC!=NOCLOCK ? temptime : "");

if (send(buffer)==ERROR) return ERROR;
if (mode==PRINT) {
		print(buffer);		/* send to list device */
		print("\r");
		}
 return NULL;	/* alls done */
}


/*******************************
 * display the user on console *
 *******************************/

disuser()
{
printf("\nYou are user #%d.\n",user.number);

sprintf(buffer,"\
\n(1) Experience=%s (2) Bell=%s   (3) Nulls=%c\
\n(4) %s         (5) %s messages when first entering the bbs.\
\n(6) Change Password.  (7) Terminal height=%d (if 0, no pause)\
\n(8) Terminal width=%d\n",
	(user.parm.expert==PON) ? "EXPERT" : "NOVICE",
	(user.parm.bell==PON) ? "ON" : "OFF",user.parm.nulls,
	(user.parm.jmpcpm==PON) ? "Skip BBS " : "Enter BBS",
	(user.parm.rp==POFF) ? "Read" : "Don't read",
	user.parm.height,user.parm.width);
send(buffer);

}


/********************
 * Save users stuff *
 ********************/

saveuser(n)
 register unsigned n;
{
char temp[10];

disuser();	/* display the user */

  do {
     if (user.parm.expert==PON) sprintf(buffer,"\nChange :");
	else sprintf(buffer,"\nEnter number to change (Return to End) :");
     ask(buffer,temp,9,UP);
     switch (*temp)
	{
	case '1':	user.parm.expert==PON ?
			  (send("\n[Novice mode]"),user.parm.expert=POFF) :
			  (send("\n[Expert mode]"),user.parm.expert=PON);
			break;

	case '2':	user.parm.bell==PON ?
				(send("\n[Bell off]"),user.parm.bell=POFF) :
				(send("\n[Bell on]"),user.parm.bell=PON);
			break;

	case '3':	ask("\nNumber of nulls (0-9)? ",buffer,5,UP);
			if ((*temp>='0') && (*temp<='9') && *buffer!='\0')
				{ *nulls=*buffer-'0';
 				  user.parm.nulls=*buffer;	}
			  else send("\n[Nulls NOT changed]");
			break;

	case '4':	if (O.user_types[user.type].maxuser==0)
				{
				send("\nYou don't have Operating System privs...");
				break;
				}
			user.parm.jmpcpm==PON ?
			  (send("\nYou will now enter the BBS when you call."),
				user.parm.jmpcpm=POFF) :
	 (send("\nYou will now enter the Operating System instead of the BBS when you call.")
				,user.parm.jmpcpm=PON);
			break;

	case '5':	user.parm.rp==POFF ?
			  (send("\n[AUTO read of messages OFF]"),user.parm.rp=PON) :
			  (send("\n[AUTO read of messages ON]"),user.parm.rp=POFF);
			break;
	case '6':	do
			  ask ("\nEnter new password, or RETURN if no change -> ",buffer,PASSLEN,UP);
			  /* no spaces, or number for first char */
			while (isspc(buffer) || isdigit(*buffer));
			if (*buffer!='\0') strcpy(user.pass,buffer);
			  else send("\n[Password NOT changed]");
			break;

	case '7':	ask("\nTerminal Height (0=no pause)? ",buffer,5,UP);
			if (*buffer!='\0')
				user.parm.height=height=atoi(buffer);
			  else send("\n[Height not changed]");
			break;

	case '8':	ask("\nTerminal width? ",buffer,5,UP);
			if (*buffer!='\0')
				{
				if (atoi(buffer)<20)
					send("\n[Must be >=20, unchanged]");
				   else user.parm.width=atoi(buffer);
				}
			  else send("\n[Width not changed]");
			break;

	case '\0':	break;
	case '?':	disuser();
			break;
	default:	send("\n[Invalid option]");
	  }	/* switch */
    } while (*temp!='\0');

ask("\nMake changes permanent for future calls (y/n)? ",temp,2,UP);
if (*temp=='Y')
	{
	char temp_time[TIMELEN+1],temp_date[DATELEN+1];
	send("\n[Saving]");
	n=user.lastread;
	user.lastread=nextmsg ? nextmsg-1 : 0;
	strcpy(temp_time,user.time);
	strcpy(temp_date,user.date);
	strcpy(user.time,time);
	strcpy(user.date,date);
	putuser(user.number);	/* write new user info back to file */
	strcpy(user.time,temp_time);
	strcpy(user.date,temp_date);
	user.lastread=n;	/* restore last read msg number */
	}
}	/* saveuser */


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


/*************************
 * Display message stats *
 *************************/

stats(n)
{
char temptime[TIMELEN+1];

strcpy(temptime,user.time);	/* make pretty time */
timefix(temptime);

sprintf(buffer,"\nYou are caller %u (User #%u).\n\
You've called %u time(s), last one being on %s%s%s.\n\n\
There are %d active messages.",callnum,user.number,user.parm.calls,
user.date,O.RTC!=NOCLOCK ? " at " : "",O.RTC!=NOCLOCK ? temptime : "",
msgcount);
if (send(buffer)==ERROR) return;

if (privmsgs) sprintf(buffer," (%d are private)",privmsgs); else *buffer='\0';
if (send(buffer)==ERROR) return;

sprintf(buffer,"\nYour last read message was %u.\n\
The current high message is %u.\n",user.lastread,nextmsg ? nextmsg-1 : 0);
send(buffer);
}


/*********************
 * List callers file *
 *********************/

calls(n)
{
if (type(CALLERS)!=ERROR)		/* type the callers of today */
  if (user.status==SYSOP)
	{
	ask("[Purge callers file?]",buffer,2,UP);
	if (*buffer=='Y')
		{
		send("[Purging]");
		unlink(CALLERS);
		}
	}
}


/* End of File */


