|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)telnet.c 4.24 (Berkeley) 7/20/83"; ! 3: #endif ! 4: ! 5: /* ! 6: * User telnet program. ! 7: */ ! 8: #include <sys/types.h> ! 9: #include <sys/ioctl.h> ! 10: ! 11: #include <sys/inet/tcp_user.h> ! 12: ! 13: #define TELOPTS ! 14: #include "telnet.h" ! 15: ! 16: #include <stdio.h> ! 17: #include <ctype.h> ! 18: #include <errno.h> ! 19: #include <signal.h> ! 20: #include <setjmp.h> ! 21: ! 22: #define strip(x) ((x)&0177) ! 23: ! 24: char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; ! 25: char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; ! 26: ! 27: char hisopts[256]; ! 28: char myopts[256]; ! 29: ! 30: char doopt[] = { IAC, DO, '%', 'c', 0 }; ! 31: char dont[] = { IAC, DONT, '%', 'c', 0 }; ! 32: char will[] = { IAC, WILL, '%', 'c', 0 }; ! 33: char wont[] = { IAC, WONT, '%', 'c', 0 }; ! 34: ! 35: int connected; ! 36: int net; ! 37: int showoptions = 0; ! 38: int options; ! 39: int debug = 0; ! 40: int crmod = 0; ! 41: char *prompt; ! 42: char escape = 035; ! 43: ! 44: char line[200]; ! 45: int margc; ! 46: char *margv[20]; ! 47: ! 48: jmp_buf toplevel; ! 49: ! 50: extern int errno; ! 51: ! 52: int tn(), quit(), bye(), help(); ! 53: int setescape(), status(), toggle(), setoptions(); ! 54: int setcrmod(), setdebug(); ! 55: ! 56: #define HELPINDENT (sizeof ("connect")) ! 57: ! 58: struct cmd { ! 59: char *name; /* command name */ ! 60: char *help; /* help string */ ! 61: int (*handler)(); /* routine which executes command */ ! 62: }; ! 63: ! 64: char openhelp[] = "open connection to a site"; ! 65: char closehelp[] = "close current connection"; ! 66: char quithelp[] = "exit telnet"; ! 67: char debughelp[] = "toggle debugging"; ! 68: char escapehelp[] = "set escape character"; ! 69: char statushelp[] = "print status information"; ! 70: char helphelp[] = "print help information"; ! 71: char optionshelp[] = "toggle viewing of options processing"; ! 72: char crmodhelp[] = "toggle mapping of received carriage returns"; ! 73: ! 74: struct cmd cmdtab[] = { ! 75: { "open", openhelp, tn }, ! 76: { "close", closehelp, bye }, ! 77: { "quit", quithelp, quit }, ! 78: { "escape", escapehelp, setescape }, ! 79: { "status", statushelp, status }, ! 80: { "options", optionshelp, setoptions }, ! 81: { "crmod", crmodhelp, setcrmod }, ! 82: { "debug", debughelp, setdebug }, ! 83: { "?", helphelp, help }, ! 84: 0 ! 85: }; ! 86: ! 87: int intr(), deadpeer(); ! 88: char *control(); ! 89: struct cmd *getcmd(); ! 90: ! 91: struct tchars otc; ! 92: struct ltchars oltc; ! 93: struct sgttyb ottyb; ! 94: ! 95: in_addr faddr; ! 96: tcp_port fport, lport; ! 97: ! 98: main(argc, argv) ! 99: int argc; ! 100: char *argv[]; ! 101: { ! 102: struct in_service *sp; ! 103: ! 104: sp = in_service("telnet", "tcp", 0); ! 105: if(sp == NULL){ ! 106: fprintf(stderr, "telnet: unknown service.\n"); ! 107: exit(1); ! 108: } ! 109: fport = sp->port; ! 110: ioctl(0, TIOCGETP, (char *)&ottyb); ! 111: ioctl(0, TIOCGETC, (char *)&otc); ! 112: ioctl(0, TIOCGLTC, (char *)&oltc); ! 113: setbuf(stdin, 0); ! 114: setbuf(stdout, 0); ! 115: prompt = argv[0]; ! 116: if (argc > 1 && !strcmp(argv[1], "-d")) ! 117: debug++, argv++, argc--; ! 118: if (argc != 1) { ! 119: if (setjmp(toplevel) != 0) ! 120: exit(0); ! 121: tn(argc, argv); ! 122: } ! 123: setjmp(toplevel); ! 124: for (;;) ! 125: command(1); ! 126: } ! 127: ! 128: char *hostname; ! 129: ! 130: tn(argc, argv) ! 131: int argc; ! 132: char *argv[]; ! 133: { ! 134: register int c; ! 135: register struct hostent *host; ! 136: ! 137: if (connected) { ! 138: printf("?Already connected to %s\n", hostname); ! 139: return; ! 140: } ! 141: if (argc < 2) { ! 142: strcpy(line, "Connect "); ! 143: printf("(to) "); ! 144: gets(&line[strlen(line)]); ! 145: makeargv(); ! 146: argc = margc; ! 147: argv = margv; ! 148: } ! 149: if (argc > 3) { ! 150: printf("usage: %s host-name [port]\n", argv[0]); ! 151: return; ! 152: } ! 153: hostname = argv[1]; ! 154: faddr = in_address(hostname); ! 155: if(faddr == 0){ ! 156: fprintf(stderr, "telnet: unknown host %s\n", argv[1]); ! 157: return; ! 158: } ! 159: if (argc == 3) { ! 160: fport = atoi(argv[2]); ! 161: if (fport < 0) { ! 162: printf("%s: bad port number\n", argv[2]); ! 163: return; ! 164: } ! 165: } ! 166: net = tcp_sock(); ! 167: if (net < 0) { ! 168: perror("telnet: socket"); ! 169: return; ! 170: } ! 171: signal(SIGINT, intr); ! 172: signal(SIGPIPE, SIG_IGN); ! 173: signal(SIGHUP, SIG_IGN); ! 174: printf("Trying...\n"); ! 175: if(getuid() == 0) ! 176: lport = 0; ! 177: else ! 178: lport = getpid() + 1024; ! 179: if(tcp_connect(net, lport, faddr, fport) < 0){ ! 180: perror("telnet: connect"); ! 181: signal(SIGINT, SIG_DFL); ! 182: return; ! 183: } ! 184: connected++; ! 185: call(status, "status", 0); ! 186: telnet(net); ! 187: fprintf(stderr, "Connection closed by foreign host.\n"); ! 188: exit(1); ! 189: } ! 190: ! 191: /* ! 192: * Print status about the connection. ! 193: */ ! 194: /*VARARGS*/ ! 195: status() ! 196: { ! 197: if (connected) ! 198: printf("Connected to %s.\n", hostname); ! 199: else ! 200: printf("No connection.\n"); ! 201: printf("Escape character is '%s'.\n", control(escape)); ! 202: fflush(stdout); ! 203: } ! 204: ! 205: makeargv() ! 206: { ! 207: register char *cp; ! 208: register char **argp = margv; ! 209: ! 210: margc = 0; ! 211: for (cp = line; *cp;) { ! 212: while (isspace(*cp)) ! 213: cp++; ! 214: if (*cp == '\0') ! 215: break; ! 216: *argp++ = cp; ! 217: margc += 1; ! 218: while (*cp != '\0' && !isspace(*cp)) ! 219: cp++; ! 220: if (*cp == '\0') ! 221: break; ! 222: *cp++ = '\0'; ! 223: } ! 224: *argp++ = 0; ! 225: } ! 226: ! 227: /*VARARGS*/ ! 228: bye() ! 229: { ! 230: register char *op; ! 231: ! 232: (void) mode(0); ! 233: if (connected) { ! 234: printf("Connection closed.\n"); ! 235: close(net); ! 236: connected = 0; ! 237: /* reset his options */ ! 238: for (op = hisopts; op < &hisopts[256]; op++) ! 239: *op = 0; ! 240: } ! 241: } ! 242: ! 243: /*VARARGS*/ ! 244: quit() ! 245: { ! 246: call(bye, "bye", 0); ! 247: exit(0); ! 248: } ! 249: ! 250: /* ! 251: * Help command. ! 252: */ ! 253: help(argc, argv) ! 254: int argc; ! 255: char *argv[]; ! 256: { ! 257: register struct cmd *c; ! 258: ! 259: if (argc == 1) { ! 260: printf("Commands may be abbreviated. Commands are:\n\n"); ! 261: for (c = cmdtab; c->name; c++) ! 262: printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); ! 263: return; ! 264: } ! 265: while (--argc > 0) { ! 266: register char *arg; ! 267: arg = *++argv; ! 268: c = getcmd(arg); ! 269: if (c == (struct cmd *)-1) ! 270: printf("?Ambiguous help command %s\n", arg); ! 271: else if (c == (struct cmd *)0) ! 272: printf("?Invalid help command %s\n", arg); ! 273: else ! 274: printf("%s\n", c->help); ! 275: } ! 276: } ! 277: ! 278: /* ! 279: * Call routine with argc, argv set from args (terminated by 0). ! 280: * VARARGS2 ! 281: */ ! 282: call(routine, args) ! 283: int (*routine)(); ! 284: int args; ! 285: { ! 286: register int *argp; ! 287: register int argc; ! 288: ! 289: for (argc = 0, argp = &args; *argp++ != 0; argc++) ! 290: ; ! 291: (*routine)(argc, &args); ! 292: } ! 293: ! 294: struct tchars notc = { -1, -1, -1, -1, -1, -1 }; ! 295: struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; ! 296: ! 297: mode(f) ! 298: register int f; ! 299: { ! 300: static int prevmode = 0; ! 301: struct tchars *tc; ! 302: struct ltchars *ltc; ! 303: struct sgttyb sb; ! 304: int onoff, old; ! 305: ! 306: if (prevmode == f) ! 307: return (f); ! 308: old = prevmode; ! 309: prevmode = f; ! 310: sb = ottyb; ! 311: switch (f) { ! 312: ! 313: case 0: ! 314: onoff = 0; ! 315: tc = &otc; ! 316: ltc = &oltc; ! 317: break; ! 318: ! 319: case 1: ! 320: case 2: ! 321: sb.sg_flags |= CBREAK; ! 322: if (f == 1) ! 323: sb.sg_flags &= ~(ECHO|CRMOD); ! 324: else ! 325: sb.sg_flags |= ECHO|CRMOD; ! 326: sb.sg_erase = sb.sg_kill = -1; ! 327: tc = ¬c; ! 328: ltc = &noltc; ! 329: onoff = 1; ! 330: break; ! 331: ! 332: default: ! 333: return; ! 334: } ! 335: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); ! 336: ioctl(fileno(stdin), TIOCSETC, (char *)tc); ! 337: ioctl(fileno(stdin), TIOCSETP, (char *)&sb); ! 338: return (old); ! 339: } ! 340: ! 341: char sibuf[BUFSIZ], *sbp; ! 342: char tibuf[BUFSIZ], *tbp; ! 343: int scc, tcc; ! 344: int hungup; ! 345: ! 346: catchhup() ! 347: { ! 348: hungup = 1; ! 349: signal(SIGHUP, SIG_IGN); ! 350: } ! 351: ! 352: /* ! 353: * Select from tty and network... ! 354: */ ! 355: telnet(s) ! 356: int s; ! 357: { ! 358: register int c; ! 359: int tin = fileno(stdin), tout = fileno(stdout); ! 360: int on = 1; ! 361: ! 362: hungup = 0; ! 363: (void) mode(2); ! 364: signal(SIGHUP, catchhup); ! 365: while(!hungup) { ! 366: fd_set ibits, obits; ! 367: int nfds; ! 368: ! 369: FD_ZERO(ibits); ! 370: FD_ZERO(obits); ! 371: if (nfrontp - nbackp) ! 372: FD_SET(s, obits); ! 373: else ! 374: FD_SET(tin, ibits); ! 375: if (tfrontp - tbackp) ! 376: FD_SET(tout, obits); ! 377: else ! 378: FD_SET(s, ibits); ! 379: if (scc < 0 && tcc < 0) ! 380: break; ! 381: nfds = select(NOFILE, &ibits, &obits, 1000); ! 382: if (nfds==0) ! 383: continue; ! 384: else if (nfds<0) ! 385: break; ! 386: ! 387: /* ! 388: * Something to read from the network... ! 389: */ ! 390: if (FD_ISSET(s, ibits)) { ! 391: scc = read(s, sibuf, sizeof (sibuf)); ! 392: if (scc <= 0) ! 393: break; ! 394: sbp = sibuf; ! 395: } ! 396: ! 397: /* ! 398: * Something to read from the tty... ! 399: */ ! 400: if (FD_ISSET(tin, ibits)) { ! 401: tcc = read(tin, tibuf, sizeof (tibuf)); ! 402: if (tcc < 0) ! 403: break; ! 404: tbp = tibuf; ! 405: } ! 406: ! 407: while (tcc > 0) { ! 408: register int c; ! 409: ! 410: if ((&netobuf[BUFSIZ] - nfrontp) < 2) ! 411: break; ! 412: c = *tbp++ & 0377, tcc--; ! 413: if (strip(c) == escape) { ! 414: command(0); ! 415: tcc = 0; ! 416: break; ! 417: } ! 418: if (c == IAC) ! 419: *nfrontp++ = c; ! 420: *nfrontp++ = c; ! 421: } ! 422: if (FD_ISSET(s, obits) && (nfrontp - nbackp) > 0) ! 423: netflush(s); ! 424: if (scc > 0) ! 425: telrcv(); ! 426: if (FD_ISSET(tout, obits) && (tfrontp - tbackp) > 0) ! 427: ttyflush(tout); ! 428: } ! 429: signal(SIGHUP, SIG_IGN); ! 430: (void) mode(0); ! 431: } ! 432: ! 433: command(top) ! 434: int top; ! 435: { ! 436: register struct cmd *c; ! 437: int oldmode, wasopen; ! 438: ! 439: oldmode = mode(0); ! 440: if (!top) ! 441: putchar('\n'); ! 442: else ! 443: signal(SIGINT, SIG_DFL); ! 444: for (;;) { ! 445: printf("%s> ", prompt); ! 446: if (gets(line) == 0) { ! 447: if (feof(stdin)) { ! 448: clearerr(stdin); ! 449: putchar('\n'); ! 450: } ! 451: break; ! 452: } ! 453: if (line[0] == 0) ! 454: break; ! 455: makeargv(); ! 456: c = getcmd(margv[0]); ! 457: if (c == (struct cmd *)-1) { ! 458: printf("?Ambiguous command\n"); ! 459: continue; ! 460: } ! 461: if (c == 0) { ! 462: printf("?Invalid command\n"); ! 463: continue; ! 464: } ! 465: (*c->handler)(margc, margv); ! 466: if (c->handler != help) ! 467: break; ! 468: } ! 469: if (!top) { ! 470: if (!connected) ! 471: longjmp(toplevel, 1); ! 472: (void) mode(oldmode); ! 473: } ! 474: } ! 475: ! 476: /* ! 477: * Telnet receiver states for fsm ! 478: */ ! 479: #define TS_DATA 0 ! 480: #define TS_IAC 1 ! 481: #define TS_WILL 2 ! 482: #define TS_WONT 3 ! 483: #define TS_DO 4 ! 484: #define TS_DONT 5 ! 485: ! 486: telrcv() ! 487: { ! 488: register int c; ! 489: static int state = TS_DATA; ! 490: ! 491: while (scc > 0) { ! 492: c = *sbp++ & 0377, scc--; ! 493: switch (state) { ! 494: ! 495: case TS_DATA: ! 496: if (c == IAC) { ! 497: state = TS_IAC; ! 498: continue; ! 499: } ! 500: *tfrontp++ = c; ! 501: /* ! 502: * This hack is needed since we can't set ! 503: * CRMOD on output only. Machines like MULTICS ! 504: * like to send \r without \n; since we must ! 505: * turn off CRMOD to get proper input, the mapping ! 506: * is done here (sigh). ! 507: */ ! 508: if (c == '\r' && crmod) ! 509: *tfrontp++ = '\n'; ! 510: continue; ! 511: ! 512: case TS_IAC: ! 513: switch (c) { ! 514: ! 515: case WILL: ! 516: state = TS_WILL; ! 517: continue; ! 518: ! 519: case WONT: ! 520: state = TS_WONT; ! 521: continue; ! 522: ! 523: case DO: ! 524: state = TS_DO; ! 525: continue; ! 526: ! 527: case DONT: ! 528: state = TS_DONT; ! 529: continue; ! 530: ! 531: case DM: ! 532: ioctl(fileno(stdout), TIOCFLUSH, 0); ! 533: break; ! 534: ! 535: case NOP: ! 536: case GA: ! 537: break; ! 538: ! 539: default: ! 540: break; ! 541: } ! 542: state = TS_DATA; ! 543: continue; ! 544: ! 545: case TS_WILL: ! 546: printoption("RCVD", will, c, !hisopts[c]); ! 547: if (!hisopts[c]) ! 548: willoption(c); ! 549: state = TS_DATA; ! 550: continue; ! 551: ! 552: case TS_WONT: ! 553: printoption("RCVD", wont, c, hisopts[c]); ! 554: if (hisopts[c]) ! 555: wontoption(c); ! 556: state = TS_DATA; ! 557: continue; ! 558: ! 559: case TS_DO: ! 560: printoption("RCVD", doopt, c, !myopts[c]); ! 561: if (!myopts[c]) ! 562: dooption(c); ! 563: state = TS_DATA; ! 564: continue; ! 565: ! 566: case TS_DONT: ! 567: printoption("RCVD", dont, c, myopts[c]); ! 568: if (myopts[c]) { ! 569: myopts[c] = 0; ! 570: sprintf(nfrontp, wont, c); ! 571: nfrontp += sizeof (wont) - 2; ! 572: printoption("SENT", wont, c); ! 573: } ! 574: state = TS_DATA; ! 575: continue; ! 576: } ! 577: } ! 578: } ! 579: ! 580: willoption(option) ! 581: int option; ! 582: { ! 583: char *fmt; ! 584: ! 585: switch (option) { ! 586: ! 587: case TELOPT_ECHO: ! 588: (void) mode(1); ! 589: ! 590: case TELOPT_SGA: ! 591: hisopts[option] = 1; ! 592: fmt = doopt; ! 593: break; ! 594: ! 595: case TELOPT_TM: ! 596: fmt = dont; ! 597: break; ! 598: ! 599: default: ! 600: fmt = dont; ! 601: break; ! 602: } ! 603: sprintf(nfrontp, fmt, option); ! 604: nfrontp += sizeof (dont) - 2; ! 605: printoption("SENT", fmt, option); ! 606: } ! 607: ! 608: wontoption(option) ! 609: int option; ! 610: { ! 611: char *fmt; ! 612: ! 613: switch (option) { ! 614: ! 615: case TELOPT_ECHO: ! 616: (void) mode(2); ! 617: ! 618: case TELOPT_SGA: ! 619: hisopts[option] = 0; ! 620: fmt = dont; ! 621: break; ! 622: ! 623: default: ! 624: fmt = dont; ! 625: } ! 626: sprintf(nfrontp, fmt, option); ! 627: nfrontp += sizeof (doopt) - 2; ! 628: printoption("SENT", fmt, option); ! 629: } ! 630: ! 631: dooption(option) ! 632: int option; ! 633: { ! 634: char *fmt; ! 635: ! 636: switch (option) { ! 637: ! 638: case TELOPT_TM: ! 639: fmt = wont; ! 640: break; ! 641: ! 642: case TELOPT_ECHO: ! 643: (void) mode(2); ! 644: fmt = will; ! 645: hisopts[option] = 0; ! 646: break; ! 647: ! 648: case TELOPT_SGA: ! 649: fmt = will; ! 650: break; ! 651: ! 652: default: ! 653: fmt = wont; ! 654: break; ! 655: } ! 656: sprintf(nfrontp, fmt, option); ! 657: nfrontp += sizeof (doopt) - 2; ! 658: printoption("SENT", fmt, option); ! 659: } ! 660: ! 661: /* ! 662: * Set the escape character. ! 663: */ ! 664: setescape(argc, argv) ! 665: int argc; ! 666: char *argv[]; ! 667: { ! 668: register char *arg; ! 669: char buf[50]; ! 670: ! 671: if (argc > 2) ! 672: arg = argv[1]; ! 673: else { ! 674: printf("new escape character: "); ! 675: gets(buf); ! 676: arg = buf; ! 677: } ! 678: if (arg[0] != '\0') ! 679: escape = arg[0]; ! 680: printf("Escape character is '%s'.\n", control(escape)); ! 681: fflush(stdout); ! 682: } ! 683: ! 684: /*VARARGS*/ ! 685: setoptions() ! 686: { ! 687: ! 688: showoptions = !showoptions; ! 689: printf("%s show option processing.\n", showoptions ? "Will" : "Wont"); ! 690: fflush(stdout); ! 691: } ! 692: ! 693: /*VARARGS*/ ! 694: setcrmod() ! 695: { ! 696: ! 697: crmod = !crmod; ! 698: printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont"); ! 699: fflush(stdout); ! 700: } ! 701: ! 702: /*VARARGS*/ ! 703: setdebug() ! 704: { ! 705: ! 706: debug = !debug; ! 707: printf("%s turn on socket level debugging.\n", ! 708: debug ? "Will" : "Wont"); ! 709: fflush(stdout); ! 710: } ! 711: ! 712: /* ! 713: * Construct a control character sequence ! 714: * for a special character. ! 715: */ ! 716: char * ! 717: control(c) ! 718: register int c; ! 719: { ! 720: static char buf[3]; ! 721: ! 722: if (c == 0177) ! 723: return ("^?"); ! 724: if (c >= 040) { ! 725: buf[0] = c; ! 726: buf[1] = 0; ! 727: } else { ! 728: buf[0] = '^'; ! 729: buf[1] = '@'+c; ! 730: buf[2] = 0; ! 731: } ! 732: return (buf); ! 733: } ! 734: ! 735: struct cmd * ! 736: getcmd(name) ! 737: register char *name; ! 738: { ! 739: register char *p, *q; ! 740: register struct cmd *c, *found; ! 741: register int nmatches, longest; ! 742: ! 743: longest = 0; ! 744: nmatches = 0; ! 745: found = 0; ! 746: for (c = cmdtab; p = c->name; c++) { ! 747: for (q = name; *q == *p++; q++) ! 748: if (*q == 0) /* exact match? */ ! 749: return (c); ! 750: if (!*q) { /* the name was a prefix */ ! 751: if (q - name > longest) { ! 752: longest = q - name; ! 753: nmatches = 1; ! 754: found = c; ! 755: } else if (q - name == longest) ! 756: nmatches++; ! 757: } ! 758: } ! 759: if (nmatches > 1) ! 760: return ((struct cmd *)-1); ! 761: return (found); ! 762: } ! 763: ! 764: intr() ! 765: { ! 766: (void) mode(0); ! 767: longjmp(toplevel, -1); ! 768: } ! 769: ! 770: ttyflush(fd) ! 771: { ! 772: int n; ! 773: ! 774: if ((n = tfrontp - tbackp) > 0) ! 775: n = write(fd, tbackp, n); ! 776: if (n < 0) ! 777: return; ! 778: tbackp += n; ! 779: if (tbackp == tfrontp) ! 780: tbackp = tfrontp = ttyobuf; ! 781: } ! 782: ! 783: netflush(fd) ! 784: { ! 785: int n; ! 786: ! 787: if ((n = nfrontp - nbackp) > 0) ! 788: n = write(fd, nbackp, n); ! 789: if (n > 0) ! 790: nbackp += n; ! 791: if (nbackp == nfrontp) ! 792: nbackp = nfrontp = netobuf; ! 793: } ! 794: ! 795: /*VARARGS*/ ! 796: printoption(direction, fmt, option, what) ! 797: char *direction, *fmt; ! 798: int option, what; ! 799: { ! 800: if (!showoptions) ! 801: return; ! 802: printf("%s ", direction); ! 803: if (fmt == doopt) ! 804: fmt = "do"; ! 805: else if (fmt == dont) ! 806: fmt = "dont"; ! 807: else if (fmt == will) ! 808: fmt = "will"; ! 809: else if (fmt == wont) ! 810: fmt = "wont"; ! 811: else ! 812: fmt = "???"; ! 813: if (option < TELOPT_SUPDUP) ! 814: printf("%s %s", fmt, telopts[option]); ! 815: else ! 816: printf("%s %d", fmt, option); ! 817: if (*direction == '<') { ! 818: printf("\r\n"); ! 819: return; ! 820: } ! 821: printf(" (%s)\r\n", what ? "reply" : "don't reply"); ! 822: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.