home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0020 - 0029 / ibm0020-0029 / ibm0028.tar / ibm0028 / GRLF-C-1.ZIP / GCOMM / _XMODEMR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-14  |  26.6 KB  |  791 lines

  1. /*
  2.  * The routines in this file are the private modules used to perform
  3.  * XMODEM file reception.  In addition to the files here, there are
  4.  * also some common routine in _XMODEMC.C.  The xmodem file transfers
  5.  * are performed by a lot of different routines that perform a small
  6.  * piece of the whole transfer.  The status of the transfer is kept
  7.  * in the xmodem parameter block that is passed back and forth by
  8.  * all of these routines.
  9.  *
  10.  * The Greenleaf Comm Library
  11.  *
  12.  * Copyright (C) 1989-90 Greenleaf Software Inc.  All Rights Reserved.
  13.  *
  14.  */
  15. #define LINT_ARGS
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "gf.h"
  20. #include "asiports.h"
  21. #include "xfer.h"
  22. #include "_xfer.h"
  23.  
  24. /*
  25.  * void _XmodemReceive(XFER *xmodem)
  26.  *
  27.  * ARGUMENTS
  28.  *
  29.  * xmodem:  A pointer to the parameter block used to perform the
  30.  *          transfer.
  31.  *
  32.  * DESCRIPTION
  33.  *
  34.  * This is the main module for the XMODEM transfer routine.  It is in
  35.  * charge of doing it all.
  36.  *
  37.  * SIDE EFFECTS
  38.  *
  39.  * File(s) may have been transfered.
  40.  *
  41.  * RETURNS
  42.  *
  43.  * The return from this program is in the xmodem parameter block
  44.  * return status structure element.  It is one of the XFER_RETURN
  45.  * codes defined in XFER.H.
  46.  *
  47.  * AUTHOR
  48.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  49.  *
  50.  * MODIFICATIONS
  51.  *
  52.  */
  53. void GF_CONV _XmodemReceive(XFER *xmodem)
  54. {
  55. int done;
  56.  
  57.     xmodem->sending=FALSE;
  58.     if (!_XferInitialize(xmodem))   /* These first few lines set up the     */
  59.         return;                     /* parameter block for an XMODEM xfer.  */
  60.     xmodem->block_number=1L;
  61.  
  62.     if (!_XferOpenFile(xmodem))     /* Next, I open the output file.        */
  63.         return;
  64.     if (!_XmodemSendNAK(xmodem))    /* Now I start the Xmodem transfer off  */
  65.         return;                     /* by sending the initial NAK.          */
  66.     done=FALSE;
  67.  
  68.     while (!done)    /* At this point I start a giant loop, reading in blocks */
  69.     {                /* until I hit an EOT, which means the whole deal is done*/
  70.  
  71.         if (!_XmodemReceiveBlock(xmodem))
  72.         {
  73.             _XferCleanup(xmodem);
  74.             return;
  75.         }
  76.         switch (xmodem->x.xmodem.last_control_char) /* After reading the block*/
  77.         {                                           /* in, I process it depend*/
  78.             case STX :                              /* ing on the type of     */
  79.             case SOH :                              /* buffer it is.          */
  80.                 if (fwrite(xmodem->buffer,xmodem->current_block_size,1,xmodem->file) != 1)
  81.                 {
  82.                     xmodem->return_status=XFER_RETURN_FILE_ERROR;
  83.                     _XferCleanup(xmodem);
  84.                     return;
  85.                 }
  86.                 xmodem->byte_count += xmodem->current_block_size;
  87.                 if (xmodem->transfer_type <= XFER_TYPE_YMODEM)
  88.                     if (!_XmodemSendACK(xmodem))  /* I don't send this ACK if*/
  89.                         done=TRUE;                /* the transfer type is *-G*/
  90.                 break;
  91.             case EOT :
  92.                 _XmodemSendACK(xmodem);
  93.                 _XferMessage(xmodem,"End of file, cleaning up");
  94.                 done=TRUE;
  95.                 break;
  96.             default :
  97.                 xmodem->return_status=XFER_RETURN_LOGIC_ERROR;
  98.                 done=TRUE;
  99.                 break;
  100.         }
  101.     }
  102.     _XferCleanup(xmodem);       /* I close my file and free the buffers now. */
  103. }
  104.  
  105.  
  106. /*
  107.  * void _YmodemReceive(XFER *xmodem)
  108.  *
  109.  * ARGUMENTS
  110.  *
  111.  * xmodem:  A pointer to the parameter block used to perform the
  112.  *          transfer.
  113.  *
  114.  * DESCRIPTION
  115.  *
  116.  * A YMODEM transfer is very similar to an XMODEM transfer.  The main
  117.  * difference is that before the transfer starts, the YMODEM sender
  118.  * sends a special block 0 that has the filename in it.  After the
  119.  * receiver ACKS the file name, it looks like XMODEM-1K transfer takes
  120.  * place.  So this YMODEM reciever code performs a block 0 read, then
  121.  * performs a regular XMODEM transfer.  It keeps doing this over and
  122.  * over until it either fails because of an error, or receives an
  123.  * empty block 0, indicating that the sender is done.
  124.  *
  125.  * SIDE EFFECTS
  126.  *
  127.  * File(s) may have been transfered.
  128.  *
  129.  * RETURNS
  130.  *
  131.  * The return from this program is in the xmodem parameter block
  132.  * return status structure element.  It is one of the XFER_RETURN
  133.  * codes defined in XFER.H.
  134.  *
  135.  * AUTHOR
  136.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  137.  *
  138.  * MODIFICATIONS
  139.  *
  140.  */
  141.  
  142. void GF_CONV _YmodemReceive(XFER *xmodem) /* The YMODEM receive routine has */
  143. {                                          /* only one job to do, and that is*/
  144. XFER ymodem;                               /* to receive the special block 0.*/
  145. static char filename[65];                  /* It can then pass all the real  */
  146. int done;                                  /* work of the file transfer on to*/
  147.                                            /* the XMODEM receiver.           */
  148.  
  149.     done=FALSE;                            /* I use the done flag to control */
  150.                                            /* my exit from the receive loop. */
  151.  
  152.     ymodem=*xmodem;                        /* When I go off to receive my    */
  153.     ymodem.sending=FALSE;                  /* special block 0, I use my own  */
  154.                                            /* private parameter block.  I set*/
  155.                                            /* it up here to have the same    */
  156.                                            /* message and idle routines as   */
  157.                                            /* my caller specified.           */
  158.  
  159.     while (!done)
  160.     {
  161.         ymodem.file_length= 0L;            /* File size is 0 right now       */
  162.         if (!_XferInitialize(&ymodem))     /* First I initialize my special  */
  163.             return;                        /* parameter block, and set the   */
  164.         ymodem.block_number = 0L;          /* block number to 0, instead of 1*/
  165.  
  166.         if (!_XmodemSendNAK(&ymodem))      /* Now I send the initial ACK to  */
  167.             return;                        /* get things started.            */
  168.  
  169.                                            /* Now I try to receive my block 0*/
  170.         if (!_XmodemReceiveBlock(&ymodem)) /* If I don't get it, things are  */
  171.         {                                  /* bad, and I quit.               */
  172.             _XferCleanup(&ymodem);
  173.             return;
  174.         }
  175.         if (!_XmodemSendACK(&ymodem))      /* After getting the first block, */
  176.         {                                  /* I go ahead an ACK it.  If the  */
  177.             done=TRUE;                     /* ACK fails, I blow out of here. */
  178.             continue;
  179.         }
  180.         if (ymodem.x.xmodem.last_control_char==SOH ||
  181.             ymodem.x.xmodem.last_control_char==STX)
  182.         {
  183.             strcpy(filename,ymodem.buffer); /* At this point I copy the file */
  184.             xmodem->filename=filename;      /* name passed in block 0 into my*/
  185.             if (strlen(filename)==0)        /* XFER parameter block.  If the */
  186.                 done=TRUE;                  /* filename is legnth 0, it means*/
  187.             else                            /* the remote end is done, and I */
  188.             {                               /* exit.  Otherwise, I call the  */
  189.                                             /* XMODEM receiver and tell it to*/
  190.                                             /* read in this file.            */
  191.                 xmodem->file_length = atol(ymodem.buffer+strlen(filename)+1);
  192.                 _XmodemReceive(xmodem);
  193.                 timer(TICKS_PER_SECOND*1);
  194.                 if (xmodem->return_status != XFER_RETURN_SUCCESS)
  195.                      done=TRUE;
  196.             }
  197.         }
  198.         else
  199.             done=TRUE;
  200.         _XferCleanup(&ymodem);     /* After the transfer is complete, I clean*/
  201.     }                              /* up my private parameter block before   */
  202. }                                  /* starting again.                        */
  203.  
  204. /*
  205.  * int _XmodemReceiveBlock(XFER *xmodem)
  206.  *
  207.  * ARGUMENTS
  208.  *
  209.  * xmodem:  A pointer to the parameter block used to perform the
  210.  *          transfer.
  211.  *
  212.  * DESCRIPTION
  213.  *
  214.  * This is a utility routine that is called to read in a block of data in
  215.  * XMODEM format.  If it returns a TRUE, it means it read in and checked
  216.  * out a full block of data.  The caller is free at that point to act
  217.  * on the data.
  218.  *
  219.  * Note that most of the routines called by this guy can return a FALSE,
  220.  * but not have it be a fatal error.  The FALSE returns are all checked
  221.  * to see if the return_status structure element has been changed.  If
  222.  * not, we don't process this buffer, but we do go back and retry.
  223.  *
  224.  * SIDE EFFECTS
  225.  *
  226.  *
  227.  * RETURNS
  228.  *
  229.  * This routine returns TRUE if it read in a block, FALSE otherwise.
  230.  * If FALSE, the error code is returned in the return_status structure
  231.  * element.
  232.  *
  233.  * AUTHOR
  234.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  235.  *
  236.  * MODIFICATIONS
  237.  *
  238.  */
  239.  
  240. int GF_CONV _XmodemReceiveBlock(XFER *xmodem)
  241. {
  242. /*
  243.  * I don't return until I have read in the block, or exceeded the
  244.  * maximum retry count.
  245.  */
  246.     while (xmodem->error_count < XMODEM_MAX_ERRORS)
  247.     {
  248.         if (_XferAbortKeyPressed(xmodem))         /* Return if the user hits */
  249.             return(FALSE);                        /* the abort key.          */
  250.         if (!_XmodemGetFirstCharacter(xmodem))  /* Here I read the first char*/
  251.                                                 /* of a block.               */
  252.             if (xmodem->return_status)          /* If the error counter has  */
  253.                 return(FALSE);                  /* overflowed, I exit        */
  254.             else
  255.                 continue;
  256.         switch (xmodem->x.xmodem.last_control_char)
  257.         {
  258.             case EOT :                            /* An EOT by itself is a  */
  259.                 return(TRUE);                     /* valid buffer, return it*/
  260.  
  261.             case STX :                            /* STX and SOH signify    */
  262.                 xmodem->current_block_size=1024;  /* normal data buffers. I */
  263.                 break;                            /* just set up the buffer */
  264.             case SOH :                            /* size for each of these */
  265.                 xmodem->current_block_size=128;   /* guys and move on to    */
  266.                 break;                            /* read in the data.      */
  267.  
  268.             default :                             /* Anything else is bad!  */
  269.                 xmodem->return_status=XFER_RETURN_LOGIC_ERROR;
  270.                 return(FALSE);
  271.         }
  272.         if (!_XmodemGetBlockNumber(xmodem)) /* Here I read in the two bytes  */
  273.             if (xmodem->return_status)      /* of the block number.  If there*/
  274.                 return(FALSE);              /* was an error reading them in, */
  275.             else                            /* check to see if it was fatal, */
  276.                 continue;                   /* and then either try again or  */
  277.                                             /* exit.                         */
  278.         if (!_XmodemReadDataForBlock(xmodem))  /* Now I call this routine to */
  279.             if (xmodem->return_status)         /* read in either 128 or 1024 */
  280.                 return(FALSE);                 /* bytes of data.  Once again */
  281.             else                               /* I have to handle both the  */
  282.                 continue;                      /* fatal and non-fatal errors.*/
  283.  
  284.         if (!_XmodemGetChecksum(xmodem))   /* Now I go out and read in the   */
  285.             if (xmodem->return_status)     /* one or two byte checksum.      */
  286.                 return(FALSE);
  287.             else
  288.                 continue;
  289.         if (!_XmodemCheckBlockNumber(xmodem)) /* Now I check to see if this  */
  290.             if (xmodem->return_status)        /* blocknumber is the one I    */
  291.                 return(FALSE);                /* expect it to be.  I handle  */
  292.             else                              /* any error by either trying  */
  293.                 continue;                     /* again or returning.         */
  294.         if (!_XmodemVerifyChecksum(xmodem)) /* Here I check to see if the    */
  295.             if (xmodem->return_status)      /* checksum is good.  If not, I  */
  296.                 return(FALSE);              /* either try again or call the  */
  297.             else                            /* whole thing off.              */
  298.                 continue;
  299. /*
  300.  *  If I made it here, this is a good block.  Increment the block number and
  301.  *  continue return the TRUE flag to the caller.
  302.  */
  303.         _XferMessage(xmodem,"Read %d byte block %ld",xmodem->current_block_size,xmodem->block_number);
  304.         xmodem->block_number++;
  305. /*
  306.  * One last detail.  If I am in a Ymodem file transfer, I might be at the
  307.  * end of the file, in which case I might want to truncate the size of this
  308.  * buffer so the length ends up being exactly what I want.
  309.  */
  310.         if ( xmodem->transfer_type == XFER_TYPE_YMODEM ||
  311.              xmodem->transfer_type == XFER_TYPE_YMODEM_G )
  312.             if ( xmodem->file_length > 0L )
  313.                 if ( (xmodem->byte_count + xmodem->current_block_size ) > xmodem->file_length )
  314.                     xmodem->current_block_size = ( int ) ( xmodem->file_length - xmodem->byte_count );
  315.         return(TRUE);
  316.     }
  317. /*
  318.  * If I fall down here, it means the maximum retry count was exceeded.
  319.  */
  320.     xmodem->return_status=XFER_RETURN_TOO_MANY_ERRORS;
  321.     return(FALSE);
  322. }
  323.  
  324. /*
  325.  * int _XmodemCheckBlockNumber(XFER *xmodem)
  326.  *
  327.  * ARGUMENTS
  328.  *
  329.  * xmodem:  A pointer to the parameter block used to perform the
  330.  *          transfer.
  331.  *
  332.  * DESCRIPTION
  333.  *
  334.  * This routine is called to check the validity of a block number.  It
  335.  * has three basic possiblities.  First, it could that this is the
  336.  * correct block number.  If so, I return a TRUE.  Secondly, I could
  337.  * be getting a second copy of the last block.  This routine takes it
  338.  * upon itself to ACK a duplicate block, but it returns a FALSE, so the
  339.  * calling routine won't try to process this block.  Finally, it could
  340.  * just be a bad number, in which case a NAK goes out, and a FALSE is
  341.  * returned.
  342.  *
  343.  * SIDE EFFECTS
  344.  *
  345.  *
  346.  * RETURNS
  347.  *
  348.  * This routine returns TRUE if it read in a good block, FALSE otherwise.
  349.  * If FALSE, the error count is incremented, and the calling process can
  350.  * assume that the block has been NAKed down here.
  351.  *
  352.  * AUTHOR
  353.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  354.  *
  355.  * MODIFICATIONS
  356.  *
  357.  */
  358.  
  359. int GF_CONV _XmodemCheckBlockNumber(XFER *xmodem)
  360. {
  361. /*
  362.  * This first check is for the duplicate block possibility.
  363.  */
  364.     if (xmodem->current_block_number == (int) ((xmodem->block_number - 1) & 0xff))
  365.     {
  366.         if (!_XmodemSendACK(xmodem))
  367.             return(FALSE);
  368.         xmodem->error_count++;
  369.         _XferMessage(xmodem,"Duplicate block %ld",xmodem->block_number);
  370.         return(FALSE);
  371.     }
  372. /*
  373.  * The second check is for a bad block number.
  374.  */
  375.     if (xmodem->current_block_number != (int) (xmodem->block_number  & 0xff))
  376.     {
  377.        if (!_XmodemSendNAK(xmodem))
  378.             return(FALSE);
  379.         xmodem->error_count++;
  380.         _XferMessage(xmodem,"Bad block number waiting for number %ld",xmodem->block_number);
  381.         return(FALSE);
  382.     }
  383. /*
  384.  * I fall through here if everything is okay.
  385.  */
  386.     return(TRUE);
  387. }
  388.  
  389. /*
  390.  * int _XmodemVerifyChecksum(XFER *xmodem)
  391.  *
  392.  * ARGUMENTS
  393.  *
  394.  * xmodem:  A pointer to the parameter block used to perform the
  395.  *          transfer.
  396.  *
  397.  * DESCRIPTION
  398.  *
  399.  * This routine is called to see if the checksum read in for the
  400.  * current block agrees with the actual checksum for the block.
  401.  *
  402.  * SIDE EFFECTS
  403.  *
  404.  *
  405.  * RETURNS
  406.  *
  407.  * This routine returns TRUE if the checksum matches up with the block.
  408.  * Otherwise, the error counter is bumped and a FALSE is returned.
  409.  *
  410.  * AUTHOR
  411.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  412.  *
  413.  * MODIFICATIONS
  414.  *
  415.  */
  416.  
  417. int GF_CONV _XmodemVerifyChecksum(XFER *xmodem)
  418. {
  419. int checksum;
  420. int i;
  421.  
  422.     if (xmodem->x.xmodem.crc_mode)
  423.     {
  424.         if (glcrc(xmodem->current_block_size,0,xmodem->buffer) != xmodem->current_block_checksum)
  425.         {
  426.             if (!_XmodemSendNAK(xmodem))
  427.                 return(FALSE);
  428.             xmodem->error_count++;
  429.             _XferMessage(xmodem,"Bad CRC on block number %ld",xmodem->block_number);
  430.             return(FALSE);
  431.         }
  432.     }
  433.     else  /* Checksum is the additive type */
  434.     {
  435.         checksum=0;
  436.         for (i=0;i<xmodem->current_block_size;i++) /* Calculate the checksum */
  437.             checksum += xmodem->buffer[i];
  438.  
  439.         if ((checksum & 0xff) != xmodem->current_block_checksum)
  440.         {
  441.             if (!_XmodemSendNAK(xmodem))
  442.                 return(FALSE);
  443.             xmodem->error_count++;
  444.             _XferMessage(xmodem,"Bad checksum on block number %ld",xmodem->block_number);
  445.             return(FALSE);
  446.         }
  447.     }
  448.     return(TRUE);
  449. }
  450.  
  451. /*
  452.  * int _XmodemGetChecksum(XFER *xmodem)
  453.  *
  454.  * ARGUMENTS
  455.  *
  456.  * xmodem:  A pointer to the parameter block used to perform the
  457.  *          transfer.
  458.  *
  459.  * DESCRIPTION
  460.  *
  461.  * This routine is called to read in the checksum, which can be either
  462.  * one or two bytes.  The resulting integer is stored in the transfer
  463.  * parameter block.
  464.  *
  465.  * SIDE EFFECTS
  466.  *
  467.  *
  468.  * RETURNS
  469.  *
  470.  * This routine returns TRUE if it successfully reads in the one or two
  471.  * byte checksum. Otherwise, the error counter is bumped and a
  472.  * FALSE is returned.
  473.  *
  474.  * AUTHOR
  475.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  476.  *
  477.  * MODIFICATIONS
  478.  *
  479.  */
  480.  
  481. int GF_CONV _XmodemGetChecksum(XFER *xmodem)
  482. {
  483. int checksum_1;
  484. int checksum_2;
  485.  
  486.     checksum_1=asigetc_timed(xmodem->port,18);    /* First I read in byte 1 */
  487.     if (xmodem->x.xmodem.crc_mode)                /* Then, if we are in CRC */
  488.         checksum_2=asigetc_timed(xmodem->port,18);/* I read in byte 2.  Else*/
  489.     else                                          /* I just set it to be a 0*/
  490.         checksum_2=0;
  491.     if (checksum_1 < 0 || checksum_2 < 0)     /* If either read generated an*/
  492.     {                                         /* error, I handle it         */
  493.         if (!_XmodemSendNAK(xmodem))
  494.             return(FALSE);
  495.         if (!_XferFlushInput(xmodem))
  496.             return(FALSE);
  497.         xmodem->error_count++;
  498.         return(FALSE);
  499.     }
  500.     xmodem->current_block_checksum=checksum_1;
  501.     if (xmodem->x.xmodem.crc_mode)
  502.     {
  503.         xmodem->current_block_checksum <<= 8;
  504.         xmodem->current_block_checksum += checksum_2;
  505.     }
  506.     return(TRUE);
  507. }
  508.  
  509. /*
  510.  * int _XmodemReadDataForBlock(XFER *xmodem)
  511.  *
  512.  * ARGUMENTS
  513.  *
  514.  * xmodem:  A pointer to the parameter block used to perform the
  515.  *          transfer.
  516.  *
  517.  * DESCRIPTION
  518.  *
  519.  * This routine is called to read in all of the bytes for the current
  520.  * block.  This is pretty simple.
  521.  *
  522.  * SIDE EFFECTS
  523.  *
  524.  *
  525.  * RETURNS
  526.  *
  527.  * This routine returns TRUE if it successfully reads in all of
  528.  * the bytes. If there are any errors on reading data it flushes
  529.  * the input buffer and returns a FALSE.
  530.  *
  531.  * AUTHOR
  532.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  533.  *
  534.  * MODIFICATIONS
  535.  *
  536.  */
  537.  
  538. int GF_CONV _XmodemReadDataForBlock(XFER *xmodem)
  539. {
  540. int i;
  541. int c;
  542.  
  543.     for (i=0;i<xmodem->current_block_size;i++) /* The block size was set up  */
  544.     {                                          /* earlier when the first     */
  545.         c=asigetc_timed(xmodem->port,18);      /* character was read in.     */
  546.         if (c < 0)                             /* All this routine has to do */
  547.         {                                      /* is read in all the chars   */
  548.             if (!_XmodemSendNAK(xmodem))       /* and make sure that none of */
  549.                 return(FALSE);                 /* the reads generate an error*/
  550.             if (!_XferFlushInput(xmodem))      /* Errors are handled by      */
  551.                 return(FALSE);                 /* flushing the buffer, bump- */
  552.             xmodem->error_count++;             /* ing the error count, and   */
  553.             return(FALSE);                     /* returning a FALSE.         */
  554.         }
  555.         xmodem->buffer[i]= (char) c;
  556.     }
  557.     return(TRUE);
  558. }
  559.  
  560. /*
  561.  * int _XmodemGetBlockNumber(XFER *xmodem)
  562.  *
  563.  * ARGUMENTS
  564.  *
  565.  * xmodem:  A pointer to the parameter block used to perform the
  566.  *          transfer.
  567.  *
  568.  * DESCRIPTION
  569.  *
  570.  * The block number for an XMODEM block is two consecutive bytes.  The first
  571.  * byte is the straight block number, and the second one is it inverse.
  572.  * This routine reads in those two bytes, and makes sure that the second
  573.  * one is the inverse of the first.
  574.  *
  575.  * SIDE EFFECTS
  576.  *
  577.  *
  578.  * RETURNS
  579.  *
  580.  * This routine returns TRUE if it successfully reads in both of the
  581.  * bytes, and the second is the inverse of the first.  If it fails
  582.  * any of these tests, it sends a NAK, increments the error count, and
  583.  * returns a FALSE.
  584.  *
  585.  * AUTHOR
  586.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  587.  *
  588.  * MODIFICATIONS
  589.  *
  590.  */
  591.  
  592. int GF_CONV _XmodemGetBlockNumber(XFER *xmodem)
  593. {
  594. int block;
  595. int inverse_block;
  596.  
  597.     block=asigetc_timed(xmodem->port,18);
  598.     inverse_block=asigetc_timed(xmodem->port,18);
  599.     if (block < 0 || inverse_block < 0 || block != (~inverse_block & 0xff))
  600.     {
  601.         if (!_XmodemSendNAK(xmodem))
  602.             return(FALSE);
  603.         if (!_XferFlushInput(xmodem))
  604.             return(FALSE);
  605.         xmodem->error_count++;
  606.         _XferMessage(xmodem,"Bad block numbers %02x %02x",block,inverse_block);
  607.         return(FALSE);
  608.     }
  609.     xmodem->current_block_number=block;
  610.     return(TRUE);
  611. }
  612.  
  613. /*
  614.  * int _XmodemGetFirstCharacter(XFER *xmodem)
  615.  *
  616.  * ARGUMENTS
  617.  *
  618.  * xmodem:  A pointer to the parameter block used to perform the
  619.  *          transfer.
  620.  *
  621.  * DESCRIPTION
  622.  *
  623.  * This routine's job is to get the first character for an XMODEM packet.
  624.  * It has a timeout timer, and sits waiting while the timeout timer is
  625.  * running.  Eventually it either gets a character or times out.  It then
  626.  * processes that event.  A valid first character can be an EOT, SOH, or
  627.  * STX.  Any of these will return a TRUE.  Just about anything else will
  628.  * cause a FALSE to be returned.  If the maximum retry count is exceeded,
  629.  * this return will set the return_status structure element, causing the
  630.  * XMODEM driver to abort.
  631.  *
  632.  * SIDE EFFECTS
  633.  *
  634.  *
  635.  * RETURNS
  636.  *
  637.  * This routine returns TRUE if it successfully reads in a good first
  638.  * character.  In the event of a CAN-CAN, or a maximum retry count exceeded,
  639.  * it will set the return_status error flag, and return a FALSE.
  640.  *
  641.  * AUTHOR
  642.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  643.  *
  644.  * MODIFICATIONS
  645.  *
  646.  */
  647.  
  648. int GF_CONV _XmodemGetFirstCharacter(XFER *xmodem)
  649. {
  650. int timeout_timer;
  651. int last_char;
  652. int c;
  653.  
  654.     if (xmodem->block_number < 2)             /* I set up the timeout timer  */
  655.         timeout_timer=XMODEM_STARTUP_TIMEOUT; /* here.  Note that blocks 0 & */
  656.     else                                      /* and 1 get a different timer */
  657.         timeout_timer=XMODEM_RECEIVE_TIMEOUT; /* than all the others.        */
  658.  
  659.     while ((c=asigetc_timed(xmodem->port,18)) < 0)/* Now I sit in this loop, &*/
  660.     {                                             /* wait for either a timeout*/
  661.         if (_XferAbortKeyPressed(xmodem))         /* a character, or the abort*/
  662.             return(FALSE);                        /* key to be pressed.       */
  663.         if (--timeout_timer == 0)
  664.             break;
  665.     }
  666.     if (timeout_timer)
  667.     {
  668.         last_char=xmodem->x.xmodem.last_control_char;/* If I get here, it means*/
  669.         xmodem->x.xmodem.last_control_char=c;        /* I read in a character, */
  670.         switch (c)                                   /* and can go ahead and   */
  671.         {                                            /* process it.            */
  672.             case CAN :
  673.                 if (last_char==CAN)
  674.                 {
  675.                     xmodem->return_status=XFER_RETURN_REMOTE_ABORT;
  676.                     return(FALSE);
  677.                 }
  678.                 break;
  679.             case EOT :
  680.                 return(TRUE);
  681.             case SOH :
  682.                 return(TRUE);
  683.             case STX :
  684.                 return(TRUE);
  685.             default :
  686.                 while (asigetc_timed(xmodem->port,18) >= 0)
  687.                     if (_XferAbortKeyPressed(xmodem))
  688.                         return(FALSE);
  689.                 break;
  690.         }
  691.     }
  692.     xmodem->error_count++;
  693.     if (xmodem->error_count > 2 && xmodem->block_number==1 &&
  694.         xmodem->transfer_type <= XFER_TYPE_YMODEM)
  695.            xmodem->x.xmodem.crc_mode=FALSE;
  696.     _XmodemSendNAK(xmodem);
  697.     if (xmodem->error_count >= XMODEM_MAX_ERRORS)
  698.         xmodem->return_status=XFER_RETURN_PACKET_TIMEOUT;
  699.     return(FALSE);
  700. }
  701.  
  702. /*
  703.  * int _XmodemSendNAK(XFER *xmodem)
  704.  *
  705.  * ARGUMENTS
  706.  *
  707.  * xmodem:  A pointer to the parameter block used to perform the
  708.  *          transfer.
  709.  *
  710.  * DESCRIPTION
  711.  *
  712.  * This routine is called to send a NAK, which is not necessarily as simple
  713.  * as it may sound.  The NAK character can be one of three different chars,
  714.  * depending both on the protocol, and what block is being sent.  After
  715.  * the NAK is sent, a check is made for transmission errors.
  716.  *
  717.  * SIDE EFFECTS
  718.  *
  719.  *
  720.  * RETURNS
  721.  *
  722.  * This routine returns TRUE if it successfully sends the character,
  723.  * otherwise it flags the fatal error and returns a FALSE.
  724.  *
  725.  * AUTHOR
  726.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  727.  *
  728.  * MODIFICATIONS
  729.  *
  730.  */
  731.  
  732. int GF_CONV _XmodemSendNAK(XFER *xmodem)
  733. {
  734. int nak_char;
  735. int stat;
  736.  
  737.     if (xmodem->block_number < 2)
  738.     {
  739.         if (xmodem->transfer_type > XFER_TYPE_YMODEM)
  740.             nak_char='G';
  741.         else if (xmodem->x.xmodem.crc_mode)
  742.             nak_char='C';
  743.         else
  744.             nak_char=NAK;
  745.     }
  746.     else
  747.         nak_char=NAK;
  748.     stat=asiputc(xmodem->port,nak_char);
  749.     if (stat == ASSUCCESS)
  750.         return(TRUE);
  751.     xmodem->return_status=XFER_RETURN_CANT_SEND_NAK;
  752.     return(FALSE);
  753. }
  754.  
  755. /*
  756.  * int _XmodemSendACK(XFER *xmodem)
  757.  *
  758.  * ARGUMENTS
  759.  *
  760.  * xmodem:  A pointer to the parameter block used to perform the
  761.  *          transfer.
  762.  *
  763.  * DESCRIPTION
  764.  *
  765.  * This routine is called to send an ACK.  After the ACK is sent,
  766.  * a check is made for transmission errors.
  767.  *
  768.  * SIDE EFFECTS
  769.  *
  770.  *
  771.  * RETURNS
  772.  *
  773.  * This routine returns TRUE if it successfully sends the character,
  774.  * otherwise it flags the fatal error and returns a FALSE.
  775.  *
  776.  * AUTHOR
  777.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  778.  *
  779.  * MODIFICATIONS
  780.  *
  781.  */
  782.  
  783. int GF_CONV _XmodemSendACK(XFER *xmodem)
  784. {
  785.     if (asiputc(xmodem->port,ACK)==ASSUCCESS)
  786.         return(TRUE);
  787.     xmodem->return_status=XFER_RETURN_CANT_SEND_ACK;
  788.     return(FALSE);
  789. }
  790.  
  791.