dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / telnet / utilities.c
blobb701ed7eb91e935a1a1d047bf351fecebdd04a31
1 /*
2 * Copyright 1994-2002 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 #pragma ident "%Z%%M% %I% %E% SMI"
8 /*
9 * usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c
13 * Copyright (c) 1988, 1993
14 * The Regents of the University of California. All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
45 static char sccsid[] = "@(#)utilities.c 8.1 (Berkeley) 6/6/93";
47 #define TELOPTS
48 #define TELCMDS
49 #define SLC_NAMES
50 #include <arpa/telnet.h>
51 #include <sys/types.h>
52 #include <sys/time.h>
53 #include <sys/param.h>
54 #include <sys/socket.h>
55 #include <errno.h>
57 #include <ctype.h>
59 #include "general.h"
61 #include "ring.h"
63 #include "defines.h"
65 #include "externs.h"
67 FILE *NetTrace = 0; /* Not in bss, since needs to stay */
68 int prettydump;
71 * upcase()
73 * Upcase (in place) the argument.
76 void
77 upcase(argument)
78 register char *argument;
80 register int c;
82 while ((c = *argument) != 0) {
83 if (islower(c)) {
84 *argument = toupper(c);
86 argument++;
91 * SetSockOpt()
93 * Compensate for differences in 4.2 and 4.3 systems.
96 int
97 SetSockOpt(fd, level, option, yesno)
98 int fd, level, option, yesno;
100 return (setsockopt(fd, level, option, &yesno, sizeof (yesno)));
104 * The following are routines used to print out debugging information.
107 unsigned char NetTraceFile[MAXPATHLEN] = "(standard output)";
109 void
110 SetNetTrace(file)
111 register char *file;
113 if (NetTrace && NetTrace != stdout)
114 (void) fclose(NetTrace);
115 if (file && (strcmp(file, "-") != 0)) {
116 NetTrace = fopen(file, "w");
117 if (NetTrace) {
118 (void) strcpy((char *)NetTraceFile, file);
119 return;
121 (void) fprintf(stderr, "Cannot open %s.\n", file);
123 NetTrace = stdout;
124 (void) strcpy((char *)NetTraceFile, "(standard output)");
127 void
128 Dump(direction, buffer, length)
129 char direction;
130 unsigned char *buffer;
131 int length;
133 #define BYTES_PER_LINE 32
134 #define min(x, y) ((x < y) ? x:y)
135 unsigned char *pThis;
136 int offset;
138 offset = 0;
140 while (length) {
141 /* print one line */
142 (void) fprintf(NetTrace, "%c 0x%x\t", direction, offset);
143 pThis = buffer;
144 if (prettydump) {
145 buffer = buffer + min(length, BYTES_PER_LINE/2);
146 while (pThis < buffer) {
147 (void) fprintf(NetTrace, "%c%.2x",
148 (((*pThis)&0xff) == 0xff) ? '*' : ' ',
149 (*pThis)&0xff);
150 pThis++;
152 length -= BYTES_PER_LINE/2;
153 offset += BYTES_PER_LINE/2;
154 } else {
155 buffer = buffer + min(length, BYTES_PER_LINE);
156 while (pThis < buffer) {
157 (void) fprintf(NetTrace, "%.2x", (*pThis)&0xff);
158 pThis++;
160 length -= BYTES_PER_LINE;
161 offset += BYTES_PER_LINE;
163 if (NetTrace == stdout) {
164 (void) fprintf(NetTrace, "\r\n");
165 } else {
166 (void) fprintf(NetTrace, "\n");
168 if (length < 0) {
169 (void) fflush(NetTrace);
170 return;
172 /* find next unique line */
174 (void) fflush(NetTrace);
178 void
179 printoption(direction, cmd, option)
180 char *direction;
181 int cmd, option;
183 if (!showoptions)
184 return;
185 if (cmd == IAC) {
186 if (TELCMD_OK(option))
187 (void) fprintf(NetTrace, "%s IAC %s", direction,
188 TELCMD(option));
189 else
190 (void) fprintf(NetTrace, "%s IAC %d", direction,
191 option);
192 } else {
193 register char *fmt;
194 fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
195 (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
196 if (fmt) {
197 (void) fprintf(NetTrace, "%s %s ", direction, fmt);
198 if (TELOPT_OK(option))
199 (void) fprintf(NetTrace, "%s", TELOPT(option));
200 else if (option == TELOPT_EXOPL)
201 (void) fprintf(NetTrace, "EXOPL");
202 else
203 (void) fprintf(NetTrace, "%d", option);
204 } else
205 (void) fprintf(NetTrace, "%s %d %d", direction, cmd,
206 option);
208 if (NetTrace == stdout) {
209 (void) fprintf(NetTrace, "\r\n");
210 (void) fflush(NetTrace);
211 } else {
212 (void) fprintf(NetTrace, "\n");
216 void
217 optionstatus()
219 register int i;
220 extern char will_wont_resp[], do_dont_resp[];
222 for (i = 0; i < SUBBUFSIZE; i++) {
223 if (do_dont_resp[i]) {
224 if (TELOPT_OK(i))
225 (void) printf("resp DO_DONT %s: %d\n",
226 TELOPT(i), do_dont_resp[i]);
227 else if (TELCMD_OK(i))
228 (void) printf("resp DO_DONT %s: %d\n",
229 TELCMD(i), do_dont_resp[i]);
230 else
231 (void) printf("resp DO_DONT %d: %d\n", i,
232 do_dont_resp[i]);
233 if (my_want_state_is_do(i)) {
234 if (TELOPT_OK(i))
235 (void) printf("want DO %s\n",
236 TELOPT(i));
237 else if (TELCMD_OK(i))
238 (void) printf("want DO %s\n",
239 TELCMD(i));
240 else
241 (void) printf("want DO %d\n", i);
242 } else {
243 if (TELOPT_OK(i))
244 (void) printf("want DONT %s\n",
245 TELOPT(i));
246 else if (TELCMD_OK(i))
247 (void) printf("want DONT %s\n",
248 TELCMD(i));
249 else
250 (void) printf("want DONT %d\n", i);
252 } else {
253 if (my_state_is_do(i)) {
254 if (TELOPT_OK(i))
255 (void) printf(" DO %s\n",
256 TELOPT(i));
257 else if (TELCMD_OK(i))
258 (void) printf(" DO %s\n",
259 TELCMD(i));
260 else
261 (void) printf(" DO %d\n", i);
264 if (will_wont_resp[i]) {
265 if (TELOPT_OK(i))
266 (void) printf("resp WILL_WONT %s: %d\n",
267 TELOPT(i), will_wont_resp[i]);
268 else if (TELCMD_OK(i))
269 (void) printf("resp WILL_WONT %s: %d\n",
270 TELCMD(i), will_wont_resp[i]);
271 else
272 (void) printf("resp WILL_WONT %d: %d\n",
273 i, will_wont_resp[i]);
274 if (my_want_state_is_will(i)) {
275 if (TELOPT_OK(i))
276 (void) printf("want WILL %s\n",
277 TELOPT(i));
278 else if (TELCMD_OK(i))
279 (void) printf("want WILL %s\n",
280 TELCMD(i));
281 else
282 (void) printf("want WILL %d\n", i);
283 } else {
284 if (TELOPT_OK(i))
285 (void) printf("want WONT %s\n",
286 TELOPT(i));
287 else if (TELCMD_OK(i))
288 (void) printf("want WONT %s\n",
289 TELCMD(i));
290 else
291 (void) printf("want WONT %d\n", i);
293 } else {
294 if (my_state_is_will(i)) {
295 if (TELOPT_OK(i))
296 (void) printf(" WILL %s\n",
297 TELOPT(i));
298 else if (TELCMD_OK(i))
299 (void) printf(" WILL %s\n",
300 TELCMD(i));
301 else
302 (void) printf(" WILL %d\n", i);
309 void
310 printsub(direction, pointer, length)
311 char direction; /* '<' or '>' */
312 unsigned char *pointer; /* where suboption data sits */
313 int length; /* length of suboption data */
315 register int i;
316 char buf[512];
317 extern int want_status_response;
319 if (showoptions || direction == 0 ||
320 (want_status_response && (pointer[0] == TELOPT_STATUS))) {
321 if (direction) {
322 (void) fprintf(NetTrace, "%s IAC SB ",
323 (direction == '<')? "RCVD":"SENT");
324 if (length >= 3) {
325 register int j;
327 i = pointer[length-2];
328 j = pointer[length-1];
330 if (i != IAC || j != SE) {
331 (void) fprintf(NetTrace,
332 "(terminated by ");
333 if (TELOPT_OK(i))
334 (void) fprintf(NetTrace, "%s ",
335 TELOPT(i));
336 else if (TELCMD_OK(i))
337 (void) fprintf(NetTrace, "%s ",
338 TELCMD(i));
339 else
340 (void) fprintf(NetTrace, "%d ",
342 if (TELOPT_OK(j))
343 (void) fprintf(NetTrace, "%s",
344 TELOPT(j));
345 else if (TELCMD_OK(j))
346 (void) fprintf(NetTrace, "%s",
347 TELCMD(j));
348 else
349 (void) fprintf(NetTrace, "%d",
351 (void) fprintf(NetTrace,
352 ", not IAC SE!) ");
355 length -= 2;
357 if (length < 1) {
358 (void) fprintf(NetTrace, "(Empty suboption??\?)");
359 if (NetTrace == stdout)
360 (void) fflush(NetTrace);
361 return;
363 switch (pointer[0]) {
364 case TELOPT_TTYPE:
365 (void) fprintf(NetTrace, "TERMINAL-TYPE ");
366 switch (pointer[1]) {
367 case TELQUAL_IS:
368 (void) fprintf(NetTrace, "IS \"%.*s\"",
369 length-2,
370 (char *)pointer+2);
371 break;
372 case TELQUAL_SEND:
373 (void) fprintf(NetTrace, "SEND");
374 break;
375 default:
376 (void) fprintf(NetTrace,
377 "- unknown qualifier %d (0x%x).",
378 pointer[1], pointer[1]);
380 break;
381 case TELOPT_TSPEED:
382 (void) fprintf(NetTrace, "TERMINAL-SPEED");
383 if (length < 2) {
384 (void) fprintf(NetTrace,
385 " (empty suboption??\?)");
386 break;
388 switch (pointer[1]) {
389 case TELQUAL_IS:
390 (void) fprintf(NetTrace, " IS ");
391 (void) fprintf(NetTrace, "%.*s", length-2,
392 (char *)pointer+2);
393 break;
394 default:
395 if (pointer[1] == 1)
396 (void) fprintf(NetTrace, " SEND");
397 else
398 (void) fprintf(NetTrace,
399 " %d (unknown)", pointer[1]);
400 for (i = 2; i < length; i++)
401 (void) fprintf(NetTrace, " ?%d?",
402 pointer[i]);
403 break;
405 break;
407 case TELOPT_LFLOW:
408 (void) fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
409 if (length < 2) {
410 (void) fprintf(NetTrace,
411 " (empty suboption??\?)");
412 break;
414 switch (pointer[1]) {
415 case LFLOW_OFF:
416 (void) fprintf(NetTrace, " OFF");
417 break;
418 case LFLOW_ON:
419 (void) fprintf(NetTrace, " ON");
420 break;
421 case LFLOW_RESTART_ANY:
422 (void) fprintf(NetTrace, " RESTART-ANY");
423 break;
424 case LFLOW_RESTART_XON:
425 (void) fprintf(NetTrace, " RESTART-XON");
426 break;
427 default:
428 (void) fprintf(NetTrace, " %d (unknown)",
429 pointer[1]);
431 for (i = 2; i < length; i++)
432 (void) fprintf(NetTrace, " ?%d?",
433 pointer[i]);
434 break;
436 case TELOPT_NAWS:
437 (void) fprintf(NetTrace, "NAWS");
438 if (length < 2) {
439 (void) fprintf(NetTrace,
440 " (empty suboption??\?)");
441 break;
443 if (length == 2) {
444 (void) fprintf(NetTrace, " ?%d?", pointer[1]);
445 break;
447 (void) fprintf(NetTrace, " %d %d (%d)",
448 pointer[1], pointer[2],
449 (int)((((unsigned int)pointer[1])<<8)|
450 ((unsigned int)pointer[2])));
451 if (length == 4) {
452 (void) fprintf(NetTrace, " ?%d?", pointer[3]);
453 break;
455 (void) fprintf(NetTrace, " %d %d (%d)",
456 pointer[3], pointer[4],
457 (int)((((unsigned int)pointer[3])<<8)|
458 ((unsigned int)pointer[4])));
459 for (i = 5; i < length; i++)
460 (void) fprintf(NetTrace, " ?%d?", pointer[i]);
461 break;
463 case TELOPT_AUTHENTICATION:
464 (void) fprintf(NetTrace, "AUTHENTICATION");
465 if (length < 2) {
466 (void) fprintf(NetTrace,
467 " (empty suboption??\?)");
468 break;
470 switch (pointer[1]) {
471 case TELQUAL_REPLY:
472 case TELQUAL_IS:
473 (void) fprintf(NetTrace, " %s ",
474 (pointer[1] == TELQUAL_IS) ?
475 "IS" : "REPLY");
476 if (AUTHTYPE_NAME_OK(pointer[2]))
477 (void) fprintf(NetTrace, "%s ",
478 AUTHTYPE_NAME(pointer[2]));
479 else
480 (void) fprintf(NetTrace, "%d ",
481 pointer[2]);
482 if (length < 3) {
483 (void) fprintf(NetTrace,
484 "(partial suboption??\?)");
485 break;
487 (void) fprintf(NetTrace, "%s|%s",
488 ((pointer[3] & AUTH_WHO_MASK) ==
489 AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER",
490 ((pointer[3] & AUTH_HOW_MASK) ==
491 AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY");
493 auth_printsub(&pointer[1], length - 1,
494 (uchar_t *)buf, sizeof (buf));
495 (void) fprintf(NetTrace, "%s", buf);
496 break;
498 case TELQUAL_SEND:
499 i = 2;
500 (void) fprintf(NetTrace, " SEND ");
501 while (i < length) {
502 if (AUTHTYPE_NAME_OK(pointer[i]))
503 (void) fprintf(NetTrace, "%s ",
504 AUTHTYPE_NAME(pointer[i]));
505 else
506 (void) fprintf(NetTrace, "%d ",
507 pointer[i]);
508 if (++i >= length) {
509 (void) fprintf(NetTrace,
510 "(partial "
511 "suboption??\?)");
512 break;
514 (void) fprintf(NetTrace, "%s|%s ",
515 ((pointer[i] & AUTH_WHO_MASK) ==
516 AUTH_WHO_CLIENT) ?
517 "CLIENT" : "SERVER",
518 ((pointer[i] & AUTH_HOW_MASK) ==
519 AUTH_HOW_MUTUAL) ?
520 "MUTUAL" : "ONE-WAY");
521 ++i;
523 break;
525 case TELQUAL_NAME:
526 i = 2;
527 (void) fprintf(NetTrace, " NAME \"");
528 while (i < length)
529 (void) putc(pointer[i++], NetTrace);
530 (void) putc('"', NetTrace);
531 break;
533 default:
534 for (i = 2; i < length; i++)
535 (void) fprintf(NetTrace, " ?%d?", pointer[i]);
536 break;
538 break;
540 case TELOPT_ENCRYPT:
541 (void) fprintf(NetTrace, "ENCRYPT");
542 if (length < 2) {
543 (void) fprintf(NetTrace,
544 " (empty suboption??\?)");
545 break;
547 switch (pointer[1]) {
548 case ENCRYPT_START:
549 (void) fprintf(NetTrace, " START");
550 break;
552 case ENCRYPT_END:
553 (void) fprintf(NetTrace, " END");
554 break;
556 case ENCRYPT_REQSTART:
557 (void) fprintf(NetTrace, " REQUEST-START");
558 break;
560 case ENCRYPT_REQEND:
561 (void) fprintf(NetTrace, " REQUEST-END");
562 break;
564 case ENCRYPT_IS:
565 case ENCRYPT_REPLY:
566 (void) fprintf(NetTrace, " %s ",
567 (pointer[1] == ENCRYPT_IS) ?
568 "IS" : "REPLY");
569 if (length < 3) {
570 (void) fprintf(NetTrace, " (partial "
571 "suboption??\?)");
572 break;
574 if (ENCTYPE_NAME_OK(pointer[2]))
575 (void) fprintf(NetTrace, "%s ",
576 ENCTYPE_NAME(pointer[2]));
577 else
578 (void) fprintf(NetTrace,
579 " %d (unknown)", pointer[2]);
581 encrypt_printsub(&pointer[1], length - 1,
582 (uchar_t *)buf, sizeof (buf));
583 (void) fprintf(NetTrace, "%s", buf);
584 break;
586 case ENCRYPT_SUPPORT:
587 i = 2;
588 (void) fprintf(NetTrace, " SUPPORT ");
589 while (i < length) {
590 if (ENCTYPE_NAME_OK(pointer[i]))
591 (void) fprintf(NetTrace, "%s ",
592 ENCTYPE_NAME(pointer[i]));
593 else
594 (void) fprintf(NetTrace, "%d ",
595 pointer[i]);
596 i++;
598 break;
600 case ENCRYPT_ENC_KEYID:
601 (void) fprintf(NetTrace, " ENC_KEYID ");
602 goto encommon;
604 case ENCRYPT_DEC_KEYID:
605 (void) fprintf(NetTrace, " DEC_KEYID ");
606 goto encommon;
608 default:
609 (void) fprintf(NetTrace, " %d (unknown)",
610 pointer[1]);
611 encommon:
612 for (i = 2; i < length; i++)
613 (void) fprintf(NetTrace, " %d",
614 pointer[i]);
615 break;
617 break;
619 case TELOPT_LINEMODE:
620 (void) fprintf(NetTrace, "LINEMODE ");
621 if (length < 2) {
622 (void) fprintf(NetTrace,
623 " (empty suboption??\?)");
624 break;
626 switch (pointer[1]) {
627 case WILL:
628 (void) fprintf(NetTrace, "WILL ");
629 goto common;
630 case WONT:
631 (void) fprintf(NetTrace, "WONT ");
632 goto common;
633 case DO:
634 (void) fprintf(NetTrace, "DO ");
635 goto common;
636 case DONT:
637 (void) fprintf(NetTrace, "DONT ");
638 common:
639 if (length < 3) {
640 (void) fprintf(NetTrace,
641 "(no option??\?)");
642 break;
644 switch (pointer[2]) {
645 case LM_FORWARDMASK:
646 (void) fprintf(NetTrace,
647 "Forward Mask");
648 for (i = 3; i < length; i++)
649 (void) fprintf(NetTrace, " %x",
650 pointer[i]);
651 break;
652 default:
653 (void) fprintf(NetTrace, "%d (unknown)",
654 pointer[2]);
655 for (i = 3; i < length; i++)
656 (void) fprintf(NetTrace,
657 " %d", pointer[i]);
658 break;
660 break;
662 case LM_SLC:
663 (void) fprintf(NetTrace, "SLC");
664 for (i = 2; i < length - 2; i += 3) {
665 if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
666 (void) fprintf(NetTrace, " %s",
667 SLC_NAME(pointer[
668 i+SLC_FUNC]));
669 else
670 (void) fprintf(NetTrace, " %d",
671 pointer[i+SLC_FUNC]);
672 switch (pointer[i+SLC_FLAGS] &
673 SLC_LEVELBITS) {
674 case SLC_NOSUPPORT:
675 (void) fprintf(NetTrace,
676 " NOSUPPORT");
677 break;
678 case SLC_CANTCHANGE:
679 (void) fprintf(NetTrace,
680 " CANTCHANGE");
681 break;
682 case SLC_VARIABLE:
683 (void) fprintf(NetTrace,
684 " VARIABLE");
685 break;
686 case SLC_DEFAULT:
687 (void) fprintf(NetTrace,
688 " DEFAULT");
689 break;
691 (void) fprintf(NetTrace, "%s%s%s",
692 pointer[i+SLC_FLAGS]&SLC_ACK ?
693 "|ACK" : "",
694 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ?
695 "|FLUSHIN" : "",
696 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ?
697 "|FLUSHOUT" : "");
698 if (pointer[i+SLC_FLAGS] &
699 ~(SLC_ACK|SLC_FLUSHIN|
700 SLC_FLUSHOUT| SLC_LEVELBITS))
701 (void) fprintf(NetTrace, "(0x%x)",
702 pointer[i+SLC_FLAGS]);
703 (void) fprintf(NetTrace, " %d;",
704 pointer[i+SLC_VALUE]);
705 if ((pointer[i+SLC_VALUE] == IAC) &&
706 (pointer[i+SLC_VALUE+1] == IAC))
707 i++;
709 for (; i < length; i++)
710 (void) fprintf(NetTrace, " ?%d?",
711 pointer[i]);
712 break;
714 case LM_MODE:
715 (void) fprintf(NetTrace, "MODE ");
716 if (length < 3) {
717 (void) fprintf(NetTrace,
718 "(no mode??\?)");
719 break;
722 char tbuf[64];
723 (void) sprintf(tbuf, "%s%s%s%s%s",
724 pointer[2]&MODE_EDIT ? "|EDIT" : "",
725 pointer[2]&MODE_TRAPSIG ?
726 "|TRAPSIG" : "",
727 pointer[2]&MODE_SOFT_TAB ?
728 "|SOFT_TAB" : "",
729 pointer[2]&MODE_LIT_ECHO ?
730 "|LIT_ECHO" : "",
731 pointer[2]&MODE_ACK ? "|ACK" : "");
732 (void) fprintf(NetTrace, "%s", tbuf[1] ?
733 &tbuf[1] : "0");
735 if (pointer[2]&~(MODE_MASK))
736 (void) fprintf(NetTrace, " (0x%x)",
737 pointer[2]);
738 for (i = 3; i < length; i++)
739 (void) fprintf(NetTrace, " ?0x%x?",
740 pointer[i]);
741 break;
742 default:
743 (void) fprintf(NetTrace, "%d (unknown)",
744 pointer[1]);
745 for (i = 2; i < length; i++)
746 (void) fprintf(NetTrace, " %d",
747 pointer[i]);
749 break;
751 case TELOPT_STATUS: {
752 register char *cp;
753 register int j, k;
755 (void) fprintf(NetTrace, "STATUS");
757 switch (pointer[1]) {
758 default:
759 if (pointer[1] == TELQUAL_SEND)
760 (void) fprintf(NetTrace,
761 " SEND");
762 else
763 (void) fprintf(NetTrace,
764 " %d (unknown)",
765 pointer[1]);
766 for (i = 2; i < length; i++)
767 (void) fprintf(NetTrace, " ?%d?",
768 pointer[i]);
769 break;
770 case TELQUAL_IS:
771 if (--want_status_response < 0)
772 want_status_response = 0;
773 if (NetTrace == stdout)
774 (void) fprintf(NetTrace,
775 " IS\r\n");
776 else
777 (void) fprintf(NetTrace,
778 " IS\n");
780 for (i = 2; i < length; i++) {
781 switch (pointer[i]) {
782 case DO:
783 cp = "DO";
784 goto common2;
785 case DONT:
786 cp = "DONT";
787 goto common2;
788 case WILL:
789 cp = "WILL";
790 goto common2;
791 case WONT:
792 cp = "WONT";
793 goto common2;
794 common2:
795 i++;
796 if (TELOPT_OK(
797 (int)pointer[i]))
798 (void) fprintf(
799 NetTrace,
800 " %s %s",
802 TELOPT(
803 pointer[
804 i]));
805 else
806 (void) fprintf(
807 NetTrace,
808 " %s %d",
810 pointer[i]);
812 if (NetTrace == stdout)
813 (void) fprintf(
814 NetTrace,
815 "\r\n");
816 else
817 (void) fprintf(
818 NetTrace,
819 "\n");
820 break;
822 case SB:
823 (void) fprintf(NetTrace,
824 " SB ");
825 i++;
826 j = k = i;
827 while (j < length) {
828 if (pointer[j] == SE) {
829 if (j+1 == length)
830 break;
831 if (pointer[j+1] == SE)
832 j++;
833 else
834 break;
836 pointer[k++] = pointer[j++];
838 printsub(0,
839 &pointer[i], k - i);
840 if (i < length) {
841 (void) fprintf(NetTrace, " SE");
842 i = j;
843 } else
844 i = j - 1;
846 if (NetTrace == stdout)
847 (void) fprintf(NetTrace, "\r\n");
848 else
849 (void) fprintf(NetTrace, "\n");
851 break;
853 default:
854 (void) fprintf(NetTrace,
855 " %d", pointer[i]);
856 break;
859 break;
861 break;
864 case TELOPT_XDISPLOC:
865 (void) fprintf(NetTrace, "X-DISPLAY-LOCATION ");
866 switch (pointer[1]) {
867 case TELQUAL_IS:
868 (void) fprintf(NetTrace, "IS \"%.*s\"",
869 length-2, (char *)pointer+2);
870 break;
871 case TELQUAL_SEND:
872 (void) fprintf(NetTrace, "SEND");
873 break;
874 default:
875 (void) fprintf(NetTrace,
876 "- unknown qualifier %d (0x%x).",
877 pointer[1], pointer[1]);
879 break;
881 case TELOPT_NEW_ENVIRON:
882 (void) fprintf(NetTrace, "NEW-ENVIRON ");
883 #ifdef OLD_ENVIRON
884 goto env_common1;
885 case TELOPT_OLD_ENVIRON:
886 (void) fprintf(NetTrace, "OLD-ENVIRON ");
887 env_common1:
888 #endif
889 switch (pointer[1]) {
890 case TELQUAL_IS:
891 (void) fprintf(NetTrace, "IS ");
892 goto env_common;
893 case TELQUAL_SEND:
894 (void) fprintf(NetTrace, "SEND ");
895 goto env_common;
896 case TELQUAL_INFO:
897 (void) fprintf(NetTrace, "INFO ");
898 env_common:
900 register int noquote = 2;
901 #if defined(ENV_HACK) && defined(OLD_ENVIRON)
902 extern int old_env_var, old_env_value;
903 #endif
904 for (i = 2; i < length; i++) {
905 switch (pointer[i]) {
906 case NEW_ENV_VALUE:
907 #ifdef OLD_ENVIRON
908 /* case NEW_ENV_OVAR: */
909 if (pointer[0] == TELOPT_OLD_ENVIRON) {
910 #ifdef ENV_HACK
911 if (old_env_var == OLD_ENV_VALUE)
912 (void) fprintf(NetTrace,
913 "\" (VALUE) " + noquote);
914 else
915 #endif
916 (void) fprintf(NetTrace,
917 "\" VAR " + noquote);
918 } else
919 #endif /* OLD_ENVIRON */
920 (void) fprintf(NetTrace, "\" VALUE " + noquote);
921 noquote = 2;
922 break;
924 case NEW_ENV_VAR:
925 #ifdef OLD_ENVIRON
926 /* case OLD_ENV_VALUE: */
927 if (pointer[0] == TELOPT_OLD_ENVIRON) {
928 #ifdef ENV_HACK
929 if (old_env_value == OLD_ENV_VAR)
930 (void) fprintf(NetTrace,
931 "\" (VAR) " + noquote);
932 else
933 #endif
934 (void) fprintf(NetTrace,
935 "\" VALUE " + noquote);
936 } else
937 #endif /* OLD_ENVIRON */
938 (void) fprintf(NetTrace, "\" VAR " + noquote);
939 noquote = 2;
940 break;
942 case ENV_ESC:
943 (void) fprintf(NetTrace, "\" ESC " + noquote);
944 noquote = 2;
945 break;
947 case ENV_USERVAR:
948 (void) fprintf(NetTrace, "\" USERVAR " + noquote);
949 noquote = 2;
950 break;
952 default:
953 def_case:
954 if (isprint(pointer[i]) && pointer[i] != '"') {
955 if (noquote) {
956 (void) putc('"', NetTrace);
957 noquote = 0;
959 (void) putc(pointer[i], NetTrace);
960 } else {
961 (void) fprintf(NetTrace, "\" %03o " + noquote,
962 pointer[i]);
963 noquote = 2;
965 break;
968 if (!noquote)
969 (void) putc('"', NetTrace);
970 break;
973 break;
975 default:
976 if (TELOPT_OK(pointer[0]))
977 (void) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
978 else
979 (void) fprintf(NetTrace, "%d (unknown)", pointer[0]);
980 for (i = 1; i < length; i++)
981 (void) fprintf(NetTrace, " %d", pointer[i]);
982 break;
984 if (direction) {
985 if (NetTrace == stdout)
986 (void) fprintf(NetTrace, "\r\n");
987 else
988 (void) fprintf(NetTrace, "\n");
990 if (NetTrace == stdout)
991 (void) fflush(NetTrace);
996 * EmptyTerminal - called to make sure that the terminal buffer is empty.
997 * Note that we consider the buffer to run all the
998 * way to the kernel (thus the select).
1001 static void
1002 EmptyTerminal()
1004 fd_set o;
1006 FD_ZERO(&o);
1008 if (TTYBYTES() == 0) {
1009 FD_SET(tout, &o);
1010 /* wait for TTLOWAT */
1011 (void) select(tout+1, NULL, &o, NULL, NULL);
1012 } else {
1013 while (TTYBYTES()) {
1014 if (ttyflush(0) == -2) {
1015 /* This will not return. */
1016 fatal_tty_error("write");
1018 FD_SET(tout, &o);
1019 /* wait for TTLOWAT */
1020 (void) select(tout+1, NULL, &o, NULL, NULL);
1025 static void
1026 SetForExit()
1028 setconnmode(0);
1029 do {
1030 (void) telrcv(); /* Process any incoming data */
1031 EmptyTerminal();
1032 } while (ring_full_count(&netiring)); /* While there is any */
1033 setcommandmode();
1034 (void) fflush(stdout);
1035 (void) fflush(stderr);
1036 setconnmode(0);
1037 EmptyTerminal(); /* Flush the path to the tty */
1038 setcommandmode();
1041 void
1042 Exit(returnCode)
1043 int returnCode;
1045 SetForExit();
1046 exit(returnCode);
1049 void
1050 ExitString(string, returnCode)
1051 char *string;
1052 int returnCode;
1054 SetForExit();
1055 (void) fwrite(string, 1, strlen(string), stderr);
1056 exit(returnCode);
1059 #define BUFFER_CHUNK_SIZE 64
1061 /* Round up to a multiple of BUFFER_CHUNK_SIZE */
1062 #define ROUND_CHUNK_SIZE(s) ((((s) + BUFFER_CHUNK_SIZE - 1) / \
1063 BUFFER_CHUNK_SIZE) * BUFFER_CHUNK_SIZE)
1066 * Optionally allocate a buffer, and optionally read a string from a stream
1067 * into the buffer, starting at the given offset. If the buffer isn't
1068 * large enough for the given offset, or if buffer space is exhausted
1069 * when reading the string, the size of the buffer is increased.
1071 * A buffer can be supplied when the function is called, passing the
1072 * buffer address via the first argument. The buffer size can be
1073 * passed as well, in the second argument. If the second argument is
1074 * NULL, the function makes no assumptions about the buffer size.
1075 * The address of the buffer is returned via the first argument, and the
1076 * buffer size via the second argument if this is not NULL.
1077 * These returned values may differ from the supplied values if the buffer
1078 * was reallocated.
1080 * If no buffer is to be supplied, specify a buffer address of NULL, via
1081 * the first argument.
1083 * If the pointer to the buffer address is NULL, the function just returns
1084 * NULL, and performs no other processing.
1086 * If a NULL stream is passed, the function will just make sure the
1087 * supplied buffer is large enough to hold the supplied offset,
1088 * reallocating it if is too small or too large.
1090 * The returned buffer will be a multiple of BUFFER_CHUNK_SIZE in size.
1092 * The function stops reading from the stream when a newline is read,
1093 * end of file is reached, or an error occurs. The newline is not
1094 * returned in the buffer. The returned string will be NULL terminated.
1096 * The function returns the address of the buffer if any characters
1097 * are read and no error occurred, otherwise it returns NULL.
1099 * If the function returns NULL, a buffer may have been allocated. The
1100 * buffer address will be returned via the first argument, together with
1101 * the buffer size if the second argument is not NULL.
1104 static char *
1105 GetStringAtOffset(bufp, cbufsiz, off, st)
1106 char **bufp;
1107 unsigned int *cbufsiz;
1108 unsigned int off;
1109 FILE *st;
1111 unsigned int bufsiz;
1112 char *buf;
1113 char *nbuf;
1114 unsigned int idx = off;
1116 if (bufp == NULL)
1117 return (NULL);
1119 buf = *bufp;
1121 bufsiz = ROUND_CHUNK_SIZE(off + 1);
1123 if (buf == NULL || cbufsiz == NULL || *cbufsiz != bufsiz) {
1124 if ((nbuf = realloc(buf, bufsiz)) == NULL)
1125 return (NULL);
1127 buf = nbuf;
1128 *bufp = buf;
1129 if (cbufsiz != NULL)
1130 *cbufsiz = bufsiz;
1134 if (st == NULL)
1135 return (buf);
1137 clearerr(st);
1138 for (;;) {
1139 int c = getc(st);
1141 /* Expand the buffer as needed. */
1142 if (idx == bufsiz) {
1143 bufsiz += BUFFER_CHUNK_SIZE;
1144 if ((nbuf = realloc(buf, bufsiz)) == NULL) {
1145 /* Discard everything we read. */
1146 buf[off] = 0;
1147 buf = NULL;
1148 break;
1150 buf = nbuf;
1151 *bufp = buf;
1152 if (cbufsiz != NULL)
1153 *cbufsiz = bufsiz;
1156 if (c == EOF || c == '\n') {
1157 buf[idx] = 0;
1158 if (ferror(st) != 0) {
1159 /* Retry if interrupted by a signal. */
1160 if (errno == EINTR) {
1161 clearerr(st);
1162 continue;
1164 buf = NULL;
1165 } else if (feof(st) != 0) {
1166 /* No characters transferred? */
1167 if (off == idx)
1168 buf = NULL;
1170 break;
1172 buf[idx++] = c;
1174 return (buf);
1178 * Read a string from the supplied stream. Stop reading when a newline
1179 * is read, end of file reached, or an error occurs.
1181 * A buffer can be supplied by specifying the buffer address via the
1182 * first argument. The buffer size can be passed via the second argument.
1183 * If the second argument is NULL, the function makes no assumptions
1184 * about the buffer size. The buffer will be reallocated if it is too
1185 * small or too large for the returned string.
1187 * If no buffer is to be supplied, specify a buffer address of NULL,
1188 * via the first argument.
1190 * If the first argument is NULL, the function just returns NULL, and
1191 * performs no other processing.
1193 * The function returns the address of the buffer if any characters are
1194 * read and no error occurred.
1196 * If the function returns NULL, a buffer may have been allocated. The
1197 * buffer address and buffer size will be returned via the first argument,
1198 * and the buffer size via the second argument, if this isn't NULL.
1200 char *
1201 GetString(bufp, bufsiz, st)
1202 char **bufp;
1203 unsigned int *bufsiz;
1204 FILE *st;
1206 return (GetStringAtOffset(bufp, bufsiz, 0, st));
1210 * Allocate a buffer to hold a string of given length.
1212 * An existing buffer can be reallocated by passing its address and via
1213 * the first argument. The buffer size can be passed via the second
1214 * argument. If the second argument is NULL, the function makes no
1215 * assumptions about the buffer size.
1217 * If no existing buffer is to be supplied, pass a NULL buffer address via
1218 * the first argument.
1220 * If the first argument is NULL, the function just returns NULL,
1221 * and performs no other processing.
1223 char *
1224 AllocStringBuffer(bufp, bufsiz, size)
1225 char **bufp;
1226 unsigned int *bufsiz;
1227 unsigned int size;
1229 return (GetStringAtOffset(bufp, bufsiz, size, NULL));
1233 * This function is similar to GetString(), except that the string read
1234 * from the stream is appended to the supplied string.
1236 char *
1237 GetAndAppendString(bufp, bufsiz, str, st)
1238 char **bufp;
1239 unsigned int *bufsiz;
1240 char *str;
1241 FILE *st;
1243 unsigned int off = strlen(str);
1245 if (GetStringAtOffset(bufp, bufsiz, off, st) == NULL)
1246 return (NULL);
1248 return (memcpy(*bufp, str, off));