[comp.sources.unix] v14i102: Dial out and terminal emulator, Part04/06

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

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


#! /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:
#	input.c
#	line_set.c
#	list_dir.c
#	ls_menu.c
#	m_lib.c
#	main.c
#	n_shell.c
#	p_lib.c
#	pexit.c
#	port.c
#	redial.c
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'input.c'" '(6599 characters)'
if test -f 'input.c'
then
	echo shar: "will not over-write existing file 'input.c'"
else
sed 's/^X//' << \SHAR_EOF > 'input.c'
X/*
X * The input routines.  These routines are run as a child process to the
X * main pcomm program.
X */
X
X#define LPR "/usr/bin/lpr"
X
X#define MAX_ROW	64
X#define MAX_COL	128
X
X#include <stdio.h>
X#include <signal.h>
X#include <setjmp.h>
X
Xjmp_buf i_jmp;
Xunsigned char vs[MAX_ROW][MAX_COL+2];
Xint row, col;
X
X/*
X * Read the serial port and write the characters to the screen.  Watch
X * for signals from the parent process to toggle the fancy options.
X * Writes the characters received to a virtual screen buffer.
X */
Xint
Xinput(fd, add_lf, log, print, max_row, max_col, vs_file, log_file)
Xint fd, add_lf, log, print, max_row, max_col;
Xchar *vs_file, *log_file;
X{
X	FILE *logfp, *lprfp, *popen();
X	int hold, skip_row, got_sig();
X	unsigned char c;
X	char lf=10;
X	void _exit();
X					/* set the trap for the signals */
X	signal(SIGALRM, SIG_IGN);
X	signal(SIGUSR1, got_sig);
X	signal(SIGUSR2, got_sig);
X	signal(SIGINT,  got_sig);
X	signal(SIGTERM, got_sig);
X					/* resonable limits */
X	if (max_row > MAX_ROW)
X		max_row = MAX_ROW;
X	if (max_col > MAX_COL)
X		max_col = MAX_COL;
X					/* read previous screen */
X	if (!access(vs_file, 0)) {
X		read_vs(vs_file, max_row, max_col);
X		skip_row = 0;
X	}
X	else 
X		skip_row = 1;
X
X	hold = 0;
X					/* startup file pointers */
X	if (print)
X		lprfp = popen(LPR, "w");
X
X	if (log && strcmp(log_file, "NOT_DEFINED"))
X		logfp = fopen(log_file, "a");
X
X	switch(setjmp(i_jmp)) {
X		case 0:			/* no signal */
X			break;
X		case 1:			/* toggle the data logging */
X			signal(SIGUSR1, got_sig);
X			if (!strcmp(log_file, "NOT_DEFINED")) {
X				log = 0;
X				break;
X			}
X			log = log ? 0 : 1;
X			if (log)
X				logfp = fopen(log_file, "a");
X			else
X				fclose(logfp);
X			break;
X		case 2:			/* toggle the printer */
X			signal(SIGUSR2, got_sig);
X			print = print ? 0 : 1;
X			if (print)
X				lprfp = popen(LPR, "w");
X			else {
X				putc(014, lprfp);
X				pclose(lprfp);
X			}
X			break;
X		case 3:			/* suspend the input */
X			signal(SIGINT, got_sig);
X			hold = hold ? 0 : 1;
X			if (hold)
X				write_vs(vs_file, max_row, max_col);
X			break;
X		case 4:			/* cleanup and go home */
X			signal(SIGTERM, got_sig);
X			if (log)
X				fclose(logfp);
X			if (print) {
X				putc(014, lprfp);
X				pclose(lprfp);
X			}
X			_exit(0);
X			break;
X	}
X					/* any signal will awaken pause() */
X	if (hold)
X		pause();
X					/* clear if vs_path doesn't exist */
X	if (access(vs_file, 0))
X		clear_vs(max_row, max_col);
X	/*
X	 * The very first screen we see after dialing has the "Connected to..."
X	 * message at row 0, therefore we start our virtual screen at row 1.
X	 */
X	if (skip_row) {
X		skip_row = 0;
X		row = 1;
X	}
X
X	while(1) {
X		if (read(fd, (char *) &c, 1) <= 0)
X			continue;
X					/* send to logfile */
X		if (log) {
X			if (c == 015 && add_lf)
X				fwrite(&lf, 1, 1, logfp);
X					/* no carriage returns in logfile */
X			if (c != 015)
X				fwrite((char *) &c, 1, 1, logfp);
X		}
X					/* send to printer too ? */
X		if (print)
X			fwrite((char *) &c, 1, 1, lprfp);
X
X					/* put a char in virtual screen */
X		putchar_vs(c, add_lf, max_row, max_col);
X
X		write(1, (char *) &c, 1);
X					/* add LF to CR ? */
X		if (add_lf)
X			write(1, &lf, 1);
X	}
X}
X
X/*
X * Figure out which signal we just received, and fix the return code of
X * the setjmp function above to the proper value.
X */
X
Xint
Xgot_sig(sig)
Xint sig;
X{
X	void longjmp();
X
X	switch(sig) {
X		case SIGUSR1:
X			longjmp(i_jmp, 1);
X		case SIGUSR2:
X			longjmp(i_jmp, 2);
X		case SIGINT:
X			longjmp(i_jmp, 3);
X		case SIGTERM:
X			longjmp(i_jmp, 4);
X	}
X}
X
X/*
X * Put a character in the virtual screen.  This routine saves incoming
X * character in a two dimensional buffer designed to mimic the real
X * screen.  CURRENTLY DOES NOT UNDERSTAND ESCAPE SEQUENCES!
X */
X
Xint
Xputchar_vs(c, add_lf, max_row, max_col)
Xunsigned char c;
Xint add_lf, max_row, max_col;
X{
X	int tab_stop;
X
X	switch(c) {
X		case 8:			/* destructive back space */
X			col--;
X			if (col < 0)
X				col = 0;
X			vs[row][col] = ' ';
X			break;
X		case 9:			/* tab character */
X			tab_stop = col + 8 - (col % 8);
X					/* if wrap around */
X			if (tab_stop >= max_col) {
X					/* spaces up to eol */
X				for (; col<max_col; col++)
X					vs[row][col] = ' ';
X				row++;
X				if (row >= max_row)
X					scroll_vs(max_row, max_col);
X
X					/* the remainder of the tab */
X				col = tab_stop - max_col;
X			}
X			else {
X				for (; col<tab_stop; col++)
X					vs[row][col] = ' ';
X			}
X			break;
X		case 13:		/* carriage return */
X			col = 0;
X			if (!add_lf)
X				break;
X			/* fall thru...*/
X		case 10:		/* line feed */
X			row++;
X			if (row >= max_row)
X				scroll_vs(max_row, max_col);
X			break;
X		default:		/* a normal character */
X			vs[row][col] = c;
X			col++;
X					/* wrap around */
X			if (col >= max_col) {
X				col = 0;
X				row++;
X				if (row >= max_row)
X					scroll_vs(max_row, max_col);
X			}
X			break;
X	}
X	return;
X}
X
X/*
X * Save the virtual screen to a file.
X */
X
Xint
Xwrite_vs(vs_file, max_row, max_col)
Xchar *vs_file;
Xint max_row, max_col;
X{
X	FILE *fp;
X	int i;
X
X	if (!(fp = fopen(vs_file, "w")))
X		return(1);
X					/* current x y coordinates */
X	fprintf(fp, "%d,%d\n", row, col);
X
X	for (i=0; i<max_row; i++) {
X		vs[i][max_col] = NULL;
X		fprintf(fp, "%s\n", vs[i]);
X	}
X	fclose(fp);
X	return(0);
X}
X
X/*
X * Get the virtual screen image from the file.  Since input() gets
X * killed from time to time, the vs_path file is the only way to retain
X * the screen image.
X */
X
Xint
Xread_vs(vs_file, max_row, max_col)
Xchar *vs_file;
Xint max_row, max_col;
X{
X	FILE *fp;
X	int i;
X	char buf[10];
X				/* in case the fopen fails... */
X	row = 0;
X	col = 0;
X				/* not guaranteed to exist yet */
X	if (!(fp = fopen(vs_file, "r")))
X		return(1);
X				/* get the x, y coordinates */
X	fgets(buf, 10, fp);
X	scanf(buf, "%d,%d\n", &row, &col);
X
X				/* read the file into the vs array */
X	for (i=0; i<max_row; i++) {
X		fgets((char *) vs[i], MAX_COL+2, fp);
X		vs[i][max_col] = NULL;
X	}
X
X	fclose(fp);
X	return(0);
X}
X
X/*
X * If the user clears the screen with the ^A-C command, the input
X * has to be in sync.  The way it gets notified, is that the vs_path
X * file disappears.
X */
X
Xint
Xclear_vs(max_row, max_col)
Xint max_row, max_col;
X{
X	int i, j;
X
X	for (i=0; i<max_row; i++) {
X		vs[i][max_col] = NULL;
X		for (j=0; j<max_col; j++)
X			vs[i][j] = ' ';
X	}
X					/* home the "cursor" */
X	row = 0;
X	col = 0;
X	return(0);
X}
X
X/*
X * Do a software scroll on the virtual screen.  Does not alter the
X * 'col' variable.
X */
X
Xint
Xscroll_vs(max_row, max_col)
Xint max_row, max_col;
X{
X	int i, j;
X	char *strcpy();
X					/* move 'em up 1 line */
X	for (i=0; i<max_row-1; i++)
X		strcpy((char *) vs[i], (char *) vs[i+1]);
X					/* clear the bottom line */
X	for (j=0; j<max_col; j++)
X		vs[max_row-1][j] = ' ';
X
X	row = max_row -1;
X	return(0);
X}
SHAR_EOF
if test 6599 -ne "`wc -c < 'input.c'`"
then
	echo shar: "error transmitting 'input.c'" '(should have been 6599 characters)'
