a revised "uw" for the 3b1

Andy Fyfe andy at cit-vax.Caltech.Edu
Fri Jul 14 09:43:44 AEST 1989


Here is the source to my uw client for the 3b1.  Since the last
posting of this, I've added the ability to transfer files using
zmodem (or, I guess, the program of your choice).  In the case
the file transfers, the code tends to be more functional than
general, but it serves my needs.  Uw is written in ansi-C, and
a (uuencoded, compressed) binary is enclosed for those without
gcc.

To run this you need the uw server written by John Bruner
(jdb at mordor.s1.gov) (who also wrote a client side for the
Macintosh).  The sources for the server are not included here.
They are archived in Mac-sorts of places, including
sumex-aim.stanford.edu [info-mac/unix/uw-42-part?.shar] and
simtel20.army.mil [PD2:<UNIX-C.MACINTOSH>UW42.TAR-Z].  (I reserve
the right to have gotten those file names wrong! :-))  The server
runs on Bsd-like machines.  (Uw 4.2 is the current version of the
server, I believe.)

Andy Fyfe
            andy at csvax.caltech.edu
            wjafyfe at caltech.bitnet
            andy at cit-vax.UUCP	(...!ames!elroy!cit-vax!andy)


#! /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 <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README Makefile config.h controller.c dial.c msg_queues.c
#   reader.c updnload.c utils.c uw.c uw.h uw_pcl.h window.c writer.c
#   uw.uue
# Wrapped by andy at marmot on Sun Jul  9 01:35:15 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4790 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XUW client for the AT&T 3b1
X
XThe original UW program is by John D. Bruner.  The copyright on this
Xprogram is the same as that for the original.
X
XThis client program supports only UW protocol 1.  It is at the level of
Xsomething just above a quick hack.  It works fine for me (I'm running
Xversion 3.5 unix).  It uses dial(3) to do the calling, and allows any
Xdevice to be specified as the line.  It must be in
X/usr/lib/uucp/L-devices. I've used it both with the OBM and a direct
X9600 baud line to a sun3.
X
XThe basic use of the program is "uw [<phone-number>]".  The phone
Xnumber is required if the L-devices entry is "OBM" or "ACU", and must
Xnot be specified if the L-devices entry is "DIR". Once you're logged
Xin, run "uw" on the host.  Any windows that the "uw" server creates
Xwill be assumed to be "adm31" type windows ("uw" will set the TERM and
XTERMCAP variables to such) and so it's necessary to override that since
Xthe "uw" client does not do any terminal emulation (and thus windows
Xare "s4"s). One way to do this is to set an environment variable when
Xyou log in (say "ATT_3B1") and in your .cshrc (or .shrc or .kshrc)
Xcheck to see if it's set and if it is, override "TERM" and "TERMCAP".
XThis even works for commands like "uwtool rn", but only if typed at the
Xkeyboard -- for some reason it doesn't if they appear in your .uwrc
X(though commands in the .uwrc that just create shells work fine).
X
XYou can use the 3b1 window manager to change windows -- the "uw" client
Xwill notice the change (though there may be a few seconds of delay if
Xyour previous window was not a uw window).  New windows can be created
Xwith "uwtool", and when all windows die, the client will automatically
Xshut down the server and return to a simple non-windowed terminal
Xprogram.
X
XBecause of the above, it is not necessary to have any control of
Xcreating, destroying or changing windows from the keyboard (via the
Xclient).  If you want to, though, it is possible.  The commands are
Xentered via an escape character followed by a command letter:  'c' (or
X'C') creates a window, 'k' (or 'K') kills the current window, and '1'
Xthrough '7' switch to window number '1' through '7' respectively. (To
Xenter the escape character, type it twice.)  Any character can be the
Xescape character.  It is entered with the "-e" option.  Printable
Xcharacters are entered as themselves, control characters (or delete)
Xare entered as the 2-character string ^A, ^B, etc. with ^? for delete.
XFurthermore, they can be preceeded by 'M' to indicate that the high
Xorder bit should be on (so \201 can be make the escape char with "uw -e
XM^A <number>").  A default escape character can be compiled in (see
Xconfig.h), and can be disabled by using the "-E" option.  Alternately,
Xthose characters can be typed along with the 'meta' key (if you have
XMichael "Ford" Ditto's nkbd driver).  It is available with the "-m"
Xoption, and like "-e" can be made the default at compile time and
Xoverrided with "-M".  Both can be used, either, or neither.  Whatever
Xsuits you.  Be warned though, since invalid commands wind up as a
X"beep", with -m all other meta-characters become "beeps".
X
XIn it's windowless mode the keyboard commands are 'b' (or 'B') to send
Xa break, and 'x' (or 'X') to terminate uw.  If you're using /dev/ph?,
Xthen uw will terminate automatically when the OBM hangs up.  There is
Xalso 'u' (or 'U') to upload a file, and 'd' (or 'D') to download a
Xfile.  At the moment these get translated to "sz -y upload" and "rz -p"
X(and it's compiled in, along with the path to sz and rz).  It might
Xbe worthwhile to prompt for information, but I haven't found that to be
Xthe case for me.  To upload a file, just type escape or meta u.  To
Xdownload, first type "rz file.1 file.2 ..." and then escape or meta d.
X
XAn alternate line can be specified with '-l' and an alternate baud rate
Xwith '-s'.
X
XThe defaults are set in "config.h".  All save the file transfer stuff
Xcan be overriden with command line options.
X
XThe program was written knowing that it would be compiled with Gnu C
X(and version >= 33 is required unless you delete the "volatile" from
Xsome function defs).  A uuencoded binary is included (it's stripped,
Xand uses the shared library).  The file <stdlib.h> is included -- it's
Xnot necessary, as it just provides prototypes for most of libc, but
Xit's handy for finding bugs.
X
XThere may well be bugs (or worse, race conditions).  If you find any
Xlet me know.  Occasionally windows hang (with the death star looming in
Xthe corner of the screen).  So far it's been enough to use the window
Xmanager to change windows to something else and back again to fix it. I
Xdon't expect to upgrade this to use protocol 2 any time soon.
X
XAndy Fyfe
X	andy at csvax.caltech.edu
X	wjafyfe at caltech.bitnet
X	andy at cit-vax.uucp       (...ames!elroy!cit-vax!andy)
END_OF_FILE
if test 4790 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(251 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XCC = gcc
XCFLAGS = -Wall -O
XLDFLAGS = -shlib -s
X
XOBJS = controller.o dial.o msg_queues.o reader.o updnload.o utils.o \
X    uw.o window.o writer.o
X
Xuw: $(OBJS)
X	$(CC) $(CFLAGS) -o uw $(OBJS) $(LDFLAGS)
X
X$(OBJS): uw.h uw_pcl.h
X
Xuw.o updnload.o: config.h
END_OF_FILE
if test 251 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'config.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'config.h'\"
else
echo shar: Extracting \"'config.h'\" \(2386 characters\)
sed "s/^X//" >'config.h' <<'END_OF_FILE'
X/*
X * any of the following defaults can be overriden by command line
X * options.
X*/
X
X/*
X * uw accepts commands from the keyboard via certain meta-keys.
X *
X * the commands can be entered in one of two ways.  the first is
X * to press the meta-key (left ctrl key -- this requires Michael
X * "Ford" Ditto's nkbd driver) and the other is to prefix the
X * character with an escape character.  you can use one or the
X * other, or both, or neither.  if you use the escape char, you
X * can send it to the host by typing it twice.
X *
X * there are 2 sets of available commands depending on the state
X * of uw.  there is the simple terminal emulator, and the windowed
X * one.  in the simple the commands are:
X *	meta-B  --  send break
X *	meta-X	--  terminate uw
X *	meta-U  --  upload the file "upload" (from /usr/spool/uucppublic)
X *	meta-D  --  download the file (into /usr/spool/uucppublic)
X * in the windowed emulator, they are:
X *	meta-C	--  create a new window
X *	meta-K	--  kill the current window
X *	meta-1	--  select window 1, through
X *      meta-7	--  select window 7 (inclusively)
X *
X * the alphabetic commands can be entered in either upper or lower case
X *
X * choose one or the other (or both, or neither) to be the default
X */
X
X#undef  DEFAULT_META				/* use the meta key */
X#define DEFAULT_KBD_ESC	"^A"			/* escape char is cntl-A */
X
X/*
X * the default terminal line
X *
X * this will probably be either "/dev/ph1" or "/dev/tty0000"
X *
X */
X
X#define DEFAULT_PHONE_LINE	"/dev/ph1"
X
X/*
X * the default baud rate
X *
X * this will probably always be 0.  it must be a string.  "0" takes
X * the baud rate from L-devices.  if there's more than one entry in
X * L-devices, make it the most common one.
X */
X
X#define DEFAULT_BAUD_RATE	"0"
X
X/*
X * options for file transfer
X *
X * Uw will do a chdir to DEFAULT_DIR before exec'ing the upload or
X * download program.  Sz only sends a fixed file name (it's easier
X * than asking for one, and I don't upload often enough to change it.
X * The last arg must be a (char *)0.
X */
X
X#define DEFAULT_DIR		"/usr/spool/uucppublic"
X
X#define UPLOAD_PROGRAM		"/usr/local/bin/sz"
X#define UPLOAD_ARG_0		"sz"
X#define UPLOAD_ARG_1		"-y"
X#define UPLOAD_ARG_2		"upload"
X#define UPLOAD_ARG_3		(char *)0
X
X#define DOWNLOAD_PROGRAM	"/usr/local/bin/rz"
X#define DOWNLOAD_ARG_0		"rz"
X#define DOWNLOAD_ARG_1		"-p"
X#define DOWNLOAD_ARG_2		(char *)0
X#define DOWNLOAD_ARG_3		(char *)0
END_OF_FILE
if test 2386 -ne `wc -c <'config.h'`; then
    echo shar: \"'config.h'\" unpacked with wrong size!
fi
# end of 'config.h'
fi
if test -f 'controller.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'controller.c'\"
else
echo shar: Extracting \"'controller.c'\" \(3037 characters\)
sed "s/^X//" >'controller.c' <<'END_OF_FILE'
X/*
X *	controller -- not much happens unless the controller requests it
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X
X#include "uw.h"
X
X#include <stdio.h>
X#include <signal.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X
Xstatic void startup_0(void);
Xstatic void new_window(int logical_window);
Xstatic int all_windows_gone(void);
Xstatic int stop = 0;
X
Xstatic void catch(void);
X
Xvoid
Xcontroller(void)
X{
X    struct message msg;
X
X    startup_0();
X
X    signal(SIGHUP, catch);
X
X    while(1) {
X	if (stop || !modem_connected()) {
X	    send_rd_wr(DIE_CMD, 0, 0);
X	    break;
X	}
X	if (msgrcv(c_id, &msg, MSG_SIZE, MSG_TYPE, IPC_NOWAIT) < 0) {
X	    sleep(TIMEOUT);
X	    continue;
X	}
X	if (msg.text[SERVER_BYTE] & P1_INTERNAL) {
X	    switch(msg.text[SERVER_BYTE]) {
X	    case P1_INT_DIE:
X		send_rd_wr(DIE_CMD, 0, 0);
X		return;
X	    case P1_INT_UPLOAD:
X		send_rd_wr(PAUSE_CMD, 0, 0);
X		upload();
X		send_rd_wr(CONT_CMD, 0, 0);
X		break;
X	    case P1_INT_DOWNLOAD:
X		send_rd_wr(PAUSE_CMD, 0, 0);
X		download();
X		send_rd_wr(CONT_CMD, 0, 0);
X		break;
X	    }
X	}
X	else {
X	    switch(msg.text[SERVER_BYTE] & P1_FN) {
X	    case P1_FN_NEWW:
X		if (msg.text[SERVER_BYTE] & P1_WINDOW)
X		    new_window(msg.text[SERVER_BYTE] & P1_WINDOW);
X		break;
X	    case P1_FN_KILLW:
X		if (msg.text[SERVER_BYTE] & P1_WINDOW) {
X		    send_rd_wr(KILL_WINDOW_CMD, 0,
X			msg.text[SERVER_BYTE] & P1_WINDOW);
X		    close_window(msg.text[SERVER_BYTE] & P1_WINDOW);
X		    if (all_windows_gone())
X			startup_0();
X		}
X		break;
X	    case P1_FN_MAINT:
X		switch (msg.text[SERVER_BYTE] & P1_MF) {
X		case P1_MF_ENTRY:
X		    if (protocol == PROTOCOL_0)
X			close_window(0);
X		    else if (protocol == PROTOCOL_1)
X			close_all_windows();
X		    send_rd_wr(PROTOCOL_1_CMD, 0, 0);
X		    protocol = PROTOCOL_1;
X		    break;
X		case P1_MF_EXIT:
X		    if (protocol == PROTOCOL_1) {
X			close_all_windows();
X			startup_0();
X		    }
X		    break;
X		}
X		break;
X	    }
X	}
X    }
X    return;
X}
X
Xstatic void
Xstartup_0(void)
X{
X    int window, fd;
X
X    protocol = PROTOCOL_0;
X
X    fd = get_window("Unix Windows");
X    window = window_number(fd);
X
X    if (window < 0) {
X	fprintf(stderr, "%s: can't open base window: ", cmd_name);
X	perror("");
X	send_rd_wr(DIE_CMD, 0, 0);
X	stop = 1;
X    }
X
X    win_info[0].fd = fd;
X    win_info[0].window_number = window;
X
X    send_rd_wr(PROTOCOL_0_CMD, window, 0);
X}
X
Xstatic void
Xcatch(void)
X{
X    stop = 1;
X
X    signal(SIGHUP, SIG_IGN);
X}
X
Xstatic void
Xnew_window(int logical_window)
X{
X    int window, fd;
X    char title[80];
X
X    sprintf(title, "UW -- window %d", logical_window);
X    fd = get_window(title);
X    window = window_number(fd);
X
X    win_info[logical_window].fd = fd;
X    win_info[logical_window].window_number = window;
X
X    send_rd_wr(CREATE_WINDOW_CMD, window, logical_window);
X}
X
Xstatic int
Xall_windows_gone(void)
X{
X    int i;
X
X    for (i=1; i <= MAX_WINDOWS; ++i)
X	if (win_info[i].fd >= 0)
X	    return 0;
X    return 1;
X}
END_OF_FILE
if test 3037 -ne `wc -c <'controller.c'`; then
    echo shar: \"'controller.c'\" unpacked with wrong size!
fi
# end of 'controller.c'
fi
if test -f 'dial.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dial.c'\"
else
echo shar: Extracting \"'dial.c'\" \(2971 characters\)
sed "s/^X//" >'dial.c' <<'END_OF_FILE'
X/*
X *	dial -- dial the phone number
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X
X#include "uw.h"
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <dial.h>
X#include <sys/phone.h>
X
Xstatic const char * const errs[] = { "zero", "interrupt", "dialer hung",
X			      "no answer", "illegal baud-rate", "acu problem",
X			      "line problem", "can't open LDEVS",
X			      "device not available", "device unknown",
X			      "no device available at baud-rate",
X			      "no device known at baud-rate" };
X
Xint dial(CALL);
Xvoid undial(int);
Xstatic int translate_baud(const char *speed);
Xstatic int is_phone = 0;
X
Xint
Xdial_number(const char *line, const char *speed, const char *number)
X{
X    CALL call;
X    struct termio term;
X    struct updata phone;
X    int fd;
X    int baud;
X
X    fd = open(line, O_RDWR | O_NDELAY, 0);
X    if (fd < 0) {
X	fprintf(stderr, "%s: Can't open %s: ", cmd_name, line);
X	perror("");
X	return -1;
X    }
X    if (strncmp(line, PHDEV, sizeof(PHDEV)-1) == 0) {
X	is_phone = 1;
X	if (ioctl(fd, PIOCGETP, &phone) >= 0) {
X	    phone.c_lineparam &= ~PULSE;
X	    phone.c_lineparam |= DTMF;
X	    phone.c_feedback &= ~(SOFTSPK | NORMSPK | LOUDSPK);
X	    phone.c_feedback |= (SPEAKERON | SOFTSPK);
X	    ioctl(fd, PIOCSETP, &phone);
X	}
X    }
X    ioctl(fd, TCGETA, &term);
X    close(fd);
X
X    baud = translate_baud(speed);
X    if (baud < 0) {
X	fprintf(stderr, "%s: illegal speed: \"%s\"\n", cmd_name, speed);
X	return -1;
X    }
X
X    term.c_iflag = IXOFF | IXON | ISTRIP | IGNPAR;
X    term.c_oflag = 0;
X    term.c_cflag = HUPCL | CREAD | CS8 | baud;
X    term.c_lflag = 0;
X    term.c_cc[VMIN] = 1;
X    term.c_cc[VTIME] = 0;
X    call.attr = &term;
X    call.baud = call.speed = atoi(speed);
X    call.line = strrchr(line, '/') + 1;
X    call.telno = (char *)number;
X    call.modem = 0;
X
X    fd = dial(call);
X    if (fd < 0) {
X	fprintf(stderr, "%s: dial failed: %s\n", cmd_name, errs[-fd]);
X	return -1;;
X    }
X
X    return fd;
X}
X
Xvoid
Xundial_number(const char *line)
X{
X    if (phone_fd >= 0) {
X	if (is_phone)
X	    ioctl(phone_fd, PIOCDISC, (char *)0);
X	undial(phone_fd);
X	close(phone_fd);
X    }
X    
X}
X
Xstatic const struct trans {
X    char *speed;
X    int baud;
X} trans[] = {
X	{"0",     0},
X	{"50",    B50},
X	{"75",    B75},
X	{"110",   B110},
X	{"134",   B134},
X	{"150",   B150},
X	{"200",   B200},
X	{"300",   B300},
X	{"600",   B600},
X	{"1200",  B1200},
X	{"1800",  B1800},
X	{"2400",  B2400},
X	{"4800",  B4800},
X	{"9600",  B9600},
X	{"19200", B19200},
X};
X
Xstatic int
Xtranslate_baud(const char *speed)
X{
X     int i;
X
X     for (i=0; i < sizeof(trans)/sizeof(struct trans); ++i) {
X	 if (strcmp(speed, trans[i].speed) == 0)
X	     return trans[i].baud;
X     }
X     return -1;
X}
X
Xint
Xmodem_connected(void)
X{
X    struct updata d;
X
X    if (!is_phone || ioctl(phone_fd, PIOCGETP, &d) < 0)
X	return 1;
X
X    return d.c_linestatus & MODEMCONNECTED;
X}
END_OF_FILE
if test 2971 -ne `wc -c <'dial.c'`; then
    echo shar: \"'dial.c'\" unpacked with wrong size!
fi
# end of 'dial.c'
fi
if test -f 'msg_queues.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'msg_queues.c'\"
else
echo shar: Extracting \"'msg_queues.c'\" \(1901 characters\)
sed "s/^X//" >'msg_queues.c' <<'END_OF_FILE'
X/*
X *	msg_queues -- create and destroy the message queues
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include "uw.h"
X
X#include <stdio.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X
Xkey_t c_key, r_key, w_key;
Xint c_id, r_id, w_id;
X
X/*
X * The 'c' queue is to send messages to the control process.
X * Both the reader and the write can do this.
X *
X * The 'r' queue is to send messages from the controller to the reader.
X *
X * The 'w' queue is to send messages from the controller to the writer.
X */
Xint
Xcreate_message_queues(void)
X{
X    c_id = r_id = w_id = -1;
X
X    c_key = ftok(UW_PROGRAM, 'c');
X    if (c_key < 0) {
X	fprintf(stderr, "%s: ftok failed (control): ", cmd_name);
X	perror("");
X	return -1;
X    }
X    c_id = msgget(c_key, IPC_CREAT | IPC_EXCL | 0722);
X    if (c_id < 0) {
X	fprintf(stderr, "%s: msgget failed (control): ", cmd_name);
X	perror("");
X	return -1;
X    }
X
X    r_key = ftok(UW_PROGRAM, 'r');
X    if (r_key < 0) {
X	fprintf(stderr, "%s: ftok failed (reader): ", cmd_name);
X	perror("");
X	return -1;
X    }
X    r_id = msgget(r_key, IPC_CREAT | IPC_EXCL | 0744);
X    if (r_id < 0) {
X	fprintf(stderr, "%s: msgget failed (reader): ", cmd_name);
X	perror("");
X	return -1;
X    }
X
X    w_key = ftok(UW_PROGRAM, 'w');
X    if (w_key < 0) {
X	fprintf(stderr, "%s: ftok failed (writer): ", cmd_name);
X	perror("");
X	return -1;
X    }
X    w_id = msgget(w_key, IPC_CREAT | IPC_EXCL | 0744);
X    if (w_id < 0) {
X	fprintf(stderr, "%s: msgget failed (writer): ", cmd_name);
X	perror("");
X	return -1;
X    }
X
X    return 0;
X}
X
Xvoid
Xdelete_message_queues(void)
X{
X    if (c_id >= 0)
X	msgctl(c_id, IPC_RMID, (struct msqid_ds *)0);
X    if (r_id >= 0)
X	msgctl(r_id, IPC_RMID, (struct msqid_ds *)0);
X    if (w_id >= 0)
X	msgctl(w_id, IPC_RMID, (struct msqid_ds *)0);
X}
END_OF_FILE
if test 1901 -ne `wc -c <'msg_queues.c'`; then
    echo shar: \"'msg_queues.c'\" unpacked with wrong size!
fi
# end of 'msg_queues.c'
fi
if test -f 'reader.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader.c'\"
else
echo shar: Extracting \"'reader.c'\" \(5317 characters\)
sed "s/^X//" >'reader.c' <<'END_OF_FILE'
X/*
X *	reader -- get input from the keyboard and sent it to the host
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include "uw.h"
X#include <sys/window.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X#include <stdio.h>
X#include <termio.h>
X#include <signal.h>
X
Xstatic int set_current(int real_window);
Xstatic void check_input(void);
Xstatic void check_command(void);
Xstatic void send_to_server(unsigned char);
X
Xstatic int window = -1, sig_usr1 = 1;
X
Xstatic void
Xcatch_usr1(void)
X{
X    signal(SIGUSR1, catch_usr1);
X    ++sig_usr1;
X}
X
Xstatic void
Xcatch_wind(void)
X{
X    signal(SIGWIND, catch_wind);
X}
X
Xvoid
Xreader(void)
X{
X    int current;
X
X    signal(SIGUSR1, catch_usr1);
X    signal(SIGWIND, catch_wind);
X
X    while (1) {
X	if (sig_usr1)
X	    check_command();
X
X	current = ioctl(STDIN, WIOCGCURR, (char *)0);
X	if (current >= 0 && (window < 0 || 
X	    (window >= 0 && current != win_info[window].window_number)))
X	    if (set_current(current) < 0 && !sig_usr1)
X		sleep(TIMEOUT);
X
X	if (window >= 0)
X	    check_input();
X    }
X}
X
Xstatic int
Xset_current(int real_window)
X{
X    int i;
X
X    if (protocol == PROTOCOL_0) {
X	if (win_info[0].window_number == real_window && win_info[0].fd >= 0) {
X	    window = 0;
X	    return 0;
X	}
X    }
X    else if (protocol == PROTOCOL_1) {
X	for (i=1; i<=MAX_WINDOWS; ++i) {
X	    if (win_info[i].window_number == real_window
X		&& win_info[i].fd >= 0) {
X		send_to_server(P1_FN_ISELW | i);
X		window = i;
X		return 0;
X	    }
X	}
X    }
X
X    return -1;
X}
X
Xstatic void
Xcheck_input(void)
X{
X    int i;
X    static int keyboard_escape = 0;
X    unsigned char c;
X
X    if (read(win_info[window].fd, &c, 1) <= 0)
X	return;
X
X    if (!keyboard_escape) {
X	if (c == kbd_esc_char) {
X	    keyboard_escape = 1;
X	    return;
X	}
X	if (use_meta && (c & META_BIT)) {
X	    keyboard_escape = 1;
X	    c &= ~META_BIT;
X	}
X    }
X    if (protocol == PROTOCOL_0) {
X	if (!keyboard_escape || (keyboard_escape && c == kbd_esc_char)) {
X	    write(phone_fd, &c, 1);
X	}
X	else {
X	    switch(c) {
X	    case 'b':
X	    case 'B':
X		ioctl(phone_fd, TCSBRK, (char *)0);
X		break;
X#if 0
X	    case 's':
X	    case 'S':
X		send_controller(P1_INT_STARTUP);
X		break;
X#endif
X	    case 'u':
X	    case 'U':
X		send_controller(P1_INT_UPLOAD);
X		break;
X	    case 'd':
X	    case 'D':
X		send_controller(P1_INT_DOWNLOAD);
X		break;
X	    case 'x':
X	    case 'X':
X		send_controller(P1_INT_DIE);
X		break;
X	    default:
X		c = '\a';
X		write(1, &c, 1);
X		break;
X	    }
X	}
X    }
X    if (protocol == PROTOCOL_1) {
X	if (!keyboard_escape || (keyboard_escape && c == kbd_esc_char)) {
X	    if (c & META_BIT) {
X		send_to_server(P1_FN_META);
X		c &= ~META_BIT;
X	    }
X	    switch(c) {
X	    case IAC:
X		send_to_server(P1_FN_CTLCH | P1_CC_IAC);
X		break;
X	    case XON:
X		send_to_server(P1_FN_CTLCH | P1_CC_XON);
X		break;
X	    case XOFF:
X		send_to_server(P1_FN_CTLCH | P1_CC_XOFF);
X		break;
X	    default:
X		write(phone_fd, &c, 1);
X		break;
X	    }
X	}
X	else {
X	    switch(c) {
X#if 0
X	    case 's':
X	    case 'S':
X		send_controller(P1_INT_SHUTDOWN);
X		break;
X#endif
X	    case 'C':
X	    case 'c':
X		for (i=1; i<=MAX_WINDOWS; ++i) {
X		    if (win_info[i].fd < 0) {
X			send_controller(P1_FN_NEWW | i);
X			send_to_server(P1_FN_NEWW | i);
X			break;
X		    }
X		}
X		break;
X	    case 'K':
X	    case 'k':
X		if (window > 0 && win_info[window].fd >= 0) {
X		    send_controller(P1_FN_KILLW | window);
X		    send_to_server(P1_FN_KILLW | window);
X		}
X		break;
X	    case '1':
X	    case '2':
X	    case '3':
X	    case '4':
X	    case '5':
X	    case '6':
X	    case '7':
X		i = c - '1' + 1;
X		if (win_info[i].fd >= 0)
X		    ioctl(win_info[i].fd, WIOCSELECT, (char *)0);
X		break;
X	    default:
X		c = '\a';
X		write(1, &c, 1);
X		break;
X	    }
X	}
X    }
X    keyboard_escape = 0;
X    return;
X}
X
Xstatic void
Xcheck_command(void)
X{
X    struct message msg;
X
X    if (msgrcv(r_id, &msg, MSG_SIZE, MSG_TYPE, IPC_NOWAIT) < 0)
X	return;
X
X    --sig_usr1;
X
X    switch (msg.text[COMMAND]) {
X    case PROTOCOL_0_CMD:
X	if (protocol == PROTOCOL_1) {
X	    close_all_windows();
X	    send_to_server(P1_FN_MAINT | P1_MF_EXIT);
X	}
X	protocol = PROTOCOL_0;
X	if (open_window(0, msg.text[REAL_WINDOW], READ_ONLY) < 0)
X	    send_controller(P1_INT_DIE);
X	else
X	    window = 0;
X	break;
X    case PROTOCOL_1_CMD:
X	if (protocol == PROTOCOL_0)
X	    close_window(0);
X	if (protocol == PROTOCOL_1)
X	    close_all_windows();
X	protocol = PROTOCOL_1;
X	window = -1;
X	break;
X    case CREATE_WINDOW_CMD:
X	if (msg.text[REAL_WINDOW] <= 0) {
X	    send_to_server(P1_FN_KILLW | window);
X	}
X	else {
X	    if (open_window(msg.text[LOGICAL_WINDOW], msg.text[REAL_WINDOW],
X		READ_ONLY) < 0)
X		send_controller(P1_FN_KILLW | msg.text[LOGICAL_WINDOW]);
X	    else {
X		window = msg.text[LOGICAL_WINDOW];
X		send_to_server(P1_FN_ISELW | window);
X	    }
X	}
X	break;
X    case KILL_WINDOW_CMD:
X	close_window(msg.text[LOGICAL_WINDOW]);
X	if (window == LOGICAL_WINDOW)
X	    window = -1;
X	break;
X    case DIE_CMD:
X	close(phone_fd);
X	exit(0);
X	break;
X    case PAUSE_CMD:
X	while (sig_usr1 == 0)
X	    pause();
X	break;
X    case CONT_CMD:
X	break;
X    }
X}
X
Xstatic void
Xsend_to_server(unsigned char c)
X{
X    static const unsigned char prefix = P1_IAC;
X
X    write(phone_fd, &prefix, 1);
X    c = c | P1_DIR_CTOS;
X    write(phone_fd, &c, 1);
X}
END_OF_FILE
if test 5317 -ne `wc -c <'reader.c'`; then
    echo shar: \"'reader.c'\" unpacked with wrong size!
fi
# end of 'reader.c'
fi
if test -f 'updnload.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'updnload.c'\"
else
echo shar: Extracting \"'updnload.c'\" \(2631 characters\)
sed "s/^X//" >'updnload.c' <<'END_OF_FILE'
X/*
X *	updnload -- do file trasfer between 3b1 and host
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include "uw.h"
X#include "config.h"
X
X#include <stdarg.h>
X#include <fcntl.h>
X#include <stdio.h>
X#include <termio.h>
X#include <sys/wait.h>
X
Xstatic void
Xupdnload(const char *path, ...)
X{
X    va_list args;
X    struct termio t;
X    int pid, ret;
X    union wait status;
X
X    if (ioctl(phone_fd, TCGETA, &t) < 0) {
X	fprintf(stderr, "%s: can't get termio for phone fd %d: ",
X	    cmd_name, phone_fd);
X	perror("");
X	return;
X    }
X
X    pid = fork();
X    if (pid < 0) {
X	va_start(args, path);
X	fprintf(stderr, "%s: can't fork \"%s\"\n",
X	    cmd_name, *(const char **)args);
X	perror("");
X	va_end(args);
X    }
X    else if (pid == 0) {			/* child */
X	setpgrp();
X	chdir(DEFAULT_DIR);
X	close(0);
X	close(1);
X	if (fcntl(phone_fd, F_DUPFD, 0) < 0) {
X	    fprintf(stderr, "%s: can't dup phone fd %d to 0\n",
X		cmd_name, phone_fd);
X	    perror("");
X	    exit(1);
X	}
X	if (fcntl(phone_fd, F_DUPFD, 1) < 0) {
X	    fprintf(stderr, "%s: can't dup phone fd %d to 1\n",
X		cmd_name, phone_fd);
X	    perror("");
X	    exit(1);
X	}
X	setgid(getgid());
X	setuid(getuid());
X	va_start(args, path);
X	execv(path, (const char **)args);
X	fprintf(stderr, "%s: can't exec \"%s\": ", cmd_name, path);
X	perror("");
X	va_end(args);
X	exit(1);
X    }
X    else {					/* parent */
X	va_start(args, path);
X	while (1) {
X	    ret = wait(&status);
X	    if (ret < 0) {
X		fprintf(stderr, "\n%s: %s: wait failed: ",
X		    cmd_name, *(const char **)args);
X		perror("");
X	    }
X	    else if (ret != pid) {
X		fprintf(stderr,
X		    "\n%s: %s: "
X		    "wait returned status [%.8x] for unknown pid %d\n",
X		    cmd_name, *(const char **)args, status.w_status, ret);
X	    }
X	    else
X		break;
X	}
X	if (status.w_termsig == 0) {
X	    if (status.w_retcode != 0)
X		fprintf(stderr, "%s: %s: exit status %d\n",
X		    cmd_name, *(const char **)args, status.w_retcode);
X	    else
X		fprintf(stderr, "%s: up/down load complete\n", cmd_name);
X	}
X	else
X	    fprintf(stderr, "%s: %s: killed signal %d\n",
X		cmd_name, *(const char **)args, status.w_termsig);
X	va_end(args);
X    }
X
X    if (ioctl(phone_fd, TCSETA, &t) < 0) {
X	fprintf(stderr, "%s: can't set termio for phone fd %d: ",
X	    cmd_name, phone_fd);
X	perror("");
X    }
X}
X
Xvoid
Xupload(void)
X{
X    updnload(UPLOAD_PROGRAM,
X	UPLOAD_ARG_0, UPLOAD_ARG_1, UPLOAD_ARG_2, UPLOAD_ARG_3);
X}
X
Xvoid
Xdownload(void)
X{
X    updnload(DOWNLOAD_PROGRAM,
X	DOWNLOAD_ARG_0, DOWNLOAD_ARG_1, DOWNLOAD_ARG_2, DOWNLOAD_ARG_3);
X}
END_OF_FILE
if test 2631 -ne `wc -c <'updnload.c'`; then
    echo shar: \"'updnload.c'\" unpacked with wrong size!
fi
# end of 'updnload.c'
fi
if test -f 'utils.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'utils.c'\"
else
echo shar: Extracting \"'utils.c'\" \(2476 characters\)
sed "s/^X//" >'utils.c' <<'END_OF_FILE'
X/*
X *	utils -- open and close windows, etc.
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include "uw.h"
X#include <fcntl.h>
X#include <stdio.h>
X#include <termio.h>
X#include <signal.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X
Xstatic int set_window_modes(int fd);
X
Xvoid
Xclose_window(int logical_window)
X{
X    if (win_info[logical_window].fd >= 0) {
X	close(win_info[logical_window].fd);
X	win_info[logical_window].fd = -1;
X	win_info[logical_window].window_number = -1;
X    }
X}
X
Xvoid
Xclose_all_windows(void)
X{
X    int i;
X
X    for (i=1; i<=MAX_WINDOWS; ++i)
X	close_window(i);
X}
X
Xint
Xopen_window(int logical_window, int real_window, int rdonly)
X{
X    char window_name[32];
X
X    if (real_window <= 0)
X	return -1;
X
X    if (win_info[logical_window].fd != -1)
X	return -1;
X
X    sprintf(window_name, WINDOW_DEVICE_BY_NUMBER, real_window);
X    win_info[logical_window].fd =
X	open(window_name, (rdonly == READ_ONLY ? O_RDONLY : O_WRONLY), 0);
X
X    if (win_info[logical_window].fd < 0) {
X	fprintf(stderr, "%s: can't open %s: ", cmd_name, window_name);
X	perror("");
X	return -1;;
X    }
X    if (set_window_modes(win_info[logical_window].fd) < 0)
X	return -1;
X
X    win_info[logical_window].window_number = real_window;
X
X    return 0;
X}
X
Xstatic int
Xset_window_modes(int fd)
X{
X    struct termio t;
X
X    if (ioctl(fd, TCGETA, &t) < 0) {
X	fprintf(stderr, "%s: can't get termio for fd %d: ", cmd_name, fd);
X	perror("");
X	return -1;
X    }
X
X    t.c_cc[VMIN] = 1;
X    t.c_cc[VTIME] = 0;
X    t.c_iflag = 0;
X    t.c_oflag = 0;
X    t.c_lflag = 0;
X
X    if (ioctl(fd, TCSETA, &t) < 0) {
X	fprintf(stderr, "%s: can't set termio for fd %d: ", cmd_name, fd);
X	perror("");
X	return -1;
X    }
X
X    return 0;
X}
X
Xvoid
Xsend_controller(int byte)
X{
X    struct message msg;
X
X    msg.type = MSG_TYPE;
X    msg.text[COMMAND] = SERVER_CMD;
X    msg.text[SERVER_BYTE] = byte;
X    msgsnd(c_id, &msg, MSG_SIZE, IPC_NOWAIT);
X}
X
Xvoid
Xsend_rd_wr(int command, int param1, int param2)
X{
X    struct message msg;
X    static int first = 1;
X
X    msg.type = MSG_TYPE;
X    msg.text[COMMAND] = command;
X    msg.text[PARAM1] = param1;
X    msg.text[PARAM2] = param2;
X    msgsnd(r_id, &msg, MSG_SIZE, IPC_NOWAIT);
X    msgsnd(w_id, &msg, MSG_SIZE, IPC_NOWAIT);
X    if (first)			/* no signals on the first message */
X	first = 0;
X    else {
X	kill(pid_rd, SIGUSR1);
X	kill(pid_wr, SIGUSR1);
X    }
X}
END_OF_FILE
if test 2476 -ne `wc -c <'utils.c'`; then
    echo shar: \"'utils.c'\" unpacked with wrong size!
