Newsgroups: comp.sys.ti
Path: utzoo!utgpu!jarvis.csri.toronto.edu!csri.toronto.edu!pkern
From: pkern@csri.toronto.edu (pkern)
Subject: a vt100 emulator in Turbo C  (3 of 3)
Message-ID: <8806071611.AA12898@bloor.csri.toronto.edu>
Organization: University of Toronto, CSRI
Date:	Tue, 7 Jun 88 10:51:13 EDT


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	types.h
#	kermit.c
#	xmodem.c
# This archive created: Tue Jun  7 11:28:14 1988
# By:	pkern ()
export PATH; PATH=/bin:$PATH
echo shar: extracting "'types.h'" '(139 characters)'
if test -f 'types.h'
then
	echo shar: will not over-write existing file "'types.h'"
else
sed 's/^X//' << \SHAR_EOF > 'types.h'
X/*
X * types.h: useful compatibility info
X */
Xtypedef unsigned long	u_long;
Xtypedef u_long	ino_t;
Xtypedef short	dev_t;
Xtypedef long	time_t;
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'kermit.c'" '(38899 characters)'
if test -f 'kermit.c'
then
	echo shar: will not over-write existing file "'kermit.c'"
else
sed 's/^X//' << \SHAR_EOF > 'kermit.c'
X/*
X *  K e r m i t	 File Transfer Utility
X *
X *  UNIX Kermit, Columbia University, 1981, 1982, 1983
X *	Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
X *
X *  Also:   Jim Guyton, Rand Corporation
X *	    Walter Underwood, Ford Aerospace
X *
X *  usage:  kermit c [lbe line baud escapechar]		to connect
X *	    kermit s [d..iflb line baud] file ...	to send files
X *	    kermit r [d..iflb line baud]		to receive files
X *
X *  where   c=connect, s=send, r=receive,
X *	    d=debug, i=image mode, f=no filename conversion, l=tty line,
X *	    b=baud rate, e=escape char.
X *
X *  For remote Kermit, format is either:
X *	    kermit r					to receive files
X *  or	    kermit s file ...				to send files
X *
X */
X
X/*
X *  Modification History:
X *
X *  Oct. 17 Included fixes from Alan Crosswell (CUCCA) for IBM_UTS:
X *	    - Changed MYEOL character from \n to \r.
X *	    - Change char to int in bufill so getc would return -1 on
X *	      EOF instead of 255 (-1 truncated to 8 bits)
X *	    - Added read() in rpack to eat the EOL character
X *	    - Added fflush() call in printmsg to force the output
X *	    NOTE: The last three changes are not conditionally compiled
X *		  since they should work equally well on any system.
X *
X *	    Changed Berkeley 4.x conditional compilation flag from
X *		UNIX4X to UCB4X.
X *	    Added support for error packets and cleaned up the printing
X *		routines.
X */
X
X#include 	    /* Standard UNIX definitions */
X
X/* Conditional compilation for different machines/operating systems */
X/* One and only one of the following lines should be 1 */
X
X#define UCB4X	    0	    /* Berkeley 4.x UNIX */
X#define TOPS_20	    0	    /* TOPS-20 */
X#define IBM_UTS	    0	    /* Amdahl UTS on IBM systems */
X#define VAX_VMS	    0	    /* VAX/VMS (not yet implemented) */
X
X/* Conditional compilation for the different Unix variants */
X/* 0 means don't compile it, nonzero means do */
X
X#if UCB4X
X#define V6_LIBS	    0	    /* Dont't use retrofit libraries */
X#define NO_FIONREAD 0	    /* We have ioctl(FIONREAD,...) for flushinput() */
X#define NO_TANDEM   0	    /* We have TANDEM line discipline (xon/xoff) */
X#endif
X
X#if IBM_UTS
X#define V6_LIBS	    0	    /* Don't use retrofit libraries */
X#define NO_FIONREAD 1	    /* No ioctl(FIONREAD,...) for flushinput() */
X#define NO_TANDEM   1	    /* No TANDEM line discipline (xon/xoff) */
X#endif
X
X#if V6_LIBS
X#include 
X#include 
X#include 
X#else
X#ifdef unix
X#include 
X#include 
X#else
X#include 
X#endif
X#include 
X#endif
X
X#if NO_TANDEM
X#define TANDEM	    0	    /* define it to be nothing if it's unsupported */
X#endif
X
X
X/* Symbol Definitions */
X
X#define MAXPACKSIZ  94	    /* Maximum packet size */
X#define SOH	    1	    /* Start of header */
X#define CR	    13	    /* ASCII Carriage Return */
X#define SP	    32	    /* ASCII space */
X#define DEL	    127	    /* Delete (rubout) */
X#define ESCCHR	    '^'	    /* Default escape character for CONNECT */
X
X#define MAXTRY	    10	    /* Times to retry a packet */
X#define MYQUOTE	    '#'	    /* Quote character I will use */
X#define MYPAD	    0	    /* Number of padding characters I will need */
X#define MYPCHAR	    0	    /* Padding character I need (NULL) */
X
X#if IBM_UTS
X#define MYEOL	    '\r'    /* End-Of-Line character for UTS systems */
X#else
X#define MYEOL	    '\n'    /* End-Of-Line character I need */
X#endif
X
X#define MYTIME	    10	    /* Seconds after which I should be timed out */
X#define MAXTIM	    60	    /* Maximum timeout interval */
X#define MINTIM	    2	    /* Minumum timeout interval */
X
X#define TRUE	    -1	    /* Boolean constants */
X#define FALSE	    0
X
X
X/* Macro Definitions */
X
X/*
X * tochar: converts a control character to a printable one by adding a space.
X *
X * unchar: undoes tochar.
X *
X * ctl:	   converts between control characters and printable characters by
X *	   toggling the control bit (ie. ^A becomes A and A becomes ^A).
X */
X#define tochar(ch)  ((ch) + ' ')
X#define unchar(ch)  ((ch) - ' ')
X#define ctl(ch)	    ((ch) ^ 64 )
X
X
X/* Global Variables */
X
X#ifndef unix
Xstatic
X#endif
Xint	size,		    /* Size of present data */
X	rpsiz,		    /* Maximum receive packet size */
X	spsiz,		    /* Maximum send packet size */
X	pad,		    /* How much padding to send */
X	timint,		    /* Timeout for foreign host on sends */
X	n,		    /* Packet number */
X	numtry,		    /* Times this packet retried */
X	oldtry,		    /* Times previous packet retried */
X	ttyfd,		    /* File descriptor of tty for I/O, 0 if remote */
X	remote,		    /* -1 means we're a remote kermit */
X	image,		    /* -1 means 8-bit mode */
X	debug,		    /* indicates level of debugging output (0=none) */
X	filnamcnv,	    /* -1 means do file name case conversions */
X	filecount;	    /* Number of files left to send */
X
X#ifndef unix
Xstatic
X#endif
Xchar	state,		    /* Present state of the automaton */
X	padchar,	    /* Padding character to send */
X	eol,		    /* End-Of-Line character to send */
X	escchr,		    /* Connect command escape character */
X	quote,		    /* Quote character in incoming data */
X	**filelist,	    /* List of files to be sent */
X	*filnam,	    /* Current file name */
X	recpkt[MAXPACKSIZ], /* Receive packet buffer */
X	packet[MAXPACKSIZ]; /* Packet buffer */
X
X#ifndef unix
Xstatic
X#endif
XFILE	*fp,		    /* File pointer for current disk file */
X	*log;		    /* File pointer for Logfile */
X
X#ifdef unix
Xjmp_buf env;		    /* Environment ptr for timeout longjump */
X#else
X
X#define exit(a)	longjmp(xjmp,a)
Xstatic jmp_buf env, xjmp;
Xextern unsigned int cntdn;
X#endif
X
X
X/*
X *  m a i n
X *
X *  Main routine - parse command and options, set up the
X *  tty lines, and dispatch to the appropriate routine.
X */
X
X#ifdef unix
Xmain(argc,argv)
X#else
Xkermit(argc,argv)
X#endif
Xint argc;			    /* Character pointers to and count of */
Xchar **argv;				/* command line arguments */
X{
X    char *ttyname,			/* tty name for LINE argument */
X	*cp;				/* char pointer */
X    int speed,				/* speed of assigned tty, */
X	cflg, rflg, sflg;		/* flags for CONNECT, RECEIVE, SEND */
X
X#ifdef unix
X    struct sgttyb
X	rawmode,			/* Controlling tty raw mode */
X	cookedmode,			/* Controlling tty cooked mode */
X	ttymode;			/* mode of tty line in LINE option */
X#else
X    int o_n, o_fmode, boom(), xboom();
X
X    counter(1);
X    o_fmode = _fmode;
X    _fmode = O_BINARY;
X    debug = 0;
X    if (o_n = setjmp(xjmp)) {
X	counter(0);
X	if (fp != NULL) {
X	    fclose(fp);
X	    fp = NULL;
X	}
X	_fmode = o_fmode;
X	ctrlbrk(boom);
X	return(o_n);
X    }
X    else
X	ctrlbrk(xboom);
X#endif
X
X    if (argc < 2) usage();		/* Make sure there's a command line */
X
X    cp = *++argv; argv++; argc -= 2;	/* Set up pointers to args */
X
X/*  Initialize these values and hope the first packet will get across OK */
X
X    eol = CR;				/* EOL for outgoing packets */
X    quote = '#';			/* Standard control-quote char "#" */
X    pad = 0;				/* No padding */
X    padchar = NULL;			/* Use null if any padding wanted */
X
X    speed = cflg = sflg = rflg = 0;	/* Turn off all parse flags */
X    ttyname = 0;			/* Default is remote mode */
X
X#if UCB4X				/* Default to 7-bit masking, CRLF */
X    image = FALSE;			/* translation and filename case */
X    filnamcnv = TRUE;			/* conversion for UNIX systems */
X#else
X    image = TRUE;			/* Default to no processing for */
X    filnamcnv = FALSE;			/* non-UNIX systems */
X#endif
X
X    escchr = ESCCHR;			/* Default escape character */
X
X    while ((*cp) != NULL)		/* Parse characters in first arg. */
X	switch (*cp++)
X	{
X	    case 'c': cflg++; break;	/* C = Connect command */
X	    case 's': sflg++; break;	/* S = Send command */
X	    case 'r': rflg++; break;	/* R = Receive command */
X
X	    case 'd':			/* D = Increment debug mode count */
X		debug++; break;
X		
X	    case 'f':
X		filnamcnv = FALSE;	/* F = don't do case conversion */
X		break;			/*     on filenames */
X
X	    case 'i':			/* I = Image (8-bit) mode */
X#ifdef unix
X		image = TRUE; break;	/* (this is default for non-UNIX) */
X#else
X		image = FALSE; break;
X#endif
X
X#ifdef unix
X	    case 'l':			/* L = specify tty line to use */
X		if (argc--) ttyname = *argv++;
X		else usage();
X		if (debug) printf("Line to remote host is %s\n",ttyname);
X		break;
X		
X	    case 'e':			/* E = specify escape char */
X		if (argc--) escchr = **argv++;
X		else usage();
X		if (debug) printf("Escape char is \"%c\"\n",escchr);
X		break;
X		
X	    case 'b':			/* B = specify baud rate */
X#if UCB4X
X		if (argc--) speed = atoi(*argv++);
X		else usage();
X		if (debug) printf("Line speed to remote host is %d\n",speed);
X		break;
X#else
X		printmsg("Speed setting implemented for Unix only.");
X		exit(1);
X#endif
X#endif
X	}
X
X/* Done parsing */
X
X    if ((cflg+sflg+rflg) != 1)		/* Only one command allowed */
X	usage();
X
X
X#ifdef unix
X    if (ttyname)			/* If LINE was specified, we */
X    {					/* operate in local mode */
X	ttyfd = open(ttyname,2);	/* Open the tty line */
X	if (ttyfd < 0)
X	{
X	    printmsg("Cannot open %s",ttyname);
X	    exit(1);
X	}
X	remote = FALSE;			/* Indicate we're in local mode */
X    }
X    else				/* No LINE specified so we operate */
X    {					/* in remote mode (ie. controlling */
X	ttyfd = 0;			/* tty is the communications line) */
X	remote = TRUE;
X    }
X
X
X/* Put the proper tty into the correct mode */
X
X    if (remote)				/* If remote, use controlling tty */
X    {
X	gtty(0,&cookedmode);		/* Save current mode so we can */
X	gtty(0,&rawmode);		/* restore it later */
X	rawmode.sg_flags |= (RAW|TANDEM);
X	rawmode.sg_flags &= ~(ECHO|CRMOD);
X	stty(0,&rawmode);		/* Put tty in raw mode */
X    }
X    else				/* Local, use assigned line */
X    {
X	gtty(ttyfd,&ttymode);
X	ttymode.sg_flags |= (RAW|TANDEM);
X	ttymode.sg_flags &= ~(ECHO|CRMOD);
X
X#if UCB4X				/* Speed changing for UNIX only */
X	if (speed)			/* User specified a speed? */
X	{
X	    switch(speed)		/* Get internal system code */
X	    {
X		case 110: speed = B110; break;
X		case 150: speed = B150; break;
X		case 300: speed = B300; break;
X		case 1200: speed = B1200; break;
X		case 2400: speed = B2400; break;
X		case 4800: speed = B4800; break;
X		case 9600: speed = B9600; break;
X
X		default:
X		    printmsg("Bad line speed.");
X		    exit(1);
X	    }
X	    ttymode.sg_ispeed = speed;
X	    ttymode.sg_ospeed = speed;
X	}
X#endif /* UCB4X */
X
X	stty(ttyfd,&ttymode);		/* Put asg'd tty in raw mode */
X    }	
X#else
X    remote = FALSE;
X#endif
X
X
X/* All set up, now execute the command that was given. */
X
X    if (debug)
X    {
X	printf("Debugging level = %d\n\n",debug);
X
X	if (cflg) printf("Connect command\n\n");
X	if (sflg) printf("Send command\n\n");
X	if (rflg) printf("Receive command\n\n");
X    }
X
X    if (cflg) connect();		/* Connect command */
X
X    if (sflg)				/* Send command */
X    {
X	if (argc--) filnam = *argv++;	/* Get file to send */
X	else
X#ifdef unix
X	{   if (remote)
X		stty(0,&cookedmode);	/* Restore controlling tty's modes */
X	    usage();			/* and give error */
X	}
X#else
X	    usage();
X#endif
X	fp = NULL;			/* Indicate no file open yet */
X	filelist = argv;		/* Set up the rest of the file list */
X	filecount = argc;		/* Number of files left to send */
X	if (sendsw() == FALSE)		/* Send the file(s) */
X	    printmsg("Send failed.");	/* Report failure */
X	else				/*  or */
X	    printmsg("done.");		/* success */
X    }
X
X    if (rflg)				/* Receive command */
X    {
X	if (recsw() == FALSE)		/* Receive the file(s) */
X	    printmsg("Receive failed.");
X	else				/* Report failure */
X	    printmsg("done.");		/* or success */
X    }
X
X#ifdef unix
X    if (remote) stty(0,&cookedmode);	/* Restore controlling tty's modes */
X#endif
X}
X
X
X/*
X *  s e n d s w
X *
X *  Sendsw is the state table switcher for sending files.  It loops until
X *  either it finishes, or an error is encountered.  The routines called
X *  by sendsw are responsible for changing the state.
X *
X */
X
X#ifndef unix
Xstatic
X#endif
Xsendsw()
X{
X    char sinit(), sfile(), sdata(), seof(), sbreak();
X
X    state = 'S';			/* Send initiate is the start state */
X    n = 0;				/* Initialize message number */
X    numtry = 0;				/* Say no tries yet */
X    while(TRUE)				/* Do this as long as necessary */
X    {
X	if (debug) printf("sendsw state: %c\n",state);
X	switch(state)
X	{
X	    case 'S':	state = sinit();  break; /* Send-Init */
X	    case 'F':	state = sfile();  break; /* Send-File */
X	    case 'D':	state = sdata();  break; /* Send-Data */
X	    case 'Z':	state = seof();	  break; /* Send-End-of-File */
X	    case 'B':	state = sbreak(); break; /* Send-Break */
X	    case 'C':	return (TRUE);		 /* Complete */
X	    case 'A':	return (FALSE);		 /* "Abort" */
X	    default:	return (FALSE);		 /* Unknown, fail */
X	}
X    }
X}
X
X
X/*
X *  s i n i t
X *
X *  Send Initiate: send this host's parameters and get other side's back.
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sinit()
X{
X    int num, len;			/* Packet number, length */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
X    spar(packet);			/* Fill up init info packet */
X
X    flushinput();			/* Flush pending input */
X
X    spack('S',n,6,packet);		/* Send an S packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {
X	case 'N':  return(state);	/* NAK, try it again */
X
X	case 'Y':			/* ACK */
X	    if (n != num)		/* If wrong ACK, stay in S state */
X		return(state);		/* and try again */
X	    rpar(recpkt);		/* Get other side's init info */
X
X	    if (eol == 0) eol = '\n';	/* Check and set defaults */
X	    if (quote == 0) quote = '#';
X
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* Bump packet count */
X	    return('F');		/* OK, switch state to F */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, try again */
X
X	default: return('A');		/* Anything else, just "abort" */
X   }
X }
X
X
X/*
X *  s f i l e
X *
X *  Send File Header.
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sfile()
X{
X    int num, len;			/* Packet number, length */
X    char filnam1[50],			/* Converted file name */
X	*newfilnam,			/* Pointer to file name to send */
X	*cp;				/* char pointer */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
X
X    if (fp == NULL)			/* If not already open, */
X    {	if (debug) printf("   Opening %s for sending.\n",filnam);
X	fp = fopen(filnam,"r");		/* open the file to be sent */
X	if (fp == NULL)			/* If bad file pointer, give up */
X	{
X	    error("Cannot open file %s",filnam);
X	    return('A');
X	}
X    }
X
X    strcpy(filnam1, filnam);		/* Copy file name */
X    newfilnam = cp = filnam1;
X    while (*cp != '\0')			/* Strip off all leading directory */
X	if (*cp++ == '/')		/* names (ie. up to the last /). */
X	    newfilnam = cp;
X
X    if (filnamcnv)			/* Convert lower case to upper	*/
X	for (cp = newfilnam; *cp != '\0'; cp++)
X	    if (*cp >= 'a' && *cp <= 'z')
X		*cp ^= 040;
X
X    len = cp - newfilnam;		/* Compute length of new filename */
X
X    printmsg("Sending %s as %s",filnam,newfilnam);
X
X    spack('F',n,len,newfilnam);		/* Send an F packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {			
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, stay in F state */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* Bump packet count */
X	    size = bufill(packet);	/* Get first data from file */
X	    return('D');		/* Switch state to D */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in F state */
X
X	default:    return('A');	/* Something else, just "abort" */
X    }
X}
X
X
X/*
X *  s d a t a
X *
X *  Send File Data
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sdata()
X{
X    int num, len;			/* Packet number, length */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, give up */
X
X    spack('D',n,size,packet);		/* Send a D packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {		
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X		
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, fail */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* Bump packet count */
X	    if ((size = bufill(packet)) == EOF) /* Get data from file */
X		return('Z');		/* If EOF set state to that */
X	    return('D');		/* Got data, stay in state D */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in D */
X
X	default:    return('A');	/* Anything else, "abort" */
X    }
X}
X
X
X/*
X *  s e o f
X *
X *  Send End-Of-File.
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar seof()
X{
X    int num, len;			/* Packet number, length */
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
X
X    spack('Z',n,0,packet);		/* Send a 'Z' packet */
X    switch(rpack(&len,&num,recpkt))	/* What was the reply? */
X    {
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless it's NAK for next packet, */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, hold out */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* and bump packet count */
X	    if (debug) printf("	  Closing input file %s, ",filnam);
X	    fclose(fp);			/* Close the input file */
X	    fp = NULL;			/* Set flag indicating no file open */
X
X	    if (debug) printf("looking for next file...\n");
X	    if (gnxtfl() == FALSE)	/* No more files go? */
X		return('B');		/* if not, break, EOT, all done */
X	    if (debug) printf("	  New file is %s\n",filnam);
X	    return('F');		/* More files, switch state to F */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in Z */
X
X	default:    return('A');	/* Something else, "abort" */
X    }
X}
X
X
X/*
X *  s b r e a k
X *
X *  Send Break (EOT)
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar sbreak()
X{
X    int num, len;			/* Packet number, length */
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
X
X    spack('B',n,0,packet);		/* Send a B packet */
X    switch (rpack(&len,&num,recpkt))	/* What was the reply? */
X    {
X	case 'N':			/* NAK, just stay in this state, */
X	    num = (--num<0 ? 63:num);	/* unless NAK for previous packet, */
X	    if (n != num)		/* which is just like an ACK for */
X		return(state);		/* this packet so fall thru to... */
X
X	case 'Y':			/* ACK */
X	    if (n != num) return(state); /* If wrong ACK, fail */
X	    numtry = 0;			/* Reset try counter */
X	    n = (n+1)%64;		/* and bump packet count */
X	    return('C');		/* Switch state to Complete */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE: return(state);	/* Receive failure, stay in B */
X
X	default:    return ('A');	/* Other, "abort" */
X   }
X}
X
X
X/*
X *  r e c s w
X *
X *  This is the state table switcher for receiving files.
X */
X
X#ifndef unix
Xstatic
X#endif
Xrecsw()
X{
X    char rinit(), rfile(), rdata();	/* Use these procedures */
X
X    state = 'R';			/* Receive-Init is the start state */
X    n = 0;				/* Initialize message number */
X    numtry = 0;				/* Say no tries yet */
X
X    while(TRUE)
X    {
X	if (debug) printf(" recsw state: %c\n",state);
X	switch(state)			/* Do until done */
X	{
X	    case 'R':	state = rinit(); break; /* Receive-Init */
X	    case 'F':	state = rfile(); break; /* Receive-File */
X	    case 'D':	state = rdata(); break; /* Receive-Data */
X	    case 'C':	return(TRUE);		/* Complete state */
X	    case 'A':	return(FALSE);		/* "Abort" state */
X	}
X    }
X}
X
X
X/*
X *  r i n i t
X *
X *  Receive Initialization
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar rinit()
X{
X    int len, num;			/* Packet length, number */
X
X    if (numtry++ > MAXTRY) return('A'); /* If too many tries, "abort" */
X
X    switch(rpack(&len,&num,packet))	/* Get a packet */
X    {
X	case 'S':			/* Send-Init */
X	    rpar(packet);		/* Get the other side's init data */
X	    spar(packet);		/* Fill up packet with my init info */
X	    spack('Y',n,6,packet);	/* ACK with my parameters */
X	    oldtry = numtry;		/* Save old try count */
X	    numtry = 0;			/* Start a new counter */
X	    n = (n+1)%64;		/* Bump packet number, mod 64 */
X	    return('F');		/* Enter File-Receive state */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE:			/* Didn't get packet */
X	    spack('N',n,0,0);		/* Return a NAK */
X	    return(state);		/* Keep trying */
X
X	default:     return('A');	/* Some other packet type, "abort" */
X    }
X}
X
X
X/*
X *  r f i l e
X *
X *  Receive File Header
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar rfile()
X{
X    int num, len;			/* Packet number, length */
X    char filnam1[50];			/* Holds the converted file name */
X
X    if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
X
X    switch(rpack(&len,&num,packet))	/* Get a packet */
X    {
X	case 'S':			/* Send-Init, maybe our ACK lost */
X	    if (oldtry++ > MAXTRY) return('A'); /* If too many tries "abort" */
X	    if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
X	    {				/* Yes, ACK it again with  */
X		spar(packet);		/* our Send-Init parameters */
X		spack('Y',num,6,packet);
X		numtry = 0;		/* Reset try counter */
X		return(state);		/* Stay in this state */
X	    }
X	    else return('A');		/* Not previous packet, "abort" */
X
X	case 'Z':			/* End-Of-File */
X	    if (oldtry++ > MAXTRY) return('A');
X	    if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
X	    {				/* Yes, ACK it again. */
X		spack('Y',num,0,0);
X		numtry = 0;
X		return(state);		/* Stay in this state */
X	    }
X	    else return('A');		/* Not previous packet, "abort" */
X
X	case 'F':			/* File Header (just what we want) */
X	    if (num != n) return('A');	/* The packet number must be right */
X	    strcpy(filnam1, packet);	/* Copy the file name */
X
X	    if (filnamcnv)		/* Convert upper case to lower */
X		for (filnam=filnam1; *filnam != '\0'; filnam++)
X		    if (*filnam >= 'A' && *filnam <= 'Z')
X			*filnam |= 040;
X
X	    if ((fp=fopen(filnam1,"w"))==NULL) /* Try to open a new file */
X	    {
X		error("Cannot create %s",filnam1); /* Give up if can't */
X		return('A');
X	    }
X	    else			/* OK, give message */
X		printmsg("Receiving %s as %s",packet,filnam1);
X
X	    spack('Y',n,0,0);		/* Acknowledge the file header */
X	    oldtry = numtry;		/* Reset try counters */
X	    numtry = 0;			/* ... */
X	    n = (n+1)%64;		/* Bump packet number, mod 64 */
X	    return('D');		/* Switch to Data state */
X
X	case 'B':			/* Break transmission (EOT) */
X	    if (num != n) return ('A'); /* Need right packet number here */
X	    spack('Y',n,0,0);		/* Say OK */
X	    return('C');		/* Go to complete state */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE:			/* Didn't get packet */
X	    spack('N',n,0,0);		/* Return a NAK */
X	    return(state);		/* Keep trying */
X
X	default:    return ('A');	/* Some other packet, "abort" */
X    }
X}
X
X
X/*
X *  r d a t a
X *
X *  Receive Data
X */
X
X#ifndef unix
Xstatic
X#endif
Xchar rdata()
X{
X    int num, len;			/* Packet number, length */
X    if (numtry++ > MAXTRY) return('A'); /* "abort" if too many tries */
X
X    switch(rpack(&len,&num,packet))	/* Get packet */
X    {
X	case 'D':			/* Got Data packet */
X	    if (num != n)		/* Right packet? */
X	    {				/* No */
X		if (oldtry++ > MAXTRY)
X		    return('A');	/* If too many tries, abort */
X		if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
X		{			/* Previous packet again? */
X		    spack('Y',num,6,packet); /* Yes, re-ACK it */
X		    numtry = 0;		/* Reset try counter */
X		    return(state);	/* Don't write out data! */
X		}
X		else return('A');	/* sorry, wrong number */
X	    }
X	    /* Got data with right packet number */
X	    bufemp(packet,len);		/* Write the data to the file */
X	    spack('Y',n,0,0);		/* Acknowledge the packet */
X	    oldtry = numtry;		/* Reset the try counters */
X	    numtry = 0;			/* ... */
X	    n = (n+1)%64;		/* Bump packet number, mod 64 */
X	    return('D');		/* Remain in data state */
X
X	case 'F':			/* Got a File Header */
X	    if (oldtry++ > MAXTRY)
X		return('A');		/* If too many tries, "abort" */
X	    if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
X	    {				/* It was the previous one */
X		spack('Y',num,0,0);	/* ACK it again */
X		numtry = 0;		/* Reset try counter */
X		return(state);		/* Stay in Data state */
X	    }
X	    else return('A');		/* Not previous packet, "abort" */
X
X	case 'Z':			/* End-Of-File */
X	    if (num != n) return('A');	/* Must have right packet number */
X	    spack('Y',n,0,0);		/* OK, ACK it. */
X	    fclose(fp);			/* Close the file */
X#ifndef unix
X	    fp = NULL;
X#endif
X	    n = (n+1)%64;		/* Bump packet number */
X	    return('F');		/* Go back to Receive File state */
X
X	case 'E':			/* Error packet received */
X	    prerrpkt(recpkt);		/* Print it out and */
X	    return('A');		/* abort */
X
X	case FALSE:			/* Didn't get packet */
X	    spack('N',n,0,0);		/* Return a NAK */
X	    return(state);		/* Keep trying */
X
X	default:     return('A');	/* Some other packet, "abort" */
X    }
X}
X
X/*
X *  c o n n e c t
X *
X *  Establish a virtual terminal connection with the remote host, over an
X *  assigned tty line.
X */
X
X#ifndef unix
Xstatic
X#endif
Xconnect()
X{
X#ifdef unix
X    int pid,				/* Holds process id of child */
X	connected;			/* Boolean connect flag */
X    char bel = '\07',
X	c;
X
X    struct sgttyb
X	rawmode,			/* Controlling tty raw mode */
X	cookedmode;			/* Controlling tty cooked mode */
X
X    if (remote)				/* Nothing to connect to in remote */
X    {					/* mode, so just return */
X	printmsg("No line specified for connection.");
X	return;
X    }
X
X    gtty(0,&cookedmode);		/* Save current mode so we can */
X    gtty(0,&rawmode);			/* restore it later */
X    rawmode.sg_flags |= (RAW|TANDEM);
X    rawmode.sg_flags &= ~(ECHO|CRMOD);
X    stty(0,&rawmode);			/* Put tty in raw mode */
X
X    pid = fork();	    /* Start fork to get typeout from remote host */
X
X    if (pid)			    /* Parent: send type-in to remote host */
X    {
X	printmsg("connected...\r");
X	connected = TRUE;		/* Put us in "connect mode" */
X	while (connected)
X	{
X	    read(0,&c,1);		/* Get a character */
X	    if ((c&0177) == escchr)	/* Check for escape character */
X	    {
X		read(0,&c,1);
X		if ((c&0177) == escchr)
X		    write(ttyfd,&c,1);
X		else
X		switch (c&0177)
X		{
X		    case 'c':
X		    case 'C':
X			connected = FALSE;
X			write(0,"\r\n",2);
X			break;
X
X		    case 'h':
X		    case 'H':
X			write(0,"\r\nYes, I'm still here...\r\n",26);
X			break;
X
X		    default:
X			write(0,&bel,1);
X			break;
X		}
X	    }
X	    else
X	    {				/* If not escape charater, */
X		write(ttyfd,&c,1);	/* write it out */
X		c = NULL;		/* Nullify it (why?) */
X	    }
X	}
X	kill(pid,9);			/* Done, kill the child */
X	wait(0);			/* and bury him */
X	stty(0,&cookedmode);		/* Restore tty mode */
X	printmsg("disconnected.");
X	return;				/* Done */
X    }
X    else		  /* Child does the reading from the remote host */
X    {
X	while(1)			/* Do this forever */
X	{
X	    read(ttyfd,&c,1);
X	    write(1,&c,1);
X	}
X    }
X#endif
X}
X
X/*
X *	KERMIT utilities.
X */
X
X#ifndef unix
Xstatic
X#endif
Xclkint()				/* Timer interrupt handler */
X{
X    longjmp(env,TRUE);			/* Tell rpack to give up */
X}
X
X
X/*
X *  s p a c k
X *
X *  Send a Packet
X */
X
X#ifndef unix
Xstatic
X#endif
Xspack(type,num,len,data)
Xchar type, *data;
Xint num, len;
X{
X    int i;				/* Character loop counter */
X    char chksum, buffer[100];		/* Checksum, packet buffer */
X    register char *bufp;		/* Buffer pointer */
X
X    if (debug>1)			/* Display outgoing packet */
X    {
X	if (data != NULL)
X	    data[len] = '\0';		/* Null-terminate data to print it */
X	printf("  spack type: %c\n",type);
X	printf("	 num:  %d\n",num);
X	printf("	 len:  %d\n",len);
X	if (data != NULL)
X	    printf("	    data: \"%s\"\n",data);
X    }
X
X    bufp = buffer;			/* Set up buffer pointer */
X    for (i=1; i<=pad; i++) 
X#ifdef unix
X	write(ttyfd,&padchar,1); /* Issue any padding */
X#else
X	xwrite(&padchar,1);
X#endif
X
X    *bufp++ = SOH;			/* Packet marker, ASCII 1 (SOH) */
X    *bufp++ = tochar(len+3);		/* Send the character count */
X    chksum  = tochar(len+3);		/* Initialize the checksum */
X    *bufp++ = tochar(num);		/* Packet number */
X    chksum += tochar(num);		/* Update checksum */
X    *bufp++ = type;			/* Packet type */
X    chksum += type;			/* Update checksum */
X
X    for (i=0; i> 6)+chksum)&077; /* Compute final checksum */
X    *bufp++ = tochar(chksum);		/* Put it in the packet */
X    *bufp = eol;			/* Extra-packet line terminator */
X#ifdef unix
X    write(ttyfd, buffer,bufp-buffer+1); /* Send the packet */
X#else
X    xwrite( buffer,bufp-buffer+1);
X#endif
X}
X
X/*
X *  r p a c k
X *
X *  Read a Packet
X */
X
X#ifndef unix
Xstatic
X#endif
Xrpack(len,num,data)
Xint *len, *num;				/* Packet length, number */
Xchar *data;				/* Packet data */
X{
X    int i, done;			/* Data character number, loop exit */
X    char t,				/* Current input character */
X	type,				/* Packet type */
X	cchksum,			/* Our (computed) checksum */
X	rchksum;			/* Checksum received from other host */
X
X#ifdef unix
X#if UCB4X				/* TOPS-20 can't handle timeouts... */
X    if (setjmp(env)) return FALSE;	/* Timed out, fail */
X    signal(SIGALRM,clkint);		/* Setup the timeout */
X    if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
X    alarm(timint);
X#endif /* UCB4X */
X#else
X
X    if (setjmp(env)) return FALSE;
X    if ((timint > MAXTIM) || (timint < MINTIM)) timint = MYTIME;
X    cntdn = timint * 10;
X
X#define read(a,b,c)	xread(b,c)
X
X#endif
X
X    while (t != SOH)			/* Wait for packet header */
X    {
X	read(ttyfd,&t,1);
X	t &= 0177;			/* Handle parity */
X    }
X
X    done = FALSE;			/* Got SOH, init loop */
X    while (!done)			/* Loop to get a packet */
X    {
X	read(ttyfd,&t,1);		/* Get character */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	cchksum = t;			/* Start the checksum */
X	*len = unchar(t)-3;		/* Character count */
X
X	read(ttyfd,&t,1);		/* Get character */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	cchksum = cchksum + t;		/* Update checksum */
X	*num = unchar(t);		/* Packet number */
X
X	read(ttyfd,&t,1);		/* Get character */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	cchksum = cchksum + t;		/* Update checksum */
X	type = t;			/* Packet type */
X
X	for (i=0; i<*len; i++)		/* The data itself, if any */
X	{				/* Loop for character count */
X	    read(ttyfd,&t,1);		/* Get character */
X	    if (!image) t &= 0177;	/* Handle parity */
X	    if (t == SOH) continue;	/* Resynch if SOH */
X	    cchksum = cchksum + t;	/* Update checksum */
X	    data[i] = t;		/* Put it in the data buffer */
X	}
X	data[*len] = 0;			/* Mark the end of the data */
X
X	read(ttyfd,&t,1);		/* Get last character (checksum) */
X	rchksum = unchar(t);		/* Convert to numeric */
X	read(ttyfd,&t,1);		/* get EOL character and toss it */
X	if (!image) t &= 0177;		/* Handle parity */
X	if (t == SOH) continue;		/* Resynchronize if SOH */
X	done = TRUE;			/* Got checksum, done */
X    }
X
X#ifdef unix
X#if UCB4X
X    alarm(0);				/* Disable the timer interrupt */
X#endif
X#else
X    cntdn = 0;
X#undef read
X#endif
X
X    if (debug>1)			/* Display incoming packet */
X    {
X	if (data != NULL)
X	    data[*len] = '\0';		/* Null-terminate data to print it */
X	printf("  rpack type: %c\n",type);
X	printf("	 num:  %d\n",*num);
X	printf("	 len:  %d\n",*len);
X	if (data != NULL)
X	    printf("	    data: \"%s\"\n",data);
X    }
X					/* Fold in bits 7,8 to compute */
X    cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
X
X    if (cchksum != rchksum) return(FALSE);
X
X    return(type);			/* All OK, return packet type */
X}
X
X
X/*
X *  b u f i l l
X *
X *  Get a bufferful of data from the file that's being sent.
X *  Only control-quoting is done; 8-bit & repeat count prefixes are
X *  not handled.
X */
X
X#ifndef unix
Xstatic
X#endif
Xbufill(buffer)
Xchar buffer[];				/* Buffer */
X{
X    int i,				/* Loop index */
X	t;				/* Char read from file */
X    char t7;				/* 7-bit version of above */
X
X    i = 0;				/* Init data buffer pointer */
X    while((t = getc(fp)) != EOF)	/* Get the next character */
X    {
X	t7 = t & 0177;			/* Get low order 7 bits */
X
X	if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
X	{				    /* special handling? */
X#ifdef unix
X	    if (t=='\n' && !image)
X	    {				/* Do LF->CRLF mapping if !image */
X		buffer[i++] = quote;
X		buffer[i++] = ctl('\r');
X	    }
X#endif
X	    buffer[i++] = quote;	/* Quote the character */
X	    if (t7 != quote)
X	    {
X		t = ctl(t);		/* and uncontrolify */
X		t7 = ctl(t7);
X	    }
X	}
X	if (image)
X	    buffer[i++] = t;		/* Deposit the character itself */
X	else
X	    buffer[i++] = t7;
X
X	if (i >= spsiz-8) return(i);	/* Check length */
X    }
X    if (i==0) return(EOF);		/* Wind up here only on EOF */
X    return(i);				/* Handle partial buffer */
X}
X
X
X/*
X *	b u f e m p
X *
X *  Put data from an incoming packet into a file.
X */
X
X#ifndef unix
Xstatic
X#endif
Xbufemp(buffer,len)
Xchar  buffer[];				/* Buffer */
Xint   len;				/* Length */
X{
X    int i;				/* Counter */
X    char t;				/* Character holder */
X
X    for (i=0; i 'xmodem.c'
X/*
X *  XMODEM Version 1.0  - by Brian Kantor, UCSD
X *
X *  XMODEM -- Implements the "CP/M User's Group XMODEM" protocol, 
X *            for packetized file up/downloading.    
X *
X *	This version is designed for 4.2BSD ONLY!  It won't work
X *	ANYWHERE else - uses the 'select' system call to replace
X *	the old alarm handlers.
X *
X *   -- Based on UMODEM 3.5 by Lauren Weinstein, Richard Conn, and others.
X *
X */
X
X#include 
X#include 
X#include 
X#include 
X
X#ifdef unix
X#include 
X#include 
X#include 
X#else
X#include 
X#include 
X#endif
X
X/* log default define */
X#ifndef LOGDEFAULT
X#define LOGDEFAULT	1
X#endif
X
X/* Delete logfile define.  Useful on small systems with limited
X * filesystem space and careless users.
X */
X#ifndef DELDEFAULT
X#define DELDEFAULT	1
X#endif
X
X#define	     VERSION	10	/* 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#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
X/*  Mode for Created Files  */
X#define      CREATMODE	0644  /* mode for created files */
X
X#ifdef unix
Xstruct sgttyb  ttys, ttysnew, ttystemp;    /* for stty terminal mode calls */
X
Xstruct stat statbuf;  	/* for terminal message on/off control */
Xchar *strcat();
XFILE *LOGFP, *fopen();
Xchar buff[BBUFSIZ];
Xint nbchr;  /* number of chars read so far for buffered read */
X
Xint wason;
X
Xint pagelen;
Xchar *ttyname();  /* forward declaration for C */
Xchar *tty;
Xchar XMITTYPE;
Xint CRCMODE, RECVFLAG, SENDFLAG, PMSG, DELFLAG, LOGFLAG, MUNGMODE;
Xint FILTER, DEBUG;
Xint STATDISP;
Xchar filename[256];
X#else
Xstatic struct stat statbuf;  	
Xstatic FILE *LOGFP;
Xstatic char buff[BBUFSIZ];
Xstatic int nbchr;  
X
Xstatic int wason;
X
Xstatic int pagelen;
Xstatic char *tty;
Xstatic char XMITTYPE;
Xstatic int CRCMODE, RECVFLAG, SENDFLAG, PMSG, DELFLAG, LOGFLAG;
Xstatic int FILTER, DEBUG, MUNGMODE;
Xstatic int STATDISP;
Xstatic char filename[256];
X
X#define exit(a)	longjmp(xjmp, a)
Xstatic jmp_buf xjmp;
X
X#endif
X
X#ifdef unix
Xmain(argc, argv)
X#else
Xxmodem(argc, argv)
X#endif
Xint argc;
Xchar **argv;
X{
X	char *getenv();
X	char *fname = filename;
X	char *logfile;
X	int index;
X	char flag;
X#ifndef unix
X	int boom(), xboom();
X
X	counter(1);	/* setup timeout counter */
X	if (index = setjmp(xjmp)) {
X		counter(0);	/* decommission timeout counter */
X		ctrlbrk(boom);
X		return(index);
X	}
X	else
X		ctrlbrk(xboom);
X#endif
X
X	logfile = "xmodem.log";  /* Name of LOG File */
X
X	printf("\nXMODEM Version %d.%d", VERSION/10, VERSION%10);
X	printf(" -- UNIX-CP/M Remote File Transfer Facility\n");
X
X	if (argc < 3)
X		{
X		help(FALSE);
X		exit(-1);
X		}
X
X	index = 0;  /* set index for loop */
X	PMSG = FALSE;  /* turn off flags */
X	DEBUG = FALSE;
X	RECVFLAG = FALSE;  /* not receive */
X	SENDFLAG = FALSE;  /* not send either */
X	FILTER = FALSE;		/* assume literal mode */
X	CRCMODE = FALSE;	/* use checksums for now */
X	XMITTYPE = 't';  /* assume text */
X
X	DELFLAG = DELDEFAULT;
X	LOGFLAG = LOGDEFAULT;
X	if (LOGFLAG) 
X		LOGFLAG = TRUE;
X	   else
X		LOGFLAG = FALSE;  
X
X	MUNGMODE = FALSE; /* protect files from overwriting */
X
X	while ((flag = argv[1][index++]) != '\0')
X	    switch (flag) {
X		case '-' : break;
X		case 'x' : DEBUG = TRUE;
X			   break;
X/* no crc mode yet
X		case 'c' : CRCMODE = TRUE;
X			   xmdebug("CRC mode selected");
X			   break;
X*/
X		case 'd' : DELFLAG = !DELDEFAULT;  /* delete log file ? */
X			   xmdebug("delete log toggled");
X			   break;
X		case 'l' : LOGFLAG = !LOGDEFAULT;  /* turn off log ? */
X			   xmdebug("write log toggled");
X			   break;
X		case 'm' : MUNGMODE = TRUE; /* allow overwriting of files */
X			   xmdebug("munge mode selected");
X			   break;
X		case 'r' : RECVFLAG = TRUE;  /* receive file */
X			   XMITTYPE = gettype(argv[1][index++]);  /* get t/b */
X			   xmdebug("receive mode selected");
X			   break;
X		case 's' : SENDFLAG = TRUE;  /* send file */
X			   XMITTYPE = gettype(argv[1][index++]);
X			   xmdebug("send mode selected");
X			   break;
X		case 'f' : FILTER = TRUE;
X			   xmdebug("filter selected");
X			   break;
X		default  : error("Invalid Flag", FALSE);
X		}
X
X	if (LOGFLAG)
X	   { 
X#ifdef unix
X	     if ((fname = getenv("HOME")) == 0)	/* Get HOME variable */
X		error("Can't get Environment!", FALSE);
X	     fname = strcat(fname, "/");
X	     fname = strcat(fname, logfile);
X#else
X	     fname = logfile;
X#endif
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("Can't Open Log File", FALSE);
X	     fprintf(LOGFP,"\n\n++++++++\n");
X	     fprintf(LOGFP,"\nXMODEM Version %d.%d\n", VERSION/10, VERSION%10);
X	     printf("\nXMODEM:  LOG File '%s' is Open\n", fname);
X	   }
X
X
X	if (RECVFLAG && SENDFLAG)
X		error("Both Send and Receive Functions Specified", FALSE);
X
X	if (!RECVFLAG && !SENDFLAG)
X		error("Either Send or Receive Function must be chosen!",FALSE);
X	
X	if (FILTER && (!RECVFLAG || XMITTYPE != 't'))
X		error("Filter is only valid in text receive mode!",FALSE);
X
X	if (RECVFLAG)
X		{  
X		if(open(argv[2], 0) != -1)  /* possible abort if file exists */
X	   		{	
X			printf("\nXMODEM:  Warning -- Target File Exists\n");
X			if( MUNGMODE == FALSE )
X				error("Fatal - Can't overwrite file\n",FALSE);
X			printf("XMODEM:  Overwriting Target File\n");
X	   		}
X	   	rfile(argv[2]);  /* receive file */
X		}
X
X	if (SENDFLAG) 
X		sfile(argv[2]);  /* send file */
X	
X	xmdebug("done");
X	if (LOGFLAG) fclose(LOGFP);
X	exit(0);
X}
X
X/*  Print Help Message  */
X#ifndef unix
Xstatic
X#endif
Xhelp()
X	{
X	xmdebug("help:");
X#ifdef unix
X	printf("\nUsage:  \n\txmodem ");
X	printf("-[rb!rt!sb!st][options] filename\n");
X	printf("\nMajor Commands --");
X	printf("\n\trb <-- Receive Binary");
X	printf("\n\trt <-- Receive Text");
X	printf("\n\tsb <-- Send Binary");
X	printf("\n\tst <-- Send Text");
X	printf("\nOptions --");
X#if DELDEFAULT == 1
X	printf("\n\td  <-- Do not delete umodem.log file before starting");
X#else
X	printf("\n\td  <-- Delete umodem.log file before starting");
X#endif
X
X#if LOGDEFAULT == 1
X	printf("\n\tl  <-- (ell) Turn OFF LOG File Entries");
X#else
X	printf("\n\tl  <-- (ell) Turn ON LOG File Entries");
X#endif
X
X/* no crc mode yet
X	printf("\n\tc  <-- Select CRC mode on receive");
X*/
X	printf("\n\tf  <-- Filter 8-bit chars on receive - use with WordStar files");
X	printf("\n");
X#else
X	cprintf("\r\n\
XUsage:  \r\n\txmodem -[rb!rt!sb!st][options] filename\r\n\
X\r\nMajor Commands --\
X\r\n\trb <-- Receive Binary\
X\r\n\trt <-- Receive Text\
X\r\n\tsb <-- Send Binary\
X\r\n\tst <-- Send Text\
X\r\nOptions --\
X\r\n\td  <-- %s\
X\r\n\tl  <-- (ell) %s%s\
X\r\n\tf  <-- Filter 8-bit chars on receive - use with WordStar files\n",
X#if DELDEFAULT == 1
X	"Do not delete xmodem.log file before starting",
X#else
X	"Delete xmodem.log file before starting",
X#endif
X#if LOGDEFAULT == 1
X	"Turn OFF LOG File Entries",
X#else
X	"Turn ON LOG File Entries",
X#endif
X/* no crc mode yet
X	"\r\n\tc  <-- Select CRC mode on receive");
X*/
X	"");
X		
X#endif
X	}
X
X/* get type of transmission requested (text or binary) */
X#ifndef unix
Xstatic
X#endif
Xgettype(ichar)
Xchar ichar;
X	{
X	xmdebug("gettype:");
X	if (ichar == 't') return(ichar);
X	if (ichar == 'b') return(ichar);
X	error("Invalid Send/Receive Parameter - not t or b", FALSE);
X	return;
X	}
X
X/* set tty modes for XMODEM transfers */
X#ifndef unix
Xstatic
X#endif
Xsetmodes()
X	{
X	xmdebug("setmodes:");
X#ifdef unix
X	if (ioctl(0,TIOCGETP,&ttys)<0)  /* get tty params [V7] */
X		error("Can't get TTY Parameters", TRUE);
X
X	tty = ttyname(0);  /* identify current tty */
X	
X	/* transfer current modes to new structure */
X	ttysnew.sg_ispeed = ttys.sg_ispeed;	/* copy input speed */
X	ttysnew.sg_ospeed = ttys.sg_ospeed;	/* copy output speed */
X	ttysnew.sg_erase  = ttys.sg_erase;	/* copy erase flags */
X	ttysnew.sg_flags  = ttys.sg_flags;	/* copy flags */
X 	ttysnew.sg_kill   = ttys.sg_kill;	/* copy std terminal flags */
X
X	ttysnew.sg_flags |= RAW;    /* set for RAW Mode */
X			/* This ORs in the RAW mode value, thereby
X			   setting RAW mode and leaving the other
X			   mode settings unchanged */
X
X	ttysnew.sg_flags &= ~ECHO;  /* set for no echoing */
X			/* This ANDs in the complement of the ECHO
X			   setting (for NO echo), thereby leaving all
X			   current parameters unchanged and turning
X			   OFF ECHO only */
X
X	ttysnew.sg_flags &= ~XTABS;  /* set for no tab expansion */
X	ttysnew.sg_flags &= ~LCASE;  /* set for no upper-to-lower case xlate */
X	ttysnew.sg_flags |= ANYP;  /* set for ANY Parity */
X	ttysnew.sg_flags &= ~NL3;  /* turn off ALL 3s - new line */
X	ttysnew.sg_flags &= ~TAB2; /* turn off tab 3s */
X	ttysnew.sg_flags &= ~CR3;  /* turn off CR 3s */
X	ttysnew.sg_flags &= ~FF1;  /* turn off FF 3s */
X	ttysnew.sg_flags &= ~BS1;  /* turn off BS 3s */
X	ttysnew.sg_flags &= ~TANDEM;  /* turn off flow control */
X
X	/* set new paramters */
X	if (ioctl(0,TIOCSETP,&ttysnew) < 0)
X		error("Can't set new TTY Parameters", TRUE);
X
X	if (stat(tty, &statbuf) < 0)  /* get tty status */ 
X		error("Can't get your TTY Status", TRUE);
X
X	if (statbuf.st_mode & 022)	/* Need to turn messages off */
X		if (chmod(tty, statbuf.st_mode & ~022) < 0)
X			error("Can't change  TTY mode", TRUE);
X		else 
X			wason = TRUE;
X	else 
X		wason = FALSE;
X#endif
X	xmdebug("tty modes set");
X	}
X
X/* restore normal tty modes */
X#ifndef unix
Xstatic
X#endif
Xrestoremodes(errcall)
Xint errcall;
X	{
X	xmdebug("restoremodes:");
X#ifdef unix
X	if (wason)
X		if (chmod(tty, statbuf.st_mode | 022) < 0)
X			error("Can't change TTY mode", FALSE);
X	if (ioctl(0,TIOCSETP,&ttys) < 0)
X		{ if (!errcall)
X		   error("RESET - Can't restore normal TTY Params", FALSE);
X		else
X		   { printf("XMODEM:  ");
X		     printf("RESET - Can't restore normal TTY Params\n");
X		   }
X		}
X#endif
X	xmdebug("tty modes reset");
X	return;
X	}
X
X/* print error message and exit; if mode == TRUE, restore normal tty modes */
X#ifndef unix
Xstatic
X#endif
Xerror(msg, mode)
Xchar *msg;
Xint mode;
X	{
X	xmdebug("error:");
X	if (mode)
X		restoremodes(TRUE);  /* put back normal tty modes */
X	printf("\r\nXMODEM:  %s\n", msg);
X#ifdef unix
X	if ((LOGFLAG || DEBUG) & (int)LOGFP)
X#else
X	if (LOGFLAG || DEBUG)
X#endif
X		{   
X		fprintf(LOGFP, "XMODEM Fatal Error:  %s\n", msg);
X	    	fclose(LOGFP);
X		}
X	exit(-1);
X	}
X
X/**  print status (size) of a file  **/
X#ifndef unix
Xstatic
X#endif
Xyfile(name)
Xchar *name;
X	{
X	xmdebug("yfile:");
X	printf("\nXMODEM File Status Display for %s\n", name);
X
X#ifdef unix
X	if (open(name,0) < 0) 
X#else
X	if (open(name,O_RDONLY|O_BINARY) < 0) 
X#endif
X		{
X		printf("File %s does not exist\n", name);
X		return;
X		}
X	prfilestat(name);  /* print status */
X	printf("\n");
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#ifndef unix
Xstatic
X#endif
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	xmdebug("getbyte:");
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		return(EOF);
X	}
X
X/**  receive a file  **/
X#ifndef unix
Xstatic
X#endif
Xrfile(name)
Xchar *name;
X	{
X	register int bufctr, checksum;
X	register int c;
X	char mode;
X	int fd, j, firstchar, sectnum, sectcurr, tmode;
X	int sectcomp, errors, errorflag, recfin;
X	int errorchar, fatalerror, startstx, inchecksum, endetx, endenq;
X	long recvsectcnt;
X
X	xmdebug("rfile:");
X	mode = XMITTYPE;  /* set t/b mode */
X
X#ifdef unix
X	if ((fd = creat(name, CREATMODE)) < 0)
X#else
X	if ((fd = open(name, O_WRONLY|O_BINARY|O_CREAT, CREATMODE)) < 0)
X#endif
X	  	error("Can't create file for receive", FALSE);
X
X	printf("XMODEM:  Ready to RECEIVE File %s\n", name);
X	puts("Control-X to cancel.\n");
X
X	if (LOGFLAG)
X		{    
X		fprintf(LOGFP, "\n----\nXMODEM Receive Function\n");
X	     	fprintf(LOGFP, "File Name: %s\n", name);
X		}
X
X	setmodes();  /* setup tty modes for xfer */
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	if (CRCMODE)
X		{
X		xmdebug("crc mode request sent");
X		sendbyte('C');	/* CRC request for first block */
X		}
X	else
X		{
X		xmdebug("NAK sent");
X		sendbyte(NAK);  /* Start up the sender's first block */
X		}
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			xmdebug("first char was timeout");
X			if (LOGFLAG)
X				fprintf(LOGFP, "Timeout on Sector %d\n", sectnum);
X               		errorflag = TRUE;
X	    		}
X
X            	if ((firstchar & 0x7f) == CAN)
X	    		{  
X			xmdebug("CAN received");
X			if (LOGFLAG)
X				fprintf(LOGFP, "Reception canceled at user's request.\n");
X			error("Reception canceled at user's request",TRUE);
X	    		}
X
X            	if (firstchar == SOH)
X	   		{
X			xmdebug("SOH received");
X               		sectcurr = readbyte(3);
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 (FILTER)	/* bit 8 */
X							buff[bufctr] &= 0x7f;
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						xmdebug("checksum ok");
X						errors = 0;
X						recvsectcnt++;
X		        			sectnum = sectcurr; 
X						if (write(fd, buff, bufctr) < 0)
X			   				error("File Write Error", TRUE);
X		        			else
X			   				sendbyte(ACK);
X		     				}
X		     			else
X		     				{  
X						xmdebug("checksum bad");
X						if (LOGFLAG)
X							fprintf(LOGFP, "Checksum Error on Sector %d\n",
X								sectnum);
X		        			errorflag = TRUE;
X		     				}
X                  			}
X                  		else
X                  			{ 
X					if (sectcurr == sectnum)
X                    				{  
X						xmdebug("dup sector flushed");
X						while(readbyte(3) != TIMEOUT)
X							;
X            	       				sendbyte(ACK);
X                    				}
X                    			else
X		    				{  
X						xmdebug("sector out of seq");
X						if (LOGFLAG)
X							{ 
X							fprintf(LOGFP, "Phase Error - Received Sector is ");
X			  				fprintf(LOGFP, "%d while Expected Sector is %d\n",
X			   					sectcurr, ((sectnum+1) & 0xff));
X							}
X						errorflag = TRUE;
X						fatalerror = TRUE;
X						sendbyte(CAN);
X		    				}
X	          			}
X           			}
X			else
X	   			{  
X				if (DEBUG)
X					fprintf(LOGFP,"DEBUG: bad sector# sectcurr=%02xH, sectcomp=%02xH\n",sectcurr,sectcomp);
X				if (LOGFLAG)
X					fprintf(LOGFP, "Header Sector Number Error on Sector %d\n",
X		   				sectnum);
X               			errorflag = TRUE;
X	   			}
X        		}
X	
X        	if (errorflag)
X        		{  
X			xmdebug("flushing bad sector");
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))
X  		{
X		xmdebug("EOT received");
X     		close(fd);
X		sendbyte(ACK);
X     		restoremodes(FALSE);  /* restore normal tty modes */
X#ifdef unix
X     		sleep(5);  /* give other side time to return to terminal mode */
X#endif
X     		if (LOGFLAG)
X     			{  
X			fprintf(LOGFP, "\nReceive Complete\n");
X			fprintf(LOGFP,"Number of Received CP/M Records is %ld\n", recvsectcnt);
X     			}
X     		printf("\n");
X  		}
X  	else
X  		{ 
X		sendbyte(CAN);
X		xmdebug("error limit exceeded");
X     		error("\r\nABORTED -- Too Many Errors", TRUE);
X  		}
X	}
X
X/**  send a file  **/
X#ifndef unix
Xstatic
X#endif
Xsfile(name)
Xchar *name;
X	{
X	register int bufctr, checksum, sectnum;
X	char blockbuf[134];
X	char mode;
X	int fd, attempts;
X	int nlflag, sendfin, tmode;
X	int bbufcnt;
X	int firstchar;
X	char c;
X	int sendresp;  /* response char to sent block */
X
X	xmdebug("sfile:");
X	nbchr = 0;  /* clear buffered read char count */
X	mode = XMITTYPE;  /* set t/b mode */
X		
X#ifdef unix
X	if ((fd = open(name, 0)) < 0)
X#else
X	if ((fd = open(name, O_RDONLY|O_BINARY)) < 0)
X#endif
X		{  
X		if (LOGFLAG) fprintf(LOGFP, "Can't Open File\n");
X     	   	error("Can't open file for send", FALSE);
X		}
X
X
X	printf("XMODEM:  File %s Ready to SEND\n", name);
X	prfilestat(name);  /* print file size statistics */
X	puts("\nControl-X to cancel.\n");
X
X	if (LOGFLAG)
X		{   
X		fprintf(LOGFP, "\n----\nXMODEM Send Function\n");
X	    	fprintf(LOGFP, "File Name: %s\n", name);
X		}
X
X	if (mode == 't')
X	   tmode = TRUE;
X	else
X	   tmode = FALSE;
X
X        sendfin = nlflag = FALSE;
X  	attempts = 0;
X
X	setmodes();  /* setup tty modes for xfer */	
X
X	while (((firstchar=readbyte(30)) != NAK)
X/* no crc mode yet
X	&& (firstchar != 'C') 
X*/
X	&& (firstchar != CAN))
X		{
X		if (++attempts > RETRYMAX)
X			error("Remote System Not Responding", TRUE);
X		}
X
X	if ((firstchar & 0x7f) == CAN)
X		{
X#ifndef unix
Xcanned:
X#endif
X		xmdebug("can received");
X		error("\nSend cancelled at user's request.\n",TRUE);
X		exit(-1);
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			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		   		if (tmode)
X		      			buff[bufctr++] = CTRLZ;  /* Control-Z for CP/M EOF */
X	           		else
X#ifdef unix
X		      			bufctr++;
X#else
X		      			buff[bufctr++] = '\0';
X#endif
X		   		continue;
X		      		}
X
X#ifdef unix
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#else
X			buff[bufctr++] = c;
X#endif
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#ifdef unix
X			write(1, blockbuf, 132);  /* write the block */
X#else
X			if (DEBUG)
X				cprintf(" %d", sectnum);
X			xwrite(blockbuf, 132);
X#endif
X
X                	attempts++;
X			sendresp = readbyte(10);  /* get response */
X			if ((sendresp != ACK) && LOGFLAG)
X		   		{
X		   		fprintf(LOGFP, "Non-ACK (%2x) Received on Sector %d\n",sendresp,sectnum);
X		   		if (sendresp == TIMEOUT)
X					fprintf(LOGFP, "This Non-ACK was a TIMEOUT\n");
X				if (sendresp == CAN)	goto canned;
X		   		}
X            		}
X			while((sendresp != ACK) && (attempts < RETRYMAX));
X
X       		sectnum++;  /* increment to next sector number */
X    		}
X		while (!sendfin && (attempts < RETRYMAX));
X
X    	if (attempts >= RETRYMAX)
X		error("Remote System Not Responding", TRUE);
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", TRUE);
X
X    	close(fd);
X    	restoremodes(FALSE);  
X#ifdef unix
X    	sleep(15);  /* give other side time to return to terminal mode */
X#endif
X
X    	if (LOGFLAG)
X    		fprintf(LOGFP, "\nSend Complete\n");
X    	printf("\n");
X
X	}
X
X/*  print file size status information  */
X#ifndef unix
Xstatic
X#endif
Xprfilestat(name)
Xchar *name;
X	{
X	struct stat filestatbuf; /* file status info */
X
X	xmdebug("prfilestat:");
X	stat(name, &filestatbuf);  /* get file status bytes */
X	printf("  Estimated File Size %ldK, %ld Records, %ld Bytes",
X	  	(filestatbuf.st_size/1024)+1, (filestatbuf.st_size/128)+1,
X	  	filestatbuf.st_size);
X	if (LOGFLAG)
X	  	fprintf(LOGFP,"Estimated File Size %ldK, %ld Records, %ld Bytes\n",
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#ifdef unix
Xint readbyte(seconds)
X#else
Xstatic int
Xreadbyte(seconds)
X#endif
Xint seconds;
X	{
X#ifdef unix
X	char c;
X	int i, readfd;
X	struct timeval tmout;
X
X	tmout.tv_sec = seconds;
X	tmout.tv_usec = 0;
X
X	readfd = 1;
X
X	if ((i=select(1, &readfd, 0, 0, &tmout)) == 0)
X		{
X		xmdebug("readbyte timeout");
X		return(TIMEOUT);
X		}
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: readbyte select returned %d\n",i);
X
X	read(0, &c, 1);
X#else
X	int c;
X	extern int recv_byt();
X	extern unsigned int cntdn;
X
X	cntdn = seconds * 10;	/* cntdn == 100 ms decrements */
X
X	do { c = recv_byt(); } while (c < 0 && cntdn);
X
X	cntdn = 0;
X
X	if (c < 0) return(TIMEOUT);
X#endif
X
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: readbyte %02xh\n",c);
X
X	return(c & 0xff);  /* return the char */
X	}
X
X/* send a byte to data stream */
X#ifndef unix
Xstatic
X#endif
Xsendbyte(data)
Xchar data;
X	{
X#ifdef unix
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: sendbyte %02xh\n",data);
X	write(1, &data, 1);  	/* write the byte */
X	ioctl(1,TIOCFLUSH,0);	/* flush so it really happens now! */
X#else
X	extern int xmit_chr();
X
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: sendbyte %02xh\n",data);
X	xmit_chr(data);
X#endif
X	return;
X	}
X
X/* type out debugging info */
X#ifndef unix
Xstatic
X#endif
Xxmdebug(str)
Xchar *str;
X	{
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: '%s'\n",str);
X	}
X
X#ifndef unix
Xstatic 
Xxwrite(p, n)
Xchar *p;
Xint n;
X{
X	if (DEBUG)
X		fprintf(LOGFP,"DEBUG: xwrite %d bytes\n",n);
X	while(n--)
X		xmit_chr(*p++);
X}
X
Xstatic
Xxboom()
X{
X	error("user break");
X}
X#endif
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0