#include <stdio.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>

#include "pcl4c.h"
#include "ascii.h"

#define FALSE 0
#define TRUE !FALSE

extern int GetChar();
extern int PutChar();

int TxyModem(Port,Filename,Buffer,OneKflag,BatchFlag)
int Port;            /* COM port [0..3] */
char Filename[];     /* filename buffer */
char Buffer[];       /* 1024 byte data buffer */
int OneKflag;        /* if TRUE, use 1K blocks when possible */
int BatchFlag;       /* if TRUE, send filename in packet 0 */
{int i, k;
 int Code;
 int Handle;         /* file Handle */
 char c;
 int p;
 char PacketType;
 char PacketNbr;
 int  PacketSize;
 int  FirstPacket;
 unsigned short CheckSum;
 long filelength();
 int Number1K = 0;       /* total # 1K packets */
 int Number128 = 0;      /* total # 128 byte packets */
 char NCGchar = NAK;
 long FileSize;
 char temp[81];
 int EmptyFlag = FALSE;
 /* begin */
 if(BatchFlag) if(Filename[0]=='\0') EmptyFlag = TRUE;
 if(!EmptyFlag)
     {/* Filename is not empty */
      EmptyFlag = FALSE;
      Handle = open(Filename,O_RDONLY|O_BINARY,S_IREAD);
      if(Handle<0)
          {strcpy(temp,"Cannot open ");
           strcat(temp,Filename);
           DisplayLine(temp,NULL,0);
           return(FALSE);
          }
     }
 DisplayLine("XYMODEM send: waiting for Receiver ",NULL,0);
 while(SioKeyPress()) SioKeyRead();
 /* compute # blocks */
 if(!EmptyFlag)
     {FileSize = filelength(Handle);
      if(OneKflag) Number1K = (int) (FileSize / 1024L);
      Number128 = 1 + (int) ((FileSize -1024L*(long)Number1K -1L) / 128L);
      sprintf(temp,"%d 1024 & %d 128 byte packets",Number1K,Number128);
      DisplayLine(temp,NULL,0);
     }
 else
     {/* empty file */
      Number128 = 0;
      Number1K = 0;
      /*DisplayLine("Empty File",NULL,0);*/
     }
 /* clear comm port ( there may be several NAKs queued up ) */
 SioRxFlush(Port);
 /* get receivers start up NAK, 'C', or 'G' */
 if(!TxStartup(Port,&NCGchar)) return(FALSE);
 /* loop over all packets */
 if(BatchFlag) FirstPacket = 0;
 else FirstPacket = 1;
 for(p=FirstPacket;p<=Number1K+Number128;p++)
       {/* user aborts ? */
        if(SioKeyPress()) if((char)SioKeyRead()==CAN)
          {TxCAN(Port);
           DisplayLine("*** Canceled by USER ***",NULL,0);
           return(FALSE);
          }
        /* issue message */
        sprintf(temp,"Packet %d",p);
        DisplayLine(temp,NULL,0);
        /* load up Buffer */
        if(p==0)
              {
               /* Filename packet ! */
               PacketSize = 128;
               k = 0;
               for(i=0;i<strlen(Filename);i++) Buffer[k++] = Filename[i];
               Buffer[k++] = '\0';
               sprintf(temp,"%ld",FileSize);
               for(i=0;i<strlen(temp);i++) Buffer[k++] = temp[i];
               while(k<128) Buffer[k++] = '\0';
              }
        else /* p > 0 */
              {/* DATA Packet: use 1K or 128 byte block ? */
               if(p<=Number1K) PacketSize = 1024;
               else PacketSize = 128;
               /* read next block from disk */
               Code = read(Handle,Buffer,PacketSize);
               if(Code<=0)
                     {SayError(Port,"Error on disk read");
                      return(FALSE);
                     }
               for(i=Code;i<PacketSize;i++) Buffer[i] = 0x1a;
              }
        /* send this packet */
        if(!TxPacket(Port,p,PacketSize,Buffer,NCGchar)) return(FALSE);
        SioDelay(5);
        /* must 'restart' after non null packet 0 */
        if(!EmptyFlag&&(p==0)) TxStartup(Port,&NCGchar);
       } /* end -- for(p) */
 /* done if empty packet 0 */
 if(EmptyFlag)
        {DisplayLine("Batch transfer complete",NULL,0);
         return(TRUE);
        }
 /* all done. send EOT up to 10 times */
 close(Handle);
 if(!TxEOT(Port))
     {SayError(Port,"EOT not acknowledged");
      return(FALSE);
     }
 DisplayLine("Transfer Complete",NULL,0);
 return(TRUE);
} /* end -- TxyModem */

