[net.sources] YAXMP

john@novavax.UUCP (John Paul O'Brien) (05/15/86)

#! /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:
#	README
#	makefile
#	termio.c
#	termio.h
#	wsstrip.c
#	wsstrip.l
#	xmodemio.c
#	xum.l
#	xumodem.c
# This archive created: Thu May 15 14:38:15 1986
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
XUM is a xmodem protocol package for BSD 4.2 unix. I don't know if it
will work with other flavors of unix but it likes BSD 4.2 just fine.
The man page for xum makes a reference to a program called wsstrip
so I have included that one also. It will take a wordstar format file
and take out all the funny characters so that vi will not complain.

XUM was written with the novice unix user in mind; there are no command
line options (though I would like to put them in someday). Instead, it is
menu driven so the novice users will not bang their heads against the wall
try to figure out which options to select. In other words I tried to make
it village-idiot proof.

The thing that distinguishes xum from other xmodem packages is the way
in which I wrote it. It is VERY modular. If you want to incorporate xmodem
i/o in another package you are writing then just use the termio.c, termio.h,
and xmodemio.c files; all that you need to pass to send or receive a
file with xmodem i/o is your terminal fid and a file fid. Also, the termio
package can be used by itself for setting modes on a terminal, allocating
a terminal, and using termcap to perform simple screen i/o without having
to go through the bother of using curses or writing your own code.

Any comments or suggestions would be appreciated.
Send them to me at:
{allegra, ucf-cs, usfvax2}!novavax!john
SHAR_EOF
if test 1358 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 1358 characters)'
fi
fi
if test -f 'makefile'
then
	echo shar: "will not over-write existing file 'makefile'"
else
cat << \SHAR_EOF > 'makefile'
#	Makefile 1.0	3/20/86
#
# make file for Xmodem on Unix Protocol Package
#
#

CFLAGS=	-O -s
OBJS=	termio.o xmodemio.o
SOURCES= termio.c xmodemio.c xumodem.c
CXREF=	/usr/ucb/ctags -xw

xum:	makefile ${OBJS} xumodem.o
	${CC} ${CFLAGS} -o xum ${OBJS} xumodem.o -ltermlib

test:	${OBJS} test.o
	${CC} ${CFLAGS} -o txum ${OBJS} test.o

termio.o:	termio.c
	${CC} ${CFLAGS} -c termio.c

xmodemio.o:	xmodemio.c
	${CC} ${CFLAGS} -c xmodemio.c
	
${OBJS}:	termio.h

test.o:	test.c
	${CC} ${CFLAGS} -c test.c

clean:
	rm -f xum txum *.o

print:
	@pr makefile
	@pr termio.h ${SOURCES}
	@${CXREF} termio.h ${SOURCES} | pr -h XREF

lint:
	-lint -hbacvx ${SOURCES}
SHAR_EOF
if test 649 -ne "`wc -c < 'makefile'`"
then
	echo shar: "error transmitting 'makefile'" '(should have been 649 characters)'
fi
fi
if test -f 'termio.c'
then
	echo shar: "will not over-write existing file 'termio.c'"
else
cat << \SHAR_EOF > 'termio.c'
#include "termio.h"

char	*getenv(),		/* These are here so we can use termlib */
	*tgetstr(),
	PC;			/* global used for padding character */
#undef	putchar			/* need to undefine it so we can redefine it */
int	putchar();
short	ospeed;			/* global used by tputs */
char	*term_name,
	str_buf[60],
	*ptr2ptr,
	*cl_str,
	*cm_str,
	*ce_str,
	terminfo_buff[1024];
	

int	timer();		/* pre-declare for signal setup in unblocked_io	*/
jmp_buf	env;			/* environment storage for setjmp/longjmp */

struct	sgttyb	org_stty,	/* Global so that we can restore Exact state */
		cur_stty;

/*
	Assign_tty: Attempts to open a tty device by pathname (ie.
	/dev/ttyi2). If successful, then return file descriptor, else
	return -1. Will also set terminal for exclusive use mode if
	open was successful.

	On Entry: string pointer to tty pathname
	On Exit:  file descriptor or -1 for failure
*/

assign_tty(path)
char	*path;
{
int	tty_fd;

	if ( (tty_fd = open(path, O_RDWR)) >= 0 )
	{
		if ( ioctl(tty_fd, TIOCEXCL) == -1 )
		{
			tty_fd = -1;
		}
	}
	return((tty_fd < 0) ? -1 : tty_fd);
}


