Annotation of src/usr.bin/telnet/telnet.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2: * Copyright (c) 1988, 1990, 1993
! 3: * The Regents of the University of California. All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. All advertising materials mentioning features or use of this software
! 14: * must display the following acknowledgement:
! 15: * This product includes software developed by the University of
! 16: * California, Berkeley and its contributors.
! 17: * 4. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: */
! 33:
! 34: #ifndef lint
! 35: /* from: static char sccsid[] = "@(#)telnet.c 8.1 (Berkeley) 6/6/93"; */
! 36: static char *rcsid = "$Id: telnet.c,v 1.4 1995/03/17 18:03:10 mycroft Exp $";
! 37: #endif /* not lint */
! 38:
! 39: #include <sys/types.h>
! 40:
! 41: #if defined(unix)
! 42: #include <signal.h>
! 43: /* By the way, we need to include curses.h before telnet.h since,
! 44: * among other things, telnet.h #defines 'DO', which is a variable
! 45: * declared in curses.h.
! 46: */
! 47: #endif /* defined(unix) */
! 48:
! 49: #include <arpa/telnet.h>
! 50:
! 51: #include <ctype.h>
! 52:
! 53: #include "ring.h"
! 54:
! 55: #include "defines.h"
! 56: #include "externs.h"
! 57: #include "types.h"
! 58: #include "general.h"
! 59:
! 60:
! 61: #define strip(x) ((x)&0x7f)
! 62:
! 63: static unsigned char subbuffer[SUBBUFSIZE],
! 64: *subpointer, *subend; /* buffer for sub-options */
! 65: #define SB_CLEAR() subpointer = subbuffer;
! 66: #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
! 67: #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
! 68: *subpointer++ = (c); \
! 69: }
! 70:
! 71: #define SB_GET() ((*subpointer++)&0xff)
! 72: #define SB_PEEK() ((*subpointer)&0xff)
! 73: #define SB_EOF() (subpointer >= subend)
! 74: #define SB_LEN() (subend - subpointer)
! 75:
! 76: char options[256]; /* The combined options */
! 77: char do_dont_resp[256];
! 78: char will_wont_resp[256];
! 79:
! 80: int
! 81: eight = 0,
! 82: autologin = 0, /* Autologin anyone? */
! 83: skiprc = 0,
! 84: connected,
! 85: showoptions,
! 86: In3270, /* Are we in 3270 mode? */
! 87: ISend, /* trying to send network data in */
! 88: debug = 0,
! 89: crmod,
! 90: netdata, /* Print out network data flow */
! 91: crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
! 92: #if defined(TN3270)
! 93: noasynchtty = 0,/* User specified "-noasynch" on command line */
! 94: noasynchnet = 0,/* User specified "-noasynch" on command line */
! 95: askedSGA = 0, /* We have talked about suppress go ahead */
! 96: #endif /* defined(TN3270) */
! 97: telnetport,
! 98: SYNCHing, /* we are in TELNET SYNCH mode */
! 99: flushout, /* flush output */
! 100: autoflush = 0, /* flush output when interrupting? */
! 101: autosynch, /* send interrupt characters with SYNCH? */
! 102: localflow, /* we handle flow control locally */
! 103: restartany, /* if flow control enabled, restart on any character */
! 104: localchars, /* we recognize interrupt/quit */
! 105: donelclchars, /* the user has set "localchars" */
! 106: donebinarytoggle, /* the user has put us in binary */
! 107: dontlecho, /* do we suppress local echoing right now? */
! 108: globalmode,
! 109: clienteof = 0;
! 110:
! 111: char *prompt = 0;
! 112:
! 113: cc_t escape;
! 114: cc_t rlogin;
! 115: #ifdef KLUDGELINEMODE
! 116: cc_t echoc;
! 117: #endif
! 118:
! 119: /*
! 120: * Telnet receiver states for fsm
! 121: */
! 122: #define TS_DATA 0
! 123: #define TS_IAC 1
! 124: #define TS_WILL 2
! 125: #define TS_WONT 3
! 126: #define TS_DO 4
! 127: #define TS_DONT 5
! 128: #define TS_CR 6
! 129: #define TS_SB 7 /* sub-option collection */
! 130: #define TS_SE 8 /* looking for sub-option end */
! 131:
! 132: static int telrcv_state;
! 133: #ifdef OLD_ENVIRON
! 134: unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
! 135: #else
! 136: # define telopt_environ TELOPT_NEW_ENVIRON
! 137: #endif
! 138:
! 139: jmp_buf toplevel = { 0 };
! 140: jmp_buf peerdied;
! 141:
! 142: int flushline;
! 143: int linemode;
! 144:
! 145: #ifdef KLUDGELINEMODE
! 146: int kludgelinemode = 1;
! 147: #endif
! 148:
! 149: /*
! 150: * The following are some clocks used to decide how to interpret
! 151: * the relationship between various variables.
! 152: */
! 153:
! 154: Clocks clocks;
! 155:
! 156: #ifdef notdef
! 157: Modelist modelist[] = {
! 158: { "telnet command mode", COMMAND_LINE },
! 159: { "character-at-a-time mode", 0 },
! 160: { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
! 161: { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
! 162: { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
! 163: { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
! 164: { "3270 mode", 0 },
! 165: };
! 166: #endif
! 167:
! 168:
! 169: /*
! 170: * Initialize telnet environment.
! 171: */
! 172:
! 173: void
! 174: init_telnet()
! 175: {
! 176: env_init();
! 177:
! 178: SB_CLEAR();
! 179: ClearArray(options);
! 180:
! 181: connected = In3270 = ISend = localflow = donebinarytoggle = 0;
! 182: #if defined(AUTHENTICATION)
! 183: auth_encrypt_connect(connected);
! 184: #endif /* defined(AUTHENTICATION) */
! 185: restartany = -1;
! 186:
! 187: SYNCHing = 0;
! 188:
! 189: /* Don't change NetTrace */
! 190:
! 191: escape = CONTROL(']');
! 192: rlogin = _POSIX_VDISABLE;
! 193: #ifdef KLUDGELINEMODE
! 194: echoc = CONTROL('E');
! 195: #endif
! 196:
! 197: flushline = 1;
! 198: telrcv_state = TS_DATA;
! 199: }
! 200:
! 201:
! 202: #ifdef notdef
! 203: #include <varargs.h>
! 204:
! 205: /*VARARGS*/
! 206: static void
! 207: printring(va_alist)
! 208: va_dcl
! 209: {
! 210: va_list ap;
! 211: char buffer[100]; /* where things go */
! 212: char *ptr;
! 213: char *format;
! 214: char *string;
! 215: Ring *ring;
! 216: int i;
! 217:
! 218: va_start(ap);
! 219:
! 220: ring = va_arg(ap, Ring *);
! 221: format = va_arg(ap, char *);
! 222: ptr = buffer;
! 223:
! 224: while ((i = *format++) != 0) {
! 225: if (i == '%') {
! 226: i = *format++;
! 227: switch (i) {
! 228: case 'c':
! 229: *ptr++ = va_arg(ap, int);
! 230: break;
! 231: case 's':
! 232: string = va_arg(ap, char *);
! 233: ring_supply_data(ring, buffer, ptr-buffer);
! 234: ring_supply_data(ring, string, strlen(string));
! 235: ptr = buffer;
! 236: break;
! 237: case 0:
! 238: ExitString("printring: trailing %%.\n", 1);
! 239: /*NOTREACHED*/
! 240: default:
! 241: ExitString("printring: unknown format character.\n", 1);
! 242: /*NOTREACHED*/
! 243: }
! 244: } else {
! 245: *ptr++ = i;
! 246: }
! 247: }
! 248: ring_supply_data(ring, buffer, ptr-buffer);
! 249: }
! 250: #endif
! 251:
! 252: /*
! 253: * These routines are in charge of sending option negotiations
! 254: * to the other side.
! 255: *
! 256: * The basic idea is that we send the negotiation if either side
! 257: * is in disagreement as to what the current state should be.
! 258: */
! 259:
! 260: void
! 261: send_do(c, init)
! 262: register int c, init;
! 263: {
! 264: if (init) {
! 265: if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
! 266: my_want_state_is_do(c))
! 267: return;
! 268: set_my_want_state_do(c);
! 269: do_dont_resp[c]++;
! 270: }
! 271: NET2ADD(IAC, DO);
! 272: NETADD(c);
! 273: printoption("SENT", DO, c);
! 274: }
! 275:
! 276: void
! 277: send_dont(c, init)
! 278: register int c, init;
! 279: {
! 280: if (init) {
! 281: if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
! 282: my_want_state_is_dont(c))
! 283: return;
! 284: set_my_want_state_dont(c);
! 285: do_dont_resp[c]++;
! 286: }
! 287: NET2ADD(IAC, DONT);
! 288: NETADD(c);
! 289: printoption("SENT", DONT, c);
! 290: }
! 291:
! 292: void
! 293: send_will(c, init)
! 294: register int c, init;
! 295: {
! 296: if (init) {
! 297: if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
! 298: my_want_state_is_will(c))
! 299: return;
! 300: set_my_want_state_will(c);
! 301: will_wont_resp[c]++;
! 302: }
! 303: NET2ADD(IAC, WILL);
! 304: NETADD(c);
! 305: printoption("SENT", WILL, c);
! 306: }
! 307:
! 308: void
! 309: send_wont(c, init)
! 310: register int c, init;
! 311: {
! 312: if (init) {
! 313: if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
! 314: my_want_state_is_wont(c))
! 315: return;
! 316: set_my_want_state_wont(c);
! 317: will_wont_resp[c]++;
! 318: }
! 319: NET2ADD(IAC, WONT);
! 320: NETADD(c);
! 321: printoption("SENT", WONT, c);
! 322: }
! 323:
! 324:
! 325: void
! 326: willoption(option)
! 327: int option;
! 328: {
! 329: int new_state_ok = 0;
! 330:
! 331: if (do_dont_resp[option]) {
! 332: --do_dont_resp[option];
! 333: if (do_dont_resp[option] && my_state_is_do(option))
! 334: --do_dont_resp[option];
! 335: }
! 336:
! 337: if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
! 338:
! 339: switch (option) {
! 340:
! 341: case TELOPT_ECHO:
! 342: # if defined(TN3270)
! 343: /*
! 344: * The following is a pain in the rear-end.
! 345: * Various IBM servers (some versions of Wiscnet,
! 346: * possibly Fibronics/Spartacus, and who knows who
! 347: * else) will NOT allow us to send "DO SGA" too early
! 348: * in the setup proceedings. On the other hand,
! 349: * 4.2 servers (telnetd) won't set SGA correctly.
! 350: * So, we are stuck. Empirically (but, based on
! 351: * a VERY small sample), the IBM servers don't send
! 352: * out anything about ECHO, so we postpone our sending
! 353: * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
! 354: * DO send).
! 355: */
! 356: {
! 357: if (askedSGA == 0) {
! 358: askedSGA = 1;
! 359: if (my_want_state_is_dont(TELOPT_SGA))
! 360: send_do(TELOPT_SGA, 1);
! 361: }
! 362: }
! 363: /* Fall through */
! 364: case TELOPT_EOR:
! 365: #endif /* defined(TN3270) */
! 366: case TELOPT_BINARY:
! 367: case TELOPT_SGA:
! 368: settimer(modenegotiated);
! 369: /* FALL THROUGH */
! 370: case TELOPT_STATUS:
! 371: #if defined(AUTHENTICATION)
! 372: case TELOPT_AUTHENTICATION:
! 373: #endif
! 374: new_state_ok = 1;
! 375: break;
! 376:
! 377: case TELOPT_TM:
! 378: if (flushout)
! 379: flushout = 0;
! 380: /*
! 381: * Special case for TM. If we get back a WILL,
! 382: * pretend we got back a WONT.
! 383: */
! 384: set_my_want_state_dont(option);
! 385: set_my_state_dont(option);
! 386: return; /* Never reply to TM will's/wont's */
! 387:
! 388: case TELOPT_LINEMODE:
! 389: default:
! 390: break;
! 391: }
! 392:
! 393: if (new_state_ok) {
! 394: set_my_want_state_do(option);
! 395: send_do(option, 0);
! 396: setconnmode(0); /* possibly set new tty mode */
! 397: } else {
! 398: do_dont_resp[option]++;
! 399: send_dont(option, 0);
! 400: }
! 401: }
! 402: set_my_state_do(option);
! 403: }
! 404:
! 405: void
! 406: wontoption(option)
! 407: int option;
! 408: {
! 409: if (do_dont_resp[option]) {
! 410: --do_dont_resp[option];
! 411: if (do_dont_resp[option] && my_state_is_dont(option))
! 412: --do_dont_resp[option];
! 413: }
! 414:
! 415: if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
! 416:
! 417: switch (option) {
! 418:
! 419: #ifdef KLUDGELINEMODE
! 420: case TELOPT_SGA:
! 421: if (!kludgelinemode)
! 422: break;
! 423: /* FALL THROUGH */
! 424: #endif
! 425: case TELOPT_ECHO:
! 426: settimer(modenegotiated);
! 427: break;
! 428:
! 429: case TELOPT_TM:
! 430: if (flushout)
! 431: flushout = 0;
! 432: set_my_want_state_dont(option);
! 433: set_my_state_dont(option);
! 434: return; /* Never reply to TM will's/wont's */
! 435:
! 436: default:
! 437: break;
! 438: }
! 439: set_my_want_state_dont(option);
! 440: if (my_state_is_do(option))
! 441: send_dont(option, 0);
! 442: setconnmode(0); /* Set new tty mode */
! 443: } else if (option == TELOPT_TM) {
! 444: /*
! 445: * Special case for TM.
! 446: */
! 447: if (flushout)
! 448: flushout = 0;
! 449: set_my_want_state_dont(option);
! 450: }
! 451: set_my_state_dont(option);
! 452: }
! 453:
! 454: static void
! 455: dooption(option)
! 456: int option;
! 457: {
! 458: int new_state_ok = 0;
! 459:
! 460: if (will_wont_resp[option]) {
! 461: --will_wont_resp[option];
! 462: if (will_wont_resp[option] && my_state_is_will(option))
! 463: --will_wont_resp[option];
! 464: }
! 465:
! 466: if (will_wont_resp[option] == 0) {
! 467: if (my_want_state_is_wont(option)) {
! 468:
! 469: switch (option) {
! 470:
! 471: case TELOPT_TM:
! 472: /*
! 473: * Special case for TM. We send a WILL, but pretend
! 474: * we sent WONT.
! 475: */
! 476: send_will(option, 0);
! 477: set_my_want_state_wont(TELOPT_TM);
! 478: set_my_state_wont(TELOPT_TM);
! 479: return;
! 480:
! 481: # if defined(TN3270)
! 482: case TELOPT_EOR: /* end of record */
! 483: # endif /* defined(TN3270) */
! 484: case TELOPT_BINARY: /* binary mode */
! 485: case TELOPT_NAWS: /* window size */
! 486: case TELOPT_TSPEED: /* terminal speed */
! 487: case TELOPT_LFLOW: /* local flow control */
! 488: case TELOPT_TTYPE: /* terminal type option */
! 489: case TELOPT_SGA: /* no big deal */
! 490: new_state_ok = 1;
! 491: break;
! 492:
! 493: case TELOPT_NEW_ENVIRON: /* New environment variable option */
! 494: #ifdef OLD_ENVIRON
! 495: if (my_state_is_will(TELOPT_OLD_ENVIRON))
! 496: send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
! 497: goto env_common;
! 498: case TELOPT_OLD_ENVIRON: /* Old environment variable option */
! 499: if (my_state_is_will(TELOPT_NEW_ENVIRON))
! 500: break; /* Don't enable if new one is in use! */
! 501: env_common:
! 502: telopt_environ = option;
! 503: #endif
! 504: new_state_ok = 1;
! 505: break;
! 506:
! 507: #if defined(AUTHENTICATION)
! 508: case TELOPT_AUTHENTICATION:
! 509: if (autologin)
! 510: new_state_ok = 1;
! 511: break;
! 512: #endif
! 513:
! 514: case TELOPT_XDISPLOC: /* X Display location */
! 515: if (env_getvalue((unsigned char *)"DISPLAY"))
! 516: new_state_ok = 1;
! 517: break;
! 518:
! 519: case TELOPT_LINEMODE:
! 520: #ifdef KLUDGELINEMODE
! 521: kludgelinemode = 0;
! 522: send_do(TELOPT_SGA, 1);
! 523: #endif
! 524: set_my_want_state_will(TELOPT_LINEMODE);
! 525: send_will(option, 0);
! 526: set_my_state_will(TELOPT_LINEMODE);
! 527: slc_init();
! 528: return;
! 529:
! 530: case TELOPT_ECHO: /* We're never going to echo... */
! 531: default:
! 532: break;
! 533: }
! 534:
! 535: if (new_state_ok) {
! 536: set_my_want_state_will(option);
! 537: send_will(option, 0);
! 538: setconnmode(0); /* Set new tty mode */
! 539: } else {
! 540: will_wont_resp[option]++;
! 541: send_wont(option, 0);
! 542: }
! 543: } else {
! 544: /*
! 545: * Handle options that need more things done after the
! 546: * other side has acknowledged the option.
! 547: */
! 548: switch (option) {
! 549: case TELOPT_LINEMODE:
! 550: #ifdef KLUDGELINEMODE
! 551: kludgelinemode = 0;
! 552: send_do(TELOPT_SGA, 1);
! 553: #endif
! 554: set_my_state_will(option);
! 555: slc_init();
! 556: send_do(TELOPT_SGA, 0);
! 557: return;
! 558: }
! 559: }
! 560: }
! 561: set_my_state_will(option);
! 562: }
! 563:
! 564: static void
! 565: dontoption(option)
! 566: int option;
! 567: {
! 568:
! 569: if (will_wont_resp[option]) {
! 570: --will_wont_resp[option];
! 571: if (will_wont_resp[option] && my_state_is_wont(option))
! 572: --will_wont_resp[option];
! 573: }
! 574:
! 575: if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
! 576: switch (option) {
! 577: case TELOPT_LINEMODE:
! 578: linemode = 0; /* put us back to the default state */
! 579: break;
! 580: #ifdef OLD_ENVIRON
! 581: case TELOPT_NEW_ENVIRON:
! 582: /*
! 583: * The new environ option wasn't recognized, try
! 584: * the old one.
! 585: */
! 586: send_will(TELOPT_OLD_ENVIRON, 1);
! 587: telopt_environ = TELOPT_OLD_ENVIRON;
! 588: break;
! 589: #endif
! 590: }
! 591: /* we always accept a DONT */
! 592: set_my_want_state_wont(option);
! 593: if (my_state_is_will(option))
! 594: send_wont(option, 0);
! 595: setconnmode(0); /* Set new tty mode */
! 596: }
! 597: set_my_state_wont(option);
! 598: }
! 599:
! 600: /*
! 601: * Given a buffer returned by tgetent(), this routine will turn
! 602: * the pipe seperated list of names in the buffer into an array
! 603: * of pointers to null terminated names. We toss out any bad,
! 604: * duplicate, or verbose names (names with spaces).
! 605: */
! 606:
! 607: static char *name_unknown = "UNKNOWN";
! 608: static char *unknown[] = { 0, 0 };
! 609:
! 610: char **
! 611: mklist(buf, name)
! 612: char *buf, *name;
! 613: {
! 614: register int n;
! 615: register char c, *cp, **argvp, *cp2, **argv, **avt;
! 616:
! 617: if (name) {
! 618: if (strlen(name) > 40) {
! 619: name = 0;
! 620: unknown[0] = name_unknown;
! 621: } else {
! 622: unknown[0] = name;
! 623: upcase(name);
! 624: }
! 625: } else
! 626: unknown[0] = name_unknown;
! 627: /*
! 628: * Count up the number of names.
! 629: */
! 630: for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
! 631: if (*cp == '|')
! 632: n++;
! 633: }
! 634: /*
! 635: * Allocate an array to put the name pointers into
! 636: */
! 637: argv = (char **)malloc((n+3)*sizeof(char *));
! 638: if (argv == 0)
! 639: return(unknown);
! 640:
! 641: /*
! 642: * Fill up the array of pointers to names.
! 643: */
! 644: *argv = 0;
! 645: argvp = argv+1;
! 646: n = 0;
! 647: for (cp = cp2 = buf; (c = *cp); cp++) {
! 648: if (c == '|' || c == ':') {
! 649: *cp++ = '\0';
! 650: /*
! 651: * Skip entries that have spaces or are over 40
! 652: * characters long. If this is our environment
! 653: * name, then put it up front. Otherwise, as
! 654: * long as this is not a duplicate name (case
! 655: * insensitive) add it to the list.
! 656: */
! 657: if (n || (cp - cp2 > 41))
! 658: ;
! 659: else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
! 660: *argv = cp2;
! 661: else if (is_unique(cp2, argv+1, argvp))
! 662: *argvp++ = cp2;
! 663: if (c == ':')
! 664: break;
! 665: /*
! 666: * Skip multiple delimiters. Reset cp2 to
! 667: * the beginning of the next name. Reset n,
! 668: * the flag for names with spaces.
! 669: */
! 670: while ((c = *cp) == '|')
! 671: cp++;
! 672: cp2 = cp;
! 673: n = 0;
! 674: }
! 675: /*
! 676: * Skip entries with spaces or non-ascii values.
! 677: * Convert lower case letters to upper case.
! 678: */
! 679: if ((c == ' ') || !isascii(c))
! 680: n = 1;
! 681: else if (islower(c))
! 682: *cp = toupper(c);
! 683: }
! 684:
! 685: /*
! 686: * Check for an old V6 2 character name. If the second
! 687: * name points to the beginning of the buffer, and is
! 688: * only 2 characters long, move it to the end of the array.
! 689: */
! 690: if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
! 691: --argvp;
! 692: for (avt = &argv[1]; avt < argvp; avt++)
! 693: *avt = *(avt+1);
! 694: *argvp++ = buf;
! 695: }
! 696:
! 697: /*
! 698: * Duplicate last name, for TTYPE option, and null
! 699: * terminate the array. If we didn't find a match on
! 700: * our terminal name, put that name at the beginning.
! 701: */
! 702: cp = *(argvp-1);
! 703: *argvp++ = cp;
! 704: *argvp = 0;
! 705:
! 706: if (*argv == 0) {
! 707: if (name)
! 708: *argv = name;
! 709: else {
! 710: --argvp;
! 711: for (avt = argv; avt < argvp; avt++)
! 712: *avt = *(avt+1);
! 713: }
! 714: }
! 715: if (*argv)
! 716: return(argv);
! 717: else
! 718: return(unknown);
! 719: }
! 720:
! 721: int
! 722: is_unique(name, as, ae)
! 723: register char *name, **as, **ae;
! 724: {
! 725: register char **ap;
! 726: register int n;
! 727:
! 728: n = strlen(name) + 1;
! 729: for (ap = as; ap < ae; ap++)
! 730: if (strncasecmp(*ap, name, n) == 0)
! 731: return(0);
! 732: return (1);
! 733: }
! 734:
! 735: #ifdef TERMCAP
! 736: char termbuf[1024];
! 737:
! 738: /*ARGSUSED*/
! 739: int
! 740: setupterm(tname, fd, errp)
! 741: char *tname;
! 742: int fd, *errp;
! 743: {
! 744: if (tgetent(termbuf, tname) == 1) {
! 745: termbuf[1023] = '\0';
! 746: if (errp)
! 747: *errp = 1;
! 748: return(0);
! 749: }
! 750: if (errp)
! 751: *errp = 0;
! 752: return(-1);
! 753: }
! 754: #else
! 755: #define termbuf ttytype
! 756: extern char ttytype[];
! 757: #endif
! 758:
! 759: int resettermname = 1;
! 760:
! 761: char *
! 762: gettermname()
! 763: {
! 764: char *tname;
! 765: static char **tnamep = 0;
! 766: static char **next;
! 767: int err;
! 768:
! 769: if (resettermname) {
! 770: resettermname = 0;
! 771: if (tnamep && tnamep != unknown)
! 772: free(tnamep);
! 773: if ((tname = (char *)env_getvalue((unsigned char *)"TERM")) &&
! 774: (setupterm(tname, 1, &err) == 0)) {
! 775: tnamep = mklist(termbuf, tname);
! 776: } else {
! 777: if (tname && (strlen(tname) <= 40)) {
! 778: unknown[0] = tname;
! 779: upcase(tname);
! 780: } else
! 781: unknown[0] = name_unknown;
! 782: tnamep = unknown;
! 783: }
! 784: next = tnamep;
! 785: }
! 786: if (*next == 0)
! 787: next = tnamep;
! 788: return(*next++);
! 789: }
! 790: /*
! 791: * suboption()
! 792: *
! 793: * Look at the sub-option buffer, and try to be helpful to the other
! 794: * side.
! 795: *
! 796: * Currently we recognize:
! 797: *
! 798: * Terminal type, send request.
! 799: * Terminal speed (send request).
! 800: * Local flow control (is request).
! 801: * Linemode
! 802: */
! 803:
! 804: static void
! 805: suboption()
! 806: {
! 807: unsigned char subchar;
! 808:
! 809: printsub('<', subbuffer, SB_LEN()+2);
! 810: switch (subchar = SB_GET()) {
! 811: case TELOPT_TTYPE:
! 812: if (my_want_state_is_wont(TELOPT_TTYPE))
! 813: return;
! 814: if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
! 815: return;
! 816: } else {
! 817: char *name;
! 818: unsigned char temp[50];
! 819: int len;
! 820:
! 821: #if defined(TN3270)
! 822: if (tn3270_ttype()) {
! 823: return;
! 824: }
! 825: #endif /* defined(TN3270) */
! 826: name = gettermname();
! 827: len = strlen(name) + 4 + 2;
! 828: if (len < NETROOM()) {
! 829: sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
! 830: TELQUAL_IS, name, IAC, SE);
! 831: ring_supply_data(&netoring, temp, len);
! 832: printsub('>', &temp[2], len-2);
! 833: } else {
! 834: ExitString("No room in buffer for terminal type.\n", 1);
! 835: /*NOTREACHED*/
! 836: }
! 837: }
! 838: break;
! 839: case TELOPT_TSPEED:
! 840: if (my_want_state_is_wont(TELOPT_TSPEED))
! 841: return;
! 842: if (SB_EOF())
! 843: return;
! 844: if (SB_GET() == TELQUAL_SEND) {
! 845: long ospeed, ispeed;
! 846: unsigned char temp[50];
! 847: int len;
! 848:
! 849: TerminalSpeeds(&ispeed, &ospeed);
! 850:
! 851: sprintf((char *)temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
! 852: TELQUAL_IS, ospeed, ispeed, IAC, SE);
! 853: len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
! 854:
! 855: if (len < NETROOM()) {
! 856: ring_supply_data(&netoring, temp, len);
! 857: printsub('>', temp+2, len - 2);
! 858: }
! 859: /*@*/ else printf("lm_will: not enough room in buffer\n");
! 860: }
! 861: break;
! 862: case TELOPT_LFLOW:
! 863: if (my_want_state_is_wont(TELOPT_LFLOW))
! 864: return;
! 865: if (SB_EOF())
! 866: return;
! 867: switch(SB_GET()) {
! 868: case LFLOW_RESTART_ANY:
! 869: restartany = 1;
! 870: break;
! 871: case LFLOW_RESTART_XON:
! 872: restartany = 0;
! 873: break;
! 874: case LFLOW_ON:
! 875: localflow = 1;
! 876: break;
! 877: case LFLOW_OFF:
! 878: localflow = 0;
! 879: break;
! 880: default:
! 881: return;
! 882: }
! 883: setcommandmode();
! 884: setconnmode(0);
! 885: break;
! 886:
! 887: case TELOPT_LINEMODE:
! 888: if (my_want_state_is_wont(TELOPT_LINEMODE))
! 889: return;
! 890: if (SB_EOF())
! 891: return;
! 892: switch (SB_GET()) {
! 893: case WILL:
! 894: lm_will(subpointer, SB_LEN());
! 895: break;
! 896: case WONT:
! 897: lm_wont(subpointer, SB_LEN());
! 898: break;
! 899: case DO:
! 900: lm_do(subpointer, SB_LEN());
! 901: break;
! 902: case DONT:
! 903: lm_dont(subpointer, SB_LEN());
! 904: break;
! 905: case LM_SLC:
! 906: slc(subpointer, SB_LEN());
! 907: break;
! 908: case LM_MODE:
! 909: lm_mode(subpointer, SB_LEN(), 0);
! 910: break;
! 911: default:
! 912: break;
! 913: }
! 914: break;
! 915:
! 916: #ifdef OLD_ENVIRON
! 917: case TELOPT_OLD_ENVIRON:
! 918: #endif
! 919: case TELOPT_NEW_ENVIRON:
! 920: if (SB_EOF())
! 921: return;
! 922: switch(SB_PEEK()) {
! 923: case TELQUAL_IS:
! 924: case TELQUAL_INFO:
! 925: if (my_want_state_is_dont(subchar))
! 926: return;
! 927: break;
! 928: case TELQUAL_SEND:
! 929: if (my_want_state_is_wont(subchar)) {
! 930: return;
! 931: }
! 932: break;
! 933: default:
! 934: return;
! 935: }
! 936: env_opt(subpointer, SB_LEN());
! 937: break;
! 938:
! 939: case TELOPT_XDISPLOC:
! 940: if (my_want_state_is_wont(TELOPT_XDISPLOC))
! 941: return;
! 942: if (SB_EOF())
! 943: return;
! 944: if (SB_GET() == TELQUAL_SEND) {
! 945: unsigned char temp[50], *dp;
! 946: int len;
! 947:
! 948: if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == NULL) {
! 949: /*
! 950: * Something happened, we no longer have a DISPLAY
! 951: * variable. So, turn off the option.
! 952: */
! 953: send_wont(TELOPT_XDISPLOC, 1);
! 954: break;
! 955: }
! 956: sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
! 957: TELQUAL_IS, dp, IAC, SE);
! 958: len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
! 959:
! 960: if (len < NETROOM()) {
! 961: ring_supply_data(&netoring, temp, len);
! 962: printsub('>', temp+2, len - 2);
! 963: }
! 964: /*@*/ else printf("lm_will: not enough room in buffer\n");
! 965: }
! 966: break;
! 967:
! 968: #if defined(AUTHENTICATION)
! 969: case TELOPT_AUTHENTICATION: {
! 970: if (!autologin)
! 971: break;
! 972: if (SB_EOF())
! 973: return;
! 974: switch(SB_GET()) {
! 975: case TELQUAL_IS:
! 976: if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
! 977: return;
! 978: auth_is(subpointer, SB_LEN());
! 979: break;
! 980: case TELQUAL_SEND:
! 981: if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
! 982: return;
! 983: auth_send(subpointer, SB_LEN());
! 984: break;
! 985: case TELQUAL_REPLY:
! 986: if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
! 987: return;
! 988: auth_reply(subpointer, SB_LEN());
! 989: break;
! 990: case TELQUAL_NAME:
! 991: if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
! 992: return;
! 993: auth_name(subpointer, SB_LEN());
! 994: break;
! 995: }
! 996: }
! 997: break;
! 998: #endif
! 999: default:
! 1000: break;
! 1001: }
! 1002: }
! 1003:
! 1004: static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
! 1005:
! 1006: void
! 1007: lm_will(cmd, len)
! 1008: unsigned char *cmd;
! 1009: int len;
! 1010: {
! 1011: if (len < 1) {
! 1012: /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
! 1013: return;
! 1014: }
! 1015: switch(cmd[0]) {
! 1016: case LM_FORWARDMASK: /* We shouldn't ever get this... */
! 1017: default:
! 1018: str_lm[3] = DONT;
! 1019: str_lm[4] = cmd[0];
! 1020: if (NETROOM() > sizeof(str_lm)) {
! 1021: ring_supply_data(&netoring, str_lm, sizeof(str_lm));
! 1022: printsub('>', &str_lm[2], sizeof(str_lm)-2);
! 1023: }
! 1024: /*@*/ else printf("lm_will: not enough room in buffer\n");
! 1025: break;
! 1026: }
! 1027: }
! 1028:
! 1029: void
! 1030: lm_wont(cmd, len)
! 1031: unsigned char *cmd;
! 1032: int len;
! 1033: {
! 1034: if (len < 1) {
! 1035: /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
! 1036: return;
! 1037: }
! 1038: switch(cmd[0]) {
! 1039: case LM_FORWARDMASK: /* We shouldn't ever get this... */
! 1040: default:
! 1041: /* We are always DONT, so don't respond */
! 1042: return;
! 1043: }
! 1044: }
! 1045:
! 1046: void
! 1047: lm_do(cmd, len)
! 1048: unsigned char *cmd;
! 1049: int len;
! 1050: {
! 1051: if (len < 1) {
! 1052: /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
! 1053: return;
! 1054: }
! 1055: switch(cmd[0]) {
! 1056: case LM_FORWARDMASK:
! 1057: default:
! 1058: str_lm[3] = WONT;
! 1059: str_lm[4] = cmd[0];
! 1060: if (NETROOM() > sizeof(str_lm)) {
! 1061: ring_supply_data(&netoring, str_lm, sizeof(str_lm));
! 1062: printsub('>', &str_lm[2], sizeof(str_lm)-2);
! 1063: }
! 1064: /*@*/ else printf("lm_do: not enough room in buffer\n");
! 1065: break;
! 1066: }
! 1067: }
! 1068:
! 1069: void
! 1070: lm_dont(cmd, len)
! 1071: unsigned char *cmd;
! 1072: int len;
! 1073: {
! 1074: if (len < 1) {
! 1075: /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
! 1076: return;
! 1077: }
! 1078: switch(cmd[0]) {
! 1079: case LM_FORWARDMASK:
! 1080: default:
! 1081: /* we are always WONT, so don't respond */
! 1082: break;
! 1083: }
! 1084: }
! 1085:
! 1086: static unsigned char str_lm_mode[] = {
! 1087: IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
! 1088: };
! 1089:
! 1090: void
! 1091: lm_mode(cmd, len, init)
! 1092: unsigned char *cmd;
! 1093: int len, init;
! 1094: {
! 1095: if (len != 1)
! 1096: return;
! 1097: if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
! 1098: return;
! 1099: if (*cmd&MODE_ACK)
! 1100: return;
! 1101: linemode = *cmd&(MODE_MASK&~MODE_ACK);
! 1102: str_lm_mode[4] = linemode;
! 1103: if (!init)
! 1104: str_lm_mode[4] |= MODE_ACK;
! 1105: if (NETROOM() > sizeof(str_lm_mode)) {
! 1106: ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
! 1107: printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
! 1108: }
! 1109: /*@*/ else printf("lm_mode: not enough room in buffer\n");
! 1110: setconnmode(0); /* set changed mode */
! 1111: }
! 1112:
! 1113:
! 1114:
! 1115: /*
! 1116: * slc()
! 1117: * Handle special character suboption of LINEMODE.
! 1118: */
! 1119:
! 1120: struct spc {
! 1121: cc_t val;
! 1122: cc_t *valp;
! 1123: char flags; /* Current flags & level */
! 1124: char mylevel; /* Maximum level & flags */
! 1125: } spc_data[NSLC+1];
! 1126:
! 1127: #define SLC_IMPORT 0
! 1128: #define SLC_EXPORT 1
! 1129: #define SLC_RVALUE 2
! 1130: static int slc_mode = SLC_EXPORT;
! 1131:
! 1132: void
! 1133: slc_init()
! 1134: {
! 1135: register struct spc *spcp;
! 1136:
! 1137: localchars = 1;
! 1138: for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
! 1139: spcp->val = 0;
! 1140: spcp->valp = 0;
! 1141: spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
! 1142: }
! 1143:
! 1144: #define initfunc(func, flags) { \
! 1145: spcp = &spc_data[func]; \
! 1146: if (spcp->valp = tcval(func)) { \
! 1147: spcp->val = *spcp->valp; \
! 1148: spcp->mylevel = SLC_VARIABLE|flags; \
! 1149: } else { \
! 1150: spcp->val = 0; \
! 1151: spcp->mylevel = SLC_DEFAULT; \
! 1152: } \
! 1153: }
! 1154:
! 1155: initfunc(SLC_SYNCH, 0);
! 1156: /* No BRK */
! 1157: initfunc(SLC_AO, 0);
! 1158: initfunc(SLC_AYT, 0);
! 1159: /* No EOR */
! 1160: initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
! 1161: initfunc(SLC_EOF, 0);
! 1162: #ifndef SYSV_TERMIO
! 1163: initfunc(SLC_SUSP, SLC_FLUSHIN);
! 1164: #endif
! 1165: initfunc(SLC_EC, 0);
! 1166: initfunc(SLC_EL, 0);
! 1167: #ifndef SYSV_TERMIO
! 1168: initfunc(SLC_EW, 0);
! 1169: initfunc(SLC_RP, 0);
! 1170: initfunc(SLC_LNEXT, 0);
! 1171: #endif
! 1172: initfunc(SLC_XON, 0);
! 1173: initfunc(SLC_XOFF, 0);
! 1174: #ifdef SYSV_TERMIO
! 1175: spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
! 1176: spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
! 1177: #endif
! 1178: initfunc(SLC_FORW1, 0);
! 1179: #ifdef USE_TERMIO
! 1180: initfunc(SLC_FORW2, 0);
! 1181: /* No FORW2 */
! 1182: #endif
! 1183:
! 1184: initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
! 1185: #undef initfunc
! 1186:
! 1187: if (slc_mode == SLC_EXPORT)
! 1188: slc_export();
! 1189: else
! 1190: slc_import(1);
! 1191:
! 1192: }
! 1193:
! 1194: void
! 1195: slcstate()
! 1196: {
! 1197: printf("Special characters are %s values\n",
! 1198: slc_mode == SLC_IMPORT ? "remote default" :
! 1199: slc_mode == SLC_EXPORT ? "local" :
! 1200: "remote");
! 1201: }
! 1202:
! 1203: void
! 1204: slc_mode_export()
! 1205: {
! 1206: slc_mode = SLC_EXPORT;
! 1207: if (my_state_is_will(TELOPT_LINEMODE))
! 1208: slc_export();
! 1209: }
! 1210:
! 1211: void
! 1212: slc_mode_import(def)
! 1213: int def;
! 1214: {
! 1215: slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
! 1216: if (my_state_is_will(TELOPT_LINEMODE))
! 1217: slc_import(def);
! 1218: }
! 1219:
! 1220: unsigned char slc_import_val[] = {
! 1221: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
! 1222: };
! 1223: unsigned char slc_import_def[] = {
! 1224: IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
! 1225: };
! 1226:
! 1227: void
! 1228: slc_import(def)
! 1229: int def;
! 1230: {
! 1231: if (NETROOM() > sizeof(slc_import_val)) {
! 1232: if (def) {
! 1233: ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
! 1234: printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
! 1235: } else {
! 1236: ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
! 1237: printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
! 1238: }
! 1239: }
! 1240: /*@*/ else printf("slc_import: not enough room\n");
! 1241: }
! 1242:
! 1243: void
! 1244: slc_export()
! 1245: {
! 1246: register struct spc *spcp;
! 1247:
! 1248: TerminalDefaultChars();
! 1249:
! 1250: slc_start_reply();
! 1251: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
! 1252: if (spcp->mylevel != SLC_NOSUPPORT) {
! 1253: if (spcp->val == (cc_t)(_POSIX_VDISABLE))
! 1254: spcp->flags = SLC_NOSUPPORT;
! 1255: else
! 1256: spcp->flags = spcp->mylevel;
! 1257: if (spcp->valp)
! 1258: spcp->val = *spcp->valp;
! 1259: slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
! 1260: }
! 1261: }
! 1262: slc_end_reply();
! 1263: (void)slc_update();
! 1264: setconnmode(1); /* Make sure the character values are set */
! 1265: }
! 1266:
! 1267: void
! 1268: slc(cp, len)
! 1269: register unsigned char *cp;
! 1270: int len;
! 1271: {
! 1272: register struct spc *spcp;
! 1273: register int func,level;
! 1274:
! 1275: slc_start_reply();
! 1276:
! 1277: for (; len >= 3; len -=3, cp +=3) {
! 1278:
! 1279: func = cp[SLC_FUNC];
! 1280:
! 1281: if (func == 0) {
! 1282: /*
! 1283: * Client side: always ignore 0 function.
! 1284: */
! 1285: continue;
! 1286: }
! 1287: if (func > NSLC) {
! 1288: if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
! 1289: slc_add_reply(func, SLC_NOSUPPORT, 0);
! 1290: continue;
! 1291: }
! 1292:
! 1293: spcp = &spc_data[func];
! 1294:
! 1295: level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
! 1296:
! 1297: if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
! 1298: ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
! 1299: continue;
! 1300: }
! 1301:
! 1302: if (level == (SLC_DEFAULT|SLC_ACK)) {
! 1303: /*
! 1304: * This is an error condition, the SLC_ACK
! 1305: * bit should never be set for the SLC_DEFAULT
! 1306: * level. Our best guess to recover is to
! 1307: * ignore the SLC_ACK bit.
! 1308: */
! 1309: cp[SLC_FLAGS] &= ~SLC_ACK;
! 1310: }
! 1311:
! 1312: if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
! 1313: spcp->val = (cc_t)cp[SLC_VALUE];
! 1314: spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
! 1315: continue;
! 1316: }
! 1317:
! 1318: level &= ~SLC_ACK;
! 1319:
! 1320: if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
! 1321: spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
! 1322: spcp->val = (cc_t)cp[SLC_VALUE];
! 1323: }
! 1324: if (level == SLC_DEFAULT) {
! 1325: if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
! 1326: spcp->flags = spcp->mylevel;
! 1327: else
! 1328: spcp->flags = SLC_NOSUPPORT;
! 1329: }
! 1330: slc_add_reply(func, spcp->flags, spcp->val);
! 1331: }
! 1332: slc_end_reply();
! 1333: if (slc_update())
! 1334: setconnmode(1); /* set the new character values */
! 1335: }
! 1336:
! 1337: void
! 1338: slc_check()
! 1339: {
! 1340: register struct spc *spcp;
! 1341:
! 1342: slc_start_reply();
! 1343: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
! 1344: if (spcp->valp && spcp->val != *spcp->valp) {
! 1345: spcp->val = *spcp->valp;
! 1346: if (spcp->val == (cc_t)(_POSIX_VDISABLE))
! 1347: spcp->flags = SLC_NOSUPPORT;
! 1348: else
! 1349: spcp->flags = spcp->mylevel;
! 1350: slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
! 1351: }
! 1352: }
! 1353: slc_end_reply();
! 1354: setconnmode(1);
! 1355: }
! 1356:
! 1357:
! 1358: unsigned char slc_reply[128];
! 1359: unsigned char *slc_replyp;
! 1360:
! 1361: void
! 1362: slc_start_reply()
! 1363: {
! 1364: slc_replyp = slc_reply;
! 1365: *slc_replyp++ = IAC;
! 1366: *slc_replyp++ = SB;
! 1367: *slc_replyp++ = TELOPT_LINEMODE;
! 1368: *slc_replyp++ = LM_SLC;
! 1369: }
! 1370:
! 1371: void
! 1372: slc_add_reply(func, flags, value)
! 1373: unsigned char func;
! 1374: unsigned char flags;
! 1375: cc_t value;
! 1376: {
! 1377: if ((*slc_replyp++ = func) == IAC)
! 1378: *slc_replyp++ = IAC;
! 1379: if ((*slc_replyp++ = flags) == IAC)
! 1380: *slc_replyp++ = IAC;
! 1381: if ((*slc_replyp++ = (unsigned char)value) == IAC)
! 1382: *slc_replyp++ = IAC;
! 1383: }
! 1384:
! 1385: void
! 1386: slc_end_reply()
! 1387: {
! 1388: register int len;
! 1389:
! 1390: *slc_replyp++ = IAC;
! 1391: *slc_replyp++ = SE;
! 1392: len = slc_replyp - slc_reply;
! 1393: if (len <= 6)
! 1394: return;
! 1395: if (NETROOM() > len) {
! 1396: ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
! 1397: printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
! 1398: }
! 1399: /*@*/else printf("slc_end_reply: not enough room\n");
! 1400: }
! 1401:
! 1402: int
! 1403: slc_update()
! 1404: {
! 1405: register struct spc *spcp;
! 1406: int need_update = 0;
! 1407:
! 1408: for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
! 1409: if (!(spcp->flags&SLC_ACK))
! 1410: continue;
! 1411: spcp->flags &= ~SLC_ACK;
! 1412: if (spcp->valp && (*spcp->valp != spcp->val)) {
! 1413: *spcp->valp = spcp->val;
! 1414: need_update = 1;
! 1415: }
! 1416: }
! 1417: return(need_update);
! 1418: }
! 1419:
! 1420: #ifdef OLD_ENVIRON
! 1421: # ifdef ENV_HACK
! 1422: /*
! 1423: * Earlier version of telnet/telnetd from the BSD code had
! 1424: * the definitions of VALUE and VAR reversed. To ensure
! 1425: * maximum interoperability, we assume that the server is
! 1426: * an older BSD server, until proven otherwise. The newer
! 1427: * BSD servers should be able to handle either definition,
! 1428: * so it is better to use the wrong values if we don't
! 1429: * know what type of server it is.
! 1430: */
! 1431: int env_auto = 1;
! 1432: int old_env_var = OLD_ENV_VAR;
! 1433: int old_env_value = OLD_ENV_VALUE;
! 1434: # else
! 1435: # define old_env_var OLD_ENV_VAR
! 1436: # define old_env_value OLD_ENV_VALUE
! 1437: # endif
! 1438: #endif
! 1439:
! 1440: void
! 1441: env_opt(buf, len)
! 1442: register unsigned char *buf;
! 1443: register int len;
! 1444: {
! 1445: register unsigned char *ep = 0, *epc = 0;
! 1446: register int i;
! 1447:
! 1448: switch(buf[0]&0xff) {
! 1449: case TELQUAL_SEND:
! 1450: env_opt_start();
! 1451: if (len == 1) {
! 1452: env_opt_add(NULL);
! 1453: } else for (i = 1; i < len; i++) {
! 1454: switch (buf[i]&0xff) {
! 1455: #ifdef OLD_ENVIRON
! 1456: case OLD_ENV_VAR:
! 1457: # ifdef ENV_HACK
! 1458: if (telopt_environ == TELOPT_OLD_ENVIRON
! 1459: && env_auto) {
! 1460: /* Server has the same definitions */
! 1461: old_env_var = OLD_ENV_VAR;
! 1462: old_env_value = OLD_ENV_VALUE;
! 1463: }
! 1464: /* FALL THROUGH */
! 1465: # endif
! 1466: case OLD_ENV_VALUE:
! 1467: /*
! 1468: * Although OLD_ENV_VALUE is not legal, we will
! 1469: * still recognize it, just in case it is an
! 1470: * old server that has VAR & VALUE mixed up...
! 1471: */
! 1472: /* FALL THROUGH */
! 1473: #else
! 1474: case NEW_ENV_VAR:
! 1475: #endif
! 1476: case ENV_USERVAR:
! 1477: if (ep) {
! 1478: *epc = 0;
! 1479: env_opt_add(ep);
! 1480: }
! 1481: ep = epc = &buf[i+1];
! 1482: break;
! 1483: case ENV_ESC:
! 1484: i++;
! 1485: /*FALL THROUGH*/
! 1486: default:
! 1487: if (epc)
! 1488: *epc++ = buf[i];
! 1489: break;
! 1490: }
! 1491: }
! 1492: if (ep) {
! 1493: *epc = 0;
! 1494: env_opt_add(ep);
! 1495: }
! 1496: env_opt_end(1);
! 1497: break;
! 1498:
! 1499: case TELQUAL_IS:
! 1500: case TELQUAL_INFO:
! 1501: /* Ignore for now. We shouldn't get it anyway. */
! 1502: break;
! 1503:
! 1504: default:
! 1505: break;
! 1506: }
! 1507: }
! 1508:
! 1509: #define OPT_REPLY_SIZE 256
! 1510: unsigned char *opt_reply;
! 1511: unsigned char *opt_replyp;
! 1512: unsigned char *opt_replyend;
! 1513:
! 1514: void
! 1515: env_opt_start()
! 1516: {
! 1517: if (opt_reply)
! 1518: opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
! 1519: else
! 1520: opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
! 1521: if (opt_reply == NULL) {
! 1522: /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
! 1523: opt_reply = opt_replyp = opt_replyend = NULL;
! 1524: return;
! 1525: }
! 1526: opt_replyp = opt_reply;
! 1527: opt_replyend = opt_reply + OPT_REPLY_SIZE;
! 1528: *opt_replyp++ = IAC;
! 1529: *opt_replyp++ = SB;
! 1530: *opt_replyp++ = telopt_environ;
! 1531: *opt_replyp++ = TELQUAL_IS;
! 1532: }
! 1533:
! 1534: void
! 1535: env_opt_start_info()
! 1536: {
! 1537: env_opt_start();
! 1538: if (opt_replyp)
! 1539: opt_replyp[-1] = TELQUAL_INFO;
! 1540: }
! 1541:
! 1542: void
! 1543: env_opt_add(ep)
! 1544: register unsigned char *ep;
! 1545: {
! 1546: register unsigned char *vp, c;
! 1547:
! 1548: if (opt_reply == NULL) /*XXX*/
! 1549: return; /*XXX*/
! 1550:
! 1551: if (ep == NULL || *ep == '\0') {
! 1552: /* Send user defined variables first. */
! 1553: env_default(1, 0);
! 1554: while (ep = env_default(0, 0))
! 1555: env_opt_add(ep);
! 1556:
! 1557: /* Now add the list of well know variables. */
! 1558: env_default(1, 1);
! 1559: while (ep = env_default(0, 1))
! 1560: env_opt_add(ep);
! 1561: return;
! 1562: }
! 1563: vp = env_getvalue(ep);
! 1564: if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
! 1565: strlen((char *)ep) + 6 > opt_replyend)
! 1566: {
! 1567: register int len;
! 1568: opt_replyend += OPT_REPLY_SIZE;
! 1569: len = opt_replyend - opt_reply;
! 1570: opt_reply = (unsigned char *)realloc(opt_reply, len);
! 1571: if (opt_reply == NULL) {
! 1572: /*@*/ printf("env_opt_add: realloc() failed!!!\n");
! 1573: opt_reply = opt_replyp = opt_replyend = NULL;
! 1574: return;
! 1575: }
! 1576: opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
! 1577: opt_replyend = opt_reply + len;
! 1578: }
! 1579: if (opt_welldefined(ep))
! 1580: #ifdef OLD_ENVIRON
! 1581: if (telopt_environ == TELOPT_OLD_ENVIRON)
! 1582: *opt_replyp++ = old_env_var;
! 1583: else
! 1584: #endif
! 1585: *opt_replyp++ = NEW_ENV_VAR;
! 1586: else
! 1587: *opt_replyp++ = ENV_USERVAR;
! 1588: for (;;) {
! 1589: while (c = *ep++) {
! 1590: switch(c&0xff) {
! 1591: case IAC:
! 1592: *opt_replyp++ = IAC;
! 1593: break;
! 1594: case NEW_ENV_VAR:
! 1595: case NEW_ENV_VALUE:
! 1596: case ENV_ESC:
! 1597: case ENV_USERVAR:
! 1598: *opt_replyp++ = ENV_ESC;
! 1599: break;
! 1600: }
! 1601: *opt_replyp++ = c;
! 1602: }
! 1603: if (ep = vp) {
! 1604: #ifdef OLD_ENVIRON
! 1605: if (telopt_environ == TELOPT_OLD_ENVIRON)
! 1606: *opt_replyp++ = old_env_value;
! 1607: else
! 1608: #endif
! 1609: *opt_replyp++ = NEW_ENV_VALUE;
! 1610: vp = NULL;
! 1611: } else
! 1612: break;
! 1613: }
! 1614: }
! 1615:
! 1616: int
! 1617: opt_welldefined(ep)
! 1618: char *ep;
! 1619: {
! 1620: if ((strcmp(ep, "USER") == 0) ||
! 1621: (strcmp(ep, "DISPLAY") == 0) ||
! 1622: (strcmp(ep, "PRINTER") == 0) ||
! 1623: (strcmp(ep, "SYSTEMTYPE") == 0) ||
! 1624: (strcmp(ep, "JOB") == 0) ||
! 1625: (strcmp(ep, "ACCT") == 0))
! 1626: return(1);
! 1627: return(0);
! 1628: }
! 1629: void
! 1630: env_opt_end(emptyok)
! 1631: register int emptyok;
! 1632: {
! 1633: register int len;
! 1634:
! 1635: len = opt_replyp - opt_reply + 2;
! 1636: if (emptyok || len > 6) {
! 1637: *opt_replyp++ = IAC;
! 1638: *opt_replyp++ = SE;
! 1639: if (NETROOM() > len) {
! 1640: ring_supply_data(&netoring, opt_reply, len);
! 1641: printsub('>', &opt_reply[2], len - 2);
! 1642: }
! 1643: /*@*/ else printf("slc_end_reply: not enough room\n");
! 1644: }
! 1645: if (opt_reply) {
! 1646: free(opt_reply);
! 1647: opt_reply = opt_replyp = opt_replyend = NULL;
! 1648: }
! 1649: }
! 1650:
! 1651:
! 1652:
! 1653: int
! 1654: telrcv()
! 1655: {
! 1656: register int c;
! 1657: register int scc;
! 1658: register unsigned char *sbp;
! 1659: int count;
! 1660: int returnValue = 0;
! 1661:
! 1662: scc = 0;
! 1663: count = 0;
! 1664: while (TTYROOM() > 2) {
! 1665: if (scc == 0) {
! 1666: if (count) {
! 1667: ring_consumed(&netiring, count);
! 1668: returnValue = 1;
! 1669: count = 0;
! 1670: }
! 1671: sbp = netiring.consume;
! 1672: scc = ring_full_consecutive(&netiring);
! 1673: if (scc == 0) {
! 1674: /* No more data coming in */
! 1675: break;
! 1676: }
! 1677: }
! 1678:
! 1679: c = *sbp++ & 0xff, scc--; count++;
! 1680:
! 1681: switch (telrcv_state) {
! 1682:
! 1683: case TS_CR:
! 1684: telrcv_state = TS_DATA;
! 1685: if (c == '\0') {
! 1686: break; /* Ignore \0 after CR */
! 1687: }
! 1688: else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
! 1689: TTYADD(c);
! 1690: break;
! 1691: }
! 1692: /* Else, fall through */
! 1693:
! 1694: case TS_DATA:
! 1695: if (c == IAC) {
! 1696: telrcv_state = TS_IAC;
! 1697: break;
! 1698: }
! 1699: # if defined(TN3270)
! 1700: if (In3270) {
! 1701: *Ifrontp++ = c;
! 1702: while (scc > 0) {
! 1703: c = *sbp++ & 0377, scc--; count++;
! 1704: if (c == IAC) {
! 1705: telrcv_state = TS_IAC;
! 1706: break;
! 1707: }
! 1708: *Ifrontp++ = c;
! 1709: }
! 1710: } else
! 1711: # endif /* defined(TN3270) */
! 1712: /*
! 1713: * The 'crmod' hack (see following) is needed
! 1714: * since we can't * set CRMOD on output only.
! 1715: * Machines like MULTICS like to send \r without
! 1716: * \n; since we must turn off CRMOD to get proper
! 1717: * input, the mapping is done here (sigh).
! 1718: */
! 1719: if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
! 1720: if (scc > 0) {
! 1721: c = *sbp&0xff;
! 1722: if (c == 0) {
! 1723: sbp++, scc--; count++;
! 1724: /* a "true" CR */
! 1725: TTYADD('\r');
! 1726: } else if (my_want_state_is_dont(TELOPT_ECHO) &&
! 1727: (c == '\n')) {
! 1728: sbp++, scc--; count++;
! 1729: TTYADD('\n');
! 1730: } else {
! 1731:
! 1732: TTYADD('\r');
! 1733: if (crmod) {
! 1734: TTYADD('\n');
! 1735: }
! 1736: }
! 1737: } else {
! 1738: telrcv_state = TS_CR;
! 1739: TTYADD('\r');
! 1740: if (crmod) {
! 1741: TTYADD('\n');
! 1742: }
! 1743: }
! 1744: } else {
! 1745: TTYADD(c);
! 1746: }
! 1747: continue;
! 1748:
! 1749: case TS_IAC:
! 1750: process_iac:
! 1751: switch (c) {
! 1752:
! 1753: case WILL:
! 1754: telrcv_state = TS_WILL;
! 1755: continue;
! 1756:
! 1757: case WONT:
! 1758: telrcv_state = TS_WONT;
! 1759: continue;
! 1760:
! 1761: case DO:
! 1762: telrcv_state = TS_DO;
! 1763: continue;
! 1764:
! 1765: case DONT:
! 1766: telrcv_state = TS_DONT;
! 1767: continue;
! 1768:
! 1769: case DM:
! 1770: /*
! 1771: * We may have missed an urgent notification,
! 1772: * so make sure we flush whatever is in the
! 1773: * buffer currently.
! 1774: */
! 1775: printoption("RCVD", IAC, DM);
! 1776: SYNCHing = 1;
! 1777: (void) ttyflush(1);
! 1778: SYNCHing = stilloob();
! 1779: settimer(gotDM);
! 1780: break;
! 1781:
! 1782: case SB:
! 1783: SB_CLEAR();
! 1784: telrcv_state = TS_SB;
! 1785: continue;
! 1786:
! 1787: # if defined(TN3270)
! 1788: case EOR:
! 1789: if (In3270) {
! 1790: if (Ibackp == Ifrontp) {
! 1791: Ibackp = Ifrontp = Ibuf;
! 1792: ISend = 0; /* should have been! */
! 1793: } else {
! 1794: Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
! 1795: ISend = 1;
! 1796: }
! 1797: }
! 1798: printoption("RCVD", IAC, EOR);
! 1799: break;
! 1800: # endif /* defined(TN3270) */
! 1801:
! 1802: case IAC:
! 1803: # if !defined(TN3270)
! 1804: TTYADD(IAC);
! 1805: # else /* !defined(TN3270) */
! 1806: if (In3270) {
! 1807: *Ifrontp++ = IAC;
! 1808: } else {
! 1809: TTYADD(IAC);
! 1810: }
! 1811: # endif /* !defined(TN3270) */
! 1812: break;
! 1813:
! 1814: case NOP:
! 1815: case GA:
! 1816: default:
! 1817: printoption("RCVD", IAC, c);
! 1818: break;
! 1819: }
! 1820: telrcv_state = TS_DATA;
! 1821: continue;
! 1822:
! 1823: case TS_WILL:
! 1824: printoption("RCVD", WILL, c);
! 1825: willoption(c);
! 1826: SetIn3270();
! 1827: telrcv_state = TS_DATA;
! 1828: continue;
! 1829:
! 1830: case TS_WONT:
! 1831: printoption("RCVD", WONT, c);
! 1832: wontoption(c);
! 1833: SetIn3270();
! 1834: telrcv_state = TS_DATA;
! 1835: continue;
! 1836:
! 1837: case TS_DO:
! 1838: printoption("RCVD", DO, c);
! 1839: dooption(c);
! 1840: SetIn3270();
! 1841: if (c == TELOPT_NAWS) {
! 1842: sendnaws();
! 1843: } else if (c == TELOPT_LFLOW) {
! 1844: localflow = 1;
! 1845: setcommandmode();
! 1846: setconnmode(0);
! 1847: }
! 1848: telrcv_state = TS_DATA;
! 1849: continue;
! 1850:
! 1851: case TS_DONT:
! 1852: printoption("RCVD", DONT, c);
! 1853: dontoption(c);
! 1854: flushline = 1;
! 1855: setconnmode(0); /* set new tty mode (maybe) */
! 1856: SetIn3270();
! 1857: telrcv_state = TS_DATA;
! 1858: continue;
! 1859:
! 1860: case TS_SB:
! 1861: if (c == IAC) {
! 1862: telrcv_state = TS_SE;
! 1863: } else {
! 1864: SB_ACCUM(c);
! 1865: }
! 1866: continue;
! 1867:
! 1868: case TS_SE:
! 1869: if (c != SE) {
! 1870: if (c != IAC) {
! 1871: /*
! 1872: * This is an error. We only expect to get
! 1873: * "IAC IAC" or "IAC SE". Several things may
! 1874: * have happend. An IAC was not doubled, the
! 1875: * IAC SE was left off, or another option got
! 1876: * inserted into the suboption are all possibilities.
! 1877: * If we assume that the IAC was not doubled,
! 1878: * and really the IAC SE was left off, we could
! 1879: * get into an infinate loop here. So, instead,
! 1880: * we terminate the suboption, and process the
! 1881: * partial suboption if we can.
! 1882: */
! 1883: SB_ACCUM(IAC);
! 1884: SB_ACCUM(c);
! 1885: subpointer -= 2;
! 1886: SB_TERM();
! 1887:
! 1888: printoption("In SUBOPTION processing, RCVD", IAC, c);
! 1889: suboption(); /* handle sub-option */
! 1890: SetIn3270();
! 1891: telrcv_state = TS_IAC;
! 1892: goto process_iac;
! 1893: }
! 1894: SB_ACCUM(c);
! 1895: telrcv_state = TS_SB;
! 1896: } else {
! 1897: SB_ACCUM(IAC);
! 1898: SB_ACCUM(SE);
! 1899: subpointer -= 2;
! 1900: SB_TERM();
! 1901: suboption(); /* handle sub-option */
! 1902: SetIn3270();
! 1903: telrcv_state = TS_DATA;
! 1904: }
! 1905: }
! 1906: }
! 1907: if (count)
! 1908: ring_consumed(&netiring, count);
! 1909: return returnValue||count;
! 1910: }
! 1911:
! 1912: static int bol = 1, local = 0;
! 1913:
! 1914: int
! 1915: rlogin_susp()
! 1916: {
! 1917: if (local) {
! 1918: local = 0;
! 1919: bol = 1;
! 1920: command(0, "z\n", 2);
! 1921: return(1);
! 1922: }
! 1923: return(0);
! 1924: }
! 1925:
! 1926: static int
! 1927: telsnd()
! 1928: {
! 1929: int tcc;
! 1930: int count;
! 1931: int returnValue = 0;
! 1932: unsigned char *tbp;
! 1933:
! 1934: tcc = 0;
! 1935: count = 0;
! 1936: while (NETROOM() > 2) {
! 1937: register int sc;
! 1938: register int c;
! 1939:
! 1940: if (tcc == 0) {
! 1941: if (count) {
! 1942: ring_consumed(&ttyiring, count);
! 1943: returnValue = 1;
! 1944: count = 0;
! 1945: }
! 1946: tbp = ttyiring.consume;
! 1947: tcc = ring_full_consecutive(&ttyiring);
! 1948: if (tcc == 0) {
! 1949: break;
! 1950: }
! 1951: }
! 1952: c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
! 1953: if (rlogin != _POSIX_VDISABLE) {
! 1954: if (bol) {
! 1955: bol = 0;
! 1956: if (sc == rlogin) {
! 1957: local = 1;
! 1958: continue;
! 1959: }
! 1960: } else if (local) {
! 1961: local = 0;
! 1962: if (sc == '.' || c == termEofChar) {
! 1963: bol = 1;
! 1964: command(0, "close\n", 6);
! 1965: continue;
! 1966: }
! 1967: if (sc == termSuspChar) {
! 1968: bol = 1;
! 1969: command(0, "z\n", 2);
! 1970: continue;
! 1971: }
! 1972: if (sc == escape) {
! 1973: command(0, (char *)tbp, tcc);
! 1974: bol = 1;
! 1975: count += tcc;
! 1976: tcc = 0;
! 1977: flushline = 1;
! 1978: break;
! 1979: }
! 1980: if (sc != rlogin) {
! 1981: ++tcc;
! 1982: --tbp;
! 1983: --count;
! 1984: c = sc = rlogin;
! 1985: }
! 1986: }
! 1987: if ((sc == '\n') || (sc == '\r'))
! 1988: bol = 1;
! 1989: } else if (sc == escape) {
! 1990: /*
! 1991: * Double escape is a pass through of a single escape character.
! 1992: */
! 1993: if (tcc && strip(*tbp) == escape) {
! 1994: tbp++;
! 1995: tcc--;
! 1996: count++;
! 1997: bol = 0;
! 1998: } else {
! 1999: command(0, (char *)tbp, tcc);
! 2000: bol = 1;
! 2001: count += tcc;
! 2002: tcc = 0;
! 2003: flushline = 1;
! 2004: break;
! 2005: }
! 2006: } else
! 2007: bol = 0;
! 2008: #ifdef KLUDGELINEMODE
! 2009: if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
! 2010: if (tcc > 0 && strip(*tbp) == echoc) {
! 2011: tcc--; tbp++; count++;
! 2012: } else {
! 2013: dontlecho = !dontlecho;
! 2014: settimer(echotoggle);
! 2015: setconnmode(0);
! 2016: flushline = 1;
! 2017: break;
! 2018: }
! 2019: }
! 2020: #endif
! 2021: if (MODE_LOCAL_CHARS(globalmode)) {
! 2022: if (TerminalSpecialChars(sc) == 0) {
! 2023: bol = 1;
! 2024: break;
! 2025: }
! 2026: }
! 2027: if (my_want_state_is_wont(TELOPT_BINARY)) {
! 2028: switch (c) {
! 2029: case '\n':
! 2030: /*
! 2031: * If we are in CRMOD mode (\r ==> \n)
! 2032: * on our local machine, then probably
! 2033: * a newline (unix) is CRLF (TELNET).
! 2034: */
! 2035: if (MODE_LOCAL_CHARS(globalmode)) {
! 2036: NETADD('\r');
! 2037: }
! 2038: NETADD('\n');
! 2039: bol = flushline = 1;
! 2040: break;
! 2041: case '\r':
! 2042: if (!crlf) {
! 2043: NET2ADD('\r', '\0');
! 2044: } else {
! 2045: NET2ADD('\r', '\n');
! 2046: }
! 2047: bol = flushline = 1;
! 2048: break;
! 2049: case IAC:
! 2050: NET2ADD(IAC, IAC);
! 2051: break;
! 2052: default:
! 2053: NETADD(c);
! 2054: break;
! 2055: }
! 2056: } else if (c == IAC) {
! 2057: NET2ADD(IAC, IAC);
! 2058: } else {
! 2059: NETADD(c);
! 2060: }
! 2061: }
! 2062: if (count)
! 2063: ring_consumed(&ttyiring, count);
! 2064: return returnValue||count; /* Non-zero if we did anything */
! 2065: }
! 2066:
! 2067: /*
! 2068: * Scheduler()
! 2069: *
! 2070: * Try to do something.
! 2071: *
! 2072: * If we do something useful, return 1; else return 0.
! 2073: *
! 2074: */
! 2075:
! 2076:
! 2077: int
! 2078: Scheduler(block)
! 2079: int block; /* should we block in the select ? */
! 2080: {
! 2081: /* One wants to be a bit careful about setting returnValue
! 2082: * to one, since a one implies we did some useful work,
! 2083: * and therefore probably won't be called to block next
! 2084: * time (TN3270 mode only).
! 2085: */
! 2086: int returnValue;
! 2087: int netin, netout, netex, ttyin, ttyout;
! 2088:
! 2089: /* Decide which rings should be processed */
! 2090:
! 2091: netout = ring_full_count(&netoring) &&
! 2092: (flushline ||
! 2093: (my_want_state_is_wont(TELOPT_LINEMODE)
! 2094: #ifdef KLUDGELINEMODE
! 2095: && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
! 2096: #endif
! 2097: ) ||
! 2098: my_want_state_is_will(TELOPT_BINARY));
! 2099: ttyout = ring_full_count(&ttyoring);
! 2100:
! 2101: #if defined(TN3270)
! 2102: ttyin = ring_empty_count(&ttyiring) && (clienteof == 0) && (shell_active == 0);
! 2103: #else /* defined(TN3270) */
! 2104: ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
! 2105: #endif /* defined(TN3270) */
! 2106:
! 2107: #if defined(TN3270)
! 2108: netin = ring_empty_count(&netiring);
! 2109: # else /* !defined(TN3270) */
! 2110: netin = !ISend && ring_empty_count(&netiring);
! 2111: # endif /* !defined(TN3270) */
! 2112:
! 2113: netex = !SYNCHing;
! 2114:
! 2115: /* If we have seen a signal recently, reset things */
! 2116: # if defined(TN3270) && defined(unix)
! 2117: if (HaveInput) {
! 2118: HaveInput = 0;
! 2119: (void) signal(SIGIO, inputAvailable);
! 2120: }
! 2121: #endif /* defined(TN3270) && defined(unix) */
! 2122:
! 2123: /* Call to system code to process rings */
! 2124:
! 2125: returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
! 2126:
! 2127: /* Now, look at the input rings, looking for work to do. */
! 2128:
! 2129: if (ring_full_count(&ttyiring)) {
! 2130: # if defined(TN3270)
! 2131: if (In3270) {
! 2132: int c;
! 2133:
! 2134: c = DataFromTerminal(ttyiring.consume,
! 2135: ring_full_consecutive(&ttyiring));
! 2136: if (c) {
! 2137: returnValue = 1;
! 2138: ring_consumed(&ttyiring, c);
! 2139: }
! 2140: } else {
! 2141: # endif /* defined(TN3270) */
! 2142: returnValue |= telsnd();
! 2143: # if defined(TN3270)
! 2144: }
! 2145: # endif /* defined(TN3270) */
! 2146: }
! 2147:
! 2148: if (ring_full_count(&netiring)) {
! 2149: # if !defined(TN3270)
! 2150: returnValue |= telrcv();
! 2151: # else /* !defined(TN3270) */
! 2152: returnValue = Push3270();
! 2153: # endif /* !defined(TN3270) */
! 2154: }
! 2155: return returnValue;
! 2156: }
! 2157:
! 2158: /*
! 2159: * Select from tty and network...
! 2160: */
! 2161: void
! 2162: telnet(user)
! 2163: char *user;
! 2164: {
! 2165: sys_telnet_init();
! 2166:
! 2167: #if defined(AUTHENTICATION)
! 2168: {
! 2169: static char local_host[256] = { 0 };
! 2170:
! 2171: if (!local_host[0]) {
! 2172: gethostname(local_host, sizeof(local_host));
! 2173: local_host[sizeof(local_host)-1] = 0;
! 2174: }
! 2175: auth_encrypt_init(local_host, hostname, "TELNET", 0);
! 2176: auth_encrypt_user(user);
! 2177: }
! 2178: #endif /* defined(AUTHENTICATION) */
! 2179: # if !defined(TN3270)
! 2180: if (telnetport) {
! 2181: #if defined(AUTHENTICATION)
! 2182: if (autologin)
! 2183: send_will(TELOPT_AUTHENTICATION, 1);
! 2184: #endif
! 2185: send_do(TELOPT_SGA, 1);
! 2186: send_will(TELOPT_TTYPE, 1);
! 2187: send_will(TELOPT_NAWS, 1);
! 2188: send_will(TELOPT_TSPEED, 1);
! 2189: send_will(TELOPT_LFLOW, 1);
! 2190: send_will(TELOPT_LINEMODE, 1);
! 2191: send_will(TELOPT_NEW_ENVIRON, 1);
! 2192: send_do(TELOPT_STATUS, 1);
! 2193: if (env_getvalue((unsigned char *)"DISPLAY"))
! 2194: send_will(TELOPT_XDISPLOC, 1);
! 2195: if (eight)
! 2196: tel_enter_binary(eight);
! 2197: }
! 2198: # endif /* !defined(TN3270) */
! 2199:
! 2200: # if !defined(TN3270)
! 2201: for (;;) {
! 2202: int schedValue;
! 2203:
! 2204: while ((schedValue = Scheduler(0)) != 0) {
! 2205: if (schedValue == -1) {
! 2206: setcommandmode();
! 2207: return;
! 2208: }
! 2209: }
! 2210:
! 2211: if (Scheduler(1) == -1) {
! 2212: setcommandmode();
! 2213: return;
! 2214: }
! 2215: }
! 2216: # else /* !defined(TN3270) */
! 2217: for (;;) {
! 2218: int schedValue;
! 2219:
! 2220: while (!In3270 && !shell_active) {
! 2221: if (Scheduler(1) == -1) {
! 2222: setcommandmode();
! 2223: return;
! 2224: }
! 2225: }
! 2226:
! 2227: while ((schedValue = Scheduler(0)) != 0) {
! 2228: if (schedValue == -1) {
! 2229: setcommandmode();
! 2230: return;
! 2231: }
! 2232: }
! 2233: /* If there is data waiting to go out to terminal, don't
! 2234: * schedule any more data for the terminal.
! 2235: */
! 2236: if (ring_full_count(&ttyoring)) {
! 2237: schedValue = 1;
! 2238: } else {
! 2239: if (shell_active) {
! 2240: if (shell_continue() == 0) {
! 2241: ConnectScreen();
! 2242: }
! 2243: } else if (In3270) {
! 2244: schedValue = DoTerminalOutput();
! 2245: }
! 2246: }
! 2247: if (schedValue && (shell_active == 0)) {
! 2248: if (Scheduler(1) == -1) {
! 2249: setcommandmode();
! 2250: return;
! 2251: }
! 2252: }
! 2253: }
! 2254: # endif /* !defined(TN3270) */
! 2255: }
! 2256:
! 2257: #if 0 /* XXX - this not being in is a bug */
! 2258: /*
! 2259: * nextitem()
! 2260: *
! 2261: * Return the address of the next "item" in the TELNET data
! 2262: * stream. This will be the address of the next character if
! 2263: * the current address is a user data character, or it will
! 2264: * be the address of the character following the TELNET command
! 2265: * if the current address is a TELNET IAC ("I Am a Command")
! 2266: * character.
! 2267: */
! 2268:
! 2269: static char *
! 2270: nextitem(current)
! 2271: char *current;
! 2272: {
! 2273: if ((*current&0xff) != IAC) {
! 2274: return current+1;
! 2275: }
! 2276: switch (*(current+1)&0xff) {
! 2277: case DO:
! 2278: case DONT:
! 2279: case WILL:
! 2280: case WONT:
! 2281: return current+3;
! 2282: case SB: /* loop forever looking for the SE */
! 2283: {
! 2284: register char *look = current+2;
! 2285:
! 2286: for (;;) {
! 2287: if ((*look++&0xff) == IAC) {
! 2288: if ((*look++&0xff) == SE) {
! 2289: return look;
! 2290: }
! 2291: }
! 2292: }
! 2293: }
! 2294: default:
! 2295: return current+2;
! 2296: }
! 2297: }
! 2298: #endif /* 0 */
! 2299:
! 2300: /*
! 2301: * netclear()
! 2302: *
! 2303: * We are about to do a TELNET SYNCH operation. Clear
! 2304: * the path to the network.
! 2305: *
! 2306: * Things are a bit tricky since we may have sent the first
! 2307: * byte or so of a previous TELNET command into the network.
! 2308: * So, we have to scan the network buffer from the beginning
! 2309: * until we are up to where we want to be.
! 2310: *
! 2311: * A side effect of what we do, just to keep things
! 2312: * simple, is to clear the urgent data pointer. The principal
! 2313: * caller should be setting the urgent data pointer AFTER calling
! 2314: * us in any case.
! 2315: */
! 2316:
! 2317: static void
! 2318: netclear()
! 2319: {
! 2320: #if 0 /* XXX */
! 2321: register char *thisitem, *next;
! 2322: char *good;
! 2323: #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
! 2324: ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
! 2325:
! 2326: thisitem = netobuf;
! 2327:
! 2328: while ((next = nextitem(thisitem)) <= netobuf.send) {
! 2329: thisitem = next;
! 2330: }
! 2331:
! 2332: /* Now, thisitem is first before/at boundary. */
! 2333:
! 2334: good = netobuf; /* where the good bytes go */
! 2335:
! 2336: while (netoring.add > thisitem) {
! 2337: if (wewant(thisitem)) {
! 2338: int length;
! 2339:
! 2340: next = thisitem;
! 2341: do {
! 2342: next = nextitem(next);
! 2343: } while (wewant(next) && (nfrontp > next));
! 2344: length = next-thisitem;
! 2345: memcpy(good, thisitem, length);
! 2346: good += length;
! 2347: thisitem = next;
! 2348: } else {
! 2349: thisitem = nextitem(thisitem);
! 2350: }
! 2351: }
! 2352:
! 2353: #endif /* 0 */
! 2354: }
! 2355:
! 2356: /*
! 2357: * These routines add various telnet commands to the data stream.
! 2358: */
! 2359:
! 2360: static void
! 2361: doflush()
! 2362: {
! 2363: NET2ADD(IAC, DO);
! 2364: NETADD(TELOPT_TM);
! 2365: flushline = 1;
! 2366: flushout = 1;
! 2367: (void) ttyflush(1); /* Flush/drop output */
! 2368: /* do printoption AFTER flush, otherwise the output gets tossed... */
! 2369: printoption("SENT", DO, TELOPT_TM);
! 2370: }
! 2371:
! 2372: void
! 2373: xmitAO()
! 2374: {
! 2375: NET2ADD(IAC, AO);
! 2376: printoption("SENT", IAC, AO);
! 2377: if (autoflush) {
! 2378: doflush();
! 2379: }
! 2380: }
! 2381:
! 2382:
! 2383: void
! 2384: xmitEL()
! 2385: {
! 2386: NET2ADD(IAC, EL);
! 2387: printoption("SENT", IAC, EL);
! 2388: }
! 2389:
! 2390: void
! 2391: xmitEC()
! 2392: {
! 2393: NET2ADD(IAC, EC);
! 2394: printoption("SENT", IAC, EC);
! 2395: }
! 2396:
! 2397:
! 2398: int
! 2399: dosynch()
! 2400: {
! 2401: netclear(); /* clear the path to the network */
! 2402: NETADD(IAC);
! 2403: setneturg();
! 2404: NETADD(DM);
! 2405: printoption("SENT", IAC, DM);
! 2406: return 1;
! 2407: }
! 2408:
! 2409: int want_status_response = 0;
! 2410:
! 2411: int
! 2412: get_status()
! 2413: {
! 2414: unsigned char tmp[16];
! 2415: register unsigned char *cp;
! 2416:
! 2417: if (my_want_state_is_dont(TELOPT_STATUS)) {
! 2418: printf("Remote side does not support STATUS option\n");
! 2419: return 0;
! 2420: }
! 2421: cp = tmp;
! 2422:
! 2423: *cp++ = IAC;
! 2424: *cp++ = SB;
! 2425: *cp++ = TELOPT_STATUS;
! 2426: *cp++ = TELQUAL_SEND;
! 2427: *cp++ = IAC;
! 2428: *cp++ = SE;
! 2429: if (NETROOM() >= cp - tmp) {
! 2430: ring_supply_data(&netoring, tmp, cp-tmp);
! 2431: printsub('>', tmp+2, cp - tmp - 2);
! 2432: }
! 2433: ++want_status_response;
! 2434: return 1;
! 2435: }
! 2436:
! 2437: void
! 2438: intp()
! 2439: {
! 2440: NET2ADD(IAC, IP);
! 2441: printoption("SENT", IAC, IP);
! 2442: flushline = 1;
! 2443: if (autoflush) {
! 2444: doflush();
! 2445: }
! 2446: if (autosynch) {
! 2447: dosynch();
! 2448: }
! 2449: }
! 2450:
! 2451: void
! 2452: sendbrk()
! 2453: {
! 2454: NET2ADD(IAC, BREAK);
! 2455: printoption("SENT", IAC, BREAK);
! 2456: flushline = 1;
! 2457: if (autoflush) {
! 2458: doflush();
! 2459: }
! 2460: if (autosynch) {
! 2461: dosynch();
! 2462: }
! 2463: }
! 2464:
! 2465: void
! 2466: sendabort()
! 2467: {
! 2468: NET2ADD(IAC, ABORT);
! 2469: printoption("SENT", IAC, ABORT);
! 2470: flushline = 1;
! 2471: if (autoflush) {
! 2472: doflush();
! 2473: }
! 2474: if (autosynch) {
! 2475: dosynch();
! 2476: }
! 2477: }
! 2478:
! 2479: void
! 2480: sendsusp()
! 2481: {
! 2482: NET2ADD(IAC, SUSP);
! 2483: printoption("SENT", IAC, SUSP);
! 2484: flushline = 1;
! 2485: if (autoflush) {
! 2486: doflush();
! 2487: }
! 2488: if (autosynch) {
! 2489: dosynch();
! 2490: }
! 2491: }
! 2492:
! 2493: void
! 2494: sendeof()
! 2495: {
! 2496: NET2ADD(IAC, xEOF);
! 2497: printoption("SENT", IAC, xEOF);
! 2498: }
! 2499:
! 2500: void
! 2501: sendayt()
! 2502: {
! 2503: NET2ADD(IAC, AYT);
! 2504: printoption("SENT", IAC, AYT);
! 2505: }
! 2506:
! 2507: /*
! 2508: * Send a window size update to the remote system.
! 2509: */
! 2510:
! 2511: void
! 2512: sendnaws()
! 2513: {
! 2514: long rows, cols;
! 2515: unsigned char tmp[16];
! 2516: register unsigned char *cp;
! 2517:
! 2518: if (my_state_is_wont(TELOPT_NAWS))
! 2519: return;
! 2520:
! 2521: #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
! 2522: if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
! 2523:
! 2524: if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
! 2525: return;
! 2526: }
! 2527:
! 2528: cp = tmp;
! 2529:
! 2530: *cp++ = IAC;
! 2531: *cp++ = SB;
! 2532: *cp++ = TELOPT_NAWS;
! 2533: PUTSHORT(cp, cols);
! 2534: PUTSHORT(cp, rows);
! 2535: *cp++ = IAC;
! 2536: *cp++ = SE;
! 2537: if (NETROOM() >= cp - tmp) {
! 2538: ring_supply_data(&netoring, tmp, cp-tmp);
! 2539: printsub('>', tmp+2, cp - tmp - 2);
! 2540: }
! 2541: }
! 2542:
! 2543: void
! 2544: tel_enter_binary(rw)
! 2545: int rw;
! 2546: {
! 2547: if (rw&1)
! 2548: send_do(TELOPT_BINARY, 1);
! 2549: if (rw&2)
! 2550: send_will(TELOPT_BINARY, 1);
! 2551: }
! 2552:
! 2553: void
! 2554: tel_leave_binary(rw)
! 2555: int rw;
! 2556: {
! 2557: if (rw&1)
! 2558: send_dont(TELOPT_BINARY, 1);
! 2559: if (rw&2)
! 2560: send_wont(TELOPT_BINARY, 1);
! 2561: }