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