
#include <X/mit-copyright.h>

/* Copyright    Massachusetts Institute of Technology    1984, 1985	*/

/* main.c */

#ifndef lint
static char *rcsid_ptyx_c = "$Header: main.c,v 10.49 86/11/19 18:55:30 jg Exp $";
#endif	lint

#ifdef vms
#include <ptyctl.h>
#include <descrip.h>
#include <ssdef.h>
Cleanup();
#else vms
#include <pwd.h>
#endif
#include <sgtty.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <sys/file.h>
#include <errno.h>
#include <signal.h>
#include <strings.h>
#include <X/Xlib.h>
#include "ptyx.h"
#include <grp.h>
#include <ttyent.h>
#include <utmp.h>

char *xterm_name;	/* argv[0] */
Terminal term;		/* master data structure for client */
int am_slave = 0;	/* set to 1 if running as a slave process */
int debug = 0; 		/* true causes error messages to be displayed */

static char *ptydev = "/dev/ptyxx";
static char *ttydev = "/dev/ttyxx";

#include "../cursors/xterm.cursor"
#include "../cursors/xterm_mask.cursor"

#ifdef ICONWINDOW
#define icon_width      screen->iconwidth
#define icon_height     screen->iconheight
#else ICONWINDOW
#include "icon.ic"
#include "icon_mask.ic"
#endif ICONWINDOW

#ifndef vms
static int reapchild ();
#endif vms

static char **command_to_exec = (char **) NULL;
static char *win_name = (char *) 0;


static struct  sgttyb d_sg = {
        0, 0, 0177, CKILL, EVENP|ODDP|ECHO|XTABS|CRMOD
};
static struct  tchars d_tc = {
        CINTR, CQUIT, CSTART,
        CSTOP, CEOF, CBRK,
};
static struct  ltchars d_ltc = {
        CSUSP, CDSUSP, CRPRNT,
        CFLUSH, CWERASE, CLNEXT
};
static int d_disipline = NTTYDISC;
static int d_lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
static int no_dev_tty = 0;
static int loginpty = 0;
static int dologinflag = 0;
#ifdef sun
#ifdef TIOCCONS
static int SunConsole = 0;
#endif TIOCCONS
#endif sun


