/********************************************************************
 * ZCPR3 routines for Metal/Z-MSG
 *
 * 	File: MEZ3.C
 *
 *	    Copyright (c) 1984,1985,1986 Tim Gary
 *		   All Rights Reserved.
 *
 ********************************************************************
 *
 * 1.50xx  04/10/86 Moved alias return, and z3_init stuff here (from metal.c)
 * 1.50xx  03/09/86 n_groups added..
 * 1.40xx  01/26/86 Fix for new date/user formats..
 * 1.31a   10/13/85 Release version.
 * 1.30xx  7/01/85  Print/echo flags saved...
 * 1.30xx  6/09/85  New bye stuff deleted, new protect method done.
 * 1.30xx  5/26/85  Save bye stuff if bye is active.. (at new topmem loc)
 * 1.30xx  5/25/85  Msg pointer saved in gp area, see also meinfreq..
 * 1.30xx  5/12/85  Bug in calculations fixed.
 * 1.30xx  5/11/85  Protection code that should work with bye..
 * 1.30xx  5/09/85  Protect mode working...
 * 1.30xx  5/05/85  Modified Path stuff, fixed protection for globals.
 * 1.30xx  5/03/85  Z3 Path stuff saved, and used in alias command lines.
 * 1.30xx  5/02/85  Z3BUG turned off, Z3MSG_OFFSET added, glbstr buffer
 *		   save fixed..
 * 1.30xx  5/01/85  Error returned only if command not found, not if
 *		   can't access it.  ALIASRET define used.  If allocation
 *		   error, command line is restored.
 * 1.30xx  4/28/85  Z3BUG stuff added.
 * 1.30xx  4/26/85  Fix for saving command buffer before entering Z3
 * 1.30xx  4/04/85  Etc..
 * 1.30xx  3/03/85  Back to work.
 * 1.30xx  2/26/85  Command routine started.
 *
 ********************************************************************/

/* #define Z3BUG  */	/* for Z3 alias debugging */

#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"


ovmain(func,parm)
 register int func;
 register char *parm;
{
#ifndef Z3
return ERROR;

#else

switch (func)
	{
	case CMD:
		return do_command(parm);
	case RETCMD:
		return ret_cmd(parm);
	case INITZ3:
		return z3_init(parm);
	default:
		send("\nMEZ3: Unknown Overlay function called for.\n");
		return ERROR;
	}

#endif
}

#ifdef Z3


/*************************************************************************
 *  do_command looks for a command in a file of the following format:
 *
 *	Status mask	Command name	Number of parms	   Alias command name
 *     (4 hex chars)   (small string)	   in alias	     ONE WORD ONLY!
 *
 *	All fields are seperated by a space.
 *
 *  		*** EVERY FIELD MUST BE PRESENT!!!!!! ***
 *
 *	The number of parms is not currently acurate.  If there are
 *   more than zero parms expected, it will take the rest of the line up
 *   to the next ';' character (or eol).  It does NOT take several parms
 *   based on the value you give it.
 *	When the alias is performed, and execution should return to
 *    metal upon termination.   This will be fairly slow, but it should
 *    work ok.
 *
 ************************************************************************/

