[comp.sources.unix] v20i073: Pcomm telecommunication package, Part07/08

rsalz@uunet.uu.net (Rich Salz) (10/26/89)

Submitted-by: Emmet P. Gray <uiucuxc!fthood!egray>
Posting-number: Volume 20, Issue 73
Archive-name: pcomm1.2/part07

#! /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:
#	terminal.c
#	tty_att.c
#	tty_ucb.c
#	vcs.c
#	vcs.h
#	waitfor.c
#	x_ascii.c
#	x_batch.c
#	x_extrnl.c
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'terminal.c'" '(9863 characters)'
if test -f 'terminal.c'
then
	echo shar: "will not over-write existing file 'terminal.c'"
else
sed 's/^X//' << \SHAR_EOF > 'terminal.c'
X/*
X * Start the terminal dialogue, fork the input routine, watch for the
X * hot key so we can execute an option.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#include "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X#include "xmodem.h"
X
X#ifdef UNIXPC
X#include <sys/phone.h>
X#include <fcntl.h>
X#endif /* UNIXPC */
X
Xstatic int pid = -1;
X
Xterminal(extra_dir, input_status)
Xchar *extra_dir;
Xint input_status;
X{
X	extern int fd;
X	int i, j, k, cr_lf, script;
X	char c, lf=10, *str_rep(), *keymac, *memset();
X	void help_screen(), line_set(), n_shell(), load_vs(), send_str();
X	void release_port(), do_input(), list_dir(), pexit(), zap_vs();
X	void st_line(), chg_dir(), screen_dump(), input_off(), suspend();
X	void info(), term_mode(), macro(), do_script();
X
X					/* if starting out in command mode */
X	if (!input_status) {
X		erase();
X		refresh();
X		st_line("");
X	}
X					/* put stdin/stdout in terminal mode */
X	resetterm();
X	term_mode();
X	cr_lf = !strcmp(param->cr_out, "CR/LF");
X
X	if (input_status) {
X		do_script(extra_dir);
X		do_input();
X	}
X
X	while (1) {
X		read(0, &c, 1);
X		c &= 0x7f;
X					/* is it the hot key? */
X		if (c == param->hot) {
X					/* suspend input */
X			input_status = 0;
X			suspend(TRUE);
X			script = 0;
X
X			/*
X			 * Put the terminal in the curses mode, load the
X			 * virtual screen and add the status line at the bottom.
X			 */
X			fixterm();
X			load_vs();
X			st_line("");
X#ifndef OLDCURSES
X			keypad(stdscr, TRUE);
X#endif /* OLDCURSES */
X			i = wgetch(stdscr);
X					/* map an additional hot key to -1 */
X			if (i == param->hot)
X				i = -1;
X
X			keymac = "";
X					/* look for options */
X			k = -1;
X			switch (i) {
X				case -1:	/* 2 "hots" means send 1 */
X					k = param->hot;
X					break;
X				case '0':	/* help screen */
X					help_screen(param->ascii_hot);
X					break;
X				case 'd':
X				case 'D':	/* dialing directory */
X					if (dial_menu())
X						input_status = dial_win();
X					script = input_status;
X					break;
X				case 'r':
X				case 'R':	/* redial */
X					if (redial())
X						input_status = dial_win();
X					script = input_status;
X					break;
X				case 'm':
X				case 'M':	/* keyboard macros */
X					macro();
X					break;
X				case 'p':
X				case 'P':	/* line settings */
X					if (ls_menu())
X						line_set();
X					break;
X				case 'x':
X				case 'X':	/* exit */
X					pexit();
X					break;
X				case '4':	/* Unix gateway */
X					n_shell();
X					break;
X				case 'i':
X				case 'I':	/* program info screen */
X					info(MANUAL_CLEAR);
X					break;
X				case 's':	/* setup menu */
X				case 'S':
X					input_status = setup_menu();
X					break;
X				case 'c':	/* clear the screen */
X				case 'C':
X					zap_vs();
X					erase();
X#ifdef SHAREDMEM
X					if (pid == -1) {
X						for (j=0; j<LINES; j++)
X							memset(status->vs[j], ' ', COLS);
X					}
X#endif /* SHAREDMEM */
X					break;
X				case 'b':
X				case 'B':	/* change directory */
X					chg_dir();
X					break;
X				case 'e':
X				case 'E':	/* toggle duplex */
X					if (dir->duplex[dir->d_cur] == 'F')
X						dir->duplex[dir->d_cur] = 'H';
X					else
X						dir->duplex[dir->d_cur] = 'F';
X
X						/* show changes */
X					st_line("");
X					k = wait_key(stdscr, 2);
X					break;
X				case 'h':
X				case 'H':	/* hang up phone */
X					release_port(VERBOSE);
X					input_off();
X					break;
X				case 'l':
X				case 'L':	/* toggle printer */
X					status->print = status->print ? 0 : 1;
X#ifndef SHAREDMEM
X					if (pid != -1)
X						kill(pid, SIGUSR2);
X#endif /* SHAREDMEM */
X						/* show changes */
X					st_line("");
X					k = wait_key(stdscr, 2);
X					break;
X				case '3':	/* toggle CR - CR/LF */
X					if (!strcmp(param->cr_in, "CR")) {
X						param->cr_in = str_rep(param->cr_in, "CR/LF");
X						status->add_lf = 1;
X					}
X					else {
X						param->cr_in = str_rep(param->cr_in, "CR");
X						status->add_lf = 0;
X					}
X#ifndef SHAREDMEM
X					input_off();
X					input_status++;
X#endif /* SHAREDMEM */
X						/* show changes */
X					st_line("");
X					k = wait_key(stdscr, 2);
X					break;
X				case '7':	/* break key */
X					if (fd != -1)
X						tty_break(fd);
X
X					st_line("   break");
X					break;
X#ifndef OLDCURSES
X				case KEY_UP:
X#endif /* OLDCURSES */
X				case 'u':
X				case 'U':	/* send files */
X					input_status = xfer_menu(UP_LOAD);
X					break;
X#ifndef OLDCURSES
X				case KEY_DOWN:
X				case '\n':
X#endif /* OLDCURSES */
X				case 'n':
X				case 'N':	/* receive files */
X					input_status = xfer_menu(DOWN_LOAD);
X					break;
X				case 't':
X				case 'T':
X					input_status = pass_thru();
X					break;
X				case 'f':
X				case 'F':	/* list directory */
X					list_dir();
X					break;
X				case 'g':	/* screen dump */
X				case 'G':
X					screen_dump();
X					st_line(" screen dump");
X					k = wait_key(stdscr, 2);
X					break;
X				case '1':	/* data logging */
X					input_status = data_logging();
X					break;
X				case '2':	/* toggle log */
X					if (!strcmp(status->log_path, "NOT_DEFINED")) {
X						beep();
X						st_line(" no log file");
X						k = wait_key(stdscr, 2);
X						break;
X					}
X					status->log = status->log ? 0 : 1;
X#ifndef SHAREDMEM
X					if (pid != -1)
X						kill(pid, SIGUSR1);
X#endif /* SHAREDMEM */
X						/* show changes */
X					st_line("");
X					k = wait_key(stdscr, 2);
X					break;
X				/*
X				 * The following are the keyboard macros
X				 * corresponding to the shifted number keys.
X				 * (Too many keys... [control] [A] [shift] [1]
X				 * is hardly a shortcut!)
X				 */
X				case '!':
X					keymac = param->mac_1;
X					break;
X				case '@':
X					keymac = param->mac_2;
X					break;
X				case '#':
X					keymac = param->mac_3;
X					break;
X				case '$':
X					keymac = param->mac_4;
X					break;
X				case '%':
X					keymac = param->mac_5;
X					break;
X				case '^':
X					keymac = param->mac_6;
X					break;
X				case '&':
X					keymac = param->mac_7;
X					break;
X				case '*':
X					keymac = param->mac_8;
X					break;
X				case '(':
X					keymac = param->mac_9;
X					break;
X				case ')':
X					keymac = param->mac_0;
X					break;
X				default:
X					fputc(BEL, stderr);
X					break;
X			}
X
X			/*
X			 * Repaint the stdscr (if we are already talking),
X			 * get the stdin/stdout out of the curses mode and
X			 * into the terminal mode.
X			 */
X			if (fd != -1) {
X				touchwin(stdscr);
X				refresh();
X			}
X			resetterm();
X			term_mode();
X
X			/*
X			 * Some of the output processing options have to be
X			 * faked...  Unfortunately, adding a LF to CR on
X			 * output is one of them.
X			 */
X			cr_lf = !strcmp(param->cr_out, "CR/LF");
X
X					/* run the auto-login script */
X			if (script)
X				do_script(extra_dir);
X
X					/* re-start input routine */
X			if (input_status)
X				do_input();
X			else
X				suspend(FALSE);
X
X					/* send the macro */
X			if (*keymac != '\0')
X				send_str(keymac, FAST);
X			/*
X			 * If you pressed a key during one of the sleeping
X			 * periods (typically the delay to see the status
X			 * line change), let the keyboard value fall thru
X			 * to the write() below.
X			 */
X			if (k == -1)
X				continue;
X			c = k;
X		}
X					/* ignore errors if fd == -1 */
X		write(fd, &c, 1);
X					/* map cr to cr_lf? */
X		if (c == '\r' && cr_lf)
X			write(fd, &lf, 1);
X	}
X}
X
X/*
X * Fire up the input routine...
X */
X
Xvoid
Xdo_input()
X{
X	extern int fd;
X	void error_win();
X	char first[(sizeof(int)*8)+1];
X#ifdef SHAREDMEM
X	extern int shm_id;
X#else /* SHAREDMEM */
X	char add_lf[2], log[2], print[2], dup_fd[3];
X#endif /* SHAREDMEM */
X					/* if no TTY, or already on */
X	if (pid != -1 || fd == -1)
X		return;
X
X	status->fd = fd;
X	status->add_lf = !strcmp(param->cr_in, "CR/LF");
X
X#ifdef SHAREDMEM
X	sprintf(first, "%d", shm_id);
X#else /* SHAREDMEM */
X	sprintf(first, "%d", status->fd);
X	sprintf(dup_fd, "%d", status->dup_fd);
X	sprintf(add_lf, "%d", status->add_lf);
X	sprintf(log, "%d", status->log);
X	sprintf(print, "%d", status->print);
X#endif /* SHAREDMEM */
X
X					/* fork the input routine */
X	if (!(pid = fork())) {
X#ifdef BSD
X		setpgrp(0, getpid());
X#else /* BSD */
X		setpgrp();
X#endif /* BSD */
X
X#ifdef SETUGID
X		setuid(getuid());
X		setgid(getgid());
X#endif /* SETUGID */
X
X#ifdef SHAREDMEM
X		execlp("pcomm_input", "pcomm_input", first, (char *) 0);
X#else /* SHAREDMEM */
X		execlp("pcomm_input", "pcomm_input", first, dup_fd, add_lf,
X		 log, print, status->log_path, status->vs_path, (char *) 0);
X#endif /* SHAREDMEM */
X		error_win(1, "Cannot find (or execute) the 'pcomm_input' program", "");
X	}
X
X	return;
X}
X
X/*
X * shut it down...
X */
X
Xvoid
Xinput_off()
X{
X	if (pid != -1) {
X		kill(pid, SIGTERM);
X		pid = -1;
X	}
X	return;
X}
X
X/*
X * Hang up the phone but remain in the Pcomm command state.  Uses the
X * hang_up string only, does *not* drop the DTR!
X */
X
Xvoid
Xhang_up(verbose)
Xint verbose;
X{
X	extern int fd;
X	void send_str(), st_line(), line_set();
X	char buf[80], *strcpy(), *ttyname();
X					/* sanity checking */
X	if (modem == NULL)
X		return;
X					/* anything to hang up? */
X	if (modem->m_cur == -1 || fd == -1)
X		return;
X
X	if (verbose)
X		st_line("disconnecting");
X					/* special case for OBM */
X#ifdef UNIXPC
X	if (!strcmp(modem->mname[modem->m_cur], "OBM")) {
X		ioctl(fd, PIOCDISC);
X		/*
X		 * The PIOCDISC ioctl screws up the file descriptor!!!
X		 * No other phone(7) ioctl can fix it.  Whatever it does,
X		 * it seems to escape detection with PIOCGETA and TCGETA.
X		 * The best I can do is close the port and start over.
X		 */
X		strcpy(buf, ttyname(fd));
X		close(fd);
X		fd = open(buf, O_RDWR|O_NDELAY);
X		line_set();
X		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY);
X	}
X	else
X#endif /* UNIXPC */
X		send_str(modem->hang_up[modem->m_cur], SLOW);
X
X	if (verbose)
X		st_line("");
X	return;
X}
X
X/*
X * Suspend or un-suspend the input routine.  The argument is used in
X * non-shared memory configurations to give the vs_path file a fighting
X * chance of being written to disk before load_vs() reads it.
X */
X
X/* ARGSUSED */
Xvoid
Xsuspend(on)
Xint on;
X{
X	unsigned int sleep();
X
X	if (pid == -1)
X		return;
X	kill(pid, SIGINT);
X
X#ifndef SHAREDMEM
X	if (on)
X		sleep(1);
X#endif /* SHAREDMEM */
X
X	return;
X}
SHAR_EOF
if test 9863 -ne "`wc -c < 'terminal.c'`"
then
	echo shar: "error transmitting 'terminal.c'" '(should have been 9863 characters)'
