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