main (argc, argv)
int argc;
char **argv;
{
	int ind;
	char *strind, *strind1, *strscan();
	char *fn = "vtsingle";
	char *fb = "vtbold";
	short fnflag = 0;	/* True iff -fn option used */
	short fbflag = 0;	/* True iff -fb option used */
#ifdef ICONWINDOW
	char *fi = "nil2";
	int allowiconinput = 0;
#endif ICONWINDOW
	char *getty = NULL;
	char *keymap = NULL;
	int reverse = 0, multiscroll = 0;
	int border = 1, tek = 0;
	int borderwidth = 2;
	int bitmapicon = 0;
#ifdef JUMPSCROLL
	int jumpscroll = 0;
#endif JUMPSCROLL
	int slave = 0;		/* if non-zero, run as slave */
	char passedPty[2];	/* name if pty if slave */
	char *fore_color;
	char *back_color;
	char *brdr_color;
	char *curs_color;
	char *mous_color;
	char display[256];
	char *getenv();
	char *option;
	char *geometry, *def = "=80x24+1+1";
	char *hcom;
	Screen *screen = &term.screen;

	screen->TekCursCR = 0;
	screen->TekPrintCom[0] = 0;

#ifdef vms
	xterm_name = basename( argv[0] );
#else vms
	xterm_name = argv[0];
#endif vms

	display[0] = '\0';
	/*
	 * go get options out of default file
	 */
	if ((option = XGetDefault(argv[0], "BodyFont")) != NULL) {
		fn = option;
		fnflag = 1;
	}
	if ((option = XGetDefault(argv[0], "BoldFont")) != NULL) {
		fb = option;
		fbflag = 1;
	}
	if ((option = XGetDefault(argv[0], "InternalBorder")) != NULL) {
		border = atoi (option);
	}
	if ((option = XGetDefault(argv[0], "BorderWidth")) != NULL) {
		borderwidth = atoi (option);
	}

#ifdef ICONWINDOW
	if ((option = XGetDefault(argv[0], "AllowIconInput")) != NULL)
		if (strcmp (option, "on") == 0)
			allowiconinput = 1;
#endif ICONWINDOW

	if ((option = XGetDefault(argv[0], "BitmapIcon")) != NULL)
		if (strcmp (option, "on") == 0) 
			bitmapicon = 
#ifdef ICONWINDOW
				allowiconinput ? 2 :
#endif ICONWINDOW
				1;

	if ((option = XGetDefault(argv[0], "ReverseVideo")) != NULL)
		if (strcmp (option, "on") == 0)
			reverse = 1;

	if ((option = XGetDefault(argv[0], "Tektronix")) != NULL)
		if (strcmp (option, "on") == 0) 
			tek = 1;
        if ((option = XGetDefault(argv[0], "TekCursCR")) != NULL)
                if (strcmp (option, "on") == 0)
                        screen->TekCursCR = 1;
#ifdef JUMPSCROLL
	if ((option = XGetDefault(argv[0], "JumpScroll")) != NULL)
		if (strcmp (option, "on") == 0) 
			jumpscroll = 1;
#endif JUMPSCROLL

	fore_color = XGetDefault(argv[0], "Foreground");
	back_color = XGetDefault(argv[0], "Background");
	brdr_color = XGetDefault(argv[0], "Border");
	curs_color = XGetDefault(argv[0], "Cursor");
	mous_color = XGetDefault(argv[0], "Mouse");
	keymap = XGetDefault(argv[0], "Keymap");

        if ((hcom = XGetDefault(argv[0], "HardCopyCom")) != NULL)
                strcpy (hcom, screen->TekPrintCom);

	/* parse command line */
	
	for (ind = 1; ind < argc; ind++) {
	    if (argv [ind] [0] == '=') {
		geometry = argv[ind];
		continue;
	    }

	    strind = index (argv[ind], ':');
	    if(strind != NULL) {
		strncpy(display,argv[ind],sizeof(display));
		continue;
	    }


	    strind = (char *) index (argv [ind], '-');

	    if (strind == NULL) Syntax ();

	    if (strcmp (argv [ind], "-L") == 0) {
		char tt[32];

		getty = argv[argc-1];
		argc -= 1;
#ifndef vms
		strcpy(tt,"/dev/");
		strcat(tt, getty);
		tt[5] = 'p';
		loginpty = open(tt, O_RDWR, 0);
		dup2(loginpty, 4);
		close(loginpty);
		loginpty=4;
		tt[5] = 't';
		chown(tt, 0, 0);
		chmod(tt, 0622);
		if (open(tt, O_RDWR, 0) < 0) {
			consolepr("open failed\n");
		}
		signal(SIGHUP, SIG_IGN);
		vhangup();
		setpgrp(0,0);
		signal(SIGHUP, SIG_DFL);
		open(tt, O_RDWR, 0);
		close(0);
		dup(1);
		dup(0);
#endif vms
		continue;
	    }
    
	    if (strncmp (argv [ind], "-S", 2) == 0) {
		sscanf(argv[ind] + 2, "%c%c%d", passedPty, passedPty+1,
			&slave);
		if (slave <= 0) Syntax();
		am_slave = 1;
		continue;
	    }

	    if (strcmp (argv [ind], "-e") == 0) {
		if (++ind >= argc) Syntax ();
		command_to_exec = argv + ind;
		break;
	    }
		
	    /* Switch to set up Tektronix-shaped (4096x3128 -> 512x390) window
	     * with characters sized to fit 39 lines of 85 characters each */

	    if (strcmp (argv [ind], "-t") == 0) {
		tek = 1;
		if (!fnflag) fn = "6x10";
		if (!fbflag) fb = "6x10";
		def = "85x39+1+1";
		continue;
	    }
		
	    if (strcmp (argv [ind], "-fn") == 0) {
		if (++ind >= argc) Syntax ();
		fn = argv [ind];
		fnflag = 1;
		continue;
	    }

	    if (strcmp (argv [ind], "-fb") == 0) {
		if (++ind >= argc) Syntax ();
		fb = argv [ind];
		fbflag = 1;
		continue;
	    }

	    if (strcmp (argv[ind], "-fi") == 0) {
		if (++ind >= argc) Syntax ();
		fi = argv [ind];
		continue;
	    }
	    
	    if (strcmp (argv [ind], "-fg") == 0) {
		if (++ind >= argc) Syntax ();
		fore_color = argv [ind];
		continue;
	    }

	    if (strcmp (argv [ind], "-bg") == 0) {
		if (++ind >= argc) Syntax ();
		back_color = argv [ind];
		continue;
	    }

	    if (strcmp (argv [ind], "-bd") == 0) {
		if (++ind >= argc) Syntax ();
		brdr_color = argv [ind];
		continue;
	    }

            if (strcmp (argv [ind], "-cc") == 0) {
                screen->TekCursCR = 1;
                continue;
            }

            if (strcmp (argv [ind], "-hc") == 0) {
                if (++ind >= argc) Syntax ();
                hcom = argv [ind];
                strcpy (hcom, screen->TekPrintCom);
                continue;
            }

	    if (strcmp (argv [ind], "-cr") == 0) {
		if (++ind >= argc) Syntax ();
		curs_color = argv [ind];
		continue;
	    }

	    if (strcmp (argv [ind], "-ms") == 0) {
		if (++ind >= argc) Syntax ();
		mous_color = argv [ind];
		continue;
	    }

	    if (strcmp (argv [ind], "-l") == 0) {
		dologinflag = 1;
		continue;
	    }

	    if (strcmp (argv [ind], "-d") == 0) {
		debug = 1;
		continue;
	    }

	    if (strcmp (argv [ind], "-b") == 0) {
		if (++ind >= argc) Syntax ();
		border = atoi (argv [ind]);
		continue;
	    }

	    if (strcmp (argv [ind], "-bw") == 0 ||
		strcmp (argv [ind], "-w") == 0) {
		if (++ind >= argc) Syntax ();
		borderwidth = atoi (argv [ind]);
		continue;
	    }

	    if (strcmp (argv [ind], "-rv") == 0 ||
		strcmp (argv [ind], "-r") == 0) {
		reverse = 1;	/* backwards from usual definition */
		continue;
	    }

	    if (strcmp (argv [ind], "-s") == 0) {
		multiscroll = 1;
		continue;
	    }

	    if (strcmp (argv [ind], "-i") == 0) {
		bitmapicon = 
#ifdef ICONWINDOW
			allowiconinput ? 2 :
#endif ICONWINDOW
		        1;
		continue;
	    }

#ifdef JUMPSCROLL
	    if (strcmp (argv [ind], "-j") == 0) {
		jumpscroll = 1;
		continue;
	    }
#endif JUMPSCROLL

	    if (strcmp (argv [ind], "-n") == 0) {
		if (++ind >= argc) Syntax ();
		win_name = argv [ind];
		continue;
	    }
	    if (strcmp (argv [ind], "-k") ==0) {
		    ind++;
		    keymap = argv[ind++];
		    continue;
	    }
#ifdef sun
#ifdef TIOCCONS
	    if (strcmp (argv [ind], "-C") == 0) {
		SunConsole = 1;
		continue;
	    }
#endif TIOCCONS
#endif sun

	    Syntax ();
	}
	
	if (fnflag && !fbflag) fb = fn;
	if (!fnflag && fbflag) fn = fb;
#ifdef JUMPSCROLL
	if(tek)
		jumpscroll = 0;
#endif JUMPSCROLL

	if ((char *)win_name == 0 && getty) {
		(char *) win_name = (char *) malloc(33);
		strcpy(win_name, "login(");
		gethostname(win_name+6, 25);
		strcat(win_name, ")");
	}
	if (keymap != NULL) XUseKeymap(keymap);
	Serve (display, fn, fb, 
#ifdef ICONWINDOW
	   fi,
#endif ICONWINDOW    
	   geometry, def, getty, slave, passedPty, 
	   border, borderwidth, tek, reverse, multiscroll, bitmapicon, 
	   fore_color, back_color, brdr_color, curs_color, mous_color
#ifdef JUMPSCROLL
	   , jumpscroll
#endif JUMPSCROLL
	   );
}