fi
# end of 'utils.c'
fi
if test -f 'uw.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uw.c'\"
else
echo shar: Extracting \"'uw.c'\" \(4441 characters\)
sed "s/^X//" >'uw.c' <<'END_OF_FILE'
X/*
X *	uw -- the main program
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include "uw.h"
X#include "config.h"
X
X#include <stdio.h>
X#include <signal.h>
X#include <errno.h>
X#include <sys/window.h>
X
Xchar *cmd_name;
X
Xstatic volatile void usage(void);
Xstatic volatile void terminate(void);
Xstatic void reap(void);
X
Xint phone_fd;
Xstatic char *phone_line = DEFAULT_PHONE_LINE;
Xstruct window_info win_info[MAX_WINDOWS + 1];
Xint protocol = PROTOCOL_NONE;
Xint pid_rd, pid_wr;
Xint use_meta, kbd_esc_char;
X
Xstatic int conv_esc(const char *);
X
Xextern char *optarg;
Xextern int optind;
X
Xvoid
Xmain(int argc, char *argv[])
X{
X    int i;
X    char *baud_rate = DEFAULT_BAUD_RATE;
X    char *phone_number = 0;
X
X    cmd_name = argv[0];
X
X    if (ioctl(STDIN, WIOCGCURR, (char *)0) < 0) {
X	fprintf(stderr, "%s: can't get current window\n", cmd_name);
X	exit(1);
X    }
X    if (init_window() < 0)
X	exit(1);
X
X#ifdef DEFAULT_META
X    use_meta = 1;
X#else
X    use_meta = 0;
X#endif
X
X#ifdef DEFAULT_KBD_ESC
X    kbd_esc_char = conv_esc(DEFAULT_KBD_ESC);
X#else
X    kbd_esc_char = -1;
X#endif
X
X    while((i = getopt(argc, argv, "mMe:El:s:")) != EOF) {
X	switch (i) {
X	case 'm':
X	    use_meta = 1;
X	    break;
X	case 'M':
X	    use_meta = 0;
X	    break;
X	case 'e':
X	    kbd_esc_char = conv_esc(optarg);
X	    break;
X	case 'E':
X	    kbd_esc_char = -1;
X	    break;
X	case 'l':
X	    phone_line = optarg;
X	    break;
X	case 's':
X	    baud_rate = optarg;
X	    break;
X	case '?':
X	    usage();
X	    break;
X	}
X    }
X    if (optind == argc - 1)
X	phone_number = argv[optind];
X    else if (optind < argc)
X	usage();
X
X    printf("uw: connecting");
X    if (phone_number)
X	printf(", dialing %s", phone_number);
X    if (use_meta)
X	printf(", using meta key");
X    if (kbd_esc_char >= 0) {
X	printf(", using escape char \"");
X	if (kbd_esc_char & 0200)
X	    printf("M");
X	i = kbd_esc_char & 0177;
X	if (i < ' ')
X	    printf("^%c", i + '@');
X	else if (i == 0177)
X	    printf("^?");
X	else
X	    printf("%c", i);
X	printf("\" ('\\%.3o')", kbd_esc_char);
X    }
X    printf("\n");
X
X    phone_fd = dial_number(phone_line, baud_rate, phone_number);
X
X    if (phone_fd < 0)
X	terminate();
X
X    for (i=0; i<=MAX_WINDOWS; ++i) {
X	win_info[i].window_number = -1;
X	win_info[i].fd = -1;
X    }
X
X    signal(SIGINT, SIG_IGN);
X    signal(SIGQUIT, SIG_IGN);
X    signal(SIGHUP, SIG_IGN);
X    signal(SIGUSR1, SIG_IGN);
X
X    if (create_message_queues() < 0)
X	terminate();
X
X    pid_rd = fork();
X    if (pid_rd < 0) {
X	fprintf(stderr, "%s: can't fork: ", cmd_name);
X	perror("");
X	terminate();
X    }
X
X    if (pid_rd == 0)
X	reader();
X
X    pid_wr = fork();
X    if (pid_wr < 0) {
X	fprintf(stderr, "%s: can't fork: ", cmd_name);
X	perror("");
X	kill(pid_rd, SIGKILL);
X	terminate();
X    }
X
X    if (pid_wr == 0)
X	writer();
X
X    controller();
X
X    terminate();
X}
X
Xstatic volatile void
Xusage(void)
X{
X    fprintf(stderr, "%s: Usage: %s [-m | -M | -E | -e esc]"
X	" [-l <line>] [-s <speed>] [<telno>]\n",
X	cmd_name, cmd_name);
X    exit(1);
X}
X
Xstatic volatile void
Xterminate(void)
X{
X    signal(SIGINT, SIG_IGN);
X    signal(SIGQUIT, SIG_IGN);
X    signal(SIGHUP, SIG_IGN);
X
X    reap();
X
X    delete_message_queues();
X
X    close_window(0);
X    close_all_windows();
X
X    undial_number(phone_line);
X
X    exit(0);
X}
X
Xstatic void
Xcatch(void)
X{
X}
X
Xstatic void
Xreap(void)
X{
X    int pid;
X
X    signal(SIGALRM, catch);
X    alarm(10);
X
X    while (pid_rd > 0 && pid_wr > 0) {
X	pid = wait((int *)0);
X	if (pid < 0) {
X	    fprintf(stderr, "%s: error from wait: ", cmd_name);
X	    perror("");
X	    break;
X	}
X	if (pid == pid_rd)
X	    pid_rd = -1;
X	if (pid == pid_wr)
X	    pid_wr = -1;
X    }
X
X    alarm(0);
X    signal(SIGALRM, SIG_DFL);
X
X    if (pid_rd > 0)
X	kill(pid_rd, SIGKILL);
X    if (pid_wr > 0)
X	kill(pid_wr, SIGKILL);
X}
X
Xstatic int
Xconv_esc(const char *p)
X{
X    const char *q = p;
X    int l = strlen(p);
X    int meta = 0;
X
X    if (l > 1) {
X	if (q[0] == 'M') {
X	    meta = 0200;
X	    q++;
X	    l--;
X	}
X    }
X    if (l == 1) {
X	if (q[0] >= ' ' && q[0] < '\177')
X	    return q[0] | meta;
X    }
X    else if (l == 2) {
X	if (q[0] == '^') {
X	    if (q[1] >= '@' && q[1] <= '_')
X		return (q[1] & 0x1f) | meta;
X	    else if (q[1] >= 'a' && q[1] <= 'z')
X		return (q[1] & 0x1f) | meta;
X	    else if (q[1] == '?')
X		return '\177' | meta;
X	}
X    }
X
X    fprintf(stderr, "%s: invalid escape %s\n", cmd_name, p);
X    return -1;
X}
END_OF_FILE
if test 4441 -ne `wc -c <'uw.c'`; then
    echo shar: \"'uw.c'\" unpacked with wrong size!
fi
# end of 'uw.c'
fi
if test -f 'uw.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uw.h'\"
else
echo shar: Extracting \"'uw.h'\" \(2247 characters\)
sed "s/^X//" >'uw.h' <<'END_OF_FILE'
X/*
X *	uw.h -- random stuff needed by the C source
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include <stdlib.h>
X#include <sys/types.h>
X#include "uw_pcl.h"
X
X#define WINDOW_DEVICE		"/dev/window"
X#define WINDOW_DEVICE_BY_NUMBER "/dev/w%d"
X
X#define UW_PROGRAM		"/usr/local/bin/uw"
X
X#define STDIN			0
X
X#define MAX_WINDOWS		P1_NWINDOW
X
X#define READ_ONLY		1
X#define WRITE_ONLY		0
X
X#define PROTOCOL_NONE		-1
X#define PROTOCOL_0		1
X#define PROTOCOL_1		2
X
X#define PROTOCOL_0_CMD		'0'
X#define PROTOCOL_1_CMD		'1'
X#define CREATE_WINDOW_CMD	'C'
X#define KILL_WINDOW_CMD		'K'
X#define DIE_CMD			'D'
X#define SERVER_CMD		'S'
X#define PAUSE_CMD		'P'
X#define CONT_CMD		'R'
X
X#define COMMAND			0
X#define PARAM1			1
X#define PARAM2			2
X#define REAL_WINDOW		PARAM1
X#define LOGICAL_WINDOW		PARAM2
X#define SERVER_BYTE		PARAM1
X
X#define MSG_SIZE		8
X#define MSG_TYPE		1
X
X#define IAC			P1_IAC
X#define XON			'\021'
X#define XOFF			'\023'
X#define META_BIT		0200
X
X#define TIMEOUT			3
X
Xstruct message {
X    long type;
X    unsigned char text[MSG_SIZE];
X};
X
Xstruct window_info {
X    int window_number;
X    int fd;
X};
X
Xextern char *cmd_name;
Xextern int phone_fd;
Xextern struct window_info win_info[MAX_WINDOWS + 1];
Xextern int pid_rd, pid_wr;
Xextern int protocol;
Xextern key_t c_key, r_key, w_key;
Xextern int c_id, r_id, w_id;
Xextern int use_meta, kbd_esc_char;
X
Xint dial_number(const char *line, const char *speed, const char *number);
Xvoid undial_number(const char *line);
Xint modem_connected(void);
X
Xint create_message_queues(void);
Xvoid delete_message_queues(void);
X
Xint init_window(void);
Xint get_window(const char *win_name);
Xint window_number(int fd);
X
Xvoid close_window(int logical_window);
Xvoid close_all_windows(void);
Xint open_window(int logical_window, int real_window, int rdonly);
X
Xvoid send_controller(int byte);
Xvoid send_rd_wr(int command, int param1, int param2);
X
Xvolatile void reader(void);
Xvolatile void writer(void);
Xvoid controller(void);
X
Xvoid upload(void);
Xvoid download(void);
X
Xint msgctl(int, int, void *);
Xint msgget(key_t, int);
Xint msgsnd(int, void *, int, int);
Xint msgrcv(int, void *, int, long, int);
END_OF_FILE
if test 2247 -ne `wc -c <'uw.h'`; then
    echo shar: \"'uw.h'\" unpacked with wrong size!
fi
# end of 'uw.h'
fi
if test -f 'uw_pcl.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uw_pcl.h'\"
else
echo shar: Extracting \"'uw_pcl.h'\" \(1669 characters\)
sed "s/^X//" >'uw_pcl.h' <<'END_OF_FILE'
X/*
X *	uw_pcl.h -- defines protocol 1.  taken from John D Bruner's source
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#define	P1_IAC		0001		/* interpret as command */
X#define	P1_DIR		0100		/* command direction: */
X#define	P1_DIR_HTOM	0000		/*	from host to Mac */
X#define	P1_DIR_MTOH	0100		/*	from Mac to host */
X#define	P1_FN		0070		/* function code: */
X#define	P1_FN_NEWW	0000		/*	new window */
X#define	P1_FN_KILLW	0010		/*	kill (delete) window */
X#define	P1_FN_ISELW	0020		/*	select window for input */
X#define	P1_FN_OSELW	0030		/*	select window for output */
X#define	P1_FN_META	0050		/*	add meta to next data char */
X#define	P1_FN_CTLCH	0060		/*	low 3 bits specify char */
X#define	P1_FN_MAINT	0070		/*	maintenance functions */
X#define	P1_WINDOW	0007		/* window number mask */
X#define	P1_CC		0007		/* control character specifier: */
X#define	P1_CC_IAC	1		/*	IAC */
X#define	P1_CC_XON	2		/*	XON */
X#define	P1_CC_XOFF	3		/*	XOFF */
X#define	P1_MF		0007		/* maintenance functions: */
X#define	P1_MF_ENTRY	0		/*	beginning execution */
X#define	P1_MF_ASKPCL	2		/*	request protocol negotiation */
X#define	P1_MF_CANPCL	3		/*	suggest protocol */
X#define	P1_MF_SETPCL	4		/*	set current protocol */
X#define	P1_MF_EXIT	7		/*	execution terminating */
X#define	P1_NWINDOW	7		/* maximum number of windows */
X
X#define P1_DIR_STOC	P1_DIR_HTOM
X#define P1_DIR_CTOS	P1_DIR_MTOH
X
X#define P1_INTERNAL	0200
X#define P1_INT_DIE	0201
X#define P1_INT_SHUTDOWN	0202
X#define P1_INT_STARTUP	0203
X#define P1_INT_UPLOAD	0204
X#define P1_INT_DOWNLOAD	0205
END_OF_FILE
if test 1669 -ne `wc -c <'uw_pcl.h'`; then
    echo shar: \"'uw_pcl.h'\" unpacked with wrong size!
