home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / amiga / system / unixwind.zoo / uw-server.1of1 < prev    next >
Encoding:
Text File  |  1988-06-23  |  33.3 KB  |  1,315 lines

  1. #    Then run the rest of the file through sh.
  2. #----cut here-----cut here-----cut here-----cut here----#
  3. #!/bin/sh
  4. # shar:    Shell Archiver
  5. #    Run the following text with /bin/sh to create:
  6. #    README
  7. #    Makefile
  8. #    openpty.c
  9. #    uw.c
  10. #    uwtool.c
  11. #    openpty.h
  12. #    uw.h
  13. # This archive created: Mon Jan 25 09:35:02 1988
  14. # By:    Patrick White (PUCC Land, USA)
  15. echo shar: extracting README '(4555 characters)'
  16. cat << \SHAR_EOF > README
  17. The program "uw" is a multiple-window terminal emulator for the
  18. Macintosh(tm) computer.  It is designed for use with a 4.2BSD
  19. UNIX(tm) system.  Up to seven independent windows may be created,
  20. each of which is connected to a pseudo-terminal on the UNIX machine.
  21. A server program which runs on the UNIX host multiplexes the input
  22. and output for these terminal sessions onto a single RS-232 serial
  23. line.
  24.  
  25. UW requires the following:
  26.  
  27.     a Macintosh
  28.     a 4.2BSD UNIX host
  29.     the "uw" program for the Macintosh
  30.     the "uw" server for the UNIX host
  31.     the "uwtool" program for the UNIX host (optional)
  32.     the RAM serial driver (resource SERD, ID=1) (optional)
  33.  
  34. At the present time, UW emulates a Lear Siegler ADM-31 terminal,
  35. a DEC VT52, and a Tektronix 4010.
  36.  
  37. All portions of UW are copyrighted 1985 by John D. Bruner.
  38. Permission to copy is given provided that the copy is not sold
  39. and the copyright notices are included.
  40.  
  41. UW was designed to use the RAM serial driver from the Apple software
  42. supplement.  Since this driver is proprietary Apple software, it is
  43. not distributed with UW.  For this reason, UW will use the ROM
  44. serial driver if the RAM serial driver is not present, and it will
  45. attempt to provide flow control itself.  The flow control provided
  46. in this fashion is not as effective as that which the RAM serial
  47. driver provides, so use of the RAM driver is recommended if it is
  48. available.
  49.  
  50. The distribution includes:
  51.  
  52.     README        - this file
  53.     Makefile    - to be used to compile the 4.2BSD programs
  54.     uw.h        - include file (describes the simple serial protocol)
  55.     uw.c        - source for the 4.2BSD server program
  56.     uwtool.c    - source for a 4.2BSD "tool" program
  57.     openpty.c   - source for a utility routine to find and open pty's
  58.     openpty.h   - include file (describes a structure used by openpty())
  59.     macmouse.ml - mlisp functions for use with (Unipress) Emacs
  60.     uw.hqx        - Binhex 4.0 binary for the Macintosh
  61.     uw.doc.hqx  - Binhex 4.0 MacWrite documentation
  62.  
  63.  
  64. Changes to UW
  65. -------------
  66.  
  67. This is UW version 2.10.  The last distributed version was 1.6.
  68.  
  69. A number of changes have been made to the Macintosh portion of UW.
  70. Some of the more significant ones are
  71.  
  72.     1)    Configuration files:  A number of parameters such as the
  73.     baud rate, parity, number of stop bits, keyboard mapping,
  74.     etc. can be saved to and reloaded from a configuration
  75.     file.
  76.  
  77.     2)    Terminal emulations:  In addition to an ADM31 emulation,
  78.     UW also can emulate the VT52 and Tektronix 4010.  (The
  79.     VT52 emulation is provisional and may be replaced by a
  80.     VT100 emulation in a future version of UW.)  The terminal
  81.     emulation is selectable on a per-window basis.
  82.  
  83.     3)    Clipboard:  Desk accessories may use all of the standard
  84.     clipboard functions.  Text may be copied from a UW window
  85.     onto the clipboard, and text in the clipboard may be
  86.     pasted into a window.
  87.  
  88.     4)    Mouse clicks:  As an alternative to the clipboard, mouse
  89.     (up/down) events within a window may be translated into an
  90.     escape sequence and transmitted as input data to the host.
  91.     This provides a rudimentary facility for (e.g.) EMACS to
  92.     use mouse input.  The use of mouse-to-host or clipboard
  93.     copying is selectable on a per-window basis.
  94.  
  95.     5)    Multiple fonts:  In addition to the standard 9-point Monaco
  96.     font, UW will also use a 7-point font.  The font size is
  97.     selectable on a per-window basis.
  98.  
  99.     6)    Inverse video:  Inverse video was not implemented in the
  100.     previous version of UW.  It is now supported for the ADM31.
  101.  
  102.     7)    Window renaming:  Window titles may be changed (on the
  103.     Macintosh).
  104.  
  105. In conjunction with (4) above, Chris Kent at Purdue (cak@purdue)
  106. has written mlisp code for Goslings Emacs which interprets the
  107. mouse-event encoding that UW can optionally provide.  He has
  108. given his permission for his file "macmouse.ml" to be included
  109. in this distribution.
  110.  
  111. There are no changes in the Mac-host interface (although some plans
  112. are being made in this area).  Thus, one of the most-requested
  113. features, file transfer, is not implemented (yet).
  114.  
  115. Of course, bugs in the previous version have been fixed (most notably
  116. some that dealt with scrolling).  Almost certainly new bugs have been
  117. introduced to take the place of those which were expunged.
  118.  
  119. Since some of the changes are rather significant (and a couple,
  120. like the method of selecting text to copy to the clipboard, are
  121. slightly non-standard), the updated documentation is recommended
  122. reading for all UW users.
  123.  
  124. UW is much larger than it was before.  Extensive use of the
  125. Tektronix 4010 emulation will almost certainly exhaust memory
  126. on a 128K Macintosh.
  127. SHAR_EOF
  128. if test 4555 -ne "`wc -c README`"
  129. then
  130. echo shar: error transmitting README '(should have been 4555 characters)'
  131. fi
  132. echo shar: extracting Makefile '(156 characters)'
  133. cat << \SHAR_EOF > Makefile
  134. CC    =    /bin/cc
  135. CFLAGS    =    -O
  136.  
  137. all:        uw uwtool
  138.  
  139. uw:        uw.o openpty.o
  140.     $(CC) -o uw uw.o openpty.o
  141.  
  142. uwtool:        uwtool.o openpty.o
  143.     $(CC) -o uwtool uwtool.o openpty.o
  144. SHAR_EOF
  145. if test 156 -ne "`wc -c Makefile`"
  146. then
  147. echo shar: error transmitting Makefile '(should have been 156 characters)'
  148. fi
  149. echo shar: extracting openpty.c '(3914 characters)'
  150. cat << \SHAR_EOF > openpty.c
  151. /*
  152.  *    openpty - open a pseudo-terminal
  153.  *
  154.  * The first time that the routine is called, the device directory is
  155.  * searched and a list of all candidate pseudo-terminals is compiled.
  156.  * Candidates are defined to be those entries in "/dev" whose names
  157.  * (1) are the same length as PTY_PROTO and (2) start with the
  158.  * initial string PTY_PREFIX.  Further, the master and slave sides
  159.  * must both exist.
  160.  *
  161.  * openpty() attempts to find an unused pseudo-terminal from the list
  162.  * of candidates.  If one is found, the master and slave sides are
  163.  * opened and the file descriptors and names of these two devices are
  164.  * returned in a "ptydesc" structure.  (The address of this structure
  165.  * is supplied by the caller.  Zero is returned if openpty() was
  166.  * successful, -1 is returned if no pty could be found.
  167.  */
  168.  
  169. #include <sys/types.h>
  170. #include <sys/dir.h>
  171. #include <fcntl.h>
  172. #include <strings.h>
  173. #include "openpty.h"
  174.  
  175. #define    DEV_DIR        "/dev"        /* directory where devices live */
  176. #define    PT_INDEX    (sizeof DEV_DIR)    /* location of 'p' in "pty" */
  177.  
  178. #define    PTY_PROTO    "ptyp0"        /* prototype for pty names */
  179. #define    PTY_PREFIX    "pty"        /* prefix required for name of pty */
  180.  
  181. struct ptyinfo {
  182.     struct ptyinfo    *pi_next;
  183.     char        *pi_pty;
  184.     char        *pi_tty;
  185. };
  186.  
  187. static struct ptyinfo *ptylist;
  188.  
  189. extern char *malloc();
  190.  
  191. static
  192. char *
  193. devname(name)
  194. char *name;
  195. {
  196.     register char *fullname;
  197.  
  198.     /*
  199.      * Construct the full name of a device in DEV_DIR.  Returns
  200.      * NULL if it failed (because malloc() failed).
  201.      */
  202.  
  203.     fullname = malloc((unsigned)(sizeof DEV_DIR + 1 + strlen(name)));
  204.     if (fullname != NULL) {
  205.         (void)strcpy(fullname, DEV_DIR);
  206.         (void)strcat(fullname, "/");
  207.         (void)strcat(fullname, name);
  208.     }
  209.     return(fullname);
  210. }
  211.  
  212. static
  213. isapty(dp)
  214. struct direct *dp;
  215. {
  216.     static struct ptyinfo *pi;
  217.  
  218.     /*
  219.      * We don't care about the gory details of the directory entry.
  220.      * Instead, what we really want is an array of pointers to
  221.      * device names (with DEV_DIR prepended).  Therefore, we create
  222.      * this array ourselves and tell scandir() to ignore every
  223.      * directory entry.
  224.      *
  225.      * If malloc() fails, the current directory entry is ignored.
  226.      */
  227.  
  228.     if (pi == NULL &&
  229.         (pi = (struct ptyinfo *)malloc((unsigned)sizeof *pi)) == NULL)
  230.         return(0);
  231.         
  232.     if (strlen(dp->d_name) == sizeof PTY_PROTO - 1 &&
  233.         strncmp(dp->d_name, PTY_PREFIX, sizeof PTY_PREFIX - 1) == 0) {
  234.         pi->pi_pty = devname(dp->d_name);
  235.         if (pi->pi_pty == NULL)
  236.             return(0);
  237.         pi->pi_tty = malloc((unsigned)(strlen(pi->pi_pty) + 1));
  238.         if (pi->pi_tty == NULL) {
  239.             free(pi->pi_pty);
  240.             return(0);
  241.         }
  242.         (void)strcpy(pi->pi_tty, pi->pi_pty);
  243.         pi->pi_tty[PT_INDEX] = 't';
  244.         if (access(pi->pi_pty, 0) == 0 && access(pi->pi_tty, 0) == 0) {
  245.             pi->pi_next = ptylist;
  246.             ptylist = pi;
  247.             pi = NULL;
  248.         } else {
  249.             free(pi->pi_pty);
  250.             free(pi->pi_tty);
  251.         }
  252.     }
  253.     return(0);
  254. }
  255.  
  256. openpty(pt)
  257. struct ptydesc *pt;
  258. {
  259.     register struct ptyinfo *pi;
  260.     static int fail;
  261.     auto struct direct **dirlist;
  262.     extern char *re_comp();
  263.     extern int alphasort();
  264.  
  265.     /*
  266.      * If the regular expression PTY_PROTO is bad, scandir() fails, or
  267.      * no possible pty's are found, then "fail" is set non-zero.  If
  268.      * "fail" is non-zero then the routine bombs out immediately.
  269.      * Otherwise, the list of candidates is examined starting with the
  270.      * entry following the last one chosen.
  271.      */
  272.  
  273.     if (fail)
  274.         return(-1);
  275.  
  276.     if (!ptylist) {        /* first time */
  277.         if (scandir(DEV_DIR, &dirlist, isapty, alphasort) < 0 ||
  278.             ptylist == NULL) {
  279.             fail = 1;
  280.             return(-1);
  281.         }
  282.         for (pi=ptylist; pi->pi_next; pi=pi->pi_next)
  283.             ;
  284.         pi->pi_next = ptylist;    /* make the list circular */
  285.     }
  286.  
  287.     pi = ptylist;
  288.     do {
  289.         if ((pt->pt_pfd = open(pi->pi_pty, O_RDWR)) >= 0) {
  290.             if ((pt->pt_tfd = open(pi->pi_tty, O_RDWR)) >= 0) {
  291.                 ptylist = pi->pi_next;
  292.                 pt->pt_pname = pi->pi_pty;
  293.                 pt->pt_tname = pi->pi_tty;
  294.                 return(0);
  295.             } else
  296.                 (void)close(pt->pt_pfd);
  297.         }
  298.         pi = pi->pi_next;
  299.     } while (pi != ptylist);
  300.     return(-1);
  301. }
  302. SHAR_EOF
  303. if test 3914 -ne "`wc -c openpty.c`"
  304. then
  305. echo shar: error transmitting openpty.c '(should have been 3914 characters)'
  306. fi
  307. echo shar: extracting uw.c '(17598 characters)'
  308. cat << \SHAR_EOF > uw.c
  309. #
  310.  
  311. /*
  312.  *    uw - UNIX windows program for the Macintosh (VAX end)
  313.  *
  314.  * Copyright 1985 by John D. Bruner.  All rights reserved.  Permission to
  315.  * copy this program is given provided that the copy is not sold and that
  316.  * this copyright notice is included.
  317.  */
  318.  
  319. #include <sys/types.h>
  320. #include <sys/stat.h>
  321. #include <sys/socket.h>
  322. #include <sys/ioctl.h>
  323. #include <sys/wait.h>
  324. #include <sys/time.h>
  325. #include <sys/resource.h>
  326. #include <sys/uio.h>
  327. #include <signal.h>
  328. #include <setjmp.h>
  329. #include <errno.h>
  330. #include <fcntl.h>
  331. #include <strings.h>
  332. #include <stdio.h>
  333. #include "uw.h"
  334. #include "openpty.h"
  335.  
  336. #define    MAXENV    128            /* maximum environment size */
  337.  
  338. #define    W_IN    0
  339. #define    W_OUT    1
  340.  
  341. #define    XON    0021            /* ASCII XON */
  342. #define    XOFF    0023            /* ASCII XOFF */
  343. #define    RUB    0177            /* ASCII RUBOUT */
  344.  
  345. #define    META    0200            /* "meta" bit for whatever it's worth */
  346.  
  347. #define    RCV_OK    (-1)            /* see recvcmd() */
  348. #define    RCV_META (-2)            /* see recvcmd() */
  349.  
  350. #ifndef FD_SET
  351. #define    FD_SET(n,p)    ((p)->fds_bits[0] |= (1 << (n)))
  352. #define    FD_CLR(n,p)    ((p)->fds_bits[0] &= ~(1 << (n)))
  353. #define    FD_ISSET(n,p)    ((p)->fds_bits[0] & (1 << (n)))
  354. #define    FD_ZERO(p)    ((p)->fds_bits[0] = 0)
  355. #endif
  356.  
  357. typedef int fildes_t;            /* file descriptor data type */
  358. typedef int nwin_t;            /* window index data type */
  359.  
  360. struct window {
  361.     fildes_t    w_fd;
  362.     char        w_tty[32];
  363. };
  364.  
  365. struct window window[NWINDOW];        /* window data structures */
  366. struct window **fdmap;            /* mapping from fd's to windows */
  367. struct window *curwin[2];        /* current input and output windows */
  368. fildes_t nfds;                /* number of file descriptors */
  369.  
  370. char portal[] = "/tmp/uwXXXXXX";    /* UNIX-domain network address */
  371.  
  372.  
  373. /* The following are added to the environment of all child processes */
  374.  
  375. char env_uwin[64] = "UWIN=";
  376. char *env[] = { 
  377.     env_uwin,
  378.     "TERM=adm31",
  379.     "TERMCAP=adm31:cr=^M:do=^J:nl=^J:al=\\EE:am:le=^H:bs:ce=\\ET:cm=\\E=%+ %+ :cl=^Z:cd=\\EY:co#80:dc=\\EW:dl=\\ER:ei=\\Er:ho=^^:im=\\Eq:li#24:mi:nd=^L:up=^K:MT:km:so=\\EG1:se=\\EG0:",
  380.     NULL
  381. };
  382.  
  383. int ctlch[] = { -1, IAC, XON, XOFF, -1, -1, -1, -1 };    /* CTL char mapping */
  384.  
  385. struct selmask {
  386.     struct fd_set    sm_rd;
  387.     struct fd_set    sm_wt;
  388.     struct fd_set    sm_ex;
  389. } selmask[2];
  390.  
  391. extern char *mktemp();
  392. extern char *getenv();
  393. extern char *malloc();
  394. extern done(), cwait();
  395. extern int errno;
  396.  
  397. main(argc, argv)
  398. char **argv;
  399. {
  400.     register fildes_t fd, sd;
  401.     register struct window *w;
  402.     struct sockaddr sa;
  403.  
  404.     /*
  405.      * Make sure we don't accidentally try to run this inside itself.
  406.      */
  407.     if (getenv("UWIN")) {
  408.         fprintf(stderr, "%s is already running\n", *argv);
  409.         exit(1);
  410.     }
  411.  
  412.     /*
  413.      * Close all file descriptors except 0, 1, and 2.
  414.      */
  415.     nfds = getdtablesize();
  416.     for (fd=3; fd < nfds; fd++)
  417.         (void)close(fd);
  418.  
  419.     /*
  420.      * Allocate "fdmap".  We can't do this at compile time because
  421.      * we get the number of file descriptors from getdtablesize().
  422.      */
  423.     if (!(fdmap=(struct window **)malloc(nfds*sizeof(struct window *)))) {
  424.         fprintf(stderr, "cannot allocate 'fdmap' array\n");
  425.         exit(1);
  426.     }
  427.  
  428.     /*
  429.      * Mark all windows closed.
  430.      */
  431.  
  432.     for (w=window; w < window+NWINDOW; w++)
  433.         w->w_fd = -1;
  434.  
  435.  
  436.     /*
  437.      * Create a UNIX-domain network address, and put its name into
  438.      * the environment so that descendents can contact us with new
  439.      * window requests.
  440.      */
  441.  
  442.     (void)strncat(env_uwin, mktemp(portal), sizeof env_uwin - 1);
  443.     setenv(env);
  444.  
  445.     if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
  446.         perror("socket");
  447.         exit(1);
  448.     }
  449.     sa.sa_family = AF_UNIX;
  450.     (void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1);
  451.     sa.sa_data[sizeof sa.sa_data-1] = '\0';
  452.     if (bind(sd, &sa, sizeof sa.sa_family + strlen(sa.sa_data)) < 0) {
  453.         perror("bind");
  454.         exit(1);
  455.     }
  456.     if (fcntl(sd, F_SETFL, FNDELAY))
  457.         perror("fcntl(sd, F_SETFL, FNDELAY)");
  458.  
  459.  
  460.     /*
  461.      * Ignore interrupts, quits, and terminal stops.  Clean up and exit
  462.      * if a hangup or termination is received.  Also catch changes in
  463.      * child status (so that we can wait for them).  Set up the terminal
  464.      * modes.
  465.      */
  466.  
  467.     (void)signal(SIGHUP, done);
  468.     (void)signal(SIGINT, SIG_IGN);
  469.     (void)signal(SIGQUIT, SIG_IGN);
  470.     (void)signal(SIGTERM, done);
  471.     (void)signal(SIGTSTP, SIG_IGN);
  472.     (void)signal(SIGCHLD, cwait);
  473.  
  474.     tmode(1);
  475.  
  476.  
  477.     /*
  478.      * Tell the Macintosh to initialize.  Initialize the current input
  479.      * and output windows to NULL.
  480.      */
  481.  
  482.     xmitcmd(CB_FN_MAINT|CB_MF_ENTRY);
  483.     curwin[W_IN] = curwin[W_OUT] = NULL;
  484.  
  485.     
  486.     /*
  487.      * Initialize the "select" masks, create window 1 (to start
  488.      * things off) and wait for input.  When input is available,
  489.      * process it.
  490.      */
  491.  
  492.     FD_ZERO(&selmask[0].sm_rd);
  493.     FD_ZERO(&selmask[0].sm_wt);
  494.     FD_ZERO(&selmask[0].sm_ex);
  495.  
  496.     FD_SET(0, &selmask[0].sm_rd);
  497.     FD_SET(sd, &selmask[0].sm_rd);
  498.  
  499.     if (newwind(window) == 0)
  500.         xmitcmd(CB_FN_NEWW|1);
  501.  
  502.     while (1) {
  503.         selmask[1] = selmask[0];
  504.         if (select(nfds, &selmask[1].sm_rd, &selmask[1].sm_wt,
  505.             &selmask[1].sm_ex, (struct timeval *)0) < 0) {
  506.             if (errno == EINTR)
  507.                 continue;
  508.             perror("select");
  509.             done(1);    /* for now -- fix this! */
  510.         }
  511.         for (fd=0; fd < nfds; fd++) {
  512.             if (FD_ISSET(fd, &selmask[1].sm_rd)) {
  513.                 if (fd < 2)
  514.                     mrecv();
  515.                 else if (fd == sd)
  516.                     netrecv(sd);
  517.                 else
  518.                     mxmit(fd);
  519.             }
  520.         }
  521.     }
  522. }
  523.  
  524. mrecv()
  525. {
  526.     register int len;
  527.     register char *cp, *cq;
  528.     auto int nready;
  529.     char ibuf[512], obuf[512];
  530.     static int seen_iac, seen_meta;
  531.  
  532.     /*
  533.      * The received bytestream is examined.  Non-command bytes are
  534.      * written to the file descriptor corresponding to the current
  535.      * "input" window (relative to the Macintosh -- the window the
  536.      * user types input to).
  537.      */
  538.  
  539.     if (ioctl(0, (int)FIONREAD, (char *)&nready) < 0) {
  540.         perror("FIONREAD");
  541.         return;
  542.     }
  543.  
  544.     cq = obuf;
  545.     while (nready > 0) {
  546.         if (nready > sizeof ibuf)
  547.             len = read(0, ibuf, sizeof ibuf);
  548.         else
  549.             len = read(0, ibuf, nready);
  550.         if (len <= 0) {
  551.             perror("read");
  552.             return;
  553.         }
  554.         for (cp=ibuf; cp < ibuf+len; cp++) {
  555.             if (seen_iac) {
  556.                 if ((*cp&CB_DIR) == CB_DIR_MTOH) {
  557.                     if (cq > obuf) {
  558.                         (void)write(curwin[W_IN]->w_fd,
  559.                                 obuf, cq-obuf);
  560.                         cq = obuf;
  561.                     }
  562.                     switch (*cq = recvcmd(*cp)) {
  563.                     case RCV_OK:
  564.                         break;
  565.                     case RCV_META:
  566.                         seen_meta = 1;
  567.                         break;
  568.                     default:
  569.                         if (seen_meta) {
  570.                             seen_meta = 0;
  571.                             *cq |= META;
  572.                         }
  573.                         if (curwin[W_IN])
  574.                             cq++;
  575.                         break;
  576.                     }
  577.                 }
  578.                 seen_iac = 0;
  579.             } else if (*cp == IAC)
  580.                 seen_iac++;
  581.             else if (curwin[W_IN]) {
  582.                 if (seen_meta) {
  583.                     seen_meta = 0;
  584.                     *cq++ = *cp|META;
  585.                 } else
  586.                     *cq++ = *cp;
  587.                 if (cq >= obuf+sizeof obuf) {
  588.                     (void)write(curwin[W_IN]->w_fd,
  589.                             obuf, cq-obuf);
  590.                     cq = obuf;
  591.                 }
  592.             }
  593.         }
  594.         nready -= len;
  595.     }
  596.     if (cq > obuf)
  597.         (void)write(curwin[W_IN]->w_fd, obuf, cq-obuf);
  598. }
  599.  
  600. recvcmd(cmd)
  601. char cmd;
  602. {
  603.     register int nwin, fn;
  604.     register struct window *w;
  605.  
  606.     /*
  607.      * Perform the function the Mac is asking for.  There are three
  608.      * broad categories of these functions: RCV_META, which tells
  609.      * the caller that the next character is a "meta" character;
  610.      * an ASCII data character, which is passed back to the caller
  611.      * for proper handling; and RCV_OK, which means that this routine
  612.      * has done everything which was required to process the command.
  613.      */
  614.  
  615.     fn = cmd&CB_FN;
  616.     switch (fn) {
  617.     case CB_FN_NEWW:
  618.     case CB_FN_KILLW:
  619.     case CB_FN_ISELW:
  620.         nwin = cmd&CB_WINDOW;
  621.         if (!nwin)
  622.             break;
  623.         w = &window[nwin-1];
  624.  
  625.         switch (fn) {
  626.         case CB_FN_NEWW:
  627.             if (w->w_fd < 0 && newwind(w) < 0)
  628.                 xmitcmd(CB_FN_KILLW|nwin);
  629.             break;
  630.  
  631.         case CB_FN_KILLW:
  632.             killwind(w, 0);
  633.             break;
  634.  
  635.         case CB_FN_ISELW:
  636.             if (w->w_fd >= 0)
  637.                 curwin[W_IN] = w;
  638.             break;
  639.         }
  640.         break;
  641.  
  642.     case CB_FN_META:
  643.         return(RCV_META);
  644.  
  645.     case CB_FN_CTLCH:
  646.         return(ctlch[cmd&CB_CC]);
  647.  
  648.     case CB_FN_MAINT:
  649.         if ((cmd&CB_MF) == CB_MF_EXIT)
  650.             done(0);
  651.         /*NOTREACHED*/
  652.     }
  653.     return(RCV_OK);
  654. }
  655.  
  656. xmitcmd(cmd)
  657. char cmd;
  658. {
  659.     static char cmdbuf[2] = { IAC, '\0' };
  660.  
  661.     /*
  662.      * Transmit the command "cmd" to the Macintosh.  The byte is ORed
  663.      * with the host-to-Mac direction indicator.
  664.      */
  665.  
  666.     cmdbuf[1] = cmd|CB_DIR_HTOM;
  667.     (void)write(1, cmdbuf, sizeof cmdbuf);
  668. }
  669.  
  670. netrecv(sd)
  671. register fildes_t sd;
  672. {
  673.     register struct window *w;
  674.     register int cnt;
  675.     struct msghdr msg;
  676.     auto int fd;
  677.     struct iovec iov;
  678.     struct stat st1, st2;
  679.     static int unity = 1;
  680.     char buf[256];
  681.  
  682.  
  683.     /*
  684.      * main() calls this routine when there is a message waiting on
  685.      * the UNIX-domain socket.  The message's access rights are
  686.      * expected to contain the file descriptor for the "master" side
  687.      * of a pseudo-tty.  The message contains the name of the pty.
  688.      * The sender is expected to start up a process on the slave side
  689.      * of the pty.  This allows the host end to create windows which
  690.      * run something other than the shell.
  691.      */
  692.  
  693.     fd = -1;
  694.  
  695.     iov.iov_base = (caddr_t)buf;
  696.     iov.iov_len = sizeof buf - 1;
  697.  
  698.     msg.msg_name = (caddr_t)0;
  699.     msg.msg_namelen = 0;
  700.     msg.msg_iov = &iov;
  701.     msg.msg_iovlen = 1;
  702.     msg.msg_accrights = (caddr_t)&fd;
  703.     msg.msg_accrightslen = sizeof fd;
  704.  
  705.     if ((cnt=recvmsg(sd, &msg, 0)) < 0)
  706.         perror("recvmsg");
  707.  
  708.     if (msg.msg_accrightslen > 0 && fd >= 0) {
  709.         /*
  710.          * We can't trust the process which connected to us, so
  711.          * we verify that it really passed us a pseudo-tty's
  712.          * file descriptor by checking the device name and its
  713.          * inode number.  [Of course, if someone else wants to
  714.          * hand us a terminal session running under their uid....]
  715.          */
  716.         buf[cnt] = 0;
  717.         if (strncmp(buf, "/dev/pty", sizeof "/dev/pty" - 1) ||
  718.             fstat(fd, &st1) < 0 || stat(buf, &st2) < 0 ||
  719.             st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
  720.             (void)close(fd);
  721.             return;
  722.         }
  723.         /*
  724.          * OK, we believe the sender.  We allocate a window and
  725.          * tell the Macintosh to create that window on its end.
  726.          */
  727.         buf[5] = 't';        /* switch to "/dev/ttyp?" */
  728.         for (w=window; w < window+NWINDOW; w++) {
  729.             if (w->w_fd < 0) {
  730.                 w->w_fd = fd;
  731.                 fdmap[fd] = w;
  732.                 FD_SET(fd, &selmask[0].sm_rd);
  733.                 (void)strncpy(w->w_tty, buf, sizeof w->w_tty-1);
  734.                 xmitcmd(CB_FN_NEWW|(w-window+1));
  735.                 break;
  736.             }
  737.         }
  738.         /*
  739.          * If we have no free windows, then we close the file
  740.          * descriptor (which will terminate the slave process).
  741.          */
  742.         if (w == window+NWINDOW)
  743.             (void)close(fd);
  744.         /*
  745.          * Set non-blocking I/O on the master side.
  746.          */
  747.         (void)ioctl(fd, (int)FIONBIO, (char *)&unity);
  748.     }
  749. }
  750.  
  751. mxmit(fd)
  752. register fildes_t fd;
  753. {
  754.     register char *cp, *cq, i;
  755.     register int len;
  756.     char ibuf[32], obuf[32];
  757.  
  758.     /*
  759.      * Copy input from file "fd" to the Macintosh.  Be sure to convert
  760.      * any embedded IAC characters.
  761.      *
  762.      * Note that the input/output buffers should NOT be very large.
  763.      * It is undesirable to perform large reads and effectively
  764.      * "lock out" all other file descriptors.  The chosen size
  765.      * should preserve a reasonable amount of efficiency.
  766.      */
  767.  
  768.     if (fdmap[fd]) {
  769.         curwin[W_OUT] = fdmap[fd];
  770.         xmitcmd(CB_FN_OSELW|(fdmap[fd]-window+1));
  771.         cq = obuf;
  772.         if ((len = read(fd, ibuf, sizeof ibuf)) < 0 &&
  773.             errno != EWOULDBLOCK) {
  774.             killwind(fdmap[fd], 1);
  775.             return;
  776.         }
  777.         for (cp=ibuf; cp < ibuf+len; cp++) {
  778.             if (*cp&META) {
  779.                 if (cq > obuf) {
  780.                     (void)write(1, obuf, cq-obuf);
  781.                     cq = obuf;
  782.                 }
  783.                 xmitcmd(CB_FN_META);
  784.                 *cp &= ~META;
  785.             }
  786.             i = -1;
  787.             if (*cp == RUB || *cp < ' ') {
  788.                 i = sizeof ctlch;
  789.                 while (i >= 0 && ctlch[i] != *cp)
  790.                     i--;
  791.             }
  792.             if (i >= 0) {
  793.                 if (cq > obuf) {
  794.                     (void)write(1, obuf, cq-obuf);
  795.                     cq = obuf;
  796.                 }
  797.                 xmitcmd(CB_FN_CTLCH|i);
  798.             } else {
  799.                 *cq++ = *cp;
  800.                 if (cq >= obuf+sizeof obuf) {
  801.                     (void)write(1, obuf, cq-obuf);
  802.                     cq = obuf;
  803.                 }
  804.             }
  805.         }
  806.     } else
  807.         (void)read(fd, ibuf, sizeof ibuf);
  808.     if (cq > obuf)
  809.         (void)write(1, obuf, cq-obuf);
  810. }
  811.  
  812. killwind(w, notify)
  813. register struct window *w;
  814. {
  815.     /*
  816.      * Kill window "w".  Notify the Macintosh that it is gone if
  817.      * "notify" is nonzero.
  818.      */
  819.  
  820.     FD_CLR(w->w_fd, &selmask[0].sm_rd);
  821.     FD_CLR(w->w_fd, &selmask[0].sm_wt);
  822.     FD_CLR(w->w_fd, &selmask[0].sm_ex);
  823.     (void)close(w->w_fd);
  824.     fdmap[w->w_fd] = NULL;
  825.     w->w_fd = -1;
  826.     if (curwin[W_IN] == w)
  827.         curwin[W_IN] = NULL;
  828.     if (curwin[W_OUT] == w)
  829.         curwin[W_OUT] = NULL;
  830.     if (notify)
  831.         xmitcmd(CB_FN_KILLW|(w-window+1));
  832. }
  833.  
  834. newwind(w)
  835. register struct window *w;
  836. {
  837.     register int pid;
  838.     register char *shell;
  839.     register int fd;
  840.     auto struct ptydesc pt;
  841.     static int unity = 1;
  842.     extern char *getenv();
  843.  
  844.     /*
  845.      * Create a new window using "w".
  846.      */
  847.  
  848.     if (openpty(&pt) < 0)
  849.         return(-1);    /* better recovery is needed */
  850.  
  851.     (void)ioctl(pt.pt_pfd, (int)FIONBIO, (char *)&unity);
  852.     fdmap[pt.pt_pfd] = w;
  853.     w->w_fd = pt.pt_pfd;
  854.     FD_SET(pt.pt_pfd, &selmask[0].sm_rd);
  855.     (void)strncpy(w->w_tty, pt.pt_tname, sizeof w->w_tty);
  856.  
  857.     /*
  858.      * We must spawn a new process with fork(), not vfork(), because
  859.      * some implementations (e.g. Sun UNIX) manipulate static
  860.      * variables within the signal() subroutine.  If we vfork()
  861.      * the parent will die when the first SIGCHLD arrives.  The
  862.      * data+bss size is fairly small, so this isn't too expensive.
  863.      */
  864.     while ((pid=fork()) < 0)
  865.         sleep(5);
  866.     if (!pid) {
  867.         (void)signal(SIGHUP, SIG_DFL);
  868.         (void)signal(SIGINT, SIG_DFL);
  869.         (void)signal(SIGQUIT, SIG_DFL);
  870.         (void)signal(SIGTERM, SIG_DFL);
  871.         (void)signal(SIGTSTP, SIG_IGN);
  872.         (void)signal(SIGCHLD, SIG_DFL);
  873.         (void)ioctl(open("/dev/tty",O_RDWR), (int)TIOCNOTTY, (char *)0);
  874.         (void)close(open(pt.pt_tname, O_RDONLY)); /* set new ctrl tty */
  875.         (void)setuid(getuid());        /* shouldn't need this */
  876.         if (!(shell = getenv("SHELL")))
  877.             shell = "/bin/sh";
  878.         (void)dup2(pt.pt_tfd, 0);
  879.         (void)dup2(0, 1);
  880.         (void)dup2(0, 2);
  881.         for (fd=3; fd < nfds; fd++)
  882.             (void)close(fd);
  883.         tmode(0);    /* HACK! */
  884.         execl(shell, shell, (char *)0);
  885.         _exit(1);
  886.     }
  887.  
  888.     (void)close(pt.pt_tfd);
  889.     return(0);
  890. }
  891.  
  892. tmode(f)
  893. {
  894.     static struct sgttyb ostty, nstty;
  895.     static struct tchars otchars, ntchars;
  896.     static struct ltchars oltchars, nltchars;
  897.     static int olmode, nlmode;
  898.     static saved;
  899.  
  900.     /*
  901.      * This routine either saves the current terminal modes and then
  902.      * sets up the terminal line or resets the terminal modes (depending
  903.      * upon the value of "f").  The terminal line is used in "cbreak"
  904.      * mode with all special characters except XON/XOFF disabled.  The
  905.      * hated (by me) LDECCTQ mode is required for the Macintosh to
  906.      * handle flow control properly.
  907.      */
  908.  
  909.     if (f == 1) {
  910.         if (ioctl(0, (int)TIOCGETP, (char *)&ostty) < 0) {
  911.             perror("ioctl((int)TIOCGETP)");
  912.             done(1);
  913.         }
  914.         if (ioctl(0, (int)TIOCGETC, (char *)&otchars) < 0) {
  915.             perror("ioctl((int)TIOCGETC)");
  916.             done(1);
  917.         }
  918.         if (ioctl(0, (int)TIOCGLTC, (char *)&oltchars) < 0) {
  919.             perror("ioctl((int)TIOCGLTC)");
  920.             done(1);
  921.         }
  922.         if (ioctl(0, (int)TIOCLGET, (char *)&olmode) < 0) {
  923.             perror("ioctl((int)TIOCLGET)");
  924.             done(1);
  925.         }
  926.         nstty = ostty;
  927.         nstty.sg_erase = nstty.sg_kill = -1;
  928.         nstty.sg_flags |= CBREAK|TANDEM;
  929.         nstty.sg_flags &= ~(RAW|CRMOD|ECHO|LCASE|XTABS);
  930.         ntchars.t_intrc = ntchars.t_quitc = -1;
  931.         ntchars.t_eofc = ntchars.t_brkc = -1;
  932.         ntchars.t_startc = XON;
  933.         ntchars.t_stopc = XOFF;
  934.         nltchars.t_suspc = nltchars.t_dsuspc = -1;
  935.         nltchars.t_rprntc = nltchars.t_flushc = -1;
  936.         nltchars.t_werasc = nltchars.t_lnextc = -1;
  937.         nlmode = olmode | LDECCTQ;
  938.         if (ioctl(0, (int)TIOCSETN, (char *)&nstty) < 0) {
  939.             perror("ioctl((int)TIOCSETN)");
  940.             done(1);
  941.         }
  942.         if (ioctl(0, (int)TIOCSETC, (char *)&ntchars) < 0) {
  943.             perror("ioctl((int)TIOCSETC");
  944.             done(1);
  945.         }
  946.         if (ioctl(0, (int)TIOCSLTC, (char *)&nltchars) < 0) {
  947.             perror("ioctl((int)TIOCSLTC");
  948.             done(1);
  949.         }
  950.         if (ioctl(0, (int)TIOCLSET, (char *)&nlmode) < 0) {
  951.             perror("ioctl((int)TIOCLSET)");
  952.             done(1);
  953.         }
  954.         saved = 1;
  955.     } else if (saved) {
  956.         (void)ioctl(0, (int)TIOCSETP, (char *)&ostty);
  957.         (void)ioctl(0, (int)TIOCSETC, (char *)&otchars);
  958.         (void)ioctl(0, (int)TIOCSLTC, (char *)&oltchars);
  959.         (void)ioctl(0, (int)TIOCLSET, (char *)&olmode);
  960.     }
  961. }
  962.  
  963. done(s)
  964. {
  965.     register fildes_t fd;
  966.  
  967.     /*
  968.      * Clean up and exit.  It is overkill to close all of the file
  969.      * descriptors, but it causes no harm.  After we are sure that
  970.      * our UNIX-domain network connection is closed we remove the
  971.      * entry that it created (as a side effect) in the filesystem.
  972.      *
  973.      * We also restore the terminal modes.
  974.      */
  975.     
  976.     /*xmitcmd(CB_FN_MAINT|CB_MF_EXIT);*/
  977.     for (fd=3; fd < nfds; fd++)
  978.         (void)close(fd);
  979.     (void)unlink(portal);
  980.     tmode(0);
  981.     exit(s);
  982. }
  983.  
  984. cwait()
  985. {
  986.     union wait status;
  987.     struct rusage rusage;
  988.  
  989.     /*
  990.      * Collect dead children.  We don't use the information that
  991.      * wait3() returns.  (Someday we might.)
  992.      */
  993.     
  994.     while (wait3(&status, WNOHANG, &rusage) > 0)
  995.         ;
  996. }
  997.  
  998.  
  999. static char *earray[MAXENV+1];
  1000.  
  1001. setenv(env)
  1002. char **env;
  1003. {
  1004.     register char **ep1, **ep2, *cp;
  1005.     char **ep3;
  1006.     extern char **environ;
  1007.  
  1008.  
  1009.     /*
  1010.      * Merge the set of environment strings in "env" into the
  1011.      * environment.
  1012.      */
  1013.  
  1014.     /*
  1015.      * The first time through, copy the environment from its
  1016.      * original location to the array "earray".  This makes it a
  1017.      * little easier to change things.
  1018.      */
  1019.  
  1020.     if (environ != earray){
  1021.         ep1=environ;
  1022.         ep2=earray;
  1023.         while(*ep1 && ep2 <= earray+MAXENV)
  1024.             *ep2++ = *ep1++;
  1025.         *ep2++ = NULL;
  1026.         environ = earray;
  1027.     }
  1028.  
  1029.  
  1030.     /*
  1031.      * If "env" is non-NULL, it points to a list of new items to
  1032.      * be added to the environment.  These replace existing items
  1033.      * with the same name.
  1034.      */
  1035.  
  1036.     if (env){
  1037.         for(ep1=env; *ep1; ep1++){
  1038.             for(ep2=environ; *ep2; ep2++)
  1039.                 if (!envcmp(*ep1, *ep2))
  1040.                     break;
  1041.             if (ep2 < earray+MAXENV) {
  1042.                 if (!*ep2)
  1043.                     ep2[1] = NULL;
  1044.                 *ep2 = *ep1;
  1045.             }
  1046.         }
  1047.     }
  1048.  
  1049.  
  1050.     /* Finally, use an insertion sort to put things in order. */
  1051.  
  1052.     for(ep1=environ+1; cp = *ep1; ep1++){
  1053.         for(ep2=environ; ep2 < ep1; ep2++)
  1054.             if (envcmp(*ep1, *ep2) < 0)
  1055.                 break;
  1056.         ep3 = ep2;
  1057.         for(ep2=ep1; ep2 > ep3; ep2--)
  1058.             ep2[0] = ep2[-1];
  1059.         *ep2 = cp;
  1060.     }
  1061. }
  1062.  
  1063.  
  1064. static
  1065. envcmp(e1, e2)
  1066. register char *e1, *e2;
  1067. {
  1068.     register d;
  1069.  
  1070.     do {
  1071.         if (d = *e1 - *e2++)
  1072.             return(d);
  1073.     } while(*e1 && *e1++ != '=');
  1074.     return(0);
  1075. }
  1076. SHAR_EOF
  1077. if test 17598 -ne "`wc -c uw.c`"
  1078. then
  1079. echo shar: error transmitting uw.c '(should have been 17598 characters)'
  1080. fi
  1081. echo shar: extracting uwtool.c '(3073 characters)'
  1082. cat << \SHAR_EOF > uwtool.c
  1083. #
  1084.  
  1085. /*
  1086.  *    uwtool
  1087.  *
  1088.  * Copyright 1985 by John D. Bruner.  All rights reserved.  Permission to
  1089.  * copy this program is given provided that the copy is not sold and that
  1090.  * this copyright notice is included.
  1091.  */
  1092.  
  1093. #include <sys/types.h>
  1094. #include <sys/socket.h>
  1095. #include <sys/ioctl.h>
  1096. #include <sys/wait.h>
  1097. #include <sys/time.h>
  1098. #include <sys/resource.h>
  1099. #include <sys/uio.h>
  1100. #include <strings.h>
  1101. #include <signal.h>
  1102. #include <stdio.h>
  1103. #include "openpty.h"
  1104.  
  1105. #define    NFDS    20            /* max number of file descriptors */
  1106.  
  1107. typedef int fildes_t;
  1108.  
  1109. extern char *getenv();
  1110.  
  1111. main(argc, argv)
  1112. char **argv;
  1113. {
  1114.     register int pid;
  1115.     register fildes_t sd;
  1116.     auto fildes_t fd;
  1117.     char *portal, *shell;
  1118.     int lmode;
  1119.     struct sgttyb sg;
  1120.     struct tchars tc;
  1121.     struct ltchars ltc;
  1122.     struct iovec iov;
  1123.     struct msghdr msg;
  1124.     struct sockaddr sa;
  1125.     auto struct ptydesc pt;
  1126.  
  1127.     /*
  1128.      * Close all file descriptors except 0, 1, and 2.
  1129.      */
  1130.  
  1131.     for (fd=3; fd < NFDS; fd++)
  1132.         (void)close(fd);
  1133.  
  1134.     /*
  1135.      * Get the terminal configuration for this tty.
  1136.      */
  1137.     (void)ioctl(0, (int)TIOCGETP, (char *)&sg);
  1138.     (void)ioctl(0, (int)TIOCGETC, (char *)&tc);
  1139.     (void)ioctl(0, (int)TIOCGLTC, (char *)<c);
  1140.     (void)ioctl(0, (int)TIOCLGET, (char *)&lmode);
  1141.  
  1142.     /*
  1143.      * Create a UNIX-domain socket.
  1144.      */
  1145.  
  1146.     if (!(portal=getenv("UWIN"))) {
  1147.         fprintf(stderr,
  1148.             "You must run %s under the window manager\n", *argv);
  1149.         exit(1);
  1150.     }
  1151.  
  1152.     if ((sd=socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
  1153.         perror("socket");
  1154.         exit(1);
  1155.     }
  1156.     sa.sa_family = AF_UNIX;
  1157.     (void)strncpy(sa.sa_data, portal, sizeof sa.sa_data-1);
  1158.     sa.sa_data[sizeof sa.sa_data-1] = '\0';
  1159.  
  1160.  
  1161.     /*
  1162.      * Obtain a pseudo-tty.
  1163.      */
  1164.  
  1165.     if (openpty(&pt) < 0) {
  1166.         fprintf(stderr, "Can't obtain a pseudo-tty for a new window\n");
  1167.         exit(1);
  1168.     }
  1169.  
  1170.  
  1171.     /* 
  1172.      * Fork a child process using this pseudo-tty.  Initialize the
  1173.      * terminal modes on the pseudo-tty to match those of the parent
  1174.      * tty.
  1175.      */
  1176.  
  1177.     while ((pid=vfork()) < 0)
  1178.         sleep(5);
  1179.     if (!pid) {
  1180.         (void)setuid(getuid());/* in case it's setuid-root by mistake */
  1181.         (void)signal(SIGTSTP, SIG_IGN);
  1182.         (void)ioctl(open("/dev/tty", 2), (int)TIOCNOTTY, (char *)0);
  1183.         (void)close(open(pt.pt_tname, 0)); /*set new ctrl tty */
  1184.         (void)dup2(pt.pt_tfd, 0);
  1185.         (void)dup2(0, 1);
  1186.         (void)dup2(0, 2);
  1187.         for (fd=3; fd < NFDS; fd++)
  1188.             (void)close(fd);
  1189.         (void)ioctl(0, (int)TIOCSETN, (char *)&sg);
  1190.         (void)ioctl(0, (int)TIOCSETC, (char *)&tc);
  1191.         (void)ioctl(0, (int)TIOCSLTC, (char *)<c);
  1192.         (void)ioctl(0, (int)TIOCLSET, (char *)&lmode);
  1193.         if (argc == 1) {
  1194.             if (!(shell=getenv("SHELL")))
  1195.                 shell = "/bin/sh";
  1196.             execl(shell, shell, (char *)0);
  1197.             perror(shell);
  1198.         } else {
  1199.             execvp(argv[1], argv+1);
  1200.             perror(argv[1]);
  1201.         }
  1202.         _exit(1);
  1203.     }
  1204.  
  1205.  
  1206.     /*
  1207.      * Pass the file descriptor to the window server and exit.
  1208.      */
  1209.  
  1210.     iov.iov_base = pt.pt_pname;
  1211.     iov.iov_len = strlen(pt.pt_pname);
  1212.     msg.msg_name = (caddr_t)&sa;
  1213.     msg.msg_namelen = sizeof sa.sa_family + strlen(sa.sa_data);
  1214.     msg.msg_iov = &iov;
  1215.     msg.msg_iovlen = 1;
  1216.     msg.msg_accrights = (caddr_t)&pt.pt_pfd;
  1217.     msg.msg_accrightslen = sizeof pt.pt_pfd;
  1218.     if (sendmsg(sd, &msg, 0) < 0) {
  1219.         perror("sendmsg");
  1220.         exit(1);
  1221.     }
  1222.  
  1223.     exit(0);
  1224. }
  1225. SHAR_EOF
  1226. if test 3073 -ne "`wc -c uwtool.c`"
  1227. then
  1228. echo shar: error transmitting uwtool.c '(should have been 3073 characters)'
  1229. fi
  1230. echo shar: extracting openpty.h '(308 characters)'
  1231. cat << \SHAR_EOF > openpty.h
  1232. /*
  1233.  *    This file defines the "ptydesc" structure which is returned
  1234.  *    by the routine "openpty".
  1235.  */
  1236.  
  1237. struct ptydesc {
  1238.     int        pt_pfd;        /* file descriptor of master side */
  1239.     int        pt_tfd;        /* file descriptor of slave side */
  1240.     char        *pt_pname;    /* master device name */
  1241.     char        *pt_tname;    /* slave device name */
  1242. };
  1243. SHAR_EOF
  1244. if test 308 -ne "`wc -c openpty.h`"
  1245. then
  1246. echo shar: error transmitting openpty.h '(should have been 308 characters)'
  1247. fi
  1248. echo shar: extracting uw.h '(2697 characters)'
  1249. cat << \SHAR_EOF > uw.h
  1250. /*
  1251.  *    uw command bytes
  1252.  *
  1253.  * Copyright 1985 by John D. Bruner.  All rights reserved.  Permission to
  1254.  * copy this program is given provided that the copy is not sold and that
  1255.  * this copyright notice is included.
  1256.  *
  1257.  *
  1258.  * Two types of information are exchanged through the 7-bit serial line:
  1259.  * ordinary data and command bytes.  Command bytes are preceeded by
  1260.  * an IAC byte.  IAC bytes and literal XON/XOFF characters (those which
  1261.  * are not used for flow control) are sent by a CB_FN_CTLCH command.
  1262.  * Characters with the eighth bit set (the "meta" bit) are prefixed with
  1263.  * a CB_FN_META function.
  1264.  *
  1265.  * The next most-significant bit in the byte specifies the sender and
  1266.  * recipient of the command.  If this bit is clear (0), the command byte
  1267.  * was sent from the host computer to the Macintosh; if it is set (1)
  1268.  * the command byte was sent from the Macintosh to the host computer.
  1269.  * This prevents confusion in the event that the host computer
  1270.  * (incorrectly) echos a command back to the Macintosh.
  1271.  *
  1272.  * The remaining six bits are partitioned into two fields.  The low-order
  1273.  * three bits specify a window number from 1-7 (window 0 is reserved for
  1274.  * other uses) or another type of command-dependent parameter.  The next
  1275.  * three bits specify the operation to be performed by the recipient of
  1276.  * the command byte.
  1277.  *
  1278.  * Note that the choice of command bytes prevents the ASCII XON (021) and
  1279.  * XOFF (023) characters from being sent as commands.  CB_FN_ISELW commands
  1280.  * are only sent by the Macintosh (and thus are tagged with the CB_DIR_MTOH
  1281.  * bit).  Since XON and XOFF data characters are handled via CB_FN_CTLCH,
  1282.  * this allows them to be used for flow control purposes.
  1283.  */
  1284.  
  1285. #define    IAC        0001        /* interpret as command */
  1286. #define    CB_DIR        0100        /* command direction: */
  1287. #define    CB_DIR_HTOM    0000        /*    from host to Mac */
  1288. #define    CB_DIR_MTOH    0100        /*    from Mac to host */
  1289. #define    CB_FN        0070        /* function code: */
  1290. #define    CB_FN_NEWW    0000        /*    new window */
  1291. #define    CB_FN_KILLW    0010        /*    kill (delete) window */
  1292. #define    CB_FN_ISELW    0020        /*    select window for input */
  1293. #define    CB_FN_OSELW    0030        /*    select window for output */
  1294. #define    CB_FN_META    0050        /*    add meta to next data char */
  1295. #define    CB_FN_CTLCH    0060        /*    low 3 bits specify char */
  1296. #define    CB_FN_MAINT    0070        /*    maintenance functions */
  1297. #define    CB_WINDOW    0007        /* window number mask */
  1298. #define    CB_CC        0007        /* control character specifier: */
  1299. #define    CB_CC_IAC    1        /*    IAC */
  1300. #define    CB_CC_XON    2        /*    XON */
  1301. #define    CB_CC_XOFF    3        /*    XOFF */
  1302. #define    CB_MF        0007        /* maintenance functions: */
  1303. #define    CB_MF_ENTRY    0        /*    beginning execution */
  1304. #define    CB_MF_EXIT    7        /*    execution terminating */
  1305. #define    NWINDOW        7        /* maximum number of windows */
  1306. SHAR_EOF
  1307. if test 2697 -ne "`wc -c uw.h`"
  1308. then
  1309. echo shar: error transmitting uw.h '(should have been 2697 characters)'
  1310. fi
  1311. #    End of shell archive
  1312. exit 0
  1313.  
  1314.  
  1315.