#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>

#include "QtTermTCP.h"

#define _CRT_SECURE_NO_WARNINGS

#define TRUE 1
#define FALSE 0
#define UCHAR unsigned char
#define MAX_PATH 256
#define WCHAR char

#ifndef WIN32
#define strtok_s strtok_r
#endif


typedef unsigned long       DWORD;
typedef int                 BOOL;
typedef unsigned char       BYTE;
typedef unsigned short      WORD;

#define MAXHOSTS 16

#define TCHAR char

void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len);
int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
void SetPortMonLine(int i, char * Text, int visible, int enabled);
void AGW_AX25_data_in(void  * Sess, UCHAR * data, int Len);
int checkUTF8(unsigned char * Msg, int Len, unsigned char * out);
void DoTermResize(Ui_ListenSession * Sess);
void DecodeTeleText(Ui_ListenSession * Sess, char * page);

int Bells = TRUE;
int StripLF = FALSE;
int LogOutput = FALSE;
int SendDisconnected = TRUE;
int ChatMode = TRUE;
int AutoTeletext = 1;

int MonPorts = 1;
int ListenOn = FALSE;

time_t LastWrite = 0xffffffff;
int AlertInterval = 300;
int AlertBeep = TRUE;
int AlertFreq = 600;
int AlertDuration = 250;
TCHAR AlertFileName[256] = { 0 };
int ConnectBeep = TRUE;
int UseKeywords = TRUE;

QString KeyWordsFile = "Keywords.sys";

char ** KeyWords = NULL;
int NumberofKeyWords = 0;


// YAPP stuff

#define SOH 1
#define STX 2
#define ETX 3
#define EOT 4
#define ENQ 5
#define ACK 6
#define DLE	0x10
#define NAK 0x15
#define CAN 0x18

#define YAPPTX	32768					// Sending YAPP file

int MaxRXSize = 100000;
char BaseDir[256] = "";

unsigned char InputBuffer[1024];

char  YAPPPath[MAX_PATH] = "";	// Path for saving YAPP Files

int paclen = 128;

int InputLen;				// Data we have already = Offset of end of an incomplete packet;

unsigned char * MailBuffer;			// Yapp Message being received
int MailBufferSize;
int YAPPLen;				// Bytes sent/received of YAPP Message
long YAPPDate;				// Date for received file - if set enables YAPPC
char ARQFilename[200];		// Filename from YAPP Header

unsigned char SavedData[8192];		// Max receive is 4096 is should never get more that 8k
int SaveLen = 0;

void YAPPSendData(Ui_ListenSession * Sess);


char * strlop(char * buf, char delim)
{
	// Terminate buf at delim, and return rest of string

	char * ptr = strchr(buf, delim);

	if (ptr == NULL) return NULL;

	*(ptr)++ = 0;

	return ptr;
}

#ifdef WIN32

char * strcasestr(char *ch1, char *ch2)
{
	char	*chN1, *chN2;
	char	*chNdx;
	char	*chRet = NULL;

	chN1 = _strdup(ch1);
	chN2 = _strdup(ch2);

	if (chN1 && chN2)
	{
		chNdx = chN1;
		while (*chNdx)
		{
			*chNdx = (char)tolower(*chNdx);
			chNdx++;
		}
		chNdx = chN2;

		while (*chNdx)
		{
			*chNdx = (char)tolower(*chNdx);
			chNdx++;
		}

		chNdx = strstr(chN1, chN2);

		if (chNdx)
			chRet = ch1 + (chNdx - chN1);
	}

	free(chN1);
	free(chN2);
	return chRet;
}

#endif

void GetKeyWordFile()
{
	DWORD FileSize;
	char * ptr1, *ptr2;
	char * KeyWordFile;

	QFile file(KeyWordsFile);
	
	if (!file.open(QIODevice::ReadOnly))
	{
		if (UseKeywords)				// Don't need to alert if not being used
		{
			QMessageBox msgBox;
			msgBox.setText("Keyword File " + KeyWordsFile + " not found");
			msgBox.exec();
		}
		return;
	}

	FileSize = file.size();

	KeyWordFile = (char *)malloc(FileSize + 1);

	file.read(KeyWordFile, FileSize);

	file.close();

	KeyWordFile[FileSize] = 0;
 
	ptr1 = KeyWordFile;

	while (ptr1)
	{
		if (*ptr1 == '\n') ptr1++;

		ptr2 = strtok_s(NULL, "\r\n", &ptr1);
		if (ptr2)
		{
			if (*ptr2 != '#')
			{
				KeyWords = (char **)realloc(KeyWords, (++NumberofKeyWords + 1) * 4);
				KeyWords[NumberofKeyWords] = ptr2;
			}
		}
		else
			break;
	}
}


