Category : C Source Code
Archive   : BPLUS22C.ZIP
Filename : BPLUS.C

 
Output of file : BPLUS.C contained in archive : BPLUS22C.ZIP
/****
BPLUS.INC - B Plus Protocol Support routines
(derived from BPROTO.INC)

Copyright 1987, CompuServe Incorporated

These routines may be used as-is or in modified form in any
personal computer terminal program to implement support of the
CompuServe B and B Plus Protocols for the purpose of transfering
information between CompuServe hosts and a personal computer.

No warranty, expressed or implied, covers this code, or the specifications
of the B and B Plus Protocols.


Last update:
Russ Ranshaw 16-Dec-87 Corrected Upload Abort problems.
Russ Ranshaw 07-Apr-88 Corrected additional Abort problems.
Russ Ranshaw 09-Apr-88 Added Quote Set to + Packet.
Russ Ranshaw 10-Apr-88 Added Download Resume.
Russ Ranshaw 22-Apr-88 Added File Information to Download.
(File length only.)
Russ Ranshaw 11-May-88 Added check to control Upload degradation
under Send Ahead.
Russ Ranshaw 16-May-88 Remove debugging code for release
of Version 2.1
Russ Ranshaw 01-Jun-88 Added externally settable file size for
Downloads. Use ST_Yes_or_No instead of
ST_Prompt to get Y/N response.
Russ Ranshaw 07-Jun-88 Added defensive check to see if Aborting
is already true. Changed comm. rate
calculation.
Russ Ranshaw 23-Jun-88 Add check for in ReSync.
Russ Ranshaw 04-Aug-88 Added WACK intercept to update the
status display, mostly so that resumes
show some activity while the host calculates
it's CRC value.
Paul Resch 28-Aug-88 Converted to standard C code.
****/

/****************
**
** This module implements the B-Protocol Functions.
**
**
** If you have any questions, contact:
** Russ Ranshaw, CompuServe Incorporated
** [70000,1010]
**
** This source was originally derived from BP.C, written by
** Steve Wilhite, CompuServe Incorporated.
**
*****************/

/*
const
UnitVersion = "2.2c";
UnitVerDate = "04 Aug 88";
UnitUpdBy = "RWR";
*/

/****************************************************************************/
/*
* C implementation notes:
* Routines with names beginning "ST_" are not supplied. They are
* strictly console I/O. Implement as needed, or see the PASCAL
* version.
* "Async_Send" is an extern that is passed a byte for output to the
* serial port.
* "Async_BuffeR_Read" is an extern that is passed the address of a byte.
* If TRUE is returned, the byte will be from the serial port.
* If FALSE is returned, the byte value is undefined.
* The CRC subroutines are included in this module.
*
* I have tried to keep as close as possible to Mr. Ranshaw's structure.
* Please see the PASCAL source to clarify any confusion.
*/
/****************************************************************************/

#ifdef DEBUG
#define STATIC
#else
#define STATIC static
#endif

#include
#include

extern size_t time();

#define TRUE 1
#define FALSE 0

STATIC size_t e_timer;

typedef char maxstr[256];

int BP_Auto_Resume = FALSE; /* True to automatically attempt transfer */
/* resumption if the Initiator can do it */
int BP_Use_File_Size = FALSE;
long BP_File_Size;
/* BP_Quote_This is invoked to set bits in BP_Special_Quote_Set. */
/* It must be called prior to calling BP_DLE_Seen for each character in the */
/* ranges 0x00 -> 0x1f and 0x80 -> 0x9f that is to be quoted. */
/* BP_Quote_This (int Value); */

/* BP_Term_ENQ is invoked when Terminal Mode receives from host */
/* BP_Term_ENQ(); */

/* BP_Term_ESC_I is invoked when Terminal Mode receives from host */
/* BP_Term_ESC_I (maxstr ESC_I_Response); */

/* BP_DLE_Seen is invoked when Terminal Mode receives from host */
/* BP_DLE_Seen(); */



/*===========================================================================*/

typedef unsigned char QS_Array[8];
typedef unsigned char QS_Array_p;

#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
int PortBps = bps2400;

