home *** CD-ROM | disk | FTP | other *** search
- /*
- * uw_pcl - protocol handling for UW
- *
- * Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission to
- * copy this program is given provided that the copy is not sold and that
- * this copyright notice is included.
- */
-
- #include <sys/types.h>
- #include <sys/ioctl.h>
- #include <errno.h>
-
- #include "uw_param.h"
- #include "uw_clk.h"
- #include "uw_opt.h"
- #include "uw_win.h"
- #include "uw_pcl.h"
- #include "openpty.h"
-
- #define XON 0021 /* ASCII XON */
- #define XOFF 0023 /* ASCII XOFF */
- #define RUB 0177 /* ASCII RUBout */
- #define META 0200 /* "meta" bit for whatever it's worth */
-
- /*
- * Protocol negotiation is performed by a finite state machine (implemented
- * in pcl_haggle()). The states are defined as the enumerated type
- * "pnstate_t". The inputs have type "pnreq_t".
- */
- typedef enum {
- PNST_NOP, /* no protocol negotiation */
- PNST_AWAIT, /* timing out an ASKPCL */
- PNST_CWAIT, /* timing out a CANPCL */
- PNST_OK, /* negotiations completed */
- PNST_FAIL /* negotiation failed */
- } pnstate_t;
-
- typedef unsigned short pnreq_t; /* finite state machine requests */
- #define PNRQ_PCL 0000377 /* protocol mask */
- #define PNRQ_CMD 0177400 /* command mask: */
- #define PNRQ_NONE (pnreq_t)(0<<8) /* no request */
- #define PNRQ_START (pnreq_t)(1<<8) /* start negotiation */
- #define PNRQ_AWAIT (pnreq_t)(2<<8) /* timeout waiting for ASKPCL */
- #define PNRQ_ASK (pnreq_t)(3<<8) /* process received ASKPCL */
- #define PNRQ_CAN (pnreq_t)(4<<8) /* process received CANPCL */
- #define PNRQ_SET (pnreq_t)(5<<8) /* process received SETPCL */
- #define PNRQ_CWAIT (pnreq_t)(6<<8) /* timeout waiting for CANPCL */
- #define PNRQ_INIT (pnreq_t)(7<<8) /* initialize everything */
-
- static int p1_ctlch[] = { -1, P1_IAC, XON, XOFF, -1, -1, -1, -1 };
-
- extern void p1_entry(), p1_renew(), p2_renew();
- extern struct window *p1_neww(), *p2_neww();
- extern void p1_killw(), p1_xmit(), p1_recv();
- extern void p1_askpcl(), p1_canpcl(), p1_setpcl();
- extern void p2_recv(), p2_chkopt(), p2_sendopt();
-
- static struct protocol pcl_table[] = {
- {
- ' ',
- P1_NWINDOW,
- p1_ctlch, sizeof p1_ctlch / sizeof p1_ctlch[0],
- p1_entry, NULL, p1_renew,
- p1_neww, p1_killw,
- p1_xmit, p1_recv, NULL, NULL,
- p1_askpcl, p1_canpcl, p1_setpcl
- },
- {
- '!',
- P2_NWINDOW,
- p1_ctlch, sizeof p1_ctlch / sizeof p1_ctlch[0],
- p1_entry, NULL, p2_renew,
- p2_neww, p1_killw,
- p1_xmit, p2_recv, p2_chkopt, p2_sendopt,
- p1_askpcl, p1_canpcl, p1_setpcl
- },
- };
-
- struct protocol *protocol = pcl_table;
-
- /*
- * Two "current" windows are defined: the current input window (for
- * input from the Macintosh) and the current output window (for output
- * to the Macintosh).
- */
- static struct {
- struct window *in;
- struct window *out;
- } curwin;
-
-
- pcl_entry(mfd)
- register fildes_t mfd;
- {
- /*
- * This routine is called to start up protocol handling. We always
- * start with protocol 1 (the original UW protocol).
- */
- protocol = pcl_table;
- pcl_haggle(mfd, PNRQ_INIT);
- if (protocol->p_entry)
- (*protocol->p_entry)(mfd);
- }
-
- pcl_exit(mfd)
- register fildes_t mfd;
- {
- /*
- * This routine is called when we shut down (just before the server
- * exits).
- */
- if (protocol->p_exit)
- (*protocol->p_exit)(mfd);
- protocol = pcl_table;
- }
-
- static
- pcl_newpcl(newproto)
- struct protocol *newproto;
- {
- extern void rc_kludge();
-
- /*
- * Switch to new protocol "newproto". Right now we can get away
- * with just changing the value of "protocol". Eventually we will
- * probably want to call protocol-dependent functions to shut down
- * the old protocol and start up the new one.
- */
- protocol = newproto;
-
- /*
- * This is a horrible kludge. See rc_kludge() in "main.c" for
- * further details.
- */
- rc_kludge();
- }
-
- static
- void
- pcl_tohaggle(arg)
- register toarg_t arg;
- {
- /*
- * This is a kludge to get around the single-argument restriction
- * on clk_timeout. We split the argument "arg" into two 16-bit
- * pieces and invoke pcl_haggle.
- */
- pcl_haggle((fildes_t)((arg>>16)&0177777), (pnreq_t)(arg&0177777));
- }
-
- static
- pcl_haggle(mfd, req)
- fildes_t mfd;
- register pnreq_t req;
- {
- register struct protocol *p, *q;
- register char pname;
- register int request;
- static pnstate_t pnstate;
- static int waitcnt;
-
- /*
- * This routine implements the finite-state machine that handles
- * protocol negotiation. This routine is called by routines which
- * recognize incoming protocol commands and at 5 second intervals
- * when negotiations are in progress. The current protocol is
- * described by the variable "protocol".
- */
- if (req == PNRQ_INIT) {
- waitcnt = 0;
- pnstate = PNST_NOP;
- req = PNRQ_NONE;
- }
- if (!(p = protocol) || !p->p_askpcl || !p->p_canpcl || !p->p_setpcl) {
- req = PNRQ_NONE;
- } else {
- pname = req & PNRQ_PCL;
- request = req & PNRQ_CMD;
- switch (request) {
- case PNRQ_START: /* start protocol negotiation */
- /*
- * The Macintosh is responsible for starting protocol
- * negotiation (if it wants something other than the
- * standard protocol). This code is present for
- * purposes of exposition only.
- */
- (*p->p_askpcl)(mfd);
- req = PNRQ_AWAIT | pname;
- waitcnt = 0;
- pnstate = PNST_AWAIT;
- break;
- case PNRQ_AWAIT: /* timeout an ASKPCL */
- /*
- * This state also is not reached on the host.
- */
- if (pnstate == PNST_AWAIT) {
- if (++waitcnt > 3) {
- pnstate = PNST_FAIL;
- req = PNRQ_NONE;
- } else
- (*p->p_askpcl)(mfd);
- } else
- req = PNRQ_NONE;
- break;
- case PNRQ_ASK: /* handle received ASKPCL */
- q = pcl_table+sizeof pcl_table/sizeof pcl_table[0] - 1;
- (*p->p_canpcl)(mfd, q->p_name);
- pnstate = PNST_CWAIT;
- req = PNRQ_CWAIT | q->p_name;
- waitcnt = 0;
- break;
- case PNRQ_CAN: /* handle received CANPCL */
- for (q=pcl_table+sizeof pcl_table/sizeof pcl_table[0]-1;
- q > pcl_table && q->p_name > pname;
- q--)
- ;
- if (q->p_name == pname || q == pcl_table) {
- (*p->p_setpcl)(mfd, q->p_name);
- pcl_newpcl(q);
- pnstate = PNST_OK;
- req = PNRQ_NONE;
- } else {
- (*p->p_canpcl)(mfd, q->p_name);
- pnstate = PNST_CWAIT;
- req = PNRQ_CWAIT | q->p_name;
- waitcnt = 0;
- }
- break;
- case PNRQ_CWAIT: /* timeout a CANPCL */
- if (pnstate == PNST_CWAIT) {
- if (++waitcnt > 3) {
- pnstate = PNST_FAIL;
- req = PNRQ_NONE;
- } else
- (*p->p_canpcl)(mfd, pname);
- } else
- req = PNRQ_NONE;
- break;
- case PNRQ_SET: /* handle a received SETPCL */
- for (q=pcl_table+sizeof pcl_table/sizeof pcl_table[0]-1;
- q > pcl_table && q->p_name != pname;
- q--)
- ;
- if (q->p_name == pname) {
- pcl_newpcl(q);
- pnstate = PNST_OK;
- req = PNRQ_NONE;
- } else {
- /*
- * We are in trouble now -- the Mac has
- * instructed us to switch to a protocol
- * that we can't support. We switch back
- * to protocol 1 and hope that our message
- * to the Mac (telling it to switch to
- * protocol 1) will be interpreted correctly.
- */
- pnstate = PNST_FAIL;
- req = PNRQ_NONE;
- (*p->p_setpcl)(mfd, ' ');
- if (p != pcl_table)
- pcl_newpcl(pcl_table);
- }
- break;
- }
- if (req != PNRQ_NONE)
- (void)clk_timeout(5*CLK_HZ,
- pcl_tohaggle, (toarg_t)(((long)mfd<<16)|req));
- }
- }
-
- static
- void
- p1_entry(mfd)
- fildes_t mfd;
- {
- static char cmdbuf[2] = { P1_IAC };
-
- cmdbuf[1] = P1_DIR_HTOM|P1_FN_MAINT|P1_MF_ENTRY;
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
-
- static
- struct window *
- p1_neww(mfd, wclass, wtype, wnum, wid, datafd, ctlfd)
- fildes_t mfd;
- wclass_t wclass;
- wtype_t wtype;
- nwin_t wnum;
- long wid;
- fildes_t datafd;
- fildes_t ctlfd;
- {
- register struct window *w;
- static char cmdbuf[2] = { P1_IAC, 0 };
-
- /*
- * Create a new window for the host. This routine is not called when
- * the Macintosh creates a window.
- */
- w = win_neww(wclass, wtype, wnum, protocol->p_maxwin, wid,
- datafd, ctlfd, (struct woptdefn *)0);
- if (w) {
- cmdbuf[1] = P1_DIR_HTOM|P1_FN_NEWW|WIN_NUM(w);
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
- return(w);
- }
-
- static
- void
- p1_killw(mfd, w)
- register struct window *w;
- {
- static char cmdbuf[] = { P1_IAC, P1_DIR_HTOM|P1_FN_KILLW };
-
- /*
- * Kill window "w" and tell the Macintosh to do the same.
- */
- if (w && w->w_alloc) {
- if (curwin.in == w)
- curwin.in = (struct window *)0;
- if (curwin.out == w)
- curwin.out = (struct window *)0;
- cmdbuf[1] = P1_DIR_HTOM|P1_FN_KILLW|WIN_NUM(w);
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- win_killw(w);
- }
- }
-
- static
- void
- p1_xmit(mfd, w)
- fildes_t mfd;
- register struct window *w;
- {
- register char *cp, *cq;
- register int i, len;
- char ibuf[32], obuf[32];
- static char refresh;
- static char cmdbuf[] = { P1_IAC, 0 };
- extern int errno;
-
- /*
- * Transmit data to the Macintosh (via file descriptor "mfd)
- * on behalf of window "w". Be sure to convert any embedded
- * control characters and meta characters.
- *
- * Note that the input/output buffers should NOT be very large.
- * It is undesirable to perform large reads and effectively
- * "lock out" all other file descriptors. The chosen size
- * should preserve a reasonable amount of efficiency.
- *
- * The UW protocol only requires an OSELW command when the
- * output window changes. We issue this command more often
- * to "refresh" the Mac's idea of what the output window is.
- * This helps (slightly) to overcome spurious output redirects
- * caused by a noisy line.
- */
- if (w && w->w_alloc) {
- if (curwin.out != w || ++refresh == 0) {
- refresh = 0;
- curwin.out = w;
- cmdbuf[1] = P1_DIR_HTOM|P1_FN_OSELW|WIN_NUM(w);
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
- cq = obuf;
- if ((len = read(w->w_datafd, ibuf, sizeof ibuf)) < 0 &&
- errno != EWOULDBLOCK)
- (*protocol->p_killw)(mfd, w);
- for (cp=ibuf; cp < ibuf+len; cp++) {
- if (*cp&META) {
- if (cq > obuf) {
- (void)write(mfd, obuf, cq-obuf);
- cq = obuf;
- }
- cmdbuf[1] = P1_DIR_HTOM|P1_FN_META;
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- *cp &= ~META;
- }
- i = -1;
- if (*cp == RUB || *cp < ' ') {
- i = protocol->p_szctlch - 1;
- while (i >= 0 && protocol->p_ctlch[i] != *cp)
- i--;
- }
- if (i >= 0) {
- if (cq > obuf) {
- (void)write(mfd, obuf, cq-obuf);
- cq = obuf;
- }
- cmdbuf[1] = P1_DIR_HTOM|P1_FN_CTLCH|i;
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- } else {
- *cq++ = *cp;
- if (cq >= obuf+sizeof obuf) {
- (void)write(mfd, obuf, cq-obuf);
- cq = obuf;
- }
- }
- }
- if (cq > obuf)
- (void)write(mfd, obuf, cq-obuf);
- } else
- (void)read(w->w_datafd, ibuf, sizeof ibuf);
- }
-
- static
- void
- p1_recv(mfd, cbuf, clen)
- fildes_t mfd;
- char *cbuf;
- int clen;
- {
- register int len;
- register char *buf, *cp, *cq;
- register struct window *w;
- nwin_t wnum;
- auto int nready;
- char ibuf[512], obuf[512];
- static int seen_iac, seen_meta;
- static pnreq_t pnrq_cmd;
- static char cmdbuf[2] = { P1_IAC };
-
- /*
- * The received bytestream is examined. Non-command bytes are
- * written to the file descriptor corresponding to the current
- * "input" window (relative to the Macintosh -- the window the
- * user types input to).
- *
- * If "clen" is nonzero, then the contents of the buffer "cbuf"
- * are processed before any input is read.
- */
- if (ioctl(mfd, (int)FIONREAD, (char *)&nready) < 0) {
- perror("FIONREAD");
- return;
- }
- nready += clen;
-
- for (cq = obuf; nready > 0; nready -= len) {
- if (clen > 0) {
- len = clen;
- buf = cbuf;
- clen = 0;
- } else {
- if (nready > sizeof ibuf)
- len = read(mfd, ibuf, sizeof ibuf);
- else
- len = read(mfd, ibuf, nready);
- if (len <= 0) {
- perror("read");
- return;
- }
- buf = ibuf;
- }
- for (cp=buf; cp < buf+len; cp++) {
- if (pnrq_cmd) {
- pcl_haggle(mfd, pnrq_cmd|*cp);
- pnrq_cmd = 0;
- /* pcl_haggle may have changed the protocol */
- if (protocol != pcl_table) {
- if (protocol->p_recv)
- (*protocol->p_recv)(mfd,
- cp+1, buf+len-cp-1);
- return;
- }
- } else if (seen_iac) {
- if ((*cp&P1_DIR) == P1_DIR_MTOH) {
- if (cq > obuf) {
- (void)write(curwin.in->w_datafd,
- obuf, cq-obuf);
- cq = obuf;
- }
- switch (*cp & P1_FN) {
- case P1_FN_NEWW:
- wnum = *cp & P1_WINDOW;
- if (!wnum)
- break;
- w = WIN_PTR(wnum);
- if (w->w_alloc)
- break;
- if (!win_neww(WC_INTERNAL,
- defwtype, wnum,
- protocol->p_maxwin, 0L,
- (fildes_t)-1, (fildes_t)-1,
- (struct woptdefn *)0)) {
- cmdbuf[1] = P1_DIR_HTOM|
- P1_FN_KILLW|wnum;
- (void)write(mfd, cmdbuf,
- sizeof cmdbuf);
- }
- break;
- case P1_FN_KILLW:
- wnum = *cp & P1_WINDOW;
- if (!wnum)
- break;
- win_killw(WIN_PTR(wnum));
- break;
- case P1_FN_ISELW:
- wnum = *cp & P1_WINDOW;
- if (!wnum)
- break;
- w = WIN_PTR(wnum);
- if (w->w_alloc)
- curwin.in = w;
- else
- curwin.in = NULL;
- break;
- case P1_FN_META:
- seen_meta = 1;
- break;
- case P1_FN_CTLCH:
- *cq = protocol->p_ctlch[*cp&P1_CC];
- if (seen_meta) {
- seen_meta = 0;
- *cq |= META;
- }
- if (curwin.in)
- cq++;
- break;
- case P1_FN_MAINT:
- switch (*cp & P1_MF) {
- case P1_MF_ENTRY:
- (*protocol->p_renew)(mfd);
- break;
- case P1_MF_ASKPCL:
- pcl_haggle(mfd,PNRQ_ASK);
- break;
- case P1_MF_CANPCL:
- pnrq_cmd = PNRQ_CAN;
- break;
- case P1_MF_SETPCL:
- pnrq_cmd = PNRQ_SET;
- break;
- case P1_MF_EXIT:
- done(0);
- break;
- }
- break;
- }
- }
- seen_iac = 0;
- } else if (*cp == P1_IAC)
- seen_iac++;
- else {
- if (seen_meta) {
- seen_meta = 0;
- *cq = *cp | META;
- } else
- *cq = *cp;
- if (curwin.in) {
- if (++cq >= obuf+sizeof obuf) {
- (void)write(curwin.in->w_datafd,
- obuf, cq-obuf);
- cq = obuf;
- }
- }
- }
- }
- }
- if (cq > obuf)
- (void)write(curwin.in->w_datafd, obuf, cq-obuf);
- }
-
- static
- void
- p1_askpcl(mfd)
- fildes_t mfd;
- {
- static char cmdbuf[2] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_ASKPCL };
-
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
-
- static
- void
- p1_canpcl(mfd, pname)
- fildes_t mfd;
- char pname;
- {
- static char cmdbuf[3] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_CANPCL };
-
- cmdbuf[2] = pname;
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
-
- static
- void
- p1_setpcl(mfd, pname)
- fildes_t mfd;
- char pname;
- {
- static char cmdbuf[3] = { P1_IAC,P1_DIR_HTOM|P1_FN_MAINT|P1_MF_SETPCL };
-
- cmdbuf[2] = pname;
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
-
- static
- void
- p1_renew(mfd)
- fildes_t mfd;
- {
- register struct window *w;
- static char cmdbuf[2] = { P1_IAC };
-
- /*
- * Re-init (re-NEW) an existing connection. Send a NEWW command
- * for each existing window. This function is invoked when the
- * Macintosh sends an ENTRY maintenance command.
- */
- for (w=window; w < window+protocol->p_maxwin; w++) {
- if (w->w_alloc) {
- win_renew(w, 0);
- cmdbuf[1] = P1_DIR_HTOM|P1_FN_NEWW|WIN_NUM(w);
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
- }
- }
-
- static
- void
- p2_renew(mfd)
- fildes_t mfd;
- {
- register struct window *w;
- static char cmdbuf[3] = { P2_IAC };
-
- /*
- * Re-init (re-NEW) an existing connection. Send a NEWW command
- * for each existing window. This function is invoked when the
- * Macintosh sends an ENTRY maintenance command.
- */
- for (w=window; w < window+protocol->p_maxwin; w++) {
- if (w->w_alloc) {
- win_renew(w, 1);
- cmdbuf[1] = P2_DIR_HTOM|P2_FN_NEWW|WIN_NUM(w);
- cmdbuf[2] = w->w_type + ' ';
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
- }
- }
-
- static
- struct window *
- p2_neww(mfd, wclass, wtype, wnum, wid, datafd, ctlfd)
- fildes_t mfd;
- wclass_t wclass;
- wtype_t wtype;
- nwin_t wnum;
- long wid;
- fildes_t datafd;
- fildes_t ctlfd;
- {
- register struct window *w;
- static char cmdbuf[3] = { P2_IAC };
-
- /*
- * Create a new window as requested by the host. This routine is not
- * called when the Macintosh creates a window.
- */
- w = win_neww(wclass, wtype, wnum, protocol->p_maxwin, wid,
- datafd, ctlfd, (struct woptdefn *)0);
- if (w) {
- cmdbuf[1] = P2_DIR_HTOM|P2_FN_NEWW|WIN_NUM(w);
- cmdbuf[2] = ' ' + wtype;
- (void)write(mfd, cmdbuf, sizeof cmdbuf);
- }
- return(w);
- }
-
- static
- void
- p2_chkopt(mfd)
- fildes_t mfd;
- {
- register struct window *w;
- nwin_t maxwin;
-
- /*
- * Ideally, this routine would call a routine in the window
- * module (perhaps win_chkopt()), passing the maximum window
- * number as one argument. The "for" loop would be in that
- * routine. However, I'm not willing to accept the overhead
- * for that conceptual nicety.
- */
- maxwin = protocol->p_maxwin;
- for (w=window; w < window+maxwin; w++)
- if (w->w_alloc)
- opt_scan((caddr_t)w, &w->w_optdefn, p2_sendopt, mfd,
- P2_FN_WOPT|WIN_NUM(w));
- }
-
- static
- void
- p2_sendopt(mfd, fn, buf, len)
- fildes_t mfd;
- int fn;
- register char *buf;
- register int len;
- {
- register char *cp;
- register int i;
- char outbuf[512];
-
- /*
- * Encode and transmit the option string contained in "buf". The
- * initial command (which will be P2_FN_WOPT|WIN_NUM(w)) is
- * contained in "fn".
- *
- * The caller is responsible for handing us a correctly-formed
- * option string. This routine merely performs the protocol encoding
- * which is required for control and meta characters.
- */
- curwin.out = NULL;
- outbuf[0] = P2_IAC;
- outbuf[1] = fn|P2_DIR_HTOM;
- for (cp=outbuf+2; len > 0; buf++,len--) {
- if (cp > outbuf+sizeof outbuf - 4) {
- (void)write(mfd, outbuf, cp-outbuf);
- cp = outbuf;
- }
- if (*buf & META) {
- *cp++ = P2_IAC;
- *cp++ = P2_DIR_HTOM|P2_FN_META;
- *buf &= ~META;
- }
- i = -1;
- if (*buf == RUB || *buf < ' ') {
- i = protocol->p_szctlch - 1;
- while (i >= 0 && protocol->p_ctlch[i] != *buf)
- i--;
- }
- if (i >= 0) {
- *cp++ = P2_IAC;
- *cp++ = P2_DIR_HTOM|P2_FN_CTLCH|(i&7);
- } else
- *cp++ = *buf;
- }
- if (cp > outbuf)
- (void)write(mfd, outbuf, cp-outbuf);
- }
-
- static
- void
- p2_recv(mfd, cbuf, clen)
- fildes_t mfd;
- char *cbuf;
- int clen;
- {
- register int len;
- register char *buf, *cp, *cq;
- register struct window *w;
- register char c;
- nwin_t wnum;
- auto int nready;
- char ibuf[512], obuf[512];
- static int seen_iac, seen_meta, is_option;
- static pnreq_t pnrq_cmd;
- static nwin_t neww;
- static char cmdbuf[2] = { P2_IAC };
-
- /*
- * The received bytestream is examined. Non-command bytes are
- * written to the file descriptor corresponding to the current
- * "input" window (relative to the Macintosh -- the window the
- * user types input to).
- *
- * If "clen" is nonzero, then the contents of the buffer "cbuf"
- * are processed before any input is read.
- */
- if (ioctl(mfd, (int)FIONREAD, (char *)&nready) < 0) {
- perror("FIONREAD");
- return;
- }
- nready += clen;
-
- for (cq = obuf; nready > 0; nready -= len) {
- if (clen > 0) {
- len = clen;
- buf = cbuf;
- clen = 0;
- } else {
- if (nready > sizeof ibuf)
- len = read(mfd, ibuf, sizeof ibuf);
- else
- len = read(mfd, ibuf, nready);
- if (len <= 0) {
- perror("read");
- return;
- }
- buf = ibuf;
- }
- for (cp=buf; cp < buf+len; cp++) {
- if (pnrq_cmd) {
- pcl_haggle(mfd, pnrq_cmd|*cp);
- pnrq_cmd = 0;
- /* pcl_haggle may have changed the protocol */
- if (protocol != pcl_table) {
- if (protocol->p_recv)
- (*protocol->p_recv)(mfd,
- cp+1, buf+len-cp-1);
- return;
- }
- } else if (neww) {
- w = WIN_PTR(neww);
- if (!w->w_alloc &&
- !win_neww(WC_INTERNAL, (wtype_t)(*cp-' '),
- neww, protocol->p_maxwin, 0L,
- (fildes_t)-1, (fildes_t)-1,
- (struct woptdefn *)0)) {
- cmdbuf[1] = P2_DIR_HTOM|
- P2_FN_KILLW|neww;
- (void)write(mfd, cmdbuf,
- sizeof cmdbuf);
- }
- neww = 0;
- } else if (seen_iac) {
- if ((*cp&P2_DIR) == P2_DIR_MTOH) {
- c = *cp & P2_FN;
- if (is_option &&
- c!=P2_FN_META && c!=P2_FN_CTLCH) {
- opt_iflush();
- is_option = 0;
- }
- if (cq > obuf) {
- (void)write(curwin.in->w_datafd,
- obuf, cq-obuf);
- cq = obuf;
- }
- switch (*cp & P2_FN) {
- case P2_FN_NEWW:
- neww = *cp & P2_WINDOW;
- break;
- case P2_FN_WOPT:
- wnum = *cp & P2_WINDOW;
- if (!wnum)
- break;
- w = WIN_PTR(wnum);
- if (!w->w_alloc) {
- curwin.in = NULL;
- break;
- }
- is_option = 1;
- opt_istart((caddr_t)w, &w->w_optdefn);
- break;
- case P2_FN_KILLW:
- wnum = *cp & P2_WINDOW;
- if (!wnum)
- break;
- win_killw(WIN_PTR(wnum));
- break;
- case P2_FN_ISELW:
- wnum = *cp & P2_WINDOW;
- if (!wnum)
- break;
- w = WIN_PTR(wnum);
- if (w->w_alloc)
- curwin.in = w;
- else
- curwin.in = NULL;
- break;
- case P2_FN_META:
- seen_meta = 1;
- if ((*cp&P2_CC) == 0)
- break;
- /* no break */
- case P2_FN_CTLCH:
- c=protocol->p_ctlch[*cp&P2_CC];
- if (seen_meta) {
- seen_meta = 0;
- c |= META;
- }
- if (is_option)
- is_option=opt_input(c);
- else
- if (curwin.in)
- *cq++ = c;
- break;
- case P2_FN_MAINT:
- switch (*cp & P2_MF) {
- case P2_MF_ENTRY:
- (*protocol->p_setpcl)(mfd, protocol->p_name);
- (*protocol->p_renew)(mfd);
- break;
- case P2_MF_ASKPCL:
- pcl_haggle(mfd,PNRQ_ASK);
- break;
- case P2_MF_CANPCL:
- pnrq_cmd = PNRQ_CAN;
- break;
- case P2_MF_SETPCL:
- pnrq_cmd = PNRQ_SET;
- break;
- case P2_MF_EXIT:
- done(0);
- break;
- }
- break;
- }
- }
- seen_iac = 0;
- } else if (*cp == P2_IAC)
- seen_iac++;
- else {
- if (seen_meta) {
- c = *cp | META;
- seen_meta = 0;
- } else
- c = *cp;
- if (is_option)
- is_option = opt_input(c);
- else
- if (curwin.in)
- *cq++ = c;
- if (cq >= obuf+sizeof obuf) {
- (void)write(curwin.in->w_datafd,
- obuf, cq-obuf);
- cq = obuf;
- }
- }
- }
- }
- if (cq > obuf)
- (void)write(curwin.in->w_datafd, obuf, cq-obuf);
- }
-