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.6 (Berkeley) 02/26/91"; 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 time_t t; 383 char *fmt, *slash, db[100]; 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 407 case 'd': { 408 char fmt[] = "%l:% %P on %A, %d %B %Y"; 409 410 fmt[4] = 'M'; /* I *hate* SCCS... */ 411 (void)time(&t); 412 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 413 putstr(db); 414 break; 415 } 416 417 case '%': 418 putchr('%'); 419 break; 420 } 421 cp++; 422 } 423 } 424 425 /*ARGSUSED*/ 426 #ifdef NO_GETTYTAB 427 getent(cp, name) 428 char *cp, *name; 429 { 430 return(0); 431 } 432 433 /*ARGSUSED*/ 434 char * 435 getstr(cp, cpp) 436 char *cp, **cpp; 437 { 438 return(0); 439 } 440 #endif /* NO_GETTYTAB */ 441 442 #ifdef DIAGNOSTICS 443 /* 444 * Print telnet options and commands in plain text, if possible. 445 */ 446 void 447 printoption(fmt, option) 448 register char *fmt; 449 register 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 461 char *slcnames[] = { SLC_NAMES }; 462 463 void 464 printsub(dirp, pointer, length) 465 char *dirp; 466 unsigned char *pointer; /* where suboption data sits */ 467 int 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 */ 911 void 912 printdata(tag, ptr, cnt) 913 register char *tag; 914 register char *ptr; 915 register int cnt; 916 { 917 register int i; 918 char 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 953 char * 954 strerror(errno) 955 { 956 extern char *sys_errlist[]; 957 958 return(sys_errlist[errno]); 959 } 960 #endif 961