fi
# end of 'uw_pcl.h'
fi
if test -f 'window.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'window.c'\"
else
echo shar: Extracting \"'window.c'\" \(1961 characters\)
sed "s/^X//" >'window.c' <<'END_OF_FILE'
X/*
X *	window -- create windows
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include "uw.h"
X
X#include <stdio.h>
X#include <string.h>
X#include <sys/window.h>
X#include <fcntl.h>
X#include <termio.h>
X#include <sys/stat.h>
X#include <sys/sysmacros.h>
X
Xstatic int window_major_number;
X
Xint
Xinit_window(void)
X{
X    struct stat buf;
X    int stat(const char *, struct stat *);
X
X    if (stat(WINDOW_DEVICE, &buf) < 0) {
X	fprintf(stderr, "%s: can't stat %s: ", cmd_name, WINDOW_DEVICE);
X	perror("");
X	return -1;
X    }
X
X    window_major_number = major(buf.st_rdev);
X    return 0;
X}
X
Xint
Xget_window(const char *win_name)
X{
X    struct uwdata d;
X    struct utdata t;
X    int fd;
X
X    /*
X     * Create a new window.
X     */
X    fd = open(WINDOW_DEVICE, O_WRONLY, 0);
X    if (fd < 0) {
X	fprintf(stderr, "%s: can't open %s: ", cmd_name, WINDOW_DEVICE);
X	perror("");
X	return -1;
X    }
X
X    /*
X     * Set the window to use the full screen
X     */
X    d.uw_x = 0;
X    d.uw_y = WLINE(2);
X    d.uw_width = WINWIDTH;
X    d.uw_height = WINHEIGHT - d.uw_y;
X    d.uw_uflags = NBORDER;
X    if (ioctl(fd, WIOCSETD, &d) < 0) {
X	fprintf(stderr, "%s: window ioctl failed: ", cmd_name);
X	perror("");
X	close(fd);
X	return -1;
X    }
X
X    /*
X     * Give the window a name.  We don't care if it fails.
X     */
X    t.ut_num = WTXTUSER;
X    strncpy(t.ut_text, win_name, WTXTLEN);
X    t.ut_text[WTXTLEN-1] = '\0';
X    (void)ioctl(fd, WIOCSETTEXT, &t);
X
X    (void)ioctl(fd, WIOCSELECT, (char *)0);
X
X    return fd;
X}
X
Xint
Xwindow_number(int fd)
X{
X    struct stat buf;
X    int fstat(int, struct stat *);
X
X    if (fd < 0)
X	return -1;
X
X    if (fstat(fd, &buf) < 0) {
X	fprintf(stderr, "%s: can't stat fd %d: ", cmd_name, fd);
X	perror("");
X	return -1;
X    }
X
X    if (major(buf.st_rdev) == window_major_number)
X	return minor(buf.st_rdev);
X    else
X	return -1;
X}
END_OF_FILE
if test 1961 -ne `wc -c <'window.c'`; then
    echo shar: \"'window.c'\" unpacked with wrong size!
