[comp.sources.unix] v20i071: Pcomm telecommunication package, Part05/08

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

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

#! /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:
#	m_lib.c
#	macro.c
#	main.c
#	matches.c
#	misc.h
#	modem.h
#	modem_break.c
#	n_shell.c
#	p_lib.c
#	param.h
#	passthru.c
#	pexit.c
#	port.c
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'm_lib.c'" '(9951 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
X/*
X * Read the modem/TTY database file.  Returns a pointer to a static area
X * containing the MODEM structure.  All modem entries and all TTY entries
X * are created regardless of the number of physical entries in the file.
X */
X
Xstruct MODEM *
Xread_modem(extra)
Xchar *extra;
X{
X	extern char *null_ptr;
X	FILE *fp, *my_fopen();
X	int i, tty, mod, line, oops, m_line, start, stop;
X	char *str_dup(), buf[200], message[80], token[40], *str_tok(), *str;
X	char *temp_token, *t_sep, *m_sep, *m_letter, *findfile();
X	static struct MODEM m;
X	void error_win();
X
X	if ((m.m_path = findfile(extra, "pcomm.modem")) == NULL)
X		error_win(1, "Support file \"pcomm.modem\" is missing", "or no read permission");
X
X	if (!(fp = my_fopen(m.m_path, "r"))) {
X		sprintf(buf, "\"%s\" for read", m.m_path);
X		error_win(1, "Can't open modem/TTY 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 pointer to NULL on a missing
X			 * token.  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] = str_dup(str);
X						break;
X					case 1:
X						m.tname[tty] = str_dup(str);
X						break;
X					case 2:
X						m.init_sp[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			 * are distinguished by the letters a, b, and, c
X			 * appended 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 = 12;
X					break;
X				case 2:
X					start = 12;
X					stop = 16;
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] = str_dup(str);
X						break;
X					case 1:
X						m.init[mod] = str_dup(str);
X						break;
X					case 2:
X						m.dial[mod] = str_dup(str);
X						break;
X					case 3:
X						m.suffix[mod] = str_dup(str);
X						break;
X					case 4:
X						m.hang_up[mod] = str_dup(str);
X						break;
X					case 5:
X						m.auto_baud[mod] = *str;
X						break;
X					case 6:
X						m.con_3[mod] = str_dup(str);
X						break;
X					case 7:
X						m.con_12[mod] = str_dup(str);
X						break;
X					case 8:
X						m.con_24[mod] = str_dup(str);
X						break;
X					case 9:
X						m.con_48[mod] = str_dup(str);
X						break;
X					case 10:
X						m.con_96[mod] = str_dup(str);
X						break;
X					case 11:
X						m.con_192[mod] = str_dup(str);
X						break;
X					case 12:
X						m.no_con1[mod] = str_dup(str);
X						break;
X					case 13:
X						m.no_con2[mod] = str_dup(str);
X						break;
X					case 14:
X						m.no_con3[mod] = str_dup(str);
X						break;
X					case 15:
X						m.no_con4[mod] = str_dup(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/TTY database file \"%s\"", m.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					/* if empty database */
X	if (!tty) {
X		sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
X		error_win(0, buf, "has no TTY data");
X	}
X	if (!mod) {
X		sprintf(buf, "Modem/TTY database file \"%s\"", m.m_path);
X		error_win(0, buf, "has no modem data");
X	}
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.init_sp[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.hang_up[mod] = null_ptr;
X
X		m.auto_baud[mod] = 'Y';
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 non-zero return code means non-fatal error.
X */
X
Xint
Xup_modem()
X{
X	FILE *fp, *my_fopen();
X	char buf[80];
X	int i;
X	void error_win();
X
X					/* open for write */
X	if (!(fp = my_fopen(modem->m_path, "w"))) {
X		sprintf(buf, "\"%s\"", modem->m_path);
X		error_win(0, "No write permission on modem/TTY database 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->init_sp[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->hang_up[i]);
X
X		fprintf(fp, "MODEM_%db=%c;%s;%s;%s;%s;%s;%s\n", i+1,
X		 modem->auto_baud[i], modem->con_3[i], modem->con_12[i],
X		 modem->con_24[i], modem->con_48[i], modem->con_96[i],
X		 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, create
X * 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 *str_rep(), buf[80];
X	void error_win();
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\"", modem->m_path);
X		error_win(0, "No empty modem slots in", buf);
X		return;
X	}
X					/* create a new entry */
X	i = modem->m_entries;
X	modem->mname[i] = str_rep(modem->mname[i], 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
Xdel_modem()
X{
X	extern char *null_ptr;
X	int i, j, match;
X	char *str_rep();
X	void free_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++;
X				break;
X			}
X		}
X					/* found a "lost" modem name */
X		if (!match) {
X			for (j=i; j<modem->m_entries-1; j++) {
X					/* copy the info */
X				modem->mname[j] = str_rep(modem->mname[j], modem->mname[j+1]);
X				modem->init[j] = str_rep(modem->init[j], modem->init[j+1]);
X				modem->dial[j] = str_rep(modem->dial[j], modem->dial[j+1]);
X				modem->suffix[j] = str_rep(modem->suffix[j], modem->suffix[j+1]);
X				modem->hang_up[j] = str_rep(modem->hang_up[j], modem->hang_up[j+1]);
X
X				modem->auto_baud[j] = modem->auto_baud[j+1];
X				modem->con_3[j] = str_rep(modem->con_3[j], modem->con_3[j+1]);
X				modem->con_12[j] = str_rep(modem->con_12[j], modem->con_12[j+1]);
X				modem->con_24[j] = str_rep(modem->con_24[j], modem->con_24[j+1]);
X				modem->con_48[j] = str_rep(modem->con_48[j], modem->con_48[j+1]);
X				modem->con_96[j] = str_rep(modem->con_96[j], modem->con_96[j+1]);
X				modem->con_192[j] = str_rep(modem->con_192[j], modem->con_192[j+1]);
X
X				modem->no_con1[j] = str_rep(modem->no_con1[j], modem->no_con1[j+1]);
X				modem->no_con2[j] = str_rep(modem->no_con2[j], modem->no_con2[j+1]);
X				modem->no_con3[j] = str_rep(modem->no_con3[j], modem->no_con3[j+1]);
X				modem->no_con4[j] = str_rep(modem->no_con4[j], 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->hang_up[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->hang_up[j] = null_ptr;
X
X			modem->auto_baud[j] = 'Y';
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 9951 -ne "`wc -c < 'm_lib.c'`"
then
	echo shar: "error transmitting 'm_lib.c'" '(should have been 9951 characters)'
fi
fi
echo shar: "extracting 'macro.c'" '(5246 characters)'
if test -f 'macro.c'
then
	echo shar: "will not over-write existing file 'macro.c'"
else
sed 's/^X//' << \SHAR_EOF > 'macro.c'
X/*
X * The keyboard macro feature.  Displays (and prompts for editing) the
X * macros assigned to the shifted number keys.  Prompts for saving
X * changes to disk.
X */
X
X#include <stdio.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X
Xvoid
Xmacro()
X{
X	extern int fd;
X	WINDOW *ma_win, *newwin();
X	int ans, changed;
X	char *mac, *str_rep(), *mac_prompt();
X
X	ma_win = newwin(18, 65, 2, 15);
X	mvwattrstr(ma_win, 1, 25, A_BOLD, "Keyboard Macros");
X	horizontal(ma_win, 2, 0, 65);
X	mvwprintw(ma_win, 4, 0, " %4.4s-!  %-50.50s\n", param->ascii_hot, param->mac_1);
X	wprintw(ma_win, " %4.4s-@  %-50.50s\n", param->ascii_hot, param->mac_2);
X	wprintw(ma_win, " %4.4s-#  %-50.50s\n", param->ascii_hot, param->mac_3);
X	wprintw(ma_win, " %4.4s-$  %-50.50s\n", param->ascii_hot, param->mac_4);
X	wprintw(ma_win, " %4.4s-%%  %-50.50s\n", param->ascii_hot, param->mac_5);
X	wprintw(ma_win, " %4.4s-^  %-50.50s\n", param->ascii_hot, param->mac_6);
X	wprintw(ma_win, " %4.4s-&  %-50.50s\n", param->ascii_hot, param->mac_7);
X	wprintw(ma_win, " %4.4s-*  %-50.50s\n", param->ascii_hot, param->mac_8);
X	wprintw(ma_win, " %4.4s-(  %-50.50s\n", param->ascii_hot, param->mac_9);
X	wprintw(ma_win, " %4.4s-)  %-50.50s\n", param->ascii_hot, param->mac_0);
X	mvwaddstr(ma_win, 15, 5, "Macro key to revise:");
X	box(ma_win, VERT, HORZ);
X					/* on the bottom line */
X	mvwaddstr(ma_win, 17, 21, " Press <ESC> to continue ");
X	wmove(ma_win, 15, 26);
X	wrefresh(ma_win);
X
X	changed = 0;
X
X	while ((ans = wgetch(ma_win)) != ESC) {
X		switch (ans) {
X			case '!':	/* shifted 1 */
X				if ((mac = mac_prompt(ans, param->mac_1)) != NULL) {
X					param->mac_1 = str_rep(param->mac_1, mac);
X					clear_line(ma_win, 4, 9, TRUE);
X					mvwattrstr(ma_win, 4, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '@':	/* shifted 2 */
X				if ((mac = mac_prompt(ans, param->mac_2)) != NULL) {
X					param->mac_2 = str_rep(param->mac_2, mac);
X					clear_line(ma_win, 5, 9, TRUE);
X					mvwattrstr(ma_win, 5, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '#':	/* shifted 3 */
X				if ((mac = mac_prompt(ans, param->mac_3)) != NULL) {
X					param->mac_3 = str_rep(param->mac_3, mac);
X					clear_line(ma_win, 6, 9, TRUE);
X					mvwattrstr(ma_win, 6, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '$':	/* shifted 4 */
X				if ((mac = mac_prompt(ans, param->mac_4)) != NULL) {
X					param->mac_4 = str_rep(param->mac_4, mac);
X					clear_line(ma_win, 7, 9, TRUE);
X					mvwattrstr(ma_win, 7, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '%':	/* shifted 5 */
X				if ((mac = mac_prompt(ans, param->mac_5)) != NULL) {
X					param->mac_5 = str_rep(param->mac_5, mac);
X					clear_line(ma_win, 8, 9, TRUE);
X					mvwattrstr(ma_win, 8, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '^':	/* shifted 6 */
X				if ((mac = mac_prompt(ans, param->mac_6)) != NULL) {
X					param->mac_6 = str_rep(param->mac_6, mac);
X					clear_line(ma_win, 9, 9, TRUE);
X					mvwattrstr(ma_win, 9, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '&':	/* shifted 7 */
X				if ((mac = mac_prompt(ans, param->mac_7)) != NULL) {
X					param->mac_7 = str_rep(param->mac_7, mac);
X					clear_line(ma_win, 10, 9, TRUE);
X					mvwattrstr(ma_win, 10, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '*':	/* shifted 8 */
X				if ((mac = mac_prompt(ans, param->mac_8)) != NULL) {
X					param->mac_8 = str_rep(param->mac_8, mac);
X					clear_line(ma_win, 11, 9, TRUE);
X					mvwattrstr(ma_win, 11, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case '(':	/* shifted 9 */
X				if ((mac = mac_prompt(ans, param->mac_9)) != NULL) {
X					param->mac_9 = str_rep(param->mac_9, mac);
X					clear_line(ma_win, 12, 9, TRUE);
X					mvwattrstr(ma_win, 12, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			case ')':	/* shifted 0 */
X				if ((mac = mac_prompt(ans, param->mac_0)) != NULL) {
X					param->mac_0 = str_rep(param->mac_0, mac);
X					clear_line(ma_win, 13, 9, TRUE);
X					mvwattrstr(ma_win, 13, 9, A_BOLD, mac);
X					changed++;
X				}
X				break;
X			default:
X				beep();
X				break;
X		}
X		touchwin(ma_win);
X		wmove(ma_win, 15, 26);
X		wrefresh(ma_win);
X	}
X					/* if something changed */
X	if (changed) {
X					/* save to disk? */
X		if (yes_prompt(ma_win, 15, 30, A_BOLD, "Save to disk")) {
X			if (up_param()) {
X				touchwin(ma_win);
X				wrefresh(ma_win);
X			}
X		}
X	}
X	if (fd == -1) {
X		werase(ma_win);
X		wrefresh(ma_win);
X	}
X	delwin(ma_win);
X	return;
X}
X
X/*
X * Sounds like McDonalds doesn't it?  Actually, it opens a new window
X * and prompts for the new macro.  Returns a pointer to the new string.
X * Since it uses get_str(), the return value points to a static area.
X */
X
Xstatic char *
Xmac_prompt(key, string)
Xchar key, *string;
X{
X	extern char *null_ptr;
X	WINDOW *mp_win, *newwin();
X	char *new, *get_str();
X
X	mp_win = newwin(6, 65, 8, 0);
X	mvwprintw(mp_win, 2, 3, "%4.4s-%c  %-50.50s", param->ascii_hot, key, string);
X	mvwaddstr(mp_win, 3, 5, "New : ");
X	box(mp_win, VERT, HORZ);
X	wrefresh(mp_win);
X
X	if ((new = get_str(mp_win, 50, "", "\n")) != NULL) {
X					/* if CR, return NULL */
X		if (*new == '\0')
X			new = NULL;
X					/* if space, change to null_ptr */
X		if (!strcmp(new, " "))
X			new = null_ptr;
X	}
X
X	werase(mp_win);
X	wrefresh(mp_win);
X	delwin(mp_win);
X	return(new);
X}
SHAR_EOF
if test 5246 -ne "`wc -c < 'macro.c'`"
then
	echo shar: "error transmitting 'macro.c'" '(should have been 5246 characters)'
fi
fi
echo shar: "extracting 'main.c'" '(7580 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 that
X * is designed to operate similar to the 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 * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X *					Directorate of Engineering & Housing
X *					Environmental Management Office
X *					Fort Hood, TX 76544-5057
X *
X *	Release v1.0	12 Mar 88
X *	Release v1.1	21 Aug 88
X *	Release v1.2.0	 4 Feb 89
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <curses.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#define	MAIN
X#include "config.h"
X#include "dial_dir.h"
X#include "extrnl.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X
X#ifndef OLDCURSES
X#include <term.h>
X#else /* OLDCURSES */
X#ifdef UNIXPC
X#include <sgtty.h>
X#endif /* UNIXPC */
Xchar tcbuf[1024];
Xstruct sgttyb t_mode, c_mode;
X#define cbreak crmode
X#endif /* OLDCURSES */
X
X#ifdef SHAREDMEM
Xint shm_id;
X#endif /* SHAREDMEM */
X
Xstruct DIAL_DIR *dir;
Xstruct EXTRNL *extrnl;
Xstruct MODEM *modem;
Xstruct PARAM *param;
Xstruct STATUS *status;
X
Xint fd = -1;				/* file descriptor for port */
Xint xmc;				/* magic cookie terminal */
Xint msg_status;				/* read/write permissions on TTY */
Xchar *null_ptr = "";			/* generic null pointer */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	extern char *optarg;
X	int c, i, code, quit();
X	char *mytty, *ttyname(), *term, *getenv(), *sys_name, *str_dup();
X	char *extra_dir, buf[80], message[80];
X	struct DIAL_DIR *read_dir();
X	struct EXTRNL *read_extrnl();
X	struct MODEM *read_modem();
X	struct PARAM *read_param();
X	struct STATUS *init();
X	struct stat stbuf;
X	void exit(), error_win(), free_ptr();
X#ifdef OLDCURSES
X	char *tgetstr(), *t, tb[1024];
X	t = tcbuf;
X#endif /* OLDCURSES */
X
X	signal(SIGINT, SIG_IGN);
X	signal(SIGQUIT, SIG_IGN);
X	signal(SIGTERM, quit);
X	signal(SIGHUP, quit);
X
X	sys_name = 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 = str_dup(optarg);
X				break;
X			case 'f':	/* the short cut into the dialing dir */
X				sys_name = str_dup(optarg);
X				break;
X			case '?':	/* default */
X				fprintf(stderr, "Usage: pcomm [-d directory] [-f system name]\n");
X				exit(1);
X				break;
X		}
X	}
X					/* get terminal type */
X	term = getenv("TERM");
X	if (term == NULL || *term == '\0') {
X		fprintf(stderr, "Windows not supported (TERM not defined)\n");
X		exit(1);
X	}
X					/* see if terminfo entry exists */
X#ifdef OLDCURSES
X	i = tgetent(tb, term);
X#else /* OLDCURSES */
X	setupterm(term, 1, &i);
X#endif /* OLDCURSES */
X
X	if (i != 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", &t) == 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 let's go! */
X#ifdef OLDCURSES
X	ioctl(0, TIOCGETP, &t_mode);
X#endif /* OLDCURSES */
X
X	initscr();
X	nonl();
X	cbreak();
X	noecho();
X
X#ifdef OLDCURSES
X	ioctl(0, TIOCGETP, &c_mode);
X#endif /* OLDCURSES */
X
X	dir = (struct DIAL_DIR *) NULL;
X	extrnl = (struct EXTRNL *) NULL;
X	param = (struct PARAM *) NULL;
X	modem = (struct MODEM *) NULL;
X					/* show the herald, return status */
X	status = init(sys_name);
X					/* get "msgs" status */
X	mytty = ttyname(0);
X	stat(mytty, &stbuf);
X	msg_status = stbuf.st_mode & 0777;
X	chmod(mytty, 0600);
X
X	mvaddstr(12, 31, "Initializing...");
X	refresh();
X					/* read the support files */
X	param = read_param(extra_dir);
X	dir = read_dir(extra_dir);
X	extrnl = read_extrnl(extra_dir);
X	modem = read_modem(extra_dir);
X
X					/* warning about screen size */
X	if (LINES > MAX_ROW || COLS > MAX_COL-1)
X		error_win(0, "Your screen size exceeds an internal Pcomm limit",
X		 "The edges of the screen may contain garbage");
X
X					/* short-cut to dialing window? */
X	code = 0;
X	if (sys_name != NULL) {
X		for (i=1; i<dir->d_entries+1; i++) {
X			if (match_ci(dir->name[i], sys_name)) {
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 match \"%s\" in dialing directory", sys_name);
X			sprintf(message, "file \"%s\"", dir->d_path);
X			error_win(0, buf, message);
X		}
X		free_ptr(sys_name);
X	}
X					/* start terminal dialogue */
X	terminal(extra_dir, code);
X	exit(0);
X}
X
X/*
X * Something dreadful happened...  Clean up 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[256], *strcpy(), *strrchr();
X
X	strcpy(path, file);
X					/* dissect the path component */
X	if (p = strrchr(path, '/'))
X		*p = '\0';
X	else
X		strcpy(path, ".");
X					/* if it already exists */
X	if (!access(file, 0)) {
X		if (!access(file, 2))
X			return(OK_BUT_EXISTS);
X		return(DENIED);
X	}
X					/* if path is writable */
X	if (!access(path, 2))
X		return(WRITE_OK);
X	return(DENIED);
X}
X
X/*
X * Check the read and write permissions before opening a file.  This
X * is a horrible kludge to work around the fact that a lot of systems
X * that claim to be SVID compatible don't treat setuid(2) and setgid(2)
X * properly.  For example, on a Masscomp, you can't flip-flop back and
X * forth between the real and effective UID/GID.
X */
X
XFILE *
Xmy_fopen(file, mode)
Xchar *file, *mode;
X{
X	FILE *fp;
X
X#ifdef SETUGID
X#ifdef SETUID_BROKE
X	switch (*mode) {
X		case 'a':
X		case 'w':
X			switch(can_write(file)) {
X				case DENIED:
X					fp = (FILE *) NULL;
X					break;
X				case OK_BUT_EXISTS:
X					fp = fopen(file, mode);
X					break;
X				case WRITE_OK:
X					fp = fopen(file, mode);
X					chown(file, getuid(), getgid());
X					break;
X			}
X			break;
X		case 'r':
X			if (access(file, 4))
X				fp = (FILE *) NULL;
X			else
X				fp = fopen(file, mode);
X			break;
X	}
X#else /* SETUID_BROKE */
X	int euid, egid;
X
X	euid = geteuid();
X	egid = getegid();
X					/* abdicate the throne */
X	setuid(getuid());
X	setgid(getgid());
X
X	fp = fopen(file, mode);
X					/* put things back */
X	setuid(euid);
X	setgid(egid);
X#endif /* SETUID_BROKE */
X	return(fp);
X#else /* SETUGID */
X	return(fopen(file, mode));
X#endif /* SETUGID */
X}
X
X/*
X * See if s2 in contained in s1 (case insensitive).  Returns a 1 on yes,
X * and a 0 on no.
X */
X
Xmatch_ci(s1, s2)
Xchar *s1, *s2;
X{
X	int i;
X	char str1[128], str2[128], *strstr();
X
X					/* copy the strings to lower case */
X	i = 0;
X	while(*s1) {
X		if (isupper(*s1))
X			str1[i++] = tolower(*s1);
X		else
X			str1[i++] = *s1;
X
X		if (i >= 127)
X			break;
X		s1++;
X	}
X	str1[i] = '\0';
X
X	i = 0;
X	while(*s2) {
X		if (isupper(*s2))
X			str2[i++] = tolower(*s2);
X		else
X			str2[i++] = *s2;
X
X		if (i >= 127)
X			break;
X		s2++;
X	}
X	str2[i] = '\0';
X					/* do they match? */
X	if (strstr(str1, str2))
X		return(1);
X	return(0);
X}
SHAR_EOF
if test 7580 -ne "`wc -c < 'main.c'`"
then
	echo shar: "error transmitting 'main.c'" '(should have been 7580 characters)'
fi
fi
echo shar: "extracting 'matches.c'" '(754 characters)'
if test -f 'matches.c'
then
	echo shar: "will not over-write existing file 'matches.c'"
else
sed 's/^X//' << \SHAR_EOF > 'matches.c'
X/*
X * See if two strings match.  Returns a 0 on success, and a 1 on failure.
X * This is an external program to be used in shell scripts.
X */
X
X#define STRSTR
X
X#include <stdio.h>
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	char *strstr();
X	void exit();
X
X	if (argc != 3) {
X		fprintf(stderr, "Usage: matches string1 string2\n");
X		exit(-1);
X	}
X
X	if (strstr(argv[1], argv[2]))
X		exit(0);
X	exit(1);
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
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 754 -ne "`wc -c < 'matches.c'`"
then
	echo shar: "error transmitting 'matches.c'" '(should have been 754 characters)'
fi
fi
echo shar: "extracting 'misc.h'" '(1549 characters)'
if test -f 'misc.h'
then
	echo shar: "will not over-write existing file 'misc.h'"
else
sed 's/^X//' << \SHAR_EOF > 'misc.h'
X/*
X * Definitions to support the home-grown curses(3) functions and to make
X * the old curses(3) routines happy.  ("config.h" must be included first).
X */
X
X#define mvwattrstr(w,y,x,a,s)	(wmove(w,y,x)==ERR?ERR:wattrstr(w,a,s))
X#define mvwattrch(w,y,x,a,c)	(wmove(w,y,x)==ERR?ERR:wattrch(w,a,c))
X#define mvwattrnum(w,y,x,a,n)	(wmove(w,y,x)==ERR?ERR:wattrnum(w,a,n))
X#define mvattrstr(y,x,a,s)	(wmove(stdscr,y,x)==ERR?ERR:wattrstr(stdscr,a,s))
X#define mvattrch(y,x,a,c)	(wmove(stdscr,y,x)==ERR?ERR:wattrch(stdscr,a,c))
X#define mvattrnum(y,x,a,n)	(wmove(stdscr,y,x)==ERR?ERR:wattrnum(stdscr,a,n))
X#define attrstr(a,s)		wattrstr(stdscr,a,s)
X#define attrch(a,c)		wattrch(stdscr,a,c)
X#define attrnum(a,n)		wattrnum(stdscr,a,n)
X
X#ifdef OLDCURSES
X#ifdef NOPROMOTE
X#define A_BOLD		0
X#define A_BLINK		0
X#define A_REVERSE	1
X#define A_DIM		0
X#define A_STANDOUT	1
X#define A_UNDERLINE	0
X#else /* NOPROMOTE */
X#define A_BOLD		1
X#define A_BLINK		1
X#define A_REVERSE	1
X#define A_DIM		1
X#define A_STANDOUT	1
X#define A_UNDERLINE	1
X#endif /* NOPROMOTE */
X#endif /* OLDCURSES */
X
X#ifdef OLDCURSES
Xtypedef char chtype;
X#endif /* OLDCURSES */
X
X#ifdef ACS_HLINE
X#define VERT		(chtype)0
X#define HORZ		(chtype)0
X#else /* ACS_HLINE */
X#define VERT		(chtype)'|'
X#define HORZ		(chtype)'-'
X#define ACS_VLINE	(chtype)'|'
X#define ACS_HLINE	(chtype)'-'
X#endif /* ACS_HLINE */
X
X/*
X * Other miscellaneous stuff
X */
X
X#define BEL		7
X#define BS		8
X#define ESC		27
X#define DEL		127
X
X#define MANUAL_CLEAR	0
X#define AUTO_CLEAR	1
X
X#define DENIED		0
X#define WRITE_OK	1
X#define OK_BUT_EXISTS	2
SHAR_EOF
if test 1549 -ne "`wc -c < 'misc.h'`"
then
	echo shar: "error transmitting 'misc.h'" '(should have been 1549 characters)'
fi
fi
echo shar: "extracting 'modem.h'" '(1538 characters)'
if test -f 'modem.h'
then
	echo shar: "will not over-write existing file 'modem.h'"
else
sed 's/^X//' << \SHAR_EOF > 'modem.h'
X/*
X * The modem and TTY databases.  The first 3 elements make up the TTY
X * database, the next 16 make up the modem database.  A "tname" in common
X * with a "mname" link the two together.
X */
X
X#define NUM_TTY		10
X#define NUM_MODEM	10
X
Xstruct MODEM {
X	char	*tty[NUM_TTY];		/* TTY names */
X	char	*tname[NUM_TTY];	/* modem name */
X	int	init_sp[NUM_TTY];	/* initialization baud rate */
X
X	char	*mname[NUM_MODEM];	/* modem name (matches tname above) */
X	char	*init[NUM_MODEM];	/* initialization */
X	char	*dial[NUM_MODEM];	/* dial command */
X	char	*suffix[NUM_MODEM];	/* dialing command suffix */
X	char	*hang_up[NUM_MODEM];	/* hang up the modem */
X	char	auto_baud[NUM_MODEM];	/* should we sync baud rates? */
X	char	*con_3[NUM_MODEM];	/* 300 baud connect message */
X	char	*con_12[NUM_MODEM];	/* 1200 baud connect message */
X	char	*con_24[NUM_MODEM];	/* 2400 baud connect message */
X	char	*con_48[NUM_MODEM];	/* 4800 baud connect message */
X	char	*con_96[NUM_MODEM];	/* 9600 baud connect message */
X	char	*con_192[NUM_MODEM];	/* 19200 baud connect message */
X	char	*no_con1[NUM_MODEM];	/* no connect #1 */
X	char	*no_con2[NUM_MODEM];	/* no connect #2 */
X	char	*no_con3[NUM_MODEM];	/* no connect #3 */
X	char	*no_con4[NUM_MODEM];	/* no connect #4 */
X
X	int	t_entries;		/* number of TTY entries */
X	int	m_entries;		/* number of modem entries */
X	int	t_cur;			/* current TTY entry number */
X	int	m_cur;			/* current modem entry number */
X
X	char	*m_path;		/* path to the pcomm.modem file */
X};
X
X#ifndef MAIN
Xextern struct MODEM *modem;
X#endif /* MAIN */
SHAR_EOF
if test 1538 -ne "`wc -c < 'modem.h'`"
then
	echo shar: "error transmitting 'modem.h'" '(should have been 1538 characters)'
fi
fi
echo shar: "extracting 'modem_break.c'" '(407 characters)'
if test -f 'modem_break.c'
then
	echo shar: "will not over-write existing file 'modem_break.c'"
else
sed 's/^X//' << \SHAR_EOF > 'modem_break.c'
X/*
X * Send a modem break.  This is an external program to be used in shell
X * scripts.
X */
X
X#include <stdio.h>
X#ifdef BSD
X#include <sgtty.h>
X#else /* BSD */
X#include <termio.h>
X#endif /* BSD */
X
Xmain()
X{
X	unsigned int sleep();
X
X#ifdef BSD
X	ioctl(1, TIOCSBRK, (struct sgttyb *) 0);
X	sleep(1);
X	return(ioctl(1, TIOCCBRK, (struct sgttyb *) 0));
X#else /* BSD */
X	return(ioctl(1, TCSBRK, 0));
X#endif /* BSD */
X}
SHAR_EOF
if test 407 -ne "`wc -c < 'modem_break.c'`"
then
	echo shar: "error transmitting 'modem_break.c'" '(should have been 407 characters)'
fi
fi
echo shar: "extracting 'n_shell.c'" '(1336 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#include "config.h"
X
Xvoid
Xn_shell()
X{
X	WINDOW *sh_win, *newwin();
X	SIG_TYPE (*istat)(), (*qstat)();
X	int sig_status, spid, 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	touchwin(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 == '\0')
X		shellpath = "/bin/sh";
X
X	if (shell = strrchr(shellpath, '/'))
X		shell++;
X	else {
X		shellpath = "/bin/sh";
X		shell = "sh";
X	}
X
X	if (!(spid = fork())) {
X		signal(SIGINT, SIG_DFL);
X		signal(SIGQUIT, SIG_DFL);
X#ifdef SETUGID
X		setgid(getgid());
X		setuid(getuid());
X#endif /* SETUGID */
X		execl(shellpath, shell, "-i", (char *) 0);
X		_exit(1);
X	}
X	istat = signal(SIGINT, SIG_IGN);
X	qstat = signal(SIGQUIT, SIG_IGN);
X
X	while ((w = wait(&sig_status)) != spid && w != -1)
X		;
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(sh_win);
X	wrefresh(sh_win);
X	delwin(sh_win);
X	return;
X}
SHAR_EOF
if test 1336 -ne "`wc -c < 'n_shell.c'`"
then
	echo shar: "error transmitting 'n_shell.c'" '(should have been 1336 characters)'
fi
fi
echo shar: "extracting 'p_lib.c'" '(7337 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
X/*
X * Read the parameter structure from the pcomm.param file.  Returns a
X * pointer to a static area containing the PARAM structure.  All errors
X * are fatal.
X */
X
Xstruct PARAM *
Xread_param(extra)
Xchar *extra;
X{
X	FILE *fp, *my_fopen();
X	int i, line, oops;
X	char buf[200], *temp_token, *str, *str_dup(), *findfile();
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", "BRK_CHAR", "ABORT", "C_DELAY", "R_DELAY", "LECHO",
X	"EXPAND", "CR_DELAY", "PACE", "CR_UP", "LF_UP", "TIMER", "CR_DN",
X	"LF_DN", "LD_PLUS", "LD_MINUS", "LD_AT", "LD_POUND", "MAC_1",
X	"MAC_2", "MAC_3", "MAC_4", "MAC_5", "MAC_6", "MAC_7", "MAC_8",
X	"MAC_9", "MAC_0"};
X	static struct PARAM p;
X	void error_win();
X
X	if ((p.p_path = findfile(extra, "pcomm.param")) == NULL)
X		error_win(1, "Support file \"pcomm.param\" is missing", "or no read permission");
X
X	if (!(fp = my_fopen(p.p_path, "r"))) {
X		sprintf(buf, "\"%s\" for read", p.p_path);
X		error_win(1, "Can't open parameter file", buf);
X	}
X
X	oops = 0;
X	line = 0;
X	for (i=0; i<NUM_PARAM; i++) {
X		line++;
X		if (fgets(buf, 200, fp) == NULL) {
X			sprintf(message, "is truncated at line %d", line);
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", line);
X			oops++;
X			break;
X		}
X		if (!(str = str_tok((char *) NULL, '\n'))) {
X			sprintf(message, "is missing a parameter at line %d", line);
X			oops++;
X			break;
X		}
X					/* sanity checking */
X		if (strcmp(temp_token, token[i])) {
X			sprintf(message, "is corrupted at line %d", line);
X			oops++;
X			break;
X		}
X
X		switch (i) {
X					/* used in ls_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 = str_dup(str);
X				break;
X			case TERM_SETUP+2:
X				p.d_duplex = str_dup(str);
X				break;
X			case TERM_SETUP+3:
X				p.flow = str_dup(str);
X				break;
X			case TERM_SETUP+4:
X				p.cr_in = str_dup(str);
X				break;
X			case TERM_SETUP+5:
X				p.cr_out = str_dup(str);
X				break;
X
X					/* used in gen_setup() */
X			case GEN_SETUP:
X				p.logfile = str_dup(str);
X				break;
X			case GEN_SETUP+1:
X				p.dumpfile = str_dup(str);
X				break;
X			case GEN_SETUP+2:
X				p.strip = str_dup(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.brk_char = *str;
X				break;
X			case GEN_SETUP+8:
X				p.abort = str_dup(str);
X				break;
X
X					/* used in gen_setup() delay_times() */
X			case DELAY_TIMES:
X				p.c_delay = atoi(str);
X				break;
X			case DELAY_TIMES+1:
X				p.r_delay = atoi(str);
X				break;
X
X					/* used in axfer_setup() */
X			case ASCII_SETUP:
X				p.lecho = str_dup(str);
X				break;
X			case ASCII_SETUP+1:
X				p.expand = str_dup(str);
X				break;
X			case ASCII_SETUP+2:
X				p.cr_delay = atoi(str);
X				break;
X			case ASCII_SETUP+3:
X				p.pace = str_dup(str);
X				break;
X			case ASCII_SETUP+4:
X				p.cr_up = str_dup(str);
X				break;
X			case ASCII_SETUP+5:
X				p.lf_up = str_dup(str);
X				break;
X			case ASCII_SETUP+6:
X				p.timer = atoi(str);
X				break;
X			case ASCII_SETUP+7:
X				p.cr_dn = str_dup(str);
X				break;
X			case ASCII_SETUP+8:
X				p.lf_dn = str_dup(str);
X				break;
X
X					/* used in d_revise() */
X			case LD_CODES:
X				p.ld_plus = str_dup(str);
X				break;
X			case LD_CODES+1:
X				p.ld_minus = str_dup(str);
X				break;
X			case LD_CODES+2:
X				p.ld_at = str_dup(str);
X				break;
X			case LD_CODES+3:
X				p.ld_pound = str_dup(str);
X				break;
X
X					/* used in macro() */
X			case MACROS:
X				p.mac_1 = str_dup(str);
X				break;
X			case MACROS+1:
X				p.mac_2 = str_dup(str);
X				break;
X			case MACROS+2:
X				p.mac_3 = str_dup(str);
X				break;
X			case MACROS+3:
X				p.mac_4 = str_dup(str);
X				break;
X			case MACROS+4:
X				p.mac_5 = str_dup(str);
X				break;
X			case MACROS+5:
X				p.mac_6 = str_dup(str);
X				break;
X			case MACROS+6:
X				p.mac_7 = str_dup(str);
X				break;
X			case MACROS+7:
X				p.mac_8 = str_dup(str);
X				break;
X			case MACROS+8:
X				p.mac_9 = str_dup(str);
X				break;
X			case MACROS+9:
X				p.mac_0 = str_dup(str);
X				break;
X		}
X	}
X	fclose(fp);
X	if (oops) {
X		sprintf(buf, "Parameter file \"%s\"", p.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 non-zero return code means non-fatal
X * error.
X */
X
Xint
Xup_param()
X{
X	FILE *fp, *my_fopen();
X	char buf[80];
X	void error_win();
X					/* open for write */
X	if (!(fp = my_fopen(param->p_path, "w"))) {
X		sprintf(buf, "\"%s\"", param->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, "BRK_CHAR=%c\n", param->brk_char);
X	fprintf(fp, "ABORT=%s\n", param->abort);
X	fprintf(fp, "C_DELAY=%d\n", param->c_delay);
X	fprintf(fp, "R_DELAY=%d\n", param->r_delay);
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	fprintf(fp, "MAC_1=%s\n", param->mac_1);
X	fprintf(fp, "MAC_2=%s\n", param->mac_2);
X	fprintf(fp, "MAC_3=%s\n", param->mac_3);
X	fprintf(fp, "MAC_4=%s\n", param->mac_4);
X	fprintf(fp, "MAC_5=%s\n", param->mac_5);
X	fprintf(fp, "MAC_6=%s\n", param->mac_6);
X	fprintf(fp, "MAC_7=%s\n", param->mac_7);
X	fprintf(fp, "MAC_8=%s\n", param->mac_8);
X	fprintf(fp, "MAC_9=%s\n", param->mac_9);
X	fprintf(fp, "MAC_0=%s\n", param->mac_0);
X
X	fclose(fp);
X	return(0);
X}
SHAR_EOF
if test 7337 -ne "`wc -c < 'p_lib.c'`"
then
	echo shar: "error transmitting 'p_lib.c'" '(should have been 7337 characters)'
fi
fi
echo shar: "extracting 'param.h'" '(2757 characters)'
if test -f 'param.h'
then
	echo shar: "will not over-write existing file 'param.h'"
else
sed 's/^X//' << \SHAR_EOF > 'param.h'
X/*
X * The standard Pcomm parameters.  Everything can be altered by using one
X * of Pcomm's menus.  Although editing by hand is not encouraged, the
X * pcomm.param file is just an ASCII file.
X */
X
X#define MAX_CDELAY	120
X#define MIN_CDELAY	10
X#define MAX_PAUSE	120
X#define MIN_PAUSE	1
X#define MAX_TIMER	20
X#define MIN_TIMER	2
X
X#define NUM_PARAM	44
X#define LINE_SET	0
X#define TERM_SETUP	4
X#define GEN_SETUP	10
X#define DELAY_TIMES	19
X#define ASCII_SETUP	21
X#define LD_CODES	30
X#define MACROS		34
X
Xstruct PARAM {
X				/* 0-3 used in ls_menu() */
X	int	d_baud;			/* default baud rate */
X	char	d_parity;		/* default parity */
X	int	d_dbits;		/* default data bits */
X	int	d_sbits;		/* default stop bits */
X
X				/* 4-9 used in term_setup() */
X	int	hot;			/* the decimal code for the hot key */
X	char	*ascii_hot;		/* ascii representation of hot key */
X	char	*d_duplex;		/* default duplex */
X	char	*flow;			/* flow control */
X	char	*cr_in;			/* send as carriage return */
X	char	*cr_out;		/* receive carriage return as */
X
X				/* 10-18 used in gen_setup() */
X	char	*logfile;		/* default log file */
X	char	*dumpfile;		/* default screen dump file */
X	char	*strip;			/* strip high bit (translate table) */
X	char	pause_char;		/* pause char synonym */
X	char	cr_char;		/* carriage return char synonym */
X	char	ctrl_char;		/* ctrl char synonym */
X	char	esc_char;		/* escape char synonym */
X	char	brk_char;		/* modem break synonym */
X	char	*abort;			/* destination of aborted downloads */
X
X				/* 19-20 used in gen_setup() & delay_times() */
X	int	c_delay;		/* connect delay time */
X	int	r_delay;		/* redial delay time */
X
X				/* 21-29 used in axfer_setup() */
X	char	*lecho;			/* echo locally? */
X	char	*expand;		/* expand blank lines? */
X	int	cr_delay;		/* carriage return delay (ms) */
X	char	*pace;			/* pace the output? */
X	char	*cr_up;			/* send carriage return as */
X	char	*lf_up;			/* send line feed as */
X	int	timer;			/* transfer timeout */
X	char	*cr_dn;			/* receive carriage return as */
X	char	*lf_dn;			/* receive line feed as */
X
X				/* 30-33 used in d_revise() */
X	char	*ld_plus;		/* + long distance code */
X	char	*ld_minus;		/* - long distance code */
X	char	*ld_at;			/* @ long distance code */
X	char	*ld_pound;		/* # long distance code */
X
X				/* 34-43 used in macro() */
X	char	*mac_1;			/* shifted 1 macro */
X	char	*mac_2;			/* shifted 2 macro */
X	char	*mac_3;			/* shifted 3 macro */
X	char	*mac_4;			/* shifted 4 macro */
X	char	*mac_5;			/* shifted 5 macro */
X	char	*mac_6;			/* shifted 6 macro */
X	char	*mac_7;			/* shifted 7 macro */
X	char	*mac_8;			/* shifted 8 macro */
X	char	*mac_9;			/* shifted 9 macro */
X	char	*mac_0;			/* shifted 0 macro */
X
X	char	*p_path;		/* path to the pcomm.param file */
X};
X
X#ifndef MAIN
Xextern struct PARAM *param;
X#endif /* MAIN */
SHAR_EOF
if test 2757 -ne "`wc -c < 'param.h'`"
then
	echo shar: "error transmitting 'param.h'" '(should have been 2757 characters)'
fi
fi
echo shar: "extracting 'passthru.c'" '(2489 characters)'
if test -f 'passthru.c'
then
	echo shar: "will not over-write existing file 'passthru.c'"
else
sed 's/^X//' << \SHAR_EOF > 'passthru.c'
X/*
X * A transparent "pass-thru" mode, designed to allow binary transfers
X * between 3 machines (with the middle machine in the pass-thru mode).
X * A non-zero return code means the input routine should be restarted.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <curses.h>
X#include "config.h"
X#include "misc.h"
X
X#ifdef BSD
X#include <setjmp.h>
Xjmp_buf cp_buf;
X#endif /* BSD */
X
Xint
Xpass_thru()
X{
X	extern int fd;
X	WINDOW *pt_win, *newwin();
X	int num;
X	void cpio(), error_win();
X
X	pt_win = newwin(5, 70, 5, 5);
X
X	mvwaddstr(pt_win, 2, 4, "Enter the expiration time (5-60 sec): ");
X	box(pt_win, VERT, HORZ);
X
X	mvwattrstr(pt_win, 0, 3, A_BOLD, " Pass Through Mode ");
X	wmove(pt_win, 2, 43);
X	wrefresh(pt_win);
X					/* get the answer */
X	while ((num = get_num(pt_win, 2)) != -1) {
X					/* out of bounds */
X		if (num < 5 || num > 60) {
X			beep();
X			clear_line(pt_win, 2, 43, TRUE);
X			wmove(pt_win, 2, 43);
X			wrefresh(pt_win);
X		}
X		else {
X			werase(pt_win);
X			wrefresh(pt_win);
X			delwin(pt_win);
X
X			if (fd == -1) {
X				error_win(0, "Not currently connected to any host", "");
X				return(0);
X			}
X
X			touchwin(stdscr);
X			refresh();
X
X			cpio((unsigned int) num);
X			return(1);
X		}
X	}
X	if (fd == -1) {
X		werase(pt_win);
X		wrefresh(pt_win);
X	}
X	delwin(pt_win);
X	return(0);
X}
X
X/*
X * Copy the stdin to the TTYout and copy the TTYin to the stdout.  Uses
X * multi character reads.  I'm not too concerned about the excess baggage
X * caused by the entire image being forked... this feature won't be used
X * that often.
X */
X
Xstatic int cp_flag;
X
Xstatic void
Xcpio(num)
Xunsigned int num;
X{
X	extern int fd;
X	int cpid, n, cp_force();
X	char buf[CLIST_SIZ];
X	unsigned int alarm(), sleep();
X	void line_set(), xmodem_mode(), input_off();
X
X					/* out of curses mode */
X	resetterm();
X
X	input_off();
X	xmodem_mode(0);
X	xmodem_mode(fd);
X
X					/* copy the TTYin to stdout */
X	if (!(cpid = fork())) {
X		while (1) {
X			n = read(fd, buf, CLIST_SIZ);
X			write(1, buf, n);
X		}
X	}
X
X	cp_flag = 0;
X	signal(SIGALRM, cp_force);
X					/* copy the stdin to TTYout */
X	while (1) {
X		alarm(num);
X#ifdef BSD
X		if (setjmp(cp_buf))
X			break;
X#endif /* BSD */
X		n = read(0, buf, CLIST_SIZ);
X		if (cp_flag)
X			break;
X		write(fd, buf, n);
X	}
X	kill(cpid, SIGKILL);
X					/* back to curses mode */
X	sleep(1);
X	fixterm();
X	beep();
X	line_set();
X	clearok(curscr, TRUE);
X	return;
X}
X
X/* ARGSUSED */
Xstatic int
Xcp_force(dummy)
X{
X#ifdef BSD
X	longjmp(cp_buf, 1);
X#else /* BSD */
X	signal(SIGALRM, cp_force);
X	cp_flag = 1;
X#endif /* BSD */
X}
SHAR_EOF
if test 2489 -ne "`wc -c < 'passthru.c'`"
then
	echo shar: "error transmitting 'passthru.c'" '(should have been 2489 characters)'
fi
fi
echo shar: "extracting 'pexit.c'" '(2579 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 "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X#include "status.h"
X
X#ifdef SHAREDMEM
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X#endif /* SHAREDMEM */
X
Xvoid
Xpexit()
X{
X	extern int fd;
X	WINDOW *ex_win, *newwin();
X	void cleanup(), st_line();
X
X	ex_win = newwin(5, 33, 3, 7);
X
X	box(ex_win, VERT, HORZ);
X	mvwattrstr(ex_win, 0, 3, A_BOLD, " Exit ");
X	if (yes_prompt(ex_win, 2, 4, A_BLINK, "Exit to Unix")) {
X		st_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 clean up detail before we exit.  Only the status structure
X * is guaranteed to exit.
X */
X
Xvoid
Xcleanup(val)
Xint val;
X{
X	extern int msg_status;
X	void release_port(), input_off(), exit();
X	char *ttyname();
X#ifdef SHAREDMEM
X	extern int shm_id;
X	void perror();
X#endif /* SHAREDMEM */
X					/* kill the input routine */
X	input_off();
X					/* release the port */
X	release_port(QUIET);
X					/* zap the virtual screen */
X#ifdef SHAREDMEM
X	if (shmdt((char *) status) < 0)
X		perror("shmdt");
X	if (shmctl(shm_id, IPC_RMID, (struct shmid_ds *) NULL) < 0)
X		perror("shmctl");
X#else /* SHAREDMEM */
X	unlink(status->vs_path);
X#endif /* SHAREDMEM */
X
X	/*
X	 * If we die an un-natural death (such as a SIGHUP on the loss of
X	 * the controlling terminal) we won't have a terminal to mess with.
X	 */
X	if (isatty(0)) {
X		touchwin(stdscr);
X		clear();
X		refresh();
X		endwin();
X					/* return the TTY chmod */
X		chmod(ttyname(0), msg_status);
X	}
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(), st_line();
X
X					/* make sure we're in curses mode */
X	fixterm();
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, VERT, HORZ);
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		st_line("   exiting");
X		cleanup(code);
X	}
X	return;
X}
SHAR_EOF
if test 2579 -ne "`wc -c < 'pexit.c'`"
then
	echo shar: "error transmitting 'pexit.c'" '(should have been 2579 characters)'
fi
fi
echo shar: "extracting 'port.c'" '(10197 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 MAX_PID	30000
X#define TRUE	1
X#define FALSE	0
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <errno.h>
X#include "config.h"
X#include "dial_dir.h"
X#include "modem.h"
X
X#ifdef BSD
X#include <sys/file.h>
X#endif /* BSD */
X
X#ifdef UNIXPC
X#include <sys/phone.h>
X#endif /* UNIXPC */
X
X#ifdef XENIX_LOCKS
X#include <ctype.h>
X#endif /* XENIX_LOCKS */
X
Xstatic int getty_status = 0;
Xstatic char *lock_path = NULL;
X/*
X * Finds a free (or requested) serial port.  Creates a lock file to hold
X * for our use.  Loads the modem database.  A non-zero return code means
X * all ports (or the requested port) are busy.
X */
X
Xint
Xget_port()
X{
X	extern int fd;
X	register int i;
X	int j, k, lfd, list[NUM_TTY], cmask, tbaud, is_dev, progpid;
X	char file[80], buf[80], message[80], *str_rep(), *last_c;
X	unsigned int sleep();
X	void error_win(), line_set(), release_port(), send_str();
X
X	is_dev = chk_script(dir->script[dir->d_cur]);
X	/*
X	 * If you already have a port, see if it is good enough for the
X	 * current request.
X	 */
X#ifdef KEEP_PORT
X	if (fd != -1) {
X		if (!strcmp(dir->script[dir->d_cur], modem->tty[modem->t_cur])
X		 || (!is_dev && ck_speed(modem->t_cur, dir->baud[dir->d_cur]))){
X			/*
X			 * Reset the line because the baud rate (or other
X			 * parameters) may have changed.
X			 */
X			line_set();
X			return(0);
X		}
X	}
X#endif /* KEEP_PORT */
X
X	release_port(VERBOSE);
X
X	list[0] = -1;
X	/*
X	 * See if you want a specific TTY port.  If the script field in the
X	 * dialing directory is a valid device name, then use that TTY.
X	 */
X	if (is_dev) {
X		for (i=0; i<modem->t_entries; i++) {
X					/* and it exists in modem database */
X			if (!strcmp(dir->script[dir->d_cur], modem->tty[i])) {
X				list[0] = i;
X				list[1] = -1;
X				break;
X			}
X		}
X					/* oops... we don't know that port */
X		if (list[0] == -1) {
X			sprintf(message, "Device \"%s\" in the script field doesn't exist in", dir->script[dir->d_cur]);
X			sprintf(buf, "modem/TTY database \"%s\"", modem->m_path);
X			error_win(0, message, buf);
X		}
X	}
X
X	/*
X	 * Create a list of acceptable TTYs.  It searches the modem 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 (ck_speed(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 the", dir->baud[dir->d_cur]);
X		sprintf(buf, "modem database \"%s\"", modem->m_path);
X		error_win(0, message, buf);
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", LOCK_DIR, modem->tty[list[i]]);
X
X#ifdef XENIX_LOCKS
X		last_c = file + strlen(file)-1;
X		if (isuuper(*last_c))
X			*last_c = tolower(*last_c);
X#endif /* XENIX_LOCKS */
X
X#ifdef DEBUG
X		fprintf(stderr, "get_port: checking '/dev/%s'\n", modem->tty[list[i]]);
X#endif /* DEBUG */
X
X					/* no lock exists or it is dead */
X		if (checklock(file)) {
X			getty_status = set_getty(modem->tty[list[i]], FALSE);
X
X			cmask = umask(0);
X			if ((lfd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0666)) < 0) {
X				if (getty_status)
X					set_getty(modem->tty[list[i]], TRUE);
X				sprintf(buf, "\"%s\"", file);
X				error_win(1, "Can't create the lockfile", buf);
X			}
X			umask(cmask);
X#ifdef ASCII_PID
X			sprintf(buf, "%10d\n", getpid());
X			write(lfd, buf, 11);
X#else /* ASCII_PID */
X			progpid = getpid();
X			write(lfd, (char *) &progpid, sizeof(int));
X#endif /* ASCII_PID */
X			close(lfd);
X					/* store the new values */
X			lock_path = str_rep(lock_path, file);
X			modem->t_cur = list[i];
X
X					/* open the device (ignore DCD) */
X			sprintf(buf, "/dev/%s", modem->tty[modem->t_cur]);
X			if ((fd = open(buf, O_RDWR|O_NDELAY)) < 0) {
X				if (getty_status)
X					set_getty(modem->tty[modem->t_cur], TRUE);
X				sprintf(file, "Can't open port \"%s\" for read and write", buf);
X				error_win(1, file, "");
X			}
X					/* change line settings */
X			line_set();
X					/* ...just to be sure */
X			close(open(buf, O_RDWR));
X
X					/* turn off the O_NDELAY setting */
X			tty_noblock(fd, FALSE);
X
X					/* load the modem data base */
X			modem->m_cur = -1;
X			for (j=0; j<modem->m_entries; j++) {
X				if (!strcmp(modem->tname[modem->t_cur], modem->mname[j])) {
X					modem->m_cur = j;
X					break;
X				}
X			}
X			if (modem->m_cur == -1) {
X				sprintf(buf, "Modem name \"%s\" in TTY database",
X				 modem->tname[modem->t_cur]);
X				error_win(1, buf, "does not exist in modem database");
X			}
X					/* initialize the modem */
X			if (modem->init_sp[modem->t_cur]) {
X				tbaud = dir->baud[dir->d_cur];
X				dir->baud[dir->d_cur] = modem->init_sp[modem->t_cur];
X				line_set();
X				send_str(modem->init[modem->m_cur], SLOW);
X				dir->baud[dir->d_cur] = tbaud;
X			}
X			else
X				send_str(modem->init[modem->m_cur], SLOW);
X			sleep(1);
X			return(0);
X		}
X		i++;
X	}
X	error_win(0, "All ports are busy now, try again later", "");
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	extern int fd;
X	extern char *null_ptr;
X	char buf[80];
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 (fd != -1) {
X		tty_flush(fd, 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 hang_up string first.
X		 */
X		hang_up(verbose);
X		close(fd);
X	}
X					/* remove the lock */
X	if (lock_path != NULL && *lock_path != '\0') {
X		if (unlink(lock_path)) {
X			sprintf(buf, "\"%s\"", lock_path);
X			error_win(0, "Can't remove the lock file", buf);
X		}
X		free_ptr(lock_path);
X		lock_path = null_ptr;
X	}
X					/* turn the getty back on? */
X	if (getty_status && modem->t_cur != -1)
X		set_getty(modem->tty[modem->t_cur], TRUE);
X					/* clean up the structure */
X	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 non-zero return
X * code means that the getty was on.  Systems with uugetty() or dedicated
X * dialout ports won't need this routine.
X */
X
X/* ARGSUSED */
Xstatic int
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++;
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	 * The return code should tell if there was a getty or not.
X	 * Obviously the program would be suid to root.
X	 */
X	return(0);
X#endif /* UNIXPC */
X}
X
X/*
X * Check the lock file for a valid pid value.  Error conditions such
X * as not being able to open the lock file or not being able to interpret
X * the contents of the lock file cause the code to assume that the lock
X * file is valid.  Let the user worry about weird special cases.  A 
X * non-zero return code means the lock is dead or doesn't exist.
X */
X
Xstatic int
Xchecklock(lockfile)
Xchar *lockfile;
X{
X	extern int errno;
X	int lfd, lckpid, n;
X	char buf[40];
X					/* doesn't exist */
X	if (access(lockfile, 0))
X		return(1);
X					/* can't open the lock file */
X	if ((lfd = open(lockfile, 0)) < 0)
X		return(0);
X
X#ifdef ASCII_PID
X	if ((n = read(lfd, buf, 40)) <= 0) {
X		close(lfd);
X		return(0);
X	}
X	close(lfd);
X	buf[n--] = '\0';
X	lckpid = atoi(buf);
X#else /* ASCII_PID */
X	if (read(lfd, (char *) &lckpid, sizeof(int)) != sizeof(int)) {
X		close(lfd);
X		return(0);
X	}
X	close(lfd);
X#endif /* ASCII_PID */
X					/* invalid pid? */
X	if (lckpid <= 0 || lckpid > MAX_PID)
X		return(0);
X
X	if ((kill(lckpid, 0) == -1) && (errno == ESRCH)) {
X		/*
X		 * If the kill was unsuccessful due to an ESRCH error,
X		 * that means the process is no longer active and the
X		 * lock file can be safely removed.
X		 */
X		unlink(lockfile);
X		sleep(1);
X		return(1);
X	}
X	/*
X	 * If the kill() was successful, that means the process must
X	 * still be active.
X	 */
X	return(0);
X}
X
X/*
X * Check to see if the desired baud rate can be handled by the modem.
X * Uses the connect strings to make this determination.  The first
X * argument is the index into the TTY database.  A non-zero return code
X * means "yes it can".
X */
X
Xstatic int
Xck_speed(tty, baud)
Xint tty, baud;
X{
X	int i, mod;
X	char buf[60];
X					/* find the modem database */
X	mod = -1;
X	for (i=0; i<modem->m_entries; i++) {
X		if (!strcmp(modem->mname[i], modem->tname[tty])) {
X			mod = i;
X			break;
X		}
X	}
X	if (mod == -1) {
X		sprintf(buf, "Modem name \"%s\" in TTY database", modem->tname[tty]);
X		error_win(1, buf, "does not exist in modem database");
X	}
X
X#ifdef DEBUG
X	fprintf(stderr, "ck_speed: checking modem \"%s\" for %d baud\n", modem->mname[mod], baud);
X#endif /* DEBUG */
X
X	switch (baud) {
X		case 300:
X			if (*modem->con_3[mod] != '\0')
X				return(1);
X			break;
X		case 1200:
X			if (*modem->con_12[mod] != '\0')
X				return(1);
X			break;
X		case 2400:
X			if (*modem->con_24[mod] != '\0')
X				return(1);
X			break;
X		case 4800:
X			if (*modem->con_48[mod] != '\0')
X				return(1);
X			break;
X		case 9600:
X			if (*modem->con_96[mod] != '\0')
X				return(1);
X			break;
X		case 19200:
X			if (*modem->con_192[mod] != '\0')
X				return(1);
X			break;
X	}
X	return(0);
X}
X
X/*
X * Check to see if the script field is a valid device name.
X */
X
Xchk_script(script)
Xchar *script;
X{
X	char buf[80], *strcpy(), *strcat();
X
X	if (*script == '\0')
X		return(0);
X
X	strcpy(buf, "/dev/");
X	strcat(buf, script);
X
X	if (!access(buf, 0))
X		return(1);
X	return(0);
X}
SHAR_EOF
if test 10197 -ne "`wc -c < 'port.c'`"
then
	echo shar: "error transmitting 'port.c'" '(should have been 10197 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.