/*
 *	DOS Type Front End Handler
 *
 *	Release 5.14	AMIGA & Unix
 *
 *	Keyboard handler based on a routine by Whalemeat
 */

#include <stdio.h>
#include <signal.h>
#ifdef AMIGA
#include <stdlib.h>
#endif
#include <string.h>
#ifdef AMIGA
#include "/communications.h"
#include "/IPC.h"
#else
#include "../communications.h"
#include "../IPC.h"
#endif
#include "Keydef.h"

#define PORT_PATH "MYTHOS"
#define FRONT_CHDIR "MUD:"

char  SysPrompt[128]="By what name shall I call you : ";
short SysEcho=1;
short SysSignal=-1;	/* Unset */
short SysMyCode=-1;	/* Unset */
short SysReadOk=0;	/* Read disabled */
short SysRedraw=0;	/* Redraw control */
PORT *SysMPort=NULL;		
short SysEditing=0;
char SysEditLine[512];	/* Edit Buffer - For Download And Edit */
PORT *DaemonPort=NULL;
short Con_Reading=0;
short Con_Echo=0;
char Con_Prompt[80]="";
short Con_Dirty=0;
short ComInit=0;
char LineBlock[80];
short LinePointer=0;

#define TTY_COOKED 0		/* Terminal Defines */
#define TTY_RAW	   1

extern void initln(),endln();
extern char *getln();

/*
 *	machine dependant tty stuff
 */

#ifdef AMIGA

void SetTerminal(m)
int m;
{
	SetConsoleMode(m);
}

#else

/* Unix version */

void SetTerminal(m)
int m;
{
	if(m==TTY_COOKED)
	{
		RestoreTTY();
	}
	else
	{
		SetTTY();
	}
}

#endif

void HangUp()
{
	extern void WrapUp();
#ifdef SIGHUP
	signal(SIGHUP,SIG_DFL);
#endif
	SetTerminal(TTY_COOKED);
	if(SysMPort!=NULL)
	{
		SendTPacket(PACKET_CLEAR,"hangup");
	}
	if(SysMPort)
	{
		CloseMPort(SysMPort);	/* Dont need delete - temp port anyway*/
	}
	if(DaemonPort)
	{
		CloseMPort(DaemonPort);
	}
	exit(0);
}

void PipeUp()
{
	fprintf(stderr,"Broken pipe - call a plumber!\n");
	WrapUp();
}
	
void WrapUp()			/* Called whenever we exit() */
{
	endln();
	SetTerminal(TTY_COOKED);
	if(SysMPort)
	{
		CloseMPort(SysMPort);	/* Dont need delete - temp port anyway*/
	}
	if(DaemonPort)
	{
		CloseMPort(DaemonPort);
	}
	exit(0);
}

void Show_File(x)
char *x;
{
	char buf[256];
	FILE *f=fopen(x,"r");
	if(f!=NULL)
	{
		while(fgets(buf,255,f)!=NULL)
			fputs(buf,stdout);
		fclose(f);
	}
}

void SetUpDisplay()
{
#ifdef AMIGA
	printf("\032\012\032");	/* USE TERMCAP cl */
#endif
	initln();
}


Con_Write(x)
char *x;
{
	write(fileno(stdout),x,strlen(x));
	return(0);
}

Con_WriteChar(c)
char c;
{
	write(fileno(stdout),&c,1);
	return(0);
}

char readph()
{
	int c;
wt:	c=WaitEvent();
	if(c!=-1)
		return((char)c);
	if(Con_Dirty)
	{
		Con_Dirty=0;
		return((char)tty_what);
	}
	goto wt;
}

void Con_Redraw()
{
	if(!Con_Reading)
		return;
	Con_Dirty=1;
}

#ifndef AMIGA

int dostopped=0;

int DoStopped()
{
	dostopped=1;
	return(1);
}

#endif 

#ifdef UNIX
BleepBleep()
{
	printf("Timeout....\n");
	signal(SIGALRM,WrapUp);
	alarm(5);	/* Allow 5 seconds for the I've died attempt */
	HangUp();	/* Try and report a flop */
}
#endif