fi
# end of 'window.c'
fi
if test -f 'writer.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'writer.c'\"
else
echo shar: Extracting \"'writer.c'\" \(3888 characters\)
sed "s/^X//" >'writer.c' <<'END_OF_FILE'
X/*
X *	writer -- take input from the host and send it to the windows.
X *
X * Copyright 1989 by W J Andrew Fyfe.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X 
X#include "uw.h"
X#include <sys/window.h>
X#include <sys/ipc.h>
X#include <sys/msg.h>
X#include <stdio.h>
X#include <signal.h>
X
X#define BUF_SIZE	256
X
Xstatic void check_input(void);
Xstatic void check_command(void);
X
Xstatic int window = 0, sig_usr1 = 1;
X
Xstatic struct output_buffer {
X    int count;
X    unsigned char buf[BUF_SIZE];
X} out_buf[MAX_WINDOWS + 1];
X
Xstatic void
Xcatch_usr1(void)
X{
X    signal(SIGUSR1, catch_usr1);
X    ++sig_usr1;
X}
X
Xvoid
Xwriter(void)
X{
X    int i;
X
X    signal(SIGUSR1, catch_usr1);
X
X    for (i=0; i<=MAX_WINDOWS; ++i)
X	out_buf[i].count = 0;
X
X    while (1) {
X	if (sig_usr1)
X	    check_command();
X
X	check_input();
X    }
X}
X
Xstatic inline void
Xflush_output(int window)
X{
X    if (win_info[window].fd >= 0 && out_buf[window].count > 0) {
X	write(win_info[window].fd, out_buf[window].buf, out_buf[window].count);
X	out_buf[window].count = 0;
X    }
X}
X
Xstatic void
Xcheck_input(void)
X{
X    static int escape = 0;
X    static unsigned char meta_flag = 0;
X    int count, i, j;
X    unsigned char c;
X    unsigned char buf[BUF_SIZE];
X
X    if (protocol == PROTOCOL_NONE)
X	return;
X
X    count = read(phone_fd, buf, sizeof(buf));
X
X    for (i=0; i < count; ++i) {
X	c = buf[i];
X
X	if (escape) {
X	    escape = 0;
X	    if ((c & P1_DIR) != P1_DIR_STOC)
X		continue;
X	    switch (c & P1_FN) {
X	    case P1_FN_NEWW:
X		send_controller(c);
X		continue;
X	    case P1_FN_KILLW:
X		send_controller(c);
X		flush_output(c & P1_WINDOW);
X		close_window(c & P1_WINDOW);
X		continue;
X	    case P1_FN_MAINT:
X		send_controller(c);
X		for (j=0; j <= MAX_WINDOWS; ++j)
X		    flush_output(j);
X		switch(c & P1_MF) {
X		case P1_MF_EXIT:
X		    if (protocol == PROTOCOL_1)
X			close_all_windows();
X		    protocol = PROTOCOL_0;
X		    window = 0;
X		    break;
X		case P1_MF_ENTRY:
X		    if (protocol == PROTOCOL_0)
X			close_window(0);
X		    if (protocol == PROTOCOL_1)
X			close_all_windows();
X		    protocol = PROTOCOL_1;
X		    window = -1;
X		    break;
X		}
X		continue;
X	    case P1_FN_OSELW:
X		if (c & P1_WINDOW)
X		    window = c & P1_WINDOW;
X		continue;
X	    case P1_FN_META:
X		meta_flag = META_BIT;
X		continue;
X	    case P1_FN_CTLCH:
X		switch(c & P1_CC) {
X		case P1_CC_IAC:
X		    c = IAC;
X		    break;
X		case P1_CC_XON:
X		    c = XON;
X		    break;
X		case P1_CC_XOFF:
X		    c = XOFF;
X		    break;
X		}
X		break;
X	    }
X	}
X	else if (c == P1_IAC) {
X	    escape = 1;
X	    continue;
X	}
X
X	if (window >= 0 && out_buf[window].count < sizeof(out_buf[window].buf))
X	    out_buf[window].buf[out_buf[window].count++] = c | meta_flag;
X	meta_flag = 0;
X    }
X
X    for (i=0; i <= MAX_WINDOWS; ++i)
X	flush_output(i);
X
X    return;
X}
X
Xstatic void
Xcheck_command(void)
X{
X    struct message msg;
X
X    if (msgrcv(w_id, &msg, MSG_SIZE, MSG_TYPE, IPC_NOWAIT) < 0)
X	return;
X
X    --sig_usr1;
X
X    switch (msg.text[COMMAND]) {
X    case PROTOCOL_0_CMD:
X	if (protocol == PROTOCOL_1)
X	    close_all_windows();
X	if (open_window(0, msg.text[REAL_WINDOW], WRITE_ONLY) < 0)
X	    send_controller(P1_INT_DIE);
X	else {
X	    if (protocol == PROTOCOL_1)
X		window = 0;
X	    protocol = PROTOCOL_0;
X	    flush_output(0);
X	}
X	break;
X    case PROTOCOL_1_CMD:
X	break;
X    case CREATE_WINDOW_CMD:
X	if (msg.text[REAL_WINDOW] > 0 &&
X	    open_window(msg.text[LOGICAL_WINDOW], msg.text[REAL_WINDOW],
X	    WRITE_ONLY) < 0)
X	    send_controller(P1_FN_KILLW | msg.text[LOGICAL_WINDOW]);
X	else
X	    flush_output(msg.text[LOGICAL_WINDOW]);
X	break;
X    case KILL_WINDOW_CMD:
X	flush_output(msg.text[LOGICAL_WINDOW]);
X	close_window(msg.text[LOGICAL_WINDOW]);
X	break;
X    case DIE_CMD:
X	close(phone_fd);
X	exit(0);
X	break;
X    case PAUSE_CMD:
X	while (sig_usr1 == 0)
X	    pause();
X	break;
X    case CONT_CMD:
X	break;
X    }
X}
END_OF_FILE
if test 3888 -ne `wc -c <'writer.c'`; then
    echo shar: \"'writer.c'\" unpacked with wrong size!
fi
# end of 'writer.c'
fi
if test -f 'uw.uue' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'uw.uue'\"
else
echo shar: Extracting \"'uw.uue'\" \(9219 characters\)
sed "s/^X//" >'uw.uue' <<'END_OF_FILE'
Xbegin 755 uw.Z
XM'YV0`:0`($#B5H-4`!(J5,A!P(,`"Q:B`*,01D($E``@4+ at Q88*$+NB4P4-G
XM84>-$BD.7,BR)0`0+LB$H1-FX4>/+"T"T.G2)1`78N;,8?G18M&+&7LJ!0#(
XM!9LT8H at B(`8 at P=2E6+-JW<JUJ]>O8,.*'4NVK-FS:-.J7<NVK=NW<./*G4NW
XMKMVR+WA4G>HD%X`8";$\`O$DRB,7F%X@&:@$DQD`__ at IUC@"V4X(!/IJS*#M
XM!0#-@/'`T!O`"1`G5O[10W(.!@@GN at 3P0*)'@#`D>`"4]ALC@!LH3P0(4OA/
XMB=^;CP'HT8S@@#DE@,XD=(-[(V[=UQ$@<:/Z18Z]5$`#X.>-'P`*T-DDE'!]
XM`.@!ZK`\H?C/EA(7__*I!T"(`OY\#`R7$"'2`4"#&PE!$*!"@11(`7V.+)A0
XM(07*0!\@0IR2X75$,(<!*10%P$6&&^8&11'Y:/2A$Y(P9X$`*F%`XBG7G9 at B
XM`BNVZ!<"%N`PXW52L%@>`!C0QP($_PF0D(^!2`"`'0C8TF!"/$`I91L),:#$
XME`!(0)\!=N`@98%J4.2//A(D&0``!TCGCSM"``)!`)[!%@`P\IGI39KY";!F
XMFP#X(TV<<WI6(@!+>$@*G_GXR2:A='ZVHP7AZ1*`-T-"`)V;GL`&@"]F6H)D
XMGPD=($23`&Q9H`-V'#!F0E"8B8<=`=AR'``<)`=!ABY2D6="%- at A@*U5X9H<
XM`BY"\F-N,2 at J[`C#%,O!D`R8Z8*PQ'Z4:Z`B).LI#V92P(0[!##P#SI.>.%$
XM'56XD08>(%R1AAMDO'''4"7,H0,(8X3AQ at ET@/`&'&6X`8(88<Q1!@AWS%OO
XM'?LJA%I"K%DD1P`C!",M;?\(PQP(V)@`P`ON[1@".R0``-Q^/'BW%Q8<MX)$
XM'CL!@,M[HG"LRWN*+`M`ASM^>''&Q0(P)`?0[@7&",+L->(I+PAP'0R*C at N`
XMN?BDN^[$``RM\4W7!1`V:+YIS>X5(+30`L,.VPM""61\EAHL%0-@@@L:D<PQ
XM.'3`0HTC4;^'2N`[@IPRX1J='$2*5G$AP@#G!!*"(!@0$`(@&(P\@&?7#5&U
XM.U?_ at XK97$=]\>). at Q#`.8`H`0L"!&"I49PJ.2!%('0<0$L at ZOUC#AP!D(`?
XM/V;K488<;P`PKTARR%$''"61D488;!P/`AIUN"&=&V^`X.\<=QRO/!O5GT']
XMP6'4048+<LQ4!@!AC%$'"'`@+T;U6#[EQL+UOW%_&5CJU[\"-K""@8`)1"B"
XM%:8``#*4P0YI&,/"N!>P,- at A#&E at 0QC^U\`'1G!AV5L#]^Z`(.Z!P($0E*#W
XM+IC!#5;/>P%#F/K8YSX`F!"%'P2!".UEL)F@;X;M$PE'!F`9!`R@&1H9P#62
XM.(XDMB.)_]`(`2("N\S!+ at 52]($4FR!%-^1K7T/P%\`$1C"#?1$$"7D!"E\`
XM!S0`X(P9+-_YYD"P,I!A7R+(EP at 4\$9]G7!Z;`"!&3!8O3N^;0Y\E-L_G,$:
XM'H``!7A#@`KPQH!#&>`%F>%-`!"0,FKM1P68=)E58*:'?PAB9C6[&6\&D+-2
XM&H)G</A'B&:3FP-P;`Z8!`T!'$`MZ"3'"5XK%@'LX`QK`&X`N($"G02`HK\`
XM`!A",H^6`"$[%`@`;_=8)`#P1H!%"H`[^?B'-&P(@`&(4V]X@((``B<):FWG
XM'];`#166*1Y@(`XP0GA!`>Q$C"&A!Q#[D8`^18D`4OHC'2I11`_X0`$2P%,(
XMW,$&`(!``%CT``C_T`9$_\&-#O!!-_\8AQ#P0PXY6$,:CFA!$,ZE3UU:H048
XMA0=,_\&.Z[P at E[PA``ND`(B9TJ,%"(+`/_`A!%=$YC4O`$%2EZK4IH(&`2CH
XMI'E(\$DB`"((^O`'",H!B!?`8",$-:@=4&D15?Z%E;%4"0%`((!Q$8`'_]B9
XMNNK`->/LA1.RTX%=/T*``LF(1NF\Y'>LPHEZ4HN at A>4-`FB`6/$(P6P6J8%%
XM;E"#O\3`(C&8`0W^(ED`R``&%ID!:`%@@]'&X+.8Q<%H94"#T=)`M1;)06DQ
XMFP/4<L0`YF`)`@R`#H6L:;?K4(B2=@NZA`Q`(P:0AT((@%Q[**0`R-6'0 at R`
XM7'\HY``:.8"2+I)=ZN*D.1%)"!^;`P&%4/$`%5`(`[*K`84T(+L?4(@#N,8:
XM'#PRDD(01!'T\0\\F$``YQC$"V2`@Y%E\B\$0`!P?"E>$!"8`+63 at B#DX`!9
XM"")N_\!&+-W*@7_`@W2IP<=>!U(@#KP3'\FDTV`1D%AG`B,]%P%>[62`'WT(
XM(`A``$"<8%":N;Z@#G.0PPO8\(9^L>$%8IC7C^_0QWV9 at 0YO6(,@"6G'1X[A
XM#6Z@`_+8D(*(-1D$;9C#&<Y0AH`-,H-51L&5L[SE+J/QC$^.\I313(9'RJ$,
XM87"@'-S\Y3"/N<QS+J2=\:QG/L,9RE(^LZ!1<`<YI(%YAO:CG\EL9BK7F=&.
XMAK27N2:'?Q#-*J#H]*<10`I1?PT!5+C.&#CV&L7:803`V`LJ5I:@L'+,`BIA
XM!FX.(`V"CHXW`(`'K,%#:P!`P-:E3(!*<I8;.=#&'\YXZJMC;156%/O8*S:H
XM+!.BAUV3 at Z"L$(^PJ4WJ:R/;'_!0"12N<X=G\T':P[8*+,R=[6>70R4H\#9!
XM82'N>",`%,5&P;GC2;.RXNS9X5FE(M*:$`+$"<0)V2NJ96>!&1$TX<Y41R^/
XM0VJ*6WS%I!"/QJ4I<5#(3@(?WPLH1`YQ`'!,']>!`-G<((5;,:#E+[\.!6;>
XM\A<H@&/&B'DS>^,&%G%,&CJ/IK%'S(`"&0`V!!!&B:[P`%X!&Q at B,)HT9:>$
XM$2-`=AR0'0]0US at 0#%8CK)/%ZP!0(!.\H#2Z`(`.Y`-C(C$].0YHSWOB\P2O
XM8^D?BO`4B"`C"!)PAWASI>\Y"GPWC>`A`+BXU;8`(`*R(X`+MH!$<M"@!%0,
XM1'9@$,*M$$"[A%@!#P*(O+22 at P0Z!,#R7!!`((C#5M;98NW)(8'K8`=V"&S7
XMV$YZ.VP*8`RF%8OT@(BP(/!P`%P(HG?*V##H.DP/$/_#'_5U>6[$QIU_P-[L
XMQV>=5V%'-A;T$A#)&X`=1 at R!Y/B`4/CY!RPX3 at N\/WX$5/D(!"@R`"A('!=^
XM=1__\`_[`0'WEW_&=DT`\`<#^'BJIRV/$0#H<2L04"`64"`D`'\#.'][47_`
XM$C;O]`^(I1(:)2?QAP>^``V$@`<V``N$$!4`8`OC``@XL`-7XP3[``0&H`3F
XM46`)`0<`8`H`X`A!6(1">(1&F(1(N(1):`A):`E*&(5,"(1"2(1,>(52F(5"
XMZ(1(:`DE0 at 4%T%A7IQ(Z<!V$4#O740 at J80#7$0@>(@>_`@`>X%%L,H`@V'UC
XMHTG:0"VH]X#&`@!*PGX66"".H('R1W_)X0<"2(#K<1TH`!L#0`T*R(#_(!^&
XMB`<1@`O1`1*8J(FRXP`.N(E=HA(R@`<3H(D%X@$J80+7T2RZ,`"6$"*0<!TR
XM`(F*$"*$<!TS`(E^$")X<(<#.(*Z$7HFV(#/H()XH`,N&!4!P`,S6(,WF(,[
XM:!YZD1#F<8WCD8W7&``LP(W>V(W@^(WBR`(`\'CA>([?"`"T,([LB([NV([P
XM"([E&(_I2`NN!WL",`BT!V"M\SH$L!\6@#@X(@<O0C*P(0"FH!*@(&',YWR]
XM at PTJ(0E>ESP`@`C?=W8(P#J[%SL)(0=X@`"(,'HXI2)R(`%G%Q&_!2EU$ANQ
XM$G'YY1\-"`W40`C?QX\;*3LN,'5A^%4'!AC`H!(:0(<'8(?;%X)Y^!<!H%$4
XM:#4=)@_61P]14QW:AQVYH1W<`94@)Q[D81[_A"4!X`M38',:B`]T``W0(`AT
XM(`*P(`C,:`HS2`,V>'/[``+3"``I0S$`(`H!8`E[V9=\^9=^&9B`.9A^"0#6
XM$``70YB$R02"V9>,X)=T(`"T('G)(0')<AT_8"=`(!^N9WS:$C8:F`^&<@HN
XM`@WG5X!M^(8AHF.CIQ+VX'J3N7I98G4:02F<*9F4>1')$IF>B2L1*8#YH"LF
XM62PHJ1$JD6K;%YJ&4HSZ4">38IHD!U`)H0%\(ETI*2>1HIH_J('Z$&\:,9P?
XM49R[@ITK"0!:H!),P)W.69M4$)FQ^1$(D!PR0`>>UC3PN8IBZ$Q"0)NA0383
XM6"Q-!QGR(#P>9C9K4CH_5Y2E)`^(-71)R2+;-%$`L`!W.*&-)0F&%QEF<T8"
XM-$:4!@+,TP9IT#UF\`9R0#]H@&4+8P9U!C=>QJ%B9&8F*F5Y-`=[-#)`)F1T
XM]`9O<&1U4`=C``=P4`?W$T%?UJ$!0P;/@Z(J*D at M6F=0!@(PP$<P.D`GM*1M
XMU*0L^C90VCTQ0*5^A*0@,!)E,`8 at 4*,B$#$*<$9G=`<85&ETIJ9LZD=N^F@@
XM<&=T4`=RL#]U-@<TD:=S``);4`(N@`-XT`6"9*(@$$(C9#!PD`9/"J;[<D8C
XM8:=^.A-`QJ62NJAPH$8\!`)$EF?\\@9M``?5(Q*;>D9K$$=5-@=I<`9N<#YP
XMLZEBJC`!$Z(CFJ at GFJ7[XZ1<NFFIH0X5`P+OY`[RI&)W95C1"9"(=6Y>0!$"
XMP`7BH0 at I\TDO0$GGA at 9D93,'IP?^<`4\$R+VH`2"$($[ITE$\&Q3(!XJD"%#
XMIV-&MWTLDG*$)1Z$,"084'<RT*SUYJTIL*UF%0.L1!O]T`X\<Y2A`9I0LV(M
XM!ACWNJP)L:\,BVS]T`\`VZW]$`H'*Z_`A@?BX0KKV1M0(!ZB$+(!H`3;<377
XMJA'BH04KBP`46PP7NTJB,"3$J@?]4`0;JQOB at 0=%`#H,8`)Z45;OI`YD0PUT
XM)YT`('`"U:_]\`@&2;,$NQMGI0C^1!_*0`NB2`*><:W_H`XOT+0O0[!T$+5G
XM5;/F4220(0I\H@[BD`"0PF`3)8#K4"`:H('KT+5B.TH$&P<J at 0,4NP<S>[;4
XMHA(JT+9OJY(CL[<%1;!J,+@"B[;G4:SRM$X,JZQ74W<"-[%.:P20.[!ZP`\7
XMP#-N92[>8#;/$ZIQTP(T,P=Z@*-!-F1%1CU(IF2NFQ!<LR&EA`T<LPT<HPT<
XMDPVPT0\[-U<M`(1R\+H_%KM$9F2UZP8OD+QRDQ`_4DK>P#'=P#'<`!O\``XX
XM=PX@``+-U#C"@W:"H`2R@`(<220#IKZ.U6DE$`CJ"[_R"P!NU4U9DWA6D$8"
XMX'J!HPO_@`OR(6%P<`!KV3OP0*"(MRYJ]$`O<`=P<Z0Q2D8&=$:XFQK at T$AV
XM$TF0=#44>56,<WD@`#F`4$JZX(_)<60$P#&V\$[>NTJHD"%Z$`"ZX`K&=BRE
XM-Q#`XQET``Y_<T^;!'N/$SF74SGX:JV6.[:E%`>?VTK_0%<*QW``H`+?1\+C
XMEQEQ1P;0\7?D4,6L$P*$L!%Q8C5P!0T;&J83_*&X2J**NJ4N^F9H;*6V"J+'
XM(Z)L?*)N;$B*Y`Y14[Y6^0_&B@?S=$_/=)KK$37(]@^0H!(^0(<!\`_[,%*1
XML5%PPAWPL%&KP1V!3`7K)`"8.TU(G,A,7'#<*K7>"L55*\4.!P@$:K3ZJQH7
XMHU*J08=3,%0=@"`+D!]2F1WOA)7@(1[V\)2L$;ZQO%+T<,L3:LL(\@#Y@<P3
XM\`\P]Y%3B0!T0`\_G,1600KO&LR2L,M5B<@KMG+M9!X@,&(44""5="L/DA#$
XMFAO8MA>\\*[&$*_&1E#0)`GW2U.D$P<-;`=LA`:`81%5ZJ&`)C_-4S`!TS#T
XM8B]\Y`5!``!MT`1EH`-%P`8ZH"\`4`<0,ZINL#]C0`?S(ATL\$?4$]*'!``C
XM#60FW09E%@8Z5`8TD]*NJCUC.@?]0C#\@@9A<*)9QT5>4`)C``!>\`-O%-0B
XM\$@GP`6$. at -O<`)81*L37*)RL`9>-KTN=PZ.U'B<A"`,@`)Z at 0`9T`/Y-0+C
XM-$I35W6D>76&3'F)?`)-C+#E^#%24'<,`-=X('I[@0L<\P`J00IP$`S0$`AZ
XM0`.P4`@P"`TSJ`-QB8-04)<VH!"\\$R2'6N4#0"8,-F87=FQEAN:G=F>W=F@
XM_=F>/1RA7=FD``#J4=H`(`LS/`+%D-<JH01X;16XH!)`X#(P``$F`'5DX&^T
XM$(<J4$JNW8$JX0$CD"*Y+3(?H;;&A at +?D=QK>)"YZ*TPX'-F&P,"8`U91RTF
XM'`B/\0\,,,)3``@<F-LB4)G at 9]Y<10(RL!$J`0'$8MX4^72Q,1LX*P]#-P"%
XM)0ET)PCH')4XNPXLLF`<!X`)D7<X:P[OP0ET1W^R\XLX&P[YO=]TMV*WL!\_
XMA[/?P"+R(0=_(`STIP<?H`N!(#L04'E(D`831;##H!(@H`=_0.*52;"WL.!Q
XM>&QB@[._=E:<`!P$10L$FPD+#AQ!ON"(3`"B1"3,40`(X&^<D"G[0=\!T#.!
XM\'VK4\+_$`*%L!&EI.6P<SMZ<``DWCOH`(*YP4PI0G3T+#:YX1[=7)3R^N94
XM:6Q*UVH:@0#B4'=2OMO`I at C^Q at O[X7;]R at _U\-:A&\P*YRGR('&\<"S,H0"B
XM,*W^!@S[80/(Q@^Q8.C\(`L[FP`$Q0OB,<]QYPD2!PR.OB,BX+$[`@`\X"F$
XMX%9PQ0YGO"]5,`=A0&:3&JA;T`)M``)\D#9-X.MI4P3"W@(+4P8VC:B['D@\
XMH#]EX`/*W@*!R at -T5`9V!.V"R@,BP0;<`^U\5#K9ELBD\-8<ZTP>J[]IE*!S
XMCN9(671RSN;EM.9CTR)QAW$(H``HE];LF2Q)C@',80!/3L[\68X9NL!TM;^?
XM,5>4VCQMC#R]7J=T$#'T54K<<!WSI4G4D1L*(!X2L''P3)%L4.H4*0;\&0!(
XMVW=*"TK]^@^>8.C[X`$\DRF&RX%6T>CB96KP3/,(8.J0H0DX;Q4_"1F%J.^`
XMD>\6/W,>7_,420'7X>DK!NK`9 at P$OA?`0)'LD1M.3_6A/NL@,"\7]!1UANPW
XMO3#YDDB*)Z4F@""<M`0OL`"Z!`*GPID!H+7[00$,,`$`T`3)P0`B4(U,,=?C
XM#9N`D!P>P`!.\@$4Z0:&#P!^@"``8`80P!Z`@`3```B!H!)TX)Z#GQ!2L/A>
XMD!Q*P``J``!$'0`4R0"B#P!?H!L4:0&I'R(4J0&I_[J^D2`0,/H!0`<?``R"
XM8/DJX0*I7_K)H0!P\`>^GQ`<T/:)[`)-+'T,T$W5YV-KI-`/(\%R_*>'5-6H
XM\0_B\$[=7TK40#9TL&!*RP(<(PR)3`R&_ at _(`$O;UB4P@!_N``Y`0/G>"0,/
XMI_!Q/$8%9$9^]&74SVV,J(\62!2-'9%XJ4$3##.X!UBP0RE!`F2#DVB=J[$?
XMS%\I82PK;]R1LH`%NOZ!#G!_*B&&:;*%$CK at P4(1`-#@'\@#&<`#N)$DL&0]
XMP)B1P$=F#R at 7'K@"G>R3U9WJMO*L@*'S!]B`9Q`R(2#%?``)-"<*,#=$@9?U
XML_Z!`E0#@$B7W"W\P`Y\#FZX`C"+W?FD>058KD`8\F22@*WDLQ:A__9%K<)^
XM>0Q8<;\^%DED!\S@#N(`B`$"\B<[1$#\`V3T#P8`@5C`.':"?+J#[D````+B
XM@)^P6>,J)9S@!R*+*/8/"-3I2CQQ8.)!LY at S<VI.L2`!/4=J4#Q*B/%.!7`@
XM.P9"=;0#0!#8N(H06#NW(W?LCM[!#D8,"7`ZD`@.>`H'0!]0QO"P/E?-!^``
XM/O`/>('DD0X#0`C at AC7Q3D;&Y=(D+&#T"8&'=35T`2%('B at P"80P+G`$^B`-
XM"`(U$`!8`!00148,"I`.`@`+S+:E940`@`%X#`*`$T"``;!=F(23X`,X0!88
XM at JC05E3'#.(!BVT?@(&ZI`,40F32`0(`(`K$@$@0^Z$A*(@(<2`JQ(28$"$/
XM0UR($/$A!L0```TDHD(,`-S`(A9$```GY,3FD!0DZ5<$`'I`*#[B&UJ'V\54
XMH`KY0`)6Q_FB!>H+)XE"4A@(UAL00%^X``!0I.0G`W(B$I`#N`#)T0#WI8>$
XM@"S(B=1"`K##/Z&X>H5(9`0E<3T-I/PB'T0`@`D$2H`65`Z9*`!&X5FRB3A1
XM)R*_`>,3@:)0K!QD0Z,<Q0G(`"0,'S@`O.#Y0`9@@!)+Q:EP$JH")+Q%7N#=
XM=(,(X`,"P!?*)I8U*2`!'\`8QD!:C$,0H!+\P6$4C!!H-ND['N$KG@!@A(Q_
XMB##6)L,H`$9`8M06O-`S%@O&F!"$@5)T%(#"9D`*[T0:`8`JF`#F81!^!!:@
XM$CQ!77P4J.(R<@D5H!L_T6/D$EXB(>@`/C``^*(%^GT6@#2LHN0(`")`<6..
XM$T`EN+[C$@#PSF$4C1]A(B2$FW at KP$Q"@`$BX.R$KP#@%6LB(&``LX`X;`08
XM9`&"P#S8""(`"4P#:&`(S at X+F`!#8"!(`65A'Z4`(7"&"*(?`(%E*`V=1C4L
XM%C1`!!"`R)$5MR)(``$$P"L2`K"X%G<B670Y9O$%T`"T6!37(K7PCWN1$/0.
XM8#`N.``?\`?>ZY6MAM8``[S9G/MCO at S4:"5_LL4`$0`(2Y=P+-D!LS0([(!:
XM&@3,"!W,(!N0#V%`7;I++B<`8`,ER227I)-LDE#R24K)*`D`F,'<BY)8$@M@
XMR27I#)HDMLA-FI%'*`L-48Q$DXZ9C!8`.F4NI04!4E/0D`,AP at I\R<%(>KHC
XMK4@:VD+B@`&O)`/&EX%0`I(@>00`M\,>H""26S%@("T*`4D0(AP`<"H0/(!$
XME,GE-"J:$TCD$6H2E$VGZJ0;9@=YNI08`$XF!&9P%VL,[&F)Y^!\P8*8F!!H
XMP8'\"#1@)I9"5G83*V1"X`07\B<&1:]"%)&26LR)*D$0E$IH=BI=HNM at E0;B
XM589"\D at 3*61.M)`]$4/N2AC0*WO#KV2+ZNE24 at K\=`SUT\!3=4CI/WV$5RB@
XMQ at 7J^P?D8)_=A77)+MNENWR7\#)>RLMY22_KI;V\E_ at R7^K+?8D6!M``\BTN
X.X;=D`!K at +Z-(2U at 3+@&E
X`
Xend
END_OF_FILE
if test 9219 -ne `wc -c <'uw.uue'`; then
    echo shar: \"'uw.uue'\" unpacked with wrong size!
fi
# end of 'uw.uue'
fi
echo shar: End of shell archive.
exit 0



More information about the Unix-pc.sources mailing list