do_command(name)
 char *name;
{
FILE *commands;
unsigned flags;		/* temp storage of current mask flag from file */
char cmd_name[20];	/* current command name in file		   */
int  n_parms;		/* number of parms			   */
char alias[MAXLINE+1];	/* alias to use, parms are simply appended */
char *ccl;		/* pointer to current command line	   */
char *ts;
char a_user,a_drive;	/* user/drive alias is in */
int ti;
char *index();
static struct cmd_line savecmd;

if ((commands=open(COMMANDS,0))==0) return ERROR;

#ifdef Z3BUG
printf("\nCommands file open, trying to match --> '%s'.\n",name);
#endif

read(commands,1);	/* fill buffer to start with */

while (1) {
   fgets(buffer,commands);
   if (strlen(buffer)<10) break;	/* EOF.... */
   while (*buffer=='\n' || *buffer=='\r') strcpy(buffer,buffer+1);

   flags=xtou(nextf(buffer));
   ts=index(buffer,' ')+1;
   strcpy(cmd_name,nextf(ts));
   ts=index(ts,' ')+1;
   n_parms=atoi(ts);
   strcpy(alias,index(ts,' ')+1);

#ifdef Z3BUG
   printf("\nFlag='%x'  User flag='%x'\nCommand name='%s'  Number of parms='%d'  Alias='%s'.\n",flags,user.type_ptr->flags,cmd_name,n_parms,alias);
#endif
   /* continue if no match, or not allowed... */
   if ( !(flags & user.type_ptr->flags) || (ustrcmp(name,cmd_name))) continue;

   /* Ok, got here, command matches and available to this user */
   ccl=z3env->cl->buffer;		/* point to z3 command line buffer */
   movmem(z3env->cl,&savecmd,z3env->cls+4);	/* save for later */
   a_user=0; a_drive=1;	/* normally use A0: */
   if (index(alias,':') && (index(alias)<(5+alias)) )
	{
	a_user=atoi(alias+1);	/* must be duu:alias format */
	a_drive=1+(tolower(*alias)-'a');
	strcpy(alias,index(alias,':')+1); /* delete drive spec */
	}

   sprintf(ccl,"%s ",alias);
   if (n_parms && strloc)	/* get parm if there is one on the line */
	{
	ask("",buffer,40,UPLOW);	/* get next parm */
	strcat(ccl,buffer);		/* append parm to command line */
	}
   strcat(ccl,O.ALIASRET);	/* make sure we return ok.. */
   z3env->cl->next_char=ccl;
   close(commands);
#ifdef Z3BUG
   printf("Command line buffer (Z3 one) is at %xh.  Contents at %xh='%s'.\n",
	  z3env->cl,ccl,ccl);
#endif
   do_alias(&savecmd,a_user,a_drive);	/* never returning function */
   return NULL;				/* if we're here, there's a problem */
   }

/* if we get here, there were problems */

close(commands);
return ERROR;

} /* do_command */


nextf(s)
 char *s;
{
static char tstr[MAXLINE+1];

strcpy(tstr,s);
if (s=index(tstr,' ')) *s='\0';	/* make ' ' into terminator */
return tstr;
}


extern char sotries;

/* do_alias function saves globals, and warm boots to perform command */

