home *** CD-ROM | disk | FTP | other *** search
- /*
- * xmodem.c: hterm xmodem module
- *
- * converted from xmodem 3.6 4/88 by Grandi
- * NO COPYRIGHT.
- *
- * Edition History:
- * 1.1 89/09/20 mnr initial port to hterm
- * 1.2 89/09/22 Halca.Hirano brush up
- * 1) remove MODEM7 protocol for simplisity
- * 2) rewrite file receive entirely
- * 3) full automatic receiving protocol & option detection
- * 1.3 89/09/25 Halca.Hirano
- * fix turboC compile error
- * ---- V2.4.0 distribution ----
- * 1.4 89/10/10 Halca.Hirano
- * fix send filename building bug
- * 1.5 89/10/14 Halca.Hirano
- * set 8 bit character length automatically (Thanks shikida@titech)
- * 1.6 89/12/06 Halca.Hirano
- * fix parity change bug
- * 1.7 89/12/12 Halca.Hirano
- * move xgetnext() in file.c
- * all public functions are callable from comm. mode as well as from setup.
- * 1.8 90/01/16 Halca.Hirano
- * get rid of bugs which cause 'devide by zero' error when sending null file
- * 1.9 90/06/23 Halca.Hirano
- * fix expected file size bug for file receiving
- *
- * $Header: xmodem.cv 1.17 90/07/04 18:09:48 hirano Exp $
- */
-
- /* original header is here. */
-
- /*
- * XMODEM -- Implements the Christensen XMODEM protocol,
- * for packetized file up/downloading.
- *
- * See the README file for some notes on SYS V adaptations.
- * The program has been successfully run on VAXes (4.3BSD) and SUN-3/4s
- * (SunOS 3.x) against MEX-PC and ZCOMM/DSZ.
- *
- * See the README and update.doc files for history and change notes.
- *
- * Please send bug fixes, additions and comments to:
- * {ihnp4,ncar}!noao!grandi grandi@noao.arizona.edu
- */
-
-
- #include "option.h"
- #ifdef XMODEM
-
- #include <stdio.h>
- #include <ctype.h>
- #include <setjmp.h>
- #include <fcntl.h>
- #include <time.h>
- #include <io.h>
- #ifdef __TURBOC__
- #include <dir.h>
- #endif
- #if !defined(__TURBOC__) || __TURBOC__ >= 0x0200
- #include <sys/types.h>
- #endif
- #include <sys/stat.h>
- #include <string.h>
- #include "config.h"
- #include "hterm.h"
- #include "default.h"
- #include "global.h"
-
- #define XVERSION 36 /* Version Number */
-
- #define FALSE 0
- #define TRUE 1
-
-
- /* ASCII Constants */
- #define STX 002
- #define ETX 003
- #define EOT 004
- #define ACK 006
- #define NAK 025
- #define SYN 026
-
- /* XMODEM Constants */
- #define TIMEOUT -1
- #define ERRORMAX 10 /* maximum errors tolerated while transferring a packet */
- #define Y_TO_X_SW 4 /* errors to switch Y to X on sending Y filename */
- #define WAITFIRST 1 /* seconds between startup characters in read */
- #define STERRORMAX 60 /* maximum "errors" tolerated in read startup */
- #define CRCSWMAX 30 /* maximum time to try CRC mode before switching */
- #define NAKMAX 120 /* maximum times to wait for initial NAK when sending */
- #define RETRYMAX 5 /* maximum retries to be made certain handshaking routines */
- #define KSWMAX 5 /* maximum errors before switching to 128 byte packets */
- #define EOTMAX 10 /* maximum times sender will send an EOT to end transfer */
- #define SLEEPNUM 100 /* target number of characters to collect during sleepy time */
- #define BBUFSIZ 1024 /* buffer size */
- #define NAMSIZ 11 /* length of a CP/M file name string */
- #define CTRLZ 032 /* CP/M EOF for text (usually!) */
- #define CRCCHR 'C' /* CRC request character */
- #define KCHR 'K' /* 1K block request character */
- #define BAD_NAME 'u' /* Bad filename indicator */
- /* CRC-16 constants. From Usenet contribution by Mark G. Mendel,
- Network Systems Corp. (ihnp4!umn-cs!hyper!mark)
- */
- #define P 0x1021 /* the CRC polynomial. */
- #define W 16 /* number of bits in CRC */
- #define B 8 /* the number of bits per char */
-
-
- static unsigned char *buff = (u_char *)XFerBuffer; /* buffer for data */
- static char xtbuf[80]; /* xmodem tmp buf to build error msg */
- static int nbchr; /* number of chars read so far for buffered read */
- static long xfilelength; /* length specified in YMODEM header */
- static long fileread; /* characters actually read so far in file */
- static char filename[256]; /* place to construct filenames */
- static char recFileName[256]; /* receive file name */
- static char localFile[MAX_FILE_NAME] = DEFAULT_XMODEM_FILENAME;
-
- /* option flags and state variables */
- static int CRCMODE; /* CRC or checksums? */
- static int LONGPACK; /* do not use long packets on transmit? */
- static int CHECKLENGTH; /* Are we truncating a file to a YMODEM length? */
- static char *xfileList;
- static char *xfilnam;
- static jmp_buf xjmpbuf;
- static int fd; /* file descriptor for file being transmitted */
- static int realProtocol; /* real protocol for automatic detection */
- static u_char paritySave; /* save old parith, char length */
- static int oldMode; /* mode of caller */
- static long LZERO = 0L;
-
- /* CRC-16 constant array...
- from Usenet contribution by Mark G. Mendel, Network Systems Corp.
- (ihnp4!umn-cs!hyper!mark)
- */
- /* crctab as calculated by initcrctab() */
- static unsigned short crctab[1<<B] = {
- 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
- };
-
- /*
- ** prototypes
- */
-
- int xinit2(char *);
- void xend(char *, int);
- void xexit(void);
- void xsfile(char *);
- void showProtocol(void);
- void xAbortCheck(void);
- int xrfile(char *);
- int receiveData(int, int, char*);
- int receiveFileName(int, int, char *);
- void unixify(char *);
- char *cpmify(char *);
- char *sectdisp(long, int, int);
- int getbyte(int, char *);
- int readbyte(int seconds);
- int readbuf(int, int, int, int *, int *);
-
-
- #define sendbyte(data) rowOutPort(data & cMask)
- #define writebuf(buffer,nbytes) rowOutPortBuffer(buffer, nbytes)
- #define xalarm(n) (kermitTimer = n * TICK_SEC)
-
-
-
-
-
- void xinit()
- {
- /* initialize option flags */
-
- xmodemMode = XY_YMODEM;
- xmodemType = XMODEM_BINARY;
- xmodemLongP = XMODEM_1024;
- }
-
- static int xinit2(msg)
- char *msg;
- {
- oldMode = mode;
- mode = M_SETUP;
- if (oldMode == M_COMM)
- showPage1();
-
- if (*msg && (emacs(msg, localFile, MAX_FILE_NAME, (E_HELP|E_FILE)) == ERR
- || localFile[0] == '\0')) {
- if (oldMode == M_COMM)
- showPage0();
- mode = oldMode;
- return(NO);
- }
-
- downLoading = YES;
- fd = 0;
- xferPanel("XMODEM");
- paritySave = paritybit;
- if (paritybit != NO_PAR_8) {
- paritybit = NO_PAR_8;
- parity = parcalc(paritybit, stopbit);
- initPortDevice(baud, parity);
- putStatus("hterm sets 8 bit, no parity.");
- }
- return(YES);
- }
-
- static void xend(msg, status)
- char *msg;
- int status;
- {
- downLoading = NO;
- if (fd)
- close(fd);
- bell();
- if (paritySave != paritybit) {
- paritybit = paritySave;
- parity = parcalc(paritybit, stopbit);
- initPortDevice(baud, parity);
- }
- if (oldMode == M_COMM) {
- showPage0();
- putComment(msg, (status == FALSE) ? " failed" : "done");
- }
- mode = oldMode;
- }
-
- static void xexit()
- {
- longjmp(xjmpbuf, 1);
- }
-
- void xrec()
- /*
- * receive xmodem files
- */
- {
- int status;
-
- (void)xinit2("");
- strcpy(recFileName, "xmodem.in");
- if (!setjmp(xjmpbuf)) {
- while (xrfile(recFileName) != FALSE)
- ;
- flushInputBuffer();
- status = TRUE;
- } else {
- xprintMsg(X_STATUS, "Abort", LZERO);
- status = FALSE;
- }
- xend("rec", status);
- }
-
- void xsend()
- /*
- * send xmodem files
- */
- {
- int first = YES;
- int status;
- char buf[MAX_FILE_NAME+20];
-
- if (xinit2("X/YMODEM send files: ") == NO)
- return;
-
- xfileList = localFile;
- if (!setjmp(xjmpbuf)) {
- realProtocol = xmodemMode;
- if (getNextFileName(1, &xfileList, &xfilnam, NO) == YES) {
- do {
- if (first == NO && realProtocol == XY_XMODEM) {
- xprintMsg(X_ERROR, "XMODEM can't send multiple files", LZERO);
- status = FALSE;
- break;
- }
- xsfile(xfilnam);
- status = TRUE;
- first = NO;
- } while (getNextFileName(0, &xfileList, &xfilnam, NO) == YES);
- } else {
- sprintf(buf, "%s not found", localFile);
- xprintMsg(X_ERROR, buf, LZERO);
- bell();
- }
- /*
- * terminate remote xmodem; this must be here even if hterm failes to
- * open first file.
- */
- if (realProtocol == XY_YMODEM) {
- xsfile("");
- }
- } else {
- xprintMsg(X_STATUS, "Abort", LZERO);
- bell();
- status = FALSE;
- }
- xend("send", status);
- }
-
- /*
- ** static void xsfile(char *name)
- *
- * x/ymodem file receive.
- * protocol and options are detected automatically.
- *
- * If "name" is NULL; close out the BATCH send.
- */
- static void xsfile(name)
- char *name;
- {
- char *sectdisp();
- char *cpmify();
-
- register int bufctr, /* array index for data buffer */
- sectnum; /* packet number for packet header */
-
- register unsigned short checksum; /* checksum/crc */
-
- static char blockbuf[BBUFSIZ+6]; /* holds packet as it is constructed */
-
- struct stat filestatbuf; /* file status info */
-
- int attempts, /* number of attempts made to transmit a packet */
- sendfin, /* flag that we are sending the last packet */
- closeout, /* flag that we are closing out batch send */
- filepack, /* TRUE when sending first packet */
- buf1024, /* TRUE when sending 1K packets */
- bbufcnt, /* array index for packet */
- firstchar, /* first character in protocol transaction */
- bufsize, /* packet size (128 or 1024) */
- sendresp; /* response char to sent block received from remote*/
- long sentsect; /* count of 128 byte sectors actually sent */
- long expsect; /* count of 128 byte sectors expected to be sent */
- time_t start; /* starting time of transfer */
- char c, *p;
-
- nbchr = 0; /* clear buffered read char count */
-
- CRCMODE = FALSE; /* Receiver determines use of crc or checksum */
-
- buf1024 = xmodemLongP; /* set packet size flag to command line switch */
-
- closeout = FALSE; filepack = FALSE; /* indicate state of batch transfer */
-
- showProtocol();
- /* Check on NULL file name */
- if (strcmp(name,"") == 0) {
- if (realProtocol == XY_YMODEM)
- closeout = TRUE;
- else {
- sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- xprintMsg(X_ERROR, "NULL file name in send", LZERO);
- xexit();
- }
- }
-
- if (!closeout) { /* Are we closing down batch? */
- /* no; let's send a file */
- if ((fd = open(name, (O_RDONLY|O_BINARY))) < 0) {
- sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- sprintf(xtbuf, msg_cantOpen, name);
- xprintMsg(X_ERROR, xtbuf, LZERO);
- xexit();
- }
-
- stat(name, &filestatbuf); /* get file status bytes */
- expsect = (filestatbuf.st_size/128) + 1;
- xprintMsg(X_FILENAME, name, LZERO);
- xprintMsg(X_STATUS, "Sending", LZERO);
- }
- /* else Closing down Batch Transmission */
-
- bufsize = buf1024 ? 1024 : 128; /* set sector size */
-
- sendfin = FALSE;
- attempts = 0;
-
- /* wait for and read startup character */
- do {
- xprintMsg(X_PSENT, NULL, 0L);
- xprintMsg(X_KBYTES, NULL, 0L);
- xprintMsg(X_PERCENT, NULL, 0L);
- xprintMsg(X_RATE, NULL, 0L);
- while (((firstchar = readbyte(1)) != NAK) &&
- (firstchar != CRCCHR) && (firstchar != CAN)) {
- xprintMsg(X_RETRY, NULL, (long)(attempts+1));
- if (++attempts > NAKMAX) {
- xprintMsg(X_ERROR, "Remote System Not Responding", LZERO);
- xexit();
- }
- xAbortCheck();
- }
-
- if (firstchar == CRCCHR)
- CRCMODE = TRUE;
- } while (firstchar != NAK && firstchar != CRCCHR);
-
- showProtocol(); /* fix CRC mode */
- xprintMsg(X_PSIZE, NULL, buf1024 ? 1024L : 128L);
-
- sectnum = 1;
-
- /*
- * if YMODEM is chosen by user, try to use YMODEM
- */
- if (realProtocol == XY_YMODEM) {
- sectnum = 0;
- bufsize = 128;
- filepack = TRUE;
- }
- attempts = 0;
- sentsect = 0;
- start = time((time_t *) 0);
- /* outer packet building/sending loop; loop till whole file is sent */
- do {
- if (closeout && realProtocol == XY_YMODEM && sectnum == 1) /* close out YMODEM */
- return;
-
- /* get set to send YMODEM data packets */
- if (realProtocol == XY_YMODEM && sectnum == 1) {
- bufsize = buf1024 ? 1024 : 128;
- do { /* establish handshaking again */
- while (((firstchar=readbyte(2)) != CRCCHR) && (firstchar != NAK) && (firstchar != CAN)) {
- xprintMsg(X_RETRY, NULL, (long)(attempts+1));
- if (++attempts > ERRORMAX) {
- xprintMsg(X_ERROR, "YMODEM protocol botch, C expected", LZERO);
- xexit();
- }
- }
- if (firstchar == CAN) {
- xprintMsg(X_ERROR, "aborted by remote", LZERO);
- xexit();
- }
- xAbortCheck();
- } while ((firstchar != CRCCHR) && (firstchar != NAK));
- attempts = 0;
- }
-
- if ((bufsize == 1024) && (attempts > KSWMAX)) {
- xprintMsg(X_STATUS, "128 byte packet due to excessive errors", LZERO);
- bufsize = 128;
- }
- if ((bufsize == 1024) && ((expsect - sentsect) < 8)) {
- xprintMsg(X_STATUS, "128 byte packet for tail end of file", LZERO);
- bufsize = 128;
- }
- xprintMsg(X_PSIZE, NULL, (long)bufsize);
-
- /* data packet */
- if (sectnum > 0) {
- for (bufctr=0; bufctr < bufsize;) {
- if (getbyte(fd, &c) == EOF) {
- sendfin = TRUE; /* this is the last sector */
- if (!bufctr) /* if EOF on sector boundary */
- break; /* avoid sending extra sector */
- buff[bufctr++] = CTRLZ; /* pad with Ctrl-Z for CP/M EOF (even do for binary files) */
- continue;
- }
- buff[bufctr++] = c; /* copy the char without change */
- }
- if (!bufctr) /* if EOF on sector boundary */
- break; /* avoid sending empty sector */
-
- /* YMODEM filename packet */
- } else {
- for (bufctr=0; bufctr<bufsize; bufctr++) /* zero packet */
- buff[bufctr]=0;
- if (!closeout) {
- strcpy((char *)buff, cpmify(name));
- /* put in file name, length, mode */
- p = (char *)buff + strlen(name) + 1;
- sprintf(p, "%lu %lo %o", filestatbuf.st_size,
- filestatbuf.st_mtime, filestatbuf.st_mode);
- buff[bufsize-2] = (expsect & 0xff); /* put in KMD kludge information */
- buff[bufsize-1] = ((expsect >> 8) & 0xff);
- }
- }
- /* build block to be sent */
- bbufcnt = 0;
- blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH; /* start of packet char */
- blockbuf[bbufcnt++] = sectnum; /* current sector # */
- blockbuf[bbufcnt++] = ~sectnum; /* and its complement */
-
- checksum = 0; /* initialize checksum */
- for (bufctr=0; bufctr < bufsize; bufctr++) {
- blockbuf[bbufcnt++] = buff[bufctr];
- checksum = CRCMODE ? (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]]
- : ((checksum+buff[bufctr]) & 0xff);
- }
-
- if (CRCMODE) { /* put in CRC */
- checksum &= 0xffff;
- blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff);
- blockbuf[bbufcnt++] = (checksum & 0xff);
- } else /* put in checksum */
- blockbuf[bbufcnt++] = checksum;
-
- attempts = 0;
- /* send a packet */
- do { /* inner packet loop */
- flushInputBuffer(); /* purge anything in input queue */
- writebuf(blockbuf, bbufcnt); /* write the block */
- attempts++;
- sendresp = readbyte(10); /* get response from remote */
-
- if (sendresp != ACK) {
- xprintMsg(X_RETRY, NULL, (long)attempts);
- if (sendresp == TIMEOUT)
- sprintf(xtbuf, "Timeout on sector %s",sectdisp(sentsect,bufsize,1));
- else if (sendresp == NAK)
- sprintf(xtbuf, "NAK on sector %s",sectdisp(sentsect,bufsize,1));
- else
- sprintf(xtbuf, "Non-ACK on sector %s",sectdisp(sentsect,bufsize,1));
- xprintMsg(X_STATUS, xtbuf, LZERO);
- /*
- * switch YMODEM to XMODEM
- */
- if (attempts > Y_TO_X_SW && sectnum == 0) {
- attempts = 0;
- realProtocol = XY_XMODEM;
- showProtocol();
- xprintMsg(X_STATUS, "receiver may be XMODEM", LZERO);
- break;
- }
- }
- } while((sendresp != ACK) && (attempts < ERRORMAX)); /* close of inner loop */
-
- /* prepare next sector */
- sectnum++; /* increment to next sector number */
- if (!filepack)
- sentsect += (bufsize == 128) ? 1 : 8;
- filepack = FALSE;
- if (!closeout) {
- time_t ptime = time((time_t *)0) - start;
-
- xprintMsg(X_PSENT, NULL, (bufsize == 128) ? sentsect : sentsect/8L);
- xprintMsg(X_KBYTES, NULL, sentsect/8L);
- if (expsect)
- xprintMsg(X_PERCENT, NULL, (long)((long)sentsect * 100L / expsect));
- if (ptime) {
- xprintMsg(X_RATE, NULL, (long)((long)sentsect * 128 / ptime));
- }
- xprintMsg(X_RETRY, NULL, (long)attempts);
- }
- } while (!sendfin && (attempts < ERRORMAX)); /* end of outer loop */
-
-
- /* error processing */
- if (attempts >= ERRORMAX) {
- sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- xprintMsg(X_ERROR, "Too many errors in transmission", LZERO);
- xexit();
- }
-
- attempts = 0;
- sendbyte(EOT); /* send 1st EOT to close down transfer */
-
- while ((readbyte(15) != ACK) && (attempts++ < EOTMAX)) { /* wait for ACK of EOT */
- xprintMsg(X_RETRY, NULL, (long)attempts);
- sendbyte(EOT);
- }
- if (attempts >= RETRYMAX) {
- xprintMsg(X_ERROR, "Remote System Not Responding on Completion", LZERO);
- xexit();
- }
-
- close(fd);
- fd = 0;
- xprintMsg(X_STATUS, "Send Complete", LZERO);
- }
-
- static void showProtocol()
- {
- char *p;
-
- if (realProtocol == XY_YMODEM)
- p = "YMODEM Batch";
- else
- p = "XMODEM";
- sprintf(xtbuf, "%s (%s)", p, CRCMODE ? "CRC" : "Checksum");
- xprintMsg(X_PROTOCOL, xtbuf, LZERO);
- }
-
- static void xAbortCheck()
- {
- short uk;
-
- if ((uk = keyin()) != -1 && uk == ESC) {
- xprintMsg(X_ERROR, "Aborted by user", LZERO);
- xexit();
- }
- }
-
- /* 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...
- *
- * OF COURSE YES! YOU ARE CRAZY! I WILL BREAK IT DOWN!
- */
-
- static int sectnum; /* number of last received packet (modulo 128) */
- static int errorflag; /* set true when packet (or first char of putative packet) is invalid */
- static int fatalerror; /* set within main "read-packet" Do-While when bad error found */
- static long expsect; /* expected number of sectors (YMODEM batch) */
- static int firstwait; /* seconds to wait for first character in a packet */
- static long recvsectcnt; /* running sector count (128 byte sectors) */
- static long modtime; /* Unix style file mod time from YMODEM header */
- static time_t start; /* starting time of transfer */
- static int openflag; /* is file open for writing? */
- static int endFlag;
- extern char *sectdisp();
-
- static int xrfile(name)
- /*
- * receive a file
- * returns TRUE if in the midst of a batch transfer
- * returns FALSE if no more files are coming
- */
- char *name;
- {
-
- int firstchar, /* first character of a packet */
- sectcurr, /* second byte of packet--should be packet number (mod 128) */
- sectcomp, /* third byte of packet--should be complement of sectcurr */
- errors, /* count of errors for each packet */
- sterrors, /* count of errors during startup handshake */
- bufsize; /* packet size (128 or 1024) */
- #ifdef COMP_MSC
- time_t timep[2]; /* used in setting mod time of received file */
- #endif
- int status;
-
- fatalerror = FALSE;
- firstwait = WAITFIRST; /* For first packet, wait short time */
- sectnum = 0;
- errors = 0;
- recvsectcnt = 0;
- bufsize = 128;
- modtime = 0l;
- xfilelength = 0l; fileread =0l; CHECKLENGTH = FALSE;
- openflag = FALSE;
-
- /* start up transfer */
-
- sterrors = 0;
- flushInputBuffer(); /* flush input queue */
-
- /*
- * first assume XMODEM
- */
- realProtocol = XY_XMODEM;
- LONGPACK = xmodemLongP == XMODEM_1024 ? 1 : 0;
-
- /*
- * first try CRC-mode
- */
- CRCMODE = TRUE;
- sendbyte(CRCCHR);
-
- endFlag = FALSE;
- while (endFlag == FALSE && fatalerror == FALSE) {
- xprintMsg(X_STATUS, "Receiving", LZERO);
- 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 || recvsectcnt > 0));
-
- switch (firstchar) {
- case EOT: /* check for REAL EOT */
- if (realProtocol == XY_XMODEM) {
- /*
- * XMODEM on some BBS can not handle NAK for EOT!
- */
- endFlag = TRUE;
- } else {
- flushInputBuffer();
- sendbyte(NAK); /* NAK the EOT */
- if ((firstchar = readbyte(3)) == EOT) { /* check next character */
- endFlag = TRUE;
- } else {
- xprintMsg(X_STATUS, "Spurious EOT detected; ignored", LZERO);
- if ((firstchar == SOH) || (firstchar == STX) ||
- (firstchar == ACK && recvsectcnt == 0) ||
- (firstchar == CAN && recvsectcnt == 0) ||
- (firstchar == TIMEOUT))
- endFlag = TRUE;
- else {
- firstchar = 0;
- errorflag = TRUE;
- }
- }
- }
- break;
- case TIMEOUT:
- if (recvsectcnt > 0) {
- sprintf(xtbuf, "Timeout on Sector %s", sectdisp(recvsectcnt,bufsize,1));
- xprintMsg(X_STATUS, xtbuf, LZERO);
- }
- errorflag = TRUE;
- break;
- /* start reading packet */
- case SOH:
- case STX:
- bufsize = (firstchar == SOH) ? 128 : 1024;
- if (recvsectcnt == 0) { /* 1st data packet, initialize */
- xprintMsg(X_PSIZE, NULL, (long)bufsize);
- start = time((time_t *) 0);
- errors = 0;
- firstwait = 5;
- }
- sectcurr = readbyte(3);
- sectcomp = readbyte(3);
- /* is packet number checksum correct? */
- if ((sectcurr + sectcomp) != 0xff) {
- /* bad packet number checksum */
- sprintf(xtbuf, "Header Sector Number Error on Sector %s\n", sectdisp(recvsectcnt, bufsize,1));
- xprintMsg(X_STATUS, xtbuf, LZERO);
- errorflag = TRUE;
- break;
- }
- if (sectcurr == ((sectnum+1) & 0xff)) /* is packet number correct? */
- status = receiveData(sectcurr, bufsize, name);
- else
- status = receiveFileName(sectcurr, bufsize, name);
- if (status == FALSE)
- return(FALSE);
- break;
- }
- /* error correction */
- /* handle startup handshake */
- if (recvsectcnt == 0 && errorflag && firstchar != EOT) {
- xprintMsg(X_RETRY, NULL, (long)sterrors);
- if (++sterrors >= STERRORMAX)
- fatalerror = TRUE;
- else if (sterrors == CRCSWMAX) {
- if (CRCMODE) {
- CRCMODE = FALSE;
- xprintMsg(X_STATUS, "Sender not accepting CRC, use checksum", LZERO);
- sendbyte(NAK);
- } else {
- CRCMODE = TRUE;
- xprintMsg(X_STATUS, "Sender not accepting checksum, use CRC", LZERO);
- sendbyte(CRCCHR);
- }
- } else if (CRCMODE)
- sendbyte(CRCCHR);
- else
- sendbyte(NAK);
- }
- if (errorflag && !fatalerror && recvsectcnt != 0) { /* Handle errors */
- xprintMsg(X_RETRY, NULL, (long)errors);
- if (++errors >= ERRORMAX)
- fatalerror = TRUE;
- else { /* flush input and NAK the packet */
- flushInputBuffer();
- while (readbyte(1) != TIMEOUT) /* wait for line to settle */
- ;
- sendbyte(NAK);
- }
- }
-
- }
-
- if ((firstchar == EOT) && !fatalerror) { /* normal exit? */
- if (openflag) /* close the file */
- close(fd);
- sendbyte(ACK); /* ACK the EOT */
- xprintMsg(X_STATUS, "Receive Complete", LZERO);
-
- #ifdef COMP_MSC
- if (openflag && modtime) { /* set file modification time */
- timep[0] = time((time_t *) 0);
- timep[1] = modtime;
- utime(name, timep);
- }
- #endif /* COMP_MSC */ /* ignore is TurboC ?? */
-
- /*
- * return from protocol. if YMODEM, we shall return.
- */
- if (realProtocol == XY_YMODEM)
- return(TRUE);
- else
- return(FALSE);
- }
- /* no, error exit */
- if (openflag) {
- sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- close(fd);
- #if 0
- unlink(name);
- #endif
- xprintMsg(X_ERROR, "Too many error! deleting file", LZERO);
- } else if (recvsectcnt == 0)
- xprintMsg(X_ERROR, "Remote system is not responding", LZERO);
- else
- xprintMsg(X_ERROR, "Too many errors", LZERO);
- return(FALSE);
- }
-
- static int receiveData(sectcurr, bufsize, name)
- int sectcurr;
- int bufsize;
- char *name;
- /*
- * receive data packet or file name packet
- */
- {
- int checksum; /* packet checksum */
- int inchecksum; /* incoming checksum or CRC */
- int rate;
- time_t ptime;
- long readbackup; /* "backup" value for characters read in file */
- int bufctr; /* number of real chars in read packet */
-
- /* Read, process and calculate checksum for a buffer of data */
- readbackup = fileread;
- if (readbuf(bufsize, 5, (xmodemType == XMODEM_TEXT), &checksum, &bufctr) == TIMEOUT) {
- sprintf(xtbuf, "Timeout while reading sector %s\n",sectdisp(recvsectcnt,bufsize,1));
- xprintMsg(X_STATUS, xtbuf, LZERO);
- fileread = readbackup;
- errorflag = TRUE;
- return(TRUE);
- }
- if (sectcurr == 1 && realProtocol == XY_XMODEM) /* if first data packet */
- showProtocol();
- /* 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) { /* check sum error */
- sprintf(xtbuf, "Checksum Error on Sector %s: sent=%x recvd=%x", sectdisp(recvsectcnt,bufsize,1), inchecksum, checksum);
- xprintMsg(X_STATUS, xtbuf, LZERO);
- fileread = readbackup;
- errorflag = TRUE;
- return(TRUE);
- }
- /*
- * check sum OK, let's go!
- */
- recvsectcnt += (bufsize == 128) ? 1L : 8L;
- sectnum = sectcurr;
- xprintMsg(X_PRECV, NULL, (bufsize == 128) ? recvsectcnt : (recvsectcnt / 8L));
- xprintMsg(X_KBYTES, NULL, (recvsectcnt / 8L));
- if ((ptime = time((time_t *)0) - start) == 0) {
- rate = 0;
- } else {
- rate = (int)((long)recvsectcnt * 128L / ptime);
- }
- xprintMsg(X_RATE, NULL, (long)rate);
- if (realProtocol == XY_YMODEM && expsect) {
- xprintMsg(X_PERCENT, NULL, (long)((long)recvsectcnt * 100L / expsect));
- }
-
- if (!openflag) { /* open output file if necessary */
- openflag = TRUE;
- if ((fd = open(name, O_WRONLY|O_BINARY|O_CREAT, 0644)) < 0) {
- sendbyte(CAN); sendbyte(CAN); sendbyte(CAN);
- xprintMsg(X_ERROR, msg_cantOpen, LZERO);
- return(FALSE);
- }
- if (realProtocol == XY_XMODEM)
- xprintMsg(X_FILENAME, name, LZERO);
- }
- if (write(fd, (char *) buff, bufctr) != bufctr) {
- close(fd);
- unlink(name);
- xprintMsg(X_ERROR, "File Write Error", LZERO);
- return(FALSE);
- } else {
- flushInputBuffer(); /* flush input */
- sendbyte(ACK); /* ACK the received packet */
- }
- return(TRUE);
- }
-
- static receiveFileName(sectcurr, bufsize, name)
- int sectcurr;
- int bufsize;
- char *name;
- /* sector number is wrong OR Ymodem filename */
- {
- int checksum; /* packet checksum */
- int inchecksum; /* incoming checksum or CRC */
- int junk; /* file mode, buffer counter */
- char *p;
-
- if (sectcurr == 0 && recvsectcnt == 0) { /* Ymodem file-name packet */
- /* Read and process a file-name packet */
- if (readbuf(bufsize, 5, FALSE, &checksum, &junk) == TIMEOUT) {
- xprintMsg(X_STATUS, "Timeout while reading filename packet", LZERO);
- errorflag = TRUE;
- return(TRUE);
- }
- /* 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 */
- xprintMsg(X_STATUS, "checksum error on filename sector", LZERO);
- errorflag = TRUE;
- return(TRUE);
- }
- strcpy(name, (char *)buff);
- /* expsect = ((buff[bufsize-1]<<8) | buff[bufsize-2]); */
- realProtocol = XY_YMODEM;
- showProtocol();
- if (strlen(name) == 0) { /* check for no more files */
- flushInputBuffer(); /* flush input */
- sendbyte(ACK); /* ACK the packet */
- xprintMsg(X_STATUS, "YMODEM Batch Receive Complete", LZERO);
- endFlag = TRUE;
- return (FALSE);
- }
- unixify(name); /* make filename canonical */
- /* read rest of YMODEM header */
- p = (char *)buff + strlen((char *)buff) + 1;
- sscanf(p, "%ld%lo%o", &xfilelength, &modtime, &junk);
- xprintMsg(X_FILENAME, name, LZERO);
- fileread = 0l;
- expsect = 0L;
- if (xfilelength) {
- CHECKLENGTH = TRUE;
- expsect = xfilelength/128L+1L;
- }
- sendbyte(ACK); /* ACK the packet */
- firstwait = WAITFIRST; /* reset to negotiate */
- } else if (sectcurr == sectnum) { /* duplicate sector? */
- sprintf(xtbuf, "Duplicate sector %s flushed\n", sectdisp(recvsectcnt,bufsize,0));
- xprintMsg(X_STATUS, xtbuf, LZERO);
- flushInputBuffer(); /* REALLY flush input */
- while(readbyte(1) != TIMEOUT)
- ;
- sendbyte(ACK);
- } else { /* no, real phase error */
- sprintf(xtbuf, "Phase Error - Expected packet is %s\n", sectdisp(recvsectcnt,bufsize,1));
- xprintMsg(X_STATUS, xtbuf, LZERO);
- errorflag = TRUE;
- fatalerror = TRUE;
- }
- return(TRUE);
- }
-
-
-
- /*
- * Various routines for batch transfer
- */
-
-
- /* make sure filename sent or received in YMODEM batch is canonical. */
-
- /* Incoming: Turn Unix '/' into CP/M ':' and translate to all lower case.
- * Remove trailing dot.
- */
-
- static void unixify (name)
- char *name;
- {
- char *ptr;
-
- /* change '/' to ':' and convert to lower case */
- for (ptr=name; *ptr; ++ptr)
- {
- if (*ptr == '/')
- *ptr = ':';
- if (isupper (*ptr))
- *ptr |= 040;
- }
-
- /* remove trailing dot if present */
- ptr--;
- if (*ptr == '.')
- *ptr = '\0';
- }
-
- /* make sure filename sent or received in YMODEM batch is canonical. */
-
- /* Outgoing: Turn ':' into '/' (for symmetry!) and turn into all lower case.
- * Remove everything before last '/'. Use "filename" to hold final name.
- */
-
- static char *
- cpmify (name)
- char *name;
- {
- char *ptr, *slash;
-
- /* find last '/' and copy rest of name */
-
- slash = name;
- for (ptr=name; *ptr; ++ptr)
- if (*ptr == '/')
- slash = ptr + 1;
- strcpy (filename, slash);
-
- /* change ':' to '/' and covert to all lower case */
-
- for (ptr=filename; *ptr; ++ptr)
- {
- if (*ptr == ':')
- *ptr = '/';
- if (isupper (*ptr))
- *ptr |= 040;
- }
- return (filename);
- }
- /* Construct a proper (i.e. pretty) sector count for messages */
-
- static char
- *sectdisp(recvsectcnt, bufsize, plus1)
- long recvsectcnt;
- int bufsize, plus1;
- {
- static char string[20];
- if (plus1)
- recvsectcnt += (bufsize == 128) ? 1 : 8;
- if (bufsize == 128 || recvsectcnt == 0)
- sprintf (string, "%d", recvsectcnt);
- else
- sprintf (string, "%d-%d", recvsectcnt-7, recvsectcnt);
- return(string);
- }
-
- /*
- *
- * Get a byte from the specified file. Buffer the read so we don't
- * have to use a system call for each character.
- *
- */
- static int getbyte(fildes, ch) /* Buffered disk read */
- int fildes;
- char *ch;
-
- {
- static char buf[BUFSIZ]; /* Remember buffer */
- static char *bufp = buf; /* Remember where we are in buffer */
-
- if (nbchr == 0) /* Buffer exausted; read some more */
- {
- if ((nbchr = read(fildes, buf, BUFSIZ)) < 0) {
- xprintMsg(X_ERROR, "File Read Error", LZERO);
- }
- bufp = buf; /* Set pointer to start of array */
- }
- if (--nbchr >= 0)
- {
- *ch = *bufp++;
- return(0);
- } else {
- return(EOF);
- }
- }
-
-
-
- /*
- * basic I/O
- */
- static readbyte(seconds)
- int seconds;
- {
- register int c;
-
- xalarm(seconds);
- for (;;) {
- if ((c = getSerial()) != -1) {
- return (c & 0xff);
- } else if ((c = keyin()) != -1) {
- if (c == 0x1b) { /* ESC */
- sendbyte(CAN);
- sendbyte(CAN);
- sendbyte(CAN);
- xexit();
- }
- }
- if (kermitTimer <= 0) {
- return(TIMEOUT); /* time out */
- }
- }
- }
-
- static int
- readbuf(bufsize, seconds, tmode, checksum, bufctr)
- int bufsize; /* number of chars to be read */
- int seconds; /* timeout period for each read */
- int tmode; /* text mode or not */
- int *checksum; /* pointer to checksum value */
- int *bufctr; /* length of actual data string in buffer */
- {
- int recfin = FALSE; /* flag that EOF read */
- register unsigned char c; /* character being processed */
- register int c1;
- register unsigned short chksm; /* working copy of checksum */
- register int bfctr; /* working copy of bufctr */
- register int bp; /* current buffer pointer */
- char *sectdisp();
-
- xalarm(seconds);
- chksm = 0;
- bfctr = 0;
-
- for (bp = 0; bp < bufsize; ) {
- if ((c1 = getSerial()) != -1) {
- xalarm(seconds); /* reset timer */
- bp++; /* add counter */
- c = c1 & 0xff; /* mask upper byte */
-
- /* now process part of packet we just read */
-
- buff[bfctr] = c;
- fileread++;
-
- if (CRCMODE) { /* CRC */
- chksm = (chksm<<B) ^ crctab[(chksm>>(W-B)) ^ c];
- } else { /* checksum */
- chksm = ((chksm+c) & 0xff);
- }
- if (CHECKLENGTH && fileread > xfilelength) { /* past EOF ? */
- continue;
- }
-
- if (tmode) { /* text mode processing */
- if (c == CR || c == 0) /* skip CRs and nulls */
- continue;
- else if (c == CTRLZ) { /* CP/M EOF char */
- recfin = TRUE;
- continue;
- } else if (!recfin) /* don't increment if past EOF */
- bfctr++;
- } else { /* binary */
- bfctr++;
- }
- } else {
- if ((c = keyin()) != -1) {
- if (c == 0x1b) { /* ESC */
- sendbyte(CAN);
- sendbyte(CAN);
- sendbyte(CAN);
- xexit();
- }
- }
- if (kermitTimer <= 0) {
- return (TIMEOUT);
- }
- }
- }
-
- *checksum = chksm;
- *bufctr = bfctr;
- return(0);
- }
-
- #endif /* XMODEM */
-