home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / util / unix / maclayer.uni < prev    next >
Encoding:
Internet Message Format  |  1992-11-05  |  110.2 KB

  1. Date: Mon, 19 Mar 1990 6:34:35 CST
  2. From: Werner Uhrig <werner@rascal.ics.utexas.edu>
  3. Subject: here comes MacLayers_1.0_UNIX-files_shar
  4.  
  5. # This is a shell archive.  Remove anything before this line,
  6. # then unpack it by saving it in a file and typing "sh file".
  7. #
  8. # Wrapped by rascal!werner on Mon Mar 19 04:58:04 CST 1990
  9. # Contents:  README layers.1 layers.c layers.h layersize.c layertitle.c
  10. #    macbput.1 macbput.c makefile protocol.c
  11.  
  12. echo x - README
  13. sed 's/^@//' > "README" <<'@//E*O*F README//'
  14.                              Layers 1.0 Release
  15.  
  16.                            ***    CONTENTS     ***
  17.  
  18. The following files are provided with the MacLayers package:
  19.  
  20.   README            -  this file
  21.   layers.1          -  the layers command manual page
  22.   makefile          -  the layers makefile
  23.   layers.h          -  Unix source for the layers command
  24.   layers.c          -                ditto
  25.   protocol.c        -                ditto
  26.   layersize.c       -  Unix source for the layersize command
  27.   layertitle.c      -  Unix source for the layertitle command
  28.   MacLayers.sit.Hqx -  the MacLayers Application download file
  29.   MacLayers.doc     -  the MacLayers User's Manual
  30.   macbput.c         -  a downloading utility
  31.   macbput.1         -  the macbput command manual page
  32.  
  33. The MacLayers.sit.Hqx file is in hexbin format. After downloading it must be
  34. processed with a Stuffit compatible utility to produce the MacLayers 
  35. application.
  36.  
  37. Macbput is a public domain download utility for downloading macbinary files.
  38. Macbinary files allow downloading to correctly set the Macintosh file creation 
  39. date and file last used date. The version with this package has an important 
  40. bug fixed.
  41.  
  42.  
  43.                          ***  SUPPORTED SYSTEMS  ***
  44.  
  45. MacLayers has been successfully installed on the following systems:
  46.  
  47.    SunOS 4.0.3
  48.    SunOS 3.2
  49.    Sequent DYNIX 3.0.12 (#DEFINE SEQUENT)
  50.    Sequent DYNIX 3.0.4  (#DEFINE SEQUENT)
  51.  
  52. MacLayers has failed to install on these systems:
  53.  
  54.    AIX 2.2.1 on IBM RT        Unsupported ioctls
  55.  
  56.  
  57.                            ***   INSTALLATION   ***
  58.  
  59. There are two ways to install the layers system:
  60.  
  61.     make install
  62.  
  63.  or
  64.     make installnopriv
  65.  
  66. The default is to install the 'layers' command set-uid which allows it to 
  67. update /etc/utmp and perform chown/chmod on its allocated pseudo-ttys. 
  68. This enables commands like 'who' to know about the presence of layers users 
  69. and commands like 'write' and 'talk' to communicate with them. This is not 
  70. a mandatory requirement however and the layers system will otherwise function.
  71.  
  72. For set-uid installers (especially Sequent users) there are a few customizing 
  73. parameters which may be of interest at the front of layers.c.
  74.  
  75.                               *end of document*
  76. @//E*O*F README//
  77. chmod u=rw,g=rw,o=rw README
  78.  
  79. echo x - layers.1
  80. sed 's/^@//' > "layers.1" <<'@//E*O*F layers.1//'
  81. @.TH LAYERS l  "17 March 1990"
  82. @.SH NAME
  83. @.PP
  84. layers, layertitle \- Protocol for MacLayers Multiwindow Terminal Emulator for Unix
  85. @.SH SYNOPSIS
  86. layers                - start window protocol
  87. @.LP
  88. layers [-l] [command] - create new window
  89. @.LP
  90. layertitle string     - retitle current layers window
  91. @.IX  "layers" "start layers protocol, create new window"
  92. @.IX  "layertitle" "rename current layers window"
  93. @.SH DESCRIPTION
  94. @.PP
  95. MacLayers provides multi-window capability for a Macintosh (greater than 128K)
  96. connected to a host UNIX(TM) system with sockets support. Each window may be 
  97. associated with a shell, login to a different host, or an individual 
  98. command. Complete facilities are available for controlling the window 
  99. and the associated host processes attached thereto.
  100. @.PP
  101. To use MacLayers, you must have the MacLayers vt-100 terminal emulation
  102. program on a Macintosh and the layers protocol program installed on your
  103. Unix host.
  104. @.SH MACLAYERS OPERATION
  105. @.PP
  106. The Maclayers Application on the Mac starts up as a garden variety 
  107. host-to-terminal vt-100 emulator. (As such you can run it with any
  108. host, not just a Unix machine.) Baud rate and other configurations are set 
  109. by selections in the Control Menu.
  110. @.PP
  111. Enter the 
  112. @.I layers
  113. command to the Unix host using no options or parameters
  114. to start the layers protocol.  The initial terminal window will be closed
  115. and replaced with a layers protocol window.  A shell is run in this
  116. window, either /bin/sh or the shell indicated by your $SHELL variable.
  117. @.PP
  118. You can start a new shell layer by picking "New" on the Layers menu. You can
  119. also start a new layer window by issuing the
  120. @.I layers 
  121. command to a
  122. shell layer window. If you use no operands then the new layer window
  123. will be a shell. However, you can specify any command you wish by
  124. simply adding it as a parameter.  Examples: "layers vi testfile.c",
  125. "layers telnet earth."
  126. @.PP
  127. If you are specifying a shell then you can also elect to have it be a 
  128. login shell by adding a -l option. This allows broadcast/write/talk 
  129. capabilities for that window. The initial layer window shell defaults
  130. to a login shell.
  131. @.PP
  132. When a layer process group terminates its window is automatically closed.
  133. MacLayers exits layers mode when the last (or only) layer window is closed.
  134. You may also use the Layers Menu "Shutdown" to terminate layers mode.
  135. You cannot quit the MacLayers application while in layers mode but must 
  136. Shutdown the multi-window mode first.
  137. @.PP
  138. You can abort host 
  139. @.I layers
  140. by using the Control Menu "Abort Host Layers" 
  141. item which is always available. This may be necessary if your Mac 
  142. loses contact with the host and you restart the MacLayers application at
  143. which time the host would still be in multi-window layers mode while
  144. the application would not. If the MacLayers application terminates due
  145. to a non-recoverable problem it will always issue an order to terminate
  146. layers mode on the host before returning to the Finder.
  147. @.SH XMODEM DOWNLOADING
  148. @.PP
  149. MacLayers has a download facility for downloading XMODEM MacTerminal
  150. ('macput' command) and MacBinary ('macbput' command) files. Straight 
  151. vanilla XMODEM is not supported.
  152. Only one window can be doing a XMODEM download at any one time.
  153. Downloading does not effect any other MacLayers operations so you can
  154. freely use any other windows or applications (with MultiFinder) while 
  155. a download is in progress. Remember though that the topmost window 
  156. receives the highest priority data transfer from the host. So for the 
  157. fastest downloading keep the XMODEM layer window the active window.
  158. @.SH FILES
  159. @.PP
  160.  /usr/tmp/layers/<login>       Directory created by 
  161. @.I layers
  162.  /usr/tmp/layers/<login>/host.ttySocket Created by 
  163. @.I layers
  164. @.SH AUTHOR
  165. Dave Trissel
  166. @.SH BUGS AND CAVEATS
  167. @.PP
  168.  *) The shell TERM variable must have the same value in your 
  169. layer shells as it does when you initially start 
  170. @.I layers
  171. up.
  172. @.PP
  173.  *) If you set the BSD shell TERMCAP variable then that variable must
  174. be set in your .login file. It may not be changed to something
  175. different in .cshrc.
  176. @.PP
  177.  *) The 
  178. @.I layers
  179. command will not properly work when being issued from a
  180. remote login into the same machine which is already running the
  181. initial 
  182. @.I layers
  183. startup command.
  184. @.PP
  185.  *) There is no file upload facility.
  186. @.PP
  187.  *) MacLayers will access the disk less often if you have RAM Cache
  188. enabled on the Macintosh.
  189. @.PP
  190.  *)Layers must be installed as set-uid with owner root in order
  191. to  be  able to correctly change the owner of the tty device
  192. file for  each  window. Special  permission  may  also  be
  193. required to write the file "/etc/utmp".
  194. @.SH SEE ALSO
  195. @.PP
  196. The MacLayers program is
  197. completely described in the manual that accompanies it.
  198. @.PP
  199. Manual page courtesy of Peter Newton.
  200. @.PP
  201. UNIX(TM) is a registered trademark of American Telephone and Telegraph.
  202. Macintosh is a trademark of McIntosh Laboratories and is licensed to Apple 
  203. Computer.
  204. @//E*O*F layers.1//
  205. chmod u=rw,g=rw,o=rw layers.1
  206.  
  207. echo x - layers.c
  208. sed 's/^@//' > "layers.c" <<'@//E*O*F layers.c//'
  209. /********                    Layers.c
  210. *********
  211. *********    Layers - MacLayers Multiwindow BSD Socket Driver
  212. *********
  213. *********          Dave Trissel oakhill!davet
  214. *********
  215. ********* The sockets handling portion of this control module is based 
  216. ********* upon 'screen' by Oliver Laumann whose copyright remains below. 
  217. ********* The rest is
  218.  *
  219.  *             Copyright (C) 1989 by David W. Trissel
  220.  *
  221.  *              Not derived from licensed software.
  222.  *
  223.  * Permission is granted to freely use, copy, modify, and redistribute
  224.  * this software, provided that no attempt is made to gain profit from it,
  225.  * the author is not construed to be liable for any results of using the
  226.  * software, alterations are clearly marked as such, and this notice is
  227.  * not modified.
  228.  *
  229.  */
  230.  
  231. static char LayersVersion[] = "layers 1.00 17-Mar-1990";
  232.  
  233. /* Layers Changes:
  234.  
  235.     Version .92 22-Mar-1989
  236.  
  237.         Original Distributed version
  238.  
  239.     Version .93 31-Mar-1989
  240.  
  241.         Deleted dl and al termcap entries since they didn't help any
  242.         (al was redundant with sc (scroll) so should never have been created)
  243.  
  244.         SIGINT no longer causes us to quit (left debugging code in by mistake)
  245.  
  246.         Layer #1 is always logged in and takes over as user's login console
  247.         (Real tty disconnected from /etc/utmp file while layers is running)
  248.  
  249.     Version .93b 05-May-1989
  250.  
  251.         Try getenv("PWD") before getwd() so Sun networking won't hang us up
  252.  
  253.     Version .93n 07-Jan-1990
  254.  
  255.         Reset TTY back to normal if initial link handshake fails.
  256.  
  257.     Version 1.00b 22-Jan-1990
  258.  
  259.         Corrected problem of layers forcing all umasks to 000.
  260.  
  261.     Version 1.00  17-Mar-1990
  262.  
  263.         First public release.
  264. */
  265.  
  266.  
  267. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  268.  * Not derived from licensed software.
  269.  *
  270.  * Permission is granted to freely use, copy, modify, and redistribute
  271.  * this software, provided that no attempt is made to gain profit from it,
  272.  * the author is not construed to be liable for any results of using the
  273.  * software, alterations are clearly marked as such, and this notice is
  274.  * not modified.
  275.  *
  276.  *    Modified by Patrick Wolfe (pat@kai.com, kailand!pat)
  277.  *    Do whatever you want with (my modifications of) this program, but
  278.  *    don't claim you wrote them, don't try to make money from them, and
  279.  *    don't remove this notice.
  280.  */
  281.  
  282. /*
  283.  *    Beginning of User Configuration Section
  284.  */
  285.  
  286. /*
  287.  * SEQUENT   -- your host system is Sequent. This changes a setvbuf()
  288.  *              call to a setlinebuf(). [Suggested by Peter Newton 
  289.  *              <newton@cs.utexas.edu>]
  290.  *
  291.  */
  292. #undef SEQUENT
  293.  
  294.  
  295. /*
  296.  * GETTTYENT -- your system has the new format /etc/ttys (like 4.3 BSD)
  297.  *              and the getttyent(3) library functions.
  298.  *
  299.  */
  300. #undef GETTTYENT
  301.  
  302.  
  303. /*
  304.  * LOGINDEFAULT -- if set to 1 (one), windows will login (add entries to
  305.  *                 /etc/utmp) by default.  Set to 0 if you don't want this.
  306.  *                 (Also see USERLIMIT below). [NOTE: current code always
  307.  *                 logs layer #1 only unless -l option used on 'layers'
  308.  *                 command.]
  309.  */
  310. #define LOGINDEFAULT 0
  311.  
  312. /*
  313.  * USERLIMIT  --   count all non-null entries in /etc/utmp before adding a 
  314.  *                   new entry. Some machine manufacturers (incorrectly) count 
  315.  *                   logins by counting non-null entries in /etc/utmp (instead 
  316.  *                   of counting non-null entries with no hostname and not on 
  317.  *                   a pseudo tty). Sequent does this, so you might reach your 
  318.  *                   limited user license early.
  319.  */
  320. #define USRLIMIT 32
  321.  
  322. /*
  323.  * SOCKDIR      -- If defined, this directory is where layers sockets will be 
  324.  *                   placed, (actually in a subdirectory by the user's loginid).
  325.  *                   This is neccessary because NFS doesn't support socket 
  326.  *                   operations, and many people's homes are on NFS mounted 
  327.  *                   partitions.  Layers will create this directory if it needs 
  328.  *                   to.
  329.  */
  330. #define SOCKDIR "/tmp/layers"    /* NFS doesn't support named sockets */
  331.  
  332. /*
  333.  *    End of User Configuration Section
  334.  */
  335.  
  336. #include <stdio.h>
  337. #include <sgtty.h>
  338. #include <signal.h>
  339. #include <errno.h>
  340. #include <ctype.h>
  341. #include <utmp.h>
  342. #include <pwd.h>
  343. #include <nlist.h>
  344. #include <fcntl.h>
  345. #include <sys/types.h>
  346. #include <sys/time.h>
  347. #include <sys/file.h>
  348. #include <sys/wait.h>
  349. #include <sys/socket.h>
  350. #include <sys/un.h>
  351. #include <sys/stat.h>
  352. #include <sys/dir.h>
  353. #include <sys/ioctl.h>
  354.  
  355. #include "layers.h"
  356.  
  357. #ifdef GETTTYENT
  358. #include <ttyent.h>
  359. #else
  360. static struct ttyent
  361.   { char *ty_name;
  362.   } *getttyent();
  363. static char *tt, *ttnext;
  364. static char ttys[] = "/etc/ttys";
  365. #endif
  366.  
  367. #ifndef FSCALE
  368. #define FSCALE 1000.0        /* Sequent doesn't define FSCALE...grrrr */
  369. #endif
  370.  
  371. #ifdef  USRLIMIT
  372. struct utmp utmpbuf;
  373. int UserCount;
  374. #endif
  375.  
  376. #define Ctrl(c) ((c)&037)
  377.  
  378. /* C library items */
  379. extern char **environ;
  380. extern errno;
  381. extern sys_nerr;
  382. extern char *sys_errlist[];
  383. extern char *index(), *rindex(), *malloc(), *getenv();
  384. extern char *getlogin(), *ttyname();
  385.  
  386. /* Local items */
  387. static void FAbort(), SigHup(), SigChld(), AddCap(), FinitTerm();
  388. static char  *MakeTermcap(), *Filename(), **SaveArgs(), *GetTtyName();
  389. static void    InitWorld(), ClearShape(), BuildTitle(), KillPG();
  390. static void SetWindowSize(), WriteUtmp();
  391. static int    ReadUtmp(), FindUtmp(), SetUtmp();
  392.  
  393. static int    loginflag = -1;
  394. static char PtyName[32], TtyName[32];
  395. static char *ShellProg;
  396. static char *ShellArgs[2];
  397. static inlen;
  398. static ESCseen;
  399. static GotSignal;
  400. static char DefaultShell[] = "/bin/sh";
  401. static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
  402. static char PtyProto[] = "/dev/ptyXY";
  403. static char TtyProto[] = "/dev/ttyXY";
  404. static int TtyMode = 0622;
  405. static struct stat RealTtyStat;                    /* Real tty stat */
  406. static char RealTtyName[32] = "";                /* Real tty name */
  407. static int    RealSlot = 0;                        /* Real tty logon slot */
  408. static struct utmp    RealUtmp;                    /* Real tty logon utmp entry */
  409. static int    RealTtyMode = 0;                    /* Real tty mode */
  410. static int    Oumask;                                /* Original user's umask */
  411. static char SockPath[512];
  412. #ifdef SOCKDIR
  413. static char SockDir[] = SOCKDIR;
  414. #else
  415. static char SockDir[] = ".layers";
  416. #endif
  417. static char *SockNamePtr, *SockName;
  418. static ServerSocket;
  419. static char *NewEnv[MAXARGS];
  420. static char Esc = Ctrl('a');
  421. static char MetaEsc = 'a';
  422. static char *home;
  423. static Abortonmsg;
  424. static utmp, utmpf;
  425. static char UtmpName[] = "/etc/utmp";
  426. static char *LoginName;
  427. static mflag, nflag, fflag, rflag;
  428. static char HostName[MAXSTR];
  429. static char *myname;
  430. static DevTty;
  431.  
  432. static struct mode {
  433.     struct sgttyb m_ttyb;
  434.     struct tchars m_tchars;
  435.     struct ltchars m_ltchars;
  436.     int m_ldisc;
  437.     int m_lmode;
  438. } OldMode, NewMode;
  439.  
  440. #define MSG_CREATE    0
  441. #define MSG_ERROR     1
  442.  
  443. struct msg
  444.   {
  445.     int type;
  446.     union
  447.       { struct
  448.           {    int    lflag;                /* login flag */
  449.             struct Shape shape;        /* window shape */
  450.             int nargs;
  451.             char line[MAXLINE];
  452.             char dir[1024];
  453.           } create;
  454.         char message[MAXLINE];
  455.       } m;
  456.   };
  457.  
  458.  
  459.             /* dynamic keyboard input buffer definition */
  460. struct Kbuff
  461.   {    struct Kbuff * next;            /* next buffer in chain (or NULL) */
  462.     int            size;                /* size of data in this buffer */
  463.     int            offset;                /* start of first data in buffer */
  464.     unsigned char text[IOSIZE];        /* text buffer itself */
  465.   };
  466.  
  467.             /* World layer definition */
  468. struct Layer {
  469.     int        chan;                    /* channel represented by this layer */
  470.     int        allocated;                /* layer allocated */
  471.     int        ptyfd;                    /* psuedo tty */
  472.     int        ptymask;                /* mask for pty descriptor */
  473.     int        lpid;                    /* layer head process ID */
  474.     int        slot;                    /* utmp slot number */
  475.     struct Kbuff *kbuff;            /* keyboard input buffers */
  476.     struct Shape shape;                /* Shape structure to/from MacLayers */
  477.     char    cmd[MAXSTR];            /* command to execute */
  478.     char    tty[MAXSTR];            /* psuedo tty ID */
  479.     };
  480.  
  481. static struct Layer World[MAXPCHAN]; /* all layer structures */
  482.  
  483. static int rows = 24;                /* default window height in lines */
  484. static int cols = 80;                /* default window width in chars */
  485. static char Termcap[1024];
  486. static char Term[MAXSTR] = "TERM=";    /* window's terminal type */
  487. static char    *UserTerm;                /* terminal ID we are mimmicing */
  488. static int flowctl;
  489. static tcLineLen = 100;
  490.  
  491. /* co#80 and li$24 added dynamically for proper window size */
  492. static char TermcapConst1[] = "TERMCAP=SC|";
  493. static char TermcapConst3[] = "|MacLayers virtual terminal|\\\n\
  494.     :cr=^M:do=^J:nl=^J:bl=^G:cl=\\E[;H\\E[2J:\\\n\
  495.     :le=^H:bs:am:cm=\\E[%i%d;%dH:nd=\\E[C:up=\\E[A:\\\n\
  496.     :ce=\\E[K:cd=\\E[J:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\\\n\
  497.     :md=\\E[1m:mr=\\E[7m:mb=\\E[5m:me=\\E[m:is=\\E[1;24r\\E[24;1H:\\\n\
  498.     :rf=/usr/lib/tabset/vt100:\\\n\
  499.     :rs=\\E>\\E[?3l\\E[?4l\\E[?5l\\E[?7h\\E[?8h:ks=\\E[?1h\\E=:ke=\\E[?1l\\E>:\\\n\
  500.     :ku=\\EOA:kd=\\EOB:kr=\\EOC:kl=\\EOD:kb=^H:\\\n\
  501.     :ho=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:ta=^I:pt:sr=\\EM:vt#3:xn:\\\n\
  502.     :sc=\\E7:rc=\\E8:cs=\\E[%i%d;%dr:\\\n\
  503.     :dc=\\ED:ic=\\EI:";
  504. /* NOTE: the above two cababilities are beyond vt100 - unique to MacLayers */
  505.  
  506. int        Dflag;                            /* debug dump flag */
  507.  
  508.                             /* main() */
  509. main(ac, av)
  510. char **av;
  511. {
  512.     register n;
  513.     register len;
  514.     register struct Layer *layer;
  515.     char    *ap;
  516.     struct passwd *ppp;
  517.     int        s;
  518.     int        r;                            /* read fd test bits */
  519.     int        w;                            /* write fd test bits */
  520.     int        stall;                        /* stall flag for priority channel */
  521.     int        fderr;                        /* error fd test bits */
  522.     struct timeval tv;
  523.     struct Shape shape;                    /* window shape */
  524.     time_t    now;
  525.     char    buf[IOSIZE];
  526.     char    rc[256];
  527.     struct stat st;
  528.     struct Kbuff *kbptr;                /* input keyboard buffer pointer */
  529.  
  530.     Abortonmsg = 1;                        /* quit if message generated */
  531.     ClearShape(&shape);                    /* initialize shape structure */
  532.     myname = (ac == 0) ? "layers" : av[0];
  533.     InitWorld();                        /* clear World array structures */
  534.  
  535.     while (ac > 0)
  536.       {    ap = *++av;
  537.         if (--ac > 0 && *ap == '-')
  538.           {    switch (ap[1])
  539.             { case 'l':        /* login this command line */
  540.                 loginflag = 1;
  541.                 break;
  542.  
  543.               case 'd':        /* dump debugging flag */
  544.                 Dflag = 1;
  545.                 (void) freopen("layers.dump", "a", stderr); /* append mode */
  546. #ifdef SEQUENT
  547.                 setlinebuf(stderr);
  548. #else
  549.                 setvbuf(stderr, NULL, _IOLBF, 0);
  550. #endif
  551.                 break;
  552.  
  553.               case 'u':        /* do not login this command line */
  554.                 loginflag = 0;
  555.                 break;
  556.  
  557.               case 'm':        /* force this to be master and not a client */
  558.                 mflag = 1;
  559.                 break;
  560.  
  561.               case 'n':        /* no flow control */
  562.                 nflag = 1;
  563.                 break;
  564.  
  565.               case 'f':        /* flow control on */
  566.                 fflag = 1;
  567.                 break;
  568.  
  569.               case 'v':        /* do nothing but issue layers version */
  570.                 printf("%s\n", LayersVersion);
  571.                 exit(0);
  572.  
  573.               default:
  574.             help:
  575.                 Msg (0,"Use: %s [-f] [-l | -u] [-m] [-n] [cmd args]\n", myname);
  576.  
  577.             } /* end switch on '-' option */
  578.  
  579.         } /* end if '-' */
  580.  
  581.         else
  582.             break;
  583.  
  584.       } /* end while parameters */
  585.  
  586.     if (nflag && fflag)
  587.         Msg (0, "-f and -n are conflicting options.");
  588.  
  589.     if ((ShellProg = getenv ("SHELL")) == 0)
  590.         ShellProg = DefaultShell;
  591.     DO DEBUG("ShellProg %s\n", ShellProg);
  592.  
  593.     /* we mimmic the user's $TERM ID */
  594.     if ((UserTerm = getenv("TERM")) == 0)
  595.         UserTerm = "layers";                /* use "layers" if none */
  596.     (void) strcat(Term, UserTerm);
  597.     DO DEBUG("%s\n", Term);
  598.  
  599.     ShellArgs[0] = ShellProg;
  600.     if (ac == 0)
  601.       { ac = 1;
  602.         av = ShellArgs;
  603.         shape.wattr |= Wa_shell;            /* indicate a shell window */
  604.       }
  605.  
  606.     if ((home = getenv ("HOME")) == 0)
  607.         Msg (0, "$HOME is undefined.");
  608.     DO DEBUG("home %s\n", home);
  609.  
  610.     if ((LoginName = getlogin ()) == 0 || LoginName[0] == '\0')
  611.       { if ((ppp = getpwuid (getuid ())) == 0)
  612.                return;
  613.         LoginName = ppp->pw_name;
  614.       }
  615.     DO DEBUG("LoginName %s\n", LoginName);
  616.  
  617.     if ((Oumask=umask(0)) == -1)
  618.         Msg (errno, "Cannot change umask to zero");
  619.     DO DEBUG("Original umask o%o\n", Oumask);
  620.  
  621. #ifdef SOCKDIR
  622.     if (stat (SOCKDIR, &st) == -1)
  623.       {    if (errno == ENOENT)
  624.           { if (mkdir (SOCKDIR, 0777) == -1)
  625.                 Msg (errno, "Cannot make directory %s", SOCKDIR);
  626.             (void) chown (SOCKDIR, 0, 0);
  627.           }
  628.         else
  629.             Msg (errno, "Cannot get status of %s", SOCKDIR);
  630.       }
  631.     else
  632.       { if ((st.st_mode & S_IFMT) != S_IFDIR)
  633.             Msg (0, "%s is not a directory.", SOCKDIR);
  634.         if ((st.st_mode & 0777) != 0777)
  635.             Msg (0, "Directory %s must have mode 777.", SOCKDIR);
  636.       }
  637.     sprintf (SockPath, "%s/%s", SockDir, LoginName);
  638. #else
  639.     sprintf (SockPath, "%s/%s", home, SockDir);
  640. #endif
  641.     DO DEBUG("SockPath %s\n", SockPath);
  642.  
  643.     if (stat (SockPath, &st) == -1)
  644.       { if (errno == ENOENT)
  645.           { if (mkdir (SockPath, 0700) == -1)
  646.                 Msg (errno, "Cannot make directory %s", SockPath);
  647.             (void) chown (SockPath, getuid (), getgid ());
  648.             DO DEBUG("SockPath directory made\n");
  649.           }
  650.         else
  651.             Msg (errno, "Cannot get status of %s", SockPath);
  652.       }
  653.     else
  654.       { if ((st.st_mode & S_IFMT) != S_IFDIR)
  655.                Msg (0, "%s is not a directory.", SockPath);
  656.         if ((st.st_mode & 0777) != 0700)
  657.             Msg (0, "Directory %s must have mode 700.", SockPath);
  658.         if (st.st_uid != getuid ())
  659.             Msg (0, "You are not the owner of %s.", SockPath);
  660.       }
  661.  
  662.     (void) strcpy(RealTtyName, GetTtyName());        /* real tty name */
  663.     if (stat(RealTtyName, &RealTtyStat) == -1)        /* get current mode */
  664.         Msg(errno, "Cannot get status of %s", RealTtyName);
  665.     DO DEBUG("Mode of %s is %#o\n", RealTtyName, RealTtyStat.st_mode);
  666.     RealTtyMode = RealTtyStat.st_mode;        /* save mode for later restore */
  667.  
  668.     (void) gethostname (HostName, MAXSTR);
  669.     HostName[MAXSTR-1] = '\0';
  670.     DO DEBUG("HostName %s\n", HostName);
  671.  
  672.     if (ap = index (HostName, '.'))
  673.         *ap = '\0';
  674.     if (ap)
  675.         DO DEBUG("*ap %s\n", *ap);
  676.  
  677.     strcat (SockPath, "/");
  678.     SockNamePtr = SockPath + strlen (SockPath);
  679.  
  680.     /* if we are a client send create message to startup window and exit */
  681.     if (GetSockName ())
  682.       {    DO DEBUG("GetSockName says that we are client\n");
  683.         DO DEBUG("SockName '%s'\n", SockName);
  684.         s = MakeClientSocket (1);
  685.         DO DEBUG("Client socket is %d\n", s);
  686.         DO DEBUG("SendCreateMsg()\n");
  687.         SendCreateMsg (s, ac, av, loginflag, &shape);
  688.         close (s);
  689.         DO DEBUG("after SendCreateMsg(), now exit(0)\n");
  690.         exit (0);
  691.       }
  692.  
  693.     /* we are the server */
  694.     DO DEBUG("SockName '%s'\n", SockName);
  695.     DO DEBUG("We are server\n");
  696.     if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1)
  697.         Msg (errno, "/dev/tty");
  698.     DO DEBUG("opened /dev/tty fd %d\n", DevTty);
  699.  
  700.     ServerSocket = MakeServerSocket ();
  701.     DO DEBUG("ServerSocket %d\n", ServerSocket);
  702.     s = ServerSocket;
  703.  
  704.     if (fflag)
  705.         flowctl = 1;
  706.     else
  707.     if (nflag)
  708.         flowctl = 0;
  709.  
  710.     if (loginflag == -1)
  711.         loginflag = LOGINDEFAULT;
  712.  
  713.     MakeNewEnv ();
  714.     InitUtmp ();
  715.     RealSlot = FindUtmp(RealTtyName);    /* find current logon slot */
  716.     if (RealSlot)
  717.       {    if (ReadUtmp(RealSlot, &RealUtmp) > 0)    /* read real login utmp */
  718.             RemoveUtmp(RealSlot);        /* remove original logon slot */
  719.         else
  720.             RealSlot = 0;                /* something's wrong */
  721.       }
  722.  
  723.     signal (SIGHUP, SigHup);
  724.     signal (SIGINT, SIG_IGN);            /* we should never see this */
  725.     signal (SIGQUIT, FAbort);            /* quit layers on these 2 signals */
  726.     signal (SIGTERM, FAbort);
  727.     signal (SIGTTIN, SIG_IGN);
  728.     signal (SIGTTOU, SIG_IGN);
  729.     signal (SIGALRM, SIG_IGN);            /* alarm clock used by protocol.c */
  730.  
  731.     GetTTY (0, &OldMode);
  732.     SetMode (&OldMode, &NewMode);
  733.     SetTTY (0, &NewMode);
  734.  
  735.     if (Initlink() == 0)
  736.       {    SetTTY(0, &OldMode);            /* revert tty back */
  737.         Msg (0, "\n\n  You are not running under MacLayers.");
  738.       }
  739.         
  740.     sprintf (rc, "%.*s/.layersrc", 245, home);
  741. #if 0 /* NOT YET SUPPORTED */
  742.     /* if no window list start up a default shell window */
  743.     if (ReadRc(rc) == 0)            
  744. #endif
  745.       {    n = MakeWindow (0, *av, av, (char *)0, loginflag, &shape);
  746.         if (n == -1)
  747.             { SetTTY (0, &OldMode);
  748.             FQuit(1);
  749.             /* NOT REACHED */
  750.             }
  751.       }
  752.  
  753.     (void) chmod(RealTtyName, 0600);        /* lock out broadcasts */
  754.     Abortonmsg = 0;                            /* don't abort on msg from now on */
  755.     signal (SIGCHLD, SigChld);
  756.     tv.tv_usec = 0;
  757.     tv.tv_sec = 0;                            /* default no timer wanted */
  758.  
  759.     /* client/Maclayers processing loop */
  760.  
  761.     /* poll .20 secs for new startups */
  762. #define WUSSTARTUP    200000                
  763.     /* stall nonpriority windows .5 seconds when top window I/O active */
  764. #define WUSSTALL    500000
  765.  
  766.     stall = 0;                                /* startout no stalled channels */
  767.     fderr = 0;                                /* startout no error fd's */
  768.  
  769.     while (1)
  770.       {    int            priochan;                /* the top window channel */
  771.  
  772.         priochan = TopChannel();            /* find highest priority channel */
  773.  
  774.         /* check for I/O on all available I/O descriptors */
  775.         r = 1<<0;                            /* always read MacLayers stream */
  776.         r |= 1<<s;                            /* always read server socket */
  777.         w = 0;                                /* initalize to no write tests */
  778.         tv.tv_usec = 0;                        /* default no startup poll */
  779.  
  780.         /* for all active layers set read and write bits as appropriate */
  781.         if (stall)
  782.             stall = 1;                        /* start counting output layers */
  783.         for (n=0; n<MAXPCHAN; n++)
  784.          if ((layer = &World[n])->allocated) /* if layer exists ... */
  785.           {    /* if not yet started or has just terminated ... */
  786.             if (layer->ptymask & fderr)
  787.                 tv.tv_usec = WUSSTARTUP;    /* don't spinloop but wait-a-bit */
  788.             else
  789.                 {    if (layer->kbuff && layer->kbuff->size)
  790.                     /* keyboard input for layer */
  791.                     w |= layer->ptymask;    /* try write to it */
  792.                 /* read layer output unless we're being nice to top window */
  793.                 if (!stall)
  794.                     r |= layer->ptymask;    /* read output from layer */
  795.                 else
  796.                 if (layer->chan == priochan)
  797.                     r |= layer->ptymask;    /* read top priority output */
  798.                 else
  799.                     stall++;                /* indicate something to stall */
  800.                }
  801.             }
  802.  
  803.         if (stall > 1)
  804.             if (!tv.tv_usec)
  805.                 tv.tv_usec = WUSSTALL;        /* set stall timout */
  806.  
  807.         /* process signals before trying select */
  808.         if (GotSignal)
  809.           { SigHandler ();
  810.             continue;
  811.           }
  812.  
  813.         DO DEBUG("Select(r %x, w %x, fderr %x, stall %d, prio %d, us %d)\n",
  814.                     r, w, fderr, stall, priochan, tv.tv_usec);
  815.  
  816.         switch ( select(32, &r, &w, NULL, tv.tv_usec ? &tv : NULL) )
  817.         { case -1:
  818.             /* errno has report */
  819.             if (errno == EINTR)                /* signal delivered or timout */
  820.               { errno = 0;
  821.                 tv.tv_usec = 0;                /* clear timer wait value */
  822.                 fderr = 0;                    /* turn off error stall */
  823.                 stall = 0;                    /* turn off output priority stall */
  824.                 DO DEBUG("select errno EINTR\n");
  825.                 continue;                    /* re-loop */
  826.               }
  827.             Abortonmsg = 1;
  828.             DO DEBUG("select errno %d\n", errno);
  829.             Msg (errno, "select");
  830.             /*NOTREACHED*/
  831.  
  832.           case 0:
  833.             /* timeout reached */
  834.             tv.tv_usec = 0;                    /* clear timer wait value */
  835.             stall = 0;                        /* turn off stall */
  836.             fderr = 0;                        /* turn off error stall */
  837.             continue;                        /* re-loop */
  838.  
  839.           default:
  840.             /* a channel has read/write status pending */
  841.             break;
  842.         }
  843.  
  844.         DO DEBUG("after select r %x w %x\n", r, w);
  845.  
  846.         /* handle any signal arriving up during select wait */
  847.         if (GotSignal)
  848.           { SigHandler ();
  849.             continue;
  850.           }
  851.  
  852.         /* if server socket has command process that now */
  853.         if (r & 1 << s)
  854.           {    ReceiveMsg(s);                    /* process client control packet */
  855.             continue;                        /* status may have changed */
  856.           }
  857.  
  858.         /* next process input stream from MacLayers */
  859.         if (r & 1 << 0)
  860.           { ProcessStreamin();                /* key input and control packets */
  861.             continue;                        /* status may have changed */
  862.           }
  863.  
  864.         /* process keyboard input first so output doesn't hold up
  865.         ** keyboard echo and break/interrupt processing
  866.         */
  867.         priochan = TopChannel();            /* find top priority channel */
  868.         stall = 0;                            /* assume no stall needed */
  869.         for (n=0; n<MAXPCHAN; n++)
  870.           if ((layer = &World[n])->allocated)
  871.             if (w & layer->ptymask)
  872.                 while ((kbptr=layer->kbuff)->size)
  873.                   {    /* pass as much keyboard as possible */
  874.                     if (layer->chan == priochan)
  875.                         stall = 1;            /* stall lower priority channels */
  876.                     len = write(layer->ptyfd, &kbptr->text[kbptr->offset],
  877.                                  kbptr->size);
  878.                     DO DEBUG("keyin len %d to chan %d\n", len, layer->chan);
  879.                     if (len <= 0)            /* if no data accepted ... */
  880.                       {    if (errno == EIO)    /* if I/O error indicated ... */
  881.                             fderr |= layer->ptymask; /* wait-a-bit on this */
  882.                         errno = 0;            /* clear errno */
  883.                         break;                /* try again later */
  884.                       }
  885.                     /* some of buffer accepted */
  886.                     kbptr->size -= len;        /* length processed */
  887.                     kbptr->offset += len;    /* bump up offset */
  888.                     if (kbptr->size > 0)    /* not all buffer accepted ... */
  889.                         break;                /* try feed again later */
  890.                     /* see if another buffer chained */
  891.                     if (kbptr->next)
  892.                       {    /* yes, free up current buffer and queue next */
  893.                         layer->kbuff = kbptr->next; /* to next buffer */
  894.                         free(kbptr);    /* free this buffer up */
  895.                       }
  896.                     else
  897.                       {    /* otherwise leave this for next input */
  898.                         kbptr->size = 0;    /* empty buffer */
  899.                         kbptr->offset = 0;    /* refill from the start */
  900.                       }
  901.                   }
  902.  
  903.         /* first process the highest priority channel (top window) */
  904.         if (priochan > 0 && priochan <= MAXPCHAN) /* if valid ... */
  905.           if ((layer = &World[priochan-1])->allocated)
  906.             if (r & layer->ptymask)
  907.               {    /* output to send to top MacLayers window */
  908.                 len = read(layer->ptyfd, buf, IOSIZE);
  909.                 if (len >= 0)                /* if no error ... */
  910.                   {    DO DEBUG("read output len %d chan %d\n", len, layer->chan);
  911.                   }
  912.                 else
  913.                   {    /* We expect EIO error if socket not yet open on other end
  914.                     ** or if process using socket has terminated. We expect
  915.                     ** EWOULDBLOCK also after process terminates.
  916.                     **/
  917.                     DO DEBUG("read output err chan %d errno %d len %d\n",
  918.                                 layer->chan, errno, len);
  919.                     if (errno == EIO || errno == EWOULDBLOCK)
  920.                         DO DEBUG(" ...anticipated\n");
  921.                     /* layer not ready or just terminated so wait-a-bit */
  922.                     fderr |= layer->ptymask;
  923.                     r &= ~layer->ptymask; /* don't read it again below */
  924.                     errno = 0;                /* clear errno */
  925.                   }
  926.                 if (len > 0)
  927.                     SendData(layer->chan, buf, len);
  928.  
  929.                 if (len >= 0)
  930.                     /* To keep lower priority channels from hogging the line
  931.                     ** we delay any output from them until the primary window 
  932.                     ** has no more data to be sent to it.
  933.                     */
  934.                     stall = 1;                /* stall output from others */
  935.               }
  936.  
  937.         /* now pass all available output to MacLayers */
  938.         if (!stall)
  939.          for (n=0; n<MAXPCHAN; n++)
  940.           if ((layer = &World[n])->allocated)
  941.             if (r & layer->ptymask)
  942.               {    /* output to send to MacLayers window */
  943.                 len = read(layer->ptyfd, buf, IOSIZE);
  944.                 if (len >= 0)                /* if no error ... */
  945.                   {    DO DEBUG("output chan %d len %d\n", layer->chan, len);
  946.                   }
  947.                 else
  948.                   {    /* We expect EIO error if socket not yet open on other end
  949.                     ** or if process using socket has terminated. We expect
  950.                     ** EWOULDBLOCK also after process terminates.
  951.                     **/
  952.                     DO DEBUG("read output err chan %d errno %d len %d\n",
  953.                                 layer->chan, errno, len);
  954.                     if (errno == EIO || errno == EWOULDBLOCK)
  955.                       {    DO DEBUG(" ...anticipated\n");
  956.                       }
  957.                     /* layer not ready or just terminated so wait-a-bit */
  958.                     fderr |= layer->ptymask;
  959.                     errno = 0;                /* clear errno */
  960.                   }
  961.                 if (len > 0)
  962.                     SendData(layer->chan, buf, len);
  963.               }
  964.  
  965.         /* handle signals again */
  966.         if (GotSignal)
  967.             SigHandler ();
  968.  
  969.       } /* end while (1) */
  970.  
  971.     /* NOT REACHED */
  972.  
  973. } /* main() */
  974.  
  975.                     /* ReceiveQuit() - MacLayers sends Quit packet */
  976.  
  977. void
  978. ReceiveQuit()
  979. {
  980.     /* We completely quit layers cancelling all active processes */
  981.     DO DEBUG("ReceiveQuit()\n");
  982.     FQuit(0);                                /* normal termination */
  983.     /* NOT REACHED */
  984.  
  985. } /* ReceiveQuit() */
  986.  
  987.  
  988.                 /* ReceiveNew() - MacLayers requests a new shell layer */
  989.  
  990. void
  991. ReceiveNew(chanid, shape)
  992. int        chanid;                                /* channel for new shell layer */
  993. struct Shape *shape;                        /* shape for new channel */
  994. {
  995.     DO DEBUG("ReceiveNew(%d)\n", chanid);
  996.     (void) MakeWindow (chanid, *ShellArgs, ShellArgs,
  997.                     (char *) 0, loginflag, shape);
  998.  
  999. } /* ReceiveNew() */
  1000.  
  1001.  
  1002.                 /* ReceiveDelete() - MacLayers has removed a layer */
  1003. void
  1004. ReceiveDelete(chanid)
  1005. int        chanid;                                /* channel which was deleted */
  1006. {
  1007.     struct Layer *layer;                    /* layer pointer */
  1008.  
  1009.     /* validate channel */
  1010.     DO DEBUG("ReceiveDelete(%d)\n", chanid);
  1011.     if (chanid <= 0 || chanid > MAXPCHAN)
  1012.         return;                                /* ignore invalid channel */
  1013.  
  1014.     /* if this layer active then kill it off, else ignore request */
  1015.     layer = &World[chanid-1];                /* locate target layer */
  1016.     if (layer->allocated)
  1017.         KillWindow(layer);
  1018.  
  1019. } /* ReceiveDelete() */
  1020.     
  1021.     
  1022.         /* ReceiveSignal() - send signal to layer's process group */
  1023.  
  1024. void
  1025. ReceiveSignal(chanid, signal)
  1026. int            chanid;                            /* layer's channel */
  1027. int            signal;                            /* signal.h signal ID */
  1028. {
  1029.     struct Layer *layer;                    /* layer pointer */
  1030.  
  1031.     DO DEBUG("ReceiveSignal(%d,%d)\n", chanid, signal);
  1032.     /* verify channel */
  1033.     if (chanid <= 0 || chanid > MAXPCHAN)
  1034.         return;                                /* ignore invalid channel */
  1035.  
  1036.     /* if this layer is active send the signal to the process group */
  1037.     layer = &World[chanid-1];                /* locate target layer */
  1038.     if (layer->allocated && layer->lpid)
  1039.         KillPG(layer, signal);
  1040.  
  1041. } /* ReceiveSignal() */
  1042.  
  1043.  
  1044.                 /* ReceiveReshape() - windowsize and location updated */
  1045. void
  1046. ReceiveReshape(chanid, shape)
  1047. int                chanid;                    /* channel having shape */
  1048. struct Shape    *shape;                    /* shape structure */
  1049. {
  1050.     struct Layer *layer;                /* layer pointer */
  1051.  
  1052.     DO DEBUG("ReceiveReshape(%d)\n", chanid);
  1053.  
  1054.     /* verify channel */
  1055.     if (chanid <= 0 || chanid > MAXPCHAN)
  1056.         return;                                /* ignore invalid channel */
  1057.  
  1058.     /* if this layer is active then reshape it's window */
  1059.     layer = &World[chanid-1];                /* locate target layer */
  1060.     if (layer->allocated && layer->lpid)
  1061.       {    layer->shape = *shape;                /* install as our new shape */
  1062.         SetWindowSize(layer);                /* udpate the O/S window info */
  1063.       }
  1064.  
  1065. } /* ReceiveReshape() */
  1066.  
  1067.  
  1068.             /* SetWindowSize() - tell O/S about new window size */
  1069.  
  1070. static void
  1071. SetWindowSize(layer)
  1072. struct Layer    *layer;                    /* layer to resize */
  1073. {
  1074. #ifdef TIOCSWINSZ
  1075.     struct    winsize    wsize;                /* window size structure */
  1076.     int            retcode;                /* ioctl return code */
  1077.  
  1078.     wsize.ws_col = layer->shape.wchars; /* character width */
  1079.     wsize.ws_row = layer->shape.wlines; /* window height */
  1080.     wsize.ws_xpixel = 0;                /* necessary? */
  1081.     wsize.ws_ypixel = 0;
  1082.     /* update O/S window state */
  1083.     retcode = ioctl(layer->ptyfd, TIOCSWINSZ, &wsize);
  1084.     DO DEBUG("SetWindowSize(chan %d) col %d, row %d iotcl() = %d\n",
  1085.             layer->chan, layer->shape.wchars, layer->shape.wlines,
  1086.             retcode);
  1087.  
  1088.     retcode = ioctl(layer->ptyfd, TIOCGWINSZ, &wsize);
  1089.     DO DEBUG("TIOCGWINSZ: col %d, row %d iotcl() = %d\n",
  1090.             wsize.ws_col, wsize.ws_row, retcode);
  1091.  
  1092. #endif
  1093. }  /* SetWindowSize() */
  1094.  
  1095.  
  1096.                 /* ReceiveData() - received keyboard input for layer */
  1097. void
  1098. ReceiveData(chanid, buff, cnt)
  1099. int        chanid;                            /* channel receiving input */
  1100. char    *buff;                            /* buffer containing data */
  1101. int        cnt;                            /* count of data bytes */
  1102. {
  1103.     struct Layer *layer;                /* layer pointer */
  1104.     struct Kbuff *kb;                    /* keybuff pointer */
  1105.  
  1106.     DO DEBUG("ReceiveData(%d, '%.*s')\n", chanid, cnt, buff);
  1107.     /* verify channel */
  1108.     if (chanid <= 0 || chanid > MAXPCHAN)
  1109.         return;                                /* ignore invalid channel */
  1110.     layer = &World[chanid-1];                /* locate target layer */
  1111.  
  1112.     /* add character stream to layer's input buffers for main loop processing */
  1113.     for (kb=layer->kbuff; kb->next; kb=kb->next); /* find oldest buffer */
  1114.     while (cnt--)
  1115.       {    
  1116.         /* if current buffer full then chain in a new one */
  1117.         if (kb->offset+kb->size >= IOSIZE)
  1118.           { kb->next = (struct Kbuff *) malloc(sizeof(struct Kbuff));
  1119.             kb = kb->next;                    /* base new keybuff */
  1120.             kb->next = NULL;                /* no next yet */
  1121.             kb->size = 0;                    /* this character is first */
  1122.             kb->offset = 0;                    /* at zero offset */
  1123.           }
  1124.  
  1125.         /* add new character to the end of this buffer */
  1126.         kb->text[kb->offset+kb->size++] = *buff++; /* insert at end of data */
  1127.       }
  1128.  
  1129. } /* ReceiveData() */
  1130.  
  1131.  
  1132.  
  1133.                     /* InitWorld() - initialize layer structures */
  1134.  
  1135. static void
  1136. InitWorld()
  1137. {
  1138.     struct Layer *layer;                /* layer pointer */
  1139.     struct Kbuff *kb;                    /* keybuff pointer */
  1140.     int        i;                            /* work variable */
  1141.  
  1142.     for (i=0; i<MAXPCHAN; i++)
  1143.       {    layer = &World[i];                /* point to layer */
  1144.         layer->chan = i+1;                /* channel ID */
  1145.         layer->allocated = 0;            /* does not exist yet */
  1146.         layer->lpid = 0;                /* head process */
  1147.         layer->ptyfd = 0;                /* no pseduo pty yet */
  1148.         layer->ptymask = 0;                /* no pty mask yet */
  1149.         layer->slot = 0;                /* no Utmp slot */
  1150.         ClearShape(&layer->shape);        /* clear shape structure */
  1151.  
  1152.         /* allocate the primary input keybuffer for this layer */
  1153.         layer->kbuff = (struct Kbuff *) malloc(sizeof(struct Kbuff));
  1154.         layer->kbuff->next = NULL;        /* no next buffer */
  1155.         layer->kbuff->size = 0;            /* no data in buffer */
  1156.         layer->kbuff->offset = 0;        /* start filling at front */
  1157.  
  1158.       } /* end for layer scan */
  1159.  
  1160. } /* InitWorld() */
  1161.  
  1162.  
  1163.                     /* clearshape() - initialize shape structure */
  1164.  
  1165. static void
  1166. ClearShape(shape)
  1167. struct Shape    *shape;                    /* shape structure pointer */
  1168. {
  1169.     shape->worigv = 0;                    /* default window position */
  1170.     shape->worigh = 0;
  1171.     shape->wlines = 0;                    /* default size */
  1172.     shape->wchars = 0;
  1173.     shape->wfont = 0;                    /* default font size */
  1174.     shape->wattr = 0;                    /* no attributes */
  1175.  
  1176. } /* clearshape() */
  1177.  
  1178.  
  1179.                     /* SigHandler() - process signals */
  1180.  
  1181. SigHandler ()
  1182. {
  1183.     DO DEBUG("GotSignal()\n");
  1184.     while (GotSignal)
  1185.       { GotSignal = 0;
  1186.         DoWait ();        /* handle dead or stopped children processes */
  1187.       }
  1188. }
  1189.  
  1190. static void
  1191. SigChld ()
  1192. {
  1193.     DO DEBUG("SigChld()\n");
  1194.     /* flag child process is stopped or dead */
  1195.     GotSignal = 1;
  1196. }
  1197.  
  1198. static void
  1199. SigHup ()
  1200. {
  1201.     DO DEBUG("SigHup()\n");
  1202.     /* Detach (0); */
  1203.     FQuit(1);            /* stop all processes */
  1204.     /* NOT REACHED */
  1205.  
  1206. }
  1207.  
  1208.     /* DoWait() -  send SIGCONT to stopped windows, Free dead process windows */
  1209. static
  1210. DoWait()
  1211. {
  1212.     register pid;
  1213.     register struct Layer *layer;
  1214.     union wait wstat;
  1215.     int        i;
  1216.  
  1217.     DO DEBUG("DoWait()\n");
  1218.     while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0)
  1219.         /* dead or stopped child process found */
  1220.         for (i=0; i<MAXPCHAN; i++)
  1221.             if ((layer = &World[i])->lpid == pid)
  1222.               { if (WIFSTOPPED (wstat))
  1223.                   {    /* stopped process so restart it */
  1224.                     /*** DO WE REALLY NEED TO DO THIS? ***/
  1225.                     DO DEBUG("killpg(, SIGCONT)\n");
  1226.                     KillPG(layer, SIGCONT);
  1227.                   }
  1228.                 else
  1229.                   {    /* remove dead process's layer */
  1230.                     DO DEBUG("kill dead process window %d\n", layer->chan);
  1231.                      KillWindow (layer);
  1232.                     /* tell MacLayers layer is dead */
  1233.                     SendDelete(layer->chan);
  1234.                   }
  1235.               }
  1236.  
  1237. } /* DoWait() */
  1238.  
  1239.  
  1240.                 /* KillPG() - send signal to layer's process group */
  1241.  
  1242. static void
  1243. KillPG(layer, signal)
  1244. struct Layer    *layer;                    /* layer to signal */
  1245. int                signal;                    /* signal to send */
  1246. {
  1247.     int            retcode;                /* work variable */
  1248.     int            pgrp;                    /* process group for layer */
  1249.     int            tgrp;                    /* terminal control process group */
  1250.  
  1251.     DO DEBUG("KillPG(%d, sig %d)\n", layer->chan, signal);
  1252.  
  1253.     if (layer->lpid)
  1254.       {    pgrp = getpgrp(layer->lpid);    /* get process group */
  1255.         DO DEBUG("getpgrp() = %d\n", pgrp);
  1256.         if (pgrp != -1)
  1257.           {    retcode = killpg(pgrp, signal);    /* signal it */
  1258.             DO DEBUG("killpg() = %d\n", retcode);
  1259.           }
  1260.  
  1261.         /* After a lot of experimenting it was determined that csh
  1262.         ** creates a new terminal control group when it runs a command.
  1263.         ** Thus the above code failed to forward SIGINT to such commands.
  1264.         ** (Csh would get it but just ignore it.) Thus the following code.
  1265.         */ 
  1266.  
  1267.         /* forward SIGINT to the terminal control group also */
  1268.         if (signal == SIGINT)
  1269.           {    retcode = ioctl(layer->ptyfd, TIOCGPGRP, &tgrp);
  1270.             DO DEBUG("ioctl(ptyfd,TIOCGPGRP) termcntlgrp %d, retcode = %d\n",
  1271.                             tgrp, retcode);
  1272.             /* but only if not the same process group */
  1273.             if (retcode != -1 && tgrp != pgrp)
  1274.               {    retcode = killpg(tgrp, signal);    /* signal it */
  1275.                 DO DEBUG("killpg(%d) = %d\n", tgrp, retcode);
  1276.                 }
  1277.           }
  1278.       }
  1279.  
  1280. } /* KillPG() */
  1281.  
  1282.  
  1283.                 /* KillWindow() - remove a layer from the system */
  1284.  
  1285. /* Note: This function does NOT tell MacLayers about the dead layer */
  1286.  
  1287. static
  1288. KillWindow (layer)
  1289. struct Layer *layer;
  1290. {
  1291.     struct Kbuff    *kb;                /* work buffer free pointer */
  1292.  
  1293.     if (layer->allocated)
  1294.       {                                 /* SHOULD THIS BE SIGKILL ??? */
  1295.         if (layer->lpid)                /* if layer process started ... */
  1296.           {    KillPG(layer, SIGHUP);        /* kill processes */
  1297.             layer->lpid = 0;            /* clear pid field */
  1298.           }
  1299.         RemoveUtmp(layer->slot);
  1300.         (void) chmod(layer->tty, 0666);
  1301.         (void) chown(layer->tty, 0, 0);
  1302.         close(layer->ptyfd);
  1303.         DO DEBUG("chmod/chown %s, SendDelete(%d)\n",layer->tty, layer->chan);
  1304.  
  1305.         ClearShape(&layer->shape);        /* reset the shape structure */
  1306.         /* free all keybuffers but one and reprime it */
  1307.         for (kb=layer->kbuff; kb->next; kb=kb->next)
  1308.             free(kb);                    /* free input buffers */
  1309.         kb->size = 0;                    /* empty buffer */
  1310.         kb->offset = 0;                    /* start refill from front */
  1311.         layer->allocated = 0;            /* window no longer allocated */
  1312.       }
  1313.  
  1314. } /* KillWindow() */
  1315.  
  1316.  
  1317.                     /* FAbort() - signal catcher for quitting */
  1318. static void
  1319. FAbort()
  1320. {
  1321.     DO DEBUG("FAbort()\n");
  1322.     FQuit (1);                            /* quit with error exit */
  1323.  
  1324. } /* FAbort() */
  1325.  
  1326.  
  1327.                     /* FQuit() - terminate layers */
  1328. void
  1329. FQuit(exitcode)
  1330. int        exitcode;
  1331. {
  1332.     int            i;
  1333.  
  1334.     DO DEBUG("FQuit(%d)\n",exitcode);
  1335.     for (i=0; i<MAXPCHAN; i++)
  1336.         KillWindow(&World[i]);            /* kill all windows */
  1337.  
  1338.     DO DEBUG("SendQuit()\n");
  1339.     SendQuit();                            /* tell MacLayers to exit layers mode */
  1340.     SetTTY (0, &OldMode);
  1341.     if (RealTtyMode)
  1342.         (void) chmod(RealTtyName, RealTtyMode);    /* restore mode */
  1343.     if (RealSlot)
  1344.         WriteUtmp(RealSlot, &RealUtmp);    /* restore original login */
  1345.     FinitTerm ();
  1346.     sleep(2);                            /* wait for port to reset */
  1347.     printf ("[layers terminated]\n");
  1348.  
  1349.     exit (exitcode);
  1350.  
  1351. } /* FQuit() */
  1352.  
  1353.  
  1354.                     /* MakeWindow() - create new layer */
  1355. static
  1356. MakeWindow (chan, prog, args, dir, lflag, shape)
  1357. int        chan;                            /* zero or channel to use for window */
  1358. char    *prog;
  1359. char     **args;
  1360. char    *dir;
  1361. int        lflag;                            /* one if this to be logged in */
  1362. struct Shape *shape;                    /* shape to use for window */
  1363. {
  1364.     register struct Layer *layer;
  1365.     register char **cp;
  1366.     register f, j;
  1367.     int tf;
  1368.     int mypid;
  1369.     char ebuf[10];
  1370.  
  1371.     DO DEBUG("MakeWindow(%d, %s, %s, dir %s, ",
  1372.                 chan, prog, args[0], dir ? dir : "(none)");
  1373.     DO DEBUG("login %d\n", lflag);
  1374.     DO DEBUG("    origv %d, origh %d, lines %d, chars %d, ",
  1375.                 shape->worigv, shape->worigh, shape->wlines, shape->wchars);
  1376.     DO DEBUG("font %d, attr 0x%x\n", shape->wfont, shape->wattr);
  1377.                     
  1378.     if ((f = OpenPTY ()) == -1)
  1379.       { Msg (0, "No more PTYs.");
  1380.         return ( -1 );
  1381.       }
  1382.  
  1383.     /* if channel not given obtain one from MacLayers */
  1384.     if (chan == 0)
  1385.       {    chan = SendNew(shape);                /* try to get free window */
  1386.         if (chan == 0)
  1387.             {    Msg (0, "No more windows.");
  1388.             return ( -1 );
  1389.             }
  1390.         DO DEBUG("SendNew() == %d\n", chan);
  1391.       }
  1392.  
  1393.     /* verify channel */
  1394.     if (chan <= 0 || chan > MAXPCHAN)
  1395.       {    Msg(0, "Invalid channel %d.", chan);
  1396.         return ( -1 );
  1397.       }
  1398.  
  1399.     /* login this window if it's layer #1 */
  1400.     if (chan == 1)
  1401.         lflag = 1;
  1402.                     
  1403.     if (lflag == -1)
  1404.         lflag = loginflag;
  1405.     
  1406. #ifdef USRLIMIT
  1407.     /*
  1408.      *    Count current number of users, and if logging windows in,
  1409.      */
  1410.     if (lflag == 1)
  1411.       { (void) lseek (utmpf, 0, 0);
  1412.         UserCount = 0;
  1413.         while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0)
  1414.           { if (utmpbuf.ut_name[0] != '\0')
  1415.                 UserCount++;
  1416.           }
  1417.         if (UserCount >= USRLIMIT)
  1418.           { Msg (0, "User limit reached.  Window will not be logged in.");
  1419.             lflag = 0;
  1420.           }
  1421.       }
  1422. #endif USRLIMIT
  1423.  
  1424.     layer = &World[chan-1];                    /* find layer structure */
  1425.     layer->shape = *shape;                    /* install new window shape */
  1426.  
  1427.     /* ??? What do we do if layer is still active as far as we're concerned? */
  1428.     if (layer->allocated)
  1429.       {    DO DEBUG("??? newlayer not free !!!\n");
  1430.         KillWindow(layer);                    /* kill off old layer */
  1431.         SendDelete(layer->chan);            /* kill window back off */
  1432.         Msg (0, "Makewindow error: Duplicate active layer %d.", chan);
  1433.         return ( -1 );                        /* return failed */
  1434.       }
  1435.  
  1436.     layer->allocated = 1;                    /* show layer now in use */
  1437.     BuildTitle(chan, prog, args);            /* install window title */
  1438.  
  1439.     (void) fcntl (f, F_SETFL, FNDELAY);
  1440.     layer->ptyfd = f;                        /* pseudo pty for task's I/O */
  1441.     layer->ptymask = 1<<f;                    /* set pty device mask */
  1442.     strncpy (layer->cmd, Filename (args[0]), MAXSTR-1);
  1443.     layer->cmd[MAXSTR-1] = '\0';
  1444.     strncpy (layer->tty, TtyName, MAXSTR-1);
  1445.     DO DEBUG("forking %s, tty %s, ptyfd %d, mask %x\n",
  1446.                 layer->cmd, layer->tty, layer->ptyfd, layer->ptymask);
  1447.     (void) chown (TtyName, getuid (), getgid ());
  1448.     if (lflag == 1)
  1449.       { layer->slot = SetUtmp(TtyName, chan == 1);
  1450.         if (chan == 1 && RealTtyMode)
  1451.             /* set to original tty umask */
  1452.             (void) chmod(TtyName, RealTtyMode);
  1453.         else
  1454.             /* force to this mode */
  1455.             (void) chmod(TtyName, TtyMode);
  1456.       }
  1457.     else
  1458.       { layer->slot = -1;
  1459.         /* do not allow any other user access to this device */
  1460.         (void) chmod (TtyName, 0600);
  1461.       }
  1462.     switch (layer->lpid = fork ())
  1463.     { case -1:
  1464.         Msg (errno, "fork");
  1465.         layer->lpid = 0;                    /* clear pid field */
  1466.         return ( -1 );                        /* return failed */
  1467.  
  1468.       case 0:
  1469.         signal (SIGHUP, SIG_DFL);
  1470.         signal (SIGINT, SIG_DFL);
  1471.         signal (SIGQUIT, SIG_DFL);
  1472.         signal (SIGTERM, SIG_DFL);
  1473.         signal (SIGTTIN, SIG_DFL);
  1474.         signal (SIGTTOU, SIG_DFL);
  1475.         signal (SIGALRM, SIG_DFL);
  1476.         setuid (getuid ());
  1477.         setgid (getgid ());
  1478.         if (dir && chdir (dir) == -1)
  1479.           { SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
  1480.             exit (1);
  1481.           }
  1482.         mypid = getpid ();
  1483.         ioctl (DevTty, TIOCNOTTY, (char *)0);
  1484.         if ((tf = open (TtyName, O_RDWR)) == -1)
  1485.           { SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]);
  1486.             exit (1);
  1487.           }
  1488.         DO DEBUG("Now in new process\n");
  1489.         (void) dup2 (tf, 0);
  1490.         (void) dup2 (tf, 1);
  1491.         (void) dup2 (tf, 2);
  1492.         for (f = getdtablesize () - 1; f > 2; f--)
  1493.             close (f);
  1494.         ioctl (0, TIOCSPGRP, &mypid);
  1495.         (void) setpgrp (0, mypid);
  1496.         SetTTY (0, &OldMode);
  1497.  
  1498.           {    struct    winsize    wsize;        /* window size structure */
  1499.             int            retcode;        /* ioctl return code */
  1500.  
  1501.             wsize.ws_col = layer->shape.wchars; /* character width */
  1502.             wsize.ws_row = layer->shape.wlines; /* window height */
  1503.             wsize.ws_xpixel = 0;                /* necessary? */
  1504.             wsize.ws_ypixel = 0;
  1505.             /* update O/S window state */
  1506.             retcode = ioctl(0, TIOCSWINSZ, &wsize);
  1507.           }
  1508.         (void) umask(Oumask);            /* restore user's original umask */
  1509.         NewEnv[2] = MakeTermcap(layer->shape.wlines, layer->shape.wchars);
  1510.         sprintf (ebuf, "LAYER=%d", chan);
  1511.         NewEnv[3] = ebuf;
  1512.         execvpe (prog, args, NewEnv);
  1513.         printf("%s: cannot exec %s: %s", myname, prog, sys_errlist[errno]);
  1514.         exit (1);
  1515.     }
  1516.  
  1517.     return ( chan );
  1518.  
  1519. } /* MakeWindow() */
  1520.  
  1521. static
  1522. execvpe (prog, args, env)
  1523. char *prog, **args, **env;
  1524. {
  1525.     register char *path, *p;
  1526.     char buf[1024];
  1527.     char *shargs[MAXARGS+1];
  1528.     register i;
  1529.     register eaccess = 0;
  1530.  
  1531.     if (prog[0] == '/')
  1532.         path = "";
  1533.     else
  1534.     if ((path = getenv ("PATH")) == 0)
  1535.         path = DefaultPath;
  1536.     do
  1537.       { p = buf;
  1538.         while (*path && *path != ':')
  1539.             *p++ = *path++;
  1540.         if (p > buf)
  1541.             *p++ = '/';
  1542.         strcpy (p, prog);
  1543.         if (*path)
  1544.             ++path;
  1545.         execve (buf, args, env);
  1546.         switch (errno)
  1547.         { case ENOEXEC:
  1548.             shargs[0] = DefaultShell;
  1549.             shargs[1] = buf;
  1550.             for (i = 1; shargs[i+1] = args[i]; ++i);
  1551.             execve (DefaultShell, shargs, env);
  1552.             return;
  1553.  
  1554.           case EACCES:
  1555.             eaccess = 1;
  1556.             break;
  1557.  
  1558.           case ENOMEM: case E2BIG: case ETXTBSY:
  1559.             return;
  1560.  
  1561.         } /* end switch */
  1562.  
  1563.     } while (*path);
  1564.  
  1565.     if (eaccess)
  1566.         errno = EACCES;
  1567.  
  1568. } /* execvpe() */
  1569.  
  1570.  
  1571.                 /* BuildTitle() - create and install window title */
  1572.  
  1573. static void
  1574. BuildTitle(chan, prog, args)
  1575. int            chan;                        /* channel for title */
  1576. char        *prog;                        /* program being executed */
  1577. char        **args;                        /* arg list */
  1578. {
  1579.     int        i;                            /* arg scan index */
  1580.     char    buff[1024];                    /* super huge title buffer */
  1581.  
  1582.     /* skip any leading "/bin/" */
  1583.     if (strncmp(prog, "/bin/", 5) == 0)
  1584.         strcpy(buff, prog+5);            /* leave /bin off */
  1585.     else
  1586.         strcpy(buff, prog);                /* start with program name */
  1587.  
  1588.     /* add all aguments but stop if option ("-") seen */
  1589.     for (i=1; args[i] && args[i][0] != '-'; i++)
  1590.       {    strcat(buff, " ");                /* delimiter */
  1591.         strcat(buff, args[i]);            /* add next parameter */
  1592.       }
  1593.  
  1594.     SendTitle(chan, buff, strlen(buff)); /* set new window title */
  1595.  
  1596. } /* BuildTitle() */
  1597.  
  1598.  
  1599. #ifdef sequent
  1600. static
  1601. OpenPTY ()
  1602. {
  1603.     char *m, *s;
  1604.     register f;
  1605.  
  1606.     f = getpseudotty (&s, &m);
  1607.     strncpy (PtyName, m, sizeof (PtyName));
  1608.     strncpy (TtyName, s, sizeof (TtyName));
  1609.     ioctl (f, TIOCFLUSH, (char *)0);
  1610.     return (f);
  1611. }
  1612.  
  1613. #else
  1614.  
  1615. static
  1616. OpenPTY ()
  1617. {
  1618.     register char *p, *l, *d;
  1619.     register i, f, tf;
  1620.  
  1621.     strcpy (PtyName, PtyProto);
  1622.     strcpy (TtyName, TtyProto);
  1623.     for (p = PtyName, i = 0; *p != 'X'; ++p, ++i);
  1624.     for (l = "qpr"; *p = *l; ++l)
  1625.       { for (d = "0123456789abcdef"; p[1] = *d; ++d)
  1626.           { if ((f = open (PtyName, O_RDWR)) != -1)
  1627.               { TtyName[i] = p[0];
  1628.                 TtyName[i+1] = p[1];
  1629.                 if ((tf = open (TtyName, O_RDWR)) != -1)
  1630.                   { close (tf);
  1631.                     return f;
  1632.                   }
  1633.                 close (f);
  1634.               }
  1635.           }
  1636.       }
  1637.  
  1638.     return -1;
  1639.  
  1640. } /* OpenPTY() */
  1641. #endif
  1642.  
  1643. static
  1644. SetTTY (fd, mp)
  1645. struct mode *mp;
  1646. {
  1647.     ioctl (fd, TIOCSETP, &mp->m_ttyb);
  1648.     ioctl (fd, TIOCSETC, &mp->m_tchars);
  1649.     ioctl (fd, TIOCSLTC, &mp->m_ltchars);
  1650.     ioctl (fd, TIOCLSET, &mp->m_lmode);
  1651.     ioctl (fd, TIOCSETD, &mp->m_ldisc);
  1652.  
  1653. } /* SetTTY() */
  1654.  
  1655. static
  1656. GetTTY (fd, mp)
  1657. struct mode *mp;
  1658. {
  1659.     ioctl (fd, TIOCGETP, &mp->m_ttyb);
  1660.     ioctl (fd, TIOCGETC, &mp->m_tchars);
  1661.     ioctl (fd, TIOCGLTC, &mp->m_ltchars);
  1662.     ioctl (fd, TIOCLGET, &mp->m_lmode);
  1663.     ioctl (fd, TIOCGETD, &mp->m_ldisc);
  1664.  
  1665. } /* GetTTY() */
  1666.  
  1667. static
  1668. SetMode (op, np)
  1669. struct mode *op, *np;
  1670. {
  1671.     *np = *op;
  1672. #if 1
  1673.     if (flowctl)
  1674.       {    np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  1675.         np->m_ttyb.sg_flags |= CBREAK | ANYP;
  1676.       }
  1677.     else
  1678.         np->m_ttyb.sg_flags = RAW | ANYP;
  1679. #else
  1680.     np->m_ttyb.sg_flags &= ~(CRMOD|ECHO);
  1681.     np->m_ttyb.sg_flags |= CBREAK | ANYP;
  1682. #endif
  1683.     np->m_tchars.t_intrc = -1;
  1684.     np->m_tchars.t_quitc = -1;
  1685.     if (!flowctl)
  1686.       { np->m_tchars.t_startc = -1;
  1687.         np->m_tchars.t_stopc = -1;
  1688.       }
  1689.     np->m_ltchars.t_suspc = -1;
  1690.     np->m_ltchars.t_dsuspc = -1;
  1691.     np->m_ltchars.t_flushc = -1;
  1692.     np->m_ltchars.t_lnextc = -1;
  1693.  
  1694. } /* SetMode() */
  1695.  
  1696. static char *
  1697. GetTtyName ()
  1698. {
  1699.     int n;
  1700.     char *p;
  1701.  
  1702.     for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++);
  1703.  
  1704.     if (!p || *p == '\0')
  1705.         Msg (0, "layers must run on a tty.");
  1706.  
  1707.     return ( p );
  1708.  
  1709. } /* GetTtyName() */
  1710.  
  1711.  
  1712. static
  1713. Kill (pid, sig)
  1714. {
  1715.     if (pid != 0)
  1716.         (void) kill (pid, sig);
  1717. }
  1718.  
  1719.             /* GetSockName() - set SockName; if LTY env return 1 else 0 */
  1720. static
  1721. GetSockName ()
  1722. {
  1723.     register client;
  1724.     static char buf[2*MAXSTR];
  1725.  
  1726.     if (!mflag && (SockName = getenv ("LTY")) != 0 && *SockName != '\0')
  1727.       { client = 1;
  1728.         setuid (getuid ());
  1729.         setgid (getgid ());
  1730.       }
  1731.     else
  1732.       { sprintf (buf, "%s.%s", HostName, Filename (RealTtyName));
  1733.         SockName = buf;
  1734.         client = 0;
  1735.       }
  1736.     return client;
  1737.  
  1738. } /* GetSockName() */
  1739.  
  1740. static
  1741. MakeServerSocket ()
  1742. {
  1743.     register s;
  1744.     struct sockaddr_un a;
  1745.     char *p;
  1746.  
  1747.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1748.         Msg (errno, "socket");
  1749.     a.sun_family = AF_UNIX;
  1750.     strcpy (SockNamePtr, SockName);
  1751.     strcpy (a.sun_path, SockPath);
  1752.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1)
  1753.       { p = Filename (SockPath);
  1754.         Msg (0, "You already have a layers running on %s.", p);
  1755.         /*NOTREACHED*/
  1756.       }
  1757.     DO DEBUG("MakeServerSocket: unlink(SockPath)/bind()/chown/listen\n");
  1758.     (void) unlink (SockPath);
  1759.     if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  1760.         Msg (errno, "bind");
  1761.     (void) chown (SockPath, getuid (), getgid ());
  1762.     if (listen (s, 5) == -1)
  1763.         Msg (errno, "listen");
  1764.     return s;
  1765.  
  1766. } /* MakeServerSocket() */
  1767.  
  1768. static
  1769. MakeClientSocket (err)
  1770. {
  1771.     register s;
  1772.     struct sockaddr_un a;
  1773.  
  1774.     if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1)
  1775.         Msg (errno, "socket");
  1776.     a.sun_family = AF_UNIX;
  1777.     strcpy (SockNamePtr, SockName);
  1778.     strcpy (a.sun_path, SockPath);
  1779.     if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1)
  1780.       { if (err)
  1781.           { Msg (errno, "connect: %s", SockPath); }
  1782.         else
  1783.           { close (s);
  1784.             return -1;
  1785.           }
  1786.       }
  1787.     return s;
  1788.  
  1789. } /* MakeClientSocket() */
  1790.  
  1791. static
  1792. SendCreateMsg (s, ac, av, lflag, shape)
  1793. char **av;
  1794. struct Shape *shape;
  1795. {
  1796.     struct msg m;
  1797.     register char *p;
  1798.     register len, n;
  1799.     char    *pwd;                    /* PWD environment string */
  1800.  
  1801.     DO DEBUG("SendCreateMsg(%d, ac %d, lflag %d\n", s, ac, lflag);
  1802.     m.type = MSG_CREATE;
  1803.     p = m.m.create.line;
  1804.     for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n)
  1805.       { len = strlen (*av) + 1;
  1806.         if (p + len >= m.m.create.line+MAXLINE)
  1807.             break;
  1808.         strcpy (p, *av);
  1809.         p += len;
  1810.       }
  1811.     DO DEBUG("  nargs %d, create line = '%s'\n", n, m.m.create.line);
  1812.     m.m.create.nargs = n;
  1813.     m.m.create.lflag = lflag;
  1814.     m.m.create.shape = *shape;            /* pass window shape */
  1815.  
  1816.     /* Since Suns can hang up on getwd() [damn their stupid networking]
  1817.     ** we try to get the current working directory first from the PWD
  1818.     ** environment variable.
  1819.     */
  1820.     if ((pwd=getenv("PWD")) && strlen(pwd) < 1024)
  1821.         (void) strcpy(m.m.create.dir, pwd);
  1822.     else
  1823.     if (getwd (m.m.create.dir) == 0)
  1824.       {    DO DEBUG("getwd() failed!!\n");
  1825.         Msg (0, "%s", m.m.create.dir);
  1826.       }
  1827.     DO DEBUG("  create.dir = '%s'\n", m.m.create.dir);
  1828.  
  1829.     if (write (s, (char *)&m, sizeof (m)) != sizeof (m))
  1830.       {    DO DEBUG("  write failed!!\n");
  1831.         Msg (errno, "write");
  1832.       }
  1833.     DO DEBUG("SendCreateMsg() done\n");
  1834.  
  1835. } /* SendCreateMsg() */
  1836.  
  1837. /*VARARGS1*/
  1838. static
  1839. SendErrorMsg (fmt, p1, p2, p3, p4, p5, p6)
  1840. char *fmt;
  1841. {
  1842.     register s;
  1843.     struct msg m;
  1844.  
  1845.     s = MakeClientSocket (1);
  1846.     m.type = MSG_ERROR;
  1847.     sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6);
  1848.     (void) write (s, (char *)&m, sizeof (m));
  1849.     close (s);
  1850.     sleep (2);
  1851. }
  1852.  
  1853. static
  1854. ReceiveMsg (s)
  1855. {
  1856.     register ns;
  1857.     struct sockaddr_un a;
  1858.     int left, len = sizeof (a);
  1859.     struct msg m;
  1860.     char *p;
  1861.  
  1862.     DO DEBUG ("ReceiveMsg()\n");
  1863.     if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1)
  1864.       { Msg (errno, "accept");
  1865.         return;
  1866.       }
  1867.     p = (char *)&m;
  1868.     left = sizeof (m);
  1869.     while (left > 0 && (len = read (ns, p, left)) > 0)
  1870.       { p += len;
  1871.         left -= len;
  1872.       }
  1873.     close (ns);
  1874.     if (len == -1)
  1875.         Msg (errno, "read");
  1876.     if (left > 0)
  1877.         return;
  1878.     switch (m.type)
  1879.     { case MSG_CREATE:
  1880.         DO DEBUG("MSG_CREATE:\n");
  1881.         ExecCreate (&m);
  1882.         break;
  1883.  
  1884.       case MSG_ERROR:
  1885.         DO DEBUG("MSG_ERROR:\n");
  1886.         Msg (0, "%s", m.m.message);
  1887.         break;
  1888.  
  1889.       default:
  1890.         Msg (0, "Invalid message (type %d).", m.type);
  1891.  
  1892.     } /* end switch */
  1893.  
  1894. } /* ReceiveMsg() */
  1895.  
  1896. static
  1897. ExecCreate (mp)
  1898. struct msg *mp;
  1899. {
  1900.     char *args[MAXARGS];
  1901.     register n;
  1902.     register char **pp = args, *p = mp->m.create.line;
  1903.  
  1904.     for (n = mp->m.create.nargs; n > 0; --n)
  1905.       { *pp++ = p;
  1906.         p += strlen (p) + 1;
  1907.       }
  1908.     *pp = 0;
  1909.     n = MakeWindow (0, mp->m.create.line, args, mp->m.create.dir,
  1910.                         mp->m.create.lflag, &mp->m.create.shape);
  1911.  
  1912. } /* ExecCreate() */
  1913.  
  1914. #if 0
  1915. static
  1916. ReadRc (fn)
  1917. char *fn;
  1918. {
  1919.     FILE *f;
  1920.     register char *p, **pp, **ap;
  1921.     register argc, num, c;
  1922.     char buf[256];
  1923.     char *args[MAXARGS];
  1924.     int key;
  1925.     struct Shape shape;                        /* shape for new window */
  1926.  
  1927.     ClearShape(&shape);                        /* initialize shape */
  1928.     ap = args;
  1929.     if (access (fn, R_OK) == -1)
  1930.         return;
  1931.     if ((f = fopen (fn, "r")) == NULL)
  1932.         return;
  1933.     while (fgets (buf, 256, f) != NULL)
  1934.       { if (p = rindex (buf, '\n'))
  1935.             *p = '\0';
  1936.         if ((argc = Parse (fn, buf, ap)) == 0)
  1937.             continue;
  1938.         if (strcmp (ap[0], "escape") == 0)
  1939.           { p = ap[1];
  1940.             if (argc < 2 || strlen (p) != 2)
  1941.                 Msg (0, "%s: two characters required after escape.", fn);
  1942.             Esc = *p++;
  1943.             MetaEsc = *p;
  1944.             ktab[Esc].type = KEY_OTHER;
  1945.           }
  1946.         else
  1947.         if (strcmp (ap[0], "login") == 0)
  1948.           { loginflag = 1;
  1949.           }
  1950.         else
  1951.         if (strcmp (ap[0], "unlogin") == 0)
  1952.           { loginflag = 0; }
  1953.         else
  1954.         if (strcmp (ap[0], "nologin") == 0)
  1955.           { loginflag = 0; }
  1956.         else
  1957.         if (strcmp (ap[0], "chdir") == 0)
  1958.            { p = argc < 2 ? home : ap[1];
  1959.             if (chdir (p) == -1)
  1960.             Msg (errno, "%s", p);
  1961.           }
  1962.         else
  1963.         if (strcmp (ap[0], "mode") == 0)
  1964.           { if (argc != 2)
  1965.               { Msg (0, "%s: mode: one argument required.", fn); }
  1966.             else
  1967.             if (!IsNum (ap[1], 7))
  1968.               { Msg (0, "%s: mode: octal number expected.", fn); }
  1969.             else
  1970.                 (void) sscanf (ap[1], "%o", &TtyMode);
  1971.           }
  1972.         else
  1973.         if (strcmp (ap[0], "bell") == 0)
  1974.           { if (argc != 2)
  1975.               { Msg (0, "%s: bell: one argument required.", fn); }
  1976.             else
  1977.               { if ((BellString = malloc (strlen (ap[1]) + 1)) == 0)
  1978.                     Msg (0, "Out of memory.");
  1979.                 istrcpy (BellString, ap[1]);
  1980.               }
  1981.           }
  1982.         else
  1983.         if (strcmp (ap[0], "screen") == 0)
  1984.           { num = 0;
  1985.             if (argc > 1 && IsNum (ap[1], 10))
  1986.               { num = atoi (ap[1]);
  1987.                 if (num < 0 || num > MAXWIN-1)
  1988.                     Msg (0, "%s: illegal screen number %d.", fn, num);
  1989.                 --argc; ++ap;
  1990.               }
  1991.             if (argc < 2)
  1992.               { ap[1] = ShellProg; argc = 2; }
  1993.             ap[argc] = 0;
  1994.             (void) MakeWindow (0, ap[1], ap+1, (char *)0, loginflag, &shape);
  1995.           }
  1996.         else
  1997.         if (strcmp (ap[0], "bind") == 0)
  1998.           { p = ap[1];
  1999.             if (argc < 2 || *p == '\0')
  2000.                 Msg (0, "%s: key expected after bind.", fn);
  2001.             if (p[1] == '\0')
  2002.               { key = *p; }
  2003.             else
  2004.             if (p[0] == '^' && p[1] != '\0' && p[2] == '\0')
  2005.               { c = p[1];
  2006.                 if (isupper (c))
  2007.                     p[1] = tolower (c);    
  2008.                 key = Ctrl(c);
  2009.               }
  2010.             else
  2011.             if (IsNum (p, 7))
  2012.               { (void) sscanf (p, "%o", &key);
  2013.               }
  2014.             else
  2015.               { Msg (0, "%s: bind: character, ^x, or octal number expected.", fn); }
  2016.             ktab[key].lflag = loginflag;
  2017.             if (argc < 3)
  2018.               { ktab[key].type = 0;
  2019.               }
  2020.             else
  2021.               { for (pp = KeyNames; *pp; ++pp)
  2022.                 if (strcmp (ap[2], *pp) == 0) break;
  2023.                 if (*pp)
  2024.                   { ktab[key].type = pp-KeyNames+1; }
  2025.                 else
  2026.                   { ktab[key].type = KEY_CREATE;
  2027.                     ktab[key].args = SaveArgs (argc-2, ap+2);
  2028.                   }
  2029.               }
  2030.           }
  2031.         else
  2032.             Msg (0, "%s: unknown keyword \"%s\".", fn, ap[0]);
  2033.       }
  2034.     (void) fclose (f);
  2035.  
  2036. } /* ReadRc() */
  2037.  
  2038. static
  2039. Parse (fn, buf, args)
  2040. char *fn, *buf, **args;
  2041. {
  2042.     register char *p, **ap;
  2043.     register delim, argc;
  2044.  
  2045.     p = buf;
  2046.     ap = args;
  2047.     argc = 0;
  2048.     for (;;)
  2049.       { while (*p && (*p == ' ' || *p == '\t'))
  2050.             ++p;
  2051.         if (*p == '\0' || *p == '#')
  2052.             return argc;
  2053.         if (argc > MAXARGS-1)
  2054.             Msg (0, "%s: too many tokens.", fn);
  2055.         delim = 0;
  2056.         if (*p == '"' || *p == '\'')
  2057.           { delim = *p; *p = '\0'; ++p; }
  2058.         ++argc;
  2059.         *ap = p; ++ap;
  2060.         while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  2061.             ++p;
  2062.         if (*p == '\0')
  2063.           { if (delim)
  2064.                 Msg (0, "%s: Missing quote.", fn);
  2065.             else
  2066.                 return argc;
  2067.           }
  2068.         *p++ = '\0';
  2069.       }
  2070.  
  2071. } /* Parse() */
  2072.  
  2073. static char **
  2074. SaveArgs (argc, argv)
  2075. register argc;
  2076. register char **argv;
  2077. {
  2078.     register char **ap, **pp;
  2079.  
  2080.     if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0)
  2081.         Msg (0, "Out of memory.");
  2082.     while (argc--)
  2083.       { if ((*pp = malloc (strlen (*argv)+1)) == 0)
  2084.             Msg (0, "Out of memory.");
  2085.         strcpy (*pp, *argv);
  2086.         ++pp; ++argv;
  2087.       }
  2088.     *pp = 0;
  2089.     return ap;
  2090.  
  2091. } /* SaveArgs() */
  2092. #endif
  2093.  
  2094. static
  2095. MakeNewEnv ()
  2096. {
  2097.     register char **op, **np = NewEnv;
  2098.     static char buf[MAXSTR];
  2099.  
  2100.     if (strlen (SockName) > MAXSTR-5)
  2101.         SockName = "?";
  2102.     sprintf (buf, "LTY=%s", SockName);
  2103.     *np++ = buf;
  2104.     *np++ = Term;
  2105.     np += 2;
  2106.     for (op = environ; *op; ++op)
  2107.       { if (np == NewEnv + MAXARGS - 1)
  2108.             break;
  2109.         if (   !IsSymbol (*op, "TERM")
  2110.             && !IsSymbol (*op, "TERMCAP")
  2111.             && !IsSymbol (*op, "LTY")
  2112.            )
  2113.             *np++ = *op;
  2114.       }
  2115.     *np = 0;
  2116.  
  2117. } /* MakeNewEnv() */
  2118.  
  2119. static
  2120. IsSymbol (e, s)
  2121. register char *e, *s;
  2122. {
  2123.     register char *p;
  2124.     register n;
  2125.  
  2126.     for (p = e; *p && *p != '='; ++p);
  2127.     if (*p)
  2128.       { *p = '\0';
  2129.         n = strcmp (e, s);
  2130.         *p = '=';
  2131.         return n == 0;
  2132.       }
  2133.  
  2134.     return 0;
  2135.  
  2136. } /* IsSymbol() */
  2137.  
  2138. /*VARARGS2*/
  2139. Msg (err, fmt, p1, p2, p3, p4, p5, p6)
  2140. char *fmt;
  2141. {
  2142.     char buf[1024];
  2143.     register char *p = buf;
  2144.  
  2145.     sprintf (p, fmt, p1, p2, p3, p4, p5, p6);
  2146.     if (err)
  2147.       { p += strlen (p);
  2148.         if (err > 0 && err < sys_nerr)
  2149.             sprintf (p, ": %s", sys_errlist[err]);
  2150.         else
  2151.             sprintf (p, ": Error %d", err);
  2152.       }
  2153.     if (!Abortonmsg)
  2154.       { /* MakeStatus (buf, curr);*/
  2155.         printf("%s\r\n", buf);
  2156.       } 
  2157.     else
  2158.       { printf ("%s\r\n", buf);
  2159.         exit (1);
  2160.       }
  2161.  
  2162. } /* Msg() */
  2163.  
  2164. static char *
  2165. Filename (s)
  2166. char *s;
  2167. {
  2168.     register char *p;
  2169.  
  2170.     p = s + strlen (s) - 1;
  2171.     while (p >= s && *p != '/')
  2172.         --p;
  2173.     return ++p;
  2174.  
  2175. } /* Filename() */
  2176.  
  2177. static
  2178. IsNum (s, base)
  2179. register char *s;
  2180. register base;
  2181. {
  2182.     for (base += '0'; *s; ++s)
  2183.         if (*s < '0' || *s > base)
  2184.             return 0;
  2185.     return 1;
  2186.  
  2187. } /* IsNum() */
  2188.  
  2189.  
  2190. static
  2191. InitUtmp ()
  2192. {
  2193.     if ((utmpf = open (UtmpName, O_RDWR)) == -1)
  2194.       { if (errno != EACCES)
  2195.             Msg (errno, UtmpName);
  2196.         return;
  2197.       }
  2198.     utmp = 1;
  2199.  
  2200. } /* InitUtmp() */
  2201.  
  2202.  
  2203. static int
  2204. FindUtmp(name)
  2205. char *name;
  2206. {
  2207.     register char *p;
  2208.     register struct ttyent *tp;
  2209.     register slot;
  2210.  
  2211.     DO DEBUG("FindUtmp(%s)\n", name);
  2212.     slot = 1;
  2213.     if (!utmp)
  2214.         return 0;
  2215.     if (p = rindex (name, '/'))
  2216.         ++p;
  2217.     else
  2218.         p = name;
  2219.     setttyent ();
  2220.     while (   (tp = getttyent ()) != NULL
  2221.            && strcmp (p, tp->ty_name) != 0
  2222.           )
  2223.         ++slot;
  2224.     if (tp == NULL)
  2225.         return 0;
  2226.  
  2227.     DO DEBUG(" slot %d\n", slot);
  2228.     return slot;
  2229.  
  2230. } /* FindUtmp() */
  2231.  
  2232.  
  2233. static int
  2234. SetUtmp (name, mainlogin)
  2235. char    *name;                            /* tty name */
  2236. int        mainlogin;                        /* this is primary login */
  2237. {
  2238.     register char *p;
  2239.     register slot;
  2240.     struct utmp u;
  2241.  
  2242.     if ((slot=FindUtmp(name)) == 0)
  2243.         return ( 0 );
  2244.  
  2245.     if (p = rindex (name, '/'))
  2246.         ++p;
  2247.     else
  2248.         p = name;
  2249.  
  2250.     strncpy (u.ut_line, p, 8);
  2251.     strncpy (u.ut_name, LoginName, 8);
  2252. #if 1
  2253.     strncpy(u.ut_host,  Filename (RealTtyName), 16); /* host is real tty */
  2254. #else
  2255.     u.ut_host[0] = '\0';
  2256. #endif
  2257.     if (RealSlot && mainlogin)
  2258.         u.ut_time = RealUtmp.ut_time;        /* use original login time */
  2259.     else
  2260.         time (&u.ut_time);
  2261.     (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  2262.     (void) write (utmpf, (char *)&u, sizeof (u));
  2263.  
  2264.     return ( slot );
  2265.  
  2266. } /* SetUtmp() */
  2267.  
  2268. static int
  2269. ReadUtmp(slot, entry)
  2270. int        slot;                                /* slot to read */
  2271. struct utmp    *entry;                            /* entry to read into */
  2272. {
  2273.     int        cnt;                            /* return count */
  2274.  
  2275.     if (!utmp)
  2276.         return;                                /* no utmp access */
  2277.  
  2278.     (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
  2279.     cnt =  read(utmpf, (char *)entry, sizeof(struct utmp));
  2280.     DO DEBUG("ReadUtmp cnt %d, errno %d, line %.8s, name %.8s, host %.16s\n",
  2281.         cnt, errno, entry->ut_line, entry->ut_name, entry->ut_host);
  2282.  
  2283.     return ( cnt );
  2284.  
  2285. } /* ReadUtmp() */
  2286.  
  2287. static void
  2288. WriteUtmp(slot, entry)
  2289. int        slot;                                /* slot to write */
  2290. struct utmp    *entry;                            /* entry to write from */
  2291. {
  2292.     int        cnt;                            /* write return code */
  2293.  
  2294.     if (!utmp)
  2295.         return;                                /* no utmp access */
  2296.  
  2297.     (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0);
  2298.     cnt = write(utmpf, (char *)entry, sizeof(struct utmp));
  2299.     DO DEBUG("WriteUtmp() slot %d cnt %d line %.8s name %.8s host %.16s\n",
  2300.                 slot, cnt, entry->ut_line, entry->ut_name, entry->ut_host);
  2301.  
  2302. } /* WriteUtmp() */
  2303.  
  2304. static
  2305. RemoveUtmp (slot)
  2306. {
  2307.     struct utmp u;
  2308.  
  2309.     if (slot)
  2310.       { bzero ((char *)&u, sizeof (u));
  2311.         (void) lseek (utmpf, (long)(slot * sizeof (u)), 0);
  2312.         (void) write (utmpf, (char *)&u, sizeof (u));
  2313.       }
  2314.  
  2315. } /* RemoveUtmp() */
  2316.  
  2317. #ifndef GETTTYENT
  2318.  
  2319. static
  2320. setttyent ()
  2321. {
  2322.     struct stat s;
  2323.     register f;
  2324.     register char *p, *ep;
  2325.  
  2326.     if (ttnext)
  2327.       { ttnext = tt;
  2328.         return;
  2329.       }
  2330.     if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1)
  2331.         Msg (errno, ttys);
  2332.     if ((tt = malloc (s.st_size + 1)) == 0)
  2333.         Msg (0, "Out of memory.");
  2334.     if (read (f, tt, s.st_size) != s.st_size)
  2335.         Msg (errno, ttys);
  2336.     close (f);
  2337.     for (p = tt, ep = p + s.st_size; p < ep; ++p)
  2338.         if (*p == '\n')
  2339.             *p = '\0';
  2340.     *p = '\0';
  2341.     ttnext = tt;
  2342.  
  2343. } /* setttyent() */
  2344.  
  2345. static struct ttyent *
  2346. getttyent ()
  2347. {
  2348.     static struct ttyent t;
  2349.  
  2350.     if (*ttnext == '\0')
  2351.         return NULL;
  2352.     t.ty_name = ttnext + 2;
  2353.     ttnext += strlen (ttnext) + 1;
  2354.     return &t;
  2355.  
  2356. } /* getttyend() */
  2357.  
  2358. #endif
  2359.  
  2360.  
  2361.  
  2362.                     /* FinitTerm() - reset vt100 terminal */
  2363. static void
  2364. FinitTerm ()
  2365. {
  2366.     /* print out termcap 'is' string to reset terminal */
  2367. #if 0
  2368.     /* This string sets scroll region 1-24 and puts cursor at bottom line */
  2369.     printf("\033[1;24r\033[24;1H");
  2370. #endif
  2371.     fflush(stdout);
  2372. }
  2373.  
  2374. static void
  2375. AddCap (s)
  2376. char *s;
  2377. {
  2378.     register n;
  2379.  
  2380.     if (tcLineLen + (n = strlen (s)) > 55)
  2381.       { strcat (Termcap, "\\\n\t:");
  2382.         tcLineLen = 0;
  2383.       }
  2384.     strcat (Termcap, s);
  2385.     tcLineLen += n;
  2386. }
  2387.  
  2388. static char *
  2389. MakeTermcap(lines, chars)
  2390. int        lines;                            /* default window lines */
  2391. int        chars;                            /* default window chars */
  2392. {
  2393.     char buf[1024];
  2394.     register char **pp, *p;
  2395.  
  2396.     strcpy(Termcap, TermcapConst1);        /* start TERMCAP build */
  2397.     strcat(Termcap, UserTerm);            /* fill in User's terminal type */
  2398.     strcat(Termcap, TermcapConst3);        /* finish our own definition */
  2399.  
  2400.     if (lines <= 0 || lines > 200)
  2401.         lines = rows;                    /* force default if none or invalid */
  2402.     if (chars <= 0 || chars > 300)
  2403.         chars = cols;                    /* force default if none or invalid */
  2404.  
  2405.     sprintf(buf, "li#%d:co#%d:", lines, chars);
  2406.     AddCap(buf);
  2407.  
  2408.     return ( Termcap );
  2409.  
  2410. } /* MakeTermcap() */
  2411.  
  2412.  
  2413.                 /* DEBUG() - dump output routine */
  2414.  
  2415. void
  2416. DEBUG(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
  2417. char        *format;
  2418. int            arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8;
  2419. {
  2420.     fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
  2421. }
  2422. @//E*O*F layers.c//
  2423. chmod u=rw,g=rw,o=rw layers.c
  2424.  
  2425. echo x - layers.h
  2426. sed 's/^@//' > "layers.h" <<'@//E*O*F layers.h//'
  2427. /*             Copyright (C) 1989 by David W. Trissel 
  2428.  *
  2429.  *  Not derived from licensed software.
  2430.  *
  2431.  * Permission is granted to freely use, copy, modify, and redistribute
  2432.  * this software, provided that no attempt is made to gain profit from it,
  2433.  * the author is not construed to be liable for any results of using the
  2434.  * software, alterations are clearly marked as such, and this notice is
  2435.  * not modified.
  2436.  *
  2437.  */
  2438.  
  2439. #define MAXPCHAN    7                        /* maximum layers supported */
  2440.  
  2441. #define MAXSTR        200
  2442. #define    MAXARGS        64
  2443. #define MAXLINE        1024
  2444. #define IOSIZE        800                        /* data gulp handling size */
  2445.  
  2446. /* WARNING - packet sizes must be insured to never match the ESCAPE char */
  2447. #define    ESCAPE        '}'                        /* datalink escape character */
  2448.  
  2449. #define DO         if (Dflag)                    /* for debugging */
  2450.  
  2451. /* miscelaneous common data */
  2452. extern    int    Dflag;                            /* debug dump indicator flag */
  2453.  
  2454. /* Shape structure passed between MacLayers and ourselves */
  2455. struct Shape
  2456. {    short    worigv;                            /* verical window bit origin */
  2457.     short    worigh;                            /* horizontal window bit origin */
  2458.     short    wlines;                            /* window height */
  2459.     short    wchars;                            /* window width */
  2460.     short    wfont;                            /* window font size */
  2461.     short    wattr;                            /* window attributes */
  2462. };
  2463.  
  2464. #define Wa_shell    0x01                    /* window is a shell */
  2465.  
  2466.  
  2467.   /* The following modules define the complete protocol/server interface */
  2468.  
  2469.                 /* layers.c */
  2470.  
  2471. extern void FQuit(/* exitcode */);
  2472. extern void ReceiveQuit();
  2473. extern void ReceiveNew(/* chanid, shape */);
  2474. extern void ReceiveDelete(/* chanid */);
  2475. extern void ReceiveSignal(/* chanid, signal */);
  2476. extern void    ReceiveData(/* chanid, buff, cnt */);
  2477. extern void ReceiveReshape(/*chanid, shape */);
  2478. extern void DEBUG(/* format, arg1, arg2, arg3, arg4 */);
  2479.  
  2480.                 /* protocol.c */
  2481.  
  2482. extern int    InitLink();
  2483. extern int    TopChannel();
  2484. extern int    SendNew(/* shape */);
  2485. extern void    SendTitle(/* chan, buff, cnt */);
  2486. extern void SendDelete(/* chan */);
  2487. extern void SendQuit();
  2488. extern void    SendReshape(/* chan, shape */);
  2489. extern void    SendData(/* chan, buff, cnt */);
  2490. extern void    ProcessStreamin();
  2491. @//E*O*F layers.h//
  2492. chmod u=rw,g=rw,o=rw layers.h
  2493.  
  2494. echo x - layersize.c
  2495. sed 's/^@//' > "layersize.c" <<'@//E*O*F layersize.c//'
  2496. /*             Copyright (C) 1989 by David W. Trissel 
  2497.  *
  2498.  *  Not derived from licensed software.
  2499.  *
  2500.  * Permission is granted to freely use, copy, modify, and redistribute
  2501.  * this software, provided that no attempt is made to gain profit from it,
  2502.  * the author is not construed to be liable for any results of using the
  2503.  * software, alterations are clearly marked as such, and this notice is
  2504.  * not modified.
  2505.  *
  2506.  */
  2507.                 /*         All rights reserved.        */
  2508.  
  2509.         /* layersize - update BSD Sun Unix with window size information */
  2510.  
  2511. #include <stdio.h>
  2512. #include <errno.h>
  2513. #include <sys/ioctl.h>
  2514.  
  2515. extern int sys_nerr;
  2516. extern char    *sys_errlist[];
  2517.  
  2518. static void gotsyserr(/* char * */);
  2519. static void goterr(/* char * */);
  2520. static int    getnumber(/* char * */);
  2521.  
  2522.  
  2523.                         /* main() - update BSD window size */
  2524.  
  2525. main(ac, av)
  2526. int            ac;                            /* argument count */
  2527. char        **av;                        /* argument vector */
  2528. {
  2529.     struct winsize wsize;                /* window size structure for ioctl() */
  2530.     char        *ap;                    /* argument scan pointer */
  2531.     int            lines;                    /* new lines value */
  2532.     int            cols;                    /* new columns value */
  2533.  
  2534.     if (--ac != 2)
  2535.         goterr("Missing lines and column options");
  2536.  
  2537.     /* get window size (actually do this to set xpixel and ypixel values) */
  2538.     if (ioctl(0, TIOCGWINSZ, &wsize) == -1)
  2539.         gotsyserr("No window support in host"); /* terminate with message */
  2540.  
  2541.     /* scan looking for -l and -c line and column numeric sizes */
  2542.     lines = cols = 0;                    /* reset values */
  2543.     while (ac > 0)
  2544.       {    ap = *++av;                        /* point to next argument string */
  2545.         if (ac-- > 0 && *ap == '-')        /* if option ... */
  2546.         switch (ap[1])
  2547.         { case 'l':        /* lines */
  2548.             lines = getnumber(&ap[2]);
  2549.             break;
  2550.  
  2551.           case 'c':        /* columns */
  2552.             cols = getnumber(&ap[2]);
  2553.             break;
  2554.  
  2555.           default:
  2556.             goterr("Usupported option"); /* unsupported option */
  2557.             break;
  2558.  
  2559.         } /* end '-' argument */
  2560.         else
  2561.             goterr("Unsupported parameter"); /* unsupported parameter */
  2562.  
  2563.       } /* end while argument vector scan */
  2564.             
  2565.     /* must have both lines and columns */
  2566.     if (lines == 0 || cols == 0)
  2567.         goterr("Must specify both lines and columns");
  2568.  
  2569.     wsize.ws_col = cols;                /* set columns */
  2570.     wsize.ws_row = lines;                /* set lines */
  2571.     /* update the kernel */
  2572.     if (ioctl(0, TIOCSWINSZ, &wsize) == -1)
  2573.         gotsyserr("Failed to update window size"); /* didn't go */
  2574.  
  2575.  
  2576.  
  2577.                 /* goterr() - issue error and terminate */
  2578.  
  2579. static void
  2580. goterr(msg)
  2581. char        *msg;                        /* error message string */
  2582. {
  2583.     printf("%s\n", msg);                /* send error message to user */
  2584.     exit(1);                            /* terminate with error */
  2585.  
  2586. } /* goterr() */
  2587.  
  2588.  
  2589.                 /* gotsyserror() - system error return */
  2590.  
  2591. static void
  2592. gotsyserr(msg)
  2593. char        *msg;                        /* error string */
  2594. {
  2595.     if (errno > 0 && errno < sys_nerr)
  2596.         printf("%s: %s\n", msg, sys_errlist[errno]);
  2597.     else
  2598.         printf("%s: Error %d\n", msg, errno);
  2599.  
  2600.     exit(1);                            /* exit with failure */
  2601.  
  2602. } /* gotsyserr() */
  2603.  
  2604.  
  2605.                     /* getnumber() - parse option number */
  2606.  
  2607. static int
  2608. getnumber(str)
  2609. char        *str;                        /* start of option string */
  2610. {
  2611.     int            n;                        /* number being built */
  2612.  
  2613.     if (str == NULL)
  2614.         goterr("Invalid numeric in option");
  2615.  
  2616.     /* skip any leading delimiters */
  2617.     while (*str && (*str == ' ' || *str == '\t'))
  2618.         str++;
  2619.  
  2620.     for(n=0; *str && *str >= '0' && *str <= '9'; str++)
  2621.         n = n*10 + *str - '0';            /* add next digit in */
  2622.  
  2623.     /* make sure number terminates legally */
  2624.     switch (*str)
  2625.     { case '\0':
  2626.       case ' ':
  2627.       case '\t':
  2628.       case '\n':
  2629.         if (n <= 0 || n > 200)
  2630.             goterr("Number out of range");
  2631.         break;                            /* these are OK */
  2632.  
  2633.       default:
  2634.         goterr("Invalid numeric in option");
  2635.  
  2636.     } /* end switch */
  2637.  
  2638.     return ( n );                        /* return the number */
  2639.  
  2640. } /* getnumber() */
  2641. @//E*O*F layersize.c//
  2642. chmod u=rw,g=rw,o=rw layersize.c
  2643.  
  2644. echo x - layertitle.c
  2645. sed 's/^@//' > "layertitle.c" <<'@//E*O*F layertitle.c//'
  2646. /*             Copyright (C) 1989 by David W. Trissel
  2647.  *
  2648.  *  Not derived from licensed software.
  2649.  *
  2650.  * Permission is granted to freely use, copy, modify, and redistribute
  2651.  * this software, provided that no attempt is made to gain profit from it,
  2652.  * the author is not construed to be liable for any results of using the
  2653.  * software, alterations are clearly marked as such, and this notice is
  2654.  * not modified.
  2655.  *
  2656.  */
  2657.                 /*         All rights reserved.        */
  2658.  
  2659.             /* layertitle - utility to specify window title */
  2660.  
  2661. #include <stdio.h>
  2662.  
  2663. #define ESC 0x1b
  2664.  
  2665.             /* main() - send string designating layers window title */
  2666.  
  2667. main(ac, av)
  2668. int         ac;                         /* argument count */
  2669. char        **av;                       /* argument vector */
  2670. {
  2671.     char        *ap;                    /* argument scan pointer */
  2672.  
  2673.     if (--ac != 1)
  2674.       { printf("usage: layertitle \"new window title\"\n");
  2675.         exit(1);
  2676.       }
  2677.        
  2678.     ap = *++av;                         /* point to argument string */
  2679.  
  2680.     /* Transmit the title string in the ANSI Private Message format
  2681.     ** which is
  2682.     **              ESC '^' message ESC '\'
  2683.     */
  2684.     printf("%c%c%s%c%c", ESC, '^', ap, ESC, '\\');
  2685.  
  2686. }  /* main() */
  2687. @//E*O*F layertitle.c//
  2688. chmod u=rw,g=rw,o=rw layertitle.c
  2689.  
  2690. echo x - macbput.1
  2691. sed 's/^@//' > "macbput.1" <<'@//E*O*F macbput.1//'
  2692. @.TH MACBPUT local "17 Mar 1990"
  2693. @.UC 4
  2694. @.SH NAME
  2695. macbput \- send file to macintosh via macbinary protocol
  2696. @.SH SYNOPSIS
  2697. @.B macbput
  2698. file
  2699. @.br
  2700. @.B macbput
  2701. [
  2702. @.B \-rdu
  2703. ] file
  2704. [
  2705. @.B \-t
  2706. type
  2707. ]
  2708. [
  2709. @.B \-a
  2710. owner
  2711. ]
  2712. [
  2713. @.B \-n
  2714. name
  2715. ]
  2716. @.SH DESCRIPTION
  2717. @.I Macbput
  2718. sends a file to a Macintosh running MacTerminal.
  2719. The File Transfer Protocol settings should specify the "MacBinary"
  2720. transfer method.
  2721. Macbput will also work with other communications programs for the Mac
  2722. (e.g. MacLayers);
  2723. consult the user's manual for your macbinary-compatable communications
  2724. program for more information.
  2725. This manual page will only address the use of macbput with MacTerminal.
  2726. @.PP
  2727. To use this program, log into the unix system using MacTerminal,
  2728. and run macbput specifying the desired options and one file to be sent.
  2729. If MacTerminal is properly configured, it will recognize that a file
  2730. is arriving on the serial line and put up an indicator showing how
  2731. much of the file has been sent.
  2732. Several Control-X's may be used to force macbput
  2733. to give up if the transfer fails.
  2734. @.PP
  2735. If none of the
  2736. @.B \-rdu
  2737. flags are specified,
  2738. @.I macbput
  2739. sends three unix files to the Mac:
  2740. @.IB file .info ,
  2741. @.IB file .data ,
  2742. and
  2743. @.IB file .rsrc .
  2744. These specify the three parts of one Mac file:  the .data file
  2745. becomes the data fork, the .rsrc file becomes the resource fork,
  2746. and the .info file specifies the sizes of the two forks, as well
  2747. as the file name, file type, creation date, and other information.
  2748. This is useful for returning files to the Mac which were stored
  2749. using macget or macbget.
  2750. @.PP
  2751. The
  2752. @.B \-r
  2753. flag specifies
  2754. @.I resource
  2755. mode.
  2756. Either
  2757. @.IB file .rsrc
  2758. or
  2759. @.I file
  2760. will be sent to the Mac, along with a forged
  2761. @.B .info
  2762. file and an empty
  2763. @.B .data
  2764. file.
  2765. The file sent becomes the resource fork of the Mac file.
  2766. @.PP
  2767. The
  2768. @.B \-d
  2769. flag specifies
  2770. @.I data
  2771. mode.
  2772. Either
  2773. @.IB file .data
  2774. ,
  2775. @.IB file .text
  2776. or
  2777. @.I file
  2778. will be sent to the Mac, along with a forged
  2779. @.B .info
  2780. file and an empty
  2781. @.B .rsrc
  2782. file.
  2783. The file sent becomes the data fork of the Mac file.
  2784. @.PP
  2785. The
  2786. @.B \-u
  2787. flag requests
  2788. @.I unix
  2789. mode, which is the same as
  2790. @.I data
  2791. mode except unix newline characters are converted
  2792. into carriage returns.
  2793. Human-readable unix text files sent to the Mac using this option
  2794. will be compatible with applications which expect "text only" files.
  2795. @.PP
  2796. The remaining options serve to override the default
  2797. file type, owner, and file name to be used on the Mac.
  2798. The default type and owner for
  2799. @.I resource
  2800. and
  2801. @.I data
  2802. mode defaults are "????", "????", and
  2803. @.I unix
  2804. mode defaults are "TEXT" and "MACA".
  2805. @.SH SEE ALSO
  2806. macput(local), macget(local), xbin(local), macbin(local), mcvert(local)
  2807. @.SH BUGS
  2808. The macbinary protocol may not work over flow controlled communication lines,
  2809. some terminal concentrators, or when using rlogin.
  2810. @.SH FEATURES
  2811. Properly initializes the Creation Date.
  2812. @.SH AUTHOR
  2813. Original base code: Dave Johnson, Brown 7/31/84
  2814. @//E*O*F macbput.1//
  2815. chmod u=rw,g=rw,o=rw macbput.1
  2816.  
  2817. echo x - macbput.c
  2818. sed 's/^@//' > "macbput.c" <<'@//E*O*F macbput.c//'
  2819. /*
  2820.  * (originally macput) -- send file to Macintosh using MacBinary XMODEM protocol
  2821.  * Dave Johnson, Brown University Computer Science
  2822.  *
  2823.  * (c) 1984 Brown University 
  2824.  * may be used but not sold without permission
  2825.  *
  2826.  */
  2827.  
  2828. /* To compile:    
  2829.                   cc -O -o macbput macbput.c
  2830.     (Sun 4.2 BSD) cc -O -DSUNBSD42 -o macbput macbput.c
  2831.     (System V)    cc -O -DSYSV -o macbput macbput.c
  2832.  
  2833.    Latest modifications 10/20/88 by Trissel -
  2834.  
  2835.  1. General cleanup by removal of unused definitions and headers.
  2836.  2. Added #ifdefs to support System V and BSD 4.2 Sun compilation.
  2837.  3. Removed ancient Macterminal Beta 0.5X code.
  2838.  4. Fixed bad bug where XMODEM block count was not bumped up
  2839.     after the first fork transfer.
  2840.  
  2841.     Dave Trissel
  2842.     Motorola Inc.
  2843.     ut-sally!oakhill!davet
  2844.  
  2845.    This code is fundamentally from two earlier programmers:
  2846.  
  2847.     Jon Hueras
  2848.     Symantec/THINK Technologies
  2849.     singer@endor.harvard.edu
  2850.  
  2851.     who added 2-Byte CRC capability to code from:
  2852.  
  2853.     Dave Johnson
  2854.     ddj%brown@csnet-relay.arpa
  2855.     Brown University Computer Science
  2856.  
  2857.    who did the initial MacTerminal 1.1 transfer protocol.
  2858. */
  2859.  
  2860. /* If you have System V define the following: */
  2861.     /* #define SYSV */
  2862.  
  2863. /* Sun BSD 4.2 systems should define the following: */
  2864.     /* #define SUNBSD42 */
  2865.  
  2866. #include <stdio.h>
  2867. #include <signal.h>
  2868. #include <setjmp.h>
  2869. #ifdef SYSV
  2870. #include <termio.h>
  2871. #else
  2872. #include <sgtty.h>
  2873. #endif
  2874. #include <sys/types.h>
  2875. #include <sys/stat.h>
  2876.  
  2877. #ifdef SUNBSD42
  2878. /* RAW is no longer being found on latest Sun system (??) (Trissel) */
  2879. #define RAW 0x20
  2880. #endif
  2881.  
  2882. #define RECORDBYTES 132
  2883. #define DATABYTES 128
  2884. #define NAMEBYTES 63
  2885.  
  2886. #define RETRIES 10
  2887. #define ACKTIMO 10
  2888.  
  2889. #define MAXRECNO 0xff
  2890. #define BYTEMASK 0xff
  2891.  
  2892. #define TMO -1
  2893. #define DUP '\000'
  2894. #define SOH '\001'
  2895. #define EOT '\004'
  2896. #define ACK '\006'
  2897. #define NAK '\025'
  2898. #define CAN '\030'
  2899. #define EEF '\032'
  2900. #define ESC '\033'
  2901.  
  2902. #define H_NLENOFF 1
  2903. #define H_NAMEOFF 2
  2904. /* 65 <-> 80 is the FInfo structure */
  2905. #define H_TYPEOFF 65
  2906. #define H_AUTHOFF 69
  2907.  
  2908. #define H_LOCKOFF 81
  2909. #define H_DLENOFF 83
  2910. #define H_RLENOFF 87
  2911. #define H_CTIMOFF 91
  2912. #define H_MTIMOFF 95
  2913.  
  2914. #define H_OLD_DLENOFF 81
  2915. #define H_OLD_RLENOFF 85
  2916.  
  2917. #define TEXT 0
  2918. #define DATA 1
  2919. #define RSRC 2
  2920. #define FULL 3
  2921.  
  2922. int mode, txtmode;
  2923.  
  2924. struct macheader {
  2925.     char m_name[NAMEBYTES+1];
  2926.     char m_type[4];
  2927.     char m_author[4];
  2928.     long m_datalen;
  2929.     long m_rsrclen;
  2930.     long m_createtime;
  2931.     long m_modifytime;
  2932. } mh;
  2933.  
  2934. struct filenames {
  2935.     char f_info[256];
  2936.     char f_data[256];
  2937.     char f_rsrc[256];
  2938. } files;
  2939.  
  2940. int recno, crc;
  2941. char buf[DATABYTES];
  2942.  
  2943. char usage[] =
  2944.     "usage: \"macbput [-rdu] [-t type] [-c creator] [-n name] filename\"\n";
  2945.  
  2946. main(ac, av)
  2947. char **av;
  2948. {
  2949.     int n;
  2950.     char *filename;
  2951.  
  2952.     if (ac == 1) {
  2953.         fprintf(stderr, usage);
  2954.         exit(1);
  2955.     }
  2956.  
  2957.     mode = FULL;
  2958.     ac--; av++;
  2959.     while (ac) {
  2960.         if (av[0][0] == '-') {
  2961.             switch (av[0][1]) {
  2962.             case 'r':
  2963.                 mode = RSRC;
  2964.                 strncpy(mh.m_type, "????", 4);
  2965.                 strncpy(mh.m_author, "????", 4);
  2966.                 break;
  2967.             case 'u':
  2968.                 mode = TEXT;
  2969.                 strncpy(mh.m_type, "TEXT", 4);
  2970.                 strncpy(mh.m_author, "MACA", 4);
  2971.                 break;
  2972.             case 'd':
  2973.                 mode = DATA;
  2974.                 strncpy(mh.m_type, "????", 4);
  2975.                 strncpy(mh.m_author, "????", 4);
  2976.                 break;
  2977.             case 'n':
  2978.                 if (ac > 1) {
  2979.                     ac--; av++;
  2980.                     n = strlen(av[0]);
  2981.                     if (n > NAMEBYTES) n = NAMEBYTES;
  2982.                     strncpy(mh.m_name, av[0], n);
  2983.                     mh.m_name[n] = '\0';
  2984.                     break;
  2985.                 }
  2986.                 else goto bad_usage;
  2987.             case 't':
  2988.                 if (ac > 1) {
  2989.                     ac--; av++;
  2990.                     strncpy(mh.m_type, av[0], 4);
  2991.                     break;
  2992.                 }
  2993.                 else goto bad_usage;
  2994.             case 'c':
  2995.                 if (ac > 1) {
  2996.                     ac--; av++;
  2997.                     strncpy(mh.m_author, av[0], 4);
  2998.                     break;
  2999.                 }
  3000.                 else goto bad_usage;
  3001.             default:
  3002. bad_usage:
  3003.                 fprintf(stderr, usage);
  3004.                 exit(1);
  3005.             }
  3006.         }
  3007.         else {
  3008.             filename = av[0];
  3009.         }
  3010.         ac--; av++;
  3011.     }
  3012.  
  3013.     setup_tty();
  3014.     find_files(filename, mode);
  3015.     if (mode != FULL)
  3016.         forge_info();
  3017.  
  3018.     if (send_sync()) {
  3019.         recno = 1;
  3020.         txtmode = 0;
  3021.         send_file(files.f_info, 1);
  3022.  
  3023.         if (mode != FULL)
  3024.             unlink(files.f_info);
  3025.  
  3026.         if (mode == TEXT) txtmode++;
  3027.         send_file(files.f_data, 1);
  3028.  
  3029.         txtmode = 0;
  3030.         send_file(files.f_rsrc, 0);
  3031.     }
  3032.     reset_tty();
  3033. }
  3034.  
  3035. find_files(filename, mode)
  3036. char *filename;
  3037. {
  3038.     int n, tdiff;
  3039.     struct stat stbuf;
  3040.  
  3041.     sprintf(files.f_data, "%s.data", filename);
  3042.     sprintf(files.f_rsrc, "%s.rsrc", filename);
  3043.  
  3044.     if (mode == FULL) {
  3045.         sprintf(files.f_info, "%s.info", filename);
  3046.         if (stat(files.f_info, &stbuf) != 0) {
  3047.             perror(files.f_info);
  3048.             cleanup(-1);
  3049.         }
  3050.         return;
  3051.     }
  3052.     else {
  3053.         strcpy(files.f_info, "#machdrXXXXXX");
  3054.         mktemp(files.f_info);
  3055.     }
  3056.  
  3057.     if (mode == RSRC) {
  3058.         strcpy(files.f_data, "/dev/null");
  3059.         if (stat(files.f_rsrc, &stbuf) != 0) {
  3060.             strcpy(files.f_rsrc, filename);
  3061.             if (stat(files.f_rsrc, &stbuf) != 0) {
  3062.                 perror(files.f_rsrc);
  3063.                 cleanup(-1);
  3064.             }
  3065.         }
  3066.         mh.m_datalen = 0;
  3067.         mh.m_rsrclen = stbuf.st_size;
  3068.     }
  3069.     else {
  3070.         strcpy(files.f_rsrc, "/dev/null");
  3071.         if (stat(files.f_data, &stbuf) != 0) {
  3072.             sprintf(files.f_data, "%s.text", filename);
  3073.             if (stat(files.f_data, &stbuf) != 0) {
  3074.                 strcpy(files.f_data, filename);
  3075.                 if (stat(files.f_data, &stbuf) != 0) {
  3076.                     perror(files.f_data);
  3077.                     cleanup(-1);
  3078.                 }
  3079.             }
  3080.         }
  3081.         mh.m_datalen = stbuf.st_size;
  3082.         mh.m_rsrclen = 0;
  3083.     }
  3084.  
  3085.     if (mh.m_name[0] == '\0') {
  3086.         n = strlen(filename);
  3087.         if (n > NAMEBYTES) n = NAMEBYTES;
  3088.         strncpy(mh.m_name, filename, n);
  3089.         mh.m_name[n] = '\0';
  3090.     }
  3091. }
  3092.  
  3093. forge_info()
  3094. {
  3095.     int n;
  3096.     char *np;
  3097.     FILE *fp;
  3098.  
  3099.     for (np = mh.m_name; *np; np++)
  3100.         if (*np == '_') *np = ' ';
  3101.  
  3102.     buf[H_NLENOFF] = n = np - mh.m_name;
  3103.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  3104.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  3105.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  3106.     put4(buf + H_DLENOFF, mh.m_datalen);
  3107.     put4(buf + H_RLENOFF, mh.m_rsrclen);
  3108.     put4(buf + H_CTIMOFF, mh.m_createtime);
  3109.     put4(buf + H_MTIMOFF, mh.m_modifytime);
  3110.     fp = fopen(files.f_info, "w");
  3111.     if (fp == NULL) {
  3112.         perror("temp file");
  3113.         cleanup(-1);
  3114.     }
  3115.     fwrite(buf, 1, DATABYTES, fp);
  3116.     fclose(fp);
  3117. }
  3118.  
  3119. send_sync()
  3120.     {
  3121.         int c;
  3122.         
  3123.         tputc(ESC);
  3124.         tputc('b');
  3125.  
  3126.         for (;;) {
  3127.  
  3128.             if ((c = tgetc(ACKTIMO)) == TMO)
  3129.               {
  3130.                 return(0);
  3131.                 }
  3132.  
  3133.             if (c == NAK)
  3134.               {
  3135.                 return(1);
  3136.                 }
  3137.  
  3138.             if (c == 'C') {
  3139.                 crc++;
  3140.                 return(1);
  3141.             }
  3142.         }
  3143.     }
  3144.  
  3145. send_file(fname, more)
  3146. char *fname;
  3147. int more;
  3148. {
  3149.     register int status, i, n;
  3150.     FILE *inf;
  3151.  
  3152.     inf = fopen(fname, "r");
  3153.     if (inf == NULL) {
  3154.         perror(fname);
  3155.         cleanup(-1);
  3156.     }
  3157.     for (;;) {
  3158.         n = fread(buf, 1, DATABYTES, inf);
  3159.         if (n > 0) {
  3160.             for (i = 0; i < RETRIES; i++) {
  3161.                 send_rec(buf, DATABYTES);
  3162.                 while ((status = tgetc(ACKTIMO)) != ACK && status != NAK && status != CAN);
  3163.                 if (status != NAK)
  3164.                     break;
  3165.             } 
  3166.             if (status != ACK) {
  3167.                 if (status != CAN)
  3168.                     while ((status = tgetc(ACKTIMO)) != CAN);
  3169.                 fclose(inf);
  3170.                 cleanup(-1);
  3171.                 /* NOTREACHED */
  3172.             }
  3173.         }
  3174.         if (n < DATABYTES) {
  3175.             if (!more) {
  3176.                 tputc(EOT);
  3177.                 tgetc(ACKTIMO);
  3178.             }
  3179.             return;
  3180.         }
  3181.         recno++;
  3182.         recno &= MAXRECNO;
  3183.     }
  3184. }
  3185.  
  3186. send_rec(buf, recsize)
  3187. char buf[];
  3188. int recsize;
  3189. {
  3190.     int i, cksum;
  3191.     char *bp;
  3192.  
  3193.     if (txtmode || !crc) {
  3194.         cksum = 0;
  3195.         bp = buf;
  3196.         for (i = 0; i < recsize; i++, bp++) {
  3197.             if (txtmode && *bp == '\n')
  3198.                 *bp = '\r';
  3199.             cksum += *bp;
  3200.         }
  3201.     }
  3202.  
  3203.     if (crc)
  3204.         cksum = calcrc(buf, recsize);
  3205.  
  3206.     tputc(SOH);
  3207.     tputc((char) recno);
  3208.     tputc((char) (MAXRECNO - recno));
  3209.     tputrec(buf, recsize);
  3210.     
  3211.     if (crc) {
  3212.         tputc((char) (cksum >> 8));
  3213.         tputc((char) cksum);
  3214.     } else
  3215.         tputc((char) cksum);
  3216. }
  3217.  
  3218. static int ttyfd;
  3219. static FILE *ttyf;
  3220. static jmp_buf timobuf;
  3221.  
  3222. tgetc(timeout)
  3223. int timeout;
  3224. {
  3225.     int c;
  3226.  
  3227.     if (setjmp(timobuf))
  3228.         return TMO;
  3229.  
  3230.     alarm(timeout);
  3231.     c = getc(ttyf);
  3232.     alarm(0);
  3233.  
  3234.     if (c == -1)    /* probably hung up or logged off */
  3235.         return EOT;
  3236.     else
  3237.         return c & BYTEMASK;
  3238. }
  3239.  
  3240. tputrec(buf, count)
  3241. char *buf;
  3242. int count;
  3243. {
  3244.     write(ttyfd, buf, count);
  3245. }
  3246.  
  3247. tputc(c)
  3248. char c;
  3249. {
  3250.     write(ttyfd, &c, 1);
  3251. }
  3252.  
  3253. timedout()
  3254. {
  3255.     signal(SIGALRM, timedout);    /* for pre-4.2 systems */
  3256.     longjmp(timobuf, 1);
  3257. }
  3258.  
  3259. #ifdef SYSV
  3260. static struct termio otty, ntty;
  3261. #else
  3262. static struct sgttyb otty, ntty;
  3263. #endif
  3264.  
  3265. /* should turn messages off */
  3266.  
  3267. setup_tty()
  3268. {
  3269.     int cleanup();
  3270.     int timedout();
  3271.  
  3272.     ttyf = stdin;
  3273.     ttyfd = fileno(stdout);
  3274. #ifdef SYSV
  3275.     ioctl(ttyfd, TCGETA, &otty);        /* get termio info */
  3276. #else
  3277.     ioctl(ttyfd, TIOCGETP, &otty);
  3278. #endif
  3279.     signal(SIGHUP, cleanup);
  3280.     signal(SIGINT, cleanup);
  3281.     signal(SIGQUIT, cleanup);
  3282.     signal(SIGTERM, cleanup);
  3283.     signal(SIGALRM, timedout);
  3284.     ntty = otty;
  3285. #ifdef SYSV
  3286.     ntty.c_iflag = BRKINT;                /* only interrupt on break */
  3287.     ntty.c_oflag = 0;                    /* no output processing */
  3288.     ntty.c_cflag |= CS8;                /* 8 bit characters */
  3289.     ntty.c_lflag = 0;                    /* no echoing */
  3290.     ntty.c_cc[VEOF] = 1;                /* "MIN" minimum chars before input */
  3291.     ntty.c_cc[VEOL] = 1;                /* "TIME" maximum .1 secs before feed */
  3292.     ioctl(ttyfd, TCSETAF, &ntty);        /* set mode and flush input */
  3293. #else
  3294.     ntty.sg_flags = RAW;
  3295.     ioctl(ttyfd, TIOCSETP, &ntty);
  3296. #endif
  3297. }
  3298.  
  3299. reset_tty()
  3300. {
  3301.     if (ttyf != NULL) {
  3302. #ifdef SYSV
  3303.         ioctl(ttyfd, TCSETAF, &otty);    /* reset after output drains */
  3304. #else
  3305.         sleep (5);                        /* wait for output to drain */
  3306.         ioctl(ttyfd, TIOCSETP, &otty);
  3307. #endif
  3308.     }
  3309. }
  3310.  
  3311. cleanup(sig)
  3312. int sig;
  3313. {
  3314.     reset_tty();
  3315.     exit(sig);
  3316. }
  3317.  
  3318. put4(bp, value)
  3319. char *bp;
  3320. long value;
  3321. {
  3322.     register int i, c;
  3323.  
  3324.     for (i = 0; i < 4; i++) {
  3325.         c = (value >> 24) & BYTEMASK;
  3326.         value <<= 8;
  3327.         *bp++ = c;
  3328.     }
  3329. }
  3330.  
  3331. int calcrc(ptr,    count)
  3332. char *ptr;
  3333. int count;
  3334.     {
  3335.         int    crc, i;
  3336.  
  3337.         crc    = 0;
  3338.         while (--count >= 0) {
  3339.          crc ^= ((int) *ptr++) << 8;
  3340.          for (i = 0; i < 8; ++i)
  3341.                  if (crc & 0x8000)
  3342.              crc = crc <<    1 ^ 0x1021;
  3343.                  else
  3344.              crc <<= 1;
  3345.          }
  3346.         return (crc    & 0xFFFF);
  3347.     }
  3348. @//E*O*F macbput.c//
  3349. chmod u=rw,g=rw,o=rw macbput.c
  3350.  
  3351. echo x - makefile
  3352. sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
  3353. #                   Makefile for Layers 1.0
  3354.  
  3355. BIN    = /usr/local
  3356. MANDIR = /usr/local/manl
  3357.  
  3358. PGM    = layers
  3359. PGM2   = layersize
  3360. PGM3   = layertitle
  3361. PGM4   = macbput
  3362. MS     = l
  3363. CFLAGS = -O
  3364. CFILES = layers.c protocol.c
  3365. OFILES = layers.o protocol.o
  3366.  
  3367. all: $(PGM) $(PGM2) $(PGM3) $(PGM4)
  3368.  
  3369. $(PGM): $(OFILES)
  3370.     $(CC) $(CFLAGS) -o $(PGM) $(OFILES)
  3371.  
  3372. #    $(CC) $(CFLAGS) -o $(PGM) $(OFILES) -ltermcap
  3373.  
  3374. layers.o: layers.c layers.h
  3375.     $(CC) $(CFLAGS) -c layers.c
  3376.  
  3377. protocol.o: protocol.c layers.h
  3378.     $(CC) $(CFLAGS) -c protocol.c
  3379.  
  3380. $(PGM2): layersize.o
  3381.     $(CC) $(CFLAGS) -o $(PGM2) layersize.o
  3382.  
  3383. $(PGM3): layertitle.o
  3384.     $(CC) $(CFLAGS) -o $(PGM3) layertitle.o
  3385.  
  3386. $(PGM4): macbput.o
  3387.     $(CC) $(CFLAGS) -o $(PGM4) macbput.o
  3388.  
  3389. layersize.o: layersize.c
  3390.     $(CC) $(CFLAGS) -c layersize.c
  3391.  
  3392. layertitle.o: layertitle.c
  3393.     $(CC) $(CFLAGS) -c layertitle.c
  3394.  
  3395. macbput.o: macbput.c
  3396.     $(CC) $(CFLAGS) -c macbput.c
  3397.  
  3398. install: $(PGM) $(PGM2) $(PGM3) $(PGM4)
  3399.     rm -f $(BIN)/$(PGM)
  3400.     install -c -s -o root -g daemon -m 4711 $(PGM) $(BIN)/$(PGM)
  3401.     install -c -s $(PGM2) $(BIN)/$(PGM2)
  3402.     install -c -s $(PGM3) $(BIN)/$(PGM3)
  3403. #    install -c -s $(PGM4) $(BIN)/$(PGM4)
  3404.  
  3405. installnopriv: $(PGM) $(PGM2) $(PGM3) $(PGM4)
  3406.     rm -f $(BIN)/$(PGM)
  3407.     install -c -s $(PGM) $(BIN)/$(PGM)
  3408.     install -c -s $(PGM2) $(BIN)/$(PGM2)
  3409.     install -c -s $(PGM3) $(BIN)/$(PGM3)
  3410. #    install -c -s $(PGM4) $(BIN)/$(PGM4)
  3411.  
  3412. manpage: layers.1
  3413.     rm -f $(MANDIR)/$(PGM).$(MS)
  3414.     cp layers.1 $(MANDIR)/$(PGM).$(MS)
  3415.     chmod 664 $(MANDIR)/$(PGM).$(MS)
  3416.  
  3417. clean:
  3418.     rm -f a.out core $(PGM) $(PGM2) $(PGM3) $(PGM4) *.o
  3419.  
  3420. shar: makefile 
  3421.     shar README layers.1 makefile layers.h layers.c \
  3422.     protocol.c layersize.c layertitle.c MacLayers.sit.Hqx MacLayers.doc \
  3423.     macbput.c macbput.1 >layers.shar
  3424. @//E*O*F makefile//
  3425. chmod u=rw,g=rw,o=rw makefile
  3426.  
  3427. echo x - protocol.c
  3428. sed 's/^@//' > "protocol.c" <<'@//E*O*F protocol.c//'
  3429. /*             Copyright (C) 1989 by David W. Trissel 
  3430.  *
  3431.  *              Not derived from licensed software.
  3432.  *
  3433.  * Permission is granted to freely use, copy, modify, and redistribute
  3434.  * this software, provided that no attempt is made to gain profit from it,
  3435.  * the author is not construed to be liable for any results of using the
  3436.  * software, alterations are clearly marked as such, and this notice is
  3437.  * not modified.
  3438.  *
  3439.  */
  3440.  
  3441. #include    <stdio.h>
  3442. #include    <signal.h>
  3443. #include    <errno.h>
  3444. #include    "layers.h"
  3445.  
  3446.                 /* protocol.c - BSD MacLayers protocol driver */
  3447.  
  3448. /*    This module handles all interaction with the Macintosh MacLayers
  3449. **    program. Services provided are:
  3450. **
  3451. **        InitLink()    - initialize link to MacLayers
  3452. **
  3453. **        TopChannel() - return highest prority channel
  3454. **
  3455. **        SendNew()    - request new layer channel of MacLayers
  3456. **
  3457. **        SendTitle() - change window title to given string (NOT IMPLENTED YET)
  3458. **
  3459. **        SendDelete()- tell MacLayers indicated layer has died
  3460. **
  3461. **        SendQuit()    - order MacLayers to terminate layers mode
  3462. **
  3463. **        SendData()    - send output to indicated channel's window
  3464. **
  3465. **        SendReshape() - send Shape structure to MacLayers
  3466. **
  3467. **        ProcessStreamin() - data is ready to be processed from MacLayers
  3468. **
  3469. */
  3470.  
  3471. #define DUMPALL
  3472. #undef    DUMPALL
  3473.  
  3474. /* C library calls */
  3475. unsigned alarm();                /* alarm system call */
  3476.  
  3477. static int        GetData();
  3478. static void        Packet();
  3479. static void        Parse();
  3480. static void        AwaitInput();
  3481. static void        asciishape();
  3482. static void        fill4();
  3483. static void        fill2();
  3484. static void        fill1();
  3485. static int        parseshape();
  3486. static unsigned    get4();
  3487. static unsigned    get2();
  3488. static unsigned    get1();
  3489.  
  3490. static char        inbuff[IOSIZE];        /* input buffer from MacLayers */
  3491. static char     *inpos;                /* current input position in buffer */
  3492. static int        insize = 0;            /* characters left to process */
  3493. static int        Outstream = -1;        /* current output stream channel */
  3494. static int        Instream = -1;        /* current input stream channel */
  3495.  
  3496. static struct Shape    SNshape;        /* SendNew() shape response */
  3497. static int        SNresp = 0;            /* SendNew() reponse poll flag */
  3498. static int        SNchan = 0;            /* SendNew() channel return */
  3499. #define SN_WAITING    -1000            /* SendNew() waiting response value */
  3500.  
  3501. #define ATTRSIZE    15                /* size of window attribute string */
  3502.  
  3503. #define FLUSH    fflush(stdout)
  3504.  
  3505.  
  3506.                 /* Initlink() - initialize link with MacLayers */
  3507.  
  3508. /* Returns:
  3509. **                0 - linkup failed
  3510. **                1 - linkup successful, Maclayers now in protocol mode
  3511. */
  3512.  
  3513. int
  3514. Initlink()
  3515. {
  3516.     int Outstream = -1;                /* no default stream yet */
  3517.     int    Instream = -1;                /* no default stream yet */
  3518.     int        num1, num2, num3;        /* scanf item result */
  3519.     int        err;                    /* error code */
  3520.  
  3521. #define WAITTIME    10                /* second wait response time */
  3522. #define INITTIME    2                /* wait time after succesful startup */
  3523.  
  3524.     /* we must non-buffer input since all input must be immediate */
  3525.     setbuf(stdin, NULL);            /* non-buffer all input */
  3526.  
  3527.     /* send intitial request for terminal type and version number */
  3528.     DO DEBUG("write: ESC [ c\n");
  3529.     if ((err=printf("\033[c")) < 0)
  3530.       {
  3531.         DO DEBUG(" printf() error code %d\n", err);
  3532.         return ( 0 );                /* problem with stdout */
  3533.       }
  3534.     FLUSH;                            /* force output buffer */
  3535.  
  3536.     /* attempt to read "ESC [ ? 8 ; typedigits ; versiondigits c" */
  3537.     num1 = num2 = num3 = -1;        /* default to unsupplied values */
  3538.     (void) alarm(WAITTIME);            /* set timeout */
  3539.     DO DEBUG(" doing first scanf\n");
  3540.     (void) scanf("\033[?%d;%d;%dc", &num1, &num2, &num3);
  3541.     (void) alarm(0);                /* cancel alarm */
  3542.     DO DEBUG("read ESC [ ? %d ; %d; %d c\n", num1, num2, num3);
  3543.     if (num1 != 8 || num2 != 10)
  3544.         return ( 0 );                /* not correct response or layers term ID */
  3545.  
  3546.     /* ask terminal if ENC_ENABLE is to be forced */
  3547.     DO DEBUG("write: ESC [ F\n");
  3548.     (void) printf("\033[F");
  3549.     FLUSH;                            /* force output buffer */
  3550.     (void) alarm(WAITTIME);            /* set timeout */
  3551.  
  3552.     /* attempt to read "ESC [ flag F" (flag indicates ENC_ENABLE status) */
  3553.     num1 = -1;                        /* default to invalid response */
  3554.     (void) scanf("\033[%dF", &num1);
  3555.     (void) alarm(0);                /* cancel alarm */
  3556.     DO DEBUG("read ESC [ %d F\n", num1);
  3557.     if (num1 != 2 && num1 != 0)
  3558.         return ( 0 );                /* something's wrong */
  3559.  
  3560.     /* now startup packet mode in non ENC_ENABLE processing */
  3561.     DO DEBUG("write: ESC [ 2 ; 0 v\n");
  3562.     (void) printf("\033[2;0v");        /* "ESC [ 2 ; 0 v" */
  3563.     FLUSH;                            /* force output buffer */
  3564.  
  3565.     /* we are now in packet mode */
  3566.     sleep( INITTIME );                /* let Macintosh keep up with us */
  3567.     return ( 1 );                    /* return successful startup */
  3568.  
  3569. } /* Initlink() */
  3570.  
  3571.  
  3572.             /* TopChannel() - return highest prority channel */
  3573.  
  3574. int
  3575. TopChannel()
  3576. {
  3577.     return ( Instream );
  3578.  
  3579. } /* TopChannel() */
  3580.  
  3581.  
  3582.     /*
  3583.     ** WARNING: Most of the following functions may be recursively called
  3584.     **            as control commands are processed from the input stream
  3585.     */
  3586.  
  3587.  
  3588.             /* ProcessStreamin() - MacLayers has input to process */
  3589.  
  3590. void
  3591. ProcessStreamin()
  3592. {
  3593.     int        c;                        /* input character being processed */
  3594.  
  3595.     DO DEBUG("ProcessStreamin()\n");
  3596.  
  3597.     GetData(0);                        /* read some and don't timeout */
  3598.  
  3599.     while (insize > 0)                /* while more data to process ... */
  3600.         Parse();                    /* process next chuck of data */
  3601.  
  3602. } /* ProcessStreamin() */
  3603.  
  3604.  
  3605.         /* SendNew() - request new layer channel from MacLayers */
  3606.  
  3607. /*    This command is unique in that it returns a response from MacLayers.
  3608. **    To do this we continue processing the input stream until we get
  3609. **    our return. (This leads to recursive conditions.) The variables
  3610. **    'SNresp', 'SNshape' and 'SNchan' are set when our reply is received.
  3611. */
  3612. int
  3613. SendNew(shape)
  3614. struct Shape    *shape;                /* shape to use for new window */
  3615. {
  3616.     int            i;                    /* attribute count variable */
  3617.     char        astring[ATTRSIZE];    /* copy of attribute string */
  3618.  
  3619.     DO DEBUG("SendNew() new layer requested: '~%cA'\n", '1'+ATTRSIZE);
  3620.  
  3621.     /* check for a recursive call */
  3622.     if (SNresp == SN_WAITING)
  3623.       {    DO DEBUG("return 0 - recursive call\n");
  3624.         return ( 0 );                /* return failure */
  3625.       }
  3626.  
  3627.     putchar(ESCAPE);                /* send start of control packet char */
  3628.     putchar('1' + ATTRSIZE);        /* send command size */
  3629.     putchar('A');                    /* send command */
  3630.     asciishape(shape, astring);        /* convert shape to string */
  3631.     for (i=0; i < ATTRSIZE; i++)
  3632.         putchar(astring[i]);        /* send next attribute digit */
  3633.     FLUSH;
  3634.  
  3635.     /* now stay here and process the input stream until we see our response */
  3636. /**** THIS SHOULD BE ENHANCED TO TIMEOUT WITH GetData() AND REISSUE REQUEST */
  3637.     SNresp = SN_WAITING;            /* indicate we are waiting a response */
  3638.     while (SNresp == SN_WAITING)
  3639.       { DO DEBUG(" while (SNresp %d == %d)\n", SNresp, SN_WAITING);
  3640.         AwaitInput();                /* wait till input from MacLayers arrives */
  3641.         ProcessStreamin();            /* process available input */
  3642.       }
  3643.  
  3644.     if (SNresp == -1)                /* if Maclayers rejected request */
  3645.         SNchan = 0;                    /* return failure channel of zero */
  3646.     else
  3647.         *shape = SNshape;            /* else update shape structure */
  3648.  
  3649.     DO DEBUG("SendNew() returning channel %d\n", SNchan);
  3650.  
  3651.     return ( SNchan );                /* return the indicated channel */
  3652.  
  3653. } /* SendNew() */
  3654.  
  3655.  
  3656.             /* SendReshape() - send to shape to MacLayers */
  3657.  
  3658. void
  3659. SendReshape(chan, shape)
  3660. int                chan;                /* channel shape belongs to */
  3661. struct Shape    *shape;                /* shape to use for new window */
  3662. {
  3663.     int            i;                    /* attribute count variable */
  3664.     char        astring[ATTRSIZE];    /* copy of attribute string */
  3665.  
  3666.     DO DEBUG("SendReshape() reshape: '~%cA'\n", '2'+ATTRSIZE);
  3667.  
  3668.     if (chan <= 0 || chan > MAXPCHAN)
  3669.       {    DO DEBUG("BAD CHANNEL!!!\n");
  3670.         return;                        /* ignore request */
  3671.       }
  3672.  
  3673.     putchar(ESCAPE);                /* send start of control packet char */
  3674.     putchar('2' + ATTRSIZE);        /* send command size */
  3675.     putchar('R');                    /* send command */
  3676.     putchar(chan + '0');            /* send channel */
  3677.     asciishape(shape, astring);        /* convert shape to string */
  3678.     DO DEBUG("shape: %.*s\n", ATTRSIZE, astring);
  3679.     for (i=0; i < ATTRSIZE; i++)
  3680.         putchar(astring[i]);        /* send next attribute digit */
  3681.     FLUSH;
  3682.  
  3683. } /* SendReshape() */
  3684.  
  3685.  
  3686.             /* SendTitle() - set layer's window title */
  3687.  
  3688. void
  3689. SendTitle(chan, buff, cnt)
  3690. int            chan;                    /* layer window ID */
  3691. char        *buff;                    /* new title string */
  3692. int            cnt;                    /* count of title length */
  3693. {
  3694.     int        i;                        /* work variable */
  3695.  
  3696.     DO DEBUG("SendTitle(chan%d, len %d, '%.*s')\n", chan, cnt, cnt, buff);
  3697.  
  3698.     if (chan <= 0 || chan > MAXPCHAN)
  3699.       {    DO DEBUG("BAD CHANNEL!!!\n");
  3700.         return;                        /* ignore request */
  3701.       }
  3702.  
  3703.     if (cnt < 0)
  3704.       {    DO DEBUG("BAD COUNT!!!\n");
  3705.         return;                        /* ignore request */
  3706.       }
  3707.  
  3708.     /* for now chop title size to 29 chars since that's MacLayer's limit */
  3709.     if (cnt > 29)
  3710.         cnt = 29;                    /* due to packet size limit */
  3711.  
  3712.     /* we must guarantee that the size will not appear to be another ESCAPE */
  3713.     if ('2' + cnt == ESCAPE)
  3714.         cnt--;                        /* truncate to avoid ESCAPE ESCAPE */
  3715.     
  3716.     putchar(ESCAPE);                /* send start of control packet char */
  3717.     putchar('2' + cnt);                /* send size of packet */
  3718.     putchar('T');                    /* send command */
  3719.     putchar(chan + '0');            /* send channel ID */
  3720.     for (i=0; i<cnt; i++)
  3721.         putchar(buff[i]);            /* send out title */
  3722.     FLUSH;
  3723.  
  3724. } /* SendTitle() */
  3725.  
  3726.  
  3727.             /* SendDelete() - tell Maclayers layer died */
  3728.  
  3729. void
  3730. SendDelete(chan)
  3731. int        chan;                        /* dead channel ID */
  3732. {
  3733.     DO DEBUG("SendDelete(%d) '~2D%d'\n", chan, chan);
  3734.  
  3735.     if (chan <= 0 || chan > MAXPCHAN) /* check channel ID */
  3736.       {    DO DEBUG("BAD CHANNEL!!!\n");
  3737.         return;                        /* ignore request */
  3738.       }
  3739.  
  3740.     putchar(ESCAPE);                /* send control packet start char */
  3741.     putchar('2');                    /* send command size */
  3742.     putchar('D');                    /* send command character */
  3743.     putchar(chan + '0');            /* channel ID in ascii */
  3744.     FLUSH;
  3745.  
  3746. } /* SendDelete() */
  3747.  
  3748.  
  3749.             /* SendQuit() - order MacLayers to end layers mode */
  3750.  
  3751. void
  3752. SendQuit(chan)
  3753. int        chan;                        /* dead channel ID */
  3754. {
  3755.     DO DEBUG("SendQuit() '~1E'\n");
  3756.  
  3757.     putchar(ESCAPE);                /* send control packet start char */
  3758.     putchar('1');                    /* send command size */
  3759.     putchar('E');                    /* send command */
  3760.     FLUSH;
  3761.  
  3762. } /* SendQuit() */
  3763.  
  3764.  
  3765.             /* SendData() - send output to layer's window */
  3766.  
  3767. void
  3768. SendData(chan, buff, cnt)
  3769. int            chan;                    /* layer window ID */
  3770. unsigned char *buff;                /* new title string */
  3771. int            cnt;                    /* count of title length */
  3772. {
  3773.     unsigned c;                        /* output character being sent */
  3774.  
  3775.     DO
  3776.       {    int        dcnt;
  3777.  
  3778.         DEBUG("SendData(chan %d, len %d, '", chan, cnt, cnt, buff);
  3779.         for (dcnt=0; dcnt<cnt; dcnt++)
  3780.             DEBUG("%c", buff[dcnt]); /* dump each char so null doesn't stop */
  3781.         DEBUG("')\n");
  3782.       }
  3783.  
  3784.     if (chan <= 0 || chan > MAXPCHAN)
  3785.       {    DO DEBUG("BAD CHANNEL!!!\n");
  3786.         return;                        /* ignore request */
  3787.       }
  3788.  
  3789.     /* if new output channel stream then prefix redirect command */
  3790.     if (chan != Outstream)
  3791.       {    DO DEBUG("Redirecting output to %d '~2O%d'\n", chan, chan);
  3792.         putchar(ESCAPE);            /* start of command sequence */
  3793.         putchar('2');                /* send command size */
  3794.         putchar('O');                /* send command */
  3795.         putchar(chan + '0');        /* put out channel in ASCII */
  3796.         Outstream = chan;            /* new output stream set */
  3797.       }
  3798.  
  3799.     /* transmit the buffer converting the ESCAPE sequence to double ESCAPE */
  3800.     while (cnt--)
  3801.       {    c = *buff++;                /* get next output character */
  3802. #ifdef DUMPALL
  3803.         DO DEBUG("outchar %c 0x%x\n", c, c);
  3804. #endif
  3805.         if (c == ESCAPE || c == (ESCAPE + 0x80))
  3806.           {    putchar(c);                /* put it out twice */
  3807. #ifdef DUMPALL
  3808.             DO DEBUG(" Doubled Escape!\n");
  3809. #endif
  3810.           }
  3811.         putchar(c);                    /* write character out */
  3812.       }
  3813.  
  3814.     FLUSH;                            /* force out queued output characters */
  3815.         
  3816. } /* SendData() */
  3817.  
  3818.  
  3819.             /* Parse() - process next chunk of input stream */
  3820.  
  3821. static void
  3822. Parse()
  3823. {
  3824. #define    ST_NULL        0                /* not primed for next state yet */
  3825. #define    ST_STREAM    1                /* processing default stream input */
  3826. #define    ST_PKT        2                /* processing packet data */
  3827.  
  3828.     int        c;                        /* input character being processed */
  3829.  
  3830.     static    int state = ST_NULL;    /* current input state */
  3831.     static    int psize = 0;            /* packet size */
  3832.     static    int    rempsize = 0;        /* remembered packet size */
  3833.     static    char pdata[MAXSTR];        /* area for packet data */
  3834.     static    char *ppos;                /* packet read insert position */
  3835.     static    int escapemode = 0;        /* processing escape character */
  3836.     static    int    escapechar;            /* escape character being processed */
  3837.     static    pchan = -1;                /* packet input stream channel */
  3838.  
  3839.     while (insize-- > 0)            /* while more data */
  3840.       {    c = *inpos++;                /* get next character */
  3841.         switch (state)                /* process according to state */
  3842.         { case ST_NULL:                /* prepare for new packet */
  3843.             DO DEBUG("ST_NULL\n");
  3844.             psize = 0;                /* clear packet size */
  3845.             ppos = pdata;            /* start fill at data position */
  3846.             pchan = Instream;        /* packet channel is current input stream */
  3847.             state = ST_STREAM;        /* default is stream processing */
  3848.  
  3849.           case ST_STREAM:
  3850.             /* stream keyboard input for layer */
  3851.             /* check for escape char with possible high bit on */
  3852. #ifdef DUMPALL
  3853.             DO DEBUG("ST_STREAM %x/%x esc %d insz %d\n",
  3854.                         c, c & 0x7f, escapemode, insize);
  3855. #endif
  3856.             if (c == ESCAPE || c == (ESCAPE | 0x80))
  3857.               {    if (escapemode && c == escapechar) /* previous was ESCAPE */
  3858.                 /* this is really a single ESCAPE character */
  3859.                     escapemode = 0;        /* back out of ESCAPE mode */
  3860.                 else
  3861.                     /* what do we do with back to back esc esc+0x80 ? */
  3862.                   {    /* flag in escape mode */
  3863.                     escapemode++;
  3864.                     escapechar = c;        /* remember character used for escape */
  3865.                     continue;            /* and continue scan */
  3866.                   }
  3867.               }
  3868.             else
  3869.             if (escapemode)
  3870.               { /* this is the start of a control packet */
  3871.                 if (psize)                /* if we have previous data packet */
  3872.                     Packet(pchan, psize, pdata); /* finish up previous pkt */
  3873.                 /* process packet size */
  3874.                 psize = (c & 0x7f) - '0'; /* save size byte */
  3875.                 if (psize <= 0 || psize > MAXSTR)
  3876.                   {    /* bad size */
  3877.                     DO DEBUG("Bad pkt size %d\n", psize);
  3878.                     break;                /* trash this packet */
  3879.                   }
  3880.                 rempsize = psize;        /* remember this size for later */
  3881. #if 0
  3882.                 ptimo = rtimo;            /* start receive timeout */                
  3883. #endif
  3884.                 escapemode = 0;            /* escape mode now off */
  3885.                 ppos = pdata;            /* initialize data store pointer */
  3886.                 state = ST_PKT;            /* expect packet data next */
  3887.                 continue;                /* continue scan */
  3888.               }
  3889.                   
  3890.             /* process standard data output character for current stream */
  3891.             
  3892.             *ppos++ = c;                /* save next data character */
  3893.                 
  3894.             if (++psize >= MAXSTR)        /* if packet full ... */
  3895.               {    Packet(pchan, psize, pdata); /* process this packet */
  3896.                 break;                    /* end packet processing */
  3897.               }                  
  3898.             continue;                    /* continue scan */
  3899.                                                 
  3900.           case ST_PKT:
  3901.             /* process next paket data byte */
  3902.             *ppos++ = c & 0x7f;        /* store next data byte */
  3903. #ifdef DUMPALL
  3904.             DO DEBUG("ST_PKT: %x sz %d\n", c & 0x7f, psize);
  3905. #endif
  3906.             if (--psize != 0)
  3907.                 continue;
  3908. #if 0
  3909.             if (crc((unsigned char *) &rpkt, rpkt.pkt.HEADER_DSIZE+2))
  3910.                 STATS(Scrcerr);            /* communications error */
  3911.             else
  3912. #endif
  3913.             Packet(0, rempsize, pdata); /* process it */
  3914.                 
  3915.             } /* end build packet switch */
  3916.             
  3917. #if 0
  3918.         ptimo = 0;                        /* no more receive timeout */
  3919. #endif
  3920.         state = ST_NULL;                /* no more receive packet in progress */
  3921.             
  3922.       } /* end while (insize) */
  3923.           
  3924.     if (state == ST_STREAM && psize )    /* if we have some data ... */
  3925.       {    Packet(Instream, psize, pdata); /* process this data */
  3926. #if 0
  3927.         ptimo = 0;                        /* no more receive timeout */
  3928. #endif
  3929.         state = ST_NULL;                /* no more receive packet in progress */
  3930.       }
  3931.  
  3932. } /* Parse() */
  3933.  
  3934.  
  3935.         /* Packet() - prcess next input data string or control packet */
  3936. static void
  3937. Packet(chan, size, buff)
  3938. int            chan;                        /* channel (0 if control packet) */
  3939. int            size;                        /* amount of data */
  3940. char        *buff;                        /* pointer to packet data */
  3941. {
  3942.     static struct Shape shape;            /* Shape structure */
  3943.  
  3944.     DO DEBUG("Packet(chan %d, size %d, '%.*s')\n", chan, size, size, buff);
  3945.  
  3946.     /* verify channel */
  3947.     if (chan < 0 || chan > MAXPCHAN)
  3948.       {    DO DEBUG("BAD CHANNEL!!\n");
  3949.         return;                            /* ignore bad channel */
  3950.       }
  3951.  
  3952.     /* if data packet (chan>0) feed data to server */
  3953.     if (chan > 0)
  3954.       {    ReceiveData(chan, buff, size);
  3955.         return;                            /* we are through */
  3956.       }
  3957.  
  3958.     /* control packet (channel 0) */
  3959.     chan = buff[1] - '0';                /* assume channel specified */
  3960.     if (chan < 0 || chan > MAXPCHAN)    /* if invalid ... */
  3961.         chan = 0;                        /* set to zero */
  3962.  
  3963.     switch (buff[0])
  3964.     { case 'I':        /* redirect stream */
  3965.         DO DEBUG("CMD 'I' redirect stream to %c\n", buff[1]);
  3966.         if (size != 2)                    /* verify size */
  3967.             break;                        /* break if bad */
  3968.         if (chan == 0)                    /* verify channel */
  3969.             break;                        /* break if bad */
  3970.         Instream = chan;                /* new instream channel */
  3971.         return;                            /* we are through */
  3972.  
  3973.       case 'A':        /* returned A_NEWLAYER packet */
  3974.         DO DEBUG("CMD 'A' A_NEWLAYER response %c newchan %c SNresp %d\n",
  3975.                     buff[2], buff[1], SNresp);
  3976.         if (size != 3 + ATTRSIZE)
  3977.             break;                        /* break if bad */
  3978.  
  3979.         /* if SendNew() not waiting for a response this is invalid */
  3980.         if (SNresp != SN_WAITING)
  3981.             break;                        /* break if bad */
  3982.  
  3983.         if (buff[2] == '1')                /* if response is "failed" ... */
  3984.             SNresp = -1;                /* show -1 response */
  3985.         else
  3986.         if (buff[2] == '0')                /* if response is "success" ... */
  3987.           {    if (chan == 0)                /* if invalid channel */
  3988.                 break;                    /* break if bad */
  3989.             /* build shape structure for SendNew() */
  3990.             if (parseshape(&SNshape, &buff[3]) == -1)
  3991.                 break;                    /* if invalid data then bad packet */
  3992.             SNresp = 0;                    /* show good response */
  3993.             SNchan = chan;                /* indicate channel returned */
  3994.           }
  3995.         else
  3996.             break;                        /* break if bad */
  3997.  
  3998.         DO DEBUG("SNresp = %d, SNchan = %d\n", SNresp, SNchan);
  3999.         return;                            /* we are through */
  4000.         
  4001.       case 'N':        /* new layer creation */
  4002.         DO DEBUG("CMD 'N' new layer creation newchan %c\n", buff[1]);
  4003.         if (size != 2 + ATTRSIZE)        /* verify size */
  4004.             break;                        /* break if bad */
  4005.         if (chan == 0)                    /* verify channel */
  4006.             break;                        /* break if bad */
  4007.         /* build shape structure */
  4008.         if (parseshape(&shape, &buff[2]) == -1)
  4009.             break;                        /* if invalid data then bad packet */
  4010.         ReceiveNew(chan, &shape);        /* pass to server */
  4011.         return;                            /* packet is done */
  4012.  
  4013.       case 'D':        /* deleted layer */
  4014.         DO DEBUG("CMD 'D' deleted layer %c\n", buff[1]);
  4015.         if (size != 2)                    /* verify size */
  4016.             break;                        /* break if bad */
  4017.         if (chan == 0)                    /* verify channel */
  4018.             break;                        /* break if bad */
  4019.         ReceiveDelete(chan);            /* pass on to server */
  4020.         return;                            /* packet is done */
  4021.  
  4022.       case 'E':        /* exit - awaiting shutdown */
  4023.         DO DEBUG("CMD 'E' exit MacLayers awaiting shutdown msg\n");
  4024.         if (size != 1)                    /* verify size */
  4025.             break;                        /* break if bad */
  4026.         ReceiveQuit();                    /* pass to server */
  4027.         /* NOT REACHED*/
  4028.         return;                            /* ?? should never reach here */
  4029.  
  4030.       case 'R':        /* reshaped */
  4031.         DO DEBUG("CMD 'R' reshape chan %c\n", buff[1]);
  4032.  
  4033.         if (size != 2 + ATTRSIZE)        /* verify size */
  4034.             break;                        /* break if bad */
  4035.  
  4036.         if (chan == 0)                    /* verify channel */
  4037.             break;                        /* break if bad */
  4038.  
  4039.         /* build shape structure */
  4040.         if (parseshape(&shape, &buff[2]) == -1)
  4041.             break;                        /* if invalid data then bad packet */
  4042.  
  4043.         ReceiveReshape(chan, &shape);     /* tell server about shape */
  4044.         return;                            /* packet processed */
  4045.  
  4046.       case 'S':        /* signal */
  4047.         DO DEBUG("CMD 'S' SIGNAL chan %c sig %c\n", buff[1], buff[2]);
  4048.         if (size != 3)                    /* verify size */
  4049.             break;                        /* break if bad */
  4050.         if (chan == 0)
  4051.             break;                        /* break if bad */
  4052.  
  4053.         if (buff[2] == '0')                /* if SIGINT */
  4054.             size = SIGINT;                /* yes */
  4055.         else
  4056.         if (buff[2] == '1')                /* if SIGHUP */
  4057.             size = SIGHUP;                /* yes */
  4058.         else
  4059.             break;                        /* invalid signal */
  4060.             
  4061.         ReceiveSignal(chan, size);        /* pass to server */
  4062.         return;                            /* packet processed */
  4063.  
  4064.       default:
  4065.         DO DEBUG("ILLEGAL CONTROL PACKET!!!\n");
  4066.         return;                            /* ignore bad packet */
  4067.  
  4068.     } /* end command packet switch */
  4069.  
  4070.     /* switch falls out if bad size or channel for given command */
  4071.     DO DEBUG("Invalid size or channel!!!\n");    /* dump error */
  4072.     return;                                /* ignore packet */
  4073.  
  4074. } /* Packet() */
  4075.  
  4076.  
  4077.             /* GetData() - read next input from MacLayers stream */
  4078.  
  4079. /*    An input timout parameter can indicate that we return if nothing
  4080. **    is read within a certain amount of seconds. The return code is:
  4081. **
  4082. **        0 - timeout occured and no data was read
  4083. **
  4084. **        1 - no timeout occured, data read
  4085. */
  4086. static int
  4087. GetData(timeout)
  4088. int            timeout;                /* timeout in seconds (or zero) */
  4089. {
  4090.     int        result;                    /* return from read() */
  4091.  
  4092.     DO DEBUG("GetData(timout %d)\n", timeout);
  4093.  
  4094.     /* if buffer still has data simply return (SHOULD NOT OCCUR?) */
  4095.     if (insize > 0)
  4096.         return ( 1 );                /* act as through data read */
  4097.     inpos = inbuff;                    /* next get will start at beginning */
  4098.     insize = 0;                        /* default insize back to zero */
  4099.  
  4100.     /* set timeout if we are to do so */
  4101.     if (timeout)
  4102.         (void) alarm(timeout);        /* set timeout in seconds */
  4103.  
  4104.     /* do the read from stdin */
  4105.     result = read(0, inbuff, IOSIZE);
  4106.  
  4107.     /* if alarm was set cancel it now */
  4108.     if (timeout)
  4109.         (void) alarm(0);            /* cancel alarm */
  4110.  
  4111.     /* check for timeout or error */
  4112.     /* EWOULDBLOCK for no data avail -(but we should not see this) */
  4113.     /* EINTR if signal stopped the read -(rare but could happen) */
  4114.     if (result <= 0)
  4115.         return ( 0 );                /* return nothing read */
  4116.  
  4117.     /* return with fresh buffer data */
  4118.     insize = result;
  4119.     DO DEBUG("read %d bytes\n", insize);
  4120.     return ( 1 );                    /* return OK code */
  4121.  
  4122. } /* GetData() */
  4123.  
  4124.  
  4125.             /* AwaitInput() - wait for more input from MacLayers */
  4126.  
  4127. static void
  4128. AwaitInput()
  4129. {
  4130.     int        r;                        /*  read descriptor bits */
  4131.  
  4132.     DO DEBUG("AwaitInput()\n");
  4133.  
  4134.     do
  4135.       {    r = 1<<0;                    /* wait for read from input device */
  4136.         if (select(32, &r, NULL, NULL, NULL) == -1)    /* if problem waiting ... */
  4137.           {    if (errno != EINTR)            /* if not simply signal taken ... */
  4138.               {    /* SHOULD NOT OCCUR - shutdown layers */
  4139.                 DO DEBUG("AwaitInput: select error %d\n", errno);
  4140.                 printf("layers: AwaitInput: bad select %d\n", errno);
  4141.                 FQuit();                    /* shutdown layers */
  4142.                 /* NOT REACHED */
  4143.               }
  4144.           }
  4145.       } while ((r & 1<<0) == 0);
  4146.         
  4147. } /* AwaitInput() */
  4148.  
  4149.                 /* asciishape() - convert Shape structure to ASCII */
  4150. static void
  4151. asciishape(shape, loc)
  4152. struct Shape    *shape;                        /* Shape structure for channel */
  4153. char            *loc;                        /* location to start filling result */
  4154. {
  4155.     char        *origloc;                    /* (for debuggin) */
  4156.  
  4157.     origloc = loc;                            /* remember start of string */
  4158.     fill4(&loc, shape->worigh);                /* origin h */
  4159.     fill4(&loc, shape->worigv);                /* origin v */
  4160.     fill2(&loc, shape->wlines);                /* lines high */
  4161.     fill2(&loc, shape->wchars);                /* chars wide */
  4162.     fill1(&loc, shape->wfont);                /* font size */
  4163.     fill2(&loc, shape->wattr);                /* attributes */
  4164.  
  4165.     DO DEBUG("asciishape(): %.*s\n", ATTRSIZE, origloc);
  4166.  
  4167. } /* asciishape() */
  4168.  
  4169.  
  4170.                     /* fill4() - convert parameter to ASCII */
  4171.  
  4172. static void
  4173. fill4(loc, valu)
  4174. char        **loc;                            /* pointer to fill area pointer */
  4175. unsigned    valu;                            /* value to use */
  4176. {
  4177.     fill2(loc, valu>>8);                    /* fill high half word */
  4178.     fill2(loc, valu & 0xff);                /* fill low half word */
  4179.  
  4180. } /* fill4() */
  4181.  
  4182.  
  4183.                     /* fill2() - convert parameter to ASCII */
  4184.  
  4185. static void
  4186. fill2(loc, valu)
  4187. char        **loc;                            /* pointer to fill area pointer */
  4188. unsigned    valu;                            /* value to use */
  4189. {
  4190.     fill1(loc, valu>>4);                    /* fill high byte */
  4191.     fill1(loc, valu & 0xf);                    /* fill low byte */
  4192.     
  4193. } /* fill2() */
  4194.  
  4195.  
  4196.                     /* fill1() - convert parameter to ASCII */
  4197.  
  4198. static void
  4199. fill1(loc, valu)
  4200. char        **loc;                            /* pointer to fill area pointer */
  4201. unsigned    valu;                            /* value to use */
  4202. {
  4203.     *(*loc)++ = "0123456789ABCDEF"[valu & 0xf]; /* return hex value */
  4204.  
  4205. } /* fill1() */
  4206.  
  4207.  
  4208.             /* parseshape() - convert ASCII image to Shape structure */
  4209.                 
  4210. static int    Badconvert;                        /* indicates bad conversion */
  4211.  
  4212. static int
  4213. parseshape(shape, loc)
  4214. struct Shape    *shape;                        /* Shape structure for channel */
  4215. char            *loc;                        /* location to start parsing */
  4216. {
  4217.     Badconvert = 0;                            /* clear bad characters indicator */
  4218.     shape->worigh = get4(&loc);                /* origin h */
  4219.     shape->worigv = get4(&loc);                /* origin v */
  4220.     shape->wlines = get2(&loc);                /* lines high */
  4221.     shape->wchars = get2(&loc);                /* chars wide */
  4222.     shape->wfont = get1(&loc);                /* font size */
  4223.     shape->wattr = get2(&loc);                /* attributes */
  4224.  
  4225.     DO DEBUG("ParseShape(): origv %d, origh %d, lines %d, chars %d\n",
  4226.                 shape->worigv, shape->worigh, shape->wlines, shape->wchars);
  4227.     DO DEBUG("   font %d, attr 0x%x, badconv %d\n",
  4228.                     shape->wfont, shape->wattr, Badconvert);
  4229.  
  4230.     return ( Badconvert ? -1 : 0 );            /* return conversion code */
  4231.  
  4232. } /* parseshape() */
  4233.  
  4234.  
  4235.                     /* get4() - convert ASCII to parameter */
  4236.  
  4237. static unsigned
  4238. get4(loc)
  4239. char        **loc;                            /* pointer to fill area pointer */
  4240. {
  4241.     unsigned    hi;                            /* high portion */
  4242.     unsigned    low;                        /* low portion */
  4243.  
  4244.     hi = get2(loc);                            /* get high byte */
  4245.     low = get2(loc);                        /* get low byte */
  4246.  
  4247.     return ( (hi<<8) + low );                /* return word value */
  4248.  
  4249. } /* get4() */
  4250.  
  4251.  
  4252.                     /* get2() - convert ASCII to parameter */
  4253.  
  4254. static unsigned
  4255. get2(loc)
  4256. char        **loc;                            /* pointer to fill area pointer */
  4257. {
  4258.     unsigned    hi;                            /* high portion */
  4259.     unsigned    low;                        /* low portion */
  4260.  
  4261.     hi = get1(loc);                            /* get high half */
  4262.     low = get1(loc);                        /* get low half */
  4263.  
  4264.     return ( (hi<<4) + low );                /* return byte value */
  4265.     
  4266. } /* get2() */
  4267.  
  4268.  
  4269.                     /* get1() - convert ASCII to parameter */
  4270.  
  4271. /*    This function sets 'Badconvert' if an invalid character is detected */
  4272.  
  4273. static unsigned
  4274. get1(loc)
  4275. char        **loc;                            /* pointer to fill area pointer */
  4276. {
  4277.     int            c;                            /* character to convert */
  4278.     
  4279.     c = *(*loc)++;                            /* fetch character */
  4280.     
  4281.     if (c >= '0' && c <= '9')
  4282.         /* zero through nine */
  4283.         return ( c - '0' );                    /* return it's binary value */
  4284.     
  4285.     if (c >= 'a' && c <= 'f')
  4286.         /* lower case hex */
  4287.         return ( c - 'a' + 10);                /* return it's binary value */
  4288.         
  4289.     if (c >= 'A' && c <= 'F')
  4290.         /* upper case hex */
  4291.         return ( c - 'A' + 10);                /* return it's binary value */
  4292.         
  4293.     /* invalid digit! */
  4294.     Badconvert++;                            /* set bad character flag */
  4295.     return ( 0 );                            /* return a zero */
  4296.  
  4297. } /* get1() */
  4298. @//E*O*F protocol.c//
  4299. chmod u=rw,g=rw,o=rw protocol.c
  4300.  
  4301. echo Inspecting for damage in transit...
  4302. temp=/tmp/shar$$; dtemp=/tmp/.shar$$
  4303. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  4304. cat > $temp <<\!!!
  4305.       62     290    2241 README
  4306.      123     795    4858 layers.1
  4307.     2213    8497   56819 layers.c
  4308.       64     311    2049 layers.h
  4309.      146     589    3586 layersize.c
  4310.       41     176    1242 layertitle.c
  4311.      122     506    2849 macbput.1
  4312.      529    1341    9383 macbput.c
  4313.       71     212    1674 makefile
  4314.      869    4181   25546 protocol.c
  4315.     4240   16898  110247 total
  4316. !!!
  4317. wc  README layers.1 layers.c layers.h layersize.c layertitle.c macbput.1 macbput.c makefile protocol.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  4318. if [ -s $dtemp ]
  4319. then echo "Ouch [diff of wc output]:" ; cat $dtemp
  4320. else echo "No problems found."
  4321. fi
  4322. exit 0
  4323.  
  4324.