386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sun, 28 Jun 1992 17:36:14 +0000 (09:36 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sun, 28 Jun 1992 17:36:14 +0000 (09:36 -0800)
Work on file usr/othersrc/public/screen-3.2/screen3.2/screen.c
Work on file usr/othersrc/public/screen-3.2/screen3.2/config.h

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/othersrc/public/screen-3.2/screen3.2/config.h [new file with mode: 0644]
usr/othersrc/public/screen-3.2/screen3.2/screen.c [new file with mode: 0644]

diff --git a/usr/othersrc/public/screen-3.2/screen3.2/config.h b/usr/othersrc/public/screen-3.2/screen3.2/config.h
new file mode 100644 (file)
index 0000000..8e4781e
--- /dev/null
@@ -0,0 +1,62 @@
+/* from libove@libove.det.dec.com (Jay Vassos-Libove)
+ ****************************************************************
+ * $Id: config.bsd386,v 1.2 92/02/03 02:30:42 jnweiger Exp $ FAU
+ */
+#define POSIX
+#define BSDJOBS
+#define TERMIO
+#undef TERMINFO
+#undef SYSV
+#define SIGVOID 
+#define DIRENT
+#define SUIDROOT
+#define UTMPOK
+#define LOGINDEFAULT   1
+#undef GETUTENT
+#define UTHOST
+#undef USRLIMIT
+#undef LOCKPTY
+#undef NOREUID
+#define  LOADAV_3DOUBLES
+#undef LOADAV_3LONGS
+#undef  LOADAV_4LONGS
+#define GETTTYENT
+#undef NFS_HACK
+#undef LOCALSOCKDIR
+#ifdef LOCALSOCKDIR
+# ifndef TMPTEST
+#  define SOCKDIR "/tmp/screens"
+# else
+#  define SOCKDIR "/tmp/testscreens"
+# endif
+#endif
+#define USEBCOPY
+#undef TOPSTAT
+#define USEVARARGS
+#undef NAMEDPIPE
+#define LOCK
+#define PASSWORD
+#define COPY_PASTE
+#define REMOTE_DETACH
+#define POW_DETACH
+#define NETHACK
+#define ETCSCREENRC "/usr/local/etc/screenrc"
+
+/* These get seen in screen.h, extern.h and other places to avoid conflicts
+ * with the definitions and declarations in /usr/include/...
+ * on BSD/386 from BSD, Inc.
+ */
+/* modified for 386BSD by rich@rice.edu */
+#define SIG_T_DEFINED
+#define PID_T_DEFINED
+#define MEMFUNCS_DECLARED
+#define WAITSTUFF_DECLARED
+#define KILLSTUFF_DECLARED
+#define REUID_DECLARED
+#define CRYPT_DECLARED
+#define MKNOD_DECLARED
+#define PUTENV_DECLARED
+#define SETPGID_DECLARED
+#define GETHOSTNAME_DECLARED
+#define VPRNT_DECLARED
+#define NLIST_DECLARED
diff --git a/usr/othersrc/public/screen-3.2/screen3.2/screen.c b/usr/othersrc/public/screen-3.2/screen3.2/screen.c
new file mode 100644 (file)
index 0000000..d7bd07f
--- /dev/null
@@ -0,0 +1,4014 @@
+/* Copyright (c) 1991
+ *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
+ *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
+ * Copyright (c) 1987 Oliver Laumann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Noteworthy contributors to screen's design and implementation:
+ *     Wayne Davison (davison@borland.com)
+ *     Patrick Wolfe (pat@kai.com, kailand!pat)
+ *     Bart Schaefer (schaefer@cse.ogi.edu)
+ *     Nathan Glasser (nathan@brokaw.lcs.mit.edu)
+ *     Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
+ *     Howard Chu (hyc@hanauma.jpl.nasa.gov)
+ *     Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
+ *     Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
+ *     Marc Boucher (marc@CAM.ORG)
+ *
+ ****************************************************************
+ */
+
+#ifndef lint
+  static char rcs_id[] = "$Id: screen.c,v 1.2 92/02/03 02:28:05 jnweiger Exp $ FAU";
+#endif
+
+
+#include <sys/param.h>
+/* #include <signal.h> */
+#include <ctype.h>
+#include <pwd.h>
+#include <fcntl.h>
+#ifdef sgi
+# include <sys/sysmacros.h>
+#endif /* sgi */
+#if !defined(sun) && !defined(B43) && !defined(ISC)
+# include <time.h>
+#endif
+/*
+ * Gee!! We should reverse that #if! 
+ */
+#if defined(sun) || defined(_AIX) || defined(sysV68) || defined(MIPS) || defined(GOULD_NP1) || defined(B43) || defined(ISC) || defined(apollo) || defined(BSDI) || defined(sgi)
+# include <sys/time.h>
+#endif
+#if defined(M_XENIX) || defined(M_UNIX)
+#include <sys/select.h> /* for timeval */
+#endif
+#include <sys/types.h>
+#ifdef ISC
+# include <sys/bsdtypes.h>
+#endif
+#if !defined(sysV68) && !defined(M_XENIX)
+# include <sys/wait.h>
+#endif
+#include <sys/stat.h>
+#ifndef sgi
+# include <sys/file.h>
+#endif /* sgi */
+#ifndef sun
+# include <sys/ioctl.h>
+#endif /* sun */
+
+#include <signal.h>
+
+#include "config.h"
+
+#ifdef SHADOWPW
+# include <shadow.h>
+#endif /* SHADOWPW */
+
+#ifdef SVR4
+# include <sys/stropts.h>
+#endif
+
+#ifdef SYSV
+# include <sys/utsname.h>
+#endif
+
+#if defined(_SEQUENT_) 
+/* for the FD.. stuff */
+# include <sys/select.h>
+#endif 
+
+#if defined(sequent) || defined(SVR4)
+# include <sys/resource.h>
+#endif /* sequent || SVR4 */
+
+#ifdef ISC
+# include <sys/tty.h>
+# include <sys/sioctl.h>
+# include <sys/pty.h>
+#endif
+
+#include "screen.h"
+
+#include "patchlevel.h"
+
+#if defined(xelos) || defined(sysV68) || defined(M_XENIX)
+ struct passwd *getpwuid __P((uid_t));
+ struct passwd *getpwnam __P((char *));
+#endif
+
+#ifdef USEVARARGS
+# if defined(__STDC__)
+#  include <stdarg.h>
+# else
+#  include <varargs.h>
+# endif
+#endif
+
+#ifdef DEBUG
+FILE *dfp;
+#endif
+
+
+#ifdef COPY_PASTE
+extern char *copybuffer;       /* def in mark.c jw. */
+extern copylen;
+#endif /* COPY_PASTE */
+
+extern char *blank, *null, Term[], screenterm[], **environ, *Termcap;
+int force_vt = 1, assume_LP = 0;
+extern int in_ovl;
+extern int ovl_blockfore;
+extern void (*ovl_process)();
+extern int help_page;
+extern int screenwidth, screenheight;
+extern char display_tty[];
+extern int default_width, default_height;
+extern int Z0width, Z1width;
+extern int ISO2022;
+extern int status, HS;
+extern char *Z0, *WS, *LastMsg;
+extern time_t TimeDisplayed;
+int BellDisplayed;
+int VBellWait, MsgWait, MsgMinWait;
+
+/* tputs uses that: jw */
+extern short ospeed;
+
+extern int flow, default_flow, wrap, visual_bell, default_monitor;
+extern int errno;
+extern sys_nerr;
+extern char *sys_errlist[];
+extern char mark_key_tab[];
+
+#if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
+extern struct winsize glwz;
+#endif
+
+static char *MakeWinMsg __P((char *, int));
+static void MakeNewEnv __P((void));
+static int Attach __P((int));
+static void Attacher __P((void));
+static void SigHandler __P((void));
+static SIGTYPE AttacherSigInt __P(SIGPROTOARG);
+static SIGTYPE SigChld __P(SIGPROTOARG);
+static SIGTYPE SigInt __P(SIGPROTOARG);
+static SIGTYPE CoreDump __P((int));
+static void DoWait __P((void));
+static SIGTYPE Finit __P((int));
+static void InitKeytab __P((void));
+static void SetForeWindow __P((int));
+static int NextWindow __P((void));
+static int PreviousWindow __P((void));
+static int MoreWindows __P((void));
+static void FreeWindow __P((struct win *));
+static void execvpe __P((char *, char **, char **));
+static void LogToggle __P((void));
+static void ShowWindows __P((void));
+static void ShowTime __P((void));
+static void ShowInfo __P((void));
+static int OpenPTY __P((void));
+#ifdef PASSWORD
+static void trysend __P((int, struct msg *, char *));
+#endif
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+static SIGTYPE SigAttWinch __P(SIGPROTOARG);
+#endif
+static void fgtty __P((void));
+static void freetty __P((void));
+static void brktty __P((void));
+
+#if defined(LOCK)
+static SIGTYPE DoLock __P(SIGPROTOARG);
+static void LockTerminal __P((void));
+#endif
+
+#ifdef COPY_PASTE
+static pastelen;
+static char *pastebuffer;
+#endif
+#ifdef PASSWORD
+extern char Password[];
+#endif
+
+static struct passwd *ppp;
+
+/* used for opening a new pty-pair: */
+static char PtyName[32], TtyName[32];
+
+/* used for the attacher's tty: */
+static char *attach_tty;
+
+char *ShellProg;
+char *ShellArgs[2];
+static char inbuf[MAXWIN][IOSIZE];
+static inlen[MAXWIN];
+static inbuf_ct;
+static ESCseen;
+static GotSignal;
+
+static char DefaultShell[] = "/bin/sh";
+static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
+
+#ifdef hpux
+char PtyProto[] = "/dev/ptym/ptyXY";
+char TtyProto[] = "/dev/pty/ttyXY";
+#else
+# if !(defined(sequent) || defined(_SEQUENT_) || defined(SVR4))
+static char PtyProto[] = "/dev/ptyXY";
+static char TtyProto[] = "/dev/ttyXY";
+# endif
+#endif /* hpux */
+int TtyMode = 0622;
+#ifdef SOCKDIR
+char *SockDir = SOCKDIR;
+#else
+char *SockDir = ".iscreen";
+#endif
+extern char SockPath[], *SockNamePtr, *SockName;
+int ServerSocket = -1;
+static char **NewEnv;
+
+char *RcFileName = NULL;
+char Esc = Ctrl('a');
+char MetaEsc = 'a';
+char *home;
+
+int HasWindow;
+char *LoginName;
+char *BellString;
+char *VisualBellString;
+char *ActivityString;
+char *BufferFile;
+char *PowDetachString;
+int auto_detach = 1;
+int iflag, rflag, dflag, lsflag, quietflag, wipeflag;
+int adaptflag, loginflag = -1, allflag;
+static intrc, startc, stopc;
+char HostName[MAXSTR];
+int Detached, Suspended;
+int DeadlyMsg = 1;
+int AttacherPid;       /* Non-Zero in child if we have an attacher */
+int MasterPid;
+int real_uid, real_gid, eff_uid, eff_gid;
+int default_histheight;
+int default_startup;
+int slowpaste;
+
+#if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
+int DevTty = -1;
+#endif
+
+#ifdef NETHACK
+int nethackflag = 0;
+#endif
+
+struct mode OldMode, NewMode;
+
+struct win *fore = NULL;
+int WinList = -1;
+int ForeNum;
+struct win *wtab[MAXWIN];
+
+struct key ktab[256];
+
+#ifndef FD_SET
+typedef struct fd_set
+{
+  int fd_bits[1];
+}      fd_set;
+# define FD_ZERO(fd) ((fd)->fd_bits[0] = 0)
+# define FD_SET(b, fd) ((fd)->fd_bits[0] |= 1 << (b))
+# define FD_ISSET(b, fd) ((fd)->fd_bits[0] & 1 << (b))
+# define FD_SETSIZE 32
+#endif
+
+
+#ifndef WTERMSIG
+# ifndef BSDWAIT /* if wait is NOT a union: */
+#  define WTERMSIG(status) (status & 0177)
+# else
+#  define WTERMSIG(status) status.w_T.w_Termsig 
+# endif
+#endif
+
+#ifndef WIFCORESIG
+# ifndef BSDWAIT /* if wait is NOT a union: */
+#  define WIFCORESIG(status) (status & 0200)
+# else
+#  define WIFCORESIG(status) status.w_T.w_Coredump
+# endif
+#endif
+
+#ifndef WEXITSTATUS
+# ifndef BSDWAIT /* if wait is NOT a union: */
+#  define WEXITSTATUS(status) ((status >> 8) & 0377)
+# else
+#  define WEXITSTATUS(status) status.w_T.w_Retcode
+# endif
+#endif
+
+char *shellaka = NULL;
+
+/*
+ * Do this last
+ */
+#include "extern.h"
+
+/*
+ * XXX: Missing system header files.
+ */
+#ifdef USEVARARGS
+# ifndef VPRNT_DECLARED
+int vsprintf __P((char *, char *, va_list));
+# endif /* VPRNT_DECLARED */
+#endif
+int select __P((int, fd_set *, fd_set *, fd_set *, struct timeval *));
+
+static void
+brktty()
+{
+#ifdef POSIX
+  setsid();            /* will break terminal affiliation */
+# ifdef BSD
+  ioctl(0, TIOCSCTTY, 0);
+# endif /* BSD */
+#else
+# ifdef SYSV
+  setpgrp();           /* will break terminal affiliation */
+# else
+#  ifdef BSDJOBS
+  if (DevTty)
+    if (ioctl(DevTty, TIOCNOTTY, (char *) 0) != 0)
+      debug2("brktty: ioctl(DevTty=%d, TIOCNOTTY, 0) = %d\n", DevTty, errno);
+#  endif
+# endif
+#endif
+}
+
+static void
+freetty()
+{
+  brktty();
+#if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
+  if (DevTty >= 0)
+    {
+      close(DevTty);
+      DevTty = -1;
+    }
+#endif
+  close(0);
+  close(1);
+  close(2);
+  debug("did freetty\n");
+}
+
+static void
+fgtty()
+{
+#ifdef BSDJOBS
+  int mypid;
+
+  mypid = getpid();
+
+# ifdef BSDI
+  setsid();
+  ioctl(0, TIOCSCTTY, 0);
+# endif /* BSDI */
+
+# ifdef POSIX
+  if (tcsetpgrp(0, mypid))
+    {
+      debug1("fgtty: tcsetpgrp: %d\n", errno);
+      /* error is likely to have side-effects -- better to warn our user */
+      SendErrorMsg("fgtty: Could not set process group id in tty");
+    }
+# else
+  if (ioctl(0, TIOCSPGRP, &mypid) != 0)
+    debug1("fgtty: TIOSETPGRP: %d\n", errno);
+  /* posix setsid() in brktty() from freetty() already made us leader */
+  if (setpgrp(0, mypid))
+    debug1("fgtty: setpgrp: %d\n", errno);
+# endif /* POSIX */
+#endif /* BSDJOBS */
+}
+
+#ifdef hpux
+/*
+ * hpux has berkeley signal semantics if we use sigvector,
+ * but not, if we use signal, so we define our own signal() routine.
+ * (jw)
+ */
+void (*signal(sig, func)) ()
+int sig;
+void (*func) ();
+{
+  struct sigvec osv, sv;
+
+  sv.sv_handler = func;
+  sv.sv_mask = sigmask(sig);
+  sv.sv_flags = SV_BSDSIG;
+  if (sigvector(sig, &sv, &osv) < 0)
+    return (BADSIG);
+  return (osv.sv_handler);
+}
+#endif /* hpux */
+
+#ifndef USEBCOPY
+void bcopy(s1, s2, len)
+register char *s1, *s2;
+register int len;
+{
+  if (s1 < s2 && s2 < s1 + len)
+    {
+      s1 += len;
+      s2 += len;
+      while (len-- > 0)
+       *--s2 = *--s1;
+    }
+  else
+    while (len-- > 0)
+      *s2++ = *s1++;
+}
+#endif /* USEBCOPY */
+
+void bclear(p, n)
+int n;
+char *p;
+{
+  bcopy(blank, p, n);
+}
+
+static void
+closeallfiles()
+{
+  int f;
+#ifdef SVR4
+  struct rlimit rl;
+  
+  if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) && rl.rlim_max != RLIM_INFINITY)
+    f = rl.rlim_max;
+  else
+#endif /* SVR4 */
+#if defined(SYSV) && !defined(ISC)
+  f = NOFILE;
+#else /* SYSV && !ISC */
+  f = getdtablesize();
+#endif /* SYSV && !ISC */
+  while (--f > 2)
+    close(f);
+}
+  
+static int InterruptPlease = 0;
+
+void main(ac, av)
+int ac;
+char **av;
+{
+  register int n, len;
+  register struct win *p;
+  char *ap, *aka = NULL;
+  char *av0;
+  char socknamebuf[2 * MAXSTR];
+  int s = 0;
+  fd_set r, w, e;
+  int mflag = 0;
+  struct timeval tv;
+  int nsel;
+  char buf[IOSIZE], *bufp, *myname = (ac == 0) ? "screen" : av[0];
+  struct stat st;
+  int buflen, tmp;
+#ifdef _MODE_T                 /* (jw) */
+  mode_t oumask;
+#else
+  int oumask;
+#endif
+#ifdef SYSV
+  struct utsname utsnam;
+#endif
+
+  /*
+   *  First, close all unused descriptors
+   *  (otherwise, we might have problems with the select() call)
+   */
+  closeallfiles();
+#ifdef DEBUG
+  (void) mkdir("/tmp/debug", 0777);
+  if ((dfp = fopen("/tmp/debug/screen.front", "w")) == NULL)
+    dfp = stderr;
+  else
+    (void) chmod("/tmp/debug/screen.front", 0666);
+#endif
+  debug1("-- screen debug started %s\n", *av);
+#ifdef POSIX
+  debug("POSIX\n");
+#endif
+#ifdef TERMIO
+  debug("TERMIO\n");
+#endif
+#ifdef SYSV
+  debug("SYSV\n");
+#endif
+#ifdef NAMEDPIPE
+  debug("NAMEDPIPE\n");
+#endif
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+  debug("Window changing enabled\n");
+#endif
+#ifdef NOREUID
+  debug("NOREUID\n");
+#endif
+#ifdef hpux
+  debug("hpux\n");
+#endif
+#ifdef USEBCOPY
+  debug("USEBCOPY\n");
+#endif
+#ifdef UTMPOK
+  debug("UTMPOK\n");
+#endif
+#ifdef LOADAV
+  debug("LOADAV\n");
+#endif
+#ifdef NETHACK
+  debug("NETHACK\n");
+#endif
+#ifdef TERMINFO
+  debug("TERMINFO\n");
+#endif
+#ifdef NAME_MAX
+  debug1("NAME_MAX = %d\n", NAME_MAX);
+#endif
+
+  BellString = SaveStr("Bell in window %");
+  VisualBellString = SaveStr("   Wuff,  Wuff!!  ");
+  ActivityString = SaveStr("Activity in window %");
+  BufferFile = SaveStr("/tmp/screen-exchange");
+  PowDetachString = 0;
+  default_histheight = DEFAULTHISTHEIGHT;
+  default_startup = (ac > 1) ? 0 : 1;
+  adaptflag = 0;
+  slowpaste = 0;
+  VBellWait = VBELLWAIT;
+  MsgWait = MSGWAIT;
+  MsgMinWait = MSGMINWAIT;
+  CompileKeys((char *)NULL, mark_key_tab);
+
+  av0 = *av;
+  while (ac > 0)
+    {
+      ap = *++av;
+      if (--ac > 0 && *ap == '-')
+       {
+         switch (ap[1])
+           {
+           case 'a':
+             allflag = 1;
+             break;
+           case 'A':
+             adaptflag = 1;
+             break;
+           case 'c':
+             if (ap[2])
+               RcFileName = ap + 2;
+             else
+               {
+                 if (--ac == 0)
+                   exit_with_usage(myname);
+                 RcFileName = *++av;
+               }
+             break;
+           case 'e':
+             if (ap[2])
+               ap += 2;
+             else
+               {
+                 if (--ac == 0)
+                   exit_with_usage(myname);
+                 ap = *++av;
+               }
+             if (!ParseEscape(ap))
+               Msg(0, "Two characters are required with -e option.");
+             break;
+           case 'f':
+             switch (ap[2])
+               {
+               case 'n':
+               case '0':
+                 default_flow = FLOW_NOW * 0;
+                 break;
+               case 'y':
+               case '1':
+               case '\0':
+                 default_flow = FLOW_NOW * 1;
+                 break;
+               case 'a':
+                 default_flow = FLOW_AUTOFLAG;
+                 break;
+               default:
+                 exit_with_usage(myname);
+               }
+             break;
+            case 'h':
+             if (ap[2])
+               default_histheight = atoi(ap + 2);
+             else
+               {
+                 if (--ac == 0)
+                   exit_with_usage(myname);
+                 default_histheight = atoi(*++av);
+               }
+             if (default_histheight < 0)
+               default_histheight = 0;
+             break;
+           case 'i':
+             iflag = 1;
+             break;
+           case 't': /* title is a synonym for AkA */
+           case 'k':
+             if (ap[2])
+               aka = ap + 2;
+             else
+               {
+                 if (--ac == 0)
+                   exit_with_usage(myname);
+                 aka = *++av;
+               }
+             break;
+           case 'l':
+             switch (ap[2])
+               {
+               case 'n':
+               case '0':
+                 loginflag = 0;
+                 break;
+               case 'y':
+               case '1':
+               case '\0':
+                 loginflag = 1;
+                 break;
+               case 's':
+               case 'i':
+                 lsflag = 1;
+                 break;
+               default:
+                 exit_with_usage(myname);
+               }
+             break;
+           case 'w':
+             lsflag = 1;
+             wipeflag = 1;
+             break;
+           case 'L':
+             assume_LP = 1;
+             break;
+           case 'm':
+             mflag = 1;
+             break;
+           case 'O':
+             force_vt = 0;
+             break;
+           case 'T':
+              if (ap[2])
+               {
+                 if (strlen(ap+2) < 20)
+                    strcpy(screenterm, ap + 2);
+               }
+              else
+                {
+                  if (--ac == 0)
+                    exit_with_usage(myname);
+                 if (strlen(*++av) < 20)
+                    strcpy(screenterm, *av);
+                }
+              break;
+           case 'q':
+             quietflag = 1;
+             break;
+           case 'r':
+           case 'R':
+             if (ap[2])
+               {
+                 SockName = ap + 2;
+                 if (ac != 1)
+                   exit_with_usage(myname);
+               }
+             else if (ac > 1 && *av[1] != '-')
+               {
+                 SockName = *++av;
+                 ac--;
+               }
+             rflag = (ap[1] == 'r') ? 1 : 2;
+             break;
+#ifdef REMOTE_DETACH
+           case 'd':
+             dflag = 1;
+             /* FALLTHRU */
+           case 'D':
+             if (!dflag)
+               dflag = 2;
+             if (ap[2])
+               SockName = ap + 2;
+             if (ac == 2)
+               {
+                 if (*av[1] != '-')
+                   {
+                     SockName = *++av;
+                     ac--;
+                   }
+               }
+             break;
+#endif
+           case 's':
+             if (ap[2])
+               ShellProg = ap + 2;
+             else
+               {
+                 if (--ac == 0)
+                   exit_with_usage(myname);
+                 ShellProg = *++av;
+               }
+             break;
+           default:
+             exit_with_usage(myname);
+           }
+       }
+      else
+       break;
+    }
+  real_uid = getuid();
+  real_gid = getgid();
+  eff_uid = geteuid();
+  eff_gid = getegid();
+  if (eff_uid != real_uid)
+    {          
+      /* if running with s-bit, we must install a special signal
+       * handler routine that resets the s-bit, so that we get a
+       * core file anyway.
+       */
+      signal(SIGBUS, CoreDump);
+      signal(SIGSEGV, CoreDump);
+    }
+  if (!ShellProg && (ShellProg = getenv("SHELL")) == 0)
+    ShellProg = DefaultShell;
+  ShellArgs[0] = ShellProg;
+#ifdef NETHACK
+  nethackflag = (getenv("NETHACKOPTIONS") != NULL);
+#endif
+  home = getenv("HOME");       /* may or may not return a result. jw. */
+  if ((LoginName = getlogin()) && LoginName[0] != '\0')
+    {
+      if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
+       if (ppp->pw_uid != real_uid)
+         ppp = (struct passwd *) 0;
+    }
+  if (ppp == 0)
+    {
+      if ((ppp = getpwuid(real_uid)) == 0)
+        {
+#ifdef NETHACK
+          if (nethackflag)
+           Msg(0, "An alarm sounds through the dungeon...\nWarning, the kops are coming.");
+         else
+#endif
+         Msg(0, "getpwuid() can't identify your account!");
+         exit(1);
+        }
+      LoginName = ppp->pw_name;
+    }
+  if (home == 0 || *home == '\0')
+    home = ppp->pw_dir;
+  if (strlen(LoginName) > 20)
+    Msg(0, "LoginName too long - sorry.");
+  if (strlen(home) > MAXPATH - 25)
+    Msg(0, "$HOME too long - sorry.");
+#ifdef PASSWORD
+  strcpy(Password, ppp->pw_passwd);
+#endif
+
+  /* ttyname implies isatty */
+  if (!(attach_tty = ttyname(0)))
+    {
+#ifdef NETHACK
+      if (nethackflag)
+       Msg(0, "You must play from a terminal.");
+      else
+#endif
+      Msg(0, "Must be connected to a terminal.");
+      exit(1);
+    }
+  if (strlen(attach_tty) >= MAXPATH)
+    Msg(0, "TtyName too long - sorry.");
+  if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
+    Msg(0, "Cannot open '%s' - please check.", attach_tty);
+  close(n);
+    
+  debug1("attach_tty is %s\n", attach_tty);
+  
+#ifdef _MODE_T
+  oumask = umask(0);           /* well, unsigned never fails? jw. */
+#else
+  if ((oumask = umask(0)) == -1)
+    Msg(errno, "Cannot change umask to zero");
+#endif
+  if ((SockDir = getenv("ISCREENDIR")) == NULL)
+    SockDir = getenv("SCREENDIR");
+  if (SockDir && strlen(SockDir) >= MAXPATH - 1)
+    Msg(0, "ridiculous long $(I)SCREENDIR - try again.");
+#ifndef SOCKDIR
+  if (SockDir == 0)
+    {
+      sprintf(SockPath, "%s/.iscreen", home);
+      SockDir = SockPath;
+    }
+#endif
+  if (SockDir)
+    {
+      if (access(SockDir, F_OK))
+       {
+         if (UserContext() > 0)
+           {
+             if (mkdir(SockDir, 0700))
+               UserReturn(0);
+             UserReturn(1);
+           }
+         if (UserStatus() <= 0)
+           Msg(0, "Cannot make directory '%s'", SockDir);
+       }
+      if (SockDir != SockPath)
+        strcpy(SockPath, SockDir);
+    }
+#ifdef SOCKDIR
+  else
+    {
+      SockDir = SOCKDIR;
+      if (stat(SockDir, &st))
+       {
+         if (mkdir(SockDir, eff_uid ? 0777 : 0755) == -1)
+           Msg(errno, "Cannot make directory '%s'", SockDir);
+       }
+      else
+       {
+          n = eff_uid ? 0777 : 0755;
+         if ((st.st_mode & 0777) != n)
+           Msg(0, "Directory '%s' must have mode %03o.", SockDir, n);
+       }
+      sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
+      if (access(SockPath, F_OK))
+       {
+         if (mkdir(SockPath, 0700) == -1)
+           Msg(errno, "Cannot make directory '%s'", SockPath);
+         (void) chown(SockPath, real_uid, real_gid);
+       }
+    }
+#endif
+  if (stat(SockPath, &st) == -1)
+    {
+      Msg(errno, "Cannot access %s", SockPath);
+    }
+  else
+    {
+#ifdef _POSIX_SOURCE
+      if (S_ISDIR(st.st_mode) == 0)
+#else
+      if ((st.st_mode & S_IFMT) != S_IFDIR)
+#endif
+       Msg(0, "%s is not a directory.", SockPath);
+      if (st.st_uid != real_uid)
+       Msg(0, "You are not the owner of %s.", SockPath);
+      if ((st.st_mode & 0777) != 0700)
+       Msg(0, "Directory %s must have mode 700.", SockPath);
+    }
+  strcat(SockPath, "/");
+  SockNamePtr = SockPath + strlen(SockPath);
+  (void) umask(oumask);
+#if defined(SYSV) && !defined(ISC)
+  if (uname(&utsnam) == -1)
+    Msg(0, "uname() failed, errno = %d", errno);
+  else
+    {
+      strncpy(HostName, utsnam.nodename, MAXSTR);
+      HostName[(sizeof(utsnam.nodename) <= MAXSTR) ? 
+               sizeof(utsnam.nodename) : MAXSTR] = '\0';
+    }
+#else
+  (void) gethostname(HostName, MAXSTR);
+#endif
+  HostName[MAXSTR - 1] = '\0';
+  if ((ap = index(HostName, '.')) != NULL)
+    *ap = '\0';
+  GetTTY(0, &OldMode);
+#ifdef POSIX
+  ospeed = (short) cfgetospeed(&OldMode.tio);
+#else
+# ifndef TERMIO
+  ospeed = (short) OldMode.m_ttyb.sg_ospeed;
+# endif
+#endif
+  debug1("...setting extern short ospeed = %d\n", ospeed);
+
+  if (lsflag)
+    {
+      int i;
+      i = FindSocket(0, (int *)NULL);
+      /* MakeClientSocket appended the last (Sock)Name there: */
+      *SockNamePtr = '\0';
+      if (i == 0)
+       {
+#ifdef NETHACK
+          if (nethackflag)
+           Msg(0, "This room is empty (%s)\n", SockPath);
+          else
+#endif /* NETHACK */
+          Msg(0, "No Sockets found in %s\n", SockPath);
+        }
+      else
+        Msg(0, "%d Socket%s in %s.\n", i, i > 1 ? "s" : "", SockPath);
+        /* NOTREACHED */
+    }
+  if (rflag)
+    {
+      debug("screen -r: - is there anybody out there?\n");
+#ifdef SHADOWPW
+      setspent();  /* open shadow file while we are still root */
+#endif /* SHADOWPW */
+      if (Attach(MSG_ATTACH))
+       {
+         Attacher();
+         /* NOTREACHED */
+       }
+      debug("screen -r: backend not responding -- still crying\n");
+    }
+  else if (dflag)
+    {
+      (void) Attach(MSG_DETACH);
+      DeadlyMsg = 0;
+      Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
+      eexit(0);
+      /* NOTREACHED */
+    }
+  if (!mflag && (SockName = getenv("STY")) != 0 && *SockName != '\0')
+    {
+      setuid(real_uid);
+      setgid(real_gid);
+      s = MakeClientSocket(1, SockName);
+      if (ac == 0)
+       {
+         ac = 1;
+         av = ShellArgs;
+       }
+      av[ac] = aka;
+      SendCreateMsg(s, ac, av, allflag, default_flow, loginflag, default_histheight,
+                   screenterm);
+      close(s);
+      exit(0);
+    }
+#if defined(BSDJOBS) && !(defined(POSIX) || defined(SYSV))
+  if ((DevTty = open("/dev/tty", O_RDWR | O_NDELAY)) == -1)
+    Msg(errno, "/dev/tty");
+#endif
+  switch (MasterPid = fork())
+    {
+    case -1:
+      Msg(errno, "fork");
+      /* NOTREACHED */
+    case 0:
+      break;
+    default:
+      sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty),
+             HostName);
+      for (ap = socknamebuf; *ap; ap++)
+       if (*ap == '/')
+         *ap = '-';
+      SockName = socknamebuf;
+#ifdef SHADOWPW
+      setspent();  /* open shadow file while we are still root */
+#endif /* SHADOWPW */
+      Attacher();
+      /* NOTREACHED */
+    }
+#ifdef DEBUG
+  if (dfp != stderr)
+    fclose(dfp);
+  if ((dfp = fopen("/tmp/debug/screen.back", "w")) == NULL)
+    dfp = stderr;
+  else
+    (void) chmod("/tmp/debug/screen.back", 0666);
+#endif
+  debug("-- screen.back debug started\n");
+  ap = av0 + strlen(av0) - 1;
+  while (ap >= av0)
+    {
+      if (!strncmp("screen", ap, 6))
+       {
+         strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
+         break;
+       }
+      ap--;
+    }
+  if (ap < av0)
+    *av0 = 'S';
+
+  AttacherPid = getppid();
+  sprintf(socknamebuf, "%d.%s.%s", getpid(), stripdev(attach_tty), HostName);
+  for (ap = socknamebuf; *ap; ap++)
+    if (*ap == '/')
+      *ap = '-';
+  SockName = socknamebuf;
+  ServerSocket = s = MakeServerSocket();
+#ifdef ETCSCREENRC
+  if ((ap = getenv("SYSSCREENRC")) == NULL)
+    StartRc(ETCSCREENRC);
+  else
+    StartRc(ap);
+#endif
+  StartRc(RcFileName);
+  InitTermcap();
+  InitTerm(0);
+  MakeNewEnv();
+  strcpy(display_tty, attach_tty);
+#ifdef UTMPOK
+# ifdef apollo
+  ReInitUtmp();
+# else
+  InitUtmp();
+# endif /* apollo */
+#endif
+#ifdef LOADAV
+# ifdef NeXT
+  InitNeXTLoadAvg(); /* NeXT load average */
+# else
+  InitKmem();
+# endif /* !NeXT */
+#endif /* LOADAV */
+  signal(SIGHUP, SigHup);
+  signal(SIGINT, Finit);
+  signal(SIGQUIT, Finit);
+  signal(SIGTERM, Finit);
+#ifdef BSDJOBS
+  signal(SIGTTIN, SIG_IGN);
+  signal(SIGTTOU, SIG_IGN);
+#endif
+  InitKeytab();
+#ifdef ETCSCREENRC
+  if ((ap = getenv("SYSSCREENRC")) == NULL)
+    FinishRc(ETCSCREENRC);
+  else
+    FinishRc(ap);
+#endif
+  FinishRc(RcFileName);
+
+  /* Note: SetMode must be called _after_ FinishRc (flow is set there).
+   */
+  SetMode(&OldMode, &NewMode);
+  SetTTY(0, &NewMode);
+  if (loginflag == -1)
+      loginflag = LOGINDEFAULT;
+  if (ac == 0)
+    {
+      ac = 1;
+      av = ShellArgs;
+      if (!aka)
+       aka = shellaka;
+    }
+  if (!HasWindow)
+    {
+      debug("We open one default window, as screenrc did not specify one.\n");
+      if (MakeWindow(aka, av, allflag, default_flow, 0, (char *)0, loginflag, -1, (char *)0) == -1)
+       {
+         Finit(1);
+         /* NOTREACHED */
+       }
+    }
+  if (default_startup)
+    display_copyright();
+#ifdef SYSV
+  signal(SIGCLD, SigChld);
+#else
+  signal(SIGCHLD, SigChld);
+#endif
+  signal(SIGINT, SigInt);
+  tv.tv_usec = 0;
+  if (rflag == 2)
+    {
+#ifdef NETHACK
+      if (nethackflag)
+        Msg(0, "I can't seem to find a... Hey, wait a minute!  Here comes a screen now.");
+      else
+#endif
+      Msg(0, "New screen...");
+      rflag = 0;
+    }
+  brktty();
+  for (;;)
+    {
+      /*
+       * check to see if message line should be removed
+       */
+      if (status)
+       {
+         int time_left;
+
+         debug("checking status...\n");
+         time_left = TimeDisplayed + (BellDisplayed ? VBellWait : MsgWait) - time((time_t *)0);
+         if (time_left > 0)
+           {
+             tv.tv_sec = time_left;
+             debug(" not yet.\n");
+           }
+         else
+           {
+             debug(" removing now.\n");
+             RemoveStatus();
+           }
+       }
+      /*
+       * check for I/O on all available I/O descriptors
+       */
+      FD_ZERO(&r);
+      FD_ZERO(&w);
+      FD_ZERO(&e);
+      if (inbuf_ct > 0)
+       for (n = 0; n < MAXWIN; n++)
+#ifdef COPY_PASTE              /* wrong here? jw. */
+         if (inlen[n] > 0 || (pastelen > 0 && n == ForeNum))
+#else
+         if (inlen[n] > 0)
+#endif
+           FD_SET(wtab[n]->ptyfd, &w);
+      if (!Detached)
+       FD_SET(0, &r);
+      for (n = WinList; n != -1; n = p->WinLink)
+       {
+         p = wtab[n];
+         if (p->active && status && !BellDisplayed && !HS)
+           continue;
+         if (p->outlen > 0)
+           continue;
+         if (in_ovl && ovl_blockfore && n == ForeNum)
+           continue;
+         FD_SET(p->ptyfd, &r);
+       }
+      FD_SET(s, &r);
+      (void) fflush(stdout);
+      if (GotSignal && !status)
+       {
+         SigHandler();
+         continue;
+       }
+      if ((nsel = select(FD_SETSIZE, &r, &w, &e, (status) ? &tv : (struct timeval *) 0)) < 0)
+       {
+         debug1("Bad select - errno %d\n", errno);
+         if (errno != EINTR)
+           {
+             perror("select");
+             Finit(1);
+           }
+         else
+           {
+             errno = 0;
+             if ((!GotSignal || status) && !InterruptPlease)
+               continue;
+           }
+       }
+      if (InterruptPlease)
+       {
+         char buf[1];
+
+         debug("Backend received interrupt\n");
+         *buf = intrc;
+         write(wtab[ForeNum]->ptyfd, buf, 1);
+         debug1("Backend wrote interrupt to %d\n", ForeNum);
+         InterruptPlease = 0;
+
+         continue;
+       }
+      if (GotSignal && !status)
+       {
+         SigHandler();
+         continue;
+       }
+      /* Process a client connect attempt and message */
+      if (nsel && FD_ISSET(s, &r))
+       {
+          nsel--;
+         if (!HS)
+           RemoveStatus();
+         if (in_ovl)
+           {
+             SetOvlCurr();
+             (*ovl_process)(0, 0); /* We have to abort first!! */
+             CheckScreenSize(1); /* Change fore */
+             DeadlyMsg = 0;
+#ifdef NETHACK
+              if (nethackflag)
+               Msg(0, "KAABLAMM!!!  You triggered a land mine!");
+              else
+#endif
+             Msg(0, "Aborted because of window change or message.");
+           }
+         else
+           CheckScreenSize(1); /* Change fore */
+         ReceiveMsg(s);
+         continue;
+       }
+      /*
+       * Write the stored user input to the window descriptors first.
+       * We do not want to choke, if he types fast.
+       */
+      if (nsel && inbuf_ct > 0)
+       {
+         for (n = 0; n < MAXWIN ; n++)
+           {
+             if (inlen[n] <= 0)
+               continue;
+             tmp = wtab[n]->ptyfd;
+              if (FD_ISSET(tmp, &w))
+                {
+                 if ((len = write(tmp, inbuf[n], inlen[n])) > 0)
+                   {
+                     if ((inlen[n] -= len) == 0)
+                     inbuf_ct--;
+                     bcopy(inbuf[n] + len, inbuf[n], inlen[n]);
+                   }
+                 if (--nsel == 0)
+                   break;
+               }
+           }
+       }
+      /* Read, process, and store the user input */
+      if (nsel && FD_ISSET(0, &r))
+       {
+          nsel--;
+         if (!HS)
+           RemoveStatus();
+         if (ESCseen)
+           {
+             buf[0] = Esc;
+             buflen = read(0, buf + 1, IOSIZE - 1) + 1;
+             ESCseen = 0;
+           }
+         else
+           buflen = read(0, buf, IOSIZE);
+         if (buflen < 0)
+           {
+             debug1("Read error: %d - SigHup()ing!\n", errno);
+             SigHup(SIGARG);
+             continue;
+           }
+         if (buflen == 0)
+           {
+             debug("Found EOF - SigHup()ing!\n");
+             SigHup(SIGARG);
+             continue;
+           }
+         bufp = buf;
+          if (in_ovl)
+           {
+             SetOvlCurr();
+             (*ovl_process)(&bufp, &buflen);
+           }
+         while (buflen > 0)
+           {
+             n = ForeNum;
+             len = inlen[n];
+             bufp = ProcessInput(bufp, &buflen, inbuf[n], &inlen[n],
+                                 sizeof *inbuf);
+             if (inlen[n] > 0 && len == 0)
+               inbuf_ct++;
+           }
+         if (inbuf_ct > 0)
+           continue;
+       }
+      if (GotSignal && !status)
+       {
+         SigHandler();
+         continue;
+       }
+#ifdef COPY_PASTE
+      /* Write the copybuffer contents first, if any. jw. */
+      if (pastelen > 0)
+       {
+         n = ForeNum;
+         debug1("writing pastebuffer (%d)\n", pastelen);
+         tmp = wtab[n]->ptyfd;
+         if (                  /* FD_ISSET(tmp, &w) && */
+             (len = write(tmp, pastebuffer,
+                          pastelen > IOSIZE ? IOSIZE : pastelen)) > 0)
+           {
+             pastebuffer += len;
+             pastelen -= len;
+             debug1("%d bytes pasted\n", len);
+             if (slowpaste > 0)
+               {
+                 struct timeval t;
+
+                  debug1("slowpaste %d\n", slowpaste);
+                 t.tv_usec = (long) (slowpaste * 1000);
+                 t.tv_sec = 0;
+                 select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
+               }
+             else
+               continue;
+           }
+         /* 
+          * We could not paste? Let's see if the pty did echo the lot.
+          * Then continue by processing some pty output.
+          */
+       }
+#endif
+      if (GotSignal && !status)
+       {
+         SigHandler();
+         continue;
+       }
+      /* Read and process the output from the window descriptors */
+      for (n = WinList; n != -1; n = p->WinLink)
+       {
+         p = wtab[n];
+         if (in_ovl && ovl_blockfore && n == ForeNum)
+           continue;
+         if (p->outlen)
+           WriteString(p, p->outbuf, p->outlen);
+         else if (nsel && FD_ISSET(p->ptyfd, &r))
+           {
+             nsel--;
+             if ((len = read(p->ptyfd, buf, IOSIZE)) == -1)
+               {
+#ifdef EWOULDBLOCK
+                 if (errno == EWOULDBLOCK)
+                   len = 0;
+#endif
+               }
+#if defined(TIOCPKT) && !defined(sgi)
+             if (buf[0])
+               {
+                 debug1("PAKET %x\n", buf[0]);
+                 if (buf[0] & TIOCPKT_NOSTOP)
+                   {
+                     NewAutoFlow(p, 0);
+                   }
+                 if (buf[0] & TIOCPKT_DOSTOP)
+                   {
+                     NewAutoFlow(p, 1);
+                   }
+               }
+             if (len > 1)
+               WriteString(p, buf + 1, len - 1);
+#else /* TIOCPKT && !sgi */
+             if (len > 0)
+               WriteString(p, buf, len);
+#endif /* TIOCPKT && !sgi */
+           }
+         if (p->bell == BELL_ON)
+           {
+             p->bell = BELL_DONE;
+             Msg(0, MakeWinMsg(BellString, n));
+             if (p->monitor == MON_FOUND)
+               p->monitor = MON_DONE;
+           }
+         else if (p->bell == BELL_VISUAL)
+           {
+             if (!BellDisplayed)
+               {
+                 p->bell = BELL_DONE;
+                 Msg(0, VisualBellString);
+                 BellDisplayed = 1;
+               }
+           }
+         else if (p->monitor == MON_FOUND)
+           {
+             p->monitor = MON_DONE;
+             Msg(0, MakeWinMsg(ActivityString, n));
+           }
+       }
+      if (GotSignal && !status)
+       SigHandler();
+#ifdef DEBUG
+      if (nsel)
+       debug1("Left over nsel: %d\n", nsel);
+#endif
+    }
+  /* NOTREACHED */
+}
+
+static void SigHandler()
+{
+  struct stat st;
+  while (GotSignal)
+    {
+      GotSignal = 0;
+      DoWait();
+#ifdef SYSV
+      signal(SIGCLD, SigChld);
+#endif
+    }
+  if (stat(SockPath, &st) == -1)
+    {
+      debug1("SigHandler: Yuck! cannot stat '%s'\n", SockPath);
+      if (!RecoverSocket())
+       {
+         debug("SCREEN cannot recover from corrupt Socket, bye\n");
+         Finit(1);
+       }
+      else
+       debug1("'%s' reconstructed\n", SockPath);
+    }
+  else
+    debug2("SigHandler: stat '%s' o.k. (%03o)\n", SockPath, st.st_mode);
+}
+
+#ifdef DEBUG
+int FEpanic;
+
+SIGTYPE FEChld(SIGDEFARG)
+{
+  FEpanic=1;
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+#endif
+
+static SIGTYPE SigChld(SIGDEFARG)
+{
+  debug("SigChld()\n");
+  GotSignal = 1;
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+
+SIGTYPE SigHup(SIGDEFARG)
+{
+  debug("SigHup()\n");
+  if (auto_detach)
+    Detach(D_DETACH);
+  else
+    Finit(0);
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+
+/*
+ * the frontend's Interrupt handler
+ * we forward SIGINT to the backend
+ */
+static SIGTYPE 
+AttacherSigInt(SIGDEFARG)
+{
+  Kill(MasterPid, SIGINT);
+  signal(SIGINT, AttacherSigInt);
+# ifndef SIGVOID
+  return (SIGTYPE) 0;
+# endif
+}
+
+
+/* 
+ * the backend's Interrupt handler
+ * we cannot insert the intrc directly, as we never know
+ * if fore and ForeNum are valid.
+ */
+static SIGTYPE SigInt(SIGDEFARG)
+{
+#if HAZARDOUS
+  char buf[1];
+
+  debug("SigInt()\n");
+  *buf = (char) intrc;
+  inlen[ForeNum] = 0;
+  if (fore && !in_ovl)
+    write(fore->ptyfd, buf, 1);
+#else
+  debug("SigInt() careful\n");
+  InterruptPlease = 1;
+  signal(SIGINT, SigInt);
+#endif
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+
+static SIGTYPE CoreDump(sig)
+int sig;
+{
+  setgid(getgid());
+  setuid(getuid());
+  unlink("core");
+  fprintf(stderr, "\r\n[screen caught signal %d.%s]\r\n", sig,
+#ifdef SHADOWPW
+          ""
+#else /* SHADOWPW */
+          " (core dumped)"
+#endif /* SHADOWPW */
+          );
+  fflush(stderr);
+  Kill(AttacherPid, SIG_BYE);
+#ifdef SHADOWPW
+  eexit(sig);
+#else /* SHADOWPW */
+  abort();
+#endif /* SHADOWPW */
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+
+static void DoWait()
+{
+  register int n, next, pid;
+#ifdef BSDWAIT
+  union wait wstat;
+#else
+  int wstat;
+#endif
+
+#ifdef BSDJOBS
+# ifndef BSDWAIT
+  while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
+# else
+  while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
+# endif
+#else  /* BSDJOBS */
+  while ((pid = wait(&wstat)) < 0)
+    if (errno != EINTR)
+      break;
+  if (pid >= 0)
+#endif /* BSDJOBS */
+    {
+      for (n = WinList; n != -1; n = next)
+       {
+         next = wtab[n]->WinLink;
+         if (pid == wtab[n]->wpid)
+           {
+#ifdef BSDJOBS
+             if (WIFSTOPPED(wstat))
+               {
+# ifdef NETHACK        
+                  if (nethackflag)
+                   Msg(0, "You regain consciousness.");
+                 else
+# endif /* NETHACK */
+                 Msg(0, "Child has been stopped, restarting.");
+                 debug1("WIFSTOPPED: %d SIGCONT\n", wtab[n]->wpid);
+                 if (killpg(wtab[n]->wpid, SIGCONT))
+                   kill(wtab[n]->wpid, SIGCONT);
+               }
+             else
+#endif
+               KillWindow(n);
+           }
+       }
+    }
+}
+
+void KillWindow(n)
+int n;
+{
+  register int i;
+  /*
+   * Remove window from linked list.
+   */
+  if (n == WinList)    /* WinList = ForeNum */
+    {
+      RemoveStatus();
+      WinList = fore->WinLink;
+      fore = 0;
+    }
+  else
+    {
+      i = WinList;
+      while (wtab[i]->WinLink != n)
+       i = wtab[i]->WinLink;
+      wtab[i]->WinLink = wtab[n]->WinLink;
+    }
+  FreeWindow(wtab[n]);
+  wtab[n] = 0;
+  if (inlen[n] > 0)
+    {
+      inlen[n] = 0;
+      inbuf_ct--;
+    }
+  /*
+   * If the foreground window disappeared check the head of the linked list
+   * of windows for the most recently used window. If no window is alive at
+   * all, exit.
+   */
+  if (WinList == -1)
+    Finit(0);
+  if (!fore)
+    SwitchWindow(WinList);
+}
+
+static SIGTYPE Finit(i)
+int i;
+{
+  register int n, next;
+
+#ifdef SYSV
+  signal(SIGCLD, SIG_IGN);
+#else
+  signal(SIGCHLD, SIG_IGN);
+#endif
+  signal(SIGHUP, SIG_IGN);
+  debug1("Finit(%d);\n", i);
+  for (n = WinList; n != -1; n = next)
+    {
+      next = wtab[n]->WinLink;
+      FreeWindow(wtab[n]);
+    }
+  FinitTerm();
+  SetTTY(0, &OldMode);
+#ifdef UTMPOK
+  RestoreLoginSlot();
+#endif
+  printf("\n[screen is terminating]\n");
+  freetty();
+  if (ServerSocket != -1)
+    {
+      debug1("we unlink(%s)\n", SockPath);
+      (void) unlink(SockPath);
+    }
+  Kill(AttacherPid, SIG_BYE);
+  exit(i);
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+
+void
+eexit(e)
+int e;
+{
+  if (ServerSocket != -1)
+    {
+      debug1("we unlink(%s)\n", SockPath);
+      (void) unlink(SockPath);
+    }
+  exit(e);
+}
+
+static void InitKeytab()
+{
+  register unsigned int i;
+
+  for (i = 0; i < sizeof(ktab)/sizeof(*ktab); i++)
+    ktab[i].type = KEY_IGNORE;
+
+  ktab['h'].type = ktab[Ctrl('h')].type = KEY_HARDCOPY;
+#ifdef BSDJOBS
+  ktab['z'].type = ktab[Ctrl('z')].type = KEY_SUSPEND;
+#endif
+  ktab['c'].type = ktab[Ctrl('c')].type = KEY_SHELL;
+  ktab[' '].type = ktab[Ctrl(' ')].type =
+    ktab['n'].type = ktab[Ctrl('n')].type = KEY_NEXT;
+  ktab['-'].type = ktab['p'].type = ktab[Ctrl('p')].type = KEY_PREV;
+  ktab['k'].type = ktab[Ctrl('k')].type = KEY_KILL;
+  ktab['l'].type = ktab[Ctrl('l')].type = KEY_REDISPLAY;
+  ktab['w'].type = ktab[Ctrl('w')].type = KEY_WINDOWS;
+  ktab['v'].type = ktab[Ctrl('v')].type = KEY_VERSION;
+  ktab['q'].type = ktab[Ctrl('q')].type = KEY_XON;
+  ktab['s'].type = ktab[Ctrl('s')].type = KEY_XOFF;
+  ktab['t'].type = ktab[Ctrl('t')].type = KEY_TIME;
+  ktab['i'].type = ktab[Ctrl('i')].type = KEY_INFO;
+  ktab['m'].type = ktab[Ctrl('m')].type = KEY_LASTMSG;
+  ktab['A'].type = KEY_AKA, ktab['A'].args = NULL;
+  ktab['L'].type = KEY_LOGIN;
+  ktab[','].type = KEY_LICENSE;
+  ktab['W'].type = KEY_WIDTH;
+  ktab['.'].type = KEY_TERMCAP;
+  ktab[Ctrl('\\')].type = KEY_QUIT;
+  ktab['d'].type = ktab[Ctrl('d')].type = KEY_DETACH;
+  ktab['r'].type = ktab[Ctrl('r')].type = KEY_WRAP;
+  ktab['f'].type = ktab[Ctrl('f')].type = KEY_FLOW;
+  ktab['C'].type = KEY_CLEAR;
+  ktab['Z'].type = KEY_RESET;
+  ktab['H'].type = KEY_LOGTOGGLE;
+  if (Esc != MetaEsc)
+    ktab[Esc].type = KEY_OTHER;
+  else
+    ktab[Esc].type = KEY_IGNORE;
+  ktab['M'].type = KEY_MONITOR;
+  ktab['?'].type = KEY_HELP;
+  for (i = 0; i <= 9; i++)
+    ktab['0' + i].type = (enum keytype) (i + (int)KEY_0);
+  ktab[Ctrl('G')].type = KEY_VBELL;
+  ktab[':'].type = KEY_COLON;
+#ifdef COPY_PASTE
+  ktab['['].type = ktab[Ctrl('[')].type = KEY_COPY;
+  ktab[']'].type = ktab[Ctrl(']')].type = KEY_PASTE;
+  ktab['{'].type = KEY_HISTORY;
+  ktab['}'].type = KEY_HISTNEXT;
+  ktab['>'].type = KEY_WRITE_BUFFER;
+  ktab['<'].type = KEY_READ_BUFFER;
+  ktab['='].type = KEY_REMOVE_BUFFERS;
+#endif
+#ifdef POW_DETACH
+  ktab['D'].type = KEY_POW_DETACH;
+#endif
+#ifdef LOCK
+  ktab['x'].type = ktab[Ctrl('x')].type = KEY_LOCK;
+#endif
+}
+
+/*
+ * this is a braindamaged hack: if (obuf == NULL) then we provided
+ * a key_type as a second char in ibuf. not a key.
+ */
+char *ProcessInput(ibuf, pilen, obuf, polen, obuf_size)
+char *ibuf, *obuf;
+register int *pilen, *polen, obuf_size;
+{
+  register int n;
+  register enum keytype k;
+  register char *s, *p;
+  char buf[2];
+  int newwidth;
+
+  if (!obuf)
+    obuf_size = 0;
+
+  for (s = ibuf, p = obuf + *polen; *pilen > 0; --*pilen, s++)
+    {
+      if (*s == Esc)
+       {
+         debug2("'%c %c ", s[0], s[1]);
+         debug2("%c %c' ", s[2], s[3]);
+         if (*pilen > 1)
+           {
+             --*pilen;
+             s++;
+#if defined(GOULD_NP1)
+             k = (obuf)?(ktab[*s].type):(enum keytype)(int)(*s);
+#else
+             k = (obuf)?(ktab[*s].type):(enum keytype)(*s);
+#endif
+             debug2("Processinput C-A %02x '%c' ", k, k);
+             debug1("%s\n", (obuf)?"std":"NOOBUF");
+             if (*s == MetaEsc)
+               {
+                 if (*polen < obuf_size)
+                   {
+                     *p++ = Esc;
+                     ++*polen;
+                   }
+               }
+             else if ((int)k >= (int)KEY_0 && (int)k <= (int)KEY_9)
+               SwitchWindow((int)k - (int)KEY_0);
+             else
+               switch (k)
+                 {
+                 case KEY_TERMCAP:
+                   WriteFile(DUMP_TERMCAP);
+                   break;
+                 case KEY_HARDCOPY:
+                   WriteFile(DUMP_HARDCOPY);
+                   break;
+                 case KEY_LOGTOGGLE:
+                   LogToggle();
+                   break;
+#ifdef BSDJOBS
+                 case KEY_SUSPEND:
+                   *pilen = 0;
+                   Detach(D_STOP);
+                   break;
+#endif
+                 case KEY_SHELL:
+                   debug("calling MakeWindow with shell\n");
+                   MakeWindow(shellaka, ShellArgs, allflag, default_flow,
+                              0, (char *) 0, loginflag, -1, (char *)0);
+                   break;
+                 case KEY_NEXT:
+                   if (MoreWindows())
+                     SwitchWindow(NextWindow());
+                   break;
+                 case KEY_PREV:
+                   if (MoreWindows())
+                     SwitchWindow(PreviousWindow());
+                   break;
+                 case KEY_KILL:
+                   KillWindow(n = ForeNum);
+#ifdef NETHACK
+                   if (nethackflag)
+                     Msg(0, "You destroy poor window %d", n);
+#endif
+                   break;
+                 case KEY_QUIT:
+                   Finit(0);
+                   /* NOTREACHED */
+                 case KEY_DETACH:
+                   *pilen = 0;
+                   Detach(D_DETACH);
+                   break;
+#ifdef POW_DETACH
+                 case KEY_POW_DETACH:
+                   *pilen = 0;
+                   if (obuf)
+                     {
+                       buf[0] = *s;
+                       buf[1] = '\0';
+                       Msg(0, buf);
+                       read(0, buf, 1);
+                       if (*buf != *s)
+                         {
+                           write(1, "\007", 1);
+                           RemoveStatus();
+#ifdef NETHACK
+                           if (nethackflag)
+                              Msg(0, "The blast of disintegration whizzes by you!");
+#endif
+                           break;
+                         }
+                     }
+                   Detach(D_POWER); /* detach and kill Attacher's
+                                     * parent   */
+                   break;
+#endif
+                 case KEY_REDISPLAY:
+                   Activate(0);
+                   break;
+                 case KEY_WINDOWS:
+                   ShowWindows();
+                   break;
+                 case KEY_VERSION:
+                   Msg(0, "screen %d.%.2d.%.2d%s (%s) %s", REV, VERS,
+                       PATCHLEVEL, STATE, ORIGIN, DATE);
+                   break;
+                 case KEY_TIME:
+                   ShowTime();
+                   break;
+                 case KEY_INFO:
+                   ShowInfo();
+                   break;
+                 case KEY_OTHER:
+                   if (MoreWindows())
+                     SwitchWindow(fore->WinLink);
+                   break;
+                 case KEY_XON:
+                   if (*polen < obuf_size)
+                     {
+                       *p++ = Ctrl('q');
+                       ++*polen;
+                     }
+                   break;
+                 case KEY_XOFF:
+                   if (*polen < obuf_size)
+                     {
+                       *p++ = Ctrl('s');
+                       ++*polen;
+                     }
+                   break;
+#ifdef LOCK
+                 case KEY_LOCK:
+                   Detach(D_LOCK); /* do it micha's way */
+                   break;
+#endif
+                 case KEY_WIDTH:
+                   if (Z0 || WS)
+                     {
+                       if (fore->width == Z0width)
+                         newwidth = Z1width;
+                       else if (fore->width == Z1width)
+                         newwidth = Z0width;
+                       else if (fore->width > (Z0width+Z1width)/2)
+                         newwidth = Z0width;
+                       else
+                         newwidth = Z1width;
+                       ChangeWindowSize(fore, newwidth, fore->height);
+                       Activate(fore->norefresh);
+                     }
+                   else
+                     Msg(0, "Your termcap does not specify how to change the terminal's width.");
+                   break;
+                 case KEY_LOGIN:
+                   SlotToggle(0);
+                   break;
+                 case KEY_AKA:
+                   if (!ktab[*s].args)
+                     InputAKA();
+                   else
+                     strncpy(fore->cmd + fore->akapos, ktab[*s].args[0], 20);
+                   break;
+                 case KEY_COLON:
+                   InputColon();
+                   break;
+                 case KEY_LASTMSG:
+                   Msg(0, "%s", LastMsg);
+                   break;
+                 case KEY_SET:
+                   DoSet(ktab[*s].args);
+                   break;
+                 case KEY_SCREEN:
+                   debug3("KEY_SCREEN DoSc(, ktab[%d].args(='%s','%s')...)\n",
+                          *s, ktab[*s].args[0], ktab[*s].args[1]);
+                   DoScreen("key", ktab[*s].args);
+                   break;
+                 case KEY_CREATE:
+                   debug2("KEY_CREATE MaWi(0, ktab[%d].args(='%s')...)\n",
+                          *s, ktab[*s].args);
+                   MakeWindow((char *) 0, ktab[*s].args, allflag, default_flow, 0, (char *) 0, loginflag, -1, (char *)0);
+                   break;
+                 case KEY_WRAP:
+                   fore->wrap = !fore->wrap;
+                   Msg(0, "%cwrap", fore->wrap ? '+' : '-');
+                   break;
+                 case KEY_FLOW:
+                   if (fore->flow & FLOW_AUTOFLAG)
+                     fore->flow = (fore->flow & FLOW_AUTO) | FLOW_NOW;
+                   else if (fore->flow & FLOW_NOW)
+                     fore->flow &= ~FLOW_NOW;
+                   else
+                     fore->flow = fore->flow ? FLOW_AUTOFLAG|FLOW_AUTO|FLOW_NOW : FLOW_AUTOFLAG;
+                   SetFlow(fore->flow & FLOW_NOW);
+                   Msg(0, "%cflow%s", (fore->flow & FLOW_NOW) ? '+' : '-',
+                       (fore->flow & FLOW_AUTOFLAG) ? "(auto)" : "");
+                   break;
+                 case KEY_CLEAR:
+                   if (fore->state == LIT)
+                     WriteString(fore, "\033[H\033[J", 6);
+                   break;
+                 case KEY_RESET:
+                   if (fore->state == LIT)
+                     WriteString(fore, "\033c", 2);
+                   break;
+                 case KEY_MONITOR:
+                   if (fore->monitor == MON_OFF)
+                     {
+                       fore->monitor = MON_ON;
+                       Msg(0,
+                           "Window %d is now being monitored for all activity.",
+                           ForeNum);
+                     }
+                   else
+                     {
+                       fore->monitor = MON_OFF;
+                       Msg(0,
+                           "Window %d is no longer being monitored for activity.",
+                           ForeNum);
+                     }
+                   break;
+                 case KEY_HELP:
+                   display_help();
+                   break;
+                 case KEY_LICENSE:
+                   display_copyright();
+                   break;
+#ifdef COPY_PASTE
+                 case KEY_COPY:
+                   (void) MarkRoutine(PLAIN);
+                   break;
+                 case KEY_HISTNEXT:
+                   if (MarkRoutine(CRAZY))
+                     if (copybuffer != NULL)
+                       {
+                         pastelen = copylen;
+                         pastebuffer = copybuffer;
+                         debug("histnext\n");
+                       }
+                   break;
+                 case KEY_HISTORY:
+                   if (MarkRoutine(TRICKY))
+                     if (copybuffer != NULL)
+                       {
+                         pastelen = copylen;
+                         pastebuffer = copybuffer;
+                         debug1("history new copylen: %d\n", pastelen);
+                       }
+                   break;
+                 case KEY_PASTE:
+                   if (copybuffer == NULL)
+                     {
+#ifdef NETHACK
+                       if (nethackflag)
+                         Msg(0, "Nothing happens.");
+                       else
+#endif
+                       Msg(0, "empty buffer");
+                       copylen = 0;
+                       break;
+                     }
+                   pastelen = copylen;
+                   pastebuffer = copybuffer;
+                   break;
+                 case KEY_WRITE_BUFFER:
+                   if (copybuffer == NULL)
+                     {
+#ifdef NETHACK
+                       if (nethackflag)
+                         Msg(0, "Nothing happens.");
+                       else
+#endif
+                       Msg(0, "empty buffer");
+                       copylen = 0;
+                       break;
+                     }
+                   WriteFile(DUMP_EXCHANGE);
+                   break;
+                 case KEY_READ_BUFFER:
+                   ReadFile();
+                   break;
+                 case KEY_REMOVE_BUFFERS:
+                   KillBuffers();
+                   break;
+#endif                         /* COPY_PASTE */
+                 case KEY_VBELL:
+                   if (visual_bell)
+                     {
+                       visual_bell = 0;
+                       Msg(0, "switched to audible bell");
+                     }
+                   else
+                     {
+                       visual_bell = 1;
+                       Msg(0, "switched to visual bell");
+                     }
+                   break;
+                  default:
+                   break;
+                 }
+           }
+         else
+           ESCseen = 1;
+         --*pilen;
+         s++;
+         break;
+       }
+      else if (*polen < obuf_size)
+       {
+         *p++ = *s;
+         ++*polen;
+       }
+    }
+  return (s);
+}
+
+/* Send a terminal report as if it were typed. */ 
+void
+Report(wp, fmt, n1, n2)
+struct win *wp;
+char *fmt;
+int n1, n2;
+{
+  register int n, len;
+  char rbuf[40];
+
+  sprintf(rbuf, fmt, n1, n2);
+  len = strlen(rbuf);
+
+  for (n = 0; n < MAXWIN; n++)
+    {
+      if (wp == wtab[n])
+       {
+         if ((unsigned)(inlen[n] + len) <= sizeof *inbuf)
+           {
+             bcopy(rbuf, inbuf[n] + inlen[n], len);
+             if (inlen[n] == 0)
+               inbuf_ct++;
+             inlen[n] += len;
+           }
+         break;
+       }
+    }/* for */
+}
+
+void
+SwitchWindow(n)
+int n;
+{
+  debug1("SwitchWindow %d\n", n);
+  if (!wtab[n])
+    {
+      ShowWindows();
+      return;
+    }
+  if (wtab[n] == fore)
+    {
+      Msg(0, "This IS window %d.", n);
+      return;
+    }
+  SetForeWindow(n);
+  if (!Detached && !in_ovl)
+    Activate(fore->norefresh);
+}
+
+static void SetForeWindow(n)
+int n;
+{
+  /*
+   * If we come from another window, make it inactive.
+   */
+  if (fore)
+    fore->active = 0;
+  ForeNum = n;
+  fore = wtab[n];
+  if (!Detached && !in_ovl)
+    fore->active = 1;
+  /*
+   * Place the window at the head of the most-recently-used list.
+   */
+  if ((n = WinList) != ForeNum)
+    {
+      /*
+       * we had a bug here. we sometimes ran into n = -1; and crashed.
+       * (this is not the perfect fix. "if (...) break;" inserted. jw.)
+       */
+      while (wtab[n]->WinLink != ForeNum)
+       {
+         if (wtab[n]->WinLink == -1)
+           break;
+         n = wtab[n]->WinLink;
+       }
+      wtab[n]->WinLink = fore->WinLink;
+      fore->WinLink = WinList;
+      WinList = ForeNum;
+    }
+}
+
+static int NextWindow()
+{
+  register struct win **pp;
+
+  for (pp = wtab + ForeNum + 1; pp != wtab + ForeNum; ++pp)
+    {
+      if (pp == wtab + MAXWIN)
+       pp = wtab;
+      if (*pp)
+       break;
+    }
+  return pp - wtab;
+}
+
+static int PreviousWindow()
+{
+  register struct win **pp;
+
+  for (pp = wtab + ForeNum - 1; pp != wtab + ForeNum; --pp)
+    {
+      if (pp < wtab)
+       pp = wtab + MAXWIN - 1;
+      if (*pp)
+       break;
+    }
+  return pp - wtab;
+}
+
+static int MoreWindows()
+{
+  if (fore->WinLink != -1)
+    return 1;
+#ifdef NETHACK
+  if (nethackflag)
+    Msg(0, "You cannot escape from window %d!", ForeNum);
+  else
+#endif
+  Msg(0, "No other window.");
+  return 0;
+}
+
+static void FreeWindow(wp)
+struct win *wp;
+{
+#ifdef UTMPOK
+  RemoveUtmp(wp);
+#endif
+#ifdef SUIDROOT
+  (void) chmod(wp->tty, 0666);
+  (void) chown(wp->tty, 0, 0);
+#endif
+  close(wp->ptyfd);
+  if (wp->logfp != NULL)
+    fclose(wp->logfp);
+  ChangeWindowSize(wp, 0, 0);
+  Free(wp);
+}
+
+int
+MakeWindow(prog, args, aflag, flowflag, StartAt, dir, lflag, histheight, term)
+char *prog, **args, *dir;
+int aflag, flowflag, StartAt, lflag, histheight;
+char *term; /* if term is nonzero we assume it "vt100" or the like.. */
+{
+  register struct win **pp, *p;
+  register int n, f;
+  int tf, tlflag;
+  char ebuf[10];
+#ifndef TIOCSWINSZ
+  char libuf[20], cobuf[20];
+#endif
+  char tebuf[25];
+
+  pp = wtab + StartAt;
+  do
+    {
+      if (*pp == 0)
+       break;
+      if (++pp == wtab + MAXWIN)
+       pp = wtab;
+    } while (pp != wtab + StartAt);
+  if (*pp)
+    {
+      Msg(0, "No more windows.");
+      return -1;
+    }
+
+   if (((tlflag = lflag) == -1) && ((tlflag = loginflag) == -1))
+       tlflag = LOGINDEFAULT;
+
+#ifdef USRLIMIT
+  /*
+   * Count current number of users, if logging windows in.
+   */
+  if (tlflag == 1 && CountUsers() >= USRLIMIT)
+    {
+      Msg(0, "User limit reached.  Window will not be logged in.");
+      tlflag = 0;
+    }
+#endif
+  n = pp - wtab;
+  debug1("Makewin creating %d\n", n);
+  if ((f = OpenPTY()) == -1)
+    {
+      Msg(0, "No more PTYs.");
+      return -1;
+    }
+#ifdef SYSV
+  (void) fcntl(f, F_SETFL, O_NDELAY);
+#else
+  (void) fcntl(f, F_SETFL, FNDELAY);
+#endif
+#ifdef TIOCPKT
+    {
+# ifdef sgi
+      /*
+       * on IRIX 3.3, regardless of stream head's read mode (RNORM/RMSGN/RMSGD)
+       * we loose data in TIOCPKT mode if our buffer is too small (IOSIZE)
+       * to hold the whole packet at first read().
+       * (Marc Boucher)
+       */
+      int flag = 0;
+# else /* sgi */
+      int flag = 1;
+# endif /* sgi */
+
+      if (ioctl(f, TIOCPKT, &flag))
+       {
+         Msg(errno, "TIOCPKT ioctl");
+         close(f);
+         return -1;
+       }
+    }
+#endif
+  if ((p = (struct win *) malloc(sizeof(struct win))) == 0)
+    {
+      close(f);
+      Msg_nomem;
+      return -1;
+    }
+  bzero((char *) p, (int) sizeof(struct win));
+  p->ptyfd = f;
+  p->aflag = aflag;
+  if (flowflag < 0)
+    flowflag = default_flow;
+  p->flow = flowflag | ((flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
+  if (!prog)
+    prog = Filename(args[0]);
+  strncpy(p->cmd, prog, MAXSTR - 1);
+  if ((prog = rindex(p->cmd, '|')) != NULL)
+    {
+      *prog++ = '\0';
+      prog += strlen(prog);
+      p->akapos = prog - p->cmd;
+      p->autoaka = 0;
+    }
+  else
+    p->akapos = 0;
+  p->monitor = default_monitor;
+  p->norefresh = 0;
+  strncpy(p->tty, TtyName, MAXSTR - 1);
+#ifdef SUIDROOT
+  (void) chown(TtyName, real_uid, real_gid);
+# ifdef UTMPOK
+  (void) chmod(TtyName, tlflag ? TtyMode : (TtyMode & ~022));
+# else
+  (void) chmod(TtyName, TtyMode);
+# endif
+#endif
+
+  if (histheight < 0)
+    histheight = default_histheight;
+  if (ChangeWindowSize(p, default_width, default_height))
+    {
+      FreeWindow(p);
+      return -1;
+    }
+  ChangeScrollback(p, histheight, default_width);
+  ResetScreen(p);
+  debug("forking...\n");
+  switch (p->wpid = fork())
+    {
+    case -1:
+      Msg(errno, "fork");
+      FreeWindow(p);
+      return -1;
+    case 0:
+      signal(SIGHUP, SIG_DFL);
+      signal(SIGINT, SIG_DFL);
+      signal(SIGQUIT, SIG_DFL);
+      signal(SIGTERM, SIG_DFL);
+#ifdef BSDJOBS
+      signal(SIGTTIN, SIG_DFL);
+      signal(SIGTTOU, SIG_DFL);
+#endif
+      setuid(real_uid);
+      setgid(real_gid);
+      if (dir && chdir(dir) == -1)
+       {
+         SendErrorMsg("Cannot chdir to %s: %s", dir, sys_errlist[errno]);
+         eexit(1);
+       }
+
+      freetty();
+      if ((tf = open(TtyName, O_RDWR)) == -1)
+       {
+         SendErrorMsg("Cannot open %s: %s", TtyName, sys_errlist[errno]);
+         eexit(1);
+       }
+#ifdef SVR4
+      if (ioctl(tf, I_PUSH, "ptem"))
+       {
+         SendErrorMsg("Cannot I_PUSH ptem %s %s", TtyName, sys_errlist[errno]);
+         eexit(1);
+       }
+      if (ioctl(tf, I_PUSH, "ldterm"))
+       {
+         SendErrorMsg("Cannot I_PUSH ldterm %s %s", TtyName, sys_errlist[errno]);
+         eexit(1);
+       }
+      if (ioctl(tf, I_PUSH, "ttcompat"))
+       {
+         SendErrorMsg("Cannot I_PUSH ttcompat %s %s", TtyName, sys_errlist[errno]);
+         eexit(1);
+       }
+#endif
+      (void) dup2(tf, 0);
+      (void) dup2(tf, 1);
+      (void) dup2(tf, 2);
+#ifdef DEBUG
+      dfp = stderr;
+#endif
+      closeallfiles();
+      fgtty();
+#ifdef TIOCSWINSZ
+      glwz.ws_col = p->width;
+      glwz.ws_row = p->height;
+      (void) ioctl(0, TIOCSWINSZ, &glwz);
+#else
+      sprintf(libuf, "LINES=%d", p->height);
+      sprintf(cobuf, "COLUMNS=%d", p->width);
+      NewEnv[4] = libuf;
+      NewEnv[5] = cobuf;
+#endif
+      SetTTY(0, &OldMode);
+      if (aflag)
+        NewEnv[2] = MakeTermcap(1);
+      else
+        NewEnv[2] = Termcap;
+      if (term && *term && strcmp(screenterm, term) &&
+         (strlen(term) < 20))
+       {
+          char *s1, *s2, tl;
+
+         sprintf(tebuf, "TERM=%s", term);
+         debug2("Makewindow %d with %s\n", n, tebuf);
+          tl = strlen(term);
+         NewEnv[1] = tebuf;
+          if (s1 = index(Termcap, '|'))
+           {
+             if (s2 = index(++s1, '|'))
+               {
+                 if (strlen(Termcap) - (s2 - s1) + tl < 1024)
+                   {
+                     bcopy(s2, s1 + tl, strlen(s2) + 1);
+                     bcopy(term, s1, tl);
+                   }
+               }
+            }
+       }
+      sprintf(ebuf, "WINDOW=%d", n);
+      NewEnv[3] = ebuf;
+
+      execvpe(*args, args, NewEnv);
+      SendErrorMsg("Cannot exec %s: %s", *args, sys_errlist[errno]);
+      exit(1);
+    } /* end fork switch */
+  /*
+   * Place the newly created window at the head of the most-recently-used list.
+   */
+  *pp = p;
+  p->WinLink = WinList;
+  WinList = n;
+  HasWindow = 1;
+#ifdef UTMPOK
+  debug1("MakeWindow will %slog in.\n", tlflag?"":"not ");
+  if (tlflag == 1)
+    SetUtmp(p, n);
+  else
+    p->slot = (slot_t) -1;
+#endif
+  SetForeWindow(n);
+  Activate(0);
+  return n;
+}
+
+static void execvpe(prog, args, env)
+char *prog, **args, **env;
+{
+  register char *path, *p;
+  char buf[1024];
+  char *shargs[MAXARGS + 1];
+  register int i, eaccess = 0;
+
+  if (prog[0] == '/')
+    path = "";
+  else if ((path = getenv("PATH")) == 0)
+    path = DefaultPath;
+  do
+    {
+      p = buf;
+      while (*path && *path != ':')
+       *p++ = *path++;
+      if (p > buf)
+       *p++ = '/';
+      strcpy(p, prog);
+      if (*path)
+       ++path;
+      execve(buf, args, env);
+      switch (errno)
+       {
+       case ENOEXEC:
+         shargs[0] = DefaultShell;
+         shargs[1] = buf;
+         for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
+           ;
+         execve(DefaultShell, shargs, env);
+         return;
+       case EACCES:
+         eaccess = 1;
+         break;
+       case ENOMEM:
+       case E2BIG:
+       case ETXTBSY:
+         return;
+       }
+    } while (*path);
+  if (eaccess)
+    errno = EACCES;
+}
+
+
+static void LogToggle()
+{
+  char buf[1024];
+
+  sprintf(buf, "screenlog.%d", ForeNum);
+  if (fore->logfp != NULL)
+    {
+      Msg(0, "Logfile \"%s\" closed.", buf);
+      fclose(fore->logfp);
+      fore->logfp = NULL;
+      return;
+    }
+  if ((fore->logfp = secfopen(buf, "a")) == NULL)
+    {
+      Msg(errno, "Error opening logfile \"%s\"", buf);
+      return;
+    }
+  Msg(0, "%s logfile \"%s\"", ftell(fore->logfp) ? "Appending to" : "Creating", buf);
+}
+
+#ifdef NOREUID
+static int UserPID;
+static SIGTYPE (*Usersigcld)__P(SIGPROTOARG);
+#endif
+static int UserSTAT;
+
+int UserContext()
+{
+#ifdef NOREUID
+  if (eff_uid == real_uid)
+    return(1);
+# ifdef SYSV
+  Usersigcld = signal(SIGCLD, SIG_DFL);
+# else
+  Usersigcld = signal(SIGCHLD, SIG_DFL);
+# endif
+  debug("UserContext: forking.\n");
+  switch (UserPID = fork())
+    {
+    case -1:
+      Msg(errno, "fork");
+      return -1;
+    case 0:
+      signal(SIGHUP, SIG_DFL);
+      signal(SIGINT, SIG_IGN);
+      signal(SIGQUIT, SIG_DFL);
+      signal(SIGTERM, SIG_DFL);
+# ifdef BSDJOBS
+      signal(SIGTTIN, SIG_DFL);
+      signal(SIGTTOU, SIG_DFL);
+# endif
+      setuid(real_uid);
+      setgid(real_gid);
+      return 1;
+    default:
+      return 0;
+    }
+#else
+  setreuid(eff_uid, real_uid);
+  setregid(eff_gid, real_gid);
+  return 1;
+#endif
+}
+
+void
+UserReturn(val)
+int val;
+{
+#if defined(NOREUID)
+  if (eff_uid == real_uid)
+    UserSTAT = val;
+  else
+    exit(val);
+#else
+  setreuid(real_uid, eff_uid);
+  setregid(real_gid, eff_gid);
+  UserSTAT = val;
+#endif
+}
+
+int UserStatus()
+{
+#ifdef NOREUID
+  int i;
+# ifdef BSDWAIT
+  union wait wstat;
+# else
+  int wstat;
+# endif
+
+  if (eff_uid == real_uid)
+    return UserSTAT;
+  if (UserPID < 0)
+    return -1;
+  while ((errno = 0, i = wait(&wstat)) != UserPID)
+    if (i < 0 && errno != EINTR)
+      break;
+# ifdef SYSV
+  (void) signal(SIGCLD, Usersigcld);
+# else
+  (void) signal(SIGCHLD, Usersigcld);
+# endif
+  if (i == -1)
+    return -1;
+  return (WEXITSTATUS(wstat));
+#else
+  return UserSTAT;
+#endif
+}
+
+static void ShowWindows()
+{
+  char buf[1024];
+  register char *s;
+  register struct win **pp, *p;
+  register int i, OtherNum = fore->WinLink;
+  register char *cmd;
+
+  for (i = 0, s = buf, pp = wtab; pp < wtab + MAXWIN; ++i, ++pp)
+    {
+      if ((p = *pp) == 0)
+       continue;
+
+      if (p->akapos)
+       {
+         if (*(p->cmd + p->akapos) && *(p->cmd + p->akapos - 1) != ':')
+           cmd = p->cmd + p->akapos;
+         else
+           cmd = p->cmd + strlen(p->cmd) + 1;
+       }
+      else
+       cmd = p->cmd;
+      if (s - buf + 5 + strlen(cmd) > fore->width - 1)
+       break;
+      if (s > buf)
+       {
+         *s++ = ' ';
+         *s++ = ' ';
+       }
+      *s++ = i + '0';
+      if (i == ForeNum)
+       *s++ = '*';
+      else if (i == OtherNum)
+       *s++ = '-';
+      if (p->monitor == MON_DONE)
+       *s++ = '@';
+      if (p->bell == BELL_DONE)
+       *s++ = '!';
+#ifdef UTMPOK
+      if (p->slot != (slot_t) 0 && p->slot != (slot_t) -1)
+       *s++ = '$';
+#endif
+      if (p->logfp != NULL)
+       {
+         strcpy(s, "(L)");
+         s += 3;
+       }
+      *s++ = ' ';
+      strcpy(s, cmd);
+      s += strlen(s);
+      if (i == ForeNum)
+       {
+         /* 
+          * this is usually done by Activate(), but when looking
+          * on your current window, you may get annoyed, as there is still
+          * that temporal '!' and '@' displayed.
+          * So we remove that after displaying it once.
+          */
+         p->bell = BELL_OFF;
+         if (p->monitor != MON_OFF)
+           p->monitor = MON_ON;
+       }
+    }
+  *s++ = ' ';
+  *s = '\0';
+  Msg(0, "%s", buf);
+}
+
+#ifdef LOADAV_3LONGS
+extern long loadav[3];
+#else
+# ifdef LOADAV_4LONGS
+extern long loadav[4];
+# else
+#  ifdef LOADAV_NEXT
+extern float loadav;
+#  else
+extern double loadav[3];
+#  endif
+# endif
+#endif
+extern avenrun;
+
+static void ShowTime()
+{
+  char buf[512];
+#ifdef LOADAV
+  char *p;
+#endif
+  struct tm *tp;
+  time_t now;
+
+  (void) time(&now);
+  tp = localtime(&now);
+  sprintf(buf, "%2d:%02.2d:%02.2d %s", tp->tm_hour, tp->tm_min, tp->tm_sec,
+         HostName);
+#ifdef LOADAV
+  if (avenrun && GetAvenrun())
+    {
+      p = buf + strlen(buf);
+# ifdef LOADAV_3LONGS
+      sprintf(p, " %2.2f %2.2f %2.2f", (double) loadav[0] / FSCALE,
+             (double) loadav[1] / FSCALE, (double) loadav[2] / FSCALE);
+# else
+#  ifdef LOADAV_4LONGS
+      sprintf(p, " %2.2f %2.2f %2.2f %2.2f", (double) loadav[0] / 100,
+             (double) loadav[1] / 100, (double) loadav[2] / 100,
+             (double) loadav[3] / 100);
+#  else
+#   ifdef LOADAV_NEXT
+      sprintf(p, " %2.2f", loadav);
+#   else
+#    ifdef apollo
+      sprintf(p, " %2.2f %2.2f %2.2f", loadav[0]/65536.0, loadav[1]/65536.0,
+             loadav[2]/65536.0);
+#    else
+      sprintf(p, " %2.2f %2.2f %2.2f", loadav[0], loadav[1], loadav[2]);
+#    endif /* apollo */
+#   endif /* LOADAV_NEXT */
+#  endif /* LOADAV_4LONGS */
+# endif /* LOADAV_3LONGS */
+    }
+#endif /* LOADAV */
+  Msg(0, "%s", buf);
+}
+
+static void ShowInfo()
+{
+  char buf[512], *p;
+  register struct win *wp = fore;
+  register int i;
+
+  sprintf(buf, "(%d,%d)/(%d,%d)+%d %c%sflow %cins %corg %cwrap %capp %clog %cmon %cr",
+         wp->x + 1, wp->y + 1, wp->width, wp->height,
+         wp->histheight,
+         (wp->flow & FLOW_NOW) ? '+' : '-',
+         (wp->flow & FLOW_AUTOFLAG) ? "" : ((wp->flow & FLOW_AUTO) ? "(+)" : "(-)"),
+         wp->insert ? '+' : '-', wp->origin ? '+' : '-',
+         wp->wrap ? '+' : '-', wp->keypad ? '+' : '-',
+         (wp->logfp != NULL) ? '+' : '-',
+         (wp->monitor != MON_OFF) ? '+' : '-',
+         wp->norefresh ? '-' : '+');
+  if (ISO2022)
+    {
+      p = buf + strlen(buf);
+      sprintf(p, " G%1d [", wp->LocalCharset);
+      for (i = 0; i < 4; i++)
+       p[i + 5] = wp->charsets[i] ? wp->charsets[i] : 'B';
+      p[9] = ']';
+      p[10] = '\0';
+    }
+  Msg(0, "%s", buf);
+}
+
+#if defined(sequent) || defined(_SEQUENT_) || defined(SVR4)
+
+static int OpenPTY()
+{
+  char *m, *s;
+  register int f;
+# ifdef SVR4
+  char *ptsname();
+  SIGTYPE (*sigcld)();
+
+  if ((f = open("/dev/ptmx", O_RDWR)) == -1)
+    return(-1);
+
+  /*
+   * SIGCLD set to SIG_DFL for grantpt() because it fork()s and
+   * exec()s pt_chmod
+   */
+  sigcld = signal(SIGCLD, SIG_DFL);
+       
+  if ((m = ptsname(f)) == NULL || unlockpt(f) || grantpt(f))
+    {
+      signal(SIGCLD, sigcld);
+      close(f);
+      return(-1);
+    } 
+  signal(SIGCLD, sigcld);
+  strncpy(TtyName, m, sizeof TtyName);
+# else /* SVR4 */
+  if ((f = getpseudotty(&s, &m)) < 0)
+    return(-1);
+  strncpy(PtyName, m, sizeof PtyName);
+  strncpy(TtyName, s, sizeof TtyName);
+# endif /* SVR4 */
+# ifdef POSIX
+  tcflush(f, TCIOFLUSH);
+# else
+  (void) ioctl(f, TIOCFLUSH, (char *) 0);
+# endif
+# ifdef LOCKPTY
+  (void) ioctl(f, TIOCEXCL, (char *) 0);
+# endif
+  return (f);
+}
+
+#else /* defined(sequent) || defined(_SEQUENT_) || defined(SVR4) */
+# ifdef MIPS
+
+static int OpenPTY()
+{
+  register char *p, *l, *d;
+  register f, tf;
+  register my_minor;
+  struct stat buf;
+   
+  strcpy(PtyName, PtyProto);
+  for (p = PtyName; *p != 'X'; ++p)
+    ;
+  for (l = "zyxwvutsrqp"; *p = *l; ++l)
+    {
+      for (d = "0123456789abcdef"; p[1] = *d; ++d)
+       {
+         if ((f = open(PtyName, O_RDWR)) != -1)
+           {
+             fstat(f, &buf);
+             my_minor = minor(buf.st_rdev);
+             sprintf(TtyName, "/dev/ttyq%d", my_minor);
+             if ((tf = open(TtyName, O_RDWR)) != -1)
+               {
+                 close(tf);
+#ifdef LOCKPTY
+                 (void) ioctl(f, TIOCEXCL, (char *)0);
+#endif
+                 return f;
+               }
+             close(f);
+           }
+       }
+    }
+  return -1;
+}
+
+# else  /* MIPS */
+#  ifdef sgi
+
+static int OpenPTY()
+{
+  register f;
+  register my_minor;
+  struct stat buf;
+   
+  strcpy(PtyName, "/dev/ptc");
+  f = open(PtyName, O_RDWR|O_NDELAY);
+  if (f >= 0)
+    {
+      if (fstat(f, &buf) < 0)
+       {
+         close(f);
+         return -1;
+       }
+      my_minor = minor(buf.st_rdev);
+      sprintf(TtyName, "/dev/ttyq%d", my_minor);
+    }
+  return f;
+}
+
+#  else /* sgi */
+#   ifdef _AIX /* RS6000 */
+
+static int OpenPTY()
+{
+  register int i, f, tf;
+
+  for (i = 0; i < 256; i++)
+    {
+      sprintf(PtyName, "/dev/ptc/%d", i);
+      if ((f = open(PtyName, O_RDWR)) != -1)
+       {
+         sprintf(TtyName, "/dev/pts/%d", i);
+         if ((tf = open(TtyName, O_RDWR)) != -1)
+           {
+             close(tf);
+#ifdef LOCKPTY
+             (void) ioctl(f, TIOCEXCL, (char *) 0);
+#endif
+             return f;
+           }
+         close(f);
+       }
+    }
+  return -1;
+}
+
+#   else /* _AIX, RS6000 */
+
+static int OpenPTY()
+{
+  register char *p, *q, *l, *d;
+  register int f, tf;
+
+#    if !defined(hpux)
+  debug("Hello, You are none of: sequent, _SEQUENT_, SVR4, MIPS, sgi, AIX\n");
+  debug("       This OpenPTY() is for hpux, ... and for you?\n");
+#    endif
+  strcpy(PtyName, PtyProto);
+  strcpy(TtyName, TtyProto);
+  for (p = PtyName; *p != 'X'; ++p)
+    ;
+  for (q = TtyName; *q != 'X'; ++q)
+    ;
+#ifdef sequent
+  /* why ask for sequent in #else (not sequent) section? jw. */
+  for (l = "p"; (*p = *l) != '\0'; ++l)
+    {                          /* } */
+      for (d = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; (p[1] = *d) != '\0'; ++d)
+       {                       /* } */
+#else
+# ifdef hpux
+  for (l = "pqrstuvw"; (*p = *l) != '\0'; ++l)
+# else
+  for (l = "qpr"; (*p = *l) != '\0'; ++l)
+#endif
+    {
+      for (d = "0123456789abcdef"; (p[1] = *d) != '\0'; ++d)
+       {
+#endif
+         if ((f = open(PtyName, O_RDWR)) != -1)
+           {
+             q[0] = *l;
+             q[1] = *d;
+             if ((tf = open(TtyName, O_RDWR)) != -1)
+               {
+                 /* close tf, thus we also get rid of an unwanted
+                  * controlling terminal! 
+                  */
+                 close(tf);
+#ifdef LOCKPTY
+                 (void) ioctl(f, TIOCEXCL, (char *) 0);
+#endif
+                 return f;
+               }
+             close(f);
+           }
+       }
+    }
+  return -1;
+}
+
+#   endif /* _AIX, RS6000 */
+#  endif /* sgi */
+# endif /* MIPS */
+#endif
+
+void 
+SetTTY(fd, mp)
+int fd;
+struct mode *mp;
+{
+  errno = 0;
+#ifdef POSIX
+  tcsetattr(fd, TCSADRAIN, &mp->tio);
+# ifdef hpux
+  ioctl(fd, TIOCSLTC, &mp->m_ltchars);
+# endif
+#else
+# ifdef TERMIO
+  ioctl(fd, TCSETA, &mp->tio);
+# else
+  /* ioctl(fd, TIOCSETP, &mp->m_ttyb); */
+  ioctl(fd, TIOCSETC, &mp->m_tchars);
+  ioctl(fd, TIOCSLTC, &mp->m_ltchars);
+  ioctl(fd, TIOCLSET, &mp->m_lmode);
+  ioctl(fd, TIOCSETD, &mp->m_ldisc);
+  ioctl(fd, TIOCSETP, &mp->m_ttyb);
+# endif
+#endif
+  if (errno)
+    Msg(0, "SetTTY: ioctl failed");
+}
+
+void
+GetTTY(fd, mp)
+int fd;
+struct mode *mp;
+{
+  errno = 0;
+#ifdef POSIX
+  tcgetattr(fd, &mp->tio);
+# ifdef hpux
+  ioctl(fd, TIOCGLTC, &mp->m_ltchars);
+# endif
+#else
+# ifdef TERMIO
+  ioctl(fd, TCGETA, &mp->tio);
+# else
+  ioctl(fd, TIOCGETP, &mp->m_ttyb);
+  ioctl(fd, TIOCGETC, &mp->m_tchars);
+  ioctl(fd, TIOCGLTC, &mp->m_ltchars);
+  ioctl(fd, TIOCLGET, &mp->m_lmode);
+  ioctl(fd, TIOCGETD, &mp->m_ldisc);
+# endif
+#endif
+  if (errno)
+    Msg(0, "GetTTY: ioctl failed");
+}
+
+void
+SetMode(op, np)
+struct mode *op, *np;
+{
+  *np = *op;
+
+#if defined(TERMIO) || defined(POSIX)
+  np->tio.c_iflag &= ~ICRNL;
+# ifdef ONLCR
+  np->tio.c_oflag &= ~ONLCR;
+# endif
+  np->tio.c_lflag &= ~(ICANON | ECHO);
+
+  /*
+   * Unfortunately, the master process never will get SIGINT if the real
+   * terminal is different from the one on which it was originaly started
+   * (process group membership has not been restored or the new tty could not
+   * be made controlling again). In my solution, it is the attacher who
+   * receives SIGINT (because it is always correctly associated with the real
+   * tty) and forwards it to the master [kill(MasterPid, SIGINT)]. 
+   * Marc Boucher (marc@CAM.ORG)
+   */
+  np->tio.c_lflag |= ISIG;
+  /* 
+   * careful, careful catche monkey..
+   * never set VMIN and VTIME to zero, if you want blocking io.
+   */
+  np->tio.c_cc[VMIN] = 1;
+  np->tio.c_cc[VTIME] = 0;
+#ifdef VSTART
+  startc = op->tio.c_cc[VSTART];
+#endif
+#ifdef VSTOP
+  stopc = op->tio.c_cc[VSTOP];
+#endif
+  if (iflag)
+    intrc = op->tio.c_cc[VINTR];
+  else
+    intrc = np->tio.c_cc[VINTR] = 0377;
+  np->tio.c_cc[VQUIT] = 0377;
+  if (flow == 0)
+    {
+      np->tio.c_cc[VINTR] = 0377;
+#ifdef VSTART
+      np->tio.c_cc[VSTART] = 0377;
+#endif
+#ifdef VSTOP
+      np->tio.c_cc[VSTOP] = 0377;
+#endif
+      np->tio.c_iflag &= ~IXON;
+    }
+#ifdef VDISCARD
+  np->tio.c_cc[VDISCARD] = 0377;
+#endif
+#ifdef VSUSP
+  np->tio.c_cc[VSUSP] = 0377;
+#endif
+# ifdef hpux
+  np->m_ltchars.t_suspc = 0377;
+  np->m_ltchars.t_dsuspc = 0377;
+  np->m_ltchars.t_flushc = 0377;
+  np->m_ltchars.t_lnextc = 0377;
+# else
+#  ifdef VDSUSP
+  np->tio.c_cc[VDSUSP] = 0377;
+#  endif
+# endif
+#else
+  startc = op->m_tchars.t_startc;
+  stopc = op->m_tchars.t_stopc;
+  if (iflag)
+    intrc = op->m_tchars.t_intrc;
+  else
+    intrc = np->m_tchars.t_intrc = -1;
+  np->m_ttyb.sg_flags &= ~(CRMOD | ECHO);
+  np->m_ttyb.sg_flags |= CBREAK;
+  np->m_tchars.t_quitc = -1;
+  if (flow == 0)
+    {
+      np->m_tchars.t_intrc = -1;
+      np->m_tchars.t_startc = -1;
+      np->m_tchars.t_stopc = -1;
+    }
+  np->m_ltchars.t_suspc = -1;
+  np->m_ltchars.t_dsuspc = -1;
+  np->m_ltchars.t_flushc = -1;
+  np->m_ltchars.t_lnextc = -1;
+#endif                         /* defined(TERMIO) || defined(POSIX) */
+}
+
+void
+SetFlow(on)
+int on;
+{
+  if (flow == on)
+    return;
+#if defined(TERMIO) || defined(POSIX)
+  if (on)
+    {
+      NewMode.tio.c_cc[VINTR] = intrc;
+#ifdef VSTART
+      NewMode.tio.c_cc[VSTART] = startc;
+#endif
+#ifdef VSTOP
+      NewMode.tio.c_cc[VSTOP] = stopc;
+#endif
+      NewMode.tio.c_iflag |= IXON;
+    }
+  else
+    {
+      NewMode.tio.c_cc[VINTR] = 0377;
+#ifdef VSTART
+      NewMode.tio.c_cc[VSTART] = 0377;
+#endif
+#ifdef VSTOP
+      NewMode.tio.c_cc[VSTOP] = 0377;
+#endif
+      NewMode.tio.c_iflag &= ~IXON;
+    }
+# ifdef POSIX
+  if (tcsetattr(0, TCSADRAIN, &NewMode.tio))
+# else
+  if (ioctl(0, TCSETA, &NewMode.tio) != 0)
+# endif
+    debug1("SetFlow: ioctl errno %d\n", errno);
+#else
+  if (on)
+    {
+      NewMode.m_tchars.t_intrc = intrc;
+      NewMode.m_tchars.t_startc = startc;
+      NewMode.m_tchars.t_stopc = stopc;
+    }
+  else
+    {
+      NewMode.m_tchars.t_intrc = -1;
+      NewMode.m_tchars.t_startc = -1;
+      NewMode.m_tchars.t_stopc = -1;
+    }
+  if (ioctl(0, TIOCSETC, &NewMode.m_tchars) != 0)
+    debug1("SetFlow: ioctl errno %d\n", errno);
+#endif                         /* defined(TERMIO) || defined(POSIX) */
+  flow = on;
+}
+
+/* we return 1 if we could attach one, or 0 if none */
+static int Attach(how)
+int how;
+{
+  int lasts;
+  struct msg m;
+  struct stat st;
+  char *s;
+
+  if (how == MSG_WINCH)
+    {
+      bzero((char *) &m, sizeof(m));
+      m.type = how;
+      if ((lasts = MakeClientSocket(0, SockName)) >= 0)
+       {
+          write(lasts, &m, sizeof(m));
+          close(lasts);
+       }
+      return 0;
+    }
+
+  if (how == MSG_CONT)
+    {
+      if ((lasts = MakeClientSocket(0, SockName)) < 0)
+        {
+          printf("Sorry, cannot contact session \"%s\" again\r\n",
+                 SockName);
+          sleep(2);
+          how = MSG_ATTACH;
+        }
+    }
+    
+  if (how != MSG_CONT)
+    {
+      switch (FindSocket(how, &lasts))
+        {
+        case 0:
+          if (rflag == 2)
+           return 0;
+          if (quietflag)
+           eexit(10);
+          if (SockName && *SockName)
+            Msg(0, "There is no screen to be %sed matching %s.", 
+               dflag ? "detach" : "resum", SockName);
+          else
+            Msg(0, "There is no screen to be %sed.",
+                dflag ? "detach" : "resum");
+          /* NOTREACHED */
+        case 1:
+          break;
+        default:
+          Msg(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
+          /* NOTREACHED */
+        }
+      /*
+       * Go in UserContext. Advantage is, you can kill your attacher
+       * when things go wrong. Any disadvantages? jw.
+       */
+      setuid(real_uid);
+      setgid(real_gid);
+
+      SockName = SockNamePtr;
+      MasterPid = 0;
+      while (*SockName)
+        {
+          if (*SockName > '9' || *SockName < '0')
+           break;
+          MasterPid = 10 * MasterPid + *SockName - '0';
+          SockName++;
+        }
+      SockName = SockNamePtr;
+      debug1("Attach decided, it is '%s'\n", SockPath);
+      debug1("Attach found MasterPid == %d\n", MasterPid);
+      if (stat(SockPath, &st) == -1)
+        Msg(errno, "stat %s", SockPath);
+      if ((st.st_mode & 0700) != (dflag ? 0700 : 0600))
+        Msg(0, "That screen is %sdetached.", dflag ? "already " : "not ");
+#ifdef REMOTE_DETACH
+      if (dflag &&
+          (how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH))
+        {
+          strcpy(m.m.detach.tty, attach_tty);
+          debug1("attach_tty is %s\n", attach_tty);
+          m.m.detach.dpid = getpid();
+# ifdef POW_DETACH
+          if (dflag == 2)
+           m.type = MSG_POW_DETACH;
+          else
+# endif
+           m.type = MSG_DETACH;
+          if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
+           Msg(errno, "write");
+          close(lasts);
+          if (how != MSG_ATTACH)
+           return 0;   /* we detached it. jw. */
+          sleep(1);    /* we dont want to overrun our poor backend. jw. */
+          if ((lasts = MakeClientSocket(0, SockName)) == -1)
+            Msg(0, "Cannot contact screen again. Shit.");
+        }
+#endif
+    }
+  m.type = how;
+  strcpy(m.m.attach.tty, attach_tty);
+  debug1("attach_tty is %s\n", attach_tty);
+  s = getenv("TERM");
+  if (s)
+    {
+      if (strlen(s) >= MAXPATH - 5)
+       Msg(0, "$TERM too long - sorry.");
+      sprintf(m.m.attach.envterm, "TERM=%s", s);
+    }
+  else
+    *m.m.attach.envterm = '\0';
+  debug1("attach: sending %d bytes... ", sizeof m);
+
+  m.m.attach.apid = getpid();
+  m.m.attach.adaptflag = adaptflag;
+  m.m.attach.lines = m.m.attach.columns = 0;
+  if (s = getenv("LINES"))
+    m.m.attach.lines = atoi(s);
+  if (s = getenv("COLUMNS"))
+    m.m.attach.columns = atoi(s);
+
+#ifdef PASSWORD
+  if (how == MSG_ATTACH || how == MSG_CONT)
+    trysend(lasts, &m, m.m.attach.password);
+  else
+#endif
+    {
+      if (write(lasts, (char *) &m, sizeof(m)) != sizeof(m))
+       Msg(errno, "write");
+      close(lasts);
+    }
+  debug1("Attach(%d): sent\n", m.type);
+  Suspended = 0;
+  rflag = 0;
+  return 1;
+}
+
+
+#ifdef PASSWORD
+
+static trysendstat;
+
+static SIGTYPE trysendok(SIGDEFARG)
+{
+  trysendstat = 1;
+}
+
+static SIGTYPE trysendfail(SIGDEFARG)
+{
+  trysendstat = -1;
+# ifdef SYSV
+  signal(SIG_PW_FAIL, trysendfail);
+# endif /* SYSV */
+}
+
+static char screenpw[9];
+
+static void trysend(fd, m, pwto)
+int fd;
+struct msg *m;
+char *pwto;
+{
+  char *npw = NULL;
+  SIGTYPE (*sighup)();
+  SIGTYPE (*sigusr1)();
+  int tries;
+
+  sigusr1 = signal(SIG_PW_OK, trysendok);
+  sighup = signal(SIG_PW_FAIL, trysendfail);
+  for (tries = 0; ; )
+    {
+      strcpy(pwto, screenpw);
+      trysendstat = 0;
+      if (write(fd, (char *) m, sizeof(*m)) != sizeof(*m))
+       Msg(errno, "write");
+      close(fd);
+      while (trysendstat == 0)
+       pause();
+      if (trysendstat > 0)
+       {
+         signal(SIG_PW_OK, sigusr1);
+         signal(SIG_PW_FAIL, sighup);
+         return;
+       }
+      if (++tries > 1 || (npw = getpass("Screen Password:")) == 0 || *npw == 0)
+       Msg(0, "Password incorrect");
+      strncpy(screenpw, npw, 8);
+      if ((fd = MakeClientSocket(0, SockName)) == -1)
+       Msg(0, "Cannot contact screen again. Shit.");
+    }
+}
+#endif /* PASSWORD */
+
+
+/*
+ * Unfortunatelly this is also the SIGHUP handler, so we have to
+ * check, if the backend is already detached.
+ */
+
+static SIGTYPE AttacherFinit(SIGDEFARG)
+{
+  struct stat statb;
+  struct msg m;
+  int s;
+
+  debug("AttacherFinit();\n");
+  signal(SIGHUP, SIG_IGN);
+  /* Check if signal comes from backend */
+  if (SockName)
+    {
+      strcpy(SockNamePtr, SockName);
+      if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
+       {
+         debug("Detaching backend!\n");
+         bzero((char *) &m, sizeof(m));
+         strcpy(m.m.detach.tty, attach_tty);
+          debug1("attach_tty is %s\n", attach_tty);
+         m.m.detach.dpid = getpid();
+         m.type = MSG_HANGUP;
+         if ((s = MakeClientSocket(0, SockName)) >= 0)
+           {
+             write(s, &m, sizeof(m));
+             close(s);
+           }
+       }
+    }
+  exit(0);
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+
+#ifdef POW_DETACH
+static SIGTYPE AttacherFinitBye(SIGDEFARG)
+{
+  int ppid;
+  debug("AttacherFintBye()\n");
+  freetty();
+  setuid(real_uid);
+  setgid(real_gid);
+  /* we don't want to disturb init (even if we were root), eh? jw */
+  if ((ppid = getppid()) > 1)
+    Kill(ppid, SIGHUP);                /* carefully say good bye. jw. */
+  exit(0);
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+#endif
+
+static SuspendPlease;
+
+static SIGTYPE SigStop(SIGDEFARG)
+{
+  debug("SigStop()\n");
+  SuspendPlease = 1;
+#ifndef SIGVOID
+  return((SIGTYPE) 0);
+#endif
+}
+
+#ifdef LOCK
+static LockPlease;
+
+static SIGTYPE DoLock(SIGDEFARG)
+{
+  debug("DoLock()\n");
+  LockPlease = 1;
+# ifdef SYSV
+  signal(SIG_LOCK, DoLock);
+# endif
+# ifndef SIGVOID
+  return((SIGTYPE) 0);
+# endif
+}
+#endif
+
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+static SigWinchPlease;
+
+static SIGTYPE SigAttWinch(SIGDEFARG)
+{
+  debug("SigAttWinch()\n");
+  SigWinchPlease = 1;
+# ifndef SIGVOID
+  return((SIGTYPE) 0);
+# endif
+}
+#endif
+
+static void Attacher()
+{
+  /*
+   * permanent in UserContext. Advantage is, you can kill your attacher
+   * when things go wrong. Any disadvantages? jw.
+   */
+  setuid(real_uid);    /* XXX: already done in Attach() */
+  setgid(real_gid);    /* XXX: already done in Attach() */
+
+  signal(SIGHUP, AttacherFinit);
+  signal(SIG_BYE, AttacherFinit);
+#ifdef POW_DETACH
+  signal(SIG_POWER_BYE, AttacherFinitBye);
+#endif
+#ifdef LOCK
+  signal(SIG_LOCK, DoLock);
+#endif
+  signal(SIGINT, AttacherSigInt);
+#ifdef BSDJOBS
+  signal(SIG_STOP, SigStop);
+#endif
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+  signal(SIGWINCH, SigAttWinch);
+#endif
+#ifdef DEBUG
+# ifdef SYSV
+  signal(SIGCLD, FEChld);
+# else
+  signal(SIGCHLD, FEChld);
+# endif
+#endif
+  debug("attacher: going for a nap.\n");
+  dflag = 0;
+  while (1)
+    {
+      pause();
+      debug("attacher: huh! a signal!\n");
+#ifdef DEBUG
+      if (FEpanic)
+        {
+         printf("\n\rSuddenly the Dungeon collapses!! - You die...\n\r");
+         SetTTY(0, &OldMode);
+         eexit(1);
+        }
+#endif
+#ifdef BSDJOBS
+      if (SuspendPlease)
+       {
+         SuspendPlease = 0;
+         signal(SIGTSTP, SIG_DFL);
+         debug("attacher: killing myself SIGTSTP\n");
+         kill(getpid(), SIGTSTP);
+
+         debug1("attacher: continuing from stop(%d)\n", Suspended);
+         signal(SIG_STOP, SigStop);
+         (void) Attach(MSG_CONT);
+       }
+#endif
+#ifdef LOCK
+      if (LockPlease)
+       {
+         LockPlease = 0;
+         LockTerminal();
+# ifdef SYSV
+         signal(SIG_LOCK, DoLock);
+# endif
+         (void) Attach(MSG_CONT);
+       }
+#endif /* LOCK */
+#if defined(SIGWINCH) && defined(TIOCGWINSZ)
+      if (SigWinchPlease)
+       {
+         SigWinchPlease = 0;
+# ifdef SYSV
+         signal(SIGWINCH, SigAttWinch);
+# endif
+         (void) Attach(MSG_WINCH);
+       }
+#endif /* SIGWINCH */
+    }
+}
+
+#ifdef LOCK
+
+/* ADDED by Rainer Pruy 10/15/87 */
+/* POLISHED by mls. 03/10/91 */
+
+static char LockEnd[] = "Welcome back to screen !!\n";
+
+static void LockTerminal()
+{
+  char *prg;
+  int sig, pid;
+  SIGTYPE (*sigs[NSIG])__P(SIGPROTOARG);
+
+  for (sig = 1; sig < NSIG; sig++)
+    {
+      sigs[sig] = signal(sig, SIG_IGN);
+    }
+  SetTTY(0, &OldMode);
+  printf("\n");
+
+  prg = getenv("LOCKPRG");
+  if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
+    {
+# ifdef SYSV
+      signal(SIGCLD, SIG_DFL);
+# else /* SYSV */
+      signal(SIGCHLD, SIG_DFL);
+# endif /* SYSV */
+      debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
+      if ((pid = fork()) == 0)
+        {
+          /* Child */
+          setuid(real_uid);    /* this should be done already */
+          setgid(real_gid);
+          closeallfiles();     /* important: /etc/shadow may be open */
+          execl(prg, "SCREEN-LOCK", NULL);
+          exit(errno);
+        }
+      if (pid == -1)
+        {
+#ifdef NETHACK
+          if (nethackflag)
+            Msg(errno, "Cannot fork terminal - lock failed");
+          else
+#endif
+          Msg(errno, "Cannot lock terminal - fork failed");
+        }
+      else
+        {
+#ifdef BSDWAIT
+          union wait wstat;
+#else
+          int wstat;
+#endif
+          int wret;
+
+#ifdef hpux
+          signal(SIGCLD, SIG_DFL);
+#endif
+          errno = 0;
+          while (((wret = wait((int *) &wstat)) != pid) ||
+                ((wret == -1) && (errno == EINTR))
+                )
+           errno = 0;
+    
+          if (errno)
+           {
+             perror("Lock");
+             sleep(2);
+           }
+         else if (WTERMSIG(wstat) != 0)
+           {
+             fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
+                     WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
+             sleep(2);
+           }
+         else if (WEXITSTATUS(wstat))
+           {
+             debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
+           }
+          else
+           printf(LockEnd);
+        }
+    }
+  else
+    {
+      if (prg)
+       {
+          debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
+       }
+      else
+       {
+         debug("lockterminal: using buitin.\n");
+       }
+      screen_builtin_lck();
+    }
+  /* reset signals */
+  for (sig = 1; sig < NSIG; sig++)
+    {
+      if (sigs[sig] != (SIGTYPE(*) ()) - 1)
+       signal(sig, sigs[sig]);
+    }
+}                              /* LockTerminal */
+
+/* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
+void
+screen_builtin_lck()
+{
+  char fullname[100], *cp1, message[BUFSIZ];
+  char c, *pass, mypass[9];
+#ifdef SHADOWPW
+  struct spwd *sss = NULL;
+#endif
+  int t;
+
+#ifdef undef
+  /* get password entry */
+  if ((ppp = getpwuid(real_uid)) == NULL)
+    {
+      fprintf(stderr, "screen_builtin_lck: No passwd entry.\007\n");
+      sleep(2);
+      return;
+    }
+  if (!isatty(0))
+    {
+      fprintf(stderr, "screen_builtin_lck: Not a tty.\007\n");
+      sleep(2);
+      return;
+    }
+#endif
+  pass = ppp->pw_passwd;
+#ifdef SHADOWPW
+realpw:
+#endif
+  for (t = 0; t < 13; t++)
+    {
+      c = pass[t];
+      if (!(c == '.' || c == '/' ||
+            (c >= '0' && c <= '9') || 
+            (c >= 'a' && c <= 'z') || 
+            (c >= 'A' && c <= 'Z'))) 
+        break;
+    }
+  if (t < 13)
+    {
+      debug("builtin_lock: ppp->pw_passwd bad, has it a shadow?\n");
+#ifdef SHADOWPW
+      setspent(); /* rewind shadow file */
+      if ((sss == NULL) && (sss = getspnam(ppp->pw_name)))
+        {
+          pass = sss->sp_pwdp;
+          goto realpw;
+        }
+#endif /* SHADOWPW */
+      if (pass = getpass("Key:   "))
+        {
+          strncpy(mypass, pass, 8);
+          mypass[8] = 0;
+          if (*mypass == 0)
+            return;
+          if (pass = getpass("Again: "))
+            {
+              if (strcmp(mypass, pass))
+                {
+                  fprintf(stderr, "Passwords don't match.\007\n");
+                  sleep(2);
+                  return;
+                }
+            }
+        }
+      if (pass == 0)
+        {
+          fprintf(stderr, "Getpass error.\007\n");
+          sleep(2);
+          return;
+        }
+      pass = 0;
+    }
+
+  debug("screen_builtin_lck looking in gcos field\n");
+  strcpy(fullname, ppp->pw_gecos);
+  if ((cp1 = index(fullname, ',')) != NULL)
+    *cp1 = '\0';
+  if ((cp1 = index(fullname, '&')) != NULL)
+    {
+      sprintf(cp1, "%s", ppp->pw_name);
+      *cp1 = islower(*cp1) ? toupper(*cp1) : *cp1;
+    }
+
+  sprintf(message, "Screen used by %s <%s>.\nPassword:\007",
+          fullname, ppp->pw_name);
+
+  /* loop here to wait for correct password */
+  for (;;)
+    {
+      debug("screen_builtin_lck awaiting password\n");
+      if ((cp1 = getpass(message)) == NULL)
+        {
+          AttacherFinit(SIGARG);
+          /* NOTREACHED */
+        }
+      if (pass)
+        {
+          if (!strcmp(crypt(cp1, pass), pass))
+            break;
+        }
+      else
+        {
+          if (!strcmp(cp1, mypass))
+            break;
+        }
+      debug("screen_builtin_lck: NO!!!!!\n");
+    }
+  debug("password ok.\n");
+}
+
+#endif /* LOCK */
+
+/*
+ * Detach now has the following modes:
+ *     D_DETACH        SIG_BYE         detach backend and exit attacher
+ *     D_STOP          SIG_STOP        stop attacher (and detach backend)
+ *     D_REMOTE        SIG_BYE         remote detach -- reattach to new attacher
+ *     D_POWER         SIG_POWER_BYE   power detach -- attacher kills his parent
+ *     D_REMOTE_POWER  SIG_POWER_BYE   remote power detach -- both
+ *     D_LOCK          SIG_LOCK        lock the attacher
+ * (jw)
+ * we always remove our utmp slots. (even when "lock" or "stop")
+ * Note: Take extra care here, we may be called by unterrupt!
+ */
+void
+Detach(mode)
+int mode;
+{
+  int sign = 0;
+#ifdef UTMPOK
+  register int n;
+#endif
+
+  if (Detached)
+    return;
+  debug1("Detach(%d)\n", mode);
+  if (fore && status)
+    RemoveStatus();
+  signal(SIGHUP, SIG_IGN);
+  SetTTY(0, &OldMode);
+  FinitTerm();
+  switch (mode)
+    {
+    case D_DETACH:
+      printf("\n[detached]\n");
+      sign = SIG_BYE;
+      break;
+#ifdef BSDJOBS
+    case D_STOP:
+      (void) fflush(stdout);
+      sign = SIG_STOP;
+      break;
+#endif
+#ifdef REMOTE_DETACH
+    case D_REMOTE:
+      printf("\n[remote detached]\n");
+      sign = SIG_BYE;
+      break;
+#endif
+#ifdef POW_DETACH
+    case D_POWER:
+      printf("\n[power detached]\n");
+      if (PowDetachString) 
+        printf("%s\n", PowDetachString);
+      sign = SIG_POWER_BYE;
+      break;
+#ifdef REMOTE_DETACH
+    case D_REMOTE_POWER:
+      printf("\n[remote power detached]\n");
+      if (PowDetachString) 
+        printf("%s\n", PowDetachString);
+      sign = SIG_POWER_BYE;
+      break;
+#endif
+#endif
+    case D_LOCK:
+      ClearDisplay();
+      sign = SIG_LOCK;
+      /* tell attacher to lock terminal with a lockprg. */
+      break;
+    }
+#ifdef UTMPOK
+  for (n = WinList; n != -1; n = wtab[n]->WinLink)
+    if (wtab[n]->slot != (slot_t) -1)
+      {
+       RemoveUtmp(wtab[n]);
+        /*
+        * Set the slot to 0 to get the window
+         * logged in again.
+        */
+       wtab[n]->slot = (slot_t) 0;
+      }
+  RestoreLoginSlot();
+#endif
+  freetty();
+  (void) chmod(SockPath, /* S_IFSOCK | */ 0600); /* Flag detached-ness */
+    /*
+     * tell father to father what to do. We do that after we
+     * freed the tty, thus getty feels more comfortable on hpux
+     * if it was a power detach.
+     */
+  Kill(AttacherPid, sign);
+  debug2("Detach: Signal %d to Attacher(%d)!\n", sign, AttacherPid);
+  if (mode != D_LOCK && mode != D_STOP)
+    AttacherPid = 0;
+
+  Detached = 1;
+  Suspended = (mode == D_STOP) ? 1 : 0;
+  if (fore)
+    fore->active = 0;
+  debug("Detach returns, we are successfully detached.\n");
+}
+
+void
+Kill(pid, sig)
+int pid, sig;
+{
+  if (pid < 2)
+    return;
+  (void) kill(pid, sig);
+}
+
+static int IsSymbol(e, s)
+register char *e, *s;
+{
+  register char *p;
+  register int n;
+
+  for (p = e; *p && *p != '='; ++p)
+    ;
+  if (*p)
+    {
+      *p = '\0';
+      n = strcmp(e, s);
+      *p = '=';
+      return n == 0;
+    }
+  return 0;
+}
+
+static void MakeNewEnv()
+{
+  register char **op, **np;
+  static char buf[MAXSTR];
+
+  for (op = environ; *op; ++op)
+    ;
+  NewEnv = np = (char **) malloc((unsigned) (op - environ + 6 + 1) * sizeof(char **));
+  if (!NewEnv)
+    Msg_nomem;
+  if (strlen(SockName) > MAXSTR - 5)
+    SockName = "?";
+  sprintf(buf, "STY=%s", SockName);
+  *np++ = buf;                 /* NewEnv[0] */
+  *np++ = Term;                        /* NewEnv[1] */
+#ifdef TIOCSWINSZ
+  np += 2;     /* room for TERMCAP and WINDOW */
+#else
+  np += 4;     /* room for TERMCAP WINDOW LINES COLUMNS */
+#endif
+
+  for (op = environ; *op; ++op)
+    {
+      if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
+         && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
+         && !IsSymbol(*op, "SCREENCAP")
+#ifndef TIOCGWINSZ
+         && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
+#endif
+         )
+       *np++ = *op;
+    }
+  *np = 0;
+}
+
+void
+#ifdef USEVARARGS
+/*VARARGS2*/
+# if defined(__STDC__)
+Msg(int err, char *fmt, ...)
+# else
+Msg(err, fmt, va_alist)
+int err;
+char *fmt;
+va_dcl
+# endif
+{
+  static va_list ap = 0;
+#else
+/*VARARGS2*/
+Msg(err, fmt, p1, p2, p3, p4, p5, p6)
+int err;
+char *fmt;
+unsigned long p1, p2, p3, p4, p5, p6;
+{
+#endif
+  char buf[MAXPATH*2];
+  char *p = buf;
+
+  if (Detached)
+    return;
+#ifdef USEVARARGS
+# if defined(__STDC__)
+  va_start(ap, fmt);
+# else
+  va_start(ap);
+# endif
+  (void) vsprintf(p, fmt, ap);
+  va_end(ap);
+#else
+  sprintf(p, fmt, p1, p2, p3, p4, p5, p6);
+#endif
+  if (err)
+    {
+      p += strlen(p);
+      if (err > 0 && err < sys_nerr)
+       sprintf(p, ": %s", sys_errlist[err]);
+      else
+       sprintf(p, ": Error %d", err);
+    }
+  if (HasWindow)
+    {
+      debug1("Msg('%s');\n", p);
+      MakeStatus(buf);
+    }
+  else
+    {
+      printf("%s\r\n", buf);
+      if (DeadlyMsg)
+       {
+          debug1("Msg('%s') screen is not up, exiting..\n", buf);
+          Kill(AttacherPid, SIG_BYE);
+          eexit(1);
+       }
+      else
+       debug1("Harmless; Msg('%s');\n", buf);
+    }
+  DeadlyMsg = 1;
+}
+
+char *Filename(s)
+char *s;
+{
+  register char *p;
+
+  if (s == NULL) 
+    return s;
+  p = s + strlen(s) - 1;
+  while (p >= s && *p != '/')
+    --p;
+  return ++p;
+}
+
+/*
+ * '^' is allowed as an escape mechanism for control characters. jw.
+ */
+static char *MakeWinMsg(s, n)
+register char *s;
+int n;
+{
+  static char buf[MAXSTR];
+  register char *p = buf;
+  register int ctrl;
+
+  ctrl = 0;
+  for (; *s && p < buf + MAXSTR - 1; s++, p++)
+    if (ctrl)
+      {
+        ctrl = 0;
+        if (*s == '^' || *s < 64)
+          *p = *s;
+        else 
+          *p = *s - 64;
+      }
+    else
+      {
+        switch (*s)
+          {
+          case '%':
+           *p = n + '0';
+           break;
+          case '~':
+           *p = BELL;
+           break;
+         case '^':
+           ctrl = 1;
+           *p-- = '^';
+           break;
+          default:
+           *p = *s;
+           break;
+          }
+      }
+  *p = '\0';
+  return buf;
+}
+