1 /* 2 * Copyright (c) 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)utility.c 5.4 (Berkeley) 06/28/90"; 10 #endif /* not lint */ 11 12 #define PRINTOPTIONS 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 28 void 29 ttloop() 30 { 31 void netflush(); 32 33 #ifdef DIAGNOSTICS 34 if (diagnostic & TD_REPORT) { 35 sprintf(nfrontp, "td: ttloop\r\n"); 36 nfrontp += strlen(nfrontp); 37 } 38 #endif /* DIAGNOSTICS */ 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 } 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 */ 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 */ 67 stilloob(s) 68 int 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 90 ptyflush() 91 { 92 int n; 93 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 */ 104 n = write(pty, pbackp, n); 105 } 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 */ 123 char * 124 nextitem(current) 125 char *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 */ 170 netclear() 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 */ 214 void 215 netflush() 216 { 217 int n; 218 extern int not42; 219 220 if ((n = nfrontp - nbackp) > 0) { 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 */ 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 */ 278 writenet(ptr, len) 279 register char *ptr; 280 register 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 299 fatal(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 311 fatalperror(f, msg) 312 int f; 313 char *msg; 314 { 315 char buf[BUFSIZ], *strerror(); 316 317 (void) sprintf(buf, "%s: %s\r\n", msg, strerror(errno)); 318 fatal(f, buf); 319 } 320 321 char editedhost[32]; 322 323 edithost(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 363 static char *putlocation; 364 365 putstr(s) 366 register char *s; 367 { 368 369 while (*s) 370 putchr(*s++); 371 } 372 373 putchr(cc) 374 { 375 *putlocation++ = cc; 376 } 377 378 putf(cp, where) 379 register char *cp; 380 char *where; 381 { 382 char *slash; 383 #ifndef NO_GETTYTAB 384 char datebuffer[60]; 385 #endif /* NO_GETTYTAB */ 386 extern char *rindex(); 387 388 putlocation = where; 389 390 while (*cp) { 391 if (*cp != '%') { 392 putchr(*cp++); 393 continue; 394 } 395 switch (*++cp) { 396 397 case 't': 398 slash = rindex(line, '/'); 399 if (slash == (char *) 0) 400 putstr(line); 401 else 402 putstr(&slash[1]); 403 break; 404 405 case 'h': 406 putstr(editedhost); 407 break; 408 409 #ifndef NO_GETTYTAB 410 case 'd': 411 get_date(datebuffer); 412 putstr(datebuffer); 413 break; 414 #endif /* NO_GETTYTAB */ 415 416 case '%': 417 putchr('%'); 418 break; 419 } 420 cp++; 421 } 422 } 423 424 /*ARGSUSED*/ 425 #ifdef NO_GETTYTAB 426 getent(cp, name) 427 char *cp, *name; 428 { 429 return(0); 430 } 431 432 /*ARGSUSED*/ 433 char * 434 getstr(cp, cpp) 435 char *cp, **cpp; 436 { 437 return(0); 438 } 439 #endif /* NO_GETTYTAB */ 440 441 #ifdef DIAGNOSTICS 442 /* 443 * Print telnet options and commands in plain text, if possible. 444 */ 445 void 446 printoption(fmt, option) 447 register char *fmt; 448 register int option; 449 { 450 if (TELOPT_OK(option)) 451 sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); 452 else if (TELCMD_OK(option)) 453 sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); 454 else 455 sprintf(nfrontp, "%s %d\r\n", fmt, option); 456 nfrontp += strlen(nfrontp); 457 return; 458 } 459 460 char *slcnames[] = { SLC_NAMES }; 461 462 void 463 printsub(dirp, pointer, length) 464 char *dirp; 465 unsigned char *pointer; /* where suboption data sits */ 466 int length; /* length of suboption data */ 467 { 468 register int i; 469 470 if (dirp) { 471 sprintf(nfrontp, "%s suboption ", dirp); 472 nfrontp += strlen(nfrontp); 473 if (length >= 3) { 474 register int j; 475 476 i = pointer[length-2]; 477 j = pointer[length-1]; 478 479 if (i != IAC || j != SE) { 480 sprintf(nfrontp, "(terminated by "); 481 nfrontp += strlen(nfrontp); 482 if (TELOPT_OK(i)) 483 sprintf(nfrontp, "%s ", TELOPT(i)); 484 else if (TELCMD_OK(i)) 485 sprintf(nfrontp, "%s ", TELCMD(i)); 486 else 487 sprintf(nfrontp, "%d ", i); 488 nfrontp += strlen(nfrontp); 489 if (TELOPT_OK(j)) 490 sprintf(nfrontp, "%s", TELOPT(j)); 491 else if (TELCMD_OK(j)) 492 sprintf(nfrontp, "%s", TELCMD(j)); 493 else 494 sprintf(nfrontp, "%d", j); 495 nfrontp += strlen(nfrontp); 496 sprintf(nfrontp, ", not IAC SE!) "); 497 nfrontp += strlen(nfrontp); 498 } 499 } 500 length -= 2; 501 } 502 if (length < 1) { 503 sprintf(nfrontp, "(Empty suboption???)"); 504 nfrontp += strlen(nfrontp); 505 return; 506 } 507 switch (pointer[0]) { 508 case TELOPT_TTYPE: 509 sprintf(nfrontp, "TERMINAL-TYPE "); 510 nfrontp += strlen(nfrontp); 511 switch (pointer[1]) { 512 case TELQUAL_IS: 513 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 514 break; 515 case TELQUAL_SEND: 516 sprintf(nfrontp, "SEND"); 517 break; 518 default: 519 sprintf(nfrontp, 520 "- unknown qualifier %d (0x%x).", 521 pointer[1], pointer[1]); 522 } 523 nfrontp += strlen(nfrontp); 524 break; 525 case TELOPT_TSPEED: 526 sprintf(nfrontp, "TERMINAL-SPEED"); 527 nfrontp += strlen(nfrontp); 528 if (length < 2) { 529 sprintf(nfrontp, " (empty suboption???)"); 530 nfrontp += strlen(nfrontp); 531 break; 532 } 533 switch (pointer[1]) { 534 case TELQUAL_IS: 535 sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); 536 nfrontp += strlen(nfrontp); 537 break; 538 default: 539 if (pointer[1] == 1) 540 sprintf(nfrontp, " SEND"); 541 else 542 sprintf(nfrontp, " %d (unknown)", pointer[1]); 543 nfrontp += strlen(nfrontp); 544 for (i = 2; i < length; i++) { 545 sprintf(nfrontp, " ?%d?", pointer[i]); 546 nfrontp += strlen(nfrontp); 547 } 548 break; 549 } 550 break; 551 552 case TELOPT_LFLOW: 553 sprintf(nfrontp, "TOGGLE-FLOW-CONTROL"); 554 nfrontp += strlen(nfrontp); 555 if (length < 2) { 556 sprintf(nfrontp, " (empty suboption???)"); 557 nfrontp += strlen(nfrontp); 558 break; 559 } 560 switch (pointer[1]) { 561 case 0: 562 sprintf(nfrontp, " OFF"); break; 563 case 1: 564 sprintf(nfrontp, " ON"); break; 565 default: 566 sprintf(nfrontp, " %d (unknown)", pointer[1]); 567 } 568 nfrontp += strlen(nfrontp); 569 for (i = 2; i < length; i++) { 570 sprintf(nfrontp, " ?%d?", pointer[i]); 571 nfrontp += strlen(nfrontp); 572 } 573 break; 574 575 case TELOPT_NAWS: 576 sprintf(nfrontp, "NAWS"); 577 nfrontp += strlen(nfrontp); 578 if (length < 2) { 579 sprintf(nfrontp, " (empty suboption???)"); 580 nfrontp += strlen(nfrontp); 581 break; 582 } 583 if (length == 2) { 584 sprintf(nfrontp, " ?%d?", pointer[1]); 585 nfrontp += strlen(nfrontp); 586 break; 587 } 588 sprintf(nfrontp, " %d %d (%d)", 589 pointer[1], pointer[2], 590 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); 591 nfrontp += strlen(nfrontp); 592 if (length == 4) { 593 sprintf(nfrontp, " ?%d?", pointer[3]); 594 nfrontp += strlen(nfrontp); 595 break; 596 } 597 sprintf(nfrontp, " %d %d (%d)", 598 pointer[3], pointer[4], 599 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); 600 nfrontp += strlen(nfrontp); 601 for (i = 5; i < length; i++) { 602 sprintf(nfrontp, " ?%d?", pointer[i]); 603 nfrontp += strlen(nfrontp); 604 } 605 break; 606 607 case TELOPT_LINEMODE: 608 sprintf(nfrontp, "LINEMODE "); 609 nfrontp += strlen(nfrontp); 610 if (length < 2) { 611 sprintf(nfrontp, " (empty suboption???)"); 612 nfrontp += strlen(nfrontp); 613 break; 614 } 615 switch (pointer[1]) { 616 case WILL: 617 sprintf(nfrontp, "WILL "); 618 goto common; 619 case WONT: 620 sprintf(nfrontp, "WONT "); 621 goto common; 622 case DO: 623 sprintf(nfrontp, "DO "); 624 goto common; 625 case DONT: 626 sprintf(nfrontp, "DONT "); 627 common: 628 nfrontp += strlen(nfrontp); 629 if (length < 3) { 630 sprintf(nfrontp, "(no option???)"); 631 nfrontp += strlen(nfrontp); 632 break; 633 } 634 switch (pointer[2]) { 635 case LM_FORWARDMASK: 636 sprintf(nfrontp, "Forward Mask"); 637 nfrontp += strlen(nfrontp); 638 for (i = 3; i < length; i++) { 639 sprintf(nfrontp, " %x", pointer[i]); 640 nfrontp += strlen(nfrontp); 641 } 642 break; 643 default: 644 sprintf(nfrontp, "%d (unknown)", pointer[2]); 645 nfrontp += strlen(nfrontp); 646 for (i = 3; i < length; i++) { 647 sprintf(nfrontp, " %d", pointer[i]); 648 nfrontp += strlen(nfrontp); 649 } 650 break; 651 } 652 break; 653 654 case LM_SLC: 655 sprintf(nfrontp, "SLC"); 656 nfrontp += strlen(nfrontp); 657 for (i = 2; i < length - 2; i += 3) { 658 if (pointer[i+SLC_FUNC] <= NSLC) 659 sprintf(nfrontp, " %s", slcnames[pointer[i+SLC_FUNC]]); 660 else 661 sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]); 662 nfrontp += strlen(nfrontp); 663 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 664 case SLC_NOSUPPORT: 665 sprintf(nfrontp, " NOSUPPORT"); break; 666 case SLC_CANTCHANGE: 667 sprintf(nfrontp, " CANTCHANGE"); break; 668 case SLC_VARIABLE: 669 sprintf(nfrontp, " VARIABLE"); break; 670 case SLC_DEFAULT: 671 sprintf(nfrontp, " DEFAULT"); break; 672 } 673 nfrontp += strlen(nfrontp); 674 sprintf(nfrontp, "%s%s%s", 675 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 676 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 677 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 678 nfrontp += strlen(nfrontp); 679 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 680 SLC_FLUSHOUT| SLC_LEVELBITS)) { 681 sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]); 682 nfrontp += strlen(nfrontp); 683 } 684 sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]); 685 nfrontp += strlen(nfrontp); 686 if ((pointer[i+SLC_VALUE] == IAC) && 687 (pointer[i+SLC_VALUE+1] == IAC)) 688 i++; 689 } 690 for (; i < length; i++) { 691 sprintf(nfrontp, " ?%d?", pointer[i]); 692 nfrontp += strlen(nfrontp); 693 } 694 break; 695 696 case LM_MODE: 697 sprintf(nfrontp, "MODE "); 698 nfrontp += strlen(nfrontp); 699 if (length < 3) { 700 sprintf(nfrontp, "(no mode???)"); 701 nfrontp += strlen(nfrontp); 702 break; 703 } 704 { 705 char tbuf[32]; 706 sprintf(tbuf, "%s%s%s%s%s", 707 pointer[2]&MODE_EDIT ? "|EDIT" : "", 708 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 709 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 710 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 711 pointer[2]&MODE_ACK ? "|ACK" : ""); 712 sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0"); 713 nfrontp += strlen(nfrontp); 714 } 715 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 716 sprintf(nfrontp, " (0x%x)", pointer[2]); 717 nfrontp += strlen(nfrontp); 718 } 719 for (i = 3; i < length; i++) { 720 sprintf(nfrontp, " ?0x%x?", pointer[i]); 721 nfrontp += strlen(nfrontp); 722 } 723 break; 724 default: 725 sprintf(nfrontp, "%d (unknown)", pointer[1]); 726 nfrontp += strlen(nfrontp); 727 for (i = 2; i < length; i++) { 728 sprintf(nfrontp, " %d", pointer[i]); 729 nfrontp += strlen(nfrontp); 730 } 731 } 732 break; 733 734 case TELOPT_STATUS: { 735 register char *cp; 736 register int j, k; 737 738 sprintf(nfrontp, "STATUS"); 739 nfrontp += strlen(nfrontp); 740 741 switch (pointer[1]) { 742 default: 743 if (pointer[1] == TELQUAL_SEND) 744 sprintf(nfrontp, " SEND"); 745 else 746 sprintf(nfrontp, " %d (unknown)", pointer[1]); 747 nfrontp += strlen(nfrontp); 748 for (i = 2; i < length; i++) { 749 sprintf(nfrontp, " ?%d?", pointer[i]); 750 nfrontp += strlen(nfrontp); 751 } 752 break; 753 case TELQUAL_IS: 754 sprintf(nfrontp, " IS\r\n"); 755 nfrontp += strlen(nfrontp); 756 757 for (i = 2; i < length; i++) { 758 switch(pointer[i]) { 759 case DO: cp = "DO"; goto common2; 760 case DONT: cp = "DONT"; goto common2; 761 case WILL: cp = "WILL"; goto common2; 762 case WONT: cp = "WONT"; goto common2; 763 common2: 764 i++; 765 if (TELOPT_OK((int)pointer[i])) 766 sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i])); 767 else 768 sprintf(nfrontp, " %s %d", cp, pointer[i]); 769 nfrontp += strlen(nfrontp); 770 771 sprintf(nfrontp, "\r\n"); 772 nfrontp += strlen(nfrontp); 773 break; 774 775 case SB: 776 sprintf(nfrontp, " SB "); 777 nfrontp += strlen(nfrontp); 778 i++; 779 j = k = i; 780 while (j < length) { 781 if (pointer[j] == SE) { 782 if (j+1 == length) 783 break; 784 if (pointer[j+1] == SE) 785 j++; 786 else 787 break; 788 } 789 pointer[k++] = pointer[j++]; 790 } 791 printsub(0, &pointer[i], k - i); 792 if (i < length) { 793 sprintf(nfrontp, " SE"); 794 nfrontp += strlen(nfrontp); 795 i = j; 796 } else 797 i = j - 1; 798 799 sprintf(nfrontp, "\r\n"); 800 nfrontp += strlen(nfrontp); 801 802 break; 803 804 default: 805 sprintf(nfrontp, " %d", pointer[i]); 806 nfrontp += strlen(nfrontp); 807 break; 808 } 809 } 810 break; 811 } 812 break; 813 } 814 815 case TELOPT_XDISPLOC: 816 sprintf(nfrontp, "X-DISPLAY-LOCATION "); 817 nfrontp += strlen(nfrontp); 818 switch (pointer[1]) { 819 case TELQUAL_IS: 820 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 821 break; 822 case TELQUAL_SEND: 823 sprintf(nfrontp, "SEND"); 824 break; 825 default: 826 sprintf(nfrontp, "- unknown qualifier %d (0x%x).", 827 pointer[1], pointer[1]); 828 } 829 nfrontp += strlen(nfrontp); 830 break; 831 832 case TELOPT_ENVIRON: 833 sprintf(nfrontp, "ENVIRON "); 834 nfrontp += strlen(nfrontp); 835 switch (pointer[1]) { 836 case TELQUAL_IS: 837 sprintf(nfrontp, "IS "); 838 goto env_common; 839 case TELQUAL_SEND: 840 sprintf(nfrontp, "SEND "); 841 goto env_common; 842 case TELQUAL_INFO: 843 sprintf(nfrontp, "INFO "); 844 env_common: 845 nfrontp += strlen(nfrontp); 846 { 847 register int noquote = 2; 848 for (i = 2; i < length; i++ ) { 849 switch (pointer[i]) { 850 case ENV_VAR: 851 if (pointer[1] == TELQUAL_SEND) 852 goto def_case; 853 sprintf(nfrontp, "\" VAR " + noquote); 854 nfrontp += strlen(nfrontp); 855 noquote = 2; 856 break; 857 858 case ENV_VALUE: 859 sprintf(nfrontp, "\" VALUE " + noquote); 860 nfrontp += strlen(nfrontp); 861 noquote = 2; 862 break; 863 864 case ENV_ESC: 865 sprintf(nfrontp, "\" ESC " + noquote); 866 nfrontp += strlen(nfrontp); 867 noquote = 2; 868 break; 869 870 default: 871 def_case: 872 if (isprint(pointer[i]) && pointer[i] != '"') { 873 if (noquote) { 874 *nfrontp++ = '"'; 875 noquote = 0; 876 } 877 *nfrontp++ = pointer[i]; 878 } else { 879 sprintf(nfrontp, "\" %03o " + noquote, 880 pointer[i]); 881 nfrontp += strlen(nfrontp); 882 noquote = 2; 883 } 884 break; 885 } 886 } 887 if (!noquote) 888 *nfrontp++ = '"'; 889 break; 890 } 891 } 892 break; 893 894 default: 895 sprintf(nfrontp, "Unknown option "); 896 nfrontp += strlen(nfrontp); 897 for (i = 0; i < length; i++) { 898 sprintf(nfrontp, " %d", pointer[i]); 899 nfrontp += strlen(nfrontp); 900 } 901 break; 902 } 903 sprintf(nfrontp, "\r\n"); 904 nfrontp += strlen(nfrontp); 905 } 906 907 /* 908 * Dump a data buffer in hex and ascii to the output data stream. 909 */ 910 void 911 printdata(tag, ptr, cnt) 912 register char *tag; 913 register char *ptr; 914 register int cnt; 915 { 916 register int i; 917 char xbuf[30]; 918 919 while (cnt) { 920 /* flush net output buffer if no room for new data) */ 921 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 922 netflush(); 923 } 924 925 /* add a line of output */ 926 sprintf(nfrontp, "%s: ", tag); 927 nfrontp += strlen(nfrontp); 928 for (i = 0; i < 20 && cnt; i++) { 929 sprintf(nfrontp, "%02x", *ptr); 930 nfrontp += strlen(nfrontp); 931 if (isprint(*ptr)) { 932 xbuf[i] = *ptr; 933 } else { 934 xbuf[i] = '.'; 935 } 936 if (i % 2) { 937 *nfrontp = ' '; 938 nfrontp++; 939 } 940 cnt--; 941 ptr++; 942 } 943 xbuf[i] = '\0'; 944 sprintf(nfrontp, " %s\r\n", xbuf ); 945 nfrontp += strlen(nfrontp); 946 } 947 } 948 949 #endif /* DIAGNOSTICS */ 950 951 #ifdef NO_STRERROR 952 char * 953 strerror(errno) 954 { 955 extern char *sys_errlist[]; 956 957 return(sys_errlist[errno]); 958 } 959 #endif 960