fi
fi
echo shar: "extracting 'line_set.c'" '(2130 characters)'
if test -f 'line_set.c'
then
	echo shar: "will not over-write existing file 'line_set.c'"
else
sed 's/^X//' << \SHAR_EOF > 'line_set.c'
X/*
X * Change the communication line settings to the new values.
X */
X
X#include <stdio.h>
X#include <termio.h>
X#include "dial_dir.h"
X#include "param.h"
X#include "status.h"
X
Xvoid
Xline_set()
X{
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 (status->fd == -1)
X		return;
X					/* get the current settings */
X	ioctl(status->fd, TCGETA, &tbuf);
X					/* set some beginning values */
X	tbuf.c_cc[4] = 1;
X	tbuf.c_cc[5] = 0;
X	tbuf.c_oflag = 0;
X	tbuf.c_iflag = 0;
X	tbuf.c_cflag = (CREAD|HUPCL);
X	tbuf.c_lflag = 0;
X
X	/*
X	 * I don't think there's any need for output flow control... (I don't
X	 * know about you guys, but I can't type faster than the host can
X	 * receive!)  Besides, the file transfers reset this anyway.
X	 */
X	if (*param->flow == 'X')
X		tbuf.c_iflag |= 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			/*
X			 * Be careful here... some systems use EXTA in lieu
X			 * of B19200.
X			 */
X			tbuf.c_cflag |= 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(status->fd, TCSETA, &tbuf);
X	ioctl(status->fd, TCFLSH, 2);
X	return;
X}
SHAR_EOF
if test 2130 -ne "`wc -c < 'line_set.c'`"
then
	echo shar: "error transmitting 'line_set.c'" '(should have been 2130 characters)'
fi
fi
echo shar: "extracting 'list_dir.c'" '(1479 characters)'
if test -f 'list_dir.c'
then
	echo shar: "will not over-write existing file 'list_dir.c'"
else
sed 's/^X//' << \SHAR_EOF > 'list_dir.c'
X/*
X * Do a shell escape with an 'ls' command
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "misc.h"
X
Xvoid
Xlist_dir(fd)
Xint fd;
X{
X	WINDOW *ls_win, *newwin();
X	FILE *pfp, *native_popen();
X	int lines, oops;
X	char *ans, *cwd, *getcwd(), buf[200], *get_str();
X
X	ls_win = newwin(6, 70, 8, 5);
X
X	cwd = getcwd(buf, 200);
X
X	mvwprintw(ls_win, 2, 4, "Current directory: %s", cwd);
X	mvwaddstr(ls_win, 3, 4, "File spec (wildcards allowed): ");
X	box(ls_win, '|', '-');
X
X	mvwattrstr(ls_win, 0, 3, A_BOLD, " List Directory ");
X	wmove(ls_win, 3, 35);
X	wrefresh(ls_win);
X
X	if ((ans = get_str(ls_win, 60, NULL, NULL)) == NULL) {
X		if (fd == -1) {
X			werase(ls_win);
X			wrefresh(ls_win);
X		}
X		delwin(ls_win);
X		return;
X	}
X					/* popen() an ls */
X	sprintf(buf, "ls -aC %s", ans);
X	pfp = native_popen(buf, "r");
X					/* make a bigger window */
X	werase(ls_win);
X	wrefresh(ls_win);
X	delwin(ls_win);
X	ls_win = newwin(LINES-1, COLS, 0, 0);
X
X	oops = 0;
X	lines = 0;
X	while (fgets(buf, BUFSIZ, pfp) != NULL) {
X		waddstr(ls_win, buf);
X		lines++;
X		if (lines == LINES-2) {
X			lines = 0;
X			mvwaddstr(ls_win, LINES-2, 28, "Press any key for more");
X			wrefresh(ls_win);
X			if (wgetch(ls_win) == 27) {
X				oops++;
X				break;
X			}
X			werase(ls_win);
X			wrefresh(ls_win);
X		}
X	}
X	native_pclose(pfp);
X
X	if (!oops) {
X		mvwaddstr(ls_win, LINES-2, 25, "Press any key to continue");
X		wrefresh(ls_win);
X		wgetch(ls_win);
X	}
X	if (fd == -1) {
X		werase(ls_win);
X		wrefresh(ls_win);
X	}
X	delwin(ls_win);
X	return;
X}
SHAR_EOF
if test 1479 -ne "`wc -c < 'list_dir.c'`"
then
	echo shar: "error transmitting 'list_dir.c'" '(should have been 1479 characters)'
fi
fi
echo shar: "extracting 'ls_menu.c'" '(4820 characters)'
if test -f 'ls_menu.c'
then
	echo shar: "will not over-write existing file 'ls_menu.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ls_menu.c'
