Category : UNIX Files
Archive   : PCOM202C.ZIP
Filename : PCOM202C.SHR

 
Output of file : PCOM202C.SHR contained in archive : PCOM202C.ZIP
Path: aplcenmp!aplcen.apl.jhu.edu!darwin.sura.net!emory!sol.ctr.columbia.edu!usc!elroy.jpl.nasa.gov!decwrl!vixie!vixie!not-for-mail
From: [email protected] (Emmet Gray)
Newsgroups: comp.sources.unix
Subject: v26i155: pcomm-2.0.2 - a serial communications program (clone of ProComm), Part03/06
Date: 14 Apr 1993 00:41:55 -0700
Organization: Vixie Home Computing
Lines: 4097
Sender: [email protected]
Approved: [email protected]
Message-ID: <[email protected]>
NNTP-Posting-Host: gw.home.vix.com

Submitted-By: [email protected] (Emmet Gray)
Posting-Number: Volume 26, Issue 155
Archive-Name: pcomm-2.0.2/part03

#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh # will see the following message at the end:
# "End of archive 3 (of 6)."
# Contents: Makefile cmd.c d_lib.c d_menu.c input.c p_lib.c s_modem.c
# terminal.c x_ascii.c x_batch.c x_menu.c xmodem.c
# Wrapped by [email protected] on Wed Apr 14 00:38:42 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(6622 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# PCOMM v2.0
X# for generic SVR4
X
X#for 80286 versions of SCO Xenix
X#CFLAGS = -Od -DM_TERMINFO -Mle2 -LARGE
X#LDFLAGS = -SEG 1000 -F 5000 -Mle2
X#CURSES = -ltinfo -lx
X
X#for 80386 versions of SCO Xenix
X#CFLAGS = -O -DM_TERMINFO
X#LDFLAGS = -s
X#CURSES = -ltinfo -lx
X
X#for the AT&T Unix PC 7300/3b1
X#LD = ld
X#SHLIB = /lib/crt0s.o /lib/shlib_c.ifile
X#OTHER = /lib/setvbuf.o /lib/doprnt.o -luipc
X
X#for Sun OS (using the System V compiler)
X#CC = /usr/5bin/cc
X#LD = /usr/5bin/cc
X
LD = cc
SHLIB =
OTHER =
CFLAGS = -O
LDFLAGS = -s
SHAR = shar -a
X
BIN_DIR = /usr/local/bin
MAN_DIR = /usr/man1
MAN_EXT = 1
PCOMM_LIB = /usr/local/lib/pcomm
X
X#for old curses (i.e. Berkeley systems)
X#CURSES = -lcurses -ltermcap
CURSES = -lcurses
X
X#for systems without getcwd(3) or getopt(3)
X#GETCWD.O = getcwd.o
X#GETCWD.C = getcwd.c
X#GETOPT.O = getopt.o
X#GETOPT.C = getopt.c
X
X#for System V or Berkeley TTY interface
X#TTY.O = tty_ucb.o
X#TTY.C = tty_ucb.c
TTY.O = tty_att.o
TTY.C = tty_att.c
X
X#for System V poll() or Berkeley select()
X#IPC.O = ipc_ucb.o
X#IPC.C = ipc_ucb.c
IPC.O = ipc_att.o
IPC.C = ipc_att.c
X
PCOMM = $(GETCWD.O) $(GETOPT.O) $(TTY.O) $(IPC.O) admin.o chg_dir.o cmd.o \
X curses.o d_delete.o d_lib.o d_manual.o d_menu.o d_print.o \
X d_prompt.o d_revise.o data_log.o di_delay.o di_win.o dial.o \
X e_lib.o expand.o help.o info.o init.o input.o list_dir.o ls_menu.o \
X m_lib.o macro.o main.o n_shell.o p_lib.o passthru.o pexit.o \
X port.o redial.o s_axfer.o s_extrnl.o s_gen.o s_menu.o s_modem.o \
X s_prompt.o s_term.o s_tty.o screen.o script.o st_line.o \
X strings.o terminal.o vcs.o x_ascii.o x_batch.o x_extrnl.o \
X x_menu.o x_rcv.o x_send.o x_win.o xmodem.o
X
all: pcomm waitfor matches pcomm_cmd
X
pcomm: $(PCOMM)
X $(LD) $(LDFLAGS) $(PCOMM) $(OTHER) -o pcomm $(CURSES) $(SHLIB)
X
waitfor: waitfor.o
X $(LD) $(LDFLAGS) waitfor.o -o waitfor $(SHLIB)
X
matches: matches.o
X $(LD) $(LDFLAGS) matches.o -o matches $(SHLIB)
X
pcomm_cmd: pcomm_cmd.o
X $(LD) $(LDFLAGS) pcomm_cmd.o -o pcomm_cmd $(SHLIB)
X
pcomm_cmd.o:
X $(CC) $(CFLAGS) -DIPC=\"$(IPC.C)\" -c pcomm_cmd.c
X
install:
X cp pcomm waitfor matches pcomm_cmd $(BIN_DIR)
X# obviously this requires super-user privelidges...
X# chmod 4755 $(BIN_DIR)/pcomm
X# chown uucp $(BIN_DIR)/pcomm
X
install_man:
X cp Pcomm.1 $(MAN_DIR)/pcomm.$(MAN_EXT)
X cp Pcomm_cmd.1 $(MAN_DIR)/pcomm_cmd.$(MAN_EXT)
X cp Waitfor.1 $(MAN_DIR)/waitfor.$(MAN_EXT)
X cp Matches.1 $(MAN_DIR)/matches.$(MAN_EXT)
X
install_support:
X cp Pcomm.dial_dir $(PCOMM_LIB)/pcomm.dial_dir
X cp Pcomm.modem $(PCOMM_LIB)/pcomm.modem
X cp Pcomm.param $(PCOMM_LIB)/pcomm.param
X cp Pcomm.extrnl $(PCOMM_LIB)/pcomm.extrnl
X
clean:
X rm pcomm waitfor matches pcomm_cmd
X
lint:
X lint -p -Dlint $(GETCWD.C) $(GETOPT.C) $(TTY.C) $(IPC.C) admin.c \
X chg_dir.c cmd.c curses.c d_delete.c d_lib.c d_manual.c d_menu.c \
X d_print.c d_prompt.c d_revise.c data_log.c di_delay.c di_win.c \
X dial.c e_lib.c expand.c help.c info.c init.c input.c list_dir.c \
X ls_menu.c m_lib.c macro.c main.c n_shell.c p_lib.c passthru.c \
X pexit.c port.c redial.c s_axfer.c s_extrnl.c s_gen.c s_menu.c \
X s_modem.c s_prompt.c s_term.c s_tty.c screen.c script.c \
X st_line.c strings.c terminal.c vcs.c x_ascii.c x_batch.c \
X x_extrnl.c x_menu.c x_rcv.c x_send.c x_win.c xmodem.c $(CURSES)
X lint -p -Dlint -DIPC=\"$(IPC.C)\" pcomm_cmd.c
X lint -p -Dlint waitfor.c
X lint -p -Dlint matches.c
X
shar:
X $(SHAR) Doc.me > pcomm_sh.1
X $(SHAR) Configure.sh Convert.sh Makefile Matches.1 Pcomm.1 \
X Pcomm.dial_dir Pcomm.extrnl Pcomm.modem Pcomm.param Pcomm_cmd.1 \
X Q_and_A Readme Release.notes Sample > pcomm_sh.2
X $(SHAR) Unixpc.shar Waitfor.1 admin.c chg_dir.c cmd.c cmd.h \
X config.h curses.c d_delete.c d_lib.c d_manual.c > pcomm_sh.3
X $(SHAR) d_menu.c d_print.c d_prompt.c d_revise.c data_log.c \
X di_delay.c di_win.c dial.c dial_dir.h e_lib.c expand.c extrnl.h \
X getcwd.c getopt.c help.c > pcomm_sh.4
X $(SHAR) info.c init.c input.c ipc.h ipc_att.c ipc_ucb.c \
X list_dir.c ls_menu.c m_lib.c macro.c main.c matches.c misc.h \
X modem.h n_shell.c > pcomm_sh.5
X $(SHAR) p_lib.c param.h passthru.c patchlevel.h pcomm_cmd.c \
X pexit.c port.c redial.c s_axfer.c s_extrnl.c s_gen.c > pcomm_sh.6
X $(SHAR) s_menu.c s_modem.c s_prompt.c s_term.c s_tty.c screen.c \
X script.c st_line.c status.h strings.c terminal.c tty_att.c \
X tty_ucb.c > pcomm_sh.7
X $(SHAR) vcs.c vcs.h waitfor.c x_ascii.c x_batch.c x_extrnl.c \
X x_menu.c x_rcv.c > pcomm_sh.8
X $(SHAR) x_send.c x_win.c xmodem.c xmodem.h > pcomm_sh.9
X# $(SHAR) Doc.out Matches.out Pcomm.out Pcomm_cmd.out Waitfor.out \
X# > pcomm_sh.10
X
admin.o: config.h dial_dir.h param.h
chg_dir.o: config.h misc.h
cmd.o: cmd.h config.h dial_dir.h extrnl.h modem.h param.h status.h xmodem.h
curses.o: config.h misc.h status.h
d_delete.o: dial_dir.h misc.h param.h
d_lib.o: dial_dir.h param.h
d_manual.o: config.h dial_dir.h misc.h
d_menu.o: config.h dial_dir.h misc.h param.h
d_print.o: config.h dial_dir.h misc.h
d_prompt.o: dial_dir.h misc.h
d_revise.o: dial_dir.h misc.h param.h
data_log.o: misc.h param.h status.h
di_delay.o: misc.h param.h
di_win.o: dial_dir.h misc.h modem.h param.h status.h
dial.o: config.h dial_dir.h misc.h modem.h param.h
e_lib.o: extrnl.h
expand.o: config.h
getopt.o: config.h
help.o: config.h misc.h
info.o: patchlevel.h
init.o: config.h misc.h status.h
input.o: config.h misc.h param.h status.h vcs.h
ipc_att.o: ipc.h
ipc_ucb.o: ipc.h
list_dir.o: misc.h
ls_menu.o: dial_dir.h misc.h param.h
m_lib.o: modem.h
macro.o: misc.h param.h
main.o: config.h dial_dir.h extrnl.h misc.h modem.h param.h status.h
n_shell.o: config.h
p_lib.o: param.h
passthru.o: config.h misc.h
pexit.o: dial_dir.h misc.h param.h status.h
port.o: config.h dial_dir.h modem.h status.h
redial.o: config.h dial_dir.h misc.h
s_axfer.o: misc.h param.h
s_extrnl.o: extrnl.h misc.h
s_gen.o: misc.h param.h
s_menu.o: misc.h
s_modem.o: misc.h modem.h
s_prompt.o: misc.h
s_term.o: dial_dir.h misc.h param.h
s_tty.o: misc.h modem.h
screen.o: param.h status.h
script.o: config.h dial_dir.h misc.h modem.h status.h
st_line.o: config.h dial_dir.h misc.h modem.h param.h status.h
strings.o: config.h
terminal.o: config.h dial_dir.h ipc.h misc.h modem.h param.h status.h xmodem.h
tty_att.o: dial_dir.h modem.h param.h
tty_ucb.o: dial_dir.h modem.h param.h
vcs.o: config.h status.h vcs.h
x_ascii.o: config.h misc.h param.h
x_batch.o: config.h misc.h xmodem.h
x_extrnl.o: config.h
x_menu.o: extrnl.h misc.h xmodem.h
x_rcv.o: config.h dial_dir.h misc.h xmodem.h
x_send.o: config.h dial_dir.h misc.h xmodem.h
x_win.o: dial_dir.h misc.h status.h xmodem.h
xmodem.o: config.h misc.h param.h xmodem.h
X
pcomm_cmd.o: config.h cmd.h $(IPC.C)
matches.o: config.h
waitfor.o: config.h
END_OF_FILE
if test 6622 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'cmd.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cmd.c'\"
else
echo shar: Extracting \"'cmd.c'\" \(7048 characters\)
sed "s/^X//" >'cmd.c' <<'END_OF_FILE'
X/*
X * Pcomm script commands. Since these will be executed from a forked
X * shell script, the commands, queries, and responses are sent thru an
X * IPC channel to Pcomm.
X */
X
X#include
X#include
X#include "cmd.h"
X#include "config.h"
X#include "dial_dir.h"
X#include "extrnl.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X#include "xmodem.h"
X
static void send_reply(), do_xfer(), cmode(), tmode();
X
void
cmd_input()
X{
X extern int fd;
X int cmd, arg1, i, n, ret_code;
X char buf[256], *s, arg2[256], *strchr(), *str_rep();
X char *entry, *strtok(), ld_code;
X void hang_up(), line_set(), pexit(), screen_dump(), log_toggle();
X void lpr_toggle();
X
X if (ipc_read(status->cmd_ipc, buf, 256))
X return;
X
X /* parse the comand line */
X if (sscanf(buf, "%d %d %s\n", &cmd, &arg1, arg2) != 3)
X return;
X
X ret_code = 0;
X switch(cmd) {
X case SET: /* the SET command */
X switch(arg1) {
X case BAUD:
X dir->baud[0] = (unsigned int) atoi(arg2);
X line_set();
X break;
X case PARITY:
X dir->parity[0] = arg2[0];
X line_set();
X break;
X case DATA_BITS:
X dir->data_bits[0] = atoi(arg2);
X line_set();
X break;
X case STOP_BITS:
X dir->stop_bits[0] = atoi(arg2);
X line_set();
X break;
X case DUPLEX:
X dir->duplex[0] = arg2[0];
X line_set();
X break;
X case AUX:
X dir->aux[0] = str_rep(dir->aux[0], arg2);
X break;
X case HOT_KEY:
X param->hot_key = atoi(arg2);
X break;
X case ASCII_HOT:
X param->ascii_hot = str_rep(param->ascii_hot, arg2);
X break;
X case FLOW_CTRL:
X param->flow_ctrl = str_rep(param->flow_ctrl, arg2);
X break;
X case CR_IN:
X param->cr_in = str_rep(param->cr_in, arg2);
X break;
X case CR_OUT:
X param->cr_out = str_rep(param->cr_out, arg2);
X break;
X case LOGFILE:
X param->logfile = str_rep(param->logfile, arg2);
X break;
X case DUMPFILE:
X param->dumpfile = str_rep(param->dumpfile, arg2);
X break;
X case STRIP:
X param->strip = str_rep(param->strip, arg2);
X break;
X case LOCAL_ECHO:
X param->local_echo = str_rep(param->local_echo, arg2);
X break;
X case EXPAND:
X param->expand = str_rep(param->expand, arg2);
X break;
X case CR_DELAY:
X param->cr_delay = atoi(arg2);
X break;
X case PACE:
X param->pace = str_rep(param->pace, arg2);
X break;
X case CR_UP:
X param->cr_up = str_rep(param->cr_up, arg2);
X break;
X case LF_UP:
X param->lf_up = str_rep(param->lf_up, arg2);
X break;
X case TIMER:
X param->timer = atoi(arg2);
X break;
X case CR_DN:
X param->cr_dn = str_rep(param->cr_dn, arg2);
X break;
X case LF_DN:
X param->lf_dn = str_rep(param->lf_dn, arg2);
X break;
X default:
X break;
X }
X break;
X case QUERY: /* the QUERY commands */
X switch(arg1) {
X case TTY_NAME:
X if (modem->t_cur != -1)
X send_reply(modem->tty[modem->t_cur]);
X else
X send_reply("NONE");
X ret_code = 99;
X break;
X case MODEM_NAME:
X if (modem->m_cur != -1)
X send_reply(modem->mname[modem->m_cur]);
X else
X send_reply("NONE");
X ret_code = 99;
X break;
X default:
X break;
X }
X break;
X case IF: /* the IF commands */
X switch(arg1) {
X case CONNECTED:
X if (status->connected)
X ret_code = 1;
X break;
X case LOG_STATUS:
X if (status->log_status)
X ret_code = 1;
X break;
X case PRINTER_STATUS:
X if (status->print_status)
X ret_code = 1;
X break;
X default:
X break;
X }
X break;
X case DIAL:
X cmode();
X ld_code = '\0';
X s = arg2;
X if (strchr("+-@#", *s)) {
X ld_code = *s;
X s++;
X }
X
X if (arg1 == 1) { /* manual dial */
X dir->name[0] = str_rep(dir->number[0], s);
X dir->number[0] = str_rep(dir->number[0], s);
X dir->d_cur = 0;
X dir->q_num[0] = 0;
X }
X else {
X n = atoi(s);
X if (n == 0 || n > NUM_DIR) {
X tmode();
X break;
X }
X
X dir->d_cur = n;
X dir->q_num[0] = n;
X }
X dir->q_ld[0] = ld_code;
X dir->q_num[1] = -1;
X ret_code = dial_win(1);
X tmode();
X break;
X case REDIAL:
X cmode();
X entry = strtok(arg2, " ");
X for (i=0; i X if (entry == NULL) {
X dir->q_num[i] = -1;
X break;
X }
X
X ld_code = '\0';
X if (strchr("+-@#", *entry)) {
X ld_code = *entry;
X entry++;
X }
X
X n = atoi(entry);
X if (n > NUM_DIR || *dir->number[n] == '\0')
X continue;
X
X dir->q_ld[i] = ld_code;
X dir->q_num[i] = n;
X entry = strtok((char *) NULL, " \t");
X }
X ret_code = dial_win(10);
X tmode();
X break;
X case EXIT:
X pexit();
X break;
X case CLEAR_SCREEN:
X fixterm();
X erase();
X refresh();
X resetterm();
X break;
X case CHG_DIR:
X chdir(arg2);
X break;
X case HANG_UP:
X hang_up(QUIET);
X break;
X case PRINTER:
X if (status->print_status + arg1 == 1)
X lpr_toggle();
X break;
X case MODEM_BREAK:
X tty_break(fd);
X break;
X case SEND:
X do_xfer(arg1, UP_LOAD, arg2);
X break;
X case RECEIVE:
X do_xfer(arg1, DOWN_LOAD, arg2);
X break;
X case SCREEN_DUMP:
X screen_dump();
X break;
X case DATA_LOG:
X if (status->log_status + arg1 == 1) {
X if (arg1 == 1 && !strcmp(status->log_path, "NOT_DEFINED"))
X status->log_path = str_rep(status->log_path, param->logfile);
X log_toggle();
X }
X break;
X default:
X break;
X }
X if (ret_code != 99) {
X sprintf(buf, "%d", ret_code);
X send_reply(buf);
X }
X return;
X}
X
X/*
X * Send a string back to pcomm_cmd
X */
X
static void
send_reply(s)
char *s;
X{
X char buf[256];
X
X sprintf(buf, "%254.254s\n", s);
X if (ipc_write(status->cmd_ipc, buf, 256))
X fprintf(stderr, "Can't write to IPC\n");
X return;
X}
X
X/*
X * Put the screen in the "curses" mode
X */
X
static void
cmode()
X{
X void load_vs(), st_line();
X
X fixterm();
X load_vs();
X st_line("");
X return;
X}
X
X/*
X * Put the screen in the "terminal" mode
X */
X
static void
tmode()
X{
X extern int fd;
X void term_mode();
X
X if (fd != -1) {
X touchwin(stdscr);
X refresh();
X }
X resetterm();
X term_mode();
X return;
X}
X
X/*
X * Do the file transfers
X */
X
static void
do_xfer(type, up, files)
int type, up;
char *files;
X{
X int n, is_batch, num_extrnl;
X char buf[256], *strcpy(), *strcat();
X void xfer_win(), xfer_ascii(), do_extrnl();
X
X num_extrnl = (up == UP_LOAD) ? extrnl->up_entries : extrnl->dn_entries;
X
X is_batch = 0;
X switch(type) {
X case MODEM7:
X case YMODEM:
X case YMODEM_G: /* built-in batch protocols */
X is_batch++;
X /* FALLTHRU */
X case XMODEM:
X case XMODEM_1k: /* non-batch built-ins */
X cmode();
X if (up == UP_LOAD || !is_batch)
X xfer_win(files, up, type);
X else
X xfer_win("", up, type);
X tmode();
X break;
X case XASCII: /* ascii xfer, yuck! */
X xfer_ascii(files, up);
X break;
X case EXT_1:
X case EXT_2:
X case EXT_3: /* one of the externals */
X n = type -NUM_INTERNAL -1;
X if (n > num_extrnl)
X break;
X strcpy(buf, extrnl->command[up][n]);
X /* see if we need to add files */
X if (extrnl->prompt[up][n] == 'Y') {
X strcat(buf, " ");
X strcat(buf, files);
X }
X do_extrnl(buf);
X break;
X default:
X break;
X }
X return;
X}
END_OF_FILE
if test 7048 -ne `wc -c <'cmd.c'`; then
echo shar: \"'cmd.c'\" unpacked with wrong size!
fi
# end of 'cmd.c'
fi
if test -f 'd_lib.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'d_lib.c'\"
else
echo shar: Extracting \"'d_lib.c'\" \(6988 characters\)
sed "s/^X//" >'d_lib.c' <<'END_OF_FILE'
X/*
X * Routines to manipulate the dialing directory file pcomm.dial_dir
X */
X
X#include
X#include "dial_dir.h"
X#include "param.h"
X
X/*
X * Read the dialing directory. Returns a pointer to a static area
X * containing the DIAL_DIR structure. All of the entries are created
X * regardless of the number of physical entries in the file. Element
X * number zero is reserved for the "manual" entry. All errors are fatal.
X */
X
struct DIAL_DIR *
read_dir()
X{
X extern char *null_ptr;
X FILE *fp, *uid_fopen();
X int i, line, oops;
X char *str_dup(), buf[200], *temp_token, *str, *str_tok(), token[20];
X char message[80], *sep, *findfile();
X static struct DIAL_DIR d;
X void error_win();
X
X if ((d.d_path = findfile("pcomm.dial_dir")) == NULL)
X error_win(1, "Support file \"pcomm.dial_dir\" is missing", "or no read permission");
X
X if (!(fp = uid_fopen(d.d_path, "r"))) {
X sprintf(buf, "\"%s\" for read", d.d_path);
X error_win(1, "Can't open dialing directory file", buf);
X }
X
X sep = ";;---;;\n";
X line = 0;
X oops = 0;
X while (fgets(buf, 200, fp) != NULL) {
X line++;
X if (line > NUM_DIR)
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 /*
X * Parse the rest of the line. This is similar to using
X * the "real" strtok() function, but this version returns
X * a pointer to NULL if the token is missing. Note the use
X * of the array of field separators.
X */
X for (i=0; i<8; i++) {
X if (!(str = str_tok((char *) NULL, 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 d.name[line] = str_dup(str);
X break;
X case 1:
X d.number[line] = str_dup(str);
X break;
X case 2:
X d.baud[line] = (unsigned int) atoi(str);
X break;
X case 3:
X d.parity[line] = *str;
X break;
X case 4:
X d.data_bits[line] = atoi(str);
X break;
X case 5:
X d.stop_bits[line] = atoi(str);
X break;
X case 6:
X d.duplex[line] = *str;
X break;
X case 7:
X d.aux[line] = str_dup(str);
X break;
X }
X }
X if (oops)
X break;
X /* sanity checking */
X sprintf(token, "DIR_%d", line);
X if (strcmp(temp_token, token)) {
X sprintf(message, "is corrupted at line %d", line);
X oops++;
X break;
X }
X }
X fclose(fp);
X
X if (oops) {
X sprintf(buf, "Dialing directory file \"%s\"", d.d_path);
X error_win(1, buf, message);
X }
X d.d_entries = line;
X /* if empty database */
X if (!line) {
X sprintf(buf, "Dialing directory file \"%s\"", d.d_path);
X error_win(0, buf, "has no data");
X }
X /* fill in the rest with defaults */
X for (i=line+1; i<=NUM_DIR; i++) {
X d.name[i] = null_ptr;
X d.number[i] = null_ptr;
X d.baud[i] = param->d_baud;
X d.parity[i] = param->d_parity;
X d.data_bits[i] = param->d_data_bits;
X d.stop_bits[i] = param->d_stop_bits;
X d.duplex[i] = *param->d_duplex;
X d.aux[i] = null_ptr;
X }
X /* create an empty "manual" entry */
X d.name[0] = null_ptr;
X d.number[0] = null_ptr;
X d.baud[0] = param->d_baud;
X d.parity[0] = param->d_parity;
X d.data_bits[0] = param->d_data_bits;
X d.stop_bits[0] = param->d_stop_bits;
X d.duplex[0] = *param->d_duplex;
X d.aux[0] = null_ptr;
X /* create an empty queue */
X for (i=0; i X d.q_ld[i] = '\0';
X d.q_num[i] = -1;
X }

X /* the start up d_cur is 0 */
X d.d_cur = 0;
X return(&d);
X}
X
X/*
X * Update a dialing directory entry. Update only the one entry asked for,
X * not the entire image in memory. If the new entry is beyond the end of
X * the physical file, then fill in the holes, and update "dir->d_entries".
X * A non-zero return code means a non-fatal error.
X */
X
int
up_dir(entry)
int entry;
X{
X FILE *fp_in, *fp_out, *uid_fopen();
X int i;
X char *temp[NUM_DIR+1], buf[200], *str_dup(), *str_rep();
X void error_win(), free_ptr();
X
X /* open for read */
X if (!(fp_in = uid_fopen(dir->d_path, "r"))) {
X sprintf(buf, "\"%s\" for read", dir->d_path);
X error_win(1, "Can't open dialing directory file", buf);
X }
X /* read in a temporary version */
X i = 0;
X while (fgets(buf, 200, fp_in) != NULL)
X temp[++i] = str_dup(buf);
X
X fclose(fp_in);
X /* alter only 1 entry */
X sprintf(buf, "DIR_%d=%s;%s;%d-%c-%d-%d;%c;%s\n", entry,
X dir->name[entry], dir->number[entry], dir->baud[entry],
X dir->parity[entry], dir->data_bits[entry], dir->stop_bits[entry],
X dir->duplex[entry], dir->aux[entry]);
X
X if (entry <= dir->d_entries)
X temp[entry] = str_rep(temp[entry], buf);
X else
X temp[entry] = str_dup(buf);
X
X /* fill in holes if beyond end */
X if (entry > dir->d_entries+1) {
X for (i=dir->d_entries+1; i X sprintf(buf, "DIR_%d=;;%d-%c-%d-%d;%c;\n", i,
X param->d_baud, param->d_parity, param->d_data_bits,
X param->d_stop_bits, *param->d_duplex);
X temp[i] = str_dup(buf);
X }
X }
X /* update "dir->d_entries" */
X if (entry > dir->d_entries)
X dir->d_entries = entry;
X
X /* open for write */
X if (!(fp_out = uid_fopen(dir->d_path, "w"))) {
X for (i=1; i<=dir->d_entries; i++)
X free_ptr(temp[i]);
X sprintf(buf, "\"%s\"", dir->d_path);
X error_win(0, "No write permission on dialing directory file", buf);
X return(1);
X }
X /* put it back */
X for (i=1; i<=dir->d_entries; i++) {
X fputs(temp[i], fp_out);
X free_ptr(temp[i]);
X }
X
X fclose(fp_out);
X return(0);
X}
X
X/*
X * Delete a range of dialing directory entries. Actually, just copies
X * default (empty) entries in place of deleted entries. However, it will
X * shrink the file if deletions occur at the physical EOF. A non-zero
X * return code means a non-fatal error.
X */
X
int
del_dir(first, last)
int first, last;
X{
X FILE *fp_in, *fp_out, *uid_fopen();
X int i;
X char *temp[NUM_DIR+1], buf[200], *str_dup(), *str_rep();
X void error_win(), free_ptr();
X /* sanity checking */
X if (first > dir->d_entries)
X return(0);
X if (last > dir->d_entries)
X last = dir->d_entries;
X
X /* open for read */
X if (!(fp_in = uid_fopen(dir->d_path, "r"))) {
X sprintf(buf, "\"%s\" for read", dir->d_path);
X error_win(1, "Can't open dialing directory file", buf);
X }
X /* read in a temporary version */
X i = 0;
X while (fgets(buf, 200, fp_in) != NULL)
X temp[++i] = str_dup(buf);
X
X fclose(fp_in);
X /* delete the range of values */
X for (i=first; i<=last; i++) {
X sprintf(buf, "DIR_%d=;;%d-%c-%d-%d;%c;\n", i, param->d_baud,
X param->d_parity, param->d_data_bits, param->d_stop_bits,
X *param->d_duplex);
X temp[i] = str_rep(temp[i], buf);
X }
X /* shrink the file? */
X if (last >= dir->d_entries) {
X for (i=first; i<=last; i++)
X free_ptr(temp[i]);
X dir->d_entries = first-1;
X }
X /* open for write */
X if (!(fp_out = uid_fopen(dir->d_path, "w"))) {
X for (i=1; i<=dir->d_entries; i++)
X free_ptr(temp[i]);
X sprintf(buf, "\"%s\"", dir->d_path);
X error_win(0, "No write permission on dialing directory file", buf);
X return(1);
X }
X /* put it all back */
X for (i=1; i<=dir->d_entries; i++) {
X fputs(temp[i], fp_out);
X free_ptr(temp[i]);
X }
X
X fclose(fp_out);
X return(0);
X}
END_OF_FILE
if test 6988 -ne `wc -c <'d_lib.c'`; then
echo shar: \"'d_lib.c'\" unpacked with wrong size!
fi
# end of 'd_lib.c'
fi
if test -f 'd_menu.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'d_menu.c'\"
else
echo shar: Extracting \"'d_menu.c'\" \(7134 characters\)
sed "s/^X//" >'d_menu.c' <<'END_OF_FILE'
X/*
X * Routines for the dialing directory menu.
X */
X
X#include
X#include
X#include "config.h"
X#include "dial_dir.h"
X#include "misc.h"
X#include "param.h"
X
static int current = 1;
static void dir_scroll(), active_ld(), disp_ld();
X
X/*
X * Display the dialing directory and prompt for options. A non-zero return
X * code means we're ready to dial.
X */
X
int
dial_menu()
X{
X extern int xmc;
X WINDOW *dm_win, *newwin();
X char buf[5], ld_code;
X int ans, start, needs_repair, count, x, y, i, ret_code;
X void print_dir(), st_line();
X
X touchwin(stdscr);
X refresh();
X st_line("");
X
X dm_win = newwin(22, 78, 1, 1);
X mvwattrstr(dm_win, 1, 20, A_BOLD, "D I A L I N G D I R E C T O R Y");
X horizontal(dm_win, 2, 0, 78);
X mvwattrstr(dm_win, 3, 0, A_STANDOUT, " Name Number Baud P D S Dpx Auxiliary ");
X /* show 10 entries */
X dir_scroll(dm_win, current);
X
X mvwaddstr(dm_win, 15, 4, "==>");
X mvwattrch(dm_win, 15, 14, A_BOLD, 'R');
X waddstr(dm_win, " Revise");
X mvwattrch(dm_win, 15, 34, A_BOLD, 'M');
X waddstr(dm_win, " Manual Dialing");
X mvwaddstr(dm_win, 15, 55, "Entry to Dial");
X
X mvwattrch(dm_win, 16, 14, A_BOLD, 'P');
X waddstr(dm_win, " LD Codes");
X mvwattrch(dm_win, 16, 34, A_BOLD, 'D');
X waddstr(dm_win, " Delete Entry");
X mvwattrstr(dm_win, 16, 55, A_BOLD, "");
X waddstr(dm_win, " Scroll Down");
X
X#ifdef OLDCURSES
X mvwattrstr(dm_win, 17, 14, A_BOLD, "U/N");
X#else /* OLDCURSES */
X mvwattrstr(dm_win, 17, 14, A_BOLD, "/");
X#endif /* OLDCURSES */
X waddstr(dm_win, " Page");
X mvwattrch(dm_win, 17, 34, A_BOLD, 'L');
X waddstr(dm_win, " Print Entries");
X mvwattrstr(dm_win, 17, 55, A_BOLD, "");
X waddstr(dm_win, " Exit");
X
X mvwaddstr(dm_win, 19, 4, "LD Codes Active:");

X /* show which LD codes are active */
X active_ld(dm_win);
X
X box(dm_win, VERT, HORZ);
X y = 15;
X x = 8;
X wmove(dm_win, 15, 8);
X wrefresh(dm_win);
X
X#ifndef OLDCURSES
X keypad(dm_win, TRUE);
X#endif /* OLDCURSES */
X /* prompt for options */
X count = 0;
X ld_code = '\0';
X ret_code = 0;
X do {
X needs_repair = 0;
X ans = wgetch(dm_win);
X /* get an entry number */
X if (ans >= '0' && ans <= '9') {
X if (count > 2) {
X beep();
X continue;
X }
X buf[count] = (char) ans;
X waddch(dm_win, (chtype) ans);
X wrefresh(dm_win);
X count++;
X continue;
X }
X switch (ans) {
X case DEL:
X case BS: /* do our own backspace */
X if (!count) {
X beep();
X break;
X }
X count--;
X if (!count)
X ld_code = '\0';
X buf[count] = '\0';
X getyx(dm_win, y, x);
X x--;
X wmove(dm_win, y, x);
X waddch(dm_win, (chtype) ' ');
X wmove(dm_win, y, x);
X wrefresh(dm_win);
X break;
X#ifndef OLDCURSES

X case KEY_UP:
X#endif /* OLDCURSES */
X case 'u':
X case 'U': /* up arrow key */
X if (current == 1) {
X beep();
X break;
X }
X start = current - 10;
X if (start < 1)
X start = 1;
X current = start;
X dir_scroll(dm_win, start);
X break;
X#ifndef OLDCURSES
X case KEY_DOWN:
X case '\n':
X#endif /* OLDCURSES */
X case 'n':
X case 'N': /* down arrow key */
X if (current == NUM_DIR-9) {
X beep();
X break;
X }
X start = current + 10;
X if (start > NUM_DIR-9)
X start = NUM_DIR-9;
X current = start;
X dir_scroll(dm_win, start);
X break;
X case '\r': /* key */
X if (!count) {
X if (current == NUM_DIR-9) {
X beep();
X break;
X }
X current++;
X if (current > NUM_DIR-9)
X current = NUM_DIR-9;
X dir_scroll(dm_win, current);
X }
X /*
X * The is used for the scroll-down-one-line
X * function, and to terminate numeric input.
X */
X else {
X buf[count] = '\0';
X i = atoi(buf);
X if (!i || i > NUM_DIR) {
X beep();
X mvwaddstr(dm_win, 15, 8, " ");
X x = 8;
X count = 0;
X break;
X }
X dir->q_ld[0] = ld_code;
X dir->q_num[0] = i;
X dir->d_cur = i;
X
X /* end of queue marker */
X dir->q_num[1] = -1;
X
X ret_code++;
X break;
X }
X break;
X case 'r':
X case 'R': /* revise */
X if (revise()) {
X active_ld(dm_win);
X dir_scroll(dm_win, current);
X }
X touchwin(dm_win);
X break;
X case 'p': /* display LD codes */
X case 'P':
X disp_ld();
X touchwin(dm_win);
X needs_repair++;
X break;
X case 'd':
X case 'D': /* delete a range of entries */
X if (delete())
X dir_scroll(dm_win, current);
X touchwin(dm_win);
X break;
X case 'm':
X case 'M': /* manual dial */
X if (manual()) {
X ret_code++;
X break;
X }
X touchwin(dm_win);
X needs_repair++;
X break;
X case 'l':
X case 'L': /* print the entries */
X print_dir();
X touchwin(dm_win);
X needs_repair++;
X break;
X case '+': /* LD codes */
X case '-':
X case '@':
X case '#':
X waddch(dm_win, (chtype) ans);
X wrefresh(dm_win);
X ld_code = (char) ans;
X continue;
X case ESC: /* key (exit) */
X break;
X default:
X beep();
X }
X if (ret_code)
X break;
X /* magic cookie terminal? */
X if (xmc > 0 && needs_repair) {
X clear_line(dm_win, 1, 0, FALSE);
X clear_line(dm_win, 3, 0, FALSE);
X wrefresh(dm_win);
X mvwattrstr(dm_win, 1, 20, A_BOLD, "D I A L I N G D I R E C T O R Y");
X mvwattrstr(dm_win, 3, 0, A_STANDOUT, " Name Number Baud P D S Dpx Auxiliary ");
X box(dm_win, VERT, HORZ);
X }
X wmove(dm_win, y, x);
X wrefresh(dm_win);
X } while (ans != ESC);
X
X werase(dm_win);
X wrefresh(dm_win);
X delwin(dm_win);
X if (ret_code) {
X touchwin(stdscr);
X refresh();
X }
X return(ret_code);
X}
X
X/*
X * Scroll the dialing directory. Actually, we're not doing a real scroll
X * function on the screen, we're just repainting 10 lines.
X */
X
static void
dir_scroll(win, start)
WINDOW *win;
int start;
X{
X int i;
X
X wmove(win, 4, 0);
X for (i=start; i X wprintw(win,
X "%4d- %-20.20s %18.18s %5d-%c-%d-%d %c %-14.14s\n", i,
X dir->name[i], dir->number[i], dir->baud[i], dir->parity[i],
X dir->data_bits[i], dir->stop_bits[i], dir->duplex[i],
X dir->aux[i]);
X box(win, VERT, HORZ);
X return;
X}
X
X/*
X * Display the Long Distance codes. Press any key to continue.
X */
X
static void
disp_ld()
X{
X WINDOW *ld_win, *newwin();
X
X ld_win = newwin(12, 30, 0, 0);
X mvwaddstr(ld_win, 1, 5, "Long Distance Codes\n");
X horizontal(ld_win, 2, 0, 30);
X mvwprintw(ld_win, 3, 2, "+ %-20.20s", param->ld_plus);
X mvwprintw(ld_win, 5, 2, "- %-20.20s", param->ld_minus);
X mvwprintw(ld_win, 7, 2, "@ %-20.20s", param->ld_at);
X mvwprintw(ld_win, 9, 2, "# %-20.20s", param->ld_pound);
X box(ld_win, VERT, HORZ);
X
X mvwaddstr(ld_win, 11, 8, " Press any key ");
X wmove(ld_win, 11, 29);
X wrefresh(ld_win);
X wgetch(ld_win);
X /* it overlaps, so erase it */
X werase(ld_win);
X wrefresh(ld_win);
X delwin(ld_win);
X return;
X}
X
X/*
X * Display which of the Long Distance codes are active.
X */
X
static void
active_ld(win)
WINDOW *win;
X{
X mvwaddstr(win, 19, 21, " ");
X wmove(win, 19, 21);
X /* a NULL means it's not active */
X if (*param->ld_plus != '\0')
X waddstr(win, "+ ");
X if (*param->ld_minus != '\0')
X waddstr(win, "- ");
X if (*param->ld_at != '\0')
X waddstr(win, "@ ");
X if (*param->ld_pound != '\0')
X waddstr(win, "# ");
X return;
X}
END_OF_FILE
if test 7134 -ne `wc -c <'d_menu.c'`; then
echo shar: \"'d_menu.c'\" unpacked with wrong size!
fi
# end of 'd_menu.c'
fi
if test -f 'input.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'input.c'\"
else
echo shar: Extracting \"'input.c'\" \(7330 characters\)
sed "s/^X//" >'input.c' <<'END_OF_FILE'
X/*
X * The input routines.
X */
X
X#include
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X#include "status.h"
X#include "vcs.h"
X
static int add_lf;
static void vs_scroll();
static FILE *logfp = (FILE *) NULL;
static FILE *lprfp = (FILE *) NULL;
X
X/*
X * Read the serial port and write the characters to the screen. Watch
X * for changes in status structure to toggle the fancy options.
X * Writes the characters received to a virtual screen buffer.
X */
X
void
tty_input()
X{
X extern int fd;
X register int in_cnt, out_cnt;
X char c, *bufp, in_buf[INPUT_BUF], out_buf[INPUT_BUF*2];
X void vs_putchar();
X
X /* here we go... */
X if ((in_cnt = read(fd, in_buf, INPUT_BUF)) <= 0)
X return;
X
X /*
X * If we're doing a script, send a duplicate down the pipe
X */
X if (status->dup_fd != -1)
X write(status->dup_fd, in_buf, in_cnt);
X
X /* "peel" the buffer one at a time */
X out_cnt = 0;
X bufp = in_buf;
X add_lf = !strcmp(param->cr_in, "CR/LF");
X while (--in_cnt >= 0) {
X c = *bufp++ & 0xff;
X /* send to logfile? */
X if (status->log_status) {
X if (c == '\r' && add_lf)
X putc('\n', logfp);
X /* no carriage returns in logfile */
X if (c != '\r')
X putc(c, logfp);
X }
X /* send to printer too? */
X if (status->print_status)
X putc(c, lprfp);
X
X /* put a char in virtual screen */
X vs_putchar(c);
X
X /* build the output buffer */
X out_buf[out_cnt++] = c;
X if (c == '\r' && add_lf)
X out_buf[out_cnt++] = '\n';
X
X /* output in smaller chunks */
X if (out_cnt >= OUTPUT_BUF) {
X write(1, out_buf, out_cnt);
X out_cnt = 0;
X }
X }
X if (out_cnt)
X write(1, out_buf, out_cnt);
X
X return;
X}
X
X/*
X * Put a character in the virtual screen. This routine saves incoming
X * characters in a two dimensional buffer designed to mimic the real
X * screen.
X */
X
void
vs_putchar(c)
char c;
X{
X register int i;
X extern int vcs_param[NUM_VCS][5], vcs_opt[NUM_VCS][10];
X char *memset();
X int tab_stop;
X
X switch (vcs_filter(c)) {
X case MAYBE: /* wait and see... */
X break;
X case 256+HOME: /* home virtual screen "cursor" */
X status->row = 0;
X status->col = 0;
X break;
X case 256+CLR_EOL: /* clear to end of line */
X memset(&status->vs[status->row][status->col], ' ', status->max_col - status->col);
X status->col = status->max_col -1;
X break;
X case 256+CLR_EOS: /* clear to end of screen */
X memset(&status->vs[status->row][status->col], ' ', status->max_col - status->col);
X for (i=status->row+1; imax_row; i++)
X memset(status->vs[i], ' ', status->max_col);
X status->row = status->max_row -1;
X status->col = status->max_col -1;
X break;
X case 256+CLEAR: /* clear all and home "cursor" */
X for (i=0; imax_row; i++)
X memset(status->vs[i], ' ', status->max_col);
X status->row = 0;
X status->col = 0;
X break;
X case 256+MV_UP: /* move "cursor" up */
X status->row--;
X if (status->row < 0)
X status->row = 0;
X break;
X case 256+MV_DOWN: /* move "cursor" down */
X status->row++;
X if (status->row >= status->max_row)
X status->row = status->max_row -1;
X break;
X case 256+MV_RIGHT: /* move "cursor" right */
X status->col++;
X if (status->col >= status->max_col)
X status->col = status->max_col -1;
X break;
X case 256+MV_LEFT: /* move "cursor" left */
X case BS: /* non destructive back space */
X status->col--;
X if (status->col < 0)
X status->col = 0;
X break;
X case 256+MV_DIRECT: /* direct cursor movement */
X status->row = vcs_param[MV_DIRECT][0];
X status->col = vcs_param[MV_DIRECT][1];
X
X /* if "add one" and "decimal" */
X if (vcs_opt[MV_DIRECT][0] && vcs_opt[MV_DIRECT][1]) {
X status->row--;
X status->col--;
X }
X /* if "character" */
X if (vcs_opt[MV_DIRECT][2]) {
X /* if "add offset" */
X if (vcs_opt[MV_DIRECT][3]) {
X status->row -= vcs_opt[MV_DIRECT][5];
X status->col -= vcs_opt[MV_DIRECT][5];
X }
X /* if "subtract offset" */
X if (vcs_opt[MV_DIRECT][4]) {
X status->row += vcs_opt[MV_DIRECT][5];
X status->col += vcs_opt[MV_DIRECT][5];
X }
X status->row--;
X status->col--;
X }
X /* sanity check... */
X if (status->row < 0)
X status->row = 0;
X if (status->col < 0)
X status->col = 0;
X if (status->row >= status->max_row)
X status->row = status->max_row -1;
X if (status->col >= status->max_col)
X status->col = status->max_col -1;
X break;
X case 0:
X case 7: /* skip NULL and "bell" character */
X break;
X case '\t': /* tab character */
X tab_stop = status->col + 8 - (status->col % 8);
X /* if wrap around */
X if (tab_stop >= status->max_col) {
X /* spaces up to eol */
X memset(&status->vs[status->row][status->col], ' ', status->max_col - status->col);
X status->row++;
X if (status->row >= status->max_row)
X vs_scroll();
X
X /* the remainder of the tab */
X status->col = tab_stop - status->max_col;
X }
X else {
X memset(&status->vs[status->row][status->col], ' ', tab_stop - status->col);
X status->col = tab_stop;
X }
X break;
X case '\r': /* carriage return */
X status->col = 0;
X if (!add_lf)
X break;
X /* FALLTHRU */
X case '\n': /* line feed */
X status->row++;
X if (status->row >= status->max_row)
X vs_scroll();
X break;
X default: /* a normal character */
X status->vs[status->row][status->col] = c;
X status->col++;
X /* wrap around */
X if (status->col >= status->max_col) {
X status->col = 0;
X status->row++;
X if (status->row >= status->max_row)
X vs_scroll();
X }
X break;
X }
X return;
X}
X
X/*
X * Do a software scroll on the virtual screen. Does not alter the
X * "col" variable.
X */
X
static void
vs_scroll()
X{
X char *memset();
X /* move 'em up 1 line */
X#ifdef MEMMOVE
X MEMMOVE(status->vs[0], status->vs[1], (status->max_row -1) * MAX_COL);
X#else /* MEMMOVE */
X register int i;
X char *strcpy();
X
X for (i=0; imax_row-1; i++)
X strcpy(status->vs[i], status->vs[i+1]);
X#endif /* MEMMOVE */
X /* clear the bottom line */
X memset(status->vs[status->max_row-1], ' ', status->max_col);
X
X status->row = status->max_row -1;
X return;
X}
X
X/*
X * A short-cut for charcters that are "echoed" in the half duplex
X * mode. Since the TTY driver is putting the characters on the
X * screen (rather than being sent back by the modem), they need
X * to be faked as modem input.
X */
X
void
half_duplex(c)
char c;
X{
X /* send to logfile? */
X if (status->log_status) {
X if (c == '\r' && add_lf)
X putc('\n', logfp);
X /* no carriage returns in logfile */
X if (c != '\r')
X putc(c, logfp);
X }
X /* send to printer too? */
X if (status->print_status)
X putc(c, lprfp);
X
X /* put a char in virtual screen */
X vs_putchar(c);
X return;
X}
X
X/*
X * Toggle the printer log
X */
X
void
lpr_toggle()
X{
X FILE *n_popen();
X
X status->print_status = status->print_status ? 0 : 1;
X
X if (status->print_status && lprfp == NULL) {
X if (!(lprfp = n_popen(LPR, "w")))
X status->print_status = 0;
X }
X
X if (!status->print_status && lprfp != NULL) {
X putc('\f', lprfp);
X n_pclose(lprfp);
X lprfp = (FILE *) NULL;
X }
X return;
X}
X
X/*
X * Toggle the data log
X */
X
void
log_toggle()
X{
X FILE *uid_fopen();
X
X status->log_status = status->log_status ? 0 : 1;
X
X if (status->log_status && logfp == NULL) {
X if (!(logfp = uid_fopen(status->log_path, "a")))
X status->log_status = 0;
X }
X
X if (!status->log_status && logfp != NULL) {
X fclose(logfp);
X logfp = (FILE *) NULL;
X }
X return;
X}
END_OF_FILE
if test 7330 -ne `wc -c <'input.c'`; then
echo shar: \"'input.c'\" unpacked with wrong size!
fi
# end of 'input.c'
fi
if test -f 'p_lib.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'p_lib.c'\"
else
echo shar: Extracting \"'p_lib.c'\" \(7341 characters\)
sed "s/^X//" >'p_lib.c' <<'END_OF_FILE'
X/*
X * Routines to manipulate the pcomm.param file.
X */
X
X#include
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
struct PARAM *
read_param()
X{
X FILE *fp, *uid_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",
X "D_DATA_BITS", "D_STOP_BITS", "HOT_KEY", "ASCII_HOT", "D_DUPLEX",
X "FLOW_CTRL", "CR_IN", "CR_OUT", "LOGFILE", "DUMPFILE", "STRIP",
X "PAUSE_CHAR", "CR_CHAR", "CTRL_CHAR", "ESC_CHAR", "BRK_CHAR",
X "ABORT", "C_DELAY", "R_DELAY", "LOCAL_ECHO", "EXPAND", "CR_DELAY",
X "PACE", "CR_UP", "LF_UP", "TIMER", "CR_DN", "LF_DN", "LD_PLUS",
X "LD_MINUS", "LD_AT", "LD_POUND", "MAC_1", "MAC_2", "MAC_3",
X "MAC_4", "MAC_5", "MAC_6", "MAC_7", "MAC_8", "MAC_9", "MAC_0"};
X static struct PARAM p;
X void error_win();
X
X if ((p.p_path = findfile("pcomm.param")) == NULL)
X error_win(1, "Support file \"pcomm.param\" is missing", "or no read permission");
X
X if (!(fp = uid_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 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 = (unsigned int) atoi(str);
X break;
X case LINE_SET+1:
X p.d_parity = *str;
X break;
X case LINE_SET+2:
X p.d_data_bits = atoi(str);
X break;
X case LINE_SET+3:
X p.d_stop_bits = atoi(str);
X break;
X
X /* used in term_setup() */
X case TERM_SETUP:
X p.hot_key = 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_ctrl = 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.local_echo = 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". A non-zero return code means non-fatal
X * error.
X */
X
int
up_param()
X{
X FILE *fp, *uid_fopen();
X char buf[80];
X void error_win();
X /* open for write */
X if (!(fp = uid_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_DATA_BITS=%d\n", param->d_data_bits);
X fprintf(fp, "D_STOP_BITS=%d\n", param->d_stop_bits);
X fprintf(fp, "HOT_KEY=%d\n", param->hot_key);
X fprintf(fp, "ASCII_HOT=%s\n", param->ascii_hot);
X fprintf(fp, "D_DUPLEX=%s\n", param->d_duplex);
X fprintf(fp, "FLOW_CTRL=%s\n", param->flow_ctrl);
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, "LOCAL_ECHO=%s\n", param->local_echo);
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}
END_OF_FILE
if test 7341 -ne `wc -c <'p_lib.c'`; then
echo shar: \"'p_lib.c'\" unpacked with wrong size!
fi
# end of 'p_lib.c'
fi
if test -f 's_modem.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'s_modem.c'\"
else
echo shar: Extracting \"'s_modem.c'\" \(6948 characters\)
sed "s/^X//" >'s_modem.c' <<'END_OF_FILE'
X/*
X * Display the modem setup, query for changes. A non-zero return code
X * means something was changed.
X */
X
X#include
X#include
X#include "misc.h"
X#include "modem.h"
X
static int mod_prompt();
static void disp_modem();
X
int
modem_setup()
X{
X WINDOW *mo_win, *newwin();
X int i, j, ret_code;
X char *ans, *str_rep(), *str_prompt(), *menu_prompt();
X extern char *v_yn[];
X /* the current modem */
X j = 0;
X if (modem->m_cur != -1)
X j = modem->m_cur;
X
X mo_win = newwin(23, 80, 0, 0);
X
X horizontal(mo_win, 0, 0, 33);
X mvwattrstr(mo_win, 0, 34, A_BOLD, "Modem Setup");
X horizontal(mo_win, 0, 46, 34);
X /* display the current settings */
X disp_modem(mo_win, j);
X horizontal(mo_win, 19, 0, 80);
X mvwattrstr(mo_win, 20, 0, A_BOLD, "OPTION ==> ");
X mvwaddstr(mo_win, 20, 58, "Press to return");
X wmove(mo_win, 20, 12);
X touchwin(mo_win);
X wrefresh(mo_win);
X /* get the option number */
X ret_code = 0;
X while ((i = get_num(mo_win, 2)) != -1) {
X switch (i) {
X case 1:
X j = mod_prompt(mo_win);
X break;
X case 2:
X if ((ans = str_prompt(mo_win, 3, 39, "Modem init string", "sent to the modem once")) != NULL) {
X modem->init[j] = str_rep(modem->init[j], ans);
X ret_code++;
X }
X break;
X case 3:
X if ((ans = str_prompt(mo_win, 4, 39, "Dialing command", "")) != NULL) {
X modem->dial[j] = str_rep(modem->dial[j], ans);
X ret_code++;
X }
X break;
X case 4:
X if ((ans = str_prompt(mo_win, 5, 39, "Dialing cmd suffix", "typically the character")) != NULL) {
X modem->suffix[j] = str_rep(modem->suffix[j], ans);
X ret_code++;
X }
X break;
X case 5:
X if ((ans = str_prompt(mo_win, 6, 39, "Hang up string", "")) != NULL) {
X modem->hang_up[j] = str_rep(modem->hang_up[j], ans);
X ret_code++;
X }
X break;
X case 6:
X if ((ans = menu_prompt(mo_win, 7, 39, "Auto Baud detect", v_yn)) != NULL) {
X modem->auto_baud[j] = *ans;
X ret_code++;
X }
X break;
X case 7:
X if ((ans = str_prompt(mo_win, 8, 39, "300 baud connect string", "")) != NULL) {
X modem->con_3[j] = str_rep(modem->con_3[j], ans);
X ret_code++;
X }
X break;
X case 8:
X if ((ans = str_prompt(mo_win, 9, 39, "1200 baud connect string", "")) != NULL) {
X modem->con_12[j] = str_rep(modem->con_12[j], ans);
X ret_code++;
X }
X break;
X case 9:
X if ((ans = str_prompt(mo_win, 10, 39, "2400 baud connect string", "")) != NULL) {
X modem->con_24[j] = str_rep(modem->con_24[j], ans);
X ret_code++;
X }
X break;
X case 10:
X if ((ans = str_prompt(mo_win, 11, 39, "4800 baud connect string", "")) != NULL) {
X modem->con_48[j] = str_rep(modem->con_48[j], ans);
X ret_code++;
X }
X break;
X case 11:
X if ((ans = str_prompt(mo_win, 12, 39, "9600 baud connect string", "")) != NULL) {
X modem->con_96[j] = str_rep(modem->con_96[j], ans);
X ret_code++;
X }
X break;
X case 12:
X if ((ans = str_prompt(mo_win, 13, 39, "19200 baud connect string", "")) != NULL) {
X modem->con_192[j] = str_rep(modem->con_192[j], ans);
X ret_code++;
X }
X break;
X case 13:
X if ((ans = str_prompt(mo_win, 14, 39, "38400 baud connect string", "")) != NULL) {
X modem->con_384[j] = str_rep(modem->con_384[j], ans);
X ret_code++;
X }
X break;
X case 14:
X if ((ans = str_prompt(mo_win, 15, 39, "No connect string 1", "")) != NULL) {
X modem->no_con1[j] = str_rep(modem->no_con1[j], ans);
X ret_code++;
X }
X break;
X case 15:
X if ((ans = str_prompt(mo_win, 16, 39, "No connect string 2", "")) != NULL) {
X modem->no_con2[j] = str_rep(modem->no_con2[j], ans);
X ret_code++;
X }
X break;
X case 16:
X if ((ans = str_prompt(mo_win, 17, 39, "No connect string 3", "")) != NULL) {
X modem->no_con3[j] = str_rep(modem->no_con3[j], ans);
X ret_code++;
X }
X break;
X case 17:
X if ((ans = str_prompt(mo_win, 18, 39, "No connect string 4", "")) != NULL) {
X modem->no_con4[j] = str_rep(modem->no_con4[j], ans);
X ret_code++;
X }
X break;
X default:
X beep();
X }
X /* clear the previous prompts */
X mvwaddstr(mo_win, 20, 12, " ");
X clear_line(mo_win, 21, 0, FALSE);
X clear_line(mo_win, 22, 0, FALSE);
X wmove(mo_win, 20, 12);
X wrefresh(mo_win);
X }
X delwin(mo_win);
X return(ret_code);
X}
X
X/*
X * Prompts for the modem name. The user selects the currently showing
X * choice by hitting a carriage return. Returns the modem entry number.
X * DOES NOT change the value of modem->m_cur.
X */
X
static int
mod_prompt(win)
WINDOW *win;
X{
X char ans;
X int i;
X void disp_modem();
X /* print prompt lines */
X mvwaddstr(win, 22, 0, "Press any key to change, or to accept");
X mvwaddstr(win, 21, 0, "Modem name: ");
X /* show current choice */
X i = 0;
X if (modem->m_cur != -1)
X i = modem->m_cur;
X mvwprintw(win, 21, 12, "%-30.30s", modem->mname[i]);
X wmove(win, 21, 12);
X wrefresh(win);
X /* show the choices one at a time */
X while ((ans = wgetch(win)) != '\r') {
X i++;
X if (*modem->mname[i] == '\0')
X i = 0;
X if (ans == ESC)
X return(0);
X mvwprintw(win, 21, 12, "%-30.30s", modem->mname[i]);
X wmove(win, 21, 12);
X wrefresh(win);
X }
X /* display the new values */
X disp_modem(win, i);
X /* display the name in bold */
X clear_line(win, 2, 39, FALSE);
X wrefresh(win);
X mvwattrstr(win, 2, 39, A_BOLD, modem->mname[i]);
X mvwprintw(win, 2, 25, "(%d of %d) ", i+1, modem->m_entries);
X
X return(i);
X}
X
X/*
X * Show the current settings for the given modem entry number.
X */
X
static void
disp_modem(w, i)
WINDOW *w;
int i;
X{
X mvwprintw(w, 2, 11, "1) Modem name ............. %-39.39s", modem->mname[i]);
X mvwprintw(w, 2, 25, "(%d of %d) ", i+1, modem->m_entries);
X mvwprintw(w, 3, 11, "2) Modem init string ...... %-39.39s", modem->init[i]);
X mvwprintw(w, 4, 11, "3) Dialing command ........ %-39.39s", modem->dial[i]);
X mvwprintw(w, 5, 11, "4) Dialing cmd suffix ..... %-39.39s", modem->suffix[i]);
X mvwprintw(w, 6, 11, "5) Hang up string ......... %-39.39s", modem->hang_up[i]);
X mvwprintw(w, 7, 11, "6) Auto baud detect ....... %c", modem->auto_baud[i]);
X mvwprintw(w, 8, 11, "7) 300 baud connect ....... %-39.39s", modem->con_3[i]);
X mvwprintw(w, 9, 11, "8) 1200 baud connect ...... %-39.39s", modem->con_12[i]);
X mvwprintw(w, 10, 11, "9) 2400 baud connect ...... %-39.39s", modem->con_24[i]);
X mvwprintw(w, 11, 10, "10) 4800 baud connect ...... %-39.39s", modem->con_48[i]);
X mvwprintw(w, 12, 10, "11) 9600 baud connect ...... %-39.39s", modem->con_96[i]);
X mvwprintw(w, 13, 10, "12) 19200 baud connect ..... %-39.39s", modem->con_192[i]);
X mvwprintw(w, 14, 10, "13) 38400 baud connect ..... %-39.39s", modem->con_384[i]);
X mvwprintw(w, 15, 10, "14) No connect string 1 .... %-39.39s", modem->no_con1[i]);
X mvwprintw(w, 16, 10, "15) No connect string 2 .... %-39.39s", modem->no_con2[i]);
X mvwprintw(w, 17, 10, "16) No connect string 3 .... %-39.39s", modem->no_con3[i]);
X mvwprintw(w, 18, 10, "17) No connect string 4 .... %-39.39s", modem->no_con4[i]);
X return;
X}
END_OF_FILE
if test 6948 -ne `wc -c <'s_modem.c'`; then
echo shar: \"'s_modem.c'\" unpacked with wrong size!
fi
# end of 's_modem.c'
fi
if test -f 'terminal.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'terminal.c'\"
else
echo shar: Extracting \"'terminal.c'\" \(8778 characters\)
sed "s/^X//" >'terminal.c' <<'END_OF_FILE'
X/*
X * Start the terminal dialogue, scan the TTY, keyboard, and the "script"
X * for input, watch for the hot key so we can execute an option.
X */
X
X#include
X#include
X#include
X#include "config.h"
X#include "dial_dir.h"
X#include "ipc.h"
X#include "misc.h"
X#include "modem.h"
X#include "param.h"
X#include "status.h"
X#include "xmodem.h"
X
X#ifdef BSD
X#ifndef SIGCLD
X#define SIGCLD SIGCHLD
X#endif /* SIGCLD */
X#include
X#else /* BSD */
X#include
X#endif /* BSD */
X
X#ifdef UNIXPC
X#include
X#endif /* UNIXPC */
X
static void key_input();
static int cr_lf;
X
void
terminal(script)
char *script;
X{
X extern int fd;
X int ret_code;
X void tty_input(), st_line(), term_mode(), cmd_input(), do_script();
X void is_active(), ipc_init();
X
X ipc_init(fd, status->cmd_ipc);
X /* if not starting with -f option */
X if (dir->q_num[0] == -1) {
X erase();
X refresh();
X st_line("");
X }
X /* put stdin/stdout in terminal mode */
X resetterm();
X term_mode();
X cr_lf = !strcmp(param->cr_out, "CR/LF");
X
X /* play a script from command line */
X if (script != NULL && *script != '\0')
X do_script(script);
X
X /* the main loop ! */
X /* CONSTCOND */
X while (1) {
X ret_code = ipc_poll(fd, status->cmd_ipc);
X
X if (ret_code & TTY_READY)
X tty_input();
X
X if (ret_code & KEY_READY)
X key_input();
X
X /*
X * This is the reason for the 1 sec "timeout" of the
X * poll/select call... to periodically check the status
X * of the "script" for input.
X */
X if (status->dup_fd != -1)
X is_active();
X /* do a command from a script */
X if (ret_code & CMD_READY)
X cmd_input();
X }
X /* NOTREACHED */
X}
X
X/*
X * There is something ready to be read from the keyboard.
X */
X
static void
key_input()
X{
X extern int fd;
X int i, k;
X char c, lf=10, *str_rep(), *keymac, *script, *script_menu();
X void help_screen(), line_set(), n_shell(), load_vs(), send_str();
X void release_port(), list_dir(), pexit(), st_line(), chg_dir();
X void screen_dump(), info(), term_mode(), macro(), stop_script();
X void setup_menu(), xfer_menu(), data_logging(), pass_thru();
X void half_duplex(), do_script(), vs_clear(), tty_restart();
X void log_toggle(), lpr_toggle();
X
X read(0, &c, 1);
X c &= 0x7f;
X /* stop the script? */
X if (status->dup_fd != -1 && c == ESC) {
X stop_script();
X return;
X }
X /* is it the hot key? */
X if (c == param->hot_key) {
X
X script = NULL;
X /*
X * Put the terminal in the curses mode, load the
X * virtual screen and add the status line at the bottom.
X */
X fixterm();
X load_vs();
X st_line("");
X#ifndef OLDCURSES
X keypad(stdscr, TRUE);
X#endif /* OLDCURSES */
X i = wgetch(stdscr);
X /* map an additional hot key to -1 */
X if (i == param->hot_key)
X i = -1;
X
X keymac = "";
X /* look for options */
X k = -1;
X switch (i) {
X case -1: /* 2 "hots" means send 1 */
X k = param->hot_key;
X break;
X case '0': /* help screen */
X help_screen(param->ascii_hot);
X break;
X case 'd':
X case 'D': /* dialing directory */
X if (dial_menu()) {
X if (!dial_win(25))
X script = dir->aux[0];
X }
X break;
X case 'r':
X case 'R': /* redial */
X if (redial()) {
X if (!dial_win(25))
X script = dir->aux[0];
X }
X break;
X case 'm':
X case 'M': /* keyboard macros */
X macro();
X break;
X case 'p':
X case 'P': /* line settings */
X if (ls_menu())
X line_set();
X break;
X case 'x':
X case 'X': /* exit */
X pexit();
X break;
X case '4': /* Unix gateway */
X n_shell();
X break;
X case '5': /* Command files */
X script = script_menu();
X break;
X case 'i':
X case 'I': /* program info screen */
X info(MANUAL_CLEAR);
X break;
X case 's': /* setup menu */
X case 'S':
X setup_menu();
X break;
X case 'c': /* clear the screen */
X case 'C':
X erase();
X vs_clear(0);
X break;
X case 'b':
X case 'B': /* change directory */
X chg_dir();
X break;
X case 'e':
X case 'E': /* toggle duplex */
X if (dir->duplex[0] == 'F')
X dir->duplex[0] = 'H';
X else
X dir->duplex[0] = 'F';
X
X /* show changes */
X st_line("");
X k = wait_key(stdscr, 2);
X break;
X case 'h':
X case 'H': /* hang up phone */
X release_port(VERBOSE);
X break;
X case 'l':
X case 'L': /* print toggle */
X lpr_toggle();
X /* show changes */
X st_line("");
X k = wait_key(stdscr, 2);
X break;
X case '3': /* toggle CR - CR/LF */
X if (!strcmp(param->cr_in, "CR"))
X param->cr_in = str_rep(param->cr_in, "CR/LF");
X else
X param->cr_in = str_rep(param->cr_in, "CR");
X /* show changes */
X st_line("");
X k = wait_key(stdscr, 2);
X break;
X case '7': /* break key */
X if (fd != -1)
X tty_break(fd);
X
X st_line(" break");
X break;
X#ifndef OLDCURSES
X case KEY_UP:
X#endif /* OLDCURSES */
X case 'u':
X case 'U': /* send files */
X xfer_menu(UP_LOAD);
X break;
X#ifndef OLDCURSES
X case KEY_DOWN:
X case '\n':
X#endif /* OLDCURSES */
X case 'n':
X case 'N': /* receive files */
X xfer_menu(DOWN_LOAD);
X break;
X case 't':
X case 'T':
X pass_thru();
X break;
X case 'f':
X case 'F': /* list directory */
X list_dir();
X break;
X case 'g': /* screen dump */
X case 'G':
X screen_dump();
X st_line(" screen dump");
X k = wait_key(stdscr, 2);
X break;
X case '1': /* data logging */
X data_logging();
X break;
X case '2': /* toggle log */
X if (!strcmp(status->log_path, "NOT_DEFINED")) {
X beep();
X st_line(" no log file");
X k = wait_key(stdscr, 2);
X break;
X }
X log_toggle();
X /* show changes */
X st_line("");
X k = wait_key(stdscr, 2);
X break;
X /*
X * The following are the keyboard macros
X * corresponding to the shifted number keys.
X * (Too many keys... [control] [A] [shift] [1]
X * is hardly a shortcut!)
X */
X case '!':
X keymac = param->mac_1;
X break;
X case '@':
X keymac = param->mac_2;
X break;
X case '#':
X keymac = param->mac_3;
X break;
X case '$':
X keymac = param->mac_4;
X break;
X case '%':
X keymac = param->mac_5;
X break;
X case '^':
X keymac = param->mac_6;
X break;
X case '&':
X keymac = param->mac_7;
X break;
X case '*':
X keymac = param->mac_8;
X break;
X case '(':
X keymac = param->mac_9;
X break;
X case ')':
X keymac = param->mac_0;
X break;
X default:
X fputc(BEL, stderr);
X break;
X }
X
X /*
X * Repaint the stdscr (if we are already talking),
X * get the stdin/stdout out of the curses mode and
X * into the terminal mode.
X */
X if (fd != -1) {
X touchwin(stdscr);
X refresh();
X }
X resetterm();
X term_mode();
X /* restart stopped flow control */
X tty_restart();
X
X /*
X * Some of the output processing options have to be
X * faked... Unfortunately, adding a LF to CR on
X * output is one of them.
X */
X cr_lf = !strcmp(param->cr_out, "CR/LF");
X
X /* play the script */
X if (script != NULL && *script != '\0')
X do_script(script);
X
X /* send the macro */
X if (*keymac != '\0')
X send_str(keymac, FAST);
X
X /*
X * If you pressed a key during one of the sleeping
X * periods (typically the delay to see the status
X * line change), let the keyboard value fall thru
X * to the write() below.
X */
X if (k == -1)
X return;
X c = (char) k;
X }
X /* ignore errors if fd == -1 */
X write(fd, &c, 1);
X
X /*
X * If you're using the half duplex mode, characters don't get
X * echoed by the driver (cause you don't type them!)
X */
X if (dir->duplex[0] == 'H')
X half_duplex(c);
X /* map cr to cr_lf? */
X if (c == '\r' && cr_lf) {
X write(fd, &lf, 1);
X
X if (dir->duplex[0] == 'H') {
X write(1, &lf, 1);
X half_duplex(lf);
X }
X }
X return;
X}
X
X/*
X * Hang up the phone but remain in the Pcomm command state. Uses the
X * hang_up string only, does *not* drop the DTR!
X */
X
void
hang_up(verbose)
int verbose;
X{
X extern int fd;
X void send_str(), st_line(), tty_restart();
X unsigned int sleep();
X /* sanity checking */
X if (modem == NULL)
X return;
X /* anything to hang up? */
X if (modem->m_cur == -1 || fd == -1)
X return;
X
X if (verbose)
X st_line("disconnecting");
X /* special case for OBM */
X if (!strcmp(modem->mname[modem->m_cur], "OBM")) /* EMPTY */ {
X#ifdef UNIXPC
X char buf[80];
X void line_set();
X
X ioctl(fd, PIOCDISC);
X /*
X * The PIOCDISC ioctl screws up the file descriptor!!!
X * No other phone(7) ioctl can fix it. Whatever it does,
X * it seems to escape detection with PIOCGETA and TCGETA.
X * The best I can do is close the port and start over.
X */
X sprintf(buf, "/dev/%s", modem->tty[modem->t_cur]);
X close(fd);
X fd = open(buf, O_RDWR|O_NDELAY);
X line_set();
X tty_noblock(fd, FALSE);
X#endif /* UNIXPC */
X }
X else {
X tty_restart();
X send_str(modem->hang_up[modem->m_cur], SLOW);
X sleep(1);
X }
X
X if (verbose)
X st_line("");
X
X status->connected = 0;
X return;
X}
END_OF_FILE
if test 8778 -ne `wc -c <'terminal.c'`; then
echo shar: \"'terminal.c'\" unpacked with wrong size!
fi
# end of 'terminal.c'
fi
if test -f 'x_ascii.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'x_ascii.c'\"
else
echo shar: Extracting \"'x_ascii.c'\" \(6560 characters\)
sed "s/^X//" >'x_ascii.c' <<'END_OF_FILE'
X/*
X * Transfer a file using just XON/XOFF flow control. Currently limited to
X * 7 bit ASCII codes. (If this causes too much trouble, I'll change it).
X */
X
X#include
X#include
X#include
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X
X#ifdef BSD
X#include
jmp_buf bl_buf;
X#endif /* BSD */
X
static void send_ascii(), rcv_ascii(), putc_ascii();
static int bgetc_line(), buf_read();
X
void
xfer_ascii(list, up)
char *list;
int up;
X{
X int cr_lf;
X char *file, *strtok();
X void line_set(), st_line();
X void ascii_mode(), term_mode();
X unsigned int sleep();
X
X touchwin(stdscr);
X refresh();
X /* only one file from list */
X file = strtok(list, " \t");
X
X cr_lf = !strcmp(param->cr_out, "CR/LF");
X ascii_mode(up);
X /* out of curses mode */
X resetterm();
X term_mode();
X tty_noblock(0, TRUE);
X
X if (up)
X send_ascii(file, cr_lf);
X else
X rcv_ascii(file, cr_lf);
X
X /*
X * Restoring the TTY modes is easier than setting them... The
X * fixterm() and line_set() routines fix most of the damage.
X */
X line_set();
X fixterm();
X tty_noblock(0, FALSE);
X
X beep();
X st_line("xfer complete");
X
X sleep(2);
X return;
X}
X
X/*
X * Send a file. The local echo option is independent of the duplex option,
X * and would very rarely be used since the characters are most likely
X * being echoed on the screen anyway.
X */
X
static void
send_ascii(file, cr_lf)
char *file;
int cr_lf;
X{
X extern int fd;
X FILE *fp, *uid_fopen();
X int i, j, strip_cr, strip_lf, add_cr, add_lf, expand, local_echo, pace;
X char buf[80], c, last;
X unsigned int sleep();
X void error_win();
X /* permission already checked */
X if (!(fp = uid_fopen(file, "r"))) {
X sprintf(buf, "\"%s\"", file);
X error_win(0, "Can't open file for read", buf);
X return;
X }
X /* ASCII transfer options */
X strip_cr = !strcmp(param->cr_up, "STRIP");
X add_lf = !strcmp(param->cr_up, "ADD LF");
X strip_lf = !strcmp(param->lf_up, "STRIP");
X add_cr = !strcmp(param->lf_up, "ADD CR");
X expand = !strcmp(param->expand, "YES");
X local_echo = !strcmp(param->local_echo, "YES");
X pace = !strcmp(param->pace, "YES");
X
X last = 0;
X while ((i = fgetc(fp)) != EOF) {
X /* any keyboard activity? */
X switch (j = getchar()) {
X case -1: /* no key was pressed */
X break;

X case ESC: /* key for abort */
X fclose(fp);
X sleep(2);
X tty_drain(fd);
X return;
X default: /* send the char */
X c = (char) j & 0x7f;
X putc_ascii(c, local_echo);
X if (c == '\r' && cr_lf)
X putc_ascii('\n', local_echo);
X break;
X }
X c = (char) i & 0x7f;
X /* expand blank lines */
X if (expand && last == '\n' && c == '\n')
X putc_ascii(' ', local_echo);
X last = c;
X
X /* CR translations */
X if (c == '\r' && strip_cr)
X continue;
X if (c == '\r' && add_lf) {
X putc_ascii(c, local_echo);
X putc_ascii('\n', local_echo);
X continue;
X }
X /* LF translations */
X if (c == '\n' && strip_lf)
X continue;
X if (c == '\n' && add_cr)
X putc_ascii('\r', local_echo);
X
X putc_ascii(c, local_echo);
X /*
X * There's really no mechanism for delaying characters
X * going to the output, so we fake it by waiting for
X * each character to clear the I/O buffer.
X */
X if (pace)
X tty_drain(fd);
X }
X fclose(fp);
X sleep(2);
X tty_drain(fd);
X return;
X}
X
X/* Put a character on the line, echo it too, if required */
X
static void
putc_ascii(c, local_echo)
char c;
int local_echo;
X{
X extern int fd;
X void vs_putchar();
X
X write(fd, &c, 1);
X if (local_echo) {
X write(1, &c, 1);
X vs_putchar(c);
X }
X return;
X}
X
X/*
X * Receive a file. The timer is used to end the transfer. This is not
X * that much different from the data logging option. The use of bgetc_line()
X * and non-blocking input makes it seem like full duplex, but it's not.
X * Be aware that while the timer is active the keyboard is deaf.
X */
X
static void
rcv_ascii(file, cr_lf)
char *file;
int cr_lf;
X{
X FILE *fp, *uid_fopen();
X int i, strip_cr, strip_lf, add_cr, add_lf, got_first;
X unsigned int delay;
X char c, buf[80];
X void error_win(), vs_putchar();
X /* permission already checked */
X if (!(fp = uid_fopen(file, "w"))) {
X sprintf(buf, "\"%s\"", file);
X error_win(0, "Can't open file for write", buf);
X return;
X }
X /* ASCII transfer options */
X strip_cr = !strcmp(param->cr_dn, "STRIP");
X add_lf = !strcmp(param->cr_dn, "ADD LF");
X strip_lf = !strcmp(param->lf_dn, "STRIP");
X add_cr = !strcmp(param->lf_dn, "ADD CR");
X
X got_first = 0;
X delay = 1;
X /* CONSTCOND */
X while (1) {
X /* keyboard activity */
X switch (i = getchar()) {
X case -1: /* no key was pressed */
X break;
X case ESC: /* key */
X fclose(fp);
X return;
X default: /* send it */
X c = (unsigned int) i;
X putc_line((unsigned char) c);
X if (c == '\r' && cr_lf)
X putc_line('\n');
X break;
X }
X /* read a character */
X if ((i = bgetc_line(delay)) == -1) {
X /*
X * The transfer timeout is not activated until the
X * first character is received. Until then, it polls
X * the line for one second and loops backs for
X * keyboard input.
X */
X if (got_first) {
X fclose(fp);
X return;
X }
X continue;
X }
X got_first = 1;
X delay = param->timer;
X c = i & 0x7f;
X /* display it on the screen */
X write(1, &c, 1);
X vs_putchar(c);
X /* CR translations */
X if (c == '\r' && strip_cr)
X continue;
X if (c == '\r' && add_lf) {
X fputc(c, fp);
X fputc('\n', fp);
X continue;
X }
X /* LF translations */
X if (c == '\n' && strip_lf)
X continue;
X if (c == '\n' && add_cr) {
X fputc('\r', fp);
X fputc(c, fp);
X continue;
X }
X fputc(c, fp);
X }
X}
X
X/*
X * Get a character from the line (using buffered I/O) with a specified
X * time-out period in seconds. If the function times-out, it returns a -1.
X */
X
static int bl_flag;
static int bl_force();
X
static int
bgetc_line(sec)
unsigned int sec;
X{
X int c;
X unsigned int alarm();
X
X signal(SIGALRM, (SIG_TYPE(*) ()) bl_force);
X bl_flag = 0;
X
X alarm(sec);
X
X#ifdef BSD
X if (setjmp(bl_buf))
X return(-1);
X#endif /* BSD */
X
X if ((c = buf_read()) < 0) {
X alarm(0);
X return(-1);
X }
X if (bl_flag)
X return(-1);
X alarm(0);
X return(c);
X}
X
X/* ARGSUSED */
static int
bl_force(dummy)
int dummy;
X{
X#ifdef BSD
X longjmp(bl_buf, 1);
X#else /* BSD */
X signal(SIGALRM, (SIG_TYPE(*) ()) bl_force);
X bl_flag = 1;
X return(0);
X#endif /* BSD */
X}
X
X/*
X * Do a single character buffered read from the serial port.
X */
X
static int
buf_read()
X{
X extern int fd;
X static char buf[CLIST_SIZ];
X static char *bufp = buf;
X static int n = 0;
X
X if (n <= 0) {
X n = read(fd, buf, CLIST_SIZ);
X bufp = buf;
X }
X if (--n >= 0)
X return(*bufp++ & 0xff);
X return(-1);
X}
END_OF_FILE
if test 6560 -ne `wc -c <'x_ascii.c'`; then
echo shar: \"'x_ascii.c'\" unpacked with wrong size!
fi
# end of 'x_ascii.c'
fi
if test -f 'x_batch.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'x_batch.c'\"
else
echo shar: Extracting \"'x_batch.c'\" \(8917 characters\)
sed "s/^X//" >'x_batch.c' <<'END_OF_FILE'
X/*
X * Routines to support the batch protocols.
X */
X
X#include
X#include
X#include
X#include "config.h"
X#include "misc.h"
X#include "xmodem.h"
X
static char *fix_name();
static void change_name(), unfix_name(), change_name();
X
X/*
X * Send the file name for the modem7 batch. Only uses 11 characters
X * of the filename. Returns zero on success or the standard error codes.
X */
X
int
send_modem7(win, name)
WINDOW *win;
char *name;
X{
X char *new_name;
X unsigned char sum, calc_sum();
X
X /* convert to 11 character name */
X new_name = fix_name(name);
X sum = calc_sum((unsigned char *) new_name, 12);
X
X putc_line(ACK);
X /* for each character in the name */
X while (*new_name != CTRLZ) {
X putc_line((unsigned char) *new_name);
X
X switch (getc_line(3)) {
X case -1: /* timed out */
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NO RESPONSE");
X wrefresh(win);
X return(ERROR);
X case ACK: /* got it! */
X break;
X case CAN: /* cancel transmission */
X if (getc_line(2) == CAN) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "REMOTE ABORTED");
X wrefresh(win);
X return(CANCEL);
X }
X /* FALLTHRU */
X default:
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NAME FAILED");
X wrefresh(win);
X return(ERROR);
X }
X new_name++;
X }
X putc_line(CTRLZ);
X /* verify the checksum */
X if (getc_line(10) != sum) {
X putc_line('u');
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "CHECKSUM FAILED");
X wrefresh(win);
X return(ERROR);
X }
X putc_line(ACK);
X return(0);
X}
X
X/*
X * Receive a modem7 file name. Returns zero on success, the standard error
X * codes, or a -1 on the end-of-batch. (Oddly enough, the end-of-batch code
X * is the same as the code for a user abort)
X */
X
int
rcv_modem7(win, default_err)
WINDOW *win;
int default_err;
X{
X extern char file_name[15];
X int i, j, err_method, err_count, got_it;

X unsigned char sum, calc_sum();
X char temp_name[13];
X
X err_method = default_err;
X if (default_err == CRC_CHECKSUM)
X err_method = CRC;
X
X err_count = 0;
X got_it = 0;
X while (err_count < MAX_ERRORS) {
X /* switch to checksum? */
X if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
X err_method = CHECKSUM;
X
X if (err_method == CRC)
X putc_line('C');
X else
X putc_line(NAK);
X /* what'd we get? */
X switch (getc_line(10)) {
X case -1: /* timed out */
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "NO RESPONSE");
X wrefresh(win);
X err_count++;
X break;
X case ACK: /* ready to go... */
X got_it++;
X break;
X default: /* huh? */
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "BAD HEADER");
X wrefresh(win);
X err_count++;
X }
X if (got_it)
X break;
X }
X if (!got_it)
X return(ERROR);
X /* get the name */
X for (i=0; i<12; i++) {
X j = getc_line(3);
X
X switch (j) {
X case -1: /* timed out */
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "NO RESPONSE");
X wrefresh(win);
X return(ERROR);
X case EOT: /* end of batch? */
X return(-1);
X case CAN: /* cancel transmission */
X if (getc_line(2) == CAN) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "REMOTE ABORTED");
X wrefresh(win);
X return(CANCEL);
X }
X /* FALLTHRU */
X case 'u': /* bad name character */
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "BAD NAME");
X wrefresh(win);
X return(ERROR);
X default: /* the name... */
X temp_name[i] = j & 0xff;
X if (j != CTRLZ)
X putc_line(ACK);
X break;
X }
X }
X temp_name[12] = '\0';
X /* send our checksum */
X sum = calc_sum((unsigned char *) temp_name, 12);
X putc_line(sum);
X /* do they agree? */
X if (getc_line(10) != ACK) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "BAD NAME");
X wrefresh(win);
X return(ERROR);
X }
X /* load the file_name array */
X unfix_name(temp_name);
X /* any name collisions? */
X change_name(win, file_name);
X return(0);
X}
X
X/*
X * Send the block 0 information for a ymodem batch transfer. Uses only
X * the name component of the path and the file size.
X */
X
int
send_ymodem(win, file, size)
WINDOW *win;
char *file;
long size;
X{
X unsigned short crc, calc_crc();
X char *strcpy(), *memset();
X unsigned char buf[133];
X /* start with a clean block */
X memset((char *) buf, '\0', 133);
X /* the header */
X buf[0] = SOH;
X buf[1] = 0;
X buf[2] = 255;
X
X /*
X * The block zero consists of the file name (no path component),
X * a NULL, and the file length (as a string). The end of batch
X * marker is an empty block.
X */
X if (*file != '\0') {
X strcpy((char *) &buf[3], file);
X sprintf((char *) &buf[strlen(file)+4], "%ld", size);
X }
X /* the crc */
X crc = calc_crc(&buf[3], 128);
X buf[131] = crc >> 8;
X buf[132] = crc & 0xff;
X /* the block count */
X mvwaddstr(win, 7, 24, "0 ");
X
X return(send_block(win, buf, 133));
X}
X
X/*
X * Receive the block 0 information for a ymodem batch transfer. We
X * only use the file name and the size (if present). Currently doesn't
X * support full path names.
X */
X
int
rcv_ymodem(win)
WINDOW *win;
X{
X extern unsigned char buf[1029];
X extern long file_length;
X extern char file_name[15];
X int code, length_is_at;
X long atol();
X
X file_length = 0L;
X file_name[0] = '\0';
X /* read the zero block */
X if (code = rcv_block(win, 1, 1024, 0))
X return(code);
X /* at end of batch */
X if (buf[3] == '\0')
X return(0);
X /* get the file name */
X change_name(win, (char *) &buf[3]);
X /* any trouble? */
X if (file_name[0] == '\0') {
X putc_line(CAN);
X return(0);
X }
X /*
X * The file length is placed after the NULL of the file name
X * and is terminated by another NULL. If the length is missing,
X * atol() will see a NULL and return 0.
X */
X length_is_at = strlen((char *) &buf[3]) + 4;
X file_length = atol((char *) &buf[length_is_at]);
X return(0);
X}
X
X/*
X * Handle file name collisions. Prepend an "X" to the name until you find
X * a name that doesn't already exist. Creates a NULL name on error.
X * Loads the global character array "file_name".
X */
X
static void
change_name(win, str)
WINDOW *win;
char *str;
X{
X extern char file_name[15];
X register int i;
X int modified;
X char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
X char *strncpy();
X unsigned int sleep();
X /* dissect the name component */
X if ((s = strrchr(str, '/')))
X strncpy(temp, ++s, 15);
X else
X strncpy(temp, str, 15);
X temp[14] = '\0';
X
X strcpy(ans, temp);
X file_name[0] = '\0';
X /* write permission on directory? */
X if (access(".", 2)) {
X beep();
X clear_line(win, 12, 24, TRUE);
X wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY");
X wrefresh(win);
X return;
X }
X /* prepend up to 13 "X"s */
X modified = 0;
X for (i=1; i<14; i++) {
X if (access(ans, 0)) {
X if (modified) {
X beep();
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "NAME COLLISION");
X wrefresh(win);
X sleep(1);
X }
X strcpy(file_name, ans);
X return;
X }
X
X modified++;
X strcpy(temp, "X");
X strncat(temp, ans, 13);
X temp[14] = '\0';
X strcpy(ans, temp);
X }
X beep();
X clear_line(win, 12, 24, TRUE);
X waddstr(win, "BAD NAME");
X wrefresh(win);
X return;
X}
X
X/*
X * Convert a perfectly good Unix file name to fit the CP/M file name
X * rules. Used for the modem7 batch file transfer. Returns a pointer
X * to a static area containing the new name.
X */
X
static char *
fix_name(path)
char *path;
X{
X int i, dot;
X char *s, *name, temp[15], *ext, *strncpy(), *strrchr();
X static char ans[13];
X /* ignore the path component */
X if (s = strrchr(path, '/'))
X strncpy(temp, ++s, 15);
X else
X strncpy(temp, path, 15);
X temp[14] = '\0';
X name = temp;
X
X ext = "";
X dot = 0;
X for (i=strlen(temp)-1; i>=0; i--) {
X if (temp[i] == '.' && !dot) {
X dot = 1;
X temp[i] = '\0';
X ext = &temp[i+1];
X }
X if (islower(temp[i]))
X temp[i] = toupper(temp[i]);
X }
X /* if null name component */
X if (*name == '\0')
X name = "X";
X /* if name too long */
X if (strlen(name) > 8)
X *(name+8) = '\0';
X /* if extension too long */
X if (strlen(ext) > 3)
X *(ext+3) = '\0';
X
X sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ);
X return(ans);
X}
X
X/*
X * Convert a CP/M style filename into a legal Unix file name. Loads the
X * global character array "file_name".
X */
X
static void
unfix_name(cpm_name)
char *cpm_name;
X{
X extern char file_name[15];
X register int i, n;
X int dot;
X char temp[15], *strcpy();
X
X file_name[0] = '\0';
X if (*cpm_name == '\0')
X return;
X
X strcpy(temp, cpm_name);
X /* 8 character of the name */
X n = 0;
X for (i=0; i<8; i++) {
X if (temp[i] != ' ') {
X if (isupper(temp[i]))
X file_name[n++] = tolower(temp[i]);
X else
X file_name[n++] = temp[i];
X }
X }
X /* 3 character extension */
X dot = 0;
X for (i=8; i<11; i++) {
X if (temp[i] != ' ') {
X if (!dot) {
X dot++;
X file_name[n++] = '.';
X }
X if (isupper(temp[i]))
X file_name[n++] = tolower(temp[i]);
X else
X file_name[n++] = temp[i];
X }
X }
X file_name[n] = '\0';
X return;
X}
END_OF_FILE
if test 8917 -ne `wc -c <'x_batch.c'`; then
echo shar: \"'x_batch.c'\" unpacked with wrong size!
fi
# end of 'x_batch.c'
fi
if test -f 'x_menu.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'x_menu.c'\"
else
echo shar: Extracting \"'x_menu.c'\" \(7412 characters\)
sed "s/^X//" >'x_menu.c' <<'END_OF_FILE'
X/*
X * Open a window to display the choices of file transfer protocols and
X * prompt for the file name(s).
X */
X
X#include
X#include
X#include
X#include
X#include "extrnl.h"
X#include "misc.h"
X#include "xmodem.h"
X
static char *get_names(), *get_extrnl();
X
void
xfer_menu(up)
int up;
X{
X extern int fd;
X extern char *null_ptr;
X WINDOW *xm_win, *newwin();
X char buf[2048], *list, *strcat(), *strcpy();
X int type, is_batch, i, ans, num_extrnl, n;
X void xfer_win(), xfer_ascii(), do_extrnl(), error_win();
X
X num_extrnl = (up) ? extrnl->up_entries : extrnl->dn_entries;
X xm_win = newwin(14+num_extrnl, 20, 2, 45);
X
X mvwaddstr(xm_win, 2, 3, "1) xmodem");
X mvwaddstr(xm_win, 3, 3, "2) xmodem-1k");
X mvwaddstr(xm_win, 4, 3, "3) modem7");
X mvwaddstr(xm_win, 5, 3, "4) ymodem");
X mvwaddstr(xm_win, 6, 3, "5) ymodem-g");
X mvwaddstr(xm_win, 7, 3, "6) ASCII");
X
X for (i=0; i X mvwprintw(xm_win, i+8, 3, "%d) %-12.12s", i+7, extrnl->name[up][i]);
X mvwaddstr(xm_win, i+8, 3, "E) (external)");
X mvwaddstr(xm_win, i+10, 3, " to Abort");
X mvwaddstr(xm_win, i+11, 3, "Protocol:");
X box(xm_win, VERT, HORZ);
X if (up)
X mvwattrstr(xm_win, 0, 6, A_BOLD, " Upload ");
X else
X mvwattrstr(xm_win, 0, 5, A_BOLD, " Download ");
X
X wmove(xm_win, i+11, 13);
X wrefresh(xm_win);
X /* get the protocol */
X type = -1;
X while ((ans = wgetch(xm_win)) != ESC) {
X switch (ans) {
X case '1':
X type = XMODEM;
X break;
X case '2':
X type = XMODEM_1k;
X break;
X case '3':
X type = MODEM7;
X break;
X case '4':
X type = YMODEM;
X break;
X case '5':
X type = YMODEM_G;
X break;
X case '6':
X type = XASCII;
X break;
X case '7':
X if (num_extrnl >= 1)
X type = EXT_1;
X else
X beep();
X break;
X case '8':
X if (num_extrnl >= 2)
X type = EXT_2;
X else
X beep();
X break;
X case '9':
X if (num_extrnl >= 3)
X type = EXT_3;
X else
X beep();
X break;
X case 'e':
X case 'E':
X type = EXT_MANUAL;
X break;
X default:
X beep();
X }
X if (type != -1)
X break;
X }
X werase(xm_win);
X wrefresh(xm_win);
X delwin(xm_win);
X /* chicken'd out */
X if (type == -1)
X return;
X
X if (fd == -1) {
X error_win(0, "Not currently connected to any host", "");
X return;
X }
X /* which protocol? */
X is_batch = 0;
X switch(type) {
X case MODEM7:
X case YMODEM:
X case YMODEM_G: /* built-in protocols */
X is_batch++;
X /* FALLTHRU */
X case XMODEM:
X case XMODEM_1k: /* non-batch built-ins */
X list = null_ptr;
X /*
X * When receiving in a batch mode, don't prompt
X * for file names.
X */
X if (up || !is_batch) {
X if (!(list = get_names(up, type, is_batch)))
X break;
X }
X xfer_win(list, up, type);
X break;
X case XASCII: /* ascii xfer, yuck! */
X if (list = get_names(up, type, FALSE))
X xfer_ascii(list, up);
X break;
X case EXT_1:
X case EXT_2:
X case EXT_3: /* one of the externals */
X n = type -NUM_INTERNAL -1;
X strcpy(buf, extrnl->command[up][n]);
X /* see if we need to prompt for files */
X if (extrnl->prompt[up][n] == 'Y') {
X if (list = get_names(up, type, TRUE)) {
X strcat(buf, " ");
X strcat(buf, list);
X }
X else
X break;
X }
X do_extrnl(buf);
X break;
X case EXT_MANUAL: /* the manual external protocol */
X if (list = get_extrnl(up))
X do_extrnl(list);
X break;
X }
X return;
X}
X
char *protocol[NUM_INTERNAL] = {"xmodem", "xmodem-1k", "modem7", "ymodem",
X "ymodem-g", "ASCII"};
X
X/*
X * Prompt for a list of files for the transfer programs. Since expand()
X * is used, it returns a pointer to a static area. Returns a NULL if
X * you chicken'd out.
X */
X
static char *
get_names(up, type, is_batch)
int up, type, is_batch;
X{
X int got_it, n;
X WINDOW *gn_win, *newwin();
X char *ans, *file, *list, buf[40], *expand(), *get_str(), *strtok();
X void st_line();
X struct stat stbuf;
X
X touchwin(stdscr);
X refresh();
X st_line("");
X
X n = type -NUM_INTERNAL -1;
X
X gn_win = newwin(7, 70, 5, 5);
X mvwaddstr(gn_win, 3, 4, "Enter filename: ");
X box(gn_win, VERT, HORZ);
X if (up) {
X if (type <= NUM_INTERNAL)
X sprintf(buf, " Send %s ", protocol[type -1]);
X else
X sprintf(buf, " Send %s ", extrnl->name[up][n]);
X }
X else {
X if (type <= NUM_INTERNAL)
X sprintf(buf, " Receive %s ", protocol[type -1]);
X else
X sprintf(buf, " Receive %s ", extrnl->name[up][n]);
X }
X mvwattrstr(gn_win, 0, 3, A_BOLD, buf);
X
X /* CONSTCOND */
X while (1) {
X wmove(gn_win, 3, 20);
X wrefresh(gn_win);
X /* get the answers */
X if (is_batch)
X ans = get_str(gn_win, 60, "", "\n");
X else
X ans = get_str(gn_win, 60, "", " \t\n");
X
X if (ans == NULL || *ans == '\0') {
X list = NULL;
X break;
X }
X list = expand(ans);
X /* batches are checked on-the-fly */
X if (is_batch)
X break;
X /*
X * Here we have the opportunity to determine the read and
X * write permissions before things get started. Much nicer
X * than finding out later when there's no way to fix it.
X * Only checks the first file.
X */
X file = strtok(list, " \t");
X /* sanity checking */
X if (!stat(file, &stbuf)) {
X if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
X beep();
X clear_line(gn_win, 4, 15, TRUE);
X mvwattrstr(gn_win, 4, 15, A_BOLD, "Not a regular file");
X wrefresh(gn_win);
X wait_key(gn_win, 3);
X clear_line(gn_win, 4, 15, TRUE);
X clear_line(gn_win, 3, 20, TRUE);
X continue;
X }
X }
X /* check read permission */
X if (up) {
X if (access(file, 0)) {
X beep();
X mvwattrstr(gn_win, 4, 15, A_BOLD, "Can't find file");
X wrefresh(gn_win);
X wait_key(gn_win, 3);
X clear_line(gn_win, 4, 15, TRUE);
X clear_line(gn_win, 3, 20, TRUE);
X continue;
X }
X if (access(file, 4)) {
X beep();
X mvwattrstr(gn_win, 4, 15, A_BOLD, "No read permission");
X wrefresh(gn_win);
X wait_key(gn_win, 3);
X clear_line(gn_win, 4, 15, TRUE);
X clear_line(gn_win, 3, 20, TRUE);
X continue;
X }
X break;
X }
X /* check write permission */
X got_it = 0;
X switch(can_write(file)) {
X case DENIED:
X beep();
X clear_line(gn_win, 4, 15, TRUE);
X mvwattrstr(gn_win, 4, 15, A_BOLD, "No write permission");
X wrefresh(gn_win);
X wait_key(gn_win, 3);
X clear_line(gn_win, 4, 15, TRUE);
X clear_line(gn_win, 3, 20, TRUE);
X break;
X case OK_BUT_EXISTS:
X if (!yes_prompt(gn_win, 4, 15, A_BOLD, "File exists, overwrite")) {
X clear_line(gn_win, 4, 15, TRUE);
X clear_line(gn_win, 3, 20, TRUE);
X break;
X }
X /* FALLTHRU */
X case WRITE_OK:
X got_it++;
X break;
X }
X if (got_it)
X break;
X }
X werase(gn_win);
X wrefresh(gn_win);
X delwin(gn_win);
X
X return(list);
X}
X
X/*
X * Prompt for the Unix command line to be used as an external file
X * transfer program. Since expand() is used, it returns a pointer to
X * a static area.
X */
X
static char *
get_extrnl(up)
int up;
X{
X WINDOW *ge_win, *newwin();
X char *ans, *cmd, *get_str(), *expand();
X void st_line();
X
X touchwin(stdscr);
X refresh();
X st_line("");
X /* prompt for command line */
X ge_win = newwin(7, 70, 5, 5);
X mvwaddstr(ge_win, 3, 4, "Enter Unix command: ");
X box(ge_win, VERT, HORZ);
X
X if (up)
X mvwattrstr(ge_win, 0, 3, A_BOLD, " Send (external) ");
X else
X mvwattrstr(ge_win, 0, 3, A_BOLD, " Receive (external) ");
X
X wmove(ge_win, 3, 24);
X wrefresh(ge_win);
X /* get the line */
X ans = get_str(ge_win, 60, "", "\n");
X if (ans == NULL || *ans == '\0')
X cmd = NULL;
X else
X cmd = expand(ans);
X
X werase(ge_win);
X wrefresh(ge_win);
X delwin(ge_win);
X return(cmd);
X}
END_OF_FILE
if test 7412 -ne `wc -c <'x_menu.c'`; then
echo shar: \"'x_menu.c'\" unpacked with wrong size!
fi
# end of 'x_menu.c'
fi
if test -f 'xmodem.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'xmodem.c'\"
else
echo shar: Extracting \"'xmodem.c'\" \(8800 characters\)
sed "s/^X//" >'xmodem.c' <<'END_OF_FILE'
X/*
X * Miscellaneous routines to support the xmodem file transfer protocols.
X */
X
X#define TMP_FILE "trunXXXXXX"
X
X#include
X#include
X#include
X#include
X#include "config.h"
X#include "misc.h"
X#include "param.h"
X#include "xmodem.h"
X
X#ifdef BSD
X#include
jmp_buf gl_buf, rl_buf;
X#endif /* BSD */
X
static int uid_link(), uid_unlink();
X
X/*
X * Calculate the CRC for the given buffer
X */
X
unsigned short
calc_crc(buf, len)
unsigned char *buf;
int len;
X{
X register int i;
X unsigned short crc;
X static unsigned short crctab[256] = {
X 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
X 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
X 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
X 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
X 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
X 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
X 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
X 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
X 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
X 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
X 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
X 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
X 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
X 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
X 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
X 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
X 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
X 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
X 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
X 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
X 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
X 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
X 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
X 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
X 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
X 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
X 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
X 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
X 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
X 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
X 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
X 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0};
X
X crc = 0;
X for (i=0; i X crc = (crc<<8) ^ crctab[(crc>>8) ^ *buf++];
X
X return(crc);
X}
X
X/*
X * Calculate the checksum for the given buffer.
X */
X
unsigned char
calc_sum(buf, len)
unsigned char *buf;
int len;
X{
X unsigned char sum;
X
X sum = 0;
X while (--len >= 0)
X sum += *buf++;
X
X return(sum);
X}
X
X/*
X * Get a single character from the line with a specified time-out period
X * in seconds. If the function times-out, it returns a -1.
X */
X
static int gl_flag;
static int gl_force();
X
int
getc_line(sec)
unsigned int sec;
X{
X extern int fd;
X char c;
X unsigned int alarm();
X
X signal(SIGALRM, (SIG_TYPE(*) ()) gl_force);
X gl_flag = 0;
X
X alarm(sec);
X
X#ifdef BSD
X if (setjmp(gl_buf))
X return(-1);
X#endif /* BSD */
X
X if (read(fd, &c, 1) <= 0) {
X alarm(0);
X return(-1);
X }
X if (gl_flag)
X return(-1);
X alarm(0);
X return(c & 0xff);
X}
X
X/* ARGSUSED */
static int
gl_force(dummy)
int dummy;
X{
X#ifdef BSD
X longjmp(gl_buf, 1);
X#else /* BSD */
X signal(SIGALRM, (SIG_TYPE(*) ()) gl_force);
X gl_flag = 1;
X return(0);
X#endif /* BSD */
X}
X
X/*
X * Same as above, but reads a bunch of characters. The return code is
X * now just a success/fail indicator.
X */
X
static int rl_flag;
static int rl_force();
X
int
fread_line(buf, len, sec)
unsigned char *buf;
unsigned int len, sec;
X{
X extern int fd;
X int n;
X unsigned int try, alarm();
X
X signal(SIGALRM, (SIG_TYPE(*) ()) rl_force);
X rl_flag = 0;
X
X alarm(sec);
X while (len) {
X /* read at most CLIST_SIZ chars */
X try = (len > CLIST_SIZ) ? CLIST_SIZ : len;
X#ifdef BSD
X if (setjmp(rl_buf))
X return(-1);
X#endif /* BSD */
X if ((n = read(fd, (char *) buf, try)) <= 0) {
X alarm(0);
X return(-1);
X }
X if (rl_flag)
X return(-1);
X len -= n;
X buf = buf + n;
X }
X alarm(0);
X return(0);
X}
X
X/* ARGSUSED */
static int
rl_force(dummy)
int dummy;
X{
X#ifdef BSD
X longjmp(rl_buf, 1);
X#else /* BSD */
X signal(SIGALRM, (SIG_TYPE(*) ()) rl_force);
X rl_flag = 1;
X return(0);
X#endif /* BSD */
X}
X
X/*
X * Put a character on the TTY line. This serves no useful purpose other
X * than making the code look pretty.
X */
X
int
putc_line(c)
unsigned char c;
X{
X extern int fd;
X
X return(write(fd, (char *) &c, 1));
X}
X
X/*
X * Cancel the file transfer. Send several ^X's to the remote, followed
X * by an equal number of backspaces (in case they have already aborted and
X * we're really at the command line).
X */
X
void
cancel_xfer(up)
int up;
X{
X extern char file_name[15];
X
X if (!up && !strcmp(param->abort, "DELETE"))
X unlink(file_name);
X
X putc_line(CAN);
X putc_line(CAN);
X putc_line(CAN);
X putc_line(BS);
X putc_line(BS);
X putc_line(BS);
X return;
X}
X
X/*
X * Shorten a file to a predetermined length. Used to remove the ^Z
X * padding from the end of files. (Heaven help us, if one day a binary
X * file actually has ^Z's as part of the end of the file).
X */
X
int
fix_length(file, len)
char *file;
long len;
X{
X FILE *fp, *tempfp, *uid_fopen();
X register int num;
X char *mktemp(), tempfile[128], buf[BUFSIZ], *strcpy();
X char *s, *strrchr(), *strcat();
X struct stat stbuf;
X
X if (stat(file, &stbuf) < 0)
X return(1);
X /* see if we have any work to do */
X if (len >= stbuf.st_size)
X return(0);
X
X#ifdef HAVE_TRUNCATE
X return(uid_truncate(file, len));
X#else /* HAVE_TRUNCATE */
X
X if (!(fp = uid_fopen(file, "r")))
X return(1);
X
X /*
X * The temporary file should be in the same directory as the
X * file being received because otherwise we'd have no way of
X * guaranteeing they would be in the same file system. (Hard
X * links across different file systems aren't allowed).
X */
X strcpy(tempfile, file);
X if (s = strrchr(tempfile, '/'))
X *++s = '\0';
X else
X strcpy(tempfile, "./");
X
X strcat(tempfile, TMP_FILE);
X mktemp(tempfile);
X
X if (!(tempfp = uid_fopen(tempfile, "w"))) {
X fclose(fp);
X return(1);
X }
X
X while (len != 0L) {
X num = (len > BUFSIZ) ? BUFSIZ : (int) len;
X fread(buf, sizeof(char), num, fp);
X if (fwrite(buf, sizeof(char), num, tempfp) != num) {
X fclose(fp);
X fclose(tempfp);
X return(1);
X }
X len -= (unsigned int) num;
X }
X
X fclose(fp);
X fclose(tempfp);
X
X if (uid_unlink(file) < 0)
X return(1);
X
X if (uid_link(tempfile, file) < 0)
X return(1);
X
X if (uid_unlink(tempfile) < 0)
X return(1);
X
X return(0);
X#endif /* HAVE_TRUNCATE */
X}
X
static int
uid_link(path1, path2)
char *path1, *path2;
X{
X int ret;
X
X#ifdef SETUID_BROKE
X int status;
X void _exit();
X
X switch(fork()) {
X case 0:
X setuid(getuid());
X setgid(getgid());
X _exit(link(path1, path2));
X case -1:
X fprintf(stderr, "uid_link: Can't fork\n");
X return(-1);
X default:
X if (wait(&status) == -1) {
X fprintf(stderr, "uid_link: wait failed\n");
X return(-1);
X }
X ret = status >> 8;
X }
X#else /* SETUID_BROKE */
X int euid, egid;
X
X euid = geteuid();
X egid = getegid();
X
X setuid(getuid());
X setgid(getgid());
X
X ret = link(path1, path2);
X
X setuid(euid);
X setgid(egid);
X#endif /* SETUID_BROKE */
X return(ret);
X}
X
static int
uid_unlink(path)
char *path;
X{
X int ret;
X
X#ifdef SETUID_BROKE
X int status;
X void _exit();
X
X switch(fork()) {
X case 0:
X setuid(getuid());
X setgid(getgid());
X _exit(unlink(path));
X case -1:
X fprintf(stderr, "uid_unlink: Can't fork\n");
X return(-1);
X default:
X if (wait(&status) == -1) {
X fprintf(stderr, "uid_unlink: wait failed\n");
X return(-1);
X }
X ret = status >> 8;
X }
X#else /* SETUID_BROKE */
X int euid, egid;
X
X euid = geteuid();
X egid = getegid();
X
X setuid(getuid());
X setgid(getgid());
X
X ret = unlink(path);
X
X setuid(euid);
X setgid(egid);
X#endif /* SETUID_BROKE */
X return(ret);
X}
X
X#ifdef HAVE_TRUNCATE
static int
uid_truncate(path, len)
char *path;
long len;
X{
X int ret;
X
X#ifdef SETUID_BROKE
X int status;
X void _exit();
X
X switch(fork()) {
X case 0:
X setuid(getuid());
X setgid(getgid());
X _exit(truncate(path, len));
X case -1:
X fprintf(stderr, "uid_truncate: Can't fork\n");
X return(-1);
X default:
X if (wait(&status) == -1) {
X fprintf(stderr, "uid_truncate: wait failed\n");
X return(-1);
X }
X ret = status >> 8;
X }
X#else /* SETUID_BROKE */
X int euid, egid;
X
X euid = geteuid();
X egid = getegid();
X
X setuid(getuid());
X setgid(getgid());
X
X ret = truncate(path, len);
X
X setuid(euid);
X setgid(egid);
X#endif /* SETUID_BROKE */
X return(ret);
X}
X#endif /* HAVE_TRUNCATE */
END_OF_FILE
if test 8800 -ne `wc -c <'xmodem.c'`; then
echo shar: \"'xmodem.c'\" unpacked with wrong size!
fi
# end of 'xmodem.c'
fi
echo shar: End of archive 3 \(of 6\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0



  3 Responses to “Category : UNIX Files
Archive   : PCOM202C.ZIP
Filename : PCOM202C.SHR

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/