[comp.sources.unix] v14i104: Dial out and terminal emulator, Part06/06

rsalz@bbn.com (Rich Salz) (05/20/88)

Submitted-by: fthood!egray
Posting-number: Volume 14, Issue 104
Archive-name: pcomm/part06

#! /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:
#	x_batch.c
#	x_menu.c
#	x_rcv.c
#	x_send.c
#	x_win.c
#	xmodem.c
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'x_batch.c'" '(7780 characters)'
if test -f 'x_batch.c'
then
	echo shar: "will not over-write existing file 'x_batch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_batch.c'
X/*
X * Routines to support the batch protocols.
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <curses.h>
X#include "misc.h"
X#include "xmodem.h"
X
X/*
X * Send the file name for the modem7 batch.  Only uses 11 characters
X * of the filename.
X */
X
Xint
Xsend_modem7(win, name)
XWINDOW *win;
Xchar *name;
X{
X	char *new_name, *fix_name();
X	unsigned char sum, calc_sum();
X
X					/* convert to 11 character name */
X	new_name = fix_name(name);
X	sum = calc_sum((unsigned char *) new_name, 12);
X
X	putc_line(ACK);
X					/* for each character in the name */
X	while (*new_name != CTRLZ) {
X		putc_line((unsigned char) *new_name);
X
X		switch (getc_line(3)) {
X			case ACK:	/* got it! */
X				break;
X			case CAN:	/* cancel transmission */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			default:
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NAME FAILED");
X				wrefresh(win);
X				return(ERROR);
X		}
X		new_name++;
X	}
X	putc_line(CTRLZ);
X					/* verify the checksum */
X	if (getc_line(10) != sum) {
X		putc_line('u');
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "CHECKSUM FAILED");
X		wrefresh(win);
X		return(ERROR);
X	}
X	putc_line(ACK);
X	return(0);
X}
X
X/*
X * Receive a modem 7 file name.  A return code of 1 means the end of the
X * batch transfers.
X */
X
Xint
Xrcv_modem7(win, default_err)
XWINDOW *win;
Xint default_err;
X{
X	int i, c, err_method, err_count, got_it;
X	unsigned char sum, calc_sum();
X	char temp_name[13];
X	extern char *null_ptr, file_name[15];
X	void change_name(), unfix_name();
X					/* send the first char */
X	err_method = default_err;
X	err_count = 0;
X	got_it = 0;
X	while (err_count < MAX_ERRORS) {
X					/* switch to checksum? */
X		if (default_err == 1 && err_count > MAX_ERRORS/2)
X			err_method = 0;
X
X		if (err_method)
X			putc_line('C');
X		else
X			putc_line(NAK);
X					/* what'd we get? */
X		if (getc_line(10) == ACK) {
X			got_it++;
X			break;
X		}
X		err_count++;
X	}
X	if (!got_it)
X		return(ERROR);
X					/* get the name */
X	for (i=0; i<12; i++) {
X		c = getc_line(3);
X
X		switch(c) {
X			case EOT:	/* end of batch? */
X				return(-1);
X			case CAN:	/* cancel transmission */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			case 'u':	/* bad name character */
X				beep();
X				clear_line(win, 12, 24, 1);
X				wattrstr(win, A_BOLD, "BAD NAME");
X				wrefresh(win);
X				return(ERROR);
X			default:	/* the name... */
X				temp_name[i] = c;
X				if (c != CTRLZ)
X					putc_line(ACK);
X				break;
X		}
X	}
X	temp_name[12] = NULL;
X					/* send our checksum */
X	sum = calc_sum((unsigned char *) temp_name, 12);
X	putc_line(sum);
X					/* do they agree ? */
X	if (getc_line(10) != ACK) {
X		beep();
X		clear_line(win, 12, 24, 1);
X		wattrstr(win, A_BOLD, "BAD NAME");
X		wrefresh(win);
X		return(ERROR);
X	}
X					/* load the file_name array */
X	unfix_name(temp_name);
X					/* any name collisions? */
X	change_name(win, file_name);
X	return(0);
X}
X
X/*
X * Send the block 0 information for a ymodem batch transfer.  Uses only
X * the name component of the path and the file size.
X */
X
Xint
Xsend_ymodem(win, file, size)
XWINDOW *win;
Xchar *file;
Xint size;
X{
X	int i, crc;
X	char *strcpy();
X	unsigned char buf[133];
X					/* start with a clean block */
X	for (i=0; i<132; i++)
X		buf[i] = NULL;
X					/* the header */
X	buf[0] = SOH;
X	buf[1] = 0;
X	buf[2] = 255;
X
X	/*
X	 * The block zero consists of the file name (no path component),
X	 * a NULL, and the file length (as a string).  The end of batch
X	 * marker is an empty block.
X	 */
X	if (file != NULL) {
X		strcpy((char *) &buf[3], file);
X		sprintf((char *) &buf[strlen(file)+4], "%d", size);
X	}
X					/* the crc */
X	crc = calc_crc(&buf[3], 128);
X	buf[131] = crc >> 8;
X	buf[132] = crc;
X					/* the block count */
X	mvwaddstr(win, 7, 24, "0   ");
X
X	return(send_block(win, buf, 133));
X}
X
X/*
X * Receive the block 0 information for a ymodem batch transfer.  We
X * only use the file name and the size (if present).  Currently doesn't
X * support full path names.
X */
X
Xint
Xrcv_ymodem(win)
XWINDOW *win;
X{
X	int code, length_is_at;
X	extern unsigned char buf[1029];
X	extern int file_length;
X	extern char file_name[15];
X
X	file_length = 0;
X	file_name[0] = NULL;
X					/* read the zero block */
X	if (code = rcv_block(win, 1, 1024, 0))
X		return(code);
X					/* at end of batch */
X	if (buf[3] == NULL)
X		return(0);
X					/* get the file name */
X	change_name(win, (char *) &buf[3]);
X					/* any trouble ?? */
X	if (file_name[0] == NULL) {
X		putc_line(CAN);
X		return(0);
X	}
X	/*
X	 * The file length is placed after the NULL of the file name
X	 * and is terminated by another NULL.  If the length is missing,
X	 * atoi() will see a NULL and return 0.
X	 */
X	length_is_at = strlen((char *) &buf[3]) + 4;
X	file_length = atoi((char *) &buf[length_is_at]);
X	return(0);
X}
X
X/*
X * Handle file name collisions.  Prepend an 'X' to the name until you find
X * a name that doesn't already exist.  Creates a NULL name on error.
X * Loads the global character array 'file_name'.
X */
X
Xvoid
Xchange_name(win, str)
XWINDOW *win;
Xchar *str;
X{
X	int i, modified;
X	char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
X	unsigned int sleep();
X	extern char file_name[15];
X					/* dissect the name component */
X	if ((s = strrchr(str, '/')))
X		strcpy(temp, s++);
X	else
X		strcpy(temp, str);
X
X	strcpy(ans, temp);
X	file_name[0] = NULL;
X					/* write permission on directory ? */
X	if (access(".", 2)) {
X		beep();
X		clear_line(win, 12, 24, 1);
X		wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY");
X		wrefresh(win);
X		return;
X	}
X					/* prepend up to 13 'X's */
X	modified = 0;
X	for (i=1; i<14; i++) {
X		if (access(ans, 0)) {
X			if (modified) {
X				beep();
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NAME COLLISION");
X				wrefresh(win);
X				sleep(1);
X			}
X			strcpy(file_name, ans);
X			return;
X		}
X
X		modified++;
X		strcpy(temp, "X");
X		strncat(temp, ans, 13);
X		temp[14] = NULL;
X		strcpy(ans, temp);
X	}
X	beep();
X	clear_line(win, 12, 24, 1);
X	waddstr(win, "BAD NAME");
X	wrefresh(win);
X	return;
X}
X
X/*
X * Convert a perfectly good Unix file name to fit the CP/M file name
X * rules.  Used for the modem7 batch file transfer.  Returns a pointer
X * to the new name.
X */
X
Xchar *
Xfix_name(path)
Xchar *path;
X{
X	int dot;
X	char *s, *name, temp[15], *ext, *strcpy(), *strrchr();
X	static char ans[13];
X					 /* ignore the path component */
X	if (s = strrchr(path, '/'))
X		strcpy(temp, s++);
X	else
X		strcpy(temp, path);
X	name = temp;
X
X	ext = NULL;
X	dot = 0;
X	for (s = name; *s; ++s) {
X		if (*s == '.' && !dot) {
X			dot = 1;
X			*s = NULL;
X			ext = s + 1;
X		}
X		if (islower(*s))
X			*s = toupper(*s);
X	}
X					/* if null name component */
X	if (*name == NULL)
X		name = "X";
X					/* if name too long */
X	if (strlen(name) > 8) 
X		*(name+8) = NULL;
X					/* if extension too long */
X	if (strlen(ext) > 3) 
X		*(ext+3) = NULL;
X
X	sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ);
X	return(ans);
X}
X
X/*
X * Convert a CP/M style filename into a legal Unix file name.  Loads the
X * global character array 'file_name'.
X */
X
Xvoid
Xunfix_name(cpm_name)
Xchar *cpm_name;
X{
X	int i, n, dot;
X	char temp[15];
X	extern char file_name[15];
X
X	file_name[0] = NULL;
X	if (!*cpm_name)
X		return;
X
X	strcpy(temp, cpm_name);
X					/* 8 character of the name */
X	n = 0;
X	for (i=0; i<8; i++) {
X		if (temp[i] != ' ') {
X			if (isupper(temp[i]))
X				file_name[n++] = tolower(temp[i]);
X			else
X				file_name[n++] = temp[i];
X		}
X	}
X					/* 3 character extension */
X	dot = 0;
X	for (i=8; i<11; i++) {
X		if (temp[i] != ' ') {
X			if (!dot) {
X				dot++;
X				file_name[n++] = '.';
X			}
X			if (isupper(temp[i]))
X				file_name[n++] = tolower(temp[i]);
X			else
X				file_name[n++] = temp[i];
X		}
X	}
X	file_name[n] = NULL;
X	return;
X}
SHAR_EOF
if test 7780 -ne "`wc -c < 'x_batch.c'`"
then
	echo shar: "error transmitting 'x_batch.c'" '(should have been 7780 characters)'
