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 - download
Index: ┃ T q

⟦b12a92f41⟧ TextFile

    Length: 16314 (0x3fba)
    Types: TextFile
    Names: »qterm.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/qterm/qterm.c« 

TextFile

#ifndef lint
static char *RCSid = "$Header: qterm.c,v 1.23 87/01/09 13:55:44 mcooper Locked $";
#endif

/*
 *------------------------------------------------------------------
 *
 * $Source: /big/src/usc/bin/qterm/RCS/qterm.c,v $
 * $Revision: 1.23 $
 * $Date: 87/01/09 13:55:44 $
 * $State: Exp $
 * $Author: mcooper $
 * $Locker: mcooper $
 *
 *------------------------------------------------------------------
 *
 * Michael A. Cooper
 * University Computing Services, 
 * University of Southern California
 * (mcooper@usc-oberon.arpa)
 *
 *------------------------------------------------------------------
 * $Log:	qterm.c,v $
 * Revision 1.23  87/01/09  13:55:44  mcooper
 * Fixed bug with -s option that caused "ers:" 
 * to be printed instead of the string
 * received from the terminal.
 * 
 * Revision 1.22  86/12/11  15:57:16  mcooper
 * Should now work under System V thanks to Brian L. Matthews
 * (cxsea!blm).
 * 
 * Revision 1.21  86/10/13  12:52:54  mcooper
 * Fixed bug that caused problems with
 * send strings not being sent from .qterm
 * files.
 * 
 * Revision 1.20  86/08/25  15:45:58  mcooper
 * BUG FIX: When the -f flag was specified and the user's
 *          tables did not produce the terminal's entry,
 *          the internal terminal tables where not tried
 *          as documented.
 * 
 * Revision 1.19  86/08/12  15:31:22  mcooper
 * Fixed bug that caused terminals to wedge due
 * to qterm failing to match receive strings
 * from the .qterm file.
 * 
 * Revision 1.18  86/08/11  13:49:42  mcooper
 * Fixed bug that caused qterm to wedge.  Problem
 * due to alarms not being set correctly.
 * 
 * Revision 1.17  86/08/08  14:40:09  mcooper
 * - Only send/listen for strings if the previously sent string
 *   is not the same as the current string.
 * - Fixed -s option.
 * 
 * Revision 1.16  86/08/08  13:16:05  mcooper
 * Major re-write: Added ~/.qterm file that contains
 * the users own copy of terminal tables.
 * 
 * Revision 1.15  86/07/21  12:35:54  mcooper
 * Now works under System V (Define USG5).
 * 
 * Revision 1.14  86/07/01  22:57:45  mcooper
 * Moved terminal table to seperate
 * file (table.c).
 * 
 * Revision 1.13  86/06/30  11:17:53  mcooper
 * More terminals to main table...
 * 
 * Revision 1.12  86/06/19  13:57:51  mcooper
 * Added responses for concept from a Pro running
 * 2.9bsd.
 * 
 * Revision 1.11  86/06/18  15:58:45  mcooper
 * Cleanup for release.
 * 
 * Revision 1.10  86/06/17  23:06:55  mcooper
 * Added Unix PC responses.
 * 
 * Revision 1.9  86/06/16  14:19:09  mcooper
 * Added vt100 responses from vt100 manual.
 * 
 * Revision 1.8  86/06/16  13:23:40  mcooper
 * Print additional information about
 * what the actual terminal is.
 * 
 * Revision 1.7  86/06/12  10:59:27  mcooper
 * *** empty log message ***
 * 
 * Revision 1.6  86/06/11  19:48:35  mcooper
 * Added alternate string and table entries for concepts.
 * 
 * Revision 1.5  86/05/19  12:30:32  mcooper
 * General clean up.
 * 
 * Revision 1.4  86/05/18  17:56:11  mcooper
 * Added another vt100.  This one is for when you rlogin
 * from a Pro 2.9bsd host on a HDS Concept.
 * 
 * Revision 1.3  86/05/08  09:24:13  mcooper
 * Added another vt100 description.
 * 
 * Revision 1.2  86/05/06  18:23:35  mcooper
 * More cleanup - de-linted (almost).
 * 
 * Revision 1.1  86/05/06  14:56:57  mcooper
 * Initial revision
 * 
 *------------------------------------------------------------------
 */

