/**************************************************************************

    FMR version Makeing by ken 89.9.5

***************************************************************************/
#include    <stdio.h>
#include    <time.h>
#include    <string.h>
#include    <fmcfrb.h>
#include    "defs.h"

#define	TRUE	1
#define	FALSE	0
#define	ERR	(-1)

#define	UNSIG	unsigned short
#define unlink	remove

#define	Async_Send(c)	send_aux(c)
#define	Bufferd_Recive	recv_aux
#define	Bufferd_Send(c)	send_aux(c)

void	Bufferd_Flush()
{
}

#define	WRITE_OP     "wb"
#define	READ_OP	     "rb"
#define	UPDATE_OP    "r+b"

extern	unsigned char *cvram;

extern	void	Send_Failure();
extern	int	kbhit();
extern	int	getch();
extern	void	wrtstr();
extern	void	Dmy_form();
extern	void	Dsp_vram();
extern	int	recv_aux();
extern	void	send_aux();

#define STMsg        0
#define STFile       1
#define STUpDow      2
#define STType       3
#define STComSent    4
#define STDataSent   5
#define STErrSent    6
#define STPacSent    7
#define STComRate    8
#define STDataRate   9
#define STElapsed    10

#define STComRead    20
#define STDataRead   21
#define STErrRead    22
#define STPacRead    23
#define STUplSize    24
#define STDowSize    25
#define STUplRem     26
#define STDowRem     27
#define STRemTime    28

int  ST_Check_Abort()
{
    if ( kbhit() != 0 && getch() == '\x1B' )
	    return 1;
    return 0;
}
void    ST_Yes_or_No(arg,yn)
char    *arg;
char    *yn;
{
    wrtstr(arg,17,20,0x02);
    *yn = getch();
}
void    ST_Initialize()
{
    int    i;
    char   tmp[160];
    static char *menu[]={
	"Msg     ","File    ","UpDow   ","Type    ","ComSent ",
	"DataSent","ErrSent ","PacSent ","ComRate ","DataRate",
	"Elapsed ",
	"        ","        ","ComRead ","DataRead","ErrRead ",
	"PacRead ","UplSize ","DowSize ","UplRem  ","DowRem  ",
	"RemTime " };

    Dmy_form(tmp,50,0x98,0x95,0x99); 
    wrtstr(tmp,15,7,0x06);

    Dmy_form(tmp,50,0x96,0x20,0x96); 
    for ( i = 0 ; i < 13 ; i++ )
        wrtstr(tmp,15,8+i,0x06);

    Dmy_form(tmp,50,0x9A,0x95,0x9B); 
    wrtstr(tmp,15,21,0x06);

    wrtstr("  <<< B Plus Protocol(SM) Abort Hit ESC Key >>>",17,8,0x02);

    for ( i = 0 ; i < 22 ; i++ )
	wrtstr(menu[i],17+(i/11)*24,9+(i%11),0x06);
}
void    ST_Terminate()
{
    Dsp_vram(cvram);
}
void    ST_Display_String(no,str)
int	no;
char	*str;
{
    wrtstr(str,27+(no/18)*24,9+(no%18),0x06);
}
void    ST_Display_Value(no,val)
int	no;
long	val;
{
    char     tmp[20];

    if ( no == STElapsed || no == STRemTime ) {
	if ( val >= 3600 )
	    sprintf(tmp,"%2ld:%02ld:%02ld",val/3600,(val%3600)/60,val%60);
	else if ( val >= 60 )
	    sprintf(tmp,"   %2ld:%02ld",val/60,val%60);
	else
	    sprintf(tmp,"      %2ld",val);
    } else
	sprintf(tmp,"%8ld",val);
    ST_Display_String(no,tmp);
}

#define	Def_BS		4	    /* Buffer size 128 x n */
#define Max_SA         	2           /* Maximum number of waiting Packets */
#define Max_Buf_Size   	(Def_BS*128+8) /* Largest data block we can handle */

#define Def_Buf_Size    511         /* Default data block               */
#define Def_WS          1           /* I can send 2 Packets ahead       */
#define Def_WR          1           /* I can receive single send-ahead  */
#define Def_CM          1           /* I can handle CRC                 */
#define Def_DQ          1           /* I can handle non-quoted NUL      */
                                    /* (including the `Tf' Packet       */
#define Def_UR          0           /* I can NOT handle Upload Recovery */
#define Def_FI          1           /* I can handle File Information */

#define max_Errors     	10

#define	bps110		0
#define	bps150		1
#define	bps300		2
#define	bps600		3
#define	bps1200		4
#define	bps1800		5
#define	bps2400		6
#define	bps4800		7
#define	bps9600		8

/* Receive States */

#define   R_Get_DLE       0
#define   R_Get_B         1
#define   R_Get_Seq       2
#define   R_Get_Data      3
#define   R_Get_Check     4
#define   R_Send_ACK      5
#define   R_Timed_Out     6
#define   R_Success       7

/* Send States */

#define   S_Get_DLE       1
#define   S_Get_Num       2
#define   S_Have_ACK      3
#define   S_Get_Packet    4
#define   S_Skip_Packet   5
#define   S_Timed_Out     6
#define   S_Send_NAK      7
#define   S_Send_ENQ      8
#define   S_Send_Data     9

/* Other Constants */

#define   dle   16
#define   etx   03
#define   nak   21
#define   enq   05

typedef struct {
	int	seq;    		/* Packet's sequence number  */
	int	num;    		/* Number of bytes in Packet */
	char	buf[Max_Buf_Size]; 	/* Actual Packet data        */
	} buf_type;