int WaitEvent()
{
	static int TimeOut=30;
	static int WaitTime=15;	/* Short login timeout */
	char c=-1;
	int s=SysReadOk;
	SysRedraw=0;
#ifdef UNIX
	if(s==0)
	{
		signal(SIGALRM,BleepBleep);
		alarm(WaitTime);
		WaitTime=60;	/* Afterwards use log timeouts */
		BlockOff(SysMPort);
		BlockOff(DaemonPort);
	}
	else
	{
		BlockOn(SysMPort);
		alarm(0);
	}
#endif
	ProcessPackets();	/* Handle everything which comes in */
	if(SysRedraw) Con_Redraw();	/* Check input lines */
#ifndef AMIGA
	if(s!=SysReadOk)
		return(-1);
#endif
#ifdef AMIGA
	if(s==0)
		Delay(10);
	else
		if(WaitForChar(Input(),200000)==-1)
			read(fileno(stdin),&c,1);
#else
	if(s==0)
	{
		if(TimeOut++>60)
		{
			printf("OVERRUN Timeout..\n");
			HangUp();
			exit(1);
		}
		return(-1);
	}
	else
	{
		TimeOut=0;
		c=getchar();	/* Will be interrupted by timer */
		alarm(0);	/* Alarm Off */
/*		if(dostopped)	/* Set by signal function */
/*			return(-1);*/
		return((int)c);
	}
#endif
	return((int)c);
}

#define prevbuf(x)	(((x)-bufhalf)&bufsiz)
#define nextbuf(x)	(((x)+bufhalf)&bufsiz)

char *backspc,*spc,*buffer;

void initln()
{
	char *s,*bs=(char *)malloc(bufhalf*2+bufsize);
	int i;
	buffer=(spc=s=(backspc=bs)+bufhalf)+bufhalf;
	if(s==0)
	{
		printf("Out Of Memory\n");
		exit(8);
	}
	for(i=0;i++<bufmax;*s++=' ',*bs++='\010');
}

void endln()
{
	if(backspc)
	{
		free(backspc);
		backspc=NULL;	/* Fixed AGC */
	}
}


short C_Posn=0;	/* Used to track for bkspc -> cursor up */

char *getlin(msg,dest,echo,length)
char *msg,*dest;
int echo,length;
{
	char *line,*lin2;
	if(echo==EDITLN&&dest)
	{
/*		printf("EDITING\n");	*/
		getln(dest,LODSTR,length);
	}
	lin2=line=getln(msg,echo,length);
	if(dest)
		while(*dest++=*lin2++);
	return(line);
}

char *shift(buftop,bufend,from,cp,ep,echo)
char *buftop,*bufend,*from,*cp,*ep;
{
	char *tp=buftop;
	while(*tp++=*from++)
		if(tp==bufend)
			break;
	*tp--=0;
	if(echo)
	{
		if(cp>buftop) writeph(backspc,cp-buftop);
		if(tp>buftop) writeph(buftop,tp-buftop);
		if(tp<ep)
		{
			writeph(spc,ep-tp);
			writeph(backspc,ep-tp);
		}
	}
	return(tp);
}

void say(str)
char *str;
{
	if(str)
		writeph(str,strlen(str));
	writeph("\n",1);
}

void prompt(str)
char *str;
{
	if(str)
		writeph(str,strlen(str));
	C_Posn=strlen(str);
}