X/*
X * Routines for displaying current line settings and prompting for changes.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X
X/*
X * Display the current line settings and prompt for changes.  A return
X * code of 1 means settings were changed.
X */
X
Xint
Xline_set_menu(fd)
Xint fd;
X{
X	WINDOW *l_win, *newwin();
X	int num, ret_code;
X	void disp_settings();
X
X	l_win = newwin(20, 47, 0, 16);
X
X	mvwattrstr(l_win, 1, 16, A_BOLD, "Line Settings");
X	waddstr(l_win, "\n----------------------------------------------");
X	mvwaddstr(l_win, 6, 5, "1)     300,E,7,1     7)     300,N,8,1");
X	mvwaddstr(l_win, 7, 5, "2)    1200,E,7,1     8)    1200,N,8,1");
X	mvwaddstr(l_win, 8, 5, "3)    2400,E,7,1     9)    2400,N,8,1");
X	mvwaddstr(l_win, 9, 5, "4)    4800,E,7,1    10)    4800,N,8,1");
X	mvwaddstr(l_win, 10, 5, "5)    9600,E,7,1    11)    9600,N,8,1");
X	mvwaddstr(l_win, 11, 5, "6)   19200,E,7,1    12)   19200,N,8,1");
X	mvwaddstr(l_win, 13, 4, "Parity        Data Bits       Stop Bits");
X	mvwaddstr(l_win, 14, 4, "13) Odd       14) 7 bits      16) 1 bit");
X	mvwaddstr(l_win, 15, 18, "15) 8 bits      17) 2 bits");
X	mvwaddstr(l_win, 17, 4, "18) Save Changes");
X	mvwattrstr(l_win, 17, 28, A_BOLD, "YOUR CHOICE:");
X	wmove(l_win, 17, 41);
X	box(l_win, '|', '-');
X
X	mvwaddstr(l_win, 19, 14, " Press ESC to return ");
X					/* display current settings */
X	disp_settings(l_win);
X	wmove(l_win, 17, 41);
X	wrefresh(l_win);
X					/* get the options */
X	ret_code = 0;
X	while ((num = get_num(l_win, 2)) != -1) {
X		switch(num) {
X			case 1:
X				dir->baud[dir->d_cur] = 300;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 2:
X				dir->baud[dir->d_cur] = 1200;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 3:
X				dir->baud[dir->d_cur] = 2400;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 4:
X				dir->baud[dir->d_cur] = 4800;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 5:
X				dir->baud[dir->d_cur] = 9600;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 6:
X				dir->baud[dir->d_cur] = 19200;
X				dir->parity[dir->d_cur] = 'E';
X				dir->dbits[dir->d_cur] = 7;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 7:
X				dir->baud[dir->d_cur] = 300;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 8:
X				dir->baud[dir->d_cur] = 1200;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 9:
X				dir->baud[dir->d_cur] = 2400;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 10:
X				dir->baud[dir->d_cur] = 4800;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 11:
X				dir->baud[dir->d_cur] = 9600;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 12:
X				dir->baud[dir->d_cur] = 19200;
X				dir->parity[dir->d_cur] = 'N';
X				dir->dbits[dir->d_cur] = 8;
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 13:
X				dir->parity[dir->d_cur] = 'O';
X				break;
X			case 14:
X				dir->dbits[dir->d_cur] = 7;
X				break;
X			case 15:
X				dir->dbits[dir->d_cur] = 8;
X				break;
X			case 16:
X				dir->sbits[dir->d_cur] = 1;
X				break;
X			case 17:
X				dir->sbits[dir->d_cur] = 2;
X				break;
X			case 18:
X					/* copy the current settings */
X				param->d_baud = dir->baud[dir->d_cur];
X				param->d_parity = dir->parity[dir->d_cur];
X				param->d_dbits = dir->dbits[dir->d_cur];
X				param->d_sbits = dir->sbits[dir->d_cur];
X				/*
X				 * We've changed the values in memory even
X				 * if the update fails.
X				 */
X				if (update_param()) {
X					touchwin(l_win);
X					wrefresh(l_win);
X				}
X				break;
X			default:
X				beep();
X		}
X		ret_code++;
X		disp_settings(l_win);
X		mvwaddstr(l_win, 17, 41, "    ");
X		wmove(l_win, 17, 41);
X		wrefresh(l_win);
X	}
X	if (fd == -1) {
X		werase(l_win);
X		wrefresh(l_win);
X	}
X	delwin(l_win);
X	return(ret_code);
X}
X
X/*
X * Display the current settings.  Formats the entire string at one
X * time, in case you've got a magic cookie terminal.
X */
X
Xvoid
Xdisp_settings(win)
XWINDOW *win;
X{
X	char buf[40];
X	extern int xmc;
X
X	sprintf(buf, "Current Settings: %5d,%c,%d,%d", dir->baud[dir->d_cur],
X	 dir->parity[dir->d_cur], dir->dbits[dir->d_cur],
X	 dir->sbits[dir->d_cur]);
X
X	if (xmc > 0) {
X		touchwin(win);
X		clear_line(win, 4, 8, 1);
X		wrefresh(win);
X	}
X	mvwattrstr(win, 4, 8, A_BOLD, buf);
X	return;
X}
SHAR_EOF
if test 4820 -ne "`wc -c < 'ls_menu.c'`"
then
	echo shar: "error transmitting 'ls_menu.c'" '(should have been 4820 characters)'
fi
fi
echo shar: "extracting 'm_lib.c'" '(9489 characters)'
if test -f 'm_lib.c'
then
	echo shar: "will not over-write existing file 'm_lib.c'"
