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

  1. /*
  2.  * _XFERC.C
  3.  *
  4.  * These are private routines used by multiple transfer routines.
  5.  *
  6.  * Contains:   _XferInitialize()
  7.  *             _XferMessage()
  8.  *             _XferCleanup()
  9.  *             _XferFlushInput()
  10.  *             _XferOpenFile()
  11.  *             _XferAbortKeyPressed()
  12.  *             _KermitSendPacket()
  13.  *             _KermitReceivePacket()
  14.  *             _KermitChecksumCalculate()
  15.  *             _KermitInitParameters()
  16.  *             _KermitUpdateErrorCount()
  17.  *             _KermitLoadInitParameters()
  18.  *
  19.  *
  20.  * The Greenleaf Comm Library
  21.  *
  22.  * Copyright (C) 1989-90 Greenleaf Software Inc.  All Rights Reserved.
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <stdarg.h>
  29. #include "gf.h"
  30. #include "asiports.h"
  31. #include "ibmkeys.h"
  32. #include "xfer.h"
  33. #include "_xfer.h"
  34.  
  35. /*
  36.  *  int _XferInitialize( XFER *xfer )
  37.  *
  38.  * ARGUMENTS
  39.  *
  40.  *  xfer:     A pointer to an XFER parameter block for the transfer in
  41.  *            progress.
  42.  *
  43.  * DESCRIPTION
  44.  *
  45.  * This routine is called to initialize the data structure that is used
  46.  * throughout all of the driver routines.  It takes care of setting up
  47.  * the buffers, error codes, error counts, etc.
  48.  *
  49.  * SIDE EFFECTS
  50.  *
  51.  * The parameter block is initialized.
  52.  *
  53.  * RETURNS
  54.  *
  55.  * This routine can fail and return FALSE if it is unable to open the
  56.  * packet buffer, or if the user has pressed the abort key.
  57.  *
  58.  * AUTHOR
  59.  *  Mark Nelson          28-Aug-1989  21:04:40.92
  60.  *
  61.  * MODIFICATIONS
  62.  *
  63.  */
  64.  
  65. int GF_CONV _XferInitialize( XFER *xfer )
  66. {
  67.     xfer->return_status = XFER_RETURN_SUCCESS; /* Current status is Okay   */
  68.     xfer->error_count = 0;                     /* Clear the error count    */
  69.     xfer->file = NULL;                         /* No open file             */
  70.     xfer->current_block_number = -1;           /* No packet block number   */
  71.     xfer->current_block_size = -1;             /* No packet block size     */
  72.     xfer->block_number = 1L;                   /* We are on file block one */
  73.     xfer->byte_count = -1L;                    /* No bytes transferred yet */
  74. /*
  75.  * If this is just regular XMODEM or Kermit, I only set up a small input buffer.
  76.  * Otherwise, I go for the large 1K buffer used by everyone else.  If
  77.  * there is no space available for a buffer, I clean up my mess, set
  78.  * the error flag, and then exit.
  79.  */
  80.     if ( xfer->transfer_type == XFER_TYPE_XMODEM ||
  81.          xfer->transfer_type == XFER_TYPE_KERMIT ||
  82.          xfer->transfer_type == XFER_TYPE_ASCII )
  83.          xfer->buffer = malloc( 128 );
  84.     else
  85.         xfer->buffer = malloc( 1024 );
  86.     if ( xfer->buffer == NULL ) {
  87.         _XferMessage( xfer, "Failed to allocate XFER buffer(s)" );
  88.         xfer->return_status = XFER_RETURN_CANT_GET_BUFFER;
  89.         _XferCleanup( xfer );
  90.         return( FALSE );
  91.     }
  92.     if ( xfer->transfer_type <= XFER_TYPE_YMODEM_G ) {
  93.         xfer->x.xmodem.last_control_char = -1;     /* No control characters yet*/
  94.     }
  95. /*
  96.  * Finally, if the xfer is a KERMIT type, I set up the defaults for a KERMIT
  97.  * transfer.  They will probably all change when I get an S packet from the
  98.  * far end.
  99.  */
  100.     if ( xfer->transfer_type == XFER_TYPE_KERMIT ) {
  101.        xfer->x.kermit.max_length = KERMIT_MY_MAX_SIZE;
  102.        xfer->x.kermit.timeout = KERMIT_MY_PACKET_TIMEOUT;
  103.        xfer->x.kermit.pad_count = KERMIT_MY_PAD_COUNT;
  104.        xfer->x.kermit.pad_char = KERMIT_MY_PAD_CHAR;
  105.        xfer->x.kermit.eol = KERMIT_MY_EOL;
  106.        xfer->x.kermit.quote_char = KERMIT_MY_QUOTE_CHAR;
  107.        xfer->block_number = 0L;
  108.     }
  109.     if ( _XferAbortKeyPressed( xfer ) )  /* Finally, I check for a keystroke */
  110.         return( FALSE );                 /* and then exit.  Note that the    */
  111.     return( TRUE );                      /* keystroke check will also call   */
  112. }                                        /* the idle routine.                */
  113.  
  114. /*
  115.  * void _XferMessage( XFER *xmodem, const char *format, ... )
  116.  *
  117.  * ARGUMENTS
  118.  *
  119.  *  xmodem:     A pointer to an XFER parameter block for the transfer in
  120.  *              progress.
  121.  *
  122.  * format,...:  This is a printf parameter list, that contains the message
  123.  *              and parameters to be printed out.
  124.  *
  125.  * DESCRIPTION
  126.  *
  127.  * The user message routine gets called at various key points during a transfer.
  128.  * This routine is responsible for formatting the message into a nice ASCII
  129.  * string and sending it to the user message routine.
  130.  *
  131.  * SIDE EFFECTS
  132.  *
  133.  * The user message routine may produce side effects.
  134.  *
  135.  * RETURNS
  136.  *
  137.  * No returns.
  138.  *
  139.  * AUTHOR
  140.  *  Mark Nelson          28-Aug-1989  21:04:40.92
  141.  *
  142.  * MODIFICATIONS
  143.  *
  144.  */
  145.  
  146. void GF_CDECL _XferMessage( XFER *xmodem, const char *format, ... )
  147. {
  148.     char buffer[ 81 ];
  149.     va_list arguments;
  150. /*
  151.  * If there is no message routine defined for this parameter block, I go ahead
  152.  * and quit right now.
  153.  */
  154.     if ( xmodem->message_routine == NULL )
  155.         return;
  156. /*
  157.  * I go through this stuff here in order to format the message for the user
  158.  * defined routine.  I then go ahead and call it, passing it a formatted
  159.  * string.
  160.  */
  161.     va_start( arguments, format );
  162.     vsprintf( buffer, format, arguments );
  163.     xmodem->message_routine( buffer );
  164.     va_end( arguments );
  165. }
  166.  
  167. /*
  168.  * void _XferCleanup( XFER *xfer )
  169.  *
  170.  * ARGUMENTS
  171.  *
  172.  *  xmodem:   A pointer to an XFER parameter block for the transfer in
  173.  *            progress.
  174.  *
  175.  * DESCRIPTION
  176.  *
  177.  * This routine is called when the drivers are ready to exit.  It has
  178.  * several jobs to do.  First of all, it has to close any open files and free
  179.  * any allocated buffers.  After doing that, it sets the pointers to NULL
  180.  * so that they won't be closed again later.  If the return status of
  181.  * the parameter is not set to the SUCCESS code, it means this is the
  182.  * result of a fatal error.  In that case, it spits out a bunch of CAN
  183.  * characters in hopes of causing the other end to abort as well.  Finally,
  184.  * it clears the receive buffer.
  185.  *
  186.  * SIDE EFFECTS
  187.  *
  188.  * Buffer is freed, file is closed.
  189.  *
  190.  * RETURNS
  191.  *
  192.  * No returns.  This routine does the best it can and doesn't complain.
  193.  *
  194.  * AUTHOR
  195.  *  Mark Nelson          28-Aug-1989  21:04:40.92
  196.  *
  197.  * MODIFICATIONS
  198.  *
  199.  */
  200.  
  201. void GF_CONV _XferCleanup( XFER *xfer )
  202. {
  203.     int i;
  204.  
  205.     if ( xfer->file != NULL ) {                   /* If the file is open, I  */
  206.         fclose( xfer->file );                     /* close it up and set it  */
  207.         xfer->file = NULL;                        /* to NULL.                */
  208.     }
  209. /*
  210.  * Finally, I this is a fatal error, and I am in the midst of an XMODEM
  211.  * transfer, I spit out a bunch of CANS to try and abort things on the
  212.  * remote end.  The backspace characters clean up the screen so you don't
  213.  * see all the ^X chars when you exit.  Finally, I flush the input
  214.  * buffer of it's whole load.
  215.  */
  216.     if ( xfer->return_status ) {
  217.         if ( xfer->transfer_type <= XFER_TYPE_YMODEM_G ) {
  218.             for ( i = 0 ; i < 10 ; i++ )
  219.                 asiputc( xfer->port, CAN );
  220.             for ( i = 0 ; i < 10 ; i++ )
  221.                 asiputc( xfer->port, 8 );
  222.         } else {
  223.             if ( xfer->buffer != NULL &&
  224.                  xfer->transfer_type == XFER_TYPE_KERMIT )
  225.                 _KermitSendPacket( xfer, 'E', 0, "" );
  226.         }
  227.         timer( TICKS_PER_SECOND * 1 );
  228.         while ( getrxcnt ( xfer->port ) > 0 )
  229.             asigetc( xfer->port );
  230.     }
  231.  
  232.     if ( xfer->buffer != NULL ) {                 /* If the packet buffer is */
  233.         free( xfer-> buffer );                    /* allocated, I free it up */
  234.         xfer->buffer = NULL;                      /* here and set it to NULL */
  235.     }
  236.  
  237. }
  238.  
  239. /*
  240.  * int _XferFlushInput( XFER *xfer )
  241.  *
  242.  * ARGUMENTS
  243.  *
  244.  *  xfer:     A pointer to an XFER parameter block for the transfer in
  245.  *            progress.
  246.  *
  247.  * DESCRIPTION
  248.  *
  249.  * This routine is nice and simple.  Its job is to read all the characters
  250.  * out of the input buffer.  If the user hits the abort key for some reason,
  251.  * it returns a FALSE, otherwise it returns a TRUE.
  252.  *
  253.  * SIDE EFFECTS
  254.  *
  255.  * The buffer should be empty.
  256.  *
  257.  * RETURNS
  258.  *
  259.  * TRUE if the buffer is flushed okay, FALSE if the user hits the abort key.
  260.  *
  261.  * AUTHOR
  262.  *  Mark Nelson          28-Aug-1989  21:04:40.92
  263.  *
  264.  * MODIFICATIONS
  265.  *
  266.  */
  267.  
  268. int GF_CONV _XferFlushInput( XFER *xfer )
  269. {
  270. /*
  271.  * I have to keep calling the abort key check here to keep from getting locked
  272.  * if the remote end is sending a slow but steady stream of characters.
  273.  */
  274.     while ( asigetc_timed( xfer->port, 18 ) >= 0 ) {
  275.         if ( _XferAbortKeyPressed( xfer ) )
  276.             return( FALSE );
  277.     }
  278.     return( TRUE );
  279. }
  280.  
  281. /*
  282.  * int _XferOpenFile( XFER *xfer )
  283.  *
  284.  * ARGUMENTS
  285.  *
  286.  *  xfer:     A pointer to an XFER parameter block for the transfer in
  287.  *            progress.
  288.  *
  289.  * DESCRIPTION
  290.  *
  291.  * This routine is called to open up a file, either for input or output.
  292.  * This routine checks to see if we are sending or receiving, and sets
  293.  * the access code accordingly.
  294.  *
  295.  * SIDE EFFECTS
  296.  *
  297.  * The file is opened, the parameter block is modified.
  298.  *
  299.  * RETURNS
  300.  *
  301.  * This routine can fail and return FALSE if it is unable to open the
  302.  * file.
  303.  *
  304.  * AUTHOR
  305.  *  Mark Nelson          28-Aug-1989  21:04:40.92
  306.  *
  307.  * MODIFICATIONS
  308.  *
  309.  */
  310.  
  311. int GF_CONV _XferOpenFile( XFER *xfer )
  312. {
  313. /*
  314.  * If the user has defined a return_file_name() function, I call it to
  315.  * get the file name.  Otherwise I just use the filename parameter from
  316.  * the parameter block.
  317.  */
  318.     if ( xfer->return_file_name != NULL )
  319.         xfer->filename = xfer->return_file_name();
  320. /*
  321.  * Now I open the file with the appropriate access mode.  I spit out a
  322.  * message at this point for the calling routine to print.
  323.  */
  324.     if ( xfer->sending )
  325.         xfer->file = fopen( xfer->filename, "rb" );
  326.     else
  327.         xfer->file = fopen( xfer->filename, "wb" );
  328.     _XferMessage( xfer, "Opening file %s", xfer->filename );
  329. /*
  330.  * If I was able to open the file up, I set up the byte count and return the
  331.  * success flag.
  332.  */
  333.     if ( xfer->file != NULL ) {
  334.         xfer->byte_count = 0;
  335.         if ( xfer->sending ) {
  336.             fseek( xfer->file, 0L, SEEK_END );
  337.             xfer->file_length = ftell( xfer->file );
  338.             fseek( xfer->file, 0L, SEEK_SET );
  339.         }
  340.         if ( _XferAbortKeyPressed( xfer) )
  341.             return( FALSE);
  342.         else
  343.             return( TRUE );
  344.     }
  345.  
  346.     xfer->return_status = XFER_RETURN_CANT_OPEN_FILE;   /* If I was not able */
  347.     _XferMessage( xfer, "Failed to open file" );        /* to open the file, */
  348.     _XferCleanup( xfer );                               /* I set the error   */
  349.     return( FALSE );                                    /* code and return a */
  350. }                                                       /* failure.          */
  351.  
  352.  
  353. /*
  354.  * int _XferAbortKeyPressed( XFER *xfer )
  355.  *
  356.  * ARGUMENTS
  357.  *
  358.  *  xfer:     A pointer to an XFER parameter block for the transfer in
  359.  *            progress.
  360.  *
  361.  * DESCRIPTION
  362.  *
  363.  * I like to check the keyboard for the abort key depression often enough
  364.  * so that the user can be sure of being able to break out of the program
  365.  * pretty promptly.  This means this routine gets called all over the place,
  366.  * all the time.  Because I am calling it all the time, I throw in a call
  367.  * to the idle routine too, killing two birds with one stone.  Note that
  368.  * while I am in ASCII receive mode, the pressed keys will get sent on
  369.  * through to the remote end.
  370.  *
  371.  * SIDE EFFECTS
  372.  *
  373.  * If the user hit the abort key, the error flag is set.
  374.  *
  375.  * RETURNS
  376.  *
  377.  * TRUE if the abort key was pressed, else FALSE.
  378.  *
  379.  * AUTHOR
  380.  *  Mark Nelson          28-Aug-1989  21:04:40.92
  381.  *
  382.  * MODIFICATIONS
  383.  *
  384.  */
  385.  
  386. int GF_CONV _XferAbortKeyPressed( XFER *xfer )
  387. {
  388.     unsigned int key;
  389.  
  390.     if ( xfer->idle_routine != NULL )     /* If there is an idle routine for */
  391.         xfer->idle_routine( xfer );       /* this parameter block, I call it */
  392.                                           /* here and let it do its stuff.   */
  393. /*
  394.  * Finally, I read in any and all characters in the input buffer.  Any
  395.  * appearance of the abort key will lead to an abort.
  396.  */
  397.     while ( gfkbhit() ) {
  398.         key = getkey();
  399.         if ( key == xfer->abort_key ) {
  400.             xfer->return_status = XFER_RETURN_KEYBOARD_ABORT;
  401.             _XferMessage( xfer, "User hit abort key" );
  402.             _XferCleanup( xfer );
  403.             return( TRUE );
  404.         } else if ( xfer->transfer_type == XFER_TYPE_ASCII && !xfer->sending )
  405.             asiputc( xfer->port, key );
  406.     }
  407.     return( FALSE );
  408. }
  409.  
  410. /*
  411.  * int _KermitSendPacket( XFER *kermit, char type, int length, char *buffer)
  412.  *
  413.  * ARGUMENTS
  414.  *
  415.  *  char *xfer:     A pointer to an XFER parameter block for the transfer in
  416.  *                  progress.
  417.  *
  418.  *  char type:      The KERMIT buffer type.  These types are defined in
  419.  *                  _KERMITS.C and _KERMITR.C.
  420.  *
  421.  *  int length:     The number of data bytes to be sent.
  422.  *
  423.  *  char *buffer:   A buffer containing all of the bytes to be sent.
  424.  *
  425.  * DESCRIPTION
  426.  *
  427.  * This routine is called to build and send a KERMIT buffer.  It builds
  428.  * up the buffer with all the correct protocol characters, and sends it
  429.  * out through the COM port.  All the routines that send a KERMIT packet
  430.  * have to do it by heading through this guy.
  431.  *
  432.  * SIDE EFFECTS
  433.  *
  434.  * A buffer is sent.
  435.  *
  436.  * RETURNS
  437.  *
  438.  * TRUE if the buffer send went okay, FALSE if something bad happpened.
  439.  * A return of FALSE means the whole protocol should be aborted.
  440.  *
  441.  * AUTHOR
  442.  *  Mark Nelson          28-Aug-1989  21:04:40.92
  443.  *
  444.  * MODIFICATIONS
  445.  *
  446.  */
  447.  
  448. int GF_CONV _KermitSendPacket( XFER *kermit, char type, int length, char *buffer)
  449. {
  450.     int i;
  451.     int j;
  452.  
  453.     i = 0;
  454.     kermit->buffer[ i++ ] = KERMIT_MY_MARK_CHARACTER;
  455.     kermit->buffer[ i++ ] = (char) tochar( length + 3 );
  456.     kermit->buffer[ i++ ] = (char) tochar( kermit->block_number & 0x3f );
  457.     kermit->current_block_number = ( int ) kermit->block_number & 0x3f;
  458.     kermit->buffer[ i++ ] = type;
  459.     for ( j=0 ; j < length ; j++ )
  460.         kermit->buffer[ i++ ] = *buffer++;
  461.     kermit->buffer[ i ] = '\0';
  462.     kermit->current_block_checksum =
  463.         _KermitChecksumCalculate( kermit->buffer+1 );
  464.     kermit->buffer[ i++ ] = (char) tochar( kermit->current_block_checksum );
  465.     kermit->buffer[ i++ ] = kermit->x.kermit.eol;
  466.     kermit->buffer[ i   ] = '\0';
  467.     kermit->current_block_size = length;
  468.  
  469.     for ( i=0 ; i < kermit->x.kermit.pad_count ; i++ ) {
  470.         if ( asiputc( kermit->port, kermit->x.kermit.pad_char ) != ASSUCCESS ) {
  471.             kermit->return_status = XFER_RETURN_CANT_PUT_BUFFER;
  472.             _XferCleanup( kermit );
  473.             return( FALSE );
  474.         }
  475.     }
  476.      asiputs( kermit->port, kermit->buffer, -1 );
  477.      if ( _aserror < ASSUCCESS ) {
  478.         _XferMessage( kermit, "Error sending buffer" );
  479.         kermit->return_status = XFER_RETURN_CANT_PUT_BUFFER;
  480.         _XferCleanup( kermit );
  481.         return( FALSE );
  482.     }
  483.     return( TRUE );
  484. }
  485.  
  486. /*
  487.  * char _KermitReceivePacket(XFER *kermit)
  488.  *
  489.  * ARGUMENTS
  490.  *
  491.  *  char *xfer:     A pointer to an XFER parameter block for the transfer in
  492.  *                  progress.  The buffer received, along with some of the
  493.  *                  information about it are stored in the structure.
  494.  *
  495.  * DESCRIPTION
  496.  *
  497.  * This routine is called to read a KERMIT packet from the remote
  498.  * end.  It reads in the data while observing all the correct protocol
  499.  * stuff, then returns both the packet and a type to the calling program.
  500.  *
  501.  * SIDE EFFECTS
  502.  *
  503.  * A buffer is received.
  504.  *
  505.  * RETURNS
  506.  *
  507.  * This routine follows an informal KERMIT code convention by returning
  508.  * a buffer type.  Most of the buffer types are determined by reading
  509.  * the packet type from the remote end, but a couple are bogus packet
  510.  * types this routine returns when for some reason or another it didn't
  511.  * get a valid packet.
  512.  *
  513.  * For the record, kermit packet types have the following definitions:
  514.  *
  515.  *   S:   The S-Init packet.  One of these comes at the startup phase
  516.  *        and tells us a few things about
  517.  *
  518.  *   F:   This is a file header packet.  It tells me the name of the
  519.  *        file that is about to be sent.
  520.  *
  521.  *   D:   This is a data packet.  Presumably it has stuff that is supposed
  522.  *        to go into the file I have just opened.
  523.  *
  524.  *   Z:   This is an EOF packet.  It means I can close up the file.
  525.  *
  526.  *   B:   This is a break packet.  It means I can now take the connection
  527.  *        down.
  528.  *
  529.  *   E:   This is an error packet.  It contains error text from the
  530.  *        remote end.
  531.  *
  532.  *   Y:   This is an ACK packet.  It usually contains no data, but
  533.  *        an ACK in response to an S packet should contain S data.
  534.  *
  535.  *   N:   This is a NAK packet.  It contains no data.
  536.  *
  537.  *   T:   This is a timeout packet.  A packet didn't really come, it
  538.  *        means the receiver couldn't get any data.
  539.  *
  540.  *   Q:   This is a questionable packet.  A valid packet didn't really
  541.  *        come through.  Something was wrong with it, like a bad checksum.
  542.  *
  543.  *   A:   This is an abort packet.  Usually happens when the user hits
  544.  *        the abort key while reading data.
  545.  *
  546.  * AUTHOR
  547.  *  Mark Nelson          01-Oct-1989  21:04:40.92
  548.  *
  549.  * MODIFICATIONS
  550.  *
  551.  */
  552.  
  553. char GF_CONV _KermitReceivePacket(XFER *kermit)
  554. {
  555.     int i;
  556.     int timeout_timer;
  557.     int c;
  558.  
  559.     timeout_timer = kermit->x.kermit.timeout;
  560.     while ( TRUE ) {
  561.         c = asigetc_timed( kermit->port, 18 );
  562.         if ( _XferAbortKeyPressed( kermit ) )
  563.             return( 'A' );
  564.         if ( c == KERMIT_MY_MARK_CHARACTER )
  565.             break;
  566.         if ( c < 0 ) {
  567.             if ( --timeout_timer == 0 ) {
  568.                 return( 'T' );
  569.             }
  570.         }
  571.     }
  572.     kermit->buffer[ 0 ] = 1;
  573.     i = 1;
  574.     while ( TRUE ){
  575.         c = asigetc_timed( kermit->port, 18 );
  576.         if ( c < 0 ) {
  577.             return( 'T' );
  578.         }
  579.         kermit->buffer[ i++ ] = (char) c;
  580.         if ( c == KERMIT_MY_EOL ) {
  581.             kermit->buffer[ i ] = '\0';
  582.             break;
  583.         }
  584.         else if ( i > 1 && i > ( unchar( kermit->buffer[ 1 ] ) + 1 ) ) {
  585.             kermit->buffer[ i ] = '\0';
  586.             break;
  587.         }
  588.     }
  589.     kermit->current_block_size = unchar( kermit->buffer[ 1 ] ) - 3;
  590.     kermit->current_block_checksum =
  591.         unchar( kermit->buffer[ kermit->current_block_size + 4 ] );
  592.     kermit->current_block_number = unchar( kermit->buffer[ 2 ] );
  593.     kermit->buffer[ kermit->current_block_size + 4 ] = '\0';
  594.     if ( _KermitChecksumCalculate( kermit->buffer + 1 ) !=
  595.         kermit->current_block_checksum ) {
  596.         return( 'Q' );
  597.     }
  598.     if ( _XferAbortKeyPressed( kermit ) )
  599.         return( 'A' );
  600.     return( kermit->buffer[ 3 ] );
  601. }
  602.  
  603. /*
  604.  * int _KermitChecksumCalculate( char *buffer )
  605.  *
  606.  * ARGUMENTS
  607.  *
  608.  *  char *buffer:   A pointer to a buffer that was either received or is
  609.  *                  about to be sent using KERMIT.  This routine calculates
  610.  *                  the checksum for the given packet.  A Kermit checksum
  611.  *                  includes all of the characters in the packet after the
  612.  *                  mark character and before the checksum.
  613.  *
  614.  * DESCRIPTION
  615.  *
  616.  * This routine performs the somewhat wierd additive checksum for a Kermit
  617.  * buffer.  It adds up all the bytes starting with the first one in the
  618.  * buffer passed here, which is the first byte after the mark.  The last
  619.  * byte in this buffer will be the last one before the checksum in the
  620.  * packet.  After the checksum is calculated, the uppper two bits are
  621.  * added to the lower 6 (that's the wierd part), and then returned to
  622.  * the callingf program.
  623.  *
  624.  * SIDE EFFECTS
  625.  *
  626.  *
  627.  * RETURNS
  628.  *
  629.  * This routine follows an informal KERMIT code convention by returning
  630.  * a buffer type.  Most of the buffer types are determined by reading
  631.  * the packet type from the remote end, but a couple are bogus packet
  632.  * types this routine returns when for some reason or another it didn't
  633.  * get a valid packet.
  634.  *
  635.  * AUTHOR
  636.  *  Mark Nelson          01-Oct-1989  21:04:40.92
  637.  *
  638.  * MODIFICATIONS
  639.  *
  640.  */
  641.  
  642. int GF_CONV _KermitChecksumCalculate( char *buffer )
  643. {
  644.     unsigned int checksum;
  645.     unsigned int kermit_checksum;
  646.  
  647.     checksum = 0;
  648.     while ( *buffer != '\0' )
  649.         checksum += *buffer++;
  650.     kermit_checksum = ( checksum & 0xc0 ) >> 6;
  651.     kermit_checksum += checksum;
  652.     kermit_checksum &= 0x3f;
  653.     return( (int) kermit_checksum );
  654. }
  655.  
  656. /*
  657.  * char *_KermitInitParameters(void)
  658.  *
  659.  * ARGUMENTS
  660.  *
  661.  *
  662.  * DESCRIPTION
  663.  *
  664.  * This routine is used to return a pointer to a buffer containing the
  665.  * kermit initialization parameters.  These parameters are sent in the
  666.  * S-Init packet, or in the ACK to an S-Init packet.
  667.  *
  668.  * SIDE EFFECTS
  669.  *
  670.  *
  671.  * RETURNS
  672.  *
  673.  * This routine returns a pointer to a static data buffer that contains
  674.  * the data to be sent in the S-Init packet.
  675.  *
  676.  * AUTHOR
  677.  *  Mark Nelson          01-Oct-1989  21:04:40.92
  678.  *
  679.  * MODIFICATIONS
  680.  *
  681.  */
  682.  
  683. char * GF_CONV _KermitInitParameters( void )
  684. {
  685.     static char data[ 6 ];
  686.  
  687.     data[ 0 ] = tochar( KERMIT_MY_MAX_SIZE );
  688.     data[ 1 ] = tochar( KERMIT_MY_PACKET_TIMEOUT );
  689.     data[ 2 ] = tochar( KERMIT_MY_PAD_COUNT );
  690.     data[ 3 ] = ctl( KERMIT_MY_PAD_CHAR );
  691.     data[ 4 ] = tochar( KERMIT_MY_EOL );
  692.     data[ 5 ] = KERMIT_MY_QUOTE_CHAR;
  693.     return( data );
  694. }
  695.  
  696. /*
  697.  * int _KermitUpdateErrorCount( XFER *kermit )
  698.  *
  699.  * ARGUMENTS
  700.  *
  701.  *  char *xfer:     A pointer to an XFER parameter block for the transfer in
  702.  *                  progress.  The buffer received, along with some of the
  703.  *                  information about it are stored in the structure.
  704.  *
  705.  *
  706.  * DESCRIPTION
  707.  *
  708.  * This routine is called whenever a Kermit non-fatal error is seen.  It
  709.  * increments the total error counter, and checks to see if it has
  710.  * exceeded the maximum error count.  If so, a fatal error occurs.
  711.  *
  712.  * SIDE EFFECTS
  713.  *
  714.  * All sorts of thing happen to the xfer buffer if a fatal error occurs.
  715.  *
  716.  * RETURNS
  717.  *
  718.  * This routine returns a TRUE if everything is okay and processing should
  719.  * continue.  A FALSE means it is time to break down the protocol, things
  720.  * are not working right.
  721.  *
  722.  * AUTHOR
  723.  *  Mark Nelson          01-Oct-1989  21:04:40.92
  724.  *
  725.  * MODIFICATIONS
  726.  *
  727.  */
  728.  
  729. int GF_CONV _KermitUpdateErrorCount( XFER *kermit )
  730. {
  731.     if ( kermit->error_count++ >= KERMIT_MAX_ERRORS ) {
  732.         kermit->return_status = XFER_RETURN_TOO_MANY_ERRORS;
  733.         _XferCleanup( kermit );
  734.         return( FALSE );
  735.     }
  736.     return( TRUE );
  737. }
  738.  
  739. /*
  740.  * void _KermitLoadInitParameters( XFER *kermit )
  741.  *
  742.  * ARGUMENTS
  743.  *
  744.  *  char *xfer:     A pointer to an XFER parameter block for the transfer in
  745.  *                  progress.  The buffer received, along with some of the
  746.  *                  information about it are stored in the structure.
  747.  *
  748.  *
  749.  * DESCRIPTION
  750.  *
  751.  * This routine is called when an S-Init packet, or the ACK to an S-Init
  752.  * packet is received.  This is when the remote end has the opprotunity
  753.  * to send some of his initialization parameters.  I decode them and
  754.  * store them here so I will know what they are when I need them.
  755.  *
  756.  * SIDE EFFECTS
  757.  *
  758.  * Nothing much.
  759.  *
  760.  * RETURNS
  761.  *
  762.  * AUTHOR
  763.  *  Mark Nelson          01-Oct-1989  21:04:40.92
  764.  *
  765.  * MODIFICATIONS
  766.  *
  767.  */
  768.  
  769. void GF_CONV _KermitLoadInitParameters( XFER *kermit )
  770. {
  771.     if ( kermit->current_block_size > 0 )
  772.         kermit->x.kermit.max_length = unchar( kermit->buffer[ 4 ] );
  773.     if ( kermit->current_block_size > 1 )
  774.         kermit->x.kermit.timeout = kermit->buffer[ 5 ];
  775.     if ( kermit->current_block_size > 2 )
  776.         kermit->x.kermit.pad_count = kermit->buffer[ 6 ];
  777.     if ( kermit->current_block_size > 3 )
  778.         kermit->x.kermit.pad_char = ctl( kermit->buffer[ 7 ] );
  779.     if ( kermit->current_block_size > 4 )
  780.         kermit->x.kermit.eol = kermit->buffer[ 8 ];
  781.     if ( kermit->current_block_size > 5 )
  782.         kermit->x.kermit.quote_char = kermit->buffer[ 9 ];
  783. }
  784.