char *getln(msg,echo,num_char)
char *msg;
int echo,num_char;
{
	static int half;
	char *buftop,*bufend,*cp,*ep,*tp,*tp2,c,cbuf;
	int bufptr=half;
	if(num_char>bufmax||num_char<0) num_char=bufmax-1;
	bufend=(ep=cp=buftop=buffer+(half=nextbuf(half)))+num_char;
	if(echo==LODSTR)
	{
		while(*ep++=*msg++)
			if(ep==bufend)
				break;
		*ep=0;
		return(cp);
	}
	strcpy(Con_Prompt,msg);
	prompt(msg);
	if(echo==EDITLN)
		cp=ep=shift(buftop,bufend,buffer+prevbuf(half),cp,
			    ep,(echo=ECHO));
	for(;;)
	{
		c=readph(&cbuf,1);
		c&=0x7F;
		if(c=='\r'||c=='\n')
		{
			say(NULL);
			break;
		}
		else if(c>=' ' && c<=126)
		{
			if(ep<bufend)
			{
				tp2=tp=ep++;
				while(tp2-->cp) *tp--=*tp2;
				*cp++=c;
				if(echo)
				{
					writeph(tp,ep-tp);
					if(ep>cp)
						writeph(backspc,ep-cp);
				}
			}
			else
				prompt("\007");
		}
		else if(c==tty_del||c==tty_bs)
		{
			if(cp!=buftop)
			{
				cp--;
				if(echo)
				{
					*cp='\010';
					*ep=' ';
					writeph(cp,ep-cp+1);
					writeph(backspc,ep-cp);
				}
				tp2=(tp=cp)+1;
				*ep--=0;
				while(*tp++=*tp2++);
			}
		}
		else if(c==tty_delr)
		{
			if(cp!=ep)
			{
				if(echo)
				{
					*ep=' ';
					writeph(cp+1,ep-cp);
					writeph(backspc,ep-cp);
				}
				tp2=(tp=cp)+1;
				*ep--=0;
				while(*tp++=*tp2++);
			}
		}
		else if(c==tty_tab)
		{
			int z=5-((cp-buftop)%5);
			if(ep+z<bufend)
			{
				ep=(tp=(tp2=ep)-1+z)+1;
				while(tp2--<cp)
					*tp--=*tp2;
				while(tp>=cp)
					*tp--=' ';
				writeph(cp,ep-cp);
				cp+=z;
				writeph(backspc,ep-cp);
			}
			else
				prompt("\007");
		}
		else if(c==tty_left||c==tty_back)
		{
			if(cp!=buftop)
			{
				cp--;
				if(echo)
					writeph(backspc,1);
			}
		}
		else if(c==tty_fwrd)
		{
			if(cp!=ep)
			{
				if(echo)
					writeph(cp,1);
				cp++;
			}
		}
		else if(c==tty_top||c==tty_home)
		{
			if(cp!=buftop)
			{
				if(echo) writeph(backspc,cp-buftop);
				cp=buftop;
			}
		}
		else if(c==tty_end)
		{
			if(cp!=ep)
			{
				if(echo) writeph(cp,ep-cp);
				cp=ep;
			}
		}
		else if(c==tty_rept)
			cp=ep=shift(buftop,bufend,buffer+(bufptr=prevbuf(half)),
				    cp,ep,echo);
		else if(c==tty_prev)
		{
			if((bufptr=prevbuf(bufptr))==half)
				bufptr=prevbuf(bufptr);
			cp=ep=shift(buftop,bufend,buffer+bufptr,cp,ep,echo);
		}
		else if(c==tty_last)
		{
			readph(&c,1);
			c&=0x7f;
			if(c>'0'&&c<'4')
				cp=ep=shift(buftop,bufend,
			buffer+(bufptr=(abs(half-(c-'0')*bufhalf))&bufsiz),
					    cp,ep,echo);
		}
		else if(c==tty_kill)
		{
			if(echo)
			{
				if(cp>buftop)
					writeph(backspc,cp-buftop);
				if(ep>buftop)
				{
					writeph(spc,ep-buftop);
					writeph(backspc,ep-buftop);
				}
			}
			ep=cp=buftop;
		}
		else if(c==tty_what)
		{
			writeph("\r",1);
			prompt(msg);
			if(echo&&ep>buftop)
			{
				writeph(buftop,ep-buftop);
				if(cp<ep)
					writeph(backspc,ep-cp);
			}
		}
		else if(c==tty_quit||c==tty_qut2)
		{
			*bufend='^';
			bufend[1]=c|0x40;
			bufend[2]='\n';
			bufend[3]='\r';
			if(echo&&ep>cp+2)
			{
				writeph(spc,ep-cp);
				writeph(backspc,ep-cp);
			}
			writeph(bufend,4);
			if(c==tty_quit)
				say("*CANCEL*");
			else
				say("*INTERRUPT*");
			prompt(msg);
			if(echo)
			{
				if(ep>buftop)
					writeph(buftop,ep-buftop);
				if(cp<ep)
					writeph(backspc,ep-cp);
			}
		}	
	}
	*ep=0;
	if(echo==NOECHO||ep==buftop) half=prevbuf(half);
	return(buftop);
}

static char OutBuf[128];
static short OutPtr=0;

void bflush()
{
	OutBuf[OutPtr]=0;
	printf("%s",OutBuf);
	OutPtr=0;
}

void bprintc(c)
char c;
{
	OutBuf[OutPtr++]=c;
	if(OutPtr==127)
		bflush();
}

void bprints(s)
unsigned char *s;
{
	while(*s)
		bprintc(*s++);
}

int writeph(string,l)
char *string;
int l;
{
	char c=string[l];
	char *x;
	if(l<1) return(0);
	string[l]=0;
	x=string;
	while(*x)
	{
		if(*x==8)
			C_Posn--;
		if(*x==13||*x==10)
			C_Posn=0;
		if(*x>31)
			C_Posn++;
/*		if(*x==8&&C_Posn==0)
			bprints("\033[\x46\033[76\x48");
		else*/
			bprintc(*x);
		x++;
		if(C_Posn==76)
			C_Posn=0;	/* Set to tty width */
	}
/*	printf("%s",string);	*/
	string[l]=c;
	bflush();
	fflush(stdout);
	return(0);
}

