[BACK]Return to telnet.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / telnet

Annotation of src/usr.bin/telnet/telnet.c, Revision 1.36

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