
/* Comm WXMODEM send routines */

#define  WXMDMSEND 1

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

extern void      emit_tx_protocol(), emit_vw(), emits_rx();
extern void      send_proto(), do_crc();
extern int       read_proto();

static int naks, errsect;
static ULONG bytes;
static UBYTE sent, acked;
static ULONG  lastacked, nak_blk, ack_blk;

WXMODEM_Send_File(file)
UBYTE *file;
{
    ULONG temp;
    int status, errcnt, eof = FALSE;
    int ch;

    naks = errsect = bytes = lastacked = acked = sent = errcnt = 0;

   while(!abort && (errcnt < RETRYMAX) )
   {
      do {
top:
            sprintf(sbuff,"File: %s  bytes= %ld  naks= %d [ %d ]\r",
                file, bytes, naks, errsect);
            status_line(0,sbuff);

            if((status = fillbuf()) == ERROR)
            {
               abortsend();
               return FALSE;
            }
            if(status == FALSE)
               eof = TRUE;
            else
            {
                if(sendwsector() == ABORT)
                {
                  abortsend();
                  return FALSE;
                }
                sent = sector & 3;
                sector++;
            }
            if((ch = getresponse()) != FALSE)
            {
               if(ch == NAK)
               {
                  errcnt++; naks++;
                  emits_rx("  NAK received\n");

                  nak_blk += 4;
                  temp = (nak_blk - (lastacked & 3)) & 3;
                  sector = (unsigned)(lastacked + temp);
                  temp = (ULONG)SECSIZ * (ULONG)(sector - 1);
                  if(lseek(fd,temp,0) == -1)
                  {
                     emits_rx("  File position error!\n");
                     abortsend();
                     return FALSE;
                  }
                  errsect = sector;
                  goto top;
               }
               else if(ch == ACK)
               {
                  errcnt = 0;
                  ack_blk += 4;
                  temp = (ack_blk - (lastacked & 3)) & 3;
                  if(temp == 0) temp = 4;
                  lastacked += temp;

                  bytes += (SECSIZ * temp);
               }
               else if(ch == CAN)
               {
                  send_proto(ACK);
                  emits_rx("  Received cancel request\n");
                  close(fd);
                  return TRUE;
               }
            }
/*
            sprintf(sbuff,"File: %s  bytes= %ld  naks= %d [ %d ]\r",
                file, bytes, naks, errsect);
            status_line(0,sbuff);
*/
      } while ( acked != sent );
      if(eof)
      {
         endfile(); close(fd);
         return TRUE;
      }
      errcnt++;
      lseek(fd,(long)(-SECSIZ),1);
      sector--;
      Delay(250L);
   }
   abortsend();
   return FALSE;
}

/**************************************
sendwsector() transmits a single sector
***************************************/
sendwsector(  )
{
   int i;
   cancel = FALSE;

   Process_window_event();
   if( cancel || abort )
       return ABORT;

   sprintf(sbuff,"\rTransmitting block %d",sector);
   emits_rx(sbuff);
   send_proto(SYN); send_proto(SYN); send_proto(SYN);

   send_wproto( SOH );          /* start of block */
   send_wproto( sector );       /* sector number  */
   send_wproto( ~sector );      /* compliment of sector number */
   crc = 0;                     /* clear CRC */

   for( i = 0 ; i < SECSIZ ; i++ )
   {
      if(xbuffer[ i ] == '\n' && asciiflg)
         xbuffer[ i ] = '\r';
      wsendchar(xbuffer[ i ]);
      do_crc( xbuffer[ i ] );
      if(viewflg)
        emit_vw( xbuffer[ i ] );
   }

   do_crc(0); do_crc(0);     /* cycle CRC generator */
   wsendchar( crc >> 8 );    /* High byte */
   wsendchar( crc );         /* Low byte */
}

send_wproto(ch)
UBYTE ch;
{
   emit_tx_protocol(ch);
   wsendchar(ch);
}

wsendchar(ch)
UBYTE ch;
{
   switch(ch)
   {
      case SYN: case DLE:
      case XON: case XOFF:
                             sendchar(DLE);
                             sendchar( ch ^ 64);
                             break;
      default:               sendchar(ch);
   }
}

getresponse()
{
   int ch;

   while(check_line())
   {
     ch = read_proto(10,0);
     switch(ch)
     {
        case XOFF:
            do {
                  ch = read_proto(10,0);
            } while( ch != XON && ch != TIMEOUT);
            return FALSE;
        case XON:
            return FALSE;
        case ACK:
            ch = read_proto(10,0);
            if(ch & ~3) return FALSE;
            ack_blk = acked = ch;
            return ACK;
        case NAK:
            ch = read_proto(10,0);
            if(ch & ~3) return FALSE;
            nak_blk = (ch & 3);
            return NAK;
        case CAN:
            ch = read_proto(10,0);
            if(ch == CAN)
               return CAN;
     }
   }
   return FALSE;
}

endfile()
{
   int ch, errs = 0;

   do {
         send_proto(EOT);
         ch = read_proto(5,0);
         if(ch == TIMEOUT) errs++;
   } while(ch != ACK && errs < 3);

}

abortsend()
{
   int ch, errs = 0;

   emits_rx("\nAborting transfer\n");
   send_proto(CAN); send_proto(CAN);

   do {
         ch = read_proto(4);
         if(ch == CAN)
         {
            if(read_proto(4) == CAN)
               break;
         }
         if(ch == TIMEOUT)
         {
            send_proto(CAN); send_proto(CAN);
            errs++;
         }
   } while (errs < 3);
   send_proto(ACK);
}