fi
fi
echo shar: "extracting 'x_menu.c'" '(4000 characters)'
if test -f 'x_menu.c'
then
	echo shar: "will not over-write existing file 'x_menu.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_menu.c'
X/*
X * Open a window to display the choices of file transfer protocols and
X * prompt for the file name(s).  A return code of 1 means turn the
X * input routine back on.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X#include "xmodem.h"
X
Xint
Xxfer_menu(up)
Xint up;
X{
X	WINDOW *xm_win, *newwin();
X	char *list, *get_names();
X	int type, is_batch;
X	extern char *null_ptr;
X	void xfer_win(), xfer_ascii(), free_ptr();
X
X	xm_win = newwin(15, 20, 2, 45);
X
X	mvwaddstr(xm_win, 2, 3, "1) xmodem");
X	mvwaddstr(xm_win, 3, 3, "2) xmodem-1k");
X	mvwaddstr(xm_win, 4, 3, "3) modem7");
X	mvwaddstr(xm_win, 5, 3, "4) ymodem");
X	mvwaddstr(xm_win, 6, 3, "5) ymodem-g");
X	mvwaddstr(xm_win, 7, 3, "6) ASCII");
X	mvwaddstr(xm_win, 11, 3, "ESC to Abort");
X	mvwaddstr(xm_win, 13, 3, "Protocol:");
X	box(xm_win, '|', '-');
X	if (up)
X		mvwattrstr(xm_win, 0, 6, A_BOLD, " Upload ");
X	else
X		mvwattrstr(xm_win, 0, 5, A_BOLD, " Download ");
X
X	wmove(xm_win, 13, 13);
X	wrefresh(xm_win);
X					/* get the protocol */
X	while ((type = get_num(xm_win, 1)) != -1) {
X		if (type >=1 && type <= PROTOCOLS)
X			break;
X		beep();
X		mvwaddch(xm_win, 13, 13, ' ');
X		wmove(xm_win, 13, 13);
X		wrefresh(xm_win);
X	}
X					/* is a batch protocol ? */
X	is_batch = 0;
X	switch (type-1) {
X		case MODEM7:
X		case YMODEM:
X		case YMODEM_G:
X			is_batch++;
X			break;
X		default:
X			break;
X	}
X	werase(xm_win);
X	wrefresh(xm_win);
X	delwin(xm_win);
X
X	touchwin(stdscr);
X	refresh();
X
X	if (type == -1)
X		return(0);
X	type--;
X
X	/*
X	 * When receiving files in one of the batch modes, there is
X	 * need to prompt for a list of file names.
X	 */
X	list = null_ptr;
X	if (up || !is_batch) {
X		if (!(list = get_names(up, type, is_batch)))
X			return(0);
X	}
X					/* if ascii transfer */
X	if (type == XASCII) {
X		xfer_ascii(list, up);
X		free_ptr(list);
X		if (up)
X			return(0);
X		return(1);
X	}
X	xfer_win(list, up, type);
X	free_ptr(list);
X	return(1);
X}
X
X/*
X * Prompt for a list of files for the transfer programs.  A NULL return
X * code means you chickened out.
X */
X
Xchar *
Xget_names(up, type, is_batch)
Xint up, type, is_batch;
X{
X	int can;
X	WINDOW *gn_win, *newwin();
X	char *ans, *list, *file, buf[40], *expand(), *get_str(), *strtok();
X	static char *direction[2] = {"Receive", "Send"};
X	static char *protocol[PROTOCOLS] = {"xmodem", "xmodem-1k", "modem7",
X	"ymodem", "ymodem-g", "ASCII"};
X					/* prompt for file spec */
X	gn_win = newwin(7, 70, 5, 5);
X
X	mvwaddstr(gn_win, 3, 4, "Enter filename: ");
X	box(gn_win, '|', '-');
X	sprintf(buf, " %s %s ", direction[up], protocol[type]);
X
X	while (1) {
X		mvwattrstr(gn_win, 0, 3, A_BOLD, buf);
X		wmove(gn_win, 3, 20);
X		wrefresh(gn_win);
X					/* get the answers */
X		if (is_batch)
X			ans = get_str(gn_win, 60, NULL, NULL);
X		else
X			ans = get_str(gn_win, 60, NULL, " 	");
X
X		if (ans == NULL || *ans == NULL) {
X			list = NULL;
X			break;
X		}
X		list = expand(ans);
X					/* batchs check "on the fly" */
X		if (is_batch)
X			break;
X		/*
X		 * The non-batch protocols don't check read and write
X		 * permission on the fly, so we check 'em here.  Since
X		 * they aren't batch, we use only one file.
X		 */
X		file = strtok(list, "	 ");
X					/* check read permission */
X		if (up) {
X			if (access(file, 4)) {
X				beep();
X				mvwattrstr(gn_win, 4, 15, A_BOLD, "Can't find or no read permission");
X				wrefresh(gn_win);
X				wait_key(gn_win, 3);
X				clear_line(gn_win, 4, 15, 1);
X				clear_line(gn_win, 3, 20, 1);
X				wrefresh(gn_win);
X			}
X			else
X				break;
X		}
X					/* check write permission */
X		else {
X			if (!(can = can_write(file))) {
X				beep();
X				clear_line(gn_win, 4, 15, 1);
X				mvwattrstr(gn_win, 4, 15, A_BOLD, "No write permission");
X				wrefresh(gn_win);
X				wait_key(gn_win, 3);
X				clear_line(gn_win, 4, 15, 1);
X				clear_line(gn_win, 3, 20, 1);
X				wrefresh(gn_win);
X			}
X			if (can == 2) {
X				if (!yes_prompt(gn_win, 4, 15, A_BOLD, "File exists, overwrite")) {
X					list = NULL;
X					break;
X				}
X			}
X			if (can)
X				break;
X		}
X	}
X	werase(gn_win);
X	wrefresh(gn_win);
X	delwin(gn_win);
X
X	touchwin(stdscr);
X	refresh();
X	return(list);
X}
SHAR_EOF
if test 4000 -ne "`wc -c < 'x_menu.c'`"
then
	echo shar: "error transmitting 'x_menu.c'" '(should have been 4000 characters)'