int RxyModem(Port,Filename,Buffer,NCGchar,BatchFlag)
int Port;            /* COM port [0..3] */
char Filename[];     /* filename buffer */
char Buffer[];       /* 1024 byte data buffer */
char NCGchar;         /* NAK, 'C', or 'G' */
int BatchFlag;       /* if TRUE, get filename from packet 0 */
{int i;
 int Handle;         /* file Handle */
 int p;              /* packet index */
 int Code;           /* return code */
 int FirstPacket;
 char PacketNbr;
 int PacketSize;           /* 128 or 1024 */
 long atol();
 long FileSize;
 char temp[81];
 int  EOTflag = FALSE;
 /* begin */
 EOTflag = FALSE;
 DisplayLine("XYMODEM Receive: Waiting for Sender ",NULL,0);
 while(SioKeyPress()) SioKeyRead();
 /* clear comm port */
 SioRxFlush(Port);
 /* Send NAKs, 'C's, or 'G's */
 if(!RxStartup(Port,&NCGchar)) return(FALSE);
 /* open file unless BatchFlag is on */
 if(BatchFlag) FirstPacket = 0;
 else
     {/* start with packet 1 */
      FirstPacket = 1;
      /* open file passed in Filename[] for write */
      Handle = open(Filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IWRITE);
      if(Handle<0)
          {strcpy(temp,"Cannot open ");
           strcat(temp,Filename);
           DisplayLine(temp,NULL,0);
           return(FALSE);
          }
     }
 /* get each packet in turn */
 for(p=FirstPacket;;p++)
     {/* user aborts ? */
      if(SioKeyPress()) if((char)SioKeyRead()==CAN)
        {TxCAN(Port);
         return(FALSE);
        }
      /* issue message */
      sprintf(temp,"Packet %d",p);
      DisplayLine(temp,NULL,0);
      /* get next packet */
      if(!RxPacket(Port,p,&PacketSize,Buffer,NCGchar,&EOTflag)) return(FALSE);
      if(p==0)
        {/* copy Filename */
         strcpy(Filename,Buffer);
         /* done if null packet 0 */
         if(Filename[0]=='\0')
                {DisplayLine("Batch Transfer Complete",NULL,0);
                 return(TRUE);
                }
        }
      /* all done if EOT was received */
      if(EOTflag)
          {close(Handle);
           DisplayLine("Transfer Complete",NULL,0);
           return(TRUE);
          }
      /* process packet */
      if(p==0)
          {/* open file using filename in packet 0 */
           Handle = open(Filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IWRITE);
           if(Handle<0)
                {strcat(Buffer," -- open failed");
                 DisplayLine(Buffer,NULL,0);
                 return(FALSE);
                }
           /* get file length */
           FileSize = atol(&Buffer[1+strlen(Buffer)]);
           /* must 'restart' after packet 0 */
           RxStartup(Port,&NCGchar);
          }
      else /* DATA packet */
          {/* write Buffer */
           if(BatchFlag)
               {if(FileSize<(long)PacketSize) i = (int) FileSize;
                else i = PacketSize;
                i = write(Handle,Buffer,i);
                FileSize -= (long)i;
               }
           else write(Handle,Buffer,PacketSize);
          } /* end -- else */
     } /* end -- for(p) */
} /* end - RxyModem */

int TxCAN(Port)
int Port;
{int i;
 for(i=0;i<6;i++) PutChar(Port,CAN);
 return(0);
}