w8sdz@brl-smoke.ARPA (Keith B. Petersen ) (05/03/88)
This is version 3.6 (finished 4/88) of Steve Grandi's 4.2/4.3 BSD Unix xmodem program which includes a few bugfixes and some enhancements (requested by Macintosh users) stimulated by the xmodem release through comp.sources.unix. See the file update.doc for details. ---- Cut Here and unpack ---- #!/bin/sh # this is part 2 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file send.c continued # CurArch=2 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file send.c" sed 's/^X//' << 'SHAR_EOF' >> send.c X fprintf(LOGFP,"File Size %ldK, %ld Records, %ld Bytes\n", X (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size); X projtime(expsect, LOGFP); X } X } X else X { X logit("----\nXMODEM Send Function\n"); X logit("Closing down Batch Transmission\n"); X } X X X bufsize = buf1024 ? 1024 : 128; /* set sector size */ X if (buf1024 && !closeout) X logit("1K packet mode chosen\n"); X X sendfin = nlflag = FALSE; X attempts = 0; X X /* wait for and read startup character */ Xrestart: X do X { X while (((firstchar=readbyte(1)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN)) X if (++attempts > NAKMAX) X { X if (MDM7BAT && startup) X { X sendbyte(ACK); sendbyte(EOT); X } X error("Remote System Not Responding", TRUE); X } X X if ((firstchar & 0x7f) == CAN) X if (readbyte(3) == CAN) X error("Send cancelled at user's request",TRUE); X X if (firstchar == CRCCHR) X { X CRCMODE = TRUE; X if (!closeout) X logit("CRC mode requested\n"); X if (readbyte(1) == KCHR) X { X buf1024 = TRUE; X logit("Receiver invoked 1K packet mode\n"); X } X } X } X while (firstchar != NAK && firstchar != CRCCHR); X X if (MDM7BAT && closeout) /* close out MODEM7 batch */ X { X sendbyte(ACK); sendbyte (EOT); X flushin(); readbyte(2); /* flush junk */ X return; X } X X if (MDM7BAT && startup) /* send MODEM7 file name */ X { X if (send_name(unix_cpm(name)) == -1) X { X attempts = 0; X goto restart; X } X startup = FALSE; X attempts = 0; X goto restart; X } X X sectnum = 1; X X if (YMDMBAT) /* Fudge for YMODEM transfer (to send name packet) */ X { X sectnum = 0; X bufsize = 128; X filepack = TRUE; X } X X attempts = sentsect = 0; X start = time((time_t *) 0); X X do /* outer packet building/sending loop; loop till whole file is sent */ X { X X if (closeout && YMDMBAT && sectnum == 1) /* close out YMODEM */ X return; X X if (YMDMBAT && sectnum == 1) /* get set to send YMODEM data packets */ X { X bufsize = buf1024 ? 1024 : 128; X X do /* establish handshaking again */ X { X while (((firstchar=readbyte(2)) != CRCCHR) && (firstchar != NAK) && (firstchar != CAN)) X if (++attempts > ERRORMAX) X error("YMODEM protocol botch, C expected", TRUE); X if ((firstchar&0x7f) == CAN) X if (readbyte(3) == CAN) X error("Send cancelled at User's request", TRUE); X } X while ((firstchar != CRCCHR) && (firstchar != NAK)); X X attempts = 0; X } X X if ((bufsize == 1024) && (attempts > KSWMAX)) X { X logit("Reducing packet size to 128 due to excessive errors\n"); X bufsize = 128; X } X X if ((bufsize == 1024) && ((expsect - sentsect) < 8)) X { X logit("Reducing packet size to 128 for tail end of file\n"); X bufsize = 128; X } X X if (sectnum > 0) /* data packet */ X { X for (bufctr=0; bufctr < bufsize;) X { X if (nlflag) X { X buff[bufctr++] = LF; /* leftover newline */ X nlflag = FALSE; X } X if (getbyte(fd, &c) == EOF) X { X sendfin = TRUE; /* this is the last sector */ X if (!bufctr) /* if EOF on sector boundary */ X break; /* avoid sending extra sector */ X buff[bufctr++] = CTRLZ; /* pad with Ctrl-Z for CP/M EOF (even do for binary files) */ X continue; X } X X if (tmode && c == LF) /* text mode & Unix newline? */ X { X buff[bufctr++] = CR; /* insert carriage return */ X if (bufctr < bufsize) X buff[bufctr++] = LF; /* insert LF */ X else X nlflag = TRUE; /* insert on next sector */ X } X else if (amode && c == LF) /* Apple mode & Unix newline? */ X buff[bufctr++] = CR; /* substitute CR */ X else X buff[bufctr++] = c; /* copy the char without change */ X } X X if (!bufctr) /* if EOF on sector boundary */ X break; /* avoid sending empty sector */ X } X X else /* YMODEM filename packet */ X { X for (bufctr=0; bufctr<bufsize; bufctr++) /* zero packet */ X buff[bufctr]=0; X if (!closeout) X { X strcpy((char *)buff, cpmify(name)); X X /* put in file name, length, mode */ X { X register char *p; X p = (char *)buff + strlen(name) + 1; X sprintf(p, "%lu %lo %o", filestatbuf.st_size, X filestatbuf.st_mtime, filestatbuf.st_mode); X if (DEBUG) X fprintf(LOGFP, "DEBUG: YMODEM header information: %s\n", p); X } X buff[bufsize-2] = (expsect & 0xff); /* put in KMD kludge information */ X buff[bufsize-1] = ((expsect >> 8) & 0xff); X } X } X X bbufcnt = 0; /* start building block to be sent */ X blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH; /* start of packet char */ X blockbuf[bbufcnt++] = sectnum; /* current sector # */ X blockbuf[bbufcnt++] = ~sectnum; /* and its complement */ X X checksum = 0; /* initialize checksum */ X for (bufctr=0; bufctr < bufsize; bufctr++) X { X blockbuf[bbufcnt++] = buff[bufctr]; X X if (CRCMODE) X checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]]; X X else X checksum = ((checksum+buff[bufctr]) & 0xff); X } X X if (CRCMODE) /* put in CRC */ X { X checksum &= 0xffff; X blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff); X blockbuf[bbufcnt++] = (checksum & 0xff); X } X else /* put in checksum */ X blockbuf[bbufcnt++] = checksum; X X attempts = 0; X X do /* inner packet loop */ X { X X writebuf(blockbuf, bbufcnt); /* write the block */ X flushin(); /* purge anything in input queue */ X X if (DEBUG) X fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n", X bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff); X X attempts++; X sendresp = readbyte(10); /* get response from remote */ X X if (sendresp != ACK) X { X if (sendresp == TIMEOUT) X { X logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1)); X } X else if (sendresp == NAK) X { X logitarg("NAK on sector %s\n",sectdisp(sentsect,bufsize,1)); X } X else X { X logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1)); X } X } X } X while((sendresp != ACK) && (attempts < ERRORMAX)); /* close of inner loop */ X X sectnum++; /* increment to next sector number */ X if (!filepack) X sentsect += (bufsize == 128) ? 1 : 8; X filepack = FALSE; X } X while (!sendfin && ( attempts < ERRORMAX)); /* end of outer loop */ X X if (attempts >= ERRORMAX) X { X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); X error ("Too many errors in transmission", TRUE); X } X X attempts = 0; X sendbyte(EOT); /* send 1st EOT to close down transfer */ X X while ((readbyte(15) != ACK) && (attempts++ < EOTMAX)) /* wait for ACK of EOT */ X { X if (attempts > 1) X logitarg("EOT not ACKed, try %d\n", attempts); X sendbyte(EOT); X } X X if (attempts >= RETRYMAX) X error("Remote System Not Responding on Completion", TRUE); X X close(fd); X X logit("Send Complete\n"); X prtime(sentsect, time((time_t *) 0) - start); X } SHAR_EOF echo "File send.c is complete" chmod 0644 send.c || echo "restore of send.c fails" echo "x - extracting tip.diffs (Text)" sed 's/^X//' << 'SHAR_EOF' > tip.diffs && X X*** cmdtab.c.ORIG Mon May 5 11:01:59 1986 X--- cmdtab.c Thu Aug 21 10:08:50 1986 X*************** X*** 15,16 **** X--- 15,17 ---- X extern int cu_take(), cu_put(), dollar(), genbrk(), suspend(); X+ extern int rtfile(), stfile(), rbfile(), sbfile(); X X*************** X*** 35,36 **** X--- 36,41 ---- X { '#', NORM, "send break", genbrk }, X+ { '{', NORM, "receive xmodem text file", rtfile }, X+ { '}', NORM, "send xmodem text file", stfile }, X+ { '(', NORM, "receive xmodem binary file", rbfile }, X+ { ')', NORM, "send xmodem binary file", sbfile }, X { 0, 0, 0 } X X X X*** cmds.c.ORIG Mon May 5 11:01:56 1986 X--- cmds.c Tue Sep 30 10:17:11 1986 X*************** X*** 855,856 **** X--- 865,1412 ---- X return(0); X+ } X+ X+ X+ /* XMODEM stuff; sag sept 1984 - Feb 1985 X+ * Taken from Brian Kantor's (sdccsu3!brian) xmodem version 1.0 X+ * Note that this code will work on version 4.2 ONLY (uses select) X+ */ X+ X+ #include <sys/stat.h> X+ #include <sys/time.h> X+ X+ /* ASCII Constants */ X+ #define SOH 001 X+ #define STX 002 X+ #define ETX 003 X+ #define EOT 004 X+ #define ENQ 005 X+ #define ACK 006 X+ #define LF 012 /* Unix LF/NL */ X+ #define CR 015 X+ #define NAK 025 X+ #define SYN 026 X+ #define CAN 030 X+ #define ESC 033 X+ #define CTRLZ 032 /* CP/M EOF for text (usually!) */ X+ X+ /* XMODEM Constants */ X+ #define TIMEOUT -1 X+ #define ERRORMAX 10 /* maximum errors tolerated */ X+ #define RETRYMAX 10 /* maximum retries to be made */ X+ #define BBUFSIZ 128 /* buffer size -- do not change! */ X+ #define DEBUG 0 /* 1 for debugging output */ X+ #define GETERR -10 /* error code for getbyte routine */ X+ X+ char buff[BBUFSIZ]; X+ X+ int nbchr; /* number of chars read so far for buffered read */ X+ X+ /* Receive a text file */ X+ rtfile(c) X+ char c; X+ { X+ putchar (c); X+ rfile ('t'); X+ } X+ X+ /* Receive a binary file */ X+ rbfile(c) X+ char c; X+ { X+ putchar (c); X+ rfile ('b'); X+ } X+ X+ /* Send a text file */ X+ stfile(c) X+ char c; X+ { X+ putchar (c); X+ sfile ('t'); X+ } X+ X+ /* Send a binary file */ X+ sbfile(c) X+ char c; X+ { X+ putchar (c); X+ sfile ('b'); X+ } X+ X+ /* print error message and cleanup for exit */ X+ error(msg) X+ char *msg; X+ { X+ printf("\r\nXMODEM: %s\n", msg); X+ ioctl (0, TIOCSETC, &tchars); X+ write (fildes[1], (char *)&ccc, 1); X+ signal (SIGINT, SIG_DFL); X+ } X+ X+ /* X+ * X+ * Get a byte from the specified file. Buffer the read so we don't X+ * have to use a system call for each character. X+ * X+ */ X+ getbyte(fildes, ch) /* Buffered disk read */ X+ int fildes; X+ char *ch; X+ X+ { X+ static char buf[BUFSIZ]; /* Remember buffer */ X+ static char *bufp = buf; /* Remember where we are in buffer */ X+ X+ if (nbchr == 0) /* Buffer exausted; read some more */ X+ { X+ if ((nbchr = read(fildes, buf, BUFSIZ)) < 0) X+ { X+ error("File Read Error"); X+ return (GETERR); X+ } X+ bufp = buf; /* Set pointer to start of array */ X+ } X+ if (--nbchr >= 0) X+ { X+ *ch = *bufp++; X+ return(0); X+ } X+ else X+ return(EOF); X+ } X+ X+ /** receive a file **/ X+ rfile(mode) X+ char mode; X+ { X+ register int bufctr, checksum; X+ register int c; X+ int j, firstchar, sectnum, sectcurr, tmode; X+ int sectcomp, errors, errorflag, recfin; X+ int fatalerror, inchecksum; X+ long recvsectcnt; X+ X+ int (*f) (); X+ char *cp, *expand(); X+ time_t start; X+ X+ if (prompt (" Receive local file name? ", copyname)) X+ return; X+ cp = expand (copyname); X+ if ((sfd = creat (cp, 0666)) < 0) X+ { X+ printf ("\r\n%s: Cannot creat\r\n", copyname); X+ return; X+ } X+ X+ kill (pid, SIGIOT); X+ read (repdes[0], (char *)&ccc, 1); /* wait until read process stops */ X+ ioctl (0, TIOCSETC, &defchars); /* set tty modes */ X+ f = signal (SIGINT, intcopy); /* intercept control-c */ X+ X+ start = time(0); X+ quit = 0; X+ (void) setjmp(intbuf); /* set control-c catcher */ X+ X+ if (quit) X+ { X+ error("Control-C; Reception canceled"); X+ close (sfd); X+ return; X+ } X+ X+ printf("XMODEM: Ready to RECEIVE File %s", cp); X+ puts("\r\nControl-C to cancel.\n"); X+ X+ recfin = FALSE; X+ sectnum = errors = 0; X+ fatalerror = FALSE; /* NO fatal errors */ X+ recvsectcnt = 0; /* number of received sectors */ X+ X+ if (mode == 't') X+ tmode = TRUE; X+ else X+ tmode = FALSE; X+ X+ sendbyte(NAK); /* Start up the sender's first block */ X+ X+ do X+ { X+ errorflag = FALSE; X+ do X+ { X+ firstchar = readbyte(6); X+ } X+ while ((firstchar != SOH) X+ && (firstchar != EOT) X+ && (firstchar != TIMEOUT) X+ && ((firstchar & 0x7f) != CAN)); X+ X+ if (firstchar == TIMEOUT) X+ { X+ printf("\r\nTimeout on Sector %d\n", sectnum+1); X+ errorflag = TRUE; X+ } X+ X+ if ((firstchar & 0x7f) == CAN) X+ { X+ error("Reception canceled at user's request"); X+ close (sfd); X+ return; X+ } X+ X+ if (firstchar == SOH) X+ { X+ sectcurr = readbyte(3); /* get sector numbers */ X+ sectcomp = readbyte(3); X+ if ((sectcurr + sectcomp) == 0xff) X+ { X+ if (sectcurr == ((sectnum+1) & 0xff)) X+ { X+ checksum = 0; X+ for (j = bufctr = 0; j < BBUFSIZ; j++) X+ { X+ buff[bufctr] = c = readbyte(3); X+ checksum = ((checksum+c) & 0xff); X+ if (!tmode) /* binary mode */ X+ { X+ bufctr++; X+ continue; X+ } X+ if (c == CR) X+ continue; /* skip CR's */ X+ if (c == CTRLZ) /* CP/M EOF char */ X+ { X+ recfin = TRUE; /* flag EOF */ X+ continue; X+ } X+ if (!recfin) X+ bufctr++; X+ } X+ inchecksum = readbyte(3); /* get checksum */ X+ if (checksum == inchecksum) /* good checksum */ X+ { X+ errors = 0; X+ recvsectcnt++; X+ sectnum = sectcurr; X+ if (DEBUG) printf ("\n"); X+ printf ("\rreceived sector %-4d", recvsectcnt); X+ if (write(sfd, buff, bufctr) < 0) X+ { X+ sendbyte(CAN); X+ error("File Write Error"); X+ close (sfd); X+ return; X+ } X+ else X+ sendbyte(ACK); X+ X+ } X+ else X+ { X+ printf("\r\nChecksum Error on Sector %d\n", sectnum+1); X+ errorflag = TRUE; X+ } X+ } X+ else X+ { X+ if (sectcurr == sectnum) X+ { X+ while(readbyte(3) != TIMEOUT) X+ ; X+ sendbyte(ACK); X+ } X+ else X+ { X+ printf("\r\nPhase Error - Received Sector is "); X+ printf("%d while Expected Sector is %d\n", X+ sectcurr, ((sectnum+1) & 0xff)); X+ errorflag = TRUE; X+ fatalerror = TRUE; X+ sendbyte(CAN); X+ } X+ } X+ } X+ else X+ { X+ printf("\r\nHeader Sector Number Error on Sector %d\n", X+ sectnum+1); X+ errorflag = TRUE; X+ } X+ } X+ X+ if (errorflag) X+ { X+ errors++; X+ while (readbyte(3) != TIMEOUT) X+ ; X+ sendbyte(NAK); X+ } X+ } X+ while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror); X+ X+ if ((firstchar == EOT) && (errors < ERRORMAX) && !fatalerror) X+ { X+ close(sfd); X+ sendbyte(ACK); X+ printf("\n\rReceive Complete"); X+ printf("\n\r%ld CP/M Records ", recvsectcnt); X+ prtime(" transferred in ", time(0)-start); X+ X+ ioctl (0, TIOCSETC, &tchars); /* reset ttys */ X+ write (fildes[1], (char *)&ccc, 1); /* wakeup tip */ X+ signal (SIGINT, SIG_DFL); /* reset control-c catcher */ X+ } X+ else X+ { X+ sendbyte(CAN); X+ error("\r\nABORTED -- Too Many Errors"); X+ close (sfd); X+ return; X+ } X+ } X+ X+ /** send a file **/ X+ sfile(mode) X+ char mode; X+ { X+ register int bufctr, checksum, sectnum; X+ char blockbuf[134]; X+ int fd, attempts; X+ int nlflag, sendfin, tmode; X+ int bbufcnt; X+ int firstchar; X+ int getretrn; X+ char c; X+ int sendresp; /* response char to sent block */ X+ X+ int (*f) (); X+ char *cp, *expand(); X+ time_t start; X+ X+ if (prompt (" Send local file name? ", copyname)) X+ return; X+ cp = expand (copyname); X+ if ((fd = open(cp, 0)) < 0) X+ { X+ printf("Can't open file for send\n"); X+ return; X+ } X+ X+ kill (pid, SIGIOT); X+ read (repdes[0], (char *)&ccc, 1); /* wait until read process stops */ X+ ioctl (0, TIOCSETC, &defchars); /* setup tty */ X+ f = signal (SIGINT, intcopy); /* prepare to catch control-c */ X+ start = time(0); X+ quit = 0; X+ (void) setjmp(intbuf); /* setup control-c catcher */ X+ X+ nbchr = 0; /* clear buffered read char count */ X+ X+ if (quit) X+ { X+ sendbyte(CAN); X+ error("Control-C; Send canceled"); X+ close (fd); X+ return; X+ } X+ X+ printf("XMODEM: File %s Ready to SEND", cp); X+ prfilestat(cp); /* print file size statistics */ X+ puts("\r\nControl-C to cancel.\n"); X+ X+ if (mode == 't') X+ tmode = TRUE; X+ else X+ tmode = FALSE; X+ X+ sendfin = nlflag = FALSE; X+ attempts = 0; X+ X+ while (((firstchar=readbyte(30)) != NAK) && (firstchar != CAN)) X+ { X+ if (++attempts > RETRYMAX) { X+ error("Remote System Not Responding"); X+ close (fd); X+ return; X+ } X+ } X+ X+ if ((firstchar & 0x7f) == CAN) X+ { X+ error("Send cancelled at user's request."); X+ close (fd); X+ return; X+ } X+ X+ sectnum = 1; /* first sector number */ X+ attempts = 0; X+ X+ do X+ { X+ for (bufctr=0; bufctr < BBUFSIZ;) X+ { X+ if (nlflag) X+ { X+ buff[bufctr++] = LF; /* leftover newline */ X+ nlflag = FALSE; X+ } X+ getretrn = getbyte(fd, &c); X+ if (getretrn == GETERR) X+ { X+ sendbyte(CAN); X+ error ("Read error on local file"); X+ close (fd); X+ return; X+ } X+ if (getretrn == EOF) X+ { X+ sendfin = TRUE; /* this is the last sector */ X+ if (!bufctr) /* if EOF on sector boundary */ X+ break; /* avoid sending extra sector */ X+ if (tmode) X+ buff[bufctr++] = CTRLZ; /* Control-Z for CP/M EOF */ X+ else X+ bufctr++; X+ continue; X+ } X+ X+ if (tmode && c == LF) /* text mode & Unix newline? */ X+ { X+ buff[bufctr++] = CR; /* insert carriage return */ X+ if (bufctr < BBUFSIZ) X+ buff[bufctr++] = LF; /* insert LF */ X+ else X+ nlflag = TRUE; /* insert on next sector */ X+ } X+ else X+ buff[bufctr++] = c; /* copy the char without change */ X+ } X+ X+ attempts = 0; X+ X+ if (!bufctr) /* if EOF on sector boundary */ X+ break; /* avoid sending empty sector */ X+ X+ do X+ { X+ bbufcnt = 0; /* start building block to be sent */ X+ blockbuf[bbufcnt++] = SOH; /* start of packet char */ X+ blockbuf[bbufcnt++] = sectnum; /* current sector # */ X+ blockbuf[bbufcnt++] = -sectnum-1; /* and its complement */ X+ X+ checksum = 0; /* init checksum */ X+ for (bufctr=0; bufctr < BBUFSIZ; bufctr++) X+ { X+ blockbuf[bbufcnt++] = buff[bufctr]; X+ checksum = ((checksum+buff[bufctr]) & 0xff); X+ } X+ X+ blockbuf[bbufcnt++] = checksum; X+ write(FD, blockbuf, 132); /* write the block */ X+ ioctl(FD,TIOCFLUSH,0); X+ X+ attempts++; X+ sendresp = readbyte(10); /* get response */ X+ if (sendresp != ACK) X+ { X+ printf("\r\nNon-ACK Received on Sector %d\n",sectnum); X+ if (sendresp == TIMEOUT) X+ printf("\r\nThis Non-ACK was a TIMEOUT\n"); X+ } X+ } X+ while((sendresp != ACK) && (attempts < RETRYMAX)); X+ X+ sectnum++; /* increment to next sector number */ X+ if (DEBUG) printf ("\n"); X+ printf ("\rsent sector %-4d", sectnum-1); X+ } X+ while (!sendfin && (attempts < RETRYMAX)); X+ X+ if (attempts >= RETRYMAX) X+ { X+ error("Remote System Not Responding"); X+ close (fd); X+ return; X+ } X+ X+ attempts = 0; X+ sendbyte(EOT); /* send 1st EOT */ X+ X+ while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX)) X+ sendbyte(EOT); X+ X+ if (attempts >= RETRYMAX) X+ error("Remote System Not Responding on Completion"); X+ X+ close(fd); X+ printf("\r\nSend Complete\r\n"); X+ prtime("Data transferred in ", time(0)-start); X+ X+ ioctl (0, TIOCSETC, &tchars); /* restore tty */ X+ write (fildes[1], (char *)&ccc, 1); /* wakeup tip */ X+ signal (SIGINT, SIG_DFL); /* reset control-c catcher */ X+ sleep(5); /* give other side time to return to terminal mode */ X+ X+ } X+ X+ /* print file size status information */ X+ prfilestat(name) X+ char *name; X+ { X+ struct stat filestatbuf; /* file status info */ X+ X+ stat(name, &filestatbuf); /* get file status bytes */ X+ printf("\r\nEstimated File Size %ldK, %ld Records, %ld Bytes", X+ (filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1, X+ filestatbuf.st_size); X+ return; X+ } X+ X+ /* get a byte from data stream -- timeout if "seconds" elapses */ X+ int readbyte(seconds) X+ int seconds; X+ { X+ int i, readfd; X+ char c; X+ struct timeval tmout; X+ X+ tmout.tv_sec = seconds; X+ tmout.tv_usec = 0; X+ X+ readfd = 1 << FD; X+ X+ if ((i=select(FD+1, &readfd, 0, 0, &tmout)) == 0) X+ { X+ return(TIMEOUT); X+ } X+ X+ read(FD, &c, 1); X+ X+ return(c & 0xff); /* return the char */ X+ } X+ X+ /* send a byte to data stream */ X+ sendbyte(data) X+ char data; X+ { X+ write(FD, &data, 1); /* write the byte */ X+ ioctl(FD,TIOCFLUSH,0); /* flush so it really happens now! */ X+ return; X+ } X+ X+ /* X+ * "nap" for specified time X+ */ X+ nap (milliseconds) X+ int milliseconds; X+ { X+ struct timeval timeout; X+ X+ if (milliseconds == 0) X+ return; X+ timeout.tv_sec = 0; X+ timeout.tv_usec = milliseconds * 1000; X+ X+ (void) select(1, 0, 0, 0, &timeout); X } SHAR_EOF chmod 0644 tip.diffs || echo "restore of tip.diffs fails" echo "x - extracting update.doc (Text)" sed 's/^X//' << 'SHAR_EOF' > update.doc && XChanges leading to version 3.3 X X1) "Better" handshaking for MODEM7 batch transfers (5/19/87). X X2) If reception of a file is aborted due to errors, delete incomplete file X(5/19/87). X X3) If an "impossible" tty speed is detected, assume 1200 bps (5/19/87). X X4) Disallow CAN-CAN abort during file send or receive except at beginning of Xfile transfer (during batch transfers, CAN-CAN abort is allowed at beginning Xof each file transfer) (5/19/87). X X5) Uncouple total allowed errors during the reception of a single packet X(ERRORMAX, now made 10) and errors allowed when starting transfer (STERRORMAX, Xset to 10) (5/19/87). X X6) Fix some bugs when receiving an empty file and when a phase error occurs Xduring a file reception (5/19/87). X X7) Portability fix in prtime and projtime; they also handle pathological Xcases better (5/19/87). X X8) During file reception an EOT is not believed unless it is sent again in Xresponse to a NAK (5/25/87). X X9) Modified cpm_unix and unixify so a filename without an extension will not Xhave a trailing dot in its filename after being received in a MODEM7 or XYMODEM batch transfer (5/25/87). X X10) Allowable errors during transmission of a single packet now set to XERRORMAX (5/27/87). X X11) When transferring a binary file, the YMODEM file length field is filled Xin on transmit and (if present) used to truncate the file on reception. XA new truncate function (truncfile) added to getput.c to do the deed (5/28/87). XThe file mode field is also set but is ignored on file reception. X X12) In a batch receive (xmodem -rt), program can be forced into checksum mode Xby specifying the "M" flag indicating a MODEM7 transfer (5/30/87). X X13) Changed the "B" option to "M" to indicate MODEM7 batch. Made all option Xflags case insensitive. Command line is now recorded in the log file X(5/30/87). X X14) The "KND/IMP" convention of using "CK" to invoke 1K packets during YMODEM Xbatch transfers was installed. This code will be sent during a batch receive Xif "K" is included on the command line unless "M" is also present. This code Xwill be recognized when sending under all circumstances (5/30/87). X X------------------------------------------------------------------------------ X XChanges leading to version 3.4 X X1) Fix usage message (10/2/87). X X2) Sender will now try up to 10 times (EOTMAX) to send an EOT to terminate a Xtransmission. Used to be 5 times, but Chuck Forsberg's "official" minimum Xrequirements for YMODEM mandate 10 (10/2/87). X X3) Handle YMODEM file modification times if present in header on reception of Xboth binary and text files (10/2/87). Retracted when can't seem to get Xproper times whn playing with dsz (10/3/87). Found bug and reinstalled Xfeature (10/16/87). Found REAL bug (10/21/87). X X4) Null bytes are now stripped out of files when received as text files (MEX Xdoesn't seem to want to put in the terminating control-Z) (10/3/87). X X5) Slightly modified terminal parameter setting to explicitly turn of CRMOD Xand to flush read queue; ideas stolen from Kermit. Will it fly on Pyramid? X(10/3/87). X X6) Decreased time between "startup" characters sent when starting a file Xreceive operation. This should increase perceived response. Now waits XWAITFIRST seconds (set to 1) instead of 6 (waits for 5 seconds for Xsubsequent packets. STERRORMAX now 60, CRCSWMAX now 30. XTimeouts on 1st sector no longer reported in log (10/5/87). X X7) Once again played with kernel sleeps in readbuf() (packet reading Xroutine). On busy system could cause real problems. Now supply flag (t) to Xsuppress sleeping on Too Busy systems. No longer suppress sleep when speeds are Xover 4800 bps. Sleep kludge DOES help: on an empty 750 running 4.3BSD, a Xfile reception at 2400 bps used 6% of the CPU with the sleep kludge and 24% Xwithout it (data transfer rates were the the same) (10/5/87). X X8) Actually count characters as they are being read for a file reception. XWhen YMODEM file length is set, stop writing characters when reach length. XThis will allow YMODEM file lengths to work for text files and the Xelimination of truncfile() in getput.c (which was impossible for SYS V) X(10/5/87). X X9) Another attempt at tty modes. Now do nothing but set speeds, set mode to Xraw, and turn off echoing and tandem (10/6/87). X X------------------------------------------------------------------------------ X XChanges leading to version 3.5 X X1) Following the suggestion of Bill Carpenter (ho5cad!wjc), I changed every Xprintf("") to fprintf(stderr, "") so one can use xmodem on either end of unix Xto unix link. (3/24/88). X X2) Again, thanks to Bill Carpenter, corrected typo in stamptime() in Xgetput.sysv.c (3/24/88). X X3) Thanks to Steve Lebowitz (prcpto!pdvshl), fixed a && that should have been Xa & in getput.sysv.c (3/25/88). X X4) Thanks to Leo Pilachowski, who managed to fool xmodem by "preplacing" ACKS Xin the VAX's input queue (improves throughput by 20%, says Leo, but makes Xerror recovery a tad dicey...!). Implemented a flushin() function in Xgetput.c to flush any pending characters. flushin is called in send.c just Xafter sending a packet to make sure a proper ACK or NAK is received (I hope Xfast machines don't beat me to it and get their ACKS flushed!). In Xreceive.c, flushin is called prior to the "startup" characters, prior to Xsending the packet acknowledgment ACK and prior to the NAK prompting for Xconfirming EOT. Now how does one implement flushin() on Sys V? (3/25/88). X X5) Fixed pair of bugs in send.c: YMODEM test enforcing CRC was testing Xnumber of attempts against STERRORMAX instead of ERRORMAX (also shortened Xtimeout interval on this read) and a "timeout" during packet send was not Xnoticed (due to a > instead of a >=) thus program started sending EOTs which Xfurther delayed abort (3/28/88). X X6) Modified send.c and cpmify function in batch.c to strip path names on file Xnames transmitted as part of YMODEM batch (3/28/88). X X7) Hacked receive.c to make end of loop processing clearer and improve Xgarbage flushing when errors are detected (3/28/88). X X8) Pulled out of decision restricting YMODEM batch send to use CRC only. Will Xnow gladly use checksum if told to and will respond to NAK as well as the Xproper C when starting up data transfer (3/28/88). Turns out this patch fixes Xproblem with Red Ryder (4/10/88). X X9) Tested MODEM7 batch against MEX-PC. Confirmation of EOT during filename Xtransmission was not working, so xmodem wasn't shutting down a MODEM7 batch Xreceive. Removed code to NAK first EOT and wait for second EOT (3/28/88). X X10) Added code to count number of newlines in a text file to get an accurate Xfile size. I thought it would take too long; but seems to be quite nimble X(see countnl in getput.c). We now transmit YMODEM file length and mode Xinformation for text as well as binary files (3/29/88). X X11) After a YMODEM file name packet was received, forgot to reset "wait" time Xfor receiving first character of data packet which definitely slowed Xperceived performance. (See note 6 for v. 3.4). Fixed (4/7/88). X X------------------------------------------------------------------------------ X XChanges leading to version 3.6 X X1) Added two new major commands (sa and ra) to send and receive text files Xfor Apple Macintoshs which use CR as EOL character instead of the MS/DOS CR XLF pair. Thanks to Dave Nowak (djnowak@iseesun.DPL.SCG.HAC.COM) for the Xinspiration (4/11/88). X X2) Experiences with Red Ryder 10.3. Fixed botch in receive.c that led to an Xinfinite loop when a checksum failed on YMODEM file name packet. Now have Xseperate variables for packet errors and "startup" errors. Prevent CRC to Xchecksum switch during receive startup if YMDMBAT flag is true. This insures Xthat no such transition will ever take place on second or subsequent file Xtransfer; can be set on first file by including Y option on command line. No Xlonger print "0" expected sectors if both YMODEM file length and KMD file Xlength are both 0 (4/12/88). X X3) Cleaned up ifs in readbuf. Removed void declaration on flushin (will Xbreak 4.2BSD compiler?). Corrected "number of sent sectors" on YMODEM Xtransfer (was counting filename packet) (4/12/88). X X4) More experiences with Red Ryder. Removed line flush before every CRCCHR Xor NAK trying to start a receive (RR YMODEM batch send to the VAX now seems Xto work). Fixed KMD "1K reception flag" to work properly on a receive. XAdded a flushin just before program exits in a futile effort to eliminate XRR's nasty habit of sending a final EOT down the line. Reaaranged Xvariables in send.c so longpackets requested by the KMD flag are not X"sticky" from file to file in a batch. RR is a real DOG: ony gets about 133 Xcps when downloading to a Mac over a 9600 bps line! (4/14/88). X X------------------------------------------------------------------------------ X XThanks to Keith Peterson (w8sdz@simtel20.arpa), John Rupley X(arizona!rupley!root), Emmet Gray (ihnp4!uiucuxc!fthood!egray), Bob Bickford X(lll-crg!well!rab), Doug Moore (moore@svax.cs.cornell.edu), David Brown X(jdb@ncsc.arpa), Bill Carpenter (ho5cad!wjc), Steve Lebowitz (prcpto!pdvshl), XLeo Pilachowski, Dave Nowak (djnowak@iseesun.DPL.SCG.HAC.COM) and Chuck XForsberg's documents and his ZCOMM/DSZ/rz/sz programs for ideas, suggestions Xand comments. SHAR_EOF chmod 0644 update.doc || echo "restore of update.doc fails" echo "x - extracting xmodem.1 (Text)" sed 's/^X//' << 'SHAR_EOF' > xmodem.1 && X.TH XMODEM LOCAL "April 14, 1988" X.UC 4.2 X.SH NAME Xxmodem \- Christensen protocol file transfer utility X.SH SYNOPSIS X.B xmodem X[\fBst|sb|sa|rt|rb|ra\fR][\fBymkctdlx\fR] X[file...] X.br X.SH DESCRIPTION XThe X.I xmodem Xprogram implements the Christensen (XMODEM) file transfer Xprotocol for moving files between 4.2/4.3BSD Unix systems and microcomputers. XThe XMODEM/CRC protocol, the MODEM7 batch protocol, the XMODEM-1K Xblock protocol and the YMODEM batch protocol are all supported by X.IR xmodem . XFor details of the protocols, Xsee the document edited by Chuck Forsberg titled X.I XXMODEM/YMODEM Protocol Reference. X.sp XOption Flags are case insensitive; the cluster of flags Xmay be preceded by an optional "-" Xcharacter. X.PP X.SH PARAMETERS XExactly one of the following must be selected: X.TP X.B rb XReceive Binary - files are placed on the Unix disk without conversion. X.I Xmodem Xwill silently destroy existing files of the same name. X.TP X.B rt XReceive Text - files are converted from the CP/M and MS-DOS Xformat of CR-LF pairs to the Unix convention of newline Xcharacters only between lines. XNull bytes are ignored and bit 8 of each character is stripped (which makes XWordstar files much more readable). XA CTRL-Z character is deemed to indicate the EOF location in the incoming Xfile. XThe resulting file Xis acceptable to the Unix editors and compilers, and is usually slightly Xsmaller than the original file. X.I Xmodem Xwill silently destroy existing files of the same name. X.TP X.B ra XReceive Apple - same as rt save CR characters in the incoming file are Xtranslated into Unix newline characters. X.TP X.B sb XSend Binary - files are sent without conversion as they exist on the Unix disk. X.TP X.B st XSend Text - newline characters in the file are converted to CR-LF pairs Xin accord with the CP/M and MS-DOS conventions for text files. The file X"grows" in this process. X.TP X.B sa XSend Apple - same as st save newline characters are converted into CR Xcharacters in accord with Apple Macintosh conventions for text files. X.PP X.SH OPTIONS X.TP X.B y XSelect the YMODEM batch protocol for sending files; a list of files specified Xon the command line will be sent in sequence. The YMODEM batch protocol is Xused automatically for file reception if the sending program requests it. XIf this flag is specified for a batch receive, (\fIxmodem rty\fR, for example), Xthe transfer will never attempt to switch from CRC to checksum mode. X.TP X.B m XSelect the MODEM7 batch protocol for sending files; a list of files specified Xon the command line will be sent in sequence. The MODEM7 batch protocol is Xused automatically for file reception if the sending program requests it. XIf this flag is specified for a batch receive, (\fIxmodem rbm\fR, for example), Xthe transfer starts in checksum mode rather than CRC mode. X.TP X.B k XSelect the XMODEM-1K file transfer mode for sending files. Use of 1K packets on Xlow-error lines increases throughput. XHowever, over direct connections at 9600 bps to a busy host, 1K packets may Xcause data overflows generating excessive retries. X1K packets are automatically Xused for file reception if the sending program requests it. XIf this flag is specified with the YMODEM flag in a batch receive (\fIxmodem Xrbyk\fR, for example), the program will attempt to use the "KMD/IMP" convention Xto invoke 1K file transfers. X.TP X.B c XSelect the CRC-16 error-checking protocol on receive. CRC mode is better at catching Xtransmission errors that occur than the alternative checksum protocol. XCRC mode is automatically selected for file Xtransmission if the receiving modem program requests it. X.TP X.B t XIndicates the Unix system is Too Busy and X.I xmodem Xshould fall back to a simpler I/O strategy than normal. X.TP X.B d XDelete the X.I xmodem.log Xfile before file transfer is begun. X.TP X.B l XDo NOT write to the log file. If logging is selected, a file X.I xmodem.log Xwill be created (or appended to), with entries for significant events, errors Xand retries. This can be useful to see why things went wrong Xwhen they do. X.TP X.B x XToggle on debug mode. If debug mode is selected, copious and possibly Xuseful debugging information will be placed in X.IR xmodem.log . X.SH "FILE NAMES" XFiles transmitted using one of the batch modes Xwill be stored on the remote machine under a CP/M-ified name (path names Xstripped, limited Xto eight characters plus a three character extension; ":" characters will Xbe turned into "/" characters; all characters will be in monocase). XFiles received using one of the batch modes Xwill be stored under their transmitted names (except that any "/" characters Xin the file name will be converted into ":" characters, all upper-case Xcharacters will be translated into lower case and trailing dots will be Xexpunged). X.PP XWhen a batch receive is requested, X.I xmodem Xtakes a wait and see attitude and can adapt to either batch protocol or even Xa classic XMODEM transfer (note that CRC-16 mode is automatically set under Xthese circumstances unless the b flag is specified). XIf a classic, "non-batch" XMODEM file reception takes place, Xthe received file is stored as X.IR xmodem.in . XFile names present on the command line for a batch receive are ignored. X.SH NOTES XWhile waiting for the beginning of a file transfer, X.I xmodem Xtreats two CAN (CTRL-X) characters that are received within 3 seconds Xas a request to abort. CAN characters will not cause an abort if received Xduring a file transfer. X.PP XIf 10 or more errors are detected during the transmission or reception of any Xone packet, the transfer is aborted. X.PP XSqueezed, compressed or ARCed files must be transferred in binary mode, even if they Xcontain text. X.PP XIf you use X.I xmodem Xover a X.I rlogin Xlink, you may have to use the form X.IR "rlogin machine -8" . X.PP XIf an unexpected error occurs before a file is completely received, the Xincomplete file is deleted. X.PP XFiles received using both binary and text mode in a YMODEM batch transfer Xwill be truncated Xto the file size specified in the YMODEM header (extra CR characters in the Xincoming file are correctly handled). File sizes are included in Xthe YMODEM header when sending both binary and text files. Thus files Xtransferred via YMODEM should preserve their exact length. XFile modification times are set for received files if present in the YMODEM Xheader; they are included in the headers for transmitted files. X.PP XThe "KMD/IMP" record count field in the YMODEM header is both set and read. X.SH EXAMPLES XTo receive a text file transmitted from a micro (using CRC-16 Xerror-checking) and store it under the Xname X.IR file.name , Xuse the command line X.RS X.B "xmodem rtc file.name" X.RE XNote that if the transmitting program on the micro uses the 1K packet Xprotocol or either batch protocol, X.I xmodem Xdetects this automatically and takes appropriate action. Further Xnote that if one of the batch protocols is used, the received file(s) Xwill be stored under their own names and the name on the command line X(if any) will be ignored. X.PP XTo send a set of text files to a microcomputer using 1K packets and the XYMODEM batch protocol, use the command line X.RS X.B "xmodem styk *.txt" X.RE X.SH FILES Xxmodem.log (if logging is enabled) X.SH BUGS XBatch mode could be smarter about bad file-names in the midst of a Xbatch transmit/receive. X.PP XBatch mode could allow a mixture of binary and text files. X.PP XBare Carriage Return characters (i.e., those not immediately followed by a XLine Feed character) are mishandled in a received file when using text mode. XA file with ``overstruck'' lines will thus come out looking funny. X.PP XYMODEM header packets are only sent as 128 byte packets. Thus VERY long file Xnames will not be handled properly. X.SH SEE ALSO Xkermit(1) X.SH AUTHOR XSteve Grandi, National Optical Astronomy Observatories. Based on X.I xmodem Xby Brian Kantor, University of California at San Diego. XThis, in turn, was based on X.I umodem Xby Lauren Weinstein, Richard Conn and others. SHAR_EOF chmod 0644 xmodem.1 || echo "restore of xmodem.1 fails" echo "x - extracting xmodem.c (Text)" sed 's/^X//' << 'SHAR_EOF' > xmodem.c && X/* X * XMODEM -- Implements the Christensen XMODEM protocol, X * for packetized file up/downloading. X * X * See the README file for some notes on SYS V adaptations. X * The program has been successfully run on VAXes (4.3BSD) and SUN-3/4s X * (SunOS 3.x) against MEX-PC and ZCOMM/DSZ. X * X * See the README and update.doc files for history and change notes. X * X * Please send bug fixes, additions and comments to: X * {ihnp4,ncar}!noao!grandi grandi@noao.arizona.edu X */ X X#include "xmodem.h" X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char *getenv(); X FILE *fopen(); X char *unix_cpm(); X char *strcpy(); X char *strcat(); X char *prtype(); X X char *fname = filename; /* convenient place to stash file names */ X char *logfile = "xmodem.log"; /* Name of LOG File */ X X char *stamptime(); /* for timestamp */ X X char *defname = "xmodem.in"; /* default file name if none given */ X X struct stat filestatbuf; /* file status info */ X X int index; X char flag; X long expsect; X X /* initialize option flags */ X X XMITTYPE = 't'; /* assume text transfer */ X DEBUG = FALSE; /* keep debugging info in log */ X RECVFLAG = FALSE; /* not receive */ X SENDFLAG = FALSE; /* not send either */ X BATCH = FALSE; /* nor batch */ X CRCMODE = FALSE; /* use checksums for now */ X DELFLAG = FALSE; /* don't delete old log file */ X LOGFLAG = TRUE; /* keep log */ X LONGPACK = FALSE; /* do not use long packets on transmit */ X MDM7BAT = FALSE; /* no MODEM7 batch mode */ X YMDMBAT = FALSE; /* no YMODEM batch mode */ X TOOBUSY = FALSE; /* not too busy for sleeping in packet read */ X X fprintf(stderr, "XMODEM Version %d.%d", VERSION/10, VERSION%10); X fprintf(stderr, " -- UNIX-Microcomputer Remote File Transfer Facility\n"); X X if (argc == 1) X { X help(); X exit(-1); X } X X index = 0; /* set index for flag loop */ X X while ((flag = argv[1][index++]) != '\0') X switch (flag) { X case '-' : break; X case 'X' : X case 'x' : DEBUG = TRUE; /* turn on debugging log */ X break; X case 'C' : X case 'c' : CRCMODE = TRUE; /* enable CRC on receive */ X break; X case 'D' : X case 'd' : DELFLAG = TRUE; /* delete log file */ X break; X case 'L' : X case 'l' : LOGFLAG = FALSE; /* turn off log */ X break; X case 'm' : X case 'M' : MDM7BAT = TRUE; /* turn on MODEM7 batch protocol */ X BATCH = TRUE; X break; X case 'y' : X case 'Y' : YMDMBAT = TRUE; /* turn on YMODEM batch protocol */ X BATCH = TRUE; X break; X case 'k' : X case 'K' : LONGPACK = TRUE; /* use 1K packets on transmit */ X break; X case 't' : X case 'T' : TOOBUSY = TRUE; /* turn off sleeping */ X break; X case 'R' : X case 'r' : RECVFLAG = TRUE; /* receive file */ X XMITTYPE = gettype(argv[1][index++]); /* get t/b */ X break; X case 'S' : X case 's' : SENDFLAG = TRUE; /* send file */ X XMITTYPE = gettype(argv[1][index++]); X break; X default : fprintf(stderr, "Invalid Flag %c ignored\n", flag); X break; X } X X if (DEBUG) X LOGFLAG = TRUE; X X if (LOGFLAG) X { X if ((fname = getenv("HOME")) == 0) /* Get HOME variable */ X error("Fatal - Can't get Environment!", FALSE); X fname = strcat(fname, "/"); X fname = strcat(fname, logfile); X if (!DELFLAG) X LOGFP = fopen(fname, "a"); /* append to LOG file */ X else X LOGFP = fopen(fname, "w"); /* new LOG file */ X if (!LOGFP) X error("Fatal - Can't Open Log File", FALSE); X X fprintf(LOGFP,"\n++++++++ %s", stamptime()); X fprintf(LOGFP,"XMODEM Version %d.%d\n", VERSION/10, VERSION%10); X fprintf(LOGFP,"Command line: %s %s", argv[0], argv[1]); X for (index=2; index<argc; ++index) X fprintf(LOGFP, " %s", argv[index]); X fprintf(LOGFP, "\n"); X } X X getspeed(); /* get tty-speed for time estimates */ X X if (RECVFLAG && SENDFLAG) X error("Fatal - Both Send and Receive Functions Specified", FALSE); X X if (MDM7BAT && YMDMBAT) X error("Fatal - Both YMODEM and MODEM7 Batch Protocols Specified", FALSE); X X if (!RECVFLAG && !SENDFLAG) X error("Fatal - Either Send or Receive Function must be chosen!",FALSE); X X if (SENDFLAG && argc==2) X error("Fatal - No file specified to send",FALSE); X X if (RECVFLAG && argc==2) X { X /* assume we really want CRC-16 in batch, unless we specify MODEM7 mode */ X CRCMODE = MDM7BAT ? FALSE : TRUE; X fprintf(stderr, "Ready for BATCH RECEIVE"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logit("Batch Receive Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X strcpy(fname, defname); X } X X if (RECVFLAG && argc>2) X { X if(open(argv[2], 0) != -1) /* check for overwriting */ X { X logit("Warning -- Target File Exists and is Being Overwritten\n"); X fprintf(stderr, "Warning -- Target File Exists and is Being Overwritten\n"); X } X fprintf(stderr, "Ready to RECEIVE File %s", argv[2]); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logitarg("Receiving in %s mode\n", prtype(XMITTYPE)); X strcpy(fname,argv[2]); X } X X if (RECVFLAG) X { X setmodes(); /* set tty modes for transfer */ X X while(rfile(fname) != FALSE); /* receive files */ X X flushin(); X restoremodes(FALSE); /* restore normal tty modes */ X X sleep(2); /* give other side time to return to terminal mode */ X exit(0); X } X X if (SENDFLAG && BATCH) X { X if (YMDMBAT) X { X fprintf(stderr, "Ready to YMODEM BATCH SEND"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X logit("YMODEM Batch Send Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X } X else if (MDM7BAT) X { X fprintf(stderr, "Ready to MODEM7 BATCH SEND"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X logit("MODEM7 Batch Send Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X } X fprintf(stderr, "Send several Control-X characters to cancel\n"); X X setmodes(); X for (index=2; index<argc; index++) { X if (stat(argv[index], &filestatbuf) < 0) { X logitarg("\nFile %s not found\n", argv[index]); X continue; X } X sfile(argv[index]); X } X sfile(""); X flushin(); X restoremodes(FALSE); X X logit("Batch Send Complete\n"); X sleep(2); X exit (0); X } X X if (SENDFLAG && !BATCH) X { X if (stat(argv[2], &filestatbuf) < 0) X error("Can't find requested file", FALSE); X expsect = (filestatbuf.st_size/128)+1; X X fprintf(stderr, "File %s Ready to SEND", argv[2]); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Estimated File Size %ldK, %ld Sectors, %ld Bytes\n", X (filestatbuf.st_size/1024)+1, expsect, X filestatbuf.st_size); X projtime(expsect, stdout); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logitarg("Sending in %s mode\n", prtype(XMITTYPE)); X X setmodes(); X sfile(argv[2]); X flushin(); X restoremodes(FALSE); X X sleep(2); X exit(0); X } X} SHAR_EOF chmod 0644 xmodem.c || echo "restore of xmodem.c fails" echo "x - extracting xmodem.h (Text)" sed 's/^X//' << 'SHAR_EOF' > xmodem.h && X#include <ctype.h> X#include <stdio.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/time.h> X#include <sgtty.h> X#include <signal.h> X X/* define macros to print messages in log file */ X#define logit(string) if(LOGFLAG)fprintf(LOGFP,string) X#define logitarg(string,argument) if(LOGFLAG)fprintf(LOGFP,string,argument) X X#define VERSION 36 /* Version Number */ X#define FALSE 0 X#define TRUE 1 X X X/* ASCII Constants */ X#define SOH 001 X#define STX 002 X#define ETX 003 X#define EOT 004 X#define ENQ 005 X#define ACK 006 X#define LF 012 /* Unix LF/NL */ X#define CR 015 X#define NAK 025 X#define SYN 026 X#define CAN 030 X#define ESC 033 X X/* XMODEM Constants */ X#define TIMEOUT -1 X#define ERRORMAX 10 /* maximum errors tolerated while transferring a packet */ X#define WAITFIRST 1 /* seconds between startup characters in read */ X#define STERRORMAX 60 /* maximum "errors" tolerated in read startup */ X#define CRCSWMAX 30 /* maximum time to try CRC mode before switching */ X#define NAKMAX 120 /* maximum times to wait for initial NAK when sending */ X#define RETRYMAX 5 /* maximum retries to be made certain handshaking routines */ X#define KSWMAX 5 /* maximum errors before switching to 128 byte packets */ X#define EOTMAX 10 /* maximum times sender will send an EOT to end transfer */ X#define SLEEPNUM 100 /* target number of characters to collect during sleepy time */ X#define BBUFSIZ 1024 /* buffer size */ X#define NAMSIZ 11 /* length of a CP/M file name string */ X#define CTRLZ 032 /* CP/M EOF for text (usually!) */ X#define CRCCHR 'C' /* CRC request character */ X#define KCHR 'K' /* 1K block request character */ X#define BAD_NAME 'u' /* Bad filename indicator */ X X#define CREATMODE 0644 /* mode for created files */ X X/* GLOBAL VARIABLES */ X Xint ttyspeed; /* tty speed (bits per second) */ Xunsigned char buff[BBUFSIZ]; /* buffer for data */ Xint nbchr; /* number of chars read so far for buffered read */ Xlong filelength; /* length specified in YMODEM header */ Xlong fileread; /* characters actually read so far in file */ Xchar filename[256]; /* place to construct filenames */ XFILE *LOGFP; /* descriptor for LOG file */ X X/* option flags and state variables */ Xchar XMITTYPE; /* text or binary? */ Xint DEBUG; /* keep debugging info in log? */ Xint RECVFLAG; /* receive? */ Xint SENDFLAG; /* send? */ Xint BATCH; /* batch? (Now used as a state variable) */ Xint CRCMODE; /* CRC or checksums? */ Xint DELFLAG; /* don't delete old log file? */ Xint LOGFLAG; /* keep log? */ Xint LONGPACK; /* do not use long packets on transmit? */ Xint MDM7BAT; /* MODEM7 batch protocol */ Xint YMDMBAT; /* YMODEM batch protocol */ Xint TOOBUSY; /* turn off sleeping in packet read routine */ Xint CHECKLENGTH; /* Are we truncating a file to a YMODEM length? */ X X X/* CRC-16 constants. From Usenet contribution by Mark G. Mendel, X Network Systems Corp. (ihnp4!umn-cs!hyper!mark) X*/ X X /* the CRC polynomial. */ X#define P 0x1021 X X /* number of bits in CRC */ X#define W 16 X X /* the number of bits per char */ X#define B 8 SHAR_EOF chmod 0644 xmodem.h || echo "restore of xmodem.h fails" rm -f s2_seq_.tmp echo "You have unpacked the last part" exit 0 -- Keith Petersen Arpa: W8SDZ@SIMTEL20.ARPA Uucp: {bellcore,decwrl,harvard,lll-crg,ucbvax,uw-beaver}!simtel20.arpa!w8sdz GEnie: W8SDZ
w8sdz@brl-smoke.arpa (Keith B. Petersen ) (06/02/88)
This is version 3.6 (finished 4/88) of Steve Grandi's 4.2/4.3 BSD Unix xmodem program which includes a few bugfixes and some enhancements (requested by Macintosh users) stimulated by the xmodem release through comp.sources.unix. See the file update.doc for details. ---- Cut Here and unpack ---- #!/bin/sh # this is part 2 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file send.c continued # CurArch=2 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file send.c" sed 's/^X//' << 'SHAR_EOF' >> send.c X fprintf(LOGFP,"File Size %ldK, %ld Records, %ld Bytes\n", X (filestatbuf.st_size/1024)+1, expsect, filestatbuf.st_size); X projtime(expsect, LOGFP); X } X } X else X { X logit("----\nXMODEM Send Function\n"); X logit("Closing down Batch Transmission\n"); X } X X X bufsize = buf1024 ? 1024 : 128; /* set sector size */ X if (buf1024 && !closeout) X logit("1K packet mode chosen\n"); X X sendfin = nlflag = FALSE; X attempts = 0; X X /* wait for and read startup character */ Xrestart: X do X { X while (((firstchar=readbyte(1)) != NAK) && (firstchar != CRCCHR) && (firstchar != CAN)) X if (++attempts > NAKMAX) X { X if (MDM7BAT && startup) X { X sendbyte(ACK); sendbyte(EOT); X } X error("Remote System Not Responding", TRUE); X } X X if ((firstchar & 0x7f) == CAN) X if (readbyte(3) == CAN) X error("Send cancelled at user's request",TRUE); X X if (firstchar == CRCCHR) X { X CRCMODE = TRUE; X if (!closeout) X logit("CRC mode requested\n"); X if (readbyte(1) == KCHR) X { X buf1024 = TRUE; X logit("Receiver invoked 1K packet mode\n"); X } X } X } X while (firstchar != NAK && firstchar != CRCCHR); X X if (MDM7BAT && closeout) /* close out MODEM7 batch */ X { X sendbyte(ACK); sendbyte (EOT); X flushin(); readbyte(2); /* flush junk */ X return; X } X X if (MDM7BAT && startup) /* send MODEM7 file name */ X { X if (send_name(unix_cpm(name)) == -1) X { X attempts = 0; X goto restart; X } X startup = FALSE; X attempts = 0; X goto restart; X } X X sectnum = 1; X X if (YMDMBAT) /* Fudge for YMODEM transfer (to send name packet) */ X { X sectnum = 0; X bufsize = 128; X filepack = TRUE; X } X X attempts = sentsect = 0; X start = time((time_t *) 0); X X do /* outer packet building/sending loop; loop till whole file is sent */ X { X X if (closeout && YMDMBAT && sectnum == 1) /* close out YMODEM */ X return; X X if (YMDMBAT && sectnum == 1) /* get set to send YMODEM data packets */ X { X bufsize = buf1024 ? 1024 : 128; X X do /* establish handshaking again */ X { X while (((firstchar=readbyte(2)) != CRCCHR) && (firstchar != NAK) && (firstchar != CAN)) X if (++attempts > ERRORMAX) X error("YMODEM protocol botch, C expected", TRUE); X if ((firstchar&0x7f) == CAN) X if (readbyte(3) == CAN) X error("Send cancelled at User's request", TRUE); X } X while ((firstchar != CRCCHR) && (firstchar != NAK)); X X attempts = 0; X } X X if ((bufsize == 1024) && (attempts > KSWMAX)) X { X logit("Reducing packet size to 128 due to excessive errors\n"); X bufsize = 128; X } X X if ((bufsize == 1024) && ((expsect - sentsect) < 8)) X { X logit("Reducing packet size to 128 for tail end of file\n"); X bufsize = 128; X } X X if (sectnum > 0) /* data packet */ X { X for (bufctr=0; bufctr < bufsize;) X { X if (nlflag) X { X buff[bufctr++] = LF; /* leftover newline */ X nlflag = FALSE; X } X if (getbyte(fd, &c) == EOF) X { X sendfin = TRUE; /* this is the last sector */ X if (!bufctr) /* if EOF on sector boundary */ X break; /* avoid sending extra sector */ X buff[bufctr++] = CTRLZ; /* pad with Ctrl-Z for CP/M EOF (even do for binary files) */ X continue; X } X X if (tmode && c == LF) /* text mode & Unix newline? */ X { X buff[bufctr++] = CR; /* insert carriage return */ X if (bufctr < bufsize) X buff[bufctr++] = LF; /* insert LF */ X else X nlflag = TRUE; /* insert on next sector */ X } X else if (amode && c == LF) /* Apple mode & Unix newline? */ X buff[bufctr++] = CR; /* substitute CR */ X else X buff[bufctr++] = c; /* copy the char without change */ X } X X if (!bufctr) /* if EOF on sector boundary */ X break; /* avoid sending empty sector */ X } X X else /* YMODEM filename packet */ X { X for (bufctr=0; bufctr<bufsize; bufctr++) /* zero packet */ X buff[bufctr]=0; X if (!closeout) X { X strcpy((char *)buff, cpmify(name)); X X /* put in file name, length, mode */ X { X register char *p; X p = (char *)buff + strlen(name) + 1; X sprintf(p, "%lu %lo %o", filestatbuf.st_size, X filestatbuf.st_mtime, filestatbuf.st_mode); X if (DEBUG) X fprintf(LOGFP, "DEBUG: YMODEM header information: %s\n", p); X } X buff[bufsize-2] = (expsect & 0xff); /* put in KMD kludge information */ X buff[bufsize-1] = ((expsect >> 8) & 0xff); X } X } X X bbufcnt = 0; /* start building block to be sent */ X blockbuf[bbufcnt++] = (bufsize == 1024) ? STX : SOH; /* start of packet char */ X blockbuf[bbufcnt++] = sectnum; /* current sector # */ X blockbuf[bbufcnt++] = ~sectnum; /* and its complement */ X X checksum = 0; /* initialize checksum */ X for (bufctr=0; bufctr < bufsize; bufctr++) X { X blockbuf[bbufcnt++] = buff[bufctr]; X X if (CRCMODE) X checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buff[bufctr]]; X X else X checksum = ((checksum+buff[bufctr]) & 0xff); X } X X if (CRCMODE) /* put in CRC */ X { X checksum &= 0xffff; X blockbuf[bbufcnt++] = ((checksum >> 8) & 0xff); X blockbuf[bbufcnt++] = (checksum & 0xff); X } X else /* put in checksum */ X blockbuf[bbufcnt++] = checksum; X X attempts = 0; X X do /* inner packet loop */ X { X X writebuf(blockbuf, bbufcnt); /* write the block */ X flushin(); /* purge anything in input queue */ X X if (DEBUG) X fprintf (LOGFP, "DEBUG: %d byte Packet %02xh (%02xh) sent, checksum %02xh %02xh\n", X bbufcnt, blockbuf[1]&0xff, blockbuf[2]&0xff, blockbuf[bufsize+3]&0xff, blockbuf[bufsize+4]&0xff); X X attempts++; X sendresp = readbyte(10); /* get response from remote */ X X if (sendresp != ACK) X { X if (sendresp == TIMEOUT) X { X logitarg("Timeout on sector %s\n",sectdisp(sentsect,bufsize,1)); X } X else if (sendresp == NAK) X { X logitarg("NAK on sector %s\n",sectdisp(sentsect,bufsize,1)); X } X else X { X logitarg("Non-ACK on sector %s\n",sectdisp(sentsect,bufsize,1)); X } X } X } X while((sendresp != ACK) && (attempts < ERRORMAX)); /* close of inner loop */ X X sectnum++; /* increment to next sector number */ X if (!filepack) X sentsect += (bufsize == 128) ? 1 : 8; X filepack = FALSE; X } X while (!sendfin && ( attempts < ERRORMAX)); /* end of outer loop */ X X if (attempts >= ERRORMAX) X { X sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); sendbyte(CAN); X error ("Too many errors in transmission", TRUE); X } X X attempts = 0; X sendbyte(EOT); /* send 1st EOT to close down transfer */ X X while ((readbyte(15) != ACK) && (attempts++ < EOTMAX)) /* wait for ACK of EOT */ X { X if (attempts > 1) X logitarg("EOT not ACKed, try %d\n", attempts); X sendbyte(EOT); X } X X if (attempts >= RETRYMAX) X error("Remote System Not Responding on Completion", TRUE); X X close(fd); X X logit("Send Complete\n"); X prtime(sentsect, time((time_t *) 0) - start); X } SHAR_EOF echo "File send.c is complete" chmod 0644 send.c || echo "restore of send.c fails" echo "x - extracting tip.diffs (Text)" sed 's/^X//' << 'SHAR_EOF' > tip.diffs && X X*** cmdtab.c.ORIG Mon May 5 11:01:59 1986 X--- cmdtab.c Thu Aug 21 10:08:50 1986 X*************** X*** 15,16 **** X--- 15,17 ---- X extern int cu_take(), cu_put(), dollar(), genbrk(), suspend(); X+ extern int rtfile(), stfile(), rbfile(), sbfile(); X X*************** X*** 35,36 **** X--- 36,41 ---- X { '#', NORM, "send break", genbrk }, X+ { '{', NORM, "receive xmodem text file", rtfile }, X+ { '}', NORM, "send xmodem text file", stfile }, X+ { '(', NORM, "receive xmodem binary file", rbfile }, X+ { ')', NORM, "send xmodem binary file", sbfile }, X { 0, 0, 0 } X X X X*** cmds.c.ORIG Mon May 5 11:01:56 1986 X--- cmds.c Tue Sep 30 10:17:11 1986 X*************** X*** 855,856 **** X--- 865,1412 ---- X return(0); X+ } X+ X+ X+ /* XMODEM stuff; sag sept 1984 - Feb 1985 X+ * Taken from Brian Kantor's (sdccsu3!brian) xmodem version 1.0 X+ * Note that this code will work on version 4.2 ONLY (uses select) X+ */ X+ X+ #include <sys/stat.h> X+ #include <sys/time.h> X+ X+ /* ASCII Constants */ X+ #define SOH 001 X+ #define STX 002 X+ #define ETX 003 X+ #define EOT 004 X+ #define ENQ 005 X+ #define ACK 006 X+ #define LF 012 /* Unix LF/NL */ X+ #define CR 015 X+ #define NAK 025 X+ #define SYN 026 X+ #define CAN 030 X+ #define ESC 033 X+ #define CTRLZ 032 /* CP/M EOF for text (usually!) */ X+ X+ /* XMODEM Constants */ X+ #define TIMEOUT -1 X+ #define ERRORMAX 10 /* maximum errors tolerated */ X+ #define RETRYMAX 10 /* maximum retries to be made */ X+ #define BBUFSIZ 128 /* buffer size -- do not change! */ X+ #define DEBUG 0 /* 1 for debugging output */ X+ #define GETERR -10 /* error code for getbyte routine */ X+ X+ char buff[BBUFSIZ]; X+ X+ int nbchr; /* number of chars read so far for buffered read */ X+ X+ /* Receive a text file */ X+ rtfile(c) X+ char c; X+ { X+ putchar (c); X+ rfile ('t'); X+ } X+ X+ /* Receive a binary file */ X+ rbfile(c) X+ char c; X+ { X+ putchar (c); X+ rfile ('b'); X+ } X+ X+ /* Send a text file */ X+ stfile(c) X+ char c; X+ { X+ putchar (c); X+ sfile ('t'); X+ } X+ X+ /* Send a binary file */ X+ sbfile(c) X+ char c; X+ { X+ putchar (c); X+ sfile ('b'); X+ } X+ X+ /* print error message and cleanup for exit */ X+ error(msg) X+ char *msg; X+ { X+ printf("\r\nXMODEM: %s\n", msg); X+ ioctl (0, TIOCSETC, &tchars); X+ write (fildes[1], (char *)&ccc, 1); X+ signal (SIGINT, SIG_DFL); X+ } X+ X+ /* X+ * X+ * Get a byte from the specified file. Buffer the read so we don't X+ * have to use a system call for each character. X+ * X+ */ X+ getbyte(fildes, ch) /* Buffered disk read */ X+ int fildes; X+ char *ch; X+ X+ { X+ static char buf[BUFSIZ]; /* Remember buffer */ X+ static char *bufp = buf; /* Remember where we are in buffer */ X+ X+ if (nbchr == 0) /* Buffer exausted; read some more */ X+ { X+ if ((nbchr = read(fildes, buf, BUFSIZ)) < 0) X+ { X+ error("File Read Error"); X+ return (GETERR); X+ } X+ bufp = buf; /* Set pointer to start of array */ X+ } X+ if (--nbchr >= 0) X+ { X+ *ch = *bufp++; X+ return(0); X+ } X+ else X+ return(EOF); X+ } X+ X+ /** receive a file **/ X+ rfile(mode) X+ char mode; X+ { X+ register int bufctr, checksum; X+ register int c; X+ int j, firstchar, sectnum, sectcurr, tmode; X+ int sectcomp, errors, errorflag, recfin; X+ int fatalerror, inchecksum; X+ long recvsectcnt; X+ X+ int (*f) (); X+ char *cp, *expand(); X+ time_t start; X+ X+ if (prompt (" Receive local file name? ", copyname)) X+ return; X+ cp = expand (copyname); X+ if ((sfd = creat (cp, 0666)) < 0) X+ { X+ printf ("\r\n%s: Cannot creat\r\n", copyname); X+ return; X+ } X+ X+ kill (pid, SIGIOT); X+ read (repdes[0], (char *)&ccc, 1); /* wait until read process stops */ X+ ioctl (0, TIOCSETC, &defchars); /* set tty modes */ X+ f = signal (SIGINT, intcopy); /* intercept control-c */ X+ X+ start = time(0); X+ quit = 0; X+ (void) setjmp(intbuf); /* set control-c catcher */ X+ X+ if (quit) X+ { X+ error("Control-C; Reception canceled"); X+ close (sfd); X+ return; X+ } X+ X+ printf("XMODEM: Ready to RECEIVE File %s", cp); X+ puts("\r\nControl-C to cancel.\n"); X+ X+ recfin = FALSE; X+ sectnum = errors = 0; X+ fatalerror = FALSE; /* NO fatal errors */ X+ recvsectcnt = 0; /* number of received sectors */ X+ X+ if (mode == 't') X+ tmode = TRUE; X+ else X+ tmode = FALSE; X+ X+ sendbyte(NAK); /* Start up the sender's first block */ X+ X+ do X+ { X+ errorflag = FALSE; X+ do X+ { X+ firstchar = readbyte(6); X+ } X+ while ((firstchar != SOH) X+ && (firstchar != EOT) X+ && (firstchar != TIMEOUT) X+ && ((firstchar & 0x7f) != CAN)); X+ X+ if (firstchar == TIMEOUT) X+ { X+ printf("\r\nTimeout on Sector %d\n", sectnum+1); X+ errorflag = TRUE; X+ } X+ X+ if ((firstchar & 0x7f) == CAN) X+ { X+ error("Reception canceled at user's request"); X+ close (sfd); X+ return; X+ } X+ X+ if (firstchar == SOH) X+ { X+ sectcurr = readbyte(3); /* get sector numbers */ X+ sectcomp = readbyte(3); X+ if ((sectcurr + sectcomp) == 0xff) X+ { X+ if (sectcurr == ((sectnum+1) & 0xff)) X+ { X+ checksum = 0; X+ for (j = bufctr = 0; j < BBUFSIZ; j++) X+ { X+ buff[bufctr] = c = readbyte(3); X+ checksum = ((checksum+c) & 0xff); X+ if (!tmode) /* binary mode */ X+ { X+ bufctr++; X+ continue; X+ } X+ if (c == CR) X+ continue; /* skip CR's */ X+ if (c == CTRLZ) /* CP/M EOF char */ X+ { X+ recfin = TRUE; /* flag EOF */ X+ continue; X+ } X+ if (!recfin) X+ bufctr++; X+ } X+ inchecksum = readbyte(3); /* get checksum */ X+ if (checksum == inchecksum) /* good checksum */ X+ { X+ errors = 0; X+ recvsectcnt++; X+ sectnum = sectcurr; X+ if (DEBUG) printf ("\n"); X+ printf ("\rreceived sector %-4d", recvsectcnt); X+ if (write(sfd, buff, bufctr) < 0) X+ { X+ sendbyte(CAN); X+ error("File Write Error"); X+ close (sfd); X+ return; X+ } X+ else X+ sendbyte(ACK); X+ X+ } X+ else X+ { X+ printf("\r\nChecksum Error on Sector %d\n", sectnum+1); X+ errorflag = TRUE; X+ } X+ } X+ else X+ { X+ if (sectcurr == sectnum) X+ { X+ while(readbyte(3) != TIMEOUT) X+ ; X+ sendbyte(ACK); X+ } X+ else X+ { X+ printf("\r\nPhase Error - Received Sector is "); X+ printf("%d while Expected Sector is %d\n", X+ sectcurr, ((sectnum+1) & 0xff)); X+ errorflag = TRUE; X+ fatalerror = TRUE; X+ sendbyte(CAN); X+ } X+ } X+ } X+ else X+ { X+ printf("\r\nHeader Sector Number Error on Sector %d\n", X+ sectnum+1); X+ errorflag = TRUE; X+ } X+ } X+ X+ if (errorflag) X+ { X+ errors++; X+ while (readbyte(3) != TIMEOUT) X+ ; X+ sendbyte(NAK); X+ } X+ } X+ while ((firstchar != EOT) && (errors < ERRORMAX) && !fatalerror); X+ X+ if ((firstchar == EOT) && (errors < ERRORMAX) && !fatalerror) X+ { X+ close(sfd); X+ sendbyte(ACK); X+ printf("\n\rReceive Complete"); X+ printf("\n\r%ld CP/M Records ", recvsectcnt); X+ prtime(" transferred in ", time(0)-start); X+ X+ ioctl (0, TIOCSETC, &tchars); /* reset ttys */ X+ write (fildes[1], (char *)&ccc, 1); /* wakeup tip */ X+ signal (SIGINT, SIG_DFL); /* reset control-c catcher */ X+ } X+ else X+ { X+ sendbyte(CAN); X+ error("\r\nABORTED -- Too Many Errors"); X+ close (sfd); X+ return; X+ } X+ } X+ X+ /** send a file **/ X+ sfile(mode) X+ char mode; X+ { X+ register int bufctr, checksum, sectnum; X+ char blockbuf[134]; X+ int fd, attempts; X+ int nlflag, sendfin, tmode; X+ int bbufcnt; X+ int firstchar; X+ int getretrn; X+ char c; X+ int sendresp; /* response char to sent block */ X+ X+ int (*f) (); X+ char *cp, *expand(); X+ time_t start; X+ X+ if (prompt (" Send local file name? ", copyname)) X+ return; X+ cp = expand (copyname); X+ if ((fd = open(cp, 0)) < 0) X+ { X+ printf("Can't open file for send\n"); X+ return; X+ } X+ X+ kill (pid, SIGIOT); X+ read (repdes[0], (char *)&ccc, 1); /* wait until read process stops */ X+ ioctl (0, TIOCSETC, &defchars); /* setup tty */ X+ f = signal (SIGINT, intcopy); /* prepare to catch control-c */ X+ start = time(0); X+ quit = 0; X+ (void) setjmp(intbuf); /* setup control-c catcher */ X+ X+ nbchr = 0; /* clear buffered read char count */ X+ X+ if (quit) X+ { X+ sendbyte(CAN); X+ error("Control-C; Send canceled"); X+ close (fd); X+ return; X+ } X+ X+ printf("XMODEM: File %s Ready to SEND", cp); X+ prfilestat(cp); /* print file size statistics */ X+ puts("\r\nControl-C to cancel.\n"); X+ X+ if (mode == 't') X+ tmode = TRUE; X+ else X+ tmode = FALSE; X+ X+ sendfin = nlflag = FALSE; X+ attempts = 0; X+ X+ while (((firstchar=readbyte(30)) != NAK) && (firstchar != CAN)) X+ { X+ if (++attempts > RETRYMAX) { X+ error("Remote System Not Responding"); X+ close (fd); X+ return; X+ } X+ } X+ X+ if ((firstchar & 0x7f) == CAN) X+ { X+ error("Send cancelled at user's request."); X+ close (fd); X+ return; X+ } X+ X+ sectnum = 1; /* first sector number */ X+ attempts = 0; X+ X+ do X+ { X+ for (bufctr=0; bufctr < BBUFSIZ;) X+ { X+ if (nlflag) X+ { X+ buff[bufctr++] = LF; /* leftover newline */ X+ nlflag = FALSE; X+ } X+ getretrn = getbyte(fd, &c); X+ if (getretrn == GETERR) X+ { X+ sendbyte(CAN); X+ error ("Read error on local file"); X+ close (fd); X+ return; X+ } X+ if (getretrn == EOF) X+ { X+ sendfin = TRUE; /* this is the last sector */ X+ if (!bufctr) /* if EOF on sector boundary */ X+ break; /* avoid sending extra sector */ X+ if (tmode) X+ buff[bufctr++] = CTRLZ; /* Control-Z for CP/M EOF */ X+ else X+ bufctr++; X+ continue; X+ } X+ X+ if (tmode && c == LF) /* text mode & Unix newline? */ X+ { X+ buff[bufctr++] = CR; /* insert carriage return */ X+ if (bufctr < BBUFSIZ) X+ buff[bufctr++] = LF; /* insert LF */ X+ else X+ nlflag = TRUE; /* insert on next sector */ X+ } X+ else X+ buff[bufctr++] = c; /* copy the char without change */ X+ } X+ X+ attempts = 0; X+ X+ if (!bufctr) /* if EOF on sector boundary */ X+ break; /* avoid sending empty sector */ X+ X+ do X+ { X+ bbufcnt = 0; /* start building block to be sent */ X+ blockbuf[bbufcnt++] = SOH; /* start of packet char */ X+ blockbuf[bbufcnt++] = sectnum; /* current sector # */ X+ blockbuf[bbufcnt++] = -sectnum-1; /* and its complement */ X+ X+ checksum = 0; /* init checksum */ X+ for (bufctr=0; bufctr < BBUFSIZ; bufctr++) X+ { X+ blockbuf[bbufcnt++] = buff[bufctr]; X+ checksum = ((checksum+buff[bufctr]) & 0xff); X+ } X+ X+ blockbuf[bbufcnt++] = checksum; X+ write(FD, blockbuf, 132); /* write the block */ X+ ioctl(FD,TIOCFLUSH,0); X+ X+ attempts++; X+ sendresp = readbyte(10); /* get response */ X+ if (sendresp != ACK) X+ { X+ printf("\r\nNon-ACK Received on Sector %d\n",sectnum); X+ if (sendresp == TIMEOUT) X+ printf("\r\nThis Non-ACK was a TIMEOUT\n"); X+ } X+ } X+ while((sendresp != ACK) && (attempts < RETRYMAX)); X+ X+ sectnum++; /* increment to next sector number */ X+ if (DEBUG) printf ("\n"); X+ printf ("\rsent sector %-4d", sectnum-1); X+ } X+ while (!sendfin && (attempts < RETRYMAX)); X+ X+ if (attempts >= RETRYMAX) X+ { X+ error("Remote System Not Responding"); X+ close (fd); X+ return; X+ } X+ X+ attempts = 0; X+ sendbyte(EOT); /* send 1st EOT */ X+ X+ while ((readbyte(15) != ACK) && (attempts++ < RETRYMAX)) X+ sendbyte(EOT); X+ X+ if (attempts >= RETRYMAX) X+ error("Remote System Not Responding on Completion"); X+ X+ close(fd); X+ printf("\r\nSend Complete\r\n"); X+ prtime("Data transferred in ", time(0)-start); X+ X+ ioctl (0, TIOCSETC, &tchars); /* restore tty */ X+ write (fildes[1], (char *)&ccc, 1); /* wakeup tip */ X+ signal (SIGINT, SIG_DFL); /* reset control-c catcher */ X+ sleep(5); /* give other side time to return to terminal mode */ X+ X+ } X+ X+ /* print file size status information */ X+ prfilestat(name) X+ char *name; X+ { X+ struct stat filestatbuf; /* file status info */ X+ X+ stat(name, &filestatbuf); /* get file status bytes */ X+ printf("\r\nEstimated File Size %ldK, %ld Records, %ld Bytes", X+ (filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1, X+ filestatbuf.st_size); X+ return; X+ } X+ X+ /* get a byte from data stream -- timeout if "seconds" elapses */ X+ int readbyte(seconds) X+ int seconds; X+ { X+ int i, readfd; X+ char c; X+ struct timeval tmout; X+ X+ tmout.tv_sec = seconds; X+ tmout.tv_usec = 0; X+ X+ readfd = 1 << FD; X+ X+ if ((i=select(FD+1, &readfd, 0, 0, &tmout)) == 0) X+ { X+ return(TIMEOUT); X+ } X+ X+ read(FD, &c, 1); X+ X+ return(c & 0xff); /* return the char */ X+ } X+ X+ /* send a byte to data stream */ X+ sendbyte(data) X+ char data; X+ { X+ write(FD, &data, 1); /* write the byte */ X+ ioctl(FD,TIOCFLUSH,0); /* flush so it really happens now! */ X+ return; X+ } X+ X+ /* X+ * "nap" for specified time X+ */ X+ nap (milliseconds) X+ int milliseconds; X+ { X+ struct timeval timeout; X+ X+ if (milliseconds == 0) X+ return; X+ timeout.tv_sec = 0; X+ timeout.tv_usec = milliseconds * 1000; X+ X+ (void) select(1, 0, 0, 0, &timeout); X } SHAR_EOF chmod 0644 tip.diffs || echo "restore of tip.diffs fails" echo "x - extracting update.doc (Text)" sed 's/^X//' << 'SHAR_EOF' > update.doc && XChanges leading to version 3.3 X X1) "Better" handshaking for MODEM7 batch transfers (5/19/87). X X2) If reception of a file is aborted due to errors, delete incomplete file X(5/19/87). X X3) If an "impossible" tty speed is detected, assume 1200 bps (5/19/87). X X4) Disallow CAN-CAN abort during file send or receive except at beginning of Xfile transfer (during batch transfers, CAN-CAN abort is allowed at beginning Xof each file transfer) (5/19/87). X X5) Uncouple total allowed errors during the reception of a single packet X(ERRORMAX, now made 10) and errors allowed when starting transfer (STERRORMAX, Xset to 10) (5/19/87). X X6) Fix some bugs when receiving an empty file and when a phase error occurs Xduring a file reception (5/19/87). X X7) Portability fix in prtime and projtime; they also handle pathological Xcases better (5/19/87). X X8) During file reception an EOT is not believed unless it is sent again in Xresponse to a NAK (5/25/87). X X9) Modified cpm_unix and unixify so a filename without an extension will not Xhave a trailing dot in its filename after being received in a MODEM7 or XYMODEM batch transfer (5/25/87). X X10) Allowable errors during transmission of a single packet now set to XERRORMAX (5/27/87). X X11) When transferring a binary file, the YMODEM file length field is filled Xin on transmit and (if present) used to truncate the file on reception. XA new truncate function (truncfile) added to getput.c to do the deed (5/28/87). XThe file mode field is also set but is ignored on file reception. X X12) In a batch receive (xmodem -rt), program can be forced into checksum mode Xby specifying the "M" flag indicating a MODEM7 transfer (5/30/87). X X13) Changed the "B" option to "M" to indicate MODEM7 batch. Made all option Xflags case insensitive. Command line is now recorded in the log file X(5/30/87). X X14) The "KND/IMP" convention of using "CK" to invoke 1K packets during YMODEM Xbatch transfers was installed. This code will be sent during a batch receive Xif "K" is included on the command line unless "M" is also present. This code Xwill be recognized when sending under all circumstances (5/30/87). X X------------------------------------------------------------------------------ X XChanges leading to version 3.4 X X1) Fix usage message (10/2/87). X X2) Sender will now try up to 10 times (EOTMAX) to send an EOT to terminate a Xtransmission. Used to be 5 times, but Chuck Forsberg's "official" minimum Xrequirements for YMODEM mandate 10 (10/2/87). X X3) Handle YMODEM file modification times if present in header on reception of Xboth binary and text files (10/2/87). Retracted when can't seem to get Xproper times whn playing with dsz (10/3/87). Found bug and reinstalled Xfeature (10/16/87). Found REAL bug (10/21/87). X X4) Null bytes are now stripped out of files when received as text files (MEX Xdoesn't seem to want to put in the terminating control-Z) (10/3/87). X X5) Slightly modified terminal parameter setting to explicitly turn of CRMOD Xand to flush read queue; ideas stolen from Kermit. Will it fly on Pyramid? X(10/3/87). X X6) Decreased time between "startup" characters sent when starting a file Xreceive operation. This should increase perceived response. Now waits XWAITFIRST seconds (set to 1) instead of 6 (waits for 5 seconds for Xsubsequent packets. STERRORMAX now 60, CRCSWMAX now 30. XTimeouts on 1st sector no longer reported in log (10/5/87). X X7) Once again played with kernel sleeps in readbuf() (packet reading Xroutine). On busy system could cause real problems. Now supply flag (t) to Xsuppress sleeping on Too Busy systems. No longer suppress sleep when speeds are Xover 4800 bps. Sleep kludge DOES help: on an empty 750 running 4.3BSD, a Xfile reception at 2400 bps used 6% of the CPU with the sleep kludge and 24% Xwithout it (data transfer rates were the the same) (10/5/87). X X8) Actually count characters as they are being read for a file reception. XWhen YMODEM file length is set, stop writing characters when reach length. XThis will allow YMODEM file lengths to work for text files and the Xelimination of truncfile() in getput.c (which was impossible for SYS V) X(10/5/87). X X9) Another attempt at tty modes. Now do nothing but set speeds, set mode to Xraw, and turn off echoing and tandem (10/6/87). X X------------------------------------------------------------------------------ X XChanges leading to version 3.5 X X1) Following the suggestion of Bill Carpenter (ho5cad!wjc), I changed every Xprintf("") to fprintf(stderr, "") so one can use xmodem on either end of unix Xto unix link. (3/24/88). X X2) Again, thanks to Bill Carpenter, corrected typo in stamptime() in Xgetput.sysv.c (3/24/88). X X3) Thanks to Steve Lebowitz (prcpto!pdvshl), fixed a && that should have been Xa & in getput.sysv.c (3/25/88). X X4) Thanks to Leo Pilachowski, who managed to fool xmodem by "preplacing" ACKS Xin the VAX's input queue (improves throughput by 20%, says Leo, but makes Xerror recovery a tad dicey...!). Implemented a flushin() function in Xgetput.c to flush any pending characters. flushin is called in send.c just Xafter sending a packet to make sure a proper ACK or NAK is received (I hope Xfast machines don't beat me to it and get their ACKS flushed!). In Xreceive.c, flushin is called prior to the "startup" characters, prior to Xsending the packet acknowledgment ACK and prior to the NAK prompting for Xconfirming EOT. Now how does one implement flushin() on Sys V? (3/25/88). X X5) Fixed pair of bugs in send.c: YMODEM test enforcing CRC was testing Xnumber of attempts against STERRORMAX instead of ERRORMAX (also shortened Xtimeout interval on this read) and a "timeout" during packet send was not Xnoticed (due to a > instead of a >=) thus program started sending EOTs which Xfurther delayed abort (3/28/88). X X6) Modified send.c and cpmify function in batch.c to strip path names on file Xnames transmitted as part of YMODEM batch (3/28/88). X X7) Hacked receive.c to make end of loop processing clearer and improve Xgarbage flushing when errors are detected (3/28/88). X X8) Pulled out of decision restricting YMODEM batch send to use CRC only. Will Xnow gladly use checksum if told to and will respond to NAK as well as the Xproper C when starting up data transfer (3/28/88). Turns out this patch fixes Xproblem with Red Ryder (4/10/88). X X9) Tested MODEM7 batch against MEX-PC. Confirmation of EOT during filename Xtransmission was not working, so xmodem wasn't shutting down a MODEM7 batch Xreceive. Removed code to NAK first EOT and wait for second EOT (3/28/88). X X10) Added code to count number of newlines in a text file to get an accurate Xfile size. I thought it would take too long; but seems to be quite nimble X(see countnl in getput.c). We now transmit YMODEM file length and mode Xinformation for text as well as binary files (3/29/88). X X11) After a YMODEM file name packet was received, forgot to reset "wait" time Xfor receiving first character of data packet which definitely slowed Xperceived performance. (See note 6 for v. 3.4). Fixed (4/7/88). X X------------------------------------------------------------------------------ X XChanges leading to version 3.6 X X1) Added two new major commands (sa and ra) to send and receive text files Xfor Apple Macintoshs which use CR as EOL character instead of the MS/DOS CR XLF pair. Thanks to Dave Nowak (djnowak@iseesun.DPL.SCG.HAC.COM) for the Xinspiration (4/11/88). X X2) Experiences with Red Ryder 10.3. Fixed botch in receive.c that led to an Xinfinite loop when a checksum failed on YMODEM file name packet. Now have Xseperate variables for packet errors and "startup" errors. Prevent CRC to Xchecksum switch during receive startup if YMDMBAT flag is true. This insures Xthat no such transition will ever take place on second or subsequent file Xtransfer; can be set on first file by including Y option on command line. No Xlonger print "0" expected sectors if both YMODEM file length and KMD file Xlength are both 0 (4/12/88). X X3) Cleaned up ifs in readbuf. Removed void declaration on flushin (will Xbreak 4.2BSD compiler?). Corrected "number of sent sectors" on YMODEM Xtransfer (was counting filename packet) (4/12/88). X X4) More experiences with Red Ryder. Removed line flush before every CRCCHR Xor NAK trying to start a receive (RR YMODEM batch send to the VAX now seems Xto work). Fixed KMD "1K reception flag" to work properly on a receive. XAdded a flushin just before program exits in a futile effort to eliminate XRR's nasty habit of sending a final EOT down the line. Reaaranged Xvariables in send.c so longpackets requested by the KMD flag are not X"sticky" from file to file in a batch. RR is a real DOG: ony gets about 133 Xcps when downloading to a Mac over a 9600 bps line! (4/14/88). X X------------------------------------------------------------------------------ X XThanks to Keith Peterson (w8sdz@simtel20.arpa), John Rupley X(arizona!rupley!root), Emmet Gray (ihnp4!uiucuxc!fthood!egray), Bob Bickford X(lll-crg!well!rab), Doug Moore (moore@svax.cs.cornell.edu), David Brown X(jdb@ncsc.arpa), Bill Carpenter (ho5cad!wjc), Steve Lebowitz (prcpto!pdvshl), XLeo Pilachowski, Dave Nowak (djnowak@iseesun.DPL.SCG.HAC.COM) and Chuck XForsberg's documents and his ZCOMM/DSZ/rz/sz programs for ideas, suggestions Xand comments. SHAR_EOF chmod 0644 update.doc || echo "restore of update.doc fails" echo "x - extracting xmodem.1 (Text)" sed 's/^X//' << 'SHAR_EOF' > xmodem.1 && X.TH XMODEM LOCAL "April 14, 1988" X.UC 4.2 X.SH NAME Xxmodem \- Christensen protocol file transfer utility X.SH SYNOPSIS X.B xmodem X[\fBst|sb|sa|rt|rb|ra\fR][\fBymkctdlx\fR] X[file...] X.br X.SH DESCRIPTION XThe X.I xmodem Xprogram implements the Christensen (XMODEM) file transfer Xprotocol for moving files between 4.2/4.3BSD Unix systems and microcomputers. XThe XMODEM/CRC protocol, the MODEM7 batch protocol, the XMODEM-1K Xblock protocol and the YMODEM batch protocol are all supported by X.IR xmodem . XFor details of the protocols, Xsee the document edited by Chuck Forsberg titled X.I XXMODEM/YMODEM Protocol Reference. X.sp XOption Flags are case insensitive; the cluster of flags Xmay be preceded by an optional "-" Xcharacter. X.PP X.SH PARAMETERS XExactly one of the following must be selected: X.TP X.B rb XReceive Binary - files are placed on the Unix disk without conversion. X.I Xmodem Xwill silently destroy existing files of the same name. X.TP X.B rt XReceive Text - files are converted from the CP/M and MS-DOS Xformat of CR-LF pairs to the Unix convention of newline Xcharacters only between lines. XNull bytes are ignored and bit 8 of each character is stripped (which makes XWordstar files much more readable). XA CTRL-Z character is deemed to indicate the EOF location in the incoming Xfile. XThe resulting file Xis acceptable to the Unix editors and compilers, and is usually slightly Xsmaller than the original file. X.I Xmodem Xwill silently destroy existing files of the same name. X.TP X.B ra XReceive Apple - same as rt save CR characters in the incoming file are Xtranslated into Unix newline characters. X.TP X.B sb XSend Binary - files are sent without conversion as they exist on the Unix disk. X.TP X.B st XSend Text - newline characters in the file are converted to CR-LF pairs Xin accord with the CP/M and MS-DOS conventions for text files. The file X"grows" in this process. X.TP X.B sa XSend Apple - same as st save newline characters are converted into CR Xcharacters in accord with Apple Macintosh conventions for text files. X.PP X.SH OPTIONS X.TP X.B y XSelect the YMODEM batch protocol for sending files; a list of files specified Xon the command line will be sent in sequence. The YMODEM batch protocol is Xused automatically for file reception if the sending program requests it. XIf this flag is specified for a batch receive, (\fIxmodem rty\fR, for example), Xthe transfer will never attempt to switch from CRC to checksum mode. X.TP X.B m XSelect the MODEM7 batch protocol for sending files; a list of files specified Xon the command line will be sent in sequence. The MODEM7 batch protocol is Xused automatically for file reception if the sending program requests it. XIf this flag is specified for a batch receive, (\fIxmodem rbm\fR, for example), Xthe transfer starts in checksum mode rather than CRC mode. X.TP X.B k XSelect the XMODEM-1K file transfer mode for sending files. Use of 1K packets on Xlow-error lines increases throughput. XHowever, over direct connections at 9600 bps to a busy host, 1K packets may Xcause data overflows generating excessive retries. X1K packets are automatically Xused for file reception if the sending program requests it. XIf this flag is specified with the YMODEM flag in a batch receive (\fIxmodem Xrbyk\fR, for example), the program will attempt to use the "KMD/IMP" convention Xto invoke 1K file transfers. X.TP X.B c XSelect the CRC-16 error-checking protocol on receive. CRC mode is better at catching Xtransmission errors that occur than the alternative checksum protocol. XCRC mode is automatically selected for file Xtransmission if the receiving modem program requests it. X.TP X.B t XIndicates the Unix system is Too Busy and X.I xmodem Xshould fall back to a simpler I/O strategy than normal. X.TP X.B d XDelete the X.I xmodem.log Xfile before file transfer is begun. X.TP X.B l XDo NOT write to the log file. If logging is selected, a file X.I xmodem.log Xwill be created (or appended to), with entries for significant events, errors Xand retries. This can be useful to see why things went wrong Xwhen they do. X.TP X.B x XToggle on debug mode. If debug mode is selected, copious and possibly Xuseful debugging information will be placed in X.IR xmodem.log . X.SH "FILE NAMES" XFiles transmitted using one of the batch modes Xwill be stored on the remote machine under a CP/M-ified name (path names Xstripped, limited Xto eight characters plus a three character extension; ":" characters will Xbe turned into "/" characters; all characters will be in monocase). XFiles received using one of the batch modes Xwill be stored under their transmitted names (except that any "/" characters Xin the file name will be converted into ":" characters, all upper-case Xcharacters will be translated into lower case and trailing dots will be Xexpunged). X.PP XWhen a batch receive is requested, X.I xmodem Xtakes a wait and see attitude and can adapt to either batch protocol or even Xa classic XMODEM transfer (note that CRC-16 mode is automatically set under Xthese circumstances unless the b flag is specified). XIf a classic, "non-batch" XMODEM file reception takes place, Xthe received file is stored as X.IR xmodem.in . XFile names present on the command line for a batch receive are ignored. X.SH NOTES XWhile waiting for the beginning of a file transfer, X.I xmodem Xtreats two CAN (CTRL-X) characters that are received within 3 seconds Xas a request to abort. CAN characters will not cause an abort if received Xduring a file transfer. X.PP XIf 10 or more errors are detected during the transmission or reception of any Xone packet, the transfer is aborted. X.PP XSqueezed, compressed or ARCed files must be transferred in binary mode, even if they Xcontain text. X.PP XIf you use X.I xmodem Xover a X.I rlogin Xlink, you may have to use the form X.IR "rlogin machine -8" . X.PP XIf an unexpected error occurs before a file is completely received, the Xincomplete file is deleted. X.PP XFiles received using both binary and text mode in a YMODEM batch transfer Xwill be truncated Xto the file size specified in the YMODEM header (extra CR characters in the Xincoming file are correctly handled). File sizes are included in Xthe YMODEM header when sending both binary and text files. Thus files Xtransferred via YMODEM should preserve their exact length. XFile modification times are set for received files if present in the YMODEM Xheader; they are included in the headers for transmitted files. X.PP XThe "KMD/IMP" record count field in the YMODEM header is both set and read. X.SH EXAMPLES XTo receive a text file transmitted from a micro (using CRC-16 Xerror-checking) and store it under the Xname X.IR file.name , Xuse the command line X.RS X.B "xmodem rtc file.name" X.RE XNote that if the transmitting program on the micro uses the 1K packet Xprotocol or either batch protocol, X.I xmodem Xdetects this automatically and takes appropriate action. Further Xnote that if one of the batch protocols is used, the received file(s) Xwill be stored under their own names and the name on the command line X(if any) will be ignored. X.PP XTo send a set of text files to a microcomputer using 1K packets and the XYMODEM batch protocol, use the command line X.RS X.B "xmodem styk *.txt" X.RE X.SH FILES Xxmodem.log (if logging is enabled) X.SH BUGS XBatch mode could be smarter about bad file-names in the midst of a Xbatch transmit/receive. X.PP XBatch mode could allow a mixture of binary and text files. X.PP XBare Carriage Return characters (i.e., those not immediately followed by a XLine Feed character) are mishandled in a received file when using text mode. XA file with ``overstruck'' lines will thus come out looking funny. X.PP XYMODEM header packets are only sent as 128 byte packets. Thus VERY long file Xnames will not be handled properly. X.SH SEE ALSO Xkermit(1) X.SH AUTHOR XSteve Grandi, National Optical Astronomy Observatories. Based on X.I xmodem Xby Brian Kantor, University of California at San Diego. XThis, in turn, was based on X.I umodem Xby Lauren Weinstein, Richard Conn and others. SHAR_EOF chmod 0644 xmodem.1 || echo "restore of xmodem.1 fails" echo "x - extracting xmodem.c (Text)" sed 's/^X//' << 'SHAR_EOF' > xmodem.c && X/* X * XMODEM -- Implements the Christensen XMODEM protocol, X * for packetized file up/downloading. X * X * See the README file for some notes on SYS V adaptations. X * The program has been successfully run on VAXes (4.3BSD) and SUN-3/4s X * (SunOS 3.x) against MEX-PC and ZCOMM/DSZ. X * X * See the README and update.doc files for history and change notes. X * X * Please send bug fixes, additions and comments to: X * {ihnp4,ncar}!noao!grandi grandi@noao.arizona.edu X */ X X#include "xmodem.h" X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char *getenv(); X FILE *fopen(); X char *unix_cpm(); X char *strcpy(); X char *strcat(); X char *prtype(); X X char *fname = filename; /* convenient place to stash file names */ X char *logfile = "xmodem.log"; /* Name of LOG File */ X X char *stamptime(); /* for timestamp */ X X char *defname = "xmodem.in"; /* default file name if none given */ X X struct stat filestatbuf; /* file status info */ X X int index; X char flag; X long expsect; X X /* initialize option flags */ X X XMITTYPE = 't'; /* assume text transfer */ X DEBUG = FALSE; /* keep debugging info in log */ X RECVFLAG = FALSE; /* not receive */ X SENDFLAG = FALSE; /* not send either */ X BATCH = FALSE; /* nor batch */ X CRCMODE = FALSE; /* use checksums for now */ X DELFLAG = FALSE; /* don't delete old log file */ X LOGFLAG = TRUE; /* keep log */ X LONGPACK = FALSE; /* do not use long packets on transmit */ X MDM7BAT = FALSE; /* no MODEM7 batch mode */ X YMDMBAT = FALSE; /* no YMODEM batch mode */ X TOOBUSY = FALSE; /* not too busy for sleeping in packet read */ X X fprintf(stderr, "XMODEM Version %d.%d", VERSION/10, VERSION%10); X fprintf(stderr, " -- UNIX-Microcomputer Remote File Transfer Facility\n"); X X if (argc == 1) X { X help(); X exit(-1); X } X X index = 0; /* set index for flag loop */ X X while ((flag = argv[1][index++]) != '\0') X switch (flag) { X case '-' : break; X case 'X' : X case 'x' : DEBUG = TRUE; /* turn on debugging log */ X break; X case 'C' : X case 'c' : CRCMODE = TRUE; /* enable CRC on receive */ X break; X case 'D' : X case 'd' : DELFLAG = TRUE; /* delete log file */ X break; X case 'L' : X case 'l' : LOGFLAG = FALSE; /* turn off log */ X break; X case 'm' : X case 'M' : MDM7BAT = TRUE; /* turn on MODEM7 batch protocol */ X BATCH = TRUE; X break; X case 'y' : X case 'Y' : YMDMBAT = TRUE; /* turn on YMODEM batch protocol */ X BATCH = TRUE; X break; X case 'k' : X case 'K' : LONGPACK = TRUE; /* use 1K packets on transmit */ X break; X case 't' : X case 'T' : TOOBUSY = TRUE; /* turn off sleeping */ X break; X case 'R' : X case 'r' : RECVFLAG = TRUE; /* receive file */ X XMITTYPE = gettype(argv[1][index++]); /* get t/b */ X break; X case 'S' : X case 's' : SENDFLAG = TRUE; /* send file */ X XMITTYPE = gettype(argv[1][index++]); X break; X default : fprintf(stderr, "Invalid Flag %c ignored\n", flag); X break; X } X X if (DEBUG) X LOGFLAG = TRUE; X X if (LOGFLAG) X { X if ((fname = getenv("HOME")) == 0) /* Get HOME variable */ X error("Fatal - Can't get Environment!", FALSE); X fname = strcat(fname, "/"); X fname = strcat(fname, logfile); X if (!DELFLAG) X LOGFP = fopen(fname, "a"); /* append to LOG file */ X else X LOGFP = fopen(fname, "w"); /* new LOG file */ X if (!LOGFP) X error("Fatal - Can't Open Log File", FALSE); X X fprintf(LOGFP,"\n++++++++ %s", stamptime()); X fprintf(LOGFP,"XMODEM Version %d.%d\n", VERSION/10, VERSION%10); X fprintf(LOGFP,"Command line: %s %s", argv[0], argv[1]); X for (index=2; index<argc; ++index) X fprintf(LOGFP, " %s", argv[index]); X fprintf(LOGFP, "\n"); X } X X getspeed(); /* get tty-speed for time estimates */ X X if (RECVFLAG && SENDFLAG) X error("Fatal - Both Send and Receive Functions Specified", FALSE); X X if (MDM7BAT && YMDMBAT) X error("Fatal - Both YMODEM and MODEM7 Batch Protocols Specified", FALSE); X X if (!RECVFLAG && !SENDFLAG) X error("Fatal - Either Send or Receive Function must be chosen!",FALSE); X X if (SENDFLAG && argc==2) X error("Fatal - No file specified to send",FALSE); X X if (RECVFLAG && argc==2) X { X /* assume we really want CRC-16 in batch, unless we specify MODEM7 mode */ X CRCMODE = MDM7BAT ? FALSE : TRUE; X fprintf(stderr, "Ready for BATCH RECEIVE"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logit("Batch Receive Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X strcpy(fname, defname); X } X X if (RECVFLAG && argc>2) X { X if(open(argv[2], 0) != -1) /* check for overwriting */ X { X logit("Warning -- Target File Exists and is Being Overwritten\n"); X fprintf(stderr, "Warning -- Target File Exists and is Being Overwritten\n"); X } X fprintf(stderr, "Ready to RECEIVE File %s", argv[2]); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logitarg("Receiving in %s mode\n", prtype(XMITTYPE)); X strcpy(fname,argv[2]); X } X X if (RECVFLAG) X { X setmodes(); /* set tty modes for transfer */ X X while(rfile(fname) != FALSE); /* receive files */ X X flushin(); X restoremodes(FALSE); /* restore normal tty modes */ X X sleep(2); /* give other side time to return to terminal mode */ X exit(0); X } X X if (SENDFLAG && BATCH) X { X if (YMDMBAT) X { X fprintf(stderr, "Ready to YMODEM BATCH SEND"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X logit("YMODEM Batch Send Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X } X else if (MDM7BAT) X { X fprintf(stderr, "Ready to MODEM7 BATCH SEND"); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X logit("MODEM7 Batch Send Started"); X logitarg(" in %s mode\n", prtype(XMITTYPE)); X } X fprintf(stderr, "Send several Control-X characters to cancel\n"); X X setmodes(); X for (index=2; index<argc; index++) { X if (stat(argv[index], &filestatbuf) < 0) { X logitarg("\nFile %s not found\n", argv[index]); X continue; X } X sfile(argv[index]); X } X sfile(""); X flushin(); X restoremodes(FALSE); X X logit("Batch Send Complete\n"); X sleep(2); X exit (0); X } X X if (SENDFLAG && !BATCH) X { X if (stat(argv[2], &filestatbuf) < 0) X error("Can't find requested file", FALSE); X expsect = (filestatbuf.st_size/128)+1; X X fprintf(stderr, "File %s Ready to SEND", argv[2]); X fprintf(stderr, " in %s mode\n", prtype(XMITTYPE)); X fprintf(stderr, "Estimated File Size %ldK, %ld Sectors, %ld Bytes\n", X (filestatbuf.st_size/1024)+1, expsect, X filestatbuf.st_size); X projtime(expsect, stdout); X fprintf(stderr, "Send several Control-X characters to cancel\n"); X logitarg("Sending in %s mode\n", prtype(XMITTYPE)); X X setmodes(); X sfile(argv[2]); X flushin(); X restoremodes(FALSE); X X sleep(2); X exit(0); X } X} SHAR_EOF chmod 0644 xmodem.c || echo "restore of xmodem.c fails" echo "x - extracting xmodem.h (Text)" sed 's/^X//' << 'SHAR_EOF' > xmodem.h && X#include <ctype.h> X#include <stdio.h> X#include