xref: /386bsd/usr/src/usr.bin/telnet/utilities.c (revision a2142627)
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
upcase(argument)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
SetSockOpt(fd,level,option,yesno)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
SetNetTrace(file)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
Dump(direction,buffer,length)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
printoption(direction,cmd,option)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
optionstatus()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
printsub(direction,pointer,length)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
EmptyTerminal()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
SetForExit()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
Exit(returnCode)880 Exit(returnCode)
881     int returnCode;
882 {
883     SetForExit();
884     exit(returnCode);
885 }
886 
887     void
ExitString(string,returnCode)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