ftp.nice.ch/pub/next/unix/macintosh/uw.4.2.N.bs.tar.gz#/uw/server/uw_win.c

This is uw_win.c in view mode; [Download] [Up]

/*
 *	uw_win - window handling for UW
 *
 * Copyright 1986 by John D. Bruner.  All rights reserved.  Permission to
 * copy this program is given provided that the copy is not sold and that
 * this copyright notice is included.
 */

#include <sys/types.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <strings.h>
#include <stdio.h>

#include "openpty.h"
#include "uw_param.h"
#include "uw_opt.h"
#include "uw_win.h"
#include "uw_fd.h"

/*
 * "defwtype" specifies the default window type.  This type is used when
 * more specific information is not available.
 */
wtype_t defwtype = WT_ADM31;

/*
 * "window" is declared in "uw_win.h"  Here we define it.
 */
struct window window[NWINDOW];		/* window data structures */

/*
 * "emulation" describes window emulation-specific data.  "generic_emul"
 * describes emulations which do not require special server attention
 * (e.g. file transfer, all of whose real work is done by a separate process).
 */
extern struct emulation adm31_emul, vt52_emul, ansi_emul, tek_emul;
static struct emulation generic_emul;
static struct emulation *emulation[WT_MAXTYPE+1] = {
	&adm31_emul,
	&vt52_emul,
	&ansi_emul,
	&tek_emul,
	&generic_emul,
	&generic_emul,
	&generic_emul,
};

extern char *win_getopt();
extern void win_setopt();

static woptarg_t woa_vis[] = { WOA_UDATA(1), WOA_END };
static woptarg_t woa_type[] = { WOA_UDATA(6), WOA_END };
static woptarg_t woa_pos[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };
static woptarg_t woa_title[] = { WOA_STRING(255), WOA_END };
static woptarg_t woa_size[] = { WOA_UDATA(12), WOA_UDATA(12), WOA_END };

static struct woptdefn genwinopt = {
	(1<<WOG_VIS), 0, 0, 0,
	(1<<WOG_VIS)|(1<<WOG_TYPE)|(1<<WOG_POS)|(1<<WOG_TITLE)|(1<<WOG_SIZE),
	{
/* WOG_END */	{ NULL, NULL, NULL },
/* WOG_VIS */	{ woa_vis, win_getopt, win_setopt },
/* WOG_TYPE */	{ woa_type, win_getopt, win_setopt },
/* WOG_POS */	{ woa_pos, win_getopt, win_setopt },
/* WOG_TITLE */	{ woa_title, win_getopt, win_setopt },
/* WOG_SIZE */	{ woa_size, win_getopt, win_setopt },
/* WOG_6 */	{ NULL, NULL, NULL },
/* WOG_7 */	{ NULL, NULL, NULL }
	}
};

/*
 * This is a violation of the level structure, but it is expedient.
 */
extern void ipc_optmsg();

win_init()
{
	register struct window *w;

	/*
	 * Initialize.  Mark all windows unallocated.
	 */
	for (w=window; w < window+NWINDOW; w++)
		w->w_alloc = 0;
}

long
win_mkid()
{
	static unsigned short i = 0;
	static long pid = -1;

	if (pid == -1)
		pid = getpid();
	return((pid << (NBBY*(sizeof(long)/sizeof(short)))) | i++);
}

struct window *
win_search(wid, maxwin)
long wid;
nwin_t maxwin;
{
	register struct window *w;

	for (w=window; w < window+maxwin; w++)
		if (w->w_alloc && w->w_id == wid)
			return(w);
	return((struct window *)0);
}

struct window *
win_neww(wclass, wtype, wnum, maxwin, wid, datafd, ctlfd, options)
wclass_t wclass;
wtype_t wtype;
nwin_t wnum;
nwin_t maxwin;
long wid;
fildes_t datafd;
fildes_t ctlfd;
struct woptdefn *options;
{
	fildes_t fd;
	int pid;
	struct window *w;
	char *tty, *shell;
	auto struct ptydesc pt;
	extern char *getenv();