Syntax ()
{
	static char *ustring[] = {
	"Usage: xterm [-rv] [-fn normal_font] [-fb bold_font]",
#ifdef ICONWINDOW
	" [-fi icon_font]",
#endif ICONWINDOW
	"\n\t[=[width]x[height][[+-]xoff[[+-]yoff]]] [-bw bdr_width]\n",
	"\t[-fg color] [-bg color] [-bd color] [-cr color] [-ms color]\n",
	"\t[[[host]:vs]] [-d] [-s] [-t] [-i] [-j] [-e command_to_exec]\n",
	"\t[-n window_name] [-cc] [-hc command] [-k keymap_file]\n\n",
	"Fonts must be of fixed width and of same size;\n",
	"If only one font is specified, it will be used for normal and bold text\n",
#ifdef JUMPSCROLL
	"The -j option enables jump scroll\n",
#endif
	"The -s option enables asynchronous scrolling\n",
	"The -t option enables Tektronics 4010 emulation\n",
	"The -i option enables bitmap icons\n",
	"The -d option turns debugging on (error messages printed)\n",
	"The -n option sets the window name\n",
	"The -b option specifies the inner padding\n",
        "The -cc option causes a carriage return after Tek cursor return\n",
        "The -hc option specifies the Tek hard copy command\n",
	"Default is: xterm -fn vtsingle -fb vtbold =80x24 :0\n",
	0};
	char **us = ustring;
	while (*us) fputs(*us++, stderr);
	exit (1);
}

char *strscan (search, what)
/*
   Returns pointer to first char ins search which is also in what, else NULL.
 */
char *search, *what;
{
	int i, len = strlen (what);
	char c;

	while ((c = *(search++)) != NULL)
	    for (i = 0; i < len; i++)
	    	if (c == what [i]) return (--search);

	return (NULL);
}

Serve (disp, fn, fb, 
#ifdef ICONWINDOW
       fi,
#endif ICONWINDOW
       geometry, def, getty, slave, passedPty,
       border, borderwidth, tek, reverse, multiscroll, bitmapicon,
       fore_color, back_color, brdr_color, curs_color, mous_color
#ifdef JUMPSCROLL
       , jumpscroll
#endif JUMPSCROLL
       )
char *disp;	 /* host of display to serve */
char *fn;	 /* fontname of normal characters */
char *fb;	 /* fontname of bold characters */
#ifdef ICONWINDOW
char *fi;	 /* fontname of icon characters */
#endif ICONWINDOW
char *getty;	 /* true iff child should be getty */
int slave;	 /* true if should run as slave (contains file # of pty) */
char *passedPty; /* name of pty to use if slave */
char *geometry;	 /* user supplied geometry spec */
char *def;	 /* default geometry spec */
int border;	 /* inner border in pixels */
int borderwidth; /* outer border in pixels */
int tek;	 /* true ==> Tektronics emulation */
int reverse;	 /* true ==> black background, white characters */
int multiscroll; /* true ==> asynchronous full-screen scrolling */
int bitmapicon;  /* true ==> bitmap icons rather than text icon */
#ifdef JUMPSCROLL
int jumpscroll;  /* true ==> fast multi-line scrolling */
#endif JUMPSCROLL
char *fore_color;/* text color */
char *back_color;/* background color */
char *brdr_color;/* border color */
char *curs_color;/* text cursor color */
char *mous_color;/* mouse cursor color */
{
	int pty;	/* fildes for pty of client */
	XEvent reply;
	XEvent *rep = & reply;
	int aborted = 0;
	int Select_mask, select_mask = 0;
	int maxplus1;
	short toggled = NULL;
	Screen *screen = &term.screen;
	int Xsocket;
	int pty_mask, X_mask;
	extern int errno;
	int mode = 1;
#ifdef TIOCSWINSZ
	struct winsize ws;
#endif

#ifndef vms
	signal (SIGCHLD, reapchild);
#endif vms
	signal (SIGHUP, SIG_IGN);

	/* open a terminal for client */
	get_terminal (disp, &term, fn, fb, 
#ifdef ICONWINDOW
	   fi,
#endif ICONWINDOW
           geometry, def, border,
	   borderwidth, (int)getty, slave, reverse, multiscroll, bitmapicon,
	   tek, fore_color, back_color, brdr_color, curs_color, mous_color
#ifdef JUMPSCROLL
	   , jumpscroll
#endif JUMPSCROLL
	   );

	Xsocket = screen->display->fd;

	spawn (disp, &pty, Xsocket, screen, getty, slave, passedPty);

	if (slave) {	/* Write window id so master end can read and use */
	    write(pty, &screen->window, sizeof(screen->window));
	    write(pty, "\n", 1);
	}

	screen->respond = term.buf.fildes = pty;

#ifdef TIOCSWINSZ
#ifdef vms
	if(!getty) {
#endif vms
	/* tell tty how big window is */
	ws.ws_row = screen->max_row + 1;
	ws.ws_col = screen->max_col + 1;
	ws.ws_xpixel = screen->width;
	ws.ws_ypixel = screen->height;
	ioctl (screen->respond, TIOCSWINSZ, &ws);
#ifdef vms
        }
#endif vms
#endif TIOCSWINSZ

	/* Initialize Tektronix graphics mode parameters */
	TekErase (&term);
	screen->TekEmu = tek;
	screen->cur_x = screen->cur_y = 0;
	screen->cur_X = screen->cur_Y = 0;
	screen->TekGMode = 0;
	screen->TekAMode = 0;
	screen->TekPMode = 0;

	if (ioctl (pty, FIONBIO, &mode) == -1) Error ();
	
	pty_mask = 1 << pty;
	X_mask = 1 << Xsocket;
	Select_mask = pty_mask | X_mask;
	maxplus1 = (pty < Xsocket) ? (1 + Xsocket) : (1 + pty);

	if (debug) printf ("debugging on\n");

	while (1)
	{
	   if (! aborted)
	   {
#ifdef JUMPSCROLL
		if(screen->scroll_amt)
			FlushScroll(screen);
#endif JUMPSCROLL
		if (toggled)
		{
		    CursorToggle (screen, toggled);
		    toggled = NULL;
		}

		select_mask = Select_mask;
		XFlush();
		while (select (maxplus1, &select_mask, NULL, NULL, 0) <= 0) {
			if (errno != EINTR) Error();
			}
	   }
	   else select_mask = NULL;

	   if (select_mask & pty_mask || aborted)
	   {
 		if (!toggled)
		{
		    CursorToggle (screen, toggled);
		    toggled = 1;
		}
		do {
			aborted = (*screen->mode)(&term);
		} while (screen->display->qlen==0 && term.buf.cnt>0);
	   }

	   if (select_mask & X_mask || aborted)
	   {
#ifdef JUMPSCROLL
		if(screen->scroll_amt)
			FlushScroll(screen);
#endif JUMPSCROLL
		XPending ();
		do {
		    XNextEvent (&reply);

		    switch ((int)reply.type)
		    {
			case KeyPressed:
				Input (&term.keyboard, &term.screen,
					(XKeyPressedEvent *)rep);
				break;

			case ExposeWindow:
#ifdef ICONWINDOW
				if (screen->window != reply.window) {
				    screen->window = reply.window;
				    if (Icon(screen)) {
				        screen->f_height = screen->if_height;
					screen->f_width = screen->if_width;
					screen->height = screen->iconheight;
					screen->width = screen->iconwidth;
				    }
				    else 
				    {
					screen->f_height = screen->ff_height;
					screen->f_width = screen->ff_width;
					screen->height = screen->fullheight;
					screen->width = screen->fullwidth;
				    }
			        }
#else ICONWINDOW
				if (bitmapicon) {
					if (((XExposeWindowEvent *)rep)->window
					== screen->iconwindow) {
						RefreshIcon(screen);
						break;
						}
					}
#endif ICONWINDOW
				toggled = 1;
				if (ScreenResize (screen,
					((XExposeWindowEvent *)rep)->width,
					((XExposeWindowEvent *)rep)->height,
					&term.flags) != -1)
				{
				    TabReset (term.tabs);
				    XClear (screen->window);
				    ScrnRefresh (screen, 0, 0,
				    		 screen->max_row + 1,
						 screen->max_col + 1);

				    if (screen->TekEmu) TekRefresh (&term);
				}
				break;

			case ExposeRegion:
				if (((XExposeWindowEvent *)rep)->detail ==
				    	ExposeCopy &&
				    screen->incopy <= 0) {
					screen->incopy = 1;
					if (screen->scrolls > 0)
						screen->scrolls--;
				}
				if (HandleExposure (screen, &reply))
					toggled = 1;
				break;

			case ExposeCopy:
				if (screen->incopy <= 0 && screen->scrolls > 0)
					screen->scrolls--;
				if (screen->scrolls)
					screen->incopy = -1;
				else
					screen->incopy = 0;
				break;

			case ButtonPressed:
			case ButtonReleased:
				if (screen->incopy)
					CopyWait (screen);
				if (HandleButtons(&term,&reply,pty))
					toggled = 1;
				break;
		        /*
			 *  Enter window is being handled just to give xterm
			 *  a kick in the pants when the mouse gets in the
			 *  window in case it was swapped out.  Of course,
			 *  one might thrash...
			 */
			case EnterWindow:
				break;
			default:
				break;
			}
		} while (screen->display->qlen > 0);
	   }
	}
}