static	time_t	e_timer;
static	int     BP_Auto_Resume = TRUE;
static	int	BP_Use_File_Size = FALSE;
static	long	BP_File_Size=0L;
static	int	PortBps = bps2400;
static	int	seq_num;
static	UNSIG	checksum;
static  char   	His_WS,His_WR,His_BS,His_CM;
static	char	His_QS[8];
static	char	His_DR,His_UR,His_FI;
static	char	Our_WS,Our_WR,Our_BS,Our_CM;
static	char	Our_QS[8];
static	char	Our_DR,Our_UR,Our_FI,Def_DR;
static	int	Port_Update_Rate;
static	int	B_Plus;
static	int	Use_CRC;
static	int	BP_Special_Quoting = 0;
static	int	Buffer_Size;
static	int	SA_Max;
static	int	SA_Error_Count;
static	char	Quote_Table[256];
static	char	BP_Special_Quote_Set[]={
			0x14, 0x00, 0xd4, 0x00,
			0x00, 0x00, 0x00, 0x00 };
static	char	DQ_Full[]={
			0xff, 0xff, 0xff, 0xff,
	   		0xff, 0xff, 0xff, 0xff };
static	char	DQ_Default[]={
        		0x14, 0x00, 0xd4, 0x00,
         		0x00, 0x00, 0x00, 0x00 };
static	char	DQ_Minimal[]={
        		0x14, 0x00, 0xd4, 0x00,
        		0x00, 0x00, 0x00, 0x00 };
static	char	DQ_Extended[]={
			0x14, 0x00, 0xd4, 0x00,
		        0x00, 0x00, 0x50, 0x00 };

static	int     R_Size,ch;
static	int     Timed_Out,Packet_Received,masked;
static	buf_type SA_Buf[Max_SA+1];
static	int     SA_Next_to_ACK;
static	int     SA_Next_to_Fill;
static	int     SA_Waiting;
static	int    	Aborting;
static	char	R_buffer[Max_Buf_Size];
static	char	filename[256];
static	int     S_Counter;
static	int     R_Counter;
static	long    S_Com_Data;
static	long    R_Com_Data;
static	long    S_File_Data;
static  long    R_File_Data;
static	long    S_Packet_Count;
static	long    R_Packet_Count;
static	long    S_Error_Count;
static	long    R_Error_Count;
static	long    S_File_Size;
static	long    R_File_Size;
static	long    S_Remaining;
static	long    R_Remaining;
static	long    Com_Rate;
static	long    Data_Rate;
static	long    Time_Estimate;
static	int	Resume_Flag;
static	UNSIG	crc_16;
static	char	Val_Str[50];
static	int	e_i, e_j, e_n;

UNSIG	crc_table[] = {
        0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
        0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
        0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
        0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
        0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
        0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
        0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
        0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
        0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
        0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
        0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
        0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
        0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
        0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
        0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
        0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
        0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
        0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
        0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
        0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
        0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
        0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
        0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
        0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
        0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
        0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
        0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
        0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
        0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
        0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
        0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
	};

void    ltoa( n, s )
long	n;
char	*s;
{
    char   *t;
    long   i;
    char   c;
    long   sign;
    long   divten;

    if ( (sign = n) < 0 )
    	n = -n;

    t = s;
    do {
    	i = (divten = (n / 10)) * 10;
	*(t++) = ( n - i ) + '0';
    } while( (n = divten) > 0 );

    if( sign < 0 )
    	*(t++) = '-';

    *t = '\0';
    t--;

    while( s < t ) {
	c = *t;
	*(t--) = *s;
	*(s++) = c;
    }
}
static void Clear_Quote_Table()
{
    memset(Quote_Table,0,256);
}
static void Update_Quote_Table (Quote_Set)
char	*Quote_Set;
{
    int	   i, j, k;
    char   b, c;

    c = 0x40;
    k = 0x00;

    for ( i = 0 ; i < 8 ; i++ ) {
	if ( i == 4 ) {
	    c = 0x60;
	    k = 0x80;
	}

	b = Quote_Set[i];

	for ( j = 0 ; j < 8 ; j++ ) {
	    if ( (b & 0x80) != 0)
		Quote_Table[k] = c;

	    b <<= 1;
	    c++;
	    k++;
	}
    }
}

void    BP_Quote_This (Value)
int	Value;
{
    int     i, j;

    if ( (Value >= 0x00 && Value <= 0x1F) ||
	 (Value >= 0x80 && Value <= 0x9f) ) {

	if ( Value > 0x1f ) {
	    i = 4;
    	    Value = Value & 0x1f;
	} else
	    i = 0;

	i = i + Value / 8;
	j = Value % 8;
	BP_Special_Quote_Set[i] |= (0x80 >> j);
	BP_Special_Quoting = TRUE;

    } else if ( Value == (-1) ) {

	for( i=0 ; i < sizeof(DQ_Minimal) ; i++ )
	    BP_Special_Quote_Set[i] = DQ_Minimal[i];

	BP_Special_Quoting = FALSE;
    }
}

void    BP_Term_ENQ()
{
    int     i;

    seq_num = 0;
    Buffer_Size = 512;               /* Set up defaults */
    Our_WS = 0;
    Our_WR = 0;
    Our_BS = 4;
    Our_CM = 0;
    Our_DR = 0;
    Our_UR = 0;
    Our_FI = 0;

    B_Plus      = FALSE;             /* Not B Plus Protocol */
    Use_CRC     = FALSE;             /* Not CRC_16      */
    SA_Max      = 1;                 /* Single Packet send */
    SA_Error_Count = 0;              /* No Upload errors yet */

    for( i = 0 ; i < sizeof(DQ_Minimal) ; i++ )
	Our_QS[i] = DQ_Minimal[i];

    Clear_Quote_Table();
    Update_Quote_Table(Our_QS);

    Async_Send(dle);
    Async_Send('+');
    Async_Send('+');
    Async_Send(dle);
    Async_Send('0');
}