fi
fi
echo shar: "extracting 'x_rcv.c'" '(10526 characters)'
if test -f 'x_rcv.c'
then
	echo shar: "will not over-write existing file 'x_rcv.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_rcv.c'
X/*
X * Receive a list of files using a version of Ward Christensen's file
X * transfer protocol.  A return code of 1 means the user must acknowledge
X * an error condition.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xunsigned char buf[1029];
Xchar file_name[15];
Xint file_length, err_method, tot_err, block_size;
X
Xint
Xrcv_xmodem(win, list, type, fast)
XWINDOW *win;
Xchar *list;
Xint type, fast;
X{
X	FILE *fp;
X	int default_err, is_batch, max_block, code, file_count, i, got_hdr;
X	int block, recv, hours, mins, secs;
X	float percent, performance;
X	unsigned char blk;
X	unsigned int sleep();
X	char *file, *name, *strcpy(), *strrchr(), *strtok();
X	void cancel_xfer();
X
X	/*
X	 * What type of xmodem?  The default_err means:  0=checksum only,
X	 * 1=CRC or checksum, 2=CRC only, and 3=none.
X	 */
X	switch(type) {
X		case XMODEM:
X			mvwaddstr(win, 2, 24, "xmodem");
X			default_err = 1;
X			is_batch = 0;
X			max_block = 128;
X			break;
X		case XMODEM_1k:
X			mvwaddstr(win, 2, 24, "xmodem-1k");
X			default_err = 1;
X			is_batch = 0;
X			max_block = 1024;
X			break;
X		case MODEM7:
X			mvwaddstr(win, 2, 24, "modem7");
X			default_err = 0;
X			is_batch = 1;
X			max_block = 128;
X			break;
X		case YMODEM:
X			mvwaddstr(win, 2, 24, "ymodem");
X			default_err = 2;
X			is_batch = 1;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case YMODEM_G:
X			mvwaddstr(win, 2, 24, "ymodem-g");
X			default_err = 3;
X			is_batch = 1;
X			max_block = 1024;
X			performance = 1.02;
X			break;
X	}
X
X	tot_err = 0;
X	file_count = 0;
X	mvwaddstr(win, 11, 24, "0  ");
X
X	while (1) {
X		file_count++;
X		file_length = 0;
X					/* user supplied name */
X		if (!is_batch) {
X			if (file_count > 1)
X				break;
X
X			file = strtok(list, " 	");
X					/* dissect the file name */
X			if ((name = strrchr(file, '/')))
X				strcpy(file_name, name++);
X			else
X				strcpy(file_name, file);
X		}
X					/* get the modem7 file name */
X		if (type == MODEM7) {
X			if (code = rcv_modem7(win, default_err))
X				return(code +1);
X
X			file = file_name;
X		}
X					/* get the block 0 */
X		if (type == YMODEM || type == YMODEM_G) {
X			if (code = send_first(win, max_block, default_err))
X				return(code +1);
X
X			if (code = rcv_ymodem(win))
X				return(code +1);
X
X					/* at the end? */
X			if (buf[3] == NULL) {
X				beep();
X				wrefresh(win);
X				putc_line(ACK);
X				sleep(1);
X				return(0);
X			}
X			file = file_name;
X		}
X					/* any trouble ? */
X		if (file_name[0] == NULL)
X			continue;
X
X		clear_line(win, 3, 24, 1);
X		waddstr(win, file_name);
X					/* if file length is known */
X		if (file_length) {
X			mvwprintw(win, 4, 24, "%-10d", file_length);
X
X			secs = (file_length * 10.0 / dir->baud[dir->d_cur]) * performance;
X			hours = secs / 3600;
X			mins = (secs % 3600) / 60;
X			secs = (secs % 3600) % 60;
X
X			mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
X		}
X					/* some starting numbers */
X		mvwaddstr(win, 7, 24, "0    ");
X		if (file_length && fast)
X			mvwaddstr(win, 8, 24, "0%  ");
X		if (fast)
X			mvwaddstr(win, 9, 24, "0          ");
X		mvwaddstr(win, 10, 24, "0 ");
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "NONE");
X		wrefresh(win);
X
X		/*
X		 * If the user supplied the name, write permission is checked
X		 * by the get_names() routine in xfer_menu().  If a modem7
X		 * or ymodem supplied name, the permission is checked by the
X		 * rcv_modem7() and rcv_ymodem() routines.
X		 */
X					/* open the file */
X		if (!(fp = fopen(file, "w"))) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
X			wrefresh(win);
X			cancel_xfer();
X			return(1);
X		}
X					/* ACK the block 0 */
X		if (type == YMODEM || type == YMODEM_G)
X			putc_line(ACK);
X
X		if (code = send_first(win, max_block, default_err)) {
X			fclose(fp);
X			cancel_xfer();
X			return(code +1);
X		}
X					/* here we go... */
X		blk = 1;
X		block = 1;
X		recv = 0;
X		got_hdr = 1;
X		while (1) {
X			code = rcv_block(win, got_hdr, max_block, blk);
X
X			if (code < 0) {
X				fclose(fp);
X				cancel_xfer();
X				return(code +1);
X			}
X			got_hdr = 0;
X					/* are we done? */
X			if (buf[0] == EOT) {
X				if (!is_batch) {
X					beep();
X					wrefresh(win);
X					sleep(1);
X				}
X				break;
X			}
X					/* if not a duplicate block */
X			if (!code) {
X				fwrite((char *) &buf[3], sizeof(buf[0]), block_size, fp);
X				mvwprintw(win, 7, 24, "%-5d", block);
X				if (fast) {
X					recv += block_size;
X					mvwprintw(win, 9, 24, "%-10d", recv);
X				}
X				blk++;
X				block++;
X			}
X			/*
X			 * If the length is known, give the same status
X			 * report as uploading
X			 */
X			if (file_length && fast) {
X				percent = recv * 100.0 / file_length;
X				if (percent > 100.0)
X					percent = 100.0;
X				mvwprintw(win, 8, 24, "%0.1f%%", percent);
X			}
X			wrefresh(win);
X			putc_line(ACK);
X		}
X		if (file_length && fast) {
X			mvwaddstr(win, 8, 24, "100%  ");
X			wrefresh(win);
X		}
X		/*
X		 * If the file length is not known, then search backwards
X		 * from the end of the file until you find a character that
X		 * is not the ^Z padding character
X		 */
X		if (!file_length) {
X			for (i=block_size+2; i>2; i--) {
X				if (buf[i] != CTRLZ)
X					break;
X			}
X			file_length = recv - block_size + i -2;
X		}
X		fclose(fp);
X		fix_length(file_name, file_length);
X					/* ACK the EOT */
X		putc_line(ACK);
X	}
X	return(0);
X}
X
X/*
X * Send the first character to start the transmission and set the error
X * checking method.  Returns the standard error codes or 0 on success.
X * The variables err_method and block_size are global.
X */
X
Xint
Xsend_first(win, max_block, default_err)
XWINDOW *win;
Xint max_block, default_err;
X{
X	int i, err_count;
X	unsigned int sleep();
X					/* default error method */
X	err_method = default_err;
X	if (err_method > 1)
X		err_method--;
X					/* send the first char */
X	err_count = 0;
X	while (err_count < MAX_ERRORS*2) {
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X
X					/* check for keyboard abort */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X					/* switch to checksum? */
X		if (default_err == 1 && err_count > MAX_ERRORS)
X			err_method = 0;
X
X					/* send error method code */
X		clear_line(win, 5, 24, 1);
X		switch (err_method) {
X			case 0:
X				waddstr(win, "CHECKSUM");
X				putc_line(NAK);
X				break;
X			case 1:
X				waddstr(win, "CRC");
X				putc_line('C');
X				break;
X			case 2:
X				waddstr(win, "NONE");
X				putc_line('G');
X				break;
X		}
X		/*
X		 * We've cut the delay time in half, so we double
X		 * the allowable errors
X		 */
X		if ((i = getc_line(5)) == -1) {
X			err_count++;
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "NO RESPONSE");
X			wrefresh(win);
X			continue;
X		}
X		buf[0] = i;
X
X		switch(buf[0]) {
X			case SOH:	/* small block follows */
X				block_size = 128;
X				return(0);
X			case STX:	/* large block follows */
X				if (max_block == 1024) {
X					block_size = 1024;
X					return(0);
X				}
X				/* fall thru */
X			default:
X				err_count++;
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "BAD HEADER");
X				wrefresh(win);
X					/* read some garbage... */
X				fread_line(buf, 1028, 3);
X				putc_line(NAK);
X				break;
X		}
X	}
X	beep();
X	clear_line(win, 12, 24, 1);
X	wattrstr(win, A_BOLD, "TIMED OUT");
X	wrefresh(win);
X	return(ERROR);
X}
X
X/*
X * Receive a block of info from the host.  Returns a 0 on success, a 1 on
X * a duplicate block or the standard error codes.   The variables 
X * err_method and block_size are global.
X */
X
Xint
Xrcv_block(win, got_hdr, max_block, blk)
XWINDOW *win;
Xint got_hdr, max_block;
Xunsigned char blk;
X{
X	int i, err_count, bad_block, out_of_sync, crc;
X	unsigned int packet, sleep();
X	unsigned char calc_sum(), crc_1, crc_2;
X
X	err_count = 0;
X	while (err_count < MAX_ERRORS) {
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X		mvwprintw(win, 11, 24, "%-3d", tot_err);
X
X					/* scan the keyboard for abort */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X					/* have we already got a hdr? */
X		if (!got_hdr) {
X			if ((i = getc_line(10)) == -1) {
X				err_count++;
X				tot_err++;
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "NO RESPONSE");
X				wrefresh(win);
X				continue;
X			}
X			buf[0] = i;
X					/* what'd we get? */
X			switch(buf[0]) {
X				case EOT:	/* we're done! */
X					clear_line(win, 12, 24, 1);
X					waddstr(win, "TRANSFER COMPLETE");
X					wrefresh(win);
X					sleep(1);
X					return(0);
X				case SOH:	/* small block follows */
X					block_size = 128;
X					break;
X				case STX:	/* large block follows */
X					if (max_block == 1024) {
X						block_size = 1024;
X						break;
X					}
X					/* fall thru... */
X				default:
X					err_count++;
X					tot_err++;
X					clear_line(win, 12, 24, 1);
X					waddstr(win, "BAD HEADER");
X					wrefresh(win);
X
X					/* flush a bad packet */
X					fread_line(buf, 1028, 5);
X					putc_line(NAK);
X					continue;
X			}
X		}
X		got_hdr = 0;
X					/* read the rest of the packet */
X		packet = block_size + 2 + (err_method ? 2 : 1);
X		if (fread_line(&buf[1], packet, 10) == -1) {
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "TIMED OUT");
X			wrefresh(win);
X			putc_line(NAK);
X			err_count++;
X			tot_err++;
X			continue;
X		}
X
X		/*
X		 * Validation of the packet includes checking the
X		 * block number, its complement, and the crc/checksum.
X		 */
X		out_of_sync = 0;
X		if (buf[1] != blk || buf[2] != (unsigned char) ~blk)
X			out_of_sync++;
X
X		bad_block = 0;
X		switch(err_method) {
X			case 0:		/* checksum */
X				if (buf[block_size +3] != calc_sum(&buf[3], block_size))
X					bad_block++;
X				break;
X			case 1:		/* CRC */
X				crc = calc_crc(&buf[3], block_size);
X				crc_1 = crc >> 8;
X				crc_2 = crc;
X				if (buf[block_size +3] != crc_1 || buf[block_size +4] != crc_2)
X					bad_block++;
X				break;
X			case 2:		/* none */
X				return(0);
X		}
X					/* handle errors */
X		if (bad_block) {
X			clear_line(win, 12, 24, 1);
X			if (err_method)
X				waddstr(win, "CRC FAILED");
X			else
X				waddstr(win, "CHECKSUM FAILED");
X			wrefresh(win);
X			putc_line(NAK);
X			err_count++;
X			tot_err++;
X			continue;
X		}
X					/* not really an error */
X		if (out_of_sync) {
X			/*
X			 * If a perfect packet is off by 1 block number,
X			 * (a lost ACK could cause this) then treat it as
X			 * a good block but don't write it to disk.
X			 */
X			if (buf[1] == (unsigned char) blk-1)
X				return(1);
X
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "OUT OF SYNC");
X			wrefresh(win);
X			putc_line(NAK);
X			err_count++;
X			tot_err++;
X			continue;
X		}
X		return(0);
X	}
X	beep();
X	clear_line(win, 12, 24, 1);
X	waddstr(win, "TOO MANY ERRORS");
X	wrefresh(win);
X	return(ERROR);
X}
SHAR_EOF
if test 10526 -ne "`wc -c < 'x_rcv.c'`"
then
	echo shar: "error transmitting 'x_rcv.c'" '(should have been 10526 characters)'
