v01i005: xtclient: use a 3b1 as a layers terminal, Part02/04

Merlin J Mathesius merlinm at i88.isc.com
Fri Feb 15 13:11:39 AEST 1991


Submitted-by: merlinm at i88.isc.com (Merlin J Mathesius)
Posting-number: Volume 1, Issue 5
Archive-name: xtclient/part02

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 02 of xtclient
# ============= xtclient/frame.h ==============
if test ! -d 'xtclient'; then
    echo 'x - creating directory xtclient'
    mkdir 'xtclient'
fi
if test -f 'xtclient/frame.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/frame.h (File already exists)'
else
echo 'x - extracting xtclient/frame.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/frame.h' &&
/*
X * File name:	frame.h
X *
X * Description:	Definitions of frame and packet formats for the "xt/layers"
X *		system for the UNIX-PC.
X *
X *		Also includes macros for mapping frames to packets and
X *		vice-versa.
X *
X * Author:	Merlin J. Mathesius
X */
X
/*
X * Frame format for physical layer/data link layer interface:
X * 
X * +---------------+--------------------------+---------------+
X * | header        | information              | crc-16        |
X * +---------------+--------------------------+---------------+
X *  <-- 2 bytes --> <--  0-32 bytes        --> <-- 2 bytes -->
X * 
X * 
X * Frame header format:
X * 
X * First byte:                       Second byte:
X * +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
X * | 1 |ctl|addr       |seq        | |size                           |
X * +---+---+---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+
X *   7   6   5   4   3   2   1   0     7   6   5   4   3   2   1   0
X * 
X * ctl     - 1 if control frame, 0 if information frame
X * addr    - the "address" of the window/process to send/receive frame (0 to 7)
X * seq     - sequence number (0 to 7)
X * size    - size of the information part of the frame (0 to 32)
X */
X
#define DAT_SZ 32
X
typedef unsigned char Byte;
X
typedef struct _Frame {
X	Byte	mark : 1;	/* always 1 */
X	Byte	ctl  : 1;
X	Byte	addr : 3;
X	Byte	seq  : 3;
X	Byte	size : 8;
X	Byte	data[DAT_SZ];
X	unsigned short	crc;
} Frame;
X
/*
X * Packet format for data link layer/network layer interface:
X * 
X * +-------+-------+--------------------------+
X * | addr  | size  | information              |
X * +-------+-------+--------------------------+
X *  1 byte  1 byte  <--  0-32 bytes        -->
X *
X */
typedef struct _Packet {
X	Byte	addr;
X	Byte	size;
X	Byte	data[DAT_SZ];
} Packet;
X
/* macro to provide simple mapping from an information frame to a packet */
#define FrmToPkt(p,f) \
X	{ \
X		(p)->addr = (f)->addr; \
X		(p)->size = (f)->size; \
X		(void)memcpy((char *)(p)->data, (char *)(f)->data, (int)(f)->size); \
X	}
X
/* macro to provide simple mapping from a packet to an information frame */
#define PktToFrm(f,p) \
X	{ \
X		(f)->addr = (p)->addr; \
X		(f)->size = (p)->size; \
X		(void)memcpy((char *)(f)->data, (char *)(p)->data, (int)(p)->size); \
X		(f)->mark = 1; \
X		(f)->ctl = 0; \
X	}
SHAR_EOF
chmod 0644 xtclient/frame.h ||
echo 'restore of xtclient/frame.h failed'
Wc_c="`wc -c < 'xtclient/frame.h'`"
test 2260 -eq "$Wc_c" ||
	echo 'xtclient/frame.h: original size 2260, current size' "$Wc_c"