fi
fi
echo shar: "extracting 'tty_att.c'" '(4795 characters)'
if test -f 'tty_att.c'
then
	echo shar: "will not over-write existing file 'tty_att.c'"
else
sed 's/^X//' << \SHAR_EOF > 'tty_att.c'
X/*
X * System V specific routines for manipulating the TTY
X */
X
X#include <stdio.h>
X#include <termio.h>
X#include <fcntl.h>
X#include "dial_dir.h"
X#include "param.h"
X
X/*
X * Change the communication line settings to the new values.
X */
X
Xvoid
Xline_set()
X{
X	extern int fd;
X	struct termio tbuf;
X
X	/*
X	 * The manual dial entry also serves to store the previous
X	 * line settings.  How else would the manual dial entry
X	 * know what line setting to use?
X	 */
X	if (dir->d_cur != 0) {
X		dir->baud[0] = dir->baud[dir->d_cur];
X		dir->parity[0] = dir->parity[dir->d_cur];
X		dir->dbits[0] = dir->dbits[dir->d_cur];
X		dir->sbits[0] = dir->sbits[dir->d_cur];
X	}
X					/* nothing to do! */
X	if (fd == -1)
X		return;
X					/* get the current settings */
X	ioctl(fd, TCGETA, &tbuf);
X					/* set some beginning values */
X	tbuf.c_cc[4] = 1;		/* VMIN */
X	tbuf.c_cc[5] = 0;		/* VTIME */
X	tbuf.c_oflag = 0;
X	tbuf.c_iflag = 0;
X	tbuf.c_cflag = (CREAD|HUPCL|CLOCAL);
X	tbuf.c_lflag = 0;
X
X	if (*param->flow == 'X')
X		tbuf.c_iflag |= (IXON|IXOFF);
X					/* strip high bit? */
X	if (*param->strip == 'Y')
X		tbuf.c_iflag |= ISTRIP;
X					/* the baud rate */
X	switch (dir->baud[dir->d_cur]) {
X		case 300:
X			tbuf.c_cflag |= B300;
X			break;
X		case 1200:
X			tbuf.c_cflag |= B1200;
X			break;
X		case 2400:
X			tbuf.c_cflag |= B2400;
X			break;
X		case 4800:
X			tbuf.c_cflag |= B4800;
X			break;
X		case 9600:
X			tbuf.c_cflag |= B9600;
X			break;
X		case 19200:
X#ifdef B19200
X			tbuf.c_cflag |= B19200;
X#else /* B19200 */
X#ifdef EXTA
X			tbuf.c_cflag |= EXTA;
X#endif /* EXTA */
X#endif /* B19200 */
X			break;
X	}
X					/* the parity */
X	switch (dir->parity[dir->d_cur]) {
X		case 'N':
X			break;
X		case 'O':
X			tbuf.c_cflag |= (PARENB|PARODD);
X			break;
X		case 'E':
X			tbuf.c_cflag |= PARENB;
X			break;
X	}
X					/* the data bits */
X	if (dir->dbits[dir->d_cur] == 8)
X		tbuf.c_cflag |= CS8;
X	else
X		tbuf.c_cflag |= CS7;
X					/* the stop bits */
X	if (dir->sbits[dir->d_cur] == 2)
X		tbuf.c_cflag |= CSTOPB;
X
X					/* now set 'em! */
X	ioctl(fd, TCSETAF, &tbuf);
X	return;
X}
X
X/*
X * Put the stdin/stdout in terminal mode.  We've divided up the
X * responsibility for the line settings options between the serial port
X * and the stdin and stdout.
X */
X
Xvoid
Xterm_mode()
X{
X	struct termio tbuf;
X
X	ioctl(0, TCGETA, &tbuf);
X
X	tbuf.c_cc[4] = 1;		/* VMIN */
X	tbuf.c_cc[5] = 0;		/* VTIME */
X	tbuf.c_iflag = 0;
X	tbuf.c_oflag = 0;
X	tbuf.c_lflag = 0;
X					/* duplex */
X	if (dir->duplex[dir->d_cur] == 'H')
X		tbuf.c_lflag = ECHO;
X
X	ioctl(0, TCSETAF, &tbuf);
X	return;
X}
X
X/*
X * Put the TTY driver in the mode suitable for xmodem transfers.
X */
X
Xvoid
Xxmodem_mode(fds)
Xint fds;
X{
X	struct termio tbuf;
X
X	ioctl(fds, TCGETA, &tbuf);
X	/*
X	 * Turn off the XON/XOFF flow control, turn off echoing, and
X	 * switch to 8 bit no parity.
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|CSIZE);/* no parity */
X	tbuf.c_cflag |= CS8;		/* 8 bit */
X
X	ioctl(fds, TCSETAF, &tbuf);
X	return;
X}
X
X/*
X * Put the TTY line in a mode suitable for the ASCII transfer.  Puts the
X * terminal in the raw, non-blocking mode.
X */
X
Xvoid
Xascii_mode(up)
Xint up;
X{
X	extern int fd;
X	struct termio tbuf;
X
X	ioctl(fd, TCGETA, &tbuf);
X	tbuf.c_oflag = 0;
X					/* flow control & 8th bit stripping */
X	if (up) {
X		tbuf.c_iflag = (ISTRIP|IXON);
X
X					/* if no CR's, use NL delays */
X		if (!strcmp(param->cr_up, "STRIP"))
X			tbuf.c_oflag = (OPOST|ONLRET);
X
X					/* CR delay times */
X		switch (param->cr_delay) {
X			case 0:
X				break;
X			case 100:
X				tbuf.c_oflag |= (OPOST|CR2);
X				break;
X			case 150:
X				tbuf.c_oflag |= (OPOST|CR3);
X				break;
X		}
X	}
X					/* if down loading */
X	else
X		tbuf.c_iflag = (ISTRIP|IXOFF);
X
X	ioctl(fd, TCSETAF, &tbuf);
X	return;
X}
X
X/*
X * Flush the file descriptor
X */
X
Xint
Xtty_flush(fds, mode)
Xint fds, mode;
X{
X	return(ioctl(fds, TCFLSH, mode));
X}
X
X/*
X * Wait for the output to drain
X */
X
Xint
Xtty_drain(fds)
Xint fds;
X{
X	return(ioctl(fds, TCSBRK, 1));
X}
X
X/*
X * Send a modem break
X */
X
Xint
Xtty_break(fds)
Xint fds;
X{
X	return(ioctl(fds, TCSBRK, 0));
X}
X
X/*
X * Fix the file descriptor so that a read is satisfied immediately.  When
X * read() is called it returns the character in the queue, or an error if
X * no key was pressed.
X */
X
Xint
Xtty_noblock(fds, on)
Xint fds, on;
X{
X	int current;
X
X	current = fcntl(fds, F_GETFL, 0);
X	if (on)
X		return(fcntl(fds, F_SETFL, current | O_NDELAY));
X	else
X		return(fcntl(fds, F_SETFL, current & ~O_NDELAY));
X}
X
X/*
X * Get the current baud rate of the terminal
X */
X
Xint
Xmy_speed()
X{
X	static int speed[15] = {0, 50, 75, 110, 134, 150, 200, 300, 600,
X	 1200, 1800, 2400, 4800, 9600, 19200};
X	struct termio tbuf;
X
X	ioctl(0, TCGETA, &tbuf);
X	return(speed[tbuf.c_cflag & CBAUD]);
X}
SHAR_EOF
if test 4795 -ne "`wc -c < 'tty_att.c'`"
then
	echo shar: "error transmitting 'tty_att.c'" '(should have been 4795 characters)'