/*
	Deassign_tty: Attempts to close a tty device by file descriptor.
	First, will reset tty to non-exclusive use mode.

	On Entry: int file descriptor
	On Exit:  0 for success or -1 for failure
*/

deassign_tty(tty_fd)
int	tty_fd;
{

	ioctl(tty_fd, TIOCNXCL);
	return(close(tty_fd));
}


/* 
	Get_tty: Will return the current sgttyb structure information
		 for a previously assigned tty.

	On Entry: tty file descriptor, and a pointer to a structure to
		  store the information in.
	On Exit:  return -1 if error else tty info in structure if all ok
*/


get_tty(tty_fd, tty_struct)
int	tty_fd;
struct	sgttyb	*tty_struct;
{
	return(ioctl(tty_fd, TIOCGETP, tty_struct));
}



/* 
	Set_tty: Will set a previously assigned tty to the parameters
		 passed in the sgttyb structure.

	On Entry: tty file descriptor, and a pointer to a structure to
		  read the information from.
	On Exit:  return -1 if error.
*/


set_tty(tty_fd, tty_struct)
int	tty_fd;
struct	sgttyb	*tty_struct;
{
	return(ioctl(tty_fd, TIOCSETP, tty_struct));
}


/*
	Raw_tty: Attempts to open a tty device by pathname (ie.
	/dev/ttyi2), and then will set terminal up for raw i/o
	mode.

	On Entry: string pointer to tty pathname
	On Exit:  file descriptor or -1 for failure
*/

raw_tty(terminal)
char	*terminal;
{
int	tty_fd;

	if ( -1 == (tty_fd = assign_tty(terminal)) )
	{
		return(-1);		/* return with error code	*/
	}

	if ( -1 == get_tty(tty_fd, &org_stty) )
	{
		deassign_tty(tty_fd);
		return(-1);		/* return with error code	*/
	}

	cur_stty = org_stty;		/* copy information	*/
	cur_stty.sg_flags |= RAW;	/* raw mode (all 8 bits pass)	*/
	cur_stty.sg_flags &= ~(TANDEM|ECHO|CRMOD);	/* remove all char processing */

	if ( -1 == set_tty(tty_fd, &cur_stty) )
	{
		deassign_tty(tty_fd);
		return(-1);		/* return with error code	*/
	}
	return(tty_fd);		/* all went well, return tty file desc	*/
}


/*
	cook_tty: Will set a terminal back to its original state by
	file descriptor and will leave that descriptor open.

	On Entry: tty file descriptor
	On Exit:  returns 0 on success or -1 on failure
*/

cook_tty(tty_fd)
int	tty_fd;
{
	if ( -1 == set_tty(tty_fd, &org_stty) )
	{
		return(-1);		/* return with error code	*/
	}

	return(0);	/* return with no errors	*/
}


/*
	uncook_tty: Will set a terminal back to its raw state by
	file descriptor and will leave that descriptor open.

	On Entry: tty file descriptor
	On Exit:  returns 0 on success or -1 on failure
*/

uncook_tty(tty_fd)
int	tty_fd;
{
	if ( -1 == set_tty(tty_fd, &cur_stty) )
	{
		return(-1);		/* return with error code	*/
	}

	return(0);	/* return with no errors	*/
}


/*
	reset_tty: Attempts to set a terminal back to its original state by
	file descriptor and then will close tty file descriptor.

	On Entry: tty file descriptor
	On Exit:  returns 0 on success or -1 on failure
*/

reset_tty(tty_fd)
int	tty_fd;
{
	if ( -1 == set_tty(tty_fd, &org_stty) )
	{
		deassign_tty(tty_fd);
		return(-1);		/* return with error code	*/
	}

	deassign_tty(tty_fd);
	return(0);	/* return with no errors	*/
}


/*
	blocked_io: Attempts to set a terminal to blocked i/o mode by
	file descriptor.

	On Entry: tty file descriptor
	On Exit:  returns fcntl value on success or -1 on failure
*/

blocked_io(tty_fd)
int	tty_fd;
{
int	f_flags;

	f_flags = fcntl(tty_fd, F_GETFL, 0);	/* get current file flags */
	if (f_flags == -1)
	{
		return(-1);
	}
	f_flags += FNDELAY;	/* no delay on read/write (no blocking i/o) */
	return(fcntl(tty_fd, F_SETFL, f_flags));
}


