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