fi
fi
echo shar: "extracting 'tty_ucb.c'" '(4666 characters)'
if test -f 'tty_ucb.c'
then
	echo shar: "will not over-write existing file 'tty_ucb.c'"
else
sed 's/^X//' << \SHAR_EOF > 'tty_ucb.c'
X/*
X * Berkeley specific routines for manipulating the TTY
X */
X
X#include <stdio.h>
X#include <sgtty.h>
X#include <fcntl.h>
X#include "dial_dir.h"
X#include "param.h"
X
X/*
X * Change the communication line settings to the new values.
X */
X
Xvoid
Xline_set()
X{
X	extern int fd;
X	struct sgttyb tbuf;
X
X	/*
X	 * The manual dial entry also serves to store the previous
X	 * line settings.  How else would the manual dial entry
X	 * know what line setting to use?
X	 */
X	if (dir->d_cur != 0) {
X		dir->baud[0] = dir->baud[dir->d_cur];
X		dir->parity[0] = dir->parity[dir->d_cur];
X		dir->dbits[0] = dir->dbits[dir->d_cur];
X		dir->sbits[0] = dir->sbits[dir->d_cur];
X	}
X					/* nothing to do! */
X	if (fd == -1)
X		return;
X					/* get the current settings */
X	ioctl(fd, TIOCGETP, &tbuf);
X					/* set some beginning values */
X	tbuf.sg_flags = CBREAK;
X
X	if (*param->flow == 'X')
X		tbuf.sg_flags |= TANDEM;
X					/* the baud rate */
X	switch (dir->baud[dir->d_cur]) {
X		case 300:
X			tbuf.sg_ispeed = B300;
X			tbuf.sg_ospeed = B300;
X			break;
X		case 1200:
X			tbuf.sg_ispeed = B1200;
X			tbuf.sg_ospeed = B1200;
X			break;
X		case 2400:
X			tbuf.sg_ispeed = B2400;
X			tbuf.sg_ospeed = B2400;
X			break;
X		case 4800:
X			tbuf.sg_ispeed = B4800;
X			tbuf.sg_ospeed = B4800;
X			break;
X		case 9600:
X			tbuf.sg_ispeed = B9600;
X			tbuf.sg_ospeed = B9600;
X			break;
X		case 19200:
X#ifdef B19200
X			tbuf.sg_ispeed = B19200;
X			tbuf.sg_ospeed = B19200;
X#else /* B19200 */
X#ifdef EXTA
X			tbuf.sg_ispeed = EXTA;
X			tbuf.sg_ospeed = EXTA;
X#endif /* EXTA */
X#endif /* B19200 */
X			break;
X	}
X					/* the parity */
X	switch (dir->parity[dir->d_cur]) {
X		case 'N':
X			tbuf.sg_flags |= ANYP;
X			break;
X		case 'O':
X			tbuf.sg_flags |= ODDP;
X			break;
X		case 'E':
X			tbuf.sg_flags |= EVENP;
X			break;
X	}
X					/* now set 'em! */
X	ioctl(fd, TIOCSETP, &tbuf);
X	return;
X}
X
X/*
X * Put the stdin/stdout in terminal mode.  We've divided up the
X * responsibility for the line settings options between the serial port
X * and the stdin and stdout.
X */
X
Xvoid
Xterm_mode()
X{
X	struct sgttyb tbuf;
X
X	ioctl(0, TIOCGETP, &tbuf);
X	
X	tbuf.sg_flags |= CBREAK;
X	tbuf.sg_flags &= ~(RAW|CRMOD|ECHO);
X
X	if (dir->duplex[dir->d_cur] == 'H')
X		tbuf.sg_flags |= ECHO;
X
X	ioctl(0, TIOCSETP, &tbuf);
X	return;
X}
X
X/*
X * Put the TTY driver in the mode suitable for xmodem transfers.
X */
X
Xvoid
Xxmodem_mode(fds)
Xint fds;
X{
X	struct sgttyb tbuf;
X
X	ioctl(fds, TIOCGETP, &tbuf);
X	/*
X	 * Turn off the XON/XOFF flow control, turn off echoing, and
X	 * switch to 8 bit no parity.
X	 */
X	tbuf.sg_flags |= (RAW|ANYP);
X	tbuf.sg_flags &= ~ECHO;
X	ioctl(fds, TIOCSETP, &tbuf);
X	return;
X}
X
X/*
X * Put the TTY line in a mode suitable for the ASCII transfer.
X */
X
Xvoid
Xascii_mode(up)
Xint up;
X{
X	extern int fd;
X	struct sgttyb tbuf;
X
X	ioctl(fd, TIOCGETP, &tbuf);
X
X	tbuf.sg_flags |= (CBREAK|TANDEM);
X	tbuf.sg_flags &= ~(RAW|CRMOD|ECHO|CRDELAY);
X
X	if (up) {
X					/* CR delay times */
X		switch (param->cr_delay) {
X			case 0:
X				break;
X			case 100:
X				tbuf.sg_flags |= CR1;
X				break;
X			case 150:
X				tbuf.sg_flags |= CR2;
X				break;
X		}
X	}
X
X	ioctl(fd, TIOCSETP, &tbuf);
X	return;
X}
X
X/*
X * Flush the file descriptor.  Very messy... flushing the input causes a
X * wait for the ouput to drain, and there is no output flushing.
X */
X
Xint
Xtty_flush(fds, mode)
Xint fds, mode;
X{
X	int ret_code = 0;
X	struct sgttyb tbuf;
X
X	switch(mode) {
X		case 0:			/* flush input queue */
X			ioctl(fds, TIOCGETP, &tbuf);
X			ioctl(fds, TIOCSETP, &tbuf);
X			break;
X		case 1:			/* flush output queue */
X			/* sorry! */
X			break;
X		case 2:			/* flush both input and output */
X			ioctl(fds, TIOCFLUSH, 0);
X			break;
X		default:
X			ret_code++;
X			break;
X	}
X	return(ret_code);
X}
X
X/*
X * Wait for the output to drain
X */
X
Xint
Xtty_drain(fds)
Xint fds;
X{
X	struct sgttyb tbuf;
X					/* this flushes the input too */
X	ioctl(fds, TIOCGETP, &tbuf);
X	return(ioctl(fds, TIOCSETP, &tbuf));
X}
X
X/*
X * Send a modem break
X */
X
Xint
Xtty_break(fds)
Xint fds;
X{
X	unsigned int sleep();
X
X	ioctl(fds, TIOCSBRK, (struct sgttyb *) 0);
X	sleep(1);
X	return(ioctl(fds, TIOCCBRK, (struct sgttyb *) 0));
X}
X
X/*
X * Fix the file descriptor so that a read is satisfied immediately.  When
X * read() is called it returns the character in the queue, or an error if
X * no key was pressed.
X */
X
Xint
Xtty_noblock(fds, on)
Xint fds, on;
X{
X	int current;
X
X	current = fcntl(fds, F_GETFL, 0);
X	if (on)
X		return(fcntl(fds, F_SETFL, current | FNDELAY));
X	else
X		return(fcntl(fds, F_SETFL, current & ~FNDELAY));
X}
X
X/*
X * Get the current baud rate of the terminal
X */
X
Xint
Xmy_speed()
X{
X	static int speed[15] = {0, 50, 75, 110, 134, 150, 200, 300, 600,
X	 1200, 1800, 2400, 4800, 9600, 19200};
X	struct sgttyb tbuf;
X
X	ioctl(0, TIOCGETP, &tbuf);
X	return(speed[tbuf.sg_ispeed]);
X}
SHAR_EOF
if test 4666 -ne "`wc -c < 'tty_ucb.c'`"
then
	echo shar: "error transmitting 'tty_ucb.c'" '(should have been 4666 characters)'