/*
	unblocked_io: Attempts to set a terminal to unblocked i/o mode by
	file descriptor.

	On Entry: tty file descriptor
	On Exit:  returns fcntl value on success or -1 on failure
*/

unblocked_io(tty_fd)
int	tty_fd;
{
int	f_flags;

	f_flags = fcntl(tty_fd, F_GETFL, 0);	/* get current file flags */
	if (f_flags == -1)
	{
		return(-1);
	}
	f_flags -= FNDELAY;	/* delay on read/write (blocking i/o) */
	return(fcntl(tty_fd, F_SETFL, f_flags));
}


/*	timer: Is an interrupt routine that will perform a longjmp 	*/
/*		when it is called by the alarm interrupt.		*/

timer(signal)
int	signal;	/* variable to catch signal sent to routine.	*/
		/* we will just ignore it.			*/
{
	longjmp(env, 1);
}


/*	timed_read: Will attempt to read from the terminal specified	*/
/*		    by the tty file descriptor for a set period of time.*/
/*									*/
/*	On Entry: tty file descriptor to read from, pointer to a byte	*/
/*		  to return received char in number of bytes to read	*/
/*		  and time in seconds.					*/
/*	On Exit:  0 for ok read or -1 for no char received.		*/
/*									*/

timed_read(tty_fd, ch, count, seconds)
int	tty_fd,
	count;
byte	*ch;
unsigned	seconds;
{
int	ret_code,
	tim_code;


	signal(SIGALRM, timer);
	alarm(seconds);

	ret_code = -1;	/* assume bad read */

	tim_code = setjmp(env);
	while ( (tim_code == 0) && (ret_code != 1) )
	{
		ret_code = read(tty_fd, ch, count);
	}

	alarm(0);	/* turn alarms off */
	signal(SIGALRM, SIG_DFL);

	return( ((ret_code != -1) && (ret_code == count)) ? 0 : -1 );
}


/*	stimed_read: Will attempt to read from the terminal specified	*/
/*		    by the tty file descriptor for a set period of time.*/
/*									*/
/*	On Entry: tty file descriptor to read from, pointer to a byte	*/
/*		  to return received char in.				*/
/*		  and time in seconds.					*/
/*	On Exit:  0 for ok read or -1 for no char received.		*/
/*									*/

stimed_read(tty_fd, ch, seconds)
int	tty_fd;
byte	*ch;
unsigned	seconds;
{
int	ret_code,
	tim_code;


	signal(SIGALRM, timer);
	alarm(seconds);

	ret_code = -1;	/* assume bad read */

	tim_code = setjmp(env);
	while ( (tim_code == 0) && (ret_code != 1) )
	{
		ret_code = read(tty_fd, ch, 1);
	}

	alarm(0);	/* turn alarms off */
	signal(SIGALRM, SIG_DFL);

	return( (ret_code != -1) ? 0 : ret_code );
}


term_setup()
{
	term_name = getenv("TERM");	/* get terminal type name */
	if (term_name == (char *) 0)	/* see if TERM is defined */
	{
		return(-1);		/* no, so return error */
	}

	if (tgetent(terminfo_buff, term_name) != 1)	/* read termcap info */
	{
		return(-1);		/* if not in termcap then return error */
	}

	gtty(1, &org_stty);		/* get stdout info */
	ospeed = org_stty.sg_ospeed;	/* set global for tputs to use */

	ptr2ptr = str_buf;		/* setup pointer to a pointer */
	cm_str = tgetstr("pc", &ptr2ptr); /* get pad character */
	if (cm_str)			/* if any pad character */
	{
		PC = *cm_str;		/* set global to it */
	}
	else
	{
		PC = 0;			/* else say no padding needed */
	}

	cl_str = tgetstr("cl", &ptr2ptr);	/* get clear screen string */
	cm_str = tgetstr("cm", &ptr2ptr);	/* get cursor motion string */
	ce_str = tgetstr("ce", &ptr2ptr);	/* get clear to end of line */

	return(0);		/* return all ok */
}


cls()
{
	tputs(cl_str, tgetnum("li"), putchar);
}

clr_eol()
{
	tputs(ce_str, tgetnum("li"), putchar);
}


