home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / qterm / qterm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-03-02  |  15.9 KB  |  742 lines

  1. #ifndef lint
  2. static char *RCSid = "$Header: qterm.c,v 1.23 87/01/09 13:55:44 mcooper Locked $";
  3. #endif
  4.  
  5. /*
  6.  *------------------------------------------------------------------
  7.  *
  8.  * $Source: /big/src/usc/bin/qterm/RCS/qterm.c,v $
  9.  * $Revision: 1.23 $
  10.  * $Date: 87/01/09 13:55:44 $
  11.  * $State: Exp $
  12.  * $Author: mcooper $
  13.  * $Locker: mcooper $
  14.  *
  15.  *------------------------------------------------------------------
  16.  *
  17.  * Michael A. Cooper
  18.  * University Computing Services, 
  19.  * University of Southern California
  20.  * (mcooper@usc-oberon.arpa)
  21.  *
  22.  *------------------------------------------------------------------
  23.  * $Log:    qterm.c,v $
  24.  * Revision 1.23  87/01/09  13:55:44  mcooper
  25.  * Fixed bug with -s option that caused "ers:" 
  26.  * to be printed instead of the string
  27.  * received from the terminal.
  28.  * 
  29.  * Revision 1.22  86/12/11  15:57:16  mcooper
  30.  * Should now work under System V thanks to Brian L. Matthews
  31.  * (cxsea!blm).
  32.  * 
  33.  * Revision 1.21  86/10/13  12:52:54  mcooper
  34.  * Fixed bug that caused problems with
  35.  * send strings not being sent from .qterm
  36.  * files.
  37.  * 
  38.  * Revision 1.20  86/08/25  15:45:58  mcooper
  39.  * BUG FIX: When the -f flag was specified and the user's
  40.  *          tables did not produce the terminal's entry,
  41.  *          the internal terminal tables where not tried
  42.  *          as documented.
  43.  * 
  44.  * Revision 1.19  86/08/12  15:31:22  mcooper
  45.  * Fixed bug that caused terminals to wedge due
  46.  * to qterm failing to match receive strings
  47.  * from the .qterm file.
  48.  * 
  49.  * Revision 1.18  86/08/11  13:49:42  mcooper
  50.  * Fixed bug that caused qterm to wedge.  Problem
  51.  * due to alarms not being set correctly.
  52.  * 
  53.  * Revision 1.17  86/08/08  14:40:09  mcooper
  54.  * - Only send/listen for strings if the previously sent string
  55.  *   is not the same as the current string.
  56.  * - Fixed -s option.
  57.  * 
  58.  * Revision 1.16  86/08/08  13:16:05  mcooper
  59.  * Major re-write: Added ~/.qterm file that contains
  60.  * the users own copy of terminal tables.
  61.  * 
  62.  * Revision 1.15  86/07/21  12:35:54  mcooper
  63.  * Now works under System V (Define USG5).
  64.  * 
  65.  * Revision 1.14  86/07/01  22:57:45  mcooper
  66.  * Moved terminal table to seperate
  67.  * file (table.c).
  68.  * 
  69.  * Revision 1.13  86/06/30  11:17:53  mcooper
  70.  * More terminals to main table...
  71.  * 
  72.  * Revision 1.12  86/06/19  13:57:51  mcooper
  73.  * Added responses for concept from a Pro running
  74.  * 2.9bsd.
  75.  * 
  76.  * Revision 1.11  86/06/18  15:58:45  mcooper
  77.  * Cleanup for release.
  78.  * 
  79.  * Revision 1.10  86/06/17  23:06:55  mcooper
  80.  * Added Unix PC responses.
  81.  * 
  82.  * Revision 1.9  86/06/16  14:19:09  mcooper
  83.  * Added vt100 responses from vt100 manual.
  84.  * 
  85.  * Revision 1.8  86/06/16  13:23:40  mcooper
  86.  * Print additional information about
  87.  * what the actual terminal is.
  88.  * 
  89.  * Revision 1.7  86/06/12  10:59:27  mcooper
  90.  * *** empty log message ***
  91.  * 
  92.  * Revision 1.6  86/06/11  19:48:35  mcooper
  93.  * Added alternate string and table entries for concepts.
  94.  * 
  95.  * Revision 1.5  86/05/19  12:30:32  mcooper
  96.  * General clean up.
  97.  * 
  98.  * Revision 1.4  86/05/18  17:56:11  mcooper
  99.  * Added another vt100.  This one is for when you rlogin
  100.  * from a Pro 2.9bsd host on a HDS Concept.
  101.  * 
  102.  * Revision 1.3  86/05/08  09:24:13  mcooper
  103.  * Added another vt100 description.
  104.  * 
  105.  * Revision 1.2  86/05/06  18:23:35  mcooper
  106.  * More cleanup - de-linted (almost).
  107.  * 
  108.  * Revision 1.1  86/05/06  14:56:57  mcooper
  109.  * Initial revision
  110.  * 
  111.  *------------------------------------------------------------------
  112.  */
  113.  
  114. /*
  115.  * [Edit with tabstop=4]
  116.  *
  117.  * qterm - Query Terminal
  118.  *
  119.  * qterm is used to query a terminal to determine the name of the terminal.
  120.  * This is done by sending a fairly universal string "\33Z" to the terminal,
  121.  * reading in a response, and comparing it against a master table of responses
  122.  * and names.  The "name" printed to standard output should be one found in
  123.  * the termcap(5) database.
  124.  *
  125.  * Putting a line in your ".login" file such as:
  126.  *
  127.  *    setenv TERM `qterm`
  128.  *
  129.  * or the following lines in your ".profile" file:
  130.  *
  131.  *    TERM=`qterm`
  132.  *    export TERM
  133.  *
  134.  * will set your terminal type automagically.
  135.  * 
  136.  * If you add a terminal to the master table, please also send me a copy
  137.  * so that I may put it into my version.
  138.  *
  139.  * Michael Cooper
  140.  * ARPA:     mcooper@usc-oberon.ARPA
  141.  * UUCP:     mcooper@usc-oberon.UUCP
  142.  * BITNET:    mcooper@uscvaxq
  143.  */
  144.  
  145. #include <stdio.h>
  146. #include <pwd.h>
  147. #include <signal.h>
  148. #include <sys/ioctl.h>
  149. #include <setjmp.h>
  150. #ifdef USG5
  151. # include <termio.h>
  152. #else
  153. # include <sys/file.h>
  154. # include <sgtty.h>
  155. #endif
  156.  
  157. #define SEND        "\033Z"        /* send this to query terminal */
  158. #define ALTSEND        "\033[c"    /* alternate string */
  159.  
  160. #define STRFILE        ".qterm"    /* file containing terminal strings */
  161.  
  162. #define dprintf        if(debug)printf
  163. #define MAXTERMS    100
  164.  
  165. #define TRUE        1
  166. #define FALSE        0
  167.  
  168. #define T_STR        0
  169. #define T_NAME        1
  170. #define T_LNAME        2
  171.  
  172. int tabmark = 0;
  173. int tabtotal = 0;
  174. int has_set = 0;
  175.  
  176.  
  177. #define BUF            666
  178.  
  179. struct qt {
  180.     char    qt_sendstr[BUFSIZ];         /* String to send to terminal */
  181.     char    qt_recvstr[BUFSIZ];            /* String expected in response */
  182.     char    qt_termname[BUFSIZ];        /* Terminal name */
  183.     char    qt_fullname[BUFSIZ];        /* Full terminal name & description */
  184. };
  185. struct qt *compare();
  186. static struct qt termtab[MAXTERMS];
  187.  
  188.  
  189. #ifdef USG5
  190. struct termio _ntty, _otty;
  191. #else
  192. struct sgttyb _tty;
  193. #endif
  194. int _tty_ch = 2;
  195.  
  196. #ifdef USG5
  197. # define crmode()        (_ntty.c_lflag &= ~ICANON,\
  198.                          _ntty.c_cc[VMIN] = 1, _ntty.c_cc[VTIME] = 0,\
  199.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  200. # define nocrmode()        (_ntty.c_lflag |= ICANON,\
  201.                          _ntty.c_cc[VMIN] = _otty.c_cc[VMIN],\
  202.                          _ntty.c_cc[VTIME] = _otty.c_cc[VTIME],\
  203.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  204. # define echo()            (_ntty.c_lflag |= ECHO,\
  205.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  206. # define noecho()        (_ntty.c_lflag &= ~ECHO,\
  207.                          ioctl(_tty_ch, TCSETAF, &_ntty))
  208. #else
  209. # define crmode()         (_tty.sg_flags |= CBREAK,\
  210.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  211. # define nocrmode()     (_tty.sg_flags &= ~CBREAK,\
  212.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  213. # define echo()         (_tty.sg_flags |= ECHO,   \
  214.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  215. # define noecho()         (_tty.sg_flags &= ~ECHO,  \
  216.                             ioctl(_tty_ch, TIOCSETP, &_tty))
  217. #endif
  218.  
  219. #define SIZE         512
  220. #define CMASK         0377
  221. #define ESC            '\033'
  222.  
  223. static char recvbuf[SIZE];
  224. static char *progname;
  225. int debug;                    /* debug mode             */
  226. int aflag;                    /* alternate string     */
  227. int sflag;                    /* print strings        */
  228. int qflag;                    /* quiet mode             */
  229. int fflag;                    /* use strings file     */
  230.  
  231. int found = FALSE;
  232. int index = 0;
  233. int finish(), wakeup(), done();
  234.  
  235. char *decode();
  236.  
  237. jmp_buf env;
  238.  
  239. main(argc, argv)
  240. char *argv[];
  241. {
  242.     register int x;
  243.  
  244.     progname = argv[0];
  245.  
  246.     for (x = 1; x < argc; x++) {
  247.         if (argv[x][0] != '-')
  248.             break;
  249.         switch (argv[x][1]) {
  250.             case 'a':
  251.                 aflag = TRUE;
  252.                 break;
  253.             case 't':
  254.             case 's':
  255.                 sflag = TRUE;
  256.                 break;
  257.             case 'q':
  258.                 qflag = TRUE;
  259.                 break;
  260.             case 'f':
  261.                 fflag = TRUE;
  262.                 break;
  263.             case 'd':
  264.                 debug = TRUE;
  265.                 break;
  266.             default:
  267.                 usage();
  268.                 exit(1);
  269.         }
  270.     }
  271.  
  272.     setbuf(stdout, 0);
  273.     if(debug)
  274.         setbuf(stderr, 0);
  275.  
  276.     dprintf("[ %s debug mode enabled ]\n\n", progname);
  277.  
  278.     if(!isatty(0))
  279.         fprintf(stderr,"Not a tty.\n");
  280.  
  281. #ifdef USG5
  282.     if(ioctl(_tty_ch, TCGETA, &_otty) < 0)
  283. #else
  284.     if(ioctl(_tty_ch, TIOCGETP, &_tty) < 0)
  285. #endif
  286.     {
  287.         perror("gtty");
  288.         exit(1);
  289.     }
  290. #ifdef USG5
  291.     _ntty = _otty;
  292. #endif
  293.     if(crmode() < 0) {
  294.         perror("crmode");
  295.         exit(1);
  296.     }
  297.     if(noecho() < 0) {
  298.         perror("noecho");
  299.         exit(1);
  300.     }
  301.  
  302.     dprintf("[ initilizing term table... ]\n");
  303.     mktable();
  304.     dprintf("[ table done ]\n");
  305.  
  306.     if(!fflag) {
  307.         dointernal();
  308.     } else
  309.         dprintf("!fflag.  not doing dointernal().\n");
  310.  
  311.     index = tabmark;
  312.     dprintf("main: we'll do a dotab()\n");
  313.     dotab();
  314.     dprintf("main: dotab done\n");
  315.  
  316.     putc('\r', stderr);
  317.     (void) nocrmode();
  318.     (void) echo();
  319.     if(!found) {
  320.         dprintf("end of main\n");
  321.         notrecognized();
  322.     }
  323. }
  324.  
  325. done()
  326. {
  327.     putc('\r', stderr);
  328.     (void) nocrmode();
  329.     (void) echo();
  330.     exit(0);
  331. }
  332.  
  333. /*
  334.  * finish - clean things up.
  335.  */
  336. finish()
  337. {
  338.     dprintf("finish called\n");
  339.     putc('\r', stderr);
  340.     (void) nocrmode();
  341.     (void) echo();
  342.     if(recvbuf[0] != NULL)
  343.         (void) prinfo(compare(recvbuf, 0, tabtotal), 1);
  344.         
  345.     dprintf("finish done\n");
  346.     if(!found)
  347.         notrecognized();
  348.     exit(0);
  349. }
  350.  
  351. prinfo(t, what)
  352. struct qt *t;
  353. int what;
  354. {
  355.     int len = 0;
  356.     int st = FALSE;
  357.  
  358.     dprintf("prinfo startup\n");
  359.     if((t->qt_termname[0] != NULL) && (recvbuf[0] != NULL)) {
  360.         if(debug || sflag) {
  361.             len = strlen(recvbuf);
  362.             fprintf(stderr, "%s receives %d character%s:", 
  363.                 progname, len, (len == 1) ? "" : "s");
  364.             fprintf(stderr, " %s\n", decode(recvbuf));
  365.         }
  366.         if(!qflag)
  367.             if(t->qt_fullname[0] != NULL)
  368.                 fprintf(stderr, "Terminal recognized as %s (%s)\n", 
  369.                     t->qt_termname, t->qt_fullname);
  370.             else
  371.                 fprintf(stderr, "Terminal recognized as %s\n", 
  372.                     t->qt_termname);
  373.         printf("%s\n", t->qt_termname);
  374.         found = TRUE;
  375.         done();
  376.         /*NOTREACHED*/
  377.     } else {
  378.         found = FALSE;
  379.         if(what) {
  380.             dprintf("prinfo(): doing notrecognized()\n");
  381.             notrecognized();
  382.             done();
  383.             /*NOTREACHED*/
  384.         }
  385.     }
  386.     dprintf("prinfo done\n");
  387.     return(st);
  388. }
  389.  
  390. /*
  391.  * compare - actually compare what we received against the table.
  392.  */
  393. struct qt *
  394. compare(str, start, stop)
  395. char *str;
  396. int start;
  397. int stop;
  398. {
  399.     register int i = 0;
  400.     int len;
  401.  
  402.     dprintf("compare(%s, %d, %d) startup.\n", decode(str), start, stop);
  403.     alarm(0);
  404.  
  405.     i = start;
  406.     while(i <= stop) {
  407.         dprintf("compare(): tr = '%s'\n", decode(termtab[i].qt_recvstr));
  408.         if(strncmp(str, termtab[i].qt_recvstr, 
  409.           strlen(termtab[i].qt_recvstr)) == 0) {
  410.             found = TRUE;
  411.             return(&termtab[i]);
  412.         }
  413.         ++i;
  414.     }
  415.     found = FALSE;
  416. }
  417.  
  418. /*
  419.  * getch - read in a character at a time.
  420.  */
  421. getch()
  422. {
  423.     char c;
  424.  
  425.     (void) read(0, &c, 1);
  426.     return(c & CMASK);
  427. }
  428.  
  429. /*
  430.  * decode - print str in a readable fashion
  431.  */
  432. char *
  433. decode(str)
  434. char *str;
  435. {
  436.     char buf[BUFSIZ];
  437.     char tmp[10];
  438.  
  439.     strcpy(buf, "");
  440.     while(*str) {
  441.         if (*str == ESC) {
  442.             strcat(buf, "<esc> ");
  443.         } else if((*str <= 33) || (*str >= 127)) {
  444.             sprintf(tmp,"\\%o ", *str);
  445.             strcat(buf, tmp);
  446.         } else {
  447.             sprintf(tmp,"%c ", *str);
  448.             strcat(buf, tmp);
  449.         }
  450.         *++str;
  451.     }
  452.     return(buf);
  453. }
  454.  
  455. usage()
  456. {
  457.     fprintf(stderr, "usage: %s [ -asq ]\n", progname);
  458. }
  459.  
  460. mktable()
  461. {
  462.     register int i, z;
  463.     FILE *fd, *fopen();
  464.     char file[BUFSIZ];
  465.     char buf[BUFSIZ];
  466.     char lbuf[4][BUFSIZ];
  467.     char *home, *msg, *fixctl();
  468.     int iserr = 0;
  469.     extern char *terms[];
  470.     struct passwd *pwd;
  471.  
  472.     i = z = 0;
  473.     /*
  474.      * Copy internal table
  475.      */
  476.     while(terms[z] != NULL && i < MAXTERMS) {
  477.         (void) strcpy(termtab[i].qt_sendstr, (aflag) ? ALTSEND : SEND);
  478.         (void) strcpy(termtab[i].qt_recvstr, terms[z + T_STR]);
  479.         (void) strcpy(termtab[i].qt_termname, terms[z + T_NAME]);
  480.         (void) strcpy(termtab[i].qt_fullname, terms[z + T_LNAME]);
  481.  
  482.         z += 3;
  483.         ++i;
  484.     }
  485.     tabmark = i;
  486.  
  487.     /*
  488.      * Try and read the user's own table
  489.      */
  490.     if((home = (char *) getenv("HOME")) == NULL) {
  491.         if((pwd = (struct passwd *) getpwuid(getuid())) == NULL) {
  492.             fprintf(stderr, "Who the hell are you????\n");
  493.             exit(1);
  494.         }
  495.         home = pwd->pw_dir;
  496.     }
  497.     dprintf("home = '%s'\n", home);
  498.     sprintf(file, "%s/%s", home, STRFILE);
  499.     dprintf("strfile = '%s'\n", file);
  500.     if(fflag && (fd = fopen(file, "r")) != NULL) {
  501.         while(fgets(buf, sizeof(buf), fd) && i < MAXTERMS) {
  502.             if(buf[0] == '#' || buf[0] == '\n')
  503.                 continue;
  504.  
  505.             lbuf[0][0] = NULL;
  506.             lbuf[1][0] = NULL;
  507.             lbuf[2][0] = NULL;
  508.             lbuf[3][0] = NULL;
  509.     
  510.             (void) sscanf(buf, "%s%s%s\t%[^\n]", 
  511.                 lbuf[0], lbuf[1], lbuf[2], lbuf[3]);
  512.             if(lbuf[0][0] == NULL)
  513.                 continue;
  514.             if(lbuf[1][0] == NULL) {
  515.                 iserr = TRUE;
  516.                 msg = "receive string";
  517.             }
  518.             if(lbuf[2][0] == NULL) {
  519.                 iserr = TRUE;
  520.                 msg = "terminal name";
  521.             }
  522.             if(iserr) {
  523.                 fprintf(stderr, "%s: Error parsing %s.\n", file, msg);
  524.                 exit(1);
  525.             }
  526.             (void) strcpy(termtab[i].qt_sendstr, fixctl(lbuf[0]));
  527.             (void) strcpy(termtab[i].qt_recvstr, fixctl(lbuf[1]));
  528.             (void) strcpy(termtab[i].qt_termname, lbuf[2]);
  529.             (void) strcpy(termtab[i].qt_fullname, lbuf[3]);
  530.  
  531.             dprintf("entry %d:\n", i);
  532.             dprintf("qt_sendstr = %s\n", decode(termtab[i].qt_sendstr));
  533.             dprintf("qt_recvstr = %s\n", decode(termtab[i].qt_recvstr));
  534.             dprintf("qt_termname = '%s'\n", termtab[i].qt_termname);
  535.             dprintf("qt_fullname = '%s'\n", termtab[i].qt_fullname);
  536.  
  537.             ++i;
  538.         }
  539.     }
  540.     tabtotal = i;
  541.     dprintf("termtab total  = %d\n", tabtotal);
  542.     dprintf("termtab mark  = %d\n", tabmark);
  543. }
  544.  
  545. listen(q)
  546. struct qt *q;
  547. {
  548.     register int i;
  549.     register char c;
  550.     char end, begin;
  551.  
  552.     dprintf("listen startup\n");
  553.     alarm(0);
  554.  
  555.     dprintf("listen: listening for '%s'\n", decode(q->qt_recvstr));
  556.  
  557.     if (q->qt_recvstr[0] == NULL) {
  558.         begin = ESC;
  559.         end = 'c';
  560.     } else {
  561.         begin = q->qt_recvstr[0];
  562.         end = q->qt_recvstr[strlen(q->qt_recvstr)-1];
  563.     }
  564.  
  565.     dprintf("listen: read initial character...\n");
  566.     if(setjmp(env)) {
  567.         dprintf("listen: setjmp TRUE\n");
  568.         if(found)
  569.             done();
  570.         ++index;
  571.         (void) fflush(stdin);
  572.         dprintf("listen: dotab()\n");
  573.         dotab();
  574.     } else {
  575.         dprintf("listen: setjmp FALSE...set alarm\n");
  576.         signal(SIGALRM, wakeup);
  577.         alarm(3);
  578.         dprintf("listen: read char\n");
  579.         recvbuf[0] = getch();
  580.         alarm(0);
  581.         dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
  582.  
  583.     }
  584.     i = 0;
  585.     if(recvbuf[0] == begin) {
  586.         dprintf("listen begin\n");
  587.         while(c != end) {
  588.             if(setjmp(env))  {
  589.                 dprintf("listen: setjmp (2) return\n");
  590.                 return;
  591.             } else {
  592.                 signal(SIGALRM, wakeup);
  593.                 alarm(2);
  594.                 dprintf("listen: read (2) char\n");
  595.                 c = getch();
  596.                 alarm(0);
  597.                 dprintf("recvbuf[0] = '\\%o'\n", recvbuf[0]);
  598.             }
  599.             recvbuf[++i] = c;
  600.         }
  601.         if(debug)
  602.             fprintf(stderr,"\n[ Received terminator. ]\n");
  603.     } else {
  604.         dprintf("listen: Not Recognized.  exiting...\n");
  605.         notrecognized();
  606.         putc('\r',stderr);
  607.         (void) nocrmode();
  608.         (void) echo();
  609.         exit(1);
  610.     }
  611.     dprintf("listen done\n");
  612. }
  613.  
  614. notrecognized()
  615. {
  616.     if(!qflag)
  617.         fprintf(stderr, 
  618.           "Terminal NOT recognized - defaults to \"dumb\".\n");
  619.     puts("dumb");
  620. }
  621.  
  622. wakeup()
  623. {
  624.     dprintf("wakeup called\n");
  625.     longjmp(env, 1);
  626.     dprintf("wakeUP: done\n");
  627. }
  628.  
  629. dotab()
  630. {
  631.     int wakeup();
  632.     int st = FALSE;
  633.     static int firsttime = TRUE;
  634.  
  635.     dprintf("dotab startup\n");
  636.     dprintf("index = %d\n", index);
  637.     if(index > tabtotal) {
  638.         /*
  639.          * if we haven't reset things yet, do so.
  640.          * now try the internal tables if the user's
  641.          * tables failed.
  642.          */
  643.         if(!has_set)  {
  644.             tabtotal = tabmark;
  645.             index = 0;
  646.             has_set = 1;
  647.             dprintf("dotab(): has_set now true.\n");
  648.             dotab();
  649.         }
  650.         dprintf("dotab(): index > tabtotal\n");
  651.         finish();
  652.     }
  653.     if(!found || fflag) {
  654.         while(!found && termtab[index].qt_sendstr[0] != NULL && !st) {
  655.             dprintf("dotab: termtab PASS %d\n", index);
  656.             dprintf("dotab: sending str %s\n", 
  657.                 decode(termtab[index].qt_sendstr));
  658.             (void) fflush(stdin);
  659.             if(firsttime || strncmp(termtab[index].qt_sendstr, 
  660.               termtab[index-1].qt_sendstr,
  661.               strlen(termtab[index].qt_sendstr))) {
  662.                 firsttime = FALSE;
  663.                 dprintf("dotab(): sendstr's didn't match.\n");
  664.                 dprintf("dotab: str1 %s\n", 
  665.                     decode(termtab[index].qt_sendstr));
  666.                 dprintf("dotab: str2 %s\n", 
  667.                     decode(termtab[index-1].qt_sendstr));
  668.                 fprintf(stderr, termtab[index].qt_sendstr);
  669.                 (void) fflush(stdout);
  670.                 (void) fflush(stderr);
  671.                 (void) listen(&termtab[index]);
  672.             } else {
  673.                 dprintf("dotab(): sendstr's DID match.  No str sent.\n");
  674.                 dprintf("dotab: str1 %s\n", 
  675.                     decode(termtab[index].qt_sendstr));
  676.                 dprintf("dotab: str2 %s\n", 
  677.                     decode(termtab[index-1].qt_sendstr));
  678.             }
  679.  
  680.             firsttime = FALSE;
  681.             dprintf("dotab(): recbuf = '%s'\n", decode(recvbuf));
  682.             dprintf("dotab(): qt_rec = '%s'\n", 
  683.                 decode(termtab[index].qt_recvstr));
  684.             st = prinfo(compare(recvbuf, tabmark, tabtotal), !fflag);
  685.             dprintf("st = %d\n", st);
  686.             ++index;
  687.         }
  688.         dprintf("dotab(): mark 1\n");
  689.     }
  690.     dprintf("i'm here (2)\n");
  691.     if(!found) {
  692.         dprintf("end of dotab\n");
  693.         dointernal();
  694.         if(!found) {
  695.             dprintf("dotab: dointernal failed.\n");
  696.             notrecognized();
  697.         }
  698.     }
  699.     done();
  700. }
  701.  
  702. dointernal()
  703. {
  704.     struct qt q;
  705.  
  706.     dprintf("DOINTERNAL startup.\n");
  707.  
  708.     (void) fflush(stdin);
  709.     fprintf(stderr, (aflag) ? ALTSEND : SEND);
  710.     (void) fflush(stdout);
  711.     (void) fflush(stderr);
  712.  
  713.     q.qt_recvstr[0] = NULL;
  714.  
  715.     (void) listen(&q);
  716.  
  717.     (void) prinfo(compare(recvbuf, 0, tabmark), 1);
  718.     if(found)
  719.         done();
  720.  
  721.     dprintf("dointernal end.\n");
  722. }
  723.  
  724. char *
  725. fixctl(str)
  726. char *str;
  727. {
  728.     register int i;
  729.     char buf[BUFSIZ];
  730.  
  731.     i = 0;
  732.     while(*str) {
  733.         if(*str == '^')
  734.             buf[i++] = *++str & 037;
  735.         else
  736.             buf[i++] = *str;
  737.         *++str;
  738.     }
  739.     buf[i] = NULL;
  740.     return(buf);
  741. }
  742.