void    BP_Term_ESC_I(esc_I_Res)
char	esc_I_Res[];
{
    int	    i;
    char    t[256];
    int	    cks;

    cks = 0;

    for ( i = 0 ; i < strlen(esc_I_Res) ; i++ ) {
  	Async_Send(esc_I_Res[i]);
	cks += esc_I_Res[i];
    }

    Async_Send (',');
    Async_Send ('+');
    cks = cks + ',' + '+';

    ltoa( (long)cks, t );

    i = 4 - strlen( t );
    while( i-- )
	Async_Send( '0' );

    for ( i = 0 ; i < strlen(t) ; i++ )
	Async_Send(t[i]);

    Async_Send(0x0d);
}

static	int	Init_CRC (value)
int	value;
{
    return( crc_16 = value );
}
static	UNSIG	Upd_CRC (value)
UNSIG	value;
{
    value &= 0xFF;
    crc_16 = crc_table [((crc_16 >> 8) ^ (value)) & 0xff] ^ (crc_16 << 8);
    return( crc_16 );
}
static	void do_checksum (c)
int	c;
{
    c &= 0xFF;
    if ( B_Plus && Use_CRC )
    	checksum = Upd_CRC (c);
    else {
       	checksum <<= 1;
	if (checksum > 255)
    	    checksum = (checksum & 0xff) + 1;
	checksum += c;
	if (checksum > 255)
    	    checksum = (checksum & 0xff) + 1;
    }
}
static	void	send_count()
{
    S_Com_Data++;
    if ( (S_Counter++) >= Port_Update_Rate ) {
	S_Counter = 0;
    	ST_Display_Value (STComSent, S_Com_Data);
    }
}
static	void send_byte (ch)
char   ch;
{
    Async_Send (ch);
    send_count();
}
static	void buf_send_byte (ch)
char   ch;
{
    Bufferd_Send(ch);
    send_count();
}
static void send_masked_byte (ch)
int	ch;
{
    ch &= 0xff;

    if (Quote_Table [ch] != 0) {
    	buf_send_byte(dle);
	buf_send_byte(Quote_Table[ch]);
    } else
	buf_send_byte(ch);
}
static void Send_ACK()
{
    send_byte(dle);
    send_byte(seq_num + '0');
}
static void Send_NAK()
{
    send_byte(nak);
}
static void Send_ENQ()
{
    send_byte(enq);
}
static int read_byte()
{
    int     chx;
    int     Hiber;
    time_t  start,now;

    Timed_Out = FALSE;

    if ( (chx = Bufferd_Recive()) != ERR )
	goto ENDOF;

    time(&start);

    if ( !Aborting )
	Hiber = 10;
    else
	Hiber = 5;

    while ( (chx = Bufferd_Recive()) == ERR ) {
        time(&now);
	if ( (now - start) >= Hiber ) {
	    Timed_Out = TRUE;
	    return( FALSE );
	}
    }

ENDOF:
    ch = chx;
    R_Com_Data++;
    if ( (R_Counter++) >= Port_Update_Rate ) {
	R_Counter = 0;
	ST_Display_Value(STComRead, R_Com_Data);
    }
    return(TRUE);
}
static int read_masked_byte()
{
    masked = FALSE;

    if ( read_byte() == FALSE )
    	return(FALSE);

    if ( ch == dle ) {
	if (read_byte() == FALSE)
    	    return(FALSE);
	if ( ch < 0x60 )
	    ch &= 0x1f;
	else
	    ch = (ch & 0x1F) | 0x80;
	masked = TRUE;
    }
    return(TRUE);
}
static	int Incr_Seq (value)
int	value;
{
    if ( value == 9 )
	return( 0);
    else
	return(value + 1);
}
static	int	Read_Packet (Lead_in_Seen, From_Send_Packet)
int	Lead_in_Seen;
int	From_Send_Packet;
{
    int	    State,
	    next_seq,
	    block_num,
	    errors,
	    new_cks;
    int	    i;
    int	    NAK_Sent;

    if ( Packet_Received ) {
	Packet_Received = FALSE;
	return( TRUE);
    }

    NAK_Sent = FALSE;
    memset(R_buffer,0,Buffer_Size);
    next_seq = (seq_num +  1) % 10;
    errors = 0;
    i = 0;

    if ( Lead_in_Seen )
	State = R_Get_Seq;
    else
	State = R_Get_DLE;

    while( TRUE ) {
	switch ( State ) {
	case R_Get_DLE :
	    if ( ST_Check_Abort() && !Aborting ) {
		ST_Display_String(STMsg,"Aborting download per your request");
	        Send_Failure ("AAborted by user");
		return(FALSE);
	    }
	    if ( !read_byte() )
		State = R_Timed_Out;
	    else if ((ch & 0x7F) == dle )
		State = R_Get_B;
	    else if ((ch & 0x7F) == enq )
		State = R_Send_ACK;
	    break;

	case R_Get_B :
	    if ( !read_byte() )
		State = R_Timed_Out;
	    else if ((ch & 0x7F) == 'B')
		State = R_Get_Seq;
	    else if (ch == enq)
		State = R_Send_ACK;
	    else if (ch == ';') {
		ST_Display_Value (STComRead, R_Com_Data);
		State = R_Get_DLE;
	    } else
		State = R_Get_DLE;
	    break;

	case R_Get_Seq :
	    if ( Resume_Flag ) {
		time(&e_timer);
		R_Com_Data = 2;
	    }
	    if ( !read_byte() )
		State = R_Timed_Out;
	    else if ( ch == enq)
		State = R_Send_ACK;
	    else {
		if (B_Plus && Use_CRC)
		    checksum = Init_CRC(0xffff);
		else
		    checksum = 0;
		block_num = ch - '0';
		do_checksum (ch);
		i = 0;
		State = R_Get_Data;
	    }
	    break;

	case R_Get_Data :
	    if ( !read_masked_byte() )
		State = R_Timed_Out;
	    else if ( (ch == etx) && !masked ) {
		do_checksum (etx);
		State = R_Get_Check;
	    } else {
		if ( i < Max_Buf_Size ) {
		    R_buffer[i] = ch;
		    i++;
		    do_checksum (ch);
		}
	    }
	    break;

	case R_Get_Check :
	    if ( !read_masked_byte() )
		State = R_Timed_Out;
	    else {
		if ( B_Plus && Use_CRC ) {
		    checksum = Upd_CRC(ch);
		    if ( !read_masked_byte() )
			new_cks = checksum ^ 0xff;
		    else {
			checksum = Upd_CRC(ch);
			new_cks = 0;
	    	    }
		} else
		    new_cks = ch;

		if (new_cks != checksum) {
		    ST_Display_String(STMsg,"CRC No Match!");
		    State = R_Timed_Out;
		} else if (R_buffer[0] == 'F') /* Watch for Failure Packet */
		    State = R_Success;	 /* which is accepted regardless */
		else if (block_num == seq_num) /* Watch for duplicate block */
		    State = R_Send_ACK; /* Simply ACK it */
		else if (block_num != next_seq)
		    State = R_Timed_Out; /* Bad seq num */
		else
		    State = R_Success;
	    }
	    break;

	case R_Timed_Out :
	    errors++;
	    if ( (errors > max_Errors) || (From_Send_Packet) )
		return( FALSE );
	    if ( !NAK_Sent || !B_Plus ) {
		R_Error_Count++;
		ST_Display_Value (STErrRead, R_Error_Count);
		NAK_Sent = TRUE;
		Send_NAK();
	    }
	    State = R_Get_DLE;
	    break;

	case R_Send_ACK :
	    if ( !Aborting )
		Send_ACK();
	    State = R_Get_DLE;        /* wait for the next block */
    	    break;

	case R_Success :
	    ST_Display_Value (STComRead, R_Com_Data);
	    ST_Display_Value (STComSent, S_Com_Data);
	    if ( !Aborting )
		seq_num = block_num;
	    R_Size = i;
	    R_Packet_Count++;
	    ST_Display_Value (STPacRead, R_Packet_Count);
	    return(TRUE);
	    break;

	}
    }

} /* Read_Packet */

