home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 2 BBS
/
02-BBS.zip
/
BTMTSRC3.ZIP
/
XMSEND.C
< prev
next >
Wrap
Text File
|
1992-03-16
|
21KB
|
889 lines
/*--------------------------------------------------------------------------*/
/* */
/* */
/* ------------ Bit-Bucket Software, Co. */
/* \ 10001101 / Writers and Distributors of */
/* \ 011110 / Freely Available<tm> Software. */
/* \ 1011 / */
/* ------ */
/* */
/* (C) Copyright 1987-90, 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.240. */
/* */
/* 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:132/491, 1:141/491 */
/* P.O. Box 460398 AlterNet 7:491/0 */
/* Aurora, CO 80046 BBS-Net 86:2030/1 */
/* Internet f491.n132.z1.fidonet.org */
/* */
/* Please feel free to contact us at any time to share your comments about */
/* our software and/or licensing policies. */
/* */
/*--------------------------------------------------------------------------*/
#define INCL_DOSPROCESS
/* System include files */
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <os2.h> /* CML */
#ifdef __TURBOC__
#include <mem.h>
#else
#include <memory.h>
#endif
/* Local include files */
#include "defines.h"
#include "com.h"
#include "xfer.h"
#include "zmodem.h"
#include "keybd.h"
#include "sbuf.h"
#include "sched.h"
#include "externs.h"
#include "prototyp.h"
static first_block = 0; /* CML */
void Build_Header_Block (args, type)
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) strcpy (ttmp->sendingprog, xfer_id);
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 >= 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));
first_block = 1; /* CML */
}
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 (args, start_state)
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 = fopen (args->filename, "rb")) == 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, msgtxt[M_SEND_MSG], args->LastBlk, args->filename, st.st_size);
if (un_attended && fullscreen)
{
clear_filetransfer ();
sb_move (filewin, 1, 2);
sb_puts (filewin, (unsigned char *) junkbuff);
elapse_time ();
sb_show ();
}
else
{
status_line ("+%s", junkbuff);
printf ("\n");
}
locate_y = wherey ();
locate_x = wherex ();
/* Start the throughput calculations */
throughput (0, 0L);
return (start_state);
}
int XSEnd (args, cur_state)
XMARGSP args;
int cur_state;
{
args->result = cur_state;
/* Close file */
fclose (args->file_pointer);
if (args->tot_errs > 3)
status_line (msgtxt[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", msgtxt[M_FILE_SENT], args->filename);
update_files (1);
}
return (cur_state);
}
void XSSetVars (args)
XMARGSP args;
{
if (no_sealink)
{
args->options.SLO = 0;
args->options.Resync = 0;
}
else
{
args->options.SLO = ((cur_baud >= 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 (args)
XMARGSP args;
{
XSSetVars (args);
Build_Header_Block (args, SOH);
return (XS1);
}
int XSXmTeStrt (args)
XMARGSP args;
{
XSSetVars (args);
Build_Header_Block (args, SYN);
return (XS1);
}
int XSCheckACK (args)
XMARGSP args;
{
Check_ACKNAK (args);
return (XS2);
}
int XSSendBlk (args)
XMARGSP args;
{
if (!CARRIER)
return (CARRIER_ERR);
if (got_ESC ())
{
status_line (msgtxt[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 (args)
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 (filename, sendname)
char *filename;
char *sendname;
{
XMARGS xm;
xm.filename = filename;
xm.temp_name = sendname;
return (state_machine (Xmodem_Sender, &xm, XS0));
}
int Xmodem_Send_File (filename, sendname)
char *filename;
char *sendname;
{
return (SEAlink_Send_File (filename, sendname));
}
int Telink_Send_File (filename, sendname)
char *filename;
char *sendname;
{
XMARGS xm;
xm.filename = filename;
xm.temp_name = sendname;
return (state_machine (Xmodem_Sender, &xm, XS0T));
}
void Get_Block (args)
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 = ~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 (args)
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);
}
if (first_block) /* CML: clean up BLOCK 0 send */
{
while (com_online && !com_out_empty())
{
if (com_char_avail()) /* CML */
CLEAR_INBOUND();
// status_line(" Clearing Inbound!");
DosSleep(1L);
}
}
UNBUFFER_BYTES ();
show_sending_blocks (args);
Get_Block (args);
}
void show_num (args, b)
XMARGSP args;
long b;
{
if (b > args->LastBlk)
{
if (fullscreen && un_attended)
sb_puts (filewin, "EOT");
else
cputs ("EOT");
}
else if (b >= 0L)
{
if (fullscreen && un_attended)
sb_puts (filewin, (unsigned char *) ultoa (((unsigned long) b), e_input, 10));
else
(void) cputs (ultoa (((unsigned long) b), e_input, 10));
}
}
void show_sending_blocks (args)
XMARGSP args;
{
char j[100];
int i;
long k;
k = args->filelen - args->curr_byte;
if (k < 0L)
k = 0L;
if (lock_baud) /* CML correctly calculating send/receive time */
i = (int) ((k * 10 / actual_baud * 100 / ((args->save_header == SOH) ? 94 : 70) + 59) / 60);
else
i = (int) ((k * 10 / cur_baud * 100 / ((args->save_header == SOH) ? 94 : 70) + 59) / 60);
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 (filewin, 2, 2);
show_num (args, args->SendBLK - 1);
(void) sb_putc (filewin, ':');
show_num (args, args->ACKBLK);
(void) sb_puts (filewin, " *Overdrive* ");
sb_move (filewin, 2, 69);
sb_puts (filewin, j);
sb_show ();
}
else
{
gotoxy (locate_x, locate_y);
show_num (args, args->SendBLK - 1);
cputs (":");
show_num (args, args->ACKBLK);
(void) cputs (" *Overdrive* ");
}
}
}
else
{
if (fullscreen && un_attended)
{
elapse_time();
sb_move (filewin, 2, 2);
show_num (args, args->SendBLK - 1);
(void) sb_putc (filewin, ':');
show_num (args, args->ACKBLK);
sb_puts (filewin, (unsigned char *) " ");
sb_move (filewin, 2, 69);
sb_puts (filewin, j);
sb_show ();
}
else
{
gotoxy (locate_x, locate_y);
show_num (args, args->SendBLK - 1);
(void) cputs (":");
show_num (args, args->ACKBLK);
(void) cputs (" ");
}
}
}
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 (args, start_state)
XMARGSP args;
int start_state;
{
args->result = 0;
return (start_state);
}
int ACEnd (args, cur_state)
XMARGSP args;
int cur_state;
{
args->result = cur_state;
return (cur_state);
}
int ACChkRcvd (args)
XMARGSP args;
{
if (PEEKBYTE () >= 0)
{
args->CHR = TIMED_READ (0);
return (AC1);
}
return (SUCCESS);
}
int ACSLCheck (args)
XMARGSP args;
{
if (args->ACKST > 2)
return (AC2);
return (AC6);
}
int ACSLVerify (args)
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 (args)
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;
/* This stuff was in 2.38 why?
CLEAR_OUTBOUND ();
if (*SLO)
*sealink = 0;
*/
return (AC4);
}
int ACXMCheck (args)
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 (args)
XMARGSP args;
{
if ((args->options.SLO == 0) || (args->ACKsRcvd < 10))
return (SUCCESS);
args->options.SLO = 0;
return (SUCCESS);
}
int ACSL1Check (args)
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 (args)
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:
return (AC0);
}
}
int ACXMACK (args)
XMARGSP args;
{
if (!args->options.SEAlink)
++(args->ACKBLK);
return (AC0);
}
int ACXMNAK (args)
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 (args)
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 (msgtxt[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 (args)
XMARGSP args;
{
state_machine (ACKNAK_Check, args, AC0);
}
int Receive_Resync (resync_block)
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 / 400);
if (window <= 0)
window = 2;
if (small_window)
window = (window > 6) ? 6 : window;
return (window);
}