do_alias(savecmd,a_user,a_drive)
 struct cmd_line *savecmd;
 char a_user,a_drive;
{
struct g_save *gp;	/* pointer to global variable area */
struct g_prot *gh_p;	/* pointer to globals protect header */
/* char *troom;	*/	/* allocated space to play it safe */
char *g_v,*global_loc;	/* pointer to start of all globals (msg, user, etc.) */
char **m_buff;		/* pointer to char pointer */
char *ptr;
int size,i;

global_loc=g_v=malloc(sizeof(user)+sizeof(struct g_save));

#ifdef Z3BUG
printf("\n%xh bytes of free memory required.",sizeof(user)+sizeof(struct g_save) );
printf("\nMalloc=%xh (zero indicates not enough space)\n",global_loc);
#endif

if (!global_loc)
	{
	movmem(savecmd,z3env->cl,(unsigned)((z3env->cls)+4));
	if (user.status==SYSOP)	send("\nERROR: Insufficient memory for aliases.");
	else send("\nCommand unavailable at this time.\n");
	return ERROR;
	}

/* to protect the private global area, we do a bye-like fake of top memory */

ptr=*((char **)0001)+3;		/* Point to bios jump table */
g_h.obdos=*((char **)0x0006);	/* warm boot address */
g_h.g_vars=g_v;			/* pointer arith!.. pt. to globals */
movmem(ptr,g_h.bt,18);		/* copy old bios jmp table */
g_h.prot_bdos=z3_hp;		/* address of our bdos jmp (defined in main) */

/* if (bye!=nothing) movmem(g_h.obdos+0x0c,g_h.bye_a1,32); */ /* save bye vars */

/* this must go before the loop.  z3_hp defined in main */
movmem(&g_h,z3_hp,sizeof(g_h));		/* move to actual location */

for (i=0; i<6; i++)
	{
	unsigned *uptr;
	z3_hp->abt[i].addr=z3_hp->bt[i].addr;  /* fill in our new bios jumps */
	z3_hp->abt[i].swapbdos=&(z3_hp->swap);
	uptr=(ptr+(3*i)+1);
	*uptr=&(z3_hp->abt[i]);		/* store new bios vector */
	}

#ifdef Z3BUG
printf("\nz3_hp=%xh   z3_hp->g_vars=%xh\n",z3_hp,z3_hp->g_vars);
#endif

#ifdef Z3BUG
printf("\nAfter swap, *(0006)=%xh.\n",*(int *)0006);
#endif

g_v=(z3_hp->g_vars);	/* point to loc for variables */
movmem(&user,g_v,sizeof(user));
g_v+=sizeof(user);
gp=g_v;		/* compute gp like this or problem might occur */

#ifdef Z3BUG
printf("gp=%xh   msg=%xh \n",gp,msg);
#endif

gp->msg=msg;		/* save location of msg array */
movmem(glbstr,gp->glbstr,MAXLINE+1);
gp->strloc=strloc;
gp->globalch=globalch;
gp->print_flag=print_flag;
gp->echo_flag=echo_flag;
gp->sepstr=sepstr;
gp->fmsg=fmsg;
gp->lmsg=lmsg;
gp->mindex=mindex;
gp->msgcount=msgcount;
gp->privmsgs=privmsgs;
gp->nextmsg=nextmsg;
gp->totalmsgs=totalmsgs;
gp->callnum=callnum;
movmem(date,gp->date,3);
movmem(time,gp->time,2);
movmem(last_date,gp->last_date,3);
movmem(last_time,gp->last_time,2);
gp->height=height;
gp->n_groups=n_groups;
gp->sotries=sotries;
movmem(z3env->expath,gp->path,(z3env->expaths)*2);
(z3env->expath)[0]=a_drive;	/* setup alias drive/user */
(z3env->expath)[1]=a_user;
(z3env->expath)[2]=1;		/* setup A0: for bbs re-entry */
(z3env->expath)[3]=0;
(z3env->expath)[4]=0;		/* end of table */

/* save command buffer, away..  4 bytes overhead for info, and buflen+1 */
movmem(savecmd,&(gp->cmdbuf),(unsigned)(z3env->cls+4));

ptr=0;
*ptr=0xc3;	/* make safe to warm boot */

/* now we put location of global save spot in message buffer (0x48/9) */
m_buff=z3env->msg+O.Z3MSG;
*m_buff=z3_hp;	/* global_loc; */		/* save this away */

#ifdef Z3BUG
   printf("Command line buffer (Z3 one) is at %xh.  Contents are '%s'.\n",
	  z3env->cl,z3env->cl->buffer);
   printf("Old contents were '%s'.\n",savecmd->buffer);
#endif

exit(0);	/* and do so */

}	/* routine generally never returns */


/************************************************************
 * Restore values on return from alias... (was in metal.c)
 ************************************************************/

