Subject: v07i092: Full-featured XMODEM, Part01/02 Newsgroups: mod.sources Approved: mirror!rs Submitted by: seismo!noao!grandi (Steve Grandi) Mod.sources: Volume 7, Issue 92 Archive-name: xmodem/Part01 [ Sorry. If I vanish again, I'll at least let you folks know. --r$ ] : This is a shar archive. Extract with sh, not csh. echo x - README sed -e 's/^X//' > README << '!Funky!Stuff!' XThe xmodem program 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 xmodem. XFor details of the protocols, see the document edited by Chuck Forsberg titled XXMODEM/YMODEM Protocol Reference. X XThis program runs on 4.2/4.3BSD systems ONLY. It has been tested on VAXes Xand Suns against the MEX-PC program from Niteowl Software. X XI have tried to keep the 4.2isms (select system call, 4.2BSD/v7 tty structures, Xgettimeofday system call, etc.) confined to the source file getput.c; but I Xmake no guarantees. Also, I have made no attempt to keep variable names Xunder 7 characters. X X XProgram history: X XDescended from UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others. X XBased on XMODEM Version 1.0 by Brian Kantor, UCSD (3/84) (Don't blame him Xfor what follows....) X XVersion 2.0 (CRC-16 and Modem7 batch file transfer) (5/85) X XVersion 2.1 (1K packets) (7/85) X XVersion 2.2 (general clean-ups and multi-character read speed-ups) (9/85) X XVersion 2.3 (nap while reading packets; split into several source files) (1/86) X XVersion 3.0 (Ymodem batch receive; associated changes) (2/86) X XVersion 3.1 (Ymodem batch send; associated changes) (8/86) X XVersion 3.2 (general cleanups) (9/86) X X X XPlease send bug fixes, additions and comments to: XSteve Grandi, National Optical Astronomy Observatories (Tucson, Arizona) X {ihnp4,seismo,hao,arizona,...}!noao!grandi !Funky!Stuff! echo x - xmodem.1 sed -e 's/^X//' > xmodem.1 << '!Funky!Stuff!' X.TH XMODEM LOCAL "August 26, 1986" X.UC 4.2 X.SH NAME Xxmodem \- Christensen protocol file transfer utility X.SH SYNOPSIS X.B xmodem X[\fBst|sb|rt|rb\fR][\fBYBKcdlx\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 XThis program runs on 4.2/4.3BSD systems ONLY. It has been tested on VAXes Xand Suns against the MEX-PC program from Niteowl Software. 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 format of CR-LF pairs to the Unix Xconvention of X.I newline Xcharacters only between lines. XBit 8 of each character is stripped (which makes Wordstar files much Xmore readable). XThe resulting file Xis acceptable to the Unix editors and compilers, and is usually slightly Xsmaller than the original CP/M file. X.I Xmodem Xwill silently destroy existing files of the same name. 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 conventions for text files. The file grows Xslightly as this occurs so the estimate of file transmission size and Xtime are always optimistically low. 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. X.TP X.B B 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. 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. 1K packets are automatically Xused for file reception if the sending program requests it. 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 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 (limited Xto eight characters plus a three character extension; ":" characters will Xbe turned into "/" characters; all characters will be in monocase). Files 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 and all upper-case Xcharacters will be translated into lower case). 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). 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 transfer or the beginning of a packet, X.I xmodem Xtreats two CAN (Cntrl-X) characters that are received within 3 seconds Xas a request to abort. X.PP XSqueezed CP/M 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 must use the flag X.IR "rlogin machine -8" . 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 XThe file lengths and creation times embedded in the YMODEM batch protocol are Xneither set on transmit nor used on receive. However, the "IMP/KMD record Xcount" field is utilized. 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. !Funky!Stuff! echo x - Makefile sed -e 's/^X//' > Makefile << '!Funky!Stuff!' XOBJECTS = xmodem.o getput.o misc.o send.o receive.o batch.o XCFLAGS = -O X Xxmodem: $(OBJECTS) X cc $(CFLAGS) $(OBJECTS) -o xmodem X X$(OBJECTS): xmodem.h X Xprint: X lpr -p -Pvmslp xmodem.h xmodem.c getput.c receive.c send.c batch.c misc.c Makefile !Funky!Stuff! echo x - xmodem.h sed -e 's/^X//' > xmodem.h << '!Funky!Stuff!' X#include X#include X#include X#include X#include X#include X#include 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 32 /* 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 */ X#define NAKMAX 2 /* maximum times to wait for initial NAK when sending */ X#define RETRYMAX 5 /* maximum retries to be made */ X#define CRCSWMAX 4 /* maximum time to try CRC mode before switching */ X#define KSWMAX 5 /* maximum errors before switching to 128 byte packets */ 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 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 */ 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 */ 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 /* this the number of bits per char */ X#define B 8 !Funky!Stuff! echo x - xmodem.c sed -e 's/^X//' > xmodem.c << '!Funky!Stuff!' X/* X * XMODEM -- Implements the Christensen XMODEM protocol, X * for packetized file up/downloading. X * X * This version runs on 4.2/4.3BSD ONLY! It won't work ANYWHERE else. X * X * I have tried to keep the 4.2isms (select system call, 4.2BSD/v7 tty X * structures, gettimeofday system call, etc.) in the source file X * getput.c; but I make no guarantees. Also, I have made no attempt to X * keep variable names under 7 characters (although a cursory check X * shows that all variables are unique within 7 first characters). X * The program has been successfully run on VAXes (4.2/4.3BSD) and SUNs X * (2.0/3.0) against MEX-PC. X * X * -- Based on UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others. X * X * XMODEM Version 1.0 - by Brian Kantor, UCSD (3/84) X * X * Version 2.0 (CRC-16 and Modem7 batch file transfer) -- Steve Grandi, NOAO (5/85) X * X * Version 2.1 (1K packets) -- Steve Grandi, NOAO (7/85) X * X * Version 2.2 (general clean-ups and multi-character read speed-ups) -- Steve Grandi, NOAO (9/85) X * X * Version 2.3 (napping while reading packet; split into several source files) -- Steve Grandi, NOAO (1/86) X * X * Version 3.0 (Ymodem batch receive; associated changes) -- Steve Grandi, NOAO (2/86) X * X * Version 3.1 (Ymodem batch send; associated changes) -- Steve Grandi, NOAO (8/86) X * X * Version 3.2 (general cleanups) -- Steve Grandi, NOAO (9/86) X * X * Please send bug fixes, additions and comments to: X * {ihnp4,seismo,hao}!noao!grandi 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 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 X printf("XMODEM Version %d.%d", VERSION/10, VERSION%10); X printf(" -- UNIX-CP/M 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' : DEBUG = TRUE; /* turn on debugging log */ X break; X case 'c' : CRCMODE = TRUE; /* enable CRC on receive */ X break; X case 'd' : DELFLAG = TRUE; /* delete log file */ X break; X case 'l' : LOGFLAG = FALSE; /* turn off log */ X break; X case 'B' : MDM7BAT = TRUE; /* turn on MODEM7 batch protocol */ X BATCH = TRUE; X break; X case 'Y' : YMDMBAT = TRUE; /* turn on YMODEM batch protocol */ X BATCH = TRUE; X break; X case 'K' : LONGPACK = TRUE; /* use 1K packets on transmit */ X break; X case 'r' : RECVFLAG = TRUE; /* receive file */ X XMITTYPE = gettype(argv[1][index++]); /* get t/b */ X break; X case 's' : SENDFLAG = TRUE; /* send file */ X XMITTYPE = gettype(argv[1][index++]); X break; X default : printf ("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 } 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 CRCMODE = TRUE; /* assume we really want CRC-16 in batch */ X printf("Ready for BATCH RECEIVE"); X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); X printf("Send several Control-X characters to cancel\n"); X logit("Batch Receive Started"); X logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); 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 printf("Warning -- Target File Exists and is Being Overwritten\n"); X } X printf("Ready to RECEIVE File %s", argv[2]); X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); X printf("Send several Control-X characters to cancel\n"); X logitarg("Receiving in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); 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 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 printf("Ready to YMODEM BATCH SEND"); X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); X logit("YMODEM Batch Send Started"); X logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); X } X else if (MDM7BAT) X { X printf("Ready to MODEM7 BATCH SEND"); X printf(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); X logit("MODEM7 Batch Send Started"); X logitarg(" in %s mode\n", (XMITTYPE == 't') ? "text" : "binary"); X } X printf("Send several Control-X characters to cancel\n"); X X setmodes(); X for (index=2; index getput.c << '!Funky!Stuff!' X/* X * Contains system routines to get and put bytes, change tty modes, etc X * Most of the routines are VERY 4.2BSD Specific!!! X */ X X#include "xmodem.h" 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 */ Xgetbyte(fildes, ch) /* Buffered disk read */ Xint fildes; Xchar *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 error("File Read Error", TRUE); 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 { X return(EOF); X } X } X X/* CRC-16 constant array... X from Usenet contribution by Mark G. Mendel, Network Systems Corp. X (ihnp4!umn-cs!hyper!mark) X*/ X X/* crctab as calculated by initcrctab() */ Xunsigned short crctab[1< 0;) { X X /* read however many chars are waiting */ X X if ((select(1, &readfd, (int *)0, (int *)0, &tmout)) == 0) X return(TIMEOUT); X X numread = read(0, inbuf, left); X left -= numread; X X if (DEBUG) X fprintf(LOGFP, "DEBUG: readbuf--read %d characters\n", numread); X X /* now process part of packet we just read */ X X for (j = 0; j < numread; j++) X { X buff[bfctr] = c = inbuf[j] & 0xff; X X if (CRCMODE) /* CRC */ X chksm = (chksm<>(W-B)) ^ c]; X X else /* checksum */ X chksm = ((chksm+c) & 0xff); X X /* binary mode */ X if (!tmode) X { X bfctr++; X continue; X } X X /* text mode */ X buff[bfctr] &= 0x7f; /* nuke bit 8 */ X if (c == CR) /* skip CR's */ X continue; X if (c == CTRLZ) /* CP/M EOF char */ X { X recfin = TRUE; X continue; X } X if (!recfin) X bfctr++; X } X X /* go to sleep to save uneeded system calls while kernel X is reading data from serial line; forget this when we X running at 9600 bps; also fudge constant from 10000 to X 9000 to avoid sleeping too long X */ X if (ttyspeed < 9600) X napms ( (left