fi
# ============= xtclient/mgrwindow.c ==============
if test -f 'xtclient/mgrwindow.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/mgrwindow.c (File already exists)'
else
echo 'x - extracting xtclient/mgrwindow.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/mgrwindow.c' &&
/*
X * File name:	mgrwindow.c
X *
X * Description:	Windowing interface specific routines for the "xt/layers"
X *		system for mgr.
X *
X *		This version uses pty's to handle the 7 xt data streams and 1
X *		parent window.  All 8 bits of each stream are passed through
X *		to mgr.  This is completely transparent to mgr applications
X *		but requires the xtclient process (This program) to run on
X *		the mgr server host.
X *		Window reshape events are not passed back to the agent or
X *		xt driver.  Use the mgr commands to determine window size
X *		for aplications that need it.  All window sizes are reported
X *		to the xt server as 0, 0.  This prevents the TERMCAP rows and
X *		columns in BSD systems from being ignored.  Use the mgr
X *		set_termcap command as apropriate to set the TERMCAP
X *		environment variable.
X *
X * Authors:	Merlin J. Mathesius
X *		Brad Bosch - mgr interface specific
X *
X * Contents:	Winit()		initialize windowing system
X *		Wshutdown()	shutdown windowing system
X *		Wmpx()		indication that multiplexed mode is starting
X *		Wunmpx()	indication that multiplexed mode is ending
X *		Wcreate()	create a new window
X *		Wdestroy()	destroy an existing window
X *		Wselect()	make a specified window current
X *		Wshape()	reshape/move a window
X *		Wtop()		pop a window to the top of window stack
X *		Wbottom()	push a window to the bottom of window stack
X *		Winput()	grab keyboard input from a window
X *		Woutput()	send output to a window
X *		findwnum()	find window corresponding to window id <local>
X *		Wlabel()	display label string on window
X *
X * Data:	wind_fds	bit map with current window file descriptor
X *		Wready		indicates unprocessed keyboard data remains
X */
X
#include <stdio.h>
#include <fcntl.h>
#ifdef sun
#include <termio.h>
#endif
#include <signal.h>
#include <string.h>
#include <varargs.h>
#ifndef sun
#include <macros.h>
#else
#define min(a,b)  (((a) < (b)) ? (a) : (b))
#define max(a,b)  (((a) > (b)) ? (a) : (b))
#endif
X
X
#include "term.h"	/* mgr macros */
#include "xtclient.h"
#include "window.h"
#include "appl.h"
#include "command.h"
X
Xextern int	readfds;	/* bit map of readable file desc (dlutil.h) */
X
#define EVENT_BUT1	"n%R\n"	/* button 1 down event */
X
#define NORMAL		1
#define ICON_NORMAL	"tty"
#define MPX		2
#define ICON_MPX	"ttys"
X
X
/* globally accessible data */
X
int wind_fds;		/* bit map with current window file descriptor */
int Wready;		/* indicates unprocessed keyboard data remains */
X
/* locally accessible data */
X
#define MENU_COUNT		(sizeof(menu)/sizeof(struct menu_entry))
X
struct menu_entry menu[] = {
X	"quit","q",
X	"create window","c",
X	"send break","b",
};
X
struct termio	term;		/* new termio struct for mgr control*/
struct termio	orig_termio;	/* initial saved termio for mgr control dev */
X
struct _w_info {
X	int	ptyfd;	/* mgr window fd, not the same as array index */
X	int	inform;	/* 0 = don't call APinform() if changes occur */
};
X
static struct _w_info w_info[MAXW+1]; /* NOTE: element 0 is unused */
X
/*from startup win */
static int def_pos_x, def_pos_y, def_height, def_width, def_font, border;
X
/* forward references */
static int findwnum();
static int Wlabel();
X
/*
X * Function name:	Winit()
X *
X * Description:		Initialize the windowing system.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
Winit()
{
X	int i;
X	int	w, h;		/* scratch width and height */
X	char	my_host[32];	/* my-host */
X	char	mgr_host[32];	/* mgr host */
X
X	/* clear out all window data structures */
X	for (i = 1; i <= MAXW; i++)
X	{
X		w_info[i].ptyfd = -1;
X		w_info[i].inform = 0;
X	}
X
X	/* set bit map of window file descriptors */
X	wind_fds = 1;	/* stdin */
X
X	/* initialize MGR windowing system */
X	/* M_DEBUG says use stdio for mgr */
X	/* M_FLUSH says flush m_termout stream after every macro call */
X	m_setup(M_DEBUG|M_FLUSH);
X
X	get_param(mgr_host,NULL,NULL,NULL);
#ifndef BSD
#ifndef sun
X	{
#include <sys/utsname.h>
X		struct utsname hostnames;
X		uname(&hostnames);
X		strcpy(my_host, hostnames.nodename);
X	}
#else
X	gethostname(my_host,sizeof(my_host));
#endif
#else
X	gethostname(my_host,sizeof(my_host));
#endif
X
X	if (strcmp(my_host,mgr_host) != 0) {
X		fprintf(stderr, "xtclient only works on local mgr host: %s\n",
X        	       mgr_host);
X		/* exit with error */
X		exit(1);
X       }
X
X	/* grab a copy of the termio structure for mgr */
X	if (ioctl(0, TCGETA, &orig_termio) < 0)
X	{
X		perror("ioctl(TCGETA)");
X
X		/* exit with error */
X		exit(1);
X	}
X
X	/* set up new termio modes for mgr */
X
X	term = orig_termio;
X
X	/* input modes: */
X	/*	IGNBRK	- ignore incoming break */
X	term.c_iflag = IGNBRK;
X
X	/* do absolutely no output processing */
X	term.c_oflag = 0;
X
X	/* set hardware control flags: */
X	/*	CREAD	- enable receiver (otherwise output only) */
X	/*	CS8	- 8 bit character size */
X	/*	B9600	- Aproximate baud rate form mgr */
X	term.c_cflag = CREAD | CS8 | B9600;
X
X	/* disable canonical processing */
X	term.c_lflag = 0;
X
X	/* input control characters */
X	term.c_cc[VMIN] = 1;	/* a read() is normaly permanently blocked */
X	term.c_cc[VTIME] = 0;
X
X	if (ioctl(0, TCSETA, &term) < 0)
X	{
X		perror("ioctl(TCSETA)");
X
X		/* exit with error */
X		exit(1);
X	}
X
X	/* prepare to set up termio modes for created "half" slave windows */
X	term.c_cc[VMIN] = 0;	/* a read() is not blocked */
X
X	/* get initial window data and save it */
X	m_push(P_BITMAP|P_CURSOR|P_EVENT|P_FLAGS|P_FONT|P_MENU|P_POSITION|
X		P_TEXT|P_WINDOW);
X
X	/* get size and font of startup window to use for defaults */
X	get_size(&def_pos_x, &def_pos_y, &def_width, &def_height);
X	get_param(NULL, NULL, NULL, &border);
X	def_width += 2 * border;
X	def_height += 2 * border;
X	def_font = get_font(NULL, NULL);
X
X	/* set modes and request events */
X
X	/* main window creates others with this event or with menu */
X	m_setevent(BUTTON_1, EVENT_BUT1);
X
X	menu_load(1,MENU_COUNT,menu);
X	m_selectmenu(1);
X
X	if (!down_load(ICON_NORMAL,NORMAL,&w,&h))
X	{
X		fprintf(stderr, "Can't find icon %s\n", ICON_NORMAL);
X	}
X	else
X	{
X		if (!down_load(ICON_MPX,MPX,&w,&h))
X		{
X			fprintf(stderr, "Can't find icon %s\n", ICON_MPX);
X			sleep(2);
X		}
X		m_shapewindow(def_pos_x, def_pos_y, 2*border+w, 2*border+h);
X		m_clear();
X		m_func(B_COPY);
X		m_bitcopyto(0, 0, 999, 999, 0, 0, 0, NORMAL);
X		
X	}
X	/* create initial window */
X	(void)Wcreate(1, 0L, 0L, 0L, 0L, 0, 0);
}
X
/*
X * Function name:	Wshutdown()
X *
X * Description:		Shutdown the windowing system.
X *
X * Parameters:		None
X *
X * Return values:	Never returns!!!!!!
X */
void
Wshutdown()
{
X	int	wd;		/* file descriptor of primary window */
X	int	i;		/* loop index */
X	char	buf[80];	/* buffer for mgr response */
X
X	/* close any open windows (except the startup window) */
X	for (i = 1; i <= MAXW; i++)
X	{
X		if (w_info[i].ptyfd != -1) {
X			(void)Wdestroy(i);
X			/*(void)close(w_info[i].ptyfd); */
X		}
X	}
X
X	/* restore tty modes */
X	if (ioctl(0, TCSETA, &orig_termio) < 0)
X	{
X		perror("ioctl(TCSETA)");
X	}
X
X	/* restore initial window data (size, location, etc.) */
X	m_popall();
X
X	/* exit with successful return code */
X	exit(0);
X
X	/* NOTREACHED */
}
X
/*
X * Function name:	Wmpx()
X *
X * Description:		Perform whatever is necessary for windowing routines
X *			to go into "multiplexed" (ie., multi window) mode.
X *
X *			This will relabel the primary window to indicate that
X *			it is multiplexed, and send a message back to the host
X *			telling them about our size.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
Wmpx()
{
X	int cols, rows, width, height;
X
X	/* relabel the primary window */
X	Wlabel(w_info[1].ptyfd, "Window #1");
X	m_bitcopyto(0, 0, 999, 999, 0, 0, 0, MPX);
X
X	/* send information back to application layer about our window */
X	/* tell it our width and height in both characters */
X	/* and pixels */
X
#ifdef LATER
X	/* get_colrow(&cols, &rows); */
X	/* get_size(NULL, NULL, &width, &height); */
#else
X	cols = rows = width = height = 0;
#endif
X	(void)APinform(XtCreate, 1,
X		       (long)cols,
X		       (long)rows,
X		       (long)width,
X		       (long)height);
}
X
/*
X * Function name:	Wunmpx()
X *
X * Description:		Perform whatever is necessary for windowing routines
X *			to return to "unmultiplexed" (ie., single window)
X *			mode.
X *
X *			This will destroy all but the primary window and
X *			re-label the primary window to indicate that we are
X *			unmultiplexed.  It is assumed that the "mpx_flag"
X *			has been reset prior to calling this function.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
Wunmpx()
{
X	int i;		/* loop index */
X	char buf[80];	/* buffer for mgr response */
X
X	if (w_info[1].ptyfd == -1) {
X		/* recreate initial window */
X		(void)Wcreate(1, 0L, 0L, 0L, 0L, 0, 0);
X	}
X
X	/* close all but the startup window and window 1 */
X	for (i = 2; i <= MAXW; i++)
X	{
X		if (w_info[i].ptyfd != -1) {
X			(void)Wdestroy(i);
X		}
X	}
X
X	/* relabel the primary window */
X	Wlabel(w_info[1].ptyfd, "Not Multiplexed");
X	m_bitcopyto(0, 0, 999, 999, 0, 0, 0, NORMAL);
}
X
/*
X * Function name:	Wcreate(n, orig_x, orig_y, corn_x, corn_y, inform, nc)
X *
X * Description:		Creates a new window.  The window number to create
X *			is passed in.
X *
X * Parameters:		n	window number to create, -1 if unknown
X *			orig_x	x-coordinate to place upper left corner
X *			orig_y	y-coordinate to place upper left corner
X *			corn_x	x-coordinate to place lower right corner
X *			corn_y	y-coordinate to place lower right corner
X *			inform	if not 0, inform application layer about
X *				create, else keep quiet
X *			nc	if not 0, don't make the new window current
X *				(Not used in mgr version)
X *
X * Note:		If all of the above coordinates are 0, a default
X *			window location will be chosen.
X *
X * Return values:	-1	unable to create window
X *			else	window number
X */
int
Wcreate(n, orig_x, orig_y, corn_x, corn_y, inform, nc)
int	n;
long	orig_x, orig_y, corn_x, corn_y;
int	inform, nc;
{
X	register int	wid;		/* mgr number of window created */
X	int		rc;		/* return code storage */
X	int		columns;	/* width of new window in chars */
X	int		width;		/* width of new window */
X	int		rows;		/* height of new window in chars */
X	int		height;		/* height of new window */
X	char		buf[80];	/* text string buffer */
X
X	/* if window number is unknown, try to find one */
X	if (n == -1)
X		n = findwnum(-1);
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't create */
X		return(-1);
X
X	if (w_info[n].ptyfd != -1)
X		/* window already exists */
X		return(n);
X
X	width = corn_x - orig_x;
X	height = corn_y - orig_y;
X
X	/* default height and width from startup window */
X	if (height <= 0)
X		height = def_height;
X	if (width <= 0)
X		width = def_width;
X
X	/* default location based upon the window number */
X	if (!orig_x)
X		orig_x = 20*(n);
X	if (!orig_y)
X		orig_y = 10*(n);
X
X	/* create the mgr window */
X	/* m_halfwin(orig_x, orig_y, width, height); */
X	printf("\033%d,%d,%d,%d%c",orig_x, orig_y, width, height,'z');
X	fflush(stdout);
X
X	m_gets(buf);	/* get tty name */
X	buf[strlen(buf) - 1] = '\0';	/* get rid of '\n' */
X
X	wid = open(buf, O_RDWR);
X
X	if (wid <= 0) {
X		/* couldn't create requested window */
X		perror("couldn't open tty");
X		return(-1);
X	}
X
X	if (ioctl(wid, TCSETA, &term) < 0)
X	{
X		perror("ioctl(TCSETA)");
X		close(wid);
X
X		/* return with error */
X		return(-1);
X	}
X
X	/* window created, store in info structure */
X	w_info[n].ptyfd = wid;
X
X	/* update bit map of window file descriptors */
X	wind_fds |= 1 << wid;
X
X	/* m_font(def_font)	 set font same as startup window */
X	sprintf(buf,"%c%d%c",m_escchar, def_font, E_FONT);
X	write(wid, buf, strlen(buf));
X
X	/* m_clear()	clear window after changing font to enable cut */
X	sprintf(buf, "%c",C_FF);
X	write(wid, buf, strlen(buf));
X
X	/* supply a window name */
X	if (n == 1)
X		/* window 1 is created before being multiplexed */
X		(void)sprintf(buf, "Not Multiplexed");
X	else
X		/* windows other than 1 can only be created when multiplexed*/
X		(void)sprintf(buf, "Window #%d", n);
X	Wlabel(wid, buf);
X
#ifdef LATER
X	/* get window size in chars */
X	get_colrow(&columns, &rows);
#else
X	columns = 0; rows = 0;
#endif
X
X	/* inform application layer about our creation now */
X	if (inform)
X	{
X		/* inform application layer of our creation. */
X		/* tell it our width and height in both characters */
X		/* and pixels */
X		(void)APinform(XtCreate, n,
X			       (long)columns,
X			       (long)rows,
X			       (long)width,
X			       (long)height);
X	}
X
X	/* set indicator for informing application layer about later changes*/
X	w_info[n].inform = 1;
X
X	/* return window number */
X	return(n);
}
X
/*
X * Function name:	Wdestroy(n)
X *
X * Description:		Destroy the requested window.
X *
X * Parameters:		n	window number to destroy
X *
X * Return values:	-1	error
X *			0	requested window destroyed (or already gone)
X */
int
Wdestroy(n)
int	n;
{
X	int wid;
X	char buf[80];
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't delete */
X		return(-1);
X
X	/* grab id of this window */
X	wid = w_info[n].ptyfd;
X
X	if (wid == -1)
X		/* window doesn't exist */
X		return(0);
X
X	/* don't inform application layer about our destruction (yet) */
X	w_info[n].inform = 0;
X
X	close(wid);	/* this should cause mgr to destroy the window */
X
X	/* remove entry from table */
X	w_info[n].ptyfd = -1;
X
X	/* update bit map of window file descriptors */
X	wind_fds &= ~ (1 << wid);
X
X	/* inform application layer of our destruction. */
X	if (mpx_flag)
X		(void)APinform(XtDelete, n, 0L, 0L, 0L, 0L);
X
X	/* window destroyed */
X	return(0);
}
X
/*
X * Function name:	Wselect(n)
X *
X * Description:		select the specified window as the current
X *			input window.
X *
X * Parameters:		n	window number to select
X *
X * Return values:	0	succesfully selected
X *			-1	error
X */
X
int
Wselect(n)
int	n;	/* window number to select */
{
X	char	buf[80];
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	if (w_info[n].ptyfd == -1)
X		/* window doesn't exist */
X		return(-1);
X
X	/* select the window */
X	/* m_setmode(M_ACTIVATE); */
X	sprintf(buf, "%c%d%c",m_escchar,M_ACTIVATE,E_SETMODE);
X	write(w_info[n].ptyfd, buf, strlen(buf));
X
X	return(0);
}
X
/*
X * Function name:	Wshape(n, orig_x, orig_y, corn_x, corn_y)
X *
X * Description:		Shape/move the specified window
X *
X * Parameters:		n	window number to shape/move
X *			orig_x	x-coordinate to place upper left corner
X *			orig_y	y-coordinate to place upper left corner
X *			corn_x	x-coordinate to place lower right corner,
X *				if -1 width will remain unaffected
X *			corn_y	y-coordinate to place lower right corner,
X *				if -1 height will remain unaffected
X *
X * Return values:	0	succesfully shaped/moved
X *			-1	error
X *			
X */
X
int
Wshape(n, orig_x, orig_y, corn_x, corn_y)
int	n;
long	orig_x, orig_y, corn_x, corn_y;
{
X	int	wid;		/* window file descriptor */
X	int	width;		/* width of window */
X	int	height;		/* height of window */
X	char	buf[80];
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	wid = w_info[n].ptyfd;
X
X	if (wid == -1)
X		/* window doesn't exist */
X		return(-1);
X
#ifdef LATER
X	/* read, set, and update the window parameters */
X	get_size(NULL, NULL, &width, &height);
#endif
X	width = def_width;
X	height = def_height;
X	if (corn_x != -1) width = corn_x - orig_x;
X	if (corn_y != -1) height = corn_y - orig_y;
X
X	/* m_shapewindow(orig_x, orig_y, width, height); */
X	sprintf(buf, "%c%d,%d,%d,%d%c",m_escchar,orig_x,orig_y,width,height,
X		E_SHAPE);
X	write(wid, buf, strlen(buf));
X	
X	return(0);
}
X
/*
X * Function name:	Wtop(n)
X *
X * Description:		Pop specified window to the top of the window stack
X *
X * Parameters:		n	window number to pop
X *
X * Return values:	0	succesfully popped to top
X *			-1	error
X */
X
int
Wtop(n)
int	n;
{
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	if (w_info[n].ptyfd == -1)
X		/* window doesn't exist */
X		return(-1);
X
X	/* We can't do this:  Popping the window to the top also selects it.*/
X
X	return(-1);
}
X
/*
X * Function name:	Wbottom(n)
X *
X * Description:		Push specified window to bottom of window stack.
X *
X * Parameters:		n	window number to push
X *
X * Return values:	0	succesfully pushed to bottom
X *			-1	error
X *			
X */
X
int
Wbottom(n)
int	n;
{
X	char	buf[80];
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number, can't select */
X		return(-1);
X
X	if (w_info[n].ptyfd == -1)
X		/* window doesn't exist */
X		return(-1);
X
X	/* bury the window */
X	/* m_clearmode(M_ACTIVATE); */
X	sprintf(buf, "%c%d%c", m_escchar, M_ACTIVATE, E_CLEARMODE);
X	write(w_info[n].ptyfd, buf, strlen(buf));
X
X	return(0);
}
X
/*
X * Function name:	Winput(n, buf, nbytes)
X *
X * Description:		Return available input from a window.
X *
X * Parameters:		n	pointer to store window number providing data
X *			buf	buffer in which to store data
X *			nbytes	maximum number of bytes return
X *
X * Return values:	number of bytes of input returned
X *			
X */
int
Winput(n, buf, nbytes)
int	*n;	/* returned window with available data */
char	*buf;	/* buffer in which to place data */
int	nbytes;	/* max number of bytes to read */
{
X	int	cr;	/* single integer size character buffer */
X	char	c;	/* single character buffer */
X	int	count;	/* number of characters read */
X	int	rc;	/* return code storage */
X	int	wn;	/* window number */
X	int	newwn;	/* window number from event */
X	char	tbuf[80];	/* temporary buffer for mgr events */
X	static int lastfd = 1;	/* last fd read or tested */
X	static int flags = 0;	/* last flags value fcntl on mgr fd */
X	int	fd;	/* next fd to read */
X
X	/* no characters read yet */
X	count = 0;
X
X	/* set non-blocking i/o */
X	if (! flags) {	/* first time only */
X		flags = fcntl(0, F_GETFL, 0);
X	}
X
X	/* Do we have control window input?  If so, process it. */
X	if ((m_termin -> _cnt) || (readfds & 1))
X	{
X		rc = fcntl(0, F_SETFL, flags | O_NDELAY);
X
X		while ((cr = m_getchar()) != EOF)
X		{
X			switch (cr)
X			{
X			case 'c':	/* create window */
X				/* if multiplexed, create new window*/
X				if (mpx_flag) {
X					fcntl(0, F_SETFL, flags);
X					Wcreate(-1,0L,0L,0L,0L,1,0);
X				}
X				goto done;
X
X			case 'q':	/* quit */
X
X				/* user wants to EXIT */
X
X				/* if user has already requested to exit but*/
X				/* we are still multiplexed, something hung;*/
X				/* force multiplex flag to false. */
X				if (user_exit && mpx_flag)
X					mpx_flag = 0;
X
X				/* set flag to request exit */
X				user_exit = 1;
X
X				/* if we are multiplexed, inform application*/
X				/* layer that we wish to go down! */
X				if (mpx_flag)
X					(void)APinform(XtExit,wn,0L,0L,0L,0L);
X
X				goto done;
X
X			case 'n':
X				/* mgr BUTTON_1 has been pressed... */
X				/* if multiplexed, create new window*/
X				/* of indicated shape */
X				if (mpx_flag) {
X					int x1, y1, x2, y2, x, y;
X
X					fcntl(0, F_SETFL, flags);/* blocking*/
X					m_gets(tbuf);
X					sscanf(tbuf, "%d %d %d %d",
X						&x1, &y1, &x2, &y2);
X
X					/* find min and max coords */
X					x = min(x1, x2);
X					y = min(y1, y2);
X					x2 = max(x1, x2);
X					y2 = max(y1, y2);
X
X					Wcreate(-1,x,y,x2,y2,1,0);
X				}
X				goto done;
X			case 'b':
X				/* send break on comunications line */
X				/* not implemented yet */
X				break;
X			default:
X				break;
X			}
X		}
X		goto done;	/* don't try to process other windows input */
X	}
X
X	/* find next fd with data ready */
X	fd = lastfd + 1;
X	if (fd >= 32)
X		fd = 1;
X	while(fd != lastfd) {
X		if (wind_fds & readfds & (1 << fd))
X			break;
X		fd ++;
X		if (fd >= 32)
X			fd = 1;
X	}
X	lastfd = fd;	/* set up for next time */
X	wn = findwnum(fd);
X	if (wn < 1) {	/* sanity check */
X		goto done;
X	}
X
X	count = read(fd, buf, nbytes);	/* Returns 0 if no data ready */
X
X	if (count < 1) {	/* eof encountered ?*/
X		/* user deleted this window, clean up */
X		(void)Wdestroy(wn);
X		/* can't do anything else with this window! */
X		goto done;
X	}
X
done:
X	/* if input is still buffered, report it cause select can't see it */
X	/* Note:  This use of _cnt may not be portable, but an equivelent */
X	/* can generally be found. */
X	Wready = m_termin -> _cnt;	/* setup ready indication */
X
X	/* clear non-blocking mode */
X	rc = fcntl(0, F_SETFL, flags);
X
X	/* return window number and count of characters */
X	*n = wn;
X	return(count);
}
X
/*
X * Function name:	Woutput(n, buf, nbytes)
X *
X * Description:		Output information in window.
X *
X * Parameters:		n	window to receive output
X *			buf	buffer of data to output
X *			nbytes	number of bytes to output
X *
X * Return values:	-1	- unsuccessful output
X *			1	- successful output
X */
int
Woutput(n, buf, nbytes)
int	n;	/* window number in which to output data */
char	*buf;	/* data to output */
int	nbytes;	/* number of bytes from "buf" to output */
{
X	int	fd;	/* mgr descriptor for window */
X
X	if (n < 1 || n > MAXW)
X		/* invalid window number */
X		return(-1);
X
X	fd = w_info[n].ptyfd;
X
X	/* window not opened, let's try to open it! */
X	if (fd == -1)
X	{
X		(void)Wcreate(n, 0L, 0L, 0L, 0L, 1, 1);
X
X		fd = w_info[n].ptyfd;
X
X		if (fd == -1)
X			/* can't create it, give up */
X			return(-1);
X	}
X
X	/* output data with 1 write */
X	write(fd, buf, nbytes);
X
X	return(1);
}
X
/*
X * Function name:	findwnum(wfd)
X *
X * Description:		Finds the window number corresponding to the mgr
X *			window fd passed in.  If a -1 is passed in as
X *			the fd, an unused but available window
X *			number is returned.
X *
X * Parameters:		wfd	file descriptor to locate
X *
X * Return values:	-1	- cannot locate requested information
X *			n	- window number corresponding to "wid"
X */
static int
findwnum(wfd)
int	wfd;	/* mgr window id to locate */
{
X	register int i;	/* loop index */
X
X	/* locate requested window */
X	for (i = 1; i <= MAXW; i++)
X		if (w_info[i].ptyfd == wfd) return(i);
X
X	return(-1);
}
X
/*
X * Function name:	Wlabel(wfd, label)
X *
X * Description:		Sets the label of the window corresponding
X *			to the mgr window fd passed in.
X *
X * Parameters:		wfd	mgr window fd.
X *			label	string containing new label.
X *
X * Return values:	-1	- relabel failed.
X *			0	- operation complete.
X */
static int
Wlabel(wfd, label)
int	wfd;	/* mgr window id */
char *	label;	/* label string */
{
X	return -1;	/* not working yet */
}
X
/* download icon */
X
int
down_load(name,where,w,h)
char *name;	/* name of icon */
int where;	/* scratchpad bitmap # */
int *w, *h;	/* icon size */
{
X	char buff[20];
X	int n;
X
X	m_bitfromfile(where,name);
X	m_flush();
X	m_gets(buff);
X	n = sscanf(buff,"%d %d",w,h);
X	if (n < 2) 
X		return(0);
X	else
X		return(1);
}
SHAR_EOF
chmod 0644 xtclient/mgrwindow.c ||
echo 'restore of xtclient/mgrwindow.c failed'
Wc_c="`wc -c < 'xtclient/mgrwindow.c'`"
test 22004 -eq "$Wc_c" ||
	echo 'xtclient/mgrwindow.c: original size 22004, current size' "$Wc_c"