static	void Send_Data (BuffeR_Number)
int	BuffeR_Number;
{
    int	    i;
    buf_type *p;

    p = &SA_Buf[BuffeR_Number];

    if (B_Plus && Use_CRC)
	checksum = Init_CRC (0xffff);
    else
	checksum = 0;

    buf_send_byte (dle);
    buf_send_byte ('B');
    buf_send_byte (p->seq + '0');
    do_checksum (p->seq + '0');

    for (i = 0; i <= p->num; i++ ) {
	send_masked_byte (p->buf [i]);
	do_checksum (p->buf[i]);
    }

    buf_send_byte (etx);
    do_checksum (etx);

    if (B_Plus && Use_CRC)
	send_masked_byte (checksum >> 8);

    send_masked_byte (checksum);

    Bufferd_Flush();
}
static	int	Incr_SA (Old_Value)
int	Old_Value;
{
    if (Old_Value == Max_SA)
	return(0);
    else
	return(Old_Value + 1);
}

#define	  Get_First_DLE     1
#define	  Get_First_Digit   2
#define	  Get_Second_DLE    3
#define	  Get_Second_Digit  4

static	int	ReSync()
{
    int	    State,Digit_1;

    send_byte (enq);     /* Send <ENQ><ENQ> */
    send_byte (enq);
    State = Get_First_DLE;

    while(1) {
	switch (State) {

	case Get_First_DLE :
	    if ( !read_byte() )
		return(-1);
	    if ( ch == dle )
		State = Get_First_Digit;
	    break;

	case Get_First_Digit :
	    if ( !read_byte() )
		return(-1);
	    if ( (ch >= '0') && (ch <= '9') ) {
		Digit_1 = ch;
		State = Get_Second_DLE;
	    } else if (ch == 'B')
		return( ch );
	    break;

	case Get_Second_DLE :
	    if ( !read_byte() )
		return(-1);
	    if ( ch == dle )
		State = Get_Second_Digit;
	    break;

	case Get_Second_Digit :
	    if ( !read_byte() )
		return(-1);
	    if ( (ch >= '0') && (ch <= '9') ) {
		if (Digit_1 == ch  )
		    return(ch);
		else if (ch == 'B')
		    return( ch );
		else {
		    Digit_1 = ch;
		    State = Get_Second_DLE;
	 	}
	    } else
		State = Get_Second_DLE;
	    break;

	} /* case */
    }  /* while TRUE */
}

