1: #ifndef lint
   2: static char *RCSid = "$Header: /src/common/usc/bin/qterm/RCS/qterm.c,v 5.4 1991/03/21 02:09:40 mcooper Exp $";
   3: #endif
   4: 
   5: /*
   6:  * Copyright (c) 1990 Michael A. Cooper.
   7:  * This software may be freely distributed provided it is not sold for
   8:  * profit and the author is credited appropriately.
   9:  */
  10: 
  11: /*
  12:  *------------------------------------------------------------------
  13:  *
  14:  * $Source: /src/common/usc/bin/qterm/RCS/qterm.c,v $
  15:  * $Revision: 5.4 $
  16:  * $Date: 1991/03/21 02:09:40 $
  17:  * $State: Exp $
  18:  * $Author: mcooper $
  19:  * $Locker:  $
  20:  *
  21:  *------------------------------------------------------------------
  22:  *
  23:  * Michael A. Cooper
  24:  * Research and Development Group
  25:  * University Computing Services
  26:  * University of Southern California
  27:  * (mcooper@usc.edu)
  28:  *
  29:  *------------------------------------------------------------------
  30:  *
  31:  * $Log: qterm.c,v $
  32:  * Revision 5.4  1991/03/21  02:09:40  mcooper
  33:  * Fix memory buffer problem with some C
  34:  * compilers.  (tp@vtold.vtol.fi)
  35:  *
  36:  * Revision 5.3  1991/03/16  05:36:30  mcooper
  37:  * Fix casting of (char) NULL problem.
  38:  *
  39:  * Revision 5.2  1991/03/12  00:46:24  mcooper
  40:  * Change CMASK to CHAR_CMASK to avoid conflict
  41:  * under AIX 3.1.
  42:  *
  43:  * Revision 5.1  1991/02/20  02:23:33  mcooper
  44:  * Cleanup #ifdef USG5 as part of port
  45:  * to UTS 2.1 (System V.3).
  46:  *
  47:  * Revision 5.0  1990/12/15  18:30:41  mcooper
  48:  * Version 5.
  49:  *
  50:  * Revision 4.13  90/12/15  18:14:23  mcooper
  51:  * Add copywrite.
  52:  *
  53:  * Revision 4.12  90/11/13  16:00:03  mcooper
  54:  * Convert OptInt's to OptBool's where needed.
  55:  *
  56:  * Revision 4.11  90/11/13  15:38:28  mcooper
  57:  * Make OLD_SepArg include both
  58:  * SepArg and StickyArg.
  59:  *
  60:  * Revision 4.10  90/11/08  15:41:08  mcooper
  61:  * Make sure qt_fullname is not 0 length.
  62:  *
  63:  * Revision 4.9  90/11/08  13:02:06  mcooper
  64:  * Fix bug that closes the tty when an error
  65:  * occurs during command line parsing.
  66:  *
  67:  * Revision 4.8  90/11/06  13:19:40  mcooper
  68:  * Changed command line options to new
  69:  * longer names.
  70:  *
  71:  * Revision 4.7  90/11/05  17:09:30  mcooper
  72:  * Update option help messages and option names
  73:  * to be more mnemonic.
  74:  *
  75:  * Revision 4.6  90/11/05  16:44:35  mcooper
  76:  * - Converted to use new ParseOptions() for
  77:  *   command line parsing.
  78:  * - Major de-linting.
  79:  * - Convert dprintf() to use varargs (if
  80:  *   HAS_VARARGS is defined).
  81:  * - Lots of misc. cleanup.
  82:  *
  83:  * Revision 4.5  89/10/20  22:50:49  mcooper
  84:  * Changed code indention to current local
  85:  * standard of 4.  (This should also mess up
  86:  * everybody trying to do diff's from older versions!)
  87:  *
  88:  * Revision 4.4  89/10/20  14:03:48  mcooper
  89:  * Fixed command line parsing of "-f -q".
  90:  *
  91:  * Revision 4.3  88/06/16  19:43:46  mcooper
  92:  * - Added -T flag to wait until timeout when
  93:  *   listening for response string.  This solves
  94:  *   problem when the first entry in a table
  95:  *   doesn't have a response string with a
  96:  *   common ending character to look for.
  97:  * - Added -I flag for "intense" query mode.
  98:  * - Cleaned up debugging a bit.
  99:  *
 100:  * Revision 4.2  88/06/08  15:30:53  mcooper
 101:  * Cleanup pass including removing
 102:  * extraneous debugging messages.
 103:  *
 104:  * Revision 4.1  88/04/25  13:24:38  mcooper
 105:  * Added -S option to print send and recieve
 106:  * strings as they are sent and recieved as
 107:  * suggested by David W. Sanderson
 108:  * (dws@attunix.att.com).
 109:  *
 110:  * Revision 4.0  88/03/08  19:30:59  mcooper
 111:  * Version 4.
 112:  *
 113:  * Revision 3.7  88/03/08  19:28:32  mcooper
 114:  * Major rewrite.
 115:  *
 116:  * Revision 3.6  88/03/08  15:31:35  mcooper
 117:  * General cleanup time.
 118:  *
 119:  * Revision 3.5  88/03/08  13:59:39  mcooper
 120:  * - Catch signals and fix terminal modes.
 121:  * - Don't allow alarm times of 0.
 122:  * - Support for HP-UX machines and cleaner
 123:  *   listen() code from Zenon Fortuna,
 124:  *   HP-UX Support, Hewlett-Packard Vienna.
 125:  *
 126:  * Revision 3.4  87/10/07  15:16:17  mcooper
 127:  * - Beautify code a bit.
 128:  * - Add -w <N> option to set the wait time.
 129:  *
 130:  * Revision 3.3  87/08/24  19:25:32  mcooper
 131:  * The following based on code from Frank Crawford
 132:  * <frank@teti.qhtours.OZ>:
 133:  * - Use $TERM as output string when the terminal
 134:  *   type is not known instead of "dumb".
 135:  * - Regular Expressions are now supported.  RE are
 136:  *   started with a leading `\'.
 137:  * - Octal values may now be used in send/recieve strings.
 138:  *
 139:  * Revision 3.1  87/08/03  15:21:07  mcooper
 140:  * As pointed out by Scott H. Robinson <shr@cetus.ece.cmu.edu>,
 141:  * the -F switch does work.  Problem was that it never read
 142:  * in the ~/.qterm file.
 143:  *
 144:  * Revision 3.0  87/06/30  19:07:59  mcooper
 145:  * Release of version 3.
 146:  *
 147:  * Revision 2.4  87/04/29  19:28:35  mcooper
 148:  * In readtabfile() we now do special
 149:  * things when opening "file" fails
 150:  * depending on the bequiet flag.
 151:  *
 152:  * Revision 2.3  87/04/29  13:11:37  mcooper
 153:  * - No more "internal" table.  The master
 154:  *   table is read from a file (TABFILE).
 155:  *   This makes ~/.qterm stuff much cleaner.
 156:  * - Error handling for qtermtab files is
 157:  *   much more informative now.
 158:  * - More things I can't remember.
 159:  *
 160:  * Revision 2.2  87/03/05  21:01:28  mcooper
 161:  * Fixed system V compiler problem.
 162:  *
 163:  * Revision 2.1  87/03/01  19:43:22  mcooper
 164:  * Be more intelligent about the size of
 165:  * the default terminal table.
 166:  *
 167:  * Revision 2.0  87/03/01  19:20:00  mcooper
 168:  * General cleanup.
 169:  *
 170:  *------------------------------------------------------------------
 171:  */
 172: 
 173: 
 174: /*
 175:  * qterm - Query Terminal
 176:  *
 177:  * qterm is used to query a terminal to determine the name of the terminal.
 178:  * This is done by sending a fairly universal string "\33Z" to the terminal,
 179:  * reading in a response, and comparing it against a master table of responses
 180:  * and names.  The "name" printed to standard output should be one found in
 181:  * the termcap(5) database.
 182:  *
 183:  * Putting a line in your ".login" file such as:
 184:  *
 185:  *	setenv TERM `qterm`
 186:  *
 187:  * or the following lines in your ".profile" file:
 188:  *
 189:  *	TERM=`qterm`
 190:  *	export TERM
 191:  *
 192:  * will set your terminal type automagically.
 193:  *
 194:  * If you add a terminal to the master table, please also send me a copy
 195:  * so that I may put it into my version.
 196:  *
 197:  * Michael Cooper
 198:  * Internet: 	mcooper@usc.edu
 199:  * UUCP: 	...!rutgers!usc!mcooper
 200:  * BITNET:	mcooper@gamera
 201:  */
 202: 
 203: #include <stdio.h>
 204: #include <ctype.h>
 205: #include <pwd.h>
 206: #include <signal.h>
 207: #include <sys/ioctl.h>
 208: #include <setjmp.h>
 209: #ifdef USG5
 210: # include <termio.h>
 211: #else /*USG5*/
 212: # include <sys/file.h>
 213: # include <sgtty.h>
 214: #endif /*USG5*/
 215: #include "qterm.h"
 216: #include "options.h"
 217: #ifdef HAS_VARARGS
 218: #include <varargs.h>
 219: #endif /*HAS_VARARGS*/
 220: 
 221: #ifdef USG5
 222: struct termio _ntty, _otty;
 223: #else
 224: struct sgttyb _tty;
 225: #endif
 226: int _tty_ch = 2;
 227: char recvbuf[SIZE];
 228: char *progname;
 229: char *termfile = NULL;
 230: 
 231: int debug = FALSE;      /* Debug mode */
 232: int use_alt_str = FALSE;    /* Alternate string */
 233: int towait = FALSE;     /* Time out wait flag */
 234: int always_send = FALSE;    /* Intense query mode */
 235: int longname = FALSE;       /* Print long terminal name */
 236: int sent_chars = FALSE;     /* Print strings sent from the terminal */
 237: int watch_chars = FALSE;    /* Watch strings as they are sent and recv. */
 238: int quiet = FALSE;      /* Quiet mode */
 239: int do_usrtabfile = FALSE;  /* Use user's own .qtermtab file */
 240: int do_systabfile = TRUE;   /* Use the system's qterm tab file */
 241: int almwait = WAIT;     /* Wait (timeout) interval */
 242: 
 243: /*
 244:  * Old options should not be visable in help and usage messages.
 245:  */
 246: #ifdef OPT_COMPAT
 247: #define OLD_NoArg   NoArg|ArgHidden
 248: #define OLD_SepArg  SepArg|StickyArg|ArgHidden
 249: #define fFLAG       "-f"
 250: #define FFLAG       "-F"
 251: #endif
 252: 
 253: /*
 254:  * Command line options table.
 255:  */
 256: OptionDescRec opts[] = {
 257: #ifdef OPT_COMPAT
 258:     {"-a",  OLD_NoArg,  OptInt, (caddr_t) &use_alt_str,     "1",
 259:      (char *)NULL,  "Use alternate query string"},
 260:     {"-s",  OLD_NoArg,  OptInt, (caddr_t) &sent_chars,      "1",
 261:      (char *)NULL,  "Display the characters the terminal sent"},
 262:     {"-t", ArgHidden|OLD_NoArg, OptInt, (caddr_t) &sent_chars,      "1",
 263:      (char *)NULL,  "Display the characters the terminal sent"},
 264:     {"-I",  OLD_NoArg,  OptInt, (caddr_t) &always_send,     "1",
 265:      (char *)NULL,  "Always send the terminal query string"},
 266:     {"-T",  OLD_NoArg,  OptInt, (caddr_t) &towait,      "1",
 267:      (char *)NULL,  "Enable time out wait"},
 268:     {"-S",  OLD_NoArg,  OptInt, (caddr_t) &watch_chars,     "1",
 269:      (char *)NULL,  "Print strings as they are sent and received"},
 270:     {"-q",  OLD_NoArg,  OptInt, (caddr_t) &quiet,       "1",
 271:      (char *)NULL,  "Enable quite mode"},
 272:     {"-f",  OLD_SepArg, OptStr, (caddr_t) &termfile,  fFLAG,
 273:      "<tabfile>",  "Try <tabfile>, then ~/.qtermtab, then system tabfile"},
 274:     {"-F",  OLD_SepArg, OptStr, (caddr_t) &termfile,  FFLAG,
 275:      "<tabfile>",   "Try <tabfile>, then ~/.qtermtab"},
 276:     {"-l",  OLD_NoArg,  OptInt, (caddr_t) &longname,        "1",
 277:      (char *)NULL,  "Output only the long (verbose) terminal name"},
 278:     {"-d",  OLD_NoArg,  OptInt, (caddr_t) &debug,       "1",
 279:      (char *)NULL,  "Enable debug mode"},
 280:     {"-w",  OLD_SepArg, OptInt, (caddr_t) &almwait,     __ NULL,
 281:      "<interval>",  "Wait (timeout) period (in seconds)"},
 282: #endif /*OPT_COMPAT*/
 283:     {"+alt",    NoArg,      OptBool, (caddr_t) &use_alt_str,    "1",
 284:      (char *)NULL,  "Use alternate query string"},
 285:     {"-alt",    NoArg,      OptBool, (caddr_t) &use_alt_str,    "0",
 286:      (char *)NULL,  "Don't use alternate query string"},
 287:     {"+always", NoArg,      OptBool, (caddr_t) &always_send,    "1",
 288:      (char *)NULL,  "Always send the terminal query string"},
 289:     {"-always", NoArg,      OptBool, (caddr_t) &always_send,    "0",
 290:      (char *)NULL,  "Don't always send the terminal query string"},
 291:     {"-file",   SepArg,     OptStr, (caddr_t) &termfile,        __ NULL,
 292:      "<tabfile>",   "Use <tabfile> to query terminal"},
 293:     {"+longname",NoArg,     OptBool, (caddr_t) &longname,       "1",
 294:      (char *)NULL,  "Output only the long (verbose) terminal name"},
 295:     {"-longname",NoArg,     OptBool, (caddr_t) &longname,       "0",
 296:      (char *)NULL,  "Don't output the long (verbose) terminal name"},
 297:     {"+quiet",  NoArg,      OptBool, (caddr_t) &quiet,      "1",
 298:      (char *)NULL,  "Enable quiet mode"},
 299:     {"-quiet",  NoArg,      OptBool, (caddr_t) &quiet,      "0",
 300:      (char *)NULL,  "Disable quiet mode"},
 301:     {"+sent",   NoArg,      OptBool, (caddr_t) &sent_chars,     "1",
 302:      (char *)NULL,  "Display the characters the terminal sent"},
 303:     {"-sent",   NoArg,      OptBool, (caddr_t) &sent_chars,     "0",
 304:      (char *)NULL,  "Don't display the characters the terminal sent"},
 305:     {"+timeout",NoArg,      OptBool, (caddr_t) &towait,     "1",
 306:      (char *)NULL,  "Enable time out wait"},
 307:     {"-timeout",NoArg,      OptBool, (caddr_t) &towait,     "0",
 308:      (char *)NULL,  "Disable time out wait"},
 309:     {"+usrtab", NoArg,      OptBool, (caddr_t) &do_usrtabfile,  "1",
 310:      (char *)NULL,  "Enable using ~/.qtermtab"},
 311:     {"-usrtab", NoArg,      OptBool, (caddr_t) &do_usrtabfile,  "0",
 312:      (char *)NULL,  "Disable using ~/.qtermtab"},
 313:     {"-wait",   SepArg,     OptInt, (caddr_t) &almwait,     __ NULL,
 314:      "<interval>",  "Wait (timeout) period (in seconds)"},
 315:     {"+watch",  NoArg,      OptBool, (caddr_t) &watch_chars,    "1",
 316:      (char *)NULL,  "Watch the characters sent and recieved"},
 317:     {"-watch",  NoArg,      OptBool, (caddr_t) &watch_chars,    "0",
 318:      (char *)NULL,  "Don't watch the characters sent and recieved"},
 319:     {"+systab", NoArg,      OptBool, (caddr_t) &do_usrtabfile,  "1",
 320:      (char *)NULL,  "Enable using system qtermtab file"},
 321:     {"-systab", NoArg,      OptBool, (caddr_t) &do_systabfile,  "0",
 322:      (char *)NULL,  "Disable using system qtermtab file"},
 323:     {"-debug", ArgHidden|NoArg, OptInt, (caddr_t) &debug,       "1",
 324:      (char *)NULL,  "Enable debug mode"},
 325: };
 326: 
 327: FILE *fopen();
 328: char *decode();
 329: char *getenv();
 330: char *malloc();
 331: char *re_comp();
 332: char *strcat();
 333: char *xmalloc();
 334: int alarm();
 335: int found = FALSE;
 336: int modes_set = FALSE;
 337: jmp_buf env;
 338: struct termtable *compare();
 339: struct passwd *getpwuid();
 340: void catch();
 341: void done();
 342: void dprintf();
 343: void exit();
 344: void myperror();
 345: void mktable();
 346: void notrecognized();
 347: void proctab();
 348: void wakeup();
 349: #ifdef USG5
 350: char *regcmp();
 351: #endif /* USG5 */
 352: 
 353: main(argc, argv)
 354:      int argc;
 355:      char **argv;
 356: {
 357:     config(argc, argv);
 358:     setmodes();
 359:     mktable();
 360:     proctab((struct termtable *)NULL);
 361:     resetmodes();
 362: 
 363:     if (!found) {
 364:     notrecognized();
 365:     }
 366: 
 367:     exit(0);
 368: }
 369: 
 370: /*
 371:  * Config() - Perform configuration operations.
 372:  */
 373: config(argc, argv)
 374:      int argc;
 375:      char **argv;
 376: {
 377:     progname = argv[0];
 378: 
 379:     /*
 380:      * Parse command line args
 381:      */
 382:     if (ParseOptions(opts, Num_Opts(opts), argc, argv) < 0) {
 383:     done(1);
 384:     /*NOTREACHED*/
 385:     }
 386: 
 387:     /*
 388:      * Check results of command line parsing and perform any
 389:      * needed post processing.
 390:      */
 391: 
 392:     if (longname)
 393:     quiet = TRUE;
 394: 
 395:     if (almwait == 0) {
 396:     (void) fprintf(stderr,
 397:               "%s: Alarm (wait) time must be greater than 0.\n",
 398:                progname);
 399:     done(1);
 400:     /*NOTREACHED*/
 401:     }
 402: 
 403: #ifdef OPT_COMPAT
 404:     /*
 405:      * Kludgy stuff to be backwards compatable for command line options.
 406:      */
 407:     if (termfile) {
 408:     if (strcmp(termfile, fFLAG) == 0) {
 409:         do_usrtabfile = TRUE;
 410:         do_systabfile = TRUE;
 411:         termfile = NULL;
 412:     } else if (strcmp(termfile, FFLAG) == 0) {
 413:         do_usrtabfile = TRUE;
 414:         do_systabfile = FALSE;
 415:         termfile = NULL;
 416:     }
 417:     }
 418: #endif /*OPT_COMPAT*/
 419: 
 420:     dprintf("[ %s debug mode enabled ]\n\n", progname);
 421: }
 422: 
 423: /*
 424:  * Set signal catches and terminal modes
 425:  */
 426: setmodes()
 427: {
 428:     if (!isatty(0)) {
 429:     (void) fprintf(stderr, "%s: Not a tty.\n", progname);
 430:     done(0);
 431:     /*NOTREACHED*/
 432:     }
 433: 
 434:     /*
 435:      * Set output buffers
 436:      */
 437:     setbuf(stdout, (char *)0);
 438:     if (debug)
 439:     setbuf(stderr, (char *)0);
 440: 
 441:     /*
 442:      * Cleanup terminal modes & such if we are killed
 443:      */
 444:     (void) signal(SIGINT, catch);
 445:     (void) signal(SIGHUP, catch);
 446:     (void) signal(SIGTERM, catch);
 447: 
 448:     /*
 449:      * Set terminal modes
 450:      */
 451: #ifdef USG5
 452:     if (ioctl(_tty_ch, TCGETA, &_otty) < 0)
 453: #else
 454:     if (ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
 455: #endif /* USG5 */
 456:     {
 457:     myperror("gtty");
 458:     done(1);
 459:     /*NOTREACHED*/
 460:     }
 461: #ifdef USG5
 462:     _ntty = _otty;
 463: #endif /* USG5 */
 464: 
 465:     if (crmode() < 0) {
 466:     myperror("crmode");
 467:     done(1);
 468:     /*NOTREACHED*/
 469:     }
 470: 
 471:     if (noecho() < 0) {
 472:     myperror("noecho");
 473:     done(1);
 474:     /*NOTREACHED*/
 475:     }
 476:     modes_set = TRUE;
 477: }
 478: 
 479: /*
 480:  * Reset terminal modes
 481:  */
 482: resetmodes()
 483: {
 484:     if (modes_set) {
 485:     (void) nocrmode();
 486:     (void) echo();
 487:     }
 488: }
 489: 
 490: /*
 491:  * Print info about terminal structure t.
 492:  */
 493: prinfo(t, what)
 494:      struct termtable *t;
 495:      int what;
 496: {
 497:     int len = 0;
 498:     int st = FALSE;
 499: 
 500:     if (t && t->qt_termname && (recvbuf[0] != (char) NULL)) {
 501:     if (debug || sent_chars) {
 502:         len = strlen(recvbuf);
 503:         (void) fprintf(stderr, "%s received %d character%s:",
 504:                progname, len, (len == 1) ? "" : "s");
 505:         (void) fprintf(stderr, " %s\n", decode(recvbuf));
 506:     }
 507: 
 508:     if (!quiet) {
 509:         (void) fprintf(stderr, "Terminal recognized as %s",
 510:                t->qt_termname);
 511:         if (t->qt_fullname && t->qt_fullname[0])
 512:         (void) fprintf(stderr, " (%s)\n", t->qt_fullname);
 513:         else
 514:         (void) fprintf(stderr, "\n");
 515:     }
 516: 
 517:     if (longname) {
 518:         if (t->qt_fullname && t->qt_fullname[0])
 519:         (void) printf("%s\n", t->qt_fullname);
 520:         else
 521:         (void) fprintf(stderr, "%s: No full terminal name for %s.\n",
 522:                    progname, t->qt_termname);
 523:     } else {
 524:         (void) printf("%s\n", t->qt_termname);
 525:     }
 526: 
 527:     found = TRUE;
 528:     done(0);
 529:     /*NOTREACHED*/
 530:     } else {
 531:     found = FALSE;
 532: 
 533:     if (what) {
 534:         notrecognized();
 535:         done(1);
 536:         /*NOTREACHED*/
 537:     }
 538:     }
 539: 
 540:     return(st);
 541: }
 542: 
 543: /*
 544:  * compare - actually compare what we received against the table.
 545:  */
 546: struct termtable *compare(str)
 547:      char *str;
 548: {
 549: #ifdef USG5
 550:     register char *reexp;
 551: #endif /* USG5 */
 552:     register struct termtable *t;
 553:     char buf[BUFSIZ];
 554: 
 555:     dprintf("compare %s\n", (str && str[0]) ? decode(str) : "nothing");
 556:     (void) alarm((unsigned)0);
 557: 
 558:     if (strlen(str) == 0)
 559:     return(NULL);
 560: 
 561:     for (t = termtab; t != NULL; t = t->nxt) {
 562:     dprintf("  with %s ", decode(t->qt_recvstr));
 563:     (void) sprintf(buf, "^%s$", t->qt_recvstr);
 564: 
 565: #ifdef USG5
 566:     if ((reexp = regcmp(buf, NULL)) == NULL) {
 567: #else
 568:     if (re_comp((char *)buf) != NULL) {
 569: #endif /* USG5 */
 570:         (void) fprintf(stderr, "%s: bad regular expression: \"%s\"\n",
 571:                progname, t->qt_recvstr);
 572:         done(1);
 573:         /*NOTREACHED*/
 574:     }
 575: 
 576: #ifdef USG5
 577:     if (regex(reexp, str) != NULL) {
 578: #else
 579:     if (re_exec(str) == 1) {
 580: #endif /* USG5 */
 581:         found = TRUE;
 582:         dprintf("\tOK\n");
 583:         return(t);
 584:     }
 585: 
 586:     dprintf("\tNOPE\n");
 587: #ifdef USG5
 588:     (void) free(reexp);
 589: #endif /* USG5 */
 590:     }
 591:     found = FALSE;
 592: 
 593:     return(NULL);
 594: }
 595: 
 596: /*
 597:  * getch - read in a character at a time.
 598:  */
 599: getch()
 600: {
 601:     char c;
 602: 
 603:     (void) read(0, &c, 1);
 604: 
 605:     return(c & CHAR_MASK);
 606: }
 607: 
 608: /*
 609:  * decode - print str in a readable fashion
 610:  */
 611: char *decode(str)
 612:      char *str;
 613: {
 614:     register int len;
 615:     static char buf[BUFSIZ];
 616:     char tmp[10];
 617: 
 618:     if (!str)
 619:       return("(null)");
 620: 
 621:     (void) strcpy(buf, "");
 622:     while (*str) {
 623:     if (*str == ESC) {
 624:         (void) strcat(buf, "<esc> ");
 625:     } else if ((*str <= 33) || (*str >= 127)) {
 626:         (void) sprintf(tmp,"\\%#o ", (unsigned) *str);
 627:         (void) strcat(buf, tmp);
 628:     } else {
 629:         (void) sprintf(tmp,"%c ", *str);
 630:         (void) strcat(buf, tmp);
 631:     }
 632:     ++str;
 633:     }
 634: 
 635:     len = strlen(buf);
 636:     if (len && buf[len - 1] == ' ') {
 637:     buf[len - 1] = (char) NULL;
 638:     }
 639: 
 640:     return(buf);
 641: }
 642: 
 643: /*
 644:  * Make a termtab table
 645:  */
 646: void mktable()
 647: {
 648:     char file[BUFSIZ];
 649:     struct passwd *pwd;
 650:     char *home;
 651: 
 652:     dprintf("[ initilizing term table... ]\n");
 653: 
 654:     if (termfile != NULL) {
 655:     (void) readtabfile(termfile, FALSE);
 656:     }
 657: 
 658:     if (do_usrtabfile) {
 659:     /*
 660: 	 * Try to read the user's own table
 661: 	 */
 662:     if ((home = getenv("HOME")) == NULL) {
 663:         if ((pwd = getpwuid(getuid())) == NULL) {
 664:         (void) fprintf(stderr,
 665:                    "%s: Cannot find user info for uid %d.\n",
 666:                    progname, getuid());
 667:         done(1);
 668:         /*NOTREACHED*/
 669:         }
 670:         home = pwd->pw_dir;
 671:     }
 672: 
 673:     (void) sprintf(file, "%s/%s", home, USRFILE);
 674:     if (readtabfile(file, TRUE) < 0) {
 675:         (void) sprintf(file, "%s/%s", home, OLDUSRFILE);
 676:         (void) readtabfile(file, TRUE);
 677:     }
 678:     }
 679: 
 680:     if (do_systabfile)
 681:     (void) readtabfile(TABFILE, FALSE);
 682: 
 683:     dprintf("[ mktable done ]\n");
 684: }
 685: 
 686: int readtabfile(file, bequiet)
 687:      char *file;
 688:      int bequiet;
 689: {
 690:     static int line = 0;
 691:     char lbuf[4][BUFSIZ];
 692:     char buf[BUFSIZ];
 693:     FILE *fd;
 694:     char *p, *fixctl();
 695:     char *errmsg = NULL;
 696:     struct termtable *t;
 697: 
 698:     if ((fd = fopen(file, "r")) == NULL) {
 699:     if (bequiet) {
 700:         dprintf("[ tab file '%s' can not read ]\n", file);
 701:         return(-1);
 702:     }
 703:     myperror(file);
 704:     done(1);
 705:     /*NOTREACHED*/
 706:     }
 707: 
 708:     dprintf("[ Read tab file '%s' ]\n", file);
 709: 
 710:     line = 0;
 711:     while (fgets(buf, sizeof(buf), fd)) {
 712:     ++line;
 713: 
 714:     if (buf[0] == '#' || buf[0] == '\n')
 715:         continue;
 716: 
 717:     lbuf[0][0] = lbuf[1][0] = lbuf[2][0] = lbuf[3][0] = (char) NULL;
 718: 
 719:     (void) sscanf(buf, "%s%s%s\t%[^\n]",
 720:               lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
 721: 
 722:     if (lbuf[0][0] == (char) NULL)
 723:         continue;
 724: 
 725:     if (lbuf[1][0] == (char) NULL)
 726:         errmsg = "receive string";
 727: 
 728:     if (lbuf[2][0] == (char) NULL)
 729:         errmsg = "terminal name";
 730: 
 731:     if (errmsg) {
 732:         (void) fprintf(stderr, "%s: Line %d of %s: Error parsing %s.\n",
 733:                progname, line, file, errmsg);
 734:         done(1);
 735:         /*NOTREACHED*/
 736:     }
 737: 
 738:     t = (struct termtable *) xmalloc(sizeof(struct termtable));
 739: 
 740:     if (use_alt_str)
 741:         p = fixctl(ALTSEND, 0);
 742:     else
 743:         p = fixctl(lbuf[0], 0);
 744: 
 745:     t->qt_sendstr = (char *) xmalloc(strlen(p)+1);
 746:     (void) strcpy(t->qt_sendstr, p);
 747: 
 748:     p = fixctl(lbuf[1], 1);
 749:     t->qt_recvstr = (char *) xmalloc(strlen(p)+1);
 750:     (void) strcpy(t->qt_recvstr, p);
 751: 
 752:     t->qt_termname = (char *) xmalloc(strlen(lbuf[2])+1);
 753:     (void) strcpy(t->qt_termname, lbuf[2]);
 754: 
 755:     t->qt_fullname = (char *) xmalloc(strlen(lbuf[3])+1);
 756:     (void) strcpy(t->qt_fullname, lbuf[3]);
 757: 
 758:     dprintf("\n  Send String = %s\n", decode(t->qt_sendstr));
 759:     dprintf("Expect String = %s\n", decode(t->qt_recvstr));
 760:     dprintf("     Terminal = '%s'\n", t->qt_termname);
 761:     dprintf("    Full Name = '%s'\n", t->qt_fullname);
 762: 
 763:     (void) addterm(t);
 764:     }
 765: 
 766:     return(0);
 767: }
 768: 
 769: /*
 770:  * Add termtab (n) entry to main termtab.
 771:  */
 772: int addterm(n)
 773:      struct termtable *n;
 774: {
 775:     register struct termtable *t;
 776: 
 777:     if (!n)
 778:       return(-1);
 779: 
 780:     n->nxt = NULL;
 781: 
 782:     if (termtab == NULL) {
 783:     termtab = n;
 784:     } else {
 785:     t = termtab;
 786:     while(t && t->nxt)
 787:       t = t->nxt;
 788:     t->nxt = n;
 789:     }
 790: 
 791:     return(0);
 792: }
 793: 
 794: /*
 795:  * Listen for a response.
 796:  */
 797: void qterm_listen(q)
 798:      struct termtable *q;
 799: {
 800:     static int i, len;
 801:     register char c;
 802:     char end;
 803: 
 804:     (void) alarm((unsigned)0);
 805:     (void) strcpy(recvbuf, "");
 806:     i = 0;
 807: 
 808:     len = strlen(q->qt_recvstr);
 809: 
 810:     if (len) {
 811:     end = q->qt_recvstr[len - 1];
 812:     } else {
 813:     end = 'c'; /* Fairly standard ANSI default */
 814:     }
 815: 
 816:     dprintf("\nlisten for %s\t [ len = %d, end = `%c' ]\n",
 817:         decode(q->qt_recvstr), len, end);
 818: 
 819:     /*
 820:      * If we don't get an initial character, bounce out
 821:      * of here and finish with done(0).
 822:      */
 823:     if (setjmp(env)) {
 824:     if (found) {
 825:         done(0);
 826:         /*NOTREACHED*/
 827:     }
 828:     (void) fflush(stdin);
 829:     proctab(q->nxt);
 830:     } else {
 831:     (void) signal(SIGALRM, wakeup);
 832:     (void) alarm((unsigned)almwait);
 833:     recvbuf[0] = getch();
 834:     (void) alarm((unsigned)0);
 835:     }
 836: 
 837:     /*
 838:      * Read in remaining response.  Loop until ending character
 839:      * is received or until alarm goes off.  If towait is set,
 840:      * then let alarm go off.
 841:      */
 842:     for (i = 1, c = -1; (!towait && (c != end)) || towait; ) {
 843:     if (setjmp(env))  {
 844:         recvbuf[i] = (char) NULL;
 845:         return;
 846:     } else {
 847:         (void) signal(SIGALRM, wakeup);
 848:         (void) alarm((unsigned)almwait);
 849:         c = getch();
 850:         (void) alarm((unsigned)0);
 851:     }
 852:     recvbuf[i++] = c;
 853:     }
 854:     recvbuf[i] = (char) NULL;
 855: 
 856:     dprintf("listen done.  read %d chars.\n\n", i);
 857: }
 858: 
 859: /*
 860:  * Print a message since we didn't recognize this terminal.
 861:  */
 862: void notrecognized()
 863: {
 864:     char *envterm;
 865: 
 866:     if ((envterm = getenv("TERM")) == NULL)
 867:     envterm = "dumb";
 868: 
 869:     if (!quiet)
 870:     (void) fprintf(stderr,
 871:                "Terminal NOT recognized - defaults to \"%s\".\n",
 872:                envterm);
 873: 
 874:     puts(envterm);
 875: }
 876: 
 877: /*
 878:  * Process entries in the termtable.
 879:  */
 880: void proctab(t)
 881:      struct termtable *t;
 882: {
 883:     int st = FALSE;
 884:     static int firsttime = TRUE;
 885:     static struct termtable *lastt;
 886: 
 887:     dprintf("\n[ Processing entries ] \n");
 888: 
 889:     if (firsttime) {
 890:     t = termtab;
 891:     lastt = NULL;
 892:     }
 893: 
 894:     while ((!found || do_usrtabfile) && t && t->qt_sendstr && !st) {
 895:     /*
 896: 	 * If this is our first time or the sendstr is the same as
 897: 	 * last time, don't send it again.
 898: 	 */
 899:     if (always_send || firsttime || lastt == NULL ||
 900:         strcmp(t->qt_sendstr, lastt->qt_sendstr) != 0) {
 901: 
 902:         if (firsttime)
 903:         firsttime = FALSE;
 904: 
 905:         if (watch_chars)
 906:         (void) printf("Send: %s\n", decode(t->qt_sendstr));
 907: 
 908:         (void) fflush(stdin);
 909:         (void) fprintf(stderr, "%s", t->qt_sendstr);
 910:         (void) fflush(stderr);
 911: 
 912:         lastt = t;
 913:         (void) qterm_listen(t);
 914: 
 915:         if (watch_chars)
 916:         (void) printf("\tRead: %s\n", decode(recvbuf));
 917:     }
 918: 
 919:     st = prinfo(compare(recvbuf), FALSE);
 920: 
 921:     lastt = t;
 922:     t = t->nxt;
 923:     }
 924: 
 925:     if (!found)
 926:     notrecognized();
 927: 
 928:     done(0);
 929:     /*NOTREACHED*/
 930: }
 931: 
 932: char *fixctl(str, rex)
 933:      char *str;
 934:      int rex;
 935: {
 936:     register int i;
 937:     static char buf[BUFSIZ];
 938: 
 939:     for (i = 0; str && *str; ) {
 940:     switch (*str) {
 941: 
 942:       case '\\':
 943:         if (isdigit(*++str)) {
 944:         buf[i] = 0;
 945:         while (isdigit(*str))
 946:             buf[i] = (char) (((int)buf[i] * 8) +
 947:                      (int)*str++ - (int) '0');
 948:         i++;
 949:         } else
 950:         buf[i++] = *str++;
 951:         continue;
 952: 
 953:       case '^':
 954:         switch (*++str) {
 955:           case '?':
 956:         buf[i++] = '\177';
 957:         break;
 958:           default:
 959:         buf[i++] = *str & 037;
 960:         break;
 961:         }
 962:         break;
 963: 
 964:         /* Special R.E. symbols */
 965:       case '[':
 966:       case '*':
 967:       case '.':
 968:       case '$':
 969:       case '{':
 970:       case '(':
 971:         if (rex)
 972:           buf[i++] = '\\';
 973: 
 974:       default:
 975:         buf[i++] = *str;
 976:     }
 977:     *++str;
 978:     }
 979: 
 980:     buf[i] = (char) NULL;
 981: 
 982:     return(buf);
 983: }
 984: 
 985: /*
 986:  * xmalloc - Do a malloc with error checking.
 987:  */
 988: char *xmalloc(size)
 989:      int size;
 990: {
 991:     char *p;
 992: 
 993:     if ((p = malloc((unsigned) size)) == NULL) {
 994:     myperror("malloc");
 995:     done(1);
 996:     /*NOTREACHED*/
 997:     }
 998: 
 999:     return(p);
1000: }
1001: 
1002: #ifdef HAS_VARARGS
1003: void dprintf(va_alist)
1004:      va_dcl
1005: {
1006:     va_list args;
1007:     char *fmt;
1008: 
1009:     if (!debug)
1010:     return;
1011: 
1012:     va_start(args);
1013:     fmt = (char *) va_arg(args, char *);
1014:     (void) vprintf(fmt, args);
1015:     va_end(args());
1016:     (void) fflush(stdout);
1017: }
1018: 
1019: #else /*HAS_VARARGS*/
1020: 
1021: void dprintf(fmt, a1, a2, a3, a4, a5, a6)
1022:      char *fmt;
1023: {
1024:     if (!debug)
1025:     return;
1026: 
1027:     (void) printf(fmt, a1, a2, a3, a4, a5, a6);
1028:     (void) fflush(stdout);
1029: }
1030: #endif /*HAS_VARARGS*/
1031: 
1032: /*
1033:  * Catch kill signals and cleanup.
1034:  */
1035: void catch()
1036: {
1037:     done(2);
1038:     /*NOTREACHED*/
1039: }
1040: 
1041: void wakeup()
1042: {
1043:     dprintf("wakeup called\n");
1044:     longjmp(env, 1);
1045: }
1046: 
1047: void myperror(msg)
1048:      char *msg;
1049: {
1050:     (void) fprintf(stderr, "%s: ", progname);
1051:     perror(msg);
1052: }
1053: 
1054: /*
1055:  * Reset terminal and exit with status s.
1056:  */
1057: void done(s)
1058:      int s;
1059: {
1060:     resetmodes();
1061:     exit(s);
1062: }

Defined functions

addterm defined in line 772; used 1 times
catch defined in line 1035; used 4 times
compare defined in line 546; used 2 times
config defined in line 373; used 1 times
decode defined in line 611; used 9 times
done defined in line 1057; used 17 times
dprintf defined in line 1021; used 18 times
fixctl defined in line 932; used 4 times
getch defined in line 599; used 2 times
main defined in line 353; never used
mktable defined in line 646; used 2 times
myperror defined in line 1047; used 6 times
notrecognized defined in line 862; used 4 times
prinfo defined in line 493; used 1 times
proctab defined in line 880; used 3 times
qterm_listen defined in line 797; used 1 times
readtabfile defined in line 686; used 4 times
resetmodes defined in line 482; used 2 times
setmodes defined in line 426; used 1 times
wakeup defined in line 1041; used 3 times
xmalloc defined in line 988; used 6 times

Defined variables

RCSid defined in line 2; never used
_ntty defined in line 222; used 1 times
_otty defined in line 222; used 2 times
_tty defined in line 224; used 1 times
_tty_ch defined in line 226; used 2 times
almwait defined in line 241; used 5 times
always_send defined in line 234; used 4 times
debug defined in line 231; used 6 times
do_systabfile defined in line 240; used 4 times
do_usrtabfile defined in line 239; used 7 times
env defined in line 337; used 3 times
found defined in line 335; used 8 times
longname defined in line 235; used 5 times
modes_set defined in line 336; used 2 times
progname defined in line 228; used 10 times
quiet defined in line 238; used 6 times
recvbuf defined in line 227; used 10 times
sent_chars defined in line 236; used 5 times
termfile defined in line 229; used 10 times
towait defined in line 233; used 5 times
use_alt_str defined in line 232; used 4 times
watch_chars defined in line 237; used 5 times

Defined macros

FFLAG defined in line 250; used 2 times
OLD_NoArg defined in line 247; used 9 times
OLD_SepArg defined in line 248; used 3 times
fFLAG defined in line 249; used 2 times
Last modified: 1995-11-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 7423
Valid CSS Valid XHTML 1.0 Strict