#ifndef ICONWINDOW
RefreshIcon(screen)
register Screen *screen;
{
	XBitmapBitsPut(screen->iconwindow, 0, 0, icon_width, icon_height,
		icon_bits, screen->foreground, screen->background,
		screen->iconmask, GXcopy, AllPlanes);
}
#endif ICONWINDOW

#ifndef vms
get_pty (pty, pty_name)
/*
   opens a pty, storing fildes in pty
   and it's identifying character in pty_name.
 */
int *pty;
char *pty_name;
{
	int devindex, letter = 0;
	int fd;
	extern errno;

	if (debug) {
	    fd = open ("xterm.debug.log", O_WRONLY | O_CREAT | O_TRUNC, 0666);
	    dup2 (fd, fileno (stderr));
	}

	while (letter < 4) {
	    ttydev [8] = ptydev [8] = "pqrs" [letter++];
	    devindex = 0;

	    while (devindex < 16) {
		ptydev [9] = *pty_name = "0123456789abcdef" [devindex++];
		if ((*pty = open (ptydev, O_RDWR, 0)) < 0)	{
			if (debug) fprintf (stderr, "pty %d code %d\n",
					devindex - 1, errno);
			continue;
		}
		goto got_pty;
	    }
	}
	
	fprintf (stderr,"Not enough available pty's\n");
	exit (11);

got_pty:
	if (debug) {
		close (fileno (stderr));
		close (fd);
	}
}
#endif vms
get_terminal (disp, term, fn, fb, 
#ifdef ICONWINDOW
      fi,
#endif ICONWINDOW
      geometry, def,
      border, borderwidth, do_warp, slave, reverse, multiscroll, bitmapicon,
      tek, fore_color, back_color, brdr_color, curs_color, mous_color
#ifdef JUMPSCROLL
      , jumpscroll
#endif JUMPSCROLL
      )
/* 
 * sets up X and initializes the terminal structure except for term.buf.fildes.
 */
