Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!rutgers!princeton!astrovax!noao!grandi
From: grandi@noao.UUCP (Steve Grandi)
Newsgroups: net.sources
Subject: XMODEM/YMODEM program for 4.2/4.3BSD (part 1/2)
Message-ID: <539@noao.UUCP>
Date: Wed, 7-Jan-87 10:46:58 EST
Article-I.D.: noao.539
Posted: Wed Jan  7 10:46:58 1987
Date-Received: Thu, 8-Jan-87 06:36:14 EST
Organization: National Optical Astronomy Observatories, Tucson, AZ
Lines: 947


Several requests have been made lately for a XMODEM/YMODEM program to
support file transfer to or from micros.  What follows is my adaptation of
a previous XMODEM program.  It runs on 4.2/4.3BSD systems only.  I
submitted this same exact package to mod.sources almost three months ago,
so when the dam bursts in that newsgroup, you might see this program again.


Steve Grandi, National Optical Astronomy Observatories, Tucson, AZ, 602-325-9228
UUCP: {decvax,hao,ihnp4,seismo}!noao!grandi           Internet: grandi@noao.arpa
------------CUT HERE-----------------------------------------------------------
: 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   grandi@noao.arpa
!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   grandi@noao.arpa
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