else
sed 's/^X//' << \SHAR_EOF > 'm_lib.c'
X/*
X * Routines to manipulate the pcomm.modem file
X */
X
X#include <stdio.h>
X#include "modem.h"
X#include "status.h"
X
X/*
X * Read the modem database file.  Returns a pointer to a static area
X * containing the MODEM structure.  All modem entries and all tty entries
X * are created reguardless of the number of physical entries in the file.
X */
X
Xstruct MODEM *
Xread_modem()
X{
X	FILE *fp;
X	int i, tty, mod, line, oops, m_line, start, stop;
X	char *strdup(), buf[200], message[80], token[40], *str_tok(), *str;
X	char *temp_token, *t_sep, *m_sep, *m_letter;
X	static struct MODEM m;
X	void error_win();
X	extern char *null_ptr;
X
X	if (!(fp = fopen(status->m_path, "r"))) {
X		sprintf(buf, "'%s' for read", status->m_path);
X		error_win(1, "Can't open modem file", buf);
X	}
X
X	t_sep = ";;\n";
X	m_sep = ";;;;\n;;;;;\n;;;\n";
X	m_letter = "abc";
X	oops = 0;
X	tty = 0;
X	mod = 0;
X	line = 0;
X	m_line = 0;
X	while (fgets(buf, 200, fp) != NULL) {
X		line++;
X		if (tty >= NUM_TTY || mod >= NUM_MODEM)
X			break;
X					/* get the token */
X		if (!(temp_token = str_tok(buf, '='))) {
X			sprintf(message, "is missing a token at line %d", line);
X			oops++;
X			break;
X		}
X		if (*temp_token != 'T' && *temp_token != 'M') {
X			sprintf(message, "is corrupted at line %d", line);
X			oops++;
X			break;
X		}
X					/* the tty database */
X		if (*temp_token == 'T') {
X			/*
X			 * This is similar to the "real" strtok() command
X			 * but this one returns a null pointer on a missing
X			 * attribute.  Note the use of the field separator
X			 * array.
X			 */
X			for (i=0; i<3; i++) {
X				if (!(str = str_tok((char *) NULL, t_sep[i]))) {
X					sprintf(message, "is missing a parameter at line %d", line);
X					oops++;
X					break;
X				}
X				switch(i) {	
X					case 0:
X						m.tty[tty] = strdup(str);
X						break;
X					case 1:
X						m.tname[tty] = strdup(str);
X						break;
X					case 2:
X						m.mbaud[tty] = atoi(str);
X						break;
X				}
X			}
X			if (oops)
X				break;
X					/* sanity checking */
X			sprintf(token, "TTY_%d", tty+1);
X			if (strcmp(token, temp_token)) {
X				sprintf(message, "is corrupted at line %d", line);
X				oops++;
X				break;
X			}
X			tty++;
X			continue;
X		}
X					/* the modem database */
X		else {
X			sprintf(token, "MODEM_%d%c", mod+1, m_letter[m_line]);
X			if (strcmp(token, temp_token)) {
X				sprintf(message, "is corrupted at line %d", line);
X				oops++;
X				break;
X			}
X			/*
X			 * There are three lines to the modem database.  They
X			 * distinguished by the letters a, b, and, c appended
X			 * to the entry number.
X			 */
X			switch(m_line) {
X				case 0:
X					start = 0;
X					stop = 5;
X					break;
X				case 1:
X					start = 5;
X					stop = 11;
X					break;
X				case 2:
X					start = 11;
X					stop = 15;
X					break;
X			}
X			for (i=start; i<stop; i++) {
X				if (!(str = str_tok((char *) NULL, m_sep[i]))) {
X					sprintf(message, "is missing a parameter at line %d", line);
X					oops++;
X					break;
X				}
X				switch(i) {
X					case 0:
X						m.mname[mod] = strdup(str);
X						break;
X					case 1:
X						m.init[mod] = strdup(str);
X						break;
X					case 2:
X						m.dial[mod] = strdup(str);
X						break;
X					case 3:
X						m.suffix[mod] = strdup(str);
X						break;
X					case 4:
X						m.hangup[mod] = strdup(str);
X						break;
X					case 5:
X						m.con_3[mod] = strdup(str);
X						break;
X					case 6:
X						m.con_12[mod] = strdup(str);
X						break;
X					case 7:
X						m.con_24[mod] = strdup(str);
X						break;
X					case 8:
X						m.con_48[mod] = strdup(str);
X						break;
X					case 9:
X						m.con_96[mod] = strdup(str);
X						break;
X					case 10:
X						m.con_192[mod] = strdup(str);
X						break;
X					case 11:
X						m.no_con1[mod] = strdup(str);
X						break;
X					case 12:
X						m.no_con2[mod] = strdup(str);
X						break;
X					case 13:
X						m.no_con3[mod] = strdup(str);
X						break;
X					case 14:
X						m.no_con4[mod] = strdup(str);
X						break;
X				}
X			}
X			if (oops)
X				break;
X			m_line++;
X			if (m_line >= 3) {
X				m_line = 0;
X				mod++;
X			}
X		}
X	}
X	fclose(fp);
X
X	if (oops) {
X		sprintf(buf, "Modem file '%s'", status->m_path);
X		error_win(1, buf, message);
X	}
X	m.t_entries = tty;
X	m.m_entries = mod;
X	m.t_cur = -1;
X	m.m_cur = -1;
X					/* fill in the rest */
X	for (; tty<NUM_TTY; tty++) {
X		m.tty[tty] = null_ptr;
X		m.tname[tty] = null_ptr;
X		m.mbaud[tty] = 0;
X	}
X	for (; mod<NUM_MODEM; mod++) {
X		m.mname[mod] = null_ptr;
X		m.init[mod] = null_ptr;
X		m.dial[mod] = null_ptr;
X		m.suffix[mod] = null_ptr;
X		m.hangup[mod] = null_ptr;
X
X		m.con_3[mod] = null_ptr;
X		m.con_12[mod] = null_ptr;
X		m.con_24[mod] = null_ptr;
X		m.con_48[mod] = null_ptr;
X		m.con_96[mod] = null_ptr;
X		m.con_192[mod] = null_ptr;
X
X		m.no_con1[mod] = null_ptr;
X		m.no_con2[mod] = null_ptr;
X		m.no_con3[mod] = null_ptr;
X		m.no_con4[mod] = null_ptr;
X	}
X	return(&m);
X}
X
X/*
X * Update the modem database.  Other routines actually do the changes
X * or deletions in memory.  A return code of 1 means non-fatal error.
X */
X
Xint
Xupdate_modem()
X{
X	FILE *fp;
X	char buf[80];
X	int i;
X	void error_win();
X
X					/* open for write */
X	if (!(fp = fopen(status->m_path, "w"))) {
X		sprintf(buf, "'%s'", status->m_path);
X		error_win(0, "No write permission on modem file", buf);
X		return(1);
X	}
X					/* put back the tty entries */
X	for (i=0; i<modem->t_entries; i++)
X		fprintf(fp, "TTY_%d=%s;%s;%d\n", i+1, modem->tty[i],
X		 modem->tname[i], modem->mbaud[i]);
X
X					/* put back the modem entries */
X	for (i=0; i<modem->m_entries; i++) {
X		fprintf(fp, "MODEM_%da=%s;%s;%s;%s;%s\n", i+1, modem->mname[i],
X		 modem->init[i], modem->dial[i], modem->suffix[i],
X		 modem->hangup[i]);
X
X		fprintf(fp, "MODEM_%db=%s;%s;%s;%s;%s;%s\n", i+1,
X		 modem->con_3[i], modem->con_12[i], modem->con_24[i],
X		 modem->con_48[i], modem->con_96[i], modem->con_192[i]);
X
X		fprintf(fp, "MODEM_%dc=%s;%s;%s;%s\n", i+1, modem->no_con1[i],
X		 modem->no_con2[i], modem->no_con3[i], modem->no_con4[i]);
X	}
X
X	fclose(fp);
X	return(0);
X}
X
X/*
X * See if the new modem is already in the database.  If it's not,
X * then create a slot for it and update the modem->m_cur variable.
X */
X
Xvoid
Xcreate_modem(str)
Xchar *str;
X{
X	int i;
X	char *strdup(), buf[80];
X	void error_win(), free_ptr();
X					/* modem entry already exists? */
X	for (i=0; i<modem->m_entries; i++) {
X		if (!strcmp(str, modem->mname[i]))
X			return;
X	}
X					/* empty slot available? */
X	if (modem->m_entries == NUM_MODEM) {
X		sprintf(buf, "'%s'", status->m_path);
X		error_win(0, "No empty modem slots in", buf);
X		return;
X	}
X					/* create a new entry */
X	free_ptr(modem->mname[modem->m_entries]);
X	modem->mname[modem->m_entries] = strdup(str);
X
X					/* update number of entries */
X	modem->m_entries++;
X	return;
X}
X
X/*
X * See if the modem names in the list still need to be in the database.
X * If you find a "lost" entry, delete it and collapse the list.
X */
X
Xvoid
Xdelete_modem()
X{
X	int i, j, match;
X	char *strdup();
X	void free_ptr();
X	extern char *null_ptr;
X
X	for (i=0; i<modem->m_entries; i++) {
X		match = 0;
X		for (j=0; j<modem->t_entries; j++) {
X			if (!strcmp(modem->mname[i], modem->tname[j])) {
X				match = 1;
X				break;
X			}
X		}
X					/* found a "lost" modem name */
X		if (!match) {
X			for (j=i; j<modem->m_entries-1; j++) {
X				free_ptr(modem->mname[j]);
X				free_ptr(modem->init[j]);
X				free_ptr(modem->dial[j]);
X				free_ptr(modem->suffix[j]);
X				free_ptr(modem->hangup[j]);
X
X				free_ptr(modem->con_3[j]);
X				free_ptr(modem->con_12[j]);
X				free_ptr(modem->con_24[j]);
X				free_ptr(modem->con_48[j]);
X				free_ptr(modem->con_96[j]);
X				free_ptr(modem->con_192[j]);
X
X				free_ptr(modem->no_con1[j]);
X				free_ptr(modem->no_con2[j]);
X				free_ptr(modem->no_con3[j]);
X				free_ptr(modem->no_con4[j]);
X
X					/* copy the info */
X				modem->mname[j] = strdup(modem->mname[j+1]);
X				modem->init[j] = strdup(modem->init[j+1]);
X				modem->dial[j] = strdup(modem->dial[j+1]);
X				modem->suffix[j] = strdup(modem->suffix[j+1]);
X				modem->hangup[j] = strdup(modem->hangup[j+1]);
X
X				modem->con_3[j] = strdup(modem->con_3[j+1]);
X				modem->con_12[j] = strdup(modem->con_12[j+1]);
X				modem->con_24[j] = strdup(modem->con_24[j+1]);
X				modem->con_48[j] = strdup(modem->con_48[j+1]);
X				modem->con_96[j] = strdup(modem->con_96[j+1]);
X				modem->con_192[j] = strdup(modem->con_192[j+1]);
X
X				modem->no_con1[j] = strdup(modem->no_con1[j+1]);
X				modem->no_con2[j] = strdup(modem->no_con2[j+1]);
X				modem->no_con3[j] = strdup(modem->no_con3[j+1]);
X				modem->no_con4[j] = strdup(modem->no_con4[j+1]);
X			}
X			j = modem->m_entries -1;
X
X			free_ptr(modem->mname[j]);
X			free_ptr(modem->init[j]);
X			free_ptr(modem->dial[j]);
X			free_ptr(modem->suffix[j]);
X			free_ptr(modem->hangup[j]);
X
X			free_ptr(modem->con_3[j]);
X			free_ptr(modem->con_12[j]);
X			free_ptr(modem->con_24[j]);
X			free_ptr(modem->con_48[j]);
X			free_ptr(modem->con_96[j]);
X			free_ptr(modem->con_192[j]);
X
X			free_ptr(modem->no_con1[j]);
X			free_ptr(modem->no_con2[j]);
X			free_ptr(modem->no_con3[j]);
X			free_ptr(modem->no_con4[j]);
X
X					/* create an empty entry */
X			modem->mname[j] = null_ptr;
X			modem->init[j] = null_ptr;
X			modem->dial[j] = null_ptr;
X			modem->suffix[j] = null_ptr;
X			modem->hangup[j] = null_ptr;
X
X			modem->con_3[j] = null_ptr;
X			modem->con_12[j] = null_ptr;
X			modem->con_24[j] = null_ptr;
X			modem->con_48[j] = null_ptr;
X			modem->con_96[j] = null_ptr;
X			modem->con_192[j] = null_ptr;
X
X			modem->no_con1[j] = null_ptr;
X			modem->no_con2[j] = null_ptr;
X			modem->no_con3[j] = null_ptr;
X			modem->no_con4[j] = null_ptr;
X
X					/* update the counts */
X			modem->m_entries--;
X			if (modem->m_cur >= modem->m_entries)
X				modem->m_cur = -1;
X			return;
X		}
X	}
X	return;
X}
SHAR_EOF
if test 9489 -ne "`wc -c < 'm_lib.c'`"
then
	echo shar: "error transmitting 'm_lib.c'" '(should have been 9489 characters)'