mov_cur(col, line)
int	col,
	line;
{
	col--;		/* termlib starts screens at 0,0 so we */
	line--;		/* need to normalize OUR coordinates */

	tputs(tgoto(cm_str, col, line), 1, putchar);
}


tolower(ch)
char	ch;
{
	return( ( (ch >= 'A') && (ch <= 'Z') ) ? ch + ' ' : ch );
}
SHAR_EOF
if test 8135 -ne "`wc -c < 'termio.c'`"
then
	echo shar: "error transmitting 'termio.c'" '(should have been 8135 characters)'
fi
fi
if test -f 'termio.h'
then
	echo shar: "will not over-write existing file 'termio.h'"
else
cat << \SHAR_EOF > 'termio.h'
#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/file.h>
#include <sys/errno.h>

typedef	unsigned char	byte;
typedef	unsigned short	word;

int	errno;	/* define this globally so that Unix can set it	*/

SHAR_EOF
if test 245 -ne "`wc -c < 'termio.h'`"
then
	echo shar: "error transmitting 'termio.h'" '(should have been 245 characters)'
fi
fi
if test -f 'wsstrip.c'
then
	echo shar: "will not over-write existing file 'wsstrip.c'"
else
cat << \SHAR_EOF > 'wsstrip.c'
/*	wsstrip.c						*/
/*	Program to strip out funny characters from a wordstar	*/
/*	document file kermited over in binary format.		*/
/*								*/
/*	Written March 19, 1985 by John Paul O'Brien		*/
/*		for Nova University Computer Center		*/
/*								*/


#include <stdio.h>

main()
{
char	ch;

	while ( (ch = getchar()) != EOF )	/* get all chars from stdin */
	{
		ch &= 0x7f;			/* strip off all high bits  */
		if ( (ch != '\r') &&		/* see if not cr or ^Z	    */
		     (ch != 0x1a) )		/* If not, then candidate   */
						/* for output.		    */
		{
			if ( (ch < ' ') &&	/* see if is a control char */
			     (ch != '\n') &&	/* excluding lf,	    */
			     (ch != '\t') &&	/* excluding tab,	    */
			     (ch != 0x07) )	/* and bell		    */
			{			/* if control character but */
						/* not one of the exclusions */
						/* then don't output it	    */
			}
			else
			{
				putchar(ch);	/* if ok then put to stdout */
			}
		}
	}
}
SHAR_EOF
if test 939 -ne "`wc -c < 'wsstrip.c'`"
then
	echo shar: "error transmitting 'wsstrip.c'" '(should have been 939 characters)'
fi
fi
if test -f 'wsstrip.l'
then
	echo shar: "will not over-write existing file 'wsstrip.l'"
else
cat << \SHAR_EOF > 'wsstrip.l'
.tr ~ \ 
.TH WSSTRIP l local
.SH NAME
wsstrip \- text file stripper to remove "bad" control characters
.SH SYNOPSIS
.BR "wsstrip <infile >outfile
.PP
.SH DESCRIPTION
.I Wsstrip
strips out unwanted control characters from text files usually created
by uploading a \fIWordStar\fR document file via kermit binary transfer.
The control characters stripped out are:
.PP

	any byte with the 7th bit turned on (larger than 0x80)
	has that bit stripped off to normalize the character

.br
	any control character that is not \\n, \\t, bell
.br

.pp

.SH EXAMPLE
For this example we will assume the file to be processed is text.bad.
We will generate the file text.good.
.PP
.sp 1
We type:   wsstrip <text.bad >text.good
.sp 1
.pp
.SH AUTHORS
WSSTRIP was written by:
John Paul O'Brien, Coordinator of Technical Support
Nova University Computer Center
3301 College Ave.
Ft. Lauderdale, Fl. 33314
(305) 475-7633
{allegra, ucf-cs, usfvax2}!novavax!john
.PP
.SH BUGS AND CAVEATS
Receive mode is too slow. Needs to be fixed. Should also include
a command line mode to bypass menu constraint (ie. xum -st file).
.PP
.SH BUGS AND CAVEATS
Options should be installed for different flavors of stripping.
Should also not use redirection (looks messy).
SHAR_EOF
if test 1231 -ne "`wc -c < 'wsstrip.l'`"
then
	echo shar: "error transmitting 'wsstrip.l'" '(should have been 1231 characters)'