Con_Read(prompt,buffer,length,echoflag)
char *prompt;
char *buffer;
int length;
int echoflag;
{
	int e=NOECHO;
	if(echoflag)
		e=ECHO;
	Con_Echo=echoflag;
	strcpy(Con_Prompt,prompt);
	Con_Reading=1;
	if(SysEditing)
	{
		strcpy(buffer,SysEditLine);
		getlin(Con_Prompt,buffer,EDITLN,490);
	}
	else
		getlin(Con_Prompt,buffer,e,490);
	SysEditing=0;
	Con_Reading=0;
	return(0);
}


char TermBuffer[1024];
char PC=0;
short ospeed=0;
short ttywidth=76;
		
void main(argc,argv)
int argc;
char *argv[];
{
	char buffer[512];
	char *t;
	signal(SIGINT,SIG_IGN);
#ifdef SIGTSTP
	signal(SIGTSTP,SIG_IGN);
#endif
#ifdef SIGQUIT
	signal(SIGQUIT,SIG_IGN);
#endif
#ifdef SIGHUP
	signal(SIGHUP,HangUp);
#endif
#ifdef SIGPIPE
	signal(SIGPIPE,PipeUp);
#endif
#ifdef UNIX
	signal(SIGSEGV,HangUp);
	signal(SIGBUS,HangUp);
	signal(SIGILL,HangUp);
	signal(SIGFPE,HangUp);
	signal(SIGSYS,HangUp);
#endif
	if(chdir(FRONT_CHDIR)==-1)
	{
		fprintf(stderr,"AberMUD seems to be concealed...\n");
		exit(1);
	}
#ifdef UNIX
	if(!isatty(fileno(stdin)))
#else
	if(!IsInteractive(Input()))
#endif
	{
		fprintf(stderr,"There seems to be a terminal redirection problem here.\n");
		exit(1);
	}
	printf("\033[0;0H\033[J");
	fflush(stdout);
	Show_File("motd");
	SetUpDisplay();
	FindDaemon();
	Con_Write("[WAIT]\r");
	HandleLogin();
	SetTerminal(TTY_RAW);
	while(1)
	{
		while(SysReadOk==0)
		{
			WaitEvent();
		}
		Con_Read(SysPrompt,buffer,70,1-SysEcho);
		SendTPacket(PACKET_COMMAND,buffer);
		SysReadOk=0;	/* Disabled automatically by system */
	}	
}

	
InterpretPacket(x)
COMDATA *x;
{
	COMTEXT *y=(COMTEXT *)x;
	switch(x->pa_Type)
	{
		case PACKET_CLEAR:
			
			DoOutput(y->pa_Data);
			DoOutput("\n");
			SendNPacket(PACKET_CLEARED,0,0,0,0);
			WrapUp();
			break;

		case PACKET_LOOPECHO:

			SendNPacket(PACKET_ECHOBACK,0,0,0,0);
			break;

		case PACKET_ECHOBACK:
		
			break;

		case PACKET_OUTPUT:

			DoOutput(y->pa_Data);
			break;

		case PACKET_SETPROMPT:

			strcpy(SysPrompt,y->pa_Data);
			break;

		case PACKET_ECHO:

			SysEcho=x->pa_Data[0];
			break;

		case PACKET_SNOOPTEXT:

			SnoopDriver(y->pa_Data);
			break;

		case PACKET_INPUT:
			
			SysReadOk=x->pa_Data[0];
			break;

		case PACKET_LOGINACCEPT:
		
			SysMyCode=x->pa_Data[1];
			Con_Write("                  \n");
			break;

		case PACKET_EDIT:
			
			SysEditing=1;
			strcpy(SysEditLine,y->pa_Data);
			break;

		case PACKET_SETTITLE:

			break;

		case PACKET_PICTURE:

			break;

		case PACKET_SETFIELD:

			SetField(x->pa_Data[0]);
			break;
	}
	return(0);
}
	