fi
fi
echo shar: "extracting 'x_send.c'" '(10461 characters)'
if test -f 'x_send.c'
then
	echo shar: "will not over-write existing file 'x_send.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_send.c'
X/*
X * Send a list of files using a version of Ward Christensen's file
X * transfer protocol.  A non-zero return code means an error must be
X * acknowledged by the user.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "dial_dir.h"
X#include "status.h"
X#include "misc.h"
X#include "xmodem.h"
X
Xint tot_err, err_method;
X
Xint
Xsend_xmodem(win, list, type, fast)
XWINDOW *win;
Xchar *list;
Xint type, fast;
X{
X	FILE *fp;
X	int i, block_size, file_count, secs, mins, hours, size, xmit_size;
X	int big_blocks, small_blocks, err_count, got_it, num, block, sent;
X	int crc, is_batch, code, max_block, default_err;
X	char *file, *strtok(), *name, *strrchr();
X	unsigned char buf[1029], blk, calc_sum();
X	unsigned int packet, sleep();
X	float performance, percent;
X	struct stat sbuf;
X
X	/*
X	 * What type of xmodem?  The default_err means: 0=checksum only,
X	 * 1=checksum or CRC, 2=CRC only, and 3=none.
X	 */
X	switch(type) {
X		case XMODEM:
X			mvwaddstr(win, 2, 24, "xmodem");
X			is_batch = 0;
X			default_err = 1;
X			max_block = 128;
X			performance = 1.36;
X			break;
X		case XMODEM_1k:
X			mvwaddstr(win, 2, 24, "xmodem-1k");
X			is_batch = 0;
X			default_err = 1;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case MODEM7:
X			mvwaddstr(win, 2, 24, "modem7");
X			is_batch = 1;
X			default_err = 0;
X			max_block = 128;
X			performance = 1.36;
X			break;
X		case YMODEM:
X			mvwaddstr(win, 2, 24, "ymodem");
X			is_batch = 1;
X			default_err = 2;
X			max_block = 1024;
X			performance = 1.09;
X			break;
X		case YMODEM_G:
X			mvwaddstr(win, 2, 24, "ymodem-g");
X			is_batch = 1;
X			default_err = 3;
X			max_block = 1024;
X			performance = 1.02;
X			break;
X	}
X
X	tot_err = 0;
X	file_count = 0;
X	mvwaddstr(win, 11, 24, "0  ");
X
X					/* each one in the list */
X	file = strtok(list, " 	");
X	do {
X					/* is it a batch type ? */
X		file_count++;
X		if (file_count > 1 && !is_batch)
X			break;
X					/* display the name */
X		clear_line(win, 3, 24, 1);
X		if ((name = strrchr(file, '/')))
X			name++;
X		else
X			name = file;
X		waddstr(win, name);
X		wrefresh(win);
X					/* get the file size */	
X		if (stat(file, &sbuf) < 0) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "CAN'T FIND FILE");
X			wrefresh(win);
X			sleep(3);
X			continue;
X		}
X
X		size = sbuf.st_size;
X		mvwprintw(win, 4, 24, "%-10d", size);
X		clear_line(win, 5, 24, 1);
X
X		if (access(file, 4)) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "PERMISSION DENIED");
X			wrefresh(win);
X			sleep(3);
X			continue;
X		}
X		if (!(fp = fopen(file, "r"))) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
X			wrefresh(win);
X			sleep(3);
X			continue;
X		}
X					/* get the xmit size */
X		block_size = max_block;
X		big_blocks = 0;
X		small_blocks = 0;
X		if (block_size == 128) {
X			small_blocks = size / 128;
X			if (size % 128)
X				small_blocks++;
X		}
X		else {
X			big_blocks = size / 1024;
X			small_blocks = (size % 1024) / 128;
X			if (size % 128)
X				small_blocks++;
X
X			if (small_blocks == 8 && !big_blocks) {
X				big_blocks++;
X				small_blocks = 0;
X			}
X					/* if tiny file */
X			if (big_blocks == 0)
X				block_size = 128;
X		}
X
X		xmit_size = (big_blocks * 1024) + (small_blocks * 128);
X					/* add block 0 to the size */
X		if (type == YMODEM || type == YMODEM_G)
X			xmit_size += 128;
X
X		secs = (xmit_size * 10.0 / dir->baud[dir->d_cur]) * performance;
X		hours = secs / 3600;
X		mins = (secs % 3600) / 60;
X		secs = (secs % 3600) % 60;
X
X		mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
X
X					/* some starting numbers */
X		mvwaddstr(win, 7, 24, "     ");
X		mvwaddstr(win, 8, 24, "0%  ");
X		mvwaddstr(win, 9, 24, "0          ");
X		mvwaddstr(win, 10, 24, "0 ");
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "NONE");
X		wrefresh(win);
X					/* send the batch stuff */
X		switch (type) {
X			case MODEM7:
X				if (code = rcv_first(win, default_err)) {
X					fclose(fp);
X					return(code +1);
X				}
X
X				if (send_modem7(win, name)) {
X					fclose(fp);
X					return(1);
X				}
X				break;
X			case YMODEM:
X			case YMODEM_G:
X				if (code = rcv_first(win, default_err)) {
X					fclose(fp);
X					return(code +1);
X				}
X
X				if (code = send_ymodem(win, name, size)) {
X					fclose(fp);
X					/*
X					 * CANCEL now means that the other
X					 * end can't open that file.
X					 */
X					if (code == CANCEL)
X						break;
X					return(code +1);
X				}
X				xmit_size -= 128;
X				break;
X			default:
X				code = 0;
X				break;
X		}
X					/* remote can't receive that file ? */
X		if (code == CANCEL)
X			break;
X					/* wait for first character */
X		if (code = rcv_first(win, default_err)) {
X			fclose(fp);
X			return(code +1);
X		}
X					/* here we go... */
X		sent = 0;
X		block = 1;
X		blk = 1;
X		while (num = fread((char *) &buf[3], sizeof(buf[0]), block_size, fp)) {
X
X					/* fill short block */
X			if (num < block_size) {
X				for (i=num; i<block_size; i++)
X					buf[i+3] = CTRLZ;
X			}
X
X					/* show current stats */
X			mvwprintw(win, 7, 24, "%-5d", block);
X			if (fast) {
X				percent = sent * 100.0 / xmit_size;
X				mvwprintw(win, 8, 24, "%0.1f%%", percent);
X				mvwprintw(win, 9, 24, "%-10d", sent);
X			}
X			wrefresh(win);
X
X					/* build the header */
X			if (block_size == 128)
X				buf[0] = SOH;
X			else
X				buf[0] = STX;
X
X			buf[1] = blk;
X			buf[2] = ~blk;
X
X					/* build the error detection stuff */
X			switch (err_method) {
X				case 0:		/* checksum */
X					buf[block_size+3] = calc_sum(&buf[3], block_size);
X					packet = block_size +4;
X					break;
X				case 1:		/* CRC */
X					crc = calc_crc(&buf[3], block_size);
X					buf[block_size+3] = crc >> 8;
X					buf[block_size+4] = crc;
X					packet = block_size +5;
X					break;
X				case 2:		/* none */
X					buf[block_size+3] = 0;
X					buf[block_size+4] = 0;
X					packet = block_size +5;
X					break;
X			}
X
X					/* send the block */
X			if (code = send_block(win, buf, packet)) {
X				fclose(fp);
X				return(code +1);
X			}
X			block++;
X			blk++;
X			sent += block_size;
X
X					/* change block size ? */
X			if (xmit_size - sent < 1024)
X				block_size = 128;
X		}
X		mvwaddstr(win, 8, 24, "100%  ");
X		mvwprintw(win, 9, 24, "%-10d", sent);
X					/* at the end of the file */
X		err_count = 0;
X		got_it = 0;
X		while (err_count < MAX_ERRORS) {
X			putc_line(EOT);
X			if (getc_line(10) == ACK) {
X				got_it++;
X				break;
X			}
X			err_count++;
X		}
X		clear_line(win, 12, 24, 1);
X		if (!got_it) {
X			/*
X			 * So what???  We don't do anything if there is
X			 * no acknowledge from the host!!
X			 */
X			waddstr(win, "NO ACKNOWLEDGE");
X		}
X		else
X			waddstr(win, "TRANSFER COMPLETE");
X		if (!is_batch)
X			beep();
X		wrefresh(win);
X		sleep(2);
X					/* prepare to start again */
X		fclose(fp);
X	} while (file = strtok((char *) NULL, " 	"));
X
X	/*
X	 * The end of batch markers... For modem7 it's an ACK and EOT, for
X	 * ymodem, it's an empty block 0.
X	 */
X	switch (type) {
X		case MODEM7:
X			if (code = rcv_first(win, default_err))
X				return(code +1);
X			putc_line(ACK);
X			putc_line(EOT);
X			beep();
X			wrefresh(win);
X			break;
X		case YMODEM:
X		case YMODEM_G:
X			if (code = rcv_first(win, default_err))
X				return(code +1);
X
X			if (code = send_ymodem(win, NULL, 0))
X				return(code +1);
X			beep();
X			wrefresh(win);
X			break;
X		default:
X			break;
X	}
X	return(0);
X}
X
X/*
X * Wait for the first character to start the transmission.  This first
X * character also sets the crc/checksum method.  Returns the standard
X * error codes, or 0 on success.  The variable err_method is global.
X */
X
Xint
Xrcv_first(win, default_err)
XWINDOW *win;
Xint default_err;
X{
X	int err_count;
X	unsigned int sleep();
X
X	err_count = 0;
X	while (err_count < MAX_ERRORS) {
X
X					/* scan the keyboard for abort */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X
X					/* scan the tty line */
X		switch(getc_line(10)) {
X			case NAK:	/* checksum marker */
X				if (default_err < 2) {
X					mvwaddstr(win, 5, 24, "CHECKSUM");
X					err_method = 0;
X					return(0);
X				}
X				err_count++;
X				break;
X			case 'C':	/* CRC marker */
X				if (default_err == 1 || default_err == 2) {
X					mvwaddstr(win, 5, 24, "CRC");
X					err_method = 1;
X					return(0);
X				}
X				err_count++;
X				break;
X			case 'G':	/* ymodem-g marker */
X				if (default_err == 3) {
X					mvwaddstr(win, 5, 24, "NONE");
X					err_method = 2;
X					return(0);
X				}
X				err_count++;
X				break;
X			case CAN:	/* two CAN's and you're out! */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			default:
X				err_count++;
X				break;
X		}
X		clear_line(win, 12, 24, 1);
X		waddstr(win, "BAD HEADER");
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X		wrefresh(win);
X	}
X					/* failed to get it right ? */
X	beep();
X	clear_line(win, 12, 24, 1);
X	wattrstr(win, A_BOLD, "TIMED OUT");
X	wrefresh(win);
X	return(ERROR);
X}
X
X/*
X * Send a block of data, scan the keyboard for a user abort, and check
X * the return codes from the host.  Returns standard error codes or 0
X * on success.
X */
X
Xint
Xsend_block(win, blk, packet)
XWINDOW *win;
Xunsigned char *blk;
Xunsigned int packet;
X{
X	int err_count;
X
X	err_count = 0;
X	while (err_count < MAX_ERRORS) {
X					/* write the block */
X		write(status->fd, (char *) blk, packet);
X					/* scan the keyboard */
X		if (wgetch(win) == 27) {
X			beep();
X			clear_line(win, 12, 24, 1);
X			waddstr(win, "ABORTED");
X			wrefresh(win);
X			sleep(3);
X			return(ABORT);
X		}
X					/* ymodem-g doesn't need ACKs */
X		if (err_method == 2)
X			return(0);
X					/* wait for acknowledge */
X		switch(getc_line(10)) {
X			case ACK:	/* Hooray!! we got it */
X				return(0);
X			case NAK:	/* show our disappointment... */
X				clear_line(win, 12, 24, 1);
X				if (err_method)
X					waddstr(win, "CRC FAILED");
X				else
X					waddstr(win, "CHECKSUM FAILED");
X				err_count++;
X				tot_err++;
X				break;
X			case CAN:	/* two CAN's and you're out! */
X				if (getc_line(2) == CAN) {
X					beep();
X					clear_line(win, 12, 24, 1);
X					wattrstr(win, A_BOLD, "REMOTE ABORTED");
X					wrefresh(win);
X					return(CANCEL);
X				}
X				/* fall thru... */
X			default:
X				clear_line(win, 12, 24, 1);
X				waddstr(win, "RESENDING");
X				err_count++;
X				tot_err++;
X				break;
X		}
X		mvwprintw(win, 10, 24, "%-2d", err_count);
X		mvwprintw(win, 11, 24, "%-3d", tot_err);
X		wrefresh(win);
X	}
X					/* failed to get it right */
X	beep();
X	clear_line(win, 12, 24, 1);
X	wattrstr(win, A_BOLD, "TOO MANY ERRORS");
X	wrefresh(win);
X	return(ERROR);
X}
SHAR_EOF
if test 10461 -ne "`wc -c < 'x_send.c'`"
then
	echo shar: "error transmitting 'x_send.c'" '(should have been 10461 characters)'