fi
fi
echo shar: "extracting 'vcs.c'" '(10939 characters)'
if test -f 'vcs.c'
then
	echo shar: "will not over-write existing file 'vcs.c'"
else
sed 's/^X//' << \SHAR_EOF > 'vcs.c'
X/*
X * Routines for VCS detection.
X */
X
X#include <stdio.h>
X#include "config.h"
X#include "vcs.h"
X
X#ifndef OLDCURSES
X#include <curses.h>
X#include <term.h>
X#endif /* OLDCURSES */
X
Xstatic int putc_cnt;
Xstatic char putc_buf[VCS_SIZE];
X
X/*
X * Test for possible VCS (video command sequence).  A character return
X * code means no match.  An return code greater than 255 means a VCS
X * was found.
X */
X
Xint
Xvcs_filter(c)
Xchar c;
X{
X	extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_leadin[NUM_VCS];
X	extern int num_leadin;
X	static int vcs_buf[VCS_SIZE];
X	static int ptr = 0;
X	register int i;
X	int maybe, possible;
X
X					/* see if possible */
X	possible = 0;
X	if (ptr == 0) {
X		/*
X		 * This is kinda crude... I'm checking to see if the
X		 * lead-in character is greater than the space character.
X		 * If so, it most probably is NOT a VCS.
X		 */
X		if (c >= ' ')
X			return(c & 0xff);
X					/* check the list */
X		for (i=0; i<num_leadin; i++) {
X			if (c == vcs_leadin[i]) {
X				possible++;
X				break;
X			}
X		}
X		if (!possible)
X			return(c & 0xff);
X	}
X
X					/* build the string */
X	vcs_buf[ptr++] = c;
X	vcs_buf[ptr] = -1;
X					/* test for match */
X	maybe = 0;
X	for (i=0; i<NUM_VCS; i++) {
X		switch (match_codes(vcs_buf, vcs_codes[i], i)) {
X			case YES:
X				ptr = 0;
X				return(i+256);
X			case NO:
X				break;
X			case MAYBE:
X				maybe++;
X				break;
X		}
X	}
X					/* abandon what you've got */
X	if (maybe && ptr == VCS_SIZE-1) {
X		ptr = 0;
X		return(c & 0xff);
X	}
X					/* hang on, wait and see */
X	if (maybe)
X		return(MAYBE);
X					/* a clean miss */
X	ptr = 0;
X	return(c & 0xff);
X}
X
X/*
X * See if the two integer arrays "match".  Character parameters are
X * designated by codes > 1000 and ASCII digit parameters are designated
X * by codes > 2000.  Uses a simple linear search, so if NUM_VCS grows
X * this routine will have to mature a bit.
X */
X
Xstatic int
Xmatch_codes(test, code, k)
Xint test[], code[], k;
X{
X	extern int vcs_param[NUM_VCS][5];
X	register int i, j;
X	int pos, done;
X					/* doesn't exist */
X	if (code[0] == -1)
X		return(NO);
X
X	i = 0;
X	j = 0;
X	while (i<VCS_SIZE && j<VCS_SIZE) {
X					/* at the end (a match) */
X		if (test[i] == -1 && code[j] == -1)
X			return(YES);
X					/* ran out of input */
X		if (test[i] == -1)
X			break;
X		/*
X		 * The char parameter (code 1000) always matches the
X		 * next character.
X		 */
X		if (code[j] >= 1000 && code[j] < 2000) {
X			pos = code[j] -1000;
X			vcs_param[k][pos] = test[i];
X			i++;
X			j++;
X			continue;
X		}
X		/*
X		 * The digit parameter (code 2000) tries to match as many
X		 * ASCII digits as it can.
X		 */
X		if (code[j] >= 2000) {
X			pos = code[j] -2000;
X					/* done with this number? */
X			if (vcs_param[k][pos])
X				done = 1;
X			else
X				done = 0;
X					/* only digits */
X			while (test[i] >= 48 && test[i] <= 57) {
X				if (!done)
X					vcs_param[k][pos] = (vcs_param[k][pos] * 10) + test[i] -48;
X				i++;
X			}
X					/* ended in a digit */
X			if (test[i] == -1 && code[j+1] != -1) {
X				vcs_param[k][pos] = 0;
X				break;
X			}
X			j++;
X			continue;
X		}
X					/* a clean miss */
X		if (test[i] != code[j]) {
X			for (j=0; j<5; j++)
X				vcs_param[k][j] = 0;
X			return(NO);
X		}
X		i++;
X		j++;
X	}
X					/* a maybe */
X	return(MAYBE);
X}
X
X/*
X * Build the table of VCS codes.  Actually we cheat... We tell curses(3)
X * to build the strings to perform the function, and then we decipher
X * what it did.
X *
X * For example: On a vt100 the cursor motion string in terminfo is:
X *	cup=\E[%i%p1%d;%p2%dH$<5>
X *
X * This gets translated to the integer array vcs_code[] as:
X *	\E   [   %p1%d  ;   %p2%d  H
X *	27,  91, 2000,  59, 2001,  72
X * 
X * Notice that the "%p1" and "%p2" parameters get translated to 2000 and
X * 2001.  This is to signify that the parameters are multiple digit ASCII
X * encoded numbers.  The "%i" and "%d" codes are imbedded into the vcs_opt[]
X * array in somewhat of a loose manner.  In other words, there is no set
X * format for the vcs_opt[] array.  The padding info "$<5>" is ignored.
X */
X
Xvoid
Xvcs_table()
X{
X	extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_opt[NUM_VCS][10];
X	extern int vcs_leadin[NUM_VCS], num_leadin, max_row, max_col;
X	int i, j, k, match, temp[VCS_SIZE];
X	char *p, *strcpy(), buf[VCS_SIZE], *getenv(), *tparm();
X	void fake_it();
X
X#ifdef OLDCURSES
X	char tcbuf[1024], tb[1024], *t, *cursor_home, *clr_eol, *clr_eos;
X	char *clear_screen, *cursor_up, *cursor_down, *cursor_right;
X	char *cursor_left, *cursor_address, *getenv(), *tgetstr(), *tgoto();
X
X	tgetent(tb, getenv("TERM"));
X	t = tcbuf;
X
X	cursor_home = tgetstr("ho", &t);
X	clr_eol = tgetstr("ce", &t);
X	clr_eos = tgetstr("cd", &t);
X	clear_screen = tgetstr("cl", &t);
X	cursor_up = tgetstr("up", &t);
X	cursor_down = tgetstr("do", &t);
X	cursor_right = tgetstr("nd", &t);
X	cursor_left = tgetstr("le", &t);
X	cursor_address = tgetstr("cm", &t);
X	max_row = tgetnum("li");
X	max_col = tgetnum("co");
X#else /* OLDCURSES */
X	setupterm(getenv("TERM"), 1, &i);
X	max_row = lines;
X	max_col = columns;
X#endif /* OLDCURSES */
X
X	/*
X	 * Do the easy ones first.  These don't take positional parameters,
X	 * so all we have to do is strip the padding info.
X	 */
X	for (i=0; i<NUM_VCS; i++) {
X		switch (i) {
X			case HOME:
X				p = cursor_home;
X				break;
X			case CLR_EOL:
X				p = clr_eol;
X				break;
X			case CLR_EOS:
X				p = clr_eos;
X				break;
X			case CLEAR:
X				p = clear_screen;
X				break;
X			case MV_UP:
X				p = cursor_up;
X				break;
X			case MV_DOWN:
X				p = cursor_down;
X				break;
X			case MV_RIGHT:
X				p = cursor_right;
X				break;
X			case MV_LEFT:
X				p = cursor_left;
X				break;
X			default:
X				p = "";
X				break;
X		}
X		/*
X		 * Either the capability doesn't exist, or we're gonna
X		 * do this one by hand (i.e.: ones with positional parameters)
X		 */
X		if (!p) {
X			vcs_codes[i][0] = -1;
X			continue;
X		}
X					/* fake an "output" */
X		fake_it(p);
X					/* copy what it did */
X		j = 0;
X		while (putc_buf[j]) {
X			vcs_codes[i][j] = putc_buf[j];
X			j++;
X			if (j == VCS_SIZE-1)
X				break;
X		}
X		vcs_codes[i][j] = -1;
X	}
X
X	/*
X	 * And now for the difficult ones.  The way it's done is: load the
X	 * string with a few known parameters and then find where the
X	 * parameters end up.  The vcs_opt[][] array is "free-flowing"
X	 * and means something only to the routine being used.
X	 */
X					/* add one to the param */
X	if (substr(cursor_address, "%i") > 0)
X		vcs_opt[MV_DIRECT][0] = 1;
X					/* decimal codes used */
X	if (substr(cursor_address, "%d") > 0)
X		vcs_opt[MV_DIRECT][1] = 1;
X					/* character codes used */
X	if (substr(cursor_address, "%c") > 0)
X		vcs_opt[MV_DIRECT][2] = 1;
X					/* add an offset */
X	if (substr(cursor_address, "%+") > 0)
X		vcs_opt[MV_DIRECT][3] = 1;
X					/* subtract an offset */
X	if (substr(cursor_address, "%-") > 0)
X		vcs_opt[MV_DIRECT][4] = 1;
X					/* load with parameters 12 & 34 */
X#ifdef OLDCURSES
X	fake_it(tgoto(cursor_address, 12, 34));
X#else /* OLDCURSES */
X	fake_it(tparm(cursor_address, 12, 34));
X#endif /* OLDCURSES */
X
X	j = 0;
X	while (putc_buf[j]) {
X		temp[j] = putc_buf[j];
X		j++;
X		if (j == VCS_SIZE-1)
X			break;
X	}
X	temp[j] = -1;
X					/* if decimal parameters */
X	if (vcs_opt[MV_DIRECT][1]) {
X					/* if add one */
X		if (vcs_opt[MV_DIRECT][0])
X			strcpy(buf, "13");
X		else
X			strcpy(buf, "12");
X					/* where is the 12 (or 13)? */
X		if ((i = substr(putc_buf, buf)) > 0) {
X			temp[i] = 2000;
X			temp[i+1] = -2;
X		}
X		else
X			temp[0] = -1;
X					/* if add one */
X		if (vcs_opt[MV_DIRECT][0])
X			strcpy(buf, "35");
X		else
X			strcpy(buf, "34");
X					/* where is the 34 (or 35)? */
X		if ((i = substr(putc_buf, buf)) > 0) {
X			temp[i] = 2001;
X			temp[i+1] = -2;
X		}
X		else
X			temp[0] = -1;
X	}
X					/* if character parameters */
X	if (vcs_opt[MV_DIRECT][2]) {
X					/* original with 12 and 34 */
X		strcpy(buf, putc_buf);
X					/* change 12 to 13 */
X#ifdef OLDCURSES
X		fake_it(tgoto(cursor_address, 13, 34));
X#else /* OLDCURSES */
X		fake_it(tparm(cursor_address, 13, 34));
X#endif /* OLDCURSES */
X					/* where are they different */
X		i = 0;
X		while (buf[i] != '\0') {
X			if (buf[i] != putc_buf[i])
X				break;
X			i++;
X		}
X					/* sanity checking */
X		if (buf[i] == '\0')
X			temp[0] = -1;
X					/* if add, what is offset? */
X		if (vcs_opt[MV_DIRECT][3])
X			vcs_opt[MV_DIRECT][5] = temp[i] - 13;
X
X					/* if subtract, what is offset? */
X		if (vcs_opt[MV_DIRECT][4])
X			vcs_opt[MV_DIRECT][5] = 13 - temp[i];
X
X		temp[i] = 1000;
X					/* change 34 to 35 */
X#ifdef OLDCURSES
X		fake_it(tgoto(cursor_address, 12, 35));
X#else /* OLDCURSES */
X		fake_it(tparm(cursor_address, 12, 35));
X#endif /* OLDCURSES */
X					/* where are they different */
X		i = 0;
X		while (buf[i] != '\0') {
X			if (buf[i] != putc_buf[i])
X				break;
X			i++;
X		}
X		temp[i] = 1001;
X		if (buf[i] == '\0')
X			temp[0] = -1;
X	}
X					/* strip the -2's out, if any */
X	i = 0;
X	j = 0;
X	while (temp[i] != -1) {
X		if (temp[i] != -2)
X			vcs_codes[MV_DIRECT][j++] = temp[i];
X		i++;
X	}
X	vcs_codes[MV_DIRECT][j] = -1;
X
X	/*
X	 * Simplify the list.  Some codes are already handled by the
X	 * virtual screen routines... no need to duplicate them.
X	 */
X	if (vcs_codes[MV_DOWN][0] == '\n')
X		vcs_codes[MV_DOWN][0] = -1;
X
X	if (vcs_codes[MV_LEFT][0] == 8)
X		vcs_codes[MV_LEFT][0] = -1;
X
X	/*
X	 * Often the "clear screen" sequence will contain the "home"
X	 * sequence... if so, don't duplicate the "home" portion.
X	 */
X	fake_it(cursor_home);
X	strcpy(buf, putc_buf);
X
X	fake_it(clear_screen);
X					/* if "home" inside "clear screen" */
X	if ((k = substr(putc_buf, buf)) >= 0) {
X					/* if at the beginning */
X		if (k == 0) {
X			i = 0;
X			for (j=strlen(buf); j<VCS_SIZE; j++)
X				vcs_codes[CLEAR][i++] = putc_buf[j];
X			vcs_codes[CLEAR][i] = -1;
X		}
X					/* if at the end */
X		else if (strlen(buf)+k == strlen(putc_buf))
X			vcs_codes[CLEAR][k] = -1;
X	}
X					/* is "clear screen" still unique */
X	k = 0;
X	for (i=0; i<NUM_VCS; i++) {
X		if (vcs_codes[CLEAR][i] == -1 || vcs_codes[CLR_EOS][i] == -1)
X			break;
X		if (vcs_codes[CLEAR][i] != vcs_codes[CLR_EOS][i]) {
X			k++;
X			break;
X		}
X	}
X	if (k == 0)
X		vcs_codes[CLEAR][0] = -1;
X
X	/*
X	 * Make a list of unique lead-in characters to be used as a
X	 * simple hash table.
X	 */
X	num_leadin = 0;
X	for (i=0; i<NUM_VCS; i++) {
X		if (vcs_codes[i][0] == -1)
X			continue;
X					/* add any new lead-in character */
X		match = 0;
X		for (j=0; j<num_leadin; j++) {
X			if (vcs_leadin[j] == vcs_codes[i][0])
X				match++;
X		}
X		if (!match)
X			vcs_leadin[num_leadin++] = vcs_codes[i][0];
X	}
X	return;
X}
X
X/*
X * The routine that fakes curses(3) into outputting the string info with
X * the padding removed.
X */
Xstatic void
Xfake_it(s)
Xchar *s;
X{
X	int fake_putc();
X
X	putc_cnt = 0;
X	putc_buf[0] = '\0';
X	tputs(s, 1, fake_putc);
X	putc_buf[putc_cnt] = '\0';
X	return;
X}
Xstatic int
Xfake_putc(c)
Xchar c;
X{
X	if (c != '\0')
X		putc_buf[putc_cnt++] = c;
X	return(c);
X}
X
X/*
X * Is string2 contained in string1?  If so, return the offset, otherwise
X * return a -1.
X */
X
Xstatic int
Xsubstr(s1, s2)
Xchar *s1, *s2;
X{
X	int i, len;
X
X	len = strlen(s2);
X					/* not possible */
X	if (len > strlen(s1))
X		return(-1);
X
X	i = 0;
X	while (*s1) {
X		if (!strncmp(s1, s2, len))
X			return(i);
X		s1++;
X		i++;
X	}
X	return(-1);
X}
SHAR_EOF
if test 10939 -ne "`wc -c < 'vcs.c'`"
then
	echo shar: "error transmitting 'vcs.c'" '(should have been 10939 characters)'
