Telnet AUTHENTICATION option
[unix-history] / usr / src / libexec / telnetd / utility.c
CommitLineData
ea139302
PB
1/*
2 * Copyright (c) 1989 Regents of the University of California.
3 * All rights reserved.
4 *
836fe169 5 * %sccs.include.redist.c%
ea139302
PB
6 */
7
8#ifndef lint
4f73d56c 9static char sccsid[] = "@(#)utility.c 5.6 (Berkeley) %G%";
ea139302
PB
10#endif /* not lint */
11
4a8a7128 12#define PRINTOPTIONS
ea139302
PB
13#include "telnetd.h"
14
15/*
16 * utility functions performing io related tasks
17 */
18
19/*
20 * ttloop
21 *
22 * A small subroutine to flush the network output buffer, get some data
23 * from the network, and pass it through the telnet state machine. We
24 * also flush the pty input buffer (by dropping its data) if it becomes
25 * too full.
26 */
27
28void
29ttloop()
30{
31 void netflush();
32
4a8a7128
PB
33#ifdef DIAGNOSTICS
34 if (diagnostic & TD_REPORT) {
35 sprintf(nfrontp, "td: ttloop\r\n");
36 nfrontp += strlen(nfrontp);
37 }
38#endif /* DIAGNOSTICS */
ea139302
PB
39 if (nfrontp-nbackp) {
40 netflush();
41 }
42 ncc = read(net, netibuf, sizeof netibuf);
43 if (ncc < 0) {
44 syslog(LOG_INFO, "ttloop: read: %m\n");
45 exit(1);
46 } else if (ncc == 0) {
47 syslog(LOG_INFO, "ttloop: peer died: %m\n");
48 exit(1);
49 }
4a8a7128
PB
50#ifdef DIAGNOSTICS
51 if (diagnostic & TD_REPORT) {
52 sprintf(nfrontp, "td: ttloop read %d chars\r\n", ncc);
53 nfrontp += strlen(nfrontp);
54 }
55#endif /* DIAGNOSTICS */
ea139302
PB
56 netip = netibuf;
57 telrcv(); /* state machine */
58 if (ncc > 0) {
59 pfrontp = pbackp = ptyobuf;
60 telrcv();
61 }
62} /* end of ttloop */
63
64/*
65 * Check a descriptor to see if out of band data exists on it.
66 */
67stilloob(s)
68int s; /* socket number */
69{
70 static struct timeval timeout = { 0 };
71 fd_set excepts;
72 int value;
73
74 do {
75 FD_ZERO(&excepts);
76 FD_SET(s, &excepts);
77 value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
78 } while ((value == -1) && (errno == EINTR));
79
80 if (value < 0) {
81 fatalperror(pty, "select");
82 }
83 if (FD_ISSET(s, &excepts)) {
84 return 1;
85 } else {
86 return 0;
87 }
88}
89
90ptyflush()
91{
92 int n;
93
4a8a7128
PB
94 if ((n = pfrontp - pbackp) > 0) {
95#ifdef DIAGNOSTICS
96 if (diagnostic & (TD_REPORT | TD_PTYDATA)) {
97 sprintf(nfrontp, "td: ptyflush %d chars\r\n", n);
98 nfrontp += strlen(nfrontp);
99 }
100 if (diagnostic & TD_PTYDATA) {
101 printdata("pd", pbackp, n);
102 }
103#endif /* DIAGNOSTICS */
ea139302 104 n = write(pty, pbackp, n);
4a8a7128 105 }
ea139302
PB
106 if (n < 0)
107 return;
108 pbackp += n;
109 if (pbackp == pfrontp)
110 pbackp = pfrontp = ptyobuf;
111}
112
113/*
114 * nextitem()
115 *
116 * Return the address of the next "item" in the TELNET data
117 * stream. This will be the address of the next character if
118 * the current address is a user data character, or it will
119 * be the address of the character following the TELNET command
120 * if the current address is a TELNET IAC ("I Am a Command")
121 * character.
122 */
123char *
124nextitem(current)
125char *current;
126{
127 if ((*current&0xff) != IAC) {
128 return current+1;
129 }
130 switch (*(current+1)&0xff) {
131 case DO:
132 case DONT:
133 case WILL:
134 case WONT:
135 return current+3;
136 case SB: /* loop forever looking for the SE */
137 {
138 register char *look = current+2;
139
140 for (;;) {
141 if ((*look++&0xff) == IAC) {
142 if ((*look++&0xff) == SE) {
143 return look;
144 }
145 }
146 }
147 }
148 default:
149 return current+2;
150 }
151} /* end of nextitem */
152
153
154/*
155 * netclear()
156 *
157 * We are about to do a TELNET SYNCH operation. Clear
158 * the path to the network.
159 *
160 * Things are a bit tricky since we may have sent the first
161 * byte or so of a previous TELNET command into the network.
162 * So, we have to scan the network buffer from the beginning
163 * until we are up to where we want to be.
164 *
165 * A side effect of what we do, just to keep things
166 * simple, is to clear the urgent data pointer. The principal
167 * caller should be setting the urgent data pointer AFTER calling
168 * us in any case.
169 */
170netclear()
171{
172 register char *thisitem, *next;
173 char *good;
174#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
175 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
176
177 thisitem = netobuf;
178
179 while ((next = nextitem(thisitem)) <= nbackp) {
180 thisitem = next;
181 }
182
183 /* Now, thisitem is first before/at boundary. */
184
185 good = netobuf; /* where the good bytes go */
186
187 while (nfrontp > thisitem) {
188 if (wewant(thisitem)) {
189 int length;
190
191 next = thisitem;
192 do {
193 next = nextitem(next);
194 } while (wewant(next) && (nfrontp > next));
195 length = next-thisitem;
196 bcopy(thisitem, good, length);
197 good += length;
198 thisitem = next;
199 } else {
200 thisitem = nextitem(thisitem);
201 }
202 }
203
204 nbackp = netobuf;
205 nfrontp = good; /* next byte to be sent */
206 neturg = 0;
207} /* end of netclear */
208
209/*
210 * netflush
211 * Send as much data as possible to the network,
212 * handling requests for urgent data.
213 */
214void
215netflush()
216{
217 int n;
218 extern int not42;
219
220 if ((n = nfrontp - nbackp) > 0) {
4a8a7128
PB
221#ifdef DIAGNOSTICS
222 if (diagnostic & TD_REPORT) {
223 sprintf(nfrontp, "td: netflush %d chars\r\n", n);
224 n += strlen(nfrontp); /* get count first */
225 nfrontp += strlen(nfrontp); /* then move pointer */
226 }
227#endif /* DIAGNOSTICS */
ea139302
PB
228 /*
229 * if no urgent data, or if the other side appears to be an
230 * old 4.2 client (and thus unable to survive TCP urgent data),
231 * write the entire buffer in non-OOB mode.
232 */
233 if ((neturg == 0) || (not42 == 0)) {
234 n = write(net, nbackp, n); /* normal write */
235 } else {
236 n = neturg - nbackp;
237 /*
238 * In 4.2 (and 4.3) systems, there is some question about
239 * what byte in a sendOOB operation is the "OOB" data.
240 * To make ourselves compatible, we only send ONE byte
241 * out of band, the one WE THINK should be OOB (though
242 * we really have more the TCP philosophy of urgent data
243 * rather than the Unix philosophy of OOB data).
244 */
245 if (n > 1) {
246 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
247 } else {
248 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
249 }
250 }
251 }
252 if (n < 0) {
253 if (errno == EWOULDBLOCK || errno == EINTR)
254 return;
255 cleanup();
256 }
257 nbackp += n;
258 if (nbackp >= neturg) {
259 neturg = 0;
260 }
261 if (nbackp == nfrontp) {
262 nbackp = nfrontp = netobuf;
263 }
264 return;
265} /* end of netflush */
266
267
268/*
269 * writenet
270 *
271 * Just a handy little function to write a bit of raw data to the net.
272 * It will force a transmit of the buffer if necessary
273 *
274 * arguments
275 * ptr - A pointer to a character string to write
276 * len - How many bytes to write
277 */
278writenet(ptr, len)
279register char *ptr;
280register int len;
281{
282 /* flush buffer if no room for new data) */
283 if ((&netobuf[BUFSIZ] - nfrontp) < len) {
284 /* if this fails, don't worry, buffer is a little big */
285 netflush();
286 }
287
288 bcopy(ptr, nfrontp, len);
289 nfrontp += len;
290
291} /* end of writenet */
292
293
294/*
295 * miscellaneous functions doing a variety of little jobs follow ...
296 */
297
298
299fatal(f, msg)
300 int f;
301 char *msg;
302{
303 char buf[BUFSIZ];
304
305 (void) sprintf(buf, "telnetd: %s.\r\n", msg);
306 (void) write(f, buf, (int)strlen(buf));
307 sleep(1); /*XXX*/
308 exit(1);
309}
310
311fatalperror(f, msg)
312 int f;
313 char *msg;
314{
396aa79f 315 char buf[BUFSIZ], *strerror();
ea139302 316
396aa79f 317 (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno));
ea139302
PB
318 fatal(f, buf);
319}
320
321char editedhost[32];
322
323edithost(pat, host)
324 register char *pat;
325 register char *host;
326{
327 register char *res = editedhost;
328 char *strncpy();
329
330 if (!pat)
331 pat = "";
332 while (*pat) {
333 switch (*pat) {
334
335 case '#':
336 if (*host)
337 host++;
338 break;
339
340 case '@':
341 if (*host)
342 *res++ = *host++;
343 break;
344
345 default:
346 *res++ = *pat;
347 break;
348 }
349 if (res == &editedhost[sizeof editedhost - 1]) {
350 *res = '\0';
351 return;
352 }
353 pat++;
354 }
355 if (*host)
356 (void) strncpy(res, host,
357 sizeof editedhost - (res - editedhost) -1);
358 else
359 *res = '\0';
360 editedhost[sizeof editedhost - 1] = '\0';
361}
362
363static char *putlocation;
364
365putstr(s)
366register char *s;
367{
368
369 while (*s)
370 putchr(*s++);
371}
372
373putchr(cc)
374{
375 *putlocation++ = cc;
376}
377
378putf(cp, where)
379register char *cp;
380char *where;
381{
977a0c8c
KB
382 time_t t;
383 char *fmt, *slash, db[100];
ea139302
PB
384 extern char *rindex();
385
386 putlocation = where;
387
388 while (*cp) {
389 if (*cp != '%') {
390 putchr(*cp++);
391 continue;
392 }
393 switch (*++cp) {
394
395 case 't':
396 slash = rindex(line, '/');
397 if (slash == (char *) 0)
398 putstr(line);
399 else
400 putstr(&slash[1]);
401 break;
402
403 case 'h':
404 putstr(editedhost);
405 break;
406
4f73d56c
KB
407 case 'd': {
408 char fmt[] = "%l:% %P on %A, %d %B %Y";
409
410 fmt[4] = 'M'; /* I *hate* SCCS... */
977a0c8c 411 (void)time(&t);
4f73d56c 412 (void)strftime(db, sizeof(db), fmt, localtime(&t));
977a0c8c 413 putstr(db);
ea139302 414 break;
4f73d56c 415 }
ea139302
PB
416
417 case '%':
418 putchr('%');
419 break;
420 }
421 cp++;
422 }
423}
424
425/*ARGSUSED*/
426#ifdef NO_GETTYTAB
427getent(cp, name)
428char *cp, *name;
429{
430 return(0);
431}
432
433/*ARGSUSED*/
434char *
435getstr(cp, cpp)
436char *cp, **cpp;
437{
438 return(0);
439}
440#endif /* NO_GETTYTAB */
4a8a7128
PB
441
442#ifdef DIAGNOSTICS
443/*
444 * Print telnet options and commands in plain text, if possible.
445 */
446void
447printoption(fmt, option)
448register char *fmt;
449register int option;
450{
451 if (TELOPT_OK(option))
452 sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option));
453 else if (TELCMD_OK(option))
454 sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option));
455 else
456 sprintf(nfrontp, "%s %d\r\n", fmt, option);
457 nfrontp += strlen(nfrontp);
458 return;
459}
460
461char *slcnames[] = { SLC_NAMES };
462
463void
464printsub(dirp, pointer, length)
465char *dirp;
466unsigned char *pointer; /* where suboption data sits */
467int length; /* length of suboption data */
468{
469 register int i;
470
471 if (dirp) {
472 sprintf(nfrontp, "%s suboption ", dirp);
473 nfrontp += strlen(nfrontp);
474 if (length >= 3) {
475 register int j;
476
477 i = pointer[length-2];
478 j = pointer[length-1];
479
480 if (i != IAC || j != SE) {
481 sprintf(nfrontp, "(terminated by ");
482 nfrontp += strlen(nfrontp);
483 if (TELOPT_OK(i))
484 sprintf(nfrontp, "%s ", TELOPT(i));
485 else if (TELCMD_OK(i))
486 sprintf(nfrontp, "%s ", TELCMD(i));
487 else
488 sprintf(nfrontp, "%d ", i);
489 nfrontp += strlen(nfrontp);
490 if (TELOPT_OK(j))
491 sprintf(nfrontp, "%s", TELOPT(j));
492 else if (TELCMD_OK(j))
493 sprintf(nfrontp, "%s", TELCMD(j));
494 else
495 sprintf(nfrontp, "%d", j);
496 nfrontp += strlen(nfrontp);
497 sprintf(nfrontp, ", not IAC SE!) ");
498 nfrontp += strlen(nfrontp);
499 }
500 }
501 length -= 2;
502 }
503 if (length < 1) {
504 sprintf(nfrontp, "(Empty suboption???)");
505 nfrontp += strlen(nfrontp);
506 return;
507 }
508 switch (pointer[0]) {
509 case TELOPT_TTYPE:
510 sprintf(nfrontp, "TERMINAL-TYPE ");
511 nfrontp += strlen(nfrontp);
512 switch (pointer[1]) {
513 case TELQUAL_IS:
514 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
515 break;
516 case TELQUAL_SEND:
517 sprintf(nfrontp, "SEND");
518 break;
519 default:
520 sprintf(nfrontp,
521 "- unknown qualifier %d (0x%x).",
522 pointer[1], pointer[1]);
523 }
524 nfrontp += strlen(nfrontp);
525 break;
526 case TELOPT_TSPEED:
527 sprintf(nfrontp, "TERMINAL-SPEED");
528 nfrontp += strlen(nfrontp);
529 if (length < 2) {
530 sprintf(nfrontp, " (empty suboption???)");
531 nfrontp += strlen(nfrontp);
532 break;
533 }
534 switch (pointer[1]) {
535 case TELQUAL_IS:
536 sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2);
537 nfrontp += strlen(nfrontp);
538 break;
539 default:
540 if (pointer[1] == 1)
541 sprintf(nfrontp, " SEND");
542 else
543 sprintf(nfrontp, " %d (unknown)", pointer[1]);
544 nfrontp += strlen(nfrontp);
545 for (i = 2; i < length; i++) {
546 sprintf(nfrontp, " ?%d?", pointer[i]);
547 nfrontp += strlen(nfrontp);
548 }
549 break;
550 }
551 break;
552
553 case TELOPT_LFLOW:
554 sprintf(nfrontp, "TOGGLE-FLOW-CONTROL");
555 nfrontp += strlen(nfrontp);
556 if (length < 2) {
557 sprintf(nfrontp, " (empty suboption???)");
558 nfrontp += strlen(nfrontp);
559 break;
560 }
561 switch (pointer[1]) {
562 case 0:
563 sprintf(nfrontp, " OFF"); break;
564 case 1:
565 sprintf(nfrontp, " ON"); break;
566 default:
567 sprintf(nfrontp, " %d (unknown)", pointer[1]);
568 }
569 nfrontp += strlen(nfrontp);
570 for (i = 2; i < length; i++) {
571 sprintf(nfrontp, " ?%d?", pointer[i]);
572 nfrontp += strlen(nfrontp);
573 }
574 break;
575
576 case TELOPT_NAWS:
577 sprintf(nfrontp, "NAWS");
578 nfrontp += strlen(nfrontp);
579 if (length < 2) {
580 sprintf(nfrontp, " (empty suboption???)");
581 nfrontp += strlen(nfrontp);
582 break;
583 }
584 if (length == 2) {
585 sprintf(nfrontp, " ?%d?", pointer[1]);
586 nfrontp += strlen(nfrontp);
587 break;
588 }
589 sprintf(nfrontp, " %d %d (%d)",
590 pointer[1], pointer[2],
591 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
592 nfrontp += strlen(nfrontp);
593 if (length == 4) {
594 sprintf(nfrontp, " ?%d?", pointer[3]);
595 nfrontp += strlen(nfrontp);
596 break;
597 }
598 sprintf(nfrontp, " %d %d (%d)",
599 pointer[3], pointer[4],
600 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
601 nfrontp += strlen(nfrontp);
602 for (i = 5; i < length; i++) {
603 sprintf(nfrontp, " ?%d?", pointer[i]);
604 nfrontp += strlen(nfrontp);
605 }
606 break;
607
608 case TELOPT_LINEMODE:
609 sprintf(nfrontp, "LINEMODE ");
610 nfrontp += strlen(nfrontp);
611 if (length < 2) {
612 sprintf(nfrontp, " (empty suboption???)");
613 nfrontp += strlen(nfrontp);
614 break;
615 }
616 switch (pointer[1]) {
617 case WILL:
618 sprintf(nfrontp, "WILL ");
619 goto common;
620 case WONT:
621 sprintf(nfrontp, "WONT ");
622 goto common;
623 case DO:
624 sprintf(nfrontp, "DO ");
625 goto common;
626 case DONT:
627 sprintf(nfrontp, "DONT ");
628 common:
629 nfrontp += strlen(nfrontp);
630 if (length < 3) {
631 sprintf(nfrontp, "(no option???)");
632 nfrontp += strlen(nfrontp);
633 break;
634 }
635 switch (pointer[2]) {
636 case LM_FORWARDMASK:
637 sprintf(nfrontp, "Forward Mask");
638 nfrontp += strlen(nfrontp);
639 for (i = 3; i < length; i++) {
640 sprintf(nfrontp, " %x", pointer[i]);
641 nfrontp += strlen(nfrontp);
642 }
643 break;
644 default:
645 sprintf(nfrontp, "%d (unknown)", pointer[2]);
646 nfrontp += strlen(nfrontp);
647 for (i = 3; i < length; i++) {
648 sprintf(nfrontp, " %d", pointer[i]);
649 nfrontp += strlen(nfrontp);
650 }
651 break;
652 }
653 break;
654
655 case LM_SLC:
656 sprintf(nfrontp, "SLC");
657 nfrontp += strlen(nfrontp);
658 for (i = 2; i < length - 2; i += 3) {
659 if (pointer[i+SLC_FUNC] <= NSLC)
660 sprintf(nfrontp, " %s", slcnames[pointer[i+SLC_FUNC]]);
661 else
662 sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]);
663 nfrontp += strlen(nfrontp);
664 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
665 case SLC_NOSUPPORT:
666 sprintf(nfrontp, " NOSUPPORT"); break;
667 case SLC_CANTCHANGE:
668 sprintf(nfrontp, " CANTCHANGE"); break;
669 case SLC_VARIABLE:
670 sprintf(nfrontp, " VARIABLE"); break;
671 case SLC_DEFAULT:
672 sprintf(nfrontp, " DEFAULT"); break;
673 }
674 nfrontp += strlen(nfrontp);
675 sprintf(nfrontp, "%s%s%s",
676 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
677 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
678 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
679 nfrontp += strlen(nfrontp);
680 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
681 SLC_FLUSHOUT| SLC_LEVELBITS)) {
682 sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]);
683 nfrontp += strlen(nfrontp);
684 }
685 sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]);
686 nfrontp += strlen(nfrontp);
687 if ((pointer[i+SLC_VALUE] == IAC) &&
688 (pointer[i+SLC_VALUE+1] == IAC))
689 i++;
690 }
691 for (; i < length; i++) {
692 sprintf(nfrontp, " ?%d?", pointer[i]);
693 nfrontp += strlen(nfrontp);
694 }
695 break;
696
697 case LM_MODE:
698 sprintf(nfrontp, "MODE ");
699 nfrontp += strlen(nfrontp);
700 if (length < 3) {
701 sprintf(nfrontp, "(no mode???)");
702 nfrontp += strlen(nfrontp);
703 break;
704 }
705 {
706 char tbuf[32];
707 sprintf(tbuf, "%s%s%s%s%s",
708 pointer[2]&MODE_EDIT ? "|EDIT" : "",
709 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
710 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
711 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
712 pointer[2]&MODE_ACK ? "|ACK" : "");
713 sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0");
714 nfrontp += strlen(nfrontp);
715 }
716 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
717 sprintf(nfrontp, " (0x%x)", pointer[2]);
718 nfrontp += strlen(nfrontp);
719 }
720 for (i = 3; i < length; i++) {
721 sprintf(nfrontp, " ?0x%x?", pointer[i]);
722 nfrontp += strlen(nfrontp);
723 }
724 break;
725 default:
726 sprintf(nfrontp, "%d (unknown)", pointer[1]);
727 nfrontp += strlen(nfrontp);
728 for (i = 2; i < length; i++) {
729 sprintf(nfrontp, " %d", pointer[i]);
730 nfrontp += strlen(nfrontp);
731 }
732 }
733 break;
734
735 case TELOPT_STATUS: {
736 register char *cp;
737 register int j, k;
738
739 sprintf(nfrontp, "STATUS");
740 nfrontp += strlen(nfrontp);
741
742 switch (pointer[1]) {
743 default:
744 if (pointer[1] == TELQUAL_SEND)
745 sprintf(nfrontp, " SEND");
746 else
747 sprintf(nfrontp, " %d (unknown)", pointer[1]);
748 nfrontp += strlen(nfrontp);
749 for (i = 2; i < length; i++) {
750 sprintf(nfrontp, " ?%d?", pointer[i]);
751 nfrontp += strlen(nfrontp);
752 }
753 break;
754 case TELQUAL_IS:
755 sprintf(nfrontp, " IS\r\n");
756 nfrontp += strlen(nfrontp);
757
758 for (i = 2; i < length; i++) {
759 switch(pointer[i]) {
760 case DO: cp = "DO"; goto common2;
761 case DONT: cp = "DONT"; goto common2;
762 case WILL: cp = "WILL"; goto common2;
763 case WONT: cp = "WONT"; goto common2;
764 common2:
765 i++;
766 if (TELOPT_OK((int)pointer[i]))
767 sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i]));
768 else
769 sprintf(nfrontp, " %s %d", cp, pointer[i]);
770 nfrontp += strlen(nfrontp);
771
772 sprintf(nfrontp, "\r\n");
773 nfrontp += strlen(nfrontp);
774 break;
775
776 case SB:
777 sprintf(nfrontp, " SB ");
778 nfrontp += strlen(nfrontp);
779 i++;
780 j = k = i;
781 while (j < length) {
782 if (pointer[j] == SE) {
783 if (j+1 == length)
784 break;
785 if (pointer[j+1] == SE)
786 j++;
787 else
788 break;
789 }
790 pointer[k++] = pointer[j++];
791 }
792 printsub(0, &pointer[i], k - i);
793 if (i < length) {
794 sprintf(nfrontp, " SE");
795 nfrontp += strlen(nfrontp);
796 i = j;
797 } else
798 i = j - 1;
799
800 sprintf(nfrontp, "\r\n");
801 nfrontp += strlen(nfrontp);
802
803 break;
804
805 default:
806 sprintf(nfrontp, " %d", pointer[i]);
807 nfrontp += strlen(nfrontp);
808 break;
809 }
810 }
811 break;
812 }
813 break;
814 }
815
816 case TELOPT_XDISPLOC:
817 sprintf(nfrontp, "X-DISPLAY-LOCATION ");
818 nfrontp += strlen(nfrontp);
819 switch (pointer[1]) {
820 case TELQUAL_IS:
821 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2);
822 break;
823 case TELQUAL_SEND:
824 sprintf(nfrontp, "SEND");
825 break;
826 default:
827 sprintf(nfrontp, "- unknown qualifier %d (0x%x).",
828 pointer[1], pointer[1]);
829 }
830 nfrontp += strlen(nfrontp);
831 break;
832
833 case TELOPT_ENVIRON:
834 sprintf(nfrontp, "ENVIRON ");
835 nfrontp += strlen(nfrontp);
836 switch (pointer[1]) {
837 case TELQUAL_IS:
838 sprintf(nfrontp, "IS ");
839 goto env_common;
840 case TELQUAL_SEND:
841 sprintf(nfrontp, "SEND ");
842 goto env_common;
843 case TELQUAL_INFO:
844 sprintf(nfrontp, "INFO ");
845 env_common:
846 nfrontp += strlen(nfrontp);
847 {
848 register int noquote = 2;
849 for (i = 2; i < length; i++ ) {
850 switch (pointer[i]) {
851 case ENV_VAR:
852 if (pointer[1] == TELQUAL_SEND)
853 goto def_case;
854 sprintf(nfrontp, "\" VAR " + noquote);
855 nfrontp += strlen(nfrontp);
856 noquote = 2;
857 break;
858
859 case ENV_VALUE:
860 sprintf(nfrontp, "\" VALUE " + noquote);
861 nfrontp += strlen(nfrontp);
862 noquote = 2;
863 break;
864
865 case ENV_ESC:
866 sprintf(nfrontp, "\" ESC " + noquote);
867 nfrontp += strlen(nfrontp);
868 noquote = 2;
869 break;
870
871 default:
872 def_case:
873 if (isprint(pointer[i]) && pointer[i] != '"') {
874 if (noquote) {
875 *nfrontp++ = '"';
876 noquote = 0;
877 }
878 *nfrontp++ = pointer[i];
879 } else {
880 sprintf(nfrontp, "\" %03o " + noquote,
881 pointer[i]);
882 nfrontp += strlen(nfrontp);
883 noquote = 2;
884 }
885 break;
886 }
887 }
888 if (!noquote)
889 *nfrontp++ = '"';
890 break;
891 }
892 }
893 break;
894
895 default:
896 sprintf(nfrontp, "Unknown option ");
897 nfrontp += strlen(nfrontp);
898 for (i = 0; i < length; i++) {
899 sprintf(nfrontp, " %d", pointer[i]);
900 nfrontp += strlen(nfrontp);
901 }
902 break;
903 }
904 sprintf(nfrontp, "\r\n");
905 nfrontp += strlen(nfrontp);
906}
907
908/*
909 * Dump a data buffer in hex and ascii to the output data stream.
910 */
911void
912printdata(tag, ptr, cnt)
913register char *tag;
914register char *ptr;
915register int cnt;
916{
917register int i;
918char xbuf[30];
919
920 while (cnt) {
921 /* flush net output buffer if no room for new data) */
922 if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
923 netflush();
924 }
925
926 /* add a line of output */
927 sprintf(nfrontp, "%s: ", tag);
928 nfrontp += strlen(nfrontp);
929 for (i = 0; i < 20 && cnt; i++) {
930 sprintf(nfrontp, "%02x", *ptr);
931 nfrontp += strlen(nfrontp);
932 if (isprint(*ptr)) {
933 xbuf[i] = *ptr;
934 } else {
935 xbuf[i] = '.';
936 }
937 if (i % 2) {
938 *nfrontp = ' ';
939 nfrontp++;
940 }
941 cnt--;
942 ptr++;
943 }
944 xbuf[i] = '\0';
945 sprintf(nfrontp, " %s\r\n", xbuf );
946 nfrontp += strlen(nfrontp);
947 }
948}
949
950#endif /* DIAGNOSTICS */
951
952#ifdef NO_STRERROR
953char *
954strerror(errno)
955{
956 extern char *sys_errlist[];
957
958 return(sys_errlist[errno]);
959}
960#endif