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