DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T v

⟦26a3df36e⟧ TextFile

    Length: 32003 (0x7d03)
    Types: TextFile
    Names: »vt.c«

Derivation

└─⟦3d0c2be1b⟧ Bits:30001254 ISODE-5.0 Tape
    └─⟦eba4602b1⟧ »./isode-5.0.tar.Z« 
        └─⟦d3ac74d73⟧ 
            └─⟦this⟧ »isode-5.0/vt/vt.c« 

TextFile

/* vt.c - VT initiator */

#ifndef	lint
static char *rcsid = "$Header: /f/osi/vt/RCS/vt.c,v 6.0 89/03/18 23:46:23 mrose Rel $";
#endif

/* 
 * $Header: /f/osi/vt/RCS/vt.c,v 6.0 89/03/18 23:46:23 mrose Rel $
 *
 *
 * $Log:	vt.c,v $
 * Revision 6.0  89/03/18  23:46:23  mrose
 * Release 5.0
 * 
 */

/*
 *				  NOTICE
 *
 *    Acquisition, use, and distribution of this module and related
 *    materials are subject to the restrictions of a license agreement.
 *    Consult the Preface in the User's Manual for the full terms of
 *    this agreement.
 *
 */


#include <signal.h>
#include "vtpm.h"
#include "sector1.h"
#include "tailor.h"

#include <sys/ioctl.h>
#include <ctype.h>
#include <setjmp.h>
#include <varargs.h>

#define	strip(x)	((x)&0177)
#define TBUFSIZ		1024

