home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume23
/
xmodem3.9
/
part01
/
receive.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-08
|
18KB
|
643 lines
#include "xmodem.h"
/** receive a file **/
/* returns TRUE if in the midst of a batch transfer */
/* returns FALSE if no more files are coming */
/* This routine is one HUGE do-while loop with far to many indented levels.
* I chose this route to facilitate error processing and to avoid GOTOs.
* Given the troubles I've had keeping the nested IF statements straight,
* I was probably mistaken...
*/
rfile(name)
char *name;
{
char *sectdisp();
char *cpm_unix();
char *strcpy();
char *ctime();
time_t time();
int fd, /* file descriptor for created file */
checksum, /* packet checksum */
firstchar, /* first character of a packet */
sectnum, /* number of last received packet (modulo 128) */
sectcurr, /* second byte of packet--should be packet number (mod 128) */
sectcomp, /* third byte of packet--should be complement of sectcurr */
tmode, /* text mode if true */
amode, /* apple mode if true */
errors, /* count of errors for each packet */
sterrors, /* count of errors during startup handshake */
errorflag, /* set true when packet (or first char of putative packet) is invalid */
fatalerror, /* set within main "read-packet" Do-While when bad error found */
inchecksum, /* incoming checksum or CRC */
expsect, /* expected number of sectors (YMODEM batch) */
firstwait, /* seconds to wait for first character in a packet */
nocancanabort, /* if true, don't allow CAN-CAN abort */
bufsize; /* packet size (128 or 1024) */
long recvsectcnt; /* running sector count (128 byte sectors) */
long modtime; /* Unix style file mod time from YMODEM header */
int filemode; /* Unix style file mode from YMODEM header */
int serial; /* serial # from YMODEM header */
int filesleft; /* # of files left from YMODEM header */
long totalleft; /* # of bytes left from YMODEM header */
int yfiletype; /* file type from YMODEM header */
long readbackup; /* "backup" value for characters read in file */
time_t timep[2]; /* used in setting mod time of received file */
char *p; /* generic pointer */
int bufctr; /* number of real chars in read packet */
unsigned char *nameptr; /* ptr in filename for MODEM7 protocol */
time_t start; /* starting time of transfer */
int openflag = FALSE; /* is file open for writing? */
logit("----\nXMODEM File Receive Function\n");
tlogit("----\nXMODEM File Receive Function\n");
if (CRCMODE)
{
logit("CRC mode requested on command line\n");
tlogit("CRC mode requested on command line\n");
}
if (YMODEMG)
{
logit("YMODEM-G mode requested on command line\n");
tlogit("YMODEM-G mode requested on command line\n");
}
BATCH = FALSE; /* don't know if really are in batch mode ! */
fatalerror = FALSE;
firstwait = WAITFIRST; /* For first packet, wait short time */
sectnum = errors = recvsectcnt = 0;
bufsize = 128;
modtime = 0l; filemode = 0;
serial = 0; filesleft = 0; totalleft = 0l; yfiletype = 0;
filelength = 0l; fileread =0l; CHECKLENGTH = FALSE;
nocancanabort = FALSE;
tmode = (XMITTYPE == 't') ? TRUE : FALSE;
amode = (XMITTYPE == 'a') ? TRUE : FALSE;
/* start up transfer */
sterrors = 0;
flushin(); /* flush input queue */
if (YMODEMG)
sendbyte(GCHR);
else if (CRCMODE && !MDM7BAT)
{
sendbyte(CRCCHR);
if (LONGPACK && !MDM7BAT)
sendbyte(KCHR);
}
else
sendbyte(NAK);
do /* start of MAIN Do-While loop to read packets */
{
errorflag = FALSE;
do /* start by reading first byte in packet */
{
firstchar = readbyte(firstwait);
}
while ((firstchar != SOH)
&& (firstchar != STX)
&& (firstchar != EOT)
&& (firstchar != ACK || recvsectcnt > 0)
&& (firstchar != TIMEOUT)
&& (firstchar != CAN || nocancanabort));
if (firstchar == EOT && !NOEOT) /* check for REAL EOT */
{
flushin();
sendbyte(NAK); /* NAK the EOT */
if ((firstchar = readbyte(5)) != EOT) /* check next character */
{
logit("Spurious EOT detected; ignored\n");
tlogit("Spurious EOT detected; ignored\n");
if ((firstchar == SOH) || (firstchar == STX) ||
(firstchar == ACK && recvsectcnt == 0) ||
(firstchar == CAN && !nocancanabort) ||
(firstchar == TIMEOUT))
;
else
{
firstchar = 0;
errorflag = TRUE;
}
}
}
if (firstchar == TIMEOUT) /* timeout? */
{
if (recvsectcnt > 0)
{
logitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
tlogitarg("Timeout on Sector %s\n", sectdisp(recvsectcnt,bufsize,1));
}
errorflag = TRUE;
}
if (firstchar == CAN) /* bailing out? (only at beginning or if CANCAN flag set) */
{
if ((readbyte(3) & 0x7f) == CAN)
{
if (openflag)
{
close(fd);
unlink(name);
error("Reception Canceled by CAN-CAN; partial file deleted",TRUE);
}
else
error("Reception Canceled by CAN-CAN",TRUE);
}
else
{
errorflag = TRUE;
logit("Received single CAN character\n");
tlogit("Received single CAN character\n");
}
}
if (firstchar == ACK) /* MODEM7 batch? (only at beginning) */
{
int i,c;
logit("MODEM7 Batch Protocol\n");
tlogit("MODEM7 Batch Protocol\n");
nameptr = buff;
checksum = 0;
for (i=0; i<NAMSIZ; i++)
{
c = readbyte(3);
if (c == CAN)
{
if (readbyte(3) == CAN)
error("Program Canceled by CAN-CAN", TRUE);
else
{
logit("Received single CAN character in MODEM7 filename\n");
tlogit("Received single CAN character in MODEM7 filename\n");
errorflag = TRUE;
break;
}
}
if (c == EOT && i == 0)
{
sendbyte(ACK); /* acknowledge EOT */
logit("MODEM7 Batch Receive Complete\n");
tlogit("MODEM7 Batch Receive Complete\n");
return (FALSE);
}
if (c == TIMEOUT)
{
logit("Timeout waiting for MODEM7 filename character\n");
tlogit("Timeout waiting for MODEM7 filename character\n");
errorflag = TRUE;
break;
}
if (c == BAD_NAME)
{
logit("Error during MODEM7 filename transfer\n");
tlogit("Error during MODEM7 filename transfer\n");
errorflag = TRUE;
break;
}
*nameptr++ = c;
checksum += c;
sendbyte(ACK);
}
if (!errorflag)
{
c = readbyte(3);
if (c == CTRLZ) /* OK; end of string found */
{
sendbyte(checksum + CTRLZ);
if (readbyte(15) == ACK) /* file name found! */
{
xmdebug("MODEM7 file name OK");
*nameptr = '\000'; /* unixify the file name */
name = cpm_unix(buff);
BATCH = TRUE;
logitarg("MODEM7 file name: %s\n", name);
tlogitarg("MODEM7 file name: %s\n", name);
errors = 0; /* restart crc handshake */
sleep(2); /* give other side a chance */
}
else
{
logit("Checksum error in MODEM7 filename\n");
tlogit("Checksum error in MODEM7 filename\n");
errorflag = TRUE;
}
}
else
{
logit("Length error in MODEM7 filename\n");
tlogit("Length error in MODEM7 filename\n");
errorflag = TRUE;
}
}
}
if (firstchar == SOH || firstchar == STX) /* start reading packet */
{
bufsize = (firstchar == SOH) ? 128 : 1024;
if (recvsectcnt == 0) /* 1st data packet, initialize */
{
if (bufsize == 1024)
{
logit("1K packet mode chosen\n");
tlogit("1K packet mode chosen\n");
}
start = time((time_t *) 0);
errors = 0;
firstwait = 5;
}
sectcurr = readbyte(3);
sectcomp = readbyte(3);
if ((sectcurr + sectcomp) == 0xff) /* is packet number checksum correct? */
{
if (sectcurr == ((sectnum+1) & 0xff)) /* is packet number correct? */
{
if (DEBUG)
fprintf(LOGFP,"DEBUG: packet with sector number %d started\n", sectnum);
/* Read, process and calculate checksum for a buffer of data */
readbackup = fileread;
if (readbuf(bufsize, 1, tmode, amode, recvsectcnt, &checksum, &bufctr) != TIMEOUT)
{
/* verify checksum or CRC */
if (CRCMODE)
{
checksum &= 0xffff;
inchecksum = readbyte(3); /* get 16-bit CRC */
inchecksum = (inchecksum<<8) | readbyte(3);
}
else
inchecksum = readbyte(3); /* get simple 8-bit checksum */
if (inchecksum == checksum) /* good checksum, hence good packet */
{
xmdebug("checksum ok");
errors = 0;
recvsectcnt += (bufsize == 128) ? 1 : 8;
nocancanabort = CANCAN ? FALSE : TRUE;
sectnum = sectcurr;
if (!openflag) /* open output file if necessary */
{
openflag = TRUE;
if ((fd = creat(name, CREATMODE)) < 0)
{
sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
error("Can't create file for receive", TRUE);
}
if (!BATCH)
{
logitarg("File Name: %s\n", name);
tlogitarg("File Name: %s\n", name);
}
}
if (write(fd, (char *) buff, bufctr) != bufctr)
{
close(fd);
unlink(name);
error("File Write Error", TRUE);
}
else
{
if (TIPFLAG && recvsectcnt % 32 == 0)
tlogitarg("Sector %s received\n", sectdisp(recvsectcnt,bufsize,0));
if (!YMODEMG)
{
flushin(); /* flush input */
sendbyte(ACK); /* ACK the received packet */
}
}
}
/* Start handling various errors and special conditions */
else /* bad checksum */
{
logitarg("Checksum Error on Sector %s: ", sectdisp(recvsectcnt,bufsize,1));
logitarg("sent=%x ", inchecksum);
logitarg("recvd=%x\n", checksum);
tlogitarg("Checksum Error on Sector %s: ", sectdisp(recvsectcnt,bufsize,1));
tlogitarg("sent=%x ", inchecksum);
tlogitarg("recvd=%x\n", checksum);
fileread = readbackup;
errorflag = TRUE;
if (YMODEMG)
fatalerror = TRUE;
}
}
else /* read timeout */
{
logitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
tlogitarg("Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
fileread = readbackup;
errorflag = TRUE;
if (YMODEMG)
fatalerror = TRUE;
}
}
else /* sector number is wrong OR Ymodem filename */
{
if (sectcurr == 0 && recvsectcnt == 0) /* Ymodem file-name packet */
{
logit("YMODEM Batch Protocol\n");
tlogit("YMODEM Batch Protocol\n");
/* Read and process a file-name packet */
if (readbuf(bufsize, 1, FALSE, FALSE, recvsectcnt, &checksum, &bufctr) != TIMEOUT)
{
/* verify checksum or CRC */
if (CRCMODE)
{
checksum &= 0xffff;
inchecksum = readbyte(3); /* get 16-bit CRC */
inchecksum = (inchecksum<<8) | readbyte(3);
}
else
inchecksum = readbyte(3); /* get simple 8-bit checksum */
if (inchecksum == checksum) /* good checksum, hence good filename */
{
xmdebug("checksum ok");
strcpy(name, (char *)buff);
expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]);
BATCH = TRUE;
YMDMBAT = TRUE;
if (strlen(name) == 0) /* check for no more files */
{
flushin(); /* flush input */
sendbyte(ACK); /* ACK the packet */
logit("YMODEM Batch Receive Complete\n");
tlogit("YMODEM Batch Receive Complete\n");
return (FALSE);
}
unixify(name); /* make filename canonical */
/* read rest of YMODEM header */
p = (char *)buff + strlen((char *)buff) + 1;
if (DEBUG)
fprintf(LOGFP, "DEBUG: header info: %s\n", p);
sscanf(p, "%ld%lo%o%o%d%ld%d",
&filelength, &modtime, &filemode,
&serial, &filesleft, &totalleft,
&yfiletype);
logitarg("YMODEM file name: %s\n", name);
tlogitarg("YMODEM file name: %s\n", name);
fileread = 0l;
if (filelength)
{
CHECKLENGTH = TRUE;
logitarg("YMODEM file size: %ld\n", filelength);
tlogitarg("YMODEM file size: %ld\n", filelength);
}
else if (expsect)
logitarg("YMODEM estimated file length %d sectors\n", expsect);
if (modtime)
{
logitarg("YMODEM file date: %s", ctime((time_t *)&modtime));
}
if (filemode)
logitarg("YMODEM file mode: %o\n", filemode);
if (filesleft)
{
logitarg("YMODEM %d file(s) left to receive ", filesleft);
logitarg("containing %ld bytes\n", totalleft);
tlogitarg("YMODEM %d file(s) left to receive ", filesleft);
tlogitarg("containing %ld bytes\n", totalleft);
}
if (serial)
logitarg("YMODEM sender's serial number: %d\n", serial);
if (yfiletype)
logitarg("YMODEM file type %d\n", yfiletype);
openflag = TRUE; /* open the file for writing */
if ((fd = creat(name, CREATMODE)) < 0)
{
sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
error("Can't create file for receive", TRUE);
}
if (!YMODEMG)
{
flushin(); /* flush the input stream */
sendbyte(ACK); /* ACK the filename packet */
}
/* do initial handshake to start file transfer */
if (YMODEMG)
sendbyte(GCHR);
else if (CRCMODE)
{
sendbyte(CRCCHR);
if (LONGPACK)
sendbyte(KCHR);
}
else
sendbyte(NAK);
firstwait = WAITFIRST; /* reset waiting time */
}
else /* bad filename checksum */
{
logit("checksum error on filename sector\n");
tlogit("checksum error on filename sector\n");
errorflag = TRUE;
if (YMODEMG)
fatalerror = TRUE;
}
}
else
{
logit("Timeout while reading filename packet\n");
tlogit("Timeout while reading filename packet\n");
errorflag = TRUE;
if (YMODEMG)
fatalerror = TRUE;
}
}
else if (sectcurr == sectnum) /* duplicate sector? */
{
logitarg("Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
tlogitarg("Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
if (YMODEMG)
{
errorflag = TRUE;
fatalerror = TRUE;
}
else
{
flushin(); /* REALLY flush input */
while(readbyte(1) != TIMEOUT)
;
sendbyte(ACK);
}
}
else /* no, real phase error */
{
logitarg("Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
tlogitarg("Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
errorflag = TRUE;
fatalerror = TRUE;
}
}
}
else /* bad packet number checksum */
{
logitarg("Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
tlogitarg("Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
errorflag = TRUE;
if (YMODEMG)
fatalerror = TRUE;
}
} /* END reading packet loop */
if (errorflag && !fatalerror && recvsectcnt != 0) /* Handle errors */
{
errors++;
if (errors >= ERRORMAX) /* over error limit? */
fatalerror = TRUE;
else /* flush input and NAK the packet */
{
flushin();
while (readbyte(2) != TIMEOUT) /* wait for line to settle */
;
sendbyte(NAK);
}
}
if (recvsectcnt == 0 && errorflag && !fatalerror && firstchar != EOT) /* handle startup handshake */
{
sterrors++;
if (sterrors >= STERRORMAX)
fatalerror = TRUE;
else if (CRCMODE && MDM7BAT && !BATCH)
sendbyte(NAK);
else if (CRCMODE && sterrors == CRCSWMAX && !YMDMBAT)
{
CRCMODE = FALSE;
logit("Sender not accepting CRC request, changing to checksum\n");
tlogit("Sender not accepting CRC request, changing to checksum\n");
sendbyte(NAK);
}
else if (!CRCMODE && sterrors == CRCSWMAX && !YMDMBAT)
{
CRCMODE = TRUE;
logit("Sender not accepting checksum request, changing to CRC\n");
tlogit("Sender not accepting checksum request, changing to CRC\n");
sendbyte(CRCCHR);
if (LONGPACK && !MDM7BAT)
sendbyte(KCHR);
}
else if (YMODEMG)
sendbyte(GCHR);
else if (CRCMODE)
{
sendbyte(CRCCHR);
if (LONGPACK && !MDM7BAT)
sendbyte(KCHR);
}
else
sendbyte(NAK);
}
}
while ((firstchar != EOT) && !fatalerror); /* end of MAIN Do-While */
if ((firstchar == EOT) && !fatalerror) /* normal exit? */
{
if (openflag) /* close the file */
close(fd);
sendbyte(ACK); /* ACK the EOT */
logit("Receive Complete\n");
tlogit("Receive Complete\n");
if (LOGFLAG)
prtime (recvsectcnt, time((time_t *) 0) - start, LOGFP);
if (TIPFLAG)
prtime (recvsectcnt, time((time_t *) 0) - start, stderr);
if (openflag && modtime) /* set file modification time */
{
timep[0] = time((time_t *) 0);
timep[1] = modtime;
utime(name, timep);
}
if (BATCH) /* send appropriate return code */
return(TRUE);
else
return(FALSE);
}
else /* no, error exit */
{
if (openflag)
{
sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
close(fd);
unlink(name);
flushin();
while (readbyte(2) != TIMEOUT) /* wait for line to settle */
;
error("ABORTED -- Too Many Errors -- Deleting File", TRUE);
}
else if (recvsectcnt != 0)
{
sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
flushin();
while (readbyte(2) != TIMEOUT) /* wait for line to settle */
;
error("ABORTED -- Too Many Errors", TRUE);
}
else
{
flushin();
while (readbyte(2) != TIMEOUT) /* wait for line to settle */
;
error("ABORTED -- Remote system is not responding", TRUE);
}
}
return(FALSE);
}