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