STATIC int seq_num; /* Current Sequence Number - init by Term_ENQ */
STATIC unsigned short checksum; /* May hold CRC */

/* Initiator's Parameters */
STATIC unsigned char His_WS, /* Initiator's Window Send */
His_WR, /* Initiator's Window Receive */
His_BS, /* Initiator's Block Size */
His_CM; /* Initiator's Check Method */
STATIC QS_Array His_QS; /* Initiator's Quote Set */
/* The next 3 Parameters are for the B Plus File Transfer Application */
STATIC unsigned char His_DR, /* Initiator's Download Recovery Option */
His_UR, /* Initiator's Upload Recovery Option */
His_FI; /* Initiator's File Information Option */

/* Negotiated Parameters */
STATIC unsigned char Our_WS, /* Negotiated Window Send */
Our_WR, /* Negotiated Window Receive */
Our_BS, /* Negotiated Block Size */
Our_CM; /* Negotiated Check Method */
STATIC QS_Array Our_QS; /* Our Quote Set */
STATIC unsigned char Our_DR, /* Our Download Recovery Option */
Our_UR, /* Our Upload Recovery Option */
Our_FI, /* Our File Information Option */
Def_DR, /* User's preferred DOW Resume option */
Def_BS; /* Default Block Size: varies depending */
/* on the baud in use */
STATIC unsigned char Port_Update_Rate; /* Number of port bytes between Status */
/* upldates for the Port */
STATIC int B_Plus; /* True if B Plus in effect */
STATIC int Use_CRC; /* True if CRC in effect */
STATIC int BP_Special_Quoting = 0;/* True to use BP_Special_Quote_Set */
STATIC QS_Array BP_Special_Quote_Set = /* User's specified Quote Set */
{0x14, 0x00, 0xd4, 0x00, /* ETX ENQ DLE XON XOFF NAK */
0x00, 0x00, 0x00, 0x00
};

STATIC int Buffer_Size; /* Our_BS * 4 */
STATIC int SA_Max; /* 1 if SA not enabled, else Max_SA */
STATIC int SA_Error_Count; /* # of times S_Send_Data called */

STATIC unsigned char Quote_Table[256]; /* The quoting table */

STATIC QS_Array DQ_Full =
{0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff
};
STATIC QS_Array DQ_Default =
{0x14, 0x00, 0xd4, 0x00, /* ETX ENQ DLE XON XOFF NAK */
0x00, 0x00, 0x00, 0x00
};
STATIC QS_Array DQ_Minimal =
{0x14, 0x00, 0xd4, 0x00, /* ETX ENQ DLE XON XOFF NAK */
0x00, 0x00, 0x00, 0x00
};
STATIC QS_Array DQ_Extended =
{0x14, 0x00, 0xd4, 0x00, /* ETX ENQ DLE XON XOFF NAK */
0x00, 0x00, 0x50, 0x00 /* XON XOFF */
};

#define Max_Buf_Size 1032 /* Largest data block we can handle */
#define Max_SA 2 /* Maximum number of waiting Packets */

#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


/* 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 char lstr[256];
typedef struct {
int seq; /* Packet's sequence number */
int num; /* Number of bytes in Packet */
unsigned char buf[Max_Buf_Size]; /* Actual Packet data */
} buf_type;

/****************************************************************************/
ltoa( n, s )
register long n;
register char *s;
{
register char *t;
register long i;
register char c;
long sign;
long divten;

if( (sign = n) < 0 )
n = -n;
t = s;
do
{
i = (divten = (n / 10)) * 10; /* get ones digit (sigh) */
*t++ = ( n - i ) + '0';
} while( (n = divten) > 0 );
if( sign < 0 )
*t++ = '-';
*t-- = '\0';
while( s < t )
{
c = *t;
*t-- = *s;
*s++ = c;
}
}
/****************************************************************************/
/*
Clear_Quote_Table:
Initialize Quote_Table to all zeros (nothing quoted).
*/

STATIC Clear_Quote_Table()
{
int i;

for( i = 0; i<=255; i++ )
Quote_Table [i] = 0;
}

/*
Update_Quote_Table:
Sets the i-th entry of Quote_Table to the necessary quoting character
according to the i-th bit of the supplied Quote Set.
*/