int CheckKeyWord(char * Word, char * Msg)
{
	char * ptr1 = Msg, *ptr2;
	int len = (int)strlen(Word);

	while (*ptr1)					// Stop at end
	{
		ptr2 = strcasestr(ptr1, Word);

		if (ptr2 == NULL)
			return FALSE;				// OK

		// Only bad if it ia not part of a longer word

		if ((ptr2 == Msg) || !(isalpha(*(ptr2 - 1))))	// No alpha before
			if (!(isalpha(*(ptr2 + len))))			// No alpha after
				return TRUE;					// Bad word

		// Keep searching

		ptr1 = ptr2 + len;
	}

	return FALSE;					// OK
}

int CheckKeyWords(UCHAR * Msg, int len)
{
	int i;

	if (UseKeywords == 0 || NumberofKeyWords == 0)
		return FALSE;

	// we need to null terminate Msg, so create a copy

	unsigned char * copy = (unsigned char *)malloc(len + 1);

	memcpy(copy, Msg, len);
	copy[len] = 0;

	for (i = 1; i <= NumberofKeyWords; i++)
	{
		if (CheckKeyWord(KeyWords[i], (char *)copy))
		{
			myBeep(&AlertWAV);
			free (copy);
			return TRUE;			// Alert
		}
	}

	free(copy);
	return FALSE;					// OK

}


void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len)
{
	int MonLen = 0;
	unsigned char * ptr;
	unsigned char * Buffptr;
	unsigned char * FEptr = 0;

	if (Sess->InputMode == 'Y')			// Yapp
	{
		ProcessYAPPMessage(Sess, Buffer, len);
		return;
	}

	// See if Teletext data

			// We need to identify a viewdata frame. Seems to start

		//1e 0a 0a 0a 0a 0a 0a 0a  0a 0a 0a 0a 0a 0a 0a 0a   ........ ........
			//00000170  0a 0a 0a 0a 0a 0a 0a 0a  11 0c 1b

		// Page seems to start 1c

		// After page get 

		//1e 0a 0a 0a 0a 0a 0a 0a  0a 0a 0a 0a 0a 0a 0a 0a   ........ ........
		//	0000049D  0a 0a 0a 0a 0a 0a 0a 0a  11 14 1b 44 1b 5d 1b 43   ........ ...D.].C
		//	000004AD  53 65 6c 65                                        Sele
		//	000004B1  63 74 20 69 74 65 6d 20  6f 72 1b 47 2a 70 61 67   ct item or .G*pag
		//	000004C1  65 5f 20 3a 20 20 20 20  20 20 20 20 20 20 20 20   e_ :
		//	000004D1  20 0d 09 09 09 09 09 09  09 09 09 09 09 09 09 09    ....... ........
		//	000004E1  09 09 09 09 09 09 09 09  09 09 09 09 09 11

	Buffer[len] = 0;

	if (AutoTeletext && (Buffer[0] == 0x1e || Buffer[0] == 0x0c))
	{
		if (Sess->TTActive == 0)
		{
			Sess->TTActive = 1;
			DoTermResize(Sess);
		}
	}

	if (Sess->TTActive)
	{
		// Feed to Teletext code

		// We need to decode a whole page. There is no obvious delimiter so process till data stops.
		// Buffer is cleared when next input is sent

		if (strlen(&Sess->pageBuffer[0] + len) > 4090)
			Sess->pageBuffer[0] = 0;							// Protect buffer

		strcat(Sess->pageBuffer, (char *)Buffer);

		DecodeTeleText(Sess, (char *)Sess->pageBuffer);			// Re-decode same data until we get the end
		return;
	}



	//	mbstowcs(Buffer, BufferB, len);

	// Look for MON delimiters (FF/FE)


	Buffptr = Buffer;

	if (Sess->MonData)
	{
		// Already in MON State

		FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);

		if (!FEptr)
		{
			// no FE - so send all to monitor

			WritetoMonWindow(Sess, Buffer, len);
			return;
		}

		Sess->MonData = FALSE;

		MonLen = FEptr - Buffptr;		// Mon Data, Excluding the FE

		WritetoMonWindow(Sess, Buffptr, MonLen);

		Buffptr = ++FEptr;				// Char following FE

		if (++MonLen < len)
		{
			len -= MonLen;
			goto MonLoop;				// See if next in MON or Data
		}

		// Nothing Left

		return;
	}