HandleLogin()
{
	char buffer[128];
	SysMPort=CreateMPort(FL_TEMPORARY);
	if(SysMPort==NULL)
	{
		WrapUp();
	}
#ifdef AMIGA
	SysSignal=SysMPort->po_Signal;
#endif
#ifdef AMIGA
	sprintf(buffer,"Someone$%ld",SysMPort);
#else
	sprintf(buffer,"%d$%ld",getuid(),getpid());
#endif
	SendTPacket(PACKET_LOGINREQUEST,buffer);
	return(0);
}

	
SendBlock(block,size)
char *block;
int size;
{
	int er;
#ifndef AMIGA
	BlockOff(DaemonPort);
#endif
	if((er=WriteMPort(DaemonPort,block,size))<0)
	{
		fprintf(stderr,"Port write error :%d\n",er);
		WrapUp();
	}
	return(1);
}
		
SendTPacket(class,data)
short class;
char *data;
{
	COMTEXT a;
	a.pa_Type=class;
	a.pa_Sender=SysMyCode;
	strcpy(a.pa_Data,data);
	return(SendBlock(&a,sizeof(COMTEXT)));
}
	
SendNPacket(class,p1,p2,p3,p4)
short class;
short p1,p2,p3,p4;
{
	COMDATA a;
	a.pa_Type=class;
	a.pa_Sender=SysMyCode;
	a.pa_Data[0]=p1;
	a.pa_Data[1]=p2;
	a.pa_Data[2]=p3;
	a.pa_Data[3]=p4;
	return(SendBlock(&a,sizeof(COMDATA)));
}


static short wptr;

SetField(x)
int x;
{
	while((LinePointer+wptr)%x)
		OutChar(' ');
}

OutChar(x)
char x;
{
	static char WordBuffer[81];
	if((x=='\n')||(x==' ')||(wptr>76))
	{
		WordBuffer[wptr++]=x;
		if(wptr+LinePointer>77)
		{
			LineBlock[LinePointer]=0;
			BlockDoOutput(LineBlock);
			BlockDoOutput("\n");
			LinePointer=0;
		}
		strncpy(LineBlock+LinePointer,WordBuffer,wptr);
		LinePointer+=wptr;
		wptr=0;
	}
	if(x=='\n')
	{
		LineBlock[LinePointer]=0;
		BlockDoOutput(LineBlock);
		LinePointer=0;
		return;
	}
	if(x!=' ')
		WordBuffer[wptr++]=x;
}
	
DoOutput(x)
char *x;
{
	while(*x) OutChar(*x++);
	return(0);
}

BlockDoOutput(x)
char *x;
{
	if((Con_Reading)&&(SysRedraw==0))
	{
		SysRedraw=1;
		Con_Write("\r\
                                                                      \r");
	}
	Con_Write(x);
	return(0);
}

GetPacket(port,packet)
PORT *port;
COMTEXT *packet;
{
	int er;
#ifndef AMIGA
	if(SysReadOk==0)
		BlockOff(port);
	else
		BlockOn(port);
#endif
	if((er=ReadMPort(port,packet))<0)
	{
		if(er==-3||er==-2)
			return(-2);
		fprintf(stderr,"Port read error: %d\n",er);
		WrapUp();
	}
	return(0);
}

ProcessPackets()
{
	int er;
	COMTEXT p;
	while(1)
	{
		er=GetPacket(SysMPort,&p);
		if(er==-2)
			break;
		InterpretPacket((COMDATA *)&p);
	}
	return(0);
}


FindDaemon()
{
	DaemonPort=FindService(PORT_PATH);
	if(DaemonPort)
		DaemonPort=OpenMPort(DaemonPort);	/* Open it */
	if(DaemonPort==NULL)
	{
		fprintf(stderr,"Sorry, AberMUD V is not currently running.\n");
		WrapUp();
	}
	return(0);
}



void OutSnoop(x)
char x;
{
	static char SnoopBuffer[128];
	static char WordBuffer[81];
	static short wptr,SnoopPointer;
	if((x=='\n')||(x==' ')||(wptr>76))
	{
		WordBuffer[wptr++]=x;
		if(wptr+SnoopPointer>77)
		{
			SnoopBuffer[SnoopPointer]=0;
			BlockDoOutput("|");
			BlockDoOutput(SnoopBuffer);
			BlockDoOutput("\n");
			SnoopPointer=0;
		}
		strncpy(SnoopBuffer+SnoopPointer,WordBuffer,wptr);
		SnoopPointer+=wptr;
		wptr=0;
	}
	if(x=='\n')
	{
		SnoopBuffer[SnoopPointer]=0;
		BlockDoOutput("|");
		BlockDoOutput(SnoopBuffer);
		SnoopPointer=0;
		return;
	}
	if(x!=' ')
		WordBuffer[wptr++]=x;
}

SnoopDriver(x)
char *x;
{
	while(*x)
		OutSnoop(*x++);
}