STATIC Update_Quote_Table (Quote_Set)
QS_Array_p *Quote_Set;
{
int i, j, k;
unsigned char b, c;

k = 0;
c = 0x40;

for( i = 0; i<=7; i++ )
{
if( i == 4 )
/* Switch to upper control set */
{
c = 0x60;
k = 128;
}

b = Quote_Set [i];

for (j = 0; j<=7; j++ )
{
if ((b & 0x80) != 0)
Quote_Table [k] = c;

b = b << 1;
c = c + 1;
k = k + 1;
}
}
}

/* BP_Quote_This sets bits in BP_Special_Quote_Set. */
/* It sets BP_Special_Quoting true to use the special quote set. */
/* If Value = -1, the Special Quote Set is restored to its default. */

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; /* = index into BP_Special_Quote_Set */
j = Value % 8; /* = Bit number in the i-th byte */
BP_Special_Quote_Set [i] =
BP_Special_Quote_Set [i] || (0x80 >> j);
BP_Special_Quoting = TRUE;
}
else if (Value == -1) /* Restore the Quote Set? */
{
for( i=0; i BP_Special_Quote_Set[i] = DQ_Minimal[i];
BP_Special_Quoting = FALSE;
}
}

/*
BP_Term_ENQ is called when the terminal emulator receives the character
from the host. Its purpose is to initialize for B Protocol and tell the
host that we support B Plus.
*/


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 */

/* Set up Our prefered Quoting Mask */
for( i=0; 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');
}

/*
BP_Term_ESC_I is called when is received by the terminal emulator.
Note that CompuServe now recognizes the string ",+xxxx" as the final field.
THis provides a checksum (xxxx being the ASCII decimal representation of the
sum of all characters in the response string from # to +. The purpose of
the checksum is to eliminate the need for retransmission and comparison of
the response.
*/


BP_Term_ESC_I (esc_I_Response)
char esc_I_Response[];
{
int i;
maxstr t;
int cks; /* checksum */

cks = 0;

for (i = 1; i<=strlen (esc_I_Response); i++ )
{
Async_Send (esc_I_Response [i]);
cks += esc_I_Response [i];
}

Async_Send (',');
Async_Send ('+');
cks = cks + ',' + '+';

ltoa( (long)cks, t );

for (i = 1; i<=strlen (t); i++ )
Async_Send (t [i]);

Async_Send (0x0d); /* */
}


/*
BP_DLE_Seen is called from the main program when the character is
received from the host.

This routine calls Read_Packet and dispatches to the appropriate
handler for the incoming Packet.
*/


STATIC int ttime,
R_Size, /* size of receiver buffer */
ch; /* current character */

STATIC int xoff_flag,
Timed_Out, /* we timed out before receiving character */
Packet_Received, /* True if a Packet was received */
masked; /* true if ctrl character was quoted */

STATIC buf_type SA_Buf[Max_SA+1]; /* Send-ahead buffers */

STATIC int SA_Next_to_ACK; /* Which SA_Buf is waiting for an ACK */
STATIC int SA_Next_to_Fill; /* Which SA_Buf is ready for new data */
STATIC int SA_Waiting; /* Number of SA_Buf's waiting for ACK */
STATIC int Aborting; /* True if aborting the transfer ]*/

STATIC unsigned char R_buffer[Max_Buf_Size];
STATIC lstr filename; /* pathname */
STATIC int i, n;
STATIC int dummy;
STATIC int S_Counter; /* Used to pace status update */
STATIC int R_Counter;
STATIC long S_Com_Data; /* Comm Port Data traffic */
STATIC long R_Com_Data;
STATIC long S_File_Data; /* File Data Traffic */
STATIC long R_File_Data;
STATIC long S_Packet_Count; /* Packet count */
STATIC long R_Packet_Count;
STATIC long S_Error_Count; /* Error count */
STATIC long R_Error_Count;
STATIC long S_File_Size; /* Length of file already sent */
STATIC long R_File_Size; /* Length of file already received */
STATIC long S_Remaining; /* # bytes remaining to be sent */
STATIC long R_Remaining; /* # bytes reamining to be received */
STATIC long Com_Rate; /* Comm. bytes per second */
STATIC long Data_Rate; /* Effective Data bytes per second */
STATIC long Time_Estimate; /* Estimated time until completion */
STATIC int Resume_Flag; /* TRUE if attempting a DOW resume */

