/*
 *	DOS Type Front End Handler
 *
 *	Release 5.21	AMIGADOS
 *			BSX is enabled by using the -b flag. This is intended
 *			for remote BSX processing.
 *
 *
 *	Keyboard handler based on a routine by Whalemeat
 */

#include <stdio.h>
#include <signal.h>
#ifdef AMIGA
#include <stdlib.h>
#include <string.h>
#endif
#define NO_USERID
#include "Keydefs.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <pragmas/socket_pragmas.h>

char  SysPrompt[128]="By what 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 */
int Socket= -1;
short SysEditing=0;
char SysEditLine[512];	/* Edit Buffer - For Download And Edit */
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;
int  DoingBSX=0;

long SocketBase;


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

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

/*
 *	machine dependant tty stuff
 */


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

		
void WrapUp()			/* Called whenever we exit() */
{
	endln();
	SetTerminal(TTY_COOKED);
	if(Socket!= -1)
		CloseSocket(Socket);
	if(SocketBase!=NULL)
		CloseLibrary(SocketBase);
	exit(0);
}


void SetUpDisplay()
{
	printf("\033[0;0H\033[2J");	/* USE TERMCAP cl entry!!! */
	printf("Creator Of Legends:: Release 5.21.5\n(C) 1987-93 Alan Cox\n\
	Use of this software for commercial gain is prohibited.\n\n");
	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;
}

/* This is used by the FD_ZERO macro (sigh!) */

void bzero(void *p,int n)
{
	memset(p,'\0',n);
}

int WaitEvent()
{
	char c=-1;
	int orok=SysReadOk;
	SysRedraw=0;
	if(SysReadOk==0)
	{
		fd_set rfm;
		FD_ZERO(&rfm);
		FD_SET(Socket,&rfm);
		WaitSelect(32,&rfm,NULL,NULL,NULL,NULL);
	}
	if(ProcessPackets()==-1)	/* Handle everything which comes in */
		exit(0);
	if(SysRedraw) Con_Redraw();	/* Check input lines */

	if(orok==0)
		return(-1);
	if(WaitForChar(Input(),200000)==-1)
		read(fileno(stdin),&c,1);
	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 */
	}
}


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));
}

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')
		{
			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);
}

int writeph(string,l)
char *string;
int l;
{
	char c=string[l];
	if(l<1) return(0);
	string[l]=0;
	printf("%s",string);
	string[l]=c;
	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=79;
		
void main(argc,argv)
int argc;
char *argv[];
{
	char buffer[512];
	int port=5001;
	char *host="localhost";
	if(argc>3)
	{
		fprintf(stderr,"%s [host [port]]\n",argv[0]);
		exit(1);
	}
	if(argc>1)
		host=argv[1];
	if(argc==3)
		sscanf(argv[2],"%d",&port);
	SocketBase=OpenLibrary("bsdsocket.library",0);
	if(SocketBase==NULL)
	{
		fprintf(stderr,"AmiTCP is not running.\n");
		exit(1);
	}
	SetUpDisplay();
	FindDaemon(port,host);
	Con_Write("\n\n\n\n[WAIT]\r");
	HandleLogin();
	SetTerminal(TTY_RAW);
	while(1)
	{
		while(SysReadOk==0)
		{
			WaitEvent();
		}
		Con_Read(SysPrompt,buffer,70,1-SysEcho);
		SendPacket(buffer);
		SysReadOk=0;	/* Disabled automatically by system */
	}	
}

	
InterpretPacket(x)
char *x;
{
/*	printf("Handling Event %c\n",*x);*/
	switch(*x)
	{
		case 'P':
			strcpy(SysPrompt,x+1);
			break;

		case 'E':

			SysEcho=x[1]=='Y'?1:0;
			break;

		case 'S':

			SnoopDriver(x+1);
			break;

		case 'G':
			
/*			printf("Got a goahead\n");*/
			SysReadOk=1;
			break;

		case 'T':
			
			SysEditing=1;
			strcpy(SysEditLine,x+1);
			break;
	}
	return(0);
}
	


HandleLogin()
{
	return(0);
}

	
SendPacket(data)
char *data;
{
	int one=1;
	int zero=0;
	ioctl(Socket,FIONBIO,&zero);
	if(send(Socket,data,strlen(data),0)!=strlen(data))
		exit(1);
	if(send(Socket,"\r\n",2,0)!=2)
		exit(1);
	ioctl(Socket,FIONBIO,&one);
}
	

void OutChar(x)
char x;
{
	static char WordBuffer[81];
	static short wptr;
	if((x=='\n')||(x==' ')||(wptr>79))
	{
		WordBuffer[wptr++]=x;
		if(wptr+LinePointer>79)
		{
			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);
}

ProcessPackets()
{
	static int mode=0;
	static char collect[512];
	static int colptr=0;
	char buf[512];
	int l,ct;
	while(1)
	{
		char *bp=buf;

		l=recv(Socket,buf,512,0);
		if(l==0 || (l==-1 && Errno()!=EWOULDBLOCK))
		{
			if(l==0)
				return(-1);
			if(Errno()!=35 && l==-1)
				printf("Got error %ld on socket %d\n",Errno(),Socket);
		}
		if(l<1)
		{
/*			printf("Got %d bytes\n",l);*/
			break;
		}
		ct=0;
/*		printf("Got %d bytes\n",l);*/
		while(ct<l)
		{
			if(mode==0)
			{
				if(*bp==2)
				{
/*					printf("SEQUENCE BEGIN\n");*/
					colptr=0;
					mode=1;
				}
				else
					OutChar(*bp);
			}
			else
			{
				if(colptr==0)
				{
					collect[colptr++]=*bp;
/*					printf("Event %c\n",*bp);*/
					if(*bp=='Q')
						exit(0);
					if(*bp=='G')
					{
						mode=0;
						SysReadOk=1;
/*						printf("Got a goahead\n");*/
					}
				}
				else
				{		
					if(*bp==3)
					{
						collect[colptr]=0;
						mode=0;
						InterpretPacket(collect);
					}
					else
					{
						collect[colptr++]=*bp;
						if(collect[0]=='E'&&colptr==2)
						{
							mode=0;
							InterpretPacket(collect);
						}
					}
				}
			}
			bp++;
			ct++;
		}
	}
	return(0);
}


FindDaemon(int port, char *host)
{
	Socket=Make_Connection(port,host);
	return(Socket);
}



void OutSnoop(x)
char x;
{
	static char SnoopBuffer[128];
	static char WordBuffer[81];
	static short wptr,SnoopPointer;
	if((x=='\n')||(x==' ')||(wptr>79))
	{
		WordBuffer[wptr++]=x;
		if(wptr+SnoopPointer>79)
		{
			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++);
}
	