fi
# ============= xtclient/network.c ==============
if test -f 'xtclient/network.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/network.c (File already exists)'
else
echo 'x - extracting xtclient/network.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/network.c' &&
/*
X * File name:	network.c
X *
X * Description:	The network layer for the "xt/layers" client system on the
X *		UNIX-PC.
X *		
X *			==> !!! ==> !!! NOTE !!! <== !!! <==
X *		The network layer intentionally "short circuits" the transport
X *		layer of the ISO model and directly interfaces to the session
X *		layer.  The transport layer performs no useful function in
X *		this program, so for efficiency it has been eliminated!
X *
X * Author:	Merlin J. Mathesius
X *
X * Contents:	NETinit()	initialize the network layer
X *		NETfromDL()	accept a packet from the data link layer
X *		NETtoDL()	return a packet to the data link layer
X *
X * Data:	None
X */
X
#include <stdio.h>
#include "frame.h"
#include "network.h"
#include "session.h"
X
/*
X * Function name:	NETinit()
X *
X * Description:		Initialize the network layer.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
NETinit()
{
X	/* nothing to do */
}
X
/*
X * Function name:	NETfromDL(p)
X *
X * Description:		Disassemble a packet from the data link layer and
X *			send it directly to the session layer.
X *
X * Parameters:		p	pointer to packet from data link layer
X *
X * Return values:	-1	error
X *			0	OK, packet successfully accepted
X */
int
NETfromDL(p)
Packet *p;
{
X	register int rc;
X
X	/* call session layer interface function */
X	rc = SESind((int)p->addr, (char *)p->data, (int)p->size);
#ifdef EBUG
X	if (rc < 0)
X		(void)fprintf(stderr, "NETfromDL: bad return from SESind, %d\n", rc);
#endif
X	return(rc);
}
X
/*
X * Function name:	NETtoDL(p)
X *
X * Parameters:		p	packet buffer in which to assemble packet
X *
X * Description:		Assemble a packet of data from the session layer
X *			and return it to the data link layer.
X *
X * Return values:	0	packet successfully retreived (with data)
X *			-1	no data, or error
X */
int
NETtoDL(p)
Packet *p;
{
X	register int rc;
X	int addr;
X
X	/* call session layer interface function */
X	rc = SESreq(&addr, (char *)p->data, DAT_SZ);
#ifdef EBUG
X	if (rc < 0)
X		(void)fprintf(stderr, "NETtoDL: bad return from SESreq, %d\n", rc);
#endif
X	if (rc <= 0)
X		/* no data, or error */
X		return(-1);
X
X	/* store address and size in packet buffer */
X	p->addr = (Byte)addr;
X	p->size = (Byte)rc;
X
X	return(0);
}
SHAR_EOF
chmod 0644 xtclient/network.c ||
echo 'restore of xtclient/network.c failed'
Wc_c="`wc -c < 'xtclient/network.c'`"
test 2168 -eq "$Wc_c" ||
	echo 'xtclient/network.c: original size 2168, current size' "$Wc_c"