fi
fi
echo shar: "extracting 'x_win.c'" '(2758 characters)'
if test -f 'x_win.c'
then
	echo shar: "will not over-write existing file 'x_win.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_win.c'
X/*
X * Display the file transfer window, and invoke the transfer protocol.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "status.h"
X#include "xmodem.h"
X
Xvoid
Xxfer_win(list, up, type)
Xchar *list;
Xint up, type;
X{
X	WINDOW *xf_win, *newwin();
X	int ret_code, fast, my_speed;
X	void xmodem_mode(), input_off(), line_set(), error_win();
X	struct termio tbuf;
X
X	if (status->fd == -1) {
X		error_win(0, "Not currently connected to any host", NULL);
X		return;
X	}
X
X	xf_win = newwin(15, 44, 2, 30);
X	/*
X	 * This window should be in the non-blocking mode, so we can
X	 * scan the keyboard for input while transferring a file.
X	 */
X	nodelay(xf_win, 1);
X					/* basic window stuff */
X	mvwaddstr(xf_win, 2, 14, "Protocol:");
X	mvwaddstr(xf_win, 3, 13, "File name:");
X	mvwaddstr(xf_win, 4, 13, "File size:");
X	mvwaddstr(xf_win, 5, 4, "Error check method:");
X	mvwaddstr(xf_win, 6, 5, "Est transfer time:");
X	mvwaddstr(xf_win, 7, 11, "Block count:");
X	mvwaddstr(xf_win, 8, 6, "Percent complete:");
X	mvwaddstr(xf_win, 9, 5, "Bytes transferred:");
X	mvwaddstr(xf_win, 10, 5, "Errors this block:");
X	mvwaddstr(xf_win, 11, 5, "Total error count:");
X	mvwaddstr(xf_win, 12, 10, "Last message: NONE");
X	box(xf_win, '|', '-');
X
X	if (up)
X		mvwattrstr(xf_win, 0, 17, A_BOLD, " Uploading ");
X	else
X		mvwattrstr(xf_win, 0, 16, A_BOLD, " Downloading ");
X	mvwaddstr(xf_win, 14, 12, " Press ESC to abort ");
X	wrefresh(xf_win);
X					/* fix up the terminal mode */
X	input_off();
X	xmodem_mode(status->fd);
X
X	/*
X	 * Is your terminal slower than the xfer baud rate?  For example:
X	 * I'm at home with my PC and 1200 baud modem, I call my system
X	 * at work so I can use their 2400 baud modems to call some other
X	 * system.  In this case, I don't wanna spend too much time updating
X	 * my screen at 1200 baud, when I'm transferring the file at 2400 baud.
X	 */
X	my_speed = 0;
X	fast = 0;
X
X	ioctl(0, TCGETA, &tbuf);
X					/* only reasonable values are here */
X	switch(tbuf.c_cflag & CBAUD) {
X		case B300:
X			my_speed = 300;
X			break;
X		case B1200:
X			my_speed = 1200;
X			break;
X		case B2400:
X			my_speed = 2400;
X			break;
X		case B4800:
X			my_speed = 4800;
X			break;
X		case B9600:
X			my_speed = 9600;
X			break;
X		case B19200:
X			my_speed = 19200;
X			break;
X	}
X	if (my_speed >= dir->baud[dir->d_cur])
X		fast++;
X
X	if (up)
X		ret_code = send_xmodem(xf_win, list, type, fast);
X	else
X		ret_code = rcv_xmodem(xf_win, list, type, fast);
X
X	nodelay(xf_win, 0);
X					/* prompt for a key on errors */
X	if (ret_code) {
X		beep();
X		clear_line(xf_win, 13, 9, 1);
X		wattrstr(xf_win, A_BOLD, "Press any key to continue");
X		wrefresh(xf_win);
X		wgetch(xf_win);
X	}
X	werase(xf_win);
X	wrefresh(xf_win);
X	delwin(xf_win);
X					/* undo what xmodem_mode() did */
X	line_set();
X	return;
X}
SHAR_EOF
if test 2758 -ne "`wc -c < 'x_win.c'`"
then
	echo shar: "error transmitting 'x_win.c'" '(should have been 2758 characters)'