STATIC lstr tmp_str;

/***************************************************************************/
/*
* crc
*
* Calculates XMODEM-style CRC (uses the CCITT V.41 polynomial but
* completely backwards from the normal bit ordering).
*/


STATIC unsigned 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
};

STATIC unsigned int crc_16;

/*
* Init_CRC initializes for XMODEM style CRC calculation by setting
* crc_16 to value. Typically value is 0 for XMODEM and -1 for
* B+ Protocl. It returns the initial value.
*/
STATIC int Init_CRC (value)
int value;
{
return( crc_16 = value );
}

/*
Upd_CRC updates crc_16 and returns the updated value. */

STATIC unsigned int Upd_CRC (value)
unsigned int value;
{
crc_16 = crc_table [((crc_16 >> 8) ^ (value)) & 0xff] ^ (crc_16 << 8);
return( crc_16 );
}
/***************************************************************************/

STATIC do_checksum (c)
int c;
{
if (B_Plus && Use_CRC)
checksum = Upd_CRC ((unsigned short)c);
else
{
checksum = checksum << 1;

if (checksum > 255)
checksum = (checksum & 0xff) + 1;

checksum += c;

if (checksum > 255)
checksum = (checksum & 0xff) + 1;
}
}

STATIC send_byte (ch)
unsigned char ch;
{
Async_Send (ch);
S_Com_Data++;
S_Counter++;
S_Counter = S_Counter % Port_Update_Rate;

if (S_Counter == 0)
ST_Display_Value (STComSent, S_Com_Data);
}

STATIC send_masked_byte (ch)
int ch;
{
ch &= 0xff;

if (Quote_Table [ch] != 0)
{
send_byte (dle);
send_byte (Quote_Table [ch]);
}
else
send_byte (ch);
}

STATIC Send_ACK()
{
send_byte (dle);
send_byte (seq_num + '0');
}

STATIC Send_NAK()
{
send_byte (nak);
}

STATIC Send_ENQ()
{
send_byte (enq);
}

STATIC int read_byte()
{
unsigned char chx;
unsigned short Hiber;
size_t start;

Timed_Out = FALSE;
start = time(NULL);

if ( !Aborting )
Hiber = 30;
else
Hiber = 10;

while ( !Async_BuffeR_Check( &chx ) )
{
if (time(NULL) - start >= Hiber)
{
Timed_Out = TRUE;
return( FALSE );
}
}

ch = chx;
R_Com_Data++;
R_Counter++;
R_Counter = R_Counter % Port_Update_Rate;

if (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 = ch & 0x1f;
else
ch = (ch & 0x1f) || 0x80;

masked = TRUE;
}

return(TRUE);
}

/*
Increment Sequence Number
*/

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;
/* Lead_in_Seen is true if the has been seen already. */

/* From_Send_Packet is true if called from Send_Packet */
/* (causes exit on first error detected) */

/* Returns True if Packet is available from host. */

{
short State,
next_seq,
block_num,
errors,
new_cks;
int i;
int NAK_Sent;

if (Packet_Received) /* See if a Packet was picked up on a call to */
/* Get_ACK */
{
Packet_Received = FALSE;
return( TRUE);
}

NAK_Sent = FALSE;

for( i=0; i R_buffer[i] = 0;

next_seq = (seq_num + 1) % 10;
errors = 0;

if (Lead_in_Seen) /* Start off on the correct foot */
State = R_Get_Seq;
else State = R_Get_DLE;

while( TRUE )
{
ttime = 300;

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 ) /* Improve status display for DOW resume */
{
e_timer = time(NULL);
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
{
R_buffer[i] = ch;
i = i + 1;
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 ((unsigned int)ch);

if (!read_masked_byte())
new_cks = checksum ^ 0xff;
else
{
checksum =
Upd_CRC((unsigned int)ch);
new_cks = 0;
}
}
else new_cks = ch;

if (new_cks != checksum)
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 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;

send_byte (dle);
send_byte ('B');

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]);
}