fi
# ============= xtclient/network.h ==============
if test -f 'xtclient/network.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/network.h (File already exists)'
else
echo 'x - extracting xtclient/network.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/network.h' &&
/*
X * File name:	network.h
X *
X * Description:	External function and data declarations for network.c
X *
X * Author:	Merlin J. Mathesius
X */
X
Xextern void	NETinit();
Xextern int	NETfromDL(), NETtoDL();
SHAR_EOF
chmod 0644 xtclient/network.h ||
echo 'restore of xtclient/network.h failed'
Wc_c="`wc -c < 'xtclient/network.h'`"
test 197 -eq "$Wc_c" ||
	echo 'xtclient/network.h: original size 197, current size' "$Wc_c"
fi
# ============= xtclient/phone.c ==============
if test -f 'xtclient/phone.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/phone.c (File already exists)'
else
echo 'x - extracting xtclient/phone.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/phone.c' &&
/*
X * File name:	phone.c
X *
X * Description:	This file contains the "particulars" for dealing
X *		with the internal modem of the AT&T UNIX-PC.
X *
X * Author:	Merlin J. Mathesius
X * Ugly hacks:	Brad Bosch	( hacks for suns and ptys )
X *
X * Contents:	connect()	establish a connection
X * 		disconnect()	destroy a connection
X *		isconnected()	check if connected
X *		translate_baud() translate baud rate
X *
X * Data:	phone_fd	phone device file descriptor
X */
X
#define R_OK 04
#define W_OK 02
#include <stdio.h>
#include <fcntl.h>
#include <termio.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef sun
#	include <dial.h>
#	include <sys/phone.h>
#endif
#include <string.h>
#include <signal.h>
X
#include "phone.h"
X
static int	translate_baud();
X
Xextern void	perror();	/* not declared in any header file */
Xextern char *	getenv();
X
#ifdef sun
#	define LINE		"/dev/cua0"
#	define SPEED		"2400"
#	define BAUDRATE	B2400
#else
#	define LINE		"/dev/ph0"
#	define SPEED		"1200"
#	define BAUDRATE	B1200
#endif sun
X
#ifndef sun
/* errors returned from dial() call, defined in /usr/include/dial.h */
X
static char *dial_errs[] = {
X	"zero",
X	"interrupt",
X	"dialer hung",
X	"no answer",
X	"illegal baud-rate",
X	"acu problem",
X	"line problem",
X	"can't open LDEVS",
X	"device not available",
X	"device unknown",
X	"no device available at baud-rate",
X	"no device known at baud-rate"
};
X
#endif not sun
static int is_phone = 0;	/* flag set if device is PHDEV (phone.h) */
static int master;		/* fd of master if pty mode */
static int slave;
static int child = 0;		/* pid of child if we are parent in pty mode */
static char *line;		/* file global copy of c_line from connect */
X
Xextern struct termio orig_termio;/* copy of stdin termio from mgrwindow.c */
X
int c_finish();			/* for forward reference */
X
X
/* global storage for phone device's file descriptor */
X
int	phone_fd = -1;
X
/*
X * Function name:	connect(number, c_line, speed)
X *
X * Description:		Establishes a connection.  If successful, file
X *			descriptor of phone device is stored in "phone_fd"
X *			so it is accessible by other modules for reading
X *			and writing.
X *
X * Parameters:		number	telephone number to dial
X *			c_line	path to device to use (NULL for default)
X *			speed	desired baud rate string (NULL for default)
X *
X * Return values:	-1	failed to connect
X *			>= 0	file descriptor of phone device
X */
int
connect(number, c_line, speed)
char	*number;	/* number to dial */
char	*c_line;		/* path to device */
char	*speed;		/* speed string */
{
#ifndef sun
X	CALL		call;
X	struct updata	phone;
#endif not sun
X	struct termio	term;
X
X	int		fd;	/* file descriptor of phone device */
X	int		rc;	/* temporary storage for return codes */
X	int		baud;	/* baud control mode from termio.h */
X
X	/* set defaults */
X	line = c_line;
X	if (line == NULL) line = LINE;
X	if (speed == NULL) speed = SPEED;
X	if (strcmp(line, "pty") == 0)
X	{
X		line = "/dev/ptyXX";
X		if (number[0] == 0)
X		{
X			number = getenv("SHELL");
X			if (number == 0)
X				number = "/bin/sh";
X		}
X		if (getmaster()) return(-1);
X
X		(void) signal(SIGCLD, c_finish);
X		child = fork();
X		if (child < 0) {
X			perror("fork");
X			return(-1);
X		}
X		if (child == 0) {
X			doshell(number);
X			return(-1);
X		}
X		fd = master;
X		/* phone device should not block */
X		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NDELAY);
X	}
X	else
X	{
X		/* open phone device */
X		fd = open(line, O_RDWR | O_NDELAY, 0);
X		if (fd < 0)
X		{
X			perror("open(phone device)");
X			return(-1);
X		}
X
#ifndef sun
X		if (strncmp(line, PHDEV, sizeof(PHDEV)-1) == 0) {
X			is_phone = 1;
X			rc = ioctl(fd, PIOCGETP, &phone);
X			if (rc < 0)
X			{
X				perror("ioctl(PIOCGETP)");
X				/* don't abort... */
X			}
X			else
X			{
X				/* use touch tone dialing */
X				phone.c_lineparam &= ~PULSE;
X				phone.c_lineparam |= DTMF;
X				/* set the internal speaker to something reasonable */
X				phone.c_feedback &= ~(SOFTSPK | NORMSPK | LOUDSPK);
X				phone.c_feedback |= (SPEAKERON | SOFTSPK);
X				rc = ioctl(fd, PIOCSETP, &phone);
X				if (rc < 0)
X				{
X					perror("ioctl(PIOCSETP)");
X					/* don't abort... */
X				}
X			}
X		}
X
#endif sun
X		/* grab a copy of the termio structure for the line */
X		rc = ioctl(fd, TCGETA, &term);
X		if (rc < 0)
X		{
X			perror("ioctl(TCGETA)");
X			/* don't abort... */
X		}
X	
X		/* set the terminal characteristics */
X	
X		baud = translate_baud(speed);
X		if (baud < 0) {
X			(void)fprintf(stderr, "illegal speed: \"%s\"\n", speed);
X			return -1;
X		}
X	
X		/* input modes: */
X		/*	IGNBRK	- ignore incoming break */
X		term.c_iflag = IGNBRK;
X	
X		/* do absolutely no output processing */
X		term.c_oflag = 0;
X	
X		/* set hardware control flags: */
X		/*	HUPCL	- hangup on last close */
X		/*	CREAD	- enable receiver (otherwise output only) */
X		/*	CS8	- 8 bit character size */
X		/*	baud	- Baud rate from above */
X		term.c_cflag = HUPCL | CREAD | CS8 | baud;
X	
X		/* default line discipline will be used */
X		term.c_lflag = 0;
X	
X		/* input control characters */
X		term.c_cc[VMIN] = 1;	/* read at least 1 character */
X		term.c_cc[VTIME] = 0;	/* a read() is permanently blocked */
X
#ifndef sun
X		/* close the file, it will be re-opened by dial() */
X		(void)close(fd);
X
X		/* setup call information */
X		call.attr = &term;
X		call.baud = call.speed = atoi(speed);	/*set baud and speed*/
X		call.line  = strrchr(line, '/') + 1;
X		call.telno = number;
X		call.modem = 0;
X
X		/* place the call... */
X		fd = dial(call);
X		if (fd < 0)
X		{
X			(void)fprintf(stderr, "dial failed: %s\n",
X				dial_errs[-fd]);
X			return(-1);
X		}
X
#endif sun
X		/* blocking mode required for dial with rs232 modems */
X		term.c_cc[VMIN] = 0;	/* a read() is not permanently blocked */
X		term.c_cc[VTIME] = 1;	/* if no data present, return after 1/10 sec*/
X		ioctl(fd, TCSETA, &term);	/* set non-blocking mode */
X	}
X	/* call was successfully dialed! */
X	phone_fd = fd;
X
X	/* return the file descriptor for the phone device */
X	return(fd);
X
} /* end of connect() */
X
/*
X * Function name:	disconnect()
X *
X * Description:		Destroy a previously established connection
X *
X * Parameters:		None
X *
X * Return values:	-1	failed to disconnect
X *			0	disconnect succeeded
X *
X */
int
disconnect()
{
X	int	rc;	/* return code from system calls */
X
X	if (phone_fd < 0)
X		return(-1);
X
#ifndef sun
X	if (is_phone) {
X		/* hangup phone line */
X		rc = ioctl(phone_fd, PIOCDISC, (char *)0);
X		if (rc < 0)
X		{
X			perror("ioctl(PIOCDISC)");
X		}
X	}
X
X	/* undo previous dial() call */
X	undial(phone_fd);
#endif sun
X
X	/* close the phone device */
X	(void)close(phone_fd);
X
X	/* reset file descriptor */
X	phone_fd = -1;
X
X	return(0);
} /* end of disconnect() */
X
/*
X * Function name:	isconnected()
X *
X * Description:		Determine if a connection is established
X *
X * Parameters:		None
X *
X * Return values:	1	connection is established
X *			0	no connection
X */
int
isconnected()
{
#ifndef sun
X	struct updata	phone;
#endif not sun
X
X	/* phone device not open, not connected */
X	if (phone_fd < 0)
X		return(0);
X
X	/* if not phone device, check if shell (pty) type connection */
X	if (! is_phone)
X		if (child == -1)
X			return(0);
X		else
X		/* if child not dead assume connected (allows for callback) */
X			return(1);
X
#ifndef sun
X	/* can't get status, not connected */
X	if (ioctl(phone_fd, PIOCGETP, &phone) < 0)
X		return(0);
X
X	/* if connected flag is set, connected */
X	if (phone.c_linestatus & MODEMCONNECTED)
X		return(1);
#endif not sun
X	/* otherwise, not connected */
X	return(0);
} /* end of isconnected() */
X
/* table of speed strings and corresponding baud rate constants from termio.h */
X
static struct trans {
X	char	*speed;
X	int	baud;
} trans[] = {
X	{"0",     0},
X	{"50",    B50},
X	{"75",    B75},
X	{"110",   B110},
X	{"134",   B134},
X	{"150",   B150},
X	{"200",   B200},
X	{"300",   B300},
X	{"600",   B600},
X	{"1200",  B1200},
X	{"1800",  B1800},
X	{"2400",  B2400},
X	{"4800",  B4800},
X	{"9600",  B9600},
X	{"19200", B19200},
};
X
/*
X * Function name:	translate_baud(speed)
X *
X * Description:		Find baud rate constant from speed
X *
X * Parameters:		speed	desired speed string
X *
X * Return values:	>=0	value of coresponding baudrate from termio.h
X *			-1	speed string not found
X */
static int
translate_baud(speed)
char *speed;
{
X	int i;
X
X	for (i=0; i < sizeof(trans)/sizeof(struct trans); ++i)
X	{
X		if (strcmp(speed, trans[i].speed) == 0)
X			return trans[i].baud;
X	}
X
X	return -1;
X
} /* end of translate_baud() */
X
getmaster()
{
X	char *pty, *bank, *cp;
X	struct stat stb;
X
X	pty = &line[strlen("/dev/ptyp")];
X	for (bank = "pqrs"; *bank; bank++) {
X		line[strlen("/dev/pty")] = *bank;
X		*pty = '0';
X		if (stat(line, &stb) < 0)
X			break;
X		for (cp = "0123456789abcdef"; *cp; cp++) {
X			*pty = *cp;
X			master = open(line, O_RDWR|O_NDELAY);
X			if (master >= 0) {
X				char *tp = &line[strlen("/dev/")];
X				int ok;
X
X				/* verify slave side is usable */
X				*tp = 't';
X				ok = access(line, R_OK|W_OK) == 0;
X				*tp = 'p';
X				if (ok) {
/*
X					ok = ioctl(0, TCGETA, &sh_term);
X					if (ok < 0)
X					{
X						  perror("ioctl(TCGETA)");
X					}
*/
X					return(0);
X				}
X				(void) close(master);
X			}
X		}
X	}
X	fprintf(stderr, "Out of pty's\n");
X	return(-1);
}
X
getslave()
{
X	struct termio sh_term;
X	int rc;
X
X	line[strlen("/dev/")] = 't';
X	slave = open(line, O_RDWR);
X	if (slave < 0) {
X		perror(line);
X		return(-1);
X	}
X	/* set modes same as stdin but with 8 bit i/o */
X	sh_term = orig_termio;
X	sh_term.c_iflag &= ~(BRKINT | INPCK | ISTRIP);
X	sh_term.c_cflag |= CS8;
X	sh_term.c_cflag &= ~(PARENB);
X	rc = ioctl(slave, TCSETA, &sh_term);
X	if (rc < 0)
X	{
X		  perror("ioctl(TCSETA)");
X		  /* don't abort... */
X	}
X	return(0);
}
X
#include <sys/wait.h>
X
c_finish()
{
X	union wait status;
X	register int pid;
X
X	while ((pid = wait(&status)) > 0)
X		if (pid == child)
X			/* mark slave as dead for is isconnected() to see */
X			slave = -1;
}
X
doshell(shell)
char * shell;
{
X	int t;
X
X	t = open("/dev/tty", O_RDWR);
X	if (t >= 0) {
#ifdef sun
X		(void) ioctl(t, TIOCNOTTY, (char *)0);
#endif
X		(void) close(t);
X	}
X	setpgrp();
X	(void) close(0);
X	(void) close(1);
X	(void) close(2);
X	if (getslave()) return(-1);
X	(void) close(master);
X	(void) dup(slave);
X	(void) dup(slave);
X	execl(shell, "sh", "-i", 0);
X	perror(shell);
X	return(-1);
}
X
X
SHAR_EOF
chmod 0644 xtclient/phone.c ||
echo 'restore of xtclient/phone.c failed'
Wc_c="`wc -c < 'xtclient/phone.c'`"
test 10054 -eq "$Wc_c" ||
	echo 'xtclient/phone.c: original size 10054, current size' "$Wc_c"