MonLoop:

	ptr = (UCHAR *)memchr(Buffptr, 0xff, len);

	if (ptr)
	{
		unsigned char telcmd[] = "\xff\xfb\x03\xff\xfb\x01";

		// Try to trap connect to normal Telnet Port

		if (memcmp(ptr, telcmd, 6) == 0)
			return;

		// Buffer contains Mon Data

		if (ptr > Buffptr)
		{
			// Some Normal Data before the FF

			int NormLen = ptr - Buffptr;				// Before the FF

			if (NormLen == 1 && Buffptr[0] == 0)
			{
				// Keepalive
			}

			else
			{
				CheckKeyWords(Buffptr, NormLen);
				WritetoOutputWindow(Sess, Buffptr, NormLen);
			}

			len -= NormLen;
			Buffptr = ptr;
			goto MonLoop;
		}

		if (ptr[1] == 0xff)
		{
			// Port Definition String

			int NumberofPorts = atoi((char *)&ptr[2]);
			char *p, *Context;
			int i = 1;
			TCHAR msg[80];
			int portnum;
			char delim[] = "|";
			int m;

			// Save for changes of Window

			if (len < 2048)
				memcpy(Sess->PortMonString, ptr, len);

			
			// Remove old menu
			
			for (i = 0; i < 65; i++)
			{
				SetPortMonLine(i, (char *)"", 0, 0);
			}

			p = strtok_s((char *)&ptr[2], delim, &Context);

			while (NumberofPorts--)
			{
				p = strtok_s(NULL, delim, &Context);
				if (p == NULL)
					break;

				m = portnum = atoi(p);
				sprintf(msg, "Port %s", p);

				if (m == 0)
					m = 64;

				if (Sess->portmask & (1ll << (m - 1)))
					SetPortMonLine(portnum, msg, 1, 1);
				else
					SetPortMonLine(portnum, msg, 1, 0);
			}
			return;
		}

		MonLen = len;				// in case no fe

		Sess->MonData = 1;

		FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);

		if (FEptr)
		{
			Sess->MonData = 0;

			MonLen = FEptr + 1 - Buffptr;				// MonLen includes FF and FE

			WritetoMonWindow(Sess, Buffptr + 1, MonLen - 2);

			len -= MonLen;
			Buffptr += MonLen;							// Char Following FE

			if (len <= 0)
			{
				return;
			}
			goto MonLoop;
		}
		else
		{
			// No FE, so rest of buffer is MON Data

			if (MonLen)
				WritetoMonWindow(Sess, Buffptr + 1, MonLen - 1);
			return;
		}
	}

	// No FF, so must be session data

	if (Sess->InputMode == 'Y')			// Yapp
	{
		ProcessYAPPMessage(Sess, Buffer, len);
		return;
	}


	if (len == 1 && Buffptr[0] == 0)
		return;							// Keepalive

	// Could be a YAPP Header

	if (len == 2 && Buffptr[0] == ENQ && Buffptr[1] == 1)		// YAPP Send_Init
	{
		char YAPPRR[2];

		// Turn off monitoring

		setTraceOff(Sess);
		
		Sess->InputMode = 'Y';

		YAPPRR[0] = ACK;
		YAPPRR[1] = 1;

		SocketFlush(Sess);			// To give Monitor Msg time to be sent
		mySleep(1000);
		QueueMsg(Sess, YAPPRR, 2);

		return;
	}
	// Check UTF8
	{
		CheckKeyWords(Buffptr, len);
		WritetoOutputWindow(Sess, Buffptr, len);
	}
	Sess->SlowTimer = 0;
	return;
}

extern myTcpSocket * VARASock;
extern myTcpSocket * VARADataSock;
extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len);

int SendMsg(Ui_ListenSession * Sess, TCHAR * Buffer, int len)
{
	if (Sess->KISSSession)
	{
		// Send to ax.25 code

		SendtoAX25(Sess->KISSSession, (unsigned char *)Buffer, len);
		return len;
	}
	else if (Sess->AGWSession)
	{
		// Terminal is in AGWPE mode - send as AGW frame

		AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Buffer, len);
		return len;
	}
	else if (VARASock && VARASock->Sess == Sess)
	{
		VARADataSock->write(Buffer, len);
		return len;
	}

	return SocketSend(Sess, Buffer, len);
}



