🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: mod.mac.sources
Article #16

UW v3.4 (part 3 of 9)

#16
From: John Bruner
Date: Thu, 23 Oct 1986 19:57
2528 lines
65634 bytes
: [UW v3.4 - part 3 of 9]
:
: This is a shar archive.  Extract with sh, not csh.
echo mkdir server
mkdir server
echo x - server/uw_opt.c
sed -e 's/^X//' > server/uw_opt.c << '!EOF!server/uw_opt.c!'
X/*
X *	uw_opt - window option handling for UW
X *
X * Copyright 1986 by John D. Bruner.  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 <sys/types.h>
X
X#include "uw_param.h"
X#include "uw_opt.h"
X
X/*
X * The following variable is a kludge for efficiency.  It is set to
X * a nonzero value when a bitmask is changed, indicating that opt_scan()
X * should be called.
X */
Xint calloptscan;			/* pending,do,dont awaits opt_scan */
X
X/* option input state variables */
Xstatic caddr_t optwin;			/* window */
Xstatic struct woptdefn *optwod;		/* window option definition */
Xstatic woptcmd_t optcmd;		/* option command */
Xstatic woption_t optnum;		/* current option number */
Xstatic woptarg_t *optarg;		/* current encoding */
Xstatic int optcnt;			/* count in current encoding */
Xstatic char *optout;			/* decoded option */
Xstatic char optbuf[512];		/* buffer for decoded option */
X
Xopt_new(wod, generic, unique)
Xregister struct woptdefn *wod, *generic, *unique;
X{
X	register int n, mask;
X
X	/*
X	 * Set up the option definition structure pointed to by "wod" to
X	 * correspond with the option definitions in "generic" (common to
X	 * all window types) and "unique" (per-window).
X	 */
X	mask = (1<<(WONUM_GENERIC+1))-1;
X	if (unique) {
X		wod->wod_askrpt = unique->wod_askrpt & ~mask;
X		wod->wod_pending = unique->wod_pending & ~mask;
X		for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
X			wod->wod_optlst[n] = unique->wod_optlst[n];
X	} else {
X		wod->wod_askrpt = 0;
X		wod->wod_pending = 0;
X		for (n=WONUM_GENERIC+1; n <= WONUM_MAX; n++)
X			wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
X	}
X	if (generic) {
X		wod->wod_askrpt |= generic->wod_askrpt & mask;
X		wod->wod_pending |= generic->wod_pending & mask;
X		for (n=1; n <= WONUM_GENERIC; n++)
X			wod->wod_optlst[n] = generic->wod_optlst[n];
X	} else {
X		for (n=1; n <= WONUM_GENERIC; n++)
X			wod->wod_optlst[n].wol_argdefn = (woptarg_t *)0;
X	}
X	wod->wod_do = wod->wod_askrpt;
X	wod->wod_dont = 0;
X	wod->wod_inquire = 0;
X	calloptscan = 1;
X}
X
Xopt_renew(wod, report)
Xregister struct woptdefn *wod;
Xint report;
X{
X	/*
X	 * Reset "wod_do" for all window options that we want the Macintosh
X	 * to report to us.  If "report" is nonzero, send the Mac the
X	 * current values of these options.
X	 */
X	wod->wod_do = wod->wod_askrpt;
X	wod->wod_dont = 0;
X	if (report)
X		wod->wod_pending = wod->wod_askrpt;
X	calloptscan = 1;
X}
X
Xopt_newtype(wod, generic, unique)
Xregister struct woptdefn *wod, *generic, *unique;
X{
X	register int n, bit;
X	register woptbmask_t oldask;
X
X	/*
X	 * Change the window options to reflect a new window emulation type.
X	 * The new emulation may not support all of the events that the old
X	 * one did, and in any event they may not mean the same thing.
X	 */
X	oldask = wod->wod_askrpt;
X	opt_new(wod, generic, unique);
X	for (n=1, bit=2; n <= WONUM_GENERIC; n++,bit<<=1) {
X		if ((oldask&bit) && !(wod->wod_askrpt&bit))
X			wod->wod_dont |= bit;
X		if (!(oldask&bit) && (wod->wod_askrpt&bit))
X			wod->wod_do |= bit;
X	}
X	for ( ; n <= WONUM_MAX; n++, bit<<=1)
X		if (wod->wod_askrpt&bit)
X			wod->wod_do |= bit;
X	calloptscan = 1;
X}
X
Xopt_setext(wod, fn)
Xregister struct woptdefn *wod;
Xregister void (*fn)();
X{
X	register int n;
X
X	/*
X	 * Set "wol_ext" to "fn" for each option that has a defined "wol_set".
X	 */
X	for (n=1; n <= WONUM_MAX; n++)
X		if (wod->wod_optlst[n].wol_set)
X			wod->wod_optlst[n].wol_ext = fn;
X}
X
Xopt_scan(w, wod, fn, mfd, cmd)
Xcaddr_t w;
Xregister struct woptdefn *wod;
Xvoid (*fn)();
Xfildes_t mfd;
Xint cmd;
X{
X	register struct woptlst *wol;
X	register char *cp;
X	register int n, bit, maxsize;
X	char buf[512];
X
X	/*
X	 * Scan the entire list of options for pending ones.  For each
X	 * one, call "fn".  "cmd" is the command that we are to pass as the
X	 * first argument to "fn".
X	 *
X	 * Note that we must send data (wod_pending) before processing
X	 * DO commands (wod_do); otherwise, the host and Mac may not
X	 * agree upon the value of a window option.  (The Mac might
X	 * respond to the "do" command before it sees the new value.)
X	 */
X	cp = buf;
X#ifdef notdef
X	for (n=1,bit=2,wol=wod->wod_optlst+1; n<=WONUM_MAX; n++,bit<<=1,wol++) {
X#else
X	for (n=WONUM_MAX, bit=(1<<WONUM_MAX), wol=wod->wod_optlst+WONUM_MAX;
X	     n > 0;
X	     n--, bit >>= 1, wol--) {
X#endif
X		if (wod->wod_pending&bit) {
X			wod->wod_pending &= ~bit;
X			if (wol->wol_argdefn) {
X				maxsize = 2 +
X				    opt_size(wol->wol_argdefn);
X				if (cp > buf + sizeof buf - maxsize - 1) {
X					*cp++ = 0;
X					(*fn)(mfd, cmd, buf, cp-buf);
X					cp = buf;
X				}
X				if (WONUM_USELONG(n)) {
X					*cp++ = WOC_SET|WONUM_LPREFIX;
X					*cp++ = WONUM_LENCODE(n);
X				} else
X					*cp++ = WOC_SET|WONUM_SENCODE(n);
X				cp += opt_encode(cp, wol->wol_argdefn,
X				    (*wol->wol_get)(w, n));
X			}
X		}
X		if (wod->wod_inquire&bit) {
X			wod->wod_inquire &= ~bit;
X			if (cp > buf + sizeof buf - 3) {
X				*cp++ = 0;
X				(*fn)(mfd, cmd, buf, cp-buf);
X				cp = buf;
X			}
X			if (wol->wol_argdefn) {
X				if (WONUM_USELONG(n)) {
X					*cp++ = WOC_INQUIRE|WONUM_LPREFIX;
X					*cp++ = WONUM_LENCODE(n);
X				} else
X					*cp++ = WOC_INQUIRE|WONUM_SENCODE(n);
X			}
X		}
X		if ((wod->wod_do|wod->wod_dont)&bit) {
X			if (cp > buf + sizeof buf - 3) {
X				*cp++ = 0;
X				(*fn)(mfd, cmd, buf, cp-buf);
X				cp = buf;
X			}
X			if (wod->wod_do&bit) {
X				wod->wod_do &= ~bit;
X				wod->wod_dont &= ~bit;
X				if (wol->wol_argdefn) {
X					if (WONUM_USELONG(n)) {
X						*cp++ = WOC_DO|WONUM_LPREFIX;
X						*cp++ = WONUM_LENCODE(n);
X					} else
X						*cp++ = WOC_DO|WONUM_SENCODE(n);
X				}
X			} else if (wod->wod_dont&bit) {
X				wod->wod_do &= ~bit;
X				wod->wod_dont &= ~bit;
X				if (wol->wol_argdefn) {
X					if (WONUM_USELONG(n)) {
X						*cp++ = WOC_DONT|WONUM_LPREFIX;
X						*cp++ = WONUM_LENCODE(n);
X					} else
X						*cp++=WOC_DONT|WONUM_SENCODE(n);
X				}
X			}
X		}
X		if (cp > buf) {
X			*cp++ = 0;
X			(*fn)(mfd, cmd, buf, cp-buf);
X			cp = buf;
X		}
X	}
X}
X
Xopt_size(woa)
Xregister woptarg_t *woa;
X{
X	register int size, cnt;
X
X	/*
X	 * Determine the maximum size of an option whose argument encoding
X	 * is specified by "woa".  This does NOT include additional encoding
X	 * (e.g. for meta characters) at the protocol level.
X	 */
X	if (woa) {
X		for (size=0; *woa != WOA_END; woa++) {
X			cnt = *woa & ~WOA_CMDMASK;
X			switch (*woa & WOA_CMDMASK) {
X			case WOA_CHARS(0):
X			case WOA_STRING(0):
X				size += cnt;
X				break;
X			case WOA_UDATA(0):
X				size += (cnt + 5) / 6;
X				break;
X			}
X		}
X	} else
X		size = 0;
X	return(size);
X}
X
Xopt_encode(buf, woa, data)
Xchar *buf;
Xregister woptarg_t *woa;
Xchar *data;
X{
X	register char *cp, *cq;
X	register int n, cnt;
X	register unsigned long ival;
X	union {
X		struct {
X			char	c1;
X			short	s;
X		}	cs;
X		struct {
X			char	c2;
X			long	l;
X		}	cl;
X	} u;
X
X	/*
X	 * Encode "data" according to the option argument specifier "woa"
X	 * into the buffer "buf".  Return the number of bytes of "buf"
X	 * actually used.  The caller has already verified that "buf" is
X	 * large enough.
X	 */
X	if (!data)
X		return(0);
X	for (cp=buf,cq=data; *woa != WOA_END; woa++) {
X		cnt = *woa & ~WOA_CMDMASK;
X		switch (*woa & WOA_CMDMASK) {
X		case WOA_CHARS(0):
X			for (n=0; n < cnt; n++)
X				*cp++ = *cq++;
X			break;
X		case WOA_STRING(0):
X			for (n=0; n < cnt-1 && *cq; n++)
X				*cp++ = *cq++;
X			if (n < cnt)
X				cq += cnt-n;
X			*cp++ = '\0';
X			break;
X		case WOA_UDATA(0):
X			if (cnt <= NBBY) {
X				ival = (unsigned char)*cq++;
X			} else if (cnt <= sizeof(short)*NBBY) {
X				while ((int)cq & ((char *)&u.cs.s-&u.cs.c1-1))
X					cq++;
X				ival = *(unsigned short *)cq;
X				cq += sizeof(short);
X			} else {
X				while ((int)cq & ((char *)&u.cl.l-&u.cl.c2-1))
X					cq++;
X				ival = *(unsigned long *)cq;
X				cq += sizeof(long);
X			}
X			if (cnt != sizeof(long)*NBBY)
X				ival &= (1<<cnt) - 1;
X			for (n=0; n < cnt; n += 6, ival >>= 6)
X				*cp++ = (ival & 077) | 0100;
X			break;
X		}
X	}
X	return(cp-buf);
X}
X			
Xopt_istart(w, wod)
Xcaddr_t w;
Xstruct woptdefn *wod;
X{
X	/*
X	 * Start collecting input for a window option specification.
X	 */
X	optwin = w;
X	optwod = wod;
X	optnum = 0;
X}
X
Xopt_input(c)
Xchar c;
X{
X	register int cnt, bit;
X	register struct woptdefn *wod;
X	register struct woptlst *wol;
X	register unsigned long ival;
X	union {
X		struct {
X			char	c1;
X			short	s;
X		}	cs;
X		struct {
X			char	c2;
X			long	l;
X		}	cl;
X	} u;
X
X	/*
X	 * Add the received character "c" to the current option specification.
X	 * If it is complete, take the appropriate action.  If option 0
X	 * (the endmarker) is received, return 0 (to notify the caller that
X	 * we are done).  Otherwise, return 1 -- more option data remains
X	 * to be processed.
X	 *
X	 * This code isn't as readable as it should be; there are far too
X	 * many return statements floating around.  Sorry about that.
X	 */
X	if (optwin) {
X		wod = optwod;
X		if (optnum == 0 || optnum == WONUM_MAX+1) {
X			/* start (or continue) decoding a new option */
X			if (optnum == 0) {
X				/* start new option (or decode endmarker) */
X				if (c & WONUM_MASK) {
X					/* new option */
X					optcmd = c & WOC_MASK;
X					if (WOC_BADCMD(optcmd)) {
X						opt_iflush();
X						return(0);
X					}
X					if (c == WONUM_LPREFIX) {
X						optnum = WONUM_MAX+1;
X						return(1);
X					} else
X						optnum = WONUM_SDECODE(c);
X				} else {
X					/* end of options */
X					opt_iflush();
X					return(0);
X				}
X			} else {
X				/* read second byte of long option number */
X				optnum = WONUM_LDECODE(c);
X				if (optnum > WONUM_MAX) {
X					opt_iflush();
X					return(0);
X				}
X			}
X			/*
X			 * This point is reached when the option number has
X			 * been completely decoded.  If the command is not
X			 * WOC_SET, then it has no arguments and we can
X			 * process it immediately.
X			 */
X			wol = &wod->wod_optlst[optnum];
X			bit = 1<<optnum;
X			if (optcmd == WOC_SET) {
X				optout = optbuf;
X				optcnt = 0;
X				optarg = wol->wol_argdefn;
X				if (!optarg) {
X					opt_iflush();
X					return(0);
X				}
X			} else {
X				if (wol->wol_ext &&
X				    (optcmd == WOC_WILL || optcmd == WOC_WONT))
X					(*wol->wol_ext)(optwin, optcmd,
X					    optnum, (char *)0, 0);
X				switch (optcmd) {
X				case WOC_INQUIRE:
X					wod->wod_pending |= bit;
X					calloptscan = 1;
X					break;
X				case WOC_DO:
X				case WOC_DONT:
X					break;
X				case WOC_WILL:
X					wod->wod_askrpt |= bit;
X					wod->wod_do &= ~bit;
X					break;
X				case WOC_WONT:
X					wod->wod_askrpt &= ~bit;
X					wod->wod_dont &= ~bit;
X					break;
X				}
X				optnum = 0;
X			}
X			return(1);
X		} else {
X			/* continue processing argument to option */
X			wol = &wod->wod_optlst[optnum];
X			bit = 1<<optnum;
X			cnt = *optarg & ~WOA_CMDMASK;
X			switch (*optarg & WOA_CMDMASK) {
X			case WOA_CHARS(0):
X				*optout++ = c;
X				optcnt++;
X				break;
X			case WOA_STRING(0):
X				*optout++ = c;
X				optcnt++;
X				if (!c) {
X					optout += cnt - optcnt;
X					optcnt = cnt;
X				} else if (optcnt == cnt-1) {
X					*optout++ = '\0';
X					optcnt = cnt;
X				}
X				break;
X			case WOA_UDATA(0):
X				if (optcnt == 0) {
X					if (cnt <= NBBY) {
X						*optout = 0;
X					} else if (cnt <= sizeof(short)*NBBY) {
X						while ((int)optout & ((char *)&u.cs.s-&u.cs.c1-1))
X							optout++;
X						*(short *)optout = 0;
X					} else {
X						while ((int)optout & ((char *)&u.cl.l-&u.cl.c2-1))
X							optout++;
X						*(long *)optout = 0;
X					}
X				}
X				ival = (c & 077) << optcnt;
X				if (cnt != NBBY*sizeof(long))
X					ival &= (1<<cnt) - 1;
X				optcnt += 6;
X				if (cnt <= NBBY) {
X					*(unsigned char *)optout |= (unsigned char)ival;
X					if (optcnt >= cnt)
X						optout++;
X				} else if (cnt <= sizeof(short)*NBBY) {
X					*(unsigned short *)optout |= (unsigned short)ival;
X					if (optcnt >= cnt)
X						optout += sizeof(short);
X				} else {
X					*(unsigned long *)optout |= ival;
X					if (optcnt >= cnt)
X						optout += sizeof(long);
X				}
X				break;
X			}
X			if (optcnt >= cnt) {
X				optcnt = 0;
X				if (*++optarg == WOA_END) {
X					wod->wod_pending &= ~bit;
X					(*wol->wol_set)(optwin, optnum, optbuf);
X					if (wol->wol_ext) {
X						(*wol->wol_ext)(optwin, WOC_SET,
X						    optnum, optbuf,
X						    optout-optbuf);
X					}
X					optnum = 0;
X				}
X			}
X			return(1);
X		}
X		/*NOTREACHED*/
X	}
X	return(0);
X}
X
Xopt_iflush()
X{
X	optwin = (caddr_t)0;
X}
X
Xopt_extopt(w, wod, cmd, num, data, na)
Xcaddr_t w;
Xregister struct woptdefn *wod;
Xwoptcmd_t cmd;
Xwoption_t num;
Xchar *data;
Xstruct netadj *na;
X{
X	register struct woptlst *wol;
X
X	if (w != NULL && wod != NULL && num <= WONUM_MAX) {
X		wol = wod->wod_optlst + num;
X		if (wol->wol_argdefn) {
X			switch (cmd) {
X			case WOC_SET:
X				if (data && wol->wol_set) {
X					if (na) {
X						opt_netadj(wol->wol_argdefn,
X						    data, na);
X					}
X					/*
X					 * Set the new value and notify the Mac.
X					 * Because of a race condition (the Mac
X					 * might concurrently be sending us its
X					 * value for this option), we ask the
X					 * Mac to send back the value after it
X					 * is set.
X					 */
X					(*wol->wol_set)(w, num, data);
X					WOPT_SET(wod->wod_pending, num);
X					WOPT_SET(wod->wod_inquire, num);
X					calloptscan = 1;
X				}
X				break;
X			case WOC_INQUIRE:
X				WOPT_SET(wod->wod_inquire, num);
X				calloptscan = 1;
X				break;
X			case WOC_DO:
X				WOPT_SET(wod->wod_do, num);
X				WOPT_SET(wod->wod_askrpt, num);
X				calloptscan = 1;
X				break;
X			case WOC_DONT:
X				WOPT_SET(wod->wod_dont, num);
X				WOPT_CLR(wod->wod_askrpt, num);
X				calloptscan = 1;
X				break;
X			}
X		}
X	}
X}
X
Xopt_netadj(woa, data, na)
Xregister woptarg_t *woa;
Xchar *data;
Xregister struct netadj *na;
X{
X	register char *cp;
X	register int cnt;
X	union {
X		struct {
X			char	c1;
X			short	s;
X		}	cs;
X		struct {
X			char	c2;
X			long	l;
X		}	cl;
X	} u;
X
X	/*
X	 * Convert an option (in internal format) from host byte order
X	 * to network byte order.  If the two are the same then this is
X	 * a NOP.
X	 */
X	if (data && na) {
X		for (cp=data; *woa != WOA_END; woa++) {
X			cnt = *woa & ~WOA_CMDMASK;
X			switch (*woa & WOA_CMDMASK) {
X			case WOA_CHARS(0):
X			case WOA_STRING(0):
X				cp += cnt;
X				break;
X			case WOA_UDATA(0):
X				if (cnt <= NBBY) {
X					cp++;
X				} else if (cnt <= sizeof(short)*NBBY) {
X					while ((int)cp & ((char *)&u.cs.s-&u.cs.c1-1))
X						cp++;
X					*(u_short *)cp =
X					    (*na->na_ushort)(*(u_short *)cp);
X					cp += sizeof(short);
X				} else {
X					while ((int)cp & ((char *)&u.cl.l-&u.cl.c2-1))
X						cp++;
X					*(u_short *)cp =
X					    (*na->na_ushort)(*(u_short *)cp);
X					cp += sizeof(long);
X				}
X			}
X		}
X	}
X}
!EOF!server/uw_opt.c!
echo x - server/uw_pcl.c
sed -e 's/^X//' > server/uw_pcl.c << '!EOF!server/uw_pcl.c!'
X/*
X *	uw_pcl - protocol handling for UW
X *
X * Copyright 1985,1986 by John D. Bruner.  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 <sys/types.h>
X#include <sys/ioctl.h>
X#include <errno.h>
X
X#include "uw_param.h"
X#include "uw_clk.h"
X#include "uw_opt.h"
X#include "uw_win.h"
X#include "uw_pcl.h"
X#include "openpty.h"
X
X#define	XON	0021			/* ASCII XON */
X#define	XOFF	0023			/* ASCII XOFF */
X#define	RUB	0177			/* ASCII RUBout */
X#define	META	0200			/* "meta" bit for whatever it's worth */
X
X/*
X * Protocol negotiation is performed by a finite state machine (implemented
X * in pcl_haggle()).  The states are defined as the enumerated type
X * "pnstate_t".  The inputs have type "pnreq_t".
X */
Xtypedef enum {
X	PNST_NOP,			/* no protocol negotiation */
X	PNST_AWAIT,			/* timing out an ASKPCL */
X	PNST_CWAIT,			/* timing out a CANPCL */
X	PNST_OK,			/* negotiations completed */
X	PNST_FAIL			/* negotiation failed */
X} pnstate_t;
X
Xtypedef unsigned short pnreq_t;		/* finite state machine requests */
X#define	PNRQ_PCL	0000377		/* protocol mask */
X#define	PNRQ_CMD	0177400		/* command mask: */
X#define	PNRQ_NONE	(pnreq_t)(0<<8)	/*	no request */
X#define	PNRQ_START	(pnreq_t)(1<<8)	/*	start negotiation */
X#define	PNRQ_AWAIT	(pnreq_t)(2<<8)	/*	timeout waiting for ASKPCL */
X#define	PNRQ_ASK	(pnreq_t)(3<<8)	/*	process received ASKPCL */
X#define	PNRQ_CAN	(pnreq_t)(4<<8)	/*	process received CANPCL */
X#define	PNRQ_SET	(pnreq_t)(5<<8)	/*	process received SETPCL */
X#define	PNRQ_CWAIT	(pnreq_t)(6<<8)	/*	timeout waiting for CANPCL */
X#define	PNRQ_INIT	(pnreq_t)(7<<8)	/*	initialize everything */
X
Xstatic int p1_ctlch[] = { -1, P1_IAC, XON, XOFF, -1, -1, -1, -1 };
X
Xextern void p1_entry(), p1_renew(), p2_renew();
Xextern struct window *p1_neww(), *p2_neww();
Xextern void p1_killw(), p1_xmit(), p1_recv();
Xextern void p1_askpcl(), p1_canpcl(), p1_setpcl();
Xextern void p2_recv(), p2_chkopt(), p2_sendopt();
X
Xstatic struct protocol pcl_table[] = {
X	{
X	  ' ',
X	  P1_NWINDOW,
X	  p1_ctlch, sizeof p1_ctlch / sizeof p1_ctlch[0],
X	  p1_entry, NULL, p1_renew,
X	  p1_neww, p1_killw,
X	  p1_xmit, p1_recv, NULL, NULL,
X	  p1_askpcl, p1_canpcl, p1_setpcl
X	},
X	{
X	  '!',
X	  P2_NWINDOW,
X	  p1_ctlch, sizeof p1_ctlch / sizeof p1_ctlch[0],
X	  p1_entry, NULL, p2_renew,
X	  p2_neww, p1_killw,
X	  p1_xmit, p2_recv, p2_chkopt, p2_sendopt,
X	  p1_askpcl, p1_canpcl, p1_setpcl
X	},
X};
X
Xstruct protocol *protocol = pcl_table;
X
X/*
X * Two "current" windows are defined: the current input window (for
X * input from the Macintosh) and the current output window (for output
X * to the Macintosh).
X */
Xstatic struct {
X	struct window	*in;
X	struct window	*out;
X} curwin;
X
X
Xpcl_entry(mfd)
Xregister fildes_t mfd;
X{
X	/*
X	 * This routine is called to start up protocol handling.  We always
X	 * start with protocol 1 (the original UW protocol).
X	 */
X	protocol = pcl_table;
X	pcl_haggle(mfd, PNRQ_INIT);
X	if (protocol->p_entry)
X		(*protocol->p_entry)(mfd);
X}
X
Xpcl_exit(mfd)
Xregister fildes_t mfd;
X{
X	/*
X	 * This routine is called when we shut down (just before the server
X	 * exits).
X	 */
X	if (protocol->p_exit)
X		(*protocol->p_exit)(mfd);
X	protocol = pcl_table;
X}
X
Xstatic
Xpcl_newpcl(newproto)
Xstruct protocol *newproto;
X{
X	extern void rc_kludge();
X
X	/*
X	 * Switch to new protocol "newproto".  Right now we can get away
X	 * with just changing the value of "protocol".  Eventually we will
X	 * probably want to call protocol-dependent functions to shut down
X	 * the old protocol and start up the new one.
X	 */
X	protocol = newproto;
X
X	/*
X	 * This is a horrible kludge.  See rc_kludge() in "main.c" for
X	 * further details.
X	 */
X	rc_kludge();
X}
X
Xstatic
Xvoid
Xpcl_tohaggle(arg)
Xregister toarg_t arg;
X{
X	/*
X	 * This is a kludge to get around the single-argument restriction
X	 * on clk_timeout.  We split the argument "arg" into two 16-bit
X	 * pieces and invoke pcl_haggle.
X	 */
X	pcl_haggle((fildes_t)((arg>>16)&0177777), (pnreq_t)(arg&0177777));
X}
X
Xstatic
Xpcl_haggle(mfd, req)
Xfildes_t mfd;
Xregister pnreq_t req;
X{
X	register struct protocol *p, *q;
X	register char pname;
X	register int request;
X	static pnstate_t pnstate;
X	static int waitcnt;
X
X	/*
X	 * This routine implements the finite-state machine that handles
X	 * protocol negotiation.  This routine is called by routines which
X	 * recognize incoming protocol commands and at 5 second intervals
X	 * when negotiations are in progress.  The current protocol is
X	 * described by the variable "protocol".
X	 */
X	if (req == PNRQ_INIT) {
X		waitcnt = 0;
X		pnstate = PNST_NOP;
X		req = PNRQ_NONE;
X	}
X	if (!(p = protocol) || !p->p_askpcl || !p->p_canpcl || !p->p_setpcl) {
X		req = PNRQ_NONE;
X	} else {
X		pname = req & PNRQ_PCL;
X		request = req & PNRQ_CMD;
X		switch (request) {
X		case PNRQ_START:	/* start protocol negotiation */
X			/*
X			 * The Macintosh is responsible for starting protocol
X			 * negotiation (if it wants something other than the
X			 * standard protocol).  This code is present for
X			 * purposes of exposition only.
X			 */
X			(*p->p_askpcl)(mfd);
X			req = PNRQ_AWAIT | pname;
X			waitcnt = 0;
X			pnstate = PNST_AWAIT;
X			break;
X		case PNRQ_AWAIT:	/* timeout an ASKPCL */
X			/*
X			 * This state also is not reached on the host.
X			 */
X			if (pnstate == PNST_AWAIT) {
X				if (++waitcnt > 3) {
X					pnstate = PNST_FAIL;
X					req = PNRQ_NONE;
X				} else
X					(*p->p_askpcl)(mfd);
X			} else
X				req = PNRQ_NONE;
X			break;
X		case PNRQ_ASK:		/* handle received ASKPCL */
X			q = pcl_table+sizeof pcl_table/sizeof pcl_table[0] - 1;
X			(*p->p_canpcl)(mfd, q->p_name);
X			pnstate = PNST_CWAIT;
X			req = PNRQ_CWAIT | q->p_name;
X			waitcnt = 0;
X			break;
X		case PNRQ_CAN:		/* handle received CANPCL */
X			for (q=pcl_table+sizeof pcl_table/sizeof pcl_table[0]-1;
X			     q > pcl_table && q->p_name > pname;
X			     q--)
X				;
X			if (q->p_name == pname || q == pcl_table) {
X				(*p->p_setpcl)(mfd, q->p_name);
X				pcl_newpcl(q);
X				pnstate = PNST_OK;
X				req = PNRQ_NONE;
X			} else {
X				(*p->p_canpcl)(mfd, q->p_name);
X				pnstate = PNST_CWAIT;
X				req = PNRQ_CWAIT | q->p_name;
X				waitcnt = 0;
X			}
X			break;
X		case PNRQ_CWAIT:	/* timeout a CANPCL */
X			if (pnstate == PNST_CWAIT) {
X				if (++waitcnt > 3) {
X					pnstate = PNST_FAIL;
X					req = PNRQ_NONE;
X				} else
X					(*p->p_canpcl)(mfd, pname);
X			} else
X				req = PNRQ_NONE;
X			break;
X		case PNRQ_SET:		/* handle a received SETPCL */
X			for (q=pcl_table+sizeof pcl_table/sizeof pcl_table[0]-1;
X			     q > pcl_table && q->p_name != pname;
X			     q--)
X				;
X			if (q->p_name == pname) {
X				pcl_newpcl(q);
X				pnstate = PNST_OK;
X				req = PNRQ_NONE;
X			} else {
X				/*
X				 * We are in trouble now -- the Mac has
X				 * instructed us to switch to a protocol
X				 * that we can't support.  We switch back
X				 * to protocol 1 and hope that our message
X				 * to the Mac (telling it to switch to
X				 * protocol 1) will be interpreted correctly.
X				 */
X				pnstate = PNST_FAIL;
X				req = PNRQ_NONE;
X				(*p->p_setpcl)(mfd, ' ');
X				if (p != pcl_table)
X					pcl_newpcl(pcl_table);
X			}
X			break;
X		}
X		if (req != PNRQ_NONE)
X			(void)clk_timeout(5*CLK_HZ,
X			    pcl_tohaggle, (toarg_t)(((long)mfd<<16)|req));
X	}
X}
X
Xstatic
Xvoid
Xp1_entry(mfd)
Xfildes_t mfd;
X{
X	static char cmdbuf[2] = { P1_IAC };
X
X	cmdbuf[1] = P1_DIR_HTOM|P1_FN_MAINT|P1_MF_ENTRY;
X	(void)write(mfd, cmdbuf, sizeof cmdbuf);
X}
X
Xstatic
Xstruct window *
Xp1_neww(mfd, wclass, wtype, wnum, wid, datafd, ctlfd)
Xfildes_t mfd;
Xwclass_t wclass;
Xwtype_t wtype;
Xnwin_t wnum;
Xlong wid;
Xfildes_t datafd;
Xfildes_t ctlfd;
X{
X	register struct window *w;
X	static char cmdbuf[2] = { P1_IAC, 0 };
X
X	/*
X	 * Create a new window for the host.  This routine is not called when
X	 * the Macintosh creates a window.
X	 */
X	w = win_neww(wclass, wtype, wnum, protocol->p_maxwin, wid,
X	    datafd, ctlfd, (struct woptdefn *)0);
X	if (w) {
X		cmdbuf[1] = P1_DIR_HTOM|P1_FN_NEWW|WIN_NUM(w);
X		(void)write(mfd, cmdbuf, sizeof cmdbuf);
X	}
X	return(w);
X}
X
Xstatic
Xvoid
Xp1_killw(mfd, w)
Xregister struct window *w;
X{
X	static char cmdbuf[] = { P1_IAC, P1_DIR_HTOM|P1_FN_KILLW };
X
X	/*
X	 * Kill window "w" and tell the Macintosh to do the same.
X	 */
X	if (w && w->w_alloc) {
X		if (curwin.in == w)
X			curwin.in = (struct window *)0;
X		if (curwin.out == w)
X			curwin.out = (struct window *)0;
X		cmdbuf[1] = P1_DIR_HTOM|P1_FN_KILLW|WIN_NUM(w);
X		(void)write(mfd, cmdbuf, sizeof cmdbuf);
X		win_killw(w);
X	}
X}
X
Xstatic
Xvoid
Xp1_xmit(mfd, w)
Xfildes_t mfd;
Xregister struct window *w;
X{
X	register char *cp, *cq;
X	register int i, len;
X	char ibuf[32], obuf[32];
X	static char refresh;
X	static char cmdbuf[] = { P1_IAC, 0 };
X	extern int errno;
X
X	/*
X	 * Transmit data to the Macintosh (via file descriptor "mfd)
X	 * on behalf of window "w".  Be sure to convert any embedded
X	 * control characters and meta characters.
X	 *
X	 * Note that the input/output buffers should NOT be very large.
X	 * It is undesirable to perform large reads and effectively
X	 * "lock out" all other file descriptors.  The chosen size
X	 * should preserve a reasonable amount of efficiency.
X	 *
X	 * The UW protocol only requires an OSELW command when the
X	 * output window changes.  We issue this command more often
X	 * to "refresh" the Mac's idea of what the output window is.
X	 * This helps (slightly) to overcome spurious output redirects
X	 * caused by a noisy line.
X	 */
X	if (w && w->w_alloc) {
X		if (curwin.out != w || ++refresh == 0) {
X			refresh = 0;
X			curwin.out = w;
X			cmdbuf[1] = P1_DIR_HTOM|P1_FN_OSELW|WIN_NUM(w);
X			(void)write(mfd, cmdbuf, sizeof cmdbuf);
X		}
X		cq = obuf;
X		if ((len = read(w->w_datafd, ibuf, sizeof ibuf)) < 0 &&
X		    errno != EWOULDBLOCK)
X			(*protocol->p_killw)(mfd, w);
X		for (cp=ibuf; cp < ibuf+len; cp++) {
X			if (*cp&META) {
X				if (cq > obuf) {
X					(void)write(mfd, obuf, cq-obuf);
X					cq = obuf;
X				}
X				cmdbuf[1] = P1_DIR_HTOM|P1_FN_META;
X				(void)write(mfd, cmdbuf, sizeof cmdbuf);
X				*cp &= ~META;
X			}
X			i = -1;
X			if (*cp == RUB || *cp < ' ') {
X				i = protocol->p_szctlch - 1;
X				while (i >= 0 && protocol->p_ctlch[i] != *cp)
X					i--;
X			}
X			if (i >= 0) {
X				if (cq > obuf) {
X					(void)write(mfd, obuf, cq-obuf);
X					cq = obuf;
X				}
X				cmdbuf[1] = P1_DIR_HTOM|P1_FN_CTLCH|i;
X				(void)write(mfd, cmdbuf, sizeof cmdbuf);
X			} else {
X				*cq++ = *cp;
X				if (cq >= obuf+sizeof obuf) {
X					(void)write(mfd, obuf, cq-obuf);
X					cq = obuf;
X				}
X			}
X		}
X		if (cq > obuf)
X			(void)write(mfd, obuf, cq-obuf);
X	} else
X		(void)read(w->w_datafd, ibuf, sizeof ibuf);
X}
X
Xstatic
Xvoid
Xp1_recv(mfd, cbuf, clen)
Xfildes_t mfd;
Xchar *cbuf;
Xint clen;
X{
X	register int len;
X	register char *buf, *cp, *cq;
X	register struct window *w;
X	nwin_t wnum;
X	auto int nready;
X	char ibuf[512], obuf[512];
X	static int seen_iac, seen_meta;
X	static pnreq_t pnrq_cmd;
X	static char cmdbuf[2] = { P1_IAC };
X
X	/*
X	 * The received bytestream is examined.  Non-command bytes are
X	 * written to the file descriptor corresponding to the current
X	 * "input" window (relative to the Macintosh -- the window the
X	 * user types input to).
X	 *
X	 * If "clen" is nonzero, then the contents of the buffer "cbuf"
X	 * are processed before any input is read.
X	 */
X	if (ioctl(mfd, (int)FIONREAD, (char *)&nready) < 0) {
X		perror("FIONREAD");
X		return;
X	}
X	nready += clen;
X
X	for (cq = obuf; nready > 0; nready -= len) {
X		if (clen > 0) {
X			len = clen;
X			buf = cbuf;
X			clen = 0;
X		} else {
X			if (nready > sizeof ibuf)
X				len = read(mfd, ibuf, sizeof ibuf);
X			else
X				len = read(mfd, ibuf, nready);
X			if (len <= 0) {
X				perror("read");
X				return;
X			}
X			buf = ibuf;
X		}
X		for (cp=buf; cp < buf+len; cp++) {
X			if (pnrq_cmd) {
X				pcl_haggle(mfd, pnrq_cmd|*cp);
X				pnrq_cmd = 0;
X				/* pcl_haggle may have changed the protocol */
X				if (protocol != pcl_table) {
X					if (protocol->p_recv)
X						(*protocol->p_recv)(mfd,
X						    cp+1, buf+len-cp-1);
X					return;
X				}
X			} else if (seen_iac) {
X				if ((*cp&P1_DIR) == P1_DIR_MTOH) {
X					if (cq > obuf) {
X						(void)write(curwin.in->w_datafd,
X							    obuf, cq-obuf);
X						cq = obuf;
X					}
X					switch (*cp & P1_FN) {
X					case P1_FN_NEWW:
X						wnum = *cp & P1_WINDOW;
X						if (!wnum)
X							break;
X						w = WIN_PTR(wnum);
X						if (w->w_alloc)
X							break;
X						if (!win_neww(WC_INTERNAL,
X						    defwtype, wnum,
X						    protocol->p_maxwin, 0L,
X						    (fildes_t)-1, (fildes_t)-1,
X						    (struct woptdefn *)0)) {
X							cmdbuf[1] = P1_DIR_HTOM|
X							    P1_FN_KILLW|wnum;
X							(void)write(mfd, cmdbuf,
X							    sizeof cmdbuf);
X						}
X						break;
X					case P1_FN_KILLW:
X						wnum = *cp & P1_WINDOW;
X						if (!wnum)
X							break;
X						win_killw(WIN_PTR(wnum));
X						break;
X					case P1_FN_ISELW:
X						wnum = *cp & P1_WINDOW;
X						if (!wnum)
X							break;
X						w = WIN_PTR(wnum);
X						if (w->w_alloc)
X							curwin.in = w;
X						else
X							curwin.in = NULL;
X						break;
X					case P1_FN_META:
X						seen_meta = 1;
X						break;
X					case P1_FN_CTLCH:
X						*cq = protocol->p_ctlch[*cp&P1_CC];
X						if (seen_meta) {
X							seen_meta = 0;
X							*cq |= META;
X						}
X						if (curwin.in)
X							cq++;
X						break;
X					case P1_FN_MAINT:
X						switch (*cp & P1_MF) {
X						case P1_MF_ENTRY:
X							(*protocol->p_renew)(mfd);
X							break;
X						case P1_MF_ASKPCL:
X							pcl_haggle(mfd,PNRQ_ASK);
X							break;
X						case P1_MF_CANPCL:
X							pnrq_cmd = PNRQ_CAN;
X							break;
X						case P1_MF_SETPCL:
X							pnrq_cmd = PNRQ_SET;
X							break;
X						case P1_MF_EXIT:
X							done(0);
X							break;
X						}
X						break;
X					}
X				}
X				seen_iac = 0;
X			} else if (*cp == P1_IAC)
X				seen_iac++;
X			else {
X				if (seen_meta) {
X					seen_meta = 0;
X					*cq = *cp | META;
X				} else
X					*cq = *cp;
X				if (curwin.in) {
X					if (++cq >= obuf+sizeof obuf) {
X						(void)write(curwin.in->w_datafd,
X							    obuf, cq-obuf);
X						cq = obuf;
X					}
X				}
X			}
X		}
X	}
X	if (cq > obuf)
X		(void)write(curwin.in->w_datafd, obuf, cq-obuf);
X}
X
Xstatic
Xvoid
Xp1_askpcl(mfd)
Xfildes_t mfd;
X{
X	static char cmdbuf[2] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_ASKPCL };
X
X	(void)write(mfd, cmdbuf, sizeof cmdbuf);
X}
X
Xstatic
Xvoid
Xp1_canpcl(mfd, pname)
Xfildes_t mfd;
Xchar pname;
X{
X	static char cmdbuf[3] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_CANPCL };
X
X	cmdbuf[2] = pname;
X	(void)write(mfd, cmdbuf, sizeof cmdbuf);
X}
X
Xstatic
Xvoid
Xp1_setpcl(mfd, pname)
Xfildes_t mfd;
Xchar pname;
X{
X	static char cmdbuf[3] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_SETPCL };
X
X	cmdbuf[2] = pname;
X	(void)write(mfd, cmdbuf, sizeof cmdbuf);
X}
X
Xstatic
Xvoid
Xp1_renew(mfd)
Xfildes_t mfd;
X{
X	register struct window *w;
X	static char cmdbuf[2] = { P1_IAC };
X
X	/*
X	 * Re-init (re-NEW) an existing connection.  Send a NEWW command
X	 * for each existing window.  This function is invoked when the
X	 * Macintosh sends an ENTRY maintenance command.
X	 */
X	for (w=window; w < window+protocol->p_maxwin; w++) {
X		if (w->w_alloc) {
X			win_renew(w, 0);
X			cmdbuf[1] = P1_DIR_HTOM|P1_FN_NEWW|WIN_NUM(w);
X			(void)write(mfd, cmdbuf, sizeof cmdbuf);
X		}
X	}
X}
X
Xstatic
Xvoid
Xp2_renew(mfd)
Xfildes_t mfd;
X{
X	register struct window *w;
X	static char cmdbuf[3] = { P2_IAC };
X
X	/*
X	 * Re-init (re-NEW) an existing connection.  Send a NEWW command
X	 * for each existing window.  This function is invoked when the
X	 * Macintosh sends an ENTRY maintenance command.
X	 */
X	for (w=window; w < window+protocol->p_maxwin; w++) {
X		if (w->w_alloc) {
X			win_renew(w, 1);
X			cmdbuf[1] = P2_DIR_HTOM|P2_FN_NEWW|WIN_NUM(w);
X			cmdbuf[2] = w->w_type + ' ';
X			(void)write(mfd, cmdbuf, sizeof cmdbuf);
X		}
X	}
X}
X
Xstatic
Xstruct window *
Xp2_neww(mfd, wclass, wtype, wnum, wid, datafd, ctlfd)
Xfildes_t mfd;
Xwclass_t wclass;
Xwtype_t wtype;
Xnwin_t wnum;
Xlong wid;
Xfildes_t datafd;
Xfildes_t ctlfd;
X{
X	register struct window *w;
X	static char cmdbuf[3] = { P2_IAC };
X
X	/*
X	 * Create a new window as requested by the host.  This routine is not
X	 * called when the Macintosh creates a window.
X	 */
X	w = win_neww(wclass, wtype, wnum, protocol->p_maxwin, wid,
X	    datafd, ctlfd, (struct woptdefn *)0);
X	if (w) {
X		cmdbuf[1] = P2_DIR_HTOM|P2_FN_NEWW|WIN_NUM(w);
X		cmdbuf[2] = ' ' + wtype;
X		(void)write(mfd, cmdbuf, sizeof cmdbuf);
X	}
X	return(w);
X}
X
Xstatic
Xvoid
Xp2_chkopt(mfd)
Xfildes_t mfd;
X{
X	register struct window *w;
X	nwin_t maxwin;
X
X	/*
X	 * Ideally, this routine would call a routine in the window
X	 * module (perhaps win_chkopt()), passing the maximum window
X	 * number as one argument.  The "for" loop would be in that
X	 * routine.  However, I'm not willing to accept the overhead
X	 * for that conceptual nicety.
X	 */
X	maxwin = protocol->p_maxwin;
X	for (w=window; w < window+maxwin; w++)
X		if (w->w_alloc)
X			opt_scan((caddr_t)w, &w->w_optdefn, p2_sendopt, mfd,
X			    P2_FN_WOPT|WIN_NUM(w));
X}
X
Xstatic
Xvoid
Xp2_sendopt(mfd, fn, buf, len)
Xfildes_t mfd;
Xint fn;
Xregister char *buf;
Xregister int len;
X{
X	register char *cp;
X	register int i;
X	char outbuf[512];
X
X	/*
X	 * Encode and transmit the option string contained in "buf".  The
X	 * initial command (which will be P2_FN_WOPT|WIN_NUM(w)) is
X	 * contained in "fn".
X	 *
X	 * The caller is responsible for handing us a correctly-formed
X	 * option string.  This routine merely performs the protocol encoding
X	 * which is required for control and meta characters.
X	 */
X	curwin.out = NULL;
X	outbuf[0] = P2_IAC;
X	outbuf[1] = fn|P2_DIR_HTOM;
X	for (cp=outbuf+2; len > 0; buf++,len--) {
X		if (cp > outbuf+sizeof outbuf - 4) {
X			(void)write(mfd, outbuf, cp-outbuf);
X			cp = outbuf;
X		}
X		if (*buf & META) {
X			*cp++ = P2_IAC;
X			*cp++ = P2_DIR_HTOM|P2_FN_META;
X			*buf &= ~META;
X		}
X		i = -1;
X		if (*buf == RUB || *buf < ' ') {
X			i = protocol->p_szctlch - 1;
X			while (i >= 0 && protocol->p_ctlch[i] != *buf)
X				i--;
X		}
X		if (i >= 0) {
X			*cp++ = P2_IAC;
X			*cp++ = P2_DIR_HTOM|P2_FN_CTLCH|(i&7);
X		} else
X			*cp++ = *buf;
X	}
X	if (cp > outbuf)
X		(void)write(mfd, outbuf, cp-outbuf);
X}
X
Xstatic
Xvoid
Xp2_recv(mfd, cbuf, clen)
Xfildes_t mfd;
Xchar *cbuf;
Xint clen;
X{
X	register int len;
X	register char *buf, *cp, *cq;
X	register struct window *w;
X	register char c;
X	nwin_t wnum;
X	auto int nready;
X	char ibuf[512], obuf[512];
X	static int seen_iac, seen_meta, is_option;
X	static pnreq_t pnrq_cmd;
X	static nwin_t neww;
X	static char cmdbuf[2] = { P2_IAC };
X
X	/*
X	 * The received bytestream is examined.  Non-command bytes are
X	 * written to the file descriptor corresponding to the current
X	 * "input" window (relative to the Macintosh -- the window the
X	 * user types input to).
X	 *
X	 * If "clen" is nonzero, then the contents of the buffer "cbuf"
X	 * are processed before any input is read.
X	 */
X	if (ioctl(mfd, (int)FIONREAD, (char *)&nready) < 0) {
X		perror("FIONREAD");
X		return;
X	}
X	nready += clen;
X
X	for (cq = obuf; nready > 0; nready -= len) {
X		if (clen > 0) {
X			len = clen;
X			buf = cbuf;
X			clen = 0;
X		} else {
X			if (nready > sizeof ibuf)
X				len = read(mfd, ibuf, sizeof ibuf);
X			else
X				len = read(mfd, ibuf, nready);
X			if (len <= 0) {
X				perror("read");
X				return;
X			}
X			buf = ibuf;
X		}
X		for (cp=buf; cp < buf+len; cp++) {
X			if (pnrq_cmd) {
X				pcl_haggle(mfd, pnrq_cmd|*cp);
X				pnrq_cmd = 0;
X				/* pcl_haggle may have changed the protocol */
X				if (protocol != pcl_table) {
X					if (protocol->p_recv)
X						(*protocol->p_recv)(mfd,
X						    cp+1, buf+len-cp-1);
X					return;
X				}
X			} else if (neww) {
X				w = WIN_PTR(neww);
X				if (!w->w_alloc &&
X				    !win_neww(WC_INTERNAL, (wtype_t)(*cp-' '),
X				    neww, protocol->p_maxwin, 0L,
X				    (fildes_t)-1, (fildes_t)-1,
X				    (struct woptdefn *)0)) {
X					cmdbuf[1] = P2_DIR_HTOM|
X					    P2_FN_KILLW|neww;
X					(void)write(mfd, cmdbuf,
X					    sizeof cmdbuf);
X				}
X				neww = 0;
X			} else if (seen_iac) {
X				if ((*cp&P2_DIR) == P2_DIR_MTOH) {
X					c = *cp & P2_FN;
X					if (is_option &&
X					    c!=P2_FN_META && c!=P2_FN_CTLCH) {
X						opt_iflush();
X						is_option = 0;
X					}
X					if (cq > obuf) {
X						(void)write(curwin.in->w_datafd,
X							    obuf, cq-obuf);
X						cq = obuf;
X					}
X					switch (*cp & P2_FN) {
X					case P2_FN_NEWW:
X						neww = *cp & P2_WINDOW;
X						break;
X					case P2_FN_WOPT:
X						wnum = *cp & P2_WINDOW;
X						if (!wnum)
X							break;
X						w = WIN_PTR(wnum);
X						if (!w->w_alloc) {
X							curwin.in = NULL;
X							break;
X						}
X						is_option = 1;
X						opt_istart((caddr_t)w, &w->w_optdefn);
X						break;
X					case P2_FN_KILLW:
X						wnum = *cp & P2_WINDOW;
X						if (!wnum)
X							break;
X						win_killw(WIN_PTR(wnum));
X						break;
X					case P2_FN_ISELW:
X						wnum = *cp & P2_WINDOW;
X						if (!wnum)
X							break;
X						w = WIN_PTR(wnum);
X						if (w->w_alloc)
X							curwin.in = w;
X						else
X							curwin.in = NULL;
X						break;
X					case P2_FN_META:
X						seen_meta = 1;
X						if ((*cp&P2_CC) == 0)
X							break;
X						/* no break */
X					case P2_FN_CTLCH:
X						c=protocol->p_ctlch[*cp&P2_CC];
X						if (seen_meta) {
X							seen_meta = 0;
X							c |= META;
X						}
X						if (is_option)
X							is_option=opt_input(c);
X						else
X							if (curwin.in)
X								*cq++ = c;
X						break;
X					case P2_FN_MAINT:
X						switch (*cp & P2_MF) {
X						case P2_MF_ENTRY:
X							(*protocol->p_setpcl)(mfd, protocol->p_name);
X							(*protocol->p_renew)(mfd);
X							break;
X						case P2_MF_ASKPCL:
X							pcl_haggle(mfd,PNRQ_ASK);
X							break;
X						case P2_MF_CANPCL:
X							pnrq_cmd = PNRQ_CAN;
X							break;
X						case P2_MF_SETPCL:
X							pnrq_cmd = PNRQ_SET;
X							break;
X						case P2_MF_EXIT:
X							done(0);
X							break;
X						}
X						break;
X					}
X				}
X				seen_iac = 0;
X			} else if (*cp == P2_IAC)
X				seen_iac++;
X			else {
X				if (seen_meta) {
X					c = *cp | META;
X					seen_meta = 0;
X				} else
X					c = *cp;
X				if (is_option)
X					is_option = opt_input(c);
X				else
X					if (curwin.in)
X						*cq++ = c;
X				if (cq >= obuf+sizeof obuf) {
X					(void)write(curwin.in->w_datafd,
X						    obuf, cq-obuf);
X					cq = obuf;
X				}
X			}
X		}
X	}
X	if (cq > obuf)
X		(void)write(curwin.in->w_datafd, obuf, cq-obuf);
X}
!EOF!server/uw_pcl.c!
echo x - server/uw_tty.c
sed -e 's/^X//' > server/uw_tty.c << '!EOF!server/uw_tty.c!'
X/*
X *	uw_tty - terminal support for UW
X *
X * Copyright 1985,1986 by John D. Bruner.  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 <sys/types.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X
X#include "uw_param.h"
X#include "uw_win.h"
X#include "uw_opt.h"
X
X#define	XON	021	/* ASCII XON (ASR-33 paper-tape reader on) */
X#define	XOFF	023	/* ASCII XOFF (ASR-33 paper-tape reader off) */
X
Xstatic char *envinfo[][3] = {
X	{
X		"TERM=adm31",
X		"TERMCAP=adm31:cr=^M:do=^J:nl=^J:al=\\EE:am:le=^H:bs:ce=\\ET:cm=\\E=%+ %+ :cl=^Z:cd=\\EY:co#80:dc=\\EW:dl=\\ER:ei=\\Er:ho=^^:im=\\Eq:li#24:mi:nd=^L:up=^K:MT:km:so=\\EG1:se=\\EG0:",
X		(char *)0
X	},
X	{
X		"TERM=vt52",
X		(char *)0
X	},
X	{
X		"TERM=ansi",
X		(char *)0
X	},
X	{
X		"TERM=tek4010",
X		(char *)0
X	}
X};
X
X/* private (emulation-specific) data */
Xstruct tty {
X	struct {
X		unsigned short	h,v;
X	}		t_size;
X	unsigned	t_fontsz;
X	unsigned	t_clipb;
X	unsigned	t_bell;
X	unsigned	t_curs;
X	unsigned	t_chgsz;
X};
X
X#define	WOTTY_SIZE	8		/* terminal size in (row, col) */
X#define	WOTTY_FONTSZ	9		/* font size index (0=7pt, 1=9pt) */
X#define	WOTTY_CLIPB	10		/* 0=clipboard, 1=encode mouse clicks */
X#define	WOTTY_BELL	11		/* bell: bit 0=visible, bit 1=audible */
X#define	WOTTY_CURSOR	12		/* cursor type: 0=block, 1=underscore */
X#define	WOTTY_CHGSZ	13		/* change actual size (not view size) */
X
Xstatic woptarg_t size_xdr[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
Xstatic woptarg_t fontsz_xdr[] = { WOA_UDATA(6), WOA_END };
Xstatic woptarg_t clipb_xdr[] = { WOA_UDATA(1), WOA_END };
Xstatic woptarg_t bell_xdr[] = { WOA_UDATA(2), WOA_END };
Xstatic woptarg_t curs_xdr[] = { WOA_UDATA(1), WOA_END };
Xstatic woptarg_t chgsz_xdr[] = { WOA_UDATA(1), WOA_END };
X
X/* TIOCSWINSZ is in 4.3BSD, TIOCSSIZE is in Sun UNIX */
X#if defined(TIOCSWINSZ) || defined(TIOCSSIZE)
X#define	RPTWINSZ	(1<<WOTTY_SIZE)
X#else
X#define	RPTWINSZ	0
X#endif
X
X#define	TTY_WOPT	{					\
X	0, 0, 0, 0,						\
X	RPTWINSZ|(1<<WOTTY_FONTSZ)|(1<<WOTTY_CLIPB)|		\
X	 (1<<WOTTY_BELL)|(1<<WOTTY_CURSOR)|(1<<WOTTY_CHGSZ),	\
X	{							\
X		{ NULL, NULL, NULL },				\
X		{ NULL, NULL, NULL },				\
X		{ NULL, NULL, NULL },				\
X		{ NULL, NULL, NULL },				\
X		{ NULL, NULL, NULL },				\
X		{ NULL, NULL, NULL },				\
X		{ NULL, NULL, NULL },				\
X		{ NULL, NULL, NULL },				\
X		{ size_xdr, tty_getopt, tty_setopt },		\
X		{ fontsz_xdr, tty_getopt, tty_setopt },		\
X		{ clipb_xdr, tty_getopt, tty_setopt },		\
X		{ bell_xdr, tty_getopt, tty_setopt },		\
X		{ curs_xdr, tty_getopt, tty_setopt },		\
X		{ chgsz_xdr, tty_getopt, tty_setopt }		\
X	}							\
X}
Xextern int tty_start();
Xextern void tty_stop(), tty_setopt(), tty_setext();
Xextern char *tty_getopt();
X
Xstruct emulation adm31_emul = { TTY_WOPT, tty_start, tty_stop, tty_setext };
Xstruct emulation vt52_emul = { TTY_WOPT, tty_start, tty_stop, tty_setext };
Xstruct emulation ansi_emul = { TTY_WOPT, tty_start, tty_stop, tty_setext };
Xstruct emulation tek_emul = { { 0, 0, 0, 0, 0 }, tty_start, tty_stop };
X
Xtty_mode(f)
Xint f;
X{
X	static struct sgttyb ostty, nstty;
X	static struct tchars otchars, ntchars;
X	static struct ltchars oltchars, nltchars;
X	static int olmode, nlmode;
X	static saved;
X	static int inout = FREAD|FWRITE;
X
X	/*
X	 * This routine either saves the current terminal modes and then
X	 * sets up the terminal line or resets the terminal modes (depending
X	 * upon the value of "f").  The terminal line is used in "cbreak"
X	 * mode with all special characters except XON/XOFF disabled.  The
X	 * hated (by me) LDECCTQ mode is required for the Macintosh to
X	 * handle flow control properly.
X	 */
X	if (f == 1) {
X		if (ioctl(0, (int)TIOCGETP, (char *)&ostty) < 0) {
X			perror("ioctl((int)TIOCGETP)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCGETC, (char *)&otchars) < 0) {
X			perror("ioctl((int)TIOCGETC)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCGLTC, (char *)&oltchars) < 0) {
X			perror("ioctl((int)TIOCGLTC)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCLGET, (char *)&olmode) < 0) {
X			perror("ioctl((int)TIOCLGET)");
X			done(1);
X		}
X		nstty = ostty;
X		nstty.sg_erase = nstty.sg_kill = -1;
X		nstty.sg_flags |= CBREAK;
X		nstty.sg_flags &= ~(RAW|CRMOD|ECHO|LCASE|XTABS|ALLDELAY);
X		ntchars.t_intrc = ntchars.t_quitc = -1;
X		ntchars.t_eofc = ntchars.t_brkc = -1;
X		ntchars.t_startc = XON;
X		ntchars.t_stopc = XOFF;
X		nltchars.t_suspc = nltchars.t_dsuspc = -1;
X		nltchars.t_rprntc = nltchars.t_flushc = -1;
X		nltchars.t_werasc = nltchars.t_lnextc = -1;
X		nlmode = olmode | LDECCTQ;
X		if (ioctl(0, (int)TIOCSETN, (char *)&nstty) < 0) {
X			perror("ioctl((int)TIOCSETN)");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCSETC, (char *)&ntchars) < 0) {
X			perror("ioctl((int)TIOCSETC");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCSLTC, (char *)&nltchars) < 0) {
X			perror("ioctl((int)TIOCSLTC");
X			done(1);
X		}
X		if (ioctl(0, (int)TIOCLSET, (char *)&nlmode) < 0) {
X			perror("ioctl((int)TIOCLSET)");
X			done(1);
X		}
X		saved = 1;
X	} else if (saved) {
X		(void)ioctl(0, (int)TIOCFLUSH, (char *)&inout);
X		(void)ioctl(0, (int)TIOCSETP, (char *)&ostty);
X		(void)ioctl(0, (int)TIOCSETC, (char *)&otchars);
X		(void)ioctl(0, (int)TIOCSLTC, (char *)&oltchars);
X		(void)ioctl(0, (int)TIOCLSET, (char *)&olmode);
X	}
X}
X
Xstatic
Xtty_start(w)
Xregister struct window *w;
X{
X	register struct tty *t;
X	extern char *malloc();
X
X	/*
X	 * Start up a terminal emulation.  Establish reasonable defaults
X	 * for the terminal-specific window options.
X	 */
X	if (w->w_type != WT_TEK4010) {
X		if ((w->w_private = malloc(sizeof(struct tty))) != NULL) {
X			t = (struct tty *)w->w_private;
X			t->t_size.h = 80;
X			t->t_size.v = 24;
X			t->t_fontsz = 0;
X			t->t_clipb = 0;
X			t->t_bell = 3;
X			t->t_curs = 0;
X			t->t_chgsz = 0;
X			return(1);
X		} else
X			return(0);
X	} else {
X		w->w_private = (char *)0;
X		return(1);
X	}
X}
X
Xstatic
Xvoid
Xtty_stop(w)
Xregister struct window *w;
X{
X	/*
X	 * Shut down (stop) a terminal emulation.
X	 */
X	free(w->w_private);
X	w->w_private = (char *)0;
X}
X
Xstatic
Xvoid
Xtty_setext(wod)
Xregister struct woptdefn *wod;
X{
X	/*
X	 * This routine makes adjustments to the window option definitions
X	 * for external windows.  Basically, we turn off reporting for
X	 * WOTTY_SIZE.  (If the external process wants to handle this, it
X	 * can turn it back on.)
X	 */
X	WOPT_CLR(wod->wod_do, WOTTY_SIZE);
X	WOPT_CLR(wod->wod_askrpt, WOTTY_SIZE);
X}
X
Xtty_envinit(wtype)
Xregister wtype_t wtype;
X{
X	/*
X	 * Set up environment variables corresponding to the window type
X	 * "wtype".
X	 */
X	env_set(envinfo[wtype]);
X}
X
Xstatic
Xchar *
Xtty_getopt(win, num)
Xcaddr_t win;
Xwoption_t num;
X{
X	register struct tty *t;
X	static union optvalue ov;
X	struct window *w;
X
X	if ((w=(struct window *)win) != NULL && w->w_alloc &&
X	    (t=(struct tty *)w->w_private) != NULL) {
X		switch (num) {
X		case WOTTY_SIZE:
X			ov.ov_point.h = t->t_size.h;
X			ov.ov_point.v = t->t_size.v;
X			break;
X		case WOTTY_FONTSZ:
X			ov.ov_udata6 = t->t_fontsz;
X			break;
X		case WOTTY_CLIPB:
X			ov.ov_udata1 = t->t_clipb;
X			break;
X		case WOTTY_BELL:
X			ov.ov_udata2 = t->t_bell;
X			break;
X		case WOTTY_CURSOR:
X			ov.ov_udata1 = t->t_curs;
X			break;
X		case WOTTY_CHGSZ:
X			ov.ov_udata1 = t->t_chgsz;
X			break;
X		}
X	}
X	return((char *)&ov);
X}
X
Xstatic
Xvoid
Xtty_setopt(win, num, value)
Xcaddr_t win;
Xwoption_t num;
Xchar *value;
X{
X	register struct tty *t;
X	register union optvalue *ovp;
X	register struct window *w;
X
X	if ((w=(struct window *)win) != NULL && w->w_alloc &&
X	    (t=(struct tty *)w->w_private) != NULL &&
X	    (ovp = (union optvalue *)value) != NULL) {
X		switch (num) {
X		case WOTTY_SIZE:
X			t->t_size.h = ovp->ov_point.h;
X			t->t_size.v = ovp->ov_point.v;
X#ifdef TIOCSWINSZ
X			if (w->w_class == WC_INTERNAL) {
X				/* set window size on pty (4.3BSD) */
X				struct winsize ws;
X				ws.ws_row = t->t_size.v;
X				ws.ws_col = t->t_size.h;
X				ws.ws_xpixel = w->w_size.h;
X				ws.ws_ypixel = w->w_size.v;
X				(void)ioctl(w->w_datafd, (int)TIOCSWINSZ,
X				    (char *)&ws);
X			}
X#else
X#ifdef TIOCSSIZE
X			if (w->w_class == WC_INTERNAL) {
X				/* set window size on pty (Sun) */
X				struct ttysize ts;
X				ts.ts_lines = t->t_size.v;
X				ts.ts_cols = t->t_size.h;
X				(void)ioctl(w->w_datafd, (int)TIOCSSIZE,
X				    (char *)&ts);
X			}
X#endif
X#endif
X			break;
X		case WOTTY_FONTSZ:
X			t->t_fontsz = ovp->ov_udata6;
X			break;
X		case WOTTY_CLIPB:
X			t->t_clipb = ovp->ov_udata1;
X			break;
X		case WOTTY_BELL:
X			t->t_bell = ovp->ov_udata2;
X			break;
X		case WOTTY_CURSOR:
X			t->t_curs = ovp->ov_udata1;
X			break;
X		case WOTTY_CHGSZ:
X			t->t_chgsz = ovp->ov_udata1;
X			break;
X		}
X	}
X}
!EOF!server/uw_tty.c!
echo x - server/uw_utmp.c
sed -e 's/^X//' > server/uw_utmp.c << '!EOF!server/uw_utmp.c!'
X/*
X *	uw_utmp - /etc/utmp handling
X *
X * Copyright 1985,1986 by John D. Bruner.  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#ifdef UTMP
X
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/time.h>
X#include <pwd.h>
X#include <utmp.h>
X#include <strings.h>
X#include <ctype.h>
X#include <stdio.h>
X
X#include "uw_param.h"
X
Xstruct utinfo {
X	struct utinfo	*ui_next;
X	struct utinfo	*ui_chain;
X	char		*ui_line;
X	int		ui_slot;
X	int		ui_inuse;
X};
X
Xstatic struct utinfo *hash[31];
Xstatic struct utinfo *head;
X
Xstatic char *myname;
Xstatic fildes_t utmpfd;
X
Xextern time_t time();
X
Xutmp_init(fd)
Xfildes_t fd;
X{
X	register char *cp, *cq;
X	register struct utinfo *ui;
X	register int hashidx, slot;
X	struct passwd *pw;
X	FILE *fp;
X	char line[256];
X
X	if ((utmpfd = fd) >= 0 && (fp = fopen("/etc/ttys", "r")) == NULL) {
X		(void)close(utmpfd);
X		utmpfd = -1;
X	}
X	if (utmpfd >= 0) {
X		slot = 0;
X		while (fgets(line, sizeof line, fp) != NULL) {
X#ifdef V7TTYS
X			if (!line[0] || !line[1]) {	/* malformed line */
X				slot++;
X				continue;
X			}
X			cp = line+2;	/* skip flag and speed index */
X#else
X			for (cp=line; *cp && isspace(*cp); cp++)
X				;
X			if (*cp == '#')
X				continue;
X#endif
X			slot++;
X			if ((ui=(struct utinfo *)malloc(sizeof *ui)) != NULL) {
X				for (cq=cp; *cq && !isspace(*cq); cq++)
X					;
X				if ((ui->ui_line=malloc(cq-cp+1)) != NULL) {
X					(void)strncpy(ui->ui_line, cp, cq-cp);
X					ui->ui_line[cq-cp] = '\0';
X				} else {
X					free((char *)ui);
X					ui = (struct utinfo *)0;
X				}
X			}
X			if (ui != NULL) {
X				ui->ui_slot = slot;
X				ui->ui_inuse = 0;
X				ui->ui_chain = head;
X				head = ui;
X				hashidx = utmp_hash(ui->ui_line);
X				ui->ui_next = hash[hashidx];
X				hash[hashidx] = ui;
X			}
X		}
X		(void)fclose(fp);
X	}
X	if ((pw = getpwuid(getuid())) != NULL &&
X	    (myname=malloc(1+strlen(pw->pw_name))) != NULL)
X		(void)strcpy(myname, pw->pw_name);
X}
X
Xstatic
Xstruct utinfo *
Xutmp_find(tty)
Xchar *tty;
X{
X	register char *cp;
X	register struct utinfo *ui;
X
X	if ((cp = rindex(tty, '/')) != NULL)
X		cp++;
X	else
X		cp = tty;
X	ui = hash[utmp_hash(cp)];
X	while (ui != NULL && strcmp(ui->ui_line, cp) != 0)
X		ui = ui->ui_next;
X	return(ui);
X}
X
Xutmp_add(tty)
Xchar *tty;
X{
X	register struct utinfo *ui;
X	struct utmp ut;
X
X	if ((ui = utmp_find(tty)) != NULL) {
X		(void)strncpy(ut.ut_line, ui->ui_line, sizeof ut.ut_line);
X		(void)strncpy(ut.ut_name, myname, sizeof ut.ut_name);
X		(void)strncpy(ut.ut_host, "", sizeof ut.ut_host);
X		ut.ut_time = (long)time((time_t)0);
X		ui->ui_inuse = 1;
X		utmp_write(ui->ui_slot, &ut);
X	}
X}
X
X
Xutmp_rm(tty)
Xchar *tty;
X{
X	register struct utinfo *ui;
X	struct utmp ut;
X
X	if ((ui = utmp_find(tty)) != NULL) {
X		(void)strncpy(ut.ut_line, ui->ui_line, sizeof ut.ut_line);
X		(void)strncpy(ut.ut_name, "", sizeof ut.ut_name);
X		(void)strncpy(ut.ut_host, "", sizeof ut.ut_host);
X		ut.ut_time = (long)time((time_t)0);
X		ui->ui_inuse = 0;
X		utmp_write(ui->ui_slot, &ut);
X	}
X}
X
Xutmp_exit()
X{
X	register struct utinfo *ui;
X	struct utmp ut;
X
X	for (ui=head; ui; ui=ui->ui_chain) {
X		if (ui->ui_inuse) {
X			(void)strncpy(ut.ut_line,ui->ui_line,sizeof ut.ut_line);
X			(void)strncpy(ut.ut_name, "", sizeof ut.ut_name);
X			(void)strncpy(ut.ut_host, "", sizeof ut.ut_host);
X			ut.ut_time = (long)time((time_t)0);
X			ui->ui_inuse = 0;
X			utmp_write(ui->ui_slot, &ut);
X		}
X	}
X}
X
Xutmp_write(slot, ut)
Xregister int slot;
Xstruct utmp *ut;
X{
X	extern off_t lseek();
X
X	if (utmpfd >= 0 &&
X	    lseek(utmpfd, slot*sizeof(*ut), L_SET) == (off_t)(slot*sizeof(*ut)))
X		(void)write(utmpfd, (char *)ut, sizeof *ut);
X}
X
Xstatic
Xutmp_hash(s)
Xregister char *s;
X{
X	register short h;
X
X	for (h=0; *s; s++)
X		h = (h << ((*s)&7)) | (h >> (sizeof h - ((*s)&7))) + *s;
X	return(h % sizeof hash / sizeof hash[0]);
X}
X#else
Xutmp_add(tty)
Xchar *tty;
X{
X}
X
Xutmp_rm(tty)
Xchar *tty;
X{
X}
X
Xutmp_rmall()
X{
X}
X#endif
!EOF!server/uw_utmp.c!
echo x - server/uw_win.c
sed -e 's/^X//' > server/uw_win.c << '!EOF!server/uw_win.c!'
X/*
X *	uw_win - window handling for UW
X *
X * Copyright 1986 by John D. Bruner.  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 <sys/types.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X#include <signal.h>
X#include <strings.h>
X#include <stdio.h>
X
X#include "openpty.h"
X#include "uw_param.h"
X#include "uw_opt.h"
X#include "uw_win.h"
X#include "uw_fd.h"
X
X/*
X * "defwtype" specifies the default window type.  This type is used when
X * more specific information is not available.
X */
Xwtype_t defwtype = WT_ADM31;
X
X/*
X * "window" is declared in "uw_win.h"  Here we define it.
X */
Xstruct window window[NWINDOW];		/* window data structures */
X
X/*
X * "emulation" describes window emulation-specific data.  "generic_emul"
X * describes emulations which do not require special server attention
X * (e.g. file transfer, all of whose real work is done by a separate process).
X */
Xextern struct emulation adm31_emul, vt52_emul, ansi_emul, tek_emul;
Xstatic struct emulation generic_emul;
Xstatic struct emulation *emulation[WT_MAXTYPE+1] = {
X	&adm31_emul,
X	&vt52_emul,
X	&ansi_emul,
X	&tek_emul,
X	&generic_emul,
X	&generic_emul
X};
X
Xextern char *win_getopt();
Xextern void win_setopt();
X
Xstatic woptarg_t woa_vis[] = { WOA_UDATA(1), WOA_END };
Xstatic woptarg_t woa_type[] = { WOA_UDATA(6), WOA_END };
Xstatic woptarg_t woa_pos[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
Xstatic woptarg_t woa_title[] = { WOA_STRING(255), WOA_END };
Xstatic woptarg_t woa_size[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
X
Xstatic struct woptdefn genwinopt = {
X	(1<<WOG_VIS), 0, 0, 0,
X	(1<<WOG_VIS)|(1<<WOG_TYPE)|(1<<WOG_POS)|(1<<WOG_TITLE)|(1<<WOG_SIZE),
X	{
X/* WOG_END */	{ NULL, NULL, NULL },
X/* WOG_VIS */	{ woa_vis, win_getopt, win_setopt },
X/* WOG_TYPE */	{ woa_type, win_getopt, win_setopt },
X/* WOG_POS */	{ woa_pos, win_getopt, win_setopt },
X/* WOG_TITLE */	{ woa_title, win_getopt, win_setopt },
X/* WOG_SIZE */	{ woa_size, win_getopt, win_setopt },
X/* WOG_6 */	{ NULL, NULL, NULL },
X/* WOG_7 */	{ NULL, NULL, NULL }
X	}
X};
X
X/*
X * This is a violation of the level structure, but it is expedient.
X */
Xextern void ipc_optmsg();
X
Xwin_init()
X{
X	register struct window *w;
X
X	/*
X	 * Initialize.  Mark all windows unallocated.
X	 */
X	for (w=window; w < window+NWINDOW; w++)
X		w->w_alloc = 0;
X}
X
Xlong
Xwin_mkid()
X{
X	static unsigned short i = 0;
X	static long pid = -1;
X
X	if (pid == -1)
X		pid = getpid();
X	return((pid << (NBBY*(sizeof(long)/sizeof(short)))) | i++);
X}
X
Xstruct window *
Xwin_search(wid, maxwin)
Xlong wid;
Xnwin_t maxwin;
X{
X	register struct window *w;
X
X	for (w=window; w < window+maxwin; w++)
X		if (w->w_alloc && w->w_id == wid)
X			return(w);
X	return((struct window *)0);
X}
X
Xstruct window *
Xwin_neww(wclass, wtype, wnum, maxwin, wid, datafd, ctlfd, options)
Xwclass_t wclass;
Xwtype_t wtype;
Xnwin_t wnum;
Xnwin_t maxwin;
Xlong wid;
Xfildes_t datafd;
Xfildes_t ctlfd;
Xstruct woptdefn *options;
X{
X	fildes_t fd;
X	int pid;
X	struct window *w;
X	char *tty, *shell;
X	auto struct ptydesc pt;
X	extern char *getenv();
X
X	/*
X	 * Create a new window.  "wclass" specifies the window wclass.
X	 * If "wnum" is negative, choose a window number; otherwise,
X	 * "wnum" is the window number.  "datafd" and "ctlfd" are the
X	 * data and control file descriptors to be associated with
X	 * this window.  If "datafd" is negative and "wclass" is
X	 * WC_INTERNAL, allocate a pseudo-terminal.
X	 *
X	 * If "options" is non-NULL it specifies the address of an
X	 * option definition structure; otherwise, a new one is constructed
X	 * from the generic and emulation-specific prototype structures.
X	 *
X	 * If "wid" is nonzero it is a proposed window ID.  It must be
X	 * unique (not in use).  If "wid" is zero, a new ID is assigned.
X	 *
X	 * The window type "wtype" will always be a terminal emulation
X	 * if the wclass is WC_INTERNAL.
X	 *
X	 * Internal-class windows are visible by default, while external
X	 * ones are initially invisible.
X	 *
X	 * Return the address of the window structure or NULL if
X	 * none could be created.
X	 */
X	tty = (char *)0;
X	if (wtype > WT_MAXTYPE)
X		return((struct window *)0);
X	if (wid == 0) {
X		while (win_search(wid=win_mkid(), maxwin) != NULL)
X			;
X	} else if (win_search(wid, maxwin) != NULL)
X		return((struct window *)0);
X	if (datafd < 0 && wclass == WC_INTERNAL) {
X		if (!openpty(&pt)) {
X			datafd = pt.pt_pfd;
X			tty = pt.pt_tname;
X			while ((pid = fork()) < 0)
X				sleep(5);
X			if (!pid) {
X				win_envinit(wtype, wid);
X				(void)signal(SIGHUP, SIG_DFL);
X				(void)signal(SIGINT, SIG_DFL);
X				(void)signal(SIGQUIT, SIG_DFL);
X				(void)signal(SIGTERM, SIG_DFL);
X				(void)signal(SIGTSTP, SIG_IGN);
X				(void)signal(SIGCHLD, SIG_DFL);
X				(void)ioctl(open("/dev/tty",O_RDWR),
X				    (int)TIOCNOTTY, (char *)0);
X				(void)close(open(pt.pt_tname, O_RDONLY));
X				(void)setuid(getuid());
X				if (!(shell = getenv("SHELL")))
X					shell = "/bin/sh";
X				if (pt.pt_tfd != 0)
X					(void)dup2(pt.pt_tfd, 0);
X				if (pt.pt_tfd != 1);
X					(void)dup2(pt.pt_tfd, 1);
X				if (pt.pt_tfd != 2)
X					(void)dup2(pt.pt_tfd, 2);
X				for (fd=3; fd < nfds; fd++)
X					(void)close(fd);
X				tty_mode(0);	/* HACK! */
X				execl(shell, shell, (char *)0);
X				_exit(1);
X			} else {
X				utmp_add(tty);
X				(void)close(pt.pt_tfd);
X			}
X		}
X	}
X
X	if (datafd >= 0) {
X		if (wnum > 0) {
X			w = WIN_PTR(wnum);
X			if (w->w_alloc)
X				w = (struct window *)0;
X		} else {
X			for (w=window; w < window+maxwin && w->w_alloc; w++)
X				;
X			if (w >= window+maxwin)
X				w = (struct window *)0;
X		}
X	} else
X		w = (struct window *)0;
X
X	if (w) {
X		w->w_alloc = 1;
X		w->w_id = wid;
X		w->w_class = wclass;
X		w->w_type = wtype;
X		w->w_visible = (w->w_class == WC_INTERNAL);
X		w->w_position.h = w->w_position.v = 0;
X		w->w_size.h = w->w_size.v = 0;
X		w->w_title[0] = '\0';
X		if (emulation[wtype]->we_start &&
X		    !(*emulation[wtype]->we_start)(w)) {
X			if (options)
X				w->w_optdefn = *options;
X			else
X				opt_new(&w->w_optdefn, &genwinopt,
X				    (struct woptdefn *)0);
X		} else {
X			if (options)
X				w->w_optdefn = *options;
X			else
X				opt_new(&w->w_optdefn, &genwinopt,
X				    &emulation[wtype]->we_optdefn);
X		}
X		w->w_datafd = datafd;
X		(void)fcntl(datafd, F_SETFL, FNDELAY);
X		FD_SET(datafd, &selmask[0].sm_rd);
X		fdmap[datafd].f_type = FDT_DATA;
X		fdmap[datafd].f_win = w;
X		if (w->w_class == WC_INTERNAL) {
X			if (tty)
X				(void)strncpy(w->w_tty, tty, sizeof w->w_tty);
X		} else {
X			w->w_ctlfd = ctlfd;
X			if (ctlfd >= 0) {
X				(void)fcntl(ctlfd, F_SETFL, FNDELAY);
X				FD_SET(ctlfd, &selmask[0].sm_rd);
X				fdmap[ctlfd].f_type = FDT_CTL;
X				fdmap[ctlfd].f_win = w;
X				if (emulation[wtype]->we_setext)
X					(*emulation[wtype]->we_setext)(&w->w_optdefn);
X				opt_setext(&w->w_optdefn, ipc_optmsg);
X			}
X		}
X	}
X			
X	return(w);
X}
X
Xwin_killw(w)
Xregister struct window *w;
X{
X	/*
X	 * Kill the window "w".  This is pretty simple; we just close
X	 * the data and control file descriptors and mark the structure
X	 * inactive.
X	 */
X	if (w && w->w_alloc) {
X		if (w->w_datafd >= 0) {
X			if (w->w_class == WC_INTERNAL)
X				utmp_rm(w->w_tty);
X			FD_CLR(w->w_datafd, &selmask[0].sm_rd);
X			FD_CLR(w->w_datafd, &selmask[0].sm_wt);
X			FD_CLR(w->w_datafd, &selmask[0].sm_ex);
X			fdmap[w->w_datafd].f_type = FDT_NONE;
X			(void)close(w->w_datafd);
X		}
X		if (w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0) {
X			FD_CLR(w->w_ctlfd, &selmask[0].sm_rd);
X			FD_CLR(w->w_ctlfd, &selmask[0].sm_wt);
X			FD_CLR(w->w_ctlfd, &selmask[0].sm_ex);
X			fdmap[w->w_ctlfd].f_type = FDT_NONE;
X			(void)close(w->w_ctlfd);
X		}
X		w->w_alloc = 0;
X	}
X}
X
Xwin_renew(w, report)
Xstruct window *w;
Xint report;
X{
X	/*
X	 * Reinitialize (re-NEW) the window "w".  Report the state of the
X	 * window to the Mac if "report" is nonzero.
X	 */
X	opt_renew(&w->w_optdefn, report);
X}
X
Xwin_newtype(w, wtype)
Xregister struct window *w;
Xregister wtype_t wtype;
X{
X	/*
X	 * Change the window emulation type to "wtype".
X	 */
X	if (wtype <= WT_MAXTYPE && wtype != w->w_type) {
X		if (emulation[w->w_type]->we_stop)
X			(*emulation[w->w_type]->we_stop)(w);
X		w->w_type = wtype;
X		if (emulation[wtype]->we_start &&
X		    !(*emulation[wtype]->we_start)(w)) {
X			opt_newtype(&w->w_optdefn, &genwinopt,
X			    (struct woptdefn *)0);
X		} else {
X			opt_newtype(&w->w_optdefn, &genwinopt,
X			    &emulation[wtype]->we_optdefn);
X		}
X		if (w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0) {
X			if (emulation[wtype]->we_setext)
X				(*emulation[wtype]->we_setext)(&w->w_optdefn);
X			opt_setext(&w->w_optdefn, ipc_optmsg);
X		}
X	}
X}
X
Xwin_envinit(wtype, wid)
Xregister wtype_t wtype;
Xlong wid;
X{
X	register char *widstr;
X	auto char *env[2];
X
X	/*
X	 * Set up the environment according to the new window type and
X	 * window ID.
X	 *
X	 * A 64-bit integer will fit in 20 digits.  If a "long" is wider
X	 * than this, then this code will have to be adjusted.
X	 */
X	if (wtype <= WT_TEK4010)
X		tty_envinit(wtype);
X	if ((widstr = malloc(sizeof "UW_ID=" + 20)) != NULL) {
X		sprintf(widstr, "UW_ID=%ld", wid);
X		env[0] = widstr;
X		env[1] = (char *)0;
X		env_set(env);
X	}
X}
X
Xstatic
Xchar *
Xwin_getopt(win, num)
Xcaddr_t win;
Xwoption_t num;
X{
X	register struct window *w;
X	static union optvalue ov;
X
X	/*
X	 * Get the value of window option "num".  It is arguably wrong to
X	 * always return the address of "ov" (even if the window isn't
X	 * allocated or an unknown option type was requested); however,
X	 * we're already in trouble and there is no good way to recover
X	 * at this point.
X	 */
X	if ((w = (struct window *)win) != NULL && w->w_alloc) {
X		switch (num) {
X		case WOG_VIS:
X			ov.ov_udata1 = w->w_visible;
X			break;
X		case WOG_TYPE:
X			ov.ov_udata6 = w->w_type;
X			break;
X		case WOG_POS:
X			ov.ov_point.h = w->w_position.h;
X			ov.ov_point.v = w->w_position.v;
X			break;
X		case WOG_TITLE:
X			(void)strncpy(ov.ov_string, w->w_title,
X			    sizeof ov.ov_string);
X			ov.ov_string[sizeof ov.ov_string-1] = '\0';
X			break;
X		case WOG_SIZE:
X			ov.ov_point.h = w->w_size.h;
X			ov.ov_point.v = w->w_size.v;
X			break;
X		}
X	}
X	return((char *)&ov);
X}
X
Xstatic
Xvoid
Xwin_setopt(win, num, value)
Xcaddr_t win;
Xwoption_t num;
Xchar *value;
X{
X	register struct window *w;
X	register union optvalue *ov;
X
X	/*
X	 * Set window option "num" to "value"
X	 */
X	if ((w = (struct window *)win) != NULL && w->w_alloc &&
X	    (ov = (union optvalue *)value) != NULL) {
X		switch (num) {
X		case WOG_VIS:
X			w->w_visible = ov->ov_udata1;
X			break;
X		case WOG_TYPE:
X			win_newtype(w, (wtype_t)ov->ov_udata6);
X			break;
X		case WOG_POS:
X			w->w_position.h = ov->ov_point.h;
X			w->w_position.v = ov->ov_point.v;
X			break;
X		case WOG_TITLE:
X			(void)strncpy(w->w_title, ov->ov_string,
X			    sizeof w->w_title);
X			w->w_title[sizeof w->w_title-1] = '\0';
X			break;
X		case WOG_SIZE:
X			w->w_size.h = ov->ov_point.h;
X			w->w_size.v = ov->ov_point.v;
X			break;
X		}
X	}
X}
!EOF!server/uw_win.c!
exit 0
: end of shell archive (part 3 of 9)
Technical Details
Message-ID: <1689@felix.UUCP>
Path: arc1-ca.pugleaf.net!utzoo!decvax!ucbvax!dual!unisoft!lll-lcc!lll-crg!mordor!sri-spam!sri-unix!hplabs!felix!macintosh
References: <1687@felix.UUCP> <1688@felix.UUCP>

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: arc1-ca.pugleaf.net!utzoo!decvax!ucbvax!dual!unisoft!lll-lcc!lll-crg!mordor!sri-spam!sri-unix!hplabs!felix!macintosh
From: jdb@mordor.ARPA (John Bruner)
Newsgroups: mod.mac.sources
Subject: UW v3.4 (part 3 of 9)
Message-ID: <1689@felix.UUCP>
Date: Thu, 23-Oct-86 15:57:59 EDT
Article-I.D.: felix.1689
Posted: Thu Oct 23 15:57:59 1986
Date-Received: Sat, 25-Oct-86 02:04:40 EDT
References: <1687@felix.UUCP> <1688@felix.UUCP>
Sender: macintosh@felix.UUCP
Reply-To: macintosh@felix.UUCP (The Moderator)
Organization: FileNet Corp., Costa Mesa, CA
Lines: 2528
Approved: bytebug@felix.UUCP (Roger L. Long)