home *** CD-ROM | disk | FTP | other *** search
- /*
- * _XFERC.C
- *
- * These are private routines used by multiple transfer routines.
- *
- * Contains: _XferInitialize()
- * _XferMessage()
- * _XferCleanup()
- * _XferFlushInput()
- * _XferOpenFile()
- * _XferAbortKeyPressed()
- * _KermitSendPacket()
- * _KermitReceivePacket()
- * _KermitChecksumCalculate()
- * _KermitInitParameters()
- * _KermitUpdateErrorCount()
- * _KermitLoadInitParameters()
- *
- *
- * The Greenleaf Comm Library
- *
- * Copyright (C) 1989-90 Greenleaf Software Inc. All Rights Reserved.
- *
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include "gf.h"
- #include "asiports.h"
- #include "ibmkeys.h"
- #include "xfer.h"
- #include "_xfer.h"
-
- /*
- * int _XferInitialize( XFER *xfer )
- *
- * ARGUMENTS
- *
- * xfer: A pointer to an XFER parameter block for the transfer in
- * progress.
- *
- * DESCRIPTION
- *
- * This routine is called to initialize the data structure that is used
- * throughout all of the driver routines. It takes care of setting up
- * the buffers, error codes, error counts, etc.
- *
- * SIDE EFFECTS
- *
- * The parameter block is initialized.
- *
- * RETURNS
- *
- * This routine can fail and return FALSE if it is unable to open the
- * packet buffer, or if the user has pressed the abort key.
- *
- * AUTHOR
- * Mark Nelson 28-Aug-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- int GF_CONV _XferInitialize( XFER *xfer )
- {
- xfer->return_status = XFER_RETURN_SUCCESS; /* Current status is Okay */
- xfer->error_count = 0; /* Clear the error count */
- xfer->file = NULL; /* No open file */
- xfer->current_block_number = -1; /* No packet block number */
- xfer->current_block_size = -1; /* No packet block size */
- xfer->block_number = 1L; /* We are on file block one */
- xfer->byte_count = -1L; /* No bytes transferred yet */
- /*
- * If this is just regular XMODEM or Kermit, I only set up a small input buffer.
- * Otherwise, I go for the large 1K buffer used by everyone else. If
- * there is no space available for a buffer, I clean up my mess, set
- * the error flag, and then exit.
- */
- if ( xfer->transfer_type == XFER_TYPE_XMODEM ||
- xfer->transfer_type == XFER_TYPE_KERMIT ||
- xfer->transfer_type == XFER_TYPE_ASCII )
- xfer->buffer = malloc( 128 );
- else
- xfer->buffer = malloc( 1024 );
- if ( xfer->buffer == NULL ) {
- _XferMessage( xfer, "Failed to allocate XFER buffer(s)" );
- xfer->return_status = XFER_RETURN_CANT_GET_BUFFER;
- _XferCleanup( xfer );
- return( FALSE );
- }
- if ( xfer->transfer_type <= XFER_TYPE_YMODEM_G ) {
- xfer->x.xmodem.last_control_char = -1; /* No control characters yet*/
- }
- /*
- * Finally, if the xfer is a KERMIT type, I set up the defaults for a KERMIT
- * transfer. They will probably all change when I get an S packet from the
- * far end.
- */
- if ( xfer->transfer_type == XFER_TYPE_KERMIT ) {
- xfer->x.kermit.max_length = KERMIT_MY_MAX_SIZE;
- xfer->x.kermit.timeout = KERMIT_MY_PACKET_TIMEOUT;
- xfer->x.kermit.pad_count = KERMIT_MY_PAD_COUNT;
- xfer->x.kermit.pad_char = KERMIT_MY_PAD_CHAR;
- xfer->x.kermit.eol = KERMIT_MY_EOL;
- xfer->x.kermit.quote_char = KERMIT_MY_QUOTE_CHAR;
- xfer->block_number = 0L;
- }
- if ( _XferAbortKeyPressed( xfer ) ) /* Finally, I check for a keystroke */
- return( FALSE ); /* and then exit. Note that the */
- return( TRUE ); /* keystroke check will also call */
- } /* the idle routine. */
-
- /*
- * void _XferMessage( XFER *xmodem, const char *format, ... )
- *
- * ARGUMENTS
- *
- * xmodem: A pointer to an XFER parameter block for the transfer in
- * progress.
- *
- * format,...: This is a printf parameter list, that contains the message
- * and parameters to be printed out.
- *
- * DESCRIPTION
- *
- * The user message routine gets called at various key points during a transfer.
- * This routine is responsible for formatting the message into a nice ASCII
- * string and sending it to the user message routine.
- *
- * SIDE EFFECTS
- *
- * The user message routine may produce side effects.
- *
- * RETURNS
- *
- * No returns.
- *
- * AUTHOR
- * Mark Nelson 28-Aug-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- void GF_CDECL _XferMessage( XFER *xmodem, const char *format, ... )
- {
- char buffer[ 81 ];
- va_list arguments;
- /*
- * If there is no message routine defined for this parameter block, I go ahead
- * and quit right now.
- */
- if ( xmodem->message_routine == NULL )
- return;
- /*
- * I go through this stuff here in order to format the message for the user
- * defined routine. I then go ahead and call it, passing it a formatted
- * string.
- */
- va_start( arguments, format );
- vsprintf( buffer, format, arguments );
- xmodem->message_routine( buffer );
- va_end( arguments );
- }
-
- /*
- * void _XferCleanup( XFER *xfer )
- *
- * ARGUMENTS
- *
- * xmodem: A pointer to an XFER parameter block for the transfer in
- * progress.
- *
- * DESCRIPTION
- *
- * This routine is called when the drivers are ready to exit. It has
- * several jobs to do. First of all, it has to close any open files and free
- * any allocated buffers. After doing that, it sets the pointers to NULL
- * so that they won't be closed again later. If the return status of
- * the parameter is not set to the SUCCESS code, it means this is the
- * result of a fatal error. In that case, it spits out a bunch of CAN
- * characters in hopes of causing the other end to abort as well. Finally,
- * it clears the receive buffer.
- *
- * SIDE EFFECTS
- *
- * Buffer is freed, file is closed.
- *
- * RETURNS
- *
- * No returns. This routine does the best it can and doesn't complain.
- *
- * AUTHOR
- * Mark Nelson 28-Aug-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- void GF_CONV _XferCleanup( XFER *xfer )
- {
- int i;
-
- if ( xfer->file != NULL ) { /* If the file is open, I */
- fclose( xfer->file ); /* close it up and set it */
- xfer->file = NULL; /* to NULL. */
- }
- /*
- * Finally, I this is a fatal error, and I am in the midst of an XMODEM
- * transfer, I spit out a bunch of CANS to try and abort things on the
- * remote end. The backspace characters clean up the screen so you don't
- * see all the ^X chars when you exit. Finally, I flush the input
- * buffer of it's whole load.
- */
- if ( xfer->return_status ) {
- if ( xfer->transfer_type <= XFER_TYPE_YMODEM_G ) {
- for ( i = 0 ; i < 10 ; i++ )
- asiputc( xfer->port, CAN );
- for ( i = 0 ; i < 10 ; i++ )
- asiputc( xfer->port, 8 );
- } else {
- if ( xfer->buffer != NULL &&
- xfer->transfer_type == XFER_TYPE_KERMIT )
- _KermitSendPacket( xfer, 'E', 0, "" );
- }
- timer( TICKS_PER_SECOND * 1 );
- while ( getrxcnt ( xfer->port ) > 0 )
- asigetc( xfer->port );
- }
-
- if ( xfer->buffer != NULL ) { /* If the packet buffer is */
- free( xfer-> buffer ); /* allocated, I free it up */
- xfer->buffer = NULL; /* here and set it to NULL */
- }
-
- }
-
- /*
- * int _XferFlushInput( XFER *xfer )
- *
- * ARGUMENTS
- *
- * xfer: A pointer to an XFER parameter block for the transfer in
- * progress.
- *
- * DESCRIPTION
- *
- * This routine is nice and simple. Its job is to read all the characters
- * out of the input buffer. If the user hits the abort key for some reason,
- * it returns a FALSE, otherwise it returns a TRUE.
- *
- * SIDE EFFECTS
- *
- * The buffer should be empty.
- *
- * RETURNS
- *
- * TRUE if the buffer is flushed okay, FALSE if the user hits the abort key.
- *
- * AUTHOR
- * Mark Nelson 28-Aug-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- int GF_CONV _XferFlushInput( XFER *xfer )
- {
- /*
- * I have to keep calling the abort key check here to keep from getting locked
- * if the remote end is sending a slow but steady stream of characters.
- */
- while ( asigetc_timed( xfer->port, 18 ) >= 0 ) {
- if ( _XferAbortKeyPressed( xfer ) )
- return( FALSE );
- }
- return( TRUE );
- }
-
- /*
- * int _XferOpenFile( XFER *xfer )
- *
- * ARGUMENTS
- *
- * xfer: A pointer to an XFER parameter block for the transfer in
- * progress.
- *
- * DESCRIPTION
- *
- * This routine is called to open up a file, either for input or output.
- * This routine checks to see if we are sending or receiving, and sets
- * the access code accordingly.
- *
- * SIDE EFFECTS
- *
- * The file is opened, the parameter block is modified.
- *
- * RETURNS
- *
- * This routine can fail and return FALSE if it is unable to open the
- * file.
- *
- * AUTHOR
- * Mark Nelson 28-Aug-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- int GF_CONV _XferOpenFile( XFER *xfer )
- {
- /*
- * If the user has defined a return_file_name() function, I call it to
- * get the file name. Otherwise I just use the filename parameter from
- * the parameter block.
- */
- if ( xfer->return_file_name != NULL )
- xfer->filename = xfer->return_file_name();
- /*
- * Now I open the file with the appropriate access mode. I spit out a
- * message at this point for the calling routine to print.
- */
- if ( xfer->sending )
- xfer->file = fopen( xfer->filename, "rb" );
- else
- xfer->file = fopen( xfer->filename, "wb" );
- _XferMessage( xfer, "Opening file %s", xfer->filename );
- /*
- * If I was able to open the file up, I set up the byte count and return the
- * success flag.
- */
- if ( xfer->file != NULL ) {
- xfer->byte_count = 0;
- if ( xfer->sending ) {
- fseek( xfer->file, 0L, SEEK_END );
- xfer->file_length = ftell( xfer->file );
- fseek( xfer->file, 0L, SEEK_SET );
- }
- if ( _XferAbortKeyPressed( xfer) )
- return( FALSE);
- else
- return( TRUE );
- }
-
- xfer->return_status = XFER_RETURN_CANT_OPEN_FILE; /* If I was not able */
- _XferMessage( xfer, "Failed to open file" ); /* to open the file, */
- _XferCleanup( xfer ); /* I set the error */
- return( FALSE ); /* code and return a */
- } /* failure. */
-
-
- /*
- * int _XferAbortKeyPressed( XFER *xfer )
- *
- * ARGUMENTS
- *
- * xfer: A pointer to an XFER parameter block for the transfer in
- * progress.
- *
- * DESCRIPTION
- *
- * I like to check the keyboard for the abort key depression often enough
- * so that the user can be sure of being able to break out of the program
- * pretty promptly. This means this routine gets called all over the place,
- * all the time. Because I am calling it all the time, I throw in a call
- * to the idle routine too, killing two birds with one stone. Note that
- * while I am in ASCII receive mode, the pressed keys will get sent on
- * through to the remote end.
- *
- * SIDE EFFECTS
- *
- * If the user hit the abort key, the error flag is set.
- *
- * RETURNS
- *
- * TRUE if the abort key was pressed, else FALSE.
- *
- * AUTHOR
- * Mark Nelson 28-Aug-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- int GF_CONV _XferAbortKeyPressed( XFER *xfer )
- {
- unsigned int key;
-
- if ( xfer->idle_routine != NULL ) /* If there is an idle routine for */
- xfer->idle_routine( xfer ); /* this parameter block, I call it */
- /* here and let it do its stuff. */
- /*
- * Finally, I read in any and all characters in the input buffer. Any
- * appearance of the abort key will lead to an abort.
- */
- while ( gfkbhit() ) {
- key = getkey();
- if ( key == xfer->abort_key ) {
- xfer->return_status = XFER_RETURN_KEYBOARD_ABORT;
- _XferMessage( xfer, "User hit abort key" );
- _XferCleanup( xfer );
- return( TRUE );
- } else if ( xfer->transfer_type == XFER_TYPE_ASCII && !xfer->sending )
- asiputc( xfer->port, key );
- }
- return( FALSE );
- }
-
- /*
- * int _KermitSendPacket( XFER *kermit, char type, int length, char *buffer)
- *
- * ARGUMENTS
- *
- * char *xfer: A pointer to an XFER parameter block for the transfer in
- * progress.
- *
- * char type: The KERMIT buffer type. These types are defined in
- * _KERMITS.C and _KERMITR.C.
- *
- * int length: The number of data bytes to be sent.
- *
- * char *buffer: A buffer containing all of the bytes to be sent.
- *
- * DESCRIPTION
- *
- * This routine is called to build and send a KERMIT buffer. It builds
- * up the buffer with all the correct protocol characters, and sends it
- * out through the COM port. All the routines that send a KERMIT packet
- * have to do it by heading through this guy.
- *
- * SIDE EFFECTS
- *
- * A buffer is sent.
- *
- * RETURNS
- *
- * TRUE if the buffer send went okay, FALSE if something bad happpened.
- * A return of FALSE means the whole protocol should be aborted.
- *
- * AUTHOR
- * Mark Nelson 28-Aug-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- int GF_CONV _KermitSendPacket( XFER *kermit, char type, int length, char *buffer)
- {
- int i;
- int j;
-
- i = 0;
- kermit->buffer[ i++ ] = KERMIT_MY_MARK_CHARACTER;
- kermit->buffer[ i++ ] = (char) tochar( length + 3 );
- kermit->buffer[ i++ ] = (char) tochar( kermit->block_number & 0x3f );
- kermit->current_block_number = ( int ) kermit->block_number & 0x3f;
- kermit->buffer[ i++ ] = type;
- for ( j=0 ; j < length ; j++ )
- kermit->buffer[ i++ ] = *buffer++;
- kermit->buffer[ i ] = '\0';
- kermit->current_block_checksum =
- _KermitChecksumCalculate( kermit->buffer+1 );
- kermit->buffer[ i++ ] = (char) tochar( kermit->current_block_checksum );
- kermit->buffer[ i++ ] = kermit->x.kermit.eol;
- kermit->buffer[ i ] = '\0';
- kermit->current_block_size = length;
-
- for ( i=0 ; i < kermit->x.kermit.pad_count ; i++ ) {
- if ( asiputc( kermit->port, kermit->x.kermit.pad_char ) != ASSUCCESS ) {
- kermit->return_status = XFER_RETURN_CANT_PUT_BUFFER;
- _XferCleanup( kermit );
- return( FALSE );
- }
- }
- asiputs( kermit->port, kermit->buffer, -1 );
- if ( _aserror < ASSUCCESS ) {
- _XferMessage( kermit, "Error sending buffer" );
- kermit->return_status = XFER_RETURN_CANT_PUT_BUFFER;
- _XferCleanup( kermit );
- return( FALSE );
- }
- return( TRUE );
- }
-
- /*
- * char _KermitReceivePacket(XFER *kermit)
- *
- * ARGUMENTS
- *
- * char *xfer: A pointer to an XFER parameter block for the transfer in
- * progress. The buffer received, along with some of the
- * information about it are stored in the structure.
- *
- * DESCRIPTION
- *
- * This routine is called to read a KERMIT packet from the remote
- * end. It reads in the data while observing all the correct protocol
- * stuff, then returns both the packet and a type to the calling program.
- *
- * SIDE EFFECTS
- *
- * A buffer is received.
- *
- * RETURNS
- *
- * This routine follows an informal KERMIT code convention by returning
- * a buffer type. Most of the buffer types are determined by reading
- * the packet type from the remote end, but a couple are bogus packet
- * types this routine returns when for some reason or another it didn't
- * get a valid packet.
- *
- * For the record, kermit packet types have the following definitions:
- *
- * S: The S-Init packet. One of these comes at the startup phase
- * and tells us a few things about
- *
- * F: This is a file header packet. It tells me the name of the
- * file that is about to be sent.
- *
- * D: This is a data packet. Presumably it has stuff that is supposed
- * to go into the file I have just opened.
- *
- * Z: This is an EOF packet. It means I can close up the file.
- *
- * B: This is a break packet. It means I can now take the connection
- * down.
- *
- * E: This is an error packet. It contains error text from the
- * remote end.
- *
- * Y: This is an ACK packet. It usually contains no data, but
- * an ACK in response to an S packet should contain S data.
- *
- * N: This is a NAK packet. It contains no data.
- *
- * T: This is a timeout packet. A packet didn't really come, it
- * means the receiver couldn't get any data.
- *
- * Q: This is a questionable packet. A valid packet didn't really
- * come through. Something was wrong with it, like a bad checksum.
- *
- * A: This is an abort packet. Usually happens when the user hits
- * the abort key while reading data.
- *
- * AUTHOR
- * Mark Nelson 01-Oct-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- char GF_CONV _KermitReceivePacket(XFER *kermit)
- {
- int i;
- int timeout_timer;
- int c;
-
- timeout_timer = kermit->x.kermit.timeout;
- while ( TRUE ) {
- c = asigetc_timed( kermit->port, 18 );
- if ( _XferAbortKeyPressed( kermit ) )
- return( 'A' );
- if ( c == KERMIT_MY_MARK_CHARACTER )
- break;
- if ( c < 0 ) {
- if ( --timeout_timer == 0 ) {
- return( 'T' );
- }
- }
- }
- kermit->buffer[ 0 ] = 1;
- i = 1;
- while ( TRUE ){
- c = asigetc_timed( kermit->port, 18 );
- if ( c < 0 ) {
- return( 'T' );
- }
- kermit->buffer[ i++ ] = (char) c;
- if ( c == KERMIT_MY_EOL ) {
- kermit->buffer[ i ] = '\0';
- break;
- }
- else if ( i > 1 && i > ( unchar( kermit->buffer[ 1 ] ) + 1 ) ) {
- kermit->buffer[ i ] = '\0';
- break;
- }
- }
- kermit->current_block_size = unchar( kermit->buffer[ 1 ] ) - 3;
- kermit->current_block_checksum =
- unchar( kermit->buffer[ kermit->current_block_size + 4 ] );
- kermit->current_block_number = unchar( kermit->buffer[ 2 ] );
- kermit->buffer[ kermit->current_block_size + 4 ] = '\0';
- if ( _KermitChecksumCalculate( kermit->buffer + 1 ) !=
- kermit->current_block_checksum ) {
- return( 'Q' );
- }
- if ( _XferAbortKeyPressed( kermit ) )
- return( 'A' );
- return( kermit->buffer[ 3 ] );
- }
-
- /*
- * int _KermitChecksumCalculate( char *buffer )
- *
- * ARGUMENTS
- *
- * char *buffer: A pointer to a buffer that was either received or is
- * about to be sent using KERMIT. This routine calculates
- * the checksum for the given packet. A Kermit checksum
- * includes all of the characters in the packet after the
- * mark character and before the checksum.
- *
- * DESCRIPTION
- *
- * This routine performs the somewhat wierd additive checksum for a Kermit
- * buffer. It adds up all the bytes starting with the first one in the
- * buffer passed here, which is the first byte after the mark. The last
- * byte in this buffer will be the last one before the checksum in the
- * packet. After the checksum is calculated, the uppper two bits are
- * added to the lower 6 (that's the wierd part), and then returned to
- * the callingf program.
- *
- * SIDE EFFECTS
- *
- *
- * RETURNS
- *
- * This routine follows an informal KERMIT code convention by returning
- * a buffer type. Most of the buffer types are determined by reading
- * the packet type from the remote end, but a couple are bogus packet
- * types this routine returns when for some reason or another it didn't
- * get a valid packet.
- *
- * AUTHOR
- * Mark Nelson 01-Oct-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- int GF_CONV _KermitChecksumCalculate( char *buffer )
- {
- unsigned int checksum;
- unsigned int kermit_checksum;
-
- checksum = 0;
- while ( *buffer != '\0' )
- checksum += *buffer++;
- kermit_checksum = ( checksum & 0xc0 ) >> 6;
- kermit_checksum += checksum;
- kermit_checksum &= 0x3f;
- return( (int) kermit_checksum );
- }
-
- /*
- * char *_KermitInitParameters(void)
- *
- * ARGUMENTS
- *
- *
- * DESCRIPTION
- *
- * This routine is used to return a pointer to a buffer containing the
- * kermit initialization parameters. These parameters are sent in the
- * S-Init packet, or in the ACK to an S-Init packet.
- *
- * SIDE EFFECTS
- *
- *
- * RETURNS
- *
- * This routine returns a pointer to a static data buffer that contains
- * the data to be sent in the S-Init packet.
- *
- * AUTHOR
- * Mark Nelson 01-Oct-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- char * GF_CONV _KermitInitParameters( void )
- {
- static char data[ 6 ];
-
- data[ 0 ] = tochar( KERMIT_MY_MAX_SIZE );
- data[ 1 ] = tochar( KERMIT_MY_PACKET_TIMEOUT );
- data[ 2 ] = tochar( KERMIT_MY_PAD_COUNT );
- data[ 3 ] = ctl( KERMIT_MY_PAD_CHAR );
- data[ 4 ] = tochar( KERMIT_MY_EOL );
- data[ 5 ] = KERMIT_MY_QUOTE_CHAR;
- return( data );
- }
-
- /*
- * int _KermitUpdateErrorCount( XFER *kermit )
- *
- * ARGUMENTS
- *
- * char *xfer: A pointer to an XFER parameter block for the transfer in
- * progress. The buffer received, along with some of the
- * information about it are stored in the structure.
- *
- *
- * DESCRIPTION
- *
- * This routine is called whenever a Kermit non-fatal error is seen. It
- * increments the total error counter, and checks to see if it has
- * exceeded the maximum error count. If so, a fatal error occurs.
- *
- * SIDE EFFECTS
- *
- * All sorts of thing happen to the xfer buffer if a fatal error occurs.
- *
- * RETURNS
- *
- * This routine returns a TRUE if everything is okay and processing should
- * continue. A FALSE means it is time to break down the protocol, things
- * are not working right.
- *
- * AUTHOR
- * Mark Nelson 01-Oct-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- int GF_CONV _KermitUpdateErrorCount( XFER *kermit )
- {
- if ( kermit->error_count++ >= KERMIT_MAX_ERRORS ) {
- kermit->return_status = XFER_RETURN_TOO_MANY_ERRORS;
- _XferCleanup( kermit );
- return( FALSE );
- }
- return( TRUE );
- }
-
- /*
- * void _KermitLoadInitParameters( XFER *kermit )
- *
- * ARGUMENTS
- *
- * char *xfer: A pointer to an XFER parameter block for the transfer in
- * progress. The buffer received, along with some of the
- * information about it are stored in the structure.
- *
- *
- * DESCRIPTION
- *
- * This routine is called when an S-Init packet, or the ACK to an S-Init
- * packet is received. This is when the remote end has the opprotunity
- * to send some of his initialization parameters. I decode them and
- * store them here so I will know what they are when I need them.
- *
- * SIDE EFFECTS
- *
- * Nothing much.
- *
- * RETURNS
- *
- * AUTHOR
- * Mark Nelson 01-Oct-1989 21:04:40.92
- *
- * MODIFICATIONS
- *
- */
-
- void GF_CONV _KermitLoadInitParameters( XFER *kermit )
- {
- if ( kermit->current_block_size > 0 )
- kermit->x.kermit.max_length = unchar( kermit->buffer[ 4 ] );
- if ( kermit->current_block_size > 1 )
- kermit->x.kermit.timeout = kermit->buffer[ 5 ];
- if ( kermit->current_block_size > 2 )
- kermit->x.kermit.pad_count = kermit->buffer[ 6 ];
- if ( kermit->current_block_size > 3 )
- kermit->x.kermit.pad_char = ctl( kermit->buffer[ 7 ] );
- if ( kermit->current_block_size > 4 )
- kermit->x.kermit.eol = kermit->buffer[ 8 ];
- if ( kermit->current_block_size > 5 )
- kermit->x.kermit.quote_char = kermit->buffer[ 9 ];
- }
-