home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff330.lzh
/
Vt100
/
Src.lzh
/
Src
/
xmodem.c
< prev
Wrap
C/C++ Source or Header
|
1990-03-01
|
17KB
|
598 lines
static char rcsid[] = "$RCSfile: xmodem.c,v $ $Revision: 1.3 $";
/*************************************************************
* vt100 terminal emulator - XMODEM protocol support
* :ts=8
*
* $Log: xmodem.c,v $
* Revision 1.3 89/12/14 20:33:37 acs
* 1) Use longs for byte count in xmodem transfers.
* 2) Remove commented out code.
*
* Revision 1.2 89/12/12 13:39:05 acs
* multi_xfer() will pass "$" to called routines. This means that
* XMODEM_Read_File(), XMODEM_Send_File() and the kermit routines need
* to check for a filename == "$".
*
* v2.9 ACS - multi_xfer() no longer looks for $ -- kermit does,
* readchar() now infers ttime of 100,000 micros if ttime == 0
* (for newkermit); readchar() doesn't output a TIMED OUT msg
* (because of newkermit); speed up sendstring().
* v2.7 870825 ACS - Make multi_xfer() non-recursive; on non-ESC in
* readchar() re-do the main window's title.
* v2.6 870227 DBW - bug fixes for all the stuff in v2.5
* v2.5 870214 DBW - more additions (see readme file)
* v2.4 861214 DBW - lots of fixes/additions (see readme file)
* v2.3 861101 DBW - minor bug fixes
* v2.2 861012 DBW - more of the same
* v2.1 860915 DBW - new features (see README)
* 860901 ACS - Added Parity and Word Length and support code
* 860823 DBW - Integrated and rewrote lots of code
* 860815 Steve Drew: readchar inproved with real timeouts
* v2.0 860809 DBW - Major rewrite
* v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes
* v1.0 860712 DBW - First version released
*
*************************************************************/
#include "vt100.h"
int enablexon = TRUE;
extern struct IntuiText MyTitle;
static unsigned long parity_settings[4] = {
0x96696996,
0x69969669,
0x69969669,
0x96696996 };
/* crctab calculated by Mark G. Mendel, Network Systems Corporation */
static unsigned short crctab[256] = {
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
};
/*
* updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
* NOTE: First srgument must be in range 0 to 255.
* Second argument is referenced twice.
*
* Programmers may incorporate any or all code into their programs,
* giving proper credit within the source. Publication of the
* source routines is permitted so long as proper credit is given
* to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
* Omen Technology.
*/
#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
/************************************************************
* Send a string (using sendchar below)
************************************************************/
void sendstring(s)
register char *s;
{
char data[20];
register char *cp = data;
int i;
LONG oldlength = Write_Request->IOSer.io_Length;
APTR saveaddr = Write_Request->IOSer.io_Data;
Write_Request->IOSer.io_Length = sizeof(data)-1;
Write_Request->IOSer.io_Data = (APTR) &(data[0]);
if (enablexon)
No_XON();
while(i = *(s++)) {
*(cp++) = addparity(i);
if( (cp - data) == sizeof(data)-1) {
*cp = '\0';
do
DoIO((struct IORequest *)Write_Request);
while(Write_Request->IOSer.io_Error != 0);
cp = data;
}
}
if(cp > data) {
*(cp++) = '\0';
Write_Request->IOSer.io_Length = strlen(data);
do
DoIO((struct IORequest *)Write_Request);
while(Write_Request->IOSer.io_Error != 0);
}
Write_Request->IOSer.io_Length = oldlength;
Write_Request->IOSer.io_Data = saveaddr;
if (enablexon)
No_XON();
}
/**************************************************************/
/* send char and read char functions for the xmodem function */
/************************************************************/
void sendchar(ch)
int ch;
{
if (enablexon)
No_XON();
rs_out[0] = addparity(ch);
do {
DoIO((struct IORequest *)Write_Request);
} while(Write_Request->IOSer.io_Error != 0);
if (enablexon)
Do_XON();
}
static int
addparity(ch)
register int ch;
{
int i, j, k;
if(p_parity > 0)
switch (p_parity) {
case 1: /* mark */
ch = (ch & 0x7F) | 0x80;
break;
case 2: /* space */
ch &= 0x7F;
break;
case 3: /* even */
case 4: /* odd */
i = (ch >> 5) & 0x3;
j = ch & 0x1F;
k = ((parity_settings[i] >> j) & 0x1) << 7;
if (p_parity == 3) /* even parity */
ch = (ch & 0x7F) | k;
else /* odd parity */
ch = (ch & 0x7F) | (k ^ 0x80);
}
return(ch & 0xFF);
}
/* send a break to the host */
void sendbreak()
{
AbortIO((struct IORequest *)Read_Request);
Wait(1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
WaitIO((struct IORequest *)Read_Request);
Read_Request->IOSer.io_Command = SDCMD_BREAK;
DoIO((struct IORequest *)Read_Request);
Read_Request->IOSer.io_Command = CMD_READ;
SendIO((struct IORequest *)Read_Request);
}
int readchar()
{
int rd,ch;
ULONG class, waitmask;
USHORT code;
if(ttime == 0)
Timer.tr_time.tv_micro = 100000;
else
Timer.tr_time.tv_micro = 0;
Timer.tr_time.tv_secs = ttime;
SendIO((struct IORequest *)&Timer.tr_node);
rd = FALSE;
waitmask = ((1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) |
( 1L << mywindow->UserPort->mp_SigBit) |
( 1L << Timer_Port->mp_SigBit));
if(reqwinup)
waitmask |= (1L << reqwindow->UserPort->mp_SigBit);
while (rd == FALSE) {
Wait(waitmask);
if (CheckIO((struct IORequest *)Read_Request)) {
WaitIO((struct IORequest *)Read_Request);
ch=rs_in[0];
rd = TRUE;
SendIO((struct IORequest *)Read_Request);
}
if(reqwinup &&
(NewMessage=(struct IntuiMessage *)GetMsg(reqwindow->UserPort))) {
class = NewMessage->Class;
ReplyMsg((struct Message *)NewMessage);
if(class == NEWSIZE)
ReqNewSize(reqwindow->Height, reqwindow->Width);
}
if (NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
class = NewMessage->Class;
code = NewMessage->Code;
ReplyMsg((struct Message *)NewMessage);
if ((class == RAWKEY) && (code == 69)) {
if(!CheckIO((struct IORequest *)&Timer))
AbortIO((struct IORequest *)&Timer);
Wait (1L << Timer_Port->mp_SigBit);
WaitIO((struct IORequest *)&Timer.tr_node);
InfoMsg1Line("ERROR: User aborted transfer");
timeout = USERABORT;
return('\0');
}
PrintIText(mywindow->RPort, &MyTitle, 0L, 0L);
}
if (rd == FALSE && CheckIO((struct IORequest *)&Timer)) {
/* InfoMsg1Line("ERROR: Timeout waiting for character"); */
timeout = TIMEOUT;
return('\0');
}
} /* end while */
if(!CheckIO((struct IORequest *)&Timer))
AbortIO((struct IORequest *)&Timer);
Wait (1L << Timer_Port->mp_SigBit);
WaitIO((struct IORequest *)&Timer.tr_node);
timeout = GOODREAD;
return(ch & (p_parity == 0 ? 0xFF : 0x7F));
}
void No_XON()
{
/* turn off XON/XOFF processing */
enablexon = FALSE;
Write_Request->io_SerFlags |= SERF_XDISABLED;
Write_Request->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO((struct IORequest *)Write_Request);
Write_Request->IOSer.io_Command = CMD_WRITE;
}
void Do_XON()
{
/* turn on XON/XOFF processing */
enablexon = TRUE;
Write_Request->io_SerFlags &= ~SERF_XDISABLED;
Write_Request->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO((struct IORequest *)Write_Request);
Write_Request->IOSer.io_Command = CMD_WRITE;
}
/**************************************/
/* xmodem send and recieve functions */
/************************************/
int XMODEM_Read_File(file)
char *file;
{
int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag,
c, good_sect, nak_char, retval = FALSE;
unsigned int checksum, j, bufptr;
unsigned short crc;
char scrstr2[40];
if(strcmp(file, "$") == 0)
return TRUE;
bytes_xferred = 0L;
ttime = TTIME_SHORT;
if( (bufr = AllocMem((long)BufSize, MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
InfoMsg1Line("XMODEM: Can't get a buffer.");
return FALSE;
}
if ((fd = creat(file, 0)) < 0) {
InfoMsg2Line("XMODEM Can't Open File:",file);
goto exit;
} else
InfoMsg1Line("XMODEM Receive, <esc> in VT100 window to abort");
sectnum = errors = bufptr = firstchar = 0;
if(p_xproto == 2)
nak_char = 'C';
else
nak_char = NAK;
No_XON();
sendchar(nak_char);
while (firstchar != EOT && errors != ERRORMAX) {
errorflag = FALSE;
while( (firstchar = readchar()) != SOH && firstchar != EOT) {
if (timeout != GOODREAD) {
if (timeout == USERABORT || errors++ == ERRORMAX)
goto exit;
}
sendchar(nak_char);
}
if (firstchar == SOH) {
sprintf(scrstr2,"%s: Block: %4d Bytes: %ld",
p_xproto==2?"XmodemCRC":"Xmodem", sectnum,
((long)sectnum)*SECSIZ);
InfoMsgNoScroll(scrstr2);
sectcurr = readchar();
if (timeout != GOODREAD)
goto exit;
sectcomp = readchar();
if (timeout != GOODREAD)
goto exit;
if ((sectcurr + sectcomp) == 255) {
if (sectcurr == ((sectnum + 1) & 0xff)) {
checksum = 0; crc = 0;
for (j = bufptr; j < (bufptr + SECSIZ); j++) {
bufr[j] = readchar();
if (timeout != GOODREAD)
goto exit;
checksum = (checksum + bufr[j]) & 0xff;
crc = updcrc(((unsigned int)bufr[j] & 0xff), crc);
}
c = readchar();
if(timeout != GOODREAD) {
errorflag = TRUE;
if(timeout == USERABORT)
goto exit;
}
if(p_xproto == 2) {
crc = updcrc(((unsigned int)c & 0xff), crc);
c = readchar();
if(timeout != GOODREAD) {
errorflag = TRUE;
if(timeout == USERABORT)
goto exit;
}
crc = updcrc(((unsigned int)c & 0xff), crc);
good_sect = (crc == 0);
} else
good_sect = (checksum == c);
if (!good_sect) {
errorflag = TRUE;
if(timeout == USERABORT)
goto exit;
} else {
errors = 0;
sectnum++;
bufptr += SECSIZ;
bytes_xferred += SECSIZ;
if (bufptr == BufSize) {
if (write(fd, bufr, BufSize-SECSIZ) == EOF) {
InfoMsg1Line("XMODEM: Error Writing File");
goto exit;
}
bufptr = SECSIZ;
for (j = 0; j < SECSIZ; j++)
bufr[j] = bufr[(BufSize-SECSIZ)+j];
}
sendchar(ACK);
}
} else {
/* got a duplicate sector */
if (sectcurr == (sectnum & 0xff)) {
/* wait until we time out for 5secs */
do {
readchar();
} while (timeout == GOODREAD);
if (timeout == USERABORT)
goto exit;
InfoMsg1Line("XMODEM: Received Duplicate Sector");
sendchar(ACK);
}
else errorflag = TRUE;
}
} else errorflag = TRUE;
}
if (errorflag == TRUE) {
errors++;
InfoMsg1Line("XMODEM: Error");
sendchar(nak_char);
}
} /* end while */
if ((firstchar == EOT) && (errors < ERRORMAX)) {
sendchar(ACK);
if (bufptr) {
if(p_autochop) {
/* use firstchar to remember the last char for chopping */
if((firstchar = bufr[--bufptr]) == 0 || firstchar == 0x1A)
while (bufptr && bufr[--bufptr] == firstchar)
;
bufptr++;
}
write(fd, bufr, bufptr);
}
close(fd);
ScrollInfoMsg(1);
retval = TRUE;
}
exit:
Do_XON();
FreeMem(bufr, (long)BufSize);
bufr = NULL;
return retval;
}
int XMODEM_Send_File(file)
char *file;
{
int sectnum, bytes_to_send, size, attempts, c, use_crc = 0,
retval = FALSE;
unsigned checksum, j, bufptr;
unsigned short crc;
char scrstr2[40];
if(strcmp(file, "$") == 0)
return TRUE;
bytes_xferred = 0;
ttime = TTIME_LONG;
if( (bufr = AllocMem((long)BufSize, MEMF_PUBLIC|MEMF_CLEAR)) == NULL) {
InfoMsg1Line("XMODEM: Can't get a buffer.");
return FALSE;
}
if ((fd = open(file, 0)) < 0) {
InfoMsg1Line("XMODEM: Cannot Open Send File");
FreeMem(bufr, (long)BufSize);
bufr = NULL;
return FALSE;
} else
InfoMsg1Line("XMODEM Send, <esc> from VT100 window to abort");
attempts = 0;
sectnum = 1;
No_XON();
/* wait for sync char */
j=1;
while (((c = readchar()) != NAK) && (c != 'C') && (j++ < ERRORMAX))
if (timeout == USERABORT)
goto bad_exit;
if (j >= (ERRORMAX)) {
InfoMsg1Line("XMODEM: Receiver not sending");
goto bad_exit;
}
if(c == 'C')
use_crc = 1;
while ((bytes_to_send = read(fd, bufr, BufSize)) &&
attempts != RETRYMAX) {
if (bytes_to_send == EOF) {
InfoMsg1Line("XMODEM: Error Reading File");
goto bad_exit;
}
bufptr = 0;
while (bytes_to_send > 0 && attempts != RETRYMAX) {
attempts = 0;
sprintf(scrstr2,"%s: Sending Block: %4d Bytes: %ld",
use_crc?"XmodemCRC":"Xmodem", sectnum,
((long)sectnum)*SECSIZ);
size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send;
bytes_to_send -= size;
do {
InfoMsgNoScroll(scrstr2);
sendchar(SOH);
sendchar(sectnum);
sendchar(~sectnum);
checksum = 0; crc = 0;
for (j = bufptr; j < bufptr + size; j++) {
sendchar(bufr[j]); /* send buffer data */
checksum += bufr[j];
crc = updcrc(((unsigned int)bufr[j] & 0xff), crc);
}
if( size < SECSIZ ) { /* check if we need to pad */
c = bufr[j-1] ? 0 : 0x1A; /* choose correct padding */
j = SECSIZ - size;
checksum += j * c;
while ( j-- ) {
if(use_crc)
crc = updcrc(c, crc);
sendchar(c); /* send padding */
}
}
if(use_crc) {
crc = updcrc(0, updcrc(0, crc));
sendchar(crc >> 8);
sendchar(crc & 0xff);
} else
sendchar(checksum);
attempts++;
c = readchar();
if (timeout == USERABORT) {
InfoMsg1Line("XMODEM: ABORTED");
goto bad_exit;
}
} while ((c != ACK) && (attempts != RETRYMAX));
bufptr += size;
bytes_xferred += size;
sectnum++;
}
}
close(fd);
if (attempts == RETRYMAX) {
InfoMsg1Line("XMODEM: No Acknowledgment, ABORTING");
goto bad_exit;
} else {
attempts = 0;
do {
sendchar(EOT);
attempts++;
} while ((readchar() != ACK) &&
(attempts != RETRYMAX) &&
(timeout != USERABORT)) ;
if (attempts == RETRYMAX)
InfoMsg1Line("XMODEM: No end of file");
}
ScrollInfoMsg(1);
retval = TRUE;
bad_exit:
Do_XON();
FreeMem(bufr, (long)BufSize);
bufr = NULL;
return retval;
}
/* allow for multi file xfers separated by commas under
kermit and XMODEM */
void multi_xfer(name,mode,do_send)
char *name;
int (*mode)();
int do_send;
{
int done = 0;
int status;
char *p, *name_start;
fd = -1;
timeout = USERABORT - 1;
for(p=name_start=name; !done && timeout != USERABORT; name_start=++p)
{
while(*p == ' ') p++;
while(*p && *p != ',' && *p != ' ') p++;
if (*p == '\0') {
done = TRUE;
multi = 0;
}
else
multi = 1;
*p = '\0';
status = ((*mode)(name_start, multi));
if (status == FALSE && fd >= 0) close(fd);
}
server = 0;
multi = 0;
if(p_xbeep)
cmd_beep(0L);
}