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