/*
 * [Edit with tabstop=4]
 *
 * qterm - Query Terminal
 *
 * qterm is used to query a terminal to determine the name of the terminal.
 * This is done by sending a fairly universal string "\33Z" to the terminal,
 * reading in a response, and comparing it against a master table of responses
 * and names.  The "name" printed to standard output should be one found in
 * the termcap(5) database.
 *
 * Putting a line in your ".login" file such as:
 *
 *	setenv TERM `qterm`
 *
 * or the following lines in your ".profile" file:
 *
 *	TERM=`qterm`
 *	export TERM
 *
 * will set your terminal type automagically.
 * 
 * If you add a terminal to the master table, please also send me a copy
 * so that I may put it into my version.
 *
 * Michael Cooper
 * ARPA: 	mcooper@usc-oberon.ARPA
 * UUCP: 	mcooper@usc-oberon.UUCP
 * BITNET:	mcooper@uscvaxq
 */

#include <stdio.h>
#include <pwd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <setjmp.h>
#ifdef USG5
# include <termio.h>
#else
# include <sys/file.h>
# include <sgtty.h>
#endif

#define SEND		"\033Z"		/* send this to query terminal */
#define ALTSEND		"\033[c"	/* alternate string */

#define STRFILE		".qterm"	/* file containing terminal strings */

#define dprintf		if(debug)printf
#define MAXTERMS	100

#define TRUE		1
#define FALSE		0

#define T_STR		0
#define T_NAME		1
#define T_LNAME		2

int tabmark = 0;
int tabtotal = 0;
int has_set = 0;


#define BUF			666

struct qt {
	char	qt_sendstr[BUFSIZ]; 		/* String to send to terminal */
	char	qt_recvstr[BUFSIZ];			/* String expected in response */
	char	qt_termname[BUFSIZ];		/* Terminal name */
	char	qt_fullname[BUFSIZ];		/* Full terminal name & description */
};
struct qt *compare();
static struct qt termtab[MAXTERMS];


#ifdef USG5
struct termio _ntty, _otty;
#else
struct sgttyb _tty;
#endif
int _tty_ch = 2;

#ifdef USG5
# define crmode()		(_ntty.c_lflag &= ~ICANON,\
						 _ntty.c_cc[VMIN] = 1, _ntty.c_cc[VTIME] = 0,\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
# define nocrmode()		(_ntty.c_lflag |= ICANON,\
						 _ntty.c_cc[VMIN] = _otty.c_cc[VMIN],\
						 _ntty.c_cc[VTIME] = _otty.c_cc[VTIME],\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
# define echo()			(_ntty.c_lflag |= ECHO,\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
# define noecho()		(_ntty.c_lflag &= ~ECHO,\
						 ioctl(_tty_ch, TCSETAF, &_ntty))
#else
# define crmode() 		(_tty.sg_flags |= CBREAK,\
							ioctl(_tty_ch, TIOCSETP, &_tty))
# define nocrmode() 	(_tty.sg_flags &= ~CBREAK,\
							ioctl(_tty_ch, TIOCSETP, &_tty))
# define echo() 		(_tty.sg_flags |= ECHO,   \
							ioctl(_tty_ch, TIOCSETP, &_tty))
# define noecho() 		(_tty.sg_flags &= ~ECHO,  \
							ioctl(_tty_ch, TIOCSETP, &_tty))
#endif

#define SIZE 		512
#define CMASK 		0377
#define ESC			'\033'

static char recvbuf[SIZE];
static char *progname;
int debug;					/* debug mode 			*/
int aflag;					/* alternate string 	*/
int sflag;					/* print strings		*/
int qflag;					/* quiet mode 			*/
int fflag;					/* use strings file 	*/

int found = FALSE;
int index = 0;
int finish(), wakeup(), done();

char *decode();

jmp_buf env;