fi
fi
echo shar: "extracting 'vcs.h'" '(330 characters)'
if test -f 'vcs.h'
then
	echo shar: "will not over-write existing file 'vcs.h'"
else
sed 's/^X//' << \SHAR_EOF > 'vcs.h'
X/*
X * Definitions to support the detection of video command sequences
X */
X
X#define VCS_SIZE	25
X#define NUM_VCS		9
X
X#define HOME		0
X#define CLR_EOL		1
X#define CLR_EOS		2
X#define CLEAR		3
X#define MV_UP		4
X#define MV_DOWN		5
X#define MV_RIGHT	6
X#define MV_LEFT		7
X#define MV_DIRECT	8
X
X#define YES		1
X#define NO		0
X#define MAYBE		(-1)
SHAR_EOF
if test 330 -ne "`wc -c < 'vcs.h'`"
then
	echo shar: "error transmitting 'vcs.h'" '(should have been 330 characters)'
fi
fi
echo shar: "extracting 'waitfor.c'" '(2108 characters)'
if test -f 'waitfor.c'
then
	echo shar: "will not over-write existing file 'waitfor.c'"
else
sed 's/^X//' << \SHAR_EOF > 'waitfor.c'
X/*
X * Wait for a string on the stdin.  Returns a 0 on success, 1 on failure
X * and -1 on error.  This is an external program designed to be used in
X * shell scripts.
X */
X
X#define TIMEOUT	10
X#define BUF_SIZ	1024
X#define HZ	60
X#define STRSTR
X
Xint wf_flag;
X
X#include <stdio.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/times.h>
X
X#ifdef BSD
X#include <setjmp.h>
Xjmp_buf wf_buf;
X#endif /* BSD */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int i, j, timeout;
X	char c, buf[BUF_SIZ], *string, *strstr();
X	struct tms t;
X	long t1;
X	void exit();
X
X	if (argc < 2 || argc > 3) {
X		fprintf(stderr, "Usage: waitfor -n string\n");
X		exit(-1);
X	}
X
X	if (argv[1][0] == '-') {
X		timeout = atoi(&argv[1][1]);
X		if (argc != 3) {
X			fprintf(stderr, "Usage: waitfor -n string\n");
X			exit(-1);
X		}
X		string = argv[2];
X	}
X	else {
X		timeout = TIMEOUT;
X		string = argv[1];
X	}
X					/* here we go.. */
X	i = 0;
X	t1 = times(&t);
X	while ((times(&t) - t1) < (HZ * timeout)) {
X		if ((j = getc_line()) != -1) {
X			c = j & 0x7f;
X					/* no NULLs please */
X			if (c != '\0') {
X				buf[i++] = c;
X				buf[i] = '\0';
X			}
X
X			if (i >= BUF_SIZ) {
X				fprintf(stderr, "waitfor: buffer overflow\n");
X				exit(-1);
X			}
X					/* yea.. we found it! */
X			if (strstr(buf, string))
X				exit(0);
X		}
X	}
X	exit(1);
X}
X
Xint
Xgetc_line()
X{
X	int wf_force();
X	char c;
X	unsigned int alarm();
X
X	signal(SIGALRM, wf_force);
X	wf_flag = 0;
X
X	alarm(1);
X
X#ifdef BSD
X	if (setjmp(wf_buf))
X		return(-1);
X#endif /* BSD */
X
X	if (read(0, &c, 1) <= 0) {
X		alarm(0);
X		return(-1);
X	}
X	if (wf_flag)
X		return(-1);
X	alarm(0);
X	return(c & 0xff);
X}
X
X/* ARGSUSED */
Xstatic int
Xwf_force(dummy)
Xint dummy;
X{
X#ifdef BSD
X	longjmp(wf_buf, 1);
X#else /* BSD */
X	signal(SIGALRM, wf_force);
X	wf_flag = 1;
X#endif /* BSD */
X}
X
X#ifdef STRSTR
X/*
X * Return a pointer to the first occurance of string str2 in str1.
X * Returns a NULL if str2 is not in str1.
X */
X
Xchar *
Xstrstr(str1, str2)
Xchar *str1, *str2;
X{
X	int len;
X	len = strlen(str2);
X	while (*str1) {
X		if (*str2 == *str1) {
X			if (!strncmp(str2, str1, len))
X				return(str1);
X		}
X		str1++;
X	}
X	return(NULL);
X}
X#endif /* STRSTR */
SHAR_EOF
if test 2108 -ne "`wc -c < 'waitfor.c'`"
then
	echo shar: "error transmitting 'waitfor.c'" '(should have been 2108 characters)'
