/* Comm XMODEM send routines */

#define  XMDMSEND 1

#include "globals.h"
#include <fcntl.h>

extern void  emit_tx(), emit_rx(), emits_tx(), emits_rx();
static int   naks,errsect;
static ULONG bytes;

XMODEM_Send_File(file)
UBYTE *file;
{
    extern void  purge_line(), send_proto(), report();
    extern int   read_proto(), readchar();

    USHORT readstatus, status, timeoutcount;
    UBYTE  ch;

    abort = cancel = FALSE;
    report(file);
    if ((fd = open(file, O_RDONLY)) < 0)
        {
        sprintf(sbuff,"\nCannot Open Send File %s\n",file);
        emits_rx(sbuff);
        send_proto(CAN); send_proto(CAN);
        return FALSE;
        }
    else
        emits_rx("Ready to send File -- ESC aborts transfer\n\n");

   naks = errsect = bytes = 0;

   Xconfig(TRUE);    /* set serial port to 8/N/1  */
   sector = 1;  timeoutcount = 0;

   purge_line();     /* flush any garbage in receiver */
   do                /* start handshake with receiver */
      {
         ch = readchar(TTIME,TRUE);
         if(timeout)
           {
             if(++timeoutcount == RETRYMAX)
               {
                  emits_rx("\nNo response, aborting\n");
                  return FALSE;
               }
            }
         if(abort || cancel ) return FALSE;
      } while (ch != NAK && ch != 'C' && ch != 'W');

   if(ch == 'W') return WXMODEM_Send_File(file);

   status = OK;
   crcflag = (ch == 'C');
   sprintf(sbuff,"%s mode requested\n",crcflag ? "\nCRC" : "\nChecksum");
   emits_rx(sbuff);

   while( (readstatus = fillbuf()) && status == OK )
    {                                  /* fill file buffer until EOF */
      if(readstatus == ERROR)          /*  or ERROR during read */
         return FALSE;
      status = sendsector( xbuffer );   /* send sector */
      sprintf(sbuff,"File: %s  bytes= %ld  naks= %d [ %d ]\r",file,bytes,
                  naks,errsect);
      status_line(0,sbuff);
      Process_window_event();
    }

   if(status == TIMEOUT || status == ABORT)
      return FALSE;

   timeoutcount = 0;
   do
     {
      purge_line();
      send_proto( EOT );     /* end transmission */
      if(timeout)
        if(timeoutcount++ == RETRYMAX || cancel || abort)
          return FALSE;
     } while ((ch = read_proto( TTIME, TRUE )) != ACK);
   close( fd );
   return TRUE;
}

int fillbuf()
{
   unsigned int bytes_read;

   bytes_read = read(fd, xbuffer, SECSIZ);

   if (bytes_read == -1)   /* error during read */
      return ERROR;
   if (bytes_read == 0)    /* end of file */
      return FALSE;
   if(bytes_read < SECSIZ)
      for(; bytes_read < SECSIZ; bytes_read++)
         xbuffer[bytes_read] = PAD;
   return TRUE;
}

/**************************************
sendsector() transmits a single sector
 with retransmit on error from receiver
***************************************/
sendsector( buf )
UBYTE *buf;
{
   extern void do_crc(), purge_line(), send_proto();
   unsigned int i, badblock;

   badblock = 0;
   cancel = FALSE;

   while( TRUE )
   {
      if( badblock == ERRORMAX )
         return TIMEOUT;
      if( cancel || abort )
         return ABORT;

      sprintf(sbuff,"\rTransmitting block %d",sector);
      emits_rx(sbuff);
      send_proto( SOH );          /* start of block */
      send_proto( sector );       /* sector number  */
      send_proto( ~sector );      /* compliment of sector number */
      checksum = crc = 0;       /* clear CRC and checksum */

      for( i = 0 ; i < SECSIZ ; i++ )
        {
          if(buf[ i ] == '\n')
            if(asciiflg) buf[ i ] = 0x0D;
          sendchar(buf[ i ]);
          do_crc( buf[ i ] );
          if(viewflg)
            emit_vw( buf[ i ] );
        }
      purge_line();              /* flush garbage from receiver */
      if( crcflag )
      {
         do_crc(0); do_crc(0);   /* cycle CRC generator */
         send_proto( crc >> 8 );   /* High byte */
         send_proto( crc );        /* Low byte */
      }
      else
         send_proto( checksum );

      if( read_proto(TTIME, TRUE ) == ACK)
      {
         bytes += SECSIZ;
         break;
      }
      else
      {
         badblock++; naks++;
         errsect = sector;
      }
   }
   sector++;            /* bump sector count   */
   return OK;
}

read_proto(time,flag)
int time,flag;
{
   int ch;

   ch = readchar(time,flag);
   emit_rx_protocol(ch);
   return (ch);
}