char *disp;
register Terminal *term;
char *fn, *fb;
#ifdef ICONWINDOW
char *fi;
#endif ICONWINDOW
char *geometry, *def;
int border, borderwidth, do_warp, reverse, multiscroll, bitmapicon;
int slave;
int tek;
#ifdef JUMPSCROLL
int jumpscroll;
#endif JUMPSCROLL
char *fore_color, *back_color, *brdr_color, *curs_color, *mous_color;
{
	int width, height;
	FontInfo *fInfo;
#ifdef ICONWINDOW
	FontInfo *ifInfo;
#endif ICONWINDOW
	register Keyboard *keyboard;
	register Screen *screen;
	Buffer *buf;
	long scale_x, scale_y;
	Color cdef;
	int pixels[2];
	int try = 10;
	OpaqueFrame twindow;

	keyboard = &term->keyboard;
	screen = &term->screen;
	buf = &term->buf;

	term->flags = WRAPAROUND|SMOOTHSCROLL;

	keyboard->flags = NULL;
	keyboard->offset = 0;
	
#ifdef ICONWINDOW
	term->actionflags = (bitmapicon == 2) ? ICONINPUT : 0;
#endif ICONWINDOW

	buf->cnt = 0;
	buf->ptr = &buf->buf[0];
	
	TabReset (term->tabs);

	while (try--)
	    if ((screen->display = XOpenDisplay(disp)) == NULL) {
		if (do_warp == 0) {
		    fprintf(stderr, "xterm: Can't open display '%s'\n",
			    XDisplayName(disp));
		    exit(1);
		}
		sleep (5);
		continue;
	    }
	    else break;

	if (try <= 0)  {
		fprintf(stderr, "%xterm: Can't open display '%s'\n",
		    XDisplayName(disp));
		exit (111);
	}	    

	screen->foreground = BlackPixel;
	screen->background = WhitePixel;
	screen->cursorcolor = BlackPixel;
	screen->mousecolor = BlackPixel;
	screen->xorplane = 1;
	if (DisplayCells() > 2 && (fore_color || back_color || curs_color)) {
		if (tek) {
			if (curs_color && XParseColor(curs_color, &cdef)) {
				if (XGetColorCells(0, 2, 1, &screen->xorplane,
								pixels)) {
					screen->background = pixels[0];
					screen->foreground = pixels[1];
					screen->cursorcolor = screen->background |
					screen->xorplane;
					cdef.pixel = screen->cursorcolor;
					XStoreColor(&cdef);
				}
			} 
			else if (XGetColorCells(0, 1, 1, &screen->xorplane,
							&screen->background)) {
				screen->foreground = screen->background |
				screen->xorplane;
				screen->cursorcolor = screen->foreground;
			}
			if (screen->background != WhitePixel) {
				if (back_color == NULL ||
					!XParseColor(back_color, &cdef)) {
					cdef.pixel = WhitePixel;
					XQueryColor(&cdef);
				}
				cdef.pixel = screen->background;
				XStoreColor(&cdef);
				if(screen->cursorcolor != screen->foreground) {
					cdef.pixel = screen->foreground |
						screen->xorplane;
					XStoreColor(&cdef);
				}
				if (fore_color == NULL ||
					!XParseColor(fore_color, &cdef)) {
					cdef.pixel = BlackPixel;
					XQueryColor(&cdef);
				}
				cdef.pixel = screen->foreground;
				XStoreColor(&cdef);
			}
		}
		else {
			if (fore_color && XParseColor(fore_color, &cdef) &&
						XGetHardwareColor(&cdef)) {
				screen->foreground = 
					screen->foreground = cdef.pixel;
				reverse = 0;
			}
			if (back_color && XParseColor(back_color, &cdef) &&
						XGetHardwareColor(&cdef)) {
				screen->background = cdef.pixel;
				reverse = 0;
			}
			if (curs_color && XParseColor(curs_color, &cdef) &&
			XGetHardwareColor(&cdef))
			screen->cursorcolor = cdef.pixel;
			else
			screen->cursorcolor = screen->foreground;
		}
	}

	screen->border = border;
	screen->borderwidth = borderwidth;
	screen->fnt_norm = screen->fnt_bold = NULL;
	   
	if ((fInfo = XOpenFont(fn)) == NULL) {
		fprintf(stderr, "%s: Could not open font %s!\n",
			xterm_name, fn);
		exit(1);
	}
	if (fn) screen->fnt_norm = fInfo->id;
	if (fb) screen->fnt_bold = XOpenFont(fb)->id;
	screen->f_width = fInfo->width;
	screen->f_height = fInfo->height;

#ifdef ICONWINDOW
	screen->fnt_icon = NULL;
	if ((ifInfo = XOpenFont(fi)) == NULL) {
		fprintf(stderr, "%s: Could not open font %s!\n",
			xterm_name, fi);
		exit(1);
	}
	screen->fnt_icon = ifInfo->id;
	screen->if_width = ifInfo->width;
	screen->if_height = ifInfo->height;
#endif ICONWINDOW

	if (brdr_color && DisplayCells() > 2 &&
	    XParseColor(brdr_color, &cdef) && XGetHardwareColor(&cdef))
	    screen->bordertile = XMakeTile(cdef.pixel);
	else
	    screen->bordertile = BlackPixmap;

	screen->cursor = XStoreBitmap(xterm_width, xterm_height, xterm_bits);
	screen->mask = 	XStoreBitmap(xterm_mask_width, xterm_mask_height, 
				    xterm_mask_bits);
	if (mous_color && DisplayCells() > 2 &&
	    XParseColor(mous_color, &cdef) && XGetHardwareColor(&cdef))
	    screen->mousecolor = cdef.pixel;
	else
	    screen->mousecolor = screen->cursorcolor;
	screen->curs = XStoreCursor(screen->cursor, screen->mask, 5, 8,
		screen->mousecolor, screen->background, GXcopy);
	screen->rcurs = XStoreCursor(screen->cursor, screen->mask, 5, 8,
		screen->background, screen->mousecolor, GXcopy);

	if (reverse) {	/* reverse is black background with white chars */
		term->flags |= REVERSE_VIDEO;
		screen->cursorcolor = screen->background;
		screen->background = screen->foreground;
		screen->foreground = screen->cursorcolor;
		if (screen->bordertile == BlackPixmap)
		    screen->bordertile = WhitePixmap;
	}
	screen->bgndtile = XMakeTile(screen->background);

	twindow.bdrwidth = screen->borderwidth;
	twindow.border = screen->bordertile;
	twindow.background = screen->bgndtile;

	screen->window = XCreateTerm ("Terminal Emulator", xterm_name,
		geometry, def, &twindow, 12, 8, 
		screen->border * 2, screen->border * 2,
		&width, &height, 
		fInfo, fInfo->width, fInfo->height);

	screen->width = twindow.width - border * 2;
	screen->height = twindow.height - border * 2;
#ifdef ICONWINDOW
	screen->fullwindow = screen->window;
	screen->fullwidth = screen->width;
	screen->fullheight = screen->height;
	screen->ff_height = screen->f_height;
	screen->ff_width = screen->f_width;
#endif ICONWINDOW

	/* Reset variables used by ANSI emulation. */

	screen->ansi.a_type = 0;		/* New sequence.	*/
	screen->ansi.a_pintro = 0;		/* New sequence.	*/
	screen->ansi.a_final = 0;		/* New sequence.	*/
	screen->gsets[0] = 'B';			/* ASCII_G		*/
	screen->gsets[1] = 'B';
	screen->gsets[2] = '<';			/* DEC supplemental.	*/
	screen->gsets[3] = '<';
	screen->curgl = 0;			/* G0 => GL.		*/
	screen->curgr = 2;			/* G2 => GR.		*/
	screen->curss = 0;			/* No single shift.	*/
	screen->rx8bit = 0;			/* 7 bit.		*/
	screen->tx8bit = 0;			/* 7 bit.		*/
	screen->mode = ANSInormal;

	/* Reset Tektronix alpha mode */
	screen->TekGMode = 0;
	screen->TekAMode = 0;
	screen->cur_x = screen->cur_y = 0;
	screen->cur_X = screen->cur_Y = 0;

        /* Set Tektronix scale factor */
        scale_x = (screen->width << 14) / 4096;
        scale_y = (screen->height << 14) / 3128;

#ifdef notdef
        /* Alternative method when divide is faster than multiple shifts */
	scale_x = (screen->width * 10000) / 4096;
        scale_y = (screen->height * 10000) / 3128;
#endif notdef

	screen->TekScale = scale_x;
	if (scale_y < scale_x) screen->TekScale = scale_y;

	if (bitmapicon) {
#ifdef ICONWINDOW
		screen->iconwidth = (screen->width  / fInfo->width) * ifInfo->width;
                screen->iconheight = (screen->height / fInfo->height) * ifInfo->height;

                screen->iconwindow = XCreateWindow (RootWindow,
                        0, 0, icon_width, icon_height,
                        screen->border, screen->bordertile, screen->bgndtile);

                XSelectInput (screen->iconwindow,
                                (bitmapicon == 2) ?
                                        ExposeWindow | ExposeRegion | ExposeCopy | KeyPressed :
                                        ExposeWindow | ExposeRegion | ExposeCopy);

                XDefineCursor(screen->iconwindow,
                                (reverse ? screen->rcurs : screen->curs));
#else ICONWINDOW
		screen->iconwindow = XCreateWindow (RootWindow,
			0, 0, icon_width, icon_height, 0, 0, 0);

		XTileRelative(screen->iconwindow);

		screen->iconmask = XStoreBitmap(icon_mask_width,
			icon_mask_height, icon_mask_bits);
		
		XSelectInput (screen->iconwindow, ExposeWindow);
#endif ICONWINDOW

		XSetIconWindow(screen->window, screen->iconwindow);
	}
#ifdef ICONWINDOW
	else
		screen->iconwindow = NULL;
#endif ICONWINDOW

	if (reverse)
		XDefineCursor(screen->window, screen->rcurs);
	else	XDefineCursor(screen->window, screen->curs);

	XStoreName (screen->window, (win_name != (char *) 0 ? win_name:
			(do_warp ? "login" :
			(slave ? "xtermslave" :
			(command_to_exec ? command_to_exec[0] : "xterm")))));

	XSetResizeHint (screen->window,
			2 * border, 2 * border, fInfo->width, fInfo->height);
		
	XMapWindow (screen->window);

	XSelectInput (screen->window, KeyPressed | ExposeWindow | EnterWindow |
		ButtonPressed | ButtonReleased | ExposeRegion | ExposeCopy);


	if (do_warp)
		XWarpMouse (screen->window,
			    screen->width >> 1, screen->height >>1);

	screen->cur_col = screen->cur_row = 0;
	screen->max_col = screen->width  / fInfo->width - 1;
	screen->top_marg = 0;
	screen->bot_marg = screen->max_row = screen->height/ fInfo->height - 1;

	screen->sc.row = screen->sc.col = screen->sc.flags = NULL;


	/* allocate memory for screen buffer */
	screen->buf = (ScrnBuf) Allocate (screen->max_row + 1,
					  screen->max_col +1);

	screen->do_wrap = NULL;
	screen->scrolls = screen->incopy = 0;
	screen->multiscroll = multiscroll;
#ifdef JUMPSCROLL
	if (screen->jumpscroll = jumpscroll)
		term->flags &= ~SMOOTHSCROLL;
#endif JUMPSCROLL


	/* display initial cursor */
	CursorToggle (screen, 1);
}

