This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/deps/Xmodem/xmodemt.c
2017-03-18 14:37:16 +10:00

411 lines
7.4 KiB
C

#ifndef lint
static const char rcsid[] = "$Id: xmodemt.c,v 1.2 2001/10/25 23:56:29 efalk Exp $" ;
#endif
/*
* Copyright (c) 1995 by Edward A. Falk
*/
/**********
*
*
* @ @ @ @ @@@ @@@@ @@@@@ @ @ @@@@@
* @ @ @@ @@ @ @ @ @ @ @@ @@ @
* @ @ @ @ @ @ @ @ @@@ @ @ @ @
* @ @ @ @ @ @ @ @ @ @ @ @ @ @
* @ @ @ @ @ @@@ @@@@ @@@@@ @ @ @ @
*
* XMODEMT - transmit side of xmodem protocol
*
* Caller sets flags defined in xmodem.h as appropriate.
* (default is basic xmodem)
*
* This code is designed to be called from inside a larger
* program, so it is implemented as a state machine where
* practical.
*
* functions:
*
* XmodemTInit(char *filename, Protocol p)
* Initiate a receive
*
* XmodemTTimeout()
* called after timeout expired
*
* XmodemTRcv(char c)
* called after character received
*
* XmodemTFinish()
* last file (ymodem)
*
* XmodemTAbort()
* abort transfer
*
* all functions return 0 on success, 1 on abort
*
* Edward A. Falk
*
* January, 1995
*
*
*
**********/
#include <stdio.h>
#include <sys/types.h>
#include "xmodem.h"
bool fileInfo = False ;
/* TODO: WXmodem, YmodemG */
typedef enum {
File, /* waiting for initial protocol character */
FileWait, /* sent file header, waiting for ACK */
Start, /* waiting to begin */
Wait, /* sent a packet, waiting for ACK */
Eot, /* sent an EOT, waiting for ACK */
EndWait, /* sent null filename, waiting for ACK */
} XmodemState ;
static XmodemState state = Start ;
static bool ymodem ;
static bool useCrc ; /* receiver wants crc */
static int pktLen ; /* length of this packet data */
static int pktMaxLen ;
static char packet[MAXPACKET] ;
static char pktHdr[3], pktCrc[2] ;
static int packetId ; /* id of last received packet */
static int packetCount ; /* # packets received */
static FILE *ifile = NULL ; /* input file fd */
static int fileLen, fileDate, fileMode ;
static int sendFilename() ;
static int sendPacket() ;
static int buildPacket() ;
static int resendPacket() ;
int
XmodemTInit( char *file, Protocol prot )
{
int err ;
protocol = prot ;
ymodem = prot == Ymodem || prot == YmodemG ;
state = ymodem ? File : Start ;
strcpy(xmFilename, file) ;
if( (ifile = fopen(xmFilename, "r")) == NULL ) {
sendCancel() ;
return XmErrCantOpen ;
}
packetId = 1 ;
packetCount = 0 ;
pktMaxLen = xmodem1k ? 1024 : 128 ;
xmTimeout = 60 ;
return 0 ;
}
int
XmodemTRcv(char c)
{
if( c == CAN ) {
if( ifile != NULL )
fclose(ifile) ;
return XmErrCancel ;
}
switch( state ) {
case File: /* waiting for command, ymodem */
switch( c ) {
case NAK: useCrc = False ; return sendFilename() ;
case 'C': useCrc = True ; return sendFilename() ;
}
break ;
case FileWait: /* waiting for filename ACK */
switch( c ) {
case NAK: return resendPacket() ;
case ACK: state = Start ; return 0 ;
}
case Start: /* waiting for command, data */
switch( c ) {
case NAK: /* wants checksums */
if( !ymodem )
protocol = Xmodem ;
useCrc = False ;
return sendPacket() ;
case 'C': useCrc = True ; return sendPacket() ;
case 'W':
if( !ymodem ) {
protocol = WXmodem ;
useCrc = True ;
/* TODO: WXmodem */
}
}
break ;
case Wait: /* waiting for ACK */
switch( c ) {
case ACK: return sendPacket() ;
case NAK: return resendPacket() ;
}
break ; /* ignore all other characters */
case Eot: /* waiting for ACK after EOT */
switch( c ) {
case ACK: return XmDone ;
case NAK: return sendChr(EOT) ;
}
break ;
case EndWait: /* waiting for filename ACK */
switch( c ) {
case NAK: return resendPacket() ;
case ACK: return XmDone ;
}
}
return 0 ;
}
static int
sendFilename()
{
int i ;
char *ptr ;
pktLen = 128 ;
/* TODO: protect against long filenames */
strcpy(packet, xmFilename) ;
ptr = packet + strlen(packet) + 1 ;
/* TODO: get file info */
if( fileInfo ) {
sprintf(ptr, "%d %o %o %o", 0,0,0100644) ;
ptr += strlen(ptr) + 1 ;
}
/* TODO: what if file desc buffer too big? */
if( ptr > packet+128 )
pktLen = 1024 ;
i = pktLen - (ptr-packet) ;
bzero(ptr, i) ;
state = FileWait ;
packetId = 0 ;
return buildPacket() ;
}
int
XmodemTFinish()
{
int i ;
char *ptr ;
pktLen = 128 ;
bzero(packet, pktLen) ;
state = EndWait ;
packetId = 0 ;
return buildPacket() ;
}
static char *bufptr ;
static int buflen = 0 ;
static int
sendPacket()
{
int i ;
/* This code assumes that a incomplete reads can only happen
* after EOF. This will fail with pipes.
* TODO: try to make pipes work.
*/
state = Wait ;
if( buflen > 0 ) /* previous incomplete packet */
{
memcpy(packet, bufptr, 128) ;
bufptr += 128 ;
if( buflen < 128 )
for(i=buflen; i<128; ++i)
packet[i] = 0x1a ;
buflen -= 128 ;
pktLen = 128 ;
return buildPacket() ;
}
if( (i=fread(packet, 1,pktMaxLen, ifile)) <= 0 ) /* EOF */
{
state = Eot ;
return sendChr(EOT) ;
}
else if( i == pktMaxLen ) /* full buffer */
{
pktLen = i ;
return buildPacket() ;
}
buflen = i ;
bufptr = packet ;
pktLen = 128 ;
return buildPacket() ;
}
static int
buildPacket()
{
int i ;
pktHdr[0] = pktLen == 128 ? SOH : STX ;
pktHdr[1] = (char)packetId ;
pktHdr[2] = (char)(255-packetId) ;
++packetId ;
if( useCrc ) {
i = calcrc(packet, pktLen) ;
pktCrc[0] = (char) (i>>8) ;
pktCrc[1] = (char) (i & 0xff) ;
}
else
pktCrc[0] = (char) calcChecksum(packet, pktLen) ;
return resendPacket() ;
}
static int
resendPacket()
{
int i ;
(i=sendStr(pktHdr, 3)) || (i=sendStr(packet, pktLen)) ||
(i=sendStr(pktCrc, useCrc?2:1)) ;
return i ;
}
int
XmodemTTimeout()
{
switch( state ) {
case File:
case Start:
return XmErrInitTo ;
case FileWait:
case Wait:
case Eot:
return XmErrRcvTo ;
}
}
int
XmodemTAbort()
{
return sendCancel() ;
}
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/termios.h>
main(argc,argv)
int argc ;
char **argv ;
{
struct termios old_settings, new_settings ;
fd_set readfds ;
struct timeval timeout ;
int i ;
int len ;
char buffer[1024] ;
bool done = False ;
int filecount = 0 ;
if( argc < 2 )
exit(2) ;
xmTfd = xmRfd = open(argv[1], O_RDWR) ;
if( xmTfd == -1 )
exit(1) ;
tcgetattr(xmTfd,&old_settings) ;
new_settings = old_settings ;
new_settings.c_iflag &=
~(ISTRIP|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXOFF|IMAXBEL) ;
new_settings.c_oflag = 0 ;
new_settings.c_cflag = B300|CS8|CREAD|CLOCAL ;
new_settings.c_lflag = 0 ;
new_settings.c_cc[VMIN] = 32 ;
new_settings.c_cc[VTIME] = 1 ;
tcsetattr(xmTfd,TCSADRAIN, &new_settings) ;
xmodem1k = 1 ;
done = XmodemTInit("xmodem.h", Ymodem) != 0 ;
while(!done)
{
FD_ZERO(&readfds) ;
FD_SET(xmTfd, &readfds) ;
timeout.tv_sec = xmTimeout ;
timeout.tv_usec = 0 ;
i = select(xmTfd+1, &readfds,NULL,NULL, &timeout) ;
if( i<0 )
perror("select") ;
else if( i==0 )
done = XmodemTTimeout() != 0 ;
else {
len = read(xmTfd, buffer, sizeof(buffer)) ;
for(i=0; !done && i<len; ++i)
done = XmodemTRcv(buffer[i]) != 0 ;
}
if( done ) {
switch( ++filecount ) {
case 1:
done = XmodemTInit("crc.c", Ymodem) != 0 ;
break ;
case 2:
done = XmodemTFinish() ;
break ;
case 3: break ;
}
}
}
tcsetattr(xmTfd,TCSADRAIN, &old_settings) ;
exit(0) ;
}