Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: 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) : [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 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<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<>= 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<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<= 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 X#include X#include 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 X#include X#include 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<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 X#include X#include X#include X#include X#include X#include X#include 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 X#include X#include X#include X#include X#include 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<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)