Annotation of 43BSDTahoe/ucb/telnet/Source/telnet.c, revision 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.