#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh '1.30/layers.c' <<'END_OF_FILE' X/******** Layers.c X********* X********* Layers - MacLayers Multiwindow BSD Socket Driver X********* X********* David W. Trissel and Eric C. Rosen X********* X********* The sockets handling portion of this control module is based X********* upon 'screen' by Oliver Laumann whose copyright remains below. X********* The rest is X * X * Copyright (C) 1993 by Eric C. Rosen X * Copyright (C) 1989-1992 by David W. Trissel X * X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the authors are not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X * X */ X Xstatic char LayersVersion[] = "layers 1.30 17-May-1993"; X X/* Layers Changes: X X X Version 1.00 17-Mar-1990 X X First public release. X X Version 1.01 10-May-1990 X X * Fixed bug 001 which caused failure of protocol mode to establish X if USRLIMIT check is enabled and USRLIMIT or more login shells X are already active. Could also keep new login layer windows from X responding until another layer is brought up front and then sent X back. X X Version 1.01 27-Jun-1991 X X * Corrected bugs where utmp login record or initial tty settings X may not be restored if initial client connection fails X X * Added return code support so shell scripts can determine what X happened: X 0 - layers connected, ran and terminated sucessfully X 1 - not running under MacLayers client terminal X 2 - layers terminated due to some abnormal condition X 3 - SIGQUIT or SIGTERM signal received X 4 - SIGHUP signal received X X * Rewrote protocl.c to avoid using scanf which was prohibiting 7-bit X communication lines from working under layers mode. (Scanf does X not work on 7-bit line in RAW mode since high bit invalidates X its character checking.) X X * Removed internal TERMCAP entries for "ic" and "dc" (insert character X and delete character) which are not ANSI standard. The "dc" collided X with a real vt-100 capability that the author did not know about! X (Note of 6/11/91: perhaps "dc" and "ic" will be reinstated with X their true ANSI definitions. 6/11/91) X X * If socket directory not 0700 then try to change it to 0700. X X Version 1.10 26-Sep-1991 X X * Host/client version ID sharing at startup. This is transparent on X both sides with older versions. X X 1) If client identifies itself as at least 1.10 MacLayers X add vt102 TERMCAP entries for ic, dc, IC, DC with correct X capabilities. (V1.00 had incorrect ones-see above.) X X X Version 1.30 10-May-1993 X X * Added support for .layersrc file. X * Added support for A/UX, IRIX, AIX, ULTRIX, and NeXT systems; X should work on most System V platforms now with a few flags set. X * Cleaned up source (a little); removed some unused variables. X*/ X X X/* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin. X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X * X * Modified by Patrick Wolfe (pat@kai.com, kailand!pat) X * Do whatever you want with (my modifications of) this program, but X * don't claim you wrote them, don't try to make money from them, and X * don't remove this notice. X */ X X/* X * Beginning of User Configuration Section X * X * You can set these variables from the command-line via the X * provided makefile. Type 'make' for details. X */ X X X/* X * GETTTYENT -- your system has the new format /etc/ttys (like 4.3 BSD) X * and the getttyent(3) library functions. X * X */ X X/* X * These options are best set within the code. Don't change these unless X * you know what you are doing. X */ X X/* X * LOGINDEFAULT -- if set to 1 (one), windows will login (add entries to X * /etc/utmp) by default. Set to 0 if you don't want this. X * (Also see USRLIMIT below). [NOTE: current code always X * logs layer #1 only unless -l option used on 'layers' X * command.] X */ X#define LOGINDEFAULT 0 X X/* X * USRLIMIT -- count all non-null entries in /etc/utmp before adding a X * new entry. Some machine manufacturers (incorrectly) count X * logins by counting non-null entries in /etc/utmp (instead X * of counting non-null entries with no hostname and not on X * a pseudo tty). Sequent does this, so you might reach your X * limited user license early. X */ X#define USRLIMIT 64 X X/* X * SOCKDIR -- If defined, this directory is where layers sockets will be X * placed, (actually in a subdirectory by the user's loginid). X * This is neccessary because NFS doesn't support socket X * operations, and many people's homes are on NFS mounted X * partitions. Layers will create this directory if it needs X * to. X */ X#define SOCKDIR "/tmp/layers" /* NFS doesn't support named sockets */ X X/* X * End of User Configuration Section X */ X X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X X/* X * Begin pre-defined environment definition section: X */ X X/* Apple A/UX: */ X#ifdef AUX X#define SYSVUTMP X#define USE_TERMIO X#undef USRLIMIT X#endif X X/* Silicon Graphics IRIX: */ X#ifdef IRIX X#define POSIXTTY X#define SYSVUTMP X#define IGNORE_SIGHUP X#undef GETTTYENT X#undef USRLIMIT X#endif X X/* NeXT: */ X#ifdef NeXT X#define GETTTYENT X#endif X X/* IBM AIX: */ X#ifdef AIX X#define USE_TERMIO X#define IGNORE_SIGHUP X#endif X X/* DEC ULTRIX: */ X#ifdef ULTRIX X#define GETTTYENT X#endif X X X/* Data General Aviion: */ X#ifdef DG_AVIION X#define _BSD_WAIT_FLAVOR 1 /* to avoid wait3 WIFSTOPPED macro error */ X#define USE_TERMIO X#define IGNORE_SIGHUP X#endif X X/* System V machines use sigset instead of signal to auto-reactivate handlers */ X#ifdef DG_AVIION X#define SIGNAL(a,b) sigset(a,b) X#endif X X#ifdef SVR4 X#define POSIXTTY X#undef USRLIMIT X#define index strchr X#endif X X#ifndef SIGNAL X#define SIGNAL(a,b) signal(a,b) X#endif X X/* X * End of predefined envirnment configuration section. X */ X X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ X X/* X * Begin include-files: X */ X X#if defined(IRIX) || defined(SVR4) X#include X#endif X X#include X X#ifdef NeXT X#include X#endif X X#include X X#ifdef __STRICT_BSD__ X#define SIGTYPE int X#else X#define SIGTYPE void X#endif X X/* X * Some systems do not have ; others don't have : X */ X#if !defined(SEQUENT) X#include X#endif X#if !defined(SVR4) X#include X#endif X X#include X#include X#include X#include X#include X#include X#include X#ifndef FD_SETSIZE Xtypedef int fd_set; X#endif X#include X#include X#include X#include X#include X#include X#include X#ifndef POSIXTTY X#include X#endif X X#ifdef SVR4 X#include X#include X#endif X X X#include "layers.h" X X#ifdef GETTTYENT X#include X#else Xstatic struct ttyent X { char *ty_name; X } *getttyent(); Xstatic char *tt, *ttnext; Xstatic char ttys[] = "/etc/ttys"; X#endif X X#ifndef FSCALE X#define FSCALE 1000.0 /* Sequent doesn't define FSCALE...grrrr */ X#endif X X#ifdef USRLIMIT Xstruct utmp utmpbuf; Xint UserCount; X#endif X X#define Ctrl(c) ((c)&037) X X/* C library items */ Xextern char **environ; Xextern errno; Xextern sys_nerr; Xextern char *sys_errlist[]; X#ifndef NeXT Xextern char *malloc(), *getenv(); Xextern char *getlogin(), *ttyname(); X#endif X X/* Local items */ Xstatic SIGTYPE FAbort(), SigHup(), SigChld(); Xstatic void AddCap(), FinitTerm(); Xstatic char *MakeTermcap(), *Filename(), **SaveArgs(), *GetTtyName(); /* [SaveArgs UNUSED] */ Xstatic void InitWorld(), ClearShape(), BuildTitle(), KillPG(); Xstatic void SetWindowSize(), RemoveTtyFromUtmp(), RestoreRealUtmp(), InitUtmp(); Xstatic int SetUtmp(); Xstatic int ProcessGeo(); X Xstatic int loginflag = -1; Xstatic char PtyName[32], TtyName[32]; Xstatic char *ShellProg; Xstatic char *ShellArgs[2]; Xstatic inlen; /* [UNUSED] */ Xstatic ESCseen; /* [UNUSED] */ Xstatic GotSignal; Xstatic char DefaultShell[] = "/bin/sh"; Xstatic char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin"; Xstatic char PtyProto[] = "/dev/ptyXY"; Xstatic char TtyProto[] = "/dev/ttyXY"; Xstatic int TtyMode = 0622; Xstatic struct stat RealTtyStat; /* Real tty stat */ Xstatic char RealTtyName[32] = ""; /* Real tty name */ Xstatic int RealTtyMode = 0; /* Real tty mode */ Xstatic int Oumask; /* Original user's umask */ Xstatic char SockPath[512]; X#ifdef SOCKDIR Xstatic char SockDir[] = SOCKDIR; X#else Xstatic char SockDir[] = ".layers"; X#endif Xstatic char *SockNamePtr, *SockName; Xstatic ServerSocket; Xstatic char *NewEnv[MAXARGS]; Xstatic char Esc = Ctrl('a'); /* [UNUSED] */ Xstatic char MetaEsc = 'a'; /* [UNUSED] */ Xstatic char *home; Xstatic Abortonmsg = 0; Xstatic Resetenvonmsg = 0; Xstatic utmp, utmpf; Xstatic char *LoginName; Xstatic mflag, nflag, fflag; Xstatic rflag; /* [UNUSED] */ Xstatic char HostName[MAXSTR]; Xstatic char *myname; Xstatic DevTty; X X#ifdef POSIXTTY X#include X Xstatic struct termios OldMode, NewMode; X#ifdef IRIX X#define SetTTY(fd, mode) ioctl(fd, TCSETA, mode) X#define GetTTY(fd, mode) ioctl(fd, TCGETA, mode) X#else X#define SetTTY(fd, mode) ioctl(fd, TCSETS, mode) X#define GetTTY(fd, mode) ioctl(fd, TCGETS, mode) X#endif /* IRIX */ X X#else X#ifdef USE_TERMIO X#include Xstruct termio OldMode, NewMode; X X#else X#include Xstatic struct mode { X struct sgttyb m_ttyb; X struct tchars m_tchars; X struct ltchars m_ltchars; X int m_ldisc; X int m_lmode; X} OldMode, NewMode; X X#endif /* AIX */ X#endif /* POSIXTTY */ X X#define MSG_CREATE 0 X#define MSG_ERROR 1 X Xstruct msg X { X int type; X union X { struct X { int lflag; /* login flag */ X struct Shape shape; /* window shape */ X int nargs; X char line[MAXLINE]; X char dir[1024]; X } create; X char message[MAXLINE]; X } m; X }; X X X /* dynamic keyboard input buffer definition */ Xstruct Kbuff X { struct Kbuff * next; /* next buffer in chain (or NULL) */ X int size; /* size of data in this buffer */ X int offset; /* start of first data in buffer */ X unsigned char text[IOSIZE]; /* text buffer itself */ X }; X X /* World layer definition */ Xstruct Layer { X int chan; /* channel represented by this layer */ X int allocated; /* layer allocated */ X int ptyfd; /* psuedo tty */ X int ptymask; /* mask for pty descriptor */ X int lpid; /* layer head process ID */ X int slot; /* utmp slot number */ X struct Kbuff *kbuff; /* keyboard input buffers */ X struct Shape shape; /* Shape structure to/from MacLayers */ X char cmd[MAXSTR]; /* command to execute */ X char tty[MAXSTR]; /* psuedo tty ID */ X }; X Xstatic struct Layer World[MAXPCHAN]; /* all layer structures */ X Xstatic int rows = 24; /* default window height in lines */ Xstatic int cols = 80; /* default window width in chars */ Xstatic char Termcap[1024]; Xstatic char Term[MAXSTR] = "TERM="; /* window's terminal type */ Xstatic char *UserTerm; /* terminal ID we are mimmicing */ Xstatic int flowctl; Xstatic tcLineLen = 100; X X#define EXITNORMAL 0 /* normal exit - connection succeeded */ X#define EXITNOMACLAYERS 1 /* not running to MacLayers terminal */ X#define EXITABNORMAL 2 /* something wrong generic error */ X#define EXITSIGQUIT 3 /* TERM or QUIT signal got us */ X#define EXITSIGHUP 4 /* HUP signal got us */ X Xstatic exitcode = EXITABNORMAL; /* default to abnormal exit */ X X/* co#80 and li$24 added dynamically for proper window size */ Xstatic char TermcapConst1[] = "TERMCAP=SC|"; X X#ifdef IRIX Xstatic char TermcapConst3[] = "|MacLayers virtual terminal|\\\n\ X :cr=^M:do=^J:nl=^J:bl=^G:cl=\\E[;H\\E[2J:\\\n\ X :le=^H:bs:am:cm=\\E[%i%d;%dH:nd=\\E[C:up=\\E[A:\\\n\ X :ce=\\E[K:cd=\\E[J:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\\\n\ X :md=\\E[1m:mr=\\E[7m:mb=\\E[5m:me=\\E[m:is=\\E[1;24r\\E[24;1H:\\\n\ X :rf=/usr/lib/tabset/vt100:\\\n\ X :rs=\\E>\\E[?3l\\E[?4l\\E[?5l\\E[?7h\\E[?8h:ks=\\E[?1h\\E=:ke=\\E>:\\\n\ X :ku=\\EOA:kd=\\EOB:kr=\\EOC:kl=\\EOD:kb=^H:\\\n\ X :ho=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:ta=^I:pt:sr=\\EM:vt#3:xn:\\\n\ X :sc=\\E7:rc=\\E8:cs=\\E[%i%d;%dr:\\\n\ X :"; X#else Xstatic char TermcapConst3[] = "|MacLayers virtual terminal|\\\n\ X :cr=^M:do=^J:nl=^J:bl=^G:cl=\\E[;H\\E[2J:\\\n\ X :le=^H:bs:am:cm=\\E[%i%d;%dH:nd=\\E[C:up=\\E[A:\\\n\ X :ce=\\E[K:cd=\\E[J:so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\\\n\ X :md=\\E[1m:mr=\\E[7m:mb=\\E[5m:me=\\E[m:is=\\E[1;24r\\E[24;1H:\\\n\ X :rf=/usr/lib/tabset/vt100:\\\n\ X :rs=\\E>\\E[?3l\\E[?4l\\E[?5l\\E[?7h\\E[?8h:ks=\\E[?1h\\E=:ke=\\E[?1l\\E>:\\\n\ X :ku=\\EOA:kd=\\EOB:kr=\\EOC:kl=\\EOD:kb=^H:\\\n\ X :ho=\\E[H:k1=\\EOP:k2=\\EOQ:k3=\\EOR:k4=\\EOS:ta=^I:pt:sr=\\EM:vt#3:xn:\\\n\ X :sc=\\E7:rc=\\E8:cs=\\E[%i%d;%dr:\\\n\ X :"; X#endif X X /* The following supported by MacLayers versions 1.1 and later */ X /* ANSI insert characters and delete characters */ Xstatic char TermcapConst101[] = "ic=\\E[@:dc=\\E[P:IC=\\E[%d@:DC=\\E[%dP:"; X Xint Dflag; /* debug dump flag */ Xint Clientlevel = 1; /* client protocol (Default to V1.00) */ Xint Protocollevel = 1; /* effective protocol (default 1) */ X X#ifdef IRIX Xstatic void ignore_alarm() X{ X signal(SIGALRM, ignore_alarm); X} X#endif X X#ifdef SVR4 X#include X Xstatic int getdtablesize() X{ X struct rlimit rl; X X (void) getrlimit(RLIMIT_NOFILE, &rl); X return rl.rlim_cur; X} X#endif X X X /* main() */ Xint Xmain(ac, av) Xint ac; Xchar **av; X{ X extern int Initlink(); X void Msg(), SigHandler(); X static void SendCreateMsg(), MakeNewEnv(); X static SetMode(); X X#ifndef POSIXTTY X static void GetTTY(), SetTTY(); X#endif X X static int GetSockName(), MakeClientSocket(), MakeServerSocket(), X MakeWindow(), ReadRc(); X static void ReceiveMsg(); X X register n; X register len; X register struct Layer *layer; X char *ap; X char *clienttitle = NULL; X struct passwd *ppp; X int s; X int r; /* read fd test bits */ X int w; /* write fd test bits */ X int stall; /* stall flag for priority channel */ X int fderr; /* error fd test bits */ X struct timeval tv; X struct Shape shape; /* window shape */ X char buf[IOSIZE]; X char rc[256]; X struct stat st; X struct Kbuff *kbptr; /* input keyboard buffer pointer */ X X time_t now; /* [UNUSED] */ X X Abortonmsg = 1; /* quit if message generated */ X ClearShape(&shape); /* initialize shape structure */ X myname = (ac == 0) ? "layers" : av[0]; X InitWorld(); /* clear World array structures */ X X while (ac > 0) X { ap = *++av; X if (--ac > 0 && *ap == '-') X { switch (ap[1]) X { case 'l': /* login this command line */ X loginflag = 1; X break; X X case 'd': /* dump debugging flag */ X Dflag = 1; X (void) freopen("layers.dump", "a", stderr); /* append mode */ X#ifdef SEQUENT X setlinebuf(stderr); X#else X setvbuf(stderr, NULL, _IOLBF, 0); X#endif X break; X X case 'u': /* do not login this command line */ X loginflag = 0; X break; X X case 'm': /* force this to be master and not a client */ X mflag = 1; X break; X X case 'n': /* no flow control */ X nflag = 1; X break; X X case 'f': /* flow control on */ X fflag = 1; X break; X X case 'v': /* do nothing but issue layers version */ X printf("%s\n", LayersVersion); X exit(EXITNORMAL); X/* X case 't': X if (ac > 1) { X clienttitle = *(++av); X ac--; X } X break; X*/ X X case 'g': X if (ac > 1) { X if (ProcessGeo(&shape, *(++av))) { X printf("%s: invalid geometry argument \"%s\"\n", myname, *av); X exit(EXITABNORMAL); X } X ac--; X } X break; X X default: X help: X Msg (0,"Use: %s [-f] [-g geometry-str] [-l | -u] [-m] [-n] [cmd args]\n", myname); X X } /* end switch on '-' option */ X X } /* end if '-' */ X X else X break; X X } /* end while parameters */ X X if (nflag && fflag) X Msg (0, "-f and -n are conflicting options."); X X if ((ShellProg = getenv ("SHELL")) == 0) X ShellProg = DefaultShell; X DO DEBUG("ShellProg %s\n", ShellProg); X X /* we mimmic the user's $TERM ID */ X if ((UserTerm = getenv("TERM")) == 0) X UserTerm = "layers"; /* use "layers" if none */ X (void) strcat(Term, UserTerm); X DO DEBUG("%s\n", Term); X X ShellArgs[0] = ShellProg; X if (ac == 0) X { ac = 1; X av = ShellArgs; X shape.wattr |= Wa_shell; /* indicate a shell window */ X } X X if ((home = getenv ("HOME")) == 0) X Msg (0, "$HOME is undefined."); X DO DEBUG("home %s\n", home); X X if ((LoginName = getlogin ()) == NULL || LoginName[0] == '\0') X { X if ((ppp = getpwuid(getuid())) == 0) { X Msg(0, "Can't get login-name from passwd file."); X exit(EXITABNORMAL); X } X LoginName = ppp->pw_name; X } X DO DEBUG("LoginName %s\n", LoginName); X X if ((Oumask=umask(0)) == -1) X Msg (errno, "Cannot change umask to zero"); X DO DEBUG("Original umask o%o\n", Oumask); X X#ifdef SOCKDIR X if (stat (SOCKDIR, &st) == -1) X { if (errno == ENOENT) X { if (mkdir (SOCKDIR, 0777) == -1) X Msg (errno, "Cannot make directory %s", SOCKDIR); X (void) chown (SOCKDIR, 0, 0); X } X else X Msg (errno, "Cannot get status of %s", SOCKDIR); X } X else X { if ((st.st_mode & S_IFMT) != S_IFDIR) X Msg (0, "%s is not a directory.", SOCKDIR); X if ((st.st_mode & 0777) != 0777) X Msg (0, "Directory %s must have mode 777.", SOCKDIR); X } X sprintf (SockPath, "%s/%s", SockDir, LoginName); X#else X sprintf (SockPath, "%s/%s", home, SockDir); X#endif X DO DEBUG("SockPath %s\n", SockPath); X X if (stat (SockPath, &st) == -1) X { if (errno == ENOENT) X { if (mkdir (SockPath, 0700) == -1) X Msg (errno, "Cannot make directory %s", SockPath); X (void) chown (SockPath, getuid (), getgid ()); X DO DEBUG("SockPath directory made\n"); X } X else X Msg (errno, "Cannot get status of %s", SockPath); X } X else X { if ((st.st_mode & S_IFMT) != S_IFDIR) X Msg (0, "%s is not a directory.", SockPath); X if ((st.st_mode & 0777) != 0700) X { if (chmod(SockPath, 0700) == -1) X Msg(0, "Cannot change directory %s to mode 700.", SockPath); X } X if (st.st_uid != getuid ()) X Msg (0, "You are not the owner of %s.", SockPath); X } X X (void) strcpy(RealTtyName, GetTtyName()); /* real tty name */ X if (stat(RealTtyName, &RealTtyStat) == -1) /* get current mode */ X Msg(errno, "Cannot get status of %s", RealTtyName); X DO DEBUG("Mode of %s is %#o\n", RealTtyName, RealTtyStat.st_mode); X RealTtyMode = RealTtyStat.st_mode; /* save mode for later restore */ X X (void) gethostname (HostName, MAXSTR); X HostName[MAXSTR-1] = '\0'; X DO DEBUG("HostName %s\n", HostName); X X if (ap = index (HostName, '.')) X *ap = '\0'; X if (ap) X DO DEBUG("*ap %s\n", *ap); X X strcat (SockPath, "/"); X SockNamePtr = SockPath + strlen (SockPath); X X /* if we are a client send create message to startup window and exit */ X if (GetSockName ()) X { DO DEBUG("GetSockName says that we are client\n"); X DO DEBUG("SockName '%s'\n", SockName); X s = MakeClientSocket (1); X DO DEBUG("Client socket is %d\n", s); X DO DEBUG("SendCreateMsg()\n"); X if (clienttitle) { X av[1] = clienttitle; /* won't work; tries to run it (of course) */ X SendCreateMsg(s, 2, av, loginflag, &shape); X } else X SendCreateMsg (s, ac, av, loginflag, &shape); X close (s); X DO DEBUG("after SendCreateMsg(), now exit(EXITNORMAL)\n"); X exit (EXITNORMAL); X } X X /* we are the server */ X DO DEBUG("SockName '%s'\n", SockName); X DO DEBUG("We are server\n"); X#ifndef SVR4 X if ((DevTty = open ("/dev/tty", O_RDWR|O_NDELAY)) == -1) X Msg (errno, "/dev/tty"); X DO DEBUG("opened /dev/tty fd %d\n", DevTty); X#endif X X ServerSocket = MakeServerSocket (); X DO DEBUG("ServerSocket %d\n", ServerSocket); X s = ServerSocket; X X if (fflag) X flowctl = 1; X else X if (nflag) X flowctl = 0; X X if (loginflag == -1) X loginflag = LOGINDEFAULT; X X MakeNewEnv (); X X Resetenvonmsg = 1; /* cleanup Utmp and tty if abort */ X X GetTTY (0, &OldMode); X SetMode (&OldMode, &NewMode); X SetTTY (0, &NewMode); X X InitUtmp (); X X /* X * On some systems, have noticed SIGHUP sent to server whenever a client X * terminates, thus terminating the *server* prematurely. X * X * Fix this by ignoring SIGHUP on such systems ... (may no longer be needed?) X */ X#ifdef IGNORE_SIGHUP X signal (SIGHUP, SIG_IGN); /* ignore SIGUP */ X#else X signal (SIGHUP, SigHup); X#endif X X signal (SIGINT, SIG_IGN); /* we should never see this */ X signal (SIGQUIT, FAbort); /* quit layers on these 2 signals */ X signal (SIGTERM, FAbort); X signal (SIGTTIN, SIG_IGN); X signal (SIGTTOU, SIG_IGN); X#ifdef IRIX X signal (SIGALRM, ignore_alarm); /* ignore alarm under IRIX */ X#else X signal (SIGALRM, SIG_IGN); /* alarm clock used by protocol.c */ X#endif X X if (Initlink() == 0) { X exitcode = EXITNOMACLAYERS; /* return special status code */ X Msg (0, "\n\n You are not running under MacLayers."); X DO DEBUG("Initlink() unsuccesful."); X } else X DO DEBUG("Initlink() successful."); X X /* X * startup at least one default shell window: X */ X n = MakeWindow (0, *av, av, (char *)0, loginflag, &shape); X if (n < 0) { X SetTTY(0, &OldMode); X FQuit(EXITABNORMAL); X /* NOT REACHED */ X } X DO DEBUG("MakeWindow() == %d", n); X X (void) chmod(RealTtyName, 0600); /* lock out broadcasts */ X Abortonmsg = 0; /* don't abort on msg from now on */ X Resetenvonmsg = 0; /* no cleanup - messages normal */ X#ifdef SVR4 X { X struct sigaction sa; X X sa.sa_handler = SigChld; X (void) sigemptyset(&sa.sa_mask); X sa.sa_flags = SA_NOCLDWAIT | SA_SIGINFO; X (void) sigaction(SIGCHLD, &sa, NULL); X } X#else X#ifdef SYSV X signal(SIGCLD, SigChld); X#else X signal (SIGCHLD, SigChld); X#endif X#endif X tv.tv_usec = 0; X tv.tv_sec = 0; /* default no timer wanted */ X X /* X * now, check for existence of .layersrc file; X * if it exists, use it: X */ X sprintf (rc, "%.*s/.layersrc", sizeof(rc)-12, home); X n = 1 + ReadRc(rc); X X X /* client/Maclayers processing loop */ X X /* poll .20 secs for new startups */ X#define WUSSTARTUP 200000 X /* stall nonpriority windows .5 seconds when top window I/O active */ X#define WUSSTALL 500000 X X stall = 0; /* startout no stalled channels */ X fderr = 0; /* startout no error fd's */ X X while (1) X { int priochan; /* the top window channel */ X X priochan = TopChannel(); /* find highest priority channel */ X X /* check for I/O on all available I/O descriptors */ X r = 1<<0; /* always read MacLayers stream */ X r |= 1<allocated) /* if layer exists ... */ X { /* if not yet started or has just terminated ... */ X if (layer->ptymask & fderr) X tv.tv_usec = WUSSTARTUP; /* don't spinloop but wait-a-bit */ X else X { if (layer->kbuff && layer->kbuff->size) X /* keyboard input for layer */ X w |= layer->ptymask; /* try write to it */ X /* read layer output unless we're being nice to top window */ X if (!stall) X r |= layer->ptymask; /* read output from layer */ X else X if (layer->chan == priochan) X r |= layer->ptymask; /* read top priority output */ X else X stall++; /* indicate something to stall */ X } X } X X if (stall > 1) X if (!tv.tv_usec) X tv.tv_usec = WUSSTALL; /* set stall timout */ X X /* process signals before trying select */ X if (GotSignal) X { SigHandler (); X continue; X } X X DO DEBUG("Select(r %x, w %x, fderr %x, stall %d, prio %d, us %d)\n", X r, w, fderr, stall, priochan, tv.tv_usec); X X switch ( select(32, (fd_set *) &r, (fd_set *) &w, (fd_set *) NULL, X tv.tv_usec ? &tv : (struct timeval *) NULL) ) X { case -1: X /* errno has report */ X if (errno == EINTR) /* signal delivered or timout */ X { errno = 0; X tv.tv_usec = 0; /* clear timer wait value */ X fderr = 0; /* turn off error stall */ X stall = 0; /* turn off output priority stall */ X DO DEBUG("select errno EINTR\n"); X continue; /* re-loop */ X } X Abortonmsg = 1; X Resetenvonmsg = 1; /* clean up tty settings */ X DO DEBUG("select errno %d\n", errno); X Msg (errno, "select"); X /*NOTREACHED*/ X X case 0: X /* timeout reached */ X tv.tv_usec = 0; /* clear timer wait value */ X stall = 0; /* turn off stall */ X fderr = 0; /* turn off error stall */ X continue; /* re-loop */ X X default: X /* a channel has read/write status pending */ X break; X } X X DO DEBUG("after select r %x w %x\n", r, w); X X /* handle any signal arriving up during select wait */ X if (GotSignal) X { SigHandler (); X continue; X } X X /* if server socket has command process that now */ X if (r & 1 << s) X { ReceiveMsg(s); /* process client control packet */ X continue; /* status may have changed */ X } X X /* next process input stream from MacLayers */ X if (r & 1 << 0) X { ProcessStreamin(); /* key input and control packets */ X continue; /* status may have changed */ X } X X /* process keyboard input first so output doesn't hold up X ** keyboard echo and break/interrupt processing X */ X priochan = TopChannel(); /* find top priority channel */ X stall = 0; /* assume no stall needed */ X for (n=0; nallocated) X if (w & layer->ptymask) X while ((kbptr=layer->kbuff)->size) X { /* pass as much keyboard as possible */ X if (layer->chan == priochan) X stall = 1; /* stall lower priority channels */ X len = write(layer->ptyfd, &kbptr->text[kbptr->offset], X kbptr->size); X DO DEBUG("keyin len %d to chan %d\n", len, layer->chan); X if (len <= 0) /* if no data accepted ... */ X { if (errno == EIO) /* if I/O error indicated ... */ X fderr |= layer->ptymask; /* wait-a-bit on this */ X errno = 0; /* clear errno */ X break; /* try again later */ X } X /* some of buffer accepted */ X kbptr->size -= len; /* length processed */ X kbptr->offset += len; /* bump up offset */ X if (kbptr->size > 0) /* not all buffer accepted ... */ X break; /* try feed again later */ X /* see if another buffer chained */ X if (kbptr->next) X { /* yes, free up current buffer and queue next */ X layer->kbuff = kbptr->next; /* to next buffer */ X free(kbptr); /* free this buffer up */ X } X else X { /* otherwise leave this for next input */ X kbptr->size = 0; /* empty buffer */ X kbptr->offset = 0; /* refill from the start */ X } X } X X /* first process the highest priority channel (top window) */ X if (priochan > 0 && priochan <= MAXPCHAN) /* if valid ... */ X if ((layer = &World[priochan-1])->allocated) X if (r & layer->ptymask) X { /* output to send to top MacLayers window */ X len = read(layer->ptyfd, buf, IOSIZE); X if (len >= 0) /* if no error ... */ X { DO DEBUG("read output len %d chan %d\n", len, layer->chan); X } X else X { /* We expect EIO error if socket not yet open on other end X ** or if process using socket has terminated. We expect X ** EWOULDBLOCK also after process terminates. X **/ X DO DEBUG("read output err chan %d errno %d len %d\n", X layer->chan, errno, len); X if (errno == EIO || errno == EWOULDBLOCK) X DO DEBUG(" ...anticipated\n"); X /* layer not ready or just terminated so wait-a-bit */ X fderr |= layer->ptymask; X r &= ~layer->ptymask; /* don't read it again below */ X errno = 0; /* clear errno */ X } X if (len > 0) X SendData(layer->chan, buf, len); X X if (len >= 0) X /* To keep lower priority channels from hogging the line X ** we delay any output from them until the primary window X ** has no more data to be sent to it. X */ X stall = 1; /* stall output from others */ X } X X /* now pass all available output to MacLayers */ X if (!stall) X for (n=0; nallocated) X if (r & layer->ptymask) X { /* output to send to MacLayers window */ X len = read(layer->ptyfd, buf, IOSIZE); X if (len >= 0) /* if no error ... */ X { DO DEBUG("output chan %d len %d\n", layer->chan, len); X } X else X { /* We expect EIO error if socket not yet open on other end X ** or if process using socket has terminated. We expect X ** EWOULDBLOCK also after process terminates. X **/ X DO DEBUG("read output err chan %d errno %d len %d\n", X layer->chan, errno, len); X if (errno == EIO || errno == EWOULDBLOCK) X { DO DEBUG(" ...anticipated\n"); X } X /* layer not ready or just terminated so wait-a-bit */ X fderr |= layer->ptymask; X errno = 0; /* clear errno */ X } X if (len > 0) X SendData(layer->chan, buf, len); X } X X /* handle signals again */ X if (GotSignal) X SigHandler (); X X } /* end while (1) */ X X /* NOT REACHED */ X X} /* main() */ X X /* ReceiveQuit() - MacLayers sends Quit packet */ X Xvoid XReceiveQuit() X{ X /* We completely quit layers cancelling all active processes */ X DO DEBUG("ReceiveQuit()\n"); X FQuit(EXITNORMAL); /* normal termination */ X /* NOT REACHED */ X X} /* ReceiveQuit() */ X X X /* ReceiveNew() - MacLayers requests a new shell layer */ X Xvoid XReceiveNew(chanid, shape) Xint chanid; /* channel for new shell layer */ Xstruct Shape *shape; /* shape for new channel */ X{ X static int MakeWindow(); X X DO DEBUG("ReceiveNew(%d)\n", chanid); X (void) MakeWindow (chanid, *ShellArgs, ShellArgs, X (char *) 0, loginflag, shape); X X} /* ReceiveNew() */ X X X /* ReceiveDelete() - MacLayers has removed a layer */ Xvoid XReceiveDelete(chanid) Xint chanid; /* channel which was deleted */ X{ X static void KillWindow(); X struct Layer *layer; /* layer pointer */ X X /* validate channel */ X DO DEBUG("ReceiveDelete(%d)\n", chanid); X if (chanid <= 0 || chanid > MAXPCHAN) X return; /* ignore invalid channel */ X X /* if this layer active then kill it off, else ignore request */ X layer = &World[chanid-1]; /* locate target layer */ X if (layer->allocated) X KillWindow(layer); X X} /* ReceiveDelete() */ X X X /* ReceiveSignal() - send signal to layer's process group */ X Xvoid XReceiveSignal(chanid, signal) Xint chanid; /* layer's channel */ Xint signal; /* signal.h signal ID */ X{ X struct Layer *layer; /* layer pointer */ X X DO DEBUG("ReceiveSignal(%d,%d)\n", chanid, signal); X /* verify channel */ X if (chanid <= 0 || chanid > MAXPCHAN) X return; /* ignore invalid channel */ X X /* if this layer is active send the signal to the process group */ X layer = &World[chanid-1]; /* locate target layer */ X if (layer->allocated && layer->lpid) X KillPG(layer, signal); X X} /* ReceiveSignal() */ X X X /* ReceiveReshape() - windowsize and location updated */ Xvoid XReceiveReshape(chanid, shape) Xint chanid; /* channel having shape */ Xstruct Shape *shape; /* shape structure */ X{ X struct Layer *layer; /* layer pointer */ X X DO DEBUG("ReceiveReshape(%d)\n", chanid); X X /* verify channel */ X if (chanid <= 0 || chanid > MAXPCHAN) X return; /* ignore invalid channel */ X X /* if this layer is active then reshape it's window */ X layer = &World[chanid-1]; /* locate target layer */ X if (layer->allocated && layer->lpid) X { layer->shape = *shape; /* install as our new shape */ X SetWindowSize(layer); /* udpate the O/S window info */ X } X X} /* ReceiveReshape() */ X X X /* SetWindowSize() - tell O/S about new window size */ X Xstatic void XSetWindowSize(layer) Xstruct Layer *layer; /* layer to resize */ X{ X#ifdef TIOCSWINSZ X struct winsize wsize; /* window size structure */ X int retcode; /* ioctl return code */ X X wsize.ws_col = layer->shape.wchars; /* character width */ X wsize.ws_row = layer->shape.wlines; /* window height */ X wsize.ws_xpixel = 0; /* necessary? */ X wsize.ws_ypixel = 0; X /* update O/S window state */ X retcode = ioctl(layer->ptyfd, TIOCSWINSZ, &wsize); X DO DEBUG("SetWindowSize(chan %d) col %d, row %d iotcl() = %d\n", X layer->chan, layer->shape.wchars, layer->shape.wlines, X retcode); X X retcode = ioctl(layer->ptyfd, TIOCGWINSZ, &wsize); X DO DEBUG("TIOCGWINSZ: col %d, row %d iotcl() = %d\n", X wsize.ws_col, wsize.ws_row, retcode); X X#ifdef SIGWCHG X /* inform process group that control terminal has altered size */ X KillPG(layer, SIGWCHG); X#endif X X#endif X} /* SetWindowSize() */ X X X /* ReceiveData() - received keyboard input for layer */ Xvoid XReceiveData(chanid, buff, cnt) Xint chanid; /* channel receiving input */ Xchar *buff; /* buffer containing data */ Xint cnt; /* count of data bytes */ X{ X struct Layer *layer; /* layer pointer */ X struct Kbuff *kb; /* keybuff pointer */ X X DO DEBUG("ReceiveData(%d, '%.*s')\n", chanid, cnt, buff); X /* verify channel */ X if (chanid <= 0 || chanid > MAXPCHAN) X return; /* ignore invalid channel */ X layer = &World[chanid-1]; /* locate target layer */ X X /* add character stream to layer's input buffers for main loop processing */ X for (kb=layer->kbuff; kb->next; kb=kb->next); /* find oldest buffer */ X while (cnt--) X { X /* if current buffer full then chain in a new one */ X if (kb->offset+kb->size >= IOSIZE) X { kb->next = (struct Kbuff *) malloc(sizeof(struct Kbuff)); X kb = kb->next; /* base new keybuff */ X kb->next = NULL; /* no next yet */ X kb->size = 0; /* this character is first */ X kb->offset = 0; /* at zero offset */ X } X X /* add new character to the end of this buffer */ X kb->text[kb->offset+kb->size++] = *buff++; /* insert at end of data */ X } X X} /* ReceiveData() */ X X X X /* InitWorld() - initialize layer structures */ X Xstatic void XInitWorld() X{ X struct Layer *layer; /* layer pointer */ X struct Kbuff *kb; /* keybuff pointer [UNUSED] */ X int i; /* work variable */ X X for (i=0; ichan = i+1; /* channel ID */ X layer->allocated = 0; /* does not exist yet */ X layer->lpid = 0; /* head process */ X layer->ptyfd = 0; /* no pseduo pty yet */ X layer->ptymask = 0; /* no pty mask yet */ X layer->slot = 0; /* no Utmp slot */ X ClearShape(&layer->shape); /* clear shape structure */ X X /* allocate the primary input keybuffer for this layer */ X layer->kbuff = (struct Kbuff *) malloc(sizeof(struct Kbuff)); X layer->kbuff->next = NULL; /* no next buffer */ X layer->kbuff->size = 0; /* no data in buffer */ X layer->kbuff->offset = 0; /* start filling at front */ X X } /* end for layer scan */ X X} /* InitWorld() */ X X X /* clearshape() - initialize shape structure */ X Xstatic void XClearShape(shape) Xstruct Shape *shape; /* shape structure pointer */ X{ X shape->worigv = 0; /* default window position */ X shape->worigh = 0; X shape->wlines = 0; /* default size */ X shape->wchars = 0; X shape->wfont = 0; /* default font size */ X shape->wattr = 0; /* no attributes */ X X} /* clearshape() */ X X X /* SigHandler() - process signals */ X Xvoid XSigHandler () X{ X static void DoWait(); X X DO DEBUG("GotSignal()\n"); X while (GotSignal) X { GotSignal = 0; X DoWait (); /* handle dead or stopped children processes */ X#ifdef SYSV X signal(SIGCLD, SigChld); X#endif X } X} X X#ifdef SVR4 Xstatic void XSigChld(int sn, siginfo_t * si, void * uc) X{ X int i; X struct Layer *layer; X X if (si == NULL) { X DO DEBUG("SigChld: OOPS! no siginfo\n"); X return; X } X DO DEBUG("code %d errno %d pid %d\n", X si->si_code, si->si_errno, si->si_pid); X X if (si->si_code == CLD_STOPPED) { X (void) sigsend(P_PID, si->si_pid, SIGCONT); X return; X } X for (i = 0; i < MAXPCHAN; i++) { X if ((layer = &World[i])->lpid == si->si_pid) { X DO DEBUG("dead session reaped\n"); X layer->lpid = (-layer->lpid); /* Mark as dead */ X GotSignal = 1; X } X } X} X X#else Xstatic SIGTYPE XSigChld () X{ X DO DEBUG("SigChld()\n"); X /* flag child process is stopped or dead */ X GotSignal = 1; X} X#endif X Xstatic SIGTYPE XSigHup () X{ X DO DEBUG("SigHup()\n"); X /* Detach (0); */ X FQuit(EXITSIGHUP); /* stop all processes */ X /* NOT REACHED */ X} X X /* DoWait() - send SIGCONT to stopped windows, Free dead process windows */ X X#ifdef SVR4 Xstatic void XDoWait() X{ X static void KillWindow(); X X int i; X register struct Layer *layer; X X DO DEBUG("DoWait()\n"); X for (i = 0; i < MAXPCHAN; i++) { X if ((layer = &World[i])->lpid < 0) { X layer->lpid = (-layer->lpid); X DO DEBUG("kill dead process window %d\n", layer->chan); X KillWindow(layer); X SendDelete(layer->chan); /* tell MacLayers layer is dead */ X } X } X} /* DoWait() */ X#else Xstatic void XDoWait() X{ X static void KillWindow(); X X register pid; X register struct Layer *layer; X union wait wstat; X int i; X X DO DEBUG("DoWait()\n"); X while ((pid = wait3 (&wstat, WNOHANG|WUNTRACED, NULL)) > 0) X /* dead or stopped child process found */ X for (i=0; ilpid == pid) X { if (WIFSTOPPED (wstat)) X { /* stopped process so restart it */ X /*** DO WE REALLY NEED TO DO THIS? ***/ X DO DEBUG("killpg(, SIGCONT)\n"); X KillPG(layer, SIGCONT); X } X else X { /* remove dead process's layer */ X DO DEBUG("kill dead process window %d\n", layer->chan); X KillWindow (layer); X /* tell MacLayers layer is dead */ X SendDelete(layer->chan); X } X } X X} /* DoWait() */ X#endif X X X /* KillPG() - send signal to layer's process group */ X Xstatic void XKillPG(layer, signal) Xstruct Layer *layer; /* layer to signal */ Xint signal; /* signal to send */ X{ X int retcode; /* work variable */ X int pgrp; /* process group for layer */ X int tgrp; /* terminal control process group */ X X DO DEBUG("KillPG(%d, sig %d)\n", layer->chan, signal); X X if (layer->lpid) { X#ifdef SVR4 X pgrp = getpgid (layer->lpid); /* get process group */ X DO DEBUG("getpgid() = %d\n", pgrp); X if (pgrp != -1) { X retcode = sigsend(P_PGID, pgrp, signal); /* signal it */ X DO DEBUG("sigsend() = %d\n", retcode); X } X#else X#if defined(AUX) || defined(AIX) X /* X * getpgrp does not get anyone else's pgrp on A/UX. You could X * find this by mucking in the kernel, but I'm not willing to X * go that far yet. X */ X pgrp = layer->lpid; X#else X pgrp = getpgrp(layer->lpid); /* get process group */ X DO DEBUG("getpgrp() = %d\n", pgrp); X if (pgrp != -1) X { retcode = killpg(pgrp, signal); /* signal it */ X DO DEBUG("killpg() = %d\n", retcode); X } X X /* X ** In order to accomplish job control, csh and derived shells X ** create a new terminal control group whenever they run a command. X ** Thus the above code failed to forward SIGINT to such commands. X ** (Csh would get it but just ignore it.) Thus the following code. X */ X X /* forward SIGINT to the terminal control group also */ X /* (This should probably be done for ALL Signals, but at present is not) */ X if (signal == SIGINT) X { retcode = ioctl(layer->ptyfd, TIOCGPGRP, &tgrp); X DO DEBUG("ioctl(ptyfd,TIOCGPGRP) termcntlgrp %d, retcode = %d\n", X tgrp, retcode); X /* but only if not the same process group */ X if (retcode != -1 && tgrp != pgrp) X { retcode = killpg(tgrp, signal); /* signal it */ X DO DEBUG("killpg(%d) = %d\n", tgrp, retcode); X } X } X#endif X#endif X } X X} /* KillPG() */ X X X /* KillWindow() - remove a layer from the system */ X X/* Note: This function does NOT tell MacLayers about the dead layer */ X Xstatic void XKillWindow (layer) Xstruct Layer *layer; X{ X struct Kbuff *kb; /* work buffer free pointer */ X X if (layer->allocated) X { /* SHOULD THIS BE SIGKILL or SIGHUP ??? */ X if (layer->lpid) /* if layer process started ... */ X { KillPG(layer, SIGHUP); /* kill processes */ X layer->lpid = 0; /* clear pid field */ X } X RemoveTtyFromUtmp(layer); X (void) chmod(layer->tty, 0666); X (void) chown(layer->tty, 0, 0); X close(layer->ptyfd); X DO DEBUG("chmod/chown %s, SendDelete(%d)\n",layer->tty, layer->chan); X X ClearShape(&layer->shape); /* reset the shape structure */ X /* free all keybuffers but the last one and reprime it */ X for (kb=layer->kbuff; kb->next; kb=layer->kbuff) { X layer->kbuff = kb->next; X free(kb); /* free input buffers */ X } X kb->size = 0; /* empty buffer */ X kb->offset = 0; /* start refill from front */ X layer->allocated = 0; /* window no longer allocated */ X } X X} /* KillWindow() */ X X X /* FAbort() - signal catcher for quitting */ Xstatic SIGTYPE XFAbort() X{ X DO DEBUG("FAbort()\n"); X FQuit (EXITSIGQUIT); /* quit with error exit */ X X} /* FAbort() */ X X X /* FQuit() - terminate layers */ Xvoid XFQuit(exitcode) Xint exitcode; X{ X int i; X X#ifndef POSIXTTY X static void SetTTY(); X#endif X X X DO DEBUG("FQuit(%d)\n",exitcode); X for (i=0; iworigv, shape->worigh, shape->wlines, shape->wchars); X DO DEBUG("font %d, attr 0x%x\n", shape->wfont, shape->wattr); X X if ((f = OpenPTY ()) == -1) X { Msg (0, "No more PTYs."); X return ( -1 ); X } X X /* X * If channel not given, X * obtain one from MacLayers: X */ X if (chan == 0) X { chan = SendNew(shape); /* try to get free window */ X if (chan == 0) X { Msg (0, "No more windows."); X return ( -1 ); X } X DO DEBUG("SendNew() == %d\n", chan); X } X X /* verify channel */ X if (chan <= 0 || chan > MAXPCHAN) X { Msg(0, "Invalid channel %d.", chan); X return ( -1 ); X } X X /* login this window if it's layer #1 */ X if (chan == 1) X lflag = 1; X X if (lflag == -1) X lflag = loginflag; X X#ifdef USRLIMIT X /* X * Count current number of users, and if logging windows in, X */ X if (lflag == 1) X { (void) lseek (utmpf, 0, 0); X UserCount = 0; X while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0) X { if (utmpbuf.ut_name[0] != '\0') X UserCount++; X } X if (UserCount >= USRLIMIT) X { /* MUST NOT ISSUE MESSAGE SINCE IT GETS INTERSPERSED WITH X ** PACKET SENT INDICATING CURRENT INPUT WINDOW!! THIS X ** CAUSES IT TO BE CORRUPTED. (1.00 Bug Fix 001) X */ X /* Msg (0, "User limit reached. Window will not be logged in."); */ X lflag = 0; X } X } X#endif USRLIMIT X X layer = &World[chan-1]; /* find layer structure */ X layer->shape = *shape; /* install new window shape */ X X /* ??? What do we do if layer is still active as far as we're concerned? */ X if (layer->allocated) X { DO DEBUG("??? newlayer not free !!!\n"); X KillWindow(layer); /* kill off old layer */ X SendDelete(layer->chan); /* kill window back off */ X Msg (0, "Makewindow error: Duplicate active layer %d.", chan); X return ( -1 ); /* return failed */ X } X X layer->allocated = 1; /* show layer now in use */ X BuildTitle(chan, prog, args); /* install window title */ X X#ifdef SYSV X (void) fcntl(f, F_SETFL, O_NDELAY); X#else X (void) fcntl(f, F_SETFL, FNDELAY); X#endif X layer->ptyfd = f; /* pseudo pty for task's I/O */ X layer->ptymask = 1<cmd, Filename (args[0]), MAXSTR-1); X layer->cmd[MAXSTR-1] = '\0'; X strncpy (layer->tty, TtyName, MAXSTR-1); X DO DEBUG("forking %s, tty %s, ptyfd %d, mask %x\n", X layer->cmd, layer->tty, layer->ptyfd, layer->ptymask); X (void) chown (TtyName, getuid (), getgid ()); X if (lflag == 1) { X layer->slot = SetUtmp(TtyName, chan == 1, World[0].lpid); X if (chan == 1 && RealTtyMode) X /* set to original tty umask */ X (void) chmod(TtyName, RealTtyMode); X else X /* force to this mode */ X (void) chmod(TtyName, TtyMode); X } X else X { layer->slot = -1; X /* do not allow any other user access to this device */ X (void) chmod (TtyName, 0600); X } X switch (layer->lpid = fork ()) X { case -1: X Msg (errno, "fork"); X layer->lpid = 0; /* clear pid field */ X return ( -1 ); /* return failed */ X X case 0: X signal (SIGHUP, SIG_DFL); X signal (SIGINT, SIG_DFL); X signal (SIGQUIT, SIG_DFL); X signal (SIGTERM, SIG_DFL); X signal (SIGTTIN, SIG_DFL); X signal (SIGTTOU, SIG_DFL); X signal (SIGALRM, SIG_DFL); X setuid (getuid ()); X setgid (getgid ()); X if (dir && chdir (dir) == -1) X { SendErrorMsg ("Cannot chdir to %s: %s", dir, sys_errlist[errno]); X exit (EXITABNORMAL); X } X#if defined(SVR4) || defined(AUX) || defined(AIX) X mypid = setsid(); X#else X mypid = getpid (); X (void) setpgrp (0, mypid); X ioctl (DevTty, TIOCNOTTY, (char *)0); X#endif X if ((tf = open (TtyName, O_RDWR)) == -1) X { SendErrorMsg ("Cannot open %s: %s", TtyName, sys_errlist[errno]); X exit (EXITABNORMAL); X } X#ifdef SVR4 X (void) ioctl(tf, I_PUSH, "ptem"); X (void) ioctl(tf, I_PUSH, "ldterm"); X if(mypid > 0 && tcsetpgrp(tf, mypid) < 0) { X DO DEBUG("tcsetpgrp(): %s\n", strerror(errno)); X } X#endif X DO DEBUG("Now in new process\n"); X fflush(stdout); X fflush(stderr); X (void) dup2 (tf, 0); X (void) dup2 (tf, 1); X (void) dup2 (tf, 2); X for (f = getdtablesize () - 1; f > 2; f--) X close (f); X ioctl (0, TIOCSPGRP, &mypid); X SetTTY (0, &OldMode); X X { struct winsize wsize; /* window size structure */ X int retcode; /* ioctl return code */ X X wsize.ws_col = layer->shape.wchars; /* character width */ X wsize.ws_row = layer->shape.wlines; /* window height */ X wsize.ws_xpixel = 0; /* necessary? */ X wsize.ws_ypixel = 0; X /* update O/S window state */ X retcode = ioctl(0, TIOCSWINSZ, &wsize); X } X (void) umask(Oumask); /* restore user's original umask */ X NewEnv[2] = MakeTermcap(layer->shape.wlines, layer->shape.wchars); X sprintf (ebuf, "LAYER=%d", chan); X NewEnv[3] = ebuf; X execvpe (prog, args, NewEnv); X printf("%s: cannot exec %s: %s", myname, prog, sys_errlist[errno]); X exit (EXITABNORMAL); X } X X DO DEBUG("MakeWindow() returning channel %d\n", chan); X return ( chan ); X X} /* MakeWindow() */ X Xstatic void Xexecvpe (prog, args, env) Xchar *prog, **args, **env; X{ X register char *path, *p; X char buf[1024]; X char *shargs[MAXARGS+1]; X register i; X register eaccess = 0; X X if (prog[0] == '/') X path = ""; X else X if ((path = getenv ("PATH")) == 0) X path = DefaultPath; X do X { p = buf; X while (*path && *path != ':') X *p++ = *path++; X if (p > buf) X *p++ = '/'; X strcpy (p, prog); X if (*path) X ++path; X execve (buf, args, env); X switch (errno) X { case ENOEXEC: X shargs[0] = DefaultShell; X shargs[1] = buf; X for (i = 1; shargs[i+1] = args[i]; ++i); X execve (DefaultShell, shargs, env); X return; X X case EACCES: X eaccess = 1; X break; X X case ENOMEM: case E2BIG: case ETXTBSY: X return; X X } /* end switch */ X X } while (*path); X X if (eaccess) X errno = EACCES; X X} /* execvpe() */ X X X /* BuildTitle() - create and install window title */ X Xstatic void XBuildTitle(chan, prog, args) Xint chan; /* channel for title */ Xchar *prog; /* program being executed */ Xchar **args; /* arg list */ X{ X int i; /* arg scan index */ X char buff[1024]; /* super huge title buffer */ X X /* skip any leading "/bin/" */ X if (strncmp(prog, "/bin/", 5) == 0) X strcpy(buff, prog+5); /* leave /bin off */ X else if (strncmp(prog, "/usr/bin/", 9) == 0) X strcpy(buff, prog+9); /* leave /usr/bin off */ X else X strcpy(buff, prog); /* start with program name */ X X /* add all aguments but stop if option ("-") seen */ X for (i=1; args[i] && args[i][0] != '-'; i++) X { strcat(buff, " "); /* delimiter */ X strcat(buff, args[i]); /* add next parameter */ X } X X SendTitle(chan, buff, strlen(buff)); /* set new window title */ X X} /* BuildTitle() */ X X X#ifdef sequent Xstatic int XOpenPTY () X{ X char *m, *s; X register f; X X f = getpseudotty (&s, &m); X strncpy (PtyName, m, sizeof (PtyName)); X strncpy (TtyName, s, sizeof (TtyName)); X ioctl (f, TIOCFLUSH, (char *)0); X return (f); X} X X#else X#ifdef IRIX Xstatic XOpenPTY () X{ X int f; X char *tn; X X if ((tn = _getpty(&f, O_RDWR, TtyMode, 0)) != 0) { X strncpy(TtyName, tn, sizeof (TtyName)); X return f; X } else X return -1; X} X#else X#ifdef SVR4 Xstatic int XOpenPTY() X{ X extern char *ptsname(); X int fdm; X X if ((fdm = open("/dev/ptmx", O_RDWR)) < 0) X return (-1); X grantpt(fdm); X unlockpt(fdm); X (void) strcpy(TtyName, ptsname(fdm)); X return fdm; X} X#else Xstatic XOpenPTY () X{ X register char *p, *l, *d; X register i, f, tf; X X strcpy (PtyName, PtyProto); X strcpy (TtyName, TtyProto); X for (p = PtyName, i = 0; *p != 'X'; ++p, ++i); X#ifndef SEQUENT X for (l = "pqrstuvwxyzPQRST"; *p = *l; ++l) X { for (d = "0123456789abcdef"; p[1] = *d; ++d) X#else X for (l = "pqrstuvwPQRSTUVW"; *p = *l; ++l) X { for (d = "0123456789abcdef"; p[1] = *d; ++d) X#endif X { if ((f = open (PtyName, O_RDWR)) != -1) X { TtyName[i] = p[0]; X TtyName[i+1] = p[1]; X#ifndef AUX X if ((tf = open (TtyName, O_RDWR)) != -1) X { close (tf); X return f; X } X#else X /* X * On A/UX, opening and closing the slave pty will result X * in the master getting nothing but EIO. Thus, we delay X * opening the slave pty until we're really ready for it. X */ X return f; X#endif X close (f); X } X } X } X X return -1; X X} /* OpenPTY() */ X X#endif /* NOT SVR4 */ X#endif /* NOT IRIX */ X#endif /* NOT sequent */ X X#ifdef POSIXTTY X Xstatic XSetMode(op, np) Xstruct termios *op, *np; X{ X *np = *op; X if (flowctl) X np->c_iflag = BRKINT|IGNPAR|IXON|IXOFF; X else X np->c_iflag = BRKINT|IGNPAR; X np->c_oflag = 0; /* No special output processing */ X /* leave cflag alone, it has the baud rate etc. */ X np->c_lflag = 0; /* should put terminal in raw mode ... */ X np->c_cc[VMIN] = 1; X np->c_cc[VTIME] = 0; X} X X#else X X#ifdef USE_TERMIO Xstatic void XSetTTY (fd, mp) Xstruct termio *mp; X{ X ioctl (fd, TCSETAF, mp); X X} /* SetTTY() */ X Xstatic void XGetTTY (fd, mp) Xstruct termio *mp; X{ X ioctl (fd, TCGETA, mp); X X} /* GetTTY() */ X Xstatic XSetMode (op, np) Xstruct termio *op, *np; X{ X *np = *op; X np->c_iflag = 0; /* no input processing */ X np->c_oflag &= ~OPOST; /* no output processing */ X np->c_lflag = NOFLSH; /* don't flush I/O on quit/swtch/intrpt */ X np->c_cc[VMIN] = 1; /* read ends of this many chars */ X np->c_cc[VTIME] = 0; /* or this many .1 seconds after char recieved */ X X} /* SetMode() */ X X#else X Xstatic void XSetTTY (fd, mp) Xint fd; Xstruct mode *mp; X{ X ioctl (fd, TIOCSETP, &mp->m_ttyb); X ioctl (fd, TIOCSETC, &mp->m_tchars); X ioctl (fd, TIOCSLTC, &mp->m_ltchars); X ioctl (fd, TIOCLSET, &mp->m_lmode); X ioctl (fd, TIOCSETD, &mp->m_ldisc); X X} /* SetTTY() */ X Xstatic void XGetTTY (fd, mp) Xint fd; Xstruct mode *mp; X{ X ioctl (fd, TIOCGETP, &mp->m_ttyb); X ioctl (fd, TIOCGETC, &mp->m_tchars); X ioctl (fd, TIOCGLTC, &mp->m_ltchars); X ioctl (fd, TIOCLGET, &mp->m_lmode); X ioctl (fd, TIOCGETD, &mp->m_ldisc); X X} /* GetTTY() */ X X Xstatic XSetMode (op, np) Xstruct mode *op, *np; X{ X *np = *op; X#if 1 X if (flowctl) X { np->m_ttyb.sg_flags &= ~(CRMOD|ECHO); X np->m_ttyb.sg_flags |= CBREAK | ANYP; X } X else X np->m_ttyb.sg_flags = RAW | ANYP; X#else X np->m_ttyb.sg_flags &= ~(CRMOD|ECHO); X np->m_ttyb.sg_flags |= CBREAK | ANYP; X#endif X np->m_tchars.t_intrc = -1; X np->m_tchars.t_quitc = -1; X if (!flowctl) X { np->m_tchars.t_startc = -1; X np->m_tchars.t_stopc = -1; X } X np->m_ltchars.t_suspc = -1; X np->m_ltchars.t_dsuspc = -1; X np->m_ltchars.t_flushc = -1; X np->m_ltchars.t_lnextc = -1; X X} /* SetMode() */ X X#endif /* USE_TERMIO */ X#endif X Xstatic char * XGetTtyName () X{ X void Msg(); X int n; X char *p; X X for (p = 0, n = 0; n <= 2 && !(p = ttyname (n)); n++); X X if (!p || *p == '\0') X Msg (0, "layers must run on a tty."); X X return ( p ); X X} /* GetTtyName() */ X X Xstatic void XKill (pid, sig) /* [UNUSED] */ X{ X if (pid != 0) X (void) kill (pid, sig); X} X X /* GetSockName() - set SockName; if LTY env return 1 else 0 */ Xstatic int XGetSockName () X{ X register int client; X static char buf[2*MAXSTR]; X X if (!mflag && (SockName = getenv ("LTY")) != 0 && *SockName != '\0') X { client = 1; X setuid (getuid ()); X setgid (getgid ()); X } X else X { sprintf (buf, "%s.%s", HostName, Filename (RealTtyName)); X SockName = buf; X client = 0; X } X return client; X X} /* GetSockName() */ X Xstatic int XMakeServerSocket () X{ X void Msg(); X register int s; X struct sockaddr_un a; X char *p; X X if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) X Msg (errno, "socket"); X a.sun_family = AF_UNIX; X strcpy (SockNamePtr, SockName); X strcpy (a.sun_path, SockPath); X if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) != -1) X { p = Filename (SockPath); X Msg (0, "You already have a layers running on %s.", p); X /*NOTREACHED*/ X } X DO DEBUG("MakeServerSocket: unlink(SockPath)/bind()/chown/listen\n"); X (void) unlink (SockPath); X if (bind (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1) X Msg (errno, "bind"); X (void) chown (SockPath, getuid (), getgid ()); X if (listen (s, 5) == -1) X Msg (errno, "listen"); X return s; X X} /* MakeServerSocket() */ X Xstatic int XMakeClientSocket (err) Xint err; X{ X void Msg(); X register int s; X struct sockaddr_un a; X X if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) == -1) X Msg (errno, "socket"); X a.sun_family = AF_UNIX; X strcpy (SockNamePtr, SockName); X strcpy (a.sun_path, SockPath); X if (connect (s, (struct sockaddr *)&a, strlen (SockPath)+2) == -1) X { if (err) X { Msg (errno, "connect: %s", SockPath); } X else X { close (s); X return -1; X } X } X return s; X X} /* MakeClientSocket() */ X Xstatic void XSendCreateMsg (s, ac, av, lflag, shape) Xint s, ac, lflag; Xchar **av; Xstruct Shape *shape; X{ X void Msg(); X struct msg m; X register char *p; X register len, n; X char *pwd; /* PWD environment string */ X X DO DEBUG("SendCreateMsg(%d, ac %d, lflag %d\n", s, ac, lflag); X m.type = MSG_CREATE; X p = m.m.create.line; X for (n = 0; ac > 0 && n < MAXARGS-1; ++av, --ac, ++n) X { len = strlen (*av) + 1; X if (p + len >= m.m.create.line+MAXLINE) X break; X strcpy (p, *av); X p += len; X } X DO DEBUG(" nargs %d, create line = '%s'\n", n, m.m.create.line); X m.m.create.nargs = n; X m.m.create.lflag = lflag; X m.m.create.shape = *shape; /* pass window shape */ X X /* Since Suns can hang up on getwd() [damn their stupid networking] X ** we try to get the current working directory first from the PWD X ** environment variable. X */ X if ((pwd=getenv("PWD")) && strlen(pwd) < 1024) X (void) strcpy(m.m.create.dir, pwd); X else X#ifdef SVR4 X if (getcwd (m.m.create.dir, sizeof(m.m.create.dir)) == NULL) { X DO DEBUG("getcwd() failed!!\n"); X Msg (0, "%s", strerror(errno)); X } X#else X if (getwd (m.m.create.dir) == 0) X { DO DEBUG("getwd() failed!!\n"); X Msg (0, "%s", m.m.create.dir); X } X#endif X DO DEBUG(" create.dir = '%s'\n", m.m.create.dir); X X if (write (s, (char *)&m, sizeof (m)) != sizeof (m)) X { DO DEBUG(" write failed!!\n"); X Msg (errno, "write"); X } X DO DEBUG("SendCreateMsg() done\n"); X X} /* SendCreateMsg() */ X X/*VARARGS1*/ Xstatic void XSendErrorMsg (fmt, p1, p2, p3, p4, p5, p6) Xchar *fmt; X{ X register s; X struct msg m; X X s = MakeClientSocket (1); X m.type = MSG_ERROR; X sprintf (m.m.message, fmt, p1, p2, p3, p4, p5, p6); X (void) write (s, (char *)&m, sizeof (m)); X close (s); X sleep (2); X} X Xstatic void XReceiveMsg (s) Xint s; X{ X void Msg(); X static void ExecCreate(); X X register ns; X struct sockaddr_un a; X int left, len = sizeof (a); X struct msg m; X char *p; X X DO DEBUG ("ReceiveMsg()\n"); X if ((ns = accept (s, (struct sockaddr *)&a, &len)) == -1) X { Msg (errno, "accept"); X return; X } X p = (char *)&m; X left = sizeof (m); X while (left > 0 && (len = read (ns, p, left)) > 0) X { p += len; X left -= len; X } X close (ns); X if (len == -1) X Msg (errno, "read"); X if (left > 0) X return; X switch (m.type) X { case MSG_CREATE: X DO DEBUG("MSG_CREATE:\n"); X ExecCreate (&m); X break; X X case MSG_ERROR: X DO DEBUG("MSG_ERROR:\n"); X Msg (0, "%s", m.m.message); X break; X X default: X Msg (0, "Invalid message (type %d).", m.type); X X } /* end switch */ X X} /* ReceiveMsg() */ X Xstatic void XExecCreate (mp) Xstruct msg *mp; X{ X char *args[MAXARGS]; X register n; X register char **pp = args, *p = mp->m.create.line; X X for (n = mp->m.create.nargs; n > 0; --n) X { *pp++ = p; X p += strlen (p) + 1; X } X *pp = 0; X n = MakeWindow (0, mp->m.create.line, args, mp->m.create.dir, X mp->m.create.lflag, &mp->m.create.shape); X X} /* ExecCreate() */ X X X/* X * manifest constants for processing .layersrc file: X */ X X#define RC_NONE 0 X#define RC_UNKNOWN 1 X#define RC_WINDOW 2 X X/* X * ProcessGeo(): X * X * expects passed string to be of the form X * X * ###x### indicating width and height X * or X * ###x###+###+### indicating width, height, absolute (x,y) position X * X * parses string and sets passed shape accordingly X * X * returns nonzero if string could not be parsed X */ Xstatic Xint ProcessGeo(shape, p) Xstruct Shape *shape; Xchar *p; X{ X char buf[256]; X int i; X X int w, h, x, y; X X /* get width: */ X i = 0; X while (isdigit(*p)) X buf[i++] = *p++; X X if (*p != 'x') X return -1; /* parse error */ X buf[i] = '\0'; X X sscanf(buf, "%d", &w); /* parse width */ X X X /* get height: */ X i = 0; p++; X while (isdigit(*p)) X buf[i++] = *p++; X X if ((*p) && (*p != '+') && (*p != '-')) X return -1; /* parse error */ X buf[i] = '\0'; X X sscanf(buf, "%d", &h); /* parse height */ X X DO DEBUG("ProcessGeo(): %d %d\n", w, h); X X shape->wchars = w; X shape->wlines = h; X if (!(*p)) X return 0; /* width x height parsed without errors */ X X buf[i=0] = *p++; X i++; X while (isdigit(*p)) X buf[i++] = *p++; X X if ((*p != '+') && (*p != '-')) X return -1; /* parse error */ X buf[i] = '\0'; X X sscanf(buf, "%d", &x); /* parse x-position */ X X buf[i=0] = *p++; X i++; X while (isdigit(*p)) X buf[i++] = *p++; X X /* should be end of argument: */ X if (*p) X return -1; /* parse error */ X buf[i] = '\0'; X X sscanf(buf, "%d", &y); /* parse y-position */ X X shape->worigh = x; X shape->worigv = y; X X DO DEBUG("ProcessGeo(): %d %d %d %d\n", w, h, x, y); X X return 0; /* width x height x horiz x vert */ X} X Xstatic Xint InterpretLayerArgs(argc, ap) Xint argc; Xchar *ap[]; X{ X char *progargs[MAXARGS]; X char *prog; X struct Shape shape; /* shape for new window */ X char *title = NULL; X int login = 0; /* login layer */ X int retval = 0, X i=0; X X ClearShape(&shape); /* initialize shape */ X progargs[0] = prog = ShellProg; X progargs[1] = NULL; X X while (++i < argc) { X if ( (!strcmp("-login", ap[i])) || (!strcmp("-l", ap[i])) ) X login = 1; X X else if ( (!strcmp("-geometry", ap[i])) || (!strcmp("-g", ap[i])) ) { X if (i+1 < argc) { X i++; X if (ProcessGeo(&shape, ap[i])) X DO DEBUG("InterpretLayerArgs(): error while parsing -geometry argument\n"); X X } else X DO DEBUG("InterpretLayerArgs(): %s missing argument\n", ap[i]); X X } else if ( (!strcmp("-exec", ap[i])) || (!strcmp("-e", ap[i])) ) { X if (i+1 < argc) { X int j=0; X X i++; X do { X progargs[j++] = ap[i]; X } while (++i < argc); X prog = progargs[0]; X progargs[j] = NULL; X X } else X DO DEBUG("InterpretLayerArgs(): %s missing argument\n", ap[i]); X X } else if ( (!strcmp("-title", ap[i])) || (!strcmp("-t", ap[i])) ) { X if (i+1 < argc) X title = ap[++i]; X else X DO DEBUG("InterpretLayerArgs(): %s missing argument\n", ap[i]); X } X } X X shape.wattr |= Wa_shell; /* indicate a shell window */ X X if ((i=MakeWindow(0, prog, progargs, home, login, &shape)) < 0) { X DO DEBUG("InterpretLayerArgs(): MakeWindow() unsuccessful (%d)\n", i); X } else { X if (title) SendTitle(i, title, strlen(title)); X retval = 1; X } X X return retval; X} X Xstatic Xint ReadRc (fn) Xchar *fn; X{ X static int Parse(); X X FILE *f; X register char *p, **ap; X register argc; X char buf[256]; X char *args[MAXARGS]; X X int rcmode; /* type of entry */ X X int l = 0, /* line within file */ X i; X X int numwin = 0; /* number of successfully */ X X ap = args; X X /* insure file can be accessed: */ X if (access (fn, R_OK) == -1) { X DO DEBUG("ReadRc(): cannot access %s\n", fn); X return 0; X } X X /* open file for reading: */ X if ((f = fopen (fn, "r")) == NULL) { X DO DEBUG("ReadRc(): cannot open %s\n", fn); X return 0; X } X X /* for each line in file: */ X while (fgets (buf, 256, f) != NULL) { X l++; X X /* terminate string with '\0': */ X if (p = index (buf, '\n')) X *p = '\0'; X X argc = Parse (fn, buf, ap); X if (Dflag) for (i=0; i MAXARGS-1) X Msg (0, "%s: too many tokens.", fn); X delim = 0; X if (*p == '"' || *p == '\'') X { delim = *p; *p = '\0'; ++p; } X ++argc; X *ap = p; ++ap; X while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t'))) X ++p; X if (*p == '\0') X { if (delim) X Msg (0, "%s: Missing quote.", fn); X else X return argc; X } X *p++ = '\0'; X } X X} /* Parse() */ X Xstatic char ** XSaveArgs (argc, argv) /* [UNUSED] */ Xregister argc; Xregister char **argv; X{ X void Msg(); X register char **ap, **pp; X X if ((pp = ap = (char **)malloc ((argc+1) * sizeof (char **))) == 0) X Msg (0, "Out of memory."); X while (argc--) X { if ((*pp = malloc (strlen (*argv)+1)) == 0) X Msg (0, "Out of memory."); X strcpy (*pp, *argv); X ++pp; ++argv; X } X *pp = 0; X return ap; X X} /* SaveArgs() */ X Xstatic void XMakeNewEnv () X{ X static int IsSymbol(); X X register char **op, **np = NewEnv; X static char buf[MAXSTR]; X X if ((int) strlen (SockName) > MAXSTR-5) X SockName = "?"; X sprintf (buf, "LTY=%s", SockName); X *np++ = buf; X *np++ = Term; X np += 2; X for (op = environ; *op; ++op) X { if (np == NewEnv + MAXARGS - 1) X break; X if ( !IsSymbol (*op, "TERM") X && !IsSymbol (*op, "TERMCAP") X && !IsSymbol (*op, "LTY") X ) X *np++ = *op; X } X *np = 0; X X} /* MakeNewEnv() */ X Xstatic int XIsSymbol (e, s) Xregister char *e, *s; X{ X register char *p; X register n; X X for (p = e; *p && *p != '='; ++p); X if (*p) X { *p = '\0'; X n = strcmp (e, s); X *p = '='; X return n == 0; X } X X return 0; X X} /* IsSymbol() */ X X/*VARARGS2*/ Xvoid XMsg (err, fmt, p1, p2, p3, p4, p5, p6) Xint err; Xchar *fmt; X{ X char buf[1024]; X register char *p = buf; X X sprintf (p, fmt, p1, p2, p3, p4, p5, p6); X if (err) { X p += strlen (p); X if (err > 0 && err < sys_nerr) X sprintf (p, ": %s", sys_errlist[err]); X else X sprintf (p, ": Error %d", err); X } X X if (!Abortonmsg) { X /* MakeStatus (buf, curr);*/ X printf("%s\r\n", buf); X fflush(stdout); X } else { X printf ("%s\r\n", buf); X fflush(stdout); X X if (Resetenvonmsg) { X SetTTY (0, &OldMode); X if (RealTtyMode) X (void) chmod(RealTtyName, RealTtyMode); /* restore mode */ X RestoreRealUtmp(); X FinitTerm (); X } X exit(exitcode); X } X X} /* Msg() */ X Xstatic char * XFilename (s) Xchar *s; X{ X register char *p; X X p = s + strlen (s) - 1; X while (p >= s && *p != '/') X --p; X return ++p; X X} /* Filename() */ X Xstatic int XIsNum (s, base) /* [UNUSED] */ Xregister char *s; Xregister base; X{ X for (base += '0'; *s; ++s) X if (*s < '0' || *s > base) X return 0; X return 1; X X} /* IsNum() */ X X#ifndef GETTTYENT X Xstatic Xsetttyent () X{ X struct stat s; X register f; X register char *p, *ep; X X if (ttnext) X { ttnext = tt; X return; X } X if ((f = open (ttys, O_RDONLY)) == -1 || fstat (f, &s) == -1) X Msg (errno, ttys); X if ((tt = malloc (s.st_size + 1)) == 0) X Msg (0, "Out of memory."); X if (read (f, tt, s.st_size) != s.st_size) X Msg (errno, ttys); X close (f); X for (p = tt, ep = p + s.st_size; p < ep; ++p) X if (*p == '\n') X *p = '\0'; X *p = '\0'; X ttnext = tt; X X} /* setttyent() */ X Xstatic struct ttyent * Xgetttyent () X{ X static struct ttyent t; X X if (*ttnext == '\0') X return NULL; X t.ty_name = ttnext + 2; X ttnext += strlen (ttnext) + 1; X return &t; X X} /* getttyend() */ X X#endif X X X /* FinitTerm() - reset vt100 terminal */ Xstatic void XFinitTerm () X{ X /* print out termcap 'is' string to reset terminal */ X#if 0 X /* This string sets scroll region 1-24 and puts cursor at bottom line */ X puts("\033[1;24r\033[24;1H", stdout); X#endif X fflush(stdout); X} X Xstatic void XAddCap (s) Xchar *s; X{ X register n; X X if (tcLineLen + (n = strlen (s)) > 55) X { strcat (Termcap, "\\\n\t:"); X tcLineLen = 0; X } X strcat (Termcap, s); X tcLineLen += n; X} X Xstatic char * XMakeTermcap(lines, chars) Xint lines; /* default window lines */ Xint chars; /* default window chars */ X{ X char buf[1024]; X X strcpy(Termcap, TermcapConst1); /* start TERMCAP build */ X strcat(Termcap, UserTerm); /* fill in User's terminal type */ X strcat(Termcap, TermcapConst3); /* finish our own definition */ X X /* add more capabilities depending upon client version */ X if (Protocollevel > 1) X strcat(Termcap, TermcapConst101); X X if (lines <= 0 || lines > 200) X lines = rows; /* force default if none or invalid */ X if (chars <= 0 || chars > 300) X chars = cols; /* force default if none or invalid */ X X sprintf(buf, "li#%d:co#%d:", lines, chars); X AddCap(buf); X X return ( Termcap ); X X} /* MakeTermcap() */ X X X /* DEBUG() - dump output routine */ X Xvoid XDEBUG(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) Xchar *format; Xint arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8; X{ X fprintf(stderr, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); X} X X X#ifdef SVR4 Xstatic struct utmpx RealUtmp; /* Real tty logon utmpx entry */ X#else Xstatic struct utmp RealUtmp; /* Real tty logon utmp entry */ X#endif X X/* X * Utmp functions for SYSV and Sun BSD: X * (Note: Appropriate utmpx functions for SVR4 follow) X * X * InitUtmp() - Zero out main utmp entry for controlling tty X * and save old value. X * SetUtmp() - Add a tty to utmp, "login" a new terminal X * RemoveTtyFromUtmp() - "logout" a terminal X * RestoreRealUtmp() - Restore original utmp entry for controlling tty X */ X X#ifdef SYSVUTMP X Xstatic char UtmpName[] = "/etc/utmp"; X#ifdef AUX Xstatic char WtmpName[] = "/etc/wtmp"; X#endif Xstatic int RealSlot = 0; /* Real tty logon slot */ X Xstatic void ut_tty_cpy(struct utmp *up, char * tty) X{ X strncpy(up->ut_line, Filename(tty), sizeof up->ut_line); X up->ut_line[(sizeof up->ut_line) - 1] = '\0'; X} X Xstatic void XReadUtmp(int slot, struct utmp *entry) X{ X int i; X struct utmp *ret; X X setutent(); X for (i=0; iut_line, entry->ut_name); X X} /* ReadUtmp() */ X Xstatic void XRemoveUtmp(int slot) X{ X struct utmp u; X#ifdef AUX X int wtmpfd; X#endif X X if (slot) { X setutent(); X ReadUtmp(slot, &u); X u.ut_type = DEAD_PROCESS; X pututline(&u); X#ifdef AUX X if ((wtmpfd = open(WtmpName,1)) >= 0) { X lseek (wtmpfd, 0L, 2); X write (wtmpfd, (char *)&u, sizeof(u)); X close (wtmpfd); X } X#endif X } X} X Xstatic int XFindUtmp(char *name) X{ X register char *p; X register struct utmp *u; X register slot = 0; X X if (p = rindex (name, '/')) X ++p; X else X p = name; X X setutent(); X while ((u = getutent()) != NULL && strcmp(p, u->ut_line) != 0) { X ++slot; X } X X if (u == NULL) X return 0; X X return slot; X} X Xstatic void XInitUtmp() X{ X struct utmp *ret; X X RealSlot = FindUtmp(RealTtyName); /* find current logon slot */ X DO DEBUG("InitUtmp(): RealSlot = %d\n", RealSlot); X if (RealSlot) { X ReadUtmp(RealSlot, &RealUtmp); X RemoveUtmp(RealSlot); X } else X RealUtmp.ut_type = DEAD_PROCESS; X} X Xstatic void XRestoreRealUtmp() X{ X if (RealUtmp.ut_type != EMPTY) { X struct utmp *ret; X#ifdef AUX X int wtmpfd; X#endif X X setutent(); X RealUtmp.ut_type = USER_PROCESS; X pututline(&RealUtmp); X#ifdef AUX X if ((wtmpfd = open(WtmpName,1)) >= 0) { X lseek (wtmpfd, 0L, 2); X write (wtmpfd, (char *)&RealUtmp, sizeof(RealUtmp)); X close (wtmpfd); X } X#endif X } else X DO DEBUG("RestoreRealUtmp(): RealUtmp.ut_type == EMPTY\n"); X} X Xstatic int XSetUtmp(char *tty, int isreal, int lpid) X{ X register char *p; X struct utmp ut, *ret; X#ifdef AUX X int wtmpfd; X#endif X X DO DEBUG("SetUtmp(): tty = %s, isreal = %d, lpid = %d\n", tty, isreal, lpid); X X if (p = rindex(tty, '/')) X ++p; X else X p = tty; X X setutent(); X strncpy(ut.ut_line, p, 8); X ret = getutline(&ut); X if (ret == NULL) { X DO DEBUG("SetUtmp(): cannot locate utmp entry for %s\n", p); X ret = &ut; X } X X strncpy(ret->ut_line, p, 8); X#ifdef AUX X ret->ut_id[0] = 'p'; X ret->ut_id[1] = 't'; X ret->ut_id[2] = ret->ut_line[3]; X ret->ut_id[3] = ret->ut_line[4]; X#endif X strncpy(ret->ut_user, LoginName, 8); X if (RealSlot && isreal) X ret->ut_time = RealUtmp.ut_time; /* use original login time */ X else X time(&(ret->ut_time)); X X ret->ut_pid = lpid; X ret->ut_type = USER_PROCESS; X X pututline(ret); X#ifdef AUX X if ((wtmpfd = open(WtmpName,1)) >= 0) { X lseek (wtmpfd, 0L, 2); X write (wtmpfd, (char *)ret, sizeof(*ret)); X close (wtmpfd); X } X#endif X return FindUtmp(p); X} X Xstatic void RemoveTtyFromUtmp(struct Layer *l) X{ X struct utmp ut, *ret; X#ifdef AUX X int wtmpfd; X#endif X X setutent(); X ut_tty_cpy(&ut, l->tty); X ret = getutline(&ut); X if (ret) { X ret->ut_type = DEAD_PROCESS; X pututline(ret); X } X#ifdef AUX X if ((wtmpfd = open(WtmpName,1)) >= 0) { X lseek (wtmpfd, 0L, 2); X write (wtmpfd, (char *)ret, sizeof(*ret)); X close (wtmpfd); X } X#endif X} X X#else X X#ifndef SVR4 Xstatic char UtmpName[] = "/etc/utmp"; Xstatic int RealSlot = 0; /* Real tty logon slot */ X Xstatic int XFindUtmp(name) Xchar *name; X{ X register char *p; X register struct ttyent *tp; X register slot; X X DO DEBUG("FindUtmp(%s)\n", name); X slot = 1; X if (!utmp) X return 0; X if (p = rindex (name, '/')) X ++p; X else X p = name; X setttyent (); X while ( (tp = getttyent ()) != NULL X && strcmp (p, tp->ty_name) != 0 X ) X ++slot; X if (tp == NULL) X return 0; X X DO DEBUG(" slot %d\n", slot); X return slot; X X} /* FindUtmp() */ X Xstatic int XSetUtmp (name, mainlogin, lpid) Xchar *name; /* tty name */ Xint mainlogin; /* this is primary login */ Xint lpid; X{ X register char *p; X register slot; X struct utmp u; X X if ((slot=FindUtmp(name)) == 0) X return ( 0 ); X X if (p = rindex (name, '/')) X ++p; X else X p = name; X X strncpy (u.ut_line, p, 8); X strncpy (u.ut_name, LoginName, 8); X strncpy(u.ut_host, Filename (RealTtyName), 16); /* host is real tty */ X if (RealSlot && mainlogin) X u.ut_time = RealUtmp.ut_time; /* use original login time */ X else X time (&u.ut_time); X (void) lseek (utmpf, (long)(slot * sizeof (u)), 0); X (void) write (utmpf, (char *)&u, sizeof (u)); X X return ( slot ); X X} /* SetUtmp() */ X Xstatic int XReadUtmp(slot, entry) Xint slot; /* slot to read */ Xstruct utmp *entry; /* entry to read into */ X{ X int cnt; /* return count */ X X if (!utmp) X exit(EXITABNORMAL); /* no utmp access */ X X (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0); X cnt = read(utmpf, (char *)entry, sizeof(struct utmp)); X DO DEBUG("ReadUtmp cnt %d, errno %d, line %.8s, name %.8s, host %.16s\n", X cnt, errno, entry->ut_line, entry->ut_name, entry->ut_host); X X return ( cnt ); X X} /* ReadUtmp() */ X Xstatic void XWriteUtmp(slot, entry) Xint slot; /* slot to write */ Xstruct utmp *entry; /* entry to write from */ X{ X int cnt; /* write return code */ X X if (!utmp) X return; /* no utmp access */ X X (void) lseek(utmpf, (long)(slot * sizeof(struct utmp)), 0); X cnt = write(utmpf, (char *)entry, sizeof(struct utmp)); X DO DEBUG("WriteUtmp() slot %d cnt %d line %.8s name %.8s host %.16s\n", X slot, cnt, entry->ut_line, entry->ut_name, entry->ut_host); X X} /* WriteUtmp() */ X Xstatic void XRemoveUtmp (slot) Xint slot; X{ X struct utmp u; X X if (slot) X { bzero ((char *)&u, sizeof (u)); X (void) lseek (utmpf, (long)(slot * sizeof (u)), 0); X (void) write (utmpf, (char *)&u, sizeof (u)); X } X X} /* RemoveUtmp() */ X Xstatic void XRemoveTtyFromUtmp(layer) Xstruct Layer *layer; X{ X RemoveUtmp(layer->slot); X} X Xstatic void XInitUtmp () X{ X if ((utmpf = open (UtmpName, O_RDWR)) == -1) X { if (errno != EACCES) X Msg (errno, UtmpName); X return; X } X utmp = 1; X X RealSlot = FindUtmp(RealTtyName); /* find current logon slot */ X if (RealSlot) X { if (ReadUtmp(RealSlot, &RealUtmp) > 0) /* read real login utmp */ X RemoveUtmp(RealSlot); /* remove original logon slot */ X else X RealSlot = 0; /* something's wrong */ X } X} X Xstatic void XRestoreRealUtmp() X{ X if (RealSlot) X WriteUtmp(RealSlot, &RealUtmp); /* restore original login */ X} X#endif /* !SVR4 */ X#endif X X#ifdef SVR4 Xstatic void Xut_tty_cpy(struct utmpx *up, char * tty) X{ X strncpy(up->ut_line, strncmp(tty, "/dev/", 5) == 0 ? tty + 5 : tty, X sizeof up->ut_line); X up->ut_line[(sizeof up->ut_line) - 1] = '\0'; X} X Xstatic void XInitUtmp() X{ X struct utmpx *ret; X X setutxent(); X ut_tty_cpy(&RealUtmp, RealTtyName); X if ((ret = getutxline(&RealUtmp)) != NULL) { X RealUtmp = *ret; X RealUtmp.ut_type = LOGIN_PROCESS; X pututxline(&RealUtmp); X } else X RealUtmp.ut_type = EMPTY; X endutxent(); X} X Xstatic void XRestoreRealUtmp() X{ X if (RealUtmp.ut_type == LOGIN_PROCESS) { X struct utmpx *ret; X X setutxent(); X ret = getutxline(&RealUtmp); X if (ret != NULL) { X RealUtmp.ut_type = USER_PROCESS; X pututxline(&RealUtmp); X } X endutxent(); X } X} X Xstatic int XSetUtmp(char *tty, int chan, int lpid) X{ X struct utmpx ut, *ret; X char buf[8]; X X setutxent(); X ut_tty_cpy(&ut, tty); X ret = getutxline(&ut); X if (ret == NULL) X ret = &ut; X *ret = RealUtmp; X ut_tty_cpy(ret, tty); X (void) sprintf(buf, "ml%02d", chan); X (void) strncpy(ret->ut_id, buf, sizeof(ret->ut_id)); X ret->ut_pid = lpid; X ret->ut_type = USER_PROCESS; X if (chan != 1) X gettimeofday(&ret->ut_tv); X (void) strncpy(ret->ut_host, RealTtyName, sizeof(ret->ut_host)); X ret->ut_syslen = strlen(RealTtyName) + 1; X pututxline(ret); X endutxent(); X} X Xstatic void XRemoveTtyFromUtmp(struct Layer *l) X{ X struct utmpx ut, *ret; X char buf[8]; X X setutxent(); X memset(&ut, '\0', sizeof(ut)); X ut_tty_cpy(&ut, l->tty); X (void) sprintf(buf, "ml%02d", l->chan); X (void) strncpy(ut.ut_id, buf, sizeof(ut.ut_id)); X ret = getutxline(&ut); X if (ret != NULL) { X ret->ut_type = DEAD_PROCESS; X pututxline(ret); X } X endutxent(); X} X#endif /* SVR4 */ X END_OF_FILE if test 77081 -ne `wc -c <'1.30/layers.c'`; then echo shar: \"'1.30/layers.c'\" unpacked with wrong size! fi # end of '1.30/layers.c' fi if test -f '1.30/protocol.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/protocol.c'\" else echo shar: Extracting \"'1.30/protocol.c'\" \(37002 characters\) sed "s/^X//" >'1.30/protocol.c' <<'END_OF_FILE' X/* Copyright (C) 1989 by David W. Trissel X * X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X * X */ X X#include X#ifdef NeXT X#include X#endif X#include X#include X#include X#include "layers.h" X X /* protocol.c - BSD MacLayers protocol driver */ X X/* This module handles all interaction with the Macintosh MacLayers X** program. Services provided are: X** X** InitLink() - initialize link to MacLayers X** X** TopChannel() - return highest prority channel X** X** SendNew() - request new layer channel of MacLayers X** X** SendTitle() - change window title to given string (NOT IMPLENTED YET) X** X** SendDelete()- tell MacLayers indicated layer has died X** X** SendQuit() - order MacLayers to terminate layers mode X** X** SendData() - send output to indicated channel's window X** X** SendReshape() - send Shape structure to MacLayers X** X** ProcessStreamin() - data is ready to be processed from MacLayers X** X*/ X X#define DUMPALL X#undef DUMPALL X X/* C library calls */ X#ifndef NeXT Xunsigned alarm(); /* alarm system call */ X#endif X Xstatic int Start_proto1(); Xstatic int Start_proto2(); Xstatic int Start_proto3(); Xstatic int Start_proto4(); Xstatic int Start_proto5(); Xstatic int Start_proto6(); Xstatic int Start_proto7(); Xstatic int Start_proto8(); Xstatic int GetData(); Xstatic void Packet(); Xstatic void Parse(); Xstatic void AwaitInput(); Xstatic void asciishape(); Xstatic void fill4(); Xstatic void fill2(); Xstatic void fill1(); Xstatic int parseshape(); Xstatic unsigned get4(); Xstatic unsigned get2(); Xstatic unsigned get1(); Xstatic int myscanf(); Xstatic int mygetchar(); Xstatic void myungetc(); Xstatic void myalarm(); Xstatic void dumptime(); X Xstatic char inbuff[IOSIZE]; /* input buffer from MacLayers */ Xstatic char *inpos; /* current input position in buffer */ Xstatic int insize = 0; /* characters left to process */ Xstatic int settimeout = 0; /* alarm system call timeout value */ Xstatic int Outstream = -1; /* current output stream channel */ Xstatic int Instream = -1; /* current input stream channel */ Xstatic int Sevenbits = 0; /* communication channel is 7 bits */ X Xstatic struct Shape SNshape; /* SendNew() shape response */ Xstatic int SNresp = 0; /* SendNew() reponse poll flag */ Xstatic int SNchan = 0; /* SendNew() channel return */ X#define SN_WAITING -1000 /* SendNew() waiting response value */ X X#define ATTRSIZE 15 /* size of window attribute string */ X X#define FLUSH fflush(stdout) X X X /* Initlink() - initialize link with MacLayers */ X X/* Returns: X** 0 - linkup failed X** 1 - linkup successful, Maclayers now in protocol mode X*/ X Xint XInitlink() X{ X int Outstream = -1; /* no default stream yet [UNUSED] */ X int Instream = -1; /* no default stream yet [UNUSED] */ X int num1, num2, num3; /* scanf item result */ X int err; /* error code */ X int doversion = 0; /* version swapping flag [UNUSED] */ X X#define WAITTIME 10 /* second wait response time */ X#define INITTIME 2 /* wait time after succesful startup */ X X X/*** This patch not yet tested or implemented. Sent to the MacLayers archive X**** as: X X This patch fixes the "Encode request not from host" bug that occurs when X running MacLayers 1.00 on a VaxStation 3100 and Ultrix 3.1d. X X I came across this patch rather accidentally, so take it with a grain of X NaCl. X X ifndef vax X /* we must non-buffer input since all input must be immediate X setbuf(stdin, NULL); /* non-buffer all input X endif X XArchive manager Peter Newton added the following comments: X X Don't have a VaxStation to try it one. Many people have had problems X with Ultrix on VaxStations. We have been giving them uuencoded X binaries made under BSD. X X*****************/ X X /* V1.1 Note: The latest BSD Sun system doesn't break reads from the X ** terminal during signals. It appears that System V does do this X ** as do earlier BSD systems. At this time no special hacks will X ** be installed in just to support Unix versions not doing the breaks. X ** Without alarm timeouts host layers will hang if inappropriate X ** responses are received during protocol startup. But this should X ** only happen when a user types the layers command when not running X ** MacLayers. X */ X X /* we must non-buffer input since all input must be immediate */ X setbuf(stdin, NULL); /* non-buffer all input */ X X /* Host layers after V1.00 can receive protocol level information. X ** Send our level as ESC . Version 1.00 MacLayers will treat X ** this as an illegal vt-100 sequence and issue a beep. Later versions X ** accept our protocol level and return their own after receiving X ** our protocol startup sequence sent here. X */ X DO DEBUG("write protocol level 2: ESC 2\n"); X /* send our protocol level out */ X if ((err=printf("\033%c", HOSTPROTOCOL + '0')) < 0) X { DO DEBUG(" printf() error code %d\n", err); X return ( 0 ); /* problem with stdout */ X } X FLUSH; X X /* send intitial request for terminal type and version number */ X DO DEBUG("write: ESC [ c\n"); X fputs("\033[c", stdout); X FLUSH; /* force output buffer */ X X /* Attempt to read "ESC [ ? 8 ; typedigits ; versiondigits c" X ** MacLayers in layers mode will return 8 ; 1 c X ** MacLayers in startup mode returns 8 ; X c X ** were X is the protocol level X */ X num1 = num2 = num3 = -1; /* default to unsupplied values */ X DO DEBUG(" doing first scanf\n"); X (void) myalarm(WAITTIME); /* set timeout */ X (void) myscanf("\033[?%d;%d;%dc", &num1, &num2, &num3); X (void) myalarm(0); /* cancel alarm */ X DO DEBUG("read ESC [ ? %d ; %d; %d c\n", num1, num2, num3); X if (num1 != 8 || num2 != 10) X return ( 0 ); /* not correct response or layers term ID */ X X DO DEBUG("Client Protocol %d, Host Protocol %d\n", num3, HOSTPROTOCOL); X X /* Terminal type was valid, now verify protocol number */ X switch (num3) X { case 1: X case 2: X case 3: X case 4: X case 5: X case 6: X /* these are all valid levels */ X break; /* break for valid levels */ X X case 9: X num3 = 7; /* 9 represents level 7 */ X break; X X case 0: X num3 = 8; /* 0 represents level 8 */ X break; X X default: X /* invalid response */ X return ( 0 ); /* incorrect protocol level */ X X } /* client protocol level switch */ X X Clientlevel = num3; /* set client protocol level offered */ X X /* final protocol level cannot be higher than our current support level */ X if (num3 > HOSTPROTOCOL) X { DO DEBUG("Protocol level forced down to host level\n"); X num3 = HOSTPROTOCOL; /* force back down to the host level */ X } X X Protocollevel = num3; /* set effective protocol level */ X X /* execute proper startup protocol level routine */ X switch (Protocollevel) X { case 1: X return ( Start_proto1() ); /* handle protocol 1 startup sequence */ X X case 2: X return ( Start_proto2() ); /* handle protocol 2 startup sequence */ X X case 3: X return ( Start_proto3() ); /* handle protocol 3 startup sequence */ X X case 4: X return ( Start_proto4() ); /* handle protocol 4 startup sequence */ X X case 5: X return ( Start_proto5() ); /* handle protocol 5 startup sequence */ X X case 6: X return ( Start_proto6() ); /* handle protocol 6 startup sequence */ X X case 7: X return ( Start_proto7() ); /* handle protocol 7 startup sequence */ X X case 8: X return ( Start_proto8() ); /* handle protocol 8 startup sequence */ X X } X X /* invalid - refuse startup */ X return ( 0 ); /* SHOULD NOT OCCUR */ X X} /* Initlink() */ X X X /* Start_proto1() - Protocol 1 startup sequence */ X Xstatic int XStart_proto1() X{ X int num1; /* scanf item result */ X X /* This is the original MacLayers protocol for V1.00 */ X X /* ask terminal if ENC_ENABLE is to be forced */ X DO DEBUG("write: ESC [ F\n"); X (void) fputs("\033[F", stdout); X FLUSH; /* force output buffer */ X X /* attempt to read "ESC [ flag F" (flag indicates ENC_ENABLE status) */ X num1 = -1; /* default to invalid response */ X myalarm(WAITTIME); /* set timeout */ X (void) myscanf("\033[%dF", &num1); X myalarm(0); /* cancel alarm */ X DO DEBUG("read ESC [ %d F\n", num1); X if (num1 != 1 && num1 != 0) X return ( 0 ); /* something's wrong */ X if (num1 == 1) X Sevenbits = 1; /* we are processing 7-bit data */ X X /* now startup packet mode in non ENC_ENABLE processing */ X DO DEBUG("write: ESC [ 2 ; 0 v\n"); X (void) fputs("\033[2;0v", stdout); /* "ESC [ 2 ; 0 v" */ X FLUSH; /* force output buffer */ X X#if 0 X { int i,j; X for (i=0; i<20; i++) X { j = mygetchar(); X DO DEBUG("---- read 0x%lx == %c\n", j, j); X } X return (0 ); X } X#endif X#if 0 X /* We must reset buffer to reread this character. Note X ** this won't work for triggering reads by layers.c unless X ** client is sending more than 1 character because the select() X ** system call is used. X */ X /* ungetc(num1, stdin); /* return character back for re-read */ X myungetc(num1); /* re-insert this character */ X#endif X#if 0 X insize = 1; /* preset buffer with one character */ X inpos = inbuff; /* setup buffer pointer */ X inbuff[0] = num1; /* setup to reread this character */ X#endif X Clientlevel = 1; /* assume protocol is level 1 */ X X /* we are now in packet mode */ X sleep( INITTIME ); /* let Macintosh keep up with us */ X X return ( 1 ); /* return successful startup */ X X} /* Start_proto1() */ X X X /* Start_proto2() - Protocol 2 startup sequence */ X Xstatic int XStart_proto2() X{ X /* This is the second MacLayers protocol starting with V1.1 */ X X /* we are now in packet mode */ X sleep( INITTIME ); /* let Macintosh keep up with us */ X X return ( 1 ); /* return successful startup */ X X} /* Start_proto2() */ X X X X /* Start_proto3() - Protocol 3 startup sequence */ X Xstatic int XStart_proto3() X{ X /* not yet defined! */ X return ( 0 ); /* SHOULD NOT OCCUR */ X X} /* Start_proto3() */ X X X X /* Start_proto4() - Protocol 4 startup sequence */ X Xstatic int XStart_proto4() X{ X /* not yet defined! */ X return ( 0 ); /* SHOULD NOT OCCUR */ X X} /* Start_proto4() */ X X X X /* Start_proto5() - Protocol 5 startup sequence */ X Xstatic int XStart_proto5() X{ X /* not yet defined! */ X return ( 0 ); /* SHOULD NOT OCCUR */ X X} /* Start_proto5() */ X X X X /* Start_proto6() - Protocol 6 startup sequence */ X Xstatic int XStart_proto6() X{ X /* not yet defined! */ X return ( 0 ); /* SHOULD NOT OCCUR */ X X} /* Start_proto6() */ X X X X /* Start_proto7() - Protocol 7 startup sequence */ X Xstatic int XStart_proto7() X{ X /* not yet defined! */ X return ( 0 ); /* SHOULD NOT OCCUR */ X X} /* Start_proto7() */ X X X X /* Start_proto8() - Protocol 8 startup sequence */ X Xstatic int XStart_proto8() X{ X /* not yet defined! */ X return ( 0 ); /* SHOULD NOT OCCUR */ X X} /* Start_proto8() */ X X X /* TopChannel() - return highest prority channel */ X Xint XTopChannel() X{ X return ( Instream ); X X} /* TopChannel() */ X X X /* X ** WARNING: Most of the following functions may be recursively called X ** as control commands are processed from the input stream X */ X X X /* ProcessStreamin() - MacLayers has input to process */ X Xvoid XProcessStreamin() X{ X DO dumptime(); X DO DEBUG("ProcessStreamin() insize %d\n", insize); X X GetData(); /* read some */ X X while (insize > 0) /* while more data to process ... */ X Parse(); /* process next chuck of data */ X X} /* ProcessStreamin() */ X X X /* SendNew() - request new layer channel from MacLayers */ X X/* This command is unique in that it returns a response from MacLayers. X** To do this we continue processing the input stream until we get X** our return. (This leads to recursive conditions.) The variables X** 'SNresp', 'SNshape' and 'SNchan' are set when our reply is received. X*/ Xint XSendNew(shape) Xstruct Shape *shape; /* shape to use for new window */ X{ X int i; /* attribute count variable */ X char astring[ATTRSIZE]; /* copy of attribute string */ X X DO dumptime(); X DO DEBUG("SendNew() new layer requested: '~%cA'\n", '1'+ATTRSIZE); X X /* check for a recursive call */ X if (SNresp == SN_WAITING) X { DO DEBUG("return 0 - recursive call\n"); X return ( 0 ); /* return failure */ X } X X putchar(ESCAPE); /* send start of control packet char */ X putchar('1' + ATTRSIZE); /* send command size */ X putchar('A'); /* send command */ X asciishape(shape, astring); /* convert shape to string */ X for (i=0; i < ATTRSIZE; i++) X putchar(astring[i]); /* send next attribute digit */ X FLUSH; X X /* now stay here and process the input stream until we see our response */ X/**** THIS SHOULD BE ENHANCED TO TIMEOUT WITH GetData() AND REISSUE REQUEST */ X SNresp = SN_WAITING; /* indicate we are waiting a response */ X while (SNresp == SN_WAITING) X { DO DEBUG(" while (SNresp %d == %d)\n", SNresp, SN_WAITING); X AwaitInput(); /* wait till input from MacLayers arrives */ X ProcessStreamin(); /* process available input */ X } X X if (SNresp == -1) /* if Maclayers rejected request */ X SNchan = 0; /* return failure channel of zero */ X else X *shape = SNshape; /* else update shape structure */ X X DO DEBUG("SendNew() returning channel %d\n", SNchan); X X return ( SNchan ); /* return the indicated channel */ X X} /* SendNew() */ X X X /* SendReshape() - send to shape to MacLayers */ X Xvoid XSendReshape(chan, shape) Xint chan; /* channel shape belongs to */ Xstruct Shape *shape; /* shape to use for new window */ X{ X int i; /* attribute count variable */ X char astring[ATTRSIZE]; /* copy of attribute string */ X X DO dumptime(); X DO DEBUG("SendReshape() reshape: '~%cA'\n", '2'+ATTRSIZE); X X if (chan <= 0 || chan > MAXPCHAN) X { DO DEBUG("BAD CHANNEL!!!\n"); X return; /* ignore request */ X } X X putchar(ESCAPE); /* send start of control packet char */ X putchar('2' + ATTRSIZE); /* send command size */ X putchar('R'); /* send command */ X putchar(chan + '0'); /* send channel */ X asciishape(shape, astring); /* convert shape to string */ X DO DEBUG("shape: %.*s\n", ATTRSIZE, astring); X for (i=0; i < ATTRSIZE; i++) X putchar(astring[i]); /* send next attribute digit */ X FLUSH; X X} /* SendReshape() */ X X X /* SendTitle() - set layer's window title */ X Xvoid XSendTitle(chan, buff, cnt) Xint chan; /* layer window ID */ Xchar *buff; /* new title string */ Xint cnt; /* count of title length */ X{ X int i; /* work variable */ X X DO DEBUG("SendTitle(chan%d, len %d, '%.*s')\n", chan, cnt, cnt, buff); X X if (chan <= 0 || chan > MAXPCHAN) X { DO DEBUG("BAD CHANNEL!!!\n"); X return; /* ignore request */ X } X X if (cnt < 0) X { DO DEBUG("BAD COUNT!!!\n"); X return; /* ignore request */ X } X X /* for now chop title size to 29 chars since that's MacLayer's limit */ X if (cnt > 29) X cnt = 29; /* due to packet size limit */ X X /* we must guarantee that the size will not appear to be another ESCAPE */ X if ('2' + cnt == ESCAPE) X cnt--; /* truncate to avoid ESCAPE ESCAPE */ X X putchar(ESCAPE); /* send start of control packet char */ X putchar('2' + cnt); /* send size of packet */ X putchar('T'); /* send command */ X putchar(chan + '0'); /* send channel ID */ X for (i=0; i MAXPCHAN) /* check channel ID */ X { DO DEBUG("BAD CHANNEL!!!\n"); X return; /* ignore request */ X } X X putchar(ESCAPE); /* send control packet start char */ X putchar('2'); /* send command size */ X putchar('D'); /* send command character */ X putchar(chan + '0'); /* channel ID in ascii */ X FLUSH; X X} /* SendDelete() */ X X X /* SendQuit() - order MacLayers to end layers mode */ X Xvoid XSendQuit(chan) Xint chan; /* dead channel ID */ X{ X DO dumptime(); X DO DEBUG("SendQuit() '~1E'\n"); X X putchar(ESCAPE); /* send control packet start char */ X putchar('1'); /* send command size */ X putchar('E'); /* send command */ X FLUSH; X X} /* SendQuit() */ X X X /* SendData() - send output to layer's window */ X Xvoid XSendData(chan, buff, cnt) Xint chan; /* layer window ID */ Xunsigned char *buff; /* new title string */ Xint cnt; /* count of title length */ X{ X unsigned c; /* output character being sent */ X X DO X { int dcnt; X X dumptime(); X DEBUG("SendData(chan %d, len %d, '", chan, cnt, cnt, buff); X for (dcnt=0; dcnt MAXPCHAN) X { DO DEBUG("BAD CHANNEL!!!\n"); X return; /* ignore request */ X } X X /* if new output channel stream then prefix redirect command */ X if (chan != Outstream) X { DO DEBUG("Redirecting output to %d '~2O%d'\n", chan, chan); X putchar(ESCAPE); /* start of command sequence */ X putchar('2'); /* send command size */ X putchar('O'); /* send command */ X putchar(chan + '0'); /* put out channel in ASCII */ X Outstream = chan; /* new output stream set */ X } X X /* transmit the buffer converting the ESCAPE sequence to double ESCAPE */ X while (cnt--) X { c = *buff++; /* get next output character */ X#ifdef DUMPALL X DO DEBUG("outchar %c 0x%x\n", c, c); X#endif X if (c == ESCAPE || c == (ESCAPE + 0x80)) X { putchar(c); /* put it out twice */ X#ifdef DUMPALL X DO DEBUG(" Doubled Escape!\n"); X#endif X } X putchar(c); /* write character out */ X } X X FLUSH; /* force out queued output characters */ X X} /* SendData() */ X X X /* Parse() - process next chunk of input stream */ X Xstatic void XParse() X{ X#define ST_NULL 0 /* not primed for next state yet */ X#define ST_STREAM 1 /* processing default stream input */ X#define ST_PKT 2 /* processing packet data */ X X int c; /* input character being processed */ X X static int state = ST_NULL; /* current input state */ X static int psize = 0; /* packet size */ X static int rempsize = 0; /* remembered packet size */ X static char pdata[MAXSTR]; /* area for packet data */ X static char *ppos; /* packet read insert position */ X static int escapemode = 0; /* processing escape character */ X static int escapechar; /* escape character being processed */ X static pchan = -1; /* packet input stream channel */ X X DO dumptime(); X DO DEBUG("Parse() insize %d\n", insize); X X while (insize-- > 0) /* while more data */ X { c = (*inpos++ & 0xFF); /* get next character (don't sign extend) */ X switch (state) /* process according to state */ X { case ST_NULL: /* prepare for new packet */ X DO DEBUG("ST_NULL\n"); X psize = 0; /* clear packet size */ X ppos = pdata; /* start fill at data position */ X pchan = Instream; /* packet channel is current input stream */ X state = ST_STREAM; /* default is stream processing */ X X case ST_STREAM: X /* stream keyboard input for layer */ X /* check for escape char with possible high bit on */ X#ifdef DUMPALL X DO DEBUG("ST_STREAM %x/%x '%c' esc %d insz %d\n", X c, c & 0x7f, c & 0x7f, escapemode, insize); X#endif X if (c == ESCAPE || c == (ESCAPE | 0x80)) X { if (escapemode && c == escapechar) /* previous was ESCAPE */ X /* this is really a single ESCAPE character */ X escapemode = 0; /* back out of ESCAPE mode */ X else X /* what do we do with back to back esc esc+0x80 ? */ X { /* flag in escape mode */ X escapemode++; X escapechar = c; /* remember character used for escape */ X continue; /* and continue scan */ X } X } X else X if (escapemode) X { /* this is the start of a control packet */ X if (psize) /* if we have previous data packet */ X Packet(pchan, psize, pdata); /* finish up previous pkt */ X /* process packet size */ X psize = (c & 0x7f) - '0'; /* save size byte */ X if (psize <= 0 || psize > MAXSTR) X { /* bad size */ X DO DEBUG("Bad pkt size %d\n", psize); X break; /* trash this packet */ X } X rempsize = psize; /* remember this size for later */ X#if 0 X ptimo = rtimo; /* start receive timeout */ X#endif X escapemode = 0; /* escape mode now off */ X ppos = pdata; /* initialize data store pointer */ X state = ST_PKT; /* expect packet data next */ X continue; /* continue scan */ X } X X /* process standard data output character for current stream */ X X *ppos++ = c; /* save next data character */ X X if (++psize >= MAXSTR) /* if packet full ... */ X { Packet(pchan, psize, pdata); /* process this packet */ X break; /* end packet processing */ X } X continue; /* continue scan */ X X case ST_PKT: X /* process next paket data byte */ X *ppos++ = c & 0x7f; /* store next data byte */ X#ifdef DUMPALL X DO DEBUG("ST_PKT: %x '%c' sz %d\n", c & 0x7f, c & 0x7f, psize); X#endif X if (--psize != 0) X continue; X#if 0 X if (crc((unsigned char *) &rpkt, rpkt.pkt.HEADER_DSIZE+2)) X STATS(Scrcerr); /* communications error */ X else X#endif X Packet(0, rempsize, pdata); /* process it */ X X } /* end build packet switch */ X X#if 0 X ptimo = 0; /* no more receive timeout */ X#endif X state = ST_NULL; /* no more receive packet in progress */ X X } /* end while (insize) */ X X if (state == ST_STREAM && psize ) /* if we have some data ... */ X { Packet(Instream, psize, pdata); /* process this data */ X#if 0 X ptimo = 0; /* no more receive timeout */ X#endif X state = ST_NULL; /* no more receive packet in progress */ X } X X} /* Parse() */ X X X /* Packet() - prcess next input data string or control packet */ Xstatic void XPacket(chan, size, buff) Xint chan; /* channel (0 if control packet) */ Xint size; /* amount of data */ Xchar *buff; /* pointer to packet data */ X{ X static struct Shape shape; /* Shape structure */ X X DO dumptime(); X DO DEBUG("Packet(chan %d, size %d, '%.*s')\n", chan, size, size, buff); X X /* verify channel */ X if (chan < 0 || chan > MAXPCHAN) X { DO DEBUG("BAD CHANNEL!!\n"); X return; /* ignore bad channel */ X } X X /* if data packet (chan>0) feed data to server */ X if (chan > 0) X { ReceiveData(chan, buff, size); X return; /* we are through */ X } X X /* control packet (channel 0) */ X chan = buff[1] - '0'; /* assume channel specified */ X if (chan < 0 || chan > MAXPCHAN) /* if invalid ... */ X chan = 0; /* set to zero */ X X switch (buff[0]) X { case 'I': /* redirect stream */ X DO DEBUG("CMD 'I' redirect stream to %c\n", buff[1]); X if (size != 2) /* verify size */ X break; /* break if bad */ X if (chan == 0) /* verify channel */ X break; /* break if bad */ X Instream = chan; /* new instream channel */ X return; /* we are through */ X X case 'A': /* returned A_NEWLAYER packet */ X DO DEBUG("CMD 'A' A_NEWLAYER response %c newchan %c SNresp %d\n", X buff[2], buff[1], SNresp); X if (size != 3 + ATTRSIZE) X break; /* break if bad */ X X /* if SendNew() not waiting for a response this is invalid */ X if (SNresp != SN_WAITING) X break; /* break if bad */ X X if (buff[2] == '1') /* if response is "failed" ... */ X SNresp = -1; /* show -1 response */ X else X if (buff[2] == '0') /* if response is "success" ... */ X { if (chan == 0) /* if invalid channel */ X break; /* break if bad */ X /* build shape structure for SendNew() */ X if (parseshape(&SNshape, &buff[3]) == -1) X break; /* if invalid data then bad packet */ X SNresp = 0; /* show good response */ X SNchan = chan; /* indicate channel returned */ X } X else X break; /* break if bad */ X X DO DEBUG("SNresp = %d, SNchan = %d\n", SNresp, SNchan); X return; /* we are through */ X X case 'N': /* new layer creation */ X DO DEBUG("CMD 'N' new layer creation newchan %c\n", buff[1]); X if (size != 2 + ATTRSIZE) /* verify size */ X break; /* break if bad */ X if (chan == 0) /* verify channel */ X break; /* break if bad */ X /* build shape structure */ X if (parseshape(&shape, &buff[2]) == -1) X break; /* if invalid data then bad packet */ X ReceiveNew(chan, &shape); /* pass to server */ X return; /* packet is done */ X X case 'D': /* deleted layer */ X DO DEBUG("CMD 'D' deleted layer %c\n", buff[1]); X if (size != 2) /* verify size */ X break; /* break if bad */ X if (chan == 0) /* verify channel */ X break; /* break if bad */ X ReceiveDelete(chan); /* pass on to server */ X return; /* packet is done */ X X case 'E': /* exit - awaiting shutdown */ X DO DEBUG("CMD 'E' exit MacLayers awaiting shutdown msg\n"); X if (size != 1) /* verify size */ X break; /* break if bad */ X ReceiveQuit(); /* pass to server */ X /* NOT REACHED*/ X return; /* ?? should never reach here */ X X case 'R': /* reshaped */ X DO DEBUG("CMD 'R' reshape chan %c\n", buff[1]); X X if (size != 2 + ATTRSIZE) /* verify size */ X break; /* break if bad */ X X if (chan == 0) /* verify channel */ X break; /* break if bad */ X X /* build shape structure */ X if (parseshape(&shape, &buff[2]) == -1) X break; /* if invalid data then bad packet */ X X ReceiveReshape(chan, &shape); /* tell server about shape */ X return; /* packet processed */ X X case 'S': /* signal */ X DO DEBUG("CMD 'S' SIGNAL chan %c sig %c\n", buff[1], buff[2]); X if (size != 3) /* verify size */ X break; /* break if bad */ X if (chan == 0) X break; /* break if bad */ X X if (buff[2] == '0') /* if SIGINT */ X size = SIGINT; /* yes */ X else X if (buff[2] == '1') /* if SIGHUP */ X size = SIGHUP; /* yes */ X else X break; /* invalid signal */ X X ReceiveSignal(chan, size); /* pass to server */ X return; /* packet processed */ X X default: X DO DEBUG("ILLEGAL CONTROL PACKET!!!\n"); X return; /* ignore bad packet */ X X } /* end command packet switch */ X X /* switch falls out if bad size or channel for given command */ X DO DEBUG("Invalid size or channel!!!\n"); /* dump error */ X return; /* ignore packet */ X X} /* Packet() */ X X X /* GetData() - read next input from MacLayers stream */ X X/* The settimeout variable indicates if we return when nothing X** is read within a certain amount of seconds. The return code is: X** X** 0 - timeout occured and no data was read X** X** 1 - no timeout occured, data read X*/ Xstatic int XGetData() X{ X int result; /* return from read() */ X int i; /* work counter */ X char *ptr; /* work pointer */ X X DO dumptime(); X DO DEBUG("GetData()\n"); X X /* if buffer still has data simply return (SHOULD NOT OCCUR?) */ X if (insize > 0) X { DO DEBUG("early return insize %d\n", insize); X return ( 1 ); /* act as through data read */ X } X inpos = inbuff; /* next get will start at beginning */ X insize = 0; /* default insize back to zero */ X X /* set timeout if we are to do so */ X if (settimeout) X { DO DEBUG("alarm(%d)\n", settimeout); X (void) alarm(settimeout); /* set timeout in seconds */ X } X X /* do the read from stdin */ X result = read(0, inbuff, IOSIZE); X X /* if alarm was set cancel it now */ X if (settimeout) X { DO DEBUG("alarm(0)\n"); X myalarm(0); /* cancel alarm */ X } X X /* check for timeout or error */ X /* EWOULDBLOCK for no data avail -(but we should not see this) */ X /* EINTR if signal stopped the read -(rare but could happen) */ X if (result <= 0) X { DO DEBUG(" ?? no data result %d\n", result); X return ( 0 ); /* return nothing read */ X } X X /* return with fresh buffer data */ X insize = result; X X /* if 7-bit communication channel then strip all high bits */ X if (Sevenbits) X for (i=result,ptr = inbuff; i>0; --i) X *ptr++ &= 0x7f; /* strip high bit */ X X DO DEBUG("read %d bytes\n", insize); X return ( 1 ); /* return OK code */ X X} /* GetData() */ X X X /* AwaitInput() - wait for more input from MacLayers */ X Xstatic void XAwaitInput() X{ X int r; /* read descriptor bits */ X X DO dumptime(); X DO DEBUG("AwaitInput() insize %d\n", insize); X X /* if buffer has data then don't wait */ X if (insize > 0) X { DO DEBUG("Return early insize %d\n", insize); X return; X } X X do X { r = 1<<0; /* wait for read from input device */ X if (select(32, (fd_set *) &r, (fd_set *) NULL, (fd_set *) NULL, X (struct timeval *) NULL) == -1) /* if problem waiting ... */ X { if (errno != EINTR) /* if not simply signal taken ... */ X { /* SHOULD NOT OCCUR - shutdown layers */ X DO DEBUG("AwaitInput: select error %d\n", errno); X printf("layers: AwaitInput: bad select %d\n", errno); X FQuit(); /* shutdown layers */ X /* NOT REACHED */ X } X } X } while ((r & 1<<0) == 0); X X} /* AwaitInput() */ X X /* asciishape() - convert Shape structure to ASCII */ Xstatic void Xasciishape(shape, loc) Xstruct Shape *shape; /* Shape structure for channel */ Xchar *loc; /* location to start filling result */ X{ X char *origloc; /* (for debuggin) */ X X origloc = loc; /* remember start of string */ X fill4(&loc, shape->worigh); /* origin h */ X fill4(&loc, shape->worigv); /* origin v */ X fill2(&loc, shape->wlines); /* lines high */ X fill2(&loc, shape->wchars); /* chars wide */ X fill1(&loc, shape->wfont); /* font size */ X fill2(&loc, shape->wattr); /* attributes */ X X DO DEBUG("asciishape(): %.*s\n", ATTRSIZE, origloc); X X} /* asciishape() */ X X X /* fill4() - convert parameter to ASCII */ X Xstatic void Xfill4(loc, valu) Xchar **loc; /* pointer to fill area pointer */ Xunsigned valu; /* value to use */ X{ X fill2(loc, valu>>8); /* fill high half word */ X fill2(loc, valu & 0xff); /* fill low half word */ X X} /* fill4() */ X X X /* fill2() - convert parameter to ASCII */ X Xstatic void Xfill2(loc, valu) Xchar **loc; /* pointer to fill area pointer */ Xunsigned valu; /* value to use */ X{ X fill1(loc, valu>>4); /* fill high byte */ X fill1(loc, valu & 0xf); /* fill low byte */ X X} /* fill2() */ X X X /* fill1() - convert parameter to ASCII */ X Xstatic void Xfill1(loc, valu) Xchar **loc; /* pointer to fill area pointer */ Xunsigned valu; /* value to use */ X{ X *(*loc)++ = "0123456789ABCDEF"[valu & 0xf]; /* return hex value */ X X} /* fill1() */ X X X /* parseshape() - convert ASCII image to Shape structure */ X Xstatic int Badconvert; /* indicates bad conversion */ X Xstatic int Xparseshape(shape, loc) Xstruct Shape *shape; /* Shape structure for channel */ Xchar *loc; /* location to start parsing */ X{ X Badconvert = 0; /* clear bad characters indicator */ X shape->worigh = get4(&loc); /* origin h */ X shape->worigv = get4(&loc); /* origin v */ X shape->wlines = get2(&loc); /* lines high */ X shape->wchars = get2(&loc); /* chars wide */ X shape->wfont = get1(&loc); /* font size */ X shape->wattr = get2(&loc); /* attributes */ X X DO DEBUG("ParseShape(): origv %d, origh %d, lines %d, chars %d\n", X shape->worigv, shape->worigh, shape->wlines, shape->wchars); X DO DEBUG(" font %d, attr 0x%x, badconv %d\n", X shape->wfont, shape->wattr, Badconvert); X X return ( Badconvert ? -1 : 0 ); /* return conversion code */ X X} /* parseshape() */ X X X /* get4() - convert ASCII to parameter */ X Xstatic unsigned Xget4(loc) Xchar **loc; /* pointer to fill area pointer */ X{ X unsigned hi; /* high portion */ X unsigned low; /* low portion */ X X hi = get2(loc); /* get high byte */ X low = get2(loc); /* get low byte */ X X return ( (hi<<8) + low ); /* return word value */ X X} /* get4() */ X X X /* get2() - convert ASCII to parameter */ X Xstatic unsigned Xget2(loc) Xchar **loc; /* pointer to fill area pointer */ X{ X unsigned hi; /* high portion */ X unsigned low; /* low portion */ X X hi = get1(loc); /* get high half */ X low = get1(loc); /* get low half */ X X return ( (hi<<4) + low ); /* return byte value */ X X} /* get2() */ X X X /* get1() - convert ASCII to parameter */ X X/* This function sets 'Badconvert' if an invalid character is detected */ X Xstatic unsigned Xget1(loc) Xchar **loc; /* pointer to fill area pointer */ X{ X int c; /* character to convert */ X X c = *(*loc)++; /* fetch character */ X X if (c >= '0' && c <= '9') X /* zero through nine */ X return ( c - '0' ); /* return it's binary value */ X X if (c >= 'a' && c <= 'f') X /* lower case hex */ X return ( c - 'a' + 10); /* return it's binary value */ X X if (c >= 'A' && c <= 'F') X /* upper case hex */ X return ( c - 'A' + 10); /* return it's binary value */ X X /* invalid digit! */ X Badconvert++; /* set bad character flag */ X return ( 0 ); /* return a zero */ X X} /* get1() */ X X X /* myscanf() - RAW mode scanf routine */ X X/** This routine is required because once our terminal is set into RAW mode X*** the standard scanf routine fails on 7-bit lines whenever a high bit X*** occurs in an input character. Only the %d, %c and exact input character X*** images are supported in the input format string. All value parameters X*** must be integer data type for both %d and %c. X*/ X Xstatic int Xmyscanf(str, arg1, arg2, arg3) Xunsigned char *str; /* scanf input string */ Xint *arg1,*arg2,*arg3; /* integer input pointer arguments */ X{ X int numscan = 0; /* items filled in */ X int build; /* %d build integer value */ X int c; /* integer input character */ X X DO dumptime(); X DO DEBUG("myscanf(%s)\n", str); X X /* scan string processing formats */ X while (*str) X switch (*str) X { case EOF: X /* Error: probably our alarm timed out */ X return ( numscan ); X /* NOT REACHED */ X X case '%': X /* format specifier */ X switch (*++str) X { case 'c': X /* return next character as is */ X if ((build=mygetchar()) == -1) X return ( numscan ); /* no input, return count */ X break; X X case 'd': X /* build input decimal value */ X build = 0; X while ((c=mygetchar()) >= '0' && c <= '9') X { build = build * 10; /* next base ten digit */ X build += c - '0'; /* add this digit */ X } X myungetc(c); /* return character ending number */ X break; X X default: X return ( numscan ); /* return if error */ X /* NOT REACHED */ X } X X /* return value to correct input parameter */ X switch (numscan) X { case 0: X *arg1 = build; X break; X X case 1: X *arg2 = build; X break; X X case 2: X *arg3 = build; X break; X X default: X /* SHOULD NOT OCCUR */ X return ( numscan ); X /* NOT REACHED */ X } X X numscan++; /* count items scanned */ X str++; /* bump scan string past 'd' */ X break; /* continue scan */ X X default: X /* input character must match exactly */ X c = mygetchar(); X if (c != *str) X return ( numscan ); /* return - we don't match string */ X str++; /* to next character */ X X } /* end scan string char switch */ X X /* return number of items scanned */ X return ( numscan ); X X} /* myscanf() */ X X X /* mygetchar() - get character stripped to 7 bits */ X X/* Return: -1 if timeout X** char stripped to 7 bits X*/ X Xstatic int Xmygetchar() X{ X int c; /* next input character */ X int result; /* read return value */ X X DO dumptime(); X X /* if character still in buffer return it */ X if (insize > 0) X { insize--; /* count down */ X c = (*inpos++) & 0x7f; /* fetch next char */ X DO DEBUG(" 0x%lx '%c' ", c, c); X return ( c ); /* return 7-bit character */ X } X X /* attempt to read the buffer */ X result = GetData(); /* no timeout (caller may have set) */ X X /* return -1 if timeout */ X if (result == 0) X { DO DEBUG(" mygetchar ret -1\n"); X return ( -1 ); X } X X return ( mygetchar() ); /* return next character */ X X#if 0 X c = getchar() & 0x7f; /* insure 7-bit only */ X XDO DEBUG(" 0x%lx '%c' ", c, c); X return ( c ); X#endif X X} /* mygetchar() */ X X X /* myungetc() - unget a character */ X X/* Must only be called to return when a character was previously fetched */ X Xstatic void Xmyungetc(c) Xint c; /* character to unget */ X{ X DO dumptime(); X DO DEBUG("myungetc(x%lx/%c)\n", c, c); X X insize++; /* count back up by one */ X *--inpos = c; /* restore previous character */ X X} /* myungetc() */ X X X /* myalarm() - setup alarm timeout for next read */ X Xstatic void Xmyalarm(time) Xint time; /* time in seconds (or zero) */ X{ X DO dumptime(); X DO DEBUG("myalarm(%d)\n", time); X settimeout = time; /* set for next read */ X X} /* myalarm() */ X X /* dumptime() - print out time in seconds */ X X/* THIS MAY BE SYSTEM DEPENDENT SO IS BASED UPON DEBUG IFDEF */ X#ifdef DUMPALL X#include X#include X#endif X Xstatic void Xdumptime() X{ X#ifdef DUMPALL X time_t seconds; X static time_t base; X X if (base == 0) X { seconds = 0; X base = time(NULL); X } X else X seconds = time(NULL) - base; X X DO DEBUG("[%3d] ", seconds); X X#endif X} /* dumptime() */ END_OF_FILE if test 37002 -ne `wc -c <'1.30/protocol.c'`; then echo shar: \"'1.30/protocol.c'\" unpacked with wrong size! fi # end of '1.30/protocol.c' fi if test -f '1.30/layertitle.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layertitle.c'\" else echo shar: Extracting \"'1.30/layertitle.c'\" \(1291 characters\) sed "s/^X//" >'1.30/layertitle.c' <<'END_OF_FILE' X/* X * Copyright 1993 by Eric C. Rosen X * Copyright 1989-1992 by David W. Trissel X * X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X * X */ X /* All rights reserved. */ X X /* layertitle - utility to specify window title */ X X#include X X#define ESC 0x1b X X /* main() - send string designating layers window title */ X Xmain(ac, av) Xint ac; /* argument count */ Xchar **av; /* argument vector */ X{ X char *ap; /* argument scan pointer */ X X if (--ac != 1) X { fputs("usage: layertitle \"new window title\"\n", stderr); X exit(1); X } X X ap = *++av; /* point to argument string */ X X /* Transmit the title string in the ANSI Private Message format X ** which is X ** ESC '^' message ESC '\' X */ X printf("%c%c%s%c%c", ESC, '^', ap, ESC, '\\'); X X} /* main() */ END_OF_FILE if test 1291 -ne `wc -c <'1.30/layertitle.c'`; then echo shar: \"'1.30/layertitle.c'\" unpacked with wrong size! fi # end of '1.30/layertitle.c' fi if test -f '1.30/layersize.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layersize.c'\" else echo shar: Extracting \"'1.30/layersize.c'\" \(3969 characters\) sed "s/^X//" >'1.30/layersize.c' <<'END_OF_FILE' X/* X * layersize.c X * X * update Unix side with window size information X * X * Copyright (C) 1993 by Eric C. Rosen X * Copyright (C) 1989-1992 by David W. Trissel X * X * All rights reserved. X * X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X * X * X * NOTE: MacLayers WILL AUTOMATICALLY UPDATE THE UNIX SIDE layers PROGRAM X * WHEN YOU RESIZE YOUR WINDOWS. YOU ONLY NEED TO USE THIS PROGRAM X * IF YOU RESIZE YOUR WINDOWS AFTER LOGGING TO A REMOTE HOST, OR IF X * YOU ARE NOT RUNNING layers. SEE DOCUMENTATION FOR DETAILS. X */ X X#include X#include X#include X#ifdef SVR4 X#include X#endif X X Xextern int sys_nerr; Xextern char *sys_errlist[]; X Xstatic void gotsyserr(/* char * */); Xstatic void goterr(/* char * */); Xstatic int getnumber(/* char * */); X X X /* main() - update BSD window size */ X Xmain(ac, av) Xint ac; /* argument count */ Xchar **av; /* argument vector */ X{ X struct winsize wsize; /* window size structure for ioctl() */ X char *ap; /* argument scan pointer */ X int lines; /* new lines value */ X int cols; /* new columns value */ X X if (--ac != 2) X goterr("Missing lines and column options"); X X /* get window size (actually do this to set xpixel and ypixel values) */ X if (ioctl(0, TIOCGWINSZ, &wsize) == -1) X gotsyserr("No window support in host"); /* terminate with message */ X X /* scan looking for -l and -c line and column numeric sizes */ X lines = cols = 0; /* reset values */ X while (ac > 0) X { ap = *++av; /* point to next argument string */ X if (ac-- > 0 && *ap == '-') /* if option ... */ X switch (ap[1]) X { case 'l': /* lines */ X lines = getnumber(&ap[2]); X break; X X case 'c': /* columns */ X cols = getnumber(&ap[2]); X break; X X default: X goterr("Unsupported option"); /* unsupported option */ X break; X X } /* end '-' argument */ X else X goterr("Unsupported parameter"); /* unsupported parameter */ X X } /* end while argument vector scan */ X X /* must have both lines and columns */ X if (lines == 0 || cols == 0) X goterr("Must specify both lines and columns"); X X wsize.ws_col = cols; /* set columns */ X wsize.ws_row = lines; /* set lines */ X /* update the kernel */ X if (ioctl(0, TIOCSWINSZ, &wsize) == -1) X gotsyserr("Failed to update window size"); /* didn't go */ X X} X X X /* goterr() - issue error and terminate */ X Xstatic void Xgoterr(msg) Xchar *msg; /* error message string */ X{ X printf("%s\n", msg); /* send error message to user */ X exit(1); /* terminate with error */ X X} /* goterr() */ X X X /* gotsyserror() - system error return */ X Xstatic void Xgotsyserr(msg) Xchar *msg; /* error string */ X{ X if (errno > 0 && errno < sys_nerr) X printf("%s: %s\n", msg, sys_errlist[errno]); X else X printf("%s: Error %d\n", msg, errno); X X exit(1); /* exit with failure */ X X} /* gotsyserr() */ X X X /* getnumber() - parse option number */ X Xstatic int Xgetnumber(str) Xchar *str; /* start of option string */ X{ X int n; /* number being built */ X X if (str == NULL) X goterr("Invalid numeric in option"); X X /* skip any leading delimiters */ X while (*str && (*str == ' ' || *str == '\t')) X str++; X X for(n=0; *str && *str >= '0' && *str <= '9'; str++) X n = n*10 + *str - '0'; /* add next digit in */ X X /* make sure number terminates legally */ X switch (*str) X { case '\0': X case ' ': X case '\t': X case '\n': X if (n <= 0 || n > 200) X goterr("Number out of range"); X break; /* these are OK */ X X default: X goterr("Invalid numeric in option"); X X } /* end switch */ X X return ( n ); /* return the number */ X X} /* getnumber() */ END_OF_FILE if test 3969 -ne `wc -c <'1.30/layersize.c'`; then echo shar: \"'1.30/layersize.c'\" unpacked with wrong size! fi # end of '1.30/layersize.c' fi if test -f '1.30/macbput.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/macbput.c'\" else echo shar: Extracting \"'1.30/macbput.c'\" \(12175 characters\) sed "s/^X//" >'1.30/macbput.c' <<'END_OF_FILE' X/* X * macbput.c X * X * This is a modified version of Dave Johnson's macput (see Copyright X * below) intended for use with MacLayers v1.20 - v1.30. X * X * Copyright 1993 by Eric C. Rosen X * Copyright 1989-1992 by David W. Trissel X * X */ X X X/* X * (originally macput) -- send file to Macintosh using MacBinary XMODEM protocol X * Dave Johnson, Brown University Computer Science X * X * (c) 1984 Brown University X * may be used but not sold without permission X * X */ X X/* To compile: X cc -O -o macbput macbput.c X (Sun 4.2 BSD) cc -O -DSUNBSD42 -o macbput macbput.c X (System V) cc -O -DSYSV -o macbput macbput.c X X Latest modification 1/93 by Eric Rosen X to be used with MacLayers v1.20 X X 1. inserted pad byte to be compatible with THINK C's word alignment X requirements in header; also added identification character as X temporary hack for version control X X 2. inserted helpful examples in the usage string when no arguments X are given X X X Latest modification 4/27/91 by Trissel- X X 1. Original code was absolutely pathetic recovering from noise on the X line. In many cases noise on the line would cause program to either X hang indefinetly or abort instantly. The code to examine responses X has been enhanced to overcome these limitations. X X X Modification 4/17/91 by Trissel - X X 1. ??? XMODEM block count not fixed in official MacLayers Release??? X Point 4 below claims that it was, however the code obviously does NOT X increment the last block count of the data fork if the data fork is X not an even multiple of 128 bytes in size. X X Modifications 10/20/88 by Trissel - X X 1. General cleanup by removal of unused definitions and headers. X 2. Added #ifdefs to support System V and BSD 4.2 Sun compilation. X 3. Removed ancient Macterminal Beta 0.5X code. X 4. Fixed bad bug where XMODEM block count was not bumped up X after the first fork transfer. X X Dave Trissel X Motorola Inc. X ut-sally!oakhill!davet X X This code is fundamentally from two earlier programmers: X X Jon Hueras X Symantec/THINK Technologies X singer@endor.harvard.edu X X who added 2-Byte CRC capability to code from: X X Dave Johnson X ddj%brown@csnet-relay.arpa X Brown University Computer Science X X who did the initial MacTerminal 1.1 transfer protocol. X*/ X X/* If you have System V define the following: */ X /* #define SYSV */ X X/* Sun BSD 4.2 systems should define the following: */ X /* #define SUNBSD42 */ X X#include X#include X#ifdef _STRICT_BSD X#define SIGTYPE int X#else X#define SIGTYPE void X#endif X#include X#ifdef SYSV X#include X#else X#include X#endif X#include X#include X X#ifdef SUNBSD42 X/* RAW is no longer being found on latest Sun system (??) (Trissel) */ X#define RAW 0x20 X#endif X X#define RECORDBYTES 132 X#define DATABYTES 128 X#define NAMEBYTES 64 X X#define RETRIES 10 X#define ACKTIMO 10 X#define FLUSHTIMO 2 X X#define MAXRECNO 0xff X#define BYTEMASK 0xff X X#define TMO -1 X#define DUP '\000' X#define SOH '\001' X#define EOT '\004' X#define ACK '\006' X#define NAK '\025' X#define CAN '\030' X#define EEF '\032' X#define ESC '\033' X X#define H_NLENOFF 1 X#define H_NAMEOFF 2 X/* 65 <-> 80 is the FInfo structure */ X#define H_TYPEOFF 65 X#define H_AUTHOFF 69 X X#define H_LOCKOFF 81 X#define H_DLENOFF 83 X#define H_RLENOFF 87 X#define H_CTIMOFF 91 X#define H_MTIMOFF 95 X X#define H_OLD_DLENOFF 81 X#define H_OLD_RLENOFF 85 X X#define TEXT 0 X#define DATA 1 X#define RSRC 2 X#define FULL 3 X Xint mode, txtmode; X Xstruct macheader { X char m_name[NAMEBYTES+1]; X char m_type[4]; X char m_author[4]; X long m_datalen; X long m_rsrclen; X long m_createtime; X long m_modifytime; X} mh; X Xstruct filenames { X char f_info[256]; X char f_data[256]; X char f_rsrc[256]; X} files; X Xint recno, crc; Xchar buf[DATABYTES]; X Xchar usage[] = X "macbput v1.20\nusage: \"macbput [-rdu] [-t type] [-c creator] [-n name] filename\"\n"; X Xmain(ac, av) Xint ac; Xchar **av; X{ X void setup_tty(), find_files(), forge_info(), send_file(), reset_tty(); X int send_sync(); X X int n; X char *filename = (char *) NULL; X X if (ac == 1) { X fputs(usage, stderr); X fputs("Eg:\n\tTo send a binary file:\n", stderr); X fputs("\n\t\tmacbput -d filename\n", stderr); X fputs("\n\tTo send a text file:\n", stderr); X fputs("\n\t\tmacbput -u -t TEXT filename\n", stderr); X exit(1); X } X X mode = FULL; X ac--; av++; X while (ac) { X if (av[0][0] == '-') { X switch (av[0][1]) { X case 'r': X mode = RSRC; X strncpy(mh.m_type, "????", 4); X strncpy(mh.m_author, "????", 4); X break; X case 'u': X mode = TEXT; X strncpy(mh.m_type, "TEXT", 4); X strncpy(mh.m_author, "MACA", 4); X break; X case 'd': X mode = DATA; X strncpy(mh.m_type, "????", 4); X strncpy(mh.m_author, "????", 4); X break; X case 'n': X if (ac > 1) { X ac--; av++; X n = strlen(av[0]); X if (n > NAMEBYTES) n = NAMEBYTES; X strncpy(mh.m_name, av[0], n); X mh.m_name[n] = '\0'; X break; X } X else goto bad_usage; X case 't': X if (ac > 1) { X ac--; av++; X strncpy(mh.m_type, av[0], 4); X break; X } X else goto bad_usage; X case 'c': X if (ac > 1) { X ac--; av++; X strncpy(mh.m_author, av[0], 4); X break; X } X else goto bad_usage; X default: Xbad_usage: X fputs(usage, stderr); X exit(1); X } X } X else { X filename = av[0]; X } X ac--; av++; X } X if (!filename) goto bad_usage; X X setup_tty(); X find_files(filename, mode); X if (mode != FULL) X forge_info(); X X if (send_sync()) { X recno = 1; X txtmode = 0; X send_file(files.f_info, 1, '*'); X X if (mode != FULL) X unlink(files.f_info); X X if (mode == TEXT) txtmode++; X send_file(files.f_data, 1, '\0'); X X txtmode = 0; X send_file(files.f_rsrc, 0, '\0'); X } X reset_tty(); X} X Xvoid find_files(filename, mode) Xchar *filename; Xint mode; X{ X SIGTYPE cleanup(); X int n; X struct stat stbuf; X X sprintf(files.f_data, "%s.data", filename); X sprintf(files.f_rsrc, "%s.rsrc", filename); X X if (mode == FULL) { X sprintf(files.f_info, "%s.info", filename); X if (stat(files.f_info, &stbuf) != 0) { X perror(files.f_info); X cleanup(-1); X } X return; X } X else { X strcpy(files.f_info, "#machdrXXXXXX"); X mktemp(files.f_info); X } X X if (mode == RSRC) { X strcpy(files.f_data, "/dev/null"); X if (stat(files.f_rsrc, &stbuf) != 0) { X strcpy(files.f_rsrc, filename); X if (stat(files.f_rsrc, &stbuf) != 0) { X perror(files.f_rsrc); X cleanup(-1); X } X } X mh.m_datalen = 0; X mh.m_rsrclen = stbuf.st_size; X } X else { X strcpy(files.f_rsrc, "/dev/null"); X if (stat(files.f_data, &stbuf) != 0) { X sprintf(files.f_data, "%s.text", filename); X if (stat(files.f_data, &stbuf) != 0) { X strcpy(files.f_data, filename); X if (stat(files.f_data, &stbuf) != 0) { X perror(files.f_data); X cleanup(-1); X } X } X } X mh.m_datalen = stbuf.st_size; X mh.m_rsrclen = 0; X } X X if (mh.m_name[0] == '\0') { X n = strlen(filename); X if (n > NAMEBYTES) n = NAMEBYTES; X strncpy(mh.m_name, filename, n); X mh.m_name[n] = '\0'; X } X} X Xvoid forge_info() X{ X void put4(); X SIGTYPE cleanup(); X X int n; X char *np; X FILE *fp; X X for (np = mh.m_name; *np; np++) X if (*np == '_') *np = ' '; X X buf[H_NLENOFF] = n = np - mh.m_name; X strncpy(buf + H_NAMEOFF, mh.m_name, n); X strncpy(buf + H_TYPEOFF, mh.m_type, 4); X strncpy(buf + H_AUTHOFF, mh.m_author, 4); X put4(buf + H_DLENOFF, mh.m_datalen); X put4(buf + H_RLENOFF, mh.m_rsrclen); X put4(buf + H_CTIMOFF, mh.m_createtime); X put4(buf + H_MTIMOFF, mh.m_modifytime); X fp = fopen(files.f_info, "w"); X if (fp == NULL) { X perror("temp file"); X cleanup(-1); X } X fwrite(buf, 1, DATABYTES, fp); X fclose(fp); X} X Xint send_sync() X{ X void tputc(); X int tgetc(); X int c; X X tputc(ESC); X tputc('b'); X X for (;;) { X X if ((c = tgetc(ACKTIMO)) == TMO) X { X return(0); X } X X if (c == NAK) X { X return(1); X } X X if (c == 'C') { X crc++; X return(1); X } X } X} X Xvoid send_file(fname, more, id) Xchar *fname; Xint more; Xchar id; X{ X void send_rec(), tputc(); X int tgetc(); X SIGTYPE cleanup(); X X register int status, i, n; X FILE *inf; X X inf = fopen(fname, "r"); X if (inf == NULL) { X perror(fname); X cleanup(-1); X } X for (;;) { X n = fread(buf, 1, DATABYTES, inf); X if (id == '*') { X buf[0] = id; X for (i=127; i>65; i--) X buf[i] = buf[i-1]; /* hack */ X } X if (n > 0) { X for (i = 0; i < RETRIES; i++) { X send_rec(buf, DATABYTES); X status = tgetc(ACKTIMO); X if ( status != ACK X && status != NAK X && status != CAN X && status != TMO X && status != EOT X ) X { /* We got unknown response - assume noise on the line X ** and flush it. Treat this as a timeout. X */ X X /* Note: the FLUSHTIMO must be short, otherwise we X ** would flush past the (presumed) noise burst and X ** possibly miss a CAN which would leave the program X ** timing out while the user wonders what happened. X ** (Missing anything else is no big deal since we X ** are going to retry anyway.) X */ X while ((status=tgetc(FLUSHTIMO)) != TMO) X ; X /* leave status == TMO */ X } X X /* exit retry loop if not to resend */ X if (status == ACK || status == EOT || status == CAN) X break; X } X if (status != ACK) { X /* we are to terminate */ X fclose(inf); X cleanup(-1); X /* NOTREACHED */ X } X X /* FIX (d.t.) recno always increments for any block sent out */ X recno++; /* FIX d.t. */ X recno &= MAXRECNO; /* FIX d.t. */ X } X if (n < DATABYTES) { X if (!more) { X tputc(EOT); X tgetc(ACKTIMO); X } X return; X } X } X} X Xvoid send_rec(buf, recsize) Xchar buf[]; Xint recsize; X{ X void tputc(), tputrec(); X int calcrc(); X X int i, cksum = 0; X char *bp; X X if (txtmode || !crc) { X bp = buf; X for (i = 0; i < recsize; i++, bp++) { X if (txtmode && *bp == '\n') X *bp = '\r'; X cksum += *bp; X } X } X X if (crc) X cksum = calcrc(buf, recsize); X X tputc(SOH); X tputc((char) recno); X tputc((char) (MAXRECNO - recno)); X tputrec(buf, recsize); X X if (crc) { X tputc((char) (cksum >> 8)); X tputc((char) cksum); X } else X tputc((char) cksum); X} X Xstatic int ttyfd; Xstatic FILE *ttyf; Xstatic jmp_buf timobuf; X Xint tgetc(timeout) Xint timeout; X{ X int c; X X if (setjmp(timobuf)) X return TMO; X X alarm(timeout); X c = getc(ttyf); X alarm(0); X X if (c == -1) /* probably hung up or logged off */ X return EOT; X else X return c & BYTEMASK; X} X Xvoid tputrec(buf, count) Xchar *buf; Xint count; X{ X write(ttyfd, buf, count); X} X Xvoid tputc(c) Xchar c; X{ X write(ttyfd, &c, 1); X} X XSIGTYPE timedout() X{ X#ifndef NeXT X signal(SIGALRM, timedout); /* for pre-4.2 systems */ X#endif X longjmp(timobuf, 1); X} X X#ifdef SYSV Xstatic struct termio otty, ntty; X#else Xstatic struct sgttyb otty, ntty; X#endif X X/* should turn messages off */ X Xvoid setup_tty() X{ X SIGTYPE cleanup(); X SIGTYPE timedout(); X X ttyf = stdin; X ttyfd = fileno(stdout); X#ifdef SYSV X ioctl(ttyfd, TCGETA, &otty); /* get termio info */ X#else X ioctl(ttyfd, TIOCGETP, &otty); X#endif X signal(SIGHUP, cleanup); X signal(SIGINT, cleanup); X signal(SIGQUIT, cleanup); X signal(SIGTERM, cleanup); X signal(SIGALRM, timedout); X ntty = otty; X#ifdef SYSV X ntty.c_iflag = BRKINT; /* only interrupt on break */ X ntty.c_oflag = 0; /* no output processing */ X ntty.c_cflag |= CS8; /* 8 bit characters */ X ntty.c_lflag = 0; /* no echoing */ X ntty.c_cc[VEOF] = 1; /* "MIN" minimum chars before input */ X ntty.c_cc[VEOL] = 1; /* "TIME" maximum .1 secs before feed */ X ioctl(ttyfd, TCSETAF, &ntty); /* set mode and flush input */ X#else X ntty.sg_flags = RAW; X ioctl(ttyfd, TIOCSETP, &ntty); X#endif X} X Xvoid reset_tty() X{ X if (ttyf != NULL) { X#ifdef SYSV X ioctl(ttyfd, TCSETAF, &otty); /* reset after output drains */ X#else X sleep (5); /* wait for output to drain */ X ioctl(ttyfd, TIOCSETP, &otty); X#endif X } X} X XSIGTYPE cleanup(sig) Xint sig; X{ X reset_tty(); X exit(sig); X} X Xvoid put4(bp, value) Xchar *bp; Xlong value; X{ X register int i, c; X X for (i = 0; i < 4; i++) { X c = (value >> 24) & BYTEMASK; X value <<= 8; X *bp++ = c; X } X} X Xint calcrc(ptr, count) Xchar *ptr; Xint count; X { X int crc, i; X X crc = 0; X while (--count >= 0) { X crc ^= ((int) *ptr++) << 8; X for (i = 0; i < 8; ++i) X if (crc & 0x8000) X crc = crc << 1 ^ 0x1021; X else X crc <<= 1; X } X return (crc & 0xFFFF); X } END_OF_FILE if test 12175 -ne `wc -c <'1.30/macbput.c'`; then echo shar: \"'1.30/macbput.c'\" unpacked with wrong size! fi # end of '1.30/macbput.c' fi if test -f '1.30/layers.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layers.h'\" else echo shar: Extracting \"'1.30/layers.h'\" \(2282 characters\) sed "s/^X//" >'1.30/layers.h' <<'END_OF_FILE' X/* Copyright (C) 1989 by David W. Trissel X * X * Not derived from licensed software. X * X * Permission is granted to freely use, copy, modify, and redistribute X * this software, provided that no attempt is made to gain profit from it, X * the author is not construed to be liable for any results of using the X * software, alterations are clearly marked as such, and this notice is X * not modified. X * X */ X X#define HOSTPROTOCOL 2 /* current host protocol */ X X#define MAXPCHAN 7 /* maximum layers supported */ X X#define MAXSTR 200 X#define MAXARGS 64 X#define MAXLINE 1024 X#define IOSIZE 800 /* data gulp handling size */ X X/* WARNING - packet sizes must be insured to never match the ESCAPE char */ X#define ESCAPE '}' /* datalink escape character */ X X#define DO if (Dflag) /* for debugging */ X X/* miscelaneous common data */ Xextern int Dflag; /* debug dump indicator flag */ Xextern int Clientversion; /* client version number */ Xextern int Protocollevel; /* effective protocol level */ Xextern int Clientlevel; /* client's protocol level */ X X/* Shape structure passed between MacLayers and ourselves */ Xstruct Shape X{ short worigv; /* verical window bit origin */ X short worigh; /* horizontal window bit origin */ X short wlines; /* window height */ X short wchars; /* window width */ X short wfont; /* window font size */ X short wattr; /* window attributes */ X}; X X#define Wa_shell 0x01 /* window is a shell */ X X X /* The following modules define the complete protocol/server interface */ X X /* layers.c */ X Xextern void FQuit(/* exitcode */); Xextern void ReceiveQuit(); Xextern void ReceiveNew(/* chanid, shape */); Xextern void ReceiveDelete(/* chanid */); Xextern void ReceiveSignal(/* chanid, signal */); Xextern void ReceiveData(/* chanid, buff, cnt */); Xextern void ReceiveReshape(/*chanid, shape */); Xextern void DEBUG(/* format, arg1, arg2, arg3, arg4 */); X X /* protocol.c */ X Xextern int InitLink(); Xextern int TopChannel(); Xextern int SendNew(/* shape */); Xextern void SendTitle(/* chan, buff, cnt */); Xextern void SendDelete(/* chan */); Xextern void SendQuit(); Xextern void SendReshape(/* chan, shape */); Xextern void SendData(/* chan, buff, cnt */); Xextern void ProcessStreamin(); END_OF_FILE if test 2282 -ne `wc -c <'1.30/layers.h'`; then echo shar: \"'1.30/layers.h'\" unpacked with wrong size! fi # end of '1.30/layers.h' fi if test -f '1.30/macbput.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/macbput.h'\" else echo shar: Extracting \"'1.30/macbput.h'\" \(3151 characters\) sed "s/^X//" >'1.30/macbput.h' <<'END_OF_FILE' X/** X*** Copyright (C) 1991 by David W. Trissel X*** X*** Not derived from licensed software. X*** X*** Permission is granted to freely use, copy, modify, and redistribute X*** this software, provided that no attempt is made to gain profit from it, X*** the author is not construed to be liable for any results of using the X*** software, alterations are clearly marked as such, and this notice is X*** not modified. X*** X X#define RECORDBYTES 132 /* complete XMODEM block length */ X#define DATABYTES 128 /* data portion of block length */ X#define NAMEBYTES 63 /* max file name size in info block */ X X#define RETRIES 10 /* max number of error retries */ X#define ACKTIMO 10 /* seconds timeout waiting for ACK */ X#define FLUSHTIMO 2 /* Flush timeout when invalid response X ** recieved, must be very short. Note: X ** a one (1) may not work because timer X ** will trip between 0 and 1 sec. */ X X#define MAXRECNO 0xff /* top modulo record number */ X#define BYTEMASK 0xff /* single byte mask for integers */ X X#define TMO -1 /* timeout function return value */ X#define SOH 0x01 /* ANSI Start Of Header */ X#define EOT 0x04 /* ANSI End Of Transmission */ X#define ACK 0x06 /* ANSI positive ACKnowledge */ X#define NAK 0x15 /* ANSI Negative AcKnowledge */ X#define CAN 0x18 /* ANSI CANcel */ X#define ESC 0x1b /* ANSI ESCape */ X X /* Definition of the 128 byte Mac file info record */ X#define H_VEROFF 0 /* Mac OS only supports version zero */ X#define H_NLENOFF 1 /* Mac file name length (1..63) */ X#define H_NAMEOFF 2 /* Mac file name */ X /* 65 <-> 80 is the FInfo structure */ X#define H_TYPEOFF 65 /* file type */ X#define H_AUTHOFF 69 /* file application owner */ X#define H_FDRFLG 73 /* first finder flag */ X#define H_ZERO1 74 /* (should be zero) */ X#define H_WVRT 75 /* folder vertical position */ X#define H_WHRZ 77 /* folder horizontal position */ X#define H_FOLDRID 79 /* folder ID */ X#define H_PROT 81 /* file protected bit (0x01) */ X#define H_ZERO2 82 /* (should be zero) */ X#define H_DLENOFF 83 /* data fork size */ X#define H_RLENOFF 87 /* resource fork size */ X#define H_CTIMOFF 91 /* file creation time */ X#define H_MTIMOFF 95 /* file last time modified time */ X#define H_FDRINFO 99 /* Finder word */ X#define H_FDRFLG2 101 /* second Finder flags */ X#define H_ZERO3 102 /* 15 bytes (should be zero) */ X#define H_UNPKSZ 116 /* hint for unpacking size (unused) */ X#define H_HDR2 120 /* info header size (unused) */ X#define H_UPBIIVER 122 /* highest MacBin II version (unused) */ X#define H_MINBIIVER 123 /* minimum MacBin II version (unused) */ X#define H_CRC 124 /* MacBin II CRC (unused) */ X Xenum {TEXT, DATA, RSRC, FULL} mode; X X#define LOGLO (Log > 1) X#define LOGMED (Log > 2) X#define LOGHI (Log > 3) X X/* C library routines */ Xextern char *getenv(); X Xstruct Macheader X { char m_name[NAMEBYTES+1]; X char m_type[4]; X char m_author[4]; X long m_datalen; X long m_rsrclen; X long m_createtime; X long m_modifytime; X } Mh; X Xstruct Filenames X { char f_info[256]; X char f_data[256]; X char f_rsrc[256]; X } Files; END_OF_FILE if test 3151 -ne `wc -c <'1.30/macbput.h'`; then echo shar: \"'1.30/macbput.h'\" unpacked with wrong size! fi # end of '1.30/macbput.h' fi if test -f '1.30/layers.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layers.1'\" else echo shar: Extracting \"'1.30/layers.1'\" \(8907 characters\) sed "s/^X//" >'1.30/layers.1' <<'END_OF_FILE' X.TH LAYERS l "17 May 1993" "MacLayers" "MacLayers" X.SH NAME X.PP Xlayers \- MacLayers Multiwindow Terminal Emulator for Unix X.SH SYNOPSIS X.LP Xlayers [options] [command] X.SH WARNING XThe information in this man page concentrates specifically on the XUNIX side component of MacLayers, and includes only an extract of the XMacintosh-side XMacLayers Manual, which is included with the Macintosh application, XPlease consult Xthe Macintosh MacLayers Manual for more complete information about Xthe Macintosh side of MacLayers. X.SH DESCRIPTION X.PP XMacLayers provides multi-window capability for a Macintosh (MacPlus or better Xrunning System 6.0.x or System 7) Xconnected to a host UNIX(TM) system with sockets support. Each window may be Xassociated with a shell, login to a different host, or an individual Xcommand. Complete facilities are available for controlling the window Xand the associated host processes attached thereto. X.SH OPTIONS XOptions must be separated. The following are intended to be used Xalone and will not start layers mode, regardless of the presence of Xother command-line options: X.TP X.B \-v Xdisplays current version information X.TP X.B \-help Xdisplays a one-line synopsis of all X.I layers Xcommand line arguments; will not start layers mode X.PP XThe following options can be used to modify the behavoir of X.I layers Xwhen it starts layers mode, or of the new shell window X.I layers Xwill create when executed while already operating under layers mode. X.TP X.B \-l Xcauses new shell to be a login shell, if layers has been compiled to Xnot login new shells by default; otherwise, causes new shell to not Xbe a login shell. X.TP X.B \-u Xexplicitly forces new shell to not be logged in X.TP X.B \-g wwxhh Xallows user to size the new shell; see next option below for details: X.TP X.B \-g wwxhh+xx+yy Xallows user to both place and size the new shell; window is Xstarted with width ww characters and height hh lines; if xx and yy Xare present, window is placed with upper-left corner at (xx,yy) on Xthe Macintosh screen; note that either xx or yy may be negative (useful Xon systems with multiple monitors). Beware: no sanity checking of Xthe window size or position is performed. X.PP XThe following options are not likely to be very useful to the typical Xuser: X.TP X.B \-d Xstarts X.I layers Xrunning in debugging dump mode; a file X.I layers.dump Xis created in the current directory (if it does not already exist) Xand internal debugging messages continuously appended; useful for Xdebugging situations where layers mode fails to startup properly, Xbut otherwise not too interesting; severely adversely affects performance Xand gobbles disk space. X.TP X.B \-m Xforces X.I layers Xto run as a server (master) and not as a client (slave) X.TP X.B \-f Xenables flow control; obsolete X.TP X.B \-n Xdisables flow control; obsolete X.PP XCommand-line arguments following valid options are interpreted as a shell Xcommand-line to execute. XUNIX host. X.SH MACLAYERS OPERATION X.PP XTo use MacLayers, you must have the MacLayers application running on your XMacintosh, as well as the UNIX side X.I layers Xprogram described herein. X XThe Maclayers application on the Macintosh starts up as a garden variety Xhost-to-terminal vt-100 emulator. (As such you can run it with any Xhost, not just a UNIX machine.) Baud rate and other configurations are set Xby selections in the Control Menu. X.PP XOnce connected to your UNIX host, enter the X.I layers Xcommand to the UNIX host using no options or parameters Xto start the layers protocol. The initial terminal window will be closed Xand replaced with a layers protocol window. A shell is run in this Xwindow, either /bin/sh or the shell indicated by your $SHELL variable. X.PP XYou can start a new shell layer (with its own separate window) Xby picking "New" on the Layers menu. You can Xalso start a new layer window by issuing the X.I layers Xcommand to a Xshell layer window. If you use no operands, then the new layer window Xwill be a shell. However, you can specify any command you wish by Xsimply adding it as a parameter. Examples: "layers vi testfile.c", X"layers telnet earth." X.PP XIf you are specifying a shell then you can also elect to have it be a Xlogin shell by adding a -l option. This allows broadcast/write/talk Xcapabilities for that window. The initial layer window shell defaults Xto a login shell. X.PP XWhen a layer process group terminates, its window is automatically closed. XMacLayers exits layers mode when the last (or only) layer window is closed. XYou may also use the Layers Menu "Shutdown" to terminate layers mode. XYou cannot quit the MacLayers application while in layers mode but must XShutdown the multi-window mode first. X.PP XYou can abort host X.I layers Xby using the Control Menu "Abort Host Layers" Xitem which is always available. This may be necessary if your Macintosh Xloses contact with the host and you restart the MacLayers application at Xwhich time the host would still be in multi-window layers mode while Xthe application would not. If the MacLayers application terminates due Xto a non-recoverable problem, it will always issue an order to terminate Xlayers mode on the host before returning to the Finder. X.SH DOWNLOADING X.PP XMacLayers has an admittedly primitive Xdownload facility for downloading text, binary, Xand MacBinary files (the X.I macbput Xcommand). Straight Xvanilla XMODEM is not supported. XOnly one window can be doing a X.I macbput Xdownload at any one time. XDownloading does not effect any other MacLayers operations so you can Xfreely use any other windows or applications (with MultiFinder) while Xa download is in progress. Remember though that the topmost window Xreceives the highest priority data transfer from the host. So for the Xfastest downloading keep the download layer window the active window. X.SH LAYERSRC XUsers can optionally store additional layer windows X(to be automatically opened when layers-mode is started) in a file called X.I .layersrc Xin their home directory. If a line in this file begins with '#', it Xis treated as a comment line and ignored; otherwise, it must conform Xto the following form: X.PP Xlayer [ [flag [arg]] [flag [arg]] ... [flag [arg]] ] X XValid flags are described below; flags can be abbreviated to their Xfirst characters: X.TP X.B \-login XTakes no argument; specifies that the layer should be a login window. X.TP X.B \-geometry XTakes as argument a string of the form wwxhh or wwxhh+xx+yy as Xdescribed earlier under OPTIONS Xfor the \-g option; sizes the window to ww characters by hh lines Xand places it at (xx,yy) on the Macintosh host screen. X.TP X.B \-title XTakes as argument a string and uses string as window title for new Xlayer. X.TP X.B \-exec XTakes as argument a command followed by a series of optional arguments Xto the command; specifies that the new layer should run the program Xwith any arguments provided instead of the default shell. Note: this Xflag should always be the last of any series of flags provided. X.PP XAs an example of some entries in a X.I .layersrc Xfile, consider: X X.nf X# weird window, named 'Purple', running mail program Xlayer -geometry 56x9+2+130 -t Purple -exec mail X.fi X X.SH FILES X X /tmp/layers/ Directory created by X.I layers X /tmp/layers//host.tty Socket Created by X.I layers X $HOME/.layersrc User window definitions X X.SH AUTHORS XEric Rosen and Dave Trissel X.SH BUGS AND CAVEATS X.PP X.TP X.B * XThe shell TERM variable must have the same value in your Xlayer shells as it does when you initially start X.I layers Xup. If you set the BSD shell TERMCAP variable, then that variable must Xbe set in your .login file. It may not be changed to something Xdifferent in .cshrc. X.TP X.B * XThe X.I layers Xcommand will not properly work when being issued from a Xremote login into the same machine which is already running the Xinitial X.I layers Xstartup command. X.TP X.B * XThere is currently no file upload facility. X.TP X.B * XLayers must be installed as set-uid with owner root in order Xto be able to correctly change the owner of the tty device Xfile for each window. On some systems, special permission Xmay also be required to write the file "/etc/utmp". X.TP X.B * XOn many System V platforms, /etc/utmp logging is broken. X.SH SEE ALSO X.PP Xlayertitle, layersize, macbput X.PP XThe MacLayers program is Xcompletely described in the MacLayers Manual that accompanies the XMacintosh side. Please read this for far more information than is Xcontained here. X.PP XManual page courtesy of Peter Newton. X.SH DISCLAIMER X.PP XPermissiom is granted to freely use, copy, modify, and redistribute Xthis software, provided that no attempt is made to gain profit from it, Xthe authors are not construed to be liable for any results of using the Xsoftware, alterations are clearly marked as such, and this notice is Xnot modified. X.PP XUNIX(TM) is a registered trademark of American Telephone and Telegraph. XMacintosh is a trademark of McIntosh Laboratories and is licensed to Apple XComputer. END_OF_FILE if test 8907 -ne `wc -c <'1.30/layers.1'`; then echo shar: \"'1.30/layers.1'\" unpacked with wrong size! fi # end of '1.30/layers.1' fi if test -f '1.30/layertitle.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layertitle.1'\" else echo shar: Extracting \"'1.30/layertitle.1'\" \(1189 characters\) sed "s/^X//" >'1.30/layertitle.1' <<'END_OF_FILE' X.TH LAYERTITLE l "17 May 1993" "MacLayers" "MacLayers" X.SH NAME X.PP Xlayertitle \- MacLayers Multiwindow Terminal Emulator Utility X.SH SYNOPSIS X.LP Xlayertitle [window-title] X.SH DESCRIPTION X.PP XThe X.I layertitle Xcommand allows you to change the window title of a MacLayers window Xon your Macintosh host from the UNIX command line. X.SH ARGUMENTS XOne required argument is defined. The argument is taken to be Xthe new window title and sent to the MacLayers application. X.SH AUTHOR XDave Trissel X.SH SEE ALSO X.PP Xlayers, layersize, macbput X.PP XThe MacLayers program is Xcompletely described in the MacLayers Manual that accompanies the XMacintosh side. Please read this for far more information than is Xcontained here. X.SH DISCLAIMER X.PP XPermissiom is granted to freely use, copy, modify, and redistribute Xthis software, provided that no attempt is made to gain profit from it, Xthe authors are not construed to be liable for any results of using the Xsoftware, alterations are clearly marked as such, and this notice is Xnot modified. X.PP XUNIX(TM) is a registered trademark of American Telephone and Telegraph. XMacintosh is a trademark of McIntosh Laboratories and is licensed to Apple XComputer. END_OF_FILE if test 1189 -ne `wc -c <'1.30/layertitle.1'`; then echo shar: \"'1.30/layertitle.1'\" unpacked with wrong size! fi # end of '1.30/layertitle.1' fi if test -f '1.30/layersize.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layersize.1'\" else echo shar: Extracting \"'1.30/layersize.1'\" \(1696 characters\) sed "s/^X//" >'1.30/layersize.1' <<'END_OF_FILE' X.TH LAYERSIZE l "17 May 1993" "MacLayers" "MacLayers" X.SH NAME X.PP Xlayersize \- MacLayers Multiwindow Terminal Emulator Utility X.SH SYNOPSIS X.LP Xlayersize [-l numlines -c numcols] X.SH DESCRIPTION X.PP XThe X.I layersize Xcommand allows you to inform hosts to which you are remotely connected Xto through a MacLayers window (for example, through X.I rlogin Xor X.I telnet X) of your window size. You only need to use X.I layersize Xif you are changing the window size of a shell which is not Xrunning on the same host which is running the X.I layers Xprogram, or if you have remotely logged in to that host. X.PP XIt is recommended that users use the MacLayers Control menu Xpicks, "Inform host of window size", to run the X.I layersize Xcommand. X.SH ARGUMENTS XThe arguments define the number of lines and number of columns Xof the current MacLayers window. These values are supplied by Xthe "Inform host of window size" menu selections under the XMacLayers' Control menu on the Macintosh host. X.SH AUTHOR XDave Trissel X.SH SEE ALSO X.PP Xlayers, layertitle, macbput X.PP XThe MacLayers program is Xcompletely described in the MacLayers Manual that accompanies the XMacintosh side. Please read this for far more information than is Xcontained here. X.SH DISCLAIMER X.PP XPermissiom is granted to freely use, copy, modify, and redistribute Xthis software, provided that no attempt is made to gain profit from it, Xthe authors are not construed to be liable for any results of using the Xsoftware, alterations are clearly marked as such, and this notice is Xnot modified. X.PP XUNIX(TM) is a registered trademark of American Telephone and Telegraph. XMacintosh is a trademark of McIntosh Laboratories and is licensed to Apple XComputer. END_OF_FILE if test 1696 -ne `wc -c <'1.30/layersize.1'`; then echo shar: \"'1.30/layersize.1'\" unpacked with wrong size! fi # end of '1.30/layersize.1' fi if test -f '1.30/macbput.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/macbput.1'\" else echo shar: Extracting \"'1.30/macbput.1'\" \(2849 characters\) sed "s/^X//" >'1.30/macbput.1' <<'END_OF_FILE' X.TH MACBPUT local "17 Mar 1990" X.UC 4 X.SH NAME Xmacbput \- send file to macintosh via macbinary protocol X.SH SYNOPSIS X.B macbput Xfile X.br X.B macbput X[ X.B \-rdu X] file X[ X.B \-t Xtype X] X[ X.B \-a Xowner X] X[ X.B \-n Xname X] X.SH DESCRIPTION X.I Macbput Xsends a file to a Macintosh running MacTerminal. XThe File Transfer Protocol settings should specify the "MacBinary" Xtransfer method. XMacbput will also work with other communications programs for the Mac X(e.g. MacLayers); Xconsult the user's manual for your macbinary-compatable communications Xprogram for more information. XThis manual page will only address the use of macbput with MacTerminal. X.PP XTo use this program, log into the unix system using MacTerminal, Xand run macbput specifying the desired options and one file to be sent. XIf MacTerminal is properly configured, it will recognize that a file Xis arriving on the serial line and put up an indicator showing how Xmuch of the file has been sent. XSeveral Control-X's may be used to force macbput Xto give up if the transfer fails. X.PP XIf none of the X.B \-rdu Xflags are specified, X.I macbput Xsends three unix files to the Mac: X.IB file .info , X.IB file .data , Xand X.IB file .rsrc . XThese specify the three parts of one Mac file: the .data file Xbecomes the data fork, the .rsrc file becomes the resource fork, Xand the .info file specifies the sizes of the two forks, as well Xas the file name, file type, creation date, and other information. XThis is useful for returning files to the Mac which were stored Xusing macget or macbget. X.PP XThe X.B \-r Xflag specifies X.I resource Xmode. XEither X.IB file .rsrc Xor X.I file Xwill be sent to the Mac, along with a forged X.B .info Xfile and an empty X.B .data Xfile. XThe file sent becomes the resource fork of the Mac file. X.PP XThe X.B \-d Xflag specifies X.I data Xmode. XEither X.IB file .data X, X.IB file .text Xor X.I file Xwill be sent to the Mac, along with a forged X.B .info Xfile and an empty X.B .rsrc Xfile. XThe file sent becomes the data fork of the Mac file. X.PP XThe X.B \-u Xflag requests X.I unix Xmode, which is the same as X.I data Xmode except unix newline characters are converted Xinto carriage returns. XHuman-readable unix text files sent to the Mac using this option Xwill be compatible with applications which expect "text only" files. X.PP XThe remaining options serve to override the default Xfile type, owner, and file name to be used on the Mac. XThe default type and owner for X.I resource Xand X.I data Xmode defaults are "????", "????", and X.I unix Xmode defaults are "TEXT" and "MACA". X.SH SEE ALSO Xmacput(local), macget(local), xbin(local), macbin(local), mcvert(local) X.SH BUGS XThe macbinary protocol may not work over flow controlled communication lines, Xsome terminal concentrators, or when using rlogin. X.SH FEATURES XProperly initializes the Creation Date. X.SH AUTHOR XOriginal base code: Dave Johnson, Brown 7/31/84 END_OF_FILE if test 2849 -ne `wc -c <'1.30/macbput.1'`; then echo shar: \"'1.30/macbput.1'\" unpacked with wrong size! fi # end of '1.30/macbput.1' fi if test -f '1.30/MacLayers.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/MacLayers.doc'\" else echo shar: Extracting \"'1.30/MacLayers.doc'\" \(1959 characters\) sed "s/^X//" >'1.30/MacLayers.doc' <<'END_OF_FILE' X X MacLayers X Version 1.30 --- 17 May, 1993 X X MacLayers provides multi-window capability for a Macintosh connected X to a host UNIX(TM) system with sockets support. Each window may be X associated with a shell, login to a different host, or an individual X command. Complete facilities are available for controlling the window X and the associated host processes attached thereto. X X X A Note About Distribution X X MacLayers is usually distributed in two parts: a BinHex or MacBinary X file that comprises the Macintosh side (and includes the MacLayers X application along with the MacLayers Manual), as well as a UNIX X shar archive that includes the UNIX side source and this file. X X The latest version can always be retrieved via anonymous FTP from X rascal.ics.utexas.edu in the directory mac/communications/MacLayers. X X X What You Need To Run MacLayers X X 1) A Unix host which supports the sockets protocol. X X 2) A Macintosh with more than 128k of RAM and 64K ROM with a connection to X the host. X X 3) The MacLayers Macintosh application provided with this package. X X 4) For System 7 users, the MacLayers keyboard layout file which should be X installed into the system. X X 5) The Unix host server command 'layers' provided with this package. X X 6) If you want to resize windows which are logged into a second BSD X machine or resize windows on a BSD machine running in non-layers X mode then you need the 'layersize' command provided with this package. X X 7) If you want to specify window titles on your own (such as to indicate X your current directory or other such information) you need the Unix X 'layertitle' command provided with this package. X XExplicit and complete documentation is provided in the MacLayers Manual Xwhich is distributed with the Macintosh application. END_OF_FILE if test 1959 -ne `wc -c <'1.30/MacLayers.doc'`; then echo shar: \"'1.30/MacLayers.doc'\" unpacked with wrong size! fi # end of '1.30/MacLayers.doc' fi if test -f '1.30/layersrc.doc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layersrc.doc'\" else echo shar: Extracting \"'1.30/layersrc.doc'\" \(2281 characters\) sed "s/^X//" >'1.30/layersrc.doc' <<'END_OF_FILE' XHere is a quick summary of the .layersrc capability. See the example Xfile 'layersrc' and the Macintosh side MacLayers Manual for more info. X XThe following line can be specified (multiple times) in a .layersrc file Xsituated in the user's home directory to direct automatic startup of Xshells and windows when layers mode is started: X X layer [ [flag [arg]] [flag [arg]] ... [flag [arg]] ] X X Creates a new window layer with default preferences; attributes X can be overriden with zero or more of the following flags: X X eg: X X layer -geometry 56x9+2+130 -t Purple X X will create a new window layer running the default shell with X width 56 characters and height 9 characters, positioned with its X top-left corner at (2,130) on the Macintosh host screen. The layer X will not be logged in, but it will be titled "Purple". X X FLAG LONG FLAG ARGS NOTES X ---- ----------- ---- ----- X -l -login makes window a login window X X -g -geometry wwxhh sizes window to be ww columns X wide by hh lines high X X wwxhh+xx+yy sizes window (see above) and X also places it at (+xx,+yy) X on the host Macintosh screen; X note that -xx or -yy are also X valid (but refer to (0,0) X X -t -title string sets window title to the first X twenty-nine characters of X string X X -e -exec command [args] specifies program and any X command line arguments to X be run in the layer; because X all remaining tokens are taken X as command line arguments for X command, this must always be X the last flag provided END_OF_FILE if test 2281 -ne `wc -c <'1.30/layersrc.doc'`; then echo shar: \"'1.30/layersrc.doc'\" unpacked with wrong size! fi # end of '1.30/layersrc.doc' fi if test -f '1.30/README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/README'\" else echo shar: Extracting \"'1.30/README'\" \(446 characters\) sed "s/^X//" >'1.30/README' <<'END_OF_FILE' XThe easiest way to compile MacLayers is to issue the command X X % make X Xand follow the instructions provided for your system. For example, Xto compile MacLayers on a SunOS 4.1 or later platform, you would Xtype: X X % make sun X XMany new systems are supported. However, if your system is not Xlisted, try experimenting. Support for System V and SVR4 platforms Xhas been greatly improved, thanks to the members of the MacLayers Xbeta-testing team. X X--Eric END_OF_FILE if test 446 -ne `wc -c <'1.30/README'`; then echo shar: \"'1.30/README'\" unpacked with wrong size! fi # end of '1.30/README' fi if test -f '1.30/layersrc' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/layersrc'\" else echo shar: Extracting \"'1.30/layersrc'\" \(719 characters\) sed "s/^X//" >'1.30/layersrc' <<'END_OF_FILE' X# X# .layersrc X# X# This file should reside in your home directory and be called .layersrc X# X# If it does not exist, only the normal initial layers layer will be X# opened. X# X# If it does exist, the layers specified in this file are opened X# in addition to the normal initial layers layer. X# X# Any line beginning with the '#' symbol is treated as a comment and X# and ignored. X# Xlayer -geometry 80x25+0+146 -title 80x25 X X# X# The following layers live on a 19" monitor placed to the X# right of the default 13" 640x480 monitor. X# X# X# layer -geometry 80x46+706-60 -title BigScreen X# layer -geometry 80x46+1212-60 -title OtherBigScreen X# layer -geometry 80x25+706+428 X# layer -geometry 80x46+1212-60 -exec trn -a -M END_OF_FILE if test 719 -ne `wc -c <'1.30/layersrc'`; then echo shar: \"'1.30/layersrc'\" unpacked with wrong size! fi # end of '1.30/layersrc' fi if test -f '1.30/macmouse.el' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/macmouse.el'\" else echo shar: Extracting \"'1.30/macmouse.el'\" \(9279 characters\) sed "s/^X//" >'1.30/macmouse.el' <<'END_OF_FILE' X;;; macmouse.el (Version: 2.0) X X;;; Copyright (C) Gregory S. Lauer (glauer@bbn), 1985. X;;; Please send suggestions and corrections to the above address. X;;; X;;; This file contains macmouse, a GNU Emacs mouse package for UW. X X X;; X;; GNU Emacs is distributed in the hope that it will be useful, X;; but without any warranty. No author or distributor X;; accepts responsibility to anyone for the consequences of using it X;; or for whether it serves any particular purpose or works at all, X;; unless he says so in writing. X X;; Everyone is granted permission to copy, modify and redistribute X;; GNU Emacs, but only under the conditions described in the X;; document "GNU Emacs copying permission notice". An exact copy X;; of the document is supposed to have been given to you along with X;; GNU Emacs so that you can know how you may redistribute it all. X;; It should be in a file named COPYING. Among other things, the X;; copyright notice and this notice must be preserved on all copies. X X X;;; Original version for Gosling emacs by Chris Kent, Purdue University 1985. X;;; Modified by Gregory Lauer, BBN, Novemeber 1985. X; X; X; X; Macmouse provides the following features: X; Up or down mouse button in a window selects that window X; X; A scroll bar/thumbing area for each window with the following features: X; the mode lines are horizontal scroll bars X; (running from rightmost column to under leftmost column) X; the unused right window bar and the dividing lines between X; windows are vertical scroll bars X; (running from top of window THRU modeline X; for vertical scroll bars: X; click at line 1 does previous page X; click at last line does next page X; click anywhere else "thumbs" to the relative portion of the buffer. X; shift-click at line 1 scrolls one line down X; shift-click at last line scrolls one line up X; shift-click elsewhere moves line to top of window X; option-shift-click elsewhere moves line to bottom of window X; for horizontal scroll bars: X; click at column 1 does scroll right one window width X; click at last column does scroll left one window width X; click anywhere else moves to that "percent" of the buffer width X; shift-click at column 1 scrolls one column right X; shift-click at last column scrolls one column left X; shift-click elsewhere moves column to right of window X; option-shift-click elsewhere moves column to left of window X; X; There is also basic positioning and kill-buffer support: X; click in a buffer moves dot there and selects that buffer X; drag copies the dragged region to the kill buffer X; shift-drag deletes the dragged region to the kill buffer X; X; It is possible to use the scrolling and thumbing area to make the region X; larger than a single screen; just click, scroll, release. Make sure X; that the last scroll is just a down event; the up must be in the buffer. X; The last mouse position is remembered for each different buffer (not X; window), and thus you can start a drag in one buffer, select another, X; go back to the first buffer, etc. X; X; option-click yanks from the kill buffer X; option-shift-click similarly yanks from a named buffer. X; X X(defconst mouse-max-x 95 "Maximum UW column returned on mouse click") X(defconst mouse-max-y 95 "Maximum UW row returned on mouse click") X X(make-variable-buffer-local 'mouse-last-x) ; x of last event X(set-default 'mouse-last-x 0) X X(make-variable-buffer-local 'mouse-last-y) ; y of last event X(set-default 'mouse-last-y 0) X X(make-variable-buffer-local 'mouse-last-b) ; buttons at last event X(set-default 'mouse-last-b 0) X X(make-variable-buffer-local 'mouse-last-dot) ; dot after last event X(set-default 'mouse-last-dot 0) X X(make-variable-buffer-local 'scrolling-p) X(set-default 'scrolling-p nil) X X(defun move-mac-cursor () X (interactive) X (let (savest b x y up down lock shift option command) X (setq savest stack-trace-on-error) X (setq stack-trace-on-error nil) X ; decode everything X (setq y (- (read-char) 32)) X (setq x (- (read-char) 32)) X (setq b (- (read-char) 32)) X (setq command (< 0 (logand b 1))) ; command key X (setq shift (< 0 (logand b 2))) ; shift X (setq lock (< 0 (logand b 4))) ; caps-lock X (setq option (< 0 (logand b 8))) ; option X (setq down (< 0 (logand b 16))) ; mouse down X (setq up (< 0 (logand b 32))) ; mouse up X (condition-case () X (progn X (select-window-containing-x-and-y x y) ; side-effect sets scrolling-p X (if scrolling-p X (mouse-scroll-region b x y) X (progn X (move-to-window-x-y x y) ; move cursor to mouse-dot always X (if down (setq mouse-last-dot (dot))) X (mouse-edit-action)))) X (error (message "Click not in selectable window") X (sit-for 1) X (message ""))) X (setq stack-trace-on-error savest) X (if down X (progn X (setq mouse-last-x x) X (setq mouse-last-y y) X (setq mouse-last-b b)) X (progn X (setq mouse-last-x 0) X (setq mouse-last-y 0) X (setq mouse-last-b 0))))) X X(defun mouse-edit-action () X ;marking and editing actions on buttons: X ; if no movement, nothing. X ; if movement, save mouse-last-dot, X ; and edit. X ; editing (on upstrokes): X ; unmodified, copy to kill buffer. X ; SHIFTed, delete (cut) to kill buffer. X ; X ; option-click yanks from kill buffer; X ; shift-option-click from named buffer. X (let ((fun (get 'mouse-function b))) X (if fun (apply fun nil)))) X X X ; individual button bindings X ; generally will only need up mouse button: mouse-last-dot X ; is saved automatically on down mouse button X X; only need to define functions for keys that get used X X(put 'mouse-function 32 ; up X '(lambda () X (if (and (not (mouse-click-p)) X (not scrolling-p)) X (copy-region-as-kill (dot) mouse-last-dot)))) X X(put 'mouse-function 34 ; up/shift X '(lambda () X (if (and (not (mouse-click-p)) X (not scrolling-p)) X (kill-region (dot) mouse-last-dot)))) X X(put 'mouse-function 40 ; up/option X '(lambda () X (if (mouse-click-p) X (progn X (yank) X (exchange-dot-and-mark))))) X X(put 'mouse-function 42 X '(lambda () ; up/option/shift X (if (mouse-click-p) X (insert-buffer (read-buffer "Insert contents of buffer: "))))) X X(defun mouse-click-p () X (= (dot) mouse-last-dot)) X X(defun set-window-boundaries () X (let ((edges (window-edges))) X (setq xl (1+ (car edges))) X (setq yt (1+ (car (cdr edges)))) X (let ((temp (car (cdr (cdr edges))))) X (setq xr (if (= (screen-width) temp) mouse-max-x temp))) X (let ((temp (car (cdr (cdr (cdr edges)))))) X (setq yb (if (= (screen-height) temp) mouse-max-y temp ))))) X X(defun select-window-containing-x-and-y (x y) X (let ((starting-window (selected-window))) X (set-window-boundaries) X (while (not (point-in-window x y)) X (other-window 1) X (if (eq (selected-window) starting-window) X (error nil) X (set-window-boundaries))) X (if (or (= x xr) (= y yb)) X (setq scrolling-p t) X (setq scrolling-p nil)))) X X(defun point-in-window (x y) X (and (<= xl x)(<= x xr)(<= yt y)(<= y yb))) X X(defun move-to-window-x-y (x y) X (move-to-window-line (- y yt)) X (move-to-window-column (- x xl))) X X(defun move-to-window-column (x) X (move-to-column (+ (max 0 (- (window-hscroll) 1)) x))) X X(defun mouse-scroll-region (b x y) X (if down X (if shift X (do-lines b x y) X (do-pages b x y))) X (if (and up X (or (/= x mouse-last-x) X (/= y mouse-last-y))) X (if shift X (do-lines b x y) X (do-pages b x y)))) X X(defun do-lines (b x y) ; fine control over lines X (if (= x xr) X (cond ((= y yt)(scroll-down 1)) X ((= y yb)(scroll-up 1)) X (t (if option X (scroll-down (- yb y 1)) X (scroll-up (- y yt)))))) X (if (and (= y yb) (/= x xr)) X (cond ((<= x xl)(scroll-right 1)) X ((>= x (1- xr))(scroll-left 1)) X (t (if option X (move-column-right x) X (move-column-left x)))))) X X(defun move-column-left (x) ;need to mess about a bit because X (scroll-left ;first scroll left of 1 just writes X (if (= (window-hscroll) 0) ;a column of $s in column 1 X (- x xl) X (- x xl 1)))) X X(defun move-column-right (x) X (scroll-right (- xr x 2))) X X X(defun do-pages (b x y) ; large motions via pages and thumbing X (if (= x xr) X (cond ((= y yt)(scroll-down nil)) X ((= y yb)(scroll-up nil)) X (t (goto-percent (/ (* (- y yt 1) 100) X (- yb yt 2)))))) X (if (and (= y yb)(/= x xr)) X (cond ((<= x xl)(scroll-right (- (window-width) X next-screen-context-lines))) X ((>= x (1- xr))(scroll-left (- (window-width) X next-screen-context-lines))) X (t (goto-horizontal-percent (/ (* (- x xl 1) 100) X (- xr xl 2))))))) X X(defun goto-percent (p) X (goto-char (/ (* (- (dot-max) (dot-min)) p) 100))) X X(defun goto-horizontal-percent (p) ;try to put this percent of columns X (let ((window-offset (window-hscroll));in the center column of the window X delta) ;unless that would move the first or X (setq delta ;last column past the window edge X (- window-offset X (min (max 0 (- (/ (* (screen-width) p) 100) X (/ (- xr xl) 2))) X (- (screen-width) (- xr xl))))) X (scroll-right delta))) X X X(global-set-key "\em" 'move-mac-cursor) X X END_OF_FILE if test 9279 -ne `wc -c <'1.30/macmouse.el'`; then echo shar: \"'1.30/macmouse.el'\" unpacked with wrong size! fi # end of '1.30/macmouse.el' fi if test -f '1.30/makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'1.30/makefile'\" else echo shar: Extracting \"'1.30/makefile'\" \(5258 characters\) sed "s/^X//" >'1.30/makefile' <<'END_OF_FILE' X# X# Makefile for layers 1.30 X# X X# This software is X# Copyright (C) 1989-1993 by Eric C. Rosen and David W. Trissel. X# X# Permission is granted to freely use, copy, modify, and redistribute X# this software, provided that no attempt is made to gain profit from it, X# the author is not construed to be liable for any results of using the X# software, alterations are clearly marked as such, and this notice is X# not modified. X# X# The author makes no claims as to the fitness or correctness of this software X# for any use whatsoever, and it is provided as is. Any use of this software X# is at the user's own risk. X XSHELL = /bin/sh XMAKE = /bin/make X X# If you want to use gcc, uncomment the following line: X# CC = gcc -pipe -g X XBIN = /usr/local XMANDIR = /usr/local/man/manl X XMS = l XCFLAGS = -O X Xdefault: X @echo " MacLayers Unix-Side Installation" X @echo " layers v1.30" X @echo "" X @echo "To build the Unix side of MacLayers in the current directory:" X @echo "" X @echo 'For SunOS prior to 4.1 and' X @echo ' other BSD hosts: % make oldsun' X @echo 'For SunOS 4.1 and later: % make sun' X @echo 'For Sequent hosts: % make sequent' X @echo 'For Apple A/UX hosts: % make aux' X @echo 'For SGI/IRIX hosts: % make irix' X @echo 'For IBM RS/6000/AIX hosts: % make rs6000' X @echo 'For SVR4 hosts: % make svr4' X @echo 'For DEC/ULTRIX hosts: % make ultrix' X @echo 'For NeXT hosts: % make NeXT' X @echo "" X @echo "To install MacLayers: (for system administrators or others who are" X @echo " [after building] making layers available to a group of users)" X @echo "" X @echo "For setuid installation: % make installsetuid" X @echo "For non-setuid installation: % make installnosetuid" X @echo "For an explanation of the major caveats of a non-setuid" X @echo "installation: % make installhelp" X Xinstallhelp: X @echo "Implications of non-setuid installation are:" X @echo "" X @echo "1) As with any socket allocating utility your system may be" X @echo " *less* secure with this option if your kernel does not protect" X @echo " virtual tty's from cross user allocation and access. One" X @echo " hole is where the undead program of a disconnected user can be" X @echo " left attached to a socket and a later user allocate the same" X @echo " socket and receive continued output. Another is that any user" X @echo " can read/write to the virtual control terminals of a" X @echo " MacLayers user. (The reason for all this is that the layers" X @echo " utility cannot set the pseudo tty owner to the user.)" X @echo "" X @echo "2) If your utmp file is protected from user writes then" X @echo " users will not be able to do login shell windows (write and" X @echo " talk-like facilities will be unavailable and who-like commands" X @echo " may give inaccurate details.)" X Xall: layers layersize layertitle macbput X Xlayers : layers.o protocol.o X $(CC) $(CFLAGS) -o layers layers.o protocol.o $(LIBS) X Xlayersize : layersize.o X $(CC) $(CFLAGS) -o layersize layersize.o $(LIBS) X Xlayertitle : layertitle.o X $(CC) $(CFLAGS) -o layertitle layertitle.o $(LIBS) X Xmacbput : macbput.o X $(CC) $(CFLAGS) -o macbput macbput.o $(LIBS) X Xlayers.o: layers.c layers.h X $(CC) $(CFLAGS) $(FLAGS) -c layers.c X Xprotocol.o: protocol.c layers.h X $(CC) $(CFLAGS) $(FLAGS) -c protocol.c X Xlayersize.o: layersize.c X $(CC) $(CFLAGS) $(FLAGS) -c layersize.c X Xlayertitle.o: layertitle.c X $(CC) $(CFLAGS) $(FLAGS) -c layertitle.c X Xmacbput.o: macbput.c macbput.h X $(CC) $(CFLAGS) $(FLAGS) -c macbput.c X Xinstallsetuid: layers layersize layertitle macbput X rm -f $(BIN)/layers X rm -f $(BIN)/layersize X rm -f $(BIN)/layertitle X rm -f $(BIN)/macbput X install -c -s -o root -g daemon -m 4711 layers $(BIN)/layers X install -c -s layersize $(BIN)/layersize X install -c -s layertitle $(BIN)/layertitle X install -c -s macbput $(BIN)/macbput X Xinstallnosetuid: $(PGM) $(PGM2) $(PGM3) $(PGM4) X rm -f $(BIN)/layers X rm -f $(BIN)/layersize X rm -f $(BIN)/layertitle X rm -f $(BIN)/macbput X install -c -s layers $(BIN)/layers X install -c -s layersize $(BIN)/layersize X install -c -s layertitle $(BIN)/layertitle X install -c -s macbput $(BIN)/macbput X Xmanpage: layers.1 X rm -f $(MANDIR)/layers.$(MS) X rm -f $(MANDIR)/macbput.$(MS) X cp layers.1 $(MANDIR)/layers.$(MS) X cp macbput.1 $(MANDIR)/macbput.$(MS) X chmod 664 $(MANDIR)/layers.$(MS) X chmod 664 $(MANDIR)/macbput.$(MS) X Xclean: X rm -f a.out core layers layersize layertitle macbput *.o X Xshar: X mkdir 1.30 X cp layers.c \ X protocol.c \ X layertitle.c \ X layersize.c \ X macbput.c \ X layers.h \ X macbput.h \ X layers.1 \ X layertitle.1 \ X layersize.1 \ X macbput.1 \ X MacLayers.doc \ X layersrc.doc \ X README \ X layersrc \ X macmouse.el \ X makefile 1.30 X shar -o layers130.shar `find 1.30 -print` X rm -r 1.30 X X# X# Make compiling easy on following systems: X# X Xoldsun: X ${MAKE} all X Xsun: X ${MAKE} FLAGS=-DPOSIXTTY all X Xaux: X ${MAKE} CC=gcc all X Xirix: X ${MAKE} FLAGS="-cckr -DSYSV -DIRIX" all X Xrs6000: X ${MAKE} FLAGS="-cckr -DSYSV -D_BSD -DAIX" all X Xsvr4: X ${MAKE} FLAGS=-DSVR4 LIBS="-lsocket -lnsl" all X Xultrix: X ${MAKE} FLAGS=-DULTRIX all X Xsequent: X ${MAKE} FLAGS=-DSEQUENT all X XNeXT: X ${MAKE} CC=gcc FLAGS=-bsd all END_OF_FILE if test 5258 -ne `wc -c <'1.30/makefile'`; then echo shar: \"'1.30/makefile'\" unpacked with wrong size! fi # end of '1.30/makefile' fi echo shar: End of shell archive. exit 0 .