home *** CD-ROM | disk | FTP | other *** search
- #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);
- }
-