fi
fi
echo shar: "extracting 'xmodem.c'" '(4611 characters)'
if test -f 'xmodem.c'
then
	echo shar: "will not over-write existing file 'xmodem.c'"
else
sed 's/^X//' << \SHAR_EOF > 'xmodem.c'
X/*
X * Miscellaneous routines to support the xmodem file transfer protocols.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <termio.h>
X#include <setjmp.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "param.h"
X#include "status.h"
X#include "xmodem.h"
X
X/*
X * Calculate the CRC for the given buffer
X */
X
Xint
Xcalc_crc(buf, len)
Xunsigned char *buf;
Xint len;
X{
X	int crc, i;
X	
X	crc = 0;
X	while (--len >= 0) {
X		/*
X		 * Some fancy foot work here... The algorithm looks good
X		 * in assembly, but in C it looks horrible!
X		 */
X		crc = crc ^ (int) *buf++ << 8;
X		for (i=0; i<8; i++) {
X			if (crc & 0x8000)
X				crc = crc << 1 ^ 0x1021;
X			else
X				crc = crc << 1;
X		}
X	}
X	return(crc & 0xffff);
X}
X
X/*
X * Calculate the checksum for the given buffer.
X */
X
Xunsigned char
Xcalc_sum(buf, len)
Xunsigned char *buf;
Xint len;
X{
X	unsigned char sum;
X
X	sum = 0;
X	while (--len >= 0)
X		sum += *buf++;
X
X	return(sum);
X}
X
X/*
X * Get a character from the line with a specified time-out period in
X * seconds.  If the function times-out, it returns a -1.
X */
X
Xjmp_buf gl_jmp;
X
Xint
Xgetc_line(sec)
Xunsigned int sec;
X{
X	int force_gl();
X	unsigned char c;
X	unsigned int alarm();
X
X	signal(SIGALRM, force_gl);
X	if (setjmp(gl_jmp))
X		return(-1);
X
X	alarm(sec);
X	if (read(status->fd, (char *) &c, 1) <= 0) {
X		alarm(0);
X		return(-1);
X	}
X	alarm(0);
X	return(c);
X}
Xint
Xforce_gl(dummy)
Xint dummy;
X{
X	void longjmp();
X
X	longjmp(gl_jmp, 1);
X}
X
X/*
X * Same as above, but reads a bunch of characters.  The return code is
X * now just a success/fail indicator.
X */
X
Xjmp_buf rl_jmp;
X
Xint
Xfread_line(buf, len, sec)
Xunsigned char *buf;
Xunsigned int len, sec;
X{
X	int i, force_rl();
X	unsigned int alarm();
X
X	signal(SIGALRM, force_rl);
X	if (setjmp(rl_jmp))
X		return(-1);
X
X	alarm(sec);
X	/*
X	 * Later, this will have some fine tuning to use more than
X	 * single character I/O.
X	 */
X	for (i=0; i<len; i++) {
X		if (read(status->fd, (char *) buf++, 1) <= 0) {
X			alarm(0);
X			return(-1);
X		}
X	}
X	alarm(0);
X	return(0);
X}
Xint
Xforce_rl(dummy)
Xint dummy;
X{
X	void longjmp();
X
X	longjmp(rl_jmp, 1);
X}
X
X/*
X * Put a character on the tty line.  This serves no useful purpose other
X * than making the code look pretty.
X */
X
Xint
Xputc_line(c)
Xunsigned char c;
X{
X	return(write(status->fd, (char *) &c, 1));
X}
X
X/*
X * Put the tty driver in the mode suitable for xmodem transfers.
X */
X
Xvoid
Xxmodem_mode(fd)
Xint fd;
X{
X	struct termio tbuf;
X
X	ioctl(fd, TCGETA, &tbuf);
X	/*
X	 * Turn off the XON/XOFF flow control, turn off echoing, and
X	 * switch to 8 bit no parity.  Later, the VTIME and VMIN variables
X	 * will be fine tuned, to allow for more efficient I/O.
X	 */
X	tbuf.c_cc[4] = 1;		/* VMIN */
X	tbuf.c_cc[5] = 0;		/* VTIME */
X	tbuf.c_iflag = 0;		/* no flow control or mapping */
X	tbuf.c_oflag = 0;		/* no char mapping or delays */
X	tbuf.c_lflag = 0;		/* no echo or signals */
X	tbuf.c_cflag &= ~PARENB;	/* no parity */
X	tbuf.c_cflag &= ~CSIZE;
X	tbuf.c_cflag |= CS8;		/* 8 bit */
X
X	ioctl(fd, TCSETA, &tbuf);
X	ioctl(fd, TCFLSH, 2);
X	return;
X}
X
X/*
X * Cancel the file transfer.  Send several ^X's to the remote, followed
X * by an equal number of backspace (in case they have already aborted and
X * we're really at the command line).
X */
X
Xvoid
Xcancel_xfer()
X{
X	extern char file_name[15];
X
X	if (!strcmp(param->abort, "DELETE"))
X		unlink(file_name);
X
X	putc_line(CAN);
X	putc_line(CAN);
X	putc_line(CAN);
X	putc_line(8);
X	putc_line(8);
X	putc_line(8);
X	return;
X}
X
X/*
X * Shorten a file to a predetermined length.  Used to remove the ^Z
X * padding from the end of files.  (Heaven help us, if one day a binary
X * file actually has ^Z's as part of the end of the file).
X */
X
Xint
Xfix_length(file, len)
Xchar *file;
Xint len;
X{
X	FILE *fp, *tempfp;
X	int num;
X	char *tempfile, *mktemp();
X	unsigned char buf[BUFSIZ];
X	struct stat stbuf;
X
X	if (stat(file, &stbuf) < 0)
X		return(1);
X					/* see if we have any work to do */
X	if (len >= stbuf.st_size)
X		return(0);
X
X	if (!(fp = fopen(file, "r")))
X		return(1);
X
X	/*
X	 * The temporary file should be in the same directory as the
X	 * file being received because otherwise we'd have no way of
X	 * guaranteeing they would be in the same file system.  (Hard
X	 * links across different file systems aren't allowed).
X	 */
X	tempfile = mktemp("trunXXXXXX");
X	if (!(tempfp = fopen(tempfile, "w"))) {
X		fclose(fp);
X		return(1);
X	}
X
X	while(len) {
X		num = (len > BUFSIZ) ? BUFSIZ : len;
X		fread((char *) buf, sizeof(buf[0]), num, fp);
X		fwrite((char *) buf, sizeof(buf[0]), num, tempfp);
X		len -= num;
X	}
X
X	fclose(fp);
X	fclose(tempfp);
X
X	if (unlink(file) < 0)
X		return(1);
X
X	if (link(tempfile, file) < 0)
X		return(1);
X
X	if (unlink(tempfile) < 0)
X		return(1);
X
X	return(0);
X}
SHAR_EOF
if test 4611 -ne "`wc -c < 'xmodem.c'`"
then
	echo shar: "error transmitting 'xmodem.c'" '(should have been 4611 characters)'
fi
fi
exit 0
#	End of shell archive


-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.