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 / _XMODEMS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-14  |  29.7 KB  |  851 lines

  1. /*
  2.  * This file contains most of the private modules used to send files
  3.  * using XMODEM protocols.  The modules that are not present in this
  4.  * file are in _XMODEMC.C, which contains routines that are common to
  5.  * both the send and receive drivers.
  6.  *
  7.  * The Greenleaf Comm Library
  8.  *
  9.  * Copyright (C) 1989-90 Greenleaf Software Inc.  All Rights Reserved.
  10.  *
  11.  */
  12. #define LINT_ARGS
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include "gf.h"
  17. #include "asiports.h"
  18. #include "xfer.h"
  19. #include "_xfer.h"
  20.  
  21. /*
  22.  * void _XmodemSend(XFER *xmodem)
  23.  *
  24.  * ARGUMENTS
  25.  *
  26.  * xmodem:  A pointer to the parameter block used to perform the
  27.  *          transfer.
  28.  *
  29.  * DESCRIPTION
  30.  *
  31.  * This is the main module for the XMODEM transfer routine.  It is in
  32.  * charge of doing it all.
  33.  *
  34.  * SIDE EFFECTS
  35.  *
  36.  * A file may have been transfered.
  37.  *
  38.  * RETURNS
  39.  *
  40.  * The return from this program is in the xmodem parameter block
  41.  * return status structure element.  It is one of the XFER_RETURN
  42.  * codes defined in XFER.H.
  43.  *
  44.  * AUTHOR
  45.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  46.  *
  47.  * MODIFICATIONS
  48.  *
  49.  */
  50.  
  51. void GF_CONV _XmodemSend(XFER *xmodem)
  52. {
  53. int done;
  54. int status;
  55.  
  56.     xmodem->sending=TRUE;
  57.     if (!_XferInitialize(xmodem))      /* Here is where I initialize the    */
  58.         return;                        /* xmodem parameter block to set the */
  59.     xmodem->block_number=1L;           /* whole thing in motions.           */
  60.     if (!_XferOpenFile(xmodem))        /* Now I open the file               */
  61.         return;
  62.     if (!_XmodemGetFirstNAK(xmodem))   /* I wait for the first NAK before I */
  63.     {                                  /* can start sending stuff.          */
  64.         _XferCleanup(xmodem);
  65.         return;
  66.     }
  67.     if (!_XmodemReadNextFileBlock(xmodem)) /* Now I read in a block from the */
  68.     {                                      /* file to "prime the pump"       */
  69.         xmodem->return_status=XFER_RETURN_FILE_ERROR;
  70.         _XferCleanup(xmodem);
  71.         return;
  72.     }
  73.     done=FALSE;
  74.     while (!done)                            /* Now I sit in this loop until */
  75.     {                                        /* there is no more data to send*/
  76.         if (xmodem->current_block_size != 0) /* or a fatal error occurs      */
  77.             status=_XmodemSendBlock(xmodem);
  78.         else
  79.         {
  80.             _XferMessage(xmodem,"File transmission complete");
  81.             status=_XmodemSendEOT(xmodem);
  82.         }
  83.         if (!status)                         /* After sending the block, I   */
  84.         {                                    /* check the returned status.   */
  85.             _XferCleanup(xmodem);
  86.             return;
  87.         }
  88.         if (_XmodemGetACK(xmodem))                /* Now I try to get an ACK */
  89.         {                                         /* If I get one, I either  */
  90.             if (xmodem->current_block_size==0)    /* read in the next block, */
  91.                 done=TRUE;                        /* or set things up to exit*/
  92.             else
  93.                 _XmodemReadNextFileBlock(xmodem);
  94.         }
  95.         else if (xmodem->return_status == XFER_RETURN_SUCCESS)
  96.         {
  97.             xmodem->error_count++;                        /* If I didn't get */
  98.             if (xmodem->error_count >= XMODEM_MAX_ERRORS) /* an ACK I handle */
  99.             {                                             /* the error.      */
  100.                 _XferMessage(xmodem,"Exceeded maximum error count");
  101.                 xmodem->return_status=XFER_RETURN_TOO_MANY_ERRORS;
  102.                 done=TRUE;
  103.             }
  104.         }
  105.         else
  106.             done=TRUE;
  107.     }
  108.     _XferCleanup(xmodem);     /* Clean everything up when done              */
  109. }
  110.  
  111. /*
  112.  * void _YmodemSend(XFER *xmodem)
  113.  *
  114.  * ARGUMENTS
  115.  *
  116.  * xmodem:  A pointer to the parameter block used to perform the
  117.  *          transfer.
  118.  *
  119.  * DESCRIPTION
  120.  *
  121.  * Sending a bunch of files using YMODEM consists of repeating two
  122.  * operations over and over.  First, a single block 0 is sent, containing
  123.  * the file name and size.  Then, a standard XMODEM-1K transfer is performed.
  124.  * This sequence is repeated until there are no more files left to send,
  125.  * when an empty file name is sent.
  126.  *
  127.  * SIDE EFFECTS
  128.  *
  129.  * A file may have been transfered.
  130.  *
  131.  * RETURNS
  132.  *
  133.  * The return from this program is in the xmodem parameter block
  134.  * return status structure element.  It is one of the XFER_RETURN
  135.  * codes defined in XFER.H.
  136.  *
  137.  * AUTHOR
  138.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  139.  *
  140.  * MODIFICATIONS
  141.  *
  142.  */
  143.  
  144. void GF_CONV _YmodemSend(XFER *xmodem)
  145. {
  146. XFER ymodem;
  147. int done;
  148. int i;
  149. char *filename_list;
  150. char *saved_xmodem_filename;
  151. char current_filename[81];
  152. FILE *temp_file;
  153.  
  154.     ymodem=*xmodem;                         /* I set up a ymodem parameter  */
  155.     filename_list=xmodem->filename;         /* block that is used to send   */
  156.     saved_xmodem_filename=xmodem->filename; /* file name in block 0.  That  */
  157.     xmodem->filename=current_filename;      /* set up is all done here.     */
  158.     ymodem.filename=NULL;                   /* The filename passed here in  */
  159.     ymodem.sending=TRUE;                    /* the xmodem parameter block is*/
  160.                                             /* potentially a list of files, */
  161.                                             /* and I save off a pointer to  */
  162.     if (!_XferInitialize(&ymodem))          /* it for storage.              */
  163.         return;
  164.     done=FALSE;
  165.  
  166.     while (!done)
  167.     {
  168.                                           /* At the start of the loop I need */
  169.         ymodem.current_block_number=0;    /* to send the block 0 with the    */
  170.         ymodem.block_number=0L;           /* filename in it.                 */
  171.         ymodem.current_block_size=128;
  172.         for (i=0;i<128;i++)               /* I start by filling the block 0  */
  173.             ymodem.buffer[i]=0;           /* with nulls                      */
  174.  
  175.         if (!_XmodemGetFirstNAK(&ymodem)) /* I try to get the first NAK so I */
  176.             break;                        /* can send the filename           */
  177. /*
  178.  * All this code with the filename list is done to copy a single filename
  179.  * into the current_filename[] array.  The ';', ',', and ' ' characters are
  180.  * valid separators for the list of filenames.
  181.  */
  182.         i=0;
  183.         while (*filename_list != ';' && *filename_list != ',' &&
  184.                *filename_list != ' ' && *filename_list != '\0')
  185.             current_filename[i++]=*filename_list++;
  186.         while (*filename_list==';' || *filename_list==',' || *filename_list == ' ')
  187.             filename_list++;
  188.         current_filename[i]='\0';
  189.  
  190.         if (i == 0)
  191.         {                                         /* If i is 0, it means     */
  192.             done=TRUE;                            /* there are no more file  */
  193.                                                   /* names.  I still need to */
  194.         }                                         /* send a block full of    */
  195.         strcpy(ymodem.buffer,current_filename);   /* Nulls, but I set the    */
  196.                                                   /* done flag so I will drop*/
  197.                                                   /* out of this loop after  */
  198.                                                   /* I send block 0          */
  199.  
  200.         if (! done ) {
  201.             temp_file = fopen(current_filename,"rb");
  202.             if ( temp_file == NULL )
  203.                 break;
  204.             fseek( temp_file, 0L, SEEK_END );
  205.             sprintf( ymodem.buffer+strlen( current_filename ) + 1,
  206.                      "%ld",
  207.                      ftell( temp_file ) );
  208.             fclose( temp_file );
  209.         }
  210.         if (!_XmodemSendBlock(&ymodem))
  211.             break;
  212.         if (!_XmodemGetACK(&ymodem))      /* After sending my block 0, I need*/
  213.             break;                        /* to get an ACK fro the far end   */
  214.  
  215.         if (!done)                        /* If there is a file to send, I do*/
  216.         {                                 /* it here, breaking if the send   */
  217.             _XmodemSend(xmodem);          /* failed for one reason or another*/
  218.             if (xmodem->return_status != XFER_RETURN_SUCCESS)
  219.                 break;
  220.         }
  221.     }
  222.     _XferCleanup(&ymodem);                  /* Cleanup and exit.  Note that  */
  223.     xmodem->filename=saved_xmodem_filename; /* when I exit, I make sure the  */
  224. }                                           /* parameter block that got      */
  225.                                             /* sent to me still points to the*/
  226.                                             /* filename list.                */
  227.  
  228.  
  229. /*
  230.  * int _XmodemSendBlock(XFER *xmodem)
  231.  *
  232.  * ARGUMENTS
  233.  *
  234.  * xmodem:  A pointer to the parameter block used to perform the
  235.  *          transfer.
  236.  *
  237.  * DESCRIPTION
  238.  *
  239.  * This is the main routine that is called to send an xmodem data block.
  240.  * It doesn't really do anything on its own.  Instead, it calls subroutines
  241.  * to send the start character, block number, data, and checksum.  Note
  242.  * that this routine assumes that we are free to send, having already
  243.  * received an ACK or NAK.
  244.  *
  245.  * SIDE EFFECTS
  246.  *
  247.  * A block is sent, and we should wait for an ACK.
  248.  *
  249.  * RETURNS
  250.  *
  251.  * The return from this program is in the xmodem parameter block
  252.  * return status structure element.  It is one of the XFER_RETURN
  253.  * codes defined in XFER.H.  If the send was successful, this routine
  254.  * returns a TRUE, else it returns a FALSE.
  255.  *
  256.  * AUTHOR
  257.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  258.  *
  259.  * MODIFICATIONS
  260.  *
  261.  */
  262.  
  263. int GF_CONV _XmodemSendBlock(XFER *xmodem)
  264. {
  265. /*
  266.  * This is one of the basic points where we call the user defined print guy.
  267.  */
  268.     if ( xmodem->block_number != 0 )
  269.         _XferMessage(xmodem,"Sending block %ld",xmodem->block_number-1);
  270.     else
  271.         _XferMessage(xmodem,"Sending YMODEM startup block");
  272.  
  273.     if (!_XmodemSendStartCharacter(xmodem))  /* First, I send either an SOH  */
  274.         return(FALSE);                       /* or STX, depending on the size*/
  275.                                              /* of the output block.         */
  276.  
  277.     if (!_XmodemSendBlockNumber(xmodem))     /* Then I send the block number */
  278.         return(FALSE);                       /* and its inverse.             */
  279.  
  280.     if (!_XmodemSendBuffer(xmodem))          /* Then I send all of the data  */
  281.         return(FALSE);                       /* bytes, either 128 or 1024.   */
  282.  
  283.     if (!_XmodemSendChecksum(xmodem))        /* Finally, send either the CRC */
  284.         return(FALSE);                       /* or additive checksum.        */
  285.  
  286.     return(TRUE);
  287. }
  288.  
  289. /*
  290.  * int _XmodemSendChecksum(XFER *xmodem)
  291.  *
  292.  * ARGUMENTS
  293.  *
  294.  * xmodem:  A pointer to the parameter block used to perform the
  295.  *          transfer.
  296.  *
  297.  * DESCRIPTION
  298.  *
  299.  * This routine is charged with sending out the checksum for a given
  300.  * data block.  This routine takes one of two approaches, one for 16 bit
  301.  * CRC checksums, which are sent out in two bytes, and the other for eight
  302.  * bit additive checksums, which are sent out in one byte.  The two routines
  303.  * both calculate the checksum, then send it.
  304.  *
  305.  * SIDE EFFECTS
  306.  *
  307.  *
  308.  * RETURNS
  309.  *
  310.  * The return from this program is in the xmodem parameter block
  311.  * return status structure element.  It is one of the XFER_RETURN
  312.  * codes defined in XFER.H.  If the send was successful, this routine
  313.  * returns a TRUE, else it returns a FALSE.
  314.  *
  315.  * AUTHOR
  316.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  317.  *
  318.  * MODIFICATIONS
  319.  *
  320.  */
  321.  
  322. int GF_CONV _XmodemSendChecksum(XFER *xmodem)
  323. {
  324. int i;
  325. int stat_1;
  326. int stat_2;                         /* If I am in CRC mode, I perform the 16 */
  327.                                     /* bit CRC calculation, then send out    */
  328.     if (xmodem->x.xmodem.crc_mode)  /* the two bytes.                        */
  329.     {
  330.         xmodem->current_block_checksum=glcrc(xmodem->current_block_size,0,xmodem->buffer);
  331.         stat_1=asiputc(xmodem->port,(xmodem->current_block_checksum >> 8) & 0xff);
  332.         stat_2=asiputc(xmodem->port,xmodem->current_block_checksum & 0xff);
  333.     }
  334.     else                   /* If I am in addititive checksum mode, I add up  */
  335.     {                      /* all the bytes and send out the checksum.       */
  336.         xmodem->current_block_checksum=0;
  337.         for (i=0;i<xmodem->current_block_size;i++)
  338.             xmodem->current_block_checksum += xmodem->buffer[i];
  339.         stat_1=asiputc(xmodem->port,xmodem->current_block_checksum & 0xff);
  340.         stat_2=ASSUCCESS;
  341.     }
  342. /*
  343.  * If either of the bytes sent out caused an error, we flag the error in the
  344.  * parameter block and return a FALSE to the calling routine.
  345.  */
  346.     if (stat_1 != ASSUCCESS || stat_2 != ASSUCCESS)
  347.     {
  348.         _XferMessage(xmodem,"Error sending checksum");
  349.         xmodem->return_status=XFER_RETURN_CANT_PUT_BUFFER;
  350.         return(FALSE);
  351.     }
  352.     return(TRUE);           /* Else return TRUE, everything is great.        */
  353. }
  354.  
  355. /*
  356.  * int _XmodemSendBlockNumber(XFER *xmodem)
  357.  *
  358.  * ARGUMENTS
  359.  *
  360.  * xmodem:  A pointer to the parameter block used to perform the
  361.  *          transfer.
  362.  *
  363.  * DESCRIPTION
  364.  *
  365.  * This routine has a real simple job.  It sends the block number for
  366.  * the current XFER block.  Because of the way XMODEM works, this means
  367.  * sending the block number once, then sending its inverse.
  368.  *
  369.  * SIDE EFFECTS
  370.  *
  371.  *
  372.  * RETURNS
  373.  *
  374.  * The return from this program is in the xmodem parameter block
  375.  * return status structure element.  It is one of the XFER_RETURN
  376.  * codes defined in XFER.H.  If the send was successful, this routine
  377.  * returns a TRUE, else it returns a FALSE.
  378.  *
  379.  * AUTHOR
  380.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  381.  *
  382.  * MODIFICATIONS
  383.  *
  384.  */
  385.  
  386. int GF_CONV _XmodemSendBlockNumber(XFER *xmodem)
  387. {
  388. int stat_1;
  389. int stat_2;
  390. /*
  391.  * Sending the two block number bytes is pretty straightforward.  By the way,
  392.  * the values in current_block_number were put there when the block of data
  393.  * was read in from the file.
  394.  */
  395.     stat_1=asiputc(xmodem->port,xmodem->current_block_number);
  396.     stat_2=asiputc(xmodem->port,~xmodem->current_block_number);
  397. /*
  398.  * If either of the asiputc() operations caused an error, it is time to
  399.  * flag it, and return a FALSE.
  400.  */
  401.     if (stat_1 != ASSUCCESS || stat_2 != ASSUCCESS)
  402.     {
  403.         _XferMessage(xmodem,"Error sending block number");
  404.         xmodem->return_status=XFER_RETURN_CANT_PUT_BUFFER;
  405.         return(FALSE);
  406.     }
  407.     return(TRUE);    /* Everything went okay, so I can return a TRUE.       */
  408. }
  409.  
  410. /*
  411.  * int _XmodemSendStartCharacter(XFER *xmodem)
  412.  *
  413.  * ARGUMENTS
  414.  *
  415.  * xmodem:  A pointer to the parameter block used to perform the
  416.  *          transfer.
  417.  *
  418.  * DESCRIPTION
  419.  *
  420.  * This routine has a real simple job.  It sends the start character for
  421.  * the current XMODEM block.  About the only thing it has to do is
  422.  * figure out whether to send an SOH or an STX, and all that requires is
  423.  * a quick peek at the block size.
  424.  *
  425.  * SIDE EFFECTS
  426.  *
  427.  *
  428.  * RETURNS
  429.  *
  430.  * The return from this program is in the xmodem parameter block
  431.  * return status structure element.  It is one of the XFER_RETURN
  432.  * codes defined in XFER.H.  If the send was successful, this routine
  433.  * returns a TRUE, else it returns a FALSE.
  434.  *
  435.  * AUTHOR
  436.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  437.  *
  438.  * MODIFICATIONS
  439.  *
  440.  */
  441.  
  442. int GF_CONV _XmodemSendStartCharacter(XFER *xmodem)
  443. {
  444. int stat;
  445.  
  446.     if (xmodem->current_block_size==128)  /* Here I send an SOH or STX,     */
  447.         stat=asiputc(xmodem->port,SOH);   /* depending on the block size.   */
  448.     else                                  /* The block size was set up when */
  449.         stat=asiputc(xmodem->port,STX);   /* the current file block was read*/
  450. /*
  451.  * Here is where I flag an error if one occurred when I sent the start char.
  452.  */
  453.     if (stat != ASSUCCESS)
  454.     {
  455.         _XferMessage(xmodem,"Error sending first character");
  456.         xmodem->return_status=XFER_RETURN_CANT_PUT_BUFFER;
  457.         return(FALSE);
  458.     }
  459.     return(TRUE);
  460. }
  461.  
  462. /*
  463.  * int _XmodemSendBuffer(XFER *xmodem)
  464.  *
  465.  * ARGUMENTS
  466.  *
  467.  * xmodem:  A pointer to the parameter block used to perform the
  468.  *          transfer.
  469.  *
  470.  * DESCRIPTION
  471.  *
  472.  * This routine has the job of sending out all the characters in the current
  473.  * data buffer.  It also watches for errors while it does it.
  474.  *
  475.  * SIDE EFFECTS
  476.  *
  477.  *
  478.  * RETURNS
  479.  *
  480.  * The return from this program is in the xmodem parameter block
  481.  * return status structure element.  It is one of the XFER_RETURN
  482.  * codes defined in XFER.H.  If the send was successful, this routine
  483.  * returns a TRUE, else it returns a FALSE.
  484.  *
  485.  * AUTHOR
  486.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  487.  *
  488.  * MODIFICATIONS
  489.  *
  490.  */
  491.  
  492. int GF_CONV _XmodemSendBuffer(XFER *xmodem)
  493. {
  494. int i;
  495.  
  496.     for (i=0;i<xmodem->current_block_size;i++)
  497.     {
  498.         if (asiputc(xmodem->port,xmodem->buffer[i]) != ASSUCCESS)
  499.         {
  500.             _XferMessage(xmodem,"Error sending buffer");
  501.             xmodem->return_status=XFER_RETURN_CANT_PUT_BUFFER;
  502.             return(FALSE);
  503.         }
  504.     }
  505.     return(TRUE);
  506. }
  507.  
  508. /*
  509.  * int _XmodemGetFirstNAK(XFER *xmodem)
  510.  *
  511.  * ARGUMENTS
  512.  *
  513.  * xmodem:  A pointer to the parameter block used to perform the
  514.  *          transfer.
  515.  *
  516.  * DESCRIPTION
  517.  *
  518.  * This piece of code has the tough job of reading in the first NAK.  When
  519.  * the protocol is just getting started, the sender has to wait for the
  520.  * receive to send a NAK character to get the ball rolling.  In addition,
  521.  * the sender has to figure out some stuff about what version of the XMODEM
  522.  * protocol to use depending on the received NAK character.
  523.  *
  524.  * SIDE EFFECTS
  525.  *
  526.  * This routine may override the senders desire to use the CRC 16 bit
  527.  * checksum protocol, changing back to additive checksum mode.
  528.  *
  529.  * RETURNS
  530.  *
  531.  * The return from this program is in the xmodem parameter block
  532.  * return status structure element.  It is one of the XFER_RETURN
  533.  * codes defined in XFER.H.  If any of several errors occur, the
  534.  * routine returns a FALSE, which means abort the program.  Otherwise
  535.  * it returns a TRUE.
  536.  *
  537.  * AUTHOR
  538.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  539.  *
  540.  * MODIFICATIONS
  541.  *
  542.  */
  543.  
  544. int GF_CONV _XmodemGetFirstNAK(XFER *xmodem)
  545. {
  546. int timeout_timer;
  547. int last_char;
  548. int c;
  549. /*
  550.  * I sit in this giant for loop forever.  The only way out of it is with
  551.  * a return statement.  While in the loop, many errors will cause a drop
  552.  * down towards the end of the loop.  At the end, I bump the error counter
  553.  * and check it to see if we have maxed out.  Exceeding the maximum error
  554.  * count causes an abort.
  555.  */
  556.     for ( ; ; )
  557.     {
  558.         timeout_timer=XMODEM_RECEIVE_TIMEOUT;          /* The first thing I do*/
  559.         while ((c=asigetc_timed(xmodem->port,18)) < 0) /* is wait to get any  */
  560.         {                                         /* char from my port.  I can*/
  561.             if (_XferAbortKeyPressed(xmodem))     /* drop out of this loop by*/
  562.                 return(FALSE);                    /* the abort key, a char,  */
  563.             if (--timeout_timer == 0)             /* or a timeout.           */
  564.                 break;
  565.         }
  566.         if (timeout_timer)                        /* If I didn't time out, I */
  567.         {                                         /* go down here and check  */
  568.                                                   /* out my input char.  Else*/
  569.                                                   /* I fall down and check   */
  570.                                                   /* my error counters out.  */
  571.             last_char=xmodem->x.xmodem.last_control_char;
  572.             xmodem->x.xmodem.last_control_char=c;
  573.             switch (c)                            /* Here is where I process */
  574.             {                                     /* the input character.    */
  575.  
  576.                 case CAN :                           /* A pair of CANs means */
  577.                                                      /* the remote end wants */
  578.                     if (last_char==CAN)              /* to abort. Look for it*/
  579.                     {
  580.                         xmodem->return_status=XFER_RETURN_REMOTE_ABORT;
  581.                         _XferMessage(xmodem,"Remote end sent cancel code");
  582.                         return(FALSE);
  583.                     }
  584.                     break;
  585.                                                      /* When waiting for the*/
  586.                 case NAK :                           /* first NAK, a NAK    */
  587.                                                      /* means the receiver  */
  588.                     if (xmodem->x.xmodem.crc_mode)   /* can't deal with CRC */
  589.                     {
  590.                         _XferMessage(xmodem,"Falling back to checksum mode");
  591.                         xmodem->x.xmodem.crc_mode=FALSE;
  592.                     }
  593.                     return(TRUE);
  594.                 case 'C' :                           /* A C char means I can */
  595.                                                      /* send 1K blocks, but  */
  596.                     if (xmodem->x.xmodem.crc_mode)   /* not in X/YMODEM-1K-G */
  597.                         if (xmodem->transfer_type < XFER_TYPE_XMODEM_1KG)
  598.                             return(TRUE);            /* If this is okay, I   */
  599.                     break;                           /* return TRUE, else    */
  600.                                                      /* I fall through to the*/
  601.                                                      /* error code.          */
  602.  
  603.                 case 'G' :                           /* A G is okay for the  */
  604.                                                      /* two -G protocols.    */
  605.                     if (xmodem->transfer_type >= XFER_TYPE_XMODEM_1KG)
  606.                         return(TRUE);
  607.                     break;
  608.                               /* If I get a 'funny' first character, I assume*/
  609.                 default :     /* it is time to flush the input buffer.       */
  610.                     while (asigetc_timed(xmodem->port,18) >= 0)
  611.                         if (_XferAbortKeyPressed(xmodem))
  612.                             return(FALSE);
  613.                     break;
  614.             }
  615.         }                                            /* I fall down here when*/
  616.         xmodem->error_count++;                       /* I get a bad char.  I */
  617.                                                      /* bump the error count,*/
  618.         if (xmodem->error_count >= XMODEM_MAX_ERRORS)/* and exit if things   */
  619.         {                                            /* are too bad.         */
  620.             xmodem->return_status=XFER_RETURN_PACKET_TIMEOUT;
  621.             return(FALSE);
  622.         }
  623.     }
  624. }
  625.  
  626. /*
  627.  * int _XmodemReadNextFileBlock(XFER *xmodem)
  628.  *
  629.  * ARGUMENTS
  630.  *
  631.  * xmodem:  A pointer to the parameter block used to perform the
  632.  *          transfer.
  633.  *
  634.  * DESCRIPTION
  635.  *
  636.  * This piece of code is called when the last buffer has been sent and
  637.  * acked properly.  It means it is time to load up a new buffer.  It
  638.  * has a few decisions to make.  First, it has to decide whether to send
  639.  * a 128 or 1024 byte buffer.  Next, it needs to check for end of file.
  640.  * That's about it.
  641.  *
  642.  * SIDE EFFECTS
  643.  *
  644.  *
  645.  * RETURNS
  646.  *
  647.  * This module returns a FALSE if an EOF is reached, otherwise a TRUE.
  648.  *
  649.  * AUTHOR
  650.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  651.  *
  652.  * MODIFICATIONS
  653.  *
  654.  */
  655.  
  656. int GF_CONV _XmodemReadNextFileBlock(XFER *xmodem)
  657. {
  658.     int bytes_read;
  659.     int i;
  660. /*
  661.  * This module is responsible for setting the current_block_size parameter
  662.  * for everyone else to use later on.  It also has to update the
  663.  * current_block_number, block_number, and byte_count fields.
  664.  */
  665.     xmodem->current_block_size=128;
  666. /*
  667.  * If I am using 1K blocks and I have at least a buffer full, I load up 1K
  668.  */
  669.     if ((xmodem->file_length - xmodem->byte_count) > 896 &&
  670.         xmodem->transfer_type != XFER_TYPE_XMODEM)
  671.         xmodem->current_block_size=1024;
  672.     bytes_read=fread(xmodem->buffer,1,xmodem->current_block_size,xmodem->file);
  673.     if (bytes_read==0)
  674.     {
  675.         xmodem->current_block_size=0;
  676.         return(FALSE);               /* This is an EOF, everything is OK*/
  677.     } else if (bytes_read < xmodem->current_block_size )
  678.     {
  679.         for (i=bytes_read;i<xmodem->current_block_size;i++)
  680.             xmodem->buffer[i]='\0';
  681.     }
  682.     xmodem->current_block_number= (int) xmodem->block_number & 0xff;
  683.     xmodem->block_number++;
  684.     xmodem->byte_count += bytes_read;
  685.     return(TRUE);
  686. }
  687.  
  688. /*
  689.  * int _XmodemGetACK(XFER *xmodem)
  690.  *
  691.  * ARGUMENTS
  692.  *
  693.  * xmodem:  A pointer to the parameter block used to perform the
  694.  *          transfer.
  695.  *
  696.  * DESCRIPTION
  697.  *
  698.  * After a buffer is sent, it is the job of this routine to wait for the
  699.  * remote end to send an ACK.  This piece of code gets pretty bad,
  700.  * because it has to handle a whole bunch of different possibilities.
  701.  * Look to the code for explanations.
  702.  *
  703.  *
  704.  * SIDE EFFECTS
  705.  *
  706.  *
  707.  * RETURNS
  708.  *
  709.  * This module returns a FALSE if a valid ACK was not received.  The calling
  710.  * program has to look at the return_status structure element to see if
  711.  * a fatal error occurred, or if he should just retry.  If a TRUE is returned,
  712.  * it means everything is ready to send the next block.
  713.  *
  714.  * AUTHOR
  715.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  716.  *
  717.  * MODIFICATIONS
  718.  *
  719.  */
  720.  
  721. int GF_CONV _XmodemGetACK(XFER *xmodem)
  722. {
  723. int timeout_timer;
  724. int last_char;
  725. int c;
  726.  
  727.     while (!istxempty(xmodem->port))        /* The first thing this routine  */
  728.     {                                       /* does is wait for the output   */
  729.         if (_XferAbortKeyPressed(xmodem))   /* buffer to empty.  It wouldn't */
  730.             return(FALSE);                  /* be fair to start the timeout  */
  731.     }                                       /* timer up until all the chars  */
  732.                                             /* have been sent to the far end.*/
  733. /*
  734.  * This is another one of those while loops that can only be exited via
  735.  * a return statement.
  736.  */
  737.     for ( ; ; )
  738.     {
  739. /*
  740.  * If I am sending with one of the "-G" protocols, and this is a data block,
  741.  * I don't wait for an ACK.  But there is always the possibility that the
  742.  * far end will send an ACK, so I only return immediately if the receive
  743.  * buffer is empty.  Else I process any incoming chars, which could be
  744.  * a NAK, or maybe a CAN-CAN.
  745.  */
  746.         if (xmodem->current_block_size != 0)
  747.             if (xmodem->transfer_type==XFER_TYPE_XMODEM_1KG ||
  748.                 xmodem->transfer_type==XFER_TYPE_YMODEM_G)
  749.                 if (isrxempty(xmodem->port))
  750.                     return(TRUE);
  751.  
  752.         timeout_timer=XMODEM_ACK_TIMEOUT;              /* Here I sit waiting */
  753.         while ((c=asigetc_timed(xmodem->port,18)) < 0) /* for a char.  One of*/
  754.         {                                         /* 3 things can happen.  I */
  755.             if (_XferAbortKeyPressed(xmodem))     /* can get a char, an abort*/
  756.                 return(FALSE);                    /* key, or a timeout.      */
  757.             if (--timeout_timer == 0)
  758.                 break;
  759.         }
  760.         if (timeout_timer==0)   /* If I timed out, it isn't a fatal error,   */
  761.             return(FALSE);      /* it is an error.  Return the error flag and*/
  762.                                 /* let the caller figure out what to do with */
  763.                                 /* it.                                       */
  764.  
  765.         last_char=xmodem->x.xmodem.last_control_char;
  766.         xmodem->x.xmodem.last_control_char=c;
  767. /*
  768.  * Now that I have an input character, it is time to decide what to do
  769.  * with it.  I process all possiblities in this switch statement, and
  770.  * return either a TRUE or FALSE.
  771.  */
  772.         switch (c)
  773.         {
  774. /*
  775.  * Even a single CAN is a fatal error for the "-G" protocols.  For
  776.  * everyone else, it takes a CAN-CAN to cause a fatal error.  Otherwise it
  777.  * is a non-fatal error.
  778.  */
  779.             case CAN :
  780.                 if (xmodem->transfer_type==XFER_TYPE_XMODEM_1KG ||
  781.                     xmodem->transfer_type==XFER_TYPE_YMODEM_G)
  782.                     xmodem->return_status=XFER_RETURN_REMOTE_ABORT;
  783.                 if (last_char==CAN)
  784.                     xmodem->return_status=XFER_RETURN_REMOTE_ABORT;
  785.                 return(FALSE);
  786. /*
  787.  * A NAK is a fatal error for a "-G" family transfer.  For everyone else
  788.  * it is a non-fatal error, which gets flagged back to the caller.
  789.  */
  790.             case NAK :
  791.                 if (xmodem->transfer_type==XFER_TYPE_XMODEM_1KG ||
  792.                     xmodem->transfer_type==XFER_TYPE_YMODEM_G)
  793.                     xmodem->return_status=XFER_RETURN_REMOTE_ABORT;
  794.                 return(FALSE);
  795. /*
  796.  * An ACK is a success story for everyone, unconditionally.
  797.  */
  798.             case ACK :
  799.                 return(TRUE);
  800. /*
  801.  * In the event of a "funny" character, I flush the input buffer, and
  802.  * return an error.
  803.  */
  804.             default :
  805.                 while (asigetc_timed(xmodem->port,18) >= 0)
  806.                     if (_XferAbortKeyPressed(xmodem))
  807.                         return(FALSE);
  808.                 return(FALSE);
  809.         }
  810.     }
  811. }
  812.  
  813.  
  814. /*
  815.  * int _XmodemSendEOT(XFER *xmodem)
  816.  *
  817.  * ARGUMENTS
  818.  *
  819.  * xmodem:  A pointer to the parameter block used to perform the
  820.  *          transfer.
  821.  *
  822.  * DESCRIPTION
  823.  *
  824.  * Sending an EOT is pretty simple.  I just have to check for any transmission
  825.  * error after sending the character.
  826.  *
  827.  *
  828.  * SIDE EFFECTS
  829.  *
  830.  *
  831.  * RETURNS
  832.  *
  833.  * This module returns a FALSE if the EOT wouldn't go.  This is a fatal error
  834.  * as flagged in the return_status structure element.  Otherwise a TRUE
  835.  * is returned to the calling program.
  836.  *
  837.  * AUTHOR
  838.  *  Mark Nelson          29-Aug-1989  20:57:40.92
  839.  *
  840.  * MODIFICATIONS
  841.  *
  842.  */
  843.  
  844. int GF_CONV _XmodemSendEOT(XFER *xmodem)
  845. {
  846.     if (asiputc(xmodem->port,EOT)==ASSUCCESS)
  847.         return(TRUE);
  848.     xmodem->return_status=XFER_RETURN_CANT_SEND_EOT;
  849.     return(FALSE);
  850. }
  851.