void QueueMsg(Ui_ListenSession * Sess, char * Msg, int len)
{
	int Sent = SendMsg(Sess, Msg, len);

	if (Sent != len)
		Sent = 0;
}

int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);

int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
{
	// may have saved data

	memcpy(&SavedData[SaveLen], Msg, Len);

	SaveLen += Len;

	while (SaveLen && Sess->InputMode == 'Y')
	{
		int Used = InnerProcessYAPPMessage(Sess, SavedData, SaveLen);

		if (Used == 0)
			return 0;			// Waiting for more

		SaveLen -= Used;

		if (SaveLen)
			memmove(SavedData, &SavedData[Used], SaveLen);
	}
	return 0;
}

extern int VARAEnable;

int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
{
	int pktLen = Msg[1];
	char Reply[2] = { ACK };
	size_t NameLen, SizeLen, OptLen;
	char * ptr;
	int FileSize;
	WCHAR MsgFile[MAX_PATH];
	FILE * hFile;
	char Mess[255];
	int len;
	UCHAR Buffer[2000];
	struct stat STAT;

	switch (Msg[0])
	{
	case ENQ: // YAPP Send_Init

		// Shouldn't occur in session. Reset state and process

		if (MailBuffer)
		{
			free(MailBuffer);
			MailBufferSize = 0;
			MailBuffer = 0;
		}

		Mess[0] = ACK;
		Mess[1] = 1;

		Sess->InputMode = 'Y';
		QueueMsg(Sess, Mess, 2);

		// Turn off monitoring

		mySleep(1000);				// To give YAPP Msg time to be sent

		setTraceOff(Sess);

		return Len;

	case SOH:

		// HD Send_Hdr     SOH  len  (Filename)  NUL  (File Size in ASCII)  NUL (Opt) 

		// YAPPC has date/time in dos format

		if (Len < Msg[1] + 1)
			return 0;				// Wait till we have it all

		NameLen = strlen((char *)&Msg[2]);
		strcpy(ARQFilename, (char *)&Msg[2]);

		ptr = (char *)&Msg[3 + NameLen];
		SizeLen = strlen(ptr);
		FileSize = atoi(ptr);

		OptLen = pktLen - (NameLen + SizeLen + 2);

		YAPPDate = 0;

		if (OptLen >= 8)		// We have a Date/Time for YAPPC
		{
			ptr = ptr + SizeLen + 1;
			YAPPDate = strtol(ptr, NULL, 16);
		}

		// Check Size

		if (FileSize > MaxRXSize && VARAEnable == 0)
		{
			Mess[0] = NAK;
			Mess[1] = sprintf(&Mess[2], "File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
			mySleep(1000);				// To give YAPP Msg time to be sent
			QueueMsg(Sess, Mess, Mess[1] + 2);

			len = sprintf((char *)Buffer, "YAPP File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
			WritetoOutputWindow(Sess, Buffer, len);

			Sess->InputMode = 0;
			SendTraceOptions(Sess);

			return Len;
		}

		// Check that Path is set

		if (YAPPPath[0] == 0)
		{
			Mess[0] = NAK;
			Mess[1] = sprintf(&Mess[2], "%s", "YAPP Receive directory not set");
			mySleep(1000);				// To give YAPP Msg time to be sent
			QueueMsg(Sess, Mess, Mess[1] + 2);
			len = sprintf((char *)Buffer, "YAPP File Receive Failed - YAPP Receive directory not set\r");
			WritetoOutputWindow(Sess, Buffer, len);

			Sess->InputMode = 0;
			SendTraceOptions(Sess);

			return Len;
		}

		// Make sure file does not exist

		sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);

		if (stat(MsgFile, &STAT) == 0)
		{
			FileSize = STAT.st_size;

			Mess[0] = NAK;
			Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists");
			mySleep(1000);				// To give YAPP Msg time to be sent
			QueueMsg(Sess, Mess, Mess[1] + 2);
			len = sprintf((char *)Buffer, "YAPP File Receive Failed - %s already exists\r", MsgFile);
			WritetoOutputWindow(Sess, Buffer, len);

			Sess->InputMode = 0;
			SendTraceOptions(Sess);

			return Len;
		}


		MailBufferSize = FileSize;
		MailBuffer = (UCHAR *)malloc(FileSize);
		YAPPLen = 0;

		if (YAPPDate)			// If present use YAPPC
			Reply[1] = ACK;			//Receive_TPK
		else
			Reply[1] = 2;			//Rcv_File

		QueueMsg(Sess, Reply, 2);

		len = sprintf((char *)Buffer, "YAPP Receving File %s size %d\r", ARQFilename, FileSize);
		WritetoOutputWindow(Sess, Buffer, len);

		return Len;

	case STX:

		// Data Packet

		// Check we have it all

		if (YAPPDate)			// If present use YAPPC so have checksum
		{
			if (pktLen > (Len - 3))		// -2 for header and checksum
				return 0;				// Wait for rest
		}
		else
		{
			if (pktLen > (Len - 2))		// -2 for header
				return 0;				// Wait for rest
		}

		// Save data and remove from buffer

		// if YAPPC check checksum

		if (YAPPDate)
		{
			UCHAR Sum = 0;
			int i;
			UCHAR * uptr = &Msg[2];

			i = pktLen;

			while (i--)
				Sum += *(uptr++);

			if (Sum != *uptr)
			{
				// Checksum Error

				Mess[0] = CAN;
				Mess[1] = sprintf(&Mess[2], "YAPPC Checksum Error");
				QueueMsg(Sess, Mess, Mess[1] + 2);

				len = sprintf((char *)Buffer, "YAPPC Checksum Error on file %s\r", MsgFile);
				WritetoOutputWindow(Sess, Buffer, len);

				Sess->InputMode = 0;
				SendTraceOptions(Sess);
				return Len;
			}
		}

		if ((YAPPLen) + pktLen > MailBufferSize)
		{
			// Too Big ??

			Mess[0] = CAN;
			Mess[1] = sprintf(&Mess[2], "YAPP Too much data received");
			QueueMsg(Sess, Mess, Mess[1] + 2);

			len = sprintf((char *)Buffer, "YAPP Too much data received on file %s\r", MsgFile);
			WritetoOutputWindow(Sess, Buffer, len);

			Sess->InputMode = 0;
			SendTraceOptions(Sess);
			return Len;
		}


		memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen);
		YAPPLen += pktLen;

		if (YAPPDate)
			++pktLen;				// Add Checksum

//		if (YAPPLen == MailBufferSize)
//			pktLen = pktLen;

		return pktLen + 2;

	case ETX:

		// End Data

		if (YAPPLen == MailBufferSize)
		{
			// All received

			int Written = 0;

			sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);

			hFile = fopen(MsgFile, "wb");

			if (hFile)
			{
				Written = (int)fwrite(MailBuffer, 1, YAPPLen, hFile);
				fclose(hFile);

				if (YAPPDate)
				{
//					struct tm TM;
//					struct timeval times[2];
					/*
										The MS-DOS date. The date is a packed value with the following format.

										cant use DosDateTimeToFileTime on Linux

										Bits	Description
										0-4	Day of the month (1–31)
										5-8	Month (1 = January, 2 = February, and so on)
										9-15	Year offset from 1980 (add 1980 to get actual year)
										wFatTime
										The MS-DOS time. The time is a packed value with the following format.
										Bits	Description
										0-4	Second divided by 2
										5-10	Minute (0–59)
										11-15	Hour (0–23 on a 24-hour clock)
					*/
					/*
				
					memset(&TM, 0, sizeof(TM));

					TM.tm_sec = (YAPPDate & 0x1f) << 1;
					TM.tm_min = ((YAPPDate >> 5) & 0x3f);
					TM.tm_hour = ((YAPPDate >> 11) & 0x1f);

					TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
					TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
					TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;

					Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec);

					times[0].tv_sec = times[1].tv_sec = mktime(&TM);
					times[0].tv_usec = times[1].tv_usec = 0;
						*/
				}
			}


			free(MailBuffer);
			MailBufferSize = 0;
			MailBuffer = 0;

			if (Written != YAPPLen)
			{
				Mess[0] = CAN;
				Mess[1] = sprintf(&Mess[2], "Failed to save YAPP File");
				QueueMsg(Sess, Mess, Mess[1] + 2);

				len = sprintf((char *)Buffer, "Failed to save YAPP File %s\r", MsgFile);
				WritetoOutputWindow(Sess, Buffer, len);

				Sess->InputMode = 0;
				SendTraceOptions(Sess);
			}
		}

		Reply[1] = 3;		//Ack_EOF
		QueueMsg(Sess, Reply, 2);

		len = sprintf((char *)Buffer, "Reception of file %s complete\r", MsgFile);
		WritetoOutputWindow(Sess, Buffer, len);

		return Len;

	case EOT:

		// End Session

		Reply[1] = 4;		// Ack_EOT
		QueueMsg(Sess, Reply, 2);
		SocketFlush(Sess);
		Sess->InputMode = 0;

		SendTraceOptions(Sess);
		return Len;

	case CAN:

		// Abort

		Mess[0] = ACK;
		Mess[1] = 5;			// CAN Ack
		QueueMsg(Sess, Mess, 2);

		if (MailBuffer)
		{
			free(MailBuffer);
			MailBufferSize = 0;
			MailBuffer = 0;
		}

		// May have an error message

		len = Msg[1];

		if (len)
		{
			len = sprintf((char *)Buffer, "YAPP Transfer cancelled - %s\r", &Msg[2]);
		}
		else
			len = sprintf(Mess, "YAPP Transfer cancelled\r");

		Sess->InputMode = 0;
		SendTraceOptions(Sess);

		return Len;

	case ACK:

		switch (Msg[1])
		{
			char * ptr;

		case 1:					// Rcv_Rdy

			// HD Send_Hdr     SOH  len  (Filename)  NUL  (File Size in ASCII)  NUL (Opt)

			// Remote only needs filename so remove path

			ptr = ARQFilename;

			while (strchr(ptr, '/'))
				ptr = strchr(ptr, '/') + 1;

			len = (int)strlen(ptr) + 3;

			strcpy(&Mess[2], ptr);
			len += sprintf(&Mess[len], "%d", MailBufferSize);
			len++;					// include null
//			len += sprintf(&Mess[len], "%8X", YAPPDate);
//			len++;					// include null
			Mess[0] = SOH;
			Mess[1] = len - 2;

			QueueMsg(Sess, Mess, len);

			return Len;

		case 2:

			YAPPDate = 0;				// Switch to Normal (No Checksum) Mode

			// Drop through

		case 6:							// Send using YAPPC

			//	Start sending message

			YAPPSendData(Sess);
			return Len;

		case 3:

			// ACK EOF - Send EOT

			Mess[0] = EOT;
			Mess[1] = 1;
			QueueMsg(Sess, Mess, 2);

			return Len;

		case 4:

			// ACK EOT

			Sess->InputMode = 0;
			SendTraceOptions(Sess);

			len = sprintf((char *)Buffer, "File transfer complete\r");
			WritetoOutputWindow(Sess, Buffer, len);
	

			return Len;

		default:
			return Len;

		}

	case NAK:

		// Either Reject or Restart

		// RE Resume       NAK  len  R  NULL  (File size in ASCII)  NULL

		if (Len > 2 && Msg[2] == 'R' && Msg[3] == 0)
		{
			int posn = atoi((char *)&Msg[4]);

			YAPPLen += posn;
			MailBufferSize -= posn;

			YAPPSendData(Sess);
			return Len;

		}

		// May have an error message

		len = Msg[1];

		if (len)
		{
			char ws[256];

			Msg[len + 2] = 0;

			strcpy(ws, (char *)&Msg[2]);

			len = sprintf((char *)Buffer, "File rejected - %s\r", ws);
		}
		else
			len = sprintf((char *)Buffer, "File rejected\r");

		WritetoOutputWindow(Sess, Buffer, len);
	

		Sess->InputMode = 0;
		SendTraceOptions(Sess);

		return Len;

	}

	len = sprintf((char *)Buffer, "Unexpected message during YAPP Transfer. Transfer cancelled\r");
	WritetoOutputWindow(Sess, Buffer, len);
	
	Sess->InputMode = 0;
	SendTraceOptions(Sess);

	return Len;

}