fi
# ============= xtclient/phone.h ==============
if test -f 'xtclient/phone.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/phone.h (File already exists)'
else
echo 'x - extracting xtclient/phone.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/phone.h' &&
/*
X * File name:	phone.h
X *
X * Description:	External function and data declarations for phone.c
X *
X * Author:	Merlin J. Mathesius
X */
X
Xextern int	connect(), disconnect(), isconnected();
X
Xextern int	phone_fd;
SHAR_EOF
chmod 0644 xtclient/phone.h ||
echo 'restore of xtclient/phone.h failed'
Wc_c="`wc -c < 'xtclient/phone.h'`"
test 208 -eq "$Wc_c" ||
	echo 'xtclient/phone.h: original size 208, current size' "$Wc_c"
fi
# ============= xtclient/phys.c ==============
if test -f 'xtclient/phys.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/phys.c (File already exists)'
else
echo 'x - extracting xtclient/phys.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/phys.c' &&
/*
X * File name:	phys.c
X *
X * Description:	Physical layer functions for "xt/layers" client system for the
X *		UNIX-PC
X *
X * Author:	Merlin J. Mathesius
X *
X * Contents:	PHinit()	Initialize the physical layer.
X *		PHfromDL()	Accept a frame from the data link layer.
X *		PHtoDL()	Return a frame to the data link layer.
X *		PHreset()	Reset (resynchronize) the physical layer <local>
X *		PHquery()	Assemble an incoming frame and return status
X *		PHcrcinit()	Initialize CRC generation tables <local>
X *		PHcrc()		Compute CRC value for a frame <local>
X *
X * Data:	None
X */
X
#include <stdio.h>
#include "xtclient.h"
#include "datalink.h"
#include "phys.h"
#include "phone.h"
X
/* various states of an arriving frame for finite state machine */
Xenum FrmState {
X	FrmNull,	/* awaiting arrival of start of frame */
X	FrmHeader,	/* awaiting arrival of 2nd byte of header */
X	FrmData,	/* awaiting arrival of remaining data */
X	FrmCRC,		/* awaiting arrival of CRC */
X	FrmDone		/* frame arrived, awaiting acceptance of frame */
X			/*  by data link layer */
};
X
static	Frame		frame;		/* current arriving frame */
static	enum FrmState	frame_state;	/* state of current arriving frame */
static	char		*fp;		/* pointer to next byte to receive */
static	unsigned	count;		/* count of remaining bytes in state */
X
static int	PHcrc();
static void	PHreset(), PHcrcinit();
X
/*
X * Function name:	PHinit()
X *
X * Description:		Initialize the physical layer.
X *
X * Parameters:		None
X *			
X * Return values:	None
X */
void
PHinit()
{
X	/* reset to a known state */
X	PHreset();
X
X	/* initialize the CRC generation tables */
X	PHcrcinit();
}
X
/*
X * Function name:	PHfromDL(f)
X *
X * Description:		Places a frame from the data link layer onto the
X *			physical medium.  Logging is also performed.
X *
X * Parameters:		f	pointer to frame to send
X *
X * Return values:	total number of bytes in frame
X */
int
PHfromDL(f)
Frame *f;
{
X	unsigned	nbyte;		/* number of bytes to write */
X	int		rc1, rc2;	/* return code */
X
X	/* compute the CRC for the frame (ignore return value) */
X	(void)PHcrc(f);
X
X	nbyte = f->size + 2;	/* size of data portion plus header */
X
X	/* write the data to the phone device */
X	rc1 = write(phone_fd, (char *)f, nbyte);
#ifdef EBUG
X	if (rc1 != nbyte)
X		(void)fprintf(stderr, "PHfromDL: only wrote %d of %d data bytes\n",
X			      rc1, nbyte);
#endif
X
X	/* write the CRC to the phone device */
X	rc2 = write(phone_fd, (char *)&f->crc, sizeof(f->crc));
#ifdef EBUG
X	if (rc2 != sizeof(f->crc))
X		(void)fprintf(stderr, "PHfromDL: only wrote %d of %d CRC bytes\n",
X			      rc2, sizeof(f->crc));
#endif
X
X	/* log the output if logging is turned on */
X	if (olog_fd != -1)
X	{
X		(void)write(olog_fd, (char *)f, (unsigned)rc1);
X		(void)write(olog_fd, (char *)&f->crc, (unsigned)rc2);
X	}
X
X	return(nbyte+sizeof(f->crc));
}
X
/*
X * Function name:	PHtoDL(f)
X *
X * Description:		Returns (to the data link layer) a frame received
X *			from the physical layer.  Unless a complete frame
X *			has arrived, this function will return nothing.
X *			Once the frame has been copied to the passed in
X *			buffer, the current incoming frame buffer is reset
X *			for the next frame.
X *
X * Parameters:		f	pointer to buffer for incoming frame
X *
X * Return values:	0	returned frame is valid
X *			-1	no frame returned
X */
int
PHtoDL(f)
Frame *f;
{
X
X	/* if there really isn't a frame to send back, return error */
X	if (frame_state != FrmDone)
X		return(-1);
X
X	/* copy the frame to the passed in buffer */
X	*f = frame;
X
X	/* reset to accept next frame */
X	PHreset();
X
X	return(0);
}
X
/*
X * Function name:	PHreset()
X *
X * Description:		Reset the physical layer.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
static void
PHreset()
{
X	/* reset to the null state (waiting for start of frame) */
X	frame_state = FrmNull;
X
X	/* reset pointer to next byte to receive to beginning of frame */
X	fp = (char *)&frame;
}
X
/*
X * Function name:	PHquery()
X *
X * Description:		Assembles an incoming frame and checks CRC of frame.
X *			Status is returned to calling data link layer.
X *
X *			This routine functions as a finite state machine.
X *			All available data (up to a complete frame) is read
X *			from the physical medium.  If a complete frame is not
X *			yet available, the current state is remembered and the
X *			next call to this function will continue where the
X *			previous call left off.
X *
X *			Input logging is also done by this function if it is
X *			turned on.
X *
X * Parameters:		None
X *
X * Return values:	1	frame ready, call PHtoDL() to get it
X *			0	frame not ready
X *			-1	CRC error, frame discarded
X */
int
PHquery()
{
X	register int rc;
X
X	switch (frame_state)
X	{
X	case FrmNull:	/* awaiting arrival of start of frame */
X
X		/* try to read first byte of header */
X		rc = read(phone_fd, fp, (unsigned)1);
X		if (rc <= 0)
X			/* no data */
X			return(0);
X
X		/* log the input if logging is turned on */
X		if (ilog_fd != -1)
X			(void)write(ilog_fd, fp, (unsigned)1);
X
X
X		/* The type first byte of a valid frame will have the */
X		/* "mark" bit set to 1.  Ignore if it is not set. */
XSyncStart:	if (frame.mark != 1)
X			return(0);
X
X		/* first byte OK, move to next state... */
X		frame_state = FrmHeader;
X		fp++;
X
X		/* FALLTHROUGH */
X
X	case FrmHeader:	/* awaiting arrival of 2nd byte of header */
X
X		/* try to read remaining byte of header */
X		rc = read(phone_fd, fp, (unsigned)1);
X		if (rc <= 0)
X			/* no data */
X			return(0);
X
X		/* log the input if logging is turned on */
X		if (ilog_fd != -1)
X			(void)write(ilog_fd, fp, (unsigned)1);
X
X		/* Size of the data portion of the frame must be in */
X		/* range.  We are out of sync if it is out of range, */
X		/* so retry to see if it is the first byte of the frame. */
X		if (frame.size > DAT_SZ) {
X			PHreset();
X			/* move the byte back to the starting position */
X			fp[0] = fp[1];
X			goto SyncStart;
X		}
X
X		/* header is OK, we are expecting "size" bytes in the */
X		/* data section of the frame. */
X
X		frame_state = FrmData;
X		fp++;
X		count = frame.size;
X
X		/* FALLTHROUGH */
X
X	case FrmData:	/* awaiting arrival of remaining data */
X
X		if (count != 0)
X		{
X			rc = read(phone_fd, fp, count);
X			if (rc <= 0)
X				/* no data */
X				return(0);
X
X			/* log the input if logging is turned on */
X			if (ilog_fd != -1)
X				(void)write(ilog_fd, fp, (unsigned)rc);
X
X			/* got some data, figure out what's left */
X			count -= rc;
X			fp += rc;
X
X			if (count != 0)
X				/* still need more data */
X				return(0);
X		}
X
X		/* got all the data we need, move on to next state */
X
X		frame_state = FrmCRC;
X		fp = (char *)&frame.crc;
X		count = sizeof(frame.crc);
X
X		/* FALLTHROUGH */
X
X	case FrmCRC:	/* awaiting arrival of CRC */
X
X		rc = read(phone_fd, fp, count);
X		if (rc <= 0)
X			/* no data */
X			return(0);
X
X		/* log the input if logging is turned on */
X		if (ilog_fd != -1)
X			(void)write(ilog_fd, fp, (unsigned)rc);
X
X		count -= rc;
X		fp += rc;
X
X		if (count != 0)
X			/* still need remaining byte(s) of CRC */
X			return(0);
X
X		/* We now have a complete frame!  Check the CRC. */
X
X		if (PHcrc(&frame))
X		{
X			/* Frame arrived damaged, discard and report error */
X			PHreset();
X			return(-1);
X		}
X
X		/* We have a happy, healthy frame! */
X
X		frame_state = FrmDone;
X
X		/* FALLTHROUGH */
X
X	case FrmDone:	/* frame arrived, awaiting acceptance of frame */
X
X		return(1);
X
X	default:
X
X		/* Don't know how we got here, reset to known state */
X		PHreset();
X		return(0);
X	}
}
X
/*
X * crctab[]
X *
X *  256 element generator table for CRC-16 (x**16 + x**15 + x**2 + 1)
X */
X
static unsigned short crctab[256];
X
/*
X * Function name:	PHcrcinit()
X *
X * Description:		Initialize the CRC-16 generation table.
X *
X *			The operation is not exactly clear, but it produces
X *			a lookup table compatible with the "xt/layers" CRC
X *			generation!
X *
X * Parameters:		None.
X *
X * Return values:	None.
X */
static void
PHcrcinit()
{
X	unsigned short ones[8];		/* 1-bits for each bit position */
X	unsigned short poly[8];		/* polynomial table for each bit */
X	register unsigned short gen;	/* temporary CRC generator */
X	register int i, j;		/* loop counters */
X
X	/* build the 1-bit and polynomial tables */
X	for (i = 0; i < 8; i++)
X	{
X		ones[i] = 0x80 >> i;
X		poly[i] = 0x6000 >> i ^ 0xc001;
X	}
X
X	/* generate the lookup table entries */
X	for (i = 0; i < 256; i++)
X	{
X		gen = 0;
X
X		/* loop for each bit of the byte */
X		for (j = 0; j < 8; j++)
X			if (i & ones[j])	/* if this bit is set */
X				gen ^= poly[j];	/* divide in the polynomial */
X
X		crctab[i] = gen;		/* store the element */
X	}
}
X
/*
X * Function name:	PHcrc(f)
X *
X * Description:		Compute the CRC value for the header and data
X *			portions of the given frame.
X *
X *			The computed CRC is always stored in the "crc"
X *			area of the frame.
X *
X * Parameters:		f	pointer to frame in which to compute CRC
X *
X * Return values:	0	computed CRC matches that in frame buffer
X *			-1	computed CRC differs from frame buffer
X */
static int
PHcrc(f)
Frame *f;
{
X	register unsigned char	*buf;	/* pointer to next byte of frame */
X        register unsigned short	crc;	/* calculated CRC value */
X        register int		cnt;	/* byte count */
X
X	/* byte count is size of data portion plus header */
X	cnt = f->size + 2;
X
X	/* starting point for CRC is beginning of header */
X	buf = (unsigned char *)f;
X
X	/* compute the CRC one byte at a time */
X
X	crc = 0;
X	while (cnt-- > 0)
X		/* shift and divide by the CRC table entry */
X		crc = (crc >> 8) ^ crctab[((*buf++)^crc)&0xff];
X
X	/* now, point the buffer at the CRC area of the frame */
X	buf = (unsigned char *)&f->crc;
X
X	/* compare computed low and high order bytes to those in frame */
X	if (buf[0] == (crc & 0xff) && buf[1] == ((crc >> 8) & 0xff))
X		return(0);
X
X	/* store the computed CRC in the frame */
X	buf[0] = crc & 0xff;
X	buf[1] = (crc >> 8) & 0xff;
X
X	return(-1);
}
SHAR_EOF
chmod 0644 xtclient/phys.c ||
echo 'restore of xtclient/phys.c failed'
Wc_c="`wc -c < 'xtclient/phys.c'`"
test 9682 -eq "$Wc_c" ||
	echo 'xtclient/phys.c: original size 9682, current size' "$Wc_c"