fi
fi
if test -f 'xmodemio.c'
then
	echo shar: "will not over-write existing file 'xmodemio.c'"
else
cat << \SHAR_EOF > 'xmodemio.c'
#include <stdio.h>

unsigned char mk_chksum();

#define	NUL	0x00
#define	SOH	0x01
#define	EOT	0x04
#define	ACK	0x06
#define	NAK	0x15
#define	CAN	0x18

#define	RETRY_MAX	10
#define	BUFF_SIZE	128




/*	Send_file()							*/
/*	Routine to send a file from Unix to another computer via 	*/
/*	/dev/tty using the xmodem protocol in checksum mode.		*/
/*									*/
/*	On Entry: terminal file id, and file to send file id
/*	On Exit: returns 0 for success or -1 for failure		*/

send_file(tty_fid, file_id)
int	tty_fid,
	file_id;
{
int	ret_code,
	read_status,
	tty_status,
	ack_status,
	retry_counter;
	

unsigned char	checksum,
		sector_num,
		temp_byte,
		start_bad;

char	cpm_buff[BUFF_SIZE]; /* CP/M disk buffers are ALWAYS 128 bytes	*/


	ret_code = 0; /* assume no errors */
	cls();
	mov_cur(12, 10);
	printf("You have 1 minute to start receiving (control X to quit)....\n");

	uncook_tty(tty_fid);

	retry_counter = 0;	/* reset counter */
	do	/* wait for NAK from receiver so we can get in sync */
	{
		tty_status = timed_read(tty_fid, &temp_byte, 1, 6);

		if ( (tty_status == 0) &&
		     ((temp_byte == NAK) || (temp_byte == CAN)) )
		{
			if (temp_byte == NAK)
			{
				start_bad = 0;
				break;
			}
			else
			{
				start_bad = 1;
				break;
			}
		}
		else
		{
			start_bad = 1;
			retry_counter++;
		}
	}
	while (retry_counter < RETRY_MAX);

	if (start_bad)
	{
		ret_code = -1;	/* say error */
				/* We timed out or we got too much noise */
	}
	else
	{
		sector_num = 0;
		do
		{
			read_status = read(file_id, cpm_buff, BUFF_SIZE);
			sector_num++;
			if (read_status > 0)
			{
				for(; read_status < BUFF_SIZE; read_status++)
				{
					cpm_buff[read_status] = 0x1a; /* CP/M eof */
				}

				retry_counter = 0;	/* reset to send actual packet */
				do
				{
					temp_byte = SOH;
					write(tty_fid, &temp_byte, 1);	/* send SOH */
					temp_byte = ~sector_num;	/* get ones complement of sector number */
					write(tty_fid, &sector_num, 1);	/* sector count */
					write(tty_fid, &temp_byte, 1);	/* and its complement */
					checksum = mk_chksum(cpm_buff, BUFF_SIZE);
					write(tty_fid, cpm_buff, BUFF_SIZE);
					write(tty_fid, &checksum, 1);	/* send checksum */
					if ((ack_status = getack(tty_fid)) == -1)
					{
						retry_counter++;
					}
				}
				while ( (ack_status == -1) && (retry_counter < RETRY_MAX) );
			}
		}
		while ( (read_status > 0) && (retry_counter < RETRY_MAX) );

		retry_counter = 0;
		do
		{
			temp_byte = EOT;
			write(tty_fid, &temp_byte, 1);	/* send EOT */
		}
		while ( (getack(tty_fid) != 0) && (retry_counter++ < RETRY_MAX) );
	}

	if (retry_counter >= RETRY_MAX)
	{
		ret_code = -1;
	}

	close(file_id);
	return(ret_code);
}



/*	Recv_file()							*/
/*	Routine to receive  a file to Unix from another computer via 	*/
/*	/dev/tty using the xmodem protocol in checksum mode.		*/
/*									*/
/*	On Entry: terminal file id, file to recv file id
/*	On Exit: returns 0 for success or -1 for failure		*/

