Latest version of UC.C (UNIX-CP/M file transfer shell)

emigh at ecsvax.UUCP emigh at ecsvax.UUCP
Thu Dec 22 00:24:31 AEST 1983


Following is the latest version of UC.C (UNIX(tm) to CP/M file transfer
shell) which corrects a minor bug.  To extract the program, delete this
header and run through the shell.  The program was written by Rick Conn
(...!ucbvax!rconn at brl).  The manual page previously posted is still valid.
	Ted H. Emigh
	mcnc!ecsvax!emigh
------------------------------------------------------------------------
: 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.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	4	/* 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 */
#define	DBGFILE	"uc.debug"	/* Debug 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 */
	int dbgflg;	/* debug output flag */
	FILE *logfd;	/* file descriptor for log file */
	FILE *dbgfd;	/* file descriptor for debug 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 */
	char dbgfile[50];	/* space for name of debug 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 */

	/* Determine Name of Debug File */
	strcat (dbgfile, getenv("HOME"));	/* Name of Home Dir */
	strcat (dbgfile, "/");		/* Separator */
	strcat (dbgfile, DBGFILE);		/* Name of Debug File */

	/* Set Defaults for ARPA Net, Menu, FTP, Logging, and 7/8-Bit Xfer */
	genv.logflg = deflog;
	genv.dbgflg = FALSE;			/* Debug Off */
	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 'D' :
		case 'd' :
			genv.dbgflg = ~genv.dbgflg;	/* flip flag */
			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 Debug File if Requested */
	if (genv.dbgflg) {
		genv.dbgfd = fopen(dbgfile, "w");
		if (genv.dbgfd == NULL) {
			printf("Can't Open Debug File\n");
			exit(0);
		}
	}

	/* 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);
		if (genv.dbgflg) fclose(genv.dbgfd);
		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);
		if (genv.dbgflg) fclose(genv.dbgfd);
		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);
		if (genv.dbgflg) fclose(genv.dbgfd);
		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("\td or D -- Debug Output (to UC.DEBUG)\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 %s File: %s\n",
		(env->filetype == 't') ? "Text" : "Binary",
		filename);
	if (env->dbgflg) fprintf(env->dbgfd,
		"\nUC Sending %s File: %s\n",
		(env->filetype == 't') ? "Text" : "Binary",
		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);
		if (env->dbgflg) fprintf(env->dbgfd,
		"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');
	if (env->dbgflg) fprintf(env->dbgfd,
		"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");
				if (env->dbgflg) fprintf(env->dbgfd,
				"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");
				if (env->dbgflg) fprintf(env->dbgfd,
				"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);
				if (env->dbgflg) fprintf(env->dbgfd,
				"%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");
			if (env->dbgflg) fprintf(env->dbgfd, "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->dbgflg) fprintf(env->dbgfd,
			"Remote System Not Completing\n");
		}
	}
	if (env->logflg) fprintf(env->logfd, "Send Complete\n");
	if (env->dbgflg) fprintf(env->dbgfd, "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, j, checksum, bitmask;
	int dbgcnt;
	char dbgchr[20];

	if (env->bit7) bitmask = 0x7f;
	else bitmask = 0xff;
	sendbyte(SOH);		/* Send Start of Header */
	if (env->dbgflg) fprintf(env->dbgfd, "SOH = %2x ", SOH);
	if (env->ftp == 1) {
		sendbyte(0);	/* FTP 1 Data Packet */
		if (env->dbgflg) fprintf(env->dbgfd, "00 ");
	}
	if (env->arpa && blocknum&bitmask == IAC) {
		sendbyte(IAC);
		if (env->dbgflg) fprintf(env->dbgfd, "%2x ", IAC);
	}
	sendbyte(blocknum&bitmask);	/* Send Block Number */
	if (env->dbgflg) fprintf(env->dbgfd, "%2x ", blocknum&bitmask);
	if (env->arpa && (-blocknum-1)&bitmask == IAC) {
		sendbyte(IAC);
		if (env->dbgflg) fprintf(env->dbgfd, "%2x ", IAC);
	}
	sendbyte((-blocknum-1)&bitmask);	/* Send Block Complement */
	if (env->dbgflg) fprintf(env->dbgfd, "%2x ", (-blocknum-1)&bitmask);
	if (env->ftp == 1) {
		sendbyte(STX);	/* FTP 1 Start of Text */
		if (env->dbgflg) fprintf(env->dbgfd, "%2x ", STX);
	}
	checksum = 0;
	dbgcnt = 0;
	if (env->dbgflg) fprintf(env->dbgfd, "\n");
	for (i = 0; i < BLOCKSZ; i++) {
		if (env->arpa && *buf&bitmask == IAC) {
			sendbyte(IAC);
			if (env->dbgflg) {
				fprintf(env->dbgfd, "%2x ", IAC);
				dbgchr[dbgcnt++] = IAC;
				}
		}
		sendbyte(*buf&bitmask);	/* Send Byte */
		if (env->dbgflg) {
			dbgchr[dbgcnt++] = *buf&0x7f;
			fprintf(env->dbgfd, "%2x ", *buf&0xff);
			if (((i+1) % 8) == 0) {
				fprintf(env->dbgfd, "   |");
				for (j=0; j<dbgcnt; j++) {
					if (dbgchr[j] < ' ')
					  fprintf(env->dbgfd, ".");
					else
					  fprintf(env->dbgfd, "%c", dbgchr[j]);
				}
				fprintf(env->dbgfd, "|\n");
				dbgcnt = 0;
			}
		}
		checksum = (checksum + *buf++) & bitmask;
	}
	if (env->dbgflg)
		if (dbgcnt) {
			fprintf(env->dbgfd, "   |");
			for (j=0; j<dbgcnt; j++) {
				if (dbgchr[j] < ' ')
				  fprintf(env->dbgfd, ".");
				else
				  fprintf(env->dbgfd, "%c", dbgchr[j]);
			}
		fprintf(env->dbgfd, "|\n");
		}
	if (env->ftp == 1) {
		sendbyte(ETX);	/* FTP 1 End of Text */
		if (env->dbgflg) fprintf(env->dbgfd, "ETX = %2x ", ETX);
	}
	if (env->arpa && checksum&bitmask == IAC) {
		sendbyte(IAC);
		if (env->dbgflg) fprintf(env->dbgfd, "%2x ", IAC);
	}
	sendbyte(checksum&bitmask);		/* Checksum */
	if (env->dbgflg) fprintf(env->dbgfd, "Checksum = %2x ",
		checksum&bitmask);
	if (env->ftp == 1) {
		sendbyte(ENQ);	/* FTP 1 Enquiry */
		if (env->dbgflg) fprintf(env->dbgfd, "ENQ = %2x ", ENQ);
	}
	if (env->dbgflg) fprintf(env->dbgfd, "\nEnd of Packet\n");
}

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);
			if (env->dbgflg) fprintf(env->dbgfd,
			"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);
		if (env->dbgflg) fprintf(env->dbgfd,
		"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);
	if (env->dbgflg)
		fprintf(env->dbgfd, "\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');
	if (env->dbgflg)
		fprintf(env->dbgfd, "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 (env->dbgflg)
				fprintf(env->dbgfd, "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");
				if (env->dbgflg)
					fprintf(env->dbgfd, "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);
			}
			if (env->dbgflg) {
				fprintf(env->dbgfd, "Receive Complete -- ");
				fprintf(env->dbgfd, "%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 */
				blocknum = ++blocknum & bitmask;
				rbcnt++;
			case 2 :	/* OK, but Duplicate Block */
				errorcnt = 0;
				if (env->ftp == 1) sendbyte(ESC);
				sendbyte(ACK);
				if (env->dbgflg) fprintf(env->dbgfd,
					"\nSending ACK\n");
				break;
			case 1 :	/* Xmit Error, Non-Fatal */
				if (++errorcnt < ERRMAX) {
					sendbyte(NAK);
					if (env->dbgflg) fprintf(env->dbgfd,
					"\nSending NAK\n");
					break;
				}
			default :	/* Xmit Error, Fatal */
				if (env->logflg)
					fprintf(env->logfd, "Error Abort\n");
				if (env->dbgfd)
					fprintf(env->dbgfd, "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];
	int j, dbgcnt;
	char dbgchr[20];

	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 (env->dbgflg) fprintf(env->dbgfd, "Block Number = %4x\n", curblock);
	if (curblock == TO) {
		if (env->logflg)
			fprintf(env->logfd, "Timeout on Block Number\n");
		return(1);
	}
	cmpblock = recvbyte(delay,bitmask);
	if (env->dbgflg) fprintf(env->dbgfd, "Block Compl  = %4x\n", cmpblock);
	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 (env->dbgflg) fprintf(env->dbgfd, "STX = %4x\n", startstx);
		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);
		if (env->dbgflg) fprintf(env->dbgfd,
		"Block Number Error on Block %d\n", blocknum);
		while (recvbyte(delay,bitmask) != TO);	/* Flush */
		return(1);
	}
	checksum = 0;		/* Init Checksum */
	dbgcnt = 0;		/* Init Char Count */
	byte = 0;		/* Init Buff Ptr */
	recdone = FALSE;	/* File Receive NOT Done */
	for (bufcnt=0; bufcnt<BLOCKSZ; bufcnt++) {
		c = recvbyte(delay,bitmask);
		if (env->dbgflg) {
			dbgchr[dbgcnt++] = c&0x7f;
			fprintf(env->dbgfd, "%2x ", c&0xff);
			if (((bufcnt+1) % 8) == 0) {
				fprintf(env->dbgfd, "   |");
				for (j=0; j<dbgcnt; j++) {
					if (dbgchr[j] < ' ')
					  fprintf(env->dbgfd, ".");
					else
					  fprintf(env->dbgfd, "%c", dbgchr[j]);
				}
				dbgcnt = 0;
				fprintf(env->dbgfd, "|\n");
			}
		}
		if (c == TO) {
			if (env->logflg)
				fprintf(env->logfd, "Timeout on Block Recv\n");
			if (env->dbgflg)
				fprintf(env->dbgfd, "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 (env->dbgflg) fprintf(env->dbgfd, "ETX = %4x\n", endetx);
		if (endetx == TO) {
			if (env->logflg)
				fprintf(env->logfd, "Timeout on ETX\n");
			return(1);
		}
	}
	inchecksum = recvbyte(delay,bitmask);
	if (env->dbgflg)
		fprintf(env->dbgfd,
			"Computed Checksum = %4x   Received Checksum = %4x\n",
			checksum, inchecksum);
	if (inchecksum == TO) {
		if (env->logflg)
			fprintf(env->logfd, "Timeout on Checksum\n");
		return(1);
	}
	if (env->ftp == 1) {
		endenq = recvbyte(delay,bitmask);
		if (env->dbgflg) fprintf(env->dbgfd, "ENQ = %4x\n", endenq);
		if (endenq == TO) {
			if (env->logflg)
				fprintf(env->logfd, "Timeout on ENQ\n");
			return(1);
		}
	}
	if (env->dbgflg) fprintf(env->dbgfd, "\nEnd of Packet\n");
	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/%xH vs Computed %d/%xH\n",
			inchecksum, inchecksum, checksum, checksum);
		errflg = TRUE;
	}
	if (errflg) return(1);
	if (curblock != blocknum) {
		if (curblock == (blocknum+1)&bitmask) {
			if (env->logflg) fprintf(env->logfd,
			"Phase Error\n");
			if (env->dbgflg) fprintf(env->dbgfd,
			"Phase Error\n");
			return(99);
		}
		if (env->logflg)
			fprintf(env->logfd, "Duplicate Block %d\n", blocknum);
		if (env->dbgflg)
			fprintf(env->dbgfd, "Duplicate Block %d\n", blocknum);
		return(2);
	}
	if (write(fd,buff,byte) < 0) {
		if (env->logflg) fprintf(env->logfd,
		"File Write Error\n");
		if (env->dbgflg) fprintf(env->dbgfd,
		"File Write Error\n");
		return(99);
	}
	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



More information about the Comp.sources.unix mailing list