void YAPPSendFile(Ui_ListenSession * Sess, WCHAR * FN)
{
	int FileSize = 0;
	char MsgFile[MAX_PATH];
	FILE * hFile;
	struct stat STAT;
	UCHAR Buffer[2000];
	int Len;

	strcpy(MsgFile, FN);

	if (MsgFile[0] == 0)
	{
		Len = sprintf((char *)Buffer, "Filename missing\r");
		WritetoOutputWindow(Sess, Buffer, Len);
	
		SendTraceOptions(Sess);

		return;
	}

	if (stat(MsgFile, &STAT) != -1)
	{
		FileSize = STAT.st_size;

		hFile = fopen(MsgFile, "rb");

		if (hFile)
		{
			char Mess[255];
//			time_t UnixTime = STAT.st_mtime;

//			FILETIME ft;
//			long long ll;
//			SYSTEMTIME st;
//			WORD FatDate;
//			WORD FatTime;
//			struct tm TM;

			strcpy(ARQFilename, MsgFile);

			if (MailBuffer)
			{
				free(MailBuffer);
				MailBufferSize = 0;
				MailBuffer = 0;
			}

			MailBuffer = (UCHAR *)malloc(FileSize);
			MailBufferSize = FileSize;
			YAPPLen = 0;
			fread(MailBuffer, 1, FileSize, hFile);

			// Get Date and Time for YAPPC Mode

/*					The MS-DOS date. The date is a packed value with the following format.

					cant use DosDateTimeToFileTime on Linux

					Bits	Description
					0-4	Day of the month (1–31)
					5-8	Month (1 = January, 2 = February, and so on)
					9-15	Year offset from 1980 (add 1980 to get actual year)
					wFatTime
					The MS-DOS time. The time is a packed value with the following format.
					Bits	Description
					0-4	Second divided by 2
					5-10	Minute (0–59)
					11-15	Hour (0–23 on a 24-hour clock)

					memset(&TM, 0, sizeof(TM));

					TM.tm_sec = (YAPPDate & 0x1f) << 1;
					TM.tm_min = ((YAPPDate >> 5) & 0x3f);
					TM.tm_hour =  ((YAPPDate >> 11) & 0x1f);

					TM.tm_mday =  ((YAPPDate >> 16) & 0x1f);
					TM.tm_mon =  ((YAPPDate >> 21) & 0xf) - 1;
					TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;


// Note that LONGLONG is a 64-bit value

			ll = Int32x32To64(UnixTime, 10000000) + 116444736000000000;
			ft.dwLowDateTime = (DWORD)ll;
			ll >>= 32;
			ft.dwHighDateTime = (DWORD)ll;

			FileTimeToSystemTime(&ft, &st);
			FileTimeToDosDateTime(&ft, &FatDate, &FatTime);

			YAPPDate = (FatDate << 16) + FatTime;

			memset(&TM, 0, sizeof(TM));

			TM.tm_sec = (YAPPDate & 0x1f) << 1;
			TM.tm_min = ((YAPPDate >> 5) & 0x3f);
			TM.tm_hour = ((YAPPDate >> 11) & 0x1f);

			TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
			TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
			TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
*/
			fclose(hFile);

			Mess[0] = ENQ;
			Mess[1] = 1;

			QueueMsg(Sess, Mess, 2);
			Sess->InputMode = 'Y';

			Len = sprintf((char *)Buffer, "Sending File %s ...\r", FN);
			WritetoOutputWindow(Sess, Buffer, Len);

			return;
		}
	}

	Len = sprintf((char *)Buffer, "File %s not found\r", FN);
	WritetoOutputWindow(Sess, Buffer, Len);

}

void YAPPSendData(Ui_ListenSession * Sess)
{
	char Mess[258];

	while (1)
	{
		int Left = MailBufferSize;

		if (Left == 0)
		{
			// Finished - send End Data

			Mess[0] = ETX;
			Mess[1] = 1;

			QueueMsg(Sess, Mess, 2);

			break;
		}

		if (Left > paclen - 3)		// two bytes header and possible checksum
			Left = paclen - 3;

		memcpy(&Mess[2], &MailBuffer[YAPPLen], Left);

		YAPPLen += Left;
		MailBufferSize -= Left;

		// if YAPPC add checksum

		if (YAPPDate)
		{
			UCHAR Sum = 0;
			int i;
			UCHAR * uptr = (UCHAR *)&Mess[2];

			i = Left;

			while (i--)
				Sum += *(uptr++);

			*(uptr) = Sum;

			Mess[0] = STX;
			Mess[1] = Left;

			QueueMsg(Sess, Mess, Left + 3);
		}
		else
		{
			Mess[0] = STX;
			Mess[1] = Left;

			QueueMsg(Sess, Mess, Left + 2);
		}
	}
}

