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

  1. /*
  2.  * _KERMITR.C
  3.  *
  4.  * Contains:    _KermitReceive()
  5.  *              _KermitGetInitPacket()
  6.  *              _KermitGetBorF()
  7.  *              _KermitReadFileData()
  8.  *              _KermitSendInitialAck()
  9.  *              _KermitSendAck()
  10.  *              _KermitResendAck()
  11.  *              _KermitResendInitialAck()
  12.  *              _KermitSaveBuffer()
  13.  *
  14.  * The Greenleaf Comm Library
  15.  *
  16.  * Copyright (C) 1989-90 Greenleaf Software Inc.  All Rights Reserved.
  17.  *
  18.  */
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include "asiports.h"
  23. #include "xfer.h"
  24. #include "_xfer.h"
  25.  
  26. /*
  27.  *  Local prototypes for static procedures.
  28.  */
  29. static int GF_CONV _KermitGetInitPacket( XFER *kermit );
  30. static int GF_CONV _KermitGetBorF( XFER *kermit );
  31. static int GF_CONV _KermitReadFileData( XFER *kermit );
  32. static int GF_CONV _KermitSendInitialAck( XFER *kermit );
  33. static int GF_CONV _KermitSendAck( XFER *kermit );
  34. static int GF_CONV _KermitResendAck( XFER *kermit );
  35. static int GF_CONV _KermitResendInitialAck( XFER *kermit );
  36. static GF_CONV _KermitSaveBuffer( XFER *kermit );
  37.  
  38. /*
  39.  * int _KermitReceive( XFER *kermit )
  40.  *
  41.  * ARGUMENTS
  42.  *
  43.  *  XFER *kermit:                      This is a pointer to an XFER block that
  44.  *                                     keeps track of how things are set up
  45.  *                                     for the file transfer.
  46.  *
  47.  * DESCRIPTION
  48.  *
  49.  * This routine is the private driver for performing a kermit file receive.
  50.  * It is called by the public setup routine, KermitReceive(), which just
  51.  * sets up the parameter block and then calls this guy.  The logic of this
  52.  * routine is pretty simple.  It first gets the inital packet from the
  53.  * remote end, which sets up a few of the parameters for the transfer.
  54.  * It then sits in a loop receiving files, one after another, until the
  55.  * remote end decides to abort, or something bad happens.  It the returns
  56.  * to the routine who called it, which is probably found in KERMIT.C, where
  57.  * all the public routines are.
  58.  *
  59.  * For the record, kermit packet types have the following definitions:
  60.  *
  61.  *   S:   The S-Init packet.  One of these comes at the startup phase
  62.  *        and tells us a few things about
  63.  *
  64.  *   F:   This is a file header packet.  It tells me the name of the
  65.  *        file that is about to be sent.
  66.  *
  67.  *   D:   This is a data packet.  Presumably it has stuff that is supposed
  68.  *        to go into the file I have just opened.
  69.  *
  70.  *   Z:   This is an EOF packet.  It means I can close up the file.
  71.  *
  72.  *   B:   This is a break packet.  It means I can now take the connection
  73.  *        down.
  74.  *
  75.  *   E:   This is an error packet.  It contains error text from the
  76.  *        remote end.
  77.  *
  78.  *   Y:   This is an ACK packet.  It usually contains no data, but
  79.  *        an ACK in response to an S packet should contain S data.
  80.  *
  81.  *   N:   This is a NAK packet.  It contains no data.
  82.  *
  83.  *   T:   This is a timeout packet.  A packet didn't really come, it
  84.  *        means the receiver couldn't get any data.
  85.  *
  86.  *   Q:   This is a questionable packet.  A valid packet didn't really
  87.  *        come through.  Something was wrong with it, like a bad checksum.
  88.  *
  89.  *   A:   This is an abort packet.  Usually happens when the user hits
  90.  *        the abort key while reading data.
  91.  *
  92.  * SIDE EFFECTS
  93.  *
  94.  * File(s) may have been transfered.
  95.  *
  96.  * RETURNS
  97.  *
  98.  * The routine returns one of the defined XFER_RETURN codes defined
  99.  * in XFER.H.
  100.  *
  101.  * AUTHOR
  102.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  103.  *
  104.  * MODIFICATIONS
  105.  *
  106.  */
  107.  
  108.  
  109. int GF_CONV _KermitReceive( XFER *kermit )
  110. {
  111.  
  112.     kermit->sending = FALSE;
  113.     if ( !_XferInitialize( kermit ) )
  114.         return( FALSE );
  115.     if ( !_KermitGetInitPacket( kermit ) )
  116.         return( FALSE );
  117.  
  118.     for ( ; ; ) {
  119.         if ( !_KermitGetBorF( kermit ) )
  120.            return( FALSE );
  121.         if ( !_KermitReadFileData( kermit ) )
  122.             return( FALSE );
  123.     }
  124. }
  125.  
  126. /*
  127.  * static int _KermitGetInitPacket( XFER *kermit )
  128.  *
  129.  * ARGUMENTS
  130.  *
  131.  *  XFER *kermit:                      This is a pointer to an XFER block that
  132.  *                                     keeps track of how things are set up
  133.  *                                     for the file transfer.
  134.  *
  135.  * DESCRIPTION
  136.  *
  137.  * This routine is a private routine called to read the initial packet
  138.  * during a Kermit Receive.  The logic of this routine is fairly simple.
  139.  * It reads in packets until it sees an 'S' type packet.  An 'S' packet
  140.  * is what it is waiting for, so when this happens, it sets up some
  141.  * parameters that it pulls out of the packet, returns, and everyone
  142.  * is happy.  Otherwise, it reads in wrong packet types until one of
  143.  * several things causes him to give up and abort.
  144.  *
  145.  * SIDE EFFECTS
  146.  *
  147.  * Packets have been read.
  148.  *
  149.  * RETURNS
  150.  *
  151.  * Like most of these kind of routines, it returns TRUE if everything is
  152.  * okay and it is time to go on ahead.  A return value of FALSE means
  153.  * the transfer is aborted and it is time to stop.
  154.  *
  155.  *
  156.  * AUTHOR
  157.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  158.  *
  159.  * MODIFICATIONS
  160.  *
  161.  */
  162.  
  163. static int GF_CONV _KermitGetInitPacket( XFER *kermit )
  164. {
  165.     int type;
  166.  
  167.     for ( ; ; ) {
  168.         type = _KermitReceivePacket( kermit );
  169.         switch ( type ) {
  170. /*
  171.  * If I get an S packet, I load up the initialization parameters, and then
  172.  * send the other end an ACK packet that contains my initialization params.
  173.  */
  174.             case 'S' :
  175.                 _XferMessage( kermit, "Received initial S packet" );
  176.                 _KermitLoadInitParameters( kermit );
  177.                 return( _KermitSendInitialAck( kermit ) );
  178. /*
  179.  * T packets mean timeout.  If I get too many of these I abort.
  180.  */
  181.             case 'T' :
  182.                 _XferMessage( kermit, "Timeout waiting for init packet" );
  183.                 if ( !_KermitUpdateErrorCount( kermit ) )
  184.                     return( FALSE );
  185.                 if ( !_KermitSendPacket( kermit, 'N', 0, "" ) )
  186.                     return( FALSE );
  187.                 break;
  188. /*
  189.  * A Q packet is a funny packet, malformed or something like that.
  190.  */
  191.             case 'Q' :
  192.                 _XferMessage( kermit, "Funny packet" );
  193.                 if ( !_KermitUpdateErrorCount( kermit ) )
  194.                     return( FALSE );
  195.                 if ( !_KermitSendPacket( kermit, 'N', 0, "" ) )
  196.                     return( FALSE );
  197.                 break;
  198. /*
  199.  * Anything else, like a B packet or an E packet and I give up entirely.
  200.  */
  201.             default :
  202.                 _XferMessage( kermit, "Protocol error" );
  203.                 kermit->return_status = XFER_RETURN_PROTOCOL_ERROR;
  204.                 _XferCleanup( kermit );
  205.                 return( FALSE );
  206.         }
  207.     }
  208. }
  209.  
  210. /*
  211.  * static int _KermitGetBorF( XFER *kermit )
  212.  *
  213.  * ARGUMENTS
  214.  *
  215.  *  XFER *kermit:                      This is a pointer to an XFER block that
  216.  *                                     keeps track of how things are set up
  217.  *                                     for the file transfer.
  218.  *
  219.  * DESCRIPTION
  220.  *
  221.  * After I have read in the init packet, or after I have finished reading
  222.  * in a file, I go to this routine.  This guy is looking for a B packet
  223.  * or an F packet.  A B packet means Kermit is through, and it is time
  224.  * to exit.  An F packet means a new file is coming down the line, and
  225.  * it is time to go ahead and receive the packets.
  226.  *
  227.  * SIDE EFFECTS
  228.  *
  229.  * Packets have been read.
  230.  *
  231.  * RETURNS
  232.  *
  233.  * Like most of these kind of routines, it returns TRUE if everything is
  234.  * okay and it is time to go on ahead.  A return value of FALSE means
  235.  * the transfer is over or aborted and it is time to stop.
  236.  *
  237.  *
  238.  * AUTHOR
  239.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  240.  *
  241.  * MODIFICATIONS
  242.  *
  243.  */
  244.  
  245. static int GF_CONV _KermitGetBorF( XFER *kermit )
  246. {
  247.     int type;
  248.  
  249.     for ( ; ; ) {
  250.         type = _KermitReceivePacket( kermit );
  251.         switch ( type ) {
  252. /*
  253.  * The only good reason for another S packet is that the remote end might
  254.  * not have seen my ACK.  Assuming this is true, I make sure I didn't
  255.  * exceed my error count, then resend the S-ACK.
  256.  */
  257.             case 'S' :
  258.                 _XferMessage( kermit, "Received duplicate S-Init packet" );
  259.                 if ( !_KermitUpdateErrorCount( kermit ) )
  260.                     return( FALSE );
  261.                 if ( !_KermitResendInitialAck( kermit ) )
  262.                     return( FALSE );
  263.                 break;
  264. /*
  265.  * The only good reason for another Z packet is the assumption that the
  266.  * remote end might not have seen my ACK to his Z.  So I try to send
  267.  * it again.
  268.  */
  269.             case 'Z' :
  270.                 _XferMessage( kermit, "Received duplicate Z-End-of-file packet" );
  271.                 if ( !_KermitUpdateErrorCount( kermit ) )
  272.                     return( FALSE );
  273.                 if ( !_KermitResendAck( kermit ) )
  274.                     return( FALSE );
  275.                 break;
  276. /*
  277.  * An F packet means it is time to get a new file.  I copy the file
  278.  * name into my buffer, open the file, and return a TRUE to keep
  279.  * on going.
  280.  */
  281.             case 'F' :
  282.                 strcpy( kermit->filename, kermit->buffer+4 );
  283.                 if ( !_XferOpenFile( kermit ) )
  284.                     return( FALSE );
  285.                 if ( !_KermitSendAck( kermit ) )
  286.                     return( FALSE );
  287.                 else
  288.                     return( TRUE );
  289.  
  290.             case 'B' :
  291.                 _XferMessage( kermit, "Received break command" );
  292.                 _KermitSendAck( kermit );
  293.                 _XferCleanup( kermit );
  294.                 return( FALSE );
  295.  
  296.             case 'T' :
  297.                 _XferMessage( kermit, "Timeout waiting for B or F packet" );
  298.                 if ( !_KermitUpdateErrorCount( kermit ) )
  299.                     return( FALSE );
  300.                 if ( !_KermitSendPacket( kermit, 'N', 0, "" ) )
  301.                     return( FALSE );
  302.                 break;
  303.             case 'Q' :
  304.                 _XferMessage( kermit, "Funny packet" );
  305.                 if ( !_KermitUpdateErrorCount( kermit ) )
  306.                     return( FALSE );
  307.                 if ( !_KermitSendPacket( kermit, 'N', 0, "" ) )
  308.                     return( FALSE );
  309.                 break;
  310.             case 'A' :
  311.                 return( FALSE );
  312.             case 'E' :
  313.                 _XferMessage( kermit, "Aborted from remote end" );
  314.                 kermit->return_status = XFER_RETURN_REMOTE_ABORT;
  315.                 _XferCleanup( kermit );
  316.                 return( FALSE );
  317.             default :
  318.                 _XferMessage( kermit, "Protocol error" );
  319.                 kermit->return_status = XFER_RETURN_PROTOCOL_ERROR;
  320.                 _XferCleanup( kermit );
  321.                 return( FALSE );
  322.         }
  323.     }
  324. }
  325.  
  326. /*
  327.  * static int _KermitReadFileData( XFER *kermit )
  328.  *
  329.  * ARGUMENTS
  330.  *
  331.  *  XFER *kermit:                      This is a pointer to an XFER block that
  332.  *                                     keeps track of how things are set up
  333.  *                                     for the file transfer.
  334.  *
  335.  * DESCRIPTION
  336.  *
  337.  * This routine is called to read in all of the data that goes into
  338.  * a file.  It sits in a loop soaking up D packets until something
  339.  * happens that causes it to return.  A Z packet is the only good
  340.  * reason to return, everything else is an error.
  341.  *
  342.  * SIDE EFFECTS
  343.  *
  344.  * Packets have been read.
  345.  *
  346.  * RETURNS
  347.  *
  348.  * Like most of these kind of routines, it returns TRUE if everything is
  349.  * okay and it is time to go on ahead.  A return value of FALSE means
  350.  * the transfer is aborted and it is time to stop.  As long as the packets
  351.  * are coming in okay, I sit in the while (TRUE) loop sucking them in.
  352.  *
  353.  *
  354.  * AUTHOR
  355.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  356.  *
  357.  * MODIFICATIONS
  358.  *
  359.  */
  360.  
  361. static int GF_CONV _KermitReadFileData( XFER *kermit )
  362. {
  363.     int type;
  364.  
  365.     for ( ; ; ) {
  366.         type = _KermitReceivePacket( kermit );
  367.         switch ( type ) {
  368. /*
  369.  * The only good reason I can think of for getting an F packet
  370.  * here is that the remote end did not see the ACK.  Guessing that
  371.  * that might be the case, I try to resend the ack.
  372.  */
  373.             case 'F' :
  374.                 _XferMessage( kermit, "Received duplicate File Header packet" );
  375.                 if ( !_KermitUpdateErrorCount( kermit ) )
  376.                     return( FALSE );
  377.                 if ( !_KermitResendAck( kermit ) )
  378.                     return( FALSE );
  379.                 break;
  380. /*
  381.  * If I get an EOF Message, everything is okay.  I close the file, ACK
  382.  * and return TRUE.
  383.  */
  384.             case 'Z' :
  385.                 _XferMessage( kermit, "Closing file" );
  386.                 if ( kermit->file != NULL ) {
  387.                     fclose( kermit->file );
  388.                     kermit->file = NULL;
  389.                 }
  390.                 if ( !_KermitSendAck( kermit ) )
  391.                     return( FALSE );
  392.                 else
  393.                     return( TRUE );
  394.             case 'T' :
  395.                 _XferMessage( kermit, "Timeout waiting for Data packet" );
  396.                 if ( !_KermitUpdateErrorCount( kermit ) )
  397.                     return( FALSE );
  398.                 if ( !_KermitSendPacket( kermit, 'N', 0, "" ) )
  399.                     return( FALSE );
  400.                 break;
  401.             case 'Q' :
  402.                 _XferMessage( kermit, "Funny packet" );
  403.                 if ( !_KermitUpdateErrorCount( kermit ) )
  404.                     return( FALSE );
  405.                 if ( !_KermitSendPacket( kermit, 'N', 0, "" ) )
  406.                     return( FALSE );
  407.                 break;
  408.             case 'A' :
  409.                 return( FALSE );
  410.             case 'E' :
  411.                 _XferMessage( kermit, "Aborted from remote end" );
  412.                 kermit->return_status = XFER_RETURN_REMOTE_ABORT;
  413.                 _XferCleanup( kermit );
  414.                 return( FALSE );
  415.             case 'D' :
  416.                 if ( ( kermit->block_number & 0x3f ) ==
  417.                        kermit->current_block_number ) {
  418.                     _XferMessage( kermit, "Received block %ld",
  419.                                   kermit->block_number );
  420.                     if ( !_KermitSaveBuffer( kermit ) )
  421.                         return( FALSE );
  422.                     if ( !_KermitSendAck( kermit ) )
  423.                         return( FALSE );
  424.                 }
  425.                 else {
  426.                     _XferMessage( kermit, "Received duplicate data block" );
  427.                     if ( !_KermitResendAck( kermit ) )
  428.                         return( FALSE );
  429.                 }
  430.                 break;
  431.             default :
  432.                 _XferMessage( kermit, "Protocol error" );
  433.                 kermit->return_status = XFER_RETURN_PROTOCOL_ERROR;
  434.                 _XferCleanup( kermit );
  435.                 return( FALSE );
  436.         }
  437.     }
  438. }
  439.  
  440. /*
  441.  * static int _KermitSendInitialAck( XFER *kermit )
  442.  *
  443.  * ARGUMENTS
  444.  *
  445.  *  XFER *kermit:                      This is a pointer to an XFER block that
  446.  *                                     keeps track of how things are set up
  447.  *                                     for the file transfer.
  448.  *
  449.  * DESCRIPTION
  450.  *
  451.  * This routine is called to send an ACK to the intial S packet.  This
  452.  * is a little different from the
  453.  *
  454.  * SIDE EFFECTS
  455.  *
  456.  * Packets have been read.
  457.  *
  458.  * RETURNS
  459.  *
  460.  * Like most of these kind of routines, it returns TRUE if everything is
  461.  * okay and it is time to go on ahead.  A return value of FALSE means
  462.  * the transfer is aborted and it is time to stop.  The only reason for
  463.  * a FALSE here is if you get an error transmitting, which means something
  464.  * really bad has happened.
  465.  *
  466.  *
  467.  * AUTHOR
  468.  *  Mark Nelson          28-Aug-1989  20:57:40.92
  469.  *
  470.  * MODIFICATIONS
  471.  *
  472.  */
  473.  
  474. static int GF_CONV _KermitSendInitialAck( XFER *kermit )
  475. {
  476.     if ( !_KermitSendPacket( kermit, 'Y', 6, _KermitInitParameters() ) )
  477.         return( FALSE );
  478.     kermit->block_number++;
  479.     return( TRUE );
  480. }
  481.  
  482. /*
  483.  * static int _KermitSendAck( XFER *kermit )
  484.  *
  485.  * ARGUMENTS
  486.  *
  487.  *  XFER *kermit:                      This is a pointer to an XFER block that
  488.  *                                     keeps track of how things are set up
  489.  *                                     for the file transfer.
  490.  *
  491.  * DESCRIPTION
  492.  *
  493.  * This little critter doesn't do much.  But, I guess it is long enought
  494.  * to justify a separate subroutine.  It sends an ACK and increments the
  495.  * block number.
  496.  *
  497.  * SIDE EFFECTS
  498.  *
  499.  * Packets have been read.
  500.  *
  501.  * RETURNS
  502.  *
  503.  * Like most of these kind of routines, it returns TRUE if everything is
  504.  * okay and it is time to go on ahead.  A return value of FALSE means
  505.  * the transfer is aborted and it is time to stop.
  506.  *
  507.  *
  508.  * AUTHOR
  509.  *  Mark Nelson          29-Sep-1989  20:57:40.92
  510.  *
  511.  * MODIFICATIONS
  512.  *
  513.  */
  514.  
  515. static int GF_CONV _KermitSendAck( XFER *kermit )
  516. {
  517.     if ( !_KermitSendPacket( kermit, 'Y', 0, "" ) )
  518.         return( FALSE );
  519.     kermit->block_number++;
  520.     return( TRUE );
  521. }
  522.  
  523. /*
  524.  * static int _KermitResendAck( XFER *kermit )
  525.  *
  526.  * ARGUMENTS
  527.  *
  528.  *  XFER *kermit:                      This is a pointer to an XFER block that
  529.  *                                     keeps track of how things are set up
  530.  *                                     for the file transfer.
  531.  *
  532.  * DESCRIPTION
  533.  *
  534.  * This routine is a little more complicated than the one where I send
  535.  * just a regular ACK.  Since I am resending, it means there is an error
  536.  * condition, and I have to figure out just how to handle it.  I check to
  537.  * see if the reason I am sending an ACK is because I got my last block
  538.  * over again.  If not, things are really fouled up and I just quit.
  539.  * But if it is, I just go back and send the ACK again.
  540.  *
  541.  * SIDE EFFECTS
  542.  *
  543.  * Packets have been read.
  544.  *
  545.  * RETURNS
  546.  *
  547.  * Like most of these kind of routines, it returns TRUE if everything is
  548.  * okay and it is time to go on ahead.  A return value of FALSE means
  549.  * the transfer is aborted and it is time to stop.
  550.  *
  551.  *
  552.  * AUTHOR
  553.  *  Mark Nelson          29-Sep-1989  20:57:40.92
  554.  *
  555.  * MODIFICATIONS
  556.  *
  557.  */
  558.  
  559. static int GF_CONV _KermitResendAck( XFER *kermit )
  560. {
  561. /*
  562.  * Since I have a funny packet, I flush my input buffer.  I don't feel
  563.  * 100% confident about this line, and I may delete it.
  564.  */
  565.     if ( !_XferFlushInput( kermit ) )
  566.         return( FALSE );
  567. /*
  568.  * We are going to work on the assumption that the remote end just didn't
  569.  * see my last ACK.  So I back up my block number and thing about resending.
  570.  * If the block numbers still don't match up, things are really fouled up.
  571.  * I just exit if that is the case.  One alternative would be to just
  572.  * send a NAK, but I'm not sure if that would be a good idea.
  573.  */
  574.     kermit->block_number--;
  575.     if ( ( kermit->block_number & 0x3f ) == kermit->current_block_number ) {
  576.         if ( !_KermitSendAck( kermit ) )
  577.             return( FALSE );
  578.     } else {
  579.         kermit->return_status = XFER_RETURN_PROTOCOL_ERROR;
  580.         _XferCleanup( kermit );
  581.         return( FALSE );
  582.     }
  583.     return( TRUE );
  584. }
  585.  
  586. /*
  587.  * static int _KermitResendInitialAck( XFER *kermit )
  588.  *
  589.  * ARGUMENTS
  590.  *
  591.  *  XFER *kermit:                      This is a pointer to an XFER block that
  592.  *                                     keeps track of how things are set up
  593.  *                                     for the file transfer.
  594.  *
  595.  * DESCRIPTION
  596.  *
  597.  * This is just like the routine about, _KermitResendAck(), with one small
  598.  * difference.  Here I have to resend my initial ACK, which has my init
  599.  * data in it.  Other than that, everything else is the same.  Maybe both
  600.  * of these routines will be combined into one routine some day.
  601.  *
  602.  * SIDE EFFECTS
  603.  *
  604.  * Packets have been read.
  605.  *
  606.  * RETURNS
  607.  *
  608.  * Like most of these kind of routines, it returns TRUE if everything is
  609.  * okay and it is time to go on ahead.  A return value of FALSE means
  610.  * the transfer is aborted and it is time to stop.
  611.  *
  612.  *
  613.  * AUTHOR
  614.  *  Mark Nelson          29-Sep-1989  20:57:40.92
  615.  *
  616.  * MODIFICATIONS
  617.  *
  618.  */
  619.  
  620. static int GF_CONV _KermitResendInitialAck( XFER *kermit )
  621. {
  622.     if ( !_XferFlushInput( kermit ) )
  623.         return( FALSE );
  624. /*
  625.  * Once again, I check to see if our block numbers are just one off.  If
  626.  * they are, everything is okay, and I resend my ACK.  If our block numbers
  627.  * are not just one off, I am so concerned about things that I just quit.
  628.  */
  629.     kermit->block_number--;
  630.     if ( ( kermit->block_number & 0x3f ) == kermit->current_block_number ) {
  631.         if ( !_KermitSendInitialAck( kermit ) )
  632.             return( FALSE );
  633.     } else {
  634.         kermit->return_status = XFER_RETURN_PROTOCOL_ERROR;
  635.         _XferCleanup( kermit );
  636.         return( FALSE );
  637.     }
  638.     return( TRUE );
  639. }
  640.  
  641. /*
  642.  * static _KermitSaveBuffer( XFER *kermit )
  643.  *
  644.  * ARGUMENTS
  645.  *
  646.  *  XFER *kermit:                      This is a pointer to an XFER block that
  647.  *                                     keeps track of how things are set up
  648.  *                                     for the file transfer.
  649.  *
  650.  * DESCRIPTION
  651.  *
  652.  * This routine is the guy that has to save off a D packet full of data
  653.  * into the file.  Normally that might be pretty easy, but KERMIT
  654.  * complicates things a little bit by performing quoting of control
  655.  * characters.
  656.  *
  657.  * SIDE EFFECTS
  658.  *
  659.  * Packets have been read.
  660.  *
  661.  * RETURNS
  662.  *
  663.  * Like most of these kind of routines, it returns TRUE if everything is
  664.  * okay and it is time to go on ahead.  A return value of FALSE means
  665.  * the transfer is aborted and it is time to stop.  The only way to get
  666.  * a FALSE out of this guy is with a write error to the file.
  667.  *
  668.  *
  669.  * AUTHOR
  670.  *  Mark Nelson          29-Sep-1989  20:57:40.92
  671.  *
  672.  * MODIFICATIONS
  673.  *
  674.  */
  675.  
  676. static GF_CONV _KermitSaveBuffer( XFER *kermit )
  677. {
  678.     unsigned char c;
  679.     int i;
  680.  
  681.     i=0;
  682.     while ( i < kermit->current_block_size ) {
  683.         c = kermit->buffer[ 4 + i++ ];
  684.         if ( c == (unsigned char)kermit->x.kermit.quote_char ) {
  685.             c = kermit->buffer[ 4 + i++ ];
  686.             if ( ( c & 0x7f ) != kermit->x.kermit.quote_char )
  687.                 c = ctl( c );
  688.         }
  689.         if ( (unsigned char)putc( c, kermit->file ) != c ) {
  690.             kermit->return_status = XFER_RETURN_FILE_ERROR;
  691.             _XferCleanup( kermit );
  692.             return( FALSE );
  693.         }
  694.         kermit->byte_count++;
  695.     }
  696.     return( TRUE );
  697. }
  698.  
  699.