Annotation of 43BSDReno/usr.bin/telnet/telnet.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.