recv_file(tty_fid, file_id)
int	tty_fid;
{
int	ret_code,
	read_status,
	tty_status,
	ack_status,
	retry_counter;
	

unsigned char	checksum,
		sector_num,
		temp_byte,
		dummys[5],
		start_bad;


char	cpm_buff[BUFF_SIZE]; /* CP/M disk buffers are ALWAYS 128 bytes	*/

	ret_code = 0; /* assume no errors */
	cls();
	mov_cur(12, 10);
	printf("You have 1 minute to start sending (control X to quit)....\n");

	retry_counter = 0;	/* reset counter */
	do	/* send a NAK to sender so we can get in sync */
	{
		temp_byte = NAK;
		write(tty_fid, &temp_byte, 1);

		tty_status = timed_read(tty_fid, &temp_byte, 1, 6);

		if ( (tty_status == 0) &&
		     ((temp_byte == SOH) || (temp_byte == CAN)) )
		{
			if (temp_byte == SOH)
			{
				start_bad = 0;
				break;
			}
			else
			{
				start_bad = 1;
				break;
			}
		}
		else
		{
			start_bad = 1;
			retry_counter++;
		}
	}
	while (retry_counter < RETRY_MAX);

	if (start_bad)
	{
		ret_code = -1;	/* say error */
				/* We timed out or we got too much noise */
	}
	else
	{
		retry_counter = 0;
		sector_num = 1;		/* to compare with sent sector number */

/* First SOH was caught in NAK, CAN, code above. */

		while ( (temp_byte == SOH) && (retry_counter < RETRY_MAX) )
		{
			tty_status = stimed_read(tty_fid, &dummys[0], 2);
			tty_status += stimed_read(tty_fid, &dummys[1], 2);

			for (ack_status = 0; ack_status < BUFF_SIZE; ack_status++)
			{
				tty_status += stimed_read(tty_fid, &cpm_buff[ack_status], 2);
			}

			tty_status += stimed_read(tty_fid, &dummys[2], 2);

			checksum = mk_chksum(cpm_buff, BUFF_SIZE);

			if ( (tty_status == 0) &&
			     (sector_num == dummys[0]) && ((~sector_num & 0xff) == dummys[1]) &&
			     (checksum == dummys[2]) )
			{
				ack_status == write(file_id, cpm_buff, BUFF_SIZE);
				if (ack_status == BUFF_SIZE)
				{
					temp_byte = ACK;
					write(tty_fid, &temp_byte, 1);
					retry_counter = 0;
					ret_code = 0;
					sector_num++;
				}
				else
				{
					temp_byte = NAK;
					write(tty_fid, &temp_byte, 1);
					retry_counter++;
					ret_code = -1;
				}
			}
			else
			{
				temp_byte = NAK;
				write(tty_fid, &temp_byte, 1);
				retry_counter++;
				ret_code = -1;
			}

			tty_status = stimed_read(tty_fid, &temp_byte, 2);

			while (	(temp_byte != SOH) && (temp_byte != EOT) &&
				(retry_counter < RETRY_MAX) )
			{
				retry_counter++;
				tty_status = stimed_read(tty_fid, &temp_byte, 2);
			}

			if (retry_counter >= RETRY_MAX)
			{
				ret_code = -1;
				break;
			}

			retry_counter = 0;
			if (temp_byte == EOT)
			{
				temp_byte = ACK;
				write(tty_fid, &temp_byte, 1);
				break;
			}
		}
	}

	close(file_id);
	return(ret_code);
}


/*	getack: Will do a timed read on a pre-selected tty and 
	will return the status.

	On Entry: is passed the file id of the tty to use
	On Exit: returns 0 if got an ACK else returns -1 
*/

getack(tty_fid)
int	tty_fid;
{
char	temp_byte;

	if ( (timed_read(tty_fid, &temp_byte, 1, 5) == 0) &&
	     (temp_byte == ACK) )
	{
		return(0);	/* got ACK ok */
	}
	else
	{
		return(-1);	/* timed out or wrong character */
	}
}


/*	mk_chksum: Will generate a checksum on array of specified size and return
		   that checksum.

	On Entry: is passed the array and size to use
	On Exit: returns checksum
*/

unsigned char mk_chksum(array, size)
char	*array;
int	size;
{
int	counter;
unsigned char	checksum;

	checksum = 0;
	for (counter = 0; counter < size; counter++)
	{
		checksum += array[counter];	/* build up checksum */
	}
	return(checksum);
}
SHAR_EOF
if test 6442 -ne "`wc -c < 'xmodemio.c'`"
then
	echo shar: "error transmitting 'xmodemio.c'" '(should have been 6442 characters)'
