Annotation of 43BSDTahoe/ucb/telnet/Source/telnet.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1988 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted
                      6:  * provided that this notice is preserved and that due credit is given
                      7:  * to the University of California at Berkeley. The name of the University
                      8:  * may not be used to endorse or promote products derived from this
                      9:  * software without specific prior written permission. This software
                     10:  * is provided ``as is'' without express or implied warranty.
                     11:  */
                     12: 
                     13: #ifndef lint
                     14: static char sccsid[] = "@(#)telnet.c   5.31 (Berkeley) 5/15/88";
                     15: #endif /* not lint */
                     16: 
                     17: #include <sys/types.h>
                     18: 
                     19: #if    defined(unix)
                     20: #include <signal.h>
                     21: /* By the way, we need to include curses.h before telnet.h since,
                     22:  * among other things, telnet.h #defines 'DO', which is a variable
                     23:  * declared in curses.h.
                     24:  */
                     25: #include <curses.h>
                     26: #endif /* defined(unix) */
                     27: 
                     28: #include <arpa/telnet.h>
                     29: 
                     30: #if    defined(unix)
                     31: #include <strings.h>
                     32: #else  /* defined(unix) */
                     33: #include <string.h>
                     34: #endif /* defined(unix) */
                     35: 
                     36: #include "ring.h"
                     37: 
                     38: #include "defines.h"
                     39: #include "externs.h"
                     40: #include "types.h"
                     41: #include "general.h"
                     42: 
                     43: 
                     44: #define        strip(x)        ((x)&0x7f)
                     45: 
                     46: 
                     47: static char    subbuffer[SUBBUFSIZE],
                     48:                *subpointer, *subend;    /* buffer for sub-options */
                     49: #define        SB_CLEAR()      subpointer = subbuffer;
                     50: #define        SB_TERM()       subend = subpointer;
                     51: #define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
                     52:                                *subpointer++ = (c); \
                     53:                        }
                     54: 
                     55: char   hisopts[256];
                     56: char   myopts[256];
                     57: 
                     58: char   doopt[] = { IAC, DO, '%', 'c', 0 };
                     59: char   dont[] = { IAC, DONT, '%', 'c', 0 };
                     60: char   will[] = { IAC, WILL, '%', 'c', 0 };
                     61: char   wont[] = { IAC, WONT, '%', 'c', 0 };
                     62: 
                     63: int
                     64:        connected,
                     65:        showoptions,
                     66:        In3270,         /* Are we in 3270 mode? */
                     67:        ISend,          /* trying to send network data in */
                     68:        debug = 0,
                     69:        crmod,
                     70:        netdata,        /* Print out network data flow */
                     71:        crlf,           /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
                     72:        noasynch = 0,   /* User specified "-noasynch" on command line */
                     73:        askedSGA = 0,   /* We have talked about suppress go ahead */
                     74:        telnetport,
                     75:        SYNCHing,       /* we are in TELNET SYNCH mode */
                     76:        flushout,       /* flush output */
                     77:        autoflush = 0,  /* flush output when interrupting? */
                     78:        autosynch,      /* send interrupt characters with SYNCH? */
                     79:        localchars,     /* we recognize interrupt/quit */
                     80:        donelclchars,   /* the user has set "localchars" */
                     81:        donebinarytoggle,       /* the user has put us in binary */
                     82:        dontlecho,      /* do we suppress local echoing right now? */
                     83:        globalmode;
                     84: 
                     85: #define        CONTROL(x)      ((x)&0x1f)              /* CTRL(x) is not portable */
                     86: 
                     87: char
                     88:        *prompt = 0,
                     89:        escape,
                     90:        echoc;
                     91: 
                     92: /*
                     93:  * Telnet receiver states for fsm
                     94:  */
                     95: #define        TS_DATA         0
                     96: #define        TS_IAC          1
                     97: #define        TS_WILL         2
                     98: #define        TS_WONT         3
                     99: #define        TS_DO           4
                    100: #define        TS_DONT         5
                    101: #define        TS_CR           6
                    102: #define        TS_SB           7               /* sub-option collection */
                    103: #define        TS_SE           8               /* looking for sub-option end */
                    104: 
                    105: static int     telrcv_state;
                    106: 
                    107: jmp_buf        toplevel = { 0 };
                    108: jmp_buf        peerdied;
                    109: 
                    110: int    flushline;
                    111: 
                    112: /*
                    113:  * The following are some clocks used to decide how to interpret
                    114:  * the relationship between various variables.
                    115:  */
                    116: 
                    117: Clocks clocks;
                    118: 
                    119: Modelist modelist[] = {
                    120:        { "telnet command mode", COMMAND_LINE },
                    121:        { "character-at-a-time mode", 0 },
                    122:        { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
                    123:        { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
                    124:        { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
                    125:        { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
                    126:        { "3270 mode", 0 },
                    127: };
                    128: 
                    129: 
                    130: /*
                    131:  * Initialize telnet environment.
                    132:  */
                    133: 
                    134: init_telnet()
                    135: {
                    136:     SB_CLEAR();
                    137:     ClearArray(hisopts);
                    138:     ClearArray(myopts);
                    139: 
                    140:     connected = In3270 = ISend = donebinarytoggle = 0;
                    141: 
                    142: #if    defined(unix) && defined(TN3270)
                    143:     HaveInput = 0;
                    144: #endif /* defined(unix) && defined(TN3270) */
                    145: 
                    146:     SYNCHing = 0;
                    147: 
                    148:     /* Don't change NetTrace */
                    149: 
                    150:     escape = CONTROL(']');
                    151:     echoc = CONTROL('E');
                    152: 
                    153:     flushline = 1;
                    154:     telrcv_state = TS_DATA;
                    155: }
                    156: 
                    157: 
                    158: #include <varargs.h>
                    159: 
                    160: static void
                    161: printring(va_alist)
                    162: va_dcl
                    163: {
                    164:     va_list ap;
                    165:     char buffer[100];          /* where things go */
                    166:     char *ptr;
                    167:     char *format;
                    168:     char *string;
                    169:     Ring *ring;
                    170:     int i;
                    171: 
                    172:     va_start(ap);
                    173: 
                    174:     ring = va_arg(ap, Ring *);
                    175:     format = va_arg(ap, char *);
                    176:     ptr = buffer;
                    177: 
                    178:     while ((i = *format++) != 0) {
                    179:        if (i == '%') {
                    180:            i = *format++;
                    181:            switch (i) {
                    182:            case 'c':
                    183:                *ptr++ = va_arg(ap, int);
                    184:                break;
                    185:            case 's':
                    186:                string = va_arg(ap, char *);
                    187:                ring_supply_data(ring, buffer, ptr-buffer);
                    188:                ring_supply_data(ring, string, strlen(string));
                    189:                ptr = buffer;
                    190:                break;
                    191:            case 0:
                    192:                ExitString("printring: trailing %%.\n", 1);
                    193:                /*NOTREACHED*/
                    194:            default:
                    195:                ExitString("printring: unknown format character.\n", 1);
                    196:                /*NOTREACHED*/
                    197:            }
                    198:        } else {
                    199:            *ptr++ = i;
                    200:        }
                    201:     }
                    202:     ring_supply_data(ring, buffer, ptr-buffer);
                    203: }
                    204: 
                    205: 
                    206: void
                    207: willoption(option, reply)
                    208:        int option, reply;
                    209: {
                    210:        char *fmt;
                    211: 
                    212:        switch (option) {
                    213: 
                    214:        case TELOPT_ECHO:
                    215: #      if defined(TN3270)
                    216:            /*
                    217:             * The following is a pain in the rear-end.
                    218:             * Various IBM servers (some versions of Wiscnet,
                    219:             * possibly Fibronics/Spartacus, and who knows who
                    220:             * else) will NOT allow us to send "DO SGA" too early
                    221:             * in the setup proceedings.  On the other hand,
                    222:             * 4.2 servers (telnetd) won't set SGA correctly.
                    223:             * So, we are stuck.  Empirically (but, based on
                    224:             * a VERY small sample), the IBM servers don't send
                    225:             * out anything about ECHO, so we postpone our sending
                    226:             * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
                    227:             * DO send).
                    228:             */
                    229:            {
                    230:                if (askedSGA == 0) {
                    231:                    askedSGA = 1;
                    232:                    if (!hisopts[TELOPT_SGA]) {
                    233:                        willoption(TELOPT_SGA, 0);
                    234:                    }
                    235:                }
                    236:            }
                    237:                /* Fall through */
                    238:        case TELOPT_EOR:
                    239:        case TELOPT_BINARY:
                    240: #endif /* defined(TN3270) */
                    241:        case TELOPT_SGA:
                    242:                settimer(modenegotiated);
                    243:                hisopts[option] = 1;
                    244:                fmt = doopt;
                    245:                setconnmode();          /* possibly set new tty mode */
                    246:                break;
                    247: 
                    248:        case TELOPT_TM:
                    249:                return;                 /* Never reply to TM will's/wont's */
                    250: 
                    251:        default:
                    252:                fmt = dont;
                    253:                break;
                    254:        }
                    255:        printring(&netoring, fmt, option);
                    256:        if (reply)
                    257:                printoption(">SENT", fmt, option, reply);
                    258:        else
                    259:                printoption("<SENT", fmt, option, reply);
                    260: }
                    261: 
                    262: void
                    263: wontoption(option, reply)
                    264:        int option, reply;
                    265: {
                    266:        char *fmt;
                    267: 
                    268:        switch (option) {
                    269: 
                    270:        case TELOPT_ECHO:
                    271:        case TELOPT_SGA:
                    272:                settimer(modenegotiated);
                    273:                hisopts[option] = 0;
                    274:                fmt = dont;
                    275:                setconnmode();                  /* Set new tty mode */
                    276:                break;
                    277: 
                    278:        case TELOPT_TM:
                    279:                return;         /* Never reply to TM will's/wont's */
                    280: 
                    281:        default:
                    282:                fmt = dont;
                    283:        }
                    284:        printring(&netoring, fmt, option);
                    285:        if (reply)
                    286:                printoption(">SENT", fmt, option, reply);
                    287:        else
                    288:                printoption("<SENT", fmt, option, reply);
                    289: }
                    290: 
                    291: static void
                    292: dooption(option)
                    293:        int option;
                    294: {
                    295:        char *fmt;
                    296: 
                    297:        switch (option) {
                    298: 
                    299:        case TELOPT_TM:
                    300:                fmt = will;
                    301:                break;
                    302: 
                    303: #      if defined(TN3270)
                    304:        case TELOPT_EOR:
                    305:        case TELOPT_BINARY:
                    306: #      endif   /* defined(TN3270) */
                    307:        case TELOPT_TTYPE:              /* terminal type option */
                    308:        case TELOPT_SGA:                /* no big deal */
                    309:                fmt = will;
                    310:                myopts[option] = 1;
                    311:                break;
                    312: 
                    313:        case TELOPT_ECHO:               /* We're never going to echo... */
                    314:        default:
                    315:                fmt = wont;
                    316:                break;
                    317:        }
                    318:        printring(&netoring, fmt, option);
                    319:        printoption(">SENT", fmt, option, 0);
                    320: }
                    321: 
                    322: /*
                    323:  * suboption()
                    324:  *
                    325:  *     Look at the sub-option buffer, and try to be helpful to the other
                    326:  * side.
                    327:  *
                    328:  *     Currently we recognize:
                    329:  *
                    330:  *             Terminal type, send request.
                    331:  */
                    332: 
                    333: static void
                    334: suboption()
                    335: {
                    336:     printsub("<", subbuffer, subend-subbuffer+1);
                    337:     switch (subbuffer[0]&0xff) {
                    338:     case TELOPT_TTYPE:
                    339:        if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
                    340:            ;
                    341:        } else {
                    342:            char *name;
                    343:            char namebuf[41];
                    344:            extern char *getenv();
                    345:            int len;
                    346: 
                    347: #if    defined(TN3270)
                    348:            if (tn3270_ttype()) {
                    349:                return;
                    350:            }
                    351: #endif /* defined(TN3270) */
                    352:            name = getenv("TERM");
                    353:            if ((name == 0) || ((len = strlen(name)) > 40)) {
                    354:                name = "UNKNOWN";
                    355:                len = strlen(name);
                    356:            }
                    357:            if ((len + 4+2) < NETROOM()) {
                    358:                strcpy(namebuf, name);
                    359:                upcase(namebuf);
                    360:                printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
                    361:                                    TELQUAL_IS, namebuf, IAC, SE);
                    362:                /* XXX */
                    363:                /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */
                    364:            } else {
                    365:                ExitString("No room in buffer for terminal type.\n",
                    366:                                                        1);
                    367:                /*NOTREACHED*/
                    368:            }
                    369:        }
                    370: 
                    371:     default:
                    372:        break;
                    373:     }
                    374: }
                    375: 
                    376: 
                    377: int
                    378: telrcv()
                    379: {
                    380:     register int c;
                    381:     register int scc;
                    382:     register char *sbp;
                    383:     int count;
                    384:     int returnValue = 0;
                    385: 
                    386:     scc = 0;
                    387:     count = 0;
                    388:     while (TTYROOM() > 2) {
                    389:        if (scc == 0) {
                    390:            if (count) {
                    391:                ring_consumed(&netiring, count);
                    392:                returnValue = 1;
                    393:                count = 0;
                    394:            }
                    395:            sbp = netiring.consume;
                    396:            scc = ring_full_consecutive(&netiring);
                    397:            if (scc == 0) {
                    398:                /* No more data coming in */
                    399:                break;
                    400:            }
                    401:        }
                    402: 
                    403:        c = *sbp++ & 0xff, scc--; count++;
                    404: 
                    405:        switch (telrcv_state) {
                    406: 
                    407:        case TS_CR:
                    408:            telrcv_state = TS_DATA;
                    409:            if (c == '\0') {
                    410:                break;  /* Ignore \0 after CR */
                    411:            } else if (c == '\n') {
                    412:                if ((!hisopts[TELOPT_ECHO]) && !crmod) {
                    413:                    TTYADD(c);
                    414:                }
                    415:                break;
                    416:            }
                    417:            /* Else, fall through */
                    418: 
                    419:        case TS_DATA:
                    420:            if (c == IAC) {
                    421:                telrcv_state = TS_IAC;
                    422:                break;
                    423:            }
                    424: #          if defined(TN3270)
                    425:            if (In3270) {
                    426:                *Ifrontp++ = c;
                    427:                while (scc > 0) {
                    428:                    c = *sbp++ & 0377, scc--; count++;
                    429:                    if (c == IAC) {
                    430:                        telrcv_state = TS_IAC;
                    431:                        break;
                    432:                    }
                    433:                    *Ifrontp++ = c;
                    434:                }
                    435:            } else
                    436: #          endif /* defined(TN3270) */
                    437:                    /*
                    438:                     * The 'crmod' hack (see following) is needed
                    439:                     * since we can't * set CRMOD on output only.
                    440:                     * Machines like MULTICS like to send \r without
                    441:                     * \n; since we must turn off CRMOD to get proper
                    442:                     * input, the mapping is done here (sigh).
                    443:                     */
                    444:            if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
                    445:                if (scc > 0) {
                    446:                    c = *sbp&0xff;
                    447:                    if (c == 0) {
                    448:                        sbp++, scc--; count++;
                    449:                        /* a "true" CR */
                    450:                        TTYADD('\r');
                    451:                    } else if (!hisopts[TELOPT_ECHO] &&
                    452:                                        (c == '\n')) {
                    453:                        sbp++, scc--; count++;
                    454:                        TTYADD('\n');
                    455:                    } else {
                    456:                        TTYADD('\r');
                    457:                        if (crmod) {
                    458:                                TTYADD('\n');
                    459:                        }
                    460:                    }
                    461:                } else {
                    462:                    telrcv_state = TS_CR;
                    463:                    TTYADD('\r');
                    464:                    if (crmod) {
                    465:                            TTYADD('\n');
                    466:                    }
                    467:                }
                    468:            } else {
                    469:                TTYADD(c);
                    470:            }
                    471:            continue;
                    472: 
                    473:        case TS_IAC:
                    474:            switch (c) {
                    475:            
                    476:            case WILL:
                    477:                telrcv_state = TS_WILL;
                    478:                continue;
                    479: 
                    480:            case WONT:
                    481:                telrcv_state = TS_WONT;
                    482:                continue;
                    483: 
                    484:            case DO:
                    485:                telrcv_state = TS_DO;
                    486:                continue;
                    487: 
                    488:            case DONT:
                    489:                telrcv_state = TS_DONT;
                    490:                continue;
                    491: 
                    492:            case DM:
                    493:                    /*
                    494:                     * We may have missed an urgent notification,
                    495:                     * so make sure we flush whatever is in the
                    496:                     * buffer currently.
                    497:                     */
                    498:                SYNCHing = 1;
                    499:                ttyflush(1);
                    500:                SYNCHing = stilloob();
                    501:                settimer(gotDM);
                    502:                break;
                    503: 
                    504:            case NOP:
                    505:            case GA:
                    506:                break;
                    507: 
                    508:            case SB:
                    509:                SB_CLEAR();
                    510:                telrcv_state = TS_SB;
                    511:                continue;
                    512: 
                    513: #          if defined(TN3270)
                    514:            case EOR:
                    515:                if (In3270) {
                    516:                    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
                    517:                    if (Ibackp == Ifrontp) {
                    518:                        Ibackp = Ifrontp = Ibuf;
                    519:                        ISend = 0;      /* should have been! */
                    520:                    } else {
                    521:                        ISend = 1;
                    522:                    }
                    523:                }
                    524:                break;
                    525: #          endif /* defined(TN3270) */
                    526: 
                    527:            case IAC:
                    528: #          if !defined(TN3270)
                    529:                TTYADD(IAC);
                    530: #          else /* !defined(TN3270) */
                    531:                if (In3270) {
                    532:                    *Ifrontp++ = IAC;
                    533:                } else {
                    534:                    TTYADD(IAC);
                    535:                }
                    536: #          endif /* !defined(TN3270) */
                    537:                break;
                    538: 
                    539:            default:
                    540:                break;
                    541:            }
                    542:            telrcv_state = TS_DATA;
                    543:            continue;
                    544: 
                    545:        case TS_WILL:
                    546:            printoption(">RCVD", will, c, !hisopts[c]);
                    547:            if (c == TELOPT_TM) {
                    548:                if (flushout) {
                    549:                    flushout = 0;
                    550:                }
                    551:            } else if (!hisopts[c]) {
                    552:                willoption(c, 1);
                    553:            }
                    554:            SetIn3270();
                    555:            telrcv_state = TS_DATA;
                    556:            continue;
                    557: 
                    558:        case TS_WONT:
                    559:            printoption(">RCVD", wont, c, hisopts[c]);
                    560:            if (c == TELOPT_TM) {
                    561:                if (flushout) {
                    562:                    flushout = 0;
                    563:                }
                    564:            } else if (hisopts[c]) {
                    565:                wontoption(c, 1);
                    566:            }
                    567:            SetIn3270();
                    568:            telrcv_state = TS_DATA;
                    569:            continue;
                    570: 
                    571:        case TS_DO:
                    572:            printoption(">RCVD", doopt, c, !myopts[c]);
                    573:            if (!myopts[c])
                    574:                dooption(c);
                    575:            SetIn3270();
                    576:            telrcv_state = TS_DATA;
                    577:            continue;
                    578: 
                    579:        case TS_DONT:
                    580:            printoption(">RCVD", dont, c, myopts[c]);
                    581:            if (myopts[c]) {
                    582:                myopts[c] = 0;
                    583:                printring(&netoring, wont, c);
                    584:                flushline = 1;
                    585:                setconnmode();  /* set new tty mode (maybe) */
                    586:                printoption(">SENT", wont, c, 0);
                    587:            }
                    588:            SetIn3270();
                    589:            telrcv_state = TS_DATA;
                    590:            continue;
                    591: 
                    592:        case TS_SB:
                    593:            if (c == IAC) {
                    594:                telrcv_state = TS_SE;
                    595:            } else {
                    596:                SB_ACCUM(c);
                    597:            }
                    598:            continue;
                    599: 
                    600:        case TS_SE:
                    601:            if (c != SE) {
                    602:                if (c != IAC) {
                    603:                    SB_ACCUM(IAC);
                    604:                }
                    605:                SB_ACCUM(c);
                    606:                telrcv_state = TS_SB;
                    607:            } else {
                    608:                SB_TERM();
                    609:                suboption();    /* handle sub-option */
                    610:                SetIn3270();
                    611:                telrcv_state = TS_DATA;
                    612:            }
                    613:        }
                    614:     }
                    615:     if (count)
                    616:        ring_consumed(&netiring, count);
                    617:     return returnValue||count;
                    618: }
                    619: 
                    620: static int
                    621: telsnd()
                    622: {
                    623:     int tcc;
                    624:     int count;
                    625:     int returnValue = 0;
                    626:     char *tbp;
                    627: 
                    628:     tcc = 0;
                    629:     count = 0;
                    630:     while (NETROOM() > 2) {
                    631:        register int sc;
                    632:        register int c;
                    633: 
                    634:        if (tcc == 0) {
                    635:            if (count) {
                    636:                ring_consumed(&ttyiring, count);
                    637:                returnValue = 1;
                    638:                count = 0;
                    639:            }
                    640:            tbp = ttyiring.consume;
                    641:            tcc = ring_full_consecutive(&ttyiring);
                    642:            if (tcc == 0) {
                    643:                break;
                    644:            }
                    645:        }
                    646:        c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
                    647:        if (sc == escape) {
                    648:            command(0);
                    649:            tcc = 0;
                    650:            flushline = 1;
                    651:            break;
                    652:        } else if (MODE_LINE(globalmode) && (sc == echoc)) {
                    653:            if (tcc > 0 && strip(*tbp) == echoc) {
                    654:                tcc--; tbp++; count++;
                    655:            } else {
                    656:                dontlecho = !dontlecho;
                    657:                settimer(echotoggle);
                    658:                setconnmode();
                    659:                flushline = 1;
                    660:                break;
                    661:            }
                    662:        }
                    663:        if (localchars) {
                    664:            if (TerminalSpecialChars(sc) == 0) {
                    665:                break;
                    666:            }
                    667:        }
                    668:        if (!myopts[TELOPT_BINARY]) {
                    669:            switch (c) {
                    670:            case '\n':
                    671:                    /*
                    672:                     * If we are in CRMOD mode (\r ==> \n)
                    673:                     * on our local machine, then probably
                    674:                     * a newline (unix) is CRLF (TELNET).
                    675:                     */
                    676:                if (MODE_LOCAL_CHARS(globalmode)) {
                    677:                    NETADD('\r');
                    678:                }
                    679:                NETADD('\n');
                    680:                flushline = 1;
                    681:                break;
                    682:            case '\r':
                    683:                if (!crlf) {
                    684:                    NET2ADD('\r', '\0');
                    685:                } else {
                    686:                    NET2ADD('\r', '\n');
                    687:                }
                    688:                flushline = 1;
                    689:                break;
                    690:            case IAC:
                    691:                NET2ADD(IAC, IAC);
                    692:                break;
                    693:            default:
                    694:                NETADD(c);
                    695:                break;
                    696:            }
                    697:        } else if (c == IAC) {
                    698:            NET2ADD(IAC, IAC);
                    699:        } else {
                    700:            NETADD(c);
                    701:        }
                    702:     }
                    703:     if (count)
                    704:        ring_consumed(&ttyiring, count);
                    705:     return returnValue||count;         /* Non-zero if we did anything */
                    706: }
                    707: 
                    708: /*
                    709:  * Scheduler()
                    710:  *
                    711:  * Try to do something.
                    712:  *
                    713:  * If we do something useful, return 1; else return 0.
                    714:  *
                    715:  */
                    716: 
                    717: 
                    718: int
                    719: Scheduler(block)
                    720: int    block;                  /* should we block in the select ? */
                    721: {
                    722:     register int c;
                    723:                /* One wants to be a bit careful about setting returnValue
                    724:                 * to one, since a one implies we did some useful work,
                    725:                 * and therefore probably won't be called to block next
                    726:                 * time (TN3270 mode only).
                    727:                 */
                    728:     int returnValue;
                    729:     int netin, netout, netex, ttyin, ttyout;
                    730: 
                    731:     /* Decide which rings should be processed */
                    732: 
                    733:     netout = ring_full_count(&netoring) &&
                    734:            (!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]);
                    735:     ttyout = ring_full_count(&ttyoring);
                    736: 
                    737: #if    defined(TN3270)
                    738:     ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
                    739: #else  /* defined(TN3270) */
                    740:     ttyin = ring_empty_count(&ttyiring);
                    741: #endif /* defined(TN3270) */
                    742: 
                    743: #if    defined(TN3270)
                    744:     netin = ring_empty_count(&netiring);
                    745: #   else /* !defined(TN3270) */
                    746:     netin = !ISend && ring_empty_count(&netiring);
                    747: #   endif /* !defined(TN3270) */
                    748: 
                    749:     netex = !SYNCHing;
                    750: 
                    751:     /* If we have seen a signal recently, reset things */
                    752: #   if defined(TN3270) && defined(unix)
                    753:     if (HaveInput) {
                    754:        HaveInput = 0;
                    755:        signal(SIGIO, inputAvailable);
                    756:     }
                    757: #endif /* defined(TN3270) && defined(unix) */
                    758: 
                    759:     /* Call to system code to process rings */
                    760: 
                    761:     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
                    762: 
                    763:     /* Now, look at the input rings, looking for work to do. */
                    764: 
                    765:     if (ring_full_count(&ttyiring)) {
                    766: #   if defined(TN3270)
                    767:        if (In3270) {
                    768:            c = DataFromTerminal(ttyiring.consume,
                    769:                                        ring_full_consecutive(&ttyiring));
                    770:            if (c) {
                    771:                returnValue = 1;
                    772:                ring_consumed(&ttyiring, c);
                    773:            }
                    774:        } else {
                    775: #   endif /* defined(TN3270) */
                    776:            returnValue |= telsnd();
                    777: #   if defined(TN3270)
                    778:        }
                    779: #   endif /* defined(TN3270) */
                    780:     }
                    781: 
                    782:     if (ring_full_count(&netiring)) {
                    783: #      if !defined(TN3270)
                    784:        returnValue |= telrcv();
                    785: #      else /* !defined(TN3270) */
                    786:        returnValue = Push3270();
                    787: #      endif /* !defined(TN3270) */
                    788:     }
                    789:     return returnValue;
                    790: }
                    791: 
                    792: /*
                    793:  * Select from tty and network...
                    794:  */
                    795: void
                    796: telnet()
                    797: {
                    798:     sys_telnet_init();
                    799: 
                    800: #   if !defined(TN3270)
                    801:     if (telnetport) {
                    802:        if (!hisopts[TELOPT_SGA]) {
                    803:            willoption(TELOPT_SGA, 0);
                    804:        }
                    805:        if (!myopts[TELOPT_TTYPE]) {
                    806:            dooption(TELOPT_TTYPE, 0);
                    807:        }
                    808:     }
                    809: #   endif /* !defined(TN3270) */
                    810: 
                    811: #   if !defined(TN3270)
                    812:     for (;;) {
                    813:        int schedValue;
                    814: 
                    815:        while ((schedValue = Scheduler(0)) != 0) {
                    816:            if (schedValue == -1) {
                    817:                setcommandmode();
                    818:                return;
                    819:            }
                    820:        }
                    821: 
                    822:        if (Scheduler(1) == -1) {
                    823:            setcommandmode();
                    824:            return;
                    825:        }
                    826:     }
                    827: #   else /* !defined(TN3270) */
                    828:     for (;;) {
                    829:        int schedValue;
                    830: 
                    831:        while (!In3270 && !shell_active) {
                    832:            if (Scheduler(1) == -1) {
                    833:                setcommandmode();
                    834:                return;
                    835:            }
                    836:        }
                    837: 
                    838:        while ((schedValue = Scheduler(0)) != 0) {
                    839:            if (schedValue == -1) {
                    840:                setcommandmode();
                    841:                return;
                    842:            }
                    843:        }
                    844:                /* If there is data waiting to go out to terminal, don't
                    845:                 * schedule any more data for the terminal.
                    846:                 */
                    847:        if (ring_full_count(&ttyoring)) {
                    848:            schedValue = 1;
                    849:        } else {
                    850:            if (shell_active) {
                    851:                if (shell_continue() == 0) {
                    852:                    ConnectScreen();
                    853:                }
                    854:            } else if (In3270) {
                    855:                schedValue = DoTerminalOutput();
                    856:            }
                    857:        }
                    858:        if (schedValue && (shell_active == 0)) {
                    859:            if (Scheduler(1) == -1) {
                    860:                setcommandmode();
                    861:                return;
                    862:            }
                    863:        }
                    864:     }
                    865: #   endif /* !defined(TN3270) */
                    866: }
                    867: 
                    868: /*
                    869:  * nextitem()
                    870:  *
                    871:  *     Return the address of the next "item" in the TELNET data
                    872:  * stream.  This will be the address of the next character if
                    873:  * the current address is a user data character, or it will
                    874:  * be the address of the character following the TELNET command
                    875:  * if the current address is a TELNET IAC ("I Am a Command")
                    876:  * character.
                    877:  */
                    878: 
                    879: static char *
                    880: nextitem(current)
                    881: char   *current;
                    882: {
                    883:     if ((*current&0xff) != IAC) {
                    884:        return current+1;
                    885:     }
                    886:     switch (*(current+1)&0xff) {
                    887:     case DO:
                    888:     case DONT:
                    889:     case WILL:
                    890:     case WONT:
                    891:        return current+3;
                    892:     case SB:           /* loop forever looking for the SE */
                    893:        {
                    894:            register char *look = current+2;
                    895: 
                    896:            for (;;) {
                    897:                if ((*look++&0xff) == IAC) {
                    898:                    if ((*look++&0xff) == SE) {
                    899:                        return look;
                    900:                    }
                    901:                }
                    902:            }
                    903:        }
                    904:     default:
                    905:        return current+2;
                    906:     }
                    907: }
                    908: 
                    909: /*
                    910:  * netclear()
                    911:  *
                    912:  *     We are about to do a TELNET SYNCH operation.  Clear
                    913:  * the path to the network.
                    914:  *
                    915:  *     Things are a bit tricky since we may have sent the first
                    916:  * byte or so of a previous TELNET command into the network.
                    917:  * So, we have to scan the network buffer from the beginning
                    918:  * until we are up to where we want to be.
                    919:  *
                    920:  *     A side effect of what we do, just to keep things
                    921:  * simple, is to clear the urgent data pointer.  The principal
                    922:  * caller should be setting the urgent data pointer AFTER calling
                    923:  * us in any case.
                    924:  */
                    925: 
                    926: static void
                    927: netclear()
                    928: {
                    929: #if    0       /* XXX */
                    930:     register char *thisitem, *next;
                    931:     char *good;
                    932: #define        wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \
                    933:                                ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
                    934: 
                    935:     thisitem = netobuf;
                    936: 
                    937:     while ((next = nextitem(thisitem)) <= netobuf.send) {
                    938:        thisitem = next;
                    939:     }
                    940: 
                    941:     /* Now, thisitem is first before/at boundary. */
                    942: 
                    943:     good = netobuf;    /* where the good bytes go */
                    944: 
                    945:     while (netoring.add > thisitem) {
                    946:        if (wewant(thisitem)) {
                    947:            int length;
                    948: 
                    949:            next = thisitem;
                    950:            do {
                    951:                next = nextitem(next);
                    952:            } while (wewant(next) && (nfrontp > next));
                    953:            length = next-thisitem;
                    954:            memcpy(good, thisitem, length);
                    955:            good += length;
                    956:            thisitem = next;
                    957:        } else {
                    958:            thisitem = nextitem(thisitem);
                    959:        }
                    960:     }
                    961: 
                    962: #endif /* 0 */
                    963: }
                    964: 
                    965: /*
                    966:  * These routines add various telnet commands to the data stream.
                    967:  */
                    968: 
                    969: static void
                    970: doflush()
                    971: {
                    972:     NET2ADD(IAC, DO);
                    973:     NETADD(TELOPT_TM);
                    974:     flushline = 1;
                    975:     flushout = 1;
                    976:     ttyflush(1);                       /* Flush/drop output */
                    977:     /* do printoption AFTER flush, otherwise the output gets tossed... */
                    978:     printoption("<SENT", doopt, TELOPT_TM, 0);
                    979: }
                    980: 
                    981: void
                    982: xmitAO()
                    983: {
                    984:     NET2ADD(IAC, AO);
                    985:     if (autoflush) {
                    986:        doflush();
                    987:     }
                    988: }
                    989: 
                    990: 
                    991: void
                    992: xmitEL()
                    993: {
                    994:     NET2ADD(IAC, EL);
                    995: }
                    996: 
                    997: void
                    998: xmitEC()
                    999: {
                   1000:     NET2ADD(IAC, EC);
                   1001: }
                   1002: 
                   1003: 
                   1004: #if    defined(NOT43)
                   1005: int
                   1006: #else  /* defined(NOT43) */
                   1007: void
                   1008: #endif /* defined(NOT43) */
                   1009: dosynch()
                   1010: {
                   1011:     netclear();                        /* clear the path to the network */
                   1012:     NETADD(IAC);
                   1013:     setneturg();
                   1014:     NETADD(DM);
                   1015: 
                   1016: #if    defined(NOT43)
                   1017:     return 0;
                   1018: #endif /* defined(NOT43) */
                   1019: }
                   1020: 
                   1021: void
                   1022: intp()
                   1023: {
                   1024:     NET2ADD(IAC, IP);
                   1025:     flushline = 1;
                   1026:     if (autoflush) {
                   1027:        doflush();
                   1028:     }
                   1029:     if (autosynch) {
                   1030:        dosynch();
                   1031:     }
                   1032: }
                   1033: 
                   1034: void
                   1035: sendbrk()
                   1036: {
                   1037:     NET2ADD(IAC, BREAK);
                   1038:     flushline = 1;
                   1039:     if (autoflush) {
                   1040:        doflush();
                   1041:     }
                   1042:     if (autosynch) {
                   1043:        dosynch();
                   1044:     }
                   1045: }

unix.superglobalmegacorp.com

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