spawn (display, pty, Xsocket, screen, getty, slave, passedPty)
/* 
 *  Inits pty and tty and forks a login process. Returns fd for pty in pty.
 *  Does not close fd Xsocket.
 *  If getty,  execs getty rather than csh and uses std fd's rather
 *  than opening a pty/tty pair.
 *  If slave, the pty named in passedPty is already open for use
 */
int *pty, Xsocket;
Screen *screen;
char *getty;		/* if true execs /etc/getty - Xwindow */
int slave;
char *passedPty;
char *display;
{
	int index1, tty;
	char pty_name;
	int discipline;
	unsigned lmode;
	struct tchars tc;
	struct ltchars ltc;
	struct sgttyb sg;

	char termcap [1024];
	char newtc [1024];
	char prog [256];
	char numbuf[10];
	char *ptr;
	char *index (), *strindex ();
	int i = 0;
	char **envnew;		/* new environment */
	struct passwd *getpwuid();
	struct passwd *pw;
	char logindev[32];
	char *TermName = "xterm";
	int ldisc = 0;

	/* be real paranoid about getting some usable entry */
	if (tgetent (termcap, TermName)  == 1
		|| (TermName = "vt102", tgetent(termcap, TermName)) == 1
		|| (TermName = "ansi",  tgetent(termcap, TermName)) == 1) {
		/* update termcap string */
		/* first do columns */
		if ((ptr = strindex (termcap, "co#")) == NULL){
			fprintf(stderr,"Can't find co# in termcap string %s\n",
				TermName);
			exit (1);
		}
		strncpy (newtc, termcap, ptr - termcap + 3);
		newtc[ptr-termcap+3] = '\0';
		sprintf (numbuf, "%d\0", screen->max_col + 1);
		strcat (newtc, numbuf);
		ptr = index (ptr, ':');
		strcat (newtc, ptr);
		strncpy (termcap, newtc, sizeof(termcap));
		/* now do lines */
		if ((ptr = strindex (termcap, "li#")) == NULL) {
			fprintf(stderr,"Can't find li# in termcap string %s\n",
				TermName);
			exit (1);
		}
		strncpy (newtc, termcap, ptr - termcap + 3);
		newtc[ptr-termcap+3] = '\0';
		sprintf (numbuf, "%d\0", screen->max_row + 1);
		strcat (newtc, numbuf);
		ptr = index (ptr, ':');
		strcat (newtc, ptr);
		if (strcmp(TermName, "xterm") != 0)
		    fprintf(stderr, 
		    "xterm: can't find xterm termcap entry, using %s instead!\n", TermName);
	}
#ifndef vms
	else fprintf(stderr,"xterm: can't find any usable termcap entry!\n");

	if (getty) {
		*pty = loginpty;
	}
	else if (slave) {
	    *pty = slave;
	    ptydev[8] = ttydev[8] = passedPty[0];
	    ptydev[9] = ttydev[9] = passedPty[1];
	}
	else {
		if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0) {
			if (errno != ENXIO) Error();
			else {
				no_dev_tty = 1;
				sg = d_sg;
				tc = d_tc;
				discipline = d_disipline;
				ltc = d_ltc;
				lmode = d_lmode;
				for (index1 = 0; index1 < 3; index1++)
				    close (index1);
			}
		}
		else {
			/* get a copy of the current terminal's state */

			if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0) Error ();

			if (ioctl (tty, TIOCGETP, &sg) == -1) Error ();
			if (ioctl (tty, TIOCGETC, (int *)&tc) == -1) Error ();
			if (ioctl (tty, TIOCGETD, &discipline) == -1) Error ();
			if (ioctl (tty, TIOCGLTC, (int *)&ltc) == -1) Error ();
			if (ioctl (tty, TIOCLGET, &lmode) == -1) Error ();

			close (tty);

			/* close all std file descriptors */
			for (index1 = 0; index1 < 3; index1++)
			    close (index1);
			if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0) Error ();

			if (ioctl (tty, TIOCNOTTY, 0) == -1) Error ();
			close (tty);
		}

		get_pty (pty, &pty_name);

		if (*pty != Xsocket + 1) {
			dup2 (*pty, Xsocket + 1);
			close (*pty);
			*pty = Xsocket + 1;
		}

		ttydev [9] = pty_name;
		if ((tty = open (ttydev, O_RDWR, 0)) < 0) Error ();

		/* change ownership of tty to real group and user id */
		chown (ttydev, getuid (), tty_gid (getgid()));

		/* change protection of tty */
		chmod (ttydev, 0620);

		if (tty != Xsocket + 2)	{
			dup2 (tty, Xsocket + 2);
			close (tty);
			tty = Xsocket + 2;
		}

		/* set the new terminal's state to be the old one's 
		   with minor modifications for efficiency */

		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
		sg.sg_flags |= ECHO | CRMOD;
		/* make sure speed is set on pty so that editors work right*/
		sg.sg_ispeed = B9600;
		sg.sg_ospeed = B9600;

		if (ioctl (tty, TIOCSETP, &sg) == -1) Error ();
		if (ioctl (tty, TIOCSETC, (int *)&tc) == -1) Error ();
		if (ioctl (tty, TIOCSETD, &discipline) == -1) Error ();
		if (ioctl (tty, TIOCSLTC, (int *)&ltc) == -1) Error ();
		if (ioctl (tty, TIOCLSET, &lmode) == -1) Error ();
