#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/telnet.h>
#include "struct.h"

int Socket[9];
int MasterSocket;
short SockState[9]={0,0,0,0,0,0,0,0};
char UserCmdLine[9][82];
char PromptLine[9][82];
char SockPos[9];
char OutPos[9];
char OutBuf[9][4096];
char Skippit[9];

int packet_init()
{
	int ct;
	signal(SIGHUP,SIG_IGN);	/* Don't want to die on a lost peer */
	MasterSocket=Make_Socket(7658);
	if(MasterSocket==-1)
	{
		perror("MasterSocket");
		exit(1);
	}
	printf("YAMA revision 1.15 is running\n");
	ct=0;
	while(ct<9)
	{
		Socket[ct]= -1;
		ct++;
	}
	return(1);
}

int ReadData(ct)
int ct;
{
	unsigned char c;
	int e;
/*	printf("Read %d\n",ct);*/
	while(1)
	{
		if((e=recv(Socket[ct],&c,1,0))!=1)
			break;
		if(Skippit[ct])
		{
			Skippit[ct]--;
			continue;
		}
		if(c==IAC)
		{
			Skippit[ct]=2;
			continue;
		}
		if(c=='\r')
		{
			SockPos[ct]=0;
			return(1);
		}
		if(c==8 || c==127 && SockPos[ct])
		{
			UserCmdLine[ct][--SockPos[ct]]=0;
		}
		if(c<32|| c>127)
			continue;
		if(SockPos[ct]==80)
			return(0);
		UserCmdLine[ct][SockPos[ct]++]=c;
		UserCmdLine[ct][SockPos[ct]]=0;
	}
	if(e==0 || (e==-1 && errno!=EWOULDBLOCK))
	{
		return(-1);
	}
	return(0);
}

void PollSocket(ct)
int ct;
{
	int err;
	if(ct==-1)
	{
		int ct=0;
		err=accept(MasterSocket,NULL,NULL);
		if(err==-1)
			return;
		fcntl(err,F_SETFL,O_NDELAY);
		while(ct<9)
		{
			if(Socket[ct]== -1)
				break;
			ct++;
		}
		if(ct==9)
		{
			close(err);
			return;
		}
		Socket[ct]=err;
		OutPos[ct]=0;
		sock_write(ct,"Welcome to YAMA\r\n",17);
		SockState[ct]=1;	/* Must set state before calling Do_Connection as it calls stuff */
		Do_Connection(ct);
		SockPos[ct]=0;
		Skippit[ct]=0;
		strcpy(PromptLine[ct],"By what name shall I call you: ");
		return;
	}
	if(SockState[ct]==1)
	{
		flushout(ct);
		switch(ReadData(ct))
		{
			case 1:	Do_Net_Driver(ct,UserCmdLine[ct]);break;
			case -1:Do_Disconnect(ct);
				close(Socket[ct]);
			        SockState[ct]= 0;
			        Socket[ct]= -1;
				break;
		}
		flushout(ct);
	}
}
	
void Scan_Packets()
{
	int ct= -1;
	struct timeval tv={1,0};
	fd_set rdset,wrset;
	FD_ZERO(&rdset);
	FD_ZERO(&wrset);
	while(ct<9)
	{
		if(SockState[ct]==1)
			FD_SET(Socket[ct],&rdset);
		if(SockState[ct]==1 && OutPos[ct]>0)
			FD_SET(Socket[ct],&wrset);
		ct++;
	}
	FD_SET(MasterSocket,&rdset);
	switch(select(32,&rdset,&wrset,NULL,&tv))
	{
	
		case 0:
			return;
		case -1:perror("select");
			return;
		default:
			ct= -1;
			while(ct<9)
			{
				PollSocket(ct);
				ct++;
			}
	}
}

void WriteToHandle(int u,int c,char *t)
{
	static char echo_off[6]={IAC,WILL,TELOPT_ECHO,IAC,WILL,TELOPT_ECHO};
	static char echo_on[7]={IAC,WONT,TELOPT_ECHO,IAC,WONT,TELOPT_ECHO,'\n'};
	
	if(SockState[u]!=1)
		return;
	switch(c)
	{
		case PK_DISC:
			SockState[u]=2;
			close(Socket[u]);
			Socket[u]= -1;
			break;
		case PK_PRMP:
			strcpy(PromptLine[u],t);
			break;
		case PK_ENAB:
			t=PromptLine[u];
		case PK_TXLN:
			sock_write(u,t,strlen(t));
			if(t!=PromptLine[u])
				sock_write(u,"\r\n",2);
			break;
		case PK_NECH:
			sock_write(u,echo_off,6);
			break;
		case PK_ECHO:
			sock_write(u,echo_on,7);
			break;
		default:break;
	}
}

void say_to_user(int m,tag u,char *t)
{
	WriteToHandle(VAL(u),PK_TXLN,t);
}

int flushout(s)
{
	int done;
	if(Socket[s]==-1)
		return(-1);
	done=write(Socket[s],OutBuf[s],OutPos[s]);
	if(done==-1 && errno!=EWOULDBLOCK)
	{
		SockState[s]=0;
		close(Socket[s]);
		Socket[s]= -1;
		Do_Disconnect(s);
		return(-1);
	}
	OutPos[s]-=done;
	bcopy(OutBuf[s]+OutPos[s],OutBuf[s],OutPos[s]-done);
	return(OutPos[s]);
}

int sock_write(int s,char *buf,int n)
{
	int sent;
	if(flushout(s)>0)
		sent=0;
	else
	{
		sent=write(Socket[s],buf,n);
		if(sent==n)
			return(1);
	}
	if(sent<0)
		sent=0;
	if(OutPos[s]+n-sent>4096)
	{
		Do_Disconnect(s);
		Socket[s]= -1;
		SockState[s]= 0;
		return(-1);
	}
	bcopy(buf+sent,OutBuf[s]+OutPos[s],n-sent);
	OutPos[s]+=sent;
}