/*  compiler directives to fetch the necessary header files */
#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/text.h>
#include <devices/serial.h>
#include <stdio.h>
#include <ctype.h>
#include <libraries/dos.h>

extern ctextf, xstrip, crlf;
extern char rs_out[2];
extern char rs_in[2];
extern struct IOExtSer *Read_Request;
extern struct IOExtSer *Write_Request;
extern struct Window *mywindow;

/* things for xmodem send and recieve */
#define SECSIZ   0x80
#define BufSize  0x1000     /* Text buffer */
#define ERRORMAX 10        /* Max errors before abort */
#define RETRYMAX 10       /* Maximum retrys before abort */
#define SOH      1       /* Start of sector char */
#define EOT      4      /* end of transmission char */
#define ACK      6     /* acknowledge sector transmission */
#define NAK      21   /* error in transmission detected */

char  bufr[BufSize];
int fd,cancelled = FALSE;
long  bytes_xferred;

/**************************************************************/
/* 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;
struct IntuiMessage *NewMessage;

cancelled = FALSE;
rd = FALSE;
while (!rd)
      {
      Wait((1 << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) | ( 1 << 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 && (NewMessage->Code) == 69)
            {
            emits("\nUser Cancelled Transfer");
            cancelled = TRUE;
            ReplyMsg(NewMessage);
            return(0);
            }
         ReplyMsg(NewMessage);
         }
      }
c = ch;
return(c);
}

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

XMODEM_Read_File(file)

char *file;
{
int sectnum, sectcurr, sectcomp, errors, errorflag, tx, firsttime;
unsigned int checksum, j, bufptr, i;
char numb[10];
unsigned char firstchar;

    tx = FALSE;
    firsttime = TRUE;
    bytes_xferred = 0L;
    if ((fd = creat(file, 0)) < 0)
        {
        emits("\nCannot Open File\n");
        return FALSE;
        }
    else
        emits("\nReceiving File\n");
        emits("Use ESC to abort\n");

    cancelled=FALSE;
    sectnum = 1;
    errors = bufptr = 0;
    sendchar(NAK);
    firstchar = 0;

    while (firstchar != EOT && errors != ERRORMAX)
        {
        errorflag = FALSE;

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

        if  (firstchar == SOH)
            {
            emits("Getting Block ");
            i = sectnum;
            stci_d(numb,i,9);
            emits(numb);
            emits("...");
            sectcurr = readchar();
            if (cancelled)
               return FALSE;
            sectcomp = readchar();
            if (cancelled)
               return FALSE;
            if ((sectcurr + sectcomp) == 255)
                {
                if (sectcurr == (sectnum & 0xff))
                    {
                    checksum = 0;
                    for (j = bufptr; j < (bufptr + SECSIZ); j++)
                        {
                        bufr[j] = readchar();
                        if (cancelled)
                           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 (firsttime && ctextf)
                               {
                               tx = TRUE;
                               for (i = 0; i < BufSize; i++)
                                   if ((tx == TRUE) && ((bufr[i] < 127) && (bufr[i] > 0)))
                                      tx = TRUE;
                                   else
                                      tx = FALSE;
                               firsttime = FALSE;
                               }

                            if (tx)
                               for (i=0; i < BufSize; i++)
                                   if (bufr[i]==10)
                                      bufr[i]=32;
                                   else if (bufr[i]==13)
                                           bufr[i]=10;

                            bufptr = 0;
                            if (write(fd, bufr, BufSize - 128) == EOF)
                                {
                                emits("\nError Writing File\n");
                                return FALSE;
                                }
                            /* keep last 128 bytes */
                            for (i = BufSize-128; i < BufSize; i++)
                                {
                                bufr[bufptr] = bufr[i];
                                bufptr++;
                                }
                            bufptr = SECSIZ;
                            }
                        sendchar(ACK);
                        }
                    else
                        {
                        errorflag = TRUE;
                        if (cancelled)
                           return FALSE;
                        }
                    }
                else
                    {
                    if (sectcurr == ((sectnum-1) & 0xff))
                        {
                        emits("\nReceived Duplicate Sector\n");
                        sendchar(ACK);
                        }
                    else
                        errorflag = TRUE;
                    }
                }
            else
                errorflag = TRUE;
            }
        if (errorflag)
            {
            errors++;
            emits("\nError\n");
            sendchar(NAK);
            }
        };        /* end while */
            
    if ((firstchar == EOT) && (errors < ERRORMAX))
        {
        sendchar(ACK);
        if (xstrip)  /* strip file */
           {
           while ((bufr[bufptr] == 0) || (bufr[bufptr] == 0x1A))
                 bufptr--;
           bufptr++;
           }
        write(fd, bufr, bufptr);
        close(fd);
        return TRUE;
        }
    return FALSE;
}

/***************************************
* read and unread functions
****************************************/

char readbuf[BufSize];
int readptr = 0;

myread(fd, buffer, length)
int fd;
char buffer[];
int length;
{
int i,j;

i=0;
while(i < readptr)
    {
    buffer[i] = readbuf[i];
    i++;
    }
readptr = 0;

j = read(fd,buffer+i,length-i);
return(j);
}

unread(buffer,top,bottom)
char buffer[];
int top,bottom;
{

readptr = 0;
while(readptr < (top-bottom))
     {
     readbuf[readptr] = buffer[readptr+bottom];
     readptr++;
     }
return(0);
}

XMODEM_Send_File(file)
    char *file;
{
int sectnum, bytes_to_send, size, attempts, c, i;
unsigned checksum, j, bufptr;
char numb[10];
char mbuffer[BufSize];
int firsttime = TRUE;
int tx = FALSE;

    cancelled = FALSE;
    bytes_xferred = 0L;
    if ((fd = open(file, 1)) < 0)
        {
        emits("\nCannot Open Send File\n");
        return FALSE;
        }
    else
        emits("\nSending File\n");
        emits("Use ESC to abort\n");
    attempts = 0;
    sectnum = 1;
/* wait for sync char */
    j=1;
    while (((c = readchar()) != NAK) && (j++ < ERRORMAX) && (!cancelled));
    if (cancelled)
       return FALSE;
    if (j >= (ERRORMAX))
       {
       emits("\nReceiver not sending NAKs\n");
       return FALSE;
       };

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

        if (firsttime && ctextf)
           {
           tx = TRUE;
           for (i = 0; i < bytes_to_send; i++)
               if ((tx == TRUE) && ((bufr[i] < 127) && (bufr[i] > 0)))
                  tx = TRUE;
               else
                  tx = FALSE;
           firsttime = FALSE;
           }

        if (tx && !crlf)
           for (i = 0; i < bytes_to_send; i++)
               if (bufr[i] == '\n')
                     bufr[i]=13;

        if (tx && crlf) /* then buffer the extra chars */
           {
           i = 0;
           j = 0;
           while (i < bytes_to_send && j < BufSize)
               {
               if (bufr[i] == '\n')
                  mbuffer[j++] = 13;
               mbuffer[j++] = bufr[i];
               i++;
               }
           if (j == BufSize)
              unread(bufr,bytes_to_send,i);
           bytes_to_send = j;
           for (i=0; i<BufSize; i++)
               bufr[i]=mbuffer[i];
           }

        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 (cancelled == TRUE)
                   return FALSE;
                }
            while ((c != ACK) && (attempts != RETRYMAX));
            bufptr += size;
            bytes_xferred += size;
            emits("Block ");
            stci_d(numb,sectnum,9);
            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) && (cancelled == FALSE));
         if (attempts == RETRYMAX)
            emits("\nNo Acknowledgment Of End Of File\n");
        };
    return TRUE;
}