static	int	Get_ACK()
{
    int	    State,
	    errors,
	    block_num,
	    i;
    int	    Sent_ENQ;
    int	    SA_Index;

    Packet_Received = FALSE;
    errors = 0;
    Sent_ENQ = FALSE;
    State = S_Get_DLE;

    while ( 1 ) {
	switch (State) {
	case S_Get_DLE :
	    if ( ST_Check_Abort() && !Aborting ) {
		ST_Display_String (STMsg,
				"Aborting the upload per your request");
		Send_Failure ("AAborted by user");
		return(FALSE);
	    }
	    if ( !read_byte() )
		State = S_Timed_Out;
	    else {
		if ( ch == dle )
		    State = S_Get_Num;
		else if (ch == nak )
		    State = S_Send_ENQ;
		else if (ch == etx )
		    State = S_Send_NAK;
	    }
	    break;

	case S_Get_Num :
	    if (!read_byte() )
		State = S_Timed_Out;
	    else if ( (ch >= '0') && (ch <= '9') )
		State = S_Have_ACK;           /* Received ACK */
	    else if ( ch == 'B' ) {
		if (!Aborting)
		    State = S_Get_Packet; /* Try to receive a Packet */
		else
		    State = S_Skip_Packet;   /* Try to skip a Packet */
	    } else if (ch == nak)
		State = S_Send_ENQ;
	    else if (ch == ';') {
		ST_Display_Value (STComRead, R_Com_Data);
		State = S_Get_DLE;
	    } else
		State = S_Timed_Out;
	    break;

	case S_Get_Packet :
	    if (Read_Packet (TRUE, TRUE) ) {
		Packet_Received = TRUE;
		if (R_buffer [0] == 'F') {
		    Send_ACK();
		    return(FALSE);
		}
		State = S_Get_DLE;     /* Stay here to find the ACK */
	    } else
		State = S_Get_DLE;
	    break;

	case S_Skip_Packet :    /* Skip an incoming Packet */
	    if (!read_byte())
		State = S_Timed_Out;
	    else if (ch == etx ) {
		if (!read_masked_byte())
		    State = S_Timed_Out;
		else if (!Use_CRC)
		    State = S_Get_DLE;
		else if (!read_masked_byte())
		    State = S_Timed_Out;
		else
		    State = S_Get_DLE;
	    }
	    break;

	case S_Have_ACK :
	    block_num = ch - '0';
	    ST_Display_Value (STComSent, S_Com_Data);
	    ST_Display_Value (STComRead, R_Com_Data);

	    if ( SA_Buf[SA_Next_to_ACK].seq == block_num  ) {
		SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
		SA_Waiting = SA_Waiting - 1;

		if (SA_Error_Count > 0 )
    	    	    SA_Error_Count--;
		return(TRUE);
	    } else if ( (SA_Buf[Incr_SA(SA_Next_to_ACK)].seq == block_num) &&
			 SA_Waiting == 2) {
		SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
		SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
		SA_Waiting = SA_Waiting - 2;
		if (SA_Error_Count > 0)
		    SA_Error_Count--;
 		return(TRUE);

	    } else if ( SA_Buf[SA_Next_to_ACK].seq == Incr_Seq(block_num) ) {
		if ( Sent_ENQ )
		    State = S_Send_Data; /* Remote missed first block */
		else
		    State = S_Get_DLE;       /* Duplicate ACK */
	    } else {
		if ( !Aborting )        /* While aborting, ignore any */
		    State = S_Timed_Out; /* ACKs that have been sent   */
		else
		    State = S_Get_DLE;	/* which are not for the failure */
	    }       	                            /* Packet. */
	    Sent_ENQ = FALSE;
	    break;

	case S_Timed_Out :
	    State = S_Send_ENQ;
	    break;

	case S_Send_NAK :
	    errors++;
	    S_Error_Count++;
	    ST_Display_Value (STErrSent, S_Error_Count);
	    if (errors > max_Errors)
		return(FALSE);
	    Send_NAK();
	    State = S_Get_DLE;
	    break;

	case S_Send_ENQ :
	    errors++;
	    S_Error_Count++;
	    ST_Display_Value (STErrSent, S_Error_Count);
	    if ( (errors > max_Errors) || (Aborting && (errors > 3)) )
		return(FALSE);
	    ch = ReSync();
	    if ( ch == (-1) )
		State = S_Get_DLE;
	    else if (ch == 'B') {
		if( !Aborting )
		    State = S_Get_Packet;   /* Try to receive a Packet */
		else
		    State = S_Skip_Packet;  /* Try to skip a Packet */
	    } else
		State = S_Have_ACK;
	    Sent_ENQ   = TRUE;
	    break;

	case S_Send_Data :
	    SA_Error_Count += 3;
	    if (SA_Error_Count >= 12) /* Stop Upload Send Ahead if too many */
		SA_Max = 1;           /* errors have occured */
	    SA_Index = SA_Next_to_ACK;
	    for ( i = 1 ; i <= SA_Waiting ; i++ ) {
		Send_Data (SA_Index);
       		SA_Index = Incr_SA (SA_Index);
	    }
	    State = S_Get_DLE;
	    Sent_ENQ = FALSE;
	    break;
	}
   }
} /* Get_ACK */

static	int	send_Packet (size)
int	size;
{
    while ( SA_Waiting >= SA_Max ) {
	if ( !Get_ACK() )
	    return(FALSE);
    }

    seq_num = Incr_Seq (seq_num);
    SA_Buf [SA_Next_to_Fill].seq = seq_num;
    SA_Buf [SA_Next_to_Fill].num = size;
    Send_Data (SA_Next_to_Fill);
    SA_Next_to_Fill = Incr_SA (SA_Next_to_Fill);
    SA_Waiting = SA_Waiting + 1;
    S_Packet_Count++;
    ST_Display_Value (STComSent, S_Com_Data);
    ST_Display_Value (STPacSent, S_Packet_Count);
    return(TRUE);
}

static	int	SA_Flush()
{
    while ( SA_Waiting > 0 ) {
	if ( !Get_ACK() )
	    return(FALSE);
    }
    return( TRUE );
}

static	void Send_Failure (Reason)
char	Reason[];
{
    int	    i;
    buf_type *p;

    SA_Next_to_ACK = 0;
    SA_Next_to_Fill = 0;
    SA_Waiting = 0;
    Aborting   = TRUE;          /* Inform Get_ACK we're aborting ]*/

    p = &SA_Buf [0];
    p->buf [0] = 'F';
    for ( i = 1 ; i <= strlen(Reason) ; i++ )
	p->buf [i] = (Reason [i]);

    if ( send_Packet (strlen(Reason)) )
	SA_Flush();   /* Gotta wait for the Initiator to ACK it */
}