main(argc, argv)
char *argv[];
{
	register int x;

	progname = argv[0];

	for (x = 1; x < argc; x++) {
		if (argv[x][0] != '-')
			break;
		switch (argv[x][1]) {
			case 'a':
				aflag = TRUE;
				break;
			case 't':
			case 's':
				sflag = TRUE;
				break;
			case 'q':
				qflag = TRUE;
				break;
			case 'f':
				fflag = TRUE;
				break;
			case 'd':
				debug = TRUE;
				break;
			default:
				usage();
				exit(1);
		}
	}

	setbuf(stdout, 0);
	if(debug)
		setbuf(stderr, 0);

	dprintf("[ %s debug mode enabled ]\n\n", progname);

	if(!isatty(0))
		fprintf(stderr,"Not a tty.\n");

#ifdef USG5
	if(ioctl(_tty_ch, TCGETA, &_otty) < 0)
#else
	if(ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
#endif
	{
		perror("gtty");
		exit(1);
	}
#ifdef USG5
	_ntty = _otty;
#endif
	if(crmode() < 0) {
		perror("crmode");
		exit(1);
	}
	if(noecho() < 0) {
		perror("noecho");
		exit(1);
	}

	dprintf("[ initilizing term table... ]\n");
	mktable();
	dprintf("[ table done ]\n");

	if(!fflag) {
		dointernal();
	} else
		dprintf("!fflag.  not doing dointernal().\n");

	index = tabmark;
	dprintf("main: we'll do a dotab()\n");
	dotab();
	dprintf("main: dotab done\n");

	putc('\r', stderr);
	(void) nocrmode();
	(void) echo();
	if(!found) {
		dprintf("end of main\n");
		notrecognized();
	}
}

done()
{
	putc('\r', stderr);
	(void) nocrmode();
	(void) echo();
	exit(0);
}

/*
 * finish - clean things up.
 */
finish()
{
	dprintf("finish called\n");
	putc('\r', stderr);
	(void) nocrmode();
	(void) echo();
	if(recvbuf[0] != NULL)
		(void) prinfo(compare(recvbuf, 0, tabtotal), 1);
		
	dprintf("finish done\n");
	if(!found)
		notrecognized();
	exit(0);
}

prinfo(t, what)
struct qt *t;
int what;
{
	int len = 0;
	int st = FALSE;

	dprintf("prinfo startup\n");
	if((t->qt_termname[0] != NULL) && (recvbuf[0] != NULL)) {
		if(debug || sflag) {
			len = strlen(recvbuf);
			fprintf(stderr, "%s receives %d character%s:", 
				progname, len, (len == 1) ? "" : "s");
			fprintf(stderr, " %s\n", decode(recvbuf));
		}
		if(!qflag)
			if(t->qt_fullname[0] != NULL)
				fprintf(stderr, "Terminal recognized as %s (%s)\n", 
					t->qt_termname, t->qt_fullname);
			else
				fprintf(stderr, "Terminal recognized as %s\n", 
					t->qt_termname);
		printf("%s\n", t->qt_termname);
		found = TRUE;
		done();
		/*NOTREACHED*/
	} else {
		found = FALSE;
		if(what) {
			dprintf("prinfo(): doing notrecognized()\n");
			notrecognized();
			done();
			/*NOTREACHED*/
		}
	}
	dprintf("prinfo done\n");
	return(st);
}

/*
 * compare - actually compare what we received against the table.
 */
struct qt *
compare(str, start, stop)
char *str;
int start;
int stop;
{
	register int i = 0;
	int len;

	dprintf("compare(%s, %d, %d) startup.\n", decode(str), start, stop);
	alarm(0);

	i = start;
	while(i <= stop) {
		dprintf("compare(): tr = '%s'\n", decode(termtab[i].qt_recvstr));
		if(strncmp(str, termtab[i].qt_recvstr, 
		  strlen(termtab[i].qt_recvstr)) == 0) {
			found = TRUE;
			return(&termtab[i]);
		}
		++i;
	}
	found = FALSE;
}

/*
 * getch - read in a character at a time.
 */
getch()
{
	char c;

	(void) read(0, &c, 1);
	return(c & CMASK);
}

/*
 * decode - print str in a readable fashion
 */
char *
decode(str)
char *str;
{
	char buf[BUFSIZ];
	char tmp[10];

	strcpy(buf, "");
	while(*str) {
		if (*str == ESC) {
			strcat(buf, "<esc> ");
		} else if((*str <= 33) || (*str >= 127)) {
			sprintf(tmp,"\\%o ", *str);
			strcat(buf, tmp);
		} else {
			sprintf(tmp,"%c ", *str);
			strcat(buf, tmp);
		}
		*++str;
	}
	return(buf);
}

usage()
{
	fprintf(stderr, "usage: %s [ -asq ]\n", progname);
}

mktable()
{
	register int i, z;
	FILE *fd, *fopen();
	char file[BUFSIZ];
	char buf[BUFSIZ];
	char lbuf[4][BUFSIZ];
	char *home, *msg, *fixctl();
	int iserr = 0;
	extern char *terms[];
	struct passwd *pwd;

	i = z = 0;
	/*
	 * Copy internal table
	 */
	while(terms[z] != NULL && i < MAXTERMS) {
		(void) strcpy(termtab[i].qt_sendstr, (aflag) ? ALTSEND : SEND);
		(void) strcpy(termtab[i].qt_recvstr, terms[z + T_STR]);
		(void) strcpy(termtab[i].qt_termname, terms[z + T_NAME]);
		(void) strcpy(termtab[i].qt_fullname, terms[z + T_LNAME]);

		z += 3;
		++i;
	}
	tabmark = i;

	/*
	 * Try and read the user's own table
	 */
	if((home = (char *) getenv("HOME")) == NULL) {
		if((pwd = (struct passwd *) getpwuid(getuid())) == NULL) {
			fprintf(stderr, "Who the hell are you????\n");
			exit(1);
		}
		home = pwd->pw_dir;
	}
	dprintf("home = '%s'\n", home);
	sprintf(file, "%s/%s", home, STRFILE);
	dprintf("strfile = '%s'\n", file);
	if(fflag && (fd = fopen(file, "r")) != NULL) {
		while(fgets(buf, sizeof(buf), fd) && i < MAXTERMS) {
			if(buf[0] == '#' || buf[0] == '\n')
				continue;

			lbuf[0][0] = NULL;
			lbuf[1][0] = NULL;
			lbuf[2][0] = NULL;
			lbuf[3][0] = NULL;
	
			(void) sscanf(buf, "%s%s%s\t%[^\n]", 
				lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
			if(lbuf[0][0] == NULL)
				continue;
			if(lbuf[1][0] == NULL) {
				iserr = TRUE;
				msg = "receive string";
			}
			if(lbuf[2][0] == NULL) {
				iserr = TRUE;
				msg = "terminal name";
			}
			if(iserr) {
				fprintf(stderr, "%s: Error parsing %s.\n", file, msg);
				exit(1);
			}
			(void) strcpy(termtab[i].qt_sendstr, fixctl(lbuf[0]));
			(void) strcpy(termtab[i].qt_recvstr, fixctl(lbuf[1]));
			(void) strcpy(termtab[i].qt_termname, lbuf[2]);
			(void) strcpy(termtab[i].qt_fullname, lbuf[3]);

			dprintf("entry %d:\n", i);
			dprintf("qt_sendstr = %s\n", decode(termtab[i].qt_sendstr));
			dprintf("qt_recvstr = %s\n", decode(termtab[i].qt_recvstr));
			dprintf("qt_termname = '%s'\n", termtab[i].qt_termname);
			dprintf("qt_fullname = '%s'\n", termtab[i].qt_fullname);

			++i;
		}
	}
	tabtotal = i;
	dprintf("termtab total  = %d\n", tabtotal);
	dprintf("termtab mark  = %d\n", tabmark);
}

listen(q)
struct qt *q;
{
	register int i;
	register char c;
	char end, begin;

	dprintf("listen startup\n");
	alarm(0);

	dprintf("listen: listening for '%s'\n", decode(q->qt_recvstr));

	if (q->qt_recvstr[0] == NULL) {
		begin = ESC;
		end = 'c';
	} else {
		begin = q->qt_recvstr[0];
		end = q->qt_recvstr[strlen(q->qt_recvstr)-1];
	}

	dprintf("listen: read initial character...\n");
	if(setjmp(env)) {
		dprintf("listen: setjmp TRUE\n");
		if(found)
			done();
		++index;
		(void) fflush(stdin);
		dprintf("listen: dotab()\n");
		dotab();
	} else {
		dprintf("listen: setjmp FALSE...set alarm\n");
		signal(SIGALRM, wakeup);
		alarm(3);
		dprintf("listen: read char\n");
		recvbuf[0] = getch();
		alarm(0);
		dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);

	}
	i = 0;
	if(recvbuf[0] == begin) {
		dprintf("listen begin\n");
		while(c != end) {
			if(setjmp(env))  {
				dprintf("listen: setjmp (2) return\n");
				return;
			} else {
				signal(SIGALRM, wakeup);
				alarm(2);
				dprintf("listen: read (2) char\n");
				c = getch();
				alarm(0);
				dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
			}
			recvbuf[++i] = c;
		}
		if(debug)
			fprintf(stderr,"\n[ Received terminator. ]\n");
	} else {
		dprintf("listen: Not Recognized.  exiting...\n");
		notrecognized();
		putc('\r',stderr);
		(void) nocrmode();
		(void) echo();
		exit(1);
	}
	dprintf("listen done\n");
}

notrecognized()
{
	if(!qflag)
		fprintf(stderr, 
		  "Terminal NOT recognized - defaults to \"dumb\".\n");
	puts("dumb");
}

wakeup()
{
	dprintf("wakeup called\n");
	longjmp(env, 1);
	dprintf("wakeUP: done\n");
}

dotab()
{
	int wakeup();
	int st = FALSE;
	static int firsttime = TRUE;

	dprintf("dotab startup\n");
	dprintf("index = %d\n", index);
	if(index > tabtotal) {
		/*
		 * if we haven't reset things yet, do so.
		 * now try the internal tables if the user's
		 * tables failed.
		 */
		if(!has_set)  {
			tabtotal = tabmark;
			index = 0;
			has_set = 1;
			dprintf("dotab(): has_set now true.\n");
			dotab();
		}
		dprintf("dotab(): index > tabtotal\n");
		finish();
	}
	if(!found || fflag) {
		while(!found && termtab[index].qt_sendstr[0] != NULL && !st) {
			dprintf("dotab: termtab PASS %d\n", index);
			dprintf("dotab: sending str %s\n", 
				decode(termtab[index].qt_sendstr));
			(void) fflush(stdin);
			if(firsttime || strncmp(termtab[index].qt_sendstr, 
			  termtab[index-1].qt_sendstr,
			  strlen(termtab[index].qt_sendstr))) {
				firsttime = FALSE;
				dprintf("dotab(): sendstr's didn't match.\n");
				dprintf("dotab: str1 %s\n", 
					decode(termtab[index].qt_sendstr));
				dprintf("dotab: str2 %s\n", 
					decode(termtab[index-1].qt_sendstr));
				fprintf(stderr, termtab[index].qt_sendstr);
				(void) fflush(stdout);
				(void) fflush(stderr);
				(void) listen(&termtab[index]);
			} else {
				dprintf("dotab(): sendstr's DID match.  No str sent.\n");
				dprintf("dotab: str1 %s\n", 
					decode(termtab[index].qt_sendstr));
				dprintf("dotab: str2 %s\n", 
					decode(termtab[index-1].qt_sendstr));
			}

			firsttime = FALSE;
			dprintf("dotab(): recbuf = '%s'\n", decode(recvbuf));
			dprintf("dotab(): qt_rec = '%s'\n", 
				decode(termtab[index].qt_recvstr));
			st = prinfo(compare(recvbuf, tabmark, tabtotal), !fflag);
			dprintf("st = %d\n", st);
			++index;
		}
		dprintf("dotab(): mark 1\n");
	}
	dprintf("i'm here (2)\n");
	if(!found) {
		dprintf("end of dotab\n");
		dointernal();
		if(!found) {
			dprintf("dotab: dointernal failed.\n");
			notrecognized();
		}
	}
	done();
}

dointernal()
{
	struct qt q;

	dprintf("DOINTERNAL startup.\n");

	(void) fflush(stdin);
	fprintf(stderr, (aflag) ? ALTSEND : SEND);
	(void) fflush(stdout);
	(void) fflush(stderr);

	q.qt_recvstr[0] = NULL;

	(void) listen(&q);

	(void) prinfo(compare(recvbuf, 0, tabmark), 1);
	if(found)
		done();

	dprintf("dointernal end.\n");
}

char *
fixctl(str)
char *str;
{
	register int i;
	char buf[BUFSIZ];

	i = 0;
	while(*str) {
		if(*str == '^')
			buf[i++] = *++str & 037;
		else
			buf[i++] = *str;
		*++str;
	}
	buf[i] = NULL;
	return(buf);
}