send_byte (etx);
do_checksum (etx);

if (B_Plus && Use_CRC)
send_masked_byte (checksum >> 8);

send_masked_byte (checksum);

}

STATIC int Incr_SA (Old_Value)
int Old_Value;
{
if (Old_Value == Max_SA)
return(0);
else
return(Old_Value + 1);
}

/*
ReSync is called to restablish syncronism with the remote. This is
accomplished by sending and waiting for the sequence
to be received, ignoring everything else.

Return is -1 on time out, `B` if seen, else the digit .
*/

STATIC int ReSync()
#define Get_First_DLE 1
#define Get_First_Digit 2
#define Get_Second_DLE 3
#define Get_Second_Digit 4
{
int State,
Digit_1;

send_byte (enq); /* Send */
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 */
}

/*
Get_ACK is called to wait until the SA_Buf indicated by SA_Next_to_ACK
has been ACKed by the host.
*/

STATIC int Get_ACK()
{
int State,
errors,
block_num,
i;
/* int new_cks;*/
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 :
ttime = 300;

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 == ';')
{ /* Received a WACK (Wait Acknowledge) */
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') /* Check for Failure Packet */
{
Send_ACK();
return(FALSE);
}

State = S_Get_DLE; /* Stay here to find the ACK */
}
else State = S_Get_DLE; /* Receive failed; keep watching for ACK */
break;

case S_Skip_Packet : /* Skip an incoming Packet */
if (!read_byte())
State = S_Timed_Out;
else if (ch == etx )
{ /* Get the Checksum or CRC */
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 )
{ /* This is the one we're waiting for */
SA_Next_to_ACK = Incr_SA (SA_Next_to_ACK);
SA_Waiting = SA_Waiting - 1;

if (SA_Error_Count > 0 ) /* Apply heuristic to control */
SA_Error_Count--; /* Upload Performance degradation */

return(TRUE);
}
else if ((SA_Buf [Incr_SA (SA_Next_to_ACK)].seq == block_num) &&
SA_Waiting == 2)
{ /* Must have missed an ACK */
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) /* Allow for possible drop out of Send Ahead */
{
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);
}

/*
SA_Flush is called after sending the last Packet to get host's
ACKs on outstanding Packets.
*/

STATIC int SA_Flush()
{
while (SA_Waiting > 0)
{
if (!Get_ACK())
return(FALSE);
}
return( TRUE );
}

STATIC 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 */
}

/* Send_File is called to send a file to the host */

STATIC int Send_File (name)
char name[];
{
int n;
FILE *data_File;
buf_type *p;

data_File = fopen (name,"rb");

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);
/* Send_File_Information here ? */

/*----------------
S_Com_Data = 0;
R_Com_Data = 0;
e_timer = time(NULL);
-------------------*/
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_Estimate = time(NULL) - 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);
}

/* Inform host that the file was sent */

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 */

/*
Do_Transport_Parameters is called when a Packet type of + is received.
It sends a Packet of Our local B Plus parameters and sets the Our_xx
parameters to the minimum of the Initiator's and Our own parameters.
*/

STATIC 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];

if (R_Size >= 14)
Quote_Set_Present = TRUE;
else Quote_Set_Present = 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 */
{
if (His_WS < Def_WR) /* Take minimal subset of Transport Params. */
Our_WR = His_WS; /* If he can send ahead, we can receive it. */
else Our_WR = Def_WR;

if (His_WR < Def_WS) /* If he can receive send ahead, we can send it. */
Our_WS = His_WR;
else Our_WS = Def_WS;

if( His_BS < Def_BS)
Our_BS = His_BS;
else Our_BS = Def_BS;

if (His_CM < Def_CM)
Our_CM = His_CM;
else Our_CM = Def_CM;

if (His_DR < Def_DR)
Our_DR = His_DR;
else Our_DR = Def_DR;

if (His_UR < Def_UR)
Our_UR = His_UR;
else Our_UR = Def_UR;

if (His_FI < Def_FI)
Our_FI = His_FI;
else Our_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);
}

