[net.sources] uc.c and uc.1l

emigh@ecsvax.UUCP (09/27/83)

: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting uc.1l'
sed 's/^X//' <<'//go.sysin dd *' >uc.1l
X.TH UC 1
X.SH NAME
uc - Version 1.0 - UNIX-to-CP/M File Transfer Tool
X.SH SYNOPSIS

UC is a file transfer tool which runs under UNIX.  It, in conjunction
with a CP/M-based MODEM communications program, allows the user to transfer
both binary and text files between UNIX and CP/M.

UC is based on ideas from UMODEM 3.5.
UC is a totally new design, including many features
of similar function but different implementation and adding many new
features and both a menu-driven and command-completion user interface.

Usage:  uc c[o] [filename]

where 'c' MUST be One of the Following Commands --
        C -- CRC Check on Binary File (filename required)
        c -- CRC Check on Text File (filename required)
        f or F -- File Status (filename required)
        R -- Receive Binary File (filename required)
        r -- Receive Text File (filename required)
        S -- Send Binary File (filename required)
        s -- Send Text File (filename required)
        z or Z -- Enter Command Mode (filename NOT required)

and Additional Options 'o' Include --
        1 -- Select File Transfer Protocol 1
        7 -- Select 7-Bit Transfer
        a or A -- Enable ARPA Net Communication
        b or B -- Override 'c', 's', or 'r' to Binary
        l or L -- Turn Off Log Entries
        t or T -- Override 'C', 'S', or 'R' to Text

Examples:
        uc S myfile -or- uc sb myfile   <-- Send Binary File
        uc s7l myfile   <-- Send Text File with 7 Bits and No Log
X.SH DESCRIPTION
X.fi
	UC is a file transfer tool which runs on UNIX.  It allows the
user to transfer files between UNIX and CP/M systems, verify the integrity
of transferred files via Cyclic Redundancy Check (CRC) value computation,
and perform other functions useful in file transfer.

	UC implements the following communications protocols:

		1) "CP/M User's Group XMODEM" protocol developed by
Ward Christensen (checksum only)

		2) TERM II/TERM III File Transfer Protocol 1 developed
by Richard Conn

	UC supports 7- or 8-bit transfers (7 or 8 significant bits/byte) for
text files and 8-bit transfers for binary files.

There is currently no batch file transfer capability.

The program
writes logging data to a file in the user's home directory
called uc.log.  This file contains a transaction of activity
since the invocation of the program, and this transaction includes
data on file transmissions (error log).

The program's defaults can be initialized for each user by a setup file
called .ucsetup (note the leading dot, so .ucsetup is hidden from
normal directory displays).  .ucsetup is a text file which contains
initialization options for uc.  It can be created by using any
editor under UNIX.

The program will do a protocol file transfer with error checking
to or from a CP/M system running Ward Christensen's program MODEM
or one of its derivatives (MODEM7 or APMOD777 etc.) or any
program that uses the same protocols (e.g. ZPRO or TERM II).  Note that
executable and squeezed files must use the -sb or -rb options.
X.SS UC SETUP FILE
If a file named .ucsetup is present in the user's home directory,
then uc will load this file and interpret commands from it.  These
commands, which are similar to the command line and command mode options,
establish default conditions for uc.  If .ucsetup is not present in
the user's home directory, then uc will configure itself with its default
values.

The following are the characters which may be placed in a .ucsetup
file to establish working conditions for uc:

X.nf

