/*************************************************************
* vt100 terminal emulator - XMODEM protocol support
*    v1.0  DBW   860621   Dave Wecker
*************************************************************/

#define MODULE_XMODEM 1
#include "vt100.h"

/************************************************************
* Send a string (using sendchar below)
************************************************************/

sendstring(s)
char *s;
    {
    char c;

    while ((c = *s++) != '\000') sendchar(c);
    }

/**************************************************************/
/* send char and read char functions for the xmodem function */
/************************************************************/
sendchar(ch)
int ch;
    {
    rs_out[0] = ch;
    DoIO(Write_Request);
    }

readchar()
    {
    unsigned char c;
    int rd,ch;

    rd = FALSE;

    while (rd == FALSE)
	{
	Wait((1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) | ( 1L << mywindow->UserPort->mp_SigBit));
	if(CheckIO(Read_Request))
	    {
	    WaitIO(Read_Request);
	    ch=rs_in[0];
	    rd = TRUE;
	    BeginIO(Read_Request);
	    }
	if (NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort))
	if ((NewMessage->Class) == RAWKEY)
	if ((NewMessage->Code) == 69)
	    {
	    emits("\nUser Cancelled Transfer");
	    break;
	    }
	}
    if (rd == FALSE)
	{
	timeout = TRUE;
	emits("\nTimeout Waiting For Character\n");
	}
    c = ch;
    return(c);
    }

/**************************************/
/* xmodem send and recieve functions */
/************************************/

XMODEM_Read_File(file)
char *file;
    {
    int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag,
	findtype, exe;
    unsigned int checksum, j, bufptr,i;
    char numb[10];
    bytes_xferred = 0L;

    if ((fd = creat(file, 0)) < 0)
	{
	emits("Cannot Open File\n");
	return FALSE;
	}
    else
    emits("Receiving File\n\nType <ESC> to abort transfer\n");

    timeout=FALSE;
    sectnum = errors = bufptr = 0;
    findtype = TRUE; exe = FALSE;
    sendchar(NAK);
    firstchar = 0;
    while (firstchar != EOT && errors != ERRORMAX)
	{
	errorflag = FALSE;

	do                                    /* get sync char */
	    {
	    firstchar = readchar();
	    if (timeout == TRUE)
	    return FALSE;
	    }
	while (firstchar != SOH && firstchar != EOT);

	if  (firstchar == SOH)
	    {
	    emits("Getting Block ");
	    sprintf(numb, "%d", sectnum);
	    emits(numb);
	    emits("...");
	    sectcurr = readchar();
	    if (timeout == TRUE)
	    return FALSE;
	    sectcomp = readchar();
	    if (timeout == TRUE)
	    return FALSE;
	    if ((sectcurr + sectcomp) == 255)
		{
		if (sectcurr == (sectnum + 1 & 0xff))
		    {
		    checksum = 0;
		    for (j = bufptr; j < (bufptr + SECSIZ); j++)
			{
			bufr[j] = readchar();
			if (findtype && sectcurr == 1 && j == 3) {
			    findtype = FALSE;
			    if (bufr[0] == 0x00 && bufr[1] == 0x00 &&
			        bufr[2] == 0x03 && bufr[3] == 0xF3)
				    exe = TRUE;
			    }
			if (timeout == TRUE)
			return FALSE;
			checksum = (checksum + bufr[j]) & 0xff;
			}
		    if (checksum == readchar())
			{
			errors = 0;
			sectnum++;
			bufptr += SECSIZ;
			bytes_xferred += SECSIZ;
			emits("verified\n");
			if (bufptr == BufSize)
			    {
			    if (write(fd, bufr, BufSize-128) == EOF)
				{
				emits("\nError Writing File\n");
				return FALSE;
				}
			    bufptr = 128;
			    for (j = 0; j < 128; j++)
				bufr[j] = bufr[(BufSize-128)+j];
			    }
			sendchar(ACK);
			}
		    else
			{
			errorflag = TRUE;
			if (timeout == TRUE)
			return FALSE;
			}
		    }
		else
		    {
		    if (sectcurr == (sectnum & 0xff))
			{
			emits("\nReceived Duplicate Sector\n");
			sendchar(ACK);
			}
		    else
		    errorflag = TRUE;
		    }
		}
	    else
	    errorflag = TRUE;
	    }
	if (errorflag == TRUE)
	    {
	    errors++;
	    emits("\nError\n");
	    sendchar(NAK);
	    }
	}        /* end while */
    if ((firstchar == EOT) && (errors < ERRORMAX))
	{
	sendchar(ACK);
	if (exe) while (bufr[--bufptr] != 0xF2) ;
	else     while (bufr[--bufptr] == 0) ;
	write(fd, bufr, ++bufptr);
	close(fd);
	return TRUE;
	}
    return FALSE;
    }

XMODEM_Send_File(file)
char *file;
    {
    int sectnum, bytes_to_send, size, attempts, c, i;
    unsigned checksum, j, bufptr;
    char numb[10];
    timeout=FALSE;
    bytes_xferred = 0;
    if ((fd = open(file, 0)) < 0) {
	emits("Cannot Open Send File\n");
	return FALSE;
	}
    else
    emits("Sending File\n\nType <ESC> to abort transfer\n");
    attempts = 0;
    sectnum = 1;
    /* wait for sync char */
    j=1;
    while (((c = readchar()) != NAK) && (j++ < ERRORMAX));
    if (j >= (ERRORMAX))
	{
	emits("\nReceiver not sending NAKs\n");
	return FALSE;
	}

    while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX)
	{
	if (bytes_to_send == EOF)
	    {
	    emits("\nError Reading File\n");
	    return FALSE;
	    }

	bufptr = 0;
	while (bytes_to_send > 0 && attempts != RETRYMAX)
	    {
	    attempts = 0;
	    do
		{
		sendchar(SOH);
		sendchar(sectnum);
		sendchar(~sectnum);
		checksum = 0;
		size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send;
		bytes_to_send -= size;
		for (j = bufptr; j < (bufptr + SECSIZ); j++)
		if (j < (bufptr + size))
		    {
		    sendchar(bufr[j]);
		    checksum += bufr[j];
		    }
		else
		    {
		    sendchar(0);
		    }
		sendchar(checksum & 0xff);
		attempts++;
		c = readchar();
		if (timeout == TRUE)
		return FALSE;
		}
	    while ((c != ACK) && (attempts != RETRYMAX));
	    bufptr += size;
	    bytes_xferred += size;
	    emits("Block ");
	    sprintf(numb, "%d", sectnum);
	    emits(numb);
	    emits(" sent\n");
	    sectnum++;
	    }
	}
    close(fd);
    if (attempts == RETRYMAX)
	{
	emits("\nNo Acknowledgment Of Sector, Aborting\n");
	return FALSE;
	}
    else
	{
	attempts = 0;
	do
	    {
	    sendchar(EOT);
	    attempts++;
	    }
	while ((readchar() != ACK) && (attempts != RETRYMAX) && (timeout == FALSE));
	if (attempts == RETRYMAX)
	emits("\nNo Acknowledgment Of End Of File\n");
	}
    return TRUE;
    }