#ifdef sun
#ifdef TIOCCONS
		if (SunConsole) {
			int on = 1;
			if (ioctl (tty, TIOCCONS, &on) == -1) Error();
		}
#endif TIOCCONS
#endif sun

		close (open ("/dev/null", O_RDWR, 0));

		for (index1 = 0; index1 < 3; index1++)
			dup2 (tty, index1);
	}

	if (!slave && (screen->pid = fork ()) == -1) Error ();
		
	if (!slave && screen->pid == 0) {
		extern char **environ;
		int pgrp = getpid();

		close (Xsocket);
		close (*pty);

		if (getty == NULL) close (tty);

		signal (SIGCHLD, SIG_DFL);
		signal (SIGHUP, SIG_IGN);

		/* copy the environment before Setenving */
		while (environ [i] != NULL) i++;
		envnew = (char **) malloc (sizeof (char *) * (i + 4));
		for (; i >= 0; i--) envnew [i] = environ [i];
		environ = envnew;
		Setenv ("TERM=", TermName);
		Setenv ("TERMCAP=", newtc);
		/* put the display into the environment of the shell*/
		if (display[0] != '\0') 
		Setenv ("DISPLAY=", screen->display->displayname);

		pw = getpwuid (getuid ());
		signal(SIGTERM, SIG_DFL);
		ioctl(0, TIOCSPGRP, &pgrp);
		setpgrp (0, 0);
		close(open(ttyname(0), O_WRONLY, 0));
		setpgrp (0, pgrp);
		if (dologinflag)	/* login */
			utrelog(1, pw->pw_name, screen->display->displayname);

		setgid(getgid ());
		setuid(getuid ());

		if (command_to_exec) {
			execvp(command_to_exec[0], command_to_exec, 0);
		}
		signal(SIGHUP, SIG_IGN);
		if (getty) {
			ioctl (0, TIOCNOTTY, 0);
			execl ("/etc/getty", "+", "Xwindow", getty, 0);
		}
		signal(SIGHUP, SIG_DFL);

		if (*pw->pw_shell == '\0') pw->pw_shell = "/bin/sh";

		/* make sure line discipline gets set */
		ldisc = 0;
		ioctl(0, TIOCSETD, &ldisc);
		if (!strcmp(pw->pw_shell, "/bin/csh")) {
			ldisc = NTTYDISC;
			ioctl(0, TIOCSETD, &ldisc);
		}
		
		ptr = rindex(pw->pw_shell, '/');
		if (ptr == NULL)
			ptr = pw->pw_shell;
		else
			ptr++;
		if (dologinflag) {
			prog[0] = '-';
			strcpy(&prog[1], ptr);
		} else
			strcpy(prog, ptr);
		execlp (pw->pw_shell, prog, 0);
		fprintf (stderr,"Error: Could not exec %s!\n", pw->pw_shell);
		sleep(5);
		Cleanup(121);
	}

	close (tty);
	signal(SIGHUP,SIG_IGN);
	signal(SIGTTOU,SIG_IGN); /* so that TIOCSWINSZ doesn't block */

	if ((tty = open (no_dev_tty ? "/dev/null" : "/dev/tty",
	    O_RDWR, 0)) < 0) Error();
	for (index1 = 0; index1 < 3; index1++)
		dup2 (tty, index1);
	if (tty > 2) close (tty);

	/* set ids to user's */
	/*
	setgid (getgid ());
	setuid (getuid ());
		setregid (getegid (), getgid ());
		setreuid (geteuid (), getuid ());
	*/