static	int	Send_File (name)
char	name[];
{
    int	    n;
    FILE    *data_File;
    buf_type *p;
    time_t now;

    data_File = fopen (name,READ_OP);

    if ( data_File == 0 ) {
	ST_Display_String (STMsg, "Cannot find that file");
	Send_Failure ("MFile not found");
	return(FALSE);
    }

    fseek(data_File,0L,2);  	    /* seek to end of file */
    S_Remaining = ftell(data_File); /* how long is this file ? */
    fseek(data_File,0L,0);  	    /* back to the start, ready to go */
    ST_Display_Value (STUplRem, S_Remaining);

    S_Com_Data = 0;
    R_Com_Data = 0;
    time(&e_timer);

    do {
	p = &SA_Buf [SA_Next_to_Fill];
	p->buf [0] = 'N';
	n = fread (&p->buf[1], 1, Buffer_Size, data_File);

	if ( n > 0 ) {
	    if (send_Packet (n) == FALSE) {
		fclose(data_File);
		return(FALSE);
	    }

	    S_File_Data = S_File_Data +  (n);
	    S_File_Size = S_File_Size +  (n);
	    S_Remaining = S_Remaining -  (n);
	    ST_Display_Value (STUplSize, S_File_Size);
	    ST_Display_Value (STDataSent, S_File_Data);
	    ST_Display_Value (STUplRem, S_Remaining);
	    time(&now);
	    Time_Estimate = now - e_timer;
	    ST_Display_Value (STElapsed, Time_Estimate);

	    if ( Time_Estimate != 0 ) {
		Com_Rate = S_Com_Data / Time_Estimate;
		Data_Rate = S_File_Data / Time_Estimate;
		ST_Display_Value (STComRate, Com_Rate);
		ST_Display_Value (STDataRate, Data_Rate);

		if ( Data_Rate != 0 ) {
		    Time_Estimate = S_Remaining / Data_Rate;
		    ST_Display_Value (STRemTime, Time_Estimate);
       		}
	    }
	}
    } while(n > 0);

    if ( ferror(data_File) != 0) {
	Send_Failure ("EFile read failure");
	ST_Display_String (STMsg, "Read failure...aborting");
	fclose(data_File);
	return(FALSE);
    }

    p = &SA_Buf [SA_Next_to_Fill];
    p->buf [0] = 'T';
    p->buf [1] = 'C';

    if ( send_Packet (2) == FALSE ) {
	fclose (data_File);
	return(FALSE);
    } else {
	fclose (data_File);
	if (!SA_Flush())
	    return(FALSE);
	return(TRUE);
    }

} /* Send_File */

static	void Do_Transport_Parameters()
{
    int	    Quote_Set_Present;
    int     i;
    buf_type *p;

    if (BP_Special_Quoting) {
	for ( i = 0 ; i < 8 ; i++ )
	    Our_QS[i] = BP_Special_Quote_Set[i];
    } else {
	for ( i = 0 ; i < 8 ; i++ )
	    Our_QS[i] = DQ_Minimal[i];
    }

    for ( i = R_Size + 1; i<=512; i++ )
	R_buffer [i] = 0;

    His_WS = R_buffer [1];     /* Pick out Initiator's parameters */
    His_WR = R_buffer [2];
    His_BS = R_buffer [3];
    His_CM = R_buffer [4];

    His_QS [0] = R_buffer [7];
    His_QS [1] = R_buffer [8];
    His_QS [2] = R_buffer [9];
    His_QS [3] = R_buffer [10];
    His_QS [4] = R_buffer [11];
    His_QS [5] = R_buffer [12];
    His_QS [6] = R_buffer [13];
    His_QS [7] = R_buffer [14];

    His_DR = R_buffer [15];
    His_UR = R_buffer [16];
    His_FI = R_buffer [17];

    Quote_Set_Present = (R_Size >= 14 ? TRUE:FALSE);

    p = &(SA_Buf[SA_Next_to_Fill]);
    p->buf [0] = '+';  /* Prepare to return Our own parameters */
    p->buf [1] = Def_WS;
    p->buf [2] = Def_WR;
    p->buf [3] = Def_BS;
    p->buf [4] = Def_CM;
    p->buf [5] = Def_DQ;
    p->buf [6] = 0;          /* No transport layer here */

    for ( i = 0 ; i <= 7 ; i++ )
	p->buf[i + 7] = Our_QS[i];

    if ( BP_Auto_Resume )      /* Set Download Resume according to */
	Def_DR = 2;       /* user's preference */
    else
	Def_DR = 1;

    p->buf [15] = Def_DR;
    p->buf [16] = Def_UR;
    p->buf [17] = Def_FI;

    Update_Quote_Table (DQ_Full);   /* Send the + Packet w/ full quoting */

    if ( !send_Packet(17) )
	return;

    if ( SA_Flush() ) {         /* Wait for host's ACK on Our Packet */
	Our_WR = His_WS < Def_WR ? His_WS:Def_WR;
	Our_WS = His_WR < Def_WS ? His_WR:Def_WS;
	Our_BS = His_BS < Def_BS ? His_BS:Def_BS;
	Our_CM = His_CM < Def_CM ? His_CM:Def_CM;
	Our_DR = His_DR < Def_DR ? His_DR:Def_DR;
	Our_UR = His_UR < Def_UR ? His_UR:Def_UR;
	Our_FI = His_FI < Def_FI ? His_FI:Def_FI;
	if (Our_BS == 0)
	    Our_BS = 4;    /* Default */

	Buffer_Size = Our_BS * 128;
	B_Plus = TRUE;

	if (Our_CM == 1)
	    Use_CRC = TRUE;

	if (Our_WS != 0)
	    SA_Max = Max_SA;
    }

    Clear_Quote_Table();            /* Restore Our Quoting Set */
    Update_Quote_Table (Our_QS);

    if ( Quote_Set_Present )     /* Insert Initiator's Quote Set */
	Update_Quote_Table (His_QS);
}