fi
fi
echo shar: "extracting 'x_ascii.c'" '(6450 characters)'
if test -f 'x_ascii.c'
then
	echo shar: "will not over-write existing file 'x_ascii.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_ascii.c'
X/*
X * Transfer a file using just XON/XOFF flow control.  Currently limited to
X * 7 bit ASCII codes.  (If this causes too much trouble, I'll change it).
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include <signal.h>
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X
X#ifdef BSD
X#include <setjmp.h>
Xjmp_buf bl_buf;
X#endif /* BSD */
X
Xvoid
Xxfer_ascii(list, up)
Xchar *list;
Xint up;
X{
X	int cr_lf;
X	char *file, *strtok();
X	void send_ascii(), rcv_ascii(), line_set(), st_line(), suspend();
X	void load_vs(), ascii_mode(), input_off(), term_mode();
X	unsigned int sleep();
X
X	touchwin(stdscr);
X	refresh();
X					/* only one file from list */
X	file = strtok(list, " \t");
X
X	cr_lf = !strcmp(param->cr_out, "CR/LF");
X	ascii_mode(up);
X					/* out of curses mode */
X	resetterm();
X	term_mode();
X	tty_noblock(0, TRUE);
X
X	if (up) {
X					/* un-suspend the input routine */
X		suspend(FALSE);
X		send_ascii(file, cr_lf);
X		suspend(TRUE);
X	}
X	else {
X		input_off();
X		rcv_ascii(file, cr_lf);
X	}
X
X	/*
X	 * Restoring the TTY modes is easier than setting them... The
X	 * fixterm() and line_set() routines fix most of the damage.
X	 */
X	line_set();
X	fixterm();
X	tty_noblock(0, FALSE);
X
X	/*
X	 * On downloading, the contents of the virtual screen won't contain
X	 * the characters shown during the transfer.  Too bad...
X	 */
X	load_vs();
X	beep();
X	st_line("xfer complete");
X
X	sleep(2);
X	return;
X}
X
X/*
X * Send a file.  The local echo option is independent of the duplex option,
X * and would very rarely be used since the characters are most likely
X * being echoed on the screen anyway.
X */
X
Xstatic void
Xsend_ascii(file, cr_lf)
Xchar *file;
Xint cr_lf;
X{
X	extern int fd;
X	FILE *fp, *my_fopen();
X	int i, j, strip_cr, strip_lf, add_cr, add_lf, expand, lecho, pace;
X	char buf[80];
X	unsigned char c, last;
X	unsigned int sleep();
X	void error_win();
X					/* permission already checked */
X	if (!(fp = my_fopen(file, "r"))) {
X		sprintf(buf, "\"%s\"", file);
X		error_win(0, "Can't open file for read", buf);
X		return;
X	}
X					/* ASCII transfer options */
X	strip_cr = !strcmp(param->cr_up, "STRIP");
X	add_lf = !strcmp(param->cr_up, "ADD LF");
X	strip_lf = !strcmp(param->lf_up, "STRIP");
X	add_cr = !strcmp(param->lf_up, "ADD CR");
X	expand = !strcmp(param->expand, "YES");
X	lecho = !strcmp(param->lecho, "YES");
X	pace = !strcmp(param->pace, "YES");
X
X	last = 0;
X	while ((i = fgetc(fp)) != EOF) {
X					/* any keyboard activity? */
X		switch (j = getchar()) {
X			case -1:	/* no key was pressed */
X				break;
X			case ESC:	/* <ESC> key for abort */
X				fclose(fp);
X				sleep(2);
X				tty_drain(fd);
X				return;
X			default:	/* send the char */
X				c = j;
X				putc_line(c);
X				if (c == '\r' && cr_lf)
X					putc_line('\n');
X				break;
X		}
X		c = i & 0x7f;
X					/* expand blank lines */
X		if (expand && last == '\n' && c == '\n')
X			putc_line(' ');
X		last = c;
X
X					/* CR translations */
X		if (c == '\r' && strip_cr)
X			continue;
X		if (c == '\r' && add_lf) {
X			putc_line(c);
X			putc_line('\n');
X			continue;
X		}
X					/* LF translations */
X		if (c == '\n' && strip_lf)
X			continue;
X		if (c == '\n' && add_cr) {
X			putc_line('\r');
X			putc_line(c);
X			continue;
X		}
X		putc_line(c);
X		/*
X		 * There's really no mechanism for delaying characters
X		 * going to the output, so we fake it by waiting for
X		 * each character to clear the I/O buffer.
X		 */
X		if (pace)
X			tty_drain(fd);
X		if (lecho) {
X			putchar((char) c);
X			fflush(stdout);
X		}
X	}
X	fclose(fp);
X	sleep(2);
X	tty_drain(fd);
X	return;
X}
X
X/*
X * Receive a file.  The timer is used to end the transfer.  This is not
X * that much different from the data logging option.  The use of bgetc_line()
X * and non-blocking input makes it seem like full duplex, but it's not.
X * Be aware that while the timer is active the keyboard is deaf.  Input is
X * NOT loaded into the virtual screen!!
X */
X
Xstatic void
Xrcv_ascii(file, cr_lf)
Xchar *file;
Xint cr_lf;
X{
X	FILE *fp, *my_fopen();
X	int i, strip_cr, strip_lf, add_cr, add_lf, got_first;
X	unsigned int delay;
X	char c, buf[80];
X	void error_win();
X					/* permission already checked */
X	if (!(fp = my_fopen(file, "w"))) {
X		sprintf(buf, "\"%s\"", file);
X		error_win(0, "Can't open file for write", buf);
X		return;
X	}
X					/* ASCII transfer options */
X	strip_cr = !strcmp(param->cr_dn, "STRIP");
X	add_lf = !strcmp(param->cr_dn, "ADD LF");
X	strip_lf = !strcmp(param->lf_dn, "STRIP");
X	add_cr = !strcmp(param->lf_dn, "ADD CR");
X
X	got_first = 0;
X	delay = 1;
X	while (1) {
X					/* keyboard activity */
X		switch (i = getchar()) {
X			case -1:	/* no key was pressed */
X				break;
X			case ESC:	/* <ESC> key */
X				fclose(fp);
X				return;
X			default:	/* send it */
X				c = i;
X				putc_line((unsigned char) c);
X				if (c == '\r' && cr_lf)
X					putc_line('\n');
X				break;
X		}
X					/* read a character */
X		if ((i = bgetc_line(delay)) == -1) {
X			/*
X			 * The transfer timeout is not activated until the
X			 * first character is received.  Until then, it polls
X			 * the line for one second and loops backs for
X			 * keyboard input.
X			 */
X			if (got_first) {
X				fclose(fp);
X				return;
X			}
X			continue;
X		}
X		got_first = 1;
X		delay = param->timer;
X		c = i & 0x7f;
X					/* display it on the screen */
X		putchar(c);
X		fflush(stdout);
X					/* CR translations */
X		if (c == '\r' && strip_cr)
X			continue;
X		if (c == '\r' && add_lf) {
X			fputc(c, fp);
X			fputc('\n', fp);
X			continue;
X		}
X					/* LF translations */
X		if (c == '\n' && strip_lf)
X			continue;
X		if (c == '\n' && add_cr) {
X			fputc('\r', fp);
X			fputc(c, fp);
X			continue;
X		}
X		fputc(c, fp);
X	}
X}
X
X/*
X * Get a character from the line (using buffered I/O) with a specified
X * time-out period in seconds.  If the function times-out, it returns a -1.
X */
X
Xstatic int bl_flag;
X
Xstatic int
Xbgetc_line(sec)
Xunsigned int sec;
X{
X	int c, bl_force();
X	unsigned int alarm();
X
X	signal(SIGALRM, bl_force);
X	bl_flag = 0;
X
X	alarm(sec);
X
X#ifdef BSD
X	if (setjmp(bl_buf))
X		return(-1);
X#endif /* BSD */
X
X	if ((c = buf_read()) < 0) {
X		alarm(0);
X		return(-1);
X	}
X	if (bl_flag)
X		return(-1);
X	alarm(0);
X	return(c);
X}
X
X/* ARGSUSED */
Xstatic int
Xbl_force(dummy)
Xint dummy;
X{
X#ifdef BSD
X	longjmp(bl_buf, 1);
X#else /* BSD */
X	signal(SIGALRM, bl_force);
X	bl_flag = 1;
X#endif /* BSD */
X}
X
X/*
X * Do a single character buffered read from the serial port.
X */
X
Xstatic int
Xbuf_read()
X{
X	extern int fd;
X	static char buf[CLIST_SIZ];
X	static char *bufp = buf;
X	static int n = 0;
X
X	if (n <= 0) {
X		n = read(fd, buf, CLIST_SIZ);
X		bufp = buf;
X	}
X	if (--n >= 0)
X		return(*bufp++ & 0xff);
X	return(-1);
X}
SHAR_EOF
if test 6450 -ne "`wc -c < 'x_ascii.c'`"
then
	echo shar: "error transmitting 'x_ascii.c'" '(should have been 6450 characters)'
