home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 2 BBS
/
02-BBS.zip
/
BTMTSRC3.ZIP
/
XMREC.C
< prev
next >
Wrap
Text File
|
1991-10-17
|
36KB
|
1,290 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 Receiver 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. */
/* */
/*--------------------------------------------------------------------------*/
/* System include files */
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dos.h>
#include <time.h>
#include <io.h>
#include <ctype.h>
#include <conio.h>
#ifdef __TURBOC__
#include "tc_utime.h"
#include <mem.h>
#include <alloc.h>
#else
#include <sys/utime.h>
#include <memory.h>
#include <malloc.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"
void Find_Char (int);
int Header_in_data (unsigned char *);
void Send_ACK (XMARGSP);
void Send_NAK (XMARGSP);
static long Open_Xmodem_File (XMARGSP);
int XRInit (XMARGSP, int);
int XREnd (XMARGSP, int);
int XRRecInit (XMARGSP);
int XRBrecInit (XMARGSP);
int XRRecStart (XMARGSP);
int XRWaitFirst (XMARGSP);
int XRWaitBlock (XMARGSP);
int XRRestart (XMARGSP);
int XRSetOvrdr (XMARGSP);
STATES Xmodem_Receiver[] = {
{ "XRInit", XRInit },
{ "XREnd", XREnd },
{ "XR0", XRRecInit },
{ "XR0B", XRBrecInit },
{ "XR1", XRRecStart },
{ "XR2", XRWaitFirst },
{ "XR3", XRWaitBlock },
{ "XR4", XRRestart },
{ "XR5", XRSetOvrdr }
};
static long Open_Xmodem_File (args)
XMARGSP args;
{
char *s1, *s2;
if (args->file_pointer == NULL)
{
args->temp_name = calloc (1, 80);
if (args->path != NULL)
(void) strcpy (args->temp_name, args->path);
s1 = &(args->temp_name[strlen (args->temp_name)]);
(void) strcpy (s1, "BTXXXXXX");
s2 = mktemp (args->temp_name);
if ((s2 == NULL) || ((args->file_pointer = buff_fopen (s2, "wb")) == NULL))
{
status_line (msgtxt[M_TEMP_NOT_OPEN], s2);
return (-1L);
}
}
throughput (0, 0L);
return (0L);
}
long Set_Up_Restart (args)
XMARGSP args;
{
char foo[100];
char foo1[50];
struct stat st;
args->sub_results = 0;
/* Look for file in directory */
if (args->path != NULL)
strcpy (foo, args->path);
if ((args->received_name != NULL) &&
(strlen (args->received_name) > 0) &&
args->options.Resync)
{
strcat (foo, args->received_name);
if (stat (foo, &st) == 0)
{
if ((st.st_size == args->filelen) && (st.st_atime == args->save_filetime.oneword.timedate))
{
if ((args->file_pointer = buff_fopen (foo, "rb+")) != NULL)
{
throughput (0, 0L);
fseek (args->file_pointer, 0L, SEEK_END);
args->sub_results = DID_RESYNC;
args->temp_name = calloc (1, 80);
strcpy (args->temp_name, foo);
args->prev_bytes = args->filelen;
status_line (msgtxt[M_ALREADY_HAVE], foo);
status_line (msgtxt[M_SYNCHRONIZING_EOF]);
return (args->total_blocks + 1L);
}
}
}
/* Look for file in .Z file */
if (dexists (Abortlog_name))
{
sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate);
if (check_failed (Abortlog_name, args->received_name, Resume_info, foo1))
{
foo[0] = '\0';
/* Here it looks like it was a failed WaZOO session */
if (args->path != NULL)
strcpy (foo, args->path);
strcat (foo, foo1);
if ((args->file_pointer = buff_fopen (foo, "rb+")) != NULL)
{
stat (foo, &st);
throughput (0, 0L);
args->temp_name = calloc (1, 80);
strcpy (args->temp_name, foo);
args->prev_bytes = (st.st_size / 128L) * 128L;
fseek (args->file_pointer, args->prev_bytes, SEEK_SET);
status_line (msgtxt[M_SYNCHRONIZING_OFFSET], args->prev_bytes);
return (args->prev_bytes / 128L + 1L);
}
}
}
}
return (Open_Xmodem_File (args));
}
void Finish_Xmodem_Receive (args)
XMARGSP args;
{
struct stat st;
char new_name[80];
struct utimbuf times;
int i, j, k;
/* Set the file's time and date stamp */
if ((args->save_header == SOH) || (args->save_header == SYN))
{
(void) buff_fclose (args->file_pointer);
times.modtime = (long) args->save_filetime.oneword.timedate;
times.actime = (long) args->save_filetime.oneword.timedate;
(void) utime (args->temp_name, ×);
}
else
{
(void) strcpy (args->received_name, "");
(void) buff_fclose (args->file_pointer);
}
if (args->result == SUCCESS)
{
/* Get the file information */
(void) stat (args->temp_name, &st);
throughput (1, (unsigned long) (st.st_size - args->prev_bytes));
update_files (0);
if (args->sub_results & DID_RESYNC)
{
status_line ("%s: %s", msgtxt[M_FILE_RECEIVED], args->temp_name);
}
else
{
new_name[0] = '\0';
if (args->path != NULL)
(void) strcpy (new_name, args->path);
if ((args->filename == NULL) || (strlen (args->filename) == 0))
{
if (strlen (args->received_name) > 0)
(void) strcat (new_name, args->received_name);
else
(void) strcat (new_name, "BAD_FILE.000");
}
else
{
(void) strcat (new_name, args->filename);
}
i = (int) strlen (args->temp_name) - 1;
j = (int) strlen (new_name) - 1;
if (args->temp_name[i] == '.')
args->temp_name[i] = '\0';
if (new_name[j] == '.')
{
new_name[j] = '\0';
--j;
}
i = 0;
k = is_arcmail (new_name, j);
status_line ("%s: %s", msgtxt[M_FILE_RECEIVED], new_name);
if ((!overwrite) || k)
{
while (rename (args->temp_name, new_name))
{
if (isdigit (new_name[j]))
new_name[j]++;
else new_name[j] = '0';
if (!isdigit (new_name[j]))
{
return;
}
i = 1;
}
CLEAR_IOERR ();
}
else
{
(void) unlink (new_name);
while (rename (args->temp_name, new_name))
{
if (!i)
{
status_line (msgtxt[M_ORIGINAL_NAME_BAD], new_name);
}
if (isdigit (new_name[j]))
new_name[j]++;
else new_name[j] = '0';
if (!isdigit (new_name[j]))
{
return;
}
i = 1;
}
CLEAR_IOERR ();
}
if (i)
{
if (locate_y && !(fullscreen && un_attended))
gotoxy (2, locate_y - 1);
status_line (msgtxt[M_RENAME_MSG], new_name);
}
}
remove_abort (Abortlog_name, args->received_name);
}
else
{
if ((args->received_name != NULL) && (strlen (args->received_name) > 0) && (args->save_header != 0))
{
sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate);
add_abort (Abortlog_name, args->received_name, args->temp_name, args->path, Resume_info);
}
else
{
/* File aborted, so remove all traces of it */
if (args->temp_name != NULL)
(void) unlink (args->temp_name);
}
}
if (args->temp_name != NULL)
free (args->temp_name);
}
void Get_Telink_Info (args)
XMARGSP args;
{
char *p1;
char junkbuff[100];
TLDATAP t;
unsigned int i, j;
/* Figure out how many blocks we will get */
t = (TLDATAP) &(args->header);
args->total_blocks = (t->filelength + 127)/ 128;
t->nullbyte = '\0';
p1 = strchr (t->filename, ' ');
if (p1 != NULL)
*p1 = '\0';
strcpy (args->received_name, t->filename);
args->save_header = args->header;
if (args->save_header == SYN)
{
i = t->filetime.twowords.time;
j = t->filetime.twowords.date;
args->save_filetime.oneword.timedate = _dtoxtime (j >> 9, (j >> 5) & 0x0f,
j & 0x1f, i >> 11, (i >> 5) & 0x3f, i & 0x1f);
}
else
{
args->save_filetime.oneword.timedate = t->filetime.oneword.timedate;
}
args->filelen = t->filelength;
(void) sprintf (junkbuff, msgtxt[M_RECEIVE_MSG],
args->total_blocks, t->filename, t->sendingprog, t->filelength);
strcpy (sending_program, t->sendingprog);
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 ();
}
}
int Read_Block (args)
XMARGSP args;
{
unsigned char *p; /* Pointers to XMODEM data */
int i; /* Counter */
int j; /* Counter start */
unsigned char c; /* character being processed */
int in_char;
char junkbuff[128];
long head_timer;
if (got_ESC ())
{
status_line (msgtxt[M_KBD_MSG]);
return (KBD_ERR);
}
/* Set up to point into the XMODEM data structure */
p = (unsigned char *) &(args->header);
/* Get the first character that is waiting */
*p = (unsigned char) TIMED_READ (8);
head_timer = timerset (6000);
j = 1;
while (!timeup (head_timer))
{
/* Now key off of the header character */
switch (*p)
{
case EOT: /* End of file */
/* Is this a valid EOT */
if (args->total_blocks <= args->WriteBLK)
{
return (EOT_BLOCK);
}
else
{
status_line (msgtxt[M_UNEXPECTED_EOF], args->total_blocks);
return (BAD_BLOCK);
}
case SYN: /* Telink block */
/* For Telink, read all of the data except the checksum */
for (i = 1; i < sizeof (TLDATA) - 2; i++)
{
/* If we go more than 5 second, then we have a short block */
if ((in_char = TIMED_READ (5)) < 0)
{
return (BAD_BLOCK);
}
*(++p) = (unsigned char) (in_char & 0xff);
}
/* if the block number or its complement are wrong, return error */
if ((args->block_num != 0) || (args->block_num_comp != 0xff))
{
return (BAD_BLOCK);
}
/* Now calculate the checksum - Telink block always checksum mode */
Data_Check ((XMDATAP) &(args->header), CHECKSUM);
/* See if we can receive the checksum byte */
if ((in_char = TIMED_READ (10)) < 0)
{
Xmodem_Error (msgtxt[M_TIMEOUT], 0L);
return (BAD_BLOCK);
}
/* Was it right */
c = (unsigned char) (in_char & 0xff);
if (c != args->data_check[0])
{
Xmodem_Error (msgtxt[M_CHECKSUM], 0L);
return (BAD_BLOCK);
}
/* Everything looks good, it must be a legal TELINK block */
Get_Telink_Info (args);
return (TELINK_BLOCK);
case SOH: /* Normal data block */
args->datalen = 128;
/* Read in all of the data for an XMODEM block except the checksum */
p += (j - 1);
for (i = j; i < sizeof (XMDATA) - 2; i++)
{
/* If we go more than 5 seconds, then it is a short block */
if ((in_char = TIMED_READ (5)) < 0)
{
return (BAD_BLOCK);
}
*(++p) = (unsigned char) (in_char & 0xff);
}
/* The block number is 0 to 255 inclusive */
c = (unsigned char) (args->blocknum & 0xff);
/* Properly calculate the CRC or checksum */
Data_Check ((XMDATAP) &(args->header), args->options.do_CRC ? CRC : CHECKSUM);
/* Can we get the checksum byte */
if ((in_char = TIMED_READ (10)) < 0)
{
Xmodem_Error (msgtxt[M_TIMEOUT], args->WriteBLK);
return (BAD_BLOCK);
}
/* Is it the right value */
c = (unsigned char) (in_char & 0xff);
if (c != args->data_check[0])
{
status_line (">Xmodem Receive: Bad %s", (args->options.do_CRC)?"CRC":"checksum");
Xmodem_Error (msgtxt[M_CRC_MSG], args->WriteBLK);
if (args->options.do_CRC)
(void) TIMED_READ (5);
return (BAD_BLOCK);
}
/* If we are in CRC mode, do the second byte */
if (args->options.do_CRC)
{
/* Can we get the character */
if ((in_char = TIMED_READ (10)) < 0)
{
status_line (">Xmodem Receive: Timeout waiting for CRC byte 2");
Xmodem_Error (msgtxt[M_TIMEOUT], args->WriteBLK);
return (BAD_BLOCK);
}
/* Is it right */
c = (unsigned char) (in_char & 0xff);
if (c != args->data_check[1])
{
Xmodem_Error (msgtxt[M_CRC_MSG], args->WriteBLK);
return (BAD_BLOCK);
}
}
/* Do we have a valid data block */
if (args->block_num_comp != ((~(args->block_num)) & 0xff))
{
if (!(args->options.SEAlink))
{
Xmodem_Error (msgtxt[M_JUNK_BLOCK], args->WriteBLK);
return (BAD_BLOCK);
}
p = (unsigned char *) &(args->header);
j = Header_in_data (p);
if (j)
{
continue;
}
j = 1;
Find_Char (SOH);
*p = (unsigned char) TIMED_READ (0);
}
if ((args->WriteBLK == 1) && (args->header == SOH) && (args->block_num == 0))
{
Get_Telink_Info (args);
return (SEALINK_BLOCK);
}
if (first_block)
{
struct _pkthdr *packet;
packet = (struct _pkthdr *) args->data;
if (!remote_capabilities)
{
remote_addr.Zone = packet->orig_zone;
remote_addr.Net = packet->orig_net;
remote_addr.Node = packet->orig_node;
if (packet->rate == 2)
{
/* This is a special type 2.2 packet! */
remote_addr.Point = (unsigned) packet->year;
packet->B_fill3 = 0L;
packet->B_fill2[8] = '\0';
remote_addr.Domain = find_domain (packet->B_fill2);
if ((pvtnet >= 0) &&
((remote_addr.Zone == alias[assumed].Zone) || (remote_addr.Zone == 0)) &&
(remote_addr.Net == boss_addr.Net) && (remote_addr.Node == boss_addr.Node) &&
(remote_addr.Point > 0))
{
remote_addr.Net = pvtnet;
remote_addr.Node = remote_addr.Point;
remote_addr.Point = 0;
}
else if (remote_addr.Point > 0)
{
remote_addr.Point = 0;
remote_addr.Node = -1;
}
}
else
{
remote_addr.Point = 0;
remote_addr.Domain = NULL;
}
}
if (who_is_he)
{
if (!remote_addr.Zone && !remote_addr.Net && !remote_addr.Node)
{
DTR_OFF (); /* Bad trip, cut it off */
timer (2); /* Wait two secs */
return(CARRIER_ERR); /* Get out of here! */
}
if (nodefind (&remote_addr, 1))
{
if (!remote_addr.Zone)
remote_addr.Zone = found_zone;
(void) sprintf (junkbuff, "%s: %s (%s)",
msgtxt[M_REMOTE_SYSTEM],
newnodedes.SystemName,
Full_Addr_Str (&remote_addr));
}
else
{
(void) sprintf (junkbuff, "%s: %s (%s)",
msgtxt[M_REMOTE_SYSTEM],
msgtxt[M_UNKNOWN_MAILER],
Full_Addr_Str (&remote_addr));
}
last_type (2, &remote_addr);
status_line (junkbuff);
}
if (sending_program[0] != '\0')
{
status_line ("%s %s", msgtxt[M_REMOTE_USES], sending_program);
}
else
{
log_product (packet->product, 0, packet->serial);
}
who_is_he = 0;
first_block = 0;
}
if (args->WriteBLK == args->total_blocks)
{
args->datalen = (int) (args->filelen - ((args->WriteBLK - 1) * 128));
}
/* If we got this far, it is a valid data block */
args->recblock = args->block_num;
return (XMODEM_BLOCK);
default: /* Bad block */
if ((args->blocknum <= 1) || (PEEKBYTE () < 0))
return (BAD_BLOCK);
/* Garbage header, return bad */
*p = (unsigned char) TIMED_READ (0);
}
}
return (BAD_BLOCK);
}
int XRInit (args, start_state)
XMARGSP args;
int start_state;
{
char *HoldName;
args->tries = 0;
args->goodfile = 1;
XON_DISABLE ();
HoldName = HoldAreaNameMunge(&called_addr);
sprintf (Abortlog_name, "%s%s.Z\0",
HoldName, Hex_Addr_Str (&remote_addr));
sending_program[0] = '\0';
return (start_state);
}
int XREnd (args, cur_state)
XMARGSP args;
int cur_state;
{
args->result = cur_state;
Finish_Xmodem_Receive (args);
return (cur_state);
}
int XRRecInit (args)
XMARGSP args;
{
args->options.SEAlink = 0;
args->options.SLO = 0;
args->options.Resync = 0;
args->options.MacFlow = 0;
args->options.do_CRC = 1;
args->blocknum = 0;
args->WriteBLK = 1;
args->curr_byte = 0L;
args->tries = 0;
return (XR1);
}
int XRBrecInit (args)
XMARGSP args;
{
args->options.SEAlink = 0;
args->options.SLO = 0;
args->options.Resync = 0;
args->options.MacFlow = 0;
args->options.do_CRC = 1;
args->blocknum = 0;
args->WriteBLK = 1;
args->curr_byte = 0L;
args->tries = 0;
return (XR2);
}
int XRRecStart (args)
XMARGSP args;
{
Send_NAK (args);
return (XR2);
}
int XRWaitFirst (args)
XMARGSP args;
{
long XR2Timer;
XR2Timer = timerset (800);
if (args->tries >= 10)
{
args->goodfile = 0;
return (TIME_ERR);
}
if (args->tries == 5)
{
args->options.do_CRC = 0;
++(args->tries);
return (XR1);
}
while (CARRIER)
{
switch (Read_Block (args))
{
case EOT_BLOCK:
args->WriteBLK = 0;
Send_ACK (args);
return (SUCCESS_EOT);
case TELINK_BLOCK:
if (Open_Xmodem_File (args) == -1L)
return (OPEN_ERR);
Send_ACK (args);
args->tries = 0;
return (XR3);
case SEALINK_BLOCK:
args->options.SEAlink = no_sealink ? 0 : 1;
if (args->options.SEAlink && !no_resync)
args->options.Resync = (((SEADATAP) (&(args->header)))->Resync) != 0;
return (XR4);
case XMODEM_BLOCK:
if (args->recblock == 1)
{
if (Open_Xmodem_File (args) == -1L)
return (OPEN_ERR);
(void) buff_fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer);
++(args->WriteBLK);
args->curr_byte = 128L;
++(args->blocknum);
Send_ACK (args);
args->tries = 0;
return (XR3);
}
/* Fallthrough on wrong block */
case BAD_BLOCK:
++(args->tries);
return (XR1);
case CARRIER_ERR:
case KBD_ERR:
return (CARRIER_ERR);
}
if (timeup (XR2Timer))
{
++(args->tries);
return (XR1);
}
}
return (CARRIER_ERR);
}
int XRWaitBlock (args)
XMARGSP args;
{
if (args->tries >= 10)
{
args->goodfile = 0;
return (TIME_ERR);
}
while (CARRIER)
{
switch (Read_Block (args))
{
case EOT_BLOCK:
args->options.SLO = 0;
Send_ACK (args);
return (SUCCESS);
case XMODEM_BLOCK:
if (args->recblock == (unsigned char) ((args->blocknum - 1) & 0xff))
{
--(args->blocknum);
Send_ACK (args);
return (XR3);
}
if (args->recblock == args->blocknum)
{
(void) buff_fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer);
++(args->WriteBLK);
args->curr_byte += 128L;
Send_ACK (args);
args->tries = 0;
return (XR3);
}
if (args->recblock < args->blocknum)
{
args->recblock += 256;
}
if ((args->recblock > (unsigned) args->blocknum) && (args->recblock <= ((unsigned) (((unsigned) args->blocknum) + 127))))
{
if (args->tries != 0)
{
/* We have sent at least one nak, now only send them
every so often to allow buffers to drain */
if ((args->recblock - (unsigned) args->blocknum) % 16)
return (XR3);
/* If it is a multiple of 16, then check that it is
higher than 32 */
if ((args->recblock - (unsigned) args->blocknum) / 16 < 2)
return (XR3);
}
}
/* fallthrough on bad block */
case BAD_BLOCK:
Send_NAK (args);
++(args->tries);
return (XR3);
case CARRIER_ERR:
case KBD_ERR:
return (CARRIER_ERR);
}
}
return (CARRIER_ERR);
}
int XRRestart (args)
XMARGSP args;
{
long c;
c = Set_Up_Restart (args);
if (c == -1L)
return (OPEN_ERR);
if ((!c) || (!(args->options.Resync)))
{
Send_ACK (args);
args->tries = 0;
}
else
{
args->WriteBLK = c;
args->curr_byte = (c - 1) * 128L;
args->blocknum = (unsigned char) ((args->WriteBLK) & 0xff);
Send_NAK (args);
}
return (XR5);
}
int XRSetOvrdr (args)
XMARGSP args;
{
if (!no_overdrive)
args->options.SLO = (((SEADATAP) (&(args->header)))->SLO) != 0;
if (args->options.SLO)
show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args);
return (XR3);
}
int Xmodem_Receive_File (path, filename)
char *path;
char *filename;
{
XMARGS xmfile;
int res;
locate_y = wherey ();
locate_x = wherex ();
memset (&xmfile, 0, sizeof (XMARGS));
xmfile.path = path;
xmfile.filename = filename;
xmfile.total_blocks = -1L;
xmfile.sent_ACK = 0;
res = state_machine (Xmodem_Receiver, &xmfile, XR0);
return (res);
}
int Batch_Xmodem_Receive_File (path, filename)
char *path;
char *filename;
{
XMARGS xmfile;
int res;
locate_y = wherey ();
locate_x = wherex ();
memset (&xmfile, 0, sizeof (XMARGS));
xmfile.path = path;
xmfile.filename = filename;
xmfile.total_blocks = -1L;
xmfile.sent_ACK = 0;
res = state_machine (Xmodem_Receiver, &xmfile, XR0B);
return (res);
}
int SAInit (XMARGSP, int);
int SAEnd (XMARGSP, int);
int SAClearLine (XMARGSP);
int SASendACK (XMARGSP);
int SASEAlink (XMARGSP);
int SAIncBlk (XMARGSP);
STATES ACK_States[] = {
{ "SAInit", SAInit },
{ "SAEnd", SAEnd },
{ "SA0", SAClearLine },
{ "SA1", SASendACK },
{ "SA2", SASEAlink },
{ "SA3", SAIncBlk }
};
int SAInit (args, start_state)
XMARGSP args;
int start_state;
{
return (start_state);
args;
}
int SAEnd (args, cur_state)
XMARGSP args;
int cur_state;
{
return (cur_state);
args;
}
int SAClearLine (args)
XMARGSP args;
{
long SA0Timer;
SA0Timer = timerset (3000);
if (args->options.SLO)
return (SA3);
if (args->options.SEAlink)
return (SA1);
while (CARRIER && !timeup (SA0Timer))
{
if (PEEKBYTE () >= 0)
{
(void) TIMED_READ (0);
time_release ();
continue;
}
return (SA1);
}
return (TIME_ERR);
}
int SASendACK (args)
XMARGSP args;
{
SENDBYTE (ACK);
args->sent_ACK = 1;
return (SA2);
}
int SASEAlink (args)
XMARGSP args;
{
if (!(args->options.SEAlink))
return (SA3);
SENDBYTE (args->blocknum);
SENDBYTE (~(args->blocknum));
return (SA3);
}
void show_block (b, c, args)
long b;
char *c;
XMARGSP args;
{
char j[100];
int i;
long k;
if (fullscreen && un_attended)
{
elapse_time();
sb_move (filewin, 2, 2);
sb_puts (filewin, (unsigned char *) ultoa (((unsigned long) b), e_input, 10));
if (c)
(void) sb_puts (filewin, c);
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);
sb_move (filewin, 2, 69);
sb_puts (filewin, j);
sb_show ();
}
else
{
gotoxy (locate_x, locate_y);
(void) printf ("%s", ultoa (((unsigned long) b), e_input, 10));
if (c)
(void) printf ("%s", c);
}
}
int SAIncBlk (args)
XMARGSP args;
{
++(args->blocknum);
if ((args->options.SLO) &&
(((args->WriteBLK > 0) && (!((args->WriteBLK - 1) & 0x001F)) && (args->WriteBLK < args->total_blocks)) ||
(args->WriteBLK >= args->total_blocks)))
{
show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args);
}
else if ((!(args->options.SLO)) && (args->WriteBLK > 0))
{
show_block ((long) (args->WriteBLK - 1), NULL, args);
}
return (SUCCESS);
}
void Send_ACK (args)
XMARGSP args;
{
state_machine (ACK_States, args, SA0);
}
void Send_Resync_Packet (XMARGSP);
int SNInit (XMARGSP, int);
int SNEnd (XMARGSP, int);
int SNClearLine (XMARGSP);
int SNSendNAK (XMARGSP);
int SNSEAlink (XMARGSP);
int SNAckResync (XMARGSP);
STATES NAK_States[] = {
{ "SNInit", SNInit },
{ "SNEnd", SNEnd },
{ "SN0", SNClearLine },
{ "SN1", SNSendNAK },
{ "SN2", SNSEAlink },
{ "SN3", SNAckResync }
};
int SNInit (args, start_state)
XMARGSP args;
int start_state;
{
return (start_state);
args;
}
int SNEnd (args, cur_state)
XMARGSP args;
int cur_state;
{
return (cur_state);
args;
}
int SNClearLine (args)
XMARGSP args;
{
long SN0Timer;
SN0Timer = timerset (3000);
if (args->options.Resync)
{
Send_Resync_Packet (args);
return (SN3);
}
if (args->options.SEAlink)
return (SN1);
while (CARRIER && !timeup (SN0Timer))
{
if (PEEKBYTE () >= 0)
{
(void) TIMED_READ (0);
time_release ();
continue;
}
return (SN1);
}
return (TIME_ERR);
}
int SNSendNAK (args)
XMARGSP args;
{
if (args->options.do_CRC && (args->sent_ACK == 0))
SENDBYTE (WANTCRC);
else
SENDBYTE (NAK);
return (SN2);
}
int SNSEAlink (args)
XMARGSP args;
{
if (!(args->options.SEAlink))
return (SUCCESS);
SENDBYTE (args->blocknum);
SENDBYTE (~(args->blocknum));
return (SUCCESS);
}
int SNAckResync (args)
XMARGSP args;
{
long SN3Timer;
int c;
SN3Timer = timerset (3000);
while (CARRIER && !timeup (SN3Timer))
{
if ((c = TIMED_READ (10)) == 0xffff)
{
Send_Resync_Packet (args);
continue;
}
if (c == ACK)
{
big_pause (1);
c = PEEKBYTE();
if ((c == SOH) || (c == EOT))
return (SUCCESS);
}
// time_release(); /* CML -- stop hogging my CPU! */
}
if (!CARRIER)
return (CARRIER_ERR);
else
return (TIME_ERR);
}
void Send_NAK (args)
XMARGSP args;
{
state_machine (NAK_States, args, SN0);
}
void Send_Resync_Packet (args)
XMARGSP args;
{
unsigned char resyncit[30];
unsigned int nak_crc;
SENDBYTE (SYN);
(void) sprintf ((char *) resyncit, "%ld", args->WriteBLK);
SENDCHARS ((char *) resyncit, strlen ((char *) resyncit), 1);
nak_crc = crc_block ((unsigned char *) resyncit, (int) strlen ((char *) resyncit));
SENDBYTE (ETX);
SENDBYTE ((unsigned char) (nak_crc & 0xff));
CLEAR_INBOUND ();
SENDBYTE ((unsigned char) (nak_crc >> 8));
}
void Xmodem_Error (s, block_number)
char *s;
long block_number;
{
char j[50];
char k[50];
(void) sprintf (j, "%s %s %ld", s, msgtxt[M_ON_BLOCK], block_number);
(void) sprintf (k, "%-49.49s", j);
status_line (">Xmodem Error: %s", k);
if (fullscreen && un_attended)
{
sb_move (filewin, 2, 20);
sb_puts (filewin, (unsigned char *) k);
sb_show ();
}
else
{
gotoxy (locate_x + 20, locate_y);
(void) cputs (k);
}
}
void Find_Char (c)
int c;
{
long t1;
long t2;
t1 = timerset (3000);
t2 = timerset (100);
while (!timeup (t1) && !timeup (t2))
{
if (!CARRIER)
break;
if (PEEKBYTE () == (c & 0xff))
break;
else if (PEEKBYTE () >= 0)
{
(void) TIMED_READ (0);
t2 = timerset (100);
}
// time_release(); /* CML -- stop hogging my CPU! */
}
}
int Header_in_data (p)
unsigned char *p;
{
int i;
int j;
char *p1;
p1 = (char *) p;
++p1;
j = sizeof (XMDATA) - 2;
for (i = 1; i < j; i++, p1++)
{
if (*p1 == SOH)
{
(void) memcpy (p, p1, (unsigned int) (j - i));
return (j - i);
}
}
return (0);
}