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