home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / telnet / utilities.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  21.2 KB  |  896 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)utilities.c    5.3 (Berkeley) 3/22/91";
  36. #endif /* not lint */
  37.  
  38. #define    TELOPTS
  39. #define    TELCMDS
  40. #define    SLC_NAMES
  41. #include <arpa/telnet.h>
  42. #include <sys/types.h>
  43. #include <sys/time.h>
  44.  
  45. #include <ctype.h>
  46.  
  47. #include "general.h"
  48.  
  49. #include "fdset.h"
  50.  
  51. #include "ring.h"
  52.  
  53. #include "defines.h"
  54.  
  55. #include "externs.h"
  56.  
  57. FILE    *NetTrace = 0;        /* Not in bss, since needs to stay */
  58. int    prettydump;
  59.  
  60. /*
  61.  * upcase()
  62.  *
  63.  *    Upcase (in place) the argument.
  64.  */
  65.  
  66.     void
  67. upcase(argument)
  68.     register char *argument;
  69. {
  70.     register int c;
  71.  
  72.     while ((c = *argument) != 0) {
  73.     if (islower(c)) {
  74.         *argument = toupper(c);
  75.     }
  76.     argument++;
  77.     }
  78. }
  79.  
  80. /*
  81.  * SetSockOpt()
  82.  *
  83.  * Compensate for differences in 4.2 and 4.3 systems.
  84.  */
  85.  
  86.     int
  87. SetSockOpt(fd, level, option, yesno)
  88.     int fd, level, option, yesno;
  89. {
  90. #ifndef    NOT43
  91.     return setsockopt(fd, level, option,
  92.                 (char *)&yesno, sizeof yesno);
  93. #else    /* NOT43 */
  94.     if (yesno == 0) {        /* Can't do that in 4.2! */
  95.     fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
  96.                 option);
  97.     return -1;
  98.     }
  99.     return setsockopt(fd, level, option, 0, 0);
  100. #endif    /* NOT43 */
  101. }
  102.  
  103. /*
  104.  * The following are routines used to print out debugging information.
  105.  */
  106.  
  107. unsigned char NetTraceFile[256] = "(standard output)";
  108.  
  109.     void
  110. SetNetTrace(file)
  111.     register char *file;
  112. {
  113.     if (NetTrace && NetTrace != stdout)
  114.     fclose(NetTrace);
  115.     if (file  && (strcmp(file, "-") != 0)) {
  116.     NetTrace = fopen(file, "w");
  117.     if (NetTrace) {
  118.         strcpy((char *)NetTraceFile, file);
  119.         return;
  120.     }
  121.     fprintf(stderr, "Cannot open %s.\n", file);
  122.     }
  123.     NetTrace = stdout;
  124.     strcpy((char *)NetTraceFile, "(standard output)");
  125. }
  126.  
  127.     void
  128. Dump(direction, buffer, length)
  129.     char direction;
  130.     unsigned char *buffer;
  131.     int length;
  132. {
  133. #   define BYTES_PER_LINE    32
  134. #   define min(x,y)    ((x<y)? x:y)
  135.     unsigned char *pThis;
  136.     int offset;
  137.     extern pettydump;
  138.  
  139.     offset = 0;
  140.  
  141.     while (length) {
  142.     /* print one line */
  143.     fprintf(NetTrace, "%c 0x%x\t", direction, offset);
  144.     pThis = buffer;
  145.     if (prettydump) {
  146.         buffer = buffer + min(length, BYTES_PER_LINE/2);
  147.         while (pThis < buffer) {
  148.         fprintf(NetTrace, "%c%.2x",
  149.             (((*pThis)&0xff) == 0xff) ? '*' : ' ',
  150.             (*pThis)&0xff);
  151.         pThis++;
  152.         }
  153.         length -= BYTES_PER_LINE/2;
  154.         offset += BYTES_PER_LINE/2;
  155.     } else {
  156.         buffer = buffer + min(length, BYTES_PER_LINE);
  157.         while (pThis < buffer) {
  158.         fprintf(NetTrace, "%.2x", (*pThis)&0xff);
  159.         pThis++;
  160.         }
  161.         length -= BYTES_PER_LINE;
  162.         offset += BYTES_PER_LINE;
  163.     }
  164.     if (NetTrace == stdout) {
  165.         fprintf(NetTrace, "\r\n");
  166.     } else {
  167.         fprintf(NetTrace, "\n");
  168.     }
  169.     if (length < 0) {
  170.         fflush(NetTrace);
  171.         return;
  172.     }
  173.     /* find next unique line */
  174.     }
  175.     fflush(NetTrace);
  176. }
  177.  
  178.  
  179.     void
  180. printoption(direction, cmd, option)
  181.     char *direction;
  182.     int cmd, option;
  183. {
  184.     if (!showoptions)
  185.         return;
  186.     if (cmd == IAC) {
  187.         if (TELCMD_OK(option))
  188.             fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
  189.         else
  190.             fprintf(NetTrace, "%s IAC %d", direction, option);
  191.     } else {
  192.         register char *fmt;
  193.         fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
  194.             (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
  195.         if (fmt) {
  196.             fprintf(NetTrace, "%s %s ", direction, fmt);
  197.             if (TELOPT_OK(option))
  198.             fprintf(NetTrace, "%s", TELOPT(option));
  199.             else if (option == TELOPT_EXOPL)
  200.             fprintf(NetTrace, "EXOPL");
  201.             else
  202.             fprintf(NetTrace, "%d", option);
  203.         } else
  204.             fprintf(NetTrace, "%s %d %d", direction, cmd, option);
  205.     }
  206.     if (NetTrace == stdout)
  207.         fprintf(NetTrace, "\r\n");
  208.     else
  209.         fprintf(NetTrace, "\n");
  210.     return;
  211. }
  212.  
  213.     void
  214. optionstatus()
  215. {
  216.     register int i;
  217.     extern char will_wont_resp[], do_dont_resp[];
  218.  
  219.     for (i = 0; i < 256; i++) {
  220.     if (do_dont_resp[i]) {
  221.         if (TELOPT_OK(i))
  222.         printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
  223.         else if (TELCMD_OK(i))
  224.         printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
  225.         else
  226.         printf("resp DO_DONT %d: %d\n", i,
  227.                 do_dont_resp[i]);
  228.         if (my_want_state_is_do(i)) {
  229.         if (TELOPT_OK(i))
  230.             printf("want DO   %s\n", TELOPT(i));
  231.         else if (TELCMD_OK(i))
  232.             printf("want DO   %s\n", TELCMD(i));
  233.         else
  234.             printf("want DO   %d\n", i);
  235.         } else {
  236.         if (TELOPT_OK(i))
  237.             printf("want DONT %s\n", TELOPT(i));
  238.         else if (TELCMD_OK(i))
  239.             printf("want DONT %s\n", TELCMD(i));
  240.         else
  241.             printf("want DONT %d\n", i);
  242.         }
  243.     } else {
  244.         if (my_state_is_do(i)) {
  245.         if (TELOPT_OK(i))
  246.             printf("     DO   %s\n", TELOPT(i));
  247.         else if (TELCMD_OK(i))
  248.             printf("     DO   %s\n", TELCMD(i));
  249.         else
  250.             printf("     DO   %d\n", i);
  251.         }
  252.     }
  253.     if (will_wont_resp[i]) {
  254.         if (TELOPT_OK(i))
  255.         printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
  256.         else if (TELCMD_OK(i))
  257.         printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
  258.         else
  259.         printf("resp WILL_WONT %d: %d\n",
  260.                 i, will_wont_resp[i]);
  261.         if (my_want_state_is_will(i)) {
  262.         if (TELOPT_OK(i))
  263.             printf("want WILL %s\n", TELOPT(i));
  264.         else if (TELCMD_OK(i))
  265.             printf("want WILL %s\n", TELCMD(i));
  266.         else
  267.             printf("want WILL %d\n", i);
  268.         } else {
  269.         if (TELOPT_OK(i))
  270.             printf("want WONT %s\n", TELOPT(i));
  271.         else if (TELCMD_OK(i))
  272.             printf("want WONT %s\n", TELCMD(i));
  273.         else
  274.             printf("want WONT %d\n", i);
  275.         }
  276.     } else {
  277.         if (my_state_is_will(i)) {
  278.         if (TELOPT_OK(i))
  279.             printf("     WILL %s\n", TELOPT(i));
  280.         else if (TELCMD_OK(i))
  281.             printf("     WILL %s\n", TELCMD(i));
  282.         else
  283.             printf("     WILL %d\n", i);
  284.         }
  285.     }
  286.     }
  287.  
  288. }
  289.  
  290.     void
  291. printsub(direction, pointer, length)
  292.     char direction;    /* '<' or '>' */
  293.     unsigned char *pointer;    /* where suboption data sits */
  294.     int          length;    /* length of suboption data */
  295. {
  296.     register int i;
  297.     char buf[512];
  298.     extern int want_status_response;
  299.  
  300.     if (showoptions || direction == 0 ||
  301.     (want_status_response && (pointer[0] == TELOPT_STATUS))) {
  302.     if (direction) {
  303.         fprintf(NetTrace, "%s IAC SB ",
  304.                 (direction == '<')? "RCVD":"SENT");
  305.         if (length >= 3) {
  306.         register int j;
  307.  
  308.         i = pointer[length-2];
  309.         j = pointer[length-1];
  310.  
  311.         if (i != IAC || j != SE) {
  312.             fprintf(NetTrace, "(terminated by ");
  313.             if (TELOPT_OK(i))
  314.             fprintf(NetTrace, "%s ", TELOPT(i));
  315.             else if (TELCMD_OK(i))
  316.             fprintf(NetTrace, "%s ", TELCMD(i));
  317.             else
  318.             fprintf(NetTrace, "%d ", i);
  319.             if (TELOPT_OK(j))
  320.             fprintf(NetTrace, "%s", TELOPT(j));
  321.             else if (TELCMD_OK(j))
  322.             fprintf(NetTrace, "%s", TELCMD(j));
  323.             else
  324.             fprintf(NetTrace, "%d", j);
  325.             fprintf(NetTrace, ", not IAC SE!) ");
  326.         }
  327.         }
  328.         length -= 2;
  329.     }
  330.     if (length < 1) {
  331.         fprintf(NetTrace, "(Empty suboption???)");
  332.         return;
  333.     }
  334.     switch (pointer[0]) {
  335.     case TELOPT_TTYPE:
  336.         fprintf(NetTrace, "TERMINAL-TYPE ");
  337.         switch (pointer[1]) {
  338.         case TELQUAL_IS:
  339.         fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
  340.         break;
  341.         case TELQUAL_SEND:
  342.         fprintf(NetTrace, "SEND");
  343.         break;
  344.         default:
  345.         fprintf(NetTrace,
  346.                 "- unknown qualifier %d (0x%x).",
  347.                 pointer[1], pointer[1]);
  348.         }
  349.         break;
  350.     case TELOPT_TSPEED:
  351.         fprintf(NetTrace, "TERMINAL-SPEED");
  352.         if (length < 2) {
  353.         fprintf(NetTrace, " (empty suboption???)");
  354.         break;
  355.         }
  356.         switch (pointer[1]) {
  357.         case TELQUAL_IS:
  358.         fprintf(NetTrace, " IS ");
  359.         fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
  360.         break;
  361.         default:
  362.         if (pointer[1] == 1)
  363.             fprintf(NetTrace, " SEND");
  364.         else
  365.             fprintf(NetTrace, " %d (unknown)", pointer[1]);
  366.         for (i = 2; i < length; i++)
  367.             fprintf(NetTrace, " ?%d?", pointer[i]);
  368.         break;
  369.         }
  370.         break;
  371.  
  372.     case TELOPT_LFLOW:
  373.         fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
  374.         if (length < 2) {
  375.         fprintf(NetTrace, " (empty suboption???)");
  376.         break;
  377.         }
  378.         switch (pointer[1]) {
  379.         case 0:
  380.         fprintf(NetTrace, " OFF"); break;
  381.         case 1:
  382.         fprintf(NetTrace, " ON"); break;
  383.         default:
  384.         fprintf(NetTrace, " %d (unknown)", pointer[1]);
  385.         }
  386.         for (i = 2; i < length; i++)
  387.         fprintf(NetTrace, " ?%d?", pointer[i]);
  388.         break;
  389.  
  390.     case TELOPT_NAWS:
  391.         fprintf(NetTrace, "NAWS");
  392.         if (length < 2) {
  393.         fprintf(NetTrace, " (empty suboption???)");
  394.         break;
  395.         }
  396.         if (length == 2) {
  397.         fprintf(NetTrace, " ?%d?", pointer[1]);
  398.         break;
  399.         }
  400.         fprintf(NetTrace, " %d %d (%d)",
  401.         pointer[1], pointer[2],
  402.         (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
  403.         if (length == 4) {
  404.         fprintf(NetTrace, " ?%d?", pointer[3]);
  405.         break;
  406.         }
  407.         fprintf(NetTrace, " %d %d (%d)",
  408.         pointer[3], pointer[4],
  409.         (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
  410.         for (i = 5; i < length; i++)
  411.         fprintf(NetTrace, " ?%d?", pointer[i]);
  412.         break;
  413.  
  414. #if    defined(AUTHENTICATE)
  415.     case TELOPT_AUTHENTICATION:
  416.         fprintf(NetTrace, "AUTHENTICATION");
  417.         if (length < 2) {
  418.         fprintf(NetTrace, " (empty suboption???)");
  419.         break;
  420.         }
  421.         switch (pointer[1]) {
  422.         case TELQUAL_REPLY:
  423.         case TELQUAL_IS:
  424.         fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
  425.                             "IS" : "REPLY");
  426.         if (AUTHTYPE_NAME_OK(pointer[2]))
  427.             fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
  428.         else
  429.             fprintf(NetTrace, "%d ", pointer[2]);
  430.         if (length < 3) {
  431.             fprintf(NetTrace, "(partial suboption???)");
  432.             break;
  433.         }
  434.         fprintf(NetTrace, "%s|%s",
  435.             ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
  436.             "CLIENT" : "SERVER",
  437.             ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
  438.             "MUTUAL" : "ONE-WAY");
  439.  
  440.         auth_printsub(&pointer[1], length - 1, buf, sizeof(buf));
  441.         fprintf(NetTrace, "%s", buf);
  442.         break;
  443.  
  444.         case TELQUAL_SEND:
  445.         i = 2;
  446.         fprintf(NetTrace, " SEND ");
  447.         while (i < length) {
  448.             if (AUTHTYPE_NAME_OK(pointer[i]))
  449.             fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
  450.             else
  451.             fprintf(NetTrace, "%d ", pointer[i]);
  452.             if (++i >= length) {
  453.             fprintf(NetTrace, "(partial suboption???)");
  454.             break;
  455.             }
  456.             fprintf(NetTrace, "%s|%s ",
  457.             ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
  458.                             "CLIENT" : "SERVER",
  459.             ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
  460.                             "MUTUAL" : "ONE-WAY");
  461.             ++i;
  462.         }
  463.         break;
  464.  
  465.         case TELQUAL_NAME:
  466.         i = 2;
  467.         fprintf(NetTrace, " NAME \"");
  468.         while (i < length)
  469.             putc(pointer[i++], NetTrace);
  470.         putc('"', NetTrace);
  471.         break;
  472.  
  473.         default:
  474.             for (i = 2; i < length; i++)
  475.             fprintf(NetTrace, " ?%d?", pointer[i]);
  476.             break;
  477.         }
  478.         break;
  479. #endif
  480.  
  481. #if    defined(ENCRYPT)
  482.     case TELOPT_ENCRYPT:
  483.         fprintf(NetTrace, "ENCRYPT");
  484.         if (length < 2) {
  485.         fprintf(NetTrace, " (empty suboption???)");
  486.         break;
  487.         }
  488.         switch (pointer[1]) {
  489.         case ENCRYPT_START:
  490.         fprintf(NetTrace, " START");
  491.         break;
  492.  
  493.         case ENCRYPT_END:
  494.         fprintf(NetTrace, " END");
  495.         break;
  496.  
  497.         case ENCRYPT_REQSTART:
  498.         fprintf(NetTrace, " REQUEST-START");
  499.         break;
  500.  
  501.         case ENCRYPT_REQEND:
  502.         fprintf(NetTrace, " REQUEST-END");
  503.         break;
  504.  
  505.         case ENCRYPT_IS:
  506.         case ENCRYPT_REPLY:
  507.         fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
  508.                             "IS" : "REPLY");
  509.         if (length < 3) {
  510.             fprintf(NetTrace, " (partial suboption???)");
  511.             break;
  512.         }
  513.         if (ENCTYPE_NAME_OK(pointer[2]))
  514.             fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
  515.         else
  516.             fprintf(NetTrace, " %d (unknown)", pointer[2]);
  517.  
  518.         encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
  519.         fprintf(NetTrace, "%s", buf);
  520.         break;
  521.  
  522.         case ENCRYPT_SUPPORT:
  523.         i = 2;
  524.         fprintf(NetTrace, " SUPPORT ");
  525.         while (i < length) {
  526.             if (ENCTYPE_NAME_OK(pointer[i]))
  527.             fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
  528.             else
  529.             fprintf(NetTrace, "%d ", pointer[i]);
  530.             i++;
  531.         }
  532.         break;
  533.  
  534.         case ENCRYPT_ENC_KEYID:
  535.         fprintf(NetTrace, " ENC_KEYID ");
  536.         goto encommon;
  537.  
  538.         case ENCRYPT_DEC_KEYID:
  539.         fprintf(NetTrace, " DEC_KEYID ");
  540.         goto encommon;
  541.  
  542.         default:
  543.         fprintf(NetTrace, " %d (unknown)", pointer[1]);
  544.         encommon:
  545.         for (i = 2; i < length; i++)
  546.             fprintf(NetTrace, " %d", pointer[i]);
  547.         break;
  548.         }
  549.         break;
  550. #endif
  551.  
  552.     case TELOPT_LINEMODE:
  553.         fprintf(NetTrace, "LINEMODE ");
  554.         if (length < 2) {
  555.         fprintf(NetTrace, " (empty suboption???)");
  556.         break;
  557.         }
  558.         switch (pointer[1]) {
  559.         case WILL:
  560.         fprintf(NetTrace, "WILL ");
  561.         goto common;
  562.         case WONT:
  563.         fprintf(NetTrace, "WONT ");
  564.         goto common;
  565.         case DO:
  566.         fprintf(NetTrace, "DO ");
  567.         goto common;
  568.         case DONT:
  569.         fprintf(NetTrace, "DONT ");
  570.         common:
  571.         if (length < 3) {
  572.             fprintf(NetTrace, "(no option???)");
  573.             break;
  574.         }
  575.         switch (pointer[2]) {
  576.         case LM_FORWARDMASK:
  577.             fprintf(NetTrace, "Forward Mask");
  578.             for (i = 3; i < length; i++)
  579.             fprintf(NetTrace, " %x", pointer[i]);
  580.             break;
  581.         default:
  582.             fprintf(NetTrace, "%d (unknown)", pointer[2]);
  583.             for (i = 3; i < length; i++)
  584.             fprintf(NetTrace, " %d", pointer[i]);
  585.             break;
  586.         }
  587.         break;
  588.         
  589.         case LM_SLC:
  590.         fprintf(NetTrace, "SLC");
  591.         for (i = 2; i < length - 2; i += 3) {
  592.             if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
  593.             fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
  594.             else
  595.             fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
  596.             switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
  597.             case SLC_NOSUPPORT:
  598.             fprintf(NetTrace, " NOSUPPORT"); break;
  599.             case SLC_CANTCHANGE:
  600.             fprintf(NetTrace, " CANTCHANGE"); break;
  601.             case SLC_VARIABLE:
  602.             fprintf(NetTrace, " VARIABLE"); break;
  603.             case SLC_DEFAULT:
  604.             fprintf(NetTrace, " DEFAULT"); break;
  605.             }
  606.             fprintf(NetTrace, "%s%s%s",
  607.             pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
  608.             pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
  609.             pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
  610.             if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
  611.                         SLC_FLUSHOUT| SLC_LEVELBITS))
  612.             fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
  613.             fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
  614.             if ((pointer[i+SLC_VALUE] == IAC) &&
  615.             (pointer[i+SLC_VALUE+1] == IAC))
  616.                 i++;
  617.         }
  618.         for (; i < length; i++)
  619.             fprintf(NetTrace, " ?%d?", pointer[i]);
  620.         break;
  621.  
  622.         case LM_MODE:
  623.         fprintf(NetTrace, "MODE ");
  624.         if (length < 3) {
  625.             fprintf(NetTrace, "(no mode???)");
  626.             break;
  627.         }
  628.         {
  629.             char tbuf[64];
  630.             sprintf(tbuf, "%s%s%s%s%s",
  631.             pointer[2]&MODE_EDIT ? "|EDIT" : "",
  632.             pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
  633.             pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
  634.             pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
  635.             pointer[2]&MODE_ACK ? "|ACK" : "");
  636.             fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
  637.         }
  638.         if (pointer[2]&~(MODE_MASK))
  639.             fprintf(NetTrace, " (0x%x)", pointer[2]);
  640.         for (i = 3; i < length; i++)
  641.             fprintf(NetTrace, " ?0x%x?", pointer[i]);
  642.         break;
  643.         default:
  644.         fprintf(NetTrace, "%d (unknown)", pointer[1]);
  645.         for (i = 2; i < length; i++)
  646.             fprintf(NetTrace, " %d", pointer[i]);
  647.         }
  648.         break;
  649.  
  650.     case TELOPT_STATUS: {
  651.         register char *cp;
  652.         register int j, k;
  653.  
  654.         fprintf(NetTrace, "STATUS");
  655.  
  656.         switch (pointer[1]) {
  657.         default:
  658.         if (pointer[1] == TELQUAL_SEND)
  659.             fprintf(NetTrace, " SEND");
  660.         else
  661.             fprintf(NetTrace, " %d (unknown)", pointer[1]);
  662.         for (i = 2; i < length; i++)
  663.             fprintf(NetTrace, " ?%d?", pointer[i]);
  664.         break;
  665.         case TELQUAL_IS:
  666.         if (--want_status_response < 0)
  667.             want_status_response = 0;
  668.         if (NetTrace == stdout)
  669.             fprintf(NetTrace, " IS\r\n");
  670.         else
  671.             fprintf(NetTrace, " IS\n");
  672.  
  673.         for (i = 2; i < length; i++) {
  674.             switch(pointer[i]) {
  675.             case DO:    cp = "DO"; goto common2;
  676.             case DONT:    cp = "DONT"; goto common2;
  677.             case WILL:    cp = "WILL"; goto common2;
  678.             case WONT:    cp = "WONT"; goto common2;
  679.             common2:
  680.             i++;
  681.             if (TELOPT_OK((int)pointer[i]))
  682.                 fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
  683.             else
  684.                 fprintf(NetTrace, " %s %d", cp, pointer[i]);
  685.  
  686.             if (NetTrace == stdout)
  687.                 fprintf(NetTrace, "\r\n");
  688.             else
  689.                 fprintf(NetTrace, "\n");
  690.             break;
  691.  
  692.             case SB:
  693.             fprintf(NetTrace, " SB ");
  694.             i++;
  695.             j = k = i;
  696.             while (j < length) {
  697.                 if (pointer[j] == SE) {
  698.                 if (j+1 == length)
  699.                     break;
  700.                 if (pointer[j+1] == SE)
  701.                     j++;
  702.                 else
  703.                     break;
  704.                 }
  705.                 pointer[k++] = pointer[j++];
  706.             }
  707.             printsub(0, &pointer[i], k - i);
  708.             if (i < length) {
  709.                 fprintf(NetTrace, " SE");
  710.                 i = j;
  711.             } else
  712.                 i = j - 1;
  713.  
  714.             if (NetTrace == stdout)
  715.                 fprintf(NetTrace, "\r\n");
  716.             else
  717.                 fprintf(NetTrace, "\n");
  718.  
  719.             break;
  720.                 
  721.             default:
  722.             fprintf(NetTrace, " %d", pointer[i]);
  723.             break;
  724.             }
  725.         }
  726.         break;
  727.         }
  728.         break;
  729.       }
  730.  
  731.     case TELOPT_XDISPLOC:
  732.         fprintf(NetTrace, "X-DISPLAY-LOCATION ");
  733.         switch (pointer[1]) {
  734.         case TELQUAL_IS:
  735.         fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
  736.         break;
  737.         case TELQUAL_SEND:
  738.         fprintf(NetTrace, "SEND");
  739.         break;
  740.         default:
  741.         fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
  742.                 pointer[1], pointer[1]);
  743.         }
  744.         break;
  745.  
  746.     case TELOPT_ENVIRON:
  747.         fprintf(NetTrace, "ENVIRON ");
  748.         switch (pointer[1]) {
  749.         case TELQUAL_IS:
  750.         fprintf(NetTrace, "IS ");
  751.         goto env_common;
  752.         case TELQUAL_SEND:
  753.         fprintf(NetTrace, "SEND ");
  754.         goto env_common;
  755.         case TELQUAL_INFO:
  756.         fprintf(NetTrace, "INFO ");
  757.         env_common:
  758.         {
  759.             register int noquote = 2;
  760.             for (i = 2; i < length; i++ ) {
  761.             switch (pointer[i]) {
  762.             case ENV_VAR:
  763.                 if (pointer[1] == TELQUAL_SEND)
  764.                 goto def_case;
  765.                 fprintf(NetTrace, "\" VAR " + noquote);
  766.                 noquote = 2;
  767.                 break;
  768.  
  769.             case ENV_VALUE:
  770.                 fprintf(NetTrace, "\" VALUE " + noquote);
  771.                 noquote = 2;
  772.                 break;
  773.  
  774.             case ENV_ESC:
  775.                 fprintf(NetTrace, "\" ESC " + noquote);
  776.                 noquote = 2;
  777.                 break;
  778.  
  779.             default:
  780.             def_case:
  781.                 if (isprint(pointer[i]) && pointer[i] != '"') {
  782.                 if (noquote) {
  783.                     putc('"', NetTrace);
  784.                     noquote = 0;
  785.                 }
  786.                 putc(pointer[i], NetTrace);
  787.                 } else {
  788.                 fprintf(NetTrace, "\" %03o " + noquote,
  789.                             pointer[i]);
  790.                 noquote = 2;
  791.                 }
  792.                 break;
  793.             }
  794.             }
  795.             if (!noquote)
  796.             putc('"', NetTrace);
  797.             break;
  798.         }
  799.         }
  800.         break;
  801.  
  802.     default:
  803.         if (TELOPT_OK(pointer[0]))
  804.         fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
  805.         else
  806.         fprintf(NetTrace, "%d (unknown)", pointer[i]);
  807.         for (i = 1; i < length; i++)
  808.         fprintf(NetTrace, " %d", pointer[i]);
  809.         break;
  810.     }
  811.     if (direction) {
  812.         if (NetTrace == stdout)
  813.         fprintf(NetTrace, "\r\n");
  814.         else
  815.         fprintf(NetTrace, "\n");
  816.     }
  817.     }
  818. }
  819.  
  820. /* EmptyTerminal - called to make sure that the terminal buffer is empty.
  821.  *            Note that we consider the buffer to run all the
  822.  *            way to the kernel (thus the select).
  823.  */
  824.  
  825.     void
  826. EmptyTerminal()
  827. {
  828. #if    defined(unix)
  829.     fd_set    o;
  830.  
  831.     FD_ZERO(&o);
  832. #endif    /* defined(unix) */
  833.  
  834.     if (TTYBYTES() == 0) {
  835. #if    defined(unix)
  836.     FD_SET(tout, &o);
  837.     (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
  838.             (struct timeval *) 0);    /* wait for TTLOWAT */
  839. #endif    /* defined(unix) */
  840.     } else {
  841.     while (TTYBYTES()) {
  842.         (void) ttyflush(0);
  843. #if    defined(unix)
  844.         FD_SET(tout, &o);
  845.         (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
  846.                 (struct timeval *) 0);    /* wait for TTLOWAT */
  847. #endif    /* defined(unix) */
  848.     }
  849.     }
  850. }
  851.  
  852.     void
  853. SetForExit()
  854. {
  855.     setconnmode(0);
  856. #if    defined(TN3270)
  857.     if (In3270) {
  858.     Finish3270();
  859.     }
  860. #else    /* defined(TN3270) */
  861.     do {
  862.     (void)telrcv();            /* Process any incoming data */
  863.     EmptyTerminal();
  864.     } while (ring_full_count(&netiring));    /* While there is any */
  865. #endif    /* defined(TN3270) */
  866.     setcommandmode();
  867.     fflush(stdout);
  868.     fflush(stderr);
  869. #if    defined(TN3270)
  870.     if (In3270) {
  871.     StopScreen(1);
  872.     }
  873. #endif    /* defined(TN3270) */
  874.     setconnmode(0);
  875.     EmptyTerminal();            /* Flush the path to the tty */
  876.     setcommandmode();
  877. }
  878.  
  879.     void
  880. Exit(returnCode)
  881.     int returnCode;
  882. {
  883.     SetForExit();
  884.     exit(returnCode);
  885. }
  886.  
  887.     void
  888. ExitString(string, returnCode)
  889.     char *string;
  890.     int returnCode;
  891. {
  892.     SetForExit();
  893.     fwrite(string, 1, strlen(string), stderr);
  894.     exit(returnCode);
  895. }
  896.