static	void Check_Keep (data_File, Name)
FILE	*data_File;
char	Name[];
{
    char    yn;
    char    str[256];

    fclose (data_File);

    if ( (!BP_Auto_Resume) || (!B_Plus) || (Our_DR == 0) ) {
	strcpy( str, "Do you wish to retain the partial " );
	strcat( str, Name );
	strcat( str, "?" );
	ST_Yes_or_No( str, &yn );
    } else
	yn = 'Y';

    if ( yn == 'N' || yn == 'n' ) {
	unlink ( Name );
	ST_Display_String (STMsg, "File erased.");
    } else {
	ST_Display_String (STMsg, "File retained.");
    }
}

static void Extract_String()   /* Extract next string of characters */
{
    int	    Digit_Seen;

    Digit_Seen = FALSE;
    e_j = 0;

    while ( e_i <= e_n ) {
	if ( (R_buffer [e_i] >= '0') && (R_buffer [e_i] <= '9') ) {
	    Digit_Seen = TRUE;
	    e_j++;
	    Val_Str [e_j] = R_buffer [e_i];
	} else if ( Digit_Seen ) {
	    Val_Str [0] = e_j;
	    return;
	}
	e_i++;
    }
}

static	void Process_File_Information()
{
    int	    i;

    e_n = R_Size - 1;
    e_i = 4;       	/* Skip data type and compression flag */
    Extract_String();
/*  Val (Val_Str, R_Remaining, e_j); */
    R_Remaining = 0;
    for ( i = 1 ; i <= e_j ; i++ )
	R_Remaining = (R_Remaining * 10) + (Val_Str[i] - '0');

    R_Remaining = R_Remaining - R_File_Size;  /* Adjust for Dow Resume */
    ST_Display_Value (STDowRem, R_Remaining);
    S_Packet_Count = 0;
    R_Packet_Count = 0;
}

static	int	Receive_File (Name)
char	Name[];
{
    FILE    *Data_File;
    int	    status;
    long    File_Length=0L;      /* For download resumption */
    char    Work_String[256];
    int	    Packet_Len;
    int	    i, n;
    char    yn;
    char    Dow_Type;
    buf_type *p;
    time_t  now;

    Dow_Type = 'D';         /* Assume normal downloading */

    Data_File = fopen( Name, UPDATE_OP );	/* open for r/w first */

    if ( Data_File != NULL ) {
	if ( (Our_DR > 1) && BP_Auto_Resume )
	    Dow_Type = 'R';  /* Remote supports `Tf', let's try */
	else if ( Our_DR > 0 ) {
	    ST_Display_String (STMsg, "File already exists.");
	    ST_Yes_or_No ("Do you wish to resume downloading? ", &yn);

	    if ( yn == 'Y' || yn == 'y' )
		Dow_Type = 'R';
	    else
		ST_Display_String (STMsg, "File being overwritten.");
	}
    }

    switch( Dow_Type ) {
    case 'D':
	if( Data_File )
	    fclose( Data_File );    /* close the read/write file */
	Data_File = fopen( Name, WRITE_OP );	    /* open for write */
	if (Data_File == NULL) {
	    Send_Failure ("CCannot create file");
	    return(FALSE);
	}
	Send_ACK();
	break;

    case 'R' :                     /* Resume download */
	ST_Display_String (STMsg, "Calculating CRC");
	p = &SA_Buf [SA_Next_to_Fill];
	if ( Dow_Type == 'R' ) {
	    checksum = Init_CRC (0xffff);
	    do {
		n = fread (&p->buf [0], 1, Buffer_Size, Data_File);
		for ( i = 0 ; i < n ; i++ )
		    checksum = Upd_CRC(p->buf[i]);
	    } while( n > 0 );
	} else
	    checksum = 0;

	p->buf [0] = 'T';
	p->buf [1] = 'r';

	Packet_Len = 2;
	File_Length = ftell(Data_File);

	ltoa (File_Length, Work_String);
	strcat( Work_String, " " );

	for ( i = 0 ; i < strlen(Work_String); i++ ) {
	    p->buf [Packet_Len] = Work_String [i];
	    Packet_Len++;
	}

	ltoa ((long)checksum, Work_String);
	strcat( Work_String, " " );

	for ( i = 0 ; i < strlen(Work_String) ; i++ ) {
	    p->buf [Packet_Len] = Work_String [i];
	    Packet_Len++;
	}

	if ( !send_Packet (Packet_Len - 1) ) {
	    fclose (Data_File);
	    return(FALSE);
	}
	if ( !SA_Flush() ) {
	    fclose (Data_File);
	    return(FALSE);
	}

	R_File_Size = File_Length;
	ST_Display_Value (STDowSize, R_File_Size);
	ST_Display_String (STMsg, "Host calculating CRC...");
	Resume_Flag = TRUE;
	break;
    }
/*
  Process each incoming Packet until 'TC' Packet received or failure
*/
    R_Packet_Count = 0;
    S_Packet_Count = 0;

    if( BP_Use_File_Size )
	R_Remaining = BP_File_Size;
    else
	R_Remaining = 0;

    while ( TRUE ) {
	if ( Read_Packet (FALSE, FALSE) ) {
	    switch (R_buffer[0]) {
            case 'N' :
		if ( Resume_Flag ) {
		    ST_Display_String( STMsg, "Resuming Download" );
		    Resume_Flag = FALSE;
		}
		status = fwrite( &R_buffer[1], 1, R_Size - 1, Data_File );

		if ( (status != (R_Size - 1)) ) {
		    ST_Display_String (STMsg, "Write failure...aborting");
		    Send_Failure ("EWrite failure");
		    Check_Keep (Data_File, Name);
		    return(FALSE);
                }
                R_File_Data = R_File_Data + (R_Size - 1);
		ST_Display_Value (STDataRead, R_File_Data);
                R_File_Size = R_File_Size +  (status);
                ST_Display_Value (STDowSize, R_File_Size);
                time(&now);
		Time_Estimate = now - e_timer;
                ST_Display_Value (STElapsed, Time_Estimate);

		if ( Time_Estimate != 0 ) {
		    Com_Rate = R_Com_Data / Time_Estimate;
                    Data_Rate = R_File_Data / Time_Estimate;
                    ST_Display_Value (STComRate, Com_Rate);
                    ST_Display_Value (STDataRate, Data_Rate);
		} else
		    Data_Rate = 0;

		if ( R_Remaining != 0 ) {
		    R_Remaining = R_Remaining - (R_Size - 1);
                    ST_Display_Value (STDowRem, R_Remaining);
		    if ( Data_Rate != 0 ) {
			Time_Estimate = R_Remaining / Data_Rate;
                        ST_Display_Value (STRemTime, Time_Estimate);
                    }
		}
                Send_ACK();
                break;

            case 'T' :
		if (R_buffer[1] == 'C') {
		    ST_Display_String (STMsg, "*** Transfer Complete ***");
                    status = fclose (Data_File);

                    if ( status == EOF ) {
			ST_Display_String (STMsg, 
				"Failure during close...aborting");
			Send_Failure ("EError during close");
                        Check_Keep (Data_File, Name);
                        return(FALSE);
		    }

                    Send_ACK();
                    return(TRUE);
                } else if ( R_buffer [1] == 'I' ) {
		    Send_ACK();
		    Process_File_Information();
		} else if ( (R_buffer [1] == 'f') && BP_Auto_Resume ) {
		    fclose (Data_File);       /* So...replace the file */
		    Data_File = fopen(Name, WRITE_OP);
		    if ( Data_File == NULL ) {
			Send_Failure ("CCannot create file");
			ST_Display_String (STMsg,
				"CRC check failed; cannot create file");
			return(FALSE);
		    }
		    if (Our_FI != 0 || BP_Use_File_Size)
                        R_Remaining = R_Remaining + R_File_Size;

                    R_File_Size = 0;
                    ST_Display_String (STMsg,
				"CRC check failed; overwriting file");
		    Resume_Flag = FALSE;
		    time(&e_timer);
		    S_Com_Data = 0;
		    R_Com_Data = 0;
                    Send_ACK();
		} else {
                    ST_Display_String (STMsg,
				"Invalid termination Packet...aborting");
                    Send_Failure ("NInvalid T Packet");
                    Check_Keep (Data_File, Name);
                    return(FALSE);
		}
		break;

	    case 'F' :
		Send_ACK();
                ST_Display_String (STMsg,
				"Failure Packet received...aborting");
                Check_Keep (Data_File, Name);
                return(FALSE);
                break;

	    }
	} else {
	    if (!Aborting)
		ST_Display_String (STMsg, "Download failure");
            Check_Keep (Data_File, Name);
            return(FALSE);
	}
    }
} /* Receive_File */