	/*
	 * Create a new window.  "wclass" specifies the window wclass.
	 * If "wnum" is negative, choose a window number; otherwise,
	 * "wnum" is the window number.  "datafd" and "ctlfd" are the
	 * data and control file descriptors to be associated with
	 * this window.  If "datafd" is negative and "wclass" is
	 * WC_INTERNAL, allocate a pseudo-terminal.
	 *
	 * If "options" is non-NULL it specifies the address of an
	 * option definition structure; otherwise, a new one is constructed
	 * from the generic and emulation-specific prototype structures.
	 *
	 * If "wid" is nonzero it is a proposed window ID.  It must be
	 * unique (not in use).  If "wid" is zero, a new ID is assigned.
	 *
	 * The window type "wtype" will always be a terminal emulation
	 * if the wclass is WC_INTERNAL.
	 *
	 * Internal-class windows are visible by default, while external
	 * ones are initially invisible.
	 *
	 * Return the address of the window structure or NULL if
	 * none could be created.
	 */
	tty = (char *)0;
	if (wtype > WT_MAXTYPE)
		return((struct window *)0);
	if (wid == 0) {
		while (win_search(wid=win_mkid(), maxwin) != NULL)
			;
	} else if (win_search(wid, maxwin) != NULL)
		return((struct window *)0);
	if (datafd < 0 && wclass == WC_INTERNAL) {
		if (!openpty(&pt)) {
			datafd = pt.pt_pfd;
			tty = pt.pt_tname;
			while ((pid = fork()) < 0)
				sleep(5);
			if (!pid) {
				win_envinit(wtype, wid);
				(void)signal(SIGHUP, SIG_DFL);
				(void)signal(SIGINT, SIG_DFL);
				(void)signal(SIGQUIT, SIG_DFL);
				(void)signal(SIGTERM, SIG_DFL);
				(void)signal(SIGTSTP, SIG_IGN);
				(void)signal(SIGCHLD, SIG_DFL);
				(void)ioctl(open("/dev/tty",O_RDWR),
				    (int)TIOCNOTTY, (char *)0);
				(void)close(open(pt.pt_tname, O_RDONLY));
				(void)setuid(getuid());
				if (!(shell = getenv("SHELL")))
					shell = "/bin/sh";
				if (pt.pt_tfd != 0)
					(void)dup2(pt.pt_tfd, 0);
				if (pt.pt_tfd != 1);
					(void)dup2(pt.pt_tfd, 1);
				if (pt.pt_tfd != 2)
					(void)dup2(pt.pt_tfd, 2);
				for (fd=3; fd < nfds; fd++)
					(void)close(fd);
				tty_mode(0);	/* HACK! */
				execl(shell, shell, (char *)0);
				_exit(1);
			} else {
				utmp_add(tty);
				(void)close(pt.pt_tfd);
			}
		}
	}

	if (datafd >= 0) {
		if (wnum > 0) {
			w = WIN_PTR(wnum);
			if (w->w_alloc)
				w = (struct window *)0;
		} else {
			for (w=window; w < window+maxwin && w->w_alloc; w++)
				;
			if (w >= window+maxwin)
				w = (struct window *)0;
		}
	} else
		w = (struct window *)0;

	if (w) {
		w->w_alloc = 1;
		w->w_id = wid;
		w->w_class = wclass;
		w->w_type = wtype;
		w->w_visible = (w->w_class == WC_INTERNAL);
		w->w_position.h = w->w_position.v = 0;
		w->w_size.h = w->w_size.v = 0;
		w->w_title[0] = '\0';
		if (emulation[wtype]->we_start &&
		    !(*emulation[wtype]->we_start)(w)) {
			if (options)
				w->w_optdefn = *options;
			else
				opt_new(&w->w_optdefn, &genwinopt,
				    (struct woptdefn *)0);
		} else {
			if (options)
				w->w_optdefn = *options;
			else
				opt_new(&w->w_optdefn, &genwinopt,
				    &emulation[wtype]->we_optdefn);
		}
		w->w_datafd = datafd;
		(void)fcntl(datafd, F_SETFL, FNDELAY);
		FD_SET(datafd, &selmask[0].sm_rd);
		fdmap[datafd].f_type = FDT_DATA;
		fdmap[datafd].f_win = w;
		if (w->w_class == WC_INTERNAL) {
			if (tty)
				(void)strncpy(w->w_tty, tty, sizeof w->w_tty);
		} else {
			w->w_ctlfd = ctlfd;
			if (ctlfd >= 0) {
				(void)fcntl(ctlfd, F_SETFL, FNDELAY);
				FD_SET(ctlfd, &selmask[0].sm_rd);
				fdmap[ctlfd].f_type = FDT_CTL;
				fdmap[ctlfd].f_win = w;
				if (emulation[wtype]->we_setext)
					(*emulation[wtype]->we_setext)(&w->w_optdefn);
				opt_setext(&w->w_optdefn, ipc_optmsg);
			}
		}
	}
			
	return(w);
}