fi
fi
if test -f 'xum.l'
then
	echo shar: "will not over-write existing file 'xum.l'"
else
cat << \SHAR_EOF > 'xum.l'
.tr ~ \ 
.TH XUM l local
.SH NAME
xum \- Xmodem file transfer for BSD 4.x Unix Systems (pronounced Zoom!)
.SH SYNOPSIS
.BR "xum
.PP
.SH DESCRIPTION
.I Xum
will transfer a text or binary file using the xmodem (a.k.a. modem7)
protocol. All commands to \fIXum\fR are entered into a menu which offers
these choices:

Selection of \fIbinary\fR or \fItext\fR file transfer.

Selection of \fIsend\fR or \fIreceive\fR from/to the host system.

\fIQuit\fI \fIXum\fR and return to \fIUnix\fR.

.SH NOTES
\fIXUM\fR needs to have a valid TERM entry in your environment to
display the menu.

\fIBinary\fR mode will transfer a file completely intact with no
characters added or deleted. \fIBinary\fR mode should be used for
uploading \fIWordstar\fR files. Then these files should be "cleaned up"
for use with \fIUnix\fR (see man entry for \fIwsstrip\fR).

\fIText\fR mode will, on upload, strip out all occurances of the
carrage return and control Z characters. On download, \fItext\fR mode
will add a carrage return before every linefeed (newline) character.

.pp

.SH AUTHOR
XUM was written by:
John Paul O'Brien, Coordinator of Technical Support
Nova University Computer Center
3301 College Ave.
Ft. Lauderdale, Fl. 33314
(305) 475-7633
{allegra, ucf-cs, usfvax2}!novavax!john
.PP
.SH BUGS AND CAVEATS
Receive mode is too slow. Needs to be fixed. Should also include
a command line mode to bypass menu constraint (ie. xum -st file).
SHAR_EOF
if test 1422 -ne "`wc -c < 'xum.l'`"
then
	echo shar: "error transmitting 'xum.l'" '(should have been 1422 characters)'
fi
fi
if test -f 'xumodem.c'
then
	echo shar: "will not over-write existing file 'xumodem.c'"
else
cat << \SHAR_EOF > 'xumodem.c'
#include <stdio.h>
#include <sys/file.h>

#define	BUFF_SIZE	128