fi
fi
echo shar: "extracting 'main.c'" '(4860 characters)'
if test -f 'main.c'
then
	echo shar: "will not over-write existing file 'main.c'"
else
sed 's/^X//' << \SHAR_EOF > 'main.c'
X/*
X * Pcomm is a public domain telecommunication program for Unix
X * designed to operate similar to the popular MSDOS program, ProComm.
X * ProComm (TM) is copyrighted by Datastorm Technologies, Inc.
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!ihnp4!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X *					Directorate of Engineering & Housing
X *					Environmental Management Office
X *					Fort Hood, TX 76544-5057
X *	Beta release	 7 Feb 88
X *	Release 1.0	12 Mar 88
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#ifndef OLDCURSES
X#include <term.h>
X#endif /* OLDCURSES */
X#include <sys/types.h>
X#include <sys/stat.h>
X#define MAIN
X#include "dial_dir.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
X#ifdef OLDCURSES
Xchar bp[1024];
X#define cbreak crmode
X#endif /* OLDCURSES */
X
Xstruct PARAM *param;
Xstruct DIAL_DIR *dir;
Xstruct STATUS *status;
Xstruct MODEM *modem;
Xint xmc;
Xchar *null_ptr;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int c, ret_code, i, code, quit();
X	char *mytty, *ttyname(), *term, *getenv(), *index, *strdup();
X	char *extra_dir, buf[80], message[80];
X	struct PARAM *read_param();
X	struct DIAL_DIR *read_dir();
X	struct STATUS *init();
X	struct MODEM *read_modem();
X	struct stat stbuf;
X	void exit(), error_win(), input_on(), free_ptr();
X	extern char *optarg;
X#ifdef OLDCURSES
X	char *tgetstr(), ocbuf[20];
X	char *ocbufptr = ocbuf;
X#endif /* OLDCURSES */
X
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGTERM, quit);
X	signal(SIGHUP, quit);
X
X	null_ptr = "";
X	index = NULL;
X	extra_dir = NULL;
X					/* the command line */
X	while ((c = getopt(argc, argv, "d:f:")) != EOF) {
X		switch (c) {
X			case 'd':	/* the extra directory to search */
X				extra_dir = strdup(optarg);
X				break;
X			case 'f':	/* the index into the dialing dir */
X				index = strdup(optarg);
X				break;
X			case '?':	/* default */
X				fprintf(stderr, "Usage: pcomm [-d directory] [-f index]\n");
X				exit(1);
X				break;
X		}
X	}
X					/* get terminal type */
X	term = getenv("TERM");
X	if (term == NULL || *term == NULL) {
X		fprintf(stderr, "Windows not supported (TERM not defined)\n");
X		exit(1);
X	}
X					/* see if terminfo entry exists */
X#ifdef OLDCURSES
X	ret_code = tgetent(bp, term);
X#else /* OLDCURSES */
X	setupterm(term, 1, &ret_code);
X#endif /* OLDCURSES */
X	if (ret_code != 1) {
X		fprintf(stderr, "Windows not supported (no terminfo data for '%s')\n", term);
X		exit(1);
X	}
X					/* minimum screen size */
X#ifdef OLDCURSES
X	if (tgetnum("co") < 80 || tgetnum("li") < 24) {
X#else /* OLDCURSES */
X	if (columns < 80 || lines < 24) {
X#endif /* OLDCURSES */
X		fprintf(stderr, "Windows not supported (minimum 80x24 screen required)\n");
X		exit(1);
X	}
X					/* must have cursor movement */
X#ifdef OLDCURSES
X	if (tgetstr("cm", &ocbufptr) == NULL) {
X#else /* OLDCURSES */
X	if (cursor_address == NULL) {
X#endif /* OLDCURSES */
X		fprintf(stderr, "Windows not supported (terminal too dumb)\n");
X		exit(1);
X	}
X					/* load magic cookie variable */
X#ifdef OLDCURSES
X	xmc = tgetnum("sg");
X#else /* OLDCURSES */
X	xmc = magic_cookie_glitch;
X#endif /* OLDCURSES */
X					/* ok... now lets go! */
X	initscr();
X	nonl();
X	cbreak();
X	noecho();
X
X	param = (struct PARAM *) NULL;
X	modem = (struct MODEM *) NULL;
X	dir = (struct DIAL_DIR *) NULL;
X					/* show the herald, return status */
X	status = init(extra_dir, index);
X					/* get 'msgs' status */
X	mytty = ttyname(0);
X	stat(mytty, &stbuf);
X	chmod(mytty, 0600);
X	status->msg = stbuf.st_mode & 0777;
X					/* read the support files */
X	param = read_param();
X	dir = read_dir();
X	modem = read_modem();
X					/* short-cut to dialing window ? */
X	code = 0;
X	if (index != NULL) {
X		for (i=1; i<dir->d_entries+1; i++) {
X			if (!strcmp(dir->index[i], index)) {
X				dir->q_num[0] = i;
X				dir->d_cur = i;
X				break;
X			}
X		}
X					/* if match is found */
X		if (dir->q_num[0] != -1)
X			code = dial_win();
X		else {
X			sprintf(buf, "Can't find index '%s' in dialing directory file", index);
X			sprintf(message, "'%s'", status->d_path);
X			error_win(0, buf, message);
X		}
X		free_ptr(index);
X	}
X					/* start terminal dialogue */
X	terminal(code);
X	exit(0);
X}
X
X/*
X * Something dreadful happened...  Cleanup the mess we made with the
X * tty driver and release the phone line.
X */
X
Xint
Xquit()
X{
X	void cleanup();
X
X	cleanup(1);
X					/* never returns... */
X	return(0);
X}
X
X/*
X * Check write permission with the real UID and GID.  Returns a 0 on
X * permission denied, 1 on OK, and 2 on OK-but the file already exists.
X */
X
Xint
Xcan_write(file)
Xchar *file;
X{
X	char *p, path[200], *strcpy(), *strrchr();
X
X	p = strcpy(path, file);
X					/* dissect the path component */
X	if (p = strrchr(path, '/'))
X		*(p++) = NULL;
X	else
X		strcpy(path, ".");
X					/* if it already exists */
X	if (!access(file, 0)) {
X		if (!access(file, 2))
X			return(2);
X		return(0);
X	}
X					/* if path is writable */
X	if (!access(path, 2))
X		return(1);
X	return(0);
X}
SHAR_EOF
if test 4860 -ne "`wc -c < 'main.c'`"
then
	echo shar: "error transmitting 'main.c'" '(should have been 4860 characters)'
fi
fi
echo shar: "extracting 'n_shell.c'" '(1369 characters)'
if test -f 'n_shell.c'
then
	echo shar: "will not over-write existing file 'n_shell.c'"
else
sed 's/^X//' << \SHAR_EOF > 'n_shell.c'
X/*
X * Spawn a 'native' shell.  'Native' means the shell found in the SHELL
X * environmental variable.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X
Xvoid
Xnative_shell()
X{
X	WINDOW *sh_win, *newwin();
X	int (*istat)(), (*qstat)(), status, pid, w;
X	char *shell, *shellpath, *getenv(), *strrchr();
X	unsigned int sleep();
X	void _exit();
X					/* a full window */
X	sh_win = newwin(LINES, COLS, 0, 0);
X
X	clear_absolute(sh_win);
X	waddstr(sh_win, "Pcomm <=> Unix gateway, use ^D or 'exit' to return\n");
X	wrefresh(sh_win);
X					/* out of curses mode */
X	resetterm();
X
X	shellpath = getenv("SHELL");
X	if (shellpath == NULL || *shellpath == NULL)
X		shellpath = "/bin/sh";
X
X	shell = strrchr(shellpath, '/') + 1;
X
X	if (!(pid = fork())) {
X#ifdef SGID
X		setgid(getgid());
X#endif /* SGID */
X		execl(shellpath, shell, "-i", 0);
X		_exit(1);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X
X	signal(SIGINT, istat);
X	signal(SIGQUIT, qstat);
X					/* back to curses mode */
X	fixterm();
X	sleep(1);
X
X	clear_absolute(stdscr);
X	delwin(sh_win);
X	return;
X}
X
X/*
X * Clear the screen absolutely!  It's incrediblely hard to get curses() to
X * clear the screen when it thinks its already clear.
X */
X
Xint
Xclear_absolute(win)
XWINDOW *win;
X{
X	clearok(curscr, 1);
X	wrefresh(win);
X	clearok(curscr, 0);
X	return(0);
X}
SHAR_EOF
if test 1369 -ne "`wc -c < 'n_shell.c'`"
then
	echo shar: "error transmitting 'n_shell.c'" '(should have been 1369 characters)'
fi
fi
echo shar: "extracting 'p_lib.c'" '(5786 characters)'
if test -f 'p_lib.c'
then
	echo shar: "will not over-write existing file 'p_lib.c'"
else
sed 's/^X//' << \SHAR_EOF > 'p_lib.c'
X/*
X * Routines to manipulate the pcomm.param file.
X */
X
X#include <stdio.h>
X#include "param.h"
X#include "status.h"
X
X/*
X * Read the parameter structure from the pcomm.param file.  Returns a
X * pointer to the PARAM structure.  All errors are fatal.
X */
X
Xstruct PARAM *
Xread_param()
X{
X	FILE *fp;
X	int i, oops;
X	char buf[80], *temp_token, *str, *strdup();
X	char message[80], *str_tok();
X	static char *token[NUM_PARAM] = {"D_BAUD", "D_PARITY", "D_DBITS",
X	"D_SBITS", "HOT", "ASCII_HOT", "D_DUPLEX", "FLOW", "CR_IN", "CR_OUT",
X	"LOGFILE", "DUMPFILE", "STRIP", "PAUSE_CHAR", "CR_CHAR", "CTRL_CHAR",
X	"ESC_CHAR", "ABORT", "CDELAY", "PAUSE", "LECHO", "EXPAND", "CR_DELAY",
X	"PACE", "CR_UP", "LF_UP", "TIMER", "CR_DN", "LF_DN", "LD_PLUS",
X	"LD_MINUS", "LD_AT", "LD_POUND"};
X	static struct PARAM p;
X	void error_win();
X					/* read permission already checked */
X	fp = fopen(status->p_path, "r");
X
X	oops = 0;
X	for (i=0; i<NUM_PARAM; i++) {
X		if (fgets(buf, 80, fp) == NULL) {
X			sprintf(message, "is truncated at line %d", i+1);
X			oops++;
X			break;
X		}
X					/* parse the input line */
X		if (!(temp_token = str_tok(buf, '='))) {
X			sprintf(message, "is missing a token at line %d", i+1);
X			oops++;
X			break;
X		}
X		if (!(str = str_tok((char *) NULL, '\n'))) {
X			sprintf(message, "is missing a parameter at line %d", i+1);
X			oops++;
X			break;
X		}
X					/* sanity checking */
X		if (strcmp(temp_token, token[i])) {
X			sprintf(message, "is corrupted at line %d", i+1);
X			oops++;
X			break;
X		}
X
X		switch(i) {
X					/* used in line_set_menu() */
X			case LINE_SET:
X				p.d_baud = atoi(str);
X				break;
X			case LINE_SET+1:
X				p.d_parity = *str;
X				break;
X			case LINE_SET+2:
X				p.d_dbits = atoi(str);
X				break;
X			case LINE_SET+3:
X				p.d_sbits = atoi(str);
X				break;
X
X					/* used in term_setup() */
X			case TERM_SETUP:
X				p.hot = atoi(str);
X				break;
X			case TERM_SETUP+1:
X				p.ascii_hot = strdup(str);
X				break;
X			case TERM_SETUP+2:
X				p.d_duplex = strdup(str);
X				break;
X			case TERM_SETUP+3:
X				p.flow = strdup(str);
X				break;
X			case TERM_SETUP+4:
X				p.cr_in = strdup(str);
X				break;
X			case TERM_SETUP+5:
X				p.cr_out = strdup(str);
X				break;
X
X					/* used in gen_setup() */
X			case GEN_SETUP:
X				p.logfile = strdup(str);
X				break;
X			case GEN_SETUP+1:
X				p.dumpfile = strdup(str);
X				break;
X			case GEN_SETUP+2:
X				p.strip = strdup(str);
X				break;
X			case GEN_SETUP+3:
X				p.pause_char = *str;
X				break;
X			case GEN_SETUP+4:
X				p.cr_char = *str;
X				break;
X			case GEN_SETUP+5:
X				p.ctrl_char = *str;
X				break;
X			case GEN_SETUP+6:
X				p.esc_char = *str;
X				break;
X			case GEN_SETUP+7:
X				p.abort = strdup(str);
X				break;
X
X					/* used in gen_setup() delay_times() */
X			case DELAY_TIMES:
X				p.cdelay = atoi(str);
X				break;
X			case DELAY_TIMES+1:
X				p.pause = atoi(str);
X				break;
X
X					/* used in ascii_xfer_setup() */
X			case ASCII_SETUP:
X				p.lecho = strdup(str);
X				break;
X			case ASCII_SETUP+1:
X				p.expand = strdup(str);
X				break;
X			case ASCII_SETUP+2:
X				p.cr_delay = atoi(str);
X				break;
X			case ASCII_SETUP+3:
X				p.pace = strdup(str);
X				break;
X			case ASCII_SETUP+4:
X				p.cr_up = strdup(str);
X				break;
X			case ASCII_SETUP+5:
X				p.lf_up = strdup(str);
X				break;
X			case ASCII_SETUP+6:
X				p.timer = atoi(str);
X				break;
X			case ASCII_SETUP+7:
X				p.cr_dn = strdup(str);
X				break;
X			case ASCII_SETUP+8:
X				p.lf_dn = strdup(str);
X				break;
X
X					/* used in d_revise() */
X			case LD_CODES:
X				p.ld_plus = strdup(str);
X				break;
X			case LD_CODES+1:
X				p.ld_minus = strdup(str);
X				break;
X			case LD_CODES+2:
X				p.ld_at = strdup(str);
X				break;
X			case LD_CODES+3:
X				p.ld_pound = strdup(str);
X				break;
X		}
X	}
X	fclose(fp);
X	if (oops) {
X		sprintf(buf, "Parameter file '%s'", status->p_path);
X		error_win(1, buf, message);
X	}
X	return(&p);
X}
X
X/*
X * Write the updated param structure to disk.  The values in memory should
X * have already been "purified".  Later, we'll update only the entries that
X * have been explicitly asked for.  A return code of 1 means non-fatal error.
X */
X
Xint
Xupdate_param()
X{
X	FILE *fp;
X	char buf[80];
X	void error_win();
X					/* open for write */
X	if (!(fp = fopen(status->p_path, "w"))) {
X		sprintf(buf, "'%s'", status->p_path);
X		error_win(0, "No write permission on parameter file", buf);
X		return(1);
X	}
X
X	fprintf(fp, "D_BAUD=%d\n", param->d_baud);
X	fprintf(fp, "D_PARITY=%c\n", param->d_parity);
X	fprintf(fp, "D_DBITS=%d\n", param->d_dbits);
X	fprintf(fp, "D_SBITS=%d\n", param->d_sbits);
X	fprintf(fp, "HOT=%d\n", param->hot);
X	fprintf(fp, "ASCII_HOT=%s\n", param->ascii_hot);
X	fprintf(fp, "D_DUPLEX=%s\n", param->d_duplex);
X	fprintf(fp, "FLOW=%s\n", param->flow);
X	fprintf(fp, "CR_IN=%s\n", param->cr_in);
X	fprintf(fp, "CR_OUT=%s\n", param->cr_out);
X	fprintf(fp, "LOGFILE=%s\n", param->logfile);
X	fprintf(fp, "DUMPFILE=%s\n", param->dumpfile);
X	fprintf(fp, "STRIP=%s\n", param->strip);
X	fprintf(fp, "PAUSE_CHAR=%c\n", param->pause_char);
X	fprintf(fp, "CR_CHAR=%c\n", param->cr_char);
X	fprintf(fp, "CTRL_CHAR=%c\n", param->ctrl_char);
X	fprintf(fp, "ESC_CHAR=%c\n", param->esc_char);
X	fprintf(fp, "ABORT=%s\n", param->abort);
X	fprintf(fp, "CDELAY=%d\n", param->cdelay);
X	fprintf(fp, "PAUSE=%d\n", param->pause);
X	fprintf(fp, "LECHO=%s\n", param->lecho);
X	fprintf(fp, "EXPAND=%s\n", param->expand);
X	fprintf(fp, "CR_DELAY=%d\n", param->cr_delay);
X	fprintf(fp, "PACE=%s\n", param->pace);
X	fprintf(fp, "CR_UP=%s\n", param->cr_up);
X	fprintf(fp, "LF_UP=%s\n", param->lf_up);
X	fprintf(fp, "TIMER=%d\n", param->timer);
X	fprintf(fp, "CR_DN=%s\n", param->cr_dn);
X	fprintf(fp, "LF_DN=%s\n", param->lf_dn);
X	fprintf(fp, "LD_PLUS=%s\n", param->ld_plus);
X	fprintf(fp, "LD_MINUS=%s\n", param->ld_minus);
X	fprintf(fp, "LD_AT=%s\n", param->ld_at);
X	fprintf(fp, "LD_POUND=%s\n", param->ld_pound);
X
X	fclose(fp);
X	return(0);
X}
SHAR_EOF
if test 5786 -ne "`wc -c < 'p_lib.c'`"
then
	echo shar: "error transmitting 'p_lib.c'" '(should have been 5786 characters)'
fi
fi
echo shar: "extracting 'pexit.c'" '(2142 characters)'
if test -f 'pexit.c'
then
	echo shar: "will not over-write existing file 'pexit.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pexit.c'
X/*
X * Exit pcomm.  A user requested abort.  There are a lot of things to do
X * before we exit!
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X#include "status.h"
X
Xvoid
Xpexit(fd)
Xint fd;
X{
X	WINDOW *ex_win, *newwin();
X	void cleanup(), status_line();
X
X	ex_win = newwin(5, 33, 3, 7);
X
X	box(ex_win, '|', '-');
X	mvwattrstr(ex_win, 0, 3, A_BOLD, " Exit ");
X	if (yes_prompt(ex_win, 2, 4, A_BLINK, "Exit to Unix")) {
X		status_line("   exiting");
X		cleanup(0);
X	}
X	if (fd == -1) {
X		werase(ex_win);
X		wrefresh(ex_win);
X	}
X	delwin(ex_win);
X	return;
X}
X
X/*
X * Do the cleanup detail before we exit.
X */
X
Xvoid
Xcleanup(val)
Xint val;
X{
X	void release_port(), input_off(), exit(), status_line();
X	char *ttyname();
X					/* kill the input routine */
X	input_off();
X					/* zap the virtual screen file */
X	unlink(status->vs_path);
X					/* release the port */
X	release_port(0);
X					/* erase the window we made */
X	touchwin(stdscr);
X	clear();
X	refresh();
X	endwin();
X					/* return the tty chmod */
X	chmod(ttyname(0), status->msg);
X	exit(val);
X}
X
X/*
X * Open a window to display an error message.  Handles both fatal and
X * non-fatal errors
X */
X
Xvoid
Xerror_win(code, line_one, line_two)
Xint code;
Xchar *line_one, *line_two;
X{
X	WINDOW *e_win, *newwin();
X	void cleanup(), status_line();
X
X	e_win = newwin(7, 70, 9, 5);
X					/* display the nasty note */
X	mvwaddstr(e_win, 2, 4, line_one);
X	mvwaddstr(e_win, 3, 4, line_two);
X	box(e_win, '|', '-');
X
X	if (code) {
X		mvwattrstr(e_win, 0, 4, A_BOLD, " Error ");
X		mvwattrstr(e_win, 5, 24, A_BLINK, "Press any key to exit");
X		wmove(e_win, 5, 46);
X	}
X	else {
X		mvwattrstr(e_win, 0, 4, A_BOLD, " Warning ");
X		mvwattrstr(e_win, 5, 22, A_BLINK, "Press any key to continue");
X		wmove(e_win, 5, 48);
X	}
X	beep();
X	wrefresh(e_win);
X
X	wgetch(e_win);
X	werase(e_win);
X	wrefresh(e_win);
X	delwin(e_win);
X
X	if (code) {
X		/*
X		 * Since this routine gets called if there is an error reading
X		 * the support files, the dir and param structures can't be
X		 * guaranteed to exist yet.
X		 */
X		if (dir != NULL && param != NULL)
X			status_line("   exiting");
X		cleanup(code);
X	}
X	return;
X}
SHAR_EOF
if test 2142 -ne "`wc -c < 'pexit.c'`"
then
	echo shar: "error transmitting 'pexit.c'" '(should have been 2142 characters)'
fi
fi
echo shar: "extracting 'port.c'" '(6122 characters)'
if test -f 'port.c'
then
	echo shar: "will not over-write existing file 'port.c'"
else
sed 's/^X//' << \SHAR_EOF > 'port.c'
X/*
X * Routines to get or release a tty port.
X */
X
X#define LOCKDIR "/usr/spool/uucp"
X#undef ASCII_PID
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <termio.h>
X#ifdef UNIXPC
X#include <sys/phone.h>
X#endif /* UNIXPC */
X#include "dial_dir.h"
X#include "modem.h"
X#include "status.h"
X
Xint getty_status;
X/*
X * Finds a free (or requested) serial port.  Creates a lock file to hold
X * it for our use.  Loads the modem database.  A return code of 1 means
X * all ports (or the requested port) are busy.
X */
X
Xint
Xget_port()
X{
X	int i, j, k, progpid, fd, list[NUM_TTY];
X	char file[80], buf[80], message[80], *strdup();
X	void error_win(), line_set(), release_port(), send_str();
X	void free_ptr();
X	
X	/*
X	 * If we already have a port, see if it is good enough for the
X	 * current request.
X	 */
X	if (status->fd != -1) {
X		if (!strcmp(dir->index[dir->d_cur], modem->tty[modem->t_cur]) ||
X		 modem->mbaud[modem->t_cur] >= dir->baud[dir->d_cur]) {
X			/*
X			 * Re-initialize the modem because the baud
X			 * rate (or other parameters) may have changed.
X			 */
X			line_set();
X			send_str(modem->init[modem->m_cur]);
X			return(0);
X		}
X	}
X	release_port(1);
X
X	/*
X	 * See if you want a specific tty port.  If the index field in the
X	 * dialing directory is a valid device name, then use that tty.
X	 */
X	sprintf(buf, "/dev/%s", dir->index[dir->d_cur]);
X	list[0] = -1;
X					/* if index is a valid device */
X	if (!access(buf, 0)) {
X		for (i=0; i<modem->t_entries; i++) {
X					/* and it exists in modem database */
X			if (!strcmp(dir->index[dir->d_cur], modem->tty[i])) {
X				list[0] = i;
X				list[1] = -1;
X				break;
X			}
X		}
X	}
X
X	/*
X	 * Create a list of acceptable ttys.  It searches the tty database
X	 * for the requested baud rate.
X	 */
X	k = 0;
X	if (list[0] == -1) {
X		for (i=0; i<modem->t_entries; i++) {
X					/* skip ports with no modems */
X			if (!strcmp(modem->tname[i], "DIRECT"))
X				continue;
X
X					/* can handle requested baud rate ? */
X			if (modem->mbaud[i] >= dir->baud[dir->d_cur])
X				list[k++] = i;
X		}
X					/* the end of list marker */
X		list[k] = -1;
X	}
X					/* empty list ? */
X	if (list[0] == -1) {
X		sprintf(message, "No modem at a %d baud rating exists in", dir->baud[dir->d_cur]);
X		sprintf(file, "modem file '%s'", status->m_path);
X		error_win(0, message, file);
X		return(1);
X	}
X					/* check the list for a free port */	
X	i = 0;
X	while (list[i] != -1) {
X					/* create a lock file name */
X		sprintf(file, "%s/LCK..%s", LOCKDIR, modem->tty[list[i]]);
X
X		/*
X		 * See if the lock file exists... We DO NOT look to see
X		 * if the pid in the file is still active.  Maybe I'll
X		 * change this later...
X		 */
X		if (access(file, 0)) {
X			getty_status = set_getty(modem->tty[list[i]], 0);
X			
X			if ((fd = open(file, O_CREAT|O_WRONLY, 0666)) < 0) {
X				set_getty(modem->tty[list[i]], 1);
X				sprintf(buf, "'%s'", file);
X				error_win(1, "Can't create the lockfile", buf);
X			}
X#ifdef ASCII_PID
X			sprintf(buf, "%10d\n", getpid());
X			write(fd, buf, 11);
X#else /* ASCII_PID */
X			progpid = getpid();
X			write(fd, (char *)&progpid, sizeof(int));
X#endif /* ASCII_PID */
X			close(fd);
X					/* store the new values */
X			free_ptr(status->lock_path);
X			status->lock_path = strdup(file);
X			modem->t_cur = list[i];
X
X					/* open the device (hold DTR high) */
X			sprintf(buf, "/dev/%s", modem->tty[list[i]]);
X			if ((fd = open(buf, O_RDWR|O_NDELAY)) < 0) {
X				set_getty(modem->tty[list[i]], 1);
X				sprintf(file, "Can't open port '%s' for read and write", buf);
X				error_win(1, file, NULL);
X			}
X
X					/* turn off the "no delay" mode */
X			fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NDELAY);
X			status->fd = fd;
X					/* change line settings */
X			line_set();
X					/* load the modem data base */
X			for (j=0; j<modem->m_entries; j++) {
X				if (!strcmp(modem->tname[list[i]], modem->mname[j])) {
X					modem->m_cur = j;
X					break;
X				}
X			}
X					/* initialize the modem */
X			send_str(modem->init[j]);
X			return(0);
X		}
X		i++;
X	}
X	error_win(0, "All ports are busy now, try again later", NULL);
X	return(1);
X}
X
X/*
X * Release the port.  Closes the file descriptor and removes the
X * lock file
X */
X
Xvoid
Xrelease_port(verbose)
Xint verbose;
X{
X	char buf[80];
X	extern char *null_ptr;
X	void free_ptr(), hang_up();
X
X	/*
X	 * The modem structure can't be guaranteed to exist yet.  For example,
X	 * an error in reading one of the other support files would cause
X	 * this routine to be used before the MODEM structure gets allocated.
X	 */
X	if (modem == NULL)
X		return;
X					/* close the port */
X	if (status->fd != -1) {
X		ioctl(status->fd, TCFLSH, 2);
X		/*
X		 * Since HUPCL is set, the close() should drop the DTR and
X		 * hang up the modem (provided you've got the modem to
X		 * respond to DTR).  Since this is not guaranteed, we send
X		 * the hangup string first.
X		 */
X		hang_up(verbose);
X		close(status->fd);
X	}
X					/* remove the lock */
X	if (*status->lock_path != NULL) {
X		if (unlink(status->lock_path)) {
X			sprintf(buf, "'%s'", status->lock_path);
X			error_win(0, "Can't remove the lock file", buf);
X		}
X		free_ptr(status->lock_path);
X		status->lock_path = null_ptr;
X	}
X					/* turn the getty back on? */
X	if (getty_status)
X		set_getty(modem->tty[modem->t_cur], 1);
X					/* cleanup the structure */
X	status->fd = -1;
X	modem->m_cur = -1;
X	modem->t_cur = -1;
X	return;
X}
X
X/*
X * Turn the /etc/getty on or off for the specified port.  A return code
X * of 1 means that the getty was on.  Systems with uugetty or dedicated
X * dialout ports won't need this routine.
X */
X
Xint
Xset_getty(tty, on)
Xchar *tty;
Xint on;
X{
X#ifdef UNIXPC
X	int i, ret_code;
X	char buf[40];
X	unsigned int sleep();
X					/* the last three characters */
X	i = strlen(tty) -3;
X
X	ret_code = 0;
X	if (on) {
X		sprintf(buf, "setgetty %s 1", tty+i);
X		system(buf);
X	}
X	else {
X		sprintf(buf, "setgetty %s 0", tty+i);
X		if (system(buf) == 512)
X			ret_code = 1;
X		sleep(1);
X	}
X	return(ret_code);
X#else /* UNIXPC */
X	/*
X	 * If you don't have one of these cute little routines, you
X	 * might wanna write one.  It should check for an existing lock
X	 * file, edit the /etc/inittab file, and issue an init -q.
X	 * Obviously the program would be suid to root.
X	 */
X	return(0);
X#endif /* UNIXPC */
X}
SHAR_EOF
if test 6122 -ne "`wc -c < 'port.c'`"
then
	echo shar: "error transmitting 'port.c'" '(should have been 6122 characters)'