win_killw(w)
register struct window *w;
{
	/*
	 * Kill the window "w".  This is pretty simple; we just close
	 * the data and control file descriptors and mark the structure
	 * inactive.
	 */
	if (w && w->w_alloc) {
		if (w->w_datafd >= 0) {
			if (w->w_class == WC_INTERNAL)
				utmp_rm(w->w_tty);
			FD_CLR(w->w_datafd, &selmask[0].sm_rd);
			FD_CLR(w->w_datafd, &selmask[0].sm_wt);
			FD_CLR(w->w_datafd, &selmask[0].sm_ex);
			fdmap[w->w_datafd].f_type = FDT_NONE;
			(void)close(w->w_datafd);
		}
		if (w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0) {
			FD_CLR(w->w_ctlfd, &selmask[0].sm_rd);
			FD_CLR(w->w_ctlfd, &selmask[0].sm_wt);
			FD_CLR(w->w_ctlfd, &selmask[0].sm_ex);
			fdmap[w->w_ctlfd].f_type = FDT_NONE;
			(void)close(w->w_ctlfd);
		}
		w->w_alloc = 0;
	}
}

win_renew(w, report)
struct window *w;
int report;
{
	/*
	 * Reinitialize (re-NEW) the window "w".  Report the state of the
	 * window to the Mac if "report" is nonzero.
	 */
	opt_renew(&w->w_optdefn, report);
}

win_newtype(w, wtype)
register struct window *w;
register wtype_t wtype;
{
	/*
	 * Change the window emulation type to "wtype".
	 */
	if (wtype <= WT_MAXTYPE && wtype != w->w_type) {
		if (emulation[w->w_type]->we_stop)
			(*emulation[w->w_type]->we_stop)(w);
		w->w_type = wtype;
		if (emulation[wtype]->we_start &&
		    !(*emulation[wtype]->we_start)(w)) {
			opt_newtype(&w->w_optdefn, &genwinopt,
			    (struct woptdefn *)0);
		} else {
			opt_newtype(&w->w_optdefn, &genwinopt,
			    &emulation[wtype]->we_optdefn);
		}
		if (w->w_class == WC_EXTERNAL && w->w_ctlfd >= 0) {
			if (emulation[wtype]->we_setext)
				(*emulation[wtype]->we_setext)(&w->w_optdefn);
			opt_setext(&w->w_optdefn, ipc_optmsg);
		}
	}
}

win_envinit(wtype, wid)
register wtype_t wtype;
long wid;
{
	register char *widstr;
	auto char *env[2];

	/*
	 * Set up the environment according to the new window type and
	 * window ID.
	 *
	 * A 64-bit integer will fit in 20 digits.  If a "long" is wider
	 * than this, then this code will have to be adjusted.
	 */
	if (wtype <= WT_TEK4010)
		tty_envinit(wtype);
	if ((widstr = malloc(sizeof "UW_ID=" + 20)) != NULL) {
		sprintf(widstr, "UW_ID=%ld", wid);
		env[0] = widstr;
		env[1] = (char *)0;
		env_set(env);
	}
}

static
char *
win_getopt(win, num)
caddr_t win;
woption_t num;
{
	register struct window *w;
	static union optvalue ov;

	/*
	 * Get the value of window option "num".  It is arguably wrong to
	 * always return the address of "ov" (even if the window isn't
	 * allocated or an unknown option type was requested); however,
	 * we're already in trouble and there is no good way to recover
	 * at this point.
	 */
	if ((w = (struct window *)win) != NULL && w->w_alloc) {
		switch (num) {
		case WOG_VIS:
			ov.ov_udata1 = w->w_visible;
			break;
		case WOG_TYPE:
			ov.ov_udata6 = w->w_type;
			break;
		case WOG_POS:
			ov.ov_point.h = w->w_position.h;
			ov.ov_point.v = w->w_position.v;
			break;
		case WOG_TITLE:
			(void)strncpy(ov.ov_string, w->w_title,
			    sizeof ov.ov_string);
			ov.ov_string[sizeof ov.ov_string-1] = '\0';
			break;
		case WOG_SIZE:
			ov.ov_point.h = w->w_size.h;
			ov.ov_point.v = w->w_size.v;
			break;
		}
	}
	return((char *)&ov);
}

static
void
win_setopt(win, num, value)
caddr_t win;
woption_t num;
char *value;
{
	register struct window *w;
	register union optvalue *ov;

	/*
	 * Set window option "num" to "value"
	 */
	if ((w = (struct window *)win) != NULL && w->w_alloc &&
	    (ov = (union optvalue *)value) != NULL) {
		switch (num) {
		case WOG_VIS:
			w->w_visible = ov->ov_udata1;
			break;
		case WOG_TYPE:
			win_newtype(w, (wtype_t)ov->ov_udata6);
			break;
		case WOG_POS:
			w->w_position.h = ov->ov_point.h;
			w->w_position.v = ov->ov_point.v;
			break;
		case WOG_TITLE:
			(void)strncpy(w->w_title, ov->ov_string,
			    sizeof w->w_title);
			w->w_title[sizeof w->w_title-1] = '\0';
			break;
		case WOG_SIZE:
			w->w_size.h = ov->ov_point.h;
			w->w_size.v = ov->ov_point.v;
			break;
		}
	}
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.