#else vms
        {
            struct astroutine ast;

            if (open_pty (pty, Xsocket+1) < 0) Error ();

            ast.routine = Cleanup;              /* do this when pty hangs up */
            ast.param = 0;
            ptyctl (*pty, TIOCHPCL, &ast);

            if (!getty) {                       /* spawn a subprocess */
                char ptyname[64], command_string[256];
                short ptychan;
                struct tmode ptymode;
                struct dsc$descriptor_s ptydsc, command;
                int flags = 0x01;

                /* in_getname() works just like getname() */
                if (in_getname( *pty, ptyname ) == NULL) {
                    perror( "Error: pty getname() failed\n" );
                    Cleanup( vaxc$errno );
                }

                ptydsc.dsc$b_dtype = DSC$K_DTYPE_T;
                ptydsc.dsc$b_class = DSC$K_CLASS_S;
                ptydsc.dsc$w_length = strlen (ptyname);
                ptydsc.dsc$a_pointer = ptyname;
                /* assign a channel to keep from hanging up pty */
                if ((vaxc$errno = sys$assign( &ptydsc, &ptychan, 0, 0 )) != SS$NORMAL) {
                    perror( "Error: Assign pty failed\n" );
                    Cleanup( vaxc$errno );
                }

                ptyctl( *pty, TIOCGETP, &ptymode );
                ptymode.type = TT$_VT102;
                ptymode.basic_char |= TT$M_LOWER | TT$M_MECHTAB | TT$M_SCOPE;
                ptymode.ext_char |= TT2$M_ANSICRT | TT2$M_EDIT | TT2$M_DECCRT;
                ptymode.width = screen->max_col + 1;
                ptymode.length = screen->max_row + 1;
                ptyctl( *pty, TIOCSETP, &ptymode );

                if (command_to_exec) {
                    int i;

                    strcpy( command_string, command_to_exec[0] );
                    for (i=1; command_to_exec[i] != NULL; i++) {
                        strcat( command_string, " " );
                        strcat( command_string, command_to_exec[i] );
                    }
                    command.dsc$b_dtype = DSC$K_DTYPE_T;
                    command.dsc$b_class = DSC$K_CLASS_S;
                    command.dsc$a_pointer = command_string;
                    command.dsc$w_length = strlen (command_string);
                }

                Setenv ("TERM", TermName);
                Setenv ("TERMCAP", newtc);
                /* put the display into the environment of the shell*/
                if (display[0] != '\0')
                Setenv ("DISPLAY", screen->display->displayname);

                if ((vaxc$errno = lib$spawn( (command_to_exec ? &command : 0)
                            , (command_to_exec ? 0 : &ptydsc), &ptydsc, &flags
                            , 0, 0, 0, 0, Cleanup, 0, 0, 0 )) != SS$_NORMAL) {
                    perror( "Error: Spawn failed\n" );
                    Cleanup( vaxc$errno );
                }
                sys$dassgn( ptychan );
            }
        }
#endif vms
}

#ifndef vms
static reapchild ()
{
	extern Terminal term;
	register long pgrp;
	union wait status;
	int pid;
	
	if (debug) printf ("Exiting\n");
	pid  = wait3 (&status, WNOHANG, NULL);
	if (!pid) return;
	if (pid != term.screen.pid) return;
	
	if (dologinflag)
		utrelog(0, "", "");
	Cleanup(0);
}

consolepr(string)
char *string;
{
	extern int errno;
	extern char *sys_errlist[];
	int oerrno;
	int f;
	oerrno = errno;
	f = open("/dev/console",O_WRONLY, 0);
	write(f, "xterm: ", 7);
	write(f, string, strlen(string));
	write(f, ": ", 2);
	write(f, sys_errlist[oerrno],strlen(sys_errlist[oerrno]));
	write(f, "\n", 1);
	close(f);
	if ((f = open("/dev/tty", 2, 0)) >= 0) {
		ioctl(f, TIOCNOTTY, 0);
		close(f);
	}
}

#define TTYGRPNAME	"tty"

tty_gid(default_gid)
	int default_gid;
{
	struct group *getgrnam(), *gr;
	int gid = default_gid;

	gr = getgrnam(TTYGRPNAME);
	if (gr != (struct group *) 0)
		gid = gr->gr_gid;

	endgrent();

	return (gid);
}

utrelog(io, user, display)
int io;
char *user;
char *display;
{
	struct utmp ut;
	struct ttyent *ty;
	register int s;
	long slot;
	int ufd;
	char *colon;
	
	if (io == 1) {
		strncpy(ut.ut_line, &ttydev[5], sizeof ut.ut_line);
		colon = index(display, ':');
		if (colon)
			*colon = '\0';
		strncpy(ut.ut_host, display, sizeof ut.ut_host);
		if (colon)
			*colon = ':';
		strncpy(ut.ut_name, user, sizeof ut.ut_name);
		(void) time(&ut.ut_time);
	}
	else {
		strcpy(ut.ut_line, "");
		strcpy(ut.ut_name, "");
		strcpy(ut.ut_host, "");
		ut.ut_time = 0;
		chown(ttydev, 0, 0);
		chmod(ttydev, 0666);
	}

	setttyent();
	slot = 0;
	s = 0;
	while ((ty = getttyent()) != NULL) {
		s++;
		if (strcmp(ty->ty_name, &ttydev[5]) == 0) {
			slot = s;
			break;
		}
	}
	endttyent();
	if (slot > 0 && (ufd = open("/etc/utmp", O_WRONLY, 0)) >= 0) {
		if (lseek(ufd, slot * sizeof ut, 0) < 0L ||
		    write(ufd, (char *)&ut, sizeof ut) != sizeof ut) {
			close(ufd);
			return(-1);
		}
		close(ufd);
	}
	return(0);
}
#endif vms