fi
fi
echo shar: "extracting 'x_batch.c'" '(8686 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 "config.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.  Returns zero on success or the standard error codes.
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 -1:	/* timed out */
X				clear_line(win, 12, 24, TRUE);
X				waddstr(win, "NO RESPONSE");
X				wrefresh(win);
X				return(ERROR);
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, TRUE);
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, TRUE);
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, TRUE);
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 modem7 file name.  Returns zero on success, the standard error
X * codes, or a -1 on the end-of-batch.  (Oddly enough, the end-of-batch code
X * is the same as the code for a user abort)
X */
X
Xint
Xrcv_modem7(win, default_err)
XWINDOW *win;
Xint default_err;
X{
X	extern char file_name[15];
X	int i, j, err_method, err_count, got_it;
X	unsigned char sum, calc_sum();
X	char temp_name[13];
X	void change_name(), unfix_name();
X
X	err_method = default_err;
X	if (default_err == CRC_CHECKSUM)
X		err_method = CRC;
X
X	err_count = 0;
X	got_it = 0;
X	while (err_count < MAX_ERRORS) {
X					/* switch to checksum? */
X		if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
X			err_method = CHECKSUM;
X
X		if (err_method == CRC)
X			putc_line('C');
X		else
X			putc_line(NAK);
X					/* what'd we get? */
X		switch (getc_line(10)) {
X			case -1:	/* timed out */
X				clear_line(win, 12, 24, TRUE);
X				wattrstr(win, A_BOLD, "NO RESPONSE");
X				wrefresh(win);
X				err_count++;
X			case ACK:	/* ready to go... */
X				got_it++;
X				break;
X			default:	/* huh? */
X				clear_line(win, 12, 24, TRUE);
X				wattrstr(win, A_BOLD, "BAD HEADER");
X				wrefresh(win);
X				err_count++;
X		}
X	}
X	if (!got_it)
X		return(ERROR);
X					/* get the name */
X	for (i=0; i<12; i++) {
X		j = getc_line(3);
X
X		switch (j) {
X			case -1:	/* timed out */
X				clear_line(win, 12, 24, TRUE);
X				wattrstr(win, A_BOLD, "NO RESPONSE");
X				wrefresh(win);
X				return(ERROR);
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, TRUE);
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, TRUE);
X				wattrstr(win, A_BOLD, "BAD NAME");
X				wrefresh(win);
X				return(ERROR);
X			default:	/* the name... */
X				temp_name[i] = j & 0xff;
X				if (j != CTRLZ)
X					putc_line(ACK);
X				break;
X		}
X	}
X	temp_name[12] = '\0';
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, TRUE);
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;
Xlong size;
X{
X	unsigned short crc, calc_crc();
X	char *strcpy(), *memset();
X	unsigned char buf[133];
X					/* start with a clean block */
X	memset(buf, '\0', 133);
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 != '\0') {
X		strcpy((char *) &buf[3], file);
X		sprintf((char *) &buf[strlen(file)+4], "%ld", 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	extern unsigned char buf[1029];
X	extern long file_length;
X	extern char file_name[15];
X	int code, length_is_at;
X	long atol();
X
X	file_length = 0L;
X	file_name[0] = '\0';
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] == '\0')
X		return(0);
X					/* get the file name */
X	change_name(win, (char *) &buf[3]);
X					/* any trouble? */
X	if (file_name[0] == '\0') {
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	 * atol() will see a NULL and return 0.
X	 */
X	length_is_at = strlen((char *) &buf[3]) + 4;
X	file_length = atol((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	extern char file_name[15];
X	register int i;
X	int modified;
X	char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
X	unsigned int sleep();
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] = '\0';
X					/* write permission on directory? */
X	if (access(".", 2)) {
X		beep();
X		clear_line(win, 12, 24, TRUE);
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, TRUE);
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] = '\0';
X		strcpy(ans, temp);
X	}
X	beep();
X	clear_line(win, 12, 24, TRUE);
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 a static area containing 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 = "";
X	dot = 0;
X	for (s=name; *s; ++s) {
X		if (*s == '.' && !dot) {
X			dot++;
X			*s = '\0';
X			ext = s + 1;
X		}
X		if (islower(*s))
X			*s = toupper(*s);
X	}
X					/* if null name component */
X	if (*name == '\0')
X		name = "X";
X					/* if name too long */
X	if (strlen(name) > 8)
X		*(name+8) = '\0';
X					/* if extension too long */
X	if (strlen(ext) > 3)
X		*(ext+3) = '\0';
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	extern char file_name[15];
X	register int i, n;
X	int dot;
X	char temp[15];
X
X	file_name[0] = '\0';
X	if (*cpm_name == '\0')
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] = '\0';
X	return;
X}
SHAR_EOF
if test 8686 -ne "`wc -c < 'x_batch.c'`"
then
	echo shar: "error transmitting 'x_batch.c'" '(should have been 8686 characters)'