char	ttyobuf[TBUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
char	netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;

int	connected;
int	net;
int	showoptions = 0;
int	options;
int	debug = 0;
int	crmod = 0;
char	escape = ']' & 037;
static char *escapestr = "^]";

VT_PROFILE vtp_profile;
int rflag = 0;
char erase_char;	/*Unix Erase*/
char erase_line;	/*Unix Kill*/
char intr_char;		/*Unix Interrupt*/
char *my_displayobj = "K";	/*Initiator's Display Object Name*/
char *my_echo_obj = "NI";	/*Initiator's Negotiation Control Object*/
char *my_signal_obj = "KB";	/*Initiator's Signal Control Object*/
char *his_echo_obj = "NA";	/*Acceptor's Negotiation Control Object*/
char *his_signal_obj = "DI";	/*Acceptor's Signal Control Object*/
int my_right = INITIATOR;
char kb_image;			/*KB Control Object Image*/
char di_image;			/*DI Control Image*/
char ni_image;			/*NI Control Object Image*/
char na_image;			/*NA Control Object Image*/
char nego_state;		/*Current state of NI affected options*/
char sync_image;		/*SY Control Object*/
char ga_image;
int transparent = 0;		/*Transparent Repertoire switch*/
int telnet_profile = 1;
int do_break = 1;		/*If VT-BREAK Functional Unit agreed to*/
char *myhostname;
char peerhost[BUFSIZ];
int pty;			/*Kludge for single map.c (sorry)*/

char	line[BUFSIZ];

jmp_buf	toplevel;
jmp_buf	peerdied;

extern	int errno;


struct dispatch {
    char   *ds_name;
    IFP	    ds_fnx;

    int	    ds_flags;
#define	DS_NULL		0x00
#define	DS_OPEN		0x01	/* association required */
#define	DS_CLOSE	0x02	/* association avoided */

    char   *ds_help;
};

struct dispatch *getds ();


int	vt_open (), vt_close (), vt_quit (), vt_status (), vt_suspend ();
int	vt_ayt (), vt_break (), vt_escape ();
int	vt_set (), vt_help ();


static struct dispatch dispatches[] = {
    "ayt", vt_ayt, DS_OPEN,
    "send \"are you there?\"",

    "break", vt_break, DS_OPEN,
    "send break",

    "close", vt_close, DS_OPEN,
    "release association with terminal service",

    "escape", vt_escape, DS_NULL,
    "set escape character (depreciated)",

    "help", vt_help, DS_NULL,
    "print help information",

    "open", vt_open, DS_CLOSE,
    "associate with terminal service",

    "quit", vt_quit, DS_NULL,
    "release association with terminal service and exit",

    "set", vt_set, DS_NULL,
    "display or change variables",

    "status", vt_status, DS_OPEN,
    "show current status",

    "suspend", vt_suspend, DS_OPEN,
    "suspend vtp",

    NULL
};


SFD	intr(), deadpeer();
char	*control(), *strdup ();

struct	tchars otc;
struct	ltchars oltc;
struct	sgttyb ottyb;

static int runcom = 0;
char	*myname;
static char *myhome;
int	tmode();

LLog    _vt_log = {
    "./vt.log", NULLCP, NULLCP,
    LLOG_NONE, LLOG_NONE, -1, LLOGCLS | LLOGCRT | LLOGZER, NOTOK 
};
LLog   *vt_log = &_vt_log;

main(argc, argv)
	int argc;
	char *argv[];
{
	int	i,
		fflag;
	char   *logname,
		buffer[BUFSIZ],
	       *vec[NVEC + 1];
	FILE   *fp;

    if (myname = rindex (*argv, '/'))
	myname++;
    if (myname == NULL || *myname == NULL)
	myname = *argv;

    isodetailor (myname, 1);

    ll_hdinit (vt_log, myname);

	fflag = 0;
	logname = 0;
	myhostname = PLocalHostName ();
	peerhost[0] = NULL;
	acc = &accs;
	acr = &acrs;
	aci = &acis;

	if (ioctl(0, TIOCGETP, (char *)&ottyb) == -1) {
		perror("ioctl");
		adios(NULLCP, "ioctl failed");
	}
	if (ioctl(0, TIOCGETC, (char *)&otc) == -1) {
		perror("ioctl");
		adios(NULLCP, "ioctl failed");
	}
	if (ioctl(0, TIOCGLTC, (char *)&oltc) == -1) {
		perror("ioctl");
		adios(NULLCP, "ioctl failed");
	}

	erase_char = ottyb.sg_erase;
	erase_line = ottyb.sg_kill;
	intr_char = otc.t_intrc;

	setbuf(stdin, NULLCP);
	setbuf(stdout, NULLCP);

	bzero ((char *) &vtp_profile, sizeof vtp_profile);
	vtp_profile.profile_name = "telnet";
	vtp_profile.arg_val.tel_arg_list.x_window = ncols (stdin);
	vtp_profile.arg_val.tel_arg_list.full_ascii = 1;

	for(i=1; i<argc; i++)
	{
		if (peerhost[0] == NULL && (*argv[i] != '-'))
		{
			(void) strcpy(peerhost,argv[i]);
		}
		else if(!strcmp(argv[i], "-g"))
		{
			vtp_profile.arg_val.tel_arg_list.full_ascii = 0;
			advise(LLOG_DEBUG,NULLCP,"using ASCII GO repertoire");
		}
		else if(!strcmp(argv[i], "-D"))
		{
			vtp_profile.profile_name = "default";
			telnet_profile = 0;
			my_displayobj = "DISPLAY-OBJECT-2";
			advise(LLOG_DEBUG,NULLCP,"using default profile");
		}
		else if(!strcmp(argv[i],"-B"))
		{
			advise(LLOG_DEBUG,NULLCP,"VT-BREAK not chosen");
			do_break = 0;
		}
		else if(!strcmp(argv[i], "-f"))
		    fflag++;
		else if(!strcmp(argv[i], "-F"))
		{
			if ((logname = argv[++i]) == NULL || *logname == '-')
			    adios (NULLCP, "usage: %s -F logfile", myname);
			vt_log -> ll_file = logname;
			(void) ll_close (vt_log);
			advise(LLOG_DEBUG,NULLCP, "logging to %s",logname);
		}
		else
		    adios("usage: %s [-g] [-D] [-B] [-f] [-F logfile] [hostname]",
			  myname);
	}


    runcom = 1;

    rcinit ();
    (void) sprintf (buffer, "%s/.vtrc", myhome);
    if (!fflag && (fp = fopen (buffer, "r"))) {
	register char   *bp;
	
	while (fgets (buffer, sizeof buffer, fp)) {
	    if (bp = index (buffer, '\n'))
		*bp = NULL;

	    bzero ((char *) vec, sizeof vec);
	    if (str2vec (buffer, vec) < 1)
		continue;

	    if (vtploop (vec, NOTOK) == NOTOK && peerhost[0])
		exit (1);
	}

	(void) fclose (fp);
    }

    runcom = 0;

	if (peerhost[0] != NULL) {
		if (setjmp(toplevel) != 0)
			exit(0);
		do_vt();
	}
	(void) setjmp(toplevel);
	for (;;)
		command(1);
}

/* \f

   DISPATCH */

command(top)
	int top;
{
	int eof,oldmode;
	char *vec[NVEC + 1];

	oldmode = tmode(0);
	if (!top)
		(void) putchar('\n');
	else
	    (void) signal (SIGINT, SIG_DFL);
	eof = 0;
	for (;;) {
		if (getline ("%s> ", line) == NOTOK) {
		    if (eof) {
			if (!connected)
			    exit (0);
			(void) vt_status (NULLVP);
			break;
		    }

		    eof = 1;
		    continue;
		}
		eof = 0;

		bzero ((char *) vec, sizeof vec);
		if (str2vec (line, vec) < 1)
		    break;

		if (vtploop (vec, NOTOK) != DONE)
		    break;
	}
	if (!top) {
		if (!connected)
			longjmp(toplevel, 1);
		(void) fflush (stdout);
		(void) fflush (stderr);
		(void) tmode(oldmode);
	}
}

/* \f

 */

static int vtploop (vec, error)
char  **vec;
int	error;
{
    register struct dispatch *ds;

    if ((ds = getds (strcmp (*vec, "?") ? *vec : "help")) == NULL)
	return error;

    if (!connected) {
	if (ds -> ds_flags & DS_OPEN) {
	    advise (LLOG_NOTICE,NULLCP,  "not associated with terminal service");
	    return error;
	    }
    }
    else
	if (ds -> ds_flags & DS_CLOSE) {
	    advise (LLOG_NOTICE,NULLCP, 
		    "already associated with terminal service");
	    return error;
	}

    switch ((*ds -> ds_fnx) (vec)) {
	case NOTOK:
	    return error;

	case OK:
	default:
	    return OK;

	case DONE:
	    return DONE;
	}
}

/* \f

 */

int	getline (prompt, buffer)
char   *prompt,
       *buffer;
{
    register int    i;
    register char  *cp,
                   *ep;
    static int  sticky = 0;

    if (sticky) {
	sticky = 0;
	return NOTOK;
    }

    (void)printf (prompt, connected ? peerhost : myname);
    (void) fflush (stdout);

    for (ep = (cp = buffer) + BUFSIZ - 1; (i = getchar ()) != '\n';) {
	if (i == EOF) {
	    (void)printf ("\n");
	    clearerr (stdin);
	    if (cp == buffer)
		return NOTOK;

	    sticky++;
	    break;
	}

	if (cp < ep)
	    *cp++ = i;
    }
    *cp = NULL;
    
    return OK;
}

/* \f

 */

struct dispatch *getds (name)
register char *name;
{
    register int    longest,
                    nmatches;
    register char  *p,
                   *q;
    char    buffer[BUFSIZ];
    register struct dispatch   *ds,
                               *fs;

    longest = nmatches = 0;
    for (ds = dispatches; p = ds -> ds_name; ds++) {
	for (q = name; *q == *p++; q++)
	    if (*q == NULL)
		return ds;
	if (*q == NULL)
	    if (q - name > longest) {
		longest = q - name;
		nmatches = 1;
		fs = ds;
	    }
	    else
		if (q - name == longest)
		    nmatches++;
    }

    switch (nmatches) {
	case 0: 
	    advise (LLOG_NOTICE,NULLCP,  "unknown operation \"%s\"", name);
	    return NULL;

	case 1: 
	    return fs;

	default: 
	    for (ds = dispatches, p = buffer; q = ds -> ds_name; ds++)
		if (strncmp (q, name, longest) == 0) {
		    (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
		    p += strlen (p);
		}
	    advise (LLOG_NOTICE,NULLCP, 
		    "ambiguous operation, it could be one of:%s",
			buffer);
	    return NULL;
    }
}

/* \f

   OPERATIONS */

static int  vt_open (vec)
char  **vec;
{
    if (*++vec == NULL) {
	if (getline ("host: ", line) == NOTOK || str2vec (line, vec) < 1)
	    return NOTOK;
    }

    (void) strcpy (peerhost, *vec);
    do_vt ();

    return OK;
}


do_vt()
{
	(void) signal(SIGINT, intr);
	(void) signal(SIGPIPE, deadpeer);
	(void)printf("Trying...\n");
	(void)fflush(stdout);

	if ((fd = con_req()) < 0)
	    return;

	connected++;
	(void) vt_status (NULLVP);
	(void)printf ("escape character is '%s'\n", escapestr);
	if (setjmp(peerdied) == 0)
		vt(fd);
	adios (NULLCP, "association terminated by peer");
}

/* \f

 */

/* ARGSUSED */

static int  vt_close (vec)
char  **vec;
{
    (void) tmode(0);
    vrelreq();
    if (getch () >= -1) {
	advise (LLOG_DEBUG,NULLCP,  "flushing input queue...");
	while (getch () >= -1)
	    continue;
    }

    /* read network events until the release sequence reached
       the point where the other side shuts down
     */

    (void)printf ("association released\n");
    (void)fflush (stdout);
    connected = 0;
    /* reset his options */

    return OK;
}

/* \f

 */

/* ARGSUSED */

static int  vt_quit (vec)
char  *vec;
{
    if (connected)
	(void) vt_close (NULLVP);

    exit(0);	/* NOTREACHED */
}

/* \f

 */

/* ARGSUSED */

static int  vt_status (vec)
char  **vec;
{
    (void)printf ("associated with terminal service on \"%s\" using %s profile\n",
	    peerhost, vtp_profile.profile_name);

    return OK;
}

/* \f

 */

/* ARGSUSED */

static int  vt_suspend (vec)
char  **vec;
{
	register int save;

	save = tmode(0);
	(void)kill(0, SIGTSTP);

	/* reget parameters in case they were changed */
	if (ioctl(0, TIOCGETP, (char *)&ottyb) == -1) {
		perror("ioctl"); 
		adios(NULLCP, "ioctl failed");
	}
	if (ioctl(0, TIOCGETC, (char *)&otc) == -1) {
		perror("ioctl");
		adios(NULLCP, "ioctl failed");
	}
	if (ioctl(0, TIOCGLTC, (char *)&oltc) == -1) {
		perror("ioctl");
		adios(NULLCP, "ioctl failed");
	}
	(void) tmode(save);

	return OK;
}

/* \f

 */

static int  vt_escape (vec)
char  **vec;
{
    char   c;

    if (*++vec == NULL) {
	if (getline ("new escape character: ", line) == NOTOK
	        || str2vec (line, vec) < 1)
	    return NOTOK;
    }

    if ((c = *vec[0]) != NULL) {
	char   *cp = control (escape = c);

	free (escapestr);
	escapestr = strdup (cp);
    }
    (void)printf ("escape character is '%s'\n", escapestr);

    return OK;
}

/* \f

   VARIABLES */

static char *debug_val[] = {
	"0", "1", "2", "3", "4", "5", "6", "7", NULL
};

static char *bool[] = {
    "off", "on", NULL
};

static char *emodes[] = {
    "local", "remote", NULL
};

static char *rmodes[] = {
    "ascii", "transparent", NULL
};

static char *xsaplevels[] = {
    "none", "fatal", "exceptions", "notice", "pdus", "trace", "debug", NULL
};


struct var {
    char   *v_name;
    IP	    v_value;

    char   *v_dname;
    char  **v_dvalue;
    char   *v_mask;

    IFP	    v_hook;
};

struct var *getvar ();


static int   echo = 0;
static int   repertoire = 0;
static int   verbose = 0;

int	set_debug (), set_echo (), set_escape (), set_repertoire ();


static struct var vars[] = {
    "acsaplevel", &_acsap_log.ll_events, "ACSAP logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "acsapfile", NULLIP, "ACSAP trace file", &_acsap_log.ll_file, NULLCP,
	NULLIFP,

    "addrlevel", &_addr_log.ll_events, "address logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "addrfile", NULLIP, "address trace file", &_addr_log.ll_file, NULLCP,
	NULLIFP,

    "compatlevel", &_compat_log.ll_events, "COMPAT logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "compatfile", NULLIP, "COMPAT trace file", &_compat_log.ll_file, NULLCP,
	NULLIFP,

    "crmod", &crmod, "map CR on output", bool, NULLCP, NULLIFP,

    "debug", &debug, "debug VT", debug_val, NULLCP, set_debug,

    "echo", &echo, "local or remote echoing", emodes, NULLCP, set_echo,

    "escape", NULLIP, "escape character", &escapestr, NULLCP, set_escape,

    "options", &showoptions, "show option processing", bool, NULLCP, NULLIFP,

    "psaplevel", &_psap_log.ll_events, "PSAP logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "psapfile", NULLIP, "PSAP trace file", &_psap_log.ll_file, NULLCP,
	NULLIFP,

    "psap2level", &_psap2_log.ll_events, "PSAP2 logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "psap2file", NULLIP, "PSAP2 trace file", &_psap2_log.ll_file, NULLCP,
	NULLIFP,

    "repertoire", &repertoire, "terminal repertoire", rmodes, NULLCP,
	set_repertoire,

    "ssaplevel", &_ssap_log.ll_events, "SSAP logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "ssapfile", NULLIP, "SSAP trace file", &_ssap_log.ll_file, NULLCP,
	NULLIFP,

    "tracelevel", &_vt_log.ll_events, "VT logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "tracefile", NULLIP, "VT trace file", &_vt_log.ll_file, NULLCP,
	NULLIFP,

    "tsaplevel", &_tsap_log.ll_events, "TSAP logging", xsaplevels,
	LLOG_MASK, NULLIFP,
    "tsapfile", NULLIP, "TSAP trace file", &_tsap_log.ll_file, NULLCP,
	NULLIFP,

    "verbose", &verbose, "verbose interaction", bool, NULLCP, NULLIFP,

    NULL
};


static int varwidth1;
static int varwidth2;

char    **getval ();

/* \f

 */

static int  vt_set (vec)
char  **vec;
{
    register int    i,
		    j;
    int     value,
	    vflag;
    register char **cp,
		   *dp;
    register struct var *v;

    if (*++vec == NULL) {
	register int    w;
	int     columns,
	        width,
	        lines;
	register struct var *u;

	for (u = vars; u -> v_name; u++)
	    continue;
	width = varwidth1;

	if ((columns = ncols (stdout) / (width = (width + 8) & ~7)) == 0)
	    columns = 1;
	lines = ((u - vars) + columns - 1) / columns;

	(void)printf ("Variables:\n");
	for (i = 0; i < lines; i++)
	    for (j = 0; j < columns; j++) {
		v = vars + j * lines + i;
		(void)printf ("%s", v -> v_name);
		if (v + lines >= u) {
		    (void)printf ("\n");
		    break;
		}
		for (w = strlen (v -> v_name); w < width; w = (w + 8) & ~7)
		    (void) putchar ('\t');
	    }

	return DONE;
    }

    echo = (nego_state & ECHO_OBJ) ? 1 : 0;
    repertoire = transparent ? 1 : 0;

    if (strcmp (*vec, "?") == 0) {
	for (v = vars; v -> v_name; v++)
	    printvar (v);

	return DONE;
    }

    if ((v = getvar (*vec)) == NULL)
	return DONE;

    if (*++vec == NULL) {
	printvar (v);

	return DONE;
    }

    if (strcmp (*vec, "?") == 0) {
	if (v -> v_value && (cp = v -> v_dvalue)) {
	    printf ("use %s of:", v -> v_mask ? "any" : "one");
	    for (i = 0; *cp; cp++)
		printf ("%s \"%s\"", i++ ? "," : "", *cp);
	    if (v -> v_mask)
		printf (";\n\tor  \"all\";\n\tor a hexadecimal number from 0 to 0x%x\n",
		    (1 << (i - 1)) - 1);
	    else
		printf (";\n\tor a number from 0 to %d\n",
		    cp - v -> v_dvalue - 1);
	}
	else
	    (void)printf ("use any %s value\n",
		    v -> v_value ? "integer" : "string");

	return DONE;
    }

    if (v -> v_value == NULLIP) {
	register int    w;

	if (*v -> v_dvalue)
	    free (*v -> v_dvalue);
	*v -> v_dvalue = strdup (*vec);
	if ((w = strlen (*v -> v_dvalue) + 2) > varwidth2)
	    varwidth2 = w;
	if (v -> v_hook)
	    (*v -> v_hook) (v);
	if (verbose)
	    printvar (v);
	return DONE;
    }

    if (v -> v_mask) {
	if (strcmp (dp = *vec, "all") == 0 && (cp = v -> v_dvalue)) {
	    i = 1;
	    while (*++cp)
		i <<= 1;
	    value = i - 1;
	    j = 1;
	}
	else {
	    if (strncmp (dp = *vec, "0x", 2) == 0)
		dp += 2;
	    for (j = sscanf (dp, "%x", &value); *dp; dp++)
		if (!isxdigit (*dp)) {
		    j = 0;
		    break;
		}
	}
    }
    else
	j = sscanf (*vec, "%d", &value);

    if (j == 1) {
	if (cp = v -> v_dvalue) {
	    if (v -> v_mask) {
		i = 1;
		while (*++cp)
		    i <<= 1;
		if (value >= i)
		    goto out_of_range;
	    }
	    else {
		for (; *cp; cp++)
		    continue;
		if (value >= cp - v -> v_dvalue) {
out_of_range: ;
		    advise (LLOG_NOTICE,NULLCP, 
			    "value out of range \"%s\"", *vec);

		    return DONE;
		}
	    }
	}

	vflag = verbose;
	*v -> v_value = value;
	if (v -> v_hook)
	    (*v -> v_hook) (v);
	if (vflag)
	    printvar (v);

	return DONE;
    }

    if (v -> v_mask) {
	i = 0;
	for (; *vec; vec++) {
	    if (!(cp = getval (*vec, v -> v_dvalue))) {
		advise (LLOG_NOTICE,NULLCP,  "bad value \"%s\"", *vec);

		return DONE;
	    }
	    if ((j = cp - v -> v_dvalue) <= 0)
		continue;

	    i |= 1 << (j - 1);
	}

	vflag = verbose;
	*v -> v_value = i;
	if (v -> v_hook)
	    (*v -> v_hook) (v);
	if (vflag)
	    printvar (v);

	return DONE;
    }

    if (v -> v_dvalue && (cp = getval (*vec, v -> v_dvalue))) {
	vflag = verbose;
	*v -> v_value = cp - v -> v_dvalue;
	if (v -> v_hook)
	    (*v -> v_hook) (v);
	if (vflag)
	    printvar (v);
    }
    else
	if (!v -> v_dvalue)
	    advise (LLOG_NOTICE,NULLCP,  "bad value \"%s\"", *vec);

    return DONE;
}

/* \f

 */

static printvar (v)
register struct var *v;
{
    int	    i;
    char    buffer[BUFSIZ];

    if (runcom)
	return;

    (void)printf ("%-*s = ", varwidth1, v -> v_name);
    if (v -> v_value) {
	i = *v -> v_value;

	if (v -> v_mask) {
	    if (v -> v_dvalue) {
		if (i == 0)
		    (void)printf ("%-*s", varwidth2, v -> v_dvalue[i]);
		else {
		    (void) strcpy (buffer, sprintb (i, v -> v_mask));
		    if (strlen (buffer) <= varwidth2)
			(void)printf ("%-*s", varwidth2, buffer);
		    else
			(void)printf ("%s\n%*s", buffer, varwidth1 + varwidth2 + 3,
				"");
		}
	    }
	    else
		(void)printf ("0x%-*x", varwidth2 - 2, i);
	}
	else {
	    if (v -> v_dvalue)
		(void)printf ("%-*s", varwidth2, v -> v_dvalue[i]);
	    else
		(void)printf ("%-*d", varwidth2, i);
	}
    }
    else
	if (*v -> v_dvalue) {
	    (void) sprintf (buffer, "\"%s\"", *v -> v_dvalue);
	    (void)printf ("%-*s", varwidth2, buffer);
	}
    (void)printf ("    - %s\n", v -> v_dname);
}

/* \f

 */

/* ARGSUSED */

static int  set_debug (v)
struct var *v;
{
    if (debug)
	ll_dbinit (vt_log, myname);
    else
	vt_log -> ll_stat &= ~LLOGTTY;
}


/* ARGSUSED */

static int  set_echo (v)
struct var *v;
{
    if (!connected) {
	advise (LLOG_NOTICE,NULLCP,  "not associated with terminal service");
	return;
    }

    vt_echo (echo);
}


/* ARGSUSED */

static int  set_escape (v)
struct var *v;
{
    if (*escapestr) {
	char   *cp = control (escape = *escapestr);

	free (escapestr);
	escapestr = strdup (cp);
    }
}


/* ARGSUSED */

static int  set_repertoire (v)
struct var *v;
{
    if (!connected) {
	advise (LLOG_NOTICE,NULLCP,  "not associated with terminal service");
	return;
    }

    vt_repertoire (repertoire);
}

/* \f

 */

static char **getval (name, choices)
register char *name;
char   **choices;
{
    register int    longest,
                    nmatches;
    register char  *p,
                   *q,
                  **cp,
                  **fp;
    char    buffer[BUFSIZ];

    longest = nmatches = 0;
    for (cp = choices; p = *cp; cp++) {
	for (q = name; *q == *p++; q++)
	    if (*q == NULL)
		return cp;
	if (*q == NULL)
	    if (q - name > longest) {
		longest = q - name;
		nmatches = 1;
		fp = cp;
	    }
	    else
		if (q - name == longest)
		    nmatches++;
    }

    switch (nmatches) {
	case 0: 
	    advise (LLOG_NOTICE,NULLCP,  "unknown value \"%s\"", name);
	    return NULL;

	case 1: 
	    return fp;

	default: 
	    for (cp = choices, p = buffer; q = *cp; cp++)
		if (strncmp (q, name, longest) == 0) {
		    (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
		    p += strlen (p);
		}
	    advise (LLOG_NOTICE,NULLCP,  "ambiguous value, it could be one of:%s",
		    buffer);
	    return NULL;
    }
}

/* \f

 */

static struct var *getvar (name)
register char *name;
{
    register int    longest,
                    nmatches;
    register char  *p,
                   *q;
    char    buffer[BUFSIZ];
    register struct var *v,
			*f;

    longest = nmatches = 0;
    for (v = vars; p = v -> v_name; v++) {
	for (q = name; *q == *p++; q++)
	    if (*q == NULL)
		return v;
	if (*q == NULL)
	    if (q - name > longest) {
		longest = q - name;
		nmatches = 1;
		f = v;
	    }
	    else
		if (q - name == longest)
		    nmatches++;
    }

    switch (nmatches) {
	case 0: 
	    advise (LLOG_NOTICE,NULLCP,  "unknown variable \"%s\"", name);
	    return NULL;

	case 1: 
	    return f;

	default: 
	    for (v = vars, p = buffer; q = v -> v_name; v++)
		if (strncmp (q, name, longest) == 0) {
		    (void) sprintf (p, "%s \"%s\"", p != buffer ? "," : "", q);
		    p += strlen (p);
		}
	    advise (LLOG_NOTICE,NULLCP, 
		    "ambiguous variable, it could be one of:%s", buffer);
	    return NULL;
    }
}

/* \f

   HELP */

static int helpwidth = 0;


static int  vt_help (vec)
char  **vec;
{
    register int    i,
                    j,
                    w;
    int     columns,
            width,
            lines;
    register struct dispatch   *ds,
                               *es;

    for (es = dispatches; es -> ds_name; es++)
	continue;
    width = helpwidth;

    if (*++vec == NULL) {
	if ((columns = ncols (stdout) / (width = (width + 8) & ~7)) == 0)
	    columns = 1;
	lines = ((es - dispatches) + columns - 1) / columns;

	(void)printf ("Operations:\n");
	for (i = 0; i < lines; i++)
	    for (j = 0; j < columns; j++) {
		ds = dispatches + j * lines + i;
		(void)printf ("%s", ds -> ds_name);
		if (ds + lines >= es) {
		    (void)printf ("\n");
		    break;
		}
		for (w = strlen (ds -> ds_name); w < width; w = (w + 8) & ~7)
		    (void) putchar ('\t');
	    }

	(void)printf ("\n");

	return DONE;
    }

    for (; *vec; vec++)
	if (strcmp (*vec, "?") == 0) {
	    for (ds = dispatches; ds -> ds_name; ds++)
		(void)printf ("%-*s\t- %s\n", width, ds -> ds_name, ds -> ds_help);

	    break;
	}
	else
	    if (ds = getds (*vec))
		(void)printf ("%-*s\t- %s\n", width, ds -> ds_name, ds -> ds_help);

    return DONE;
}


static int    ncols (fp)
FILE *fp;
{
#ifdef	TIOCGWINSZ
    int	    i;
    struct winsize win;

    if (ioctl (fileno (fp), TIOCGWINSZ, (char *) &win) != NOTOK
	    && (i = win.ws_col) > 0)
	return i;
#endif

    return 80;
}

/* \f

 */

char   *strdup (s)
char   *s;
{
    char    *p;

    if ((p = malloc((unsigned) (strlen (s) + 1))) == NULL)
	adios (NULLCP, "out of memory");

    (void) strcpy (p, s);

    return p;
}

/* \f

 */

static rcinit ()
{
    register int    w;
    register char **cp;
    register struct dispatch *ds;
    register struct var *v;

    if ((myhome = getenv ("HOME")) == NULL)
	myhome = ".";		/* could do passwd search... */

    escapestr = strdup (control (escape));
    for (ds = dispatches, helpwidth = 0; ds -> ds_name; ds++)
	if ((w = strlen (ds -> ds_name)) > helpwidth)
	    helpwidth = w;

    for (v = vars, varwidth1 = 0; v -> v_name; v++) {
	if ((w = strlen (v -> v_name)) > varwidth1)
	    varwidth1 = w;

	if (v -> v_value) {
	    if (cp = v -> v_dvalue) {
		if (v -> v_mask) {
#ifdef	notdef
		    w = 1;
		    while (*++cp)
			w <<= 1;
		    w--;
		    if ((w = strlen (sprintb (w, v -> v_mask))) > varwidth2)
			varwidth2 = w;
#endif
		}
		else
		    for (; *cp; cp++)
			if ((w = strlen (*cp)) > varwidth2)
			    varwidth2 = w;
	    }
	}
	else
	    if (*v -> v_dvalue) {
		*v -> v_dvalue = strdup (*v -> v_dvalue);
		if ((w = strlen (*v -> v_dvalue) + 2) > varwidth2)
		    varwidth2 = w;
	    }
    }
}

char	sibuf[BUFSIZ << 3], *sbp;
char	tibuf[BUFSIZ], *tbp;
int	tcc;

/*
 * Select from tty and network...
 */
vt(s)
	int s;
{
	register int c;
	int tin = fileno(stdin), tout = fileno(stdout);
	int result;

	nego_state = 0;
	if(telnet_profile)
	{
		(void) tmode(2);
		vt_rem_echo(&ni_image);		/*Request Remote Echo*/
		vt_sup_ga(&ni_image);		/*Request Suppress Go Ahead*/
		repertoire = 1;
		vt_repertoire(repertoire);
	}
	else (void) tmode(1);

	for (;;) {
	    	fd_set    ibits, obits;

		FD_ZERO (&ibits);

		FD_ZERO (&obits);
		FD_SET (tout, &obits);
		FD_SET (s, &obits);

		if (nfrontp - nbackp)
		    FD_SET (s, &obits);
		else
		    FD_SET (tin, &ibits);

		if (tfrontp - tbackp)
		    FD_SET (tout, &obits);
		else
		    FD_SET (s, &ibits);
		if (FD_ISSET (s, &ibits) && data_pending()) {
		        FD_CLR (s, &ibits);
			result = xselect(FD_SETSIZE, &ibits, &obits,
					 (fd_set *)NULL, OK);
			if (result == -1)
			    adios ("failed", "xselect");
			FD_SET (s, &ibits);
		}
		else {			
			result = xselect(FD_SETSIZE, &ibits, &obits,
					 (fd_set *)NULL, NOTOK);
			if (result == -1)
			    adios ("failed", "xselect");
		}
		if (!FD_ISSET (s, &ibits)
		        && !FD_ISSET (tin, &ibits)
		        && !FD_ISSET (s, &obits)
		        && !FD_ISSET (tout, &obits)) {
			sleep(5);
			continue;
		}

		/*
		 * Something to read from the network...
		 */
		if (FD_ISSET (s, &ibits)) {

			while ( (c = getch()) > 0){
				*tfrontp++ = c;
				if(tfrontp >= &ttyobuf[TBUFSIZ-1]) break;
			}

			if (c == E_EOF) {
				break;
			}
		}

		/*
		 * Something to read from the tty...
		 */
		if (FD_ISSET (tin, &ibits)) {
			tcc = read(tin, tibuf, sizeof (tibuf));
			if (tcc < 0 && errno == EWOULDBLOCK)
				tcc = 0;
			else {
				if (tcc <= 0) {
					advise(LLOG_NOTICE,NULLCP,  "error: read from terminal returned %d", tcc);
					break;
				}
				tbp = tibuf;
			}
		}

		while (tcc > 0) {
			register int ch;

			if ((&netobuf[BUFSIZ] - nfrontp) < 2)
				break;
			ch = *tbp++ & 0377, tcc--;
			if (strip(ch) == escape) {
				command(0);
				tcc = 0;
				break;
			}
			*nfrontp++ = ch;
		}
		if (FD_ISSET (s, &obits) && (nfrontp - nbackp) > 0)
			netflush(s);
		if (FD_ISSET (tout, &obits) && (tfrontp - tbackp) > 0)
			ttyflush(tout);
	}
	(void) tmode(0);
}

/*
 * Construct a control character sequence
 * for a special character.
 */
char *
control(c)
	register int c;
{
	static char buf[3];

	if (c == 0177)
		return ("^?");
	if (c >= 040) {
		buf[0] = c;
		buf[1] = 0;
	} else {
		buf[0] = '^';
		buf[1] = '@'+c;
		buf[2] = 0;
	}
	return (buf);
}

SFD	deadpeer()
{
	(void) tmode(0);
	longjmp(peerdied, -1);
}

SFD	intr()
{
	(void) tmode(0);
	longjmp(toplevel, -1);
}

ttyflush(dd)
int	dd;
{
	int n;

	if ((n = tfrontp - tbackp) > 0) {

		n = write(dd, tbackp, n);

	}
	if (n < 0)
	{
		advise(LLOG_NOTICE,NULLCP,  "ttyflush(): Negative returned from write");
		return;
	}
	tbackp += n;
	if (tbackp == tfrontp)
		tbackp = tfrontp = ttyobuf;
}

netflush(dd)
int	dd;
{
	register char *cp;
	int n, i, j;
	int nl_flag;		/*If current PDU includes newline, follow it
				  with a Deliver Request*/

	nl_flag = 0;
	if ((n = nfrontp - nbackp) > 0) {
		if(transparent)
		{
			if (vt_text(nbackp,n) != OK)
				advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
			vtsend();
			cp = nbackp;
			for(i=0; i<n; i++)
			{
				if( (*cp == '\r') ||
				    (*cp == '\n') )
				{
					vdelreq(FALSE);
					break;
				}
				++cp;
			}
			nbackp += n;
		}
		else
		{
		    cp = nbackp;
		    for(i=0,j=0; i<n; i++)
		    {
			if(*cp == '\r')
			{
			    if(j) 
					if (vt_text(nbackp,j) != OK) 
						advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
			    nbackp += (j+1);
			    cp = nbackp;
			    j = 0;
			    rflag = 1;
			    vt_newline();
			    ++nl_flag;
			}
			else if(*cp == '\n')
			{
			    if(!rflag) /*If preceeding char was not CR*/
			    {
				if(j) 
					if (vt_text(nbackp,j) != OK)
						advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
				nbackp += (j+1);
				cp = nbackp;
				j = 0;
				vt_newline();
				++nl_flag;
			    }
			    else /*Preceeding char was CR so already sent
				   the Update.  Remove this LF from buffer*/
			    {
				++nbackp;
				++cp;
			        rflag = 0;
			    }
			} 
			else if(telnet_profile)
			{
			    rflag = 0;
			    if(*cp == erase_char)
			    {
				    if(j) 
						if (vt_text(nbackp,j) != OK)
							advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
				    nbackp += (j+1);
				    cp = nbackp;
				    j = 0;
			 	    vt_char_erase();
			    }
			    else if(*cp == erase_line)
			    {
				    if(j) 
						if (vt_text(nbackp,j) != OK)
							advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
				    nbackp += (j+1);
				    cp = nbackp;
				    j = 0;
				    vt_line_erase();
			    }
			    else if(*cp == intr_char)
			    {
				    if(j) 
						if (vt_text(nbackp,j) != OK)
							advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
				    nbackp += (j+1);
				    cp = nbackp;
				    j = 0;
				    vt_interrupt();
			    }
			    else if(!vtp_profile.arg_val.tel_arg_list.full_ascii)
					/*If ASCII GO, dump ctrl chars*/
			    {
				if((*cp < 0x20) || (*cp > 0x7e))
				{
				    if(j) 
						if (vt_text(nbackp,j) != OK)
							advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
				    nbackp += (j+1);
				    cp = nbackp;
				    j = 0;
				}
				else
				{
				    ++j;
				    ++cp;
				}
			    }
			    else
			    {
				++j;
				++cp;
			    }
			}
			else	/*Else Default Profile*/
			{
			    if((*cp < 0x20) || (*cp > 0x7e))
			    {
				if(j) 
					if (vt_text(nbackp,j) != OK)
							advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
				nbackp += (j+1);
				cp = nbackp;
				j = 0;
			    }
			    else
			    {
				++j; ++cp;
			    }
			}
		    }		/*End for loop*/
		    if(j) 
				if (vt_text(nbackp,j) != OK) /*Load anything left if CR or LF
							wasn't last char in buffer*/
						advise(LLOG_NOTICE,NULLCP,  "vt_text failed");
		    nbackp += j;
		    vtsend();	/*Send the whole NDQ*/
		    if(nl_flag && telnet_profile) vdelreq(FALSE);
		    rflag = 0;
		}

	}
	if (n < 0) {
		if (errno != ENOBUFS && errno != EWOULDBLOCK) {
			(void) tmode(0);
			perror(peerhost);
			(void)close(dd);
			longjmp(peerdied, -1);
			/*NOTREACHED*/
		}
		n = 0;
	}
	if (nbackp == nfrontp)
		nbackp = nfrontp = netobuf;
}
\f


flushbufs()
{
	tcc = 0;
	tbp = tibuf;
	nfrontp = nbackp = netobuf;
	while (getch() > 0)
	    continue;
	tfrontp = tbackp = ttyobuf;
}
	
/* \f

   ERRORS */

void	finalbye ()
{
    (void) tmode (0);
}


#ifndef	lint
void	adios (va_alist)
va_dcl
{
    int	    code;
    va_list ap;
    static int latched = 0;

    va_start (ap);

    code = va_arg (ap, int);

    (void) _ll_log (vt_log, code, ap);

    va_end (ap);

    if (connected && latched++ == 0)
	(void) vt_close (NULLVP);

    _exit (1);
}
#else
/* VARARGS2 */

void	adios (what, fmt)
char   *what,
       *fmt;
{
    adios (what, fmt);
}
#endif


#ifndef	lint
void	advise (va_alist)
va_dcl
{
    int	    code,
	    flags;
    char    buffer[BUFSIZ];
    va_list ap;

    va_start (ap);

    code = va_arg (ap, int);

    asprintf (buffer, ap);

    flags = vt_log -> ll_stat;

    if (code & (LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE)) {
	(void) fflush (stdout);

	fprintf (stderr, "%s: ", myname);
	(void) fputs (buffer, stderr);
	(void) fputc ('\n', stderr);

	(void) fflush (stderr);

	vt_log -> ll_stat &= ~LLOGTTY;
    }

    (void) ll_log (vt_log, code, NULLCP, "%s", buffer);

    vt_log -> ll_stat = flags;

    va_end (ap);
}
#else
/* VARARGS3 */

void	advise (code, what, fmt)
int	code;
char   *what,
       *fmt;
{
    advise (code, what, fmt);
}
#endif

/*ARGSUSED*/
setmode(on, off)
{
}