Char	Function
 !	Comment, extending from "!" to end of line
 1	Select FTP 1
 3	Select FTP 3 (CP/M User's Group Protocol)
 7	Select 7-Bit Transmission
 8	Select 8-Bit Transmission
a/A	Turn on ARPA Net Communication
l/L	Turn on Logging to uc.log
m/M	Turn on Menu Display for uc Command Mode
 -	Negate Effect of a/A, l/L, or m/M: -a/-A, -l/-L, or -m/-M

X.fi
If a command is omitted or the .ucsetup file is not found in the user's
home directory, then the following defaults apply:

X.nf
 3   FTP 3 (CP/M User's Group Protocol)
 8   8-Bit Transmission
-A   No ARPA Net Communication
 L   Activity Log uc.log is Generated
-M   No Menu Display for uc Command Mode

X.fi
The following is a sample (and complete) .ucsetup file:

X.nf

!  UC Configuration File for Richard Conn
3  !  Use FTP 3 (since 3 is default, this is not necessary)
8  !  Use 8 Bits
-a !  No ARPA Net Communication
-m !  No Menu
L  !  Log File

X.fi
X.SS UC COMMAND MODE
The following options are supported under the command mode of uc:

X.nf
                           UC Command Summary

   ------- Major Function -------    -- File Xfer Options --
    c <file>  CRC Value of File      1 or 3  Select FTP
    r <file>  Receive File           7 or 8  Select Bits
    s <file>  Send File              a or A  Toggle ARPA Net
                                     e or E  Display Environ

   ------- UNIX  Function -------    -------- Notes --------
   d <dir/file> Display Directory    Major Fct - if caps(C),
   f <file>     File Size Info       binary file; if not(c),
   l <dir>      Log Into Dir         text file
   m            Toggle Menu
   x            Exit to UNIX         UNIX Fct - either case
   z            UNIX Command

X.fi
A sample session which illustrates the command mode of uc follows.
Comments are inserted into the session; these comments are preceeded
by '<--' and continue to the end of the line.

X.nf
$ uc z
	<-- Invoke uc in command mode
UC Version 1.0 - UNIX-to-CP/M File Transfer Tool
UC Configuration File /user/rxc/.ucsetup
UC Command Mode -- Type 'h' for Help
UC Command?
	<-- You can type h, H, ?, or / to receive online doc
UC Command? Directory of (dir or file spec)
	<-- I typed "d" and <CR> (<CR> selects all files)
  -- Filename --  - Size -      -- Filename --  - Size -
  comhex.1             810      menu.1              8571
  comhex.man          1448      menu.man           10706
  cpmunix.1            825      skeleton             146
  cpmunix.man         1490      type.1              1575
  cpmutl7.doc          766      type.man            2239
  crck.1              1553      uc.1                7743
  crck.man            2189      uc.man              9338
  dir.1               5542      umodem.1            4751
  dir.man             5744      umodem.man          6440
  man.1               3968      unixcpm.1            617
  man.doc            14827      unixcpm.man         1284
  man.menu             784
           -- 23 Entries Displayed, 93356 Bytes --
UC Command? Login (directory) /user/rxc/.c
	<-- I typed "l" and "/us..."
X/user/rxc/.c	<-- uc showed new dir
UC Command? Directory of (dir or file spec)
	<-- I typed "d" and <CR>
  -- Filename --  - Size -      -- Filename --  - Size -
  dir.c               7485      uc.c               30629
           -- 2 Entries Displayed, 38114 Bytes --
UC Command? Directory of (dir or file spec) /user/rxc/.man
  -- Filename --  - Size -      -- Filename --  - Size -
  comhex.1             810      menu.1              8571
  comhex.man          1448      menu.man           10706
  cpmunix.1            825      skeleton             146
  cpmunix.man         1490      type.1              1575
  cpmutl7.doc          766      type.man            2239
  crck.1              1553      uc.1                7743
  crck.man            2189      uc.man              9338
  dir.1               5542      umodem.1            4751
  dir.man             5744      umodem.man          6440
  man.1               3968      unixcpm.1            617
  man.doc            14827      unixcpm.man         1284
  man.menu             784
           -- 23 Entries Displayed, 93356 Bytes --
UC Command? UNIX Command Line (command line) pwd
X/user/rxc/.c

UC Command? File Status of (file name) dir.c
	<-- I typed "f" and "dir.c"
File Size of dir.c is 26K, 201 Blocks
UC Command? File Status of (file name) uc.c
File Size of uc.c is 27K, 216 Blocks
UC Command? CRC of Text File (file name) uc.c
	<-- I typed "c" and "uc.c"
CRC of uc.c is 72EE
UC Command? CRC of Binary File (file name)
	<-- typing "C" gives binary, and striking <CR> usually aborts
UC Command? Send Text File (file name) dir.c
	<-- I typed "s" and "dir.c"
UC Sending File: dir.c
File Size of dir.c is 26K, 201 Blocks
FTP 3, 8-Bit Transfer Selected
Ready to Send File

<-- Detail Left Out -->
UC Command? Exit

X.fi
X.SH FILES
X.nf
 uc.c       <-- source code
 uc.log     <-- activity log file
 .ucsetup   <-- user-specific setup options
 dir.c      <-- source code to directory display program
 dir        <-- binary file executed by uc for directory displays
X.fi

X.SH INSTALLATION NOTES
	UC uses another program, dir, to provide its
directory displays.  This program should be placed by the user in a
directory along his command search path (as identified by the PATH
shell variable).

	Creation and installation of the setup file, .ucsetup, is
not mandatory.  If the user desires this, .ucsetup must be placed
in his HOME directory (as identified by the HOME shell variable).

X.SH SEE ALSO
DIR (1)

X.SH WARNING
	UC has been tested extensively except for the ARPA Net
interface.  This interface is believed to work correctly, but
problems may exist which are unknown at this tim.

X.SH AUTHOR
Richard Conn
X.sp 2
DDN Addresses: rconn@brl, rconn@simtel20
X.sp 2
UC is based on ideas from UMODEM 3.5, where UMODEM was originally written
by Lauren Weinstein, and was mutated by Richard Conn, Bennett Marks,
Michael Rubenstein, Ben Goldfarb, David Hinnant, and Lauren Weinstein
into version 3.5.  UC is a totally new design, including many features
of similar function but different implementation and adding many new
features and both a menu-driven and command-completion user interface.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 uc.1l
	/bin/echo -n '	'; /bin/ls -ld uc.1l
fi
/bin/echo 'Extracting uc.c'
sed 's/^X//' <<'//go.sysin dd *' >uc.c
X/*
 *  UC - a UNIX-to-CP/M file transfer shell
 *	by Richard Conn
 *
 *  UC is based on ideas from UMODEM 3.5, where UMODEM was originally written
 *  by Lauren Weinstein, and was mutated by Richard Conn, Bennett Marks,
 *  Michael Rubenstein, Ben Goldfarb, David Hinnant, and Lauren Weinstein
 *  into version 3.5.  UC is a totally new design, including many features
 *  of similar function but different implementation and adding many new
 *  features and both a menu-driven and command-completion user interface.
 *
 *  UC is a rather complete rewrite of the UMODEM program, with emphasis
 *  on implementation as a "pseudo-shell".
 *
 */

#define	versmaj	1	/* Major Version */
#define	versmin	1	/* Minor Version */

X/*  Basics  */
#define	FALSE	0
#define	TRUE	~FALSE

X/*  ASCII Characters  */
#define	SOH	001
#define	STX	002
#define	ETX	003
#define	EOT	004
#define	ENQ	005
#define	ACK	006
#define	LF	012
#define	CR	015
#define	NAK	025
#define	SYN	026
#define	CAN	030
#define	CTRLZ	032
#define	ESC	033

X/*  UC Constants  */
#define	TO	-1		/* Timeout Flag */
#define	ERRMAX	10		/* Max errors tolerated */
#define	BLOCKSZ	128		/* Size of transmission block */
#define	CREATE	0644		/* Mode for New Files */
#define	LOGFILE	"uc.log"	/* Log File */
#define	CFGFILE	".ucsetup"	/* Configuration File */

X/*  UC Defaults  */
#define	defarpa	FALSE		/* Not Using ARPA Net */
#define	defmenu	FALSE		/* Menu */
#define	defftp	3		/* FTP */
#define	deflog	TRUE		/* Log to Disk? */
#define	defbit7	FALSE		/* 7-Bit Transfer? */

X/*  Library Utilities  */
#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<sgtty.h>
#include	<signal.h>
#include	<ctype.h>

X/*  Configuration Structure  */
struct environ {
	char filetype;	/* text or binary */
	int ftp;	/* File Transfer Protocol */
	int logflg;	/* log error summary to file */
	FILE *logfd;	/* file descriptor for log file */
	int bit7;	/* allow only 7-bit transfers */
	int menu;	/* menu for command mode */
	int arpa;	/* negotiate binary on ARPA Net */
}

X/*  ARPA Net Constants  */
X/*	The following constants are used to communicate with the ARPA
 *	Net SERVER TELNET and TAC programs.  These constants are defined
 *	as follows:
 *		IAC			<-- Is A Command; indicates that
 *						a command follows
 *		WILL/WONT		<-- Command issued to SERVER TELNET
 *						(Host); WILL issues command
 *						and WONT issues negative of
 *						the command
 *		DO/DONT			<-- Command issued to TAC; DO issues
 *						command and DONT issues
 *						negative of the command
 *		TRBIN			<-- Transmit Binary Command
 *	Examples:
 *		IAC WILL TRBIN	<-- Host is configured to transmit Binary
 *		IAC WONT TRBIN	<-- Host is configured NOT to transmit binary
 *		IAC DO TRBIN	<-- TIP is configured to transmit Binary
 *		IAC DONT TRBIN	<-- TIP is configured NOT to transmit binary
 */
#define	     IAC	0377	/* Is A Command */
#define	     DO		0375	/* Command to TAC */
#define	     DONT	0376	/* Negative of Command to TAC */
#define	     WILL	0373	/* Command to SERVER TELNET (Host) */
#define	     WONT	0374	/* Negative of Command to SERVER TELNET */
#define	     TRBIN	0	/* Transmit Binary Command */

main (argc, argv)
int argc;
char *argv[];
{
	int sendflg, recvflg, statflg, cmndflg;	/* major functions */
	int crckflg;				/* major function */
	struct environ genv;			/* global environ */
	FILE *fopen();				/* forward ref */

	int index;	/* index for arg parsing loop */
	char opt;	/* current option character */
	char *getenv();	/* getenv function defn */
	char logfile[50];	/* space for name of log file */
	char cfgfile[50];	/* space for name of configuration file */

	/* Print Banner */
	printf("UC Version %d.%d - UNIX-to-CP/M File Transfer Tool\n",
	versmaj, versmin);

	/* Check for Help Request */
	if (argc == 1) {
		help();
		exit(0);
	}

	/* Determine Name of Log File */
	strcat (logfile, getenv("HOME"));	/* Name of Home Dir */
	strcat (logfile, "/");			/* Separator */
	strcat (logfile, LOGFILE);		/* Name of Log File */

	/* Determine Name of Configuration File */
	strcat (cfgfile, getenv("HOME"));	/* Name of Home Dir */
	strcat (cfgfile, "/");			/* Separator */
	strcat (cfgfile, CFGFILE);		/* Name of Configuration File */

	/* Set Defaults for ARPA Net, Menu, FTP, Logging, and 7/8-Bit Xfer */
	genv.logflg = deflog;
	genv.bit7 = defbit7;
	genv.ftp = defftp;
	genv.menu = defmenu;
	genv.arpa = defarpa;
	getdef (cfgfile, &genv);		/* Get Defs from File */

	/* Init for Option Parsing */
	sendflg = FALSE;
	recvflg = FALSE;
	statflg = FALSE;
	crckflg = FALSE;
	cmndflg = FALSE;

	/* Process Options */
	index = 0;
	while ((opt = argv[1][index++]) != '\0')
		switch (opt) {
		case '-' :		/* skip dash */
			break;
		case '1' :
			genv.ftp = 1;	/* select FTP 1 */
			break;
		case '3' :
			genv.ftp = 3;	/* select FTP 3 */
			break;
		case '7' :
			genv.bit7 = TRUE;	/* set 7 bits */
			break;
		case '8' :
			genv.bit7 = FALSE;	/* set 8 bits */
			break;
		case 'A' :
		case 'a' :
			genv.arpa = TRUE;	/* set ARPA Net */
			break;
		case 'B' :
		case 'b' :
			genv.filetype = 'b';	/* set binary type */
			break;
		case 'C' :
			crckflg = TRUE;	/* set crc check mode */
			genv.filetype = 'b';	/* binary */
			break;
		case 'c' :
			crckflg = TRUE;	/* set crc check mode */
			genv.filetype = 't';	/* text */
			break;
		case 'F' :
		case 'f' :
			statflg = TRUE;	/* set file stat mode */
			break;
		case 'L' :
		case 'l' :
			genv.logflg = ~genv.logflg;  /* comp log */
			break;
		case 'R' :
			recvflg = TRUE;	/* set file recv mode */
			genv.filetype = 'b';
			break;
		case 'r' :
			recvflg = TRUE;	/* set file recv mode */
			genv.filetype = 't';
			break;
		case 'S' :
			sendflg = TRUE;	/* set file send mode */
			genv.filetype = 'b';
			break;
		case 's' :
			sendflg = TRUE;	/* set file send mode */
			genv.filetype = 't';
			break;
		case 'T' :
		case 't' :
			genv.filetype = 't';	/* set text file type */
			break;
		case 'Z' :
		case 'z' :
			cmndflg = TRUE;	/* set command mode */
			break;
		default :
			printf("Invalid Option %c\n", opt);
			break;
		}

	/* Open Log File if Needed */
	if (sendflg || recvflg || cmndflg && genv.logflg) {
		genv.logfd = fopen(logfile, "w");
		if (genv.logfd == NULL) {
			printf("Can't Open Log File\n");
			exit(0);
		}
	}

	/* Select and Execute Major Mode */
	if (cmndflg) {		/* Command Mode */
		command(&genv);
		if (genv.logflg) fclose(genv.logfd);
		exit(0);
	}
	if (statflg) {		/* File Status Display */
		if (argc < 3) {
			printf("File Name NOT Given\n");
			exit(0);
		}
		genv.logflg = FALSE;	/* no logging right now */
		fstat(&genv,argv[2]);
		exit(0);
	}
	if (crckflg) {		/* CRC Check */
		if (argc < 3) {
			printf("File Name NOT Given\n");
			exit(0);
		}
		if (genv.filetype == 't') crct(argv[2]);
		else crcb(argv[2]);
		exit(0);
	}
	if (sendflg) {		/* Send File */
		if (argc < 3) {
			printf("File Name NOT Given\n");
			exit(0);
		}
		send(&genv,argv[2]);
		if (genv.logflg) fclose(genv.logfd);
		exit(0);
	}
	if (recvflg) {		/* Receive File */
		if (argc < 3) {
			printf("File Name NOT Given\n");
			exit(0);
		}
		recv(&genv,argv[2]);
		if (genv.logflg) fclose(genv.logfd);
		exit(0);
	}
	printf("Major Mode NOT Selected\n");
	help();
	exit(0);
}

X/* Get Defaults from User's Configuration File, if Any */
getdef (filename, env)
char *filename;
struct environ *env;
{
	FILE *fd;	/* File Descriptor */
	FILE *fopen();	/* fopen Function */
	int c;		/* Dummy Input Char */

	/* Open File */
	if ((fd = fopen (filename, "r")) == NULL) return;	/* no file */
	printf("UC Configuration File %s\n", filename);

	/* Read Loop */
	while ((c = getc(fd)) != EOF)
		switch (c) {
		case '-' :
			c = getc(fd);	/* get next char */
			switch (c) {
			case 'A' :
			case 'a' :
				env->arpa = FALSE;
				break;
			case 'L' :
			case 'l' :
				env->logflg = FALSE;
				break;
			case 'M' :
			case 'm' :
				env->menu = FALSE;
				break;
			default :
				ungetc(fd,c);	/* put back */
				break;
			}
			break;
		case '!' :	/* Comment */
			do {
				c = getc(fd);	/* Flush Comment */
			}
			while (c != LF && c != EOF);
			if (c == EOF) ungetc(fd,c);
			break;
		case '1' :
			env->ftp = 1;
			break;
		case '3' :
			env->ftp = 3;
			break;
		case '7' :
			env->bit7 = TRUE;
			break;
		case '8' :
			env->bit7 = FALSE;
			break;
		case 'A' :
		case 'a' :
			env->arpa = TRUE;
		case 'L' :
		case 'l' :
			env->logflg = TRUE;
			break;
		case 'M' :
		case 'm' :
			env->menu = TRUE;
			break;
		default :
			break;
		}

	/* Close File */
	fclose(fd);
}

X/* Print Help */
help()
{
	printf("Usage:  uc c[o] [filename]\n");
	printf("\n");
	printf("where 'c' MUST be One of the Following Commands --\n");
	printf("\tC -- CRC Check on Binary File (filename required)\n");
	printf("\tc -- CRC Check on Text File (filename required)\n");
	printf("\tf or F -- File Status (filename required)\n");
	printf("\tR -- Receive Binary File (filename required)\n");
	printf("\tr -- Receive Text File (filename required)\n");
	printf("\tS -- Send Binary File (filename required)\n");
	printf("\ts -- Send Text File (filename required)\n");
	printf("\tz or Z -- Enter Command Mode (filename NOT required)\n");
	printf("\n");
	printf("and Additional Options 'o' Include --\n");
	printf("\t1 -- Select File Transfer Protocol 1\n");
	printf("\t7 -- Select 7-Bit Transfer\n");
	printf("\ta or A -- Enable ARPA Net Communication\n");
	printf("\tb or B -- Override 'c', 's', or 'r' to Binary\n");
	printf("\tl or L -- Turn Off Log Entries\n");
	printf("\tt or T -- Override 'C', 'S', or 'R' to Text\n");
	printf("\n");
	printf("Examples:\n");
	printf("\tuc S myfile -or- uc sb myfile	<-- Send Binary File\n");
	printf("\tuc s7l myfile	<-- Send Text File with 7 Bits and No Log\n");
}

X/* Command Mode */
command(env)
struct environ *env;
{
	int charx(), chelp();
	int running;
	int tlogflg;
	char c, uline[200], cline[200];

	printf("UC Command Mode -- Type 'h' for Help\n");
	running = TRUE;
	while (running) {
		if (env->menu) chelp();
		printf("UC Command? ");
		switch (c = charx()) {
		case CR :
			printf("\n");
			break;
		case '1' :
			env->ftp = 1;
			printf("FTP 1\n");
			break;
		case '3' :
			env->ftp = 3;
			printf("FTP 3\n");
			break;
		case '7' :
			env->bit7 = TRUE;
			printf("7-Bit Transmission\n");
			break;
		case '8' :
			env->bit7 = FALSE;
			printf("8-Bit Transmission\n");
			break;
		case 'A' :
		case 'a' :
			env->arpa = ~env->arpa;
			printf("ARPA Net Communication %s\n",
				env->arpa ? "Enabled" : "Disabled");
			break;
		case 'C' :
			printf("CRC of Binary File (file name) ");
			gets(uline);
			if (uline[0]) crcb(uline);
			break;
		case 'c' :
			printf("CRC of Text File (file name) ");
			gets(uline);
			if (uline[0]) crct(uline);
			break;
		case 'D' :
		case 'd' :
			printf("Directory of (dir or file spec) ");
			gets(uline);
			cline[0] = '\0';
			strcat (cline, "dir ");
			strcat (cline, uline);
			system(cline);
			break;
		case 'E' :
		case 'e' :
			printf("Transmission Environment\n");
			printf("\tFile Transfer Protocol %c\n",
			env->ftp==1 ? '1' : '3');
			printf("\t%c-Bit Transfer\n",
			env->bit7 ? '7' : '8');
			printf("\tARPA Net Communication %s\n",
			env->arpa ? "Enabled" : "Disabled");
			break;
		case 'F' :
		case 'f' :
			printf("File Status of (file name) ");
			gets(uline);
			tlogflg = env->logflg;
			env->logflg = FALSE;
			if (uline[0]) fstat(env,uline);
			env->logflg = tlogflg;
			break;
		case '?' :
		case '/' :
		case 'H' :
		case 'h' :
			printf("\n");
			chelp();
			break;
		case 'L' :
		case 'l' :
			printf("Login (directory) ");
			gets(uline);
			if (uline[0]) chdir(uline);
			system("pwd");
			break;
		case 'M' :
		case 'm' :
			env->menu = ~env->menu;	/* toggle menu */
			printf("Menu %s\n", env->menu ? "ON" : "OFF");
			break;
		case 'R' :
			env->filetype = 'b';
			env->bit7 = FALSE;
			printf("Receive Binary File (file name) ");
			gets(uline);
			if (uline[0]) recv(env,uline);
			printf("\n");
			break;
		case 'r' :
			env->filetype = 't';
			printf("Receive Text File (file name) ");
			gets(uline);
			if (uline[0]) recv(env,uline);
			printf("\n");
			break;
		case 'S' :
			env->filetype = 'b';
			env->bit7 = FALSE;
			printf("Send Binary File (file name) ");
			gets(uline);
			if (uline[0]) send(env,uline);
			printf("\n");
			break;
		case 's' :
			env->filetype = 't';
			printf("Send Text File (file name) ");
			gets(uline);
			if (uline[0]) send(env,uline);
			printf("\n");
			break;
		case 'X':
		case 'x' :
			running = FALSE;
			printf("Exit\n");
			break;
		case 'Z' :
		case 'z' :
			printf("UNIX Command Line ");
			printf("(command line) ");
			gets(uline);
			if (uline[0]) system(uline);
			printf("\n");
			break;
		default :
			printf("Invalid Command %c -- Type H for Help\n", c);
			break;
		}
	}
}

X/* print help for command mode */
chelp()
{
	printf("\t\t\t\tUC Command Summary\n");
	printf("\n");
	printf("\t------- Major Function -------    -- File Xfer Options --\n");
	printf("\t c <file>  CRC Value of File      1 or 3  Select FTP\n");
	printf("\t r <file>  Receive File           7 or 8  Select Bits\n");
	printf("\t s <file>  Send File              a or A  Toggle ARPA Net\n");
	printf("\t                                  e or E  Display Environ\n");
	printf("\n");
	printf("\t------- UNIX  Function -------    -------- Notes --------\n");
	printf("\td <dir/file> Display Directory    Major Fct - if caps(C),\n");
	printf("\tf <file>     File Size Info       binary file; if not(c),\n");
	printf("\tl <dir>      Log Into Dir         text file\n");
	printf("\tm            Toggle Menu\n");
	printf("\tx            Exit to UNIX         UNIX Fct - either case\n");
	printf("\tz            UNIX Command\n");
	printf("\n");
}

X/* Send File */
send(env,filename)
struct environ *env;
char *filename;
{
	FILE *fd, *fopen();
	int blocknum;			/* Current Block Number */
	int nlflg;			/* New Line for File Convert */
	int sending;			/* Xmit In-Progress Flag */
	int tries;			/* Attempt Count */
	int bufctr;			/* Counter for Buffer Build */
	int bitmask;			/* 7/8 Bit Mask */
	int c;				/* Temp Char */
	int rcode;			/* Return Code */
	char buf[BLOCKSZ];		/* Buffer for Transfer */

	/* Print Banner */
	printf("UC Sending %s File: %s\n",
		(env->filetype == 't') ? "Text" : "Binary",
		filename);
	if (env->logflg) fprintf(env->logfd,
	"\nUC Sending File: %s\n", filename);

	/* Open File for Input and Print Opening Messages */
	if ((fd = fopen(filename, "r")) == 0) {
		printf("Can`t Open File %s for Send\n", filename);
		if (env->logflg) fprintf(env->logfd,
		"Can't Open File %s for Send\n", filename);
		return;
	}
	fstat(env,filename);	/* Print File Status Info */
	printf("FTP %c, %c-Bit Transfer Selected\n",
	(env->ftp == 1) ? '1' : '3',
	env->bit7 ? '7' : '8');
	if (env->logflg) fprintf(env->logfd,
	"FTP %c, %c-Bit Transfer Selected\n",
	(env->ftp == 1) ? '1' : '3',
	env->bit7 ? '7' : '8');
	printf("Ready to Send File\n");
	binary(TRUE,TRUE);	/* Open Binary Communications */
	if (env->arpa) setarpa();	/* Binary on ARPA Net? */
	if (env->bit7) bitmask = 0x7f;
	else bitmask = 0xff;

	/* Init Parameters */
	blocknum = 1;
	nlflg = FALSE;
	sending = TRUE;

	/* Synchronize */
	tries = 0;
	if (env->ftp == 1) {
		sendbyte(SYN);
		while (recvbyte(5,bitmask) != ACK) {
			if (++tries > ERRMAX) {
				printf("Remote System Not Responding\n");
				if (env->logflg) fprintf(env->logfd,
				"Remote System Not Responding\n");
				return;
			}
			sendbyte(SYN);
		}
	}
	else {
		while (recvbyte(30,bitmask) != NAK)
			if (++tries > ERRMAX) {
				printf("Remote System Not Responding\n");
				if (env->logflg) fprintf(env->logfd,
				"Remote System Not Responding\n");
				return;
			}
	}

	/* Main Transmission Loop */
	while (sending) {
		/* Build Next Block into buf */
		for (bufctr = 0; bufctr < BLOCKSZ;) {
			if (nlflg) {	/* New Line */
				buf[bufctr++] = LF;	/* Store LF */
				nlflg = FALSE;
			}
			if (bufctr == BLOCKSZ) break;	/* Leave for Loop */
			c = getc(fd);	/* Get Next Byte from File */
			if (c == EOF) {
				sending = FALSE;	/* Done */
				if (!bufctr)	/* Avoid Extra Block */
					break;
				if (env->filetype == 't')
					for (;bufctr < BLOCKSZ; bufctr++)
						buf[bufctr] = CTRLZ;
				continue;	/* Exit for Loop */
			}
			if (c == LF && env->filetype == 't') {	/* NL? */
				buf[bufctr++] = CR;	/* Insert CR */
				nlflg = TRUE;		/* New Line */
			}
			else buf[bufctr++] = c;		/* Store Char */
		}

		/* Send Block */
		tries = 0;	/* Set Try Count */
		if (bufctr) do {
			putblock(env,buf,blocknum);	/* Send Block */
			rcode = recvbyte(10,bitmask);	/* Get Response */
			if (env->ftp == 1 && rcode == ESC)
				rcode = recvbyte(10,bitmask);
			if (rcode != ACK && env->logflg)
				fprintf(env->logfd, "%s Received on Block %d\n",
				(rcode == TO) ? "Timeout" : "Non-ACK",
				blocknum);
		}
		while (rcode != ACK && ++tries < ERRMAX);
		blocknum = (blocknum + 1) & bitmask;
		if (tries == ERRMAX) {	/* Error Abort */
			sending = FALSE;
			if (env->logflg) fprintf(env->logfd, "Error Abort\n");
		}
	}

	/* Cleanup After Send */
	fclose(fd);	/* Close File */
	tries = 0;
	if (env->ftp == 1) while (++tries < ERRMAX) sendbyte(EOT);
	else {
		sendbyte(EOT);
		while (recvbyte(15,bitmask) != ACK && ++tries < ERRMAX)
			sendbyte(EOT);
		if (tries == ERRMAX && env->logflg)
			fprintf(env->logfd, "Remote System Not Completing\n");
	}
	if (env->logflg) fprintf(env->logfd, "Send Complete\n");
	if (env->arpa) resetarpa();	/* Binary on ARPA Net? */
	binary(FALSE,TRUE);	/* Leave Binary Mode */
	sleep(3);
	printf("\n");
}

X/* Send Buffer to Receiver */
putblock(env,buf,blocknum)
struct environ *env;
char *buf;
int blocknum;
{
	int i, checksum, bitmask;

	if (env->bit7) bitmask = 0x7f;
	else bitmask = 0xff;
	sendbyte(SOH);		/* Send Start of Header */
	if (env->ftp == 1) sendbyte(0);	/* FTP 1 Data Packet */
	if (env->arpa && blocknum&bitmask == IAC) sendbyte(IAC);
	sendbyte(blocknum&bitmask);	/* Send Block Number */
	if (env->arpa && (-blocknum-1)&bitmask == IAC) sendbyte(IAC);
	sendbyte((-blocknum-1)&bitmask);	/* Send Block Complement */
	if (env->ftp == 1) sendbyte(STX);	/* FTP 1 Start of Text */
	checksum = 0;
	for (i = 0; i < BLOCKSZ; i++) {
		if (env->arpa && *buf&bitmask == IAC) sendbyte(IAC);
		sendbyte(*buf&bitmask);	/* Send Byte */
		checksum = (checksum + *buf++) & bitmask;
	}
	if (env->ftp == 1) sendbyte(ETX);	/* FTP 1 End of Text */
	if (env->arpa && checksum&bitmask == IAC) sendbyte(IAC);
	sendbyte(checksum&bitmask);		/* Checksum */
	if (env->ftp == 1) sendbyte(ENQ);	/* FTP 1 Enquiry */
}

X/* Receive File */
recv(env,filename)
struct environ *env;
char *filename;
{
	int fd;			/* file descriptor */
	int blocknum;		/* next block to receive */
	int rbcnt;		/* total number of received blocks */
	int errorcnt;		/* number of errors on current block */
	int receiving;		/* continuation flag */
	int char1;		/* first char received in block */
	int delay;		/* inter-char delay for FTP */
	int rcode;		/* received block code */
	int bitmask;		/* 7/8 bit mask */

	/* Set Mask for 7/8 Bits */
	if (env->bit7) bitmask = 0x7f;
	else bitmask = 0xff;

	if (!access(filename,2)) {
		printf("File %s Exists -- Delete it? ", filename);
		if (!getyn()) {
			printf("Aborting\n");
			if (env->logflg) fprintf(env->logfd,
			"Overwrite of %s Disallowed\n", filename);
			return;
		}
	}
	unlink(filename);	/* delete old file, if any */
	if ((fd = creat(filename, CREATE)) == -1) {	/* can't create */
		printf("Can't Create %s\n", filename);
		if (env->logflg) fprintf(env->logfd,
		"Can't Create %s\n", filename);
		return;
	}

	/* We Have a GO */
	printf("UC Receiving %s File: %s\n",
		(env->filetype == 't') ? "Text" : "Binary",
		filename);
	if (env->logflg)
		fprintf(env->logfd, "\nUC Receiving File: %s\n", filename);
	printf("FTP %c, %c-Bit Transmission Selected\n",
	(env->ftp == 1) ? '1' : '3',
	env->bit7 ? '7' : '8');
	if (env->logflg)
		fprintf(env->logfd, "FTP %c, %c-Bit Transmission Selected\n",
		(env->ftp == 1) ? '1' : '3',
		env->bit7 ? '7' : '8');
	printf("Ready to Receive\n");

	/* Init Counters et al */
	blocknum = 1;
	rbcnt = 0;
	errorcnt = 0;
	receiving = TRUE;

	/* Establish Binary Communications */
	binary(TRUE,TRUE);
	if (env->arpa) setarpa();

	/* Synchronize with Sender */
	if (env->ftp == 1) {
		while (recvbyte(4,bitmask) != SYN);
		sendbyte(ACK);
	}
	else sendbyte(NAK);

	/* Receive Next Packet */
	while (receiving) {
		do {
			char1 = recvbyte(6,bitmask);
		}
		while ((char1 != SOH) && (char1 != EOT) && (char1 != TO));
		switch (char1) {
		case TO :	/* Timeout */
			if (env->logflg)
				fprintf(env->logfd, "Timeout on Block %d\n",
				blocknum);
			if (++errorcnt == ERRMAX) {
				close(fd);	/* Close File */
				sleep(3);	/* Delay for Sender */
				if (env->arpa) resetarpa();	/* ARPA Net */
				binary(FALSE,TRUE);	/* Normal I/O */
				if (env->logflg)
					fprintf(env->logfd, "Error Abort\n");
				receiving = FALSE;
			}
			sendbyte(NAK);
			break;
		case EOT :	/* End of Transmission */
			if (env->ftp == 3) sendbyte(ACK);
			while (recvbyte(3,bitmask) != TO);
			close(fd);	/* Close File */
			sleep(3);	/* Delay for Sender */
			if (env->arpa) resetarpa();	/* ARPA Net */
			binary(FALSE,TRUE);	/* Normal I/O */
			if (env->logflg) {
				fprintf(env->logfd, "Receive Complete -- ");
				fprintf(env->logfd, "%dK, %d Blocks Received\n",
				(rbcnt%8) ? (rbcnt/8)+1 : rbcnt/8,
				rbcnt);
			}
			printf("\n");
			receiving = FALSE;
			break;
		case SOH :	/* New or Old Block */
			rcode = getblock(env,fd,blocknum);	/* read block */
			switch (rcode) {
			case 0 :	/* OK */
				errorcnt = 0;
				blocknum = ++blocknum & bitmask;
				rbcnt++;
				if (env->ftp == 1) sendbyte(ESC);
				sendbyte(ACK);
				break;
			case 1 :	/* Xmit Error, Non-Fatal */
				if (++errorcnt < ERRMAX) {
					sendbyte(NAK);
					break;
				}
			default :	/* Xmit Error, Fatal */
				if (env->logflg)
					fprintf(env->logfd, "Error Abort\n");
				close(fd);
				if (env->ftp == 1) sendbyte(ESC);
				sendbyte(CAN);
				if (env->arpa) resetarpa();	/* ARPA Net */
				binary(FALSE,TRUE);
				while (recvbyte(3,bitmask) != TO);
				receiving = FALSE;
				break;
			}
			break;
		}
	}
}

X/* Get Block from Sender */
getblock(env,fd,blocknum)
struct environ *env;
int fd, blocknum;
{
	int curblock, cmpblock, delay, bitmask;
	int recdone, checksum, inchecksum, byte, bufcnt, c;
	int startstx, endetx, endenq;
	int errflg, errchr;
	char buff[BLOCKSZ];

	if (env->ftp == 1) {
		delay = 5;	/* FTP 1 Delay Constant */
		recvbyte(5,bitmask);	/* Flush Leading Zero */
	}
	else delay = 3;		/* FTP 3 Delay Constant */
	if (env->bit7) bitmask = 0x7f;
	else bitmask = 0xff;

	curblock = recvbyte(delay,bitmask);
	if (curblock == TO) {
		if (env->logflg)
			fprintf(env->logfd, "Timeout on Block Number\n");
		return(1);
	}
	cmpblock = recvbyte(delay,bitmask);
	if (curblock == TO) {
		if (env->logflg)
			fprintf(env->logfd, "Timeout on Block Complement\n");
		return(1);
	}
	if (env->ftp == 1) {
		startstx = recvbyte(delay,bitmask);
		if (startstx == TO) {
			if (env->logflg)
				fprintf(env->logfd, "Timeout on STX\n");
			return(1);
		}
	}
	if ((curblock + cmpblock) != bitmask) {
		if (env->logflg) fprintf(env->logfd,
		"Block Number Error on Block %d\n", blocknum);
		while (recvbyte(delay,bitmask) != TO);	/* Flush */
		return(1);
	}
	checksum = 0;		/* Init Checksum */
	byte = 0;		/* Init Buff Ptr */
	recdone = FALSE;	/* File Receive NOT Done */
	for (bufcnt=0; bufcnt<BLOCKSZ; bufcnt++) {
		c = recvbyte(delay,bitmask);
		if (c == TO) {
			if (env->logflg)
				fprintf(env->logfd, "Timeout on Block Recv\n");
			return(1);
		}
		buff[byte] = c;
		checksum = (checksum + c) & bitmask;
		if (env->filetype != 't') {
			byte++;		/* binary xfer, so advance */
			continue;
		}
		if (c == CR) continue;	/* skip CR */
		if (c == CTRLZ) {	/* done */
			recdone = TRUE;
			continue;
		}
		if (!recdone) byte++;		/* continue */
	}
	if (env->ftp == 1) {
		endetx = recvbyte(delay,bitmask);
		if (endetx == TO) {
			if (env->logflg)
				fprintf(env->logfd, "Timeout on ETX\n");
			return(1);
		}
	}
	inchecksum = recvbyte(delay,bitmask);
	if (inchecksum == TO) {
		if (env->logflg)
			fprintf(env->logfd, "Timeout on Checksum\n");
		return(1);
	}
	if (env->ftp == 1) {
		endenq = recvbyte(delay,bitmask);
		if (endenq == TO) {
			if (env->logflg)
				fprintf(env->logfd, "Timeout on ENQ\n");
			return(1);
		}
	}
	errflg = FALSE;
	if (env->ftp == 1) {
		if (startstx != STX) {
			errflg = TRUE;
			errchr = STX;
		}
		if (endetx != ETX) {
			errflg = TRUE;
			errchr = ETX;
		}
		if (endenq != ENQ) {
			errflg = TRUE;
			errchr = ENQ;
		}
		if (errflg && env->logflg) {
			fprintf(env->logfd, "Invalid Packet Control -- ");
			switch (errchr) {
			case STX :
				fprintf(env->logfd,"STX");
				break;
			case ETX :
				fprintf(env->logfd,"ETX");
				break;
			case ENQ :
				fprintf(env->logfd,"ENQ");
				break;
			}
			fprintf(env->logfd,"\n");
		}
	}
	if (checksum != inchecksum) {
		if (env->logflg)
			fprintf(env->logfd,
			"Checksum Error: Received %d vs Computed %d\n",
			inchecksum, checksum);
		errflg = TRUE;
	}
	if (errflg) return(1);
	if (curblock != blocknum) {
		if (curblock == (blocknum+1)&bitmask) {
			if (env->logflg) fprintf(env->logfd,
			"Phase Error\n");
			return(2);
		}
		if (env->logflg)
			fprintf(env->logfd, "Duplicate Block %d\n", blocknum);
		return(0);
	}
	if (write(fd,buff,byte) < 0) {
		if (env->logflg) fprintf(env->logfd,
		"File Write Error\n");
		return(2);
	}
	return(0);
}

X/* Compute the CRC for a UNIX Text File */
crct(filename)
char *filename;
{
	unsigned crcupd();
	FILE *fd, *fopen();
	unsigned crc;
	int c;
	int bytecnt;

	/* open file for input */
	if ((fd=fopen(filename, "r")) == NULL) {
		printf("File %s Not Found\n", filename);
		return;
	}

	/* init byte counter (for last block) */
	bytecnt = 0;

	/* init CRC Value */
	crc = 0;

	/* compute CRC on all bytes of file with file format conversion */
	while ((c = getc(fd)) != EOF) {
		bytecnt++;
		if (!(bytecnt%BLOCKSZ)) bytecnt=0;
		if (c == LF) {
			crc = crcupd(CR, crc);	/* Insert CR */
			bytecnt++;
			if (!(bytecnt%BLOCKSZ)) bytecnt=0;
		}
		crc = crcupd(c, crc);		/* Update CRC */
	}

	/* fill last block with CTRLZ's */
	for (;bytecnt < BLOCKSZ; bytecnt++) crc = crcupd(CTRLZ, crc);

	/* close file */
	fclose(fd);

	/* print result */
	printf("CRC of Text File %s is %4X\n", filename, crc);
}
X/* Compute a CRC Value for a Binary File */
crcb(filename)
char *filename;
{
	unsigned crcupd();
	FILE *fd, *fopen();
	unsigned crc;
	int c;

	/* open file for input */
	if ((fd=fopen(filename, "r")) == NULL) {
		printf("File %s Not Found\n", filename);
		return;
	}

	/* init CRC Value */
	crc = 0;

	/* compute CRC on all bytes of file */
	while ((c = getc(fd)) != EOF) crc = crcupd(c, crc);

	/* close file */
	fclose(fd);

	/* print result */
	printf("CRC of Binary File %s is %4X\n", filename, crc);
}

X/* compute CRC on a byte-for-byte basis */
unsigned crcupd(byteval, crc)
int byteval;
unsigned crc;
{
	unsigned newcrc, high, low;

	newcrc = crc << 1;	/* shift CRC left one bit */
	high = newcrc & 0xff00;	/* get new high byte */
	low  = (newcrc + byteval) & 0xff;	/* get new low byte */
	newcrc = high | low;	/* OR the two bytes together */
	if (crc & 0x8000) crc = newcrc ^ 0xa097;	/* apply offset */
	else crc = newcrc;
	return(crc);
}

X/* File Status Display */
fstat(env,filename)
struct environ *env;
char *filename;
{
	struct stat fsi;	/* file status info */

	if (stat (filename, &fsi) == -1) {	/* get file status info */
		printf("File %s Not Found\n", filename);
		return;
	}
	printf("File Size of %s is %ldK, %ld Blocks\n",
	filename,
	fsi.st_size%1024 ? (fsi.st_size/1024)+1 : fsi.st_size/1024,
	fsi.st_size%128 ? (fsi.st_size/128)+1 : fsi.st_size/128);
	if (env->logflg) fprintf(env->logfd,
	"File Size of %s is %ldK, %ld Blocks\n",
	filename,
	fsi.st_size%1024 ? (fsi.st_size/1024)+1 : fsi.st_size/1024,
	fsi.st_size%128 ? (fsi.st_size/128)+1 : fsi.st_size/128);
}

X/*  SUPPORT ROUTINES  */

X/* get yes or no response from user */
getyn()
{
	int c;

	c = charx();	/* get char */
	if (c == 'y' || c == 'Y') {
		printf("Yes\n");
		return(TRUE);
	}
	else {
		printf("No\n");
		return(FALSE);
	}
}

X/* get single char input */
charx()
{
	int binary();
	int c;

	binary(TRUE,FALSE);
	c = getchar();
	binary(FALSE,FALSE);
	return (c);
}

X/*  set ARPA Net for 8-bit transfers  */
setarpa()
{
	sendbyte(IAC);	/* Is A Command */
	sendbyte(WILL);	/* Command to SERVER TELNET (Host) */
	sendbyte(TRBIN);	/* Command is:  Transmit Binary */

	sendbyte(IAC);	/* Is A Command */
	sendbyte(DO);	/* Command to TAC */
	sendbyte(TRBIN);	/* Command is:  Transmit Binary */

	sleep(3);  /* wait for TAC to configure */

	return;
}

X/* reset the ARPA Net */
resetarpa()
{
	sendbyte(IAC);	/* Is A Command */
	sendbyte(WONT);	/* Negative Command to SERVER TELNET (Host) */
	sendbyte(TRBIN);	/* Command is:  Don't Transmit Binary */

	sendbyte(IAC);	/* Is A Command */
	sendbyte(DONT);	/* Negative Command to TAC */
	sendbyte(TRBIN);	/* Command is:  Don't Transmit Binary */

	return;
}

X/* send byte to receiver */
sendbyte(data)
char data;
{
	write (1, &data, 1);	/* write the byte */
}

X/* receive a byte from sender */
recvbyte(seconds,bitmask)
unsigned seconds;
int bitmask;
{
	char c;
	int alarmfunc();		/* forward declaration */

	signal(SIGALRM,alarmfunc);	/* catch alarms */
	alarm(seconds);			/* set clock */
	if (read (0, &c, 1) < 0)	/* get char or timeout */
		return (TO);
	alarm(0);			/* clear clock */
	return (c&bitmask);
}

X/* dummy alarm function */
alarmfunc()
{
	return;
}

X/* set and clear binary mode */
binary(setflg,scope)
int setflg, scope;
{
	static struct sgttyb ttys, ttysold;
	static struct stat statbuf;

	if (setflg) {	/* set binary */
		if (gtty (0, &ttys) < 0) return(FALSE);	/* failed */
		ttysold.sg_ispeed = ttys.sg_ispeed;	/* save old values */
		ttysold.sg_ospeed = ttys.sg_ospeed;
		ttysold.sg_erase = ttys.sg_erase;
		ttysold.sg_kill = ttys.sg_kill;
		ttysold.sg_flags = ttys.sg_flags;
		ttys.sg_flags |= RAW;		/* set for RAW Mode */
		ttys.sg_flags &= ~ECHO;		/* set no ECHO */
		if (scope) {		/* cover all values? */
			ttys.sg_flags &= ~XTABS;	/* set no tab exp */
			ttys.sg_flags &= ~LCASE;	/* set no case xlate */
			ttys.sg_flags |= ANYP;		/* set any parity */
			ttys.sg_flags &= ~NL3;		/* no delays on nl */
			ttys.sg_flags &= ~TAB0;		/* no tab delays */
			ttys.sg_flags &= ~TAB1;
			ttys.sg_flags &= ~CR3;		/* no CR delay */
			ttys.sg_flags &= ~FF1;		/* no FF delay */
			ttys.sg_flags &= ~BS1;		/* no BS delay */
		}
		if (stty (0, &ttys) < 0) return(FALSE);	/* failed */
		if (scope) system("mesg n");	/* turn off messages */
		return(TRUE);
	}
	else {		/* clear binary */
		if (stty (0, &ttysold) < 0) return (FALSE);
		if (scope) system("mesg y");	/* turn on messages */
		return(TRUE);	/* OK */
	}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 uc.c
	/bin/echo -n '	'; /bin/ls -ld uc.c
fi