main()
{
int	tty_fid,
	file_fid,
	cnt0,
	cnt1,
	t_tmp;

char	ch_reply,
	tmp_filename[24],
	file_name[50],		/* arbitrary size */
	f_buff[BUFF_SIZE],
	file_type;

FILE	*f_tmp;

	if (term_setup() != 0)
	{
		printf("Warning: This program needs to have the\n");
		printf("TERM environment variable setup before\n");
		printf("being run. Make sure this is done before\n");
		printf("executing xumodem again (set yourself up like\n");
		printf("you were going to use vi).\n");
		exit(1);
	}

	tty_fid = raw_tty("/dev/tty");
	if (tty_fid == -1)
	{
		printf("Error opening terminal for raw i/o\n");
		exit(1);
	}

	ch_reply = 0;
	file_type = 0;

	cls();
	mov_cur(22, 1);
	printf("XUMODEM - Xmodem for Unix Systems");
	mov_cur(9, 3);
        printf("NOTICE: This version of XUMODEM supports checksum transfers only.");
	mov_cur(7,10);
	printf("Send a file, Receive a file, set Text file xfer, set Binary file xfer,");
	mov_cur(25, 12);
	printf("or Quit (s, r, t, b, q): ");
	clr_eol();
	mov_cur(24, 7);
	printf("File transfer mode = ");

	while (ch_reply != 'q')
	{
		mov_cur(45, 7);
		if (file_type == 0)
		{
			printf("text files");
		}
		else
		{
			printf("binary files");
		}
		clr_eol();

		mov_cur(50, 12);
		ch_reply = tolower(0x7f & getchar());

		switch(ch_reply)
		{
			case 's' :
				file_fid = get_fileid(tty_fid, file_name, ch_reply);
				if (file_fid >= 0)
				{
					if (file_type == 0)
					{
						sprintf(tmp_filename, "/tmp/xum%d", getpid());
						f_tmp = fopen(tmp_filename, "w+");
						while( (cnt0 = read(file_fid, f_buff, BUFF_SIZE)) > 0 )
						{
							for (cnt1 = 0; cnt1 < cnt0; cnt1++)
							{
								if (f_buff[cnt1] == '\n')
								{
									fputc('\r', f_tmp);
								}
								fputc(f_buff[cnt1], f_tmp);
							}
						}
						fclose(f_tmp);
						close(file_fid);
						file_fid = open(tmp_filename, O_RDONLY);
					}
					send_file(tty_fid, file_fid);
					if (file_type == 0)
					{
						unlink(tmp_filename);
					}
				}
				ch_reply = 'q';
				break;
			case 'r' :
				file_fid = get_fileid(tty_fid, file_name, ch_reply);
				if (file_fid >= 0)
				{
					cnt0 = recv_file(tty_fid, file_fid);
					if ( (file_type == 0) &&
					     (cnt0 == 0) )
					{
						sprintf(tmp_filename, "/tmp/xum%d", getpid());
						f_tmp = fopen(tmp_filename, "w+");
						file_fid = open(file_name, O_RDONLY);
						while( (cnt0 = read(file_fid, f_buff, BUFF_SIZE)) > 0 )
						{
							for (cnt1 = 0; cnt1 < cnt0; cnt1++)
							{
								if ( (f_buff[cnt1] != '\r') &&
								     (f_buff[cnt1] != 0x1a) )
								{
									fputc(f_buff[cnt1], f_tmp);
								}
							}
						}
						close(file_fid);
						fclose(f_tmp);
						t_tmp = open(tmp_filename, O_RDONLY);
						file_fid = open(file_name, O_CREAT | O_TRUNC | O_WRONLY, 0600);
						while( (cnt0 = read(t_tmp, f_buff, BUFF_SIZE)) > 0 )
						{
							write(file_fid, f_buff, cnt0);
						}
						close(file_fid);
						close(t_tmp);
						unlink(tmp_filename);
					}
				}
				ch_reply = 'q';
				break;
			case 't' :
				file_type = 0;
				break;
			case 'b' :
				file_type = 1;
				break;
			default :
				break;
		}
	}

	mov_cur(50, 12);
	clr_eol();
	printf("Quit");
	reset_tty(tty_fid);
	mov_cur(1, 24);
}



/*	Get_fileid()							*/
/*	Routine to ask for a filename and do processing based on send	*/
/*	or receive mode.						*/
/*									*/
/*	On Entry: terminal file id, array for file name, and		*/
/*		  type of file function (send, recv).			*/
/*	On Exit: returns opened or created file id or -1 for failure	*/
/*		 and file_name is the file name used.			*/


get_fileid(tty_fid, file_name, file_func)
int	tty_fid;
char	*file_name,
	file_func;
{
int	file_id;
char	temp_byte;

	if (file_func == 'r')
	{

		printf("receive a file");

		mov_cur(1, 14);
		clr_eol();

		mov_cur(10, 14);

		printf("Input filename to receive: ");
		clr_eol();
		cook_tty(tty_fid);
		scanf("%s", file_name);
		uncook_tty(tty_fid);

		file_id = open(file_name, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, 0600);
		if (-1 == file_id)
		{
			printf("\nError creating %s. File may exist. Overwrite (y, n) ? ", file_name);

			temp_byte = tolower(0x7f & getchar());
			while ( (temp_byte != 'y') &&
				(temp_byte != 'n') )
			{
				temp_byte = tolower(0x7f & getchar());
			}

			if (temp_byte == 'y')
			{
				file_id = open(file_name, O_CREAT | O_TRUNC | O_WRONLY, 0600);
			}
		}

		if (file_id  < 0)
		{
			printf("\r\nError opening file; can not create %s\r\n", file_name);
		}
	}
	else
	{
		printf("send a file");


		mov_cur(10, 14);

		printf("Input filename to send: ");
		clr_eol();
		cook_tty(tty_fid);
		scanf("%s", file_name);
		uncook_tty(tty_fid);

		if (-1 == (file_id = open(file_name, O_RDONLY)))
		{
			printf("Error opening %s; file does not exist\n", file_name);
		}
	}
	return(file_id);
}
SHAR_EOF
if test 4841 -ne "`wc -c < 'xumodem.c'`"
then
	echo shar: "error transmitting 'xumodem.c'" '(should have been 4841 characters)'
fi
fi
exit 0
#	End of shell archive