Path: utzoo!mnetor!uunet!ccicpg!felix!dhw68k!macintosh From: jdb@mordor.s1.gov (John Bruner) Newsgroups: comp.sources.mac Subject: UW v4.2 (part 7 of 9) Message-ID: <6609@dhw68k.cts.com> Date: 7 Apr 88 14:00:44 GMT References: <6493@dhw68k.cts.com> <6497@dhw68k.cts.com> <6515@dhw68k.cts.com> <6538@dhw68k.cts.com> <6587@dhw68k.cts.com> <6602@dhw68k.cts.com> Sender: macintosh@dhw68k.cts.com Organization: Lawrence Livermore National Laboratory, S-1 Project Lines: 1580 Approved: bytebug@dhw68k.cts.com (Roger L. Long) [UW v4.2 - part 7 of 9] --- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # server/uw_opt.c # server/uw_pcl.c # This archive created: Mon Apr 4 07:52:09 1988 # By: Roger L. Long (macintosh@dhw68k.cts.com) export PATH; PATH=/bin:$PATH if test ! -d server then echo shar: mkdir server mkdir server fi echo shar: extracting "'server/uw_opt.c'" '(14287 characters)' if test -f 'server/uw_opt.c' then echo shar: will not over-write existing file "'server/uw_opt.c'" else sed 's/^X//' << \SHAR_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} SHAR_EOF if test 14287 -ne "`wc -c < 'server/uw_opt.c'`" then echo shar: error transmitting "'server/uw_opt.c'" '(should have been 14287 characters)' fi fi # end of overwriting check echo shar: extracting "'server/uw_pcl.c'" '(21808 characters)' if test -f 'server/uw_pcl.c' then echo shar: will not over-write existing file "'server/uw_pcl.c'" else sed 's/^X//' << \SHAR_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} SHAR_EOF if test 21808 -ne "`wc -c < 'server/uw_pcl.c'`" then echo shar: error transmitting "'server/uw_pcl.c'" '(should have been 21808 characters)' fi fi # end of overwriting check # End of shell archive exit 0 --- end of part 7 ---