fi
fi
echo shar: "extracting 'x_extrnl.c'" '(2965 characters)'
if test -f 'x_extrnl.c'
then
	echo shar: "will not over-write existing file 'x_extrnl.c'"
else
sed 's/^X//' << \SHAR_EOF > 'x_extrnl.c'
X/*
X * Spawn a shell with the stdin and stdout swapped with the remote
X * system, ie:
X *                               +----------+
X *    TTYin ------------> stdin  |          |
X *                               |  shell   |
X *    TTYout <---------- stdout  |          |
X *                               +----------+
X *
X * An undocumented feature:  The external protocol gateway
X * can be used to pipe the output of a normal Unix command to the
X * remote system.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#include <errno.h>
X#include "config.h"
X
X#ifdef BSD
X#include <sys/file.h>
X#else /* BSD */
X#include <fcntl.h>
X#endif /* BSD */
X
Xvoid
Xdo_extrnl(cmd)
Xchar *cmd;
X{
X	extern int fd, errno;
X	WINDOW *xt_win, *newwin();
X	SIG_TYPE (*istat)(), (*qstat)();
X	int epid, want_out, sig_status;
X	char buf[80], *ttyname(), *strcpy();
X	unsigned int sleep();
X	void _exit(), input_off();
X
X	input_off();
X					/* a full window */
X	xt_win = newwin(LINES, COLS, 0, 0);
X	touchwin(xt_win);
X	wrefresh(xt_win);
X					/* out of curses mode */
X	resetterm();
X
X	if (!(epid = fork())) {
X					/* create a new process group ID */
X#ifdef BSD
X		setpgrp(0, getpid());
X#else /* BSD */
X		setpgrp();
X#endif /* BSD */
X					/* recreate the device name */
X		strcpy(buf, ttyname(fd));
X		close(fd);
X					/* swap the stdin */
X		close(0);
X#ifdef UNIXPC
X/*
X * Some strange things here... The OBM uses the second parameter of 
X * open() to determine if the port should be in the DATA mode or
X * the VOICE mode.  Therefore, we must always open with read and write.
X */
X		if (!strncmp(buf, "/dev/ph", 7))
X			open(buf, O_RDWR);
X		else
X#endif /* UNIXPC */
X		open(buf, O_RDONLY);
X					/* swap the stdout */
X		close(1);
X#ifdef UNIXPC
X		if (!strncmp(buf, "/dev/ph", 7))
X			open(buf, O_RDWR);
X		else
X#endif /* UNIXPC */
X		open(buf, O_WRONLY);
X#ifdef SETUGID
X		setgid(getgid());
X		setuid(getuid());
X#endif /* SETUGID */
X		execl("/bin/sh", "sh", "-c", cmd, (char *) 0);
X		_exit(1);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	/*
X	 * Check the keyboard while the external program is running.  If
X	 * the user hits the <ESC> key, then kill the entire process
X	 * group associated with the new shell.
X	 */
X	want_out = 0;
X	while(1) {
X		switch(wait_key(stdscr, 1)) {
X			case -1:	/* timed out */
X				break;
X			case 27:	/* a user abort */
X#ifdef BSD
X				killpg(epid, SIGKILL);
X#else /* BSD */
X				kill(-epid, SIGKILL);
X#endif /* BSD */
X				want_out++;
X				break;
X			default:
X				beep();
X				break;
X		}
X		if (want_out)
X			break;
X					/* see if the process it still active */
X#ifdef BSD
X		if ((kill(epid, 0) == -1) && errno == ESRCH) 
X#else /* BSD */
X		if ((kill(-epid, 0) == -1) && errno == ESRCH) 
X#endif /* BSD */
X			break;
X	}
X					/* wait for the zombie process */
X	wait(&sig_status);
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X					/* back to curses mode */
X	sleep(1);
X	fixterm();
X
X	clearok(curscr, TRUE);
X	werase(xt_win);
X	wrefresh(xt_win);
X	delwin(xt_win);
X	return;
X}
SHAR_EOF
if test 2965 -ne "`wc -c < 'x_extrnl.c'`"
then
	echo shar: "error transmitting 'x_extrnl.c'" '(should have been 2965 characters)'
fi
fi
exit 0
#	End of shell archive


-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.