home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 2 BBS
/
02-BBS.zip
/
BSRC_250.LZH
/
XMSEND.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-15
|
22KB
|
818 lines
/*--------------------------------------------------------------------------*/
/* */
/* */
/* ------------ Bit-Bucket Software, Co. */
/* \ 10001101 / Writers and Distributors of */
/* \ 011110 / Freely Available<tm> Software. */
/* \ 1011 / */
/* ------ */
/* */
/* (C) Copyright 1987-91, Bit Bucket Software Co., a Delaware Corporation. */
/* */
/* */
/* This module was written by Bob Hartman */
/* */
/* */
/* BinkleyTerm Xmodem Sender State Machine */
/* */
/* */
/* For complete details of the licensing restrictions, please refer */
/* to the License agreement, which is published in its entirety in */
/* the MAKEFILE and BT.C, and also contained in the file LICENSE.250. */
/* */
/* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */
/* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */
/* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */
/* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */
/* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */
/* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */
/* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */
/* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */
/* */
/* */
/* You can contact Bit Bucket Software Co. at any one of the following */
/* addresses: */
/* */
/* Bit Bucket Software Co. FidoNet 1:104/501, 1:343/491 */
/* P.O. Box 460398 AlterNet 7:491/0 */
/* Aurora, CO 80046 BBS-Net 86:2030/1 */
/* Internet f491.n343.z1.fidonet.org */
/* */
/* Please feel free to contact us at any time to share your comments about */
/* our software and/or licensing policies. */
/* */
/*--------------------------------------------------------------------------*/
/* Include this file before any other includes or defines! */
#include "includes.h"
void Build_Header_Block (XMARGSP args, char type)
{
struct FILEINFO dta;
SEADATAP ttmp;
(void) dfind (&dta, args->filename, 0);
args->save_header = type;
ttmp = (SEADATAP) &(args->header);
(void) memset (ttmp, 0, sizeof (XMDATA));
ttmp->header = type;
ttmp->block_num = 0;
ttmp->block_num_comp = 0xff;
ttmp->filelength = args->filelen;
(void) strncpy (ttmp->sendingprog, xfer_id, 14);
if (type == SYN)
{
(void) memset (ttmp->filename, ' ', 16);
ttmp->timedate = dta.time;
/* This is the CRC bit in the TeLink header */
ttmp->Resync = 1;
}
else
{
ttmp->timedate = args->save_filetime.oneword.timedate;
ttmp->SLO = (unsigned char) (((cur_baud.rate_value >= 9600) && !no_overdrive)? 1 : 0);
ttmp->Resync = (unsigned char) (no_resync ? 0 : 1);
ttmp->MACFLOW = 1;
}
if (args->temp_name != NULL)
(void) strncpy (ttmp->filename, args->temp_name, strlen (args->temp_name));
else
(void) strncpy (ttmp->filename, (char *) (dta.name), strlen (dta.name));
}
void XSSetVars (XMARGSP);
int XSInit (XMARGSP, int);
int XSEnd (XMARGSP, int);
int XSXmtStart (XMARGSP);
int XSXmTeStrt (XMARGSP);
int XSCheckACK (XMARGSP);
int XSSendBlk (XMARGSP);
int XSWaitEnd (XMARGSP);
STATES Xmodem_Sender[] = {
{ "XSInit", XSInit },
{ "XSEnd", XSEnd },
{ "XS0", XSXmtStart },
{ "XS0T", XSXmTeStrt },
{ "XS1", XSCheckACK },
{ "XS2", XSSendBlk },
{ "XS3", XSWaitEnd }
};
int XSInit (XMARGSP args, int start_state)
{
struct stat st;
char junkbuff[100];
/* Get the file information */
if (stat (args->filename, &st))
{
/* Print error message */
return (OPEN_ERR);
}
if ((args->file_pointer = share_fopen (args->filename, "rb", DENY_WRITE)) == NULL)
{
/* Print error message */
return (OPEN_ERR);
}
/* Get important information out of it */
args->filelen = st.st_size;
args->LastBlk = (st.st_size + 127) / 128;
args->save_filetime.oneword.timedate = st.st_atime;
args->prev_bytes = 0L;
args->tot_errs = 0;
(void) sprintf (junkbuff, MSG_TXT(M_SEND_MSG), args->LastBlk, args->filename, st.st_size);
if (un_attended && fullscreen)
{
clear_filetransfer ();
sb_move (file_hWnd, 1, 2);
FlLnModeSet( FILE_LN_2, 1 );
sb_puts( GetDlgItem( file_hWnd, FILE_LN_1 ), junkbuff );
elapse_time ();
sb_show ();
}
else
{
status_line ("+%s", junkbuff);
(void) printf ("\n");
}
locate_y = wherey ();
locate_x = wherex ();
/* Start the throughput calculations */
throughput (0, 0L);
return (start_state);
}
int XSEnd (XMARGSP args, int cur_state)
{
args->result = cur_state;
/* Close file */
(void) fclose (args->file_pointer);
if (args->tot_errs > 3)
status_line (MSG_TXT(M_CORRECTED_ERRORS), args->tot_errs, args->LastBlk);
/* Log that we sent it */
if (cur_state == SUCCESS)
{
throughput (1, (unsigned long) (args->filelen - args->prev_bytes));
status_line ("%s: %s", MSG_TXT(M_FILE_SENT), args->filename);
update_files (1);
}
return (cur_state);
}
void XSSetVars (XMARGSP args)
{
if (no_sealink)
{
args->options.SLO = 0;
args->options.Resync = 0;
}
else
{
args->options.SLO = ((cur_baud.rate_value >= 9600) && !no_overdrive) ? 1 : 0;
args->options.Resync = (~no_resync) & 1;
}
args->options.SEAlink = 0;
args->SendBLK = 1;
args->curr_byte = 0L;
args->NextBLK = 1;
args->ACKST = 0;
args->ACKBLK = -1L;
args->Window = 1;
args->ACKsRcvd = 0;
args->NumNAK = 0;
args->T1 = timerset (3000);
}
int XSXmtStart (XMARGSP args)
{
XSSetVars (args);
Build_Header_Block (args, SOH);
return (XS1);
}
int XSXmTeStrt (XMARGSP args)
{
XSSetVars (args);
Build_Header_Block (args, SYN);
return (XS1);
}
int XSCheckACK (XMARGSP args)
{
Check_ACKNAK (args);
return (XS2);
}
int XSSendBlk (XMARGSP args)
{
if (!CARRIER)
return (CARRIER_ERR);
if (got_ESC ())
{
status_line (MSG_TXT(M_KBD_MSG));
return (KBD_ERR);
}
if ((args->NumNAK > 4) && (args->SendBLK == 0))
{
if (args->save_header == SOH)
return (XS0T);
else
{
args->NumNAK = 0;
++(args->ACKBLK);
++(args->SendBLK);
return (XS2);
}
}
if (args->NumNAK > 10)
{
/* Too Many Errors */
return (SEND_RETRY_ERR);
}
if (timeup (args->T1))
{
/* Fatal Timeout */
return (SEND_TIMEOUT);
}
if (args->SendBLK > (args->LastBlk + 1))
return (XS3);
if (args->SendBLK > (args->ACKBLK + args->Window))
{
time_release ();
return (XS1);
}
if (args->SendBLK == (args->LastBlk + 1))
{
SENDBYTE (EOT);
++(args->SendBLK);
args->T1 = timerset (3000);
show_sending_blocks (args);
time_release ();
return (XS1);
}
/*
Increment the block count before sending because we read the next
block immediately after sending this block. On error free connects
we have a big net win because we never do a seek, and while we are
sending one block, we read the next. If we do get errors, then we
have to seek back to the previous block, and that will be a bother.
With today's phone lines and modems, we'll assume error free is more
often than not, and take our chances.
*/
if (args->options.SLO && args->options.SEAlink)
{
args->ACKBLK = args->SendBLK;
}
++(args->SendBLK);
args->curr_byte += 128L;
Send_Block (args);
args->T1 = timerset (6000);
return (XS1);
}
int XSWaitEnd (XMARGSP args)
{
show_sending_blocks (args);
if (args->ACKBLK < (args->LastBlk + 1))
{
time_release ();
return (XS1);
}
if (!CARRIER)
return (CARRIER_ERR);
return (SUCCESS);
}
int SEAlink_Send_File (char *filename, char *sendname)
{
XMARGS xm;
xm.filename = filename;
xm.temp_name = sendname;
return (state_machine (Xmodem_Sender, &xm, XS0));
}
int Xmodem_Send_File (char *filename, char *sendname)
{
return (SEAlink_Send_File (filename, sendname));
}
int Telink_Send_File (char *filename, char *sendname)
{
XMARGS xm;
xm.filename = filename;
xm.temp_name = sendname;
return (state_machine (Xmodem_Sender, &xm, XS0T));
}
void Get_Block (XMARGSP args)
{
XMDATAP xtmp;
if (args->SendBLK == 0)
{
Build_Header_Block (args, args->save_header);
args->NextBLK = -1L;
return;
}
xtmp = (XMDATAP) &(args->header);
/* Set up buffer as all ^Zs for EOF */
(void) memset (xtmp, SUB, sizeof (XMDATA));
/* Now set up the header stuff */
xtmp->header = SOH;
xtmp->block_num = (unsigned char) (args->SendBLK & 0xff);
xtmp->block_num_comp = (unsigned char)~xtmp->block_num;
if (args->NextBLK != args->SendBLK)
{
(void) fseek (args->file_pointer, (args->SendBLK - 1) * 128, SEEK_SET);
}
args->NextBLK = args->SendBLK + 1;
/* Can we read any data? */
if (fread ((char *) xtmp->data_bytes, 1, 128, args->file_pointer) <= 0)
return;
/* Looks good */
return;
}
void Send_Block (XMARGSP args)
{
if (args->header == SYN)
{
Data_Check ((XMDATAP) &(args->header), CHECKSUM);
}
else
{
Data_Check ((XMDATAP) &(args->header), args->options.do_CRC ? CRC : CHECKSUM);
}
if ((!(args->options.do_CRC)) || (args->header == SYN))
{
SENDCHARS ((char *) &(args->header), sizeof (XMDATA) - 1, 1);
}
else
{
SENDCHARS ((char *) &(args->header), sizeof (XMDATA), 1);
}
UNBUFFER_BYTES ();
show_sending_blocks (args);
Get_Block (args);
}
char *show_num (XMARGSP args, long b)
{
char *Rtn;
Rtn = "EOT";
if (b > args->LastBlk)
{
if (!(fullscreen && un_attended))
(void) cputs (Rtn);
}
else if (b >= 0L)
{
Rtn = ultoa (((unsigned long) b), e_input, 10);
if (!(fullscreen && un_attended))
(void) cputs (Rtn);
}
return Rtn;
}
void show_sending_blocks (XMARGSP args)
{
char *TmpPtr = (char *)&happy_compiler;
char j[100];
int i;
long k;
k = args->filelen - args->curr_byte;
if (k < 0L)
k = 0L;
i = (int) ((k * 10 / cur_baud.rate_value * 100 /
((args->save_header == SOH) ? 94 : 70) + 59) / 60);
(void) sprintf (j, "%3d min", i);
if (args->options.SLO)
{
if ((!((args->SendBLK - 1) & 0x1f)) || ((args->SendBLK - 1) > args->LastBlk))
{
if (fullscreen && un_attended)
{
elapse_time();
sb_move (file_hWnd, 2, 2);
TmpPtr = show_num (args, args->SendBLK - 1);
sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_TOTAL ),
TmpPtr );
#ifndef MILQ
(void) sb_putc (file_hWnd, ':');
#endif
TmpPtr = show_num (args, args->ACKBLK);
sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_SIZE ),
TmpPtr );
sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_STATUS ),
" *Overdrive* ");
sb_move (file_hWnd, 2, 69);
sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_DTTM ), j );
sb_show ();
}
else
{
gotoxy (locate_x, locate_y);
(void) show_num (args, args->SendBLK - 1);
(void) cputs (":");
(void) show_num (args, args->ACKBLK);
(void) cputs (" *Overdrive* ");
}
}
}
else
{
if (fullscreen && un_attended)
{
elapse_time();
sb_move (file_hWnd, 2, 2);
TmpPtr = show_num (args, args->SendBLK - 1);
sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_TOTAL ),
TmpPtr );
#ifndef MILQ
(void) sb_putc (file_hWnd, ':');
#endif
TmpPtr = show_num (args, args->ACKBLK);
sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_SIZE ),
TmpPtr );
#ifndef MILQ
sb_puts (file_hWnd, " ");
#endif
sb_move (file_hWnd, 2, 69);
sb_puts( GetDlgItem( file_hWnd, FILE_LN_2 + GD_DTTM ), j );
sb_show ();
}
else
{
gotoxy (locate_x, locate_y);
(void) show_num (args, args->SendBLK - 1);
(void) cputs (":");
(void) show_num (args, args->ACKBLK);
(void) cputs (" ");
}
}
happy_compiler = * (int *) TmpPtr; /* Makes the compiler happy! */
}
int ACInit (XMARGSP, int);
int ACEnd (XMARGSP, int);
int ACChkRcvd (XMARGSP);
int ACSLCheck (XMARGSP);
int ACSLVerify (XMARGSP);
int ACSLACKNAK (XMARGSP);
int ACXMCheck (XMARGSP);
int ACSLOCheck (XMARGSP);
int ACSL1Check (XMARGSP);
int ACACKNAK (XMARGSP);
int ACXMACK (XMARGSP);
int ACXMNAK (XMARGSP);
int ACRESYNC (XMARGSP);
STATES ACKNAK_Check[] = {
{ "ACInit", ACInit },
{ "ACEnd", ACEnd },
{ "AC0", ACChkRcvd },
{ "AC1", ACSLCheck },
{ "AC2", ACSLVerify },
{ "AC3", ACSLACKNAK },
{ "AC4", ACXMCheck },
{ "AC5", ACSLOCheck },
{ "AC6", ACSL1Check },
{ "AC7", ACACKNAK },
{ "AC8", ACXMACK },
{ "AC9", ACXMNAK },
{ "AC10", ACRESYNC }
};
int ACInit (XMARGSP args, int start_state)
{
args->result = 0;
return (start_state);
}
int ACEnd (XMARGSP args, int cur_state)
{
args->result = cur_state;
return (cur_state);
}
int ACChkRcvd (XMARGSP args)
{
if (PEEKBYTE () >= 0)
{
args->CHR = TIMED_READ (0);
return (AC1);
}
return (SUCCESS);
}
int ACSLCheck (XMARGSP args)
{
if (args->ACKST > 2)
return (AC2);
return (AC6);
}
int ACSLVerify (XMARGSP args)
{
if (args->ARBLK8 == (unsigned char) ((~args->CHR) & 0xff))
{
args->ARBLK = args->SendBLK - ((args->SendBLK - args->ARBLK8) & 0xff);
return (AC3);
}
args->options.SEAlink = 0;
args->Window = 1;
args->ACKST = 0;
return (AC6);
}
int ACSLACKNAK (XMARGSP args)
{
if ((args->ARBLK < 0)
|| (args->ARBLK > args->SendBLK)
|| (args->ARBLK <= (args->SendBLK - 128)))
{
return (AC0);
}
if (args->ACKST == 3)
{
args->options.SEAlink = (~no_sealink) & 1;
args->Window = calc_window ();
args->ACKBLK = args->ARBLK;
++(args->ACKsRcvd);
args->ACKST = 0;
return (AC5);
}
args->SendBLK = args->ARBLK;
args->curr_byte = (args->SendBLK - 1) * 128L;
if (args->curr_byte < 0L)
args->curr_byte = 0L;
if (args->SendBLK > 0)
++(args->tot_errs);
Get_Block (args);
args->ACKST = 0;
return (AC4);
}
int ACXMCheck (XMARGSP args)
{
if (args->NumNAK < 4)
{
args->options.SEAlink = (~no_sealink) & 1;
args->Window = calc_window ();
}
else
{
args->options.SEAlink = 0;
args->Window = 1;
}
return (SUCCESS);
}
int ACSLOCheck (XMARGSP args)
{
if ((args->options.SLO == 0) || (args->ACKsRcvd < 10))
return (SUCCESS);
args->options.SLO = 0;
return (SUCCESS);
}
int ACSL1Check (XMARGSP args)
{
if ((args->ACKST == 1) || (args->ACKST == 2))
{
args->ARBLK8 = (unsigned char) args->CHR;
args->ACKST += 2;
return (AC6);
}
if ((args->options.SEAlink == 0) || (args->ACKST == 0))
return (AC7);
return (AC0);
}
int ACACKNAK (XMARGSP args)
{
long mac_timer;
switch (args->CHR)
{
case ACK:
args->ACKST = 1;
args->NumNAK = 0;
return (AC8);
case WANTCRC:
args->options.do_CRC = 1;
/* Fallthrough */
case NAK:
args->ACKST = 2;
++(args->NumNAK);
CLEAR_OUTBOUND ();
timer (6);
return (AC9);
case SYN:
CLEAR_OUTBOUND ();
if (!no_resync)
{
args->result = Receive_Resync (&(args->resync_block));
args->ACKST = 0;
return (AC10);
}
else
{
return (AC0);
}
case DC3: /* ^S */
if (args->options.SEAlink && (args->ACKST == 0))
{
mac_timer = timerset (1000);
while (CARRIER && !timeup (mac_timer))
{
if (TIMED_READ (0) == DC1)
break;
time_release ();
}
return (AC0);
}
/* Otherwise, fallthrough */
default:
break;
}
return (AC0);
}
int ACXMACK (XMARGSP args)
{
if (!args->options.SEAlink)
++(args->ACKBLK);
return (AC0);
}
int ACXMNAK (XMARGSP args)
{
if (!args->options.SEAlink)
{
args->SendBLK = args->ACKBLK + 1;
args->curr_byte = (args->SendBLK - 1) * 128L;
if (args->curr_byte < 0L)
args->curr_byte = 0L;
if (args->SendBLK > 0)
++(args->tot_errs);
Get_Block (args);
}
return (AC0);
}
int ACRESYNC (XMARGSP args)
{
CLEAR_OUTBOUND ();
if (args->result != SUCCESS)
{
SENDBYTE (NAK);
return (SUCCESS);
}
if (args->SendBLK == 1)
{
args->prev_bytes = (args->resync_block - 1) * 128;
if (args->prev_bytes > args->filelen)
args->prev_bytes = args->filelen;
status_line (MSG_TXT(M_SYNCHRONIZING), args->prev_bytes);
}
else
{
++(args->tot_errs);
}
args->options.SEAlink = 1;
args->Window = calc_window ();
args->SendBLK = args->resync_block;
args->curr_byte = (args->SendBLK - 1) * 128L;
if (args->curr_byte < 0L)
args->curr_byte = 0L;
Get_Block (args);
args->ACKBLK = args->SendBLK - 1;
SENDBYTE (ACK);
return (SUCCESS);
}
void Check_ACKNAK (XMARGSP args)
{
(void) state_machine (ACKNAK_Check, args, AC0);
}
int Receive_Resync (long *resync_block)
{
unsigned char resyncit[30];
unsigned char *p;
unsigned char a, b;
unsigned int nak_crc, his_crc;
p = resyncit;
while ((*p = (unsigned char) TIMED_READ(1)) != ETX)
{
if ((*p < '0') || (*p > '9'))
{
status_line (">SEAlink Send: Resync bad byte '%02x'", *p);
return (RESYNC_ERR);
}
++p;
}
*p = '\0';
nak_crc = crc_block ((unsigned char *) resyncit, (int) strlen ((char *) resyncit));
a = (unsigned char) TIMED_READ (1);
b = (unsigned char) TIMED_READ (1);
his_crc = (b << 8) | a;
if (nak_crc != his_crc)
{
status_line (">SEAlink Send: Resync bad crc %04x/%04x", nak_crc, his_crc);
return (CRC_ERR);
}
*resync_block = atol ((char *) resyncit);
status_line (">SEAlink Send: Resync to %ld", *resync_block);
return (SUCCESS);
}
int calc_window ()
{
int window;
window = (int) (cur_baud.rate_value / 400);
if (window <= 0)
window = 2;
if (small_window)
window = (window > 6) ? 6 : window;
return (window);
}