xref: /original-bsd/usr.bin/telnet/utilities.c (revision e0c0d005)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)utilities.c	5.1 (Berkeley) 09/14/90";
10 #endif /* not lint */
11 
12 #define	TELOPTS
13 #define	TELCMDS
14 #include <arpa/telnet.h>
15 #include <sys/types.h>
16 #include <sys/time.h>
17 
18 #include <ctype.h>
19 
20 #include "general.h"
21 
22 #include "fdset.h"
23 
24 #include "ring.h"
25 
26 #include "defines.h"
27 
28 #include "externs.h"
29 
30 FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
31 int	prettydump;
32 
33 /*
34  * upcase()
35  *
36  *	Upcase (in place) the argument.
37  */
38 
39 void
40 upcase(argument)
41 register char *argument;
42 {
43     register int c;
44 
45     while ((c = *argument) != 0) {
46 	if (islower(c)) {
47 	    *argument = toupper(c);
48 	}
49 	argument++;
50     }
51 }
52 
53 /*
54  * SetSockOpt()
55  *
56  * Compensate for differences in 4.2 and 4.3 systems.
57  */
58 
59 int
60 SetSockOpt(fd, level, option, yesno)
61 int
62 	fd,
63 	level,
64 	option,
65 	yesno;
66 {
67 #ifndef	NOT43
68     return setsockopt(fd, level, option,
69 				(char *)&yesno, sizeof yesno);
70 #else	/* NOT43 */
71     if (yesno == 0) {		/* Can't do that in 4.2! */
72 	fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
73 				option);
74 	return -1;
75     }
76     return setsockopt(fd, level, option, 0, 0);
77 #endif	/* NOT43 */
78 }
79 
80 /*
81  * The following are routines used to print out debugging information.
82  */
83 
84 unsigned char NetTraceFile[256] = "(standard output)";
85 
86 void
87 SetNetTrace(file)
88 register char *file;
89 {
90     if (NetTrace && NetTrace != stdout)
91 	fclose(NetTrace);
92     if (file  && (strcmp(file, "-") != 0)) {
93 	NetTrace = fopen(file, "w");
94 	if (NetTrace) {
95 	    strcpy(NetTraceFile, file);
96 	    return;
97 	}
98 	fprintf(stderr, "Cannot open %s.\n", file);
99     }
100     NetTrace = stdout;
101     strcpy(NetTraceFile, "(standard output)");
102 }
103 
104 void
105 Dump(direction, buffer, length)
106 char	direction;
107 char	*buffer;
108 int	length;
109 {
110 #   define BYTES_PER_LINE	32
111 #   define min(x,y)	((x<y)? x:y)
112     char *pThis;
113     int offset;
114     extern pettydump;
115 
116     offset = 0;
117 
118     while (length) {
119 	/* print one line */
120 	fprintf(NetTrace, "%c 0x%x\t", direction, offset);
121 	pThis = buffer;
122 	if (prettydump) {
123 	    buffer = buffer + min(length, BYTES_PER_LINE/2);
124 	    while (pThis < buffer) {
125 		fprintf(NetTrace, "%c%.2x",
126 		    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
127 		    (*pThis)&0xff);
128 		pThis++;
129 	    }
130 	    length -= BYTES_PER_LINE/2;
131 	    offset += BYTES_PER_LINE/2;
132 	} else {
133 	    buffer = buffer + min(length, BYTES_PER_LINE);
134 	    while (pThis < buffer) {
135 		fprintf(NetTrace, "%.2x", (*pThis)&0xff);
136 		pThis++;
137 	    }
138 	    length -= BYTES_PER_LINE;
139 	    offset += BYTES_PER_LINE;
140 	}
141 	if (NetTrace == stdout) {
142 	    fprintf(NetTrace, "\r\n");
143 	} else {
144 	    fprintf(NetTrace, "\n");
145 	}
146 	if (length < 0) {
147 	    fflush(NetTrace);
148 	    return;
149 	}
150 	/* find next unique line */
151     }
152     fflush(NetTrace);
153 }
154 
155 
156 void
157 printoption(direction, fmt, option)
158 	char *direction, *fmt;
159 	int option;
160 {
161 	if (!showoptions)
162 		return;
163 	fprintf(NetTrace, "%s ", direction);
164 	if (TELOPT_OK(option))
165 		fprintf(NetTrace, "%s %s", fmt, TELOPT(option));
166 	else if (TELCMD_OK(option))
167 		fprintf(NetTrace, "%s %s", fmt, TELCMD(option));
168 	else
169 		fprintf(NetTrace, "%s %d", fmt, option);
170 	if (NetTrace == stdout)
171 	    fprintf(NetTrace, "\r\n");
172 	else
173 	    fprintf(NetTrace, "\n");
174 	return;
175 }
176 
177 optionstatus()
178 {
179     register int i;
180     extern char will_wont_resp[], do_dont_resp[];
181 
182     for (i = 0; i < 256; i++) {
183 	if (do_dont_resp[i]) {
184 	    if (TELOPT_OK(i))
185 		printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
186 	    else if (TELCMD_OK(i))
187 		printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
188 	    else
189 		printf("resp DO_DONT %d: %d\n", i,
190 				do_dont_resp[i]);
191 	    if (my_want_state_is_do(i)) {
192 		if (TELOPT_OK(i))
193 		    printf("want DO   %s\n", TELOPT(i));
194 		else if (TELCMD_OK(i))
195 		    printf("want DO   %s\n", TELCMD(i));
196 		else
197 		    printf("want DO   %d\n", i);
198 	    } else {
199 		if (TELOPT_OK(i))
200 		    printf("want DONT %s\n", TELOPT(i));
201 		else if (TELCMD_OK(i))
202 		    printf("want DONT %s\n", TELCMD(i));
203 		else
204 		    printf("want DONT %d\n", i);
205 	    }
206 	} else {
207 	    if (my_state_is_do(i)) {
208 		if (TELOPT_OK(i))
209 		    printf("     DO   %s\n", TELOPT(i));
210 		else if (TELCMD_OK(i))
211 		    printf("     DO   %s\n", TELCMD(i));
212 		else
213 		    printf("     DO   %d\n", i);
214 	    }
215 	}
216 	if (will_wont_resp[i]) {
217 	    if (TELOPT_OK(i))
218 		printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
219 	    else if (TELCMD_OK(i))
220 		printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
221 	    else
222 		printf("resp WILL_WONT %d: %d\n",
223 				i, will_wont_resp[i]);
224 	    if (my_want_state_is_will(i)) {
225 		if (TELOPT_OK(i))
226 		    printf("want WILL %s\n", TELOPT(i));
227 		else if (TELCMD_OK(i))
228 		    printf("want WILL %s\n", TELCMD(i));
229 		else
230 		    printf("want WILL %d\n", i);
231 	    } else {
232 		if (TELOPT_OK(i))
233 		    printf("want WONT %s\n", TELOPT(i));
234 		else if (TELCMD_OK(i))
235 		    printf("want WONT %s\n", TELCMD(i));
236 		else
237 		    printf("want WONT %d\n", i);
238 	    }
239 	} else {
240 	    if (my_state_is_will(i)) {
241 		if (TELOPT_OK(i))
242 		    printf("     WILL %s\n", TELOPT(i));
243 		else if (TELCMD_OK(i))
244 		    printf("     WILL %s\n", TELCMD(i));
245 		else
246 		    printf("     WILL %d\n", i);
247 	    }
248 	}
249     }
250 
251 }
252 
253 char *slcnames[] = { SLC_NAMES };
254 
255 #ifdef	KERBEROS
256 static char *authtypes[3] = { "NONE", "PRIVATE", "KERBEROS" };
257 #endif
258 
259 void
260 printsub(direction, pointer, length)
261 char	direction;		/* '<' or '>' */
262 unsigned char	*pointer;	/* where suboption data sits */
263 int	length;			/* length of suboption data */
264 {
265     register int i;
266 
267     if (showoptions) {
268 	if (direction) {
269 	    fprintf(NetTrace, "%s suboption ",
270 				(direction == '<')? "Received":"Sent");
271 	    if (length >= 3) {
272 		register int j;
273 
274 		i = pointer[length-2];
275 		j = pointer[length-1];
276 
277 		if (i != IAC || j != SE) {
278 		    fprintf(NetTrace, "(terminated by ");
279 		    if (TELOPT_OK(i))
280 			fprintf(NetTrace, "%s ", TELOPT(i));
281 		    else if (TELCMD_OK(i))
282 			fprintf(NetTrace, "%s ", TELCMD(i));
283 		    else
284 			fprintf(NetTrace, "%d ", i);
285 		    if (TELOPT_OK(j))
286 			fprintf(NetTrace, "%s", TELOPT(j));
287 		    else if (TELCMD_OK(j))
288 			fprintf(NetTrace, "%s", TELCMD(j));
289 		    else
290 			fprintf(NetTrace, "%d", j);
291 		    fprintf(NetTrace, ", not IAC SE!) ");
292 		}
293 	    }
294 	    length -= 2;
295 	}
296 	if (length < 1) {
297 	    fprintf(NetTrace, "(Empty suboption???)");
298 	    return;
299 	}
300 	switch (pointer[0]) {
301 	case TELOPT_TTYPE:
302 	    fprintf(NetTrace, "TERMINAL-TYPE ");
303 	    switch (pointer[1]) {
304 	    case TELQUAL_IS:
305 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
306 		break;
307 	    case TELQUAL_SEND:
308 		fprintf(NetTrace, "SEND");
309 		break;
310 	    default:
311 		fprintf(NetTrace,
312 				"- unknown qualifier %d (0x%x).",
313 				pointer[1], pointer[1]);
314 	    }
315 	    break;
316 	case TELOPT_TSPEED:
317 	    fprintf(NetTrace, "TERMINAL-SPEED");
318 	    if (length < 2) {
319 		fprintf(NetTrace, " (empty suboption???)");
320 		break;
321 	    }
322 	    switch (pointer[1]) {
323 	    case TELQUAL_IS:
324 		fprintf(NetTrace, " IS ");
325 		fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
326 		break;
327 	    default:
328 		if (pointer[1] == 1)
329 		    fprintf(NetTrace, " SEND");
330 		else
331 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
332 		for (i = 2; i < length; i++)
333 		    fprintf(NetTrace, " ?%d?", pointer[i]);
334 		break;
335 	    }
336 	    break;
337 
338 	case TELOPT_LFLOW:
339 	    fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
340 	    if (length < 2) {
341 		fprintf(NetTrace, " (empty suboption???)");
342 		break;
343 	    }
344 	    switch (pointer[1]) {
345 	    case 0:
346 		fprintf(NetTrace, " OFF"); break;
347 	    case 1:
348 		fprintf(NetTrace, " ON"); break;
349 	    default:
350 		fprintf(NetTrace, " %d (unknown)", pointer[1]);
351 	    }
352 	    for (i = 2; i < length; i++)
353 		fprintf(NetTrace, " ?%d?", pointer[i]);
354 	    break;
355 
356 	case TELOPT_NAWS:
357 	    fprintf(NetTrace, "NAWS");
358 	    if (length < 2) {
359 		fprintf(NetTrace, " (empty suboption???)");
360 		break;
361 	    }
362 	    if (length == 2) {
363 		fprintf(NetTrace, " ?%d?", pointer[1]);
364 		break;
365 	    }
366 	    fprintf(NetTrace, " %d %d (%d)",
367 		pointer[1], pointer[2],
368 		(int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
369 	    if (length == 4) {
370 		fprintf(NetTrace, " ?%d?", pointer[3]);
371 		break;
372 	    }
373 	    fprintf(NetTrace, " %d %d (%d)",
374 		pointer[3], pointer[4],
375 		(int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
376 	    for (i = 5; i < length; i++)
377 		fprintf(NetTrace, " ?%d?", pointer[i]);
378 	    break;
379 
380 #ifdef	KERBEROS
381 	case TELOPT_AUTHENTICATION:
382 	    fprintf(NetTrace, "Authentication information ");
383 	    switch (pointer[1]) {
384 	    case TELQUAL_IS:
385 		switch (pointer[2]) {
386 		case TELQUAL_AUTHTYPE_NONE:
387 		case TELQUAL_AUTHTYPE_PRIVATE:
388 		case TELQUAL_AUTHTYPE_KERBEROS:
389 
390 			fprintf(NetTrace, "is type %s\r\n", authtypes[pointer[2]]);
391 			break;
392 		default:
393 			fprintf(NetTrace, "is type unknown\r\n");
394 			break;
395 		}
396 
397 	    case TELQUAL_SEND:
398 	    {
399 		int	idx = 2;
400 		fprintf(NetTrace, "- request to send, types");
401 		for (idx = 2; idx < length - 1; idx++)
402 			switch (pointer[idx]) {
403 			case TELQUAL_AUTHTYPE_NONE:
404 			case TELQUAL_AUTHTYPE_PRIVATE:
405 			case TELQUAL_AUTHTYPE_KERBEROS:
406 				fprintf(NetTrace, " %s",
407 					authtypes[pointer[idx]]);
408 					break;
409 			default:
410 				fprintf(NetTrace, " <unknown %u>",
411 					pointer[idx]);
412 				break;
413 			}
414 		fprintf(NetTrace, "\r\n");
415 	    }
416 		break;
417 
418 	    default:
419 		fprintf(NetTrace, " - unknown qualifier %d (0x%x).\r\n",
420 			pointer[1], pointer[1]);
421 	    }
422 	    break;
423 #endif /* KERBEROS */
424 
425 	case TELOPT_LINEMODE:
426 	    fprintf(NetTrace, "LINEMODE ");
427 	    if (length < 2) {
428 		fprintf(NetTrace, " (empty suboption???)");
429 		break;
430 	    }
431 	    switch (pointer[1]) {
432 	    case WILL:
433 		fprintf(NetTrace, "WILL ");
434 		goto common;
435 	    case WONT:
436 		fprintf(NetTrace, "WONT ");
437 		goto common;
438 	    case DO:
439 		fprintf(NetTrace, "DO ");
440 		goto common;
441 	    case DONT:
442 		fprintf(NetTrace, "DONT ");
443 	    common:
444 		if (length < 3) {
445 		    fprintf(NetTrace, "(no option???)");
446 		    break;
447 		}
448 		switch (pointer[2]) {
449 		case LM_FORWARDMASK:
450 		    fprintf(NetTrace, "Forward Mask");
451 		    for (i = 3; i < length; i++)
452 			fprintf(NetTrace, " %x", pointer[i]);
453 		    break;
454 		default:
455 		    fprintf(NetTrace, "%d (unknown)", pointer[2]);
456 		    for (i = 3; i < length; i++)
457 			fprintf(NetTrace, " %d", pointer[i]);
458 		    break;
459 		}
460 		break;
461 
462 	    case LM_SLC:
463 		fprintf(NetTrace, "SLC");
464 		for (i = 2; i < length - 2; i += 3) {
465 		    if (pointer[i+SLC_FUNC] <= NSLC)
466 			fprintf(NetTrace, " %s", slcnames[pointer[i+SLC_FUNC]]);
467 		    else
468 			fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
469 		    switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
470 		    case SLC_NOSUPPORT:
471 			fprintf(NetTrace, " NOSUPPORT"); break;
472 		    case SLC_CANTCHANGE:
473 			fprintf(NetTrace, " CANTCHANGE"); break;
474 		    case SLC_VARIABLE:
475 			fprintf(NetTrace, " VARIABLE"); break;
476 		    case SLC_DEFAULT:
477 			fprintf(NetTrace, " DEFAULT"); break;
478 		    }
479 		    fprintf(NetTrace, "%s%s%s",
480 			pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
481 			pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
482 			pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
483 		    if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
484 						SLC_FLUSHOUT| SLC_LEVELBITS))
485 			fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
486 		    fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
487 		    if ((pointer[i+SLC_VALUE] == IAC) &&
488 			(pointer[i+SLC_VALUE+1] == IAC))
489 				i++;
490 		}
491 		for (; i < length; i++)
492 		    fprintf(NetTrace, " ?%d?", pointer[i]);
493 		break;
494 
495 	    case LM_MODE:
496 		fprintf(NetTrace, "MODE ");
497 		if (length < 3) {
498 		    fprintf(NetTrace, "(no mode???)");
499 		    break;
500 		}
501 		{
502 		    char tbuf[64];
503 		    sprintf(tbuf, "%s%s%s%s%s",
504 			pointer[2]&MODE_EDIT ? "|EDIT" : "",
505 			pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
506 			pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
507 			pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
508 			pointer[2]&MODE_ACK ? "|ACK" : "");
509 		    fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
510 		}
511 		if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK))
512 		    fprintf(NetTrace, " (0x%x)", pointer[2]);
513 		for (i = 3; i < length; i++)
514 		    fprintf(NetTrace, " ?0x%x?", pointer[i]);
515 		break;
516 	    default:
517 		fprintf(NetTrace, "%d (unknown)", pointer[1]);
518 		for (i = 2; i < length; i++)
519 		    fprintf(NetTrace, " %d", pointer[i]);
520 	    }
521 	    break;
522 
523 	case TELOPT_STATUS: {
524 	    register char *cp;
525 	    register int j, k;
526 
527 	    fprintf(NetTrace, "STATUS");
528 
529 	    switch (pointer[1]) {
530 	    default:
531 		if (pointer[1] == TELQUAL_SEND)
532 		    fprintf(NetTrace, " SEND");
533 		else
534 		    fprintf(NetTrace, " %d (unknown)", pointer[1]);
535 		for (i = 2; i < length; i++)
536 		    fprintf(NetTrace, " ?%d?", pointer[i]);
537 		break;
538 	    case TELQUAL_IS:
539 		if (NetTrace == stdout)
540 		    fprintf(NetTrace, " IS\r\n");
541 		else
542 		    fprintf(NetTrace, " IS\n");
543 
544 		for (i = 2; i < length; i++) {
545 		    switch(pointer[i]) {
546 		    case DO:	cp = "DO"; goto common2;
547 		    case DONT:	cp = "DONT"; goto common2;
548 		    case WILL:	cp = "WILL"; goto common2;
549 		    case WONT:	cp = "WONT"; goto common2;
550 		    common2:
551 			i++;
552 			if (TELOPT_OK((int)pointer[i]))
553 			    fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
554 			else
555 			    fprintf(NetTrace, " %s %d", cp, pointer[i]);
556 
557 			if (NetTrace == stdout)
558 			    fprintf(NetTrace, "\r\n");
559 			else
560 			    fprintf(NetTrace, "\n");
561 			break;
562 
563 		    case SB:
564 			fprintf(NetTrace, " SB ");
565 			i++;
566 			j = k = i;
567 			while (j < length) {
568 			    if (pointer[j] == SE) {
569 				if (j+1 == length)
570 				    break;
571 				if (pointer[j+1] == SE)
572 				    j++;
573 				else
574 				    break;
575 			    }
576 			    pointer[k++] = pointer[j++];
577 			}
578 			printsub(0, &pointer[i], k - i);
579 			if (i < length) {
580 			    fprintf(NetTrace, " SE");
581 			    i = j;
582 			} else
583 			    i = j - 1;
584 
585 			if (NetTrace == stdout)
586 			    fprintf(NetTrace, "\r\n");
587 			else
588 			    fprintf(NetTrace, "\n");
589 
590 			break;
591 
592 		    default:
593 			fprintf(NetTrace, " %d", pointer[i]);
594 			break;
595 		    }
596 		}
597 		break;
598 	    }
599 	    break;
600 	  }
601 
602 	case TELOPT_XDISPLOC:
603 	    fprintf(NetTrace, "X-DISPLAY-LOCATION ");
604 	    switch (pointer[1]) {
605 	    case TELQUAL_IS:
606 		fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
607 		break;
608 	    case TELQUAL_SEND:
609 		fprintf(NetTrace, "SEND");
610 		break;
611 	    default:
612 		fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
613 				pointer[1], pointer[1]);
614 	    }
615 	    break;
616 
617 	case TELOPT_ENVIRON:
618 	    fprintf(NetTrace, "ENVIRON ");
619 	    switch (pointer[1]) {
620 	    case TELQUAL_IS:
621 		fprintf(NetTrace, "IS ");
622 		goto env_common;
623 	    case TELQUAL_SEND:
624 		fprintf(NetTrace, "SEND ");
625 		goto env_common;
626 	    case TELQUAL_INFO:
627 		fprintf(NetTrace, "INFO ");
628 	    env_common:
629 		{
630 		    register int noquote = 2;
631 		    for (i = 2; i < length; i++ ) {
632 			switch (pointer[i]) {
633 			case ENV_VAR:
634 			    if (pointer[1] == TELQUAL_SEND)
635 				goto def_case;
636 			    fprintf(NetTrace, "\" VAR " + noquote);
637 			    noquote = 2;
638 			    break;
639 
640 			case ENV_VALUE:
641 			    fprintf(NetTrace, "\" VALUE " + noquote);
642 			    noquote = 2;
643 			    break;
644 
645 			case ENV_ESC:
646 			    fprintf(NetTrace, "\" ESC " + noquote);
647 			    noquote = 2;
648 			    break;
649 
650 			default:
651 			def_case:
652 			    if (isprint(pointer[i]) && pointer[i] != '"') {
653 				if (noquote) {
654 				    putc('"', NetTrace);
655 				    noquote = 0;
656 				}
657 				putc(pointer[i], NetTrace);
658 			    } else {
659 				fprintf(NetTrace, "\" %03o " + noquote,
660 							pointer[i]);
661 				noquote = 2;
662 			    }
663 			    break;
664 			}
665 		    }
666 		    if (!noquote)
667 			putc('"', NetTrace);
668 		    break;
669 		}
670 	    }
671 	    break;
672 
673 	default:
674 	    fprintf(NetTrace, "Unknown option ");
675 	    for (i = 0; i < length; i++)
676 		fprintf(NetTrace, " %d", pointer[i]);
677 	    break;
678 	}
679 	if (direction) {
680 	    if (NetTrace == stdout)
681 		fprintf(NetTrace, "\r\n");
682 	    else
683 		fprintf(NetTrace, "\n");
684 	}
685     }
686 }
687 
688 /* EmptyTerminal - called to make sure that the terminal buffer is empty.
689  *			Note that we consider the buffer to run all the
690  *			way to the kernel (thus the select).
691  */
692 
693 void
694 EmptyTerminal()
695 {
696 #if	defined(unix)
697     fd_set	o;
698 
699     FD_ZERO(&o);
700 #endif	/* defined(unix) */
701 
702     if (TTYBYTES() == 0) {
703 #if	defined(unix)
704 	FD_SET(tout, &o);
705 	(void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
706 			(struct timeval *) 0);	/* wait for TTLOWAT */
707 #endif	/* defined(unix) */
708     } else {
709 	while (TTYBYTES()) {
710 	    (void) ttyflush(0);
711 #if	defined(unix)
712 	    FD_SET(tout, &o);
713 	    (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
714 				(struct timeval *) 0);	/* wait for TTLOWAT */
715 #endif	/* defined(unix) */
716 	}
717     }
718 }
719 
720 void
721 SetForExit()
722 {
723     setconnmode(0);
724 #if	defined(TN3270)
725     if (In3270) {
726 	Finish3270();
727     }
728 #else	/* defined(TN3270) */
729     do {
730 	(void)telrcv();			/* Process any incoming data */
731 	EmptyTerminal();
732     } while (ring_full_count(&netiring));	/* While there is any */
733 #endif	/* defined(TN3270) */
734     setcommandmode();
735     fflush(stdout);
736     fflush(stderr);
737 #if	defined(TN3270)
738     if (In3270) {
739 	StopScreen(1);
740     }
741 #endif	/* defined(TN3270) */
742     setconnmode(0);
743     EmptyTerminal();			/* Flush the path to the tty */
744     setcommandmode();
745 }
746 
747 void
748 Exit(returnCode)
749 int returnCode;
750 {
751     SetForExit();
752     exit(returnCode);
753 }
754 
755 void
756 ExitString(string, returnCode)
757 char *string;
758 int returnCode;
759 {
760     SetForExit();
761     fwrite(string, 1, strlen(string), stderr);
762     exit(returnCode);
763 }
764