ret_cmd(glob_loc)
 char *glob_loc;
{
struct g_prot *gh_p;	/* header pointer */
struct g_save *gp;	/* global variables pointer */
int size;

gh_p=glob_loc;		/* header loc */
glob_loc=gh_p->g_vars;	/* skip to real fields */

#ifdef Z3BUG
printf("\nglob_loc now=%x   gh_p=%x\n",glob_loc,gh_p);
#endif

movmem(glob_loc,&user,sizeof(user));
glob_loc+=sizeof(user);
gp=glob_loc;	/* get misc. variables area */

#ifdef Z3BUG
printf("\nUser #%d  '%s'  From %s\n",user.number,user.name,user.city);
printf("gp=%x, gp->glbstr=%x  glbstr=%x\n",gp,gp->glbstr,glbstr);
#endif

movmem(gp->glbstr,glbstr,MAXLINE+1);	/* restore command line */

#ifdef Z3BUG
printf("after glbstr move, name='%s'\n",user.name);
#endif

/* msg=gp->msg;	*/	/* restore msg variable pointer */
strloc=gp->strloc;
globalch=gp->globalch;
print_flag=gp->print_flag;
echo_flag=gp->echo_flag;
sepstr=gp->sepstr;
fmsg=gp->fmsg;
lmsg=gp->lmsg;
mindex=gp->mindex;
msgcount=gp->msgcount;
privmsgs=gp->privmsgs;
nextmsg=gp->nextmsg;
totalmsgs=gp->totalmsgs;
callnum=gp->callnum;
movmem(gp->date,date,3);
movmem(gp->time,time,2);
movmem(gp->last_date,last_date,3);
movmem(gp->last_time,last_time,2);
height=gp->height;
n_groups=gp->n_groups;
sotries=gp->sotries;

#ifdef Z3BUG
printf("\nname='%s'  city='%s'...gp=%xh\n",user.name,user.city,gp);
#endif

movmem(gp->path,z3env->expath,(unsigned)(2*z3env->expaths));
movmem(&(gp->cmdbuf),z3env->cl,(unsigned)(z3env->cls+4) );

} /* g_restore */


/*************************************************************************
 *  z3_init() does init stuff for zcpr3 systems..
 *  Like: loading system segments and setting registers..
 ****************/

z3_init(t)
 char *t;
{
static struct seg_type
	{
	int num;	/* segment # offset into sysseg array	*/
	char *type;	/* Filetype to add to file		*/
	}
	segs[] = {
			ENV,".ENV",	NDR,".NDR",	RCP,".RCP",
			FCP,".FCP",	IOP,".IOP",	-1,0		};
int i;
struct seg_type *sp;
u_types *uptr;
char *cp;

send("\n[Initializing Environment]\n");
uptr=user.type_ptr;

/* load system segments.. */

for (sp=segs; (sp->num)>=0; sp++)
	if (*(uptr->sysseg[sp->num]))
		load_seg(uptr->sysseg[sp->num],sp->num,sp->type);

/* Set z3 regsiters.. */

for (i=0; i<10; i++)
	if (uptr->regs[i] & 0xff00) z3env->msg[0x30+i] = uptr->regs[i] &0xff;

/* Put user name in system file name area */

cp=z3env; cp+=0x52+((uptr->sysnum-1)*11);	/* point to system file name */
setmem(cp,11,' ');				/* blank pad */

/*----------Try this-----------*/
movmem(&user.number,cp+8,3);

strncpy(cp,index(user.name,' '),8);

/* Set system path */

if (uptr->path) movmem(uptr->path,z3env->expath,(unsigned)(2*z3env->expaths));

}


load_seg(file,num,ft)
 int num;
 char *file,*ft;
{
char tfile[20],*addr;
FILE *seg_file;

sprintf(tfile,"%s%s",file,ft);
switch (num) {
	case ENV:
		addr=z3env->env;
		break;
	case NDR:
		addr=z3env->ndir;
		break;
	case RCP:
		addr=z3env->rcp;
		break;
	case FCP:
		addr=z3env->fcp;
		break;
	case IOP:
		addr=z3env->iop;
		break;
	} /* switch */


if (seg_file=open(tfile,F_RD))
	{
	for ( ; read(seg_file,1)==128; addr+=128)
		movmem(bufloc(seg_file),addr,128);
	close(seg_file);
	}

} /* load_seg */
		

#endif	/* Z3 */

/* eof.. */