fi
fi
echo shar: "extracting 'redial.c'" '(2216 characters)'
if test -f 'redial.c'
then
	echo shar: "will not over-write existing file 'redial.c'"
else
sed 's/^X//' << \SHAR_EOF > 'redial.c'
X/*
X * The redial option (actually a misnomer, it's really a queuing system).
X * We expect a space-separated list of dialing directory entries (although
X * new users always try to put in a phone number).  A return code of 1
X * means we're ready to dial.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "dial_dir.h"
X#include "misc.h"
X
Xint
Xredial(fd)
Xint fd;
X{
X	WINDOW *rd_win, *newwin();
X	char *ans, *entry, *get_str(), *strchr(), *strtok();
X	int i, oops, number, ret_code;
X	
X	rd_win = newwin(6, 70, 5, 5);
X
X	mvwaddstr(rd_win, 4, 23, "(CR for previous numbers)");
X	mvwaddstr(rd_win, 2, 4, "Directory Entry Number(s): ");
X	box(rd_win, '|', '-');
X
X	mvwattrstr(rd_win, 0, 3, A_BOLD, " Redial Queue ");
X	wmove(rd_win, 2, 31);
X	wrefresh(rd_win);
X					/* get the string of numbers */
X	ret_code = 0;
X	while ((ans = get_str(rd_win, 35, "0123456789+-@# ", NULL)) != NULL) {
X		oops = 0;
X		if (*ans == NULL) {
X					/* use previous queue */
X			if (dir->q_num[0] != -1) {
X				ret_code = 1;
X				break;
X			}
X					/* there is no previous queue */
X			beep();
X			mvwattrstr(rd_win, 3, 4, A_BOLD, "No previous numbers");
X			wrefresh(rd_win);
X			wait_key(rd_win, 3);
X			clear_line(rd_win, 3, 4, 1);
X			wmove(rd_win, 2, 31);
X			wrefresh(rd_win);
X			continue;
X		}
X					/* parse the queue values */
X		entry = strtok(ans, "	 ");
X		for (i=0; i<NUM_QUEUE; i++) {
X			if (*entry == NULL) {
X				dir->q_num[i] = -1;
X				continue;
X			}
X					/* is there a LD code ? */
X			dir->q_ld[i] = NULL;
X			if (strchr("+-@#", *entry)) {
X				dir->q_ld[i] = *entry;
X				entry++;
X			}
X
X			/*
X			 * Zero is valid here, because it means use
X			 * the current entry information.
X			 */
X			number = atoi(entry);
X			if (number < -1 || number > NUM_DIR) {
X				beep();
X				mvwattrstr(rd_win, 3, 4, A_BOLD, "Invalid directory entry number");
X				wrefresh(rd_win);
X				wait_key(rd_win, 3);
X				clear_line(rd_win, 3, 4, 1);
X				clear_line(rd_win, 2, 31, 1);
X				wrefresh(rd_win);
X				oops++;
X				break;
X			}
X					/* store the number in the queue */
X			dir->q_num[i] = number;
X			entry = strtok((char *) NULL, "	 ");
X		}
X		if (oops)
X			continue;
X		ret_code = 1;
X		break;
X	}
X	if (fd == -1) {
X		werase(rd_win);
X		wrefresh(rd_win);
X	}
X	delwin(rd_win);
X	return(ret_code);
X}
SHAR_EOF
if test 2216 -ne "`wc -c < 'redial.c'`"
then
	echo shar: "error transmitting 'redial.c'" '(should have been 2216 characters)'
fi
fi
exit 0
#	End of shell archive


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