home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989 by David W. Trissel
- *
- * Not derived from licensed software.
- *
- * Permission is granted to freely use, copy, modify, and redistribute
- * this software, provided that no attempt is made to gain profit from it,
- * the author is not construed to be liable for any results of using the
- * software, alterations are clearly marked as such, and this notice is
- * not modified.
- *
- */
-
- #include <stdio.h>
- #ifdef NeXT
- #include <libc.h>
- #endif
- #include <sys/types.h>
- #include <signal.h>
- #include <errno.h>
- #include "layers.h"
-
- /* protocol.c - BSD MacLayers protocol driver */
-
- /* This module handles all interaction with the Macintosh MacLayers
- ** program. Services provided are:
- **
- ** InitLink() - initialize link to MacLayers
- **
- ** TopChannel() - return highest prority channel
- **
- ** SendNew() - request new layer channel of MacLayers
- **
- ** SendTitle() - change window title to given string (NOT IMPLENTED YET)
- **
- ** SendDelete()- tell MacLayers indicated layer has died
- **
- ** SendQuit() - order MacLayers to terminate layers mode
- **
- ** SendData() - send output to indicated channel's window
- **
- ** SendReshape() - send Shape structure to MacLayers
- **
- ** ProcessStreamin() - data is ready to be processed from MacLayers
- **
- */
-
- #define DUMPALL
- #undef DUMPALL
-
- /* C library calls */
- #ifndef NeXT
- unsigned alarm(); /* alarm system call */
- #endif
-
- static int Start_proto1();
- static int Start_proto2();
- static int Start_proto3();
- static int Start_proto4();
- static int Start_proto5();
- static int Start_proto6();
- static int Start_proto7();
- static int Start_proto8();
- static int GetData();
- static void Packet();
- static void Parse();
- static void AwaitInput();
- static void asciishape();
- static void fill4();
- static void fill2();
- static void fill1();
- static int parseshape();
- static unsigned get4();
- static unsigned get2();
- static unsigned get1();
- static int myscanf();
- static int mygetchar();
- static void myungetc();
- static void myalarm();
- static void dumptime();
-
- static char inbuff[IOSIZE]; /* input buffer from MacLayers */
- static char *inpos; /* current input position in buffer */
- static int insize = 0; /* characters left to process */
- static int settimeout = 0; /* alarm system call timeout value */
- static int Outstream = -1; /* current output stream channel */
- static int Instream = -1; /* current input stream channel */
- static int Sevenbits = 0; /* communication channel is 7 bits */
-
- static struct Shape SNshape; /* SendNew() shape response */
- static int SNresp = 0; /* SendNew() reponse poll flag */
- static int SNchan = 0; /* SendNew() channel return */
- #define SN_WAITING -1000 /* SendNew() waiting response value */
-
- #define ATTRSIZE 15 /* size of window attribute string */
-
- #define FLUSH fflush(stdout)
-
-
- /* Initlink() - initialize link with MacLayers */
-
- /* Returns:
- ** 0 - linkup failed
- ** 1 - linkup successful, Maclayers now in protocol mode
- */
-
- int
- Initlink()
- {
- int Outstream = -1; /* no default stream yet [UNUSED] */
- int Instream = -1; /* no default stream yet [UNUSED] */
- int num1, num2, num3; /* scanf item result */
- int err; /* error code */
- int doversion = 0; /* version swapping flag [UNUSED] */
-
- #define WAITTIME 10 /* second wait response time */
- #define INITTIME 2 /* wait time after succesful startup */
-
-
- /*** This patch not yet tested or implemented. Sent to the MacLayers archive
- **** as:
-
- This patch fixes the "Encode request not from host" bug that occurs when
- running MacLayers 1.00 on a VaxStation 3100 and Ultrix 3.1d.
-
- I came across this patch rather accidentally, so take it with a grain of
- NaCl.
-
- ifndef vax
- /* we must non-buffer input since all input must be immediate
- setbuf(stdin, NULL); /* non-buffer all input
- endif
-
- Archive manager Peter Newton added the following comments:
-
- Don't have a VaxStation to try it one. Many people have had problems
- with Ultrix on VaxStations. We have been giving them uuencoded
- binaries made under BSD.
-
- *****************/
-
- /* V1.1 Note: The latest BSD Sun system doesn't break reads from the
- ** terminal during signals. It appears that System V does do this
- ** as do earlier BSD systems. At this time no special hacks will
- ** be installed in just to support Unix versions not doing the breaks.
- ** Without alarm timeouts host layers will hang if inappropriate
- ** responses are received during protocol startup. But this should
- ** only happen when a user types the layers command when not running
- ** MacLayers.
- */
-
- /* we must non-buffer input since all input must be immediate */
- setbuf(stdin, NULL); /* non-buffer all input */
-
- /* Host layers after V1.00 can receive protocol level information.
- ** Send our level as ESC <id>. Version 1.00 MacLayers will treat
- ** this as an illegal vt-100 sequence and issue a beep. Later versions
- ** accept our protocol level and return their own after receiving
- ** our protocol startup sequence sent here.
- */
- DO DEBUG("write protocol level 2: ESC 2\n");
- /* send our protocol level out */
- if ((err=printf("\033%c", HOSTPROTOCOL + '0')) < 0)
- { DO DEBUG(" printf() error code %d\n", err);
- return ( 0 ); /* problem with stdout */
- }
- FLUSH;
-
- /* send intitial request for terminal type and version number */
- DO DEBUG("write: ESC [ c\n");
- fputs("\033[c", stdout);
- FLUSH; /* force output buffer */
-
- /* Attempt to read "ESC [ ? 8 ; typedigits ; versiondigits c"
- ** MacLayers in layers mode will return 8 ; 1 c
- ** MacLayers in startup mode returns 8 ; X c
- ** were X is the protocol level
- */
- num1 = num2 = num3 = -1; /* default to unsupplied values */
- DO DEBUG(" doing first scanf\n");
- (void) myalarm(WAITTIME); /* set timeout */
- (void) myscanf("\033[?%d;%d;%dc", &num1, &num2, &num3);
- (void) myalarm(0); /* cancel alarm */
- DO DEBUG("read ESC [ ? %d ; %d; %d c\n", num1, num2, num3);
- if (num1 != 8 || num2 != 10)
- return ( 0 ); /* not correct response or layers term ID */
-
- DO DEBUG("Client Protocol %d, Host Protocol %d\n", num3, HOSTPROTOCOL);
-
- /* Terminal type was valid, now verify protocol number */
- switch (num3)
- { case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- /* these are all valid levels */
- break; /* break for valid levels */
-
- case 9:
- num3 = 7; /* 9 represents level 7 */
- break;
-
- case 0:
- num3 = 8; /* 0 represents level 8 */
- break;
-
- default:
- /* invalid response */
- return ( 0 ); /* incorrect protocol level */
-
- } /* client protocol level switch */
-
- Clientlevel = num3; /* set client protocol level offered */
-
- /* final protocol level cannot be higher than our current support level */
- if (num3 > HOSTPROTOCOL)
- { DO DEBUG("Protocol level forced down to host level\n");
- num3 = HOSTPROTOCOL; /* force back down to the host level */
- }
-
- Protocollevel = num3; /* set effective protocol level */
-
- /* execute proper startup protocol level routine */
- switch (Protocollevel)
- { case 1:
- return ( Start_proto1() ); /* handle protocol 1 startup sequence */
-
- case 2:
- return ( Start_proto2() ); /* handle protocol 2 startup sequence */
-
- case 3:
- return ( Start_proto3() ); /* handle protocol 3 startup sequence */
-
- case 4:
- return ( Start_proto4() ); /* handle protocol 4 startup sequence */
-
- case 5:
- return ( Start_proto5() ); /* handle protocol 5 startup sequence */
-
- case 6:
- return ( Start_proto6() ); /* handle protocol 6 startup sequence */
-
- case 7:
- return ( Start_proto7() ); /* handle protocol 7 startup sequence */
-
- case 8:
- return ( Start_proto8() ); /* handle protocol 8 startup sequence */
-
- }
-
- /* invalid - refuse startup */
- return ( 0 ); /* SHOULD NOT OCCUR */
-
- } /* Initlink() */
-
-
- /* Start_proto1() - Protocol 1 startup sequence */
-
- static int
- Start_proto1()
- {
- int num1; /* scanf item result */
-
- /* This is the original MacLayers protocol for V1.00 */
-
- /* ask terminal if ENC_ENABLE is to be forced */
- DO DEBUG("write: ESC [ F\n");
- (void) fputs("\033[F", stdout);
- FLUSH; /* force output buffer */
-
- /* attempt to read "ESC [ flag F" (flag indicates ENC_ENABLE status) */
- num1 = -1; /* default to invalid response */
- myalarm(WAITTIME); /* set timeout */
- (void) myscanf("\033[%dF", &num1);
- myalarm(0); /* cancel alarm */
- DO DEBUG("read ESC [ %d F\n", num1);
- if (num1 != 1 && num1 != 0)
- return ( 0 ); /* something's wrong */
- if (num1 == 1)
- Sevenbits = 1; /* we are processing 7-bit data */
-
- /* now startup packet mode in non ENC_ENABLE processing */
- DO DEBUG("write: ESC [ 2 ; 0 v\n");
- (void) fputs("\033[2;0v", stdout); /* "ESC [ 2 ; 0 v" */
- FLUSH; /* force output buffer */
-
- #if 0
- { int i,j;
- for (i=0; i<20; i++)
- { j = mygetchar();
- DO DEBUG("---- read 0x%lx == %c\n", j, j);
- }
- return (0 );
- }
- #endif
- #if 0
- /* We must reset buffer to reread this character. Note
- ** this won't work for triggering reads by layers.c unless
- ** client is sending more than 1 character because the select()
- ** system call is used.
- */
- /* ungetc(num1, stdin); /* return character back for re-read */
- myungetc(num1); /* re-insert this character */
- #endif
- #if 0
- insize = 1; /* preset buffer with one character */
- inpos = inbuff; /* setup buffer pointer */
- inbuff[0] = num1; /* setup to reread this character */
- #endif
- Clientlevel = 1; /* assume protocol is level 1 */
-
- /* we are now in packet mode */
- sleep( INITTIME ); /* let Macintosh keep up with us */
-
- return ( 1 ); /* return successful startup */
-
- } /* Start_proto1() */
-
-
- /* Start_proto2() - Protocol 2 startup sequence */
-
- static int
- Start_proto2()
- {
- /* This is the second MacLayers protocol starting with V1.1 */
-
- /* we are now in packet mode */
- sleep( INITTIME ); /* let Macintosh keep up with us */
-
- return ( 1 ); /* return successful startup */
-
- } /* Start_proto2() */
-
-
-
- /* Start_proto3() - Protocol 3 startup sequence */
-
- static int
- Start_proto3()
- {
- /* not yet defined! */
- return ( 0 ); /* SHOULD NOT OCCUR */
-
- } /* Start_proto3() */
-
-
-
- /* Start_proto4() - Protocol 4 startup sequence */
-
- static int
- Start_proto4()
- {
- /* not yet defined! */
- return ( 0 ); /* SHOULD NOT OCCUR */
-
- } /* Start_proto4() */
-
-
-
- /* Start_proto5() - Protocol 5 startup sequence */
-
- static int
- Start_proto5()
- {
- /* not yet defined! */
- return ( 0 ); /* SHOULD NOT OCCUR */
-
- } /* Start_proto5() */
-
-
-
- /* Start_proto6() - Protocol 6 startup sequence */
-
- static int
- Start_proto6()
- {
- /* not yet defined! */
- return ( 0 ); /* SHOULD NOT OCCUR */
-
- } /* Start_proto6() */
-
-
-
- /* Start_proto7() - Protocol 7 startup sequence */
-
- static int
- Start_proto7()
- {
- /* not yet defined! */
- return ( 0 ); /* SHOULD NOT OCCUR */
-
- } /* Start_proto7() */
-
-
-
- /* Start_proto8() - Protocol 8 startup sequence */
-
- static int
- Start_proto8()
- {
- /* not yet defined! */
- return ( 0 ); /* SHOULD NOT OCCUR */
-
- } /* Start_proto8() */
-
-
- /* TopChannel() - return highest prority channel */
-
- int
- TopChannel()
- {
- return ( Instream );
-
- } /* TopChannel() */
-
-
- /*
- ** WARNING: Most of the following functions may be recursively called
- ** as control commands are processed from the input stream
- */
-
-
- /* ProcessStreamin() - MacLayers has input to process */
-
- void
- ProcessStreamin()
- {
- DO dumptime();
- DO DEBUG("ProcessStreamin() insize %d\n", insize);
-
- GetData(); /* read some */
-
- while (insize > 0) /* while more data to process ... */
- Parse(); /* process next chuck of data */
-
- } /* ProcessStreamin() */
-
-
- /* SendNew() - request new layer channel from MacLayers */
-
- /* This command is unique in that it returns a response from MacLayers.
- ** To do this we continue processing the input stream until we get
- ** our return. (This leads to recursive conditions.) The variables
- ** 'SNresp', 'SNshape' and 'SNchan' are set when our reply is received.
- */
- int
- SendNew(shape)
- struct Shape *shape; /* shape to use for new window */
- {
- int i; /* attribute count variable */
- char astring[ATTRSIZE]; /* copy of attribute string */
-
- DO dumptime();
- DO DEBUG("SendNew() new layer requested: '~%cA'\n", '1'+ATTRSIZE);
-
- /* check for a recursive call */
- if (SNresp == SN_WAITING)
- { DO DEBUG("return 0 - recursive call\n");
- return ( 0 ); /* return failure */
- }
-
- putchar(ESCAPE); /* send start of control packet char */
- putchar('1' + ATTRSIZE); /* send command size */
- putchar('A'); /* send command */
- asciishape(shape, astring); /* convert shape to string */
- for (i=0; i < ATTRSIZE; i++)
- putchar(astring[i]); /* send next attribute digit */
- FLUSH;
-
- /* now stay here and process the input stream until we see our response */
- /**** THIS SHOULD BE ENHANCED TO TIMEOUT WITH GetData() AND REISSUE REQUEST */
- SNresp = SN_WAITING; /* indicate we are waiting a response */
- while (SNresp == SN_WAITING)
- { DO DEBUG(" while (SNresp %d == %d)\n", SNresp, SN_WAITING);
- AwaitInput(); /* wait till input from MacLayers arrives */
- ProcessStreamin(); /* process available input */
- }
-
- if (SNresp == -1) /* if Maclayers rejected request */
- SNchan = 0; /* return failure channel of zero */
- else
- *shape = SNshape; /* else update shape structure */
-
- DO DEBUG("SendNew() returning channel %d\n", SNchan);
-
- return ( SNchan ); /* return the indicated channel */
-
- } /* SendNew() */
-
-
- /* SendReshape() - send to shape to MacLayers */
-
- void
- SendReshape(chan, shape)
- int chan; /* channel shape belongs to */
- struct Shape *shape; /* shape to use for new window */
- {
- int i; /* attribute count variable */
- char astring[ATTRSIZE]; /* copy of attribute string */
-
- DO dumptime();
- DO DEBUG("SendReshape() reshape: '~%cA'\n", '2'+ATTRSIZE);
-
- if (chan <= 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- putchar(ESCAPE); /* send start of control packet char */
- putchar('2' + ATTRSIZE); /* send command size */
- putchar('R'); /* send command */
- putchar(chan + '0'); /* send channel */
- asciishape(shape, astring); /* convert shape to string */
- DO DEBUG("shape: %.*s\n", ATTRSIZE, astring);
- for (i=0; i < ATTRSIZE; i++)
- putchar(astring[i]); /* send next attribute digit */
- FLUSH;
-
- } /* SendReshape() */
-
-
- /* SendTitle() - set layer's window title */
-
- void
- SendTitle(chan, buff, cnt)
- int chan; /* layer window ID */
- char *buff; /* new title string */
- int cnt; /* count of title length */
- {
- int i; /* work variable */
-
- DO DEBUG("SendTitle(chan%d, len %d, '%.*s')\n", chan, cnt, cnt, buff);
-
- if (chan <= 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- if (cnt < 0)
- { DO DEBUG("BAD COUNT!!!\n");
- return; /* ignore request */
- }
-
- /* for now chop title size to 29 chars since that's MacLayer's limit */
- if (cnt > 29)
- cnt = 29; /* due to packet size limit */
-
- /* we must guarantee that the size will not appear to be another ESCAPE */
- if ('2' + cnt == ESCAPE)
- cnt--; /* truncate to avoid ESCAPE ESCAPE */
-
- putchar(ESCAPE); /* send start of control packet char */
- putchar('2' + cnt); /* send size of packet */
- putchar('T'); /* send command */
- putchar(chan + '0'); /* send channel ID */
- for (i=0; i<cnt; i++)
- putchar(buff[i]); /* send out title */
- FLUSH;
-
- } /* SendTitle() */
-
-
- /* SendDelete() - tell Maclayers layer died */
-
- void
- SendDelete(chan)
- int chan; /* dead channel ID */
- {
- DO DEBUG("SendDelete(%d) '~2D%d'\n", chan, chan);
-
- if (chan <= 0 || chan > MAXPCHAN) /* check channel ID */
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- putchar(ESCAPE); /* send control packet start char */
- putchar('2'); /* send command size */
- putchar('D'); /* send command character */
- putchar(chan + '0'); /* channel ID in ascii */
- FLUSH;
-
- } /* SendDelete() */
-
-
- /* SendQuit() - order MacLayers to end layers mode */
-
- void
- SendQuit(chan)
- int chan; /* dead channel ID */
- {
- DO dumptime();
- DO DEBUG("SendQuit() '~1E'\n");
-
- putchar(ESCAPE); /* send control packet start char */
- putchar('1'); /* send command size */
- putchar('E'); /* send command */
- FLUSH;
-
- } /* SendQuit() */
-
-
- /* SendData() - send output to layer's window */
-
- void
- SendData(chan, buff, cnt)
- int chan; /* layer window ID */
- unsigned char *buff; /* new title string */
- int cnt; /* count of title length */
- {
- unsigned c; /* output character being sent */
-
- DO
- { int dcnt;
-
- dumptime();
- DEBUG("SendData(chan %d, len %d, '", chan, cnt, cnt, buff);
- for (dcnt=0; dcnt<cnt; dcnt++)
- DEBUG("%c", buff[dcnt]); /* dump each char so null doesn't stop */
- DEBUG("')\n");
- }
-
- if (chan <= 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!!\n");
- return; /* ignore request */
- }
-
- /* if new output channel stream then prefix redirect command */
- if (chan != Outstream)
- { DO DEBUG("Redirecting output to %d '~2O%d'\n", chan, chan);
- putchar(ESCAPE); /* start of command sequence */
- putchar('2'); /* send command size */
- putchar('O'); /* send command */
- putchar(chan + '0'); /* put out channel in ASCII */
- Outstream = chan; /* new output stream set */
- }
-
- /* transmit the buffer converting the ESCAPE sequence to double ESCAPE */
- while (cnt--)
- { c = *buff++; /* get next output character */
- #ifdef DUMPALL
- DO DEBUG("outchar %c 0x%x\n", c, c);
- #endif
- if (c == ESCAPE || c == (ESCAPE + 0x80))
- { putchar(c); /* put it out twice */
- #ifdef DUMPALL
- DO DEBUG(" Doubled Escape!\n");
- #endif
- }
- putchar(c); /* write character out */
- }
-
- FLUSH; /* force out queued output characters */
-
- } /* SendData() */
-
-
- /* Parse() - process next chunk of input stream */
-
- static void
- Parse()
- {
- #define ST_NULL 0 /* not primed for next state yet */
- #define ST_STREAM 1 /* processing default stream input */
- #define ST_PKT 2 /* processing packet data */
-
- int c; /* input character being processed */
-
- static int state = ST_NULL; /* current input state */
- static int psize = 0; /* packet size */
- static int rempsize = 0; /* remembered packet size */
- static char pdata[MAXSTR]; /* area for packet data */
- static char *ppos; /* packet read insert position */
- static int escapemode = 0; /* processing escape character */
- static int escapechar; /* escape character being processed */
- static pchan = -1; /* packet input stream channel */
-
- DO dumptime();
- DO DEBUG("Parse() insize %d\n", insize);
-
- while (insize-- > 0) /* while more data */
- { c = (*inpos++ & 0xFF); /* get next character (don't sign extend) */
- switch (state) /* process according to state */
- { case ST_NULL: /* prepare for new packet */
- DO DEBUG("ST_NULL\n");
- psize = 0; /* clear packet size */
- ppos = pdata; /* start fill at data position */
- pchan = Instream; /* packet channel is current input stream */
- state = ST_STREAM; /* default is stream processing */
-
- case ST_STREAM:
- /* stream keyboard input for layer */
- /* check for escape char with possible high bit on */
- #ifdef DUMPALL
- DO DEBUG("ST_STREAM %x/%x '%c' esc %d insz %d\n",
- c, c & 0x7f, c & 0x7f, escapemode, insize);
- #endif
- if (c == ESCAPE || c == (ESCAPE | 0x80))
- { if (escapemode && c == escapechar) /* previous was ESCAPE */
- /* this is really a single ESCAPE character */
- escapemode = 0; /* back out of ESCAPE mode */
- else
- /* what do we do with back to back esc esc+0x80 ? */
- { /* flag in escape mode */
- escapemode++;
- escapechar = c; /* remember character used for escape */
- continue; /* and continue scan */
- }
- }
- else
- if (escapemode)
- { /* this is the start of a control packet */
- if (psize) /* if we have previous data packet */
- Packet(pchan, psize, pdata); /* finish up previous pkt */
- /* process packet size */
- psize = (c & 0x7f) - '0'; /* save size byte */
- if (psize <= 0 || psize > MAXSTR)
- { /* bad size */
- DO DEBUG("Bad pkt size %d\n", psize);
- break; /* trash this packet */
- }
- rempsize = psize; /* remember this size for later */
- #if 0
- ptimo = rtimo; /* start receive timeout */
- #endif
- escapemode = 0; /* escape mode now off */
- ppos = pdata; /* initialize data store pointer */
- state = ST_PKT; /* expect packet data next */
- continue; /* continue scan */
- }
-
- /* process standard data output character for current stream */
-
- *ppos++ = c; /* save next data character */
-
- if (++psize >= MAXSTR) /* if packet full ... */
- { Packet(pchan, psize, pdata); /* process this packet */
- break; /* end packet processing */
- }
- continue; /* continue scan */
-
- case ST_PKT:
- /* process next paket data byte */
- *ppos++ = c & 0x7f; /* store next data byte */
- #ifdef DUMPALL
- DO DEBUG("ST_PKT: %x '%c' sz %d\n", c & 0x7f, c & 0x7f, psize);
- #endif
- if (--psize != 0)
- continue;
- #if 0
- if (crc((unsigned char *) &rpkt, rpkt.pkt.HEADER_DSIZE+2))
- STATS(Scrcerr); /* communications error */
- else
- #endif
- Packet(0, rempsize, pdata); /* process it */
-
- } /* end build packet switch */
-
- #if 0
- ptimo = 0; /* no more receive timeout */
- #endif
- state = ST_NULL; /* no more receive packet in progress */
-
- } /* end while (insize) */
-
- if (state == ST_STREAM && psize ) /* if we have some data ... */
- { Packet(Instream, psize, pdata); /* process this data */
- #if 0
- ptimo = 0; /* no more receive timeout */
- #endif
- state = ST_NULL; /* no more receive packet in progress */
- }
-
- } /* Parse() */
-
-
- /* Packet() - prcess next input data string or control packet */
- static void
- Packet(chan, size, buff)
- int chan; /* channel (0 if control packet) */
- int size; /* amount of data */
- char *buff; /* pointer to packet data */
- {
- static struct Shape shape; /* Shape structure */
-
- DO dumptime();
- DO DEBUG("Packet(chan %d, size %d, '%.*s')\n", chan, size, size, buff);
-
- /* verify channel */
- if (chan < 0 || chan > MAXPCHAN)
- { DO DEBUG("BAD CHANNEL!!\n");
- return; /* ignore bad channel */
- }
-
- /* if data packet (chan>0) feed data to server */
- if (chan > 0)
- { ReceiveData(chan, buff, size);
- return; /* we are through */
- }
-
- /* control packet (channel 0) */
- chan = buff[1] - '0'; /* assume channel specified */
- if (chan < 0 || chan > MAXPCHAN) /* if invalid ... */
- chan = 0; /* set to zero */
-
- switch (buff[0])
- { case 'I': /* redirect stream */
- DO DEBUG("CMD 'I' redirect stream to %c\n", buff[1]);
- if (size != 2) /* verify size */
- break; /* break if bad */
- if (chan == 0) /* verify channel */
- break; /* break if bad */
- Instream = chan; /* new instream channel */
- return; /* we are through */
-
- case 'A': /* returned A_NEWLAYER packet */
- DO DEBUG("CMD 'A' A_NEWLAYER response %c newchan %c SNresp %d\n",
- buff[2], buff[1], SNresp);
- if (size != 3 + ATTRSIZE)
- break; /* break if bad */
-
- /* if SendNew() not waiting for a response this is invalid */
- if (SNresp != SN_WAITING)
- break; /* break if bad */
-
- if (buff[2] == '1') /* if response is "failed" ... */
- SNresp = -1; /* show -1 response */
- else
- if (buff[2] == '0') /* if response is "success" ... */
- { if (chan == 0) /* if invalid channel */
- break; /* break if bad */
- /* build shape structure for SendNew() */
- if (parseshape(&SNshape, &buff[3]) == -1)
- break; /* if invalid data then bad packet */
- SNresp = 0; /* show good response */
- SNchan = chan; /* indicate channel returned */
- }
- else
- break; /* break if bad */
-
- DO DEBUG("SNresp = %d, SNchan = %d\n", SNresp, SNchan);
- return; /* we are through */
-
- case 'N': /* new layer creation */
- DO DEBUG("CMD 'N' new layer creation newchan %c\n", buff[1]);
- if (size != 2 + ATTRSIZE) /* verify size */
- break; /* break if bad */
- if (chan == 0) /* verify channel */
- break; /* break if bad */
- /* build shape structure */
- if (parseshape(&shape, &buff[2]) == -1)
- break; /* if invalid data then bad packet */
- ReceiveNew(chan, &shape); /* pass to server */
- return; /* packet is done */
-
- case 'D': /* deleted layer */
- DO DEBUG("CMD 'D' deleted layer %c\n", buff[1]);
- if (size != 2) /* verify size */
- break; /* break if bad */
- if (chan == 0) /* verify channel */
- break; /* break if bad */
- ReceiveDelete(chan); /* pass on to server */
- return; /* packet is done */
-
- case 'E': /* exit - awaiting shutdown */
- DO DEBUG("CMD 'E' exit MacLayers awaiting shutdown msg\n");
- if (size != 1) /* verify size */
- break; /* break if bad */
- ReceiveQuit(); /* pass to server */
- /* NOT REACHED*/
- return; /* ?? should never reach here */
-
- case 'R': /* reshaped */
- DO DEBUG("CMD 'R' reshape chan %c\n", buff[1]);
-
- if (size != 2 + ATTRSIZE) /* verify size */
- break; /* break if bad */
-
- if (chan == 0) /* verify channel */
- break; /* break if bad */
-
- /* build shape structure */
- if (parseshape(&shape, &buff[2]) == -1)
- break; /* if invalid data then bad packet */
-
- ReceiveReshape(chan, &shape); /* tell server about shape */
- return; /* packet processed */
-
- case 'S': /* signal */
- DO DEBUG("CMD 'S' SIGNAL chan %c sig %c\n", buff[1], buff[2]);
- if (size != 3) /* verify size */
- break; /* break if bad */
- if (chan == 0)
- break; /* break if bad */
-
- if (buff[2] == '0') /* if SIGINT */
- size = SIGINT; /* yes */
- else
- if (buff[2] == '1') /* if SIGHUP */
- size = SIGHUP; /* yes */
- else
- break; /* invalid signal */
-
- ReceiveSignal(chan, size); /* pass to server */
- return; /* packet processed */
-
- default:
- DO DEBUG("ILLEGAL CONTROL PACKET!!!\n");
- return; /* ignore bad packet */
-
- } /* end command packet switch */
-
- /* switch falls out if bad size or channel for given command */
- DO DEBUG("Invalid size or channel!!!\n"); /* dump error */
- return; /* ignore packet */
-
- } /* Packet() */
-
-
- /* GetData() - read next input from MacLayers stream */
-
- /* The settimeout variable indicates if we return when nothing
- ** is read within a certain amount of seconds. The return code is:
- **
- ** 0 - timeout occured and no data was read
- **
- ** 1 - no timeout occured, data read
- */
- static int
- GetData()
- {
- int result; /* return from read() */
- int i; /* work counter */
- char *ptr; /* work pointer */
-
- DO dumptime();
- DO DEBUG("GetData()\n");
-
- /* if buffer still has data simply return (SHOULD NOT OCCUR?) */
- if (insize > 0)
- { DO DEBUG("early return insize %d\n", insize);
- return ( 1 ); /* act as through data read */
- }
- inpos = inbuff; /* next get will start at beginning */
- insize = 0; /* default insize back to zero */
-
- /* set timeout if we are to do so */
- if (settimeout)
- { DO DEBUG("alarm(%d)\n", settimeout);
- (void) alarm(settimeout); /* set timeout in seconds */
- }
-
- /* do the read from stdin */
- result = read(0, inbuff, IOSIZE);
-
- /* if alarm was set cancel it now */
- if (settimeout)
- { DO DEBUG("alarm(0)\n");
- myalarm(0); /* cancel alarm */
- }
-
- /* check for timeout or error */
- /* EWOULDBLOCK for no data avail -(but we should not see this) */
- /* EINTR if signal stopped the read -(rare but could happen) */
- if (result <= 0)
- { DO DEBUG(" ?? no data result %d\n", result);
- return ( 0 ); /* return nothing read */
- }
-
- /* return with fresh buffer data */
- insize = result;
-
- /* if 7-bit communication channel then strip all high bits */
- if (Sevenbits)
- for (i=result,ptr = inbuff; i>0; --i)
- *ptr++ &= 0x7f; /* strip high bit */
-
- DO DEBUG("read %d bytes\n", insize);
- return ( 1 ); /* return OK code */
-
- } /* GetData() */
-
-
- /* AwaitInput() - wait for more input from MacLayers */
-
- static void
- AwaitInput()
- {
- int r; /* read descriptor bits */
-
- DO dumptime();
- DO DEBUG("AwaitInput() insize %d\n", insize);
-
- /* if buffer has data then don't wait */
- if (insize > 0)
- { DO DEBUG("Return early insize %d\n", insize);
- return;
- }
-
- do
- { r = 1<<0; /* wait for read from input device */
- if (select(32, (fd_set *) &r, (fd_set *) NULL, (fd_set *) NULL,
- (struct timeval *) NULL) == -1) /* if problem waiting ... */
- { if (errno != EINTR) /* if not simply signal taken ... */
- { /* SHOULD NOT OCCUR - shutdown layers */
- DO DEBUG("AwaitInput: select error %d\n", errno);
- printf("layers: AwaitInput: bad select %d\n", errno);
- FQuit(); /* shutdown layers */
- /* NOT REACHED */
- }
- }
- } while ((r & 1<<0) == 0);
-
- } /* AwaitInput() */
-
- /* asciishape() - convert Shape structure to ASCII */
- static void
- asciishape(shape, loc)
- struct Shape *shape; /* Shape structure for channel */
- char *loc; /* location to start filling result */
- {
- char *origloc; /* (for debuggin) */
-
- origloc = loc; /* remember start of string */
- fill4(&loc, shape->worigh); /* origin h */
- fill4(&loc, shape->worigv); /* origin v */
- fill2(&loc, shape->wlines); /* lines high */
- fill2(&loc, shape->wchars); /* chars wide */
- fill1(&loc, shape->wfont); /* font size */
- fill2(&loc, shape->wattr); /* attributes */
-
- DO DEBUG("asciishape(): %.*s\n", ATTRSIZE, origloc);
-
- } /* asciishape() */
-
-
- /* fill4() - convert parameter to ASCII */
-
- static void
- fill4(loc, valu)
- char **loc; /* pointer to fill area pointer */
- unsigned valu; /* value to use */
- {
- fill2(loc, valu>>8); /* fill high half word */
- fill2(loc, valu & 0xff); /* fill low half word */
-
- } /* fill4() */
-
-
- /* fill2() - convert parameter to ASCII */
-
- static void
- fill2(loc, valu)
- char **loc; /* pointer to fill area pointer */
- unsigned valu; /* value to use */
- {
- fill1(loc, valu>>4); /* fill high byte */
- fill1(loc, valu & 0xf); /* fill low byte */
-
- } /* fill2() */
-
-
- /* fill1() - convert parameter to ASCII */
-
- static void
- fill1(loc, valu)
- char **loc; /* pointer to fill area pointer */
- unsigned valu; /* value to use */
- {
- *(*loc)++ = "0123456789ABCDEF"[valu & 0xf]; /* return hex value */
-
- } /* fill1() */
-
-
- /* parseshape() - convert ASCII image to Shape structure */
-
- static int Badconvert; /* indicates bad conversion */
-
- static int
- parseshape(shape, loc)
- struct Shape *shape; /* Shape structure for channel */
- char *loc; /* location to start parsing */
- {
- Badconvert = 0; /* clear bad characters indicator */
- shape->worigh = get4(&loc); /* origin h */
- shape->worigv = get4(&loc); /* origin v */
- shape->wlines = get2(&loc); /* lines high */
- shape->wchars = get2(&loc); /* chars wide */
- shape->wfont = get1(&loc); /* font size */
- shape->wattr = get2(&loc); /* attributes */
-
- DO DEBUG("ParseShape(): origv %d, origh %d, lines %d, chars %d\n",
- shape->worigv, shape->worigh, shape->wlines, shape->wchars);
- DO DEBUG(" font %d, attr 0x%x, badconv %d\n",
- shape->wfont, shape->wattr, Badconvert);
-
- return ( Badconvert ? -1 : 0 ); /* return conversion code */
-
- } /* parseshape() */
-
-
- /* get4() - convert ASCII to parameter */
-
- static unsigned
- get4(loc)
- char **loc; /* pointer to fill area pointer */
- {
- unsigned hi; /* high portion */
- unsigned low; /* low portion */
-
- hi = get2(loc); /* get high byte */
- low = get2(loc); /* get low byte */
-
- return ( (hi<<8) + low ); /* return word value */
-
- } /* get4() */
-
-
- /* get2() - convert ASCII to parameter */
-
- static unsigned
- get2(loc)
- char **loc; /* pointer to fill area pointer */
- {
- unsigned hi; /* high portion */
- unsigned low; /* low portion */
-
- hi = get1(loc); /* get high half */
- low = get1(loc); /* get low half */
-
- return ( (hi<<4) + low ); /* return byte value */
-
- } /* get2() */
-
-
- /* get1() - convert ASCII to parameter */
-
- /* This function sets 'Badconvert' if an invalid character is detected */
-
- static unsigned
- get1(loc)
- char **loc; /* pointer to fill area pointer */
- {
- int c; /* character to convert */
-
- c = *(*loc)++; /* fetch character */
-
- if (c >= '0' && c <= '9')
- /* zero through nine */
- return ( c - '0' ); /* return it's binary value */
-
- if (c >= 'a' && c <= 'f')
- /* lower case hex */
- return ( c - 'a' + 10); /* return it's binary value */
-
- if (c >= 'A' && c <= 'F')
- /* upper case hex */
- return ( c - 'A' + 10); /* return it's binary value */
-
- /* invalid digit! */
- Badconvert++; /* set bad character flag */
- return ( 0 ); /* return a zero */
-
- } /* get1() */
-
-
- /* myscanf() - RAW mode scanf routine */
-
- /** This routine is required because once our terminal is set into RAW mode
- *** the standard scanf routine fails on 7-bit lines whenever a high bit
- *** occurs in an input character. Only the %d, %c and exact input character
- *** images are supported in the input format string. All value parameters
- *** must be integer data type for both %d and %c.
- */
-
- static int
- myscanf(str, arg1, arg2, arg3)
- unsigned char *str; /* scanf input string */
- int *arg1,*arg2,*arg3; /* integer input pointer arguments */
- {
- int numscan = 0; /* items filled in */
- int build; /* %d build integer value */
- int c; /* integer input character */
-
- DO dumptime();
- DO DEBUG("myscanf(%s)\n", str);
-
- /* scan string processing formats */
- while (*str)
- switch (*str)
- { case EOF:
- /* Error: probably our alarm timed out */
- return ( numscan );
- /* NOT REACHED */
-
- case '%':
- /* format specifier */
- switch (*++str)
- { case 'c':
- /* return next character as is */
- if ((build=mygetchar()) == -1)
- return ( numscan ); /* no input, return count */
- break;
-
- case 'd':
- /* build input decimal value */
- build = 0;
- while ((c=mygetchar()) >= '0' && c <= '9')
- { build = build * 10; /* next base ten digit */
- build += c - '0'; /* add this digit */
- }
- myungetc(c); /* return character ending number */
- break;
-
- default:
- return ( numscan ); /* return if error */
- /* NOT REACHED */
- }
-
- /* return value to correct input parameter */
- switch (numscan)
- { case 0:
- *arg1 = build;
- break;
-
- case 1:
- *arg2 = build;
- break;
-
- case 2:
- *arg3 = build;
- break;
-
- default:
- /* SHOULD NOT OCCUR */
- return ( numscan );
- /* NOT REACHED */
- }
-
- numscan++; /* count items scanned */
- str++; /* bump scan string past 'd' */
- break; /* continue scan */
-
- default:
- /* input character must match exactly */
- c = mygetchar();
- if (c != *str)
- return ( numscan ); /* return - we don't match string */
- str++; /* to next character */
-
- } /* end scan string char switch */
-
- /* return number of items scanned */
- return ( numscan );
-
- } /* myscanf() */
-
-
- /* mygetchar() - get character stripped to 7 bits */
-
- /* Return: -1 if timeout
- ** char stripped to 7 bits
- */
-
- static int
- mygetchar()
- {
- int c; /* next input character */
- int result; /* read return value */
-
- DO dumptime();
-
- /* if character still in buffer return it */
- if (insize > 0)
- { insize--; /* count down */
- c = (*inpos++) & 0x7f; /* fetch next char */
- DO DEBUG(" 0x%lx '%c' ", c, c);
- return ( c ); /* return 7-bit character */
- }
-
- /* attempt to read the buffer */
- result = GetData(); /* no timeout (caller may have set) */
-
- /* return -1 if timeout */
- if (result == 0)
- { DO DEBUG(" mygetchar ret -1\n");
- return ( -1 );
- }
-
- return ( mygetchar() ); /* return next character */
-
- #if 0
- c = getchar() & 0x7f; /* insure 7-bit only */
-
- DO DEBUG(" 0x%lx '%c' ", c, c);
- return ( c );
- #endif
-
- } /* mygetchar() */
-
-
- /* myungetc() - unget a character */
-
- /* Must only be called to return when a character was previously fetched */
-
- static void
- myungetc(c)
- int c; /* character to unget */
- {
- DO dumptime();
- DO DEBUG("myungetc(x%lx/%c)\n", c, c);
-
- insize++; /* count back up by one */
- *--inpos = c; /* restore previous character */
-
- } /* myungetc() */
-
-
- /* myalarm() - setup alarm timeout for next read */
-
- static void
- myalarm(time)
- int time; /* time in seconds (or zero) */
- {
- DO dumptime();
- DO DEBUG("myalarm(%d)\n", time);
- settimeout = time; /* set for next read */
-
- } /* myalarm() */
-
- /* dumptime() - print out time in seconds */
-
- /* THIS MAY BE SYSTEM DEPENDENT SO IS BASED UPON DEBUG IFDEF */
- #ifdef DUMPALL
- #include <sys/types.h>
- #include <sys/time.h>
- #endif
-
- static void
- dumptime()
- {
- #ifdef DUMPALL
- time_t seconds;
- static time_t base;
-
- if (base == 0)
- { seconds = 0;
- base = time(NULL);
- }
- else
- seconds = time(NULL) - base;
-
- DO DEBUG("[%3d] ", seconds);
-
- #endif
- } /* dumptime() */
-