fi
# ============= xtclient/phys.h ==============
if test -f 'xtclient/phys.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/phys.h (File already exists)'
else
echo 'x - extracting xtclient/phys.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/phys.h' &&
/*
X * File name:	phys.h
X *
X * Description:	External function declarations for phys.c
X *
X * Author:	Merlin J. Mathesius
X */
X
Xextern void	PHinit();
Xextern int	PHtoDL(), PHfromDL(), PHquery();
SHAR_EOF
chmod 0644 xtclient/phys.h ||
echo 'restore of xtclient/phys.h failed'
Wc_c="`wc -c < 'xtclient/phys.h'`"
test 190 -eq "$Wc_c" ||
	echo 'xtclient/phys.h: original size 190, current size' "$Wc_c"
fi
# ============= xtclient/select.h ==============
if test -f 'xtclient/select.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/select.h (File already exists)'
else
echo 'x - extracting xtclient/select.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/select.h' &&
struct timeval {
X	long	tv_sec;		/* seconds */
X	long	tv_usec;	/* and microseconds */
};
X
/*
X * Operations on timevals.
X *
X * NB: timercmp does not work for >= or <=.
X */
#define	timerisset(tvp)		((tvp)->tv_sec || (tvp)->tv_usec)
#define	timercmp(tvp, uvp, cmp)	\
X	((tvp)->tv_sec cmp (uvp)->tv_sec || \
X	 (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
#define	timerclear(tvp)		(tvp)->tv_sec = (tvp)->tv_usec = 0
X
/* extra masks for p_flag in proc struct */
#define	SSEL	0x400000	/* This process is selecting */
/* #define SELPROC(tp) (*((struct proc **) (& tp->spacer[0]))) */
#define SELPROC(tp) (*((long *) (& tp->spacer[0])))
X
#define select(nfds, reads, writes, excepts, tmout) \
X	syslocal(32, nfds, reads, writes, excepts, tmout)
SHAR_EOF
chmod 0644 xtclient/select.h ||
echo 'restore of xtclient/select.h failed'
Wc_c="`wc -c < 'xtclient/select.h'`"
test 755 -eq "$Wc_c" ||
	echo 'xtclient/select.h: original size 755, current size' "$Wc_c"
fi
true || echo 'restore of xtclient/session.c failed'
echo End of part 2, continue with part 3
exit 0
-- 
David H. Brierley
Home: dave at galaxia.newport.ri.us; Work: dhb at quahog.ssd.ray.com
Send comp.sources.3b1 submissions to comp-sources-3b1 at galaxia.newport.ri.us
%% Can I be excused, my brain is full. **



More information about the Comp.sources.3b1 mailing list