/* =================================================================== */

int	BP_DLE_Seen()
{
    int     i;

    Port_Update_Rate = 256;
    ST_Initialize(0);
    if ( !read_byte() )
	return 0;
    if (ch != 'B')
	return 0;

    SA_Next_to_ACK  = 0;    /* Initialize Send-ahead variables */
    SA_Next_to_Fill = 0;
    SA_Waiting      = 0;
    Aborting        = FALSE;
    Packet_Received = FALSE;

    switch (PortBps) {
    case bps110:
    case bps150:
    case bps300:
        Port_Update_Rate = 32;
	break;
    case bps600:
    case bps1200:
        Port_Update_Rate = 64;
	break;
    case bps1800 :
    case bps2400:
        Port_Update_Rate = 128;
	break;
    case bps4800:
    case bps9600:
        Port_Update_Rate = 256;
	break;
    }

    R_Counter   = 0;
    S_Counter   = 0;
    R_File_Data = 0;
    S_File_Data = 0;
    R_Com_Data  = 0;
    S_Com_Data  = 0;
    S_Packet_Count = 0;
    R_Packet_Count = 0;
    S_File_Size = 0;
    R_File_Size = 0;
    S_Error_Count = 0;
    R_Error_Count = 0;
    Resume_Flag = FALSE;

    if (Read_Packet (TRUE, FALSE)) {
	switch (R_buffer[0]) {
	case 'T':                      /* File Transfer Application */
	    ST_Initialize(0);
	    ST_Display_Value (STComRead, R_Com_Data);
	    S_Com_Data = 0;
	    R_Com_Data = 0;
	    time(&e_timer);

	    switch (R_buffer[1]) {
	    case 'D' :
		ST_Display_String (STUpDow, "Downloading ");
		break;
	    case 'U' :
     		ST_Display_String (STUpDow, "Uploading ");
		break;
	    default:
		ST_Display_String (STMsg, "Unimplemented Transfer Function");
		Send_Failure ("NUnimplemented Transfer function");
		ST_Terminate();
		return 0;
	    }

	    switch (R_buffer[2]) {
	    case 'A':
		ST_Display_String (STType, "ASCII");
		break;
	    case 'B':
		ST_Display_String (STType, "Binary");
		break;
	    default:
		ST_Display_String (STMsg, "Unimplemented File Type");
		Send_Failure ("NUnimplemented file type");
		ST_Terminate();
		return 0;
	    }

	    i = 2;
	    memset(filename,0,sizeof(filename));

	    while ((R_buffer[i] != 0) && (i < R_Size - 1)) {
		i = i + 1;
		filename[i-3] = R_buffer[i];
	    }

	    ST_Display_String (STFile, filename);
	    S_Packet_Count =  (0);
	    R_Packet_Count =  (0);

	    if (R_buffer[1] == 'U')
		Send_File (filename);
	    else
		Receive_File (filename);

	    ST_Terminate();
	    return 1;
	    break;

	case '+':          /* Received Transport Parameters Packet */
	    Do_Transport_Parameters();
	    break;

	default:	/* Unknown Packet; tell the host we don't know */
	    Send_Failure ("NUnknown Packet Type");
            break;

	}  /* of case */
    }    /* of if Read_Packet then*/

    return 0;
} /* DLE_Seen */
