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