/* Check_Keep is called from Receive_File when a fatal error */
/* occurs. It asks the user if the file should be retained */

STATIC Check_Keep (data_File, Name)
FILE *data_File;
char Name[];
{
char yn;
char str[80];

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')
{
unlink (data_File);
ST_Display_String (STMsg, "File erased.");
}
else
{
/* implementation dependent option: Hide the file from casual view */
ST_Display_String (STMsg, "File retained.");
}
}

/* Process_File_Information is called from Receive_File when a TI Packet */
/* is received. It extracts the desired information from the Packet. */

STATIC char Val_Str[50];
STATIC int e_i, e_j, e_n;

STATIC 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 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];
R_Remaining = R_Remaining - R_File_Size; /* Adjust for Dow Resume */
ST_Display_Value (STDowRem, R_Remaining);

/* Ignore rest of parameters for now */

S_Packet_Count = 0;
R_Packet_Count = 0;
}

/* Receive_File is called to receive a file from the host */

STATIC int Receive_File (Name)
char Name[];
{
FILE *Data_File;
int status;
long File_Length; /* For download resumption */
lstr Work_String;
int Packet_Len;
int i, n;
char yn;
char Dow_Type;
buf_type *p;

Dow_Type = 'D'; /* Assume normal downloading */

Data_File = fopen( Name, "rwb" ); /* open for r/w first */

if (Data_File != NULL) /* this file already exists */
{ /* See if we can try automatic resume */
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')
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, "wb" ); /* open for write */
if (Data_File == NULL)
{
Send_Failure ("CCannot create file");
return(FALSE);
}
Send_ACK();
break;

case 'R' :
/* Resume download */
/* file is open and at start */
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 checksum =
Upd_CRC((unsigned int)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 {
p->buf [Packet_Len] = Work_String [i];
Packet_Len++;
}

ltoa ((long)checksum, Work_String);
strcat( Work_String, " " );

for (i = 0; i {
p->buf [Packet_Len] = Work_String [i];
Packet_Len++;
}

if (!send_Packet (Packet_Len - 1)) /* Send_Data sends 0..Size */
{
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_Estimate = time(NULL) - 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)
/* Decrement remaining byte count */
{
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)
/* `Tf' Packet implies host failed the */
{ /* CRC check on a DOW resume */
fclose (Data_File); /* So...replace the file */
Data_File = fopen(Name, "wb");
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;
e_timer = time(NULL);
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 */

/* =================================================================== */

BP_DLE_Seen()
{ /* DLE_Seen */


/*
Begin by getting the next character. If it is then enter the
B_Protocol state. Otherwise simply return.
*/

Port_Update_Rate = 30;

ST_Initialize();

if (!read_byte())
return;

if (ch != 'B')
return;

SA_Next_to_ACK = 0; /* Initialize Send-ahead variables */
SA_Next_to_Fill = 0;
SA_Waiting = 0;
Aborting = FALSE;
Packet_Received = FALSE;

/* Establish Data Block Size as a function of the Baud */
/* The intent is to keep the per-Packet time to 4-5 seconds */

switch (PortBps) {
case bps110:
case bps150:
case bps300:
Def_BS = 1;
Port_Update_Rate = 30;
break;
case bps600:
case bps1200:
Def_BS = 4;
Port_Update_Rate = 120;
break;
case bps1800 :
Def_BS = 6;
Port_Update_Rate = 180;
break;
case bps2400:
case bps4800:
case bps9600:
Def_BS = 8;
Port_Update_Rate = 240;
break;
}

/* received; begin B Protocol */

xoff_flag = TRUE;

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))
{
/* Dispatch on the type of Packet just received */

switch (R_buffer[0]) {
case 'T': /* File Transfer Application */
/* ST_Initialize();*/
ST_Display_Value (STComRead, R_Com_Data);
S_Com_Data = 0;
R_Com_Data = 0;
e_timer = time(NULL);

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;
}

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;
}

i = 2;
strcpy( 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();
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*/
} /* DLE_Seen */


  3 Responses to “Category : C Source Code
Archive   : BPLUS22C.ZIP
Filename : BPLUS.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/