Annotation of 43BSDTahoe/ucb/tn3270/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: char copyright[] =
                     15: "@(#) Copyright (c) 1988 Regents of the University of California.\n\
                     16:  All rights reserved.\n";
                     17: #endif /* not lint */
                     18: 
                     19: #ifndef lint
                     20: static char sccsid[] = "@(#)telnet.c   6.9 (Berkeley) 3/28/88";
                     21: #endif /* not lint */
                     22: 
                     23: /*
                     24:  * User telnet program, modified for use by tn3270.c.
                     25:  *
                     26:  * Many of the FUNCTIONAL changes in this newest version of TELNET
                     27:  * were suggested by Dave Borman of Cray Research, Inc.
                     28:  *
                     29:  * Other changes in the tn3270 side come from Alan Crosswell (Columbia),
                     30:  * Bob Braden (ISI), Steve Jacobson (Berkeley), and Cliff Frost (Berkeley).
                     31:  *
                     32:  * This code is common between telnet(1c) and tn3270(1c).  There are the
                     33:  * following defines used to generate the various versions:
                     34:  *
                     35:  *     TN3270          -       This is to be linked with tn3270.
                     36:  *
                     37:  *     NOT43           -       Allows the program to compile and run on
                     38:  *                             a 4.2BSD system.
                     39:  *
                     40:  *     PUTCHAR         -       Within tn3270, on a NOT43 system,
                     41:  *                             allows the use of the 4.3 curses
                     42:  *                             (greater speed updating the screen).
                     43:  *                             You need the 4.3 curses for this to work.
                     44:  *
                     45:  *     FD_SETSIZE      -       On whichever system, if this isn't defined,
                     46:  *                             we patch over the FD_SET, etc., macros with
                     47:  *                             some homebrewed ones.
                     48:  *
                     49:  *     SO_OOBINLINE    -       This is a socket option which we would like
                     50:  *                             to set to allow TCP urgent data to come
                     51:  *                             to us "inline".  This is NECESSARY for
                     52:  *                             CORRECT operation, and desireable for
                     53:  *                             simpler operation.
                     54:  *
                     55:  *     LNOFLSH         -       Detects the presence of the LNOFLSH bit
                     56:  *                             in the tty structure.
                     57:  *
                     58:  *     unix            -       Compiles in unix specific stuff.
                     59:  *
                     60:  *     MSDOS           -       Compiles in MSDOS specific stuff.
                     61:  *
                     62:  */
                     63: 
                     64: #if    !defined(TN3270)
                     65: #define        ExitString(f,s,r)       { fprintf(f, s); exit(r); }
                     66: #define        Exit(x)                 exit(x)
                     67: #define        SetIn3270()
                     68: 
                     69: void   setcommandmode(), command();    /* forward declarations */
                     70: #endif /* !defined(TN3270) */
                     71: 
                     72: #include <sys/types.h>
                     73: 
                     74: #if     defined(pyr)
                     75: #define fd_set fdset_t
                     76: #endif  /* defined(pyr) */
                     77:  
                     78: #include <sys/socket.h>
                     79: 
                     80: #include <netinet/in.h>
                     81: 
                     82: #if    defined(unix)
                     83: /* By the way, we need to include curses.h before telnet.h since,
                     84:  * among other things, telnet.h #defines 'DO', which is a variable
                     85:  * declared in curses.h.
                     86:  */
                     87: #include <curses.h>
                     88: #endif /* defined(unix) */
                     89: 
                     90: #define        TELOPTS
                     91: #include <arpa/telnet.h>
                     92: 
                     93: #if    !defined(NOT43)
                     94: #include <arpa/inet.h>
                     95: #else  /* !defined(NOT43) */
                     96: extern unsigned long inet_addr();
                     97: extern char    *inet_ntoa();
                     98: #endif /* !defined(NOT43) */
                     99: 
                    100: #include <stdio.h>
                    101: #include <ctype.h>
                    102: #include <errno.h>
                    103: #include <setjmp.h>
                    104: #include <netdb.h>
                    105: 
                    106: #if    defined(unix)
                    107: #include <strings.h>
                    108: #else  /* defined(unix) */
                    109: #include <string.h>
                    110: #endif /* defined(unix) */
                    111: 
                    112: #if    defined(TN3270)
                    113: #include "ascii/termin.ext"
                    114: #include "ctlr/screen.h"
                    115: #include "ctlr/oia.h"
                    116: #include "ctlr/options.ext"
                    117: #include "ctlr/outbound.ext"
                    118: #include "general/globals.h"
                    119: #include "telnet.ext"
                    120: #endif /* defined(TN3270) */
                    121: 
                    122: #include "general/general.h"
                    123: 
                    124: 
                    125: 
                    126: #ifndef        FD_SETSIZE
                    127: /*
                    128:  * The following is defined just in case someone should want to run
                    129:  * this telnet on a 4.2 system.
                    130:  *
                    131:  */
                    132: 
                    133: #define        FD_SET(n, p)    ((p)->fds_bits[0] |= (1<<(n)))
                    134: #define        FD_CLR(n, p)    ((p)->fds_bits[0] &= ~(1<<(n)))
                    135: #define        FD_ISSET(n, p)  ((p)->fds_bits[0] & (1<<(n)))
                    136: #define FD_ZERO(p)     ((p)->fds_bits[0] = 0)
                    137: 
                    138: #endif
                    139: 
                    140: #define        strip(x)        ((x)&0x7f)
                    141: #define min(x,y)       ((x<y)? x:y)
                    142: 
                    143: #if    defined(TN3270)
                    144: static char    Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
                    145: #endif /* defined(TN3270) */
                    146: 
                    147: static char    ttyobuf[2*BUFSIZ], *tfrontp, *tbackp;
                    148: #define        TTYADD(c)       { if (!(SYNCHing||flushout)) { *tfrontp++ = c; } }
                    149: #define        TTYLOC()        (tfrontp)
                    150: #define        TTYMAX()        (ttyobuf+sizeof ttyobuf-1)
                    151: #define        TTYMIN()        (netobuf)
                    152: #define        TTYBYTES()      (tfrontp-tbackp)
                    153: #define        TTYROOM()       (TTYMAX()-TTYLOC()+1)
                    154: 
                    155: static char    netobuf[2*BUFSIZ], *nfrontp, *nbackp;
                    156: #define        NETADD(c)       { *nfrontp++ = c; }
                    157: #define        NET2ADD(c1,c2)  { NETADD(c1); NETADD(c2); }
                    158: #define NETLOC()       (nfrontp)
                    159: #define        NETMAX()        (netobuf+sizeof netobuf-1)
                    160: #define        NETBYTES()      (nfrontp-nbackp)
                    161: #define        NETROOM()       (NETMAX()-NETLOC()+1)
                    162: static char    *neturg;                /* one past last byte of urgent data */
                    163: 
                    164: static char    subbuffer[100],
                    165:                *subpointer, *subend;    /* buffer for sub-options */
                    166: #define        SB_CLEAR()      subpointer = subbuffer;
                    167: #define        SB_TERM()       subend = subpointer;
                    168: #define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
                    169:                                *subpointer++ = (c); \
                    170:                        }
                    171: 
                    172: static char    sb_terminal[] = { IAC, SB,
                    173:                        TELOPT_TTYPE, TELQUAL_IS,
                    174:                        'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
                    175:                        IAC, SE };
                    176: #define        SBTERMMODEL     13
                    177: 
                    178: 
                    179: static char    hisopts[256];
                    180: static char    myopts[256];
                    181: 
                    182: static char    doopt[] = { IAC, DO, '%', 'c', 0 };
                    183: static char    dont[] = { IAC, DONT, '%', 'c', 0 };
                    184: static char    will[] = { IAC, WILL, '%', 'c', 0 };
                    185: static char    wont[] = { IAC, WONT, '%', 'c', 0 };
                    186: 
                    187: struct cmd {
                    188:        char    *name;          /* command name */
                    189:        char    *help;          /* help string */
                    190:        int     (*handler)();   /* routine which executes command */
                    191:        int     dohelp;         /* Should we give general help information? */
                    192:        int     needconnect;    /* Do we need to be connected to execute? */
                    193: };
                    194: 
                    195: static char    sibuf[BUFSIZ], *sbp;
                    196: static char    tibuf[BUFSIZ], *tbp;
                    197: static fd_set ibits, obits, xbits;
                    198: 
                    199: 
                    200: static int
                    201:        connected,
                    202:        net,
                    203:        scc,
                    204:        tcc,
                    205:        showoptions,
                    206:        In3270,         /* Are we in 3270 mode? */
                    207:        ISend,          /* trying to send network data in */
                    208:        debug = 0,
                    209:        crmod,
                    210:        netdata,        /* Print out network data flow */
                    211:        crlf,           /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
                    212:        noasynch = 0,   /* User specified "-noasynch" on command line */
                    213:        askedSGA = 0,   /* We have talked about suppress go ahead */
                    214:        telnetport = 1;
                    215: 
                    216: static FILE    *NetTrace = 0;          /* Not in bss, since needs to stay */
                    217: 
                    218: #define        CONTROL(x)      ((x)&0x1f)              /* CTRL(x) is not portable */
                    219: 
                    220: static char
                    221:        *prompt = 0,
                    222:        escape,
                    223:        echoc;
                    224: 
                    225: static int
                    226:        SYNCHing,               /* we are in TELNET SYNCH mode */
                    227:        flushout,               /* flush output */
                    228:        autoflush = 0,          /* flush output when interrupting? */
                    229:        autosynch,              /* send interrupt characters with SYNCH? */
                    230:        localchars,             /* we recognize interrupt/quit */
                    231:        donelclchars,           /* the user has set "localchars" */
                    232:        donebinarytoggle,       /* the user has put us in binary */
                    233:        dontlecho,              /* do we suppress local echoing right now? */
                    234:        globalmode;
                    235: 
                    236: /*     The following are some tn3270 specific flags */
                    237: #if    defined(TN3270)
                    238: 
                    239: static int
                    240:        Sent3270TerminalType;   /* Have we said we are a 3270? */
                    241: 
                    242: /* Some real, live, globals. */
                    243: int
                    244:        tout,                   /* Output file descriptor */
                    245:        tin;                    /* Input file descriptor */
                    246: 
                    247: #else  /* defined(TN3270) */
                    248: static int tin, tout;          /* file descriptors */
                    249: #endif /* defined(TN3270) */
                    250: 
                    251: 
                    252: /*
                    253:  * Telnet receiver states for fsm
                    254:  */
                    255: #define        TS_DATA         0
                    256: #define        TS_IAC          1
                    257: #define        TS_WILL         2
                    258: #define        TS_WONT         3
                    259: #define        TS_DO           4
                    260: #define        TS_DONT         5
                    261: #define        TS_CR           6
                    262: #define        TS_SB           7               /* sub-option collection */
                    263: #define        TS_SE           8               /* looking for sub-option end */
                    264: 
                    265: static int     telrcv_state = TS_DATA;
                    266: 
                    267: static char    line[200];
                    268: static int     margc;
                    269: static char    *margv[20];
                    270: 
                    271: static jmp_buf toplevel = { 0 };
                    272: static jmp_buf peerdied;
                    273: 
                    274: extern int errno;
                    275: 
                    276: 
                    277: static struct sockaddr_in sin;
                    278: 
                    279: static struct  servent *sp = 0;
                    280: 
                    281: static int     flushline;
                    282: 
                    283: static char    *hostname;
                    284: static char    hnamebuf[32];
                    285: 
                    286: /*
                    287:  * The following are some clocks used to decide how to interpret
                    288:  * the relationship between various variables.
                    289:  */
                    290: 
                    291: static struct {
                    292:     int
                    293:        system,                 /* what the current time is */
                    294:        echotoggle,             /* last time user entered echo character */
                    295:        modenegotiated,         /* last time operating mode negotiated */
                    296:        didnetreceive,          /* last time we read data from network */
                    297:        gotDM;                  /* when did we last see a data mark */
                    298: } clocks;
                    299: 
                    300: #define        settimer(x)     clocks.x = clocks.system++
                    301: 
                    302: /*     Various modes */
                    303: #define        MODE_LINE(m)    (modelist[m].modetype & LINE)
                    304: #define        MODE_LOCAL_CHARS(m)     (modelist[m].modetype &  LOCAL_CHARS)
                    305: #define        MODE_LOCAL_ECHO(m)      (modelist[m].modetype & LOCAL_ECHO)
                    306: #define        MODE_COMMAND_LINE(m)    (modelist[m].modetype & COMMAND_LINE)
                    307: 
                    308: #define        LOCAL_CHARS     0x01            /* Characters processed locally */
                    309: #define        LINE            0x02            /* Line-by-line mode of operation */
                    310: #define        LOCAL_ECHO      0x04            /* Echoing locally */
                    311: #define        COMMAND_LINE    0x08            /* Command line mode */
                    312: 
                    313: static struct {
                    314:     char *modedescriptions;
                    315:     char modetype;
                    316: } modelist[] = {
                    317:        { "telnet command mode", COMMAND_LINE },
                    318:        { "character-at-a-time mode", 0 },
                    319:        { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
                    320:        { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
                    321:        { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
                    322:        { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
                    323:        { "3270 mode", 0 },
                    324: };
                    325: 
                    326: 
                    327: /*
                    328:  * The following routines try to encapsulate what is system dependent
                    329:  * (at least between 4.x and dos) which is used in telnet.c.
                    330:  */
                    331: 
                    332: #if    defined(unix)
                    333: #include <sys/ioctl.h>
                    334: #include <sys/time.h>
                    335: #include <signal.h>
                    336: 
                    337: int
                    338:        HaveInput;              /* There is input available to scan */
                    339: 
                    340: #if    defined(TN3270)
                    341: static char    tline[200];
                    342: char   *transcom = 0;  /* transparent mode command (default: none) */
                    343: #endif /* defined(TN3270) */
                    344: 
                    345: static struct  tchars otc = { 0 }, ntc = { 0 };
                    346: static struct  ltchars oltc = { 0 }, nltc = { 0 };
                    347: static struct  sgttyb ottyb = { 0 }, nttyb = { 0 };
                    348: 
                    349: 
                    350: #define        TerminalWrite(fd,buf,n) write(fd,buf,n)
                    351: #define        TerminalRead(fd,buf,n)  read(fd,buf,n)
                    352: 
                    353: /*
                    354:  *
                    355:  */
                    356: 
                    357: static int
                    358: TerminalAutoFlush()                                    /* unix */
                    359: {
                    360: #if    defined(LNOFLSH)
                    361:     ioctl(0, TIOCLGET, (char *)&autoflush);
                    362:     return !(autoflush&LNOFLSH);       /* if LNOFLSH, no autoflush */
                    363: #else  /* LNOFLSH */
                    364:     return 1;
                    365: #endif /* LNOFLSH */
                    366: }
                    367: 
                    368: /*
                    369:  * TerminalSpecialChars()
                    370:  *
                    371:  * Look at an input character to see if it is a special character
                    372:  * and decide what to do.
                    373:  *
                    374:  * Output:
                    375:  *
                    376:  *     0       Don't add this character.
                    377:  *     1       Do add this character
                    378:  */
                    379: 
                    380: int
                    381: TerminalSpecialChars(c)                        /* unix */
                    382: int    c;
                    383: {
                    384:     void doflush(), intp(), sendbrk();
                    385: 
                    386:     if (c == ntc.t_intrc) {
                    387:        intp();
                    388:        return 0;
                    389:     } else if (c == ntc.t_quitc) {
                    390:        sendbrk();
                    391:        return 0;
                    392:     } else if (c == nltc.t_flushc) {
                    393:        NET2ADD(IAC, AO);
                    394:        if (autoflush) {
                    395:            doflush();
                    396:        }
                    397:        return 0;
                    398:     } else if (!MODE_LOCAL_CHARS(globalmode)) {
                    399:        if (c == nttyb.sg_kill) {
                    400:            NET2ADD(IAC, EL);
                    401:            return 0;
                    402:        } else if (c == nttyb.sg_erase) {
                    403:            NET2ADD(IAC, EC);
                    404:            return 0;
                    405:        }
                    406:     }
                    407:     return 1;
                    408: }
                    409: 
                    410: 
                    411: /*
                    412:  * Flush output to the terminal
                    413:  */
                    414:  
                    415: static void
                    416: TerminalFlushOutput()                          /* unix */
                    417: {
                    418:     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
                    419: }
                    420: 
                    421: static void
                    422: TerminalSaveState()                            /* unix */
                    423: {
                    424:     ioctl(0, TIOCGETP, (char *)&ottyb);
                    425:     ioctl(0, TIOCGETC, (char *)&otc);
                    426:     ioctl(0, TIOCGLTC, (char *)&oltc);
                    427: 
                    428:     ntc = otc;
                    429:     nltc = oltc;
                    430:     nttyb = ottyb;
                    431: }
                    432: 
                    433: static void
                    434: TerminalRestoreState()                         /* unix */
                    435: {
                    436: }
                    437: 
                    438: /*
                    439:  * TerminalNewMode - set up terminal to a specific mode.
                    440:  */
                    441: 
                    442: 
                    443: static void
                    444: TerminalNewMode(f)                                     /* unix */
                    445: register int f;
                    446: {
                    447:     static int prevmode = 0;
                    448:     struct tchars *tc;
                    449:     struct tchars tc3;
                    450:     struct ltchars *ltc;
                    451:     struct sgttyb sb;
                    452:     int onoff;
                    453:     int old;
                    454:     struct     tchars notc2;
                    455:     struct     ltchars noltc2;
                    456:     static struct      tchars notc =   { -1, -1, -1, -1, -1, -1 };
                    457:     static struct      ltchars noltc = { -1, -1, -1, -1, -1, -1 };
                    458: 
                    459:     globalmode = f;
                    460:     if (prevmode == f)
                    461:        return;
                    462:     old = prevmode;
                    463:     prevmode = f;
                    464:     sb = nttyb;
                    465: 
                    466:     switch (f) {
                    467: 
                    468:     case 0:
                    469:        onoff = 0;
                    470:        tc = &otc;
                    471:        ltc = &oltc;
                    472:        break;
                    473: 
                    474:     case 1:            /* remote character processing, remote echo */
                    475:     case 2:            /* remote character processing, local echo */
                    476:     case 6:            /* 3270 mode - like 1, but with xon/xoff local */
                    477:                    /* (might be nice to have "6" in telnet also...) */
                    478:            sb.sg_flags |= CBREAK;
                    479:            if ((f == 1) || (f == 6)) {
                    480:                sb.sg_flags &= ~(ECHO|CRMOD);
                    481:            } else {
                    482:                sb.sg_flags |= ECHO|CRMOD;
                    483:            }
                    484:            sb.sg_erase = sb.sg_kill = -1;
                    485:            if (f == 6) {
                    486:                tc = &tc3;
                    487:                tc3 = notc;
                    488:                    /* get XON, XOFF characters */
                    489:                tc3.t_startc = otc.t_startc;
                    490:                tc3.t_stopc = otc.t_stopc;
                    491:            } else {
                    492:                /*
                    493:                 * If user hasn't specified one way or the other,
                    494:                 * then default to not trapping signals.
                    495:                 */
                    496:                if (!donelclchars) {
                    497:                    localchars = 0;
                    498:                }
                    499:                if (localchars) {
                    500:                    notc2 = notc;
                    501:                    notc2.t_intrc = ntc.t_intrc;
                    502:                    notc2.t_quitc = ntc.t_quitc;
                    503:                    tc = &notc2;
                    504:                } else {
                    505:                    tc = &notc;
                    506:                }
                    507:            }
                    508:            ltc = &noltc;
                    509:            onoff = 1;
                    510:            break;
                    511:     case 3:            /* local character processing, remote echo */
                    512:     case 4:            /* local character processing, local echo */
                    513:     case 5:            /* local character processing, no echo */
                    514:            sb.sg_flags &= ~CBREAK;
                    515:            sb.sg_flags |= CRMOD;
                    516:            if (f == 4)
                    517:                sb.sg_flags |= ECHO;
                    518:            else
                    519:                sb.sg_flags &= ~ECHO;
                    520:            notc2 = ntc;
                    521:            tc = &notc2;
                    522:            noltc2 = oltc;
                    523:            ltc = &noltc2;
                    524:            /*
                    525:             * If user hasn't specified one way or the other,
                    526:             * then default to trapping signals.
                    527:             */
                    528:            if (!donelclchars) {
                    529:                localchars = 1;
                    530:            }
                    531:            if (localchars) {
                    532:                notc2.t_brkc = nltc.t_flushc;
                    533:                noltc2.t_flushc = -1;
                    534:            } else {
                    535:                notc2.t_intrc = notc2.t_quitc = -1;
                    536:            }
                    537:            noltc2.t_suspc = escape;
                    538:            noltc2.t_dsuspc = -1;
                    539:            onoff = 1;
                    540:            break;
                    541: 
                    542:     default:
                    543:            return;
                    544:     }
                    545:     ioctl(tin, TIOCSLTC, (char *)ltc);
                    546:     ioctl(tin, TIOCSETC, (char *)tc);
                    547:     ioctl(tin, TIOCSETP, (char *)&sb);
                    548: #if    (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
                    549:     ioctl(tin, FIONBIO, (char *)&onoff);
                    550:     ioctl(tout, FIONBIO, (char *)&onoff);
                    551: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
                    552: #if    defined(TN3270)
                    553:     if (noasynch == 0) {
                    554:        ioctl(tin, FIOASYNC, (char *)&onoff);
                    555:     }
                    556: #endif /* defined(TN3270) */
                    557: 
                    558:     if (MODE_LINE(f)) {
                    559:        void doescape();
                    560: 
                    561:        signal(SIGTSTP, doescape);
                    562:     } else if (MODE_LINE(old)) {
                    563:        signal(SIGTSTP, SIG_DFL);
                    564:        sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
                    565:     }
                    566: }
                    567: 
                    568: 
                    569: int
                    570: NetClose(net)
                    571: int    net;
                    572: {
                    573:     return close(net);
                    574: }
                    575: 
                    576: 
                    577: static void
                    578: NetNonblockingIO(fd, onoff)                            /* unix */
                    579: int
                    580:        fd,
                    581:        onoff;
                    582: {
                    583:     ioctl(net, FIONBIO, (char *)&onoff);
                    584: }
                    585: 
                    586: static void
                    587: NetSigIO(fd, onoff)                            /* unix */
                    588: int
                    589:        fd,
                    590:        onoff;
                    591: {
                    592:     ioctl(net, FIOASYNC, (char *)&onoff);      /* hear about input */
                    593: }
                    594: 
                    595: static void
                    596: NetSetPgrp(fd)                         /* unix */
                    597: int fd;
                    598: {
                    599:     int myPid;
                    600: 
                    601:     myPid = getpid();
                    602: #if    defined(NOT43)
                    603:     myPid = -myPid;
                    604: #endif /* defined(NOT43) */
                    605:     ioctl(net, SIOCSPGRP, (char *)&myPid);     /* set my pid */
                    606: }
                    607: 
                    608: 
                    609: #endif /* defined(unix) */
                    610: 
                    611: #if    defined(MSDOS)
                    612: #include <time.h>
                    613: #include <signal.h>
                    614: #include <process.h>
                    615: #include <fcntl.h>
                    616: #include <io.h>
                    617: #include <dos.h>
                    618: 
                    619: #if    !defined(SO_OOBINLINE)
                    620: #define        SO_OOBINLINE
                    621: #endif /* !defined(SO_OOBINLINE) */
                    622: 
                    623: 
                    624: static char
                    625:     termEofChar,
                    626:     termEraseChar,
                    627:     termFlushChar,
                    628:     termIntChar,
                    629:     termKillChar,
                    630:     termLiteralNextChar,
                    631:     termQuitChar;
                    632: 
                    633: static char
                    634:     savedInState, savedOutState;
                    635: 
                    636: /*
                    637:  * MSDOS doesn't have anyway of deciding whether a full-edited line
                    638:  * is ready to be read in, so we need to do character-by-character
                    639:  * reads, and then do the editing in the program (in the case where
                    640:  * we are supporting line-by-line mode).
                    641:  *
                    642:  * The following routines, which are internal to the MSDOS-specific
                    643:  * code, accomplish this miracle.
                    644:  */
                    645: 
                    646: #define Hex(c) HEX[(c)&0xff]
                    647: 
                    648: static survivorSetup = 0;              /* Do we have ^C hooks in? */
                    649: 
                    650: static int
                    651:        lineend = 0,            /* There is a line terminator */
                    652:        ctrlCCount = 0;
                    653: 
                    654: static char    linein[200],            /* Where input line is assembled */
                    655:                *nextin = linein,       /* Next input character */
                    656:                *nextout = linein;      /* Next character to be consumed */
                    657: 
                    658: #define consumechar() \
                    659:     if ((++nextout) >= nextin) { \
                    660:        nextout = nextin = linein; \
                    661:        lineend = 0; \
                    662:     }
                    663: 
                    664: #define        characteratatime()      (!MODE_LINE(globalmode))        /* one by one */
                    665: 
                    666: 
                    667: /*
                    668:  * killone()
                    669:  *
                    670:  *  Erase the last character on the line.
                    671:  */
                    672: 
                    673: static void
                    674: killone()
                    675: {
                    676:     if (lineend) {
                    677:        return;                 /* ??? XXX */
                    678:     }
                    679:     if (nextin == linein) {
                    680:        return;                 /* Nothing to do */
                    681:     }
                    682:     nextin--;
                    683:     if (!(isspace(*nextin) || isprint(*nextin))) {
                    684:        putchar('\b');
                    685:        putchar(' ');
                    686:        putchar('\b');
                    687:     }
                    688:     putchar('\b');
                    689:     putchar(' ');
                    690:     putchar('\b');
                    691: }
                    692: 
                    693: 
                    694: /*
                    695:  * setlineend()
                    696:  *
                    697:  *  Decide if it's time to send the current line up to the user
                    698:  * process.
                    699:  */
                    700: 
                    701: static void
                    702: setlineend()
                    703: {
                    704:     if (nextin == nextout) {
                    705:        return;
                    706:     }
                    707:     if (characteratatime()) {
                    708:        lineend = 1;
                    709:     } else if (nextin >= (linein+sizeof linein)) {
                    710:        lineend = 1;
                    711:     } else {
                    712:        int c = *(nextin-1);
                    713:        if ((c == termIntChar)
                    714:                || (c == termQuitChar)
                    715:                || (c == termEofChar)) {
                    716:            lineend = 1;
                    717:        } else if (c == termFlushChar) {
                    718:            lineend = 1;
                    719:        } else if ((c == '\n') || (c == '\r')) {
                    720:            lineend = 1;
                    721:        }
                    722:     }
                    723:     /* Otherwise, leave it alone (reset by 'consumechar') */
                    724: }
                    725: 
                    726: /*
                    727:  * OK, what we do here is:
                    728:  *
                    729:  *   o  If we are echoing, then
                    730:  *     o  Look for character erase, line kill characters
                    731:  *     o  Echo the character (using '^' if a control character)
                    732:  *   o  Put the character in the input buffer
                    733:  *   o  Set 'lineend' as necessary
                    734:  */
                    735: 
                    736: static void
                    737: DoNextChar(c)
                    738: int    c;                      /* Character to process */
                    739: {
                    740:     static char literalnextcharacter = 0;
                    741: 
                    742:     if (nextin >= (linein+sizeof linein)) {
                    743:        putchar('\7');          /* Ring bell */
                    744:        setlineend();
                    745:        return;
                    746:     }
                    747:     if (MODE_LOCAL_CHARS(globalmode)) {
                    748:        /* Look for some special character */
                    749:        if (!literalnextcharacter) {
                    750:            if (c == termEraseChar) {
                    751:                killone();
                    752:                setlineend();
                    753:                return;
                    754:            } else if (c == termKillChar) {
                    755:                while (nextin != linein) {
                    756:                    killone();
                    757:                }
                    758:                setlineend();
                    759:                return;
                    760:            } else if (c == termLiteralNextChar) {
                    761:                literalnextcharacter = 1;
                    762:                return;
                    763:            }
                    764:        }
                    765: 
                    766:        if (MODE_LOCAL_ECHO(globalmode)) {
                    767:            if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) {
                    768:                putchar('\r');
                    769:                putchar('\n');
                    770:                c = '\n';
                    771:            } else if (!isprint(c) && !isspace(c)) {
                    772:                putchar('^');
                    773:                putchar(c^0x40);
                    774:            } else {
                    775:                putchar(c);
                    776:            }
                    777:        }
                    778:        literalnextcharacter = 0;
                    779:     }
                    780:     *nextin++ = c;
                    781:     setlineend();
                    782: }
                    783: 
                    784: static int
                    785: inputExists()
                    786: {
                    787:     int input;
                    788:     static state = 0;
                    789: 
                    790:     while (ctrlCCount) {
                    791:        DoNextChar(0x03);
                    792:        ctrlCCount--;
                    793:     }
                    794:     if (lineend) {
                    795:        return 1;
                    796:     }
                    797: #if    1       /* For BIOS variety of calls */
                    798:     if (kbhit() == 0) {
                    799:        return lineend;
                    800:     }
                    801:     input = getch();                   /* MSC - get console character */
                    802:     if ((input&0xff) == 0) {
                    803:        DoNextChar(0x01);               /* ^A */
                    804:     } else {
                    805:        DoNextChar(input&0xff);
                    806:     }
                    807: #else  /* 0 */
                    808:     if ((input = dirconio()) == -1) {
                    809:        return lineend;
                    810:     }
                    811:     if ((input&0xff) == 0) {
                    812:        if ((input&0xff00) == 0x0300) {         /* Null */
                    813:            DoNextChar(0);
                    814:        } else {
                    815:            DoNextChar(0x01);
                    816:            if (input&0x8000) {
                    817:                DoNextChar(0x01);
                    818:                DoNextChar((input>>8)&0x7f);
                    819:            } else {
                    820:                DoNextChar((input>>8)&0xff);
                    821:            }
                    822:        }
                    823:     } else {
                    824:        DoNextChar(input&0xff);
                    825:     }
                    826: #endif /* 0 */
                    827:     return lineend;
                    828: }
                    829: 
                    830: 
                    831: void
                    832: CtrlCInterrupt()
                    833: {
                    834:     if (!MODE_COMMAND_LINE(globalmode)) {
                    835:        char far *Bios_Break = (char far *) (((long)0x40<<16)|0x71);
                    836: 
                    837:        *Bios_Break = 0;
                    838:        ctrlCCount++;           /* XXX */
                    839:        signal(SIGINT, CtrlCInterrupt);
                    840:     } else {
                    841:        closeallsockets();
                    842:        exit(1);
                    843:     }
                    844: }
                    845: 
                    846: int
                    847: dosbinary(fd, onoff)
                    848: int    fd;
                    849: int    onoff;
                    850: {
                    851:     union REGS regs;
                    852:     int oldstate;
                    853: 
                    854:     /* Get old stuff */
                    855:     regs.h.ah = 0x44;
                    856:     regs.h.al = 0;
                    857:     regs.x.bx = fd;
                    858:     intdos(&regs, &regs);
                    859:     oldstate = regs.h.dl&(1<<5);               /* Save state */
                    860: 
                    861:     /* Set correct bits in new mode */
                    862:     regs.h.dh = 0;
                    863:     if (onoff) {
                    864:        regs.h.dl |= 1<<5;
                    865:     } else {
                    866:        regs.h.dl &= ~(1<<5);
                    867:     }
                    868: 
                    869:     /* Set in new mode */
                    870:     regs.h.ah = 0x44;
                    871:     regs.h.al = 1;
                    872:     regs.x.bx = fd;
                    873:     intdos(&regs, &regs);
                    874: 
                    875:     return oldstate;
                    876: }
                    877: 
                    878: /*
                    879:  * The MSDOS routines, called from elsewhere.
                    880:  */
                    881: 
                    882: 
                    883: static int
                    884: TerminalAutoFlush()                            /* MSDOS */
                    885: {
                    886:     return 1;
                    887: }
                    888: 
                    889: static int
                    890: TerminalCanRead()
                    891: {
                    892:     return inputExists();
                    893: }
                    894: 
                    895: 
                    896: /*
                    897:  * Flush output to the terminal
                    898:  */
                    899:  
                    900: static void
                    901: TerminalFlushOutput()                          /* MSDOS */
                    902: {
                    903: }
                    904: 
                    905: 
                    906: static void
                    907: TerminalNewMode(f)                             /* MSDOS */
                    908: register int f;
                    909: {
                    910:     union REGS inregs;
                    911:     struct SREGS segregs;
                    912:     static old_1b_offset = 0, old_1b_segment = 0;
                    913: 
                    914:     globalmode = f;
                    915:     if (MODE_COMMAND_LINE(f)) {
                    916:        signal(SIGINT, SIG_DFL);
                    917:        if (old_1b_segment|old_1b_offset) {
                    918:            inregs.h.ah = 0x25;
                    919:            inregs.h.al = 0x1b;
                    920:            inregs.x.dx = old_1b_offset;
                    921:            segregs.ds = old_1b_segment;
                    922:            intdosx(&inregs, &inregs, &segregs);
                    923:            old_1b_segment = old_1b_offset = 0;
                    924:        }
                    925:        if (setmode(fileno(stdout), O_TEXT) == -1) {
                    926:            ExitPerror("setmode (text)", 1);
                    927:        }
                    928:        (void) dosbinary(fileno(stdout), 0);
                    929:        if (setmode(fileno(stdin), O_TEXT) == -1) {
                    930:            ExitPerror("setmode (text)", 1);
                    931:        }
                    932:        (void) dosbinary(fileno(stdin), 0);
                    933:     } else {
                    934:        signal(SIGINT, CtrlCInterrupt);
                    935:        if ((old_1b_segment|old_1b_offset) == 0) {
                    936:            extern void iret_subr();
                    937:            void (far *foo_subr)() = iret_subr;
                    938: 
                    939:            inregs.h.ah = 0x35;
                    940:            inregs.h.al = 0x1b;
                    941:            intdosx(&inregs, &inregs, &segregs);
                    942:            old_1b_segment = segregs.es;
                    943:            old_1b_offset = inregs.x.bx;
                    944:            inregs.h.ah = 0x25;
                    945:            inregs.h.al = 0x1b;
                    946:            inregs.x.dx = FP_OFF(foo_subr);
                    947:            segregs.ds = FP_SEG(foo_subr);
                    948:            intdosx(&inregs, &inregs, &segregs);
                    949:        }
                    950:        if (MODE_LOCAL_CHARS(f)) {
                    951:            if (setmode(fileno(stdout), O_TEXT) == -1) {
                    952:                ExitPerror("setmode (text)", 1);
                    953:            }
                    954:            (void) dosbinary(fileno(stdout), 0);
                    955:            if (setmode(fileno(stdin), O_TEXT) == -1) {
                    956:                ExitPerror("setmode (text)", 1);
                    957:            }
                    958:            (void) dosbinary(fileno(stdin), 0);
                    959:        } else {
                    960:            if (setmode(fileno(stdout), O_BINARY) == -1) {
                    961:                ExitPerror("setmode (binary)", 1);
                    962:            }
                    963:            (void) dosbinary(fileno(stdout), 1);
                    964:            if (setmode(fileno(stdin), O_BINARY) == -1) {
                    965:                ExitPerror("setmode (binary)", 1);
                    966:            }
                    967:            (void) dosbinary(fileno(stdin), 1);
                    968:        }
                    969:     }
                    970: }
                    971: 
                    972: 
                    973: int
                    974: TerminalRead(fd, buffer, count)
                    975: int    fd;
                    976: char   *buffer;
                    977: int    count;
                    978: {
                    979:     int done = 0;
                    980: 
                    981:     for (;;) {
                    982:        while (inputExists() && (done < count)) {
                    983:            *buffer++ = *nextout;
                    984:            consumechar();
                    985:            done++;
                    986:        }
                    987:        if (done) {
                    988:            return(done);
                    989:        } else {
                    990:            return 0;
                    991:        }
                    992:     }
                    993: }
                    994: 
                    995: 
                    996: static void
                    997: TerminalSaveState()                            /* MSDOS */
                    998: {
                    999:     savedInState = dosbinary(fileno(stdin), 0);
                   1000:     savedOutState = dosbinary(fileno(stdout), 0);
                   1001: }
                   1002: 
                   1003: int
                   1004: TerminalSpecialChars(c)                        /* MSDOS */
                   1005: {
                   1006:     return 1;
                   1007: }
                   1008: 
                   1009: 
                   1010: static void
                   1011: TerminalRestoreState()                         /* MSDOS */
                   1012: {
                   1013:     (void) dosbinary(fileno(stdin), savedInState);
                   1014:     (void) dosbinary(fileno(stdout), savedOutState);
                   1015: }
                   1016: 
                   1017: 
                   1018: static int
                   1019: TerminalWrite(fd, buffer, count)               /* MSDOS */
                   1020: int    fd;
                   1021: char   *buffer;
                   1022: int    count;
                   1023: {
                   1024:     return fwrite(buffer, sizeof (char), count, stdout);
                   1025: }
                   1026: 
                   1027: 
                   1028: static int
                   1029: NetClose(fd)
                   1030: {
                   1031:     return closesocket(fd);
                   1032: }
                   1033: 
                   1034: static void
                   1035: NetNonblockingIO(fd, onoff)                            /* MSDOS */
                   1036: int
                   1037:        fd,
                   1038:        onoff;
                   1039: {
                   1040:     if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) {
                   1041:        perror("setsockop (SO_NONBLOCKING) ");
                   1042:        ExitString(stderr, "exiting\n", 1);
                   1043:     }
                   1044: }
                   1045: 
                   1046: static void
                   1047: NetSigIO(fd)                           /* MSDOS */
                   1048: int fd;
                   1049: {
                   1050: }
                   1051: 
                   1052: static void
                   1053: NetSetPgrp(fd)                         /* MSDOS */
                   1054: int fd;
                   1055: {
                   1056: }
                   1057: 
                   1058: 
                   1059: #endif /* defined(MSDOS) */
                   1060: 
                   1061: /*
                   1062:  * Initialize variables.
                   1063:  */
                   1064: 
                   1065: static void
                   1066: tninit()
                   1067: {
                   1068: #if    defined(TN3270)
                   1069:     Sent3270TerminalType = 0;
                   1070:     Ifrontp = Ibackp = Ibuf;
                   1071: #endif /* defined(TN3270) */
                   1072: 
                   1073:     tfrontp = tbackp = ttyobuf;
                   1074:     nfrontp = nbackp = netobuf;
                   1075:     
                   1076:     /* Don't change telnetport */
                   1077:     SB_CLEAR();
                   1078:     ClearArray(hisopts);
                   1079:     ClearArray(myopts);
                   1080:     sbp = sibuf;
                   1081:     tbp = tibuf;
                   1082: 
                   1083:     connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0;
                   1084:     telnetport = 0;
                   1085: #if    defined(unix)
                   1086:     HaveInput = 0;
                   1087: #endif /* defined(unix) */
                   1088: 
                   1089:     SYNCHing = 0;
                   1090: 
                   1091:     errno = 0;
                   1092: 
                   1093:     flushline = 0;
                   1094: 
                   1095:     /* Don't change NetTrace */
                   1096: 
                   1097:     escape = CONTROL(']');
                   1098:     echoc = CONTROL('E');
                   1099: 
                   1100:     flushline = 1;
                   1101:     sp = getservbyname("telnet", "tcp");
                   1102:     if (sp == 0) {
                   1103:        ExitString(stderr, "telnet: tcp/telnet: unknown service\n",1);
                   1104:        /*NOTREACHED*/
                   1105:     }
                   1106: 
                   1107: #if    defined(TN3270)
                   1108:     init_ctlr();               /* Initialize some things */
                   1109:     init_keyboard();
                   1110:     init_screen();
                   1111:     init_system();
                   1112: #endif /* defined(TN3270) */
                   1113: }
                   1114: 
                   1115: /*
                   1116:  * Various utility routines.
                   1117:  */
                   1118: 
                   1119: static void
                   1120: makeargv()
                   1121: {
                   1122:     register char *cp;
                   1123:     register char **argp = margv;
                   1124: 
                   1125:     margc = 0;
                   1126:     cp = line;
                   1127:     if (*cp == '!') {          /* Special case shell escape */
                   1128:        *argp++ = "!";          /* No room in string to get this */
                   1129:        margc++;
                   1130:        cp++;
                   1131:     }
                   1132:     while (*cp) {
                   1133:        while (isspace(*cp))
                   1134:            cp++;
                   1135:        if (*cp == '\0')
                   1136:            break;
                   1137:        *argp++ = cp;
                   1138:        margc += 1;
                   1139:        while (*cp != '\0' && !isspace(*cp))
                   1140:            cp++;
                   1141:        if (*cp == '\0')
                   1142:            break;
                   1143:        *cp++ = '\0';
                   1144:     }
                   1145:     *argp++ = 0;
                   1146: }
                   1147: 
                   1148: static char *ambiguous;                /* special return value */
                   1149: #define Ambiguous(t)   ((t)&ambiguous)
                   1150: 
                   1151: 
                   1152: static char **
                   1153: genget(name, table, next)
                   1154: char   *name;          /* name to match */
                   1155: char   **table;                /* name entry in table */
                   1156: char   **(*next)();    /* routine to return next entry in table */
                   1157: {
                   1158:        register char *p, *q;
                   1159:        register char **c, **found;
                   1160:        register int nmatches, longest;
                   1161: 
                   1162:        if (name == 0) {
                   1163:            return 0;
                   1164:        }
                   1165:        longest = 0;
                   1166:        nmatches = 0;
                   1167:        found = 0;
                   1168:        for (c = table; (p = *c) != 0; c = (*next)(c)) {
                   1169:                for (q = name;
                   1170:                    (*q == *p) || (isupper(*q) && tolower(*q) == *p); p++, q++)
                   1171:                        if (*q == 0)            /* exact match? */
                   1172:                                return (c);
                   1173:                if (!*q) {                      /* the name was a prefix */
                   1174:                        if (q - name > longest) {
                   1175:                                longest = q - name;
                   1176:                                nmatches = 1;
                   1177:                                found = c;
                   1178:                        } else if (q - name == longest)
                   1179:                                nmatches++;
                   1180:                }
                   1181:        }
                   1182:        if (nmatches > 1)
                   1183:                return Ambiguous(char **);
                   1184:        return (found);
                   1185: }
                   1186: 
                   1187: /*
                   1188:  * Make a character string into a number.
                   1189:  *
                   1190:  * Todo:  1.  Could take random integers (12, 0x12, 012, 0b1).
                   1191:  */
                   1192: 
                   1193: static
                   1194: special(s)
                   1195: register char *s;
                   1196: {
                   1197:        register char c;
                   1198:        char b;
                   1199: 
                   1200:        switch (*s) {
                   1201:        case '^':
                   1202:                b = *++s;
                   1203:                if (b == '?') {
                   1204:                    c = b | 0x40;               /* DEL */
                   1205:                } else {
                   1206:                    c = b & 0x1f;
                   1207:                }
                   1208:                break;
                   1209:        default:
                   1210:                c = *s;
                   1211:                break;
                   1212:        }
                   1213:        return c;
                   1214: }
                   1215: 
                   1216: /*
                   1217:  * Construct a control character sequence
                   1218:  * for a special character.
                   1219:  */
                   1220: static char *
                   1221: control(c)
                   1222:        register int c;
                   1223: {
                   1224:        static char buf[3];
                   1225: 
                   1226:        if (c == 0x7f)
                   1227:                return ("^?");
                   1228:        if (c == '\377') {
                   1229:                return "off";
                   1230:        }
                   1231:        if (c >= 0x20) {
                   1232:                buf[0] = c;
                   1233:                buf[1] = 0;
                   1234:        } else {
                   1235:                buf[0] = '^';
                   1236:                buf[1] = '@'+c;
                   1237:                buf[2] = 0;
                   1238:        }
                   1239:        return (buf);
                   1240: }
                   1241: 
                   1242: 
                   1243: /*
                   1244:  * upcase()
                   1245:  *
                   1246:  *     Upcase (in place) the argument.
                   1247:  */
                   1248: 
                   1249: static void
                   1250: upcase(argument)
                   1251: register char *argument;
                   1252: {
                   1253:     register int c;
                   1254: 
                   1255:     while ((c = *argument) != 0) {
                   1256:        if (islower(c)) {
                   1257:            *argument = toupper(c);
                   1258:        }
                   1259:        argument++;
                   1260:     }
                   1261: }
                   1262: 
                   1263: /*
                   1264:  * SetSockOpt()
                   1265:  *
                   1266:  * Compensate for differences in 4.2 and 4.3 systems.
                   1267:  */
                   1268: 
                   1269: static int
                   1270: SetSockOpt(fd, level, option, yesno)
                   1271: int
                   1272:        fd,
                   1273:        level,
                   1274:        option,
                   1275:        yesno;
                   1276: {
                   1277: #ifndef        NOT43
                   1278:     return setsockopt(fd, level, option,
                   1279:                                (char *)&yesno, sizeof yesno);
                   1280: #else  /* NOT43 */
                   1281:     if (yesno == 0) {          /* Can't do that in 4.2! */
                   1282:        fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
                   1283:                                option);
                   1284:        return -1;
                   1285:     }
                   1286:     return setsockopt(fd, level, option, 0, 0);
                   1287: #endif /* NOT43 */
                   1288: }
                   1289: 
                   1290: /*
                   1291:  * The following are routines used to print out debugging information.
                   1292:  */
                   1293: 
                   1294: 
                   1295: static void
                   1296: Dump(direction, buffer, length)
                   1297: char   direction;
                   1298: char   *buffer;
                   1299: int    length;
                   1300: {
                   1301: #   define BYTES_PER_LINE      32
                   1302: #   define min(x,y)    ((x<y)? x:y)
                   1303:     char *pThis;
                   1304:     int offset;
                   1305: 
                   1306:     offset = 0;
                   1307: 
                   1308:     while (length) {
                   1309:        /* print one line */
                   1310:        fprintf(NetTrace, "%c 0x%x\t", direction, offset);
                   1311:        pThis = buffer;
                   1312:        buffer = buffer+min(length, BYTES_PER_LINE);
                   1313:        while (pThis < buffer) {
                   1314:            fprintf(NetTrace, "%.2x", (*pThis)&0xff);
                   1315:            pThis++;
                   1316:        }
                   1317:        fprintf(NetTrace, "\n");
                   1318:        length -= BYTES_PER_LINE;
                   1319:        offset += BYTES_PER_LINE;
                   1320:        if (length < 0) {
                   1321:            return;
                   1322:        }
                   1323:        /* find next unique line */
                   1324:     }
                   1325: }
                   1326: 
                   1327: 
                   1328: /*VARARGS*/
                   1329: static void
                   1330: printoption(direction, fmt, option, what)
                   1331:        char *direction, *fmt;
                   1332:        int option, what;
                   1333: {
                   1334:        if (!showoptions)
                   1335:                return;
                   1336:        fprintf(NetTrace, "%s ", direction+1);
                   1337:        if (fmt == doopt)
                   1338:                fmt = "do";
                   1339:        else if (fmt == dont)
                   1340:                fmt = "dont";
                   1341:        else if (fmt == will)
                   1342:                fmt = "will";
                   1343:        else if (fmt == wont)
                   1344:                fmt = "wont";
                   1345:        else
                   1346:                fmt = "???";
                   1347:        if (option < (sizeof telopts/sizeof telopts[0]))
                   1348:                fprintf(NetTrace, "%s %s", fmt, telopts[option]);
                   1349:        else
                   1350:                fprintf(NetTrace, "%s %d", fmt, option);
                   1351:        if (*direction == '<') {
                   1352:                fprintf(NetTrace, "\r\n");
                   1353:                return;
                   1354:        }
                   1355:        fprintf(NetTrace, " (%s)\r\n", what ? "reply" : "don't reply");
                   1356: }
                   1357: 
                   1358: static void
                   1359: printsub(direction, pointer, length)
                   1360: char   *direction,             /* "<" or ">" */
                   1361:        *pointer;               /* where suboption data sits */
                   1362: int    length;                 /* length of suboption data */
                   1363: {
                   1364:     if (showoptions) {
                   1365:        fprintf(NetTrace, "%s suboption ",
                   1366:                                (direction[0] == '<')? "Received":"Sent");
                   1367:        switch (pointer[0]) {
                   1368:        case TELOPT_TTYPE:
                   1369:            fprintf(NetTrace, "Terminal type ");
                   1370:            switch (pointer[1]) {
                   1371:            case TELQUAL_IS:
                   1372:                {
                   1373:                    char tmpbuf[sizeof subbuffer];
                   1374:                    int minlen = min(length-4, sizeof tmpbuf-1);
                   1375: 
                   1376:                    memcpy(tmpbuf, pointer+2, minlen);
                   1377:                    tmpbuf[minlen] = 0;
                   1378:                    fprintf(NetTrace, "is %s.\n", tmpbuf);
                   1379:                }
                   1380:                break;
                   1381:            case TELQUAL_SEND:
                   1382:                fprintf(NetTrace, "- request to send.\n");
                   1383:                break;
                   1384:            default:
                   1385:                fprintf(NetTrace,
                   1386:                                "- unknown qualifier %d (0x%x).\n", pointer[1]);
                   1387:            }
                   1388:            break;
                   1389:        default:
                   1390:            fprintf(NetTrace, "Unknown option %d (0x%x)\n",
                   1391:                                        pointer[0], pointer[0]);
                   1392:        }
                   1393:     }
                   1394: }
                   1395: 
                   1396: /*
                   1397:  * Check to see if any out-of-band data exists on a socket (for
                   1398:  * Telnet "synch" processing).
                   1399:  */
                   1400: 
                   1401: static int
                   1402: stilloob(s)
                   1403: int    s;              /* socket number */
                   1404: {
                   1405:     static struct timeval timeout = { 0 };
                   1406:     fd_set     excepts;
                   1407:     int value;
                   1408: 
                   1409:     do {
                   1410:        FD_ZERO(&excepts);
                   1411:        FD_SET(s, &excepts);
                   1412:        value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
                   1413:     } while ((value == -1) && (errno == EINTR));
                   1414: 
                   1415:     if (value < 0) {
                   1416:        perror("select");
                   1417:        quit();
                   1418:     }
                   1419:     if (FD_ISSET(s, &excepts)) {
                   1420:        return 1;
                   1421:     } else {
                   1422:        return 0;
                   1423:     }
                   1424: }
                   1425: 
                   1426: 
                   1427: /*
                   1428:  *  netflush
                   1429:  *             Send as much data as possible to the network,
                   1430:  *     handling requests for urgent data.
                   1431:  *
                   1432:  *             The return value indicates whether we did any
                   1433:  *     useful work.
                   1434:  */
                   1435: 
                   1436: 
                   1437: int
                   1438: netflush()
                   1439: {
                   1440:     int n;
                   1441: 
                   1442:     if ((n = nfrontp - nbackp) > 0) {
                   1443:        if (!neturg) {
                   1444:            n = send(net, nbackp, n, 0);        /* normal write */
                   1445:        } else {
                   1446:            n = neturg - nbackp;
                   1447:            /*
                   1448:             * In 4.2 (and 4.3) systems, there is some question about
                   1449:             * what byte in a sendOOB operation is the "OOB" data.
                   1450:             * To make ourselves compatible, we only send ONE byte
                   1451:             * out of band, the one WE THINK should be OOB (though
                   1452:             * we really have more the TCP philosophy of urgent data
                   1453:             * rather than the Unix philosophy of OOB data).
                   1454:             */
                   1455:            if (n > 1) {
                   1456:                n = send(net, nbackp, n-1, 0);  /* send URGENT all by itself */
                   1457:            } else {
                   1458:                n = send(net, nbackp, n, MSG_OOB);      /* URGENT data */
                   1459:            }
                   1460:        }
                   1461:     }
                   1462:     if (n < 0) {
                   1463:        if (errno != ENOBUFS && errno != EWOULDBLOCK) {
                   1464:            setcommandmode();
                   1465:            perror(hostname);
                   1466:            NetClose(net);
                   1467:            neturg = 0;
                   1468:            longjmp(peerdied, -1);
                   1469:            /*NOTREACHED*/
                   1470:        }
                   1471:        n = 0;
                   1472:     }
                   1473:     if (netdata && n) {
                   1474:        Dump('>', nbackp, n);
                   1475:     }
                   1476:     nbackp += n;
                   1477:     if (nbackp >= neturg) {
                   1478:        neturg = 0;
                   1479:     }
                   1480:     if (nbackp == nfrontp) {
                   1481:        nbackp = nfrontp = netobuf;
                   1482:     }
                   1483:     return n > 0;
                   1484: }
                   1485: 
                   1486: /*
                   1487:  * nextitem()
                   1488:  *
                   1489:  *     Return the address of the next "item" in the TELNET data
                   1490:  * stream.  This will be the address of the next character if
                   1491:  * the current address is a user data character, or it will
                   1492:  * be the address of the character following the TELNET command
                   1493:  * if the current address is a TELNET IAC ("I Am a Command")
                   1494:  * character.
                   1495:  */
                   1496: 
                   1497: static char *
                   1498: nextitem(current)
                   1499: char   *current;
                   1500: {
                   1501:     if ((*current&0xff) != IAC) {
                   1502:        return current+1;
                   1503:     }
                   1504:     switch (*(current+1)&0xff) {
                   1505:     case DO:
                   1506:     case DONT:
                   1507:     case WILL:
                   1508:     case WONT:
                   1509:        return current+3;
                   1510:     case SB:           /* loop forever looking for the SE */
                   1511:        {
                   1512:            register char *look = current+2;
                   1513: 
                   1514:            for (;;) {
                   1515:                if ((*look++&0xff) == IAC) {
                   1516:                    if ((*look++&0xff) == SE) {
                   1517:                        return look;
                   1518:                    }
                   1519:                }
                   1520:            }
                   1521:        }
                   1522:     default:
                   1523:        return current+2;
                   1524:     }
                   1525: }
                   1526: /*
                   1527:  * netclear()
                   1528:  *
                   1529:  *     We are about to do a TELNET SYNCH operation.  Clear
                   1530:  * the path to the network.
                   1531:  *
                   1532:  *     Things are a bit tricky since we may have sent the first
                   1533:  * byte or so of a previous TELNET command into the network.
                   1534:  * So, we have to scan the network buffer from the beginning
                   1535:  * until we are up to where we want to be.
                   1536:  *
                   1537:  *     A side effect of what we do, just to keep things
                   1538:  * simple, is to clear the urgent data pointer.  The principal
                   1539:  * caller should be setting the urgent data pointer AFTER calling
                   1540:  * us in any case.
                   1541:  */
                   1542: 
                   1543: static void
                   1544: netclear()
                   1545: {
                   1546:     register char *thisitem, *next;
                   1547:     char *good;
                   1548: #define        wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \
                   1549:                                ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
                   1550: 
                   1551:     thisitem = netobuf;
                   1552: 
                   1553:     while ((next = nextitem(thisitem)) <= nbackp) {
                   1554:        thisitem = next;
                   1555:     }
                   1556: 
                   1557:     /* Now, thisitem is first before/at boundary. */
                   1558: 
                   1559:     good = netobuf;    /* where the good bytes go */
                   1560: 
                   1561:     while (nfrontp > thisitem) {
                   1562:        if (wewant(thisitem)) {
                   1563:            int length;
                   1564: 
                   1565:            next = thisitem;
                   1566:            do {
                   1567:                next = nextitem(next);
                   1568:            } while (wewant(next) && (nfrontp > next));
                   1569:            length = next-thisitem;
                   1570:            memcpy(good, thisitem, length);
                   1571:            good += length;
                   1572:            thisitem = next;
                   1573:        } else {
                   1574:            thisitem = nextitem(thisitem);
                   1575:        }
                   1576:     }
                   1577: 
                   1578:     nbackp = netobuf;
                   1579:     nfrontp = good;            /* next byte to be sent */
                   1580:     neturg = 0;
                   1581: }
                   1582: 
                   1583: /*
                   1584:  * These routines add various telnet commands to the data stream.
                   1585:  */
                   1586: 
                   1587: #if    defined(NOT43)
                   1588: static int
                   1589: #else  /* defined(NOT43) */
                   1590: static void
                   1591: #endif /* defined(NOT43) */
                   1592: dosynch()
                   1593: {
                   1594:     netclear();                        /* clear the path to the network */
                   1595:     NET2ADD(IAC, DM);
                   1596:     neturg = NETLOC()-1;       /* Some systems are off by one XXX */
                   1597: 
                   1598: #if    defined(NOT43)
                   1599:     return 0;
                   1600: #endif /* defined(NOT43) */
                   1601: }
                   1602: 
                   1603: static void
                   1604: doflush()
                   1605: {
                   1606:     NET2ADD(IAC, DO);
                   1607:     NETADD(TELOPT_TM);
                   1608:     flushline = 1;
                   1609:     flushout = 1;
                   1610:     ttyflush();
                   1611:     /* do printoption AFTER flush, otherwise the output gets tossed... */
                   1612:     printoption("<SENT", doopt, TELOPT_TM, 0);
                   1613: }
                   1614: 
                   1615: static void
                   1616: intp()
                   1617: {
                   1618:     NET2ADD(IAC, IP);
                   1619:     if (autoflush) {
                   1620:        doflush();
                   1621:     }
                   1622:     if (autosynch) {
                   1623:        dosynch();
                   1624:     }
                   1625: }
                   1626: 
                   1627: static void
                   1628: sendbrk()
                   1629: {
                   1630:     NET2ADD(IAC, BREAK);
                   1631:     if (autoflush) {
                   1632:        doflush();
                   1633:     }
                   1634:     if (autosynch) {
                   1635:        dosynch();
                   1636:     }
                   1637: }
                   1638: 
                   1639: /*
                   1640:  *             Send as much data as possible to the terminal.
                   1641:  *
                   1642:  *             The return value indicates whether we did any
                   1643:  *     useful work.
                   1644:  */
                   1645: 
                   1646: 
                   1647: static int
                   1648: ttyflush()
                   1649: {
                   1650:     int n;
                   1651: 
                   1652:     if ((n = tfrontp - tbackp) > 0) {
                   1653:        if (!(SYNCHing||flushout)) {
                   1654:            n = TerminalWrite(tout, tbackp, n);
                   1655:        } else {
                   1656:            TerminalFlushOutput();
                   1657:            /* we leave 'n' alone! */
                   1658:        }
                   1659:     }
                   1660:     if (n >= 0) {
                   1661:        tbackp += n;
                   1662:        if (tbackp == tfrontp) {
                   1663:            tbackp = tfrontp = ttyobuf;
                   1664:        }
                   1665:     }
                   1666:     return n > 0;
                   1667: }
                   1668: 
                   1669: #if    defined(TN3270)
                   1670: 
                   1671: #if    defined(unix)
                   1672: static void
                   1673: inputAvailable()
                   1674: {
                   1675:     HaveInput = 1;
                   1676: }
                   1677: #endif /* defined(unix) */
                   1678: 
                   1679: void
                   1680: outputPurge()
                   1681: {
                   1682:     int tmp = flushout;
                   1683: 
                   1684:     flushout = 1;
                   1685: 
                   1686:     ttyflush();
                   1687: 
                   1688:     flushout = tmp;
                   1689: }
                   1690: 
                   1691: #endif /* defined(TN3270) */
                   1692: 
                   1693: #if    defined(unix)
                   1694: /*
                   1695:  * Various signal handling routines.
                   1696:  */
                   1697: 
                   1698: static void
                   1699: deadpeer()
                   1700: {
                   1701:        setcommandmode();
                   1702:        longjmp(peerdied, -1);
                   1703: }
                   1704: 
                   1705: static void
                   1706: intr()
                   1707: {
                   1708:     if (localchars) {
                   1709:        intp();
                   1710:        return;
                   1711:     }
                   1712:     setcommandmode();
                   1713:     longjmp(toplevel, -1);
                   1714: }
                   1715: 
                   1716: static void
                   1717: intr2()
                   1718: {
                   1719:     if (localchars) {
                   1720:        sendbrk();
                   1721:        return;
                   1722:     }
                   1723: }
                   1724: 
                   1725: static void
                   1726: doescape()
                   1727: {
                   1728:     command(0);
                   1729: }
                   1730: #endif /* defined(unix) */
                   1731: 
                   1732: /*
                   1733:  * These routines decides on what the mode should be (based on the values
                   1734:  * of various global variables).
                   1735:  */
                   1736: 
                   1737: 
                   1738: static
                   1739: getconnmode()
                   1740: {
                   1741:     static char newmode[16] =
                   1742:                        { 4, 5, 3, 3, 2, 2, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6 };
                   1743:     int modeindex = 0;
                   1744: 
                   1745:     if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
                   1746:        modeindex += 1;
                   1747:     }
                   1748:     if (hisopts[TELOPT_ECHO]) {
                   1749:        modeindex += 2;
                   1750:     }
                   1751:     if (hisopts[TELOPT_SGA]) {
                   1752:        modeindex += 4;
                   1753:     }
                   1754:     if (In3270) {
                   1755:        modeindex += 8;
                   1756:     }
                   1757:     return newmode[modeindex];
                   1758: }
                   1759: 
                   1760: void
                   1761: setconnmode()
                   1762: {
                   1763:     TerminalNewMode(getconnmode());
                   1764: }
                   1765: 
                   1766: 
                   1767: void
                   1768: setcommandmode()
                   1769: {
                   1770:     TerminalNewMode(0);
                   1771: }
                   1772: 
                   1773: static void
                   1774: willoption(option, reply)
                   1775:        int option, reply;
                   1776: {
                   1777:        char *fmt;
                   1778: 
                   1779:        switch (option) {
                   1780: 
                   1781:        case TELOPT_ECHO:
                   1782: #      if defined(TN3270)
                   1783:            /*
                   1784:             * The following is a pain in the rear-end.
                   1785:             * Various IBM servers (some versions of Wiscnet,
                   1786:             * possibly Fibronics/Spartacus, and who knows who
                   1787:             * else) will NOT allow us to send "DO SGA" too early
                   1788:             * in the setup proceedings.  On the other hand,
                   1789:             * 4.2 servers (telnetd) won't set SGA correctly.
                   1790:             * So, we are stuck.  Empirically (but, based on
                   1791:             * a VERY small sample), the IBM servers don't send
                   1792:             * out anything about ECHO, so we postpone our sending
                   1793:             * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
                   1794:             * DO send).
                   1795:             */
                   1796:            {
                   1797:                if (askedSGA == 0) {
                   1798:                    askedSGA = 1;
                   1799:                    if (!hisopts[TELOPT_SGA]) {
                   1800:                        willoption(TELOPT_SGA, 0);
                   1801:                    }
                   1802:                }
                   1803:            }
                   1804:                /* Fall through */
                   1805:        case TELOPT_EOR:
                   1806:        case TELOPT_BINARY:
                   1807: #endif /* defined(TN3270) */
                   1808:        case TELOPT_SGA:
                   1809:                settimer(modenegotiated);
                   1810:                hisopts[option] = 1;
                   1811:                fmt = doopt;
                   1812:                setconnmode();          /* possibly set new tty mode */
                   1813:                break;
                   1814: 
                   1815:        case TELOPT_TM:
                   1816:                return;                 /* Never reply to TM will's/wont's */
                   1817: 
                   1818:        default:
                   1819:                fmt = dont;
                   1820:                break;
                   1821:        }
                   1822:        sprintf(nfrontp, fmt, option);
                   1823:        nfrontp += sizeof (dont) - 2;
                   1824:        if (reply)
                   1825:                printoption(">SENT", fmt, option, reply);
                   1826:        else
                   1827:                printoption("<SENT", fmt, option, reply);
                   1828: }
                   1829: 
                   1830: static void
                   1831: wontoption(option, reply)
                   1832:        int option, reply;
                   1833: {
                   1834:        char *fmt;
                   1835: 
                   1836:        switch (option) {
                   1837: 
                   1838:        case TELOPT_ECHO:
                   1839:        case TELOPT_SGA:
                   1840:                settimer(modenegotiated);
                   1841:                hisopts[option] = 0;
                   1842:                fmt = dont;
                   1843:                setconnmode();                  /* Set new tty mode */
                   1844:                break;
                   1845: 
                   1846:        case TELOPT_TM:
                   1847:                return;         /* Never reply to TM will's/wont's */
                   1848: 
                   1849:        default:
                   1850:                fmt = dont;
                   1851:                hisopts[option] = 0;
                   1852:                break;
                   1853:        }
                   1854:        sprintf(nfrontp, fmt, option);
                   1855:        nfrontp += sizeof (doopt) - 2;
                   1856:        if (reply)
                   1857:                printoption(">SENT", fmt, option, reply);
                   1858:        else
                   1859:                printoption("<SENT", fmt, option, reply);
                   1860: }
                   1861: 
                   1862: static void
                   1863: dooption(option)
                   1864:        int option;
                   1865: {
                   1866:        char *fmt;
                   1867: 
                   1868:        switch (option) {
                   1869: 
                   1870:        case TELOPT_TM:
                   1871:                fmt = will;
                   1872:                break;
                   1873: 
                   1874: #      if defined(TN3270)
                   1875:        case TELOPT_EOR:
                   1876:        case TELOPT_BINARY:
                   1877: #      endif   /* defined(TN3270) */
                   1878:        case TELOPT_TTYPE:              /* terminal type option */
                   1879:        case TELOPT_SGA:                /* no big deal */
                   1880:                fmt = will;
                   1881:                myopts[option] = 1;
                   1882:                break;
                   1883: 
                   1884:        case TELOPT_ECHO:               /* We're never going to echo... */
                   1885:        default:
                   1886:                fmt = wont;
                   1887:                break;
                   1888:        }
                   1889:        sprintf(nfrontp, fmt, option);
                   1890:        nfrontp += sizeof (doopt) - 2;
                   1891:        printoption(">SENT", fmt, option, 0);
                   1892: }
                   1893: 
                   1894: /*
                   1895:  * suboption()
                   1896:  *
                   1897:  *     Look at the sub-option buffer, and try to be helpful to the other
                   1898:  * side.
                   1899:  *
                   1900:  *     Currently we recognize:
                   1901:  *
                   1902:  *             Terminal type, send request.
                   1903:  */
                   1904: 
                   1905: static void
                   1906: suboption()
                   1907: {
                   1908:     printsub("<", subbuffer, subend-subbuffer+1);
                   1909:     switch (subbuffer[0]&0xff) {
                   1910:     case TELOPT_TTYPE:
                   1911:        if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
                   1912:            ;
                   1913:        } else {
                   1914:            char *name;
                   1915:            char namebuf[41];
                   1916:            extern char *getenv();
                   1917:            int len;
                   1918: 
                   1919: #if    defined(TN3270)
                   1920:            /*
                   1921:             * Try to send a 3270 type terminal name.  Decide which one based
                   1922:             * on the format of our screen, and (in the future) color
                   1923:             * capaiblities.
                   1924:             */
                   1925: #if    defined(unix)
                   1926:            if (initscr() != ERR) {     /* Initialize curses to get line size */
                   1927:                MaxNumberLines = LINES;
                   1928:                MaxNumberColumns = COLS;
                   1929:            }
                   1930: #else  /* defined(unix) */
                   1931:            InitTerminal();
                   1932: #endif /* defined(unix) */
                   1933:            if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
                   1934:                Sent3270TerminalType = 1;
                   1935:                if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
                   1936:                    MaxNumberLines = 27;
                   1937:                    MaxNumberColumns = 132;
                   1938:                    sb_terminal[SBTERMMODEL] = '5';
                   1939:                } else if (MaxNumberLines >= 43) {
                   1940:                    MaxNumberLines = 43;
                   1941:                    MaxNumberColumns = 80;
                   1942:                    sb_terminal[SBTERMMODEL] = '4';
                   1943:                } else if (MaxNumberLines >= 32) {
                   1944:                    MaxNumberLines = 32;
                   1945:                    MaxNumberColumns = 80;
                   1946:                    sb_terminal[SBTERMMODEL] = '3';
                   1947:                } else {
                   1948:                    MaxNumberLines = 24;
                   1949:                    MaxNumberColumns = 80;
                   1950:                    sb_terminal[SBTERMMODEL] = '2';
                   1951:                }
                   1952:                NumberLines = 24;               /* before we start out... */
                   1953:                NumberColumns = 80;
                   1954:                ScreenSize = NumberLines*NumberColumns;
                   1955:                if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
                   1956:                    ExitString(stderr,
                   1957:                        "Programming error:  MAXSCREENSIZE too small.\n", 1);
                   1958:                    /*NOTREACHED*/
                   1959:                }
                   1960:                memcpy(nfrontp, sb_terminal, sizeof sb_terminal);
                   1961:                printsub(">", nfrontp+2, sizeof sb_terminal-2);
                   1962:                nfrontp += sizeof sb_terminal;
                   1963:                return;
                   1964:            }
                   1965: #endif /* defined(TN3270) */
                   1966: 
                   1967:            name = getenv("TERM");
                   1968:            if ((name == 0) || ((len = strlen(name)) > 40)) {
                   1969:                name = "UNKNOWN";
                   1970:            }
                   1971:            if ((len + 4+2) < NETROOM()) {
                   1972:                strcpy(namebuf, name);
                   1973:                upcase(namebuf);
                   1974:                sprintf(nfrontp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
                   1975:                                    TELQUAL_IS, namebuf, IAC, SE);
                   1976:                printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2);
                   1977:                nfrontp += 4+strlen(namebuf)+2;
                   1978:            } else {
                   1979:                ExitString(stderr, "No room in buffer for terminal type.\n",
                   1980:                                                        1);
                   1981:                /*NOTREACHED*/
                   1982:            }
                   1983:        }
                   1984: 
                   1985:     default:
                   1986:        break;
                   1987:     }
                   1988: }
                   1989: 
                   1990: #if    defined(TN3270)
                   1991: static void
                   1992: SetIn3270()
                   1993: {
                   1994:     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
                   1995:                            && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
                   1996:        if (!In3270) {
                   1997:            In3270 = 1;
                   1998:            Init3270();         /* Initialize 3270 functions */
                   1999:            /* initialize terminal key mapping */
                   2000:            InitTerminal();     /* Start terminal going */
                   2001:            LocalClearScreen(); /* Make sure the screen is clear */
                   2002:            setconnmode();
                   2003:        }
                   2004:     } else {
                   2005:        if (In3270) {
                   2006:            StopScreen(1);
                   2007:            In3270 = 0;
                   2008:            Stop3270();         /* Tell 3270 we aren't here anymore */
                   2009:            setconnmode();
                   2010:        }
                   2011:     }
                   2012: }
                   2013: #endif /* defined(TN3270) */
                   2014: 
                   2015: 
                   2016: static void
                   2017: telrcv()
                   2018: {
                   2019:     register int c;
                   2020:     static int telrcv_state = TS_DATA;
                   2021: #   if defined(TN3270)
                   2022:     register int Scc;
                   2023:     register char *Sbp;
                   2024: #   endif /* defined(TN3270) */
                   2025: 
                   2026:     while ((scc > 0) && (TTYROOM() > 2)) {
                   2027:        c = *sbp++ & 0xff, scc--;
                   2028:        switch (telrcv_state) {
                   2029: 
                   2030:        case TS_CR:
                   2031:            telrcv_state = TS_DATA;
                   2032:            if (c == '\0') {
                   2033:                break;  /* Ignore \0 after CR */
                   2034:            } else if (c == '\n') {
                   2035:                if (hisopts[TELOPT_ECHO] && !crmod) {
                   2036:                    TTYADD(c);
                   2037:                }
                   2038:                break;
                   2039:            }
                   2040:            /* Else, fall through */
                   2041: 
                   2042:        case TS_DATA:
                   2043:            if (c == IAC) {
                   2044:                telrcv_state = TS_IAC;
                   2045:                continue;
                   2046:            }
                   2047: #          if defined(TN3270)
                   2048:            if (In3270) {
                   2049:                *Ifrontp++ = c;
                   2050:                Sbp = sbp;
                   2051:                Scc = scc;
                   2052:                while (Scc > 0) {
                   2053:                    c = *Sbp++ & 0377, Scc--;
                   2054:                    if (c == IAC) {
                   2055:                        telrcv_state = TS_IAC;
                   2056:                        break;
                   2057:                    }
                   2058:                    *Ifrontp++ = c;
                   2059:                }
                   2060:                sbp = Sbp;
                   2061:                scc = Scc;
                   2062:            } else
                   2063: #          endif /* defined(TN3270) */
                   2064:                    /*
                   2065:                     * The 'crmod' hack (see following) is needed
                   2066:                     * since we can't * set CRMOD on output only.
                   2067:                     * Machines like MULTICS like to send \r without
                   2068:                     * \n; since we must turn off CRMOD to get proper
                   2069:                     * input, the mapping is done here (sigh).
                   2070:                     */
                   2071:            if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
                   2072:                if (scc > 0) {
                   2073:                    c = *sbp&0xff;
                   2074:                    if (c == 0) {
                   2075:                        sbp++, scc--;
                   2076:                        /* a "true" CR */
                   2077:                        TTYADD('\r');
                   2078:                    } else if (!hisopts[TELOPT_ECHO] &&
                   2079:                                        (c == '\n')) {
                   2080:                        sbp++, scc--;
                   2081:                        TTYADD('\n');
                   2082:                    } else {
                   2083:                        TTYADD('\r');
                   2084:                        if (crmod) {
                   2085:                                TTYADD('\n');
                   2086:                        }
                   2087:                    }
                   2088:                } else {
                   2089:                    telrcv_state = TS_CR;
                   2090:                    TTYADD('\r');
                   2091:                    if (crmod) {
                   2092:                            TTYADD('\n');
                   2093:                    }
                   2094:                }
                   2095:            } else {
                   2096:                TTYADD(c);
                   2097:            }
                   2098:            continue;
                   2099: 
                   2100:        case TS_IAC:
                   2101:            switch (c) {
                   2102:            
                   2103:            case WILL:
                   2104:                telrcv_state = TS_WILL;
                   2105:                continue;
                   2106: 
                   2107:            case WONT:
                   2108:                telrcv_state = TS_WONT;
                   2109:                continue;
                   2110: 
                   2111:            case DO:
                   2112:                telrcv_state = TS_DO;
                   2113:                continue;
                   2114: 
                   2115:            case DONT:
                   2116:                telrcv_state = TS_DONT;
                   2117:                continue;
                   2118: 
                   2119:            case DM:
                   2120:                    /*
                   2121:                     * We may have missed an urgent notification,
                   2122:                     * so make sure we flush whatever is in the
                   2123:                     * buffer currently.
                   2124:                     */
                   2125:                SYNCHing = 1;
                   2126:                ttyflush();
                   2127:                SYNCHing = stilloob(net);
                   2128:                settimer(gotDM);
                   2129:                break;
                   2130: 
                   2131:            case NOP:
                   2132:            case GA:
                   2133:                break;
                   2134: 
                   2135:            case SB:
                   2136:                SB_CLEAR();
                   2137:                telrcv_state = TS_SB;
                   2138:                continue;
                   2139: 
                   2140: #          if defined(TN3270)
                   2141:            case EOR:
                   2142:                if (In3270) {
                   2143:                    Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
                   2144:                    if (Ibackp == Ifrontp) {
                   2145:                        Ibackp = Ifrontp = Ibuf;
                   2146:                        ISend = 0;      /* should have been! */
                   2147:                    } else {
                   2148:                        ISend = 1;
                   2149:                    }
                   2150:                }
                   2151:                break;
                   2152: #          endif /* defined(TN3270) */
                   2153: 
                   2154:            case IAC:
                   2155: #          if !defined(TN3270)
                   2156:                TTYADD(IAC);
                   2157: #          else /* !defined(TN3270) */
                   2158:                if (In3270) {
                   2159:                    *Ifrontp++ = IAC;
                   2160:                } else {
                   2161:                    TTYADD(IAC);
                   2162:                }
                   2163: #          endif /* !defined(TN3270) */
                   2164:                break;
                   2165: 
                   2166:            default:
                   2167:                break;
                   2168:            }
                   2169:            telrcv_state = TS_DATA;
                   2170:            continue;
                   2171: 
                   2172:        case TS_WILL:
                   2173:            printoption(">RCVD", will, c, !hisopts[c]);
                   2174:            if (c == TELOPT_TM) {
                   2175:                if (flushout) {
                   2176:                    flushout = 0;
                   2177:                }
                   2178:            } else if (!hisopts[c]) {
                   2179:                willoption(c, 1);
                   2180:            }
                   2181:            SetIn3270();
                   2182:            telrcv_state = TS_DATA;
                   2183:            continue;
                   2184: 
                   2185:        case TS_WONT:
                   2186:            printoption(">RCVD", wont, c, hisopts[c]);
                   2187:            if (c == TELOPT_TM) {
                   2188:                if (flushout) {
                   2189:                    flushout = 0;
                   2190:                }
                   2191:            } else if (hisopts[c]) {
                   2192:                wontoption(c, 1);
                   2193:            }
                   2194:            SetIn3270();
                   2195:            telrcv_state = TS_DATA;
                   2196:            continue;
                   2197: 
                   2198:        case TS_DO:
                   2199:            printoption(">RCVD", doopt, c, !myopts[c]);
                   2200:            if (!myopts[c])
                   2201:                dooption(c);
                   2202:            SetIn3270();
                   2203:            telrcv_state = TS_DATA;
                   2204:            continue;
                   2205: 
                   2206:        case TS_DONT:
                   2207:            printoption(">RCVD", dont, c, myopts[c]);
                   2208:            if (myopts[c]) {
                   2209:                myopts[c] = 0;
                   2210:                sprintf(nfrontp, wont, c);
                   2211:                nfrontp += sizeof (wont) - 2;
                   2212:                flushline = 1;
                   2213:                setconnmode();  /* set new tty mode (maybe) */
                   2214:                printoption(">SENT", wont, c, 0);
                   2215:            }
                   2216:            SetIn3270();
                   2217:            telrcv_state = TS_DATA;
                   2218:            continue;
                   2219: 
                   2220:        case TS_SB:
                   2221:            if (c == IAC) {
                   2222:                telrcv_state = TS_SE;
                   2223:            } else {
                   2224:                SB_ACCUM(c);
                   2225:            }
                   2226:            continue;
                   2227: 
                   2228:        case TS_SE:
                   2229:            if (c != SE) {
                   2230:                if (c != IAC) {
                   2231:                    SB_ACCUM(IAC);
                   2232:                }
                   2233:                SB_ACCUM(c);
                   2234:                telrcv_state = TS_SB;
                   2235:            } else {
                   2236:                SB_TERM();
                   2237:                suboption();    /* handle sub-option */
                   2238:                SetIn3270();
                   2239:                telrcv_state = TS_DATA;
                   2240:            }
                   2241:        }
                   2242:     }
                   2243: }
                   2244: 
                   2245: #if    defined(TN3270)
                   2246: 
                   2247: /*
                   2248:  * The following routines are places where the various tn3270
                   2249:  * routines make calls into telnet.c.
                   2250:  */
                   2251: 
                   2252: /* TtyChars() - returns the number of characters in the TTY buffer */
                   2253: TtyChars()
                   2254: {
                   2255:     return(tfrontp-tbackp);
                   2256: }
                   2257: 
                   2258: /*
                   2259:  * DataToNetwork - queue up some data to go to network.  If "done" is set,
                   2260:  * then when last byte is queued, we add on an IAC EOR sequence (so,
                   2261:  * don't call us with "done" until you want that done...)
                   2262:  *
                   2263:  * We actually do send all the data to the network buffer, since our
                   2264:  * only client needs for us to do that.
                   2265:  */
                   2266: 
                   2267: int
                   2268: DataToNetwork(buffer, count, done)
                   2269: register char  *buffer;        /* where the data is */
                   2270: register int   count;          /* how much to send */
                   2271: int            done;           /* is this the last of a logical block */
                   2272: {
                   2273:     register int c;
                   2274:     int origCount;
                   2275:     fd_set o;
                   2276: 
                   2277:     origCount = count;
                   2278:     FD_ZERO(&o);
                   2279: 
                   2280:     while (count) {
                   2281:        if ((netobuf+sizeof netobuf - nfrontp) < 6) {
                   2282:            netflush();
                   2283:            while ((netobuf+sizeof netobuf - nfrontp) < 6) {
                   2284:                FD_SET(net, &o);
                   2285:                (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
                   2286:                                                (struct timeval *) 0);
                   2287:                netflush();
                   2288:            }
                   2289:        }
                   2290:        c = *buffer++;
                   2291:        count--;
                   2292:        if (c == IAC) {
                   2293:            *nfrontp++ = IAC;
                   2294:            *nfrontp++ = IAC;
                   2295:        } else {
                   2296:            *nfrontp++ = c;
                   2297:        }
                   2298:     }
                   2299: 
                   2300:     if (done && !count) {
                   2301:        *nfrontp++ = IAC;
                   2302:        *nfrontp++ = EOR;
                   2303:        netflush();             /* try to move along as quickly as ... */
                   2304:     }
                   2305:     return(origCount - count);
                   2306: }
                   2307: 
                   2308: /* DataToTerminal - queue up some data to go to terminal. */
                   2309: 
                   2310: int
                   2311: DataToTerminal(buffer, count)
                   2312: register char  *buffer;                /* where the data is */
                   2313: register int   count;                  /* how much to send */
                   2314: {
                   2315:     int origCount;
                   2316: #if    defined(unix)
                   2317:     fd_set     o;
                   2318: 
                   2319:     FD_ZERO(&o);
                   2320: #endif /* defined(unix) */
                   2321:     origCount = count;
                   2322: 
                   2323:     while (count) {
                   2324:        if (tfrontp >= ttyobuf+sizeof ttyobuf) {
                   2325:            ttyflush();
                   2326:            while (tfrontp >= ttyobuf+sizeof ttyobuf) {
                   2327: #if    defined(unix)
                   2328:                FD_SET(tout, &o);
                   2329:                (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
                   2330:                                                (struct timeval *) 0);
                   2331: #endif /* defined(unix) */
                   2332:                ttyflush();
                   2333:            }
                   2334:        }
                   2335:        *tfrontp++ = *buffer++;
                   2336:        count--;
                   2337:     }
                   2338:     return(origCount - count);
                   2339: }
                   2340: 
                   2341: /* EmptyTerminal - called to make sure that the terminal buffer is empty.
                   2342:  *                     Note that we consider the buffer to run all the
                   2343:  *                     way to the kernel (thus the select).
                   2344:  */
                   2345: 
                   2346: void
                   2347: EmptyTerminal()
                   2348: {
                   2349: #if    defined(unix)
                   2350:     fd_set     o;
                   2351: 
                   2352:     FD_ZERO(&o);
                   2353: #endif /* defined(unix) */
                   2354: 
                   2355:     if (tfrontp == tbackp) {
                   2356: #if    defined(unix)
                   2357:        FD_SET(tout, &o);
                   2358:        (void) select(tout+1, (int *) 0, &o, (int *) 0,
                   2359:                        (struct timeval *) 0);  /* wait for TTLOWAT */
                   2360: #endif /* defined(unix) */
                   2361:     } else {
                   2362:        while (tfrontp != tbackp) {
                   2363:            ttyflush();
                   2364: #if    defined(unix)
                   2365:            FD_SET(tout, &o);
                   2366:            (void) select(tout+1, (int *) 0, &o, (int *) 0,
                   2367:                                (struct timeval *) 0);  /* wait for TTLOWAT */
                   2368: #endif /* defined(unix) */
                   2369:        }
                   2370:     }
                   2371: }
                   2372: 
                   2373: /*
                   2374:  * Push3270 - Try to send data along the 3270 output (to screen) direction.
                   2375:  */
                   2376: 
                   2377: static int
                   2378: Push3270()
                   2379: {
                   2380:     int save = scc;
                   2381: 
                   2382:     if (scc) {
                   2383:        if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
                   2384:            if (Ibackp != Ibuf) {
                   2385:                memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
                   2386:                Ifrontp -= (Ibackp-Ibuf);
                   2387:                Ibackp = Ibuf;
                   2388:            }
                   2389:        }
                   2390:        if (Ifrontp+scc < Ibuf+sizeof Ibuf) {
                   2391:            telrcv();
                   2392:        }
                   2393:     }
                   2394:     return save != scc;
                   2395: }
                   2396: 
                   2397: 
                   2398: /*
                   2399:  * Finish3270 - get the last dregs of 3270 data out to the terminal
                   2400:  *             before quitting.
                   2401:  */
                   2402: 
                   2403: static void
                   2404: Finish3270()
                   2405: {
                   2406:     while (Push3270() || !DoTerminalOutput()) {
                   2407: #if    defined(unix)
                   2408:        HaveInput = 0;
                   2409: #endif /* defined(unix) */
                   2410:        ;
                   2411:     }
                   2412: }
                   2413: 
                   2414: 
                   2415: 
                   2416: /* StringToTerminal - output a null terminated string to the terminal */
                   2417: 
                   2418: void
                   2419: StringToTerminal(s)
                   2420: char *s;
                   2421: {
                   2422:     int count;
                   2423: 
                   2424:     count = strlen(s);
                   2425:     if (count) {
                   2426:        (void) DataToTerminal(s, count);        /* we know it always goes... */
                   2427:     }
                   2428: }
                   2429: 
                   2430: 
                   2431: #if    defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR))
                   2432: /* _putchar - output a single character to the terminal.  This name is so that
                   2433:  *     curses(3x) can call us to send out data.
                   2434:  */
                   2435: 
                   2436: void
                   2437: _putchar(c)
                   2438: char c;
                   2439: {
                   2440:     if (tfrontp >= ttyobuf+sizeof ttyobuf) {
                   2441:        (void) DataToTerminal(&c, 1);
                   2442:     } else {
                   2443:        *tfrontp++ = c;         /* optimize if possible. */
                   2444:     }
                   2445: }
                   2446: #endif /* defined(TN3270) && ((!defined(NOT43)) || defined(PUTCHAR)) */
                   2447: 
                   2448: static void
                   2449: SetForExit()
                   2450: {
                   2451:     setconnmode();
                   2452:     if (In3270) {
                   2453:        Finish3270();
                   2454:     }
                   2455:     setcommandmode();
                   2456:     fflush(stdout);
                   2457:     fflush(stderr);
                   2458:     if (In3270) {
                   2459:        StopScreen(1);
                   2460:     }
                   2461:     setconnmode();
                   2462:     setcommandmode();
                   2463: }
                   2464: 
                   2465: static void
                   2466: Exit(returnCode)
                   2467: int returnCode;
                   2468: {
                   2469:     SetForExit();
                   2470:     exit(returnCode);
                   2471: }
                   2472: 
                   2473: void
                   2474: ExitString(file, string, returnCode)
                   2475: FILE *file;
                   2476: char *string;
                   2477: int returnCode;
                   2478: {
                   2479:     SetForExit();
                   2480:     fwrite(string, 1, strlen(string), file);
                   2481:     exit(returnCode);
                   2482: }
                   2483: 
                   2484: void
                   2485: ExitPerror(string, returnCode)
                   2486: char *string;
                   2487: int returnCode;
                   2488: {
                   2489:     SetForExit();
                   2490:     perror(string);
                   2491:     exit(returnCode);
                   2492: }
                   2493: 
                   2494: #endif /* defined(TN3270) */
                   2495: 
                   2496: /*
                   2497:  * Scheduler()
                   2498:  *
                   2499:  * Try to do something.
                   2500:  *
                   2501:  * If we do something useful, return 1; else return 0.
                   2502:  *
                   2503:  */
                   2504: 
                   2505: 
                   2506: int
                   2507: Scheduler(block)
                   2508: int    block;                  /* should we block in the select ? */
                   2509: {
                   2510:     register int c;
                   2511:                /* One wants to be a bit careful about setting returnValue
                   2512:                 * to one, since a one implies we did some useful work,
                   2513:                 * and therefore probably won't be called to block next
                   2514:                 * time (TN3270 mode only).
                   2515:                 */
                   2516:     int returnValue = 0;
                   2517:     static struct timeval TimeValue = { 0 };
                   2518: 
                   2519:     if (scc < 0 && tcc < 0) {
                   2520:        return -1;
                   2521:     }
                   2522: 
                   2523:     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
                   2524:        FD_SET(net, &obits);
                   2525:     } 
                   2526: #if    !defined(MSDOS)
                   2527:     if (TTYBYTES()) {
                   2528:        FD_SET(tout, &obits);
                   2529:     }
                   2530: #if    defined(TN3270)
                   2531:     if ((tcc == 0) && NETROOM() && (shell_active == 0)) {
                   2532:        FD_SET(tin, &ibits);
                   2533:     }
                   2534: #else  /* defined(TN3270) */
                   2535:     if ((tcc == 0) && NETROOM()) {
                   2536:        FD_SET(tin, &ibits);
                   2537:     }
                   2538: #endif /* defined(TN3270) */
                   2539: #endif /* !defined(MSDOS) */
                   2540: #   if !defined(TN3270)
                   2541:     if (TTYROOM()) {
                   2542:        FD_SET(net, &ibits);
                   2543:     }
                   2544: #   else /* !defined(TN3270) */
                   2545:     if (!ISend && TTYROOM()) {
                   2546:        FD_SET(net, &ibits);
                   2547:     }
                   2548: #   endif /* !defined(TN3270) */
                   2549:     if (!SYNCHing) {
                   2550:        FD_SET(net, &xbits);
                   2551:     }
                   2552: #   if defined(TN3270) && defined(unix)
                   2553:     if (HaveInput) {
                   2554:        HaveInput = 0;
                   2555:        signal(SIGIO, inputAvailable);
                   2556:     }
                   2557: #endif /* defined(TN3270) && defined(unix) */
                   2558:     if ((c = select(16, &ibits, &obits, &xbits,
                   2559:                        block? (struct timeval *)0 : &TimeValue)) < 0) {
                   2560:        if (c == -1) {
                   2561:                    /*
                   2562:                     * we can get EINTR if we are in line mode,
                   2563:                     * and the user does an escape (TSTP), or
                   2564:                     * some other signal generator.
                   2565:                     */
                   2566:            if (errno == EINTR) {
                   2567:                return 0;
                   2568:            }
                   2569: #          if defined(TN3270)
                   2570:                    /*
                   2571:                     * we can get EBADF if we were in transparent
                   2572:                     * mode, and the transcom process died.
                   2573:                    */
                   2574:            if (errno == EBADF) {
                   2575:                        /*
                   2576:                         * zero the bits (even though kernel does it)
                   2577:                         * to make sure we are selecting on the right
                   2578:                         * ones.
                   2579:                        */
                   2580:                FD_ZERO(&ibits);
                   2581:                FD_ZERO(&obits);
                   2582:                FD_ZERO(&xbits);
                   2583:                return 0;
                   2584:            }
                   2585: #          endif /* defined(TN3270) */
                   2586:                    /* I don't like this, does it ever happen? */
                   2587:            printf("sleep(5) from telnet, after select\r\n");
                   2588: #if    defined(unix)
                   2589:            sleep(5);
                   2590: #endif /* defined(unix) */
                   2591:        }
                   2592:        return 0;
                   2593:     }
                   2594: 
                   2595:     /*
                   2596:      * Any urgent data?
                   2597:      */
                   2598:     if (FD_ISSET(net, &xbits)) {
                   2599:        FD_CLR(net, &xbits);
                   2600:        SYNCHing = 1;
                   2601:        ttyflush();     /* flush already enqueued data */
                   2602:     }
                   2603: 
                   2604:     /*
                   2605:      * Something to read from the network...
                   2606:      */
                   2607:     if (FD_ISSET(net, &ibits)) {
                   2608:        int canread;
                   2609: 
                   2610:        FD_CLR(net, &ibits);
                   2611:        if (scc == 0) {
                   2612:            sbp = sibuf;
                   2613:        }
                   2614:        canread = sibuf + sizeof sibuf - (sbp+scc);
                   2615: #if    !defined(SO_OOBINLINE)
                   2616:            /*
                   2617:             * In 4.2 (and some early 4.3) systems, the
                   2618:             * OOB indication and data handling in the kernel
                   2619:             * is such that if two separate TCP Urgent requests
                   2620:             * come in, one byte of TCP data will be overlaid.
                   2621:             * This is fatal for Telnet, but we try to live
                   2622:             * with it.
                   2623:             *
                   2624:             * In addition, in 4.2 (and...), a special protocol
                   2625:             * is needed to pick up the TCP Urgent data in
                   2626:             * the correct sequence.
                   2627:             *
                   2628:             * What we do is:  if we think we are in urgent
                   2629:             * mode, we look to see if we are "at the mark".
                   2630:             * If we are, we do an OOB receive.  If we run
                   2631:             * this twice, we will do the OOB receive twice,
                   2632:             * but the second will fail, since the second
                   2633:             * time we were "at the mark", but there wasn't
                   2634:             * any data there (the kernel doesn't reset
                   2635:             * "at the mark" until we do a normal read).
                   2636:             * Once we've read the OOB data, we go ahead
                   2637:             * and do normal reads.
                   2638:             *
                   2639:             * There is also another problem, which is that
                   2640:             * since the OOB byte we read doesn't put us
                   2641:             * out of OOB state, and since that byte is most
                   2642:             * likely the TELNET DM (data mark), we would
                   2643:             * stay in the TELNET SYNCH (SYNCHing) state.
                   2644:             * So, clocks to the rescue.  If we've "just"
                   2645:             * received a DM, then we test for the
                   2646:             * presence of OOB data when the receive OOB
                   2647:             * fails (and AFTER we did the normal mode read
                   2648:             * to clear "at the mark").
                   2649:             */
                   2650:        if (SYNCHing) {
                   2651:            int atmark;
                   2652: 
                   2653:            ioctl(net, SIOCATMARK, (char *)&atmark);
                   2654:            if (atmark) {
                   2655:                c = recv(net, sbp+scc, canread, MSG_OOB);
                   2656:                if ((c == -1) && (errno == EINVAL)) {
                   2657:                    c = recv(net, sbp+scc, canread, 0);
                   2658:                    if (clocks.didnetreceive < clocks.gotDM) {
                   2659:                        SYNCHing = stilloob(net);
                   2660:                    }
                   2661:                }
                   2662:            } else {
                   2663:                c = recv(net, sbp+scc, canread, 0);
                   2664:            }
                   2665:        } else {
                   2666:            c = recv(net, sbp+scc, canread, 0);
                   2667:        }
                   2668:        settimer(didnetreceive);
                   2669: #else  /* !defined(SO_OOBINLINE) */
                   2670:        c = recv(net, sbp+scc, canread, 0);
                   2671: #endif /* !defined(SO_OOBINLINE) */
                   2672:        if (c < 0 && errno == EWOULDBLOCK) {
                   2673:            c = 0;
                   2674:        } else if (c <= 0) {
                   2675:            return -1;
                   2676:        }
                   2677:        if (netdata) {
                   2678:            Dump('<', sbp+scc, c);
                   2679:        }
                   2680:        scc += c;
                   2681:        returnValue = 1;
                   2682:     }
                   2683: 
                   2684:     /*
                   2685:      * Something to read from the tty...
                   2686:      */
                   2687: #if    defined(MSDOS)
                   2688:     if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead())
                   2689: #else  /* defined(MSDOS) */
                   2690:     if (FD_ISSET(tin, &ibits))
                   2691: #endif /* defined(MSDOS) */
                   2692:                                    {
                   2693:        FD_CLR(tin, &ibits);
                   2694:        if (tcc == 0) {
                   2695:            tbp = tibuf;        /* nothing left, reset */
                   2696:        }
                   2697:        c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp);
                   2698:        if (c < 0 && errno == EWOULDBLOCK) {
                   2699:            c = 0;
                   2700:        } else {
                   2701: #if    defined(unix)
                   2702:            /* EOF detection for line mode!!!! */
                   2703:            if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
                   2704:                        /* must be an EOF... */
                   2705:                *tbp = ntc.t_eofc;
                   2706:                c = 1;
                   2707:            }
                   2708: #endif /* defined(unix) */
                   2709:            if (c <= 0) {
                   2710:                tcc = c;
                   2711:                return -1;
                   2712:            }
                   2713:        }
                   2714:        tcc += c;
                   2715:        returnValue = 1;                /* did something useful */
                   2716:     }
                   2717: 
                   2718: #   if defined(TN3270)
                   2719:     if (tcc > 0) {
                   2720:        if (In3270) {
                   2721:            c = DataFromTerminal(tbp, tcc);
                   2722:            if (c) {
                   2723:                returnValue = 1;
                   2724:            }
                   2725:            tcc -= c;
                   2726:            tbp += c;
                   2727:        } else {
                   2728: #   endif /* defined(TN3270) */
                   2729:            returnValue = 1;
                   2730:            while (tcc > 0) {
                   2731:                register int sc;
                   2732: 
                   2733:                if (NETROOM() < 2) {
                   2734:                    flushline = 1;
                   2735:                    break;
                   2736:                }
                   2737:                c = *tbp++ & 0xff, sc = strip(c), tcc--;
                   2738:                if (sc == escape) {
                   2739:                    command(0);
                   2740:                    tcc = 0;
                   2741:                    flushline = 1;
                   2742:                    break;
                   2743:                } else if (MODE_LINE(globalmode) && (sc == echoc)) {
                   2744:                    if (tcc > 0 && strip(*tbp) == echoc) {
                   2745:                        tbp++;
                   2746:                        tcc--;
                   2747:                    } else {
                   2748:                        dontlecho = !dontlecho;
                   2749:                        settimer(echotoggle);
                   2750:                        setconnmode();
                   2751:                        tcc = 0;
                   2752:                        flushline = 1;
                   2753:                        break;
                   2754:                    }
                   2755:                }
                   2756:                if (localchars) {
                   2757:                    if (TerminalSpecialChars(sc) == 0) {
                   2758:                        break;
                   2759:                    }
                   2760:                }
                   2761:                if (!myopts[TELOPT_BINARY]) {
                   2762:                    switch (c) {
                   2763:                    case '\n':
                   2764:                            /*
                   2765:                             * If we are in CRMOD mode (\r ==> \n)
                   2766:                             * on our local machine, then probably
                   2767:                             * a newline (unix) is CRLF (TELNET).
                   2768:                             */
                   2769:                        if (MODE_LOCAL_CHARS(globalmode)) {
                   2770:                            NETADD('\r');
                   2771:                        }
                   2772:                        NETADD('\n');
                   2773:                        flushline = 1;
                   2774:                        break;
                   2775:                    case '\r':
                   2776:                        if (!crlf) {
                   2777:                            NET2ADD('\r', '\0');
                   2778:                        } else {
                   2779:                            NET2ADD('\r', '\n');
                   2780:                        }
                   2781:                        flushline = 1;
                   2782:                        break;
                   2783:                    case IAC:
                   2784:                        NET2ADD(IAC, IAC);
                   2785:                        break;
                   2786:                    default:
                   2787:                        NETADD(c);
                   2788:                        break;
                   2789:                    }
                   2790:                } else if (c == IAC) {
                   2791:                    NET2ADD(IAC, IAC);
                   2792:                } else {
                   2793:                    NETADD(c);
                   2794:                }
                   2795:            }
                   2796: #   if defined(TN3270)
                   2797:        }
                   2798:     }
                   2799: #   endif /* defined(TN3270) */
                   2800: 
                   2801:     if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) &&
                   2802:        FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
                   2803:        FD_CLR(net, &obits);
                   2804:        returnValue = netflush();
                   2805:     }
                   2806:     if (scc > 0) {
                   2807: #      if !defined(TN3270)
                   2808:        telrcv();
                   2809:        returnValue = 1;
                   2810: #      else /* !defined(TN3270) */
                   2811:        returnValue = Push3270();
                   2812: #      endif /* !defined(TN3270) */
                   2813:     }
                   2814: #if    defined(MSDOS)
                   2815:     if (TTYBYTES())
                   2816: #else  /* defined(MSDOS) */
                   2817:     if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
                   2818: #endif /* defined(MSDOS) */
                   2819:                                                    {
                   2820:        FD_CLR(tout, &obits);
                   2821:        returnValue = ttyflush();
                   2822:     }
                   2823:     return returnValue;
                   2824: }
                   2825: 
                   2826: /*
                   2827:  * Select from tty and network...
                   2828:  */
                   2829: static void
                   2830: telnet()
                   2831: {
                   2832: #if    defined(MSDOS)
                   2833: #define        SCHED_BLOCK     0               /* Don't block in MSDOS */
                   2834: #else  /* defined(MSDOS) */
                   2835: #define        SCHED_BLOCK     1
                   2836: #endif /* defined(MSDOS) */
                   2837: 
                   2838: #if    defined(TN3270) && defined(unix)
                   2839:     int myPid;
                   2840: #endif /* defined(TN3270) */
                   2841: 
                   2842:     tout = fileno(stdout);
                   2843:     tin = fileno(stdin);
                   2844:     setconnmode();
                   2845:     scc = 0;
                   2846:     tcc = 0;
                   2847:     FD_ZERO(&ibits);
                   2848:     FD_ZERO(&obits);
                   2849:     FD_ZERO(&xbits);
                   2850: 
                   2851:     NetNonblockingIO(net, 1);
                   2852: 
                   2853: #if    defined(TN3270)
                   2854:     if (noasynch == 0) {                       /* DBX can't handle! */
                   2855:        NetSigIO(net, 1);
                   2856:     }
                   2857:     NetSetPgrp(net);
                   2858: #endif /* defined(TN3270) */
                   2859: 
                   2860: 
                   2861: #if    defined(SO_OOBINLINE) && !defined(MSDOS)
                   2862:     SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
                   2863: #endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */
                   2864: 
                   2865: #   if !defined(TN3270)
                   2866:     if (telnetport) {
                   2867:        if (!hisopts[TELOPT_SGA]) {
                   2868:            willoption(TELOPT_SGA, 0);
                   2869:        }
                   2870:        if (!myopts[TELOPT_TTYPE]) {
                   2871:            dooption(TELOPT_TTYPE, 0);
                   2872:        }
                   2873:     }
                   2874: #   endif /* !defined(TN3270) */
                   2875: 
                   2876: #   if !defined(TN3270)
                   2877:     for (;;) {
                   2878:        if (Scheduler(SCHED_BLOCK) == -1) {
                   2879:            setcommandmode();
                   2880:            return;
                   2881:        }
                   2882:     }
                   2883: #   else /* !defined(TN3270) */
                   2884:     for (;;) {
                   2885:        int schedValue;
                   2886: 
                   2887:        while (!In3270 && !shell_active) {
                   2888:            if (Scheduler(SCHED_BLOCK) == -1) {
                   2889:                setcommandmode();
                   2890:                return;
                   2891:            }
                   2892:        }
                   2893: 
                   2894:        while ((schedValue = Scheduler(0)) != 0) {
                   2895:            if (schedValue == -1) {
                   2896:                setcommandmode();
                   2897:                return;
                   2898:            }
                   2899:        }
                   2900:                /* If there is data waiting to go out to terminal, don't
                   2901:                 * schedule any more data for the terminal.
                   2902:                 */
                   2903:        if (tfrontp-tbackp) {
                   2904:            schedValue = 1;
                   2905:        } else {
                   2906:            if (shell_active) {
                   2907:                if (shell_continue() == 0) {
                   2908:                    ConnectScreen();
                   2909:                }
                   2910:            } else if (In3270) {
                   2911:                schedValue = DoTerminalOutput();
                   2912:            }
                   2913:        }
                   2914:        if (schedValue && (shell_active == 0)) {
                   2915:            if (Scheduler(SCHED_BLOCK) == -1) {
                   2916:                setcommandmode();
                   2917:                return;
                   2918:            }
                   2919:        }
                   2920:     }
                   2921: #   endif /* !defined(TN3270) */
                   2922: }
                   2923: 
                   2924: /*
                   2925:  *     The following are data structures and routines for
                   2926:  *     the "send" command.
                   2927:  *
                   2928:  */
                   2929:  
                   2930: struct sendlist {
                   2931:     char       *name;          /* How user refers to it (case independent) */
                   2932:     int                what;           /* Character to be sent (<0 ==> special) */
                   2933:     char       *help;          /* Help information (0 ==> no help) */
                   2934: #if    defined(NOT43)
                   2935:     int                (*routine)();   /* Routine to perform (for special ops) */
                   2936: #else  /* defined(NOT43) */
                   2937:     void       (*routine)();   /* Routine to perform (for special ops) */
                   2938: #endif /* defined(NOT43) */
                   2939: };
                   2940: 
                   2941: #define        SENDQUESTION    -1
                   2942: #define        SENDESCAPE      -3
                   2943: 
                   2944: static struct sendlist Sendlist[] = {
                   2945:     { "ao", AO, "Send Telnet Abort output" },
                   2946:     { "ayt", AYT, "Send Telnet 'Are You There'" },
                   2947:     { "brk", BREAK, "Send Telnet Break" },
                   2948:     { "ec", EC, "Send Telnet Erase Character" },
                   2949:     { "el", EL, "Send Telnet Erase Line" },
                   2950:     { "escape", SENDESCAPE, "Send current escape character" },
                   2951:     { "ga", GA, "Send Telnet 'Go Ahead' sequence" },
                   2952:     { "ip", IP, "Send Telnet Interrupt Process" },
                   2953:     { "nop", NOP, "Send Telnet 'No operation'" },
                   2954:     { "synch", SYNCH, "Perform Telnet 'Synch operation'", dosynch },
                   2955:     { "?", SENDQUESTION, "Display send options" },
                   2956:     { 0 }
                   2957: };
                   2958: 
                   2959: static struct sendlist Sendlist2[] = {         /* some synonyms */
                   2960:        { "break", BREAK, 0 },
                   2961: 
                   2962:        { "intp", IP, 0 },
                   2963:        { "interrupt", IP, 0 },
                   2964:        { "intr", IP, 0 },
                   2965: 
                   2966:        { "help", SENDQUESTION, 0 },
                   2967: 
                   2968:        { 0 }
                   2969: };
                   2970: 
                   2971: static char **
                   2972: getnextsend(name)
                   2973: char *name;
                   2974: {
                   2975:     struct sendlist *c = (struct sendlist *) name;
                   2976: 
                   2977:     return (char **) (c+1);
                   2978: }
                   2979: 
                   2980: static struct sendlist *
                   2981: getsend(name)
                   2982: char *name;
                   2983: {
                   2984:     struct sendlist *sl;
                   2985: 
                   2986:     if ((sl = (struct sendlist *)
                   2987:                        genget(name, (char **) Sendlist, getnextsend)) != 0) {
                   2988:        return sl;
                   2989:     } else {
                   2990:        return (struct sendlist *)
                   2991:                                genget(name, (char **) Sendlist2, getnextsend);
                   2992:     }
                   2993: }
                   2994: 
                   2995: static
                   2996: sendcmd(argc, argv)
                   2997: int    argc;
                   2998: char   **argv;
                   2999: {
                   3000:     int what;          /* what we are sending this time */
                   3001:     int count;         /* how many bytes we are going to need to send */
                   3002:     int i;
                   3003:     int question = 0;  /* was at least one argument a question */
                   3004:     struct sendlist *s;        /* pointer to current command */
                   3005: 
                   3006:     if (argc < 2) {
                   3007:        printf("need at least one argument for 'send' command\n");
                   3008:        printf("'send ?' for help\n");
                   3009:        return 0;
                   3010:     }
                   3011:     /*
                   3012:      * First, validate all the send arguments.
                   3013:      * In addition, we see how much space we are going to need, and
                   3014:      * whether or not we will be doing a "SYNCH" operation (which
                   3015:      * flushes the network queue).
                   3016:      */
                   3017:     count = 0;
                   3018:     for (i = 1; i < argc; i++) {
                   3019:        s = getsend(argv[i]);
                   3020:        if (s == 0) {
                   3021:            printf("Unknown send argument '%s'\n'send ?' for help.\n",
                   3022:                        argv[i]);
                   3023:            return 0;
                   3024:        } else if (s == Ambiguous(struct sendlist *)) {
                   3025:            printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
                   3026:                        argv[i]);
                   3027:            return 0;
                   3028:        }
                   3029:        switch (s->what) {
                   3030:        case SENDQUESTION:
                   3031:            break;
                   3032:        case SENDESCAPE:
                   3033:            count += 1;
                   3034:            break;
                   3035:        case SYNCH:
                   3036:            count += 2;
                   3037:            break;
                   3038:        default:
                   3039:            count += 2;
                   3040:            break;
                   3041:        }
                   3042:     }
                   3043:     /* Now, do we have enough room? */
                   3044:     if (NETROOM() < count) {
                   3045:        printf("There is not enough room in the buffer TO the network\n");
                   3046:        printf("to process your request.  Nothing will be done.\n");
                   3047:        printf("('send synch' will throw away most data in the network\n");
                   3048:        printf("buffer, if this might help.)\n");
                   3049:        return 0;
                   3050:     }
                   3051:     /* OK, they are all OK, now go through again and actually send */
                   3052:     for (i = 1; i < argc; i++) {
                   3053:        if ((s = getsend(argv[i])) == 0) {
                   3054:            fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
                   3055:            quit();
                   3056:            /*NOTREACHED*/
                   3057:        }
                   3058:        if (s->routine) {
                   3059:            (*s->routine)(s);
                   3060:        } else {
                   3061:            switch (what = s->what) {
                   3062:            case SYNCH:
                   3063:                dosynch();
                   3064:                break;
                   3065:            case SENDQUESTION:
                   3066:                for (s = Sendlist; s->name; s++) {
                   3067:                    if (s->help) {
                   3068:                        printf(s->name);
                   3069:                        if (s->help) {
                   3070:                            printf("\t%s", s->help);
                   3071:                        }
                   3072:                        printf("\n");
                   3073:                    }
                   3074:                }
                   3075:                question = 1;
                   3076:                break;
                   3077:            case SENDESCAPE:
                   3078:                NETADD(escape);
                   3079:                break;
                   3080:            default:
                   3081:                NET2ADD(IAC, what);
                   3082:                break;
                   3083:            }
                   3084:        }
                   3085:     }
                   3086:     return !question;
                   3087: }
                   3088: 
                   3089: /*
                   3090:  * The following are the routines and data structures referred
                   3091:  * to by the arguments to the "toggle" command.
                   3092:  */
                   3093: 
                   3094: static
                   3095: lclchars()
                   3096: {
                   3097:     donelclchars = 1;
                   3098:     return 1;
                   3099: }
                   3100: 
                   3101: static
                   3102: togdebug()
                   3103: {
                   3104: #ifndef        NOT43
                   3105:     if (net > 0 &&
                   3106:        (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
                   3107:            perror("setsockopt (SO_DEBUG)");
                   3108:     }
                   3109: #else  /* NOT43 */
                   3110:     if (debug) {
                   3111:        if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
                   3112:            perror("setsockopt (SO_DEBUG)");
                   3113:     } else
                   3114:        printf("Cannot turn off socket debugging\n");
                   3115: #endif /* NOT43 */
                   3116:     return 1;
                   3117: }
                   3118: 
                   3119: 
                   3120: static int
                   3121: togcrlf()
                   3122: {
                   3123:     if (crlf) {
                   3124:        printf("Will send carriage returns as telnet <CR><LF>.\n");
                   3125:     } else {
                   3126:        printf("Will send carriage returns as telnet <CR><NUL>.\n");
                   3127:     }
                   3128:     return 1;
                   3129: }
                   3130: 
                   3131: 
                   3132: static int
                   3133: togbinary()
                   3134: {
                   3135:     donebinarytoggle = 1;
                   3136: 
                   3137:     if (myopts[TELOPT_BINARY] == 0) {  /* Go into binary mode */
                   3138:        NET2ADD(IAC, DO);
                   3139:        NETADD(TELOPT_BINARY);
                   3140:        printoption("<SENT", doopt, TELOPT_BINARY, 0);
                   3141:        NET2ADD(IAC, WILL);
                   3142:        NETADD(TELOPT_BINARY);
                   3143:        printoption("<SENT", doopt, TELOPT_BINARY, 0);
                   3144:        hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1;
                   3145:        printf("Negotiating binary mode with remote host.\n");
                   3146:     } else {                           /* Turn off binary mode */
                   3147:        NET2ADD(IAC, DONT);
                   3148:        NETADD(TELOPT_BINARY);
                   3149:        printoption("<SENT", dont, TELOPT_BINARY, 0);
                   3150:        NET2ADD(IAC, DONT);
                   3151:        NETADD(TELOPT_BINARY);
                   3152:        printoption("<SENT", dont, TELOPT_BINARY, 0);
                   3153:        hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0;
                   3154:        printf("Negotiating network ascii mode with remote host.\n");
                   3155:     }
                   3156:     return 1;
                   3157: }
                   3158: 
                   3159: 
                   3160: 
                   3161: extern int togglehelp();
                   3162: 
                   3163: struct togglelist {
                   3164:     char       *name;          /* name of toggle */
                   3165:     char       *help;          /* help message */
                   3166:     int                (*handler)();   /* routine to do actual setting */
                   3167:     int                dohelp;         /* should we display help information */
                   3168:     int                *variable;
                   3169:     char       *actionexplanation;
                   3170: };
                   3171: 
                   3172: static struct togglelist Togglelist[] = {
                   3173:     { "autoflush",
                   3174:        "toggle flushing of output when sending interrupt characters",
                   3175:            0,
                   3176:                1,
                   3177:                    &autoflush,
                   3178:                        "flush output when sending interrupt characters" },
                   3179:     { "autosynch",
                   3180:        "toggle automatic sending of interrupt characters in urgent mode",
                   3181:            0,
                   3182:                1,
                   3183:                    &autosynch,
                   3184:                        "send interrupt characters in urgent mode" },
                   3185:     { "binary",
                   3186:        "toggle sending and receiving of binary data",
                   3187:            togbinary,
                   3188:                1,
                   3189:                    0,
                   3190:                        0 },
                   3191:     { "crlf",
                   3192:        "toggle sending carriage returns as telnet <CR><LF>",
                   3193:            togcrlf,
                   3194:                1,
                   3195:                    &crlf,
                   3196:                        0 },
                   3197:     { "crmod",
                   3198:        "toggle mapping of received carriage returns",
                   3199:            0,
                   3200:                1,
                   3201:                    &crmod,
                   3202:                        "map carriage return on output" },
                   3203:     { "localchars",
                   3204:        "toggle local recognition of certain control characters",
                   3205:            lclchars,
                   3206:                1,
                   3207:                    &localchars,
                   3208:                        "recognize certain control characters" },
                   3209:     { " ", "", 0, 1 },         /* empty line */
                   3210:     { "debug",
                   3211:        "(debugging) toggle debugging",
                   3212:            togdebug,
                   3213:                1,
                   3214:                    &debug,
                   3215:                        "turn on socket level debugging" },
                   3216:     { "netdata",
                   3217:        "(debugging) toggle printing of hexadecimal network data",
                   3218:            0,
                   3219:                1,
                   3220:                    &netdata,
                   3221:                        "print hexadecimal representation of network traffic" },
                   3222:     { "options",
                   3223:        "(debugging) toggle viewing of options processing",
                   3224:            0,
                   3225:                1,
                   3226:                    &showoptions,
                   3227:                        "show option processing" },
                   3228:     { " ", "", 0, 1 },         /* empty line */
                   3229:     { "?",
                   3230:        "display help information",
                   3231:            togglehelp,
                   3232:                1 },
                   3233:     { "help",
                   3234:        "display help information",
                   3235:            togglehelp,
                   3236:                0 },
                   3237:     { 0 }
                   3238: };
                   3239: 
                   3240: static
                   3241: togglehelp()
                   3242: {
                   3243:     struct togglelist *c;
                   3244: 
                   3245:     for (c = Togglelist; c->name; c++) {
                   3246:        if (c->dohelp) {
                   3247:            printf("%s\t%s\n", c->name, c->help);
                   3248:        }
                   3249:     }
                   3250:     return 0;
                   3251: }
                   3252: 
                   3253: static char **
                   3254: getnexttoggle(name)
                   3255: char *name;
                   3256: {
                   3257:     struct togglelist *c = (struct togglelist *) name;
                   3258: 
                   3259:     return (char **) (c+1);
                   3260: }
                   3261: 
                   3262: static struct togglelist *
                   3263: gettoggle(name)
                   3264: char *name;
                   3265: {
                   3266:     return (struct togglelist *)
                   3267:                        genget(name, (char **) Togglelist, getnexttoggle);
                   3268: }
                   3269: 
                   3270: static
                   3271: toggle(argc, argv)
                   3272: int    argc;
                   3273: char   *argv[];
                   3274: {
                   3275:     int retval = 1;
                   3276:     char *name;
                   3277:     struct togglelist *c;
                   3278: 
                   3279:     if (argc < 2) {
                   3280:        fprintf(stderr,
                   3281:            "Need an argument to 'toggle' command.  'toggle ?' for help.\n");
                   3282:        return 0;
                   3283:     }
                   3284:     argc--;
                   3285:     argv++;
                   3286:     while (argc--) {
                   3287:        name = *argv++;
                   3288:        c = gettoggle(name);
                   3289:        if (c == Ambiguous(struct togglelist *)) {
                   3290:            fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
                   3291:                                        name);
                   3292:            return 0;
                   3293:        } else if (c == 0) {
                   3294:            fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
                   3295:                                        name);
                   3296:            return 0;
                   3297:        } else {
                   3298:            if (c->variable) {
                   3299:                *c->variable = !*c->variable;           /* invert it */
                   3300:                if (c->actionexplanation) {
                   3301:                    printf("%s %s.\n", *c->variable? "Will" : "Won't",
                   3302:                                                        c->actionexplanation);
                   3303:                }
                   3304:            }
                   3305:            if (c->handler) {
                   3306:                retval &= (*c->handler)(c);
                   3307:            }
                   3308:        }
                   3309:     }
                   3310:     return retval;
                   3311: }
                   3312: 
                   3313: /*
                   3314:  * The following perform the "set" command.
                   3315:  */
                   3316: 
                   3317: struct setlist {
                   3318:     char *name;                                /* name */
                   3319:     char *help;                                /* help information */
                   3320:     char *charp;                       /* where it is located at */
                   3321: };
                   3322: 
                   3323: static struct setlist Setlist[] = {
                   3324:     { "echo",  "character to toggle local echoing on/off", &echoc },
                   3325:     { "escape",        "character to escape back to telnet command mode", &escape },
                   3326:     { " ", "" },
                   3327:     { " ", "The following need 'localchars' to be toggled true", 0 },
                   3328: #if    defined(unix)
                   3329:     { "erase", "character to cause an Erase Character", &nttyb.sg_erase },
                   3330:     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
                   3331:     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
                   3332:     { "kill",  "character to cause an Erase Line", &nttyb.sg_kill },
                   3333:     { "quit",  "character to cause a Break", &ntc.t_quitc },
                   3334:     { "eof",   "character to cause an EOF ", &ntc.t_eofc },
                   3335: #endif /* defined(unix) */
                   3336: #if    defined(MSDOS)
                   3337:     { "erase", "character to cause an Erase Character", &termEraseChar },
                   3338:     { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
                   3339:     { "interrupt", "character to cause an Interrupt Process", &termIntChar },
                   3340:     { "kill",  "character to cause an Erase Line", &termKillChar },
                   3341:     { "quit",  "character to cause a Break", &termQuitChar },
                   3342:     { "eof",   "character to cause an EOF ", &termEofChar },
                   3343: #endif /* defined(MSDOS) */
                   3344:     { 0 }
                   3345: };
                   3346: 
                   3347: static char **
                   3348: getnextset(name)
                   3349: char *name;
                   3350: {
                   3351:     struct setlist *c = (struct setlist *)name;
                   3352: 
                   3353:     return (char **) (c+1);
                   3354: }
                   3355: 
                   3356: static struct setlist *
                   3357: getset(name)
                   3358: char *name;
                   3359: {
                   3360:     return (struct setlist *) genget(name, (char **) Setlist, getnextset);
                   3361: }
                   3362: 
                   3363: static
                   3364: setcmd(argc, argv)
                   3365: int    argc;
                   3366: char   *argv[];
                   3367: {
                   3368:     int value;
                   3369:     struct setlist *ct;
                   3370: 
                   3371:     /* XXX back we go... sigh */
                   3372:     if (argc != 3) {
                   3373:        if ((argc == 2) &&
                   3374:                    ((!strcmp(argv[1], "?")) || (!strcmp(argv[1], "help")))) {
                   3375:            for (ct = Setlist; ct->name; ct++) {
                   3376:                printf("%s\t%s\n", ct->name, ct->help);
                   3377:            }
                   3378:            printf("?\tdisplay help information\n");
                   3379:        } else {
                   3380:            printf("Format is 'set Name Value'\n'set ?' for help.\n");
                   3381:        }
                   3382:        return 0;
                   3383:     }
                   3384: 
                   3385:     ct = getset(argv[1]);
                   3386:     if (ct == 0) {
                   3387:        fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
                   3388:                        argv[1]);
                   3389:        return 0;
                   3390:     } else if (ct == Ambiguous(struct setlist *)) {
                   3391:        fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
                   3392:                        argv[1]);
                   3393:        return 0;
                   3394:     } else {
                   3395:        if (strcmp("off", argv[2])) {
                   3396:            value = special(argv[2]);
                   3397:        } else {
                   3398:            value = -1;
                   3399:        }
                   3400:        *(ct->charp) = value;
                   3401:        printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
                   3402:     }
                   3403:     return 1;
                   3404: }
                   3405: 
                   3406: /*
                   3407:  * The following are the data structures and routines for the
                   3408:  * 'mode' command.
                   3409:  */
                   3410: 
                   3411: static
                   3412: dolinemode()
                   3413: {
                   3414:     if (hisopts[TELOPT_SGA]) {
                   3415:        wontoption(TELOPT_SGA, 0);
                   3416:     }
                   3417:     if (hisopts[TELOPT_ECHO]) {
                   3418:        wontoption(TELOPT_ECHO, 0);
                   3419:     }
                   3420:     return 1;
                   3421: }
                   3422: 
                   3423: static
                   3424: docharmode()
                   3425: {
                   3426:     if (!hisopts[TELOPT_SGA]) {
                   3427:        willoption(TELOPT_SGA, 0);
                   3428:     }
                   3429:     if (!hisopts[TELOPT_ECHO]) {
                   3430:        willoption(TELOPT_ECHO, 0);
                   3431:     }
                   3432:     return 1;
                   3433: }
                   3434: 
                   3435: static struct cmd Modelist[] = {
                   3436:     { "character",     "character-at-a-time mode",     docharmode, 1, 1 },
                   3437:     { "line",          "line-by-line mode",            dolinemode, 1, 1 },
                   3438:     { 0 },
                   3439: };
                   3440: 
                   3441: static char **
                   3442: getnextmode(name)
                   3443: char *name;
                   3444: {
                   3445:     struct cmd *c = (struct cmd *) name;
                   3446: 
                   3447:     return (char **) (c+1);
                   3448: }
                   3449: 
                   3450: static struct cmd *
                   3451: getmodecmd(name)
                   3452: char *name;
                   3453: {
                   3454:     return (struct cmd *) genget(name, (char **) Modelist, getnextmode);
                   3455: }
                   3456: 
                   3457: static
                   3458: modecmd(argc, argv)
                   3459: int    argc;
                   3460: char   *argv[];
                   3461: {
                   3462:     struct cmd *mt;
                   3463: 
                   3464:     if ((argc != 2) || !strcmp(argv[1], "?") || !strcmp(argv[1], "help")) {
                   3465:        printf("format is:  'mode Mode', where 'Mode' is one of:\n\n");
                   3466:        for (mt = Modelist; mt->name; mt++) {
                   3467:            printf("%s\t%s\n", mt->name, mt->help);
                   3468:        }
                   3469:        return 0;
                   3470:     }
                   3471:     mt = getmodecmd(argv[1]);
                   3472:     if (mt == 0) {
                   3473:        fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
                   3474:        return 0;
                   3475:     } else if (mt == Ambiguous(struct cmd *)) {
                   3476:        fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
                   3477:        return 0;
                   3478:     } else {
                   3479:        (*mt->handler)();
                   3480:     }
                   3481:     return 1;
                   3482: }
                   3483: 
                   3484: /*
                   3485:  * The following data structures and routines implement the
                   3486:  * "display" command.
                   3487:  */
                   3488: 
                   3489: static
                   3490: display(argc, argv)
                   3491: int    argc;
                   3492: char   *argv[];
                   3493: {
                   3494: #define        dotog(tl)       if (tl->variable && tl->actionexplanation) { \
                   3495:                            if (*tl->variable) { \
                   3496:                                printf("will"); \
                   3497:                            } else { \
                   3498:                                printf("won't"); \
                   3499:                            } \
                   3500:                            printf(" %s.\n", tl->actionexplanation); \
                   3501:                        }
                   3502: 
                   3503: #define        doset(sl)   if (sl->name && *sl->name != ' ') { \
                   3504:                        printf("[%s]\t%s.\n", control(*sl->charp), sl->name); \
                   3505:                    }
                   3506: 
                   3507:     struct togglelist *tl;
                   3508:     struct setlist *sl;
                   3509: 
                   3510:     if (argc == 1) {
                   3511:        for (tl = Togglelist; tl->name; tl++) {
                   3512:            dotog(tl);
                   3513:        }
                   3514:        printf("\n");
                   3515:        for (sl = Setlist; sl->name; sl++) {
                   3516:            doset(sl);
                   3517:        }
                   3518:     } else {
                   3519:        int i;
                   3520: 
                   3521:        for (i = 1; i < argc; i++) {
                   3522:            sl = getset(argv[i]);
                   3523:            tl = gettoggle(argv[i]);
                   3524:            if ((sl == Ambiguous(struct setlist *)) ||
                   3525:                                (tl == Ambiguous(struct togglelist *))) {
                   3526:                printf("?Ambiguous argument '%s'.\n", argv[i]);
                   3527:                return 0;
                   3528:            } else if (!sl && !tl) {
                   3529:                printf("?Unknown argument '%s'.\n", argv[i]);
                   3530:                return 0;
                   3531:            } else {
                   3532:                if (tl) {
                   3533:                    dotog(tl);
                   3534:                }
                   3535:                if (sl) {
                   3536:                    doset(sl);
                   3537:                }
                   3538:            }
                   3539:        }
                   3540:     }
                   3541:     return 1;
                   3542: #undef doset
                   3543: #undef dotog
                   3544: }
                   3545: 
                   3546: /*
                   3547:  * The following are the data structures, and many of the routines,
                   3548:  * relating to command processing.
                   3549:  */
                   3550: 
                   3551: /*
                   3552:  * Set the escape character.
                   3553:  */
                   3554: static
                   3555: setescape(argc, argv)
                   3556:        int argc;
                   3557:        char *argv[];
                   3558: {
                   3559:        register char *arg;
                   3560:        char buf[50];
                   3561: 
                   3562:        printf(
                   3563:            "Deprecated usage - please use 'set escape%s%s' in the future.\n",
                   3564:                                (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
                   3565:        if (argc > 2)
                   3566:                arg = argv[1];
                   3567:        else {
                   3568:                printf("new escape character: ");
                   3569:                gets(buf);
                   3570:                arg = buf;
                   3571:        }
                   3572:        if (arg[0] != '\0')
                   3573:                escape = arg[0];
                   3574:        if (!In3270) {
                   3575:                printf("Escape character is '%s'.\n", control(escape));
                   3576:        }
                   3577:        fflush(stdout);
                   3578:        return 1;
                   3579: }
                   3580: 
                   3581: /*VARARGS*/
                   3582: static
                   3583: togcrmod()
                   3584: {
                   3585:     crmod = !crmod;
                   3586:     printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
                   3587:     printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
                   3588:     fflush(stdout);
                   3589:     return 1;
                   3590: }
                   3591: 
                   3592: /*VARARGS*/
                   3593: suspend()
                   3594: {
                   3595:        setcommandmode();
                   3596: #if    defined(unix)
                   3597:        kill(0, SIGTSTP);
                   3598: #endif /* defined(unix) */
                   3599:        /* reget parameters in case they were changed */
                   3600:        TerminalSaveState();
                   3601:        setconnmode();
                   3602:        return 1;
                   3603: }
                   3604: 
                   3605: /*VARARGS*/
                   3606: static
                   3607: bye(argc, argv)
                   3608: int    argc;           /* Number of arguments */
                   3609: char   *argv[];        /* arguments */
                   3610: {
                   3611:     if (connected) {
                   3612:        shutdown(net, 2);
                   3613:        printf("Connection closed.\n");
                   3614:        NetClose(net);
                   3615:        connected = 0;
                   3616:        /* reset options */
                   3617:        tninit();
                   3618: #if    defined(TN3270)
                   3619:        SetIn3270();            /* Get out of 3270 mode */
                   3620: #endif /* defined(TN3270) */
                   3621:     }
                   3622:     if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
                   3623:        longjmp(toplevel, 1);
                   3624:        /* NOTREACHED */
                   3625:     }
                   3626:     return 1;                  /* Keep lint, etc., happy */
                   3627: }
                   3628: 
                   3629: /*VARARGS*/
                   3630: quit()
                   3631: {
                   3632:        (void) call(bye, "bye", "fromquit", 0);
                   3633:        Exit(0);
                   3634:        /*NOTREACHED*/
                   3635:        return 1;                       /* just to keep lint happy */
                   3636: }
                   3637: 
                   3638: /*
                   3639:  * Print status about the connection.
                   3640:  */
                   3641: static
                   3642: status(argc, argv)
                   3643: int    argc;
                   3644: char   *argv[];
                   3645: {
                   3646:     if (connected) {
                   3647:        printf("Connected to %s.\n", hostname);
                   3648:        if (argc < 2) {
                   3649:            printf("Operating in %s.\n",
                   3650:                                modelist[getconnmode()].modedescriptions);
                   3651:            if (localchars) {
                   3652:                printf("Catching signals locally.\n");
                   3653:            }
                   3654:        }
                   3655:     } else {
                   3656:        printf("No connection.\n");
                   3657:     }
                   3658: #   if !defined(TN3270)
                   3659:     printf("Escape character is '%s'.\n", control(escape));
                   3660:     fflush(stdout);
                   3661: #   else /* !defined(TN3270) */
                   3662:     if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) {
                   3663:        printf("Escape character is '%s'.\n", control(escape));
                   3664:     }
                   3665: #   if defined(unix)
                   3666:     if (In3270 && transcom) {
                   3667:        printf("Transparent mode command is '%s'.\n", transcom);
                   3668:     }
                   3669: #   endif /* defined(unix) */
                   3670:     fflush(stdout);
                   3671:     if (In3270) {
                   3672:        return 0;
                   3673:     }
                   3674: #   endif /* defined(TN3270) */
                   3675:     return 1;
                   3676: }
                   3677: 
                   3678: #if    defined(TN3270) && defined(unix)
                   3679: static
                   3680: settranscom(argc, argv)
                   3681:        int argc;
                   3682:        char *argv[];
                   3683: {
                   3684:        int i, len = 0;
                   3685:        char *strcpy(), *strcat();
                   3686: 
                   3687:        if (argc == 1 && transcom) {
                   3688:           transcom = 0;
                   3689:        }
                   3690:        if (argc == 1) {
                   3691:           return;
                   3692:        }
                   3693:        for (i = 1; i < argc; ++i) {
                   3694:            len += 1 + strlen(argv[1]);
                   3695:        }
                   3696:        transcom = tline;
                   3697:        (void) strcpy(transcom, argv[1]);
                   3698:        for (i = 2; i < argc; ++i) {
                   3699:            (void) strcat(transcom, " ");
                   3700:            (void) strcat(transcom, argv[i]);
                   3701:        }
                   3702: }
                   3703: #endif /* defined(TN3270) && defined(unix) */
                   3704: 
                   3705: 
                   3706: 
                   3707: static
                   3708: tn(argc, argv)
                   3709:        int argc;
                   3710:        char *argv[];
                   3711: {
                   3712:     register struct hostent *host = 0;
                   3713: #if defined(MSDOS)
                   3714:     char *cp;
                   3715: #endif /* defined(MSDOS) */
                   3716: 
                   3717:     if (connected) {
                   3718:        printf("?Already connected to %s\n", hostname);
                   3719:        return 0;
                   3720:     }
                   3721:     if (argc < 2) {
                   3722:        (void) strcpy(line, "Connect ");
                   3723:        printf("(to) ");
                   3724:        gets(&line[strlen(line)]);
                   3725:        makeargv();
                   3726:        argc = margc;
                   3727:        argv = margv;
                   3728:     }
                   3729:     if ((argc < 2) || (argc > 3)) {
                   3730:        printf("usage: %s host-name [port]\n", argv[0]);
                   3731:        return 0;
                   3732:     }
                   3733: #if    defined(MSDOS)
                   3734:     for (cp = argv[1]; *cp; cp++) {
                   3735:        if (isupper(*cp)) {
                   3736:            *cp = tolower(*cp);
                   3737:        }
                   3738:     }
                   3739: #endif /* defined(MSDOS) */
                   3740:     sin.sin_addr.s_addr = inet_addr(argv[1]);
                   3741:     if (sin.sin_addr.s_addr != -1) {
                   3742:        sin.sin_family = AF_INET;
                   3743:        (void) strcpy(hnamebuf, argv[1]);
                   3744:        hostname = hnamebuf;
                   3745:     } else {
                   3746:        host = gethostbyname(argv[1]);
                   3747:        if (host) {
                   3748:            sin.sin_family = host->h_addrtype;
                   3749: #if    defined(h_addr)         /* In 4.3, this is a #define */
                   3750:            memcpy((caddr_t)&sin.sin_addr,
                   3751:                                host->h_addr_list[0], host->h_length);
                   3752: #else  /* defined(h_addr) */
                   3753:            memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
                   3754: #endif /* defined(h_addr) */
                   3755:            hostname = host->h_name;
                   3756:        } else {
                   3757:            printf("%s: unknown host\n", argv[1]);
                   3758:            return 0;
                   3759:        }
                   3760:     }
                   3761:     sin.sin_port = sp->s_port;
                   3762:     if (argc == 3) {
                   3763:        sin.sin_port = atoi(argv[2]);
                   3764:        if (sin.sin_port == 0) {
                   3765:            sp = getservbyname(argv[2], "tcp");
                   3766:            if (sp)
                   3767:                sin.sin_port = sp->s_port;
                   3768:            else {
                   3769:                printf("%s: bad port number\n", argv[2]);
                   3770:                return 0;
                   3771:            }
                   3772:        } else {
                   3773:            sin.sin_port = atoi(argv[2]);
                   3774:            sin.sin_port = htons(sin.sin_port);
                   3775:        }
                   3776:        telnetport = 0;
                   3777:     } else {
                   3778:        telnetport = 1;
                   3779:     }
                   3780: #if    defined(unix)
                   3781:     signal(SIGINT, intr);
                   3782:     signal(SIGQUIT, intr2);
                   3783:     signal(SIGPIPE, deadpeer);
                   3784: #endif /* defined(unix) */
                   3785:     printf("Trying...\n");
                   3786:     do {
                   3787:        net = socket(AF_INET, SOCK_STREAM, 0);
                   3788:        if (net < 0) {
                   3789:            perror("telnet: socket");
                   3790:            return 0;
                   3791:        }
                   3792:        if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
                   3793:                perror("setsockopt (SO_DEBUG)");
                   3794:        }
                   3795: 
                   3796:        if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
                   3797: #if    defined(h_addr)         /* In 4.3, this is a #define */
                   3798:            if (host && host->h_addr_list[1]) {
                   3799:                int oerrno = errno;
                   3800: 
                   3801:                fprintf(stderr, "telnet: connect to address %s: ",
                   3802:                                                inet_ntoa(sin.sin_addr));
                   3803:                errno = oerrno;
                   3804:                perror((char *)0);
                   3805:                host->h_addr_list++;
                   3806:                memcpy((caddr_t)&sin.sin_addr, 
                   3807:                        host->h_addr_list[0], host->h_length);
                   3808:                fprintf(stderr, "Trying %s...\n",
                   3809:                        inet_ntoa(sin.sin_addr));
                   3810:                (void) NetClose(net);
                   3811:                continue;
                   3812:            }
                   3813: #endif /* defined(h_addr) */
                   3814:            perror("telnet: Unable to connect to remote host");
                   3815: #if defined(unix)
                   3816:            signal(SIGINT, SIG_DFL);
                   3817:            signal(SIGQUIT, SIG_DFL);
                   3818: #endif /* defined(unix) */
                   3819:            return 0;
                   3820:            }
                   3821:        connected++;
                   3822:     } while (connected == 0);
                   3823:     call(status, "status", "notmuch", 0);
                   3824:     if (setjmp(peerdied) == 0)
                   3825:        telnet();
                   3826:     NetClose(net);
                   3827:     ExitString(stderr, "Connection closed by foreign host.\n",1);
                   3828:     /*NOTREACHED*/
                   3829: }
                   3830: 
                   3831: 
                   3832: #define HELPINDENT (sizeof ("connect"))
                   3833: 
                   3834: static char
                   3835:        openhelp[] =    "connect to a site",
                   3836:        closehelp[] =   "close current connection",
                   3837:        quithelp[] =    "exit telnet",
                   3838:        statushelp[] =  "print status information",
                   3839:        helphelp[] =    "print help information",
                   3840:        sendhelp[] =    "transmit special characters ('send ?' for more)",
                   3841:        sethelp[] =     "set operating parameters ('set ?' for more)",
                   3842:        togglestring[] ="toggle operating parameters ('toggle ?' for more)",
                   3843:        displayhelp[] = "display operating parameters",
                   3844: #if    defined(TN3270) && defined(unix)
                   3845:        transcomhelp[] = "specify Unix command for transparent mode pipe",
                   3846: #endif /* defined(TN3270) && defined(unix) */
                   3847: #if    defined(unix)
                   3848:        zhelp[] =       "suspend telnet",
                   3849: #endif /* defined(unix */
                   3850: #if    defined(TN3270)
                   3851:        shellhelp[] =   "invoke a subshell",
                   3852: #endif /* defined(TN3270) */
                   3853:        modehelp[] = "try to enter line-by-line or character-at-a-time mode";
                   3854: 
                   3855: extern int     help(), shell();
                   3856: 
                   3857: static struct cmd cmdtab[] = {
                   3858:        { "close",      closehelp,      bye,            1, 1 },
                   3859:        { "display",    displayhelp,    display,        1, 0 },
                   3860:        { "mode",       modehelp,       modecmd,        1, 1 },
                   3861:        { "open",       openhelp,       tn,             1, 0 },
                   3862:        { "quit",       quithelp,       quit,           1, 0 },
                   3863:        { "send",       sendhelp,       sendcmd,        1, 1 },
                   3864:        { "set",        sethelp,        setcmd,         1, 0 },
                   3865:        { "status",     statushelp,     status,         1, 0 },
                   3866:        { "toggle",     togglestring,   toggle,         1, 0 },
                   3867: #if    defined(TN3270) && defined(unix)
                   3868:        { "transcom",   transcomhelp,   settranscom,    1, 0 },
                   3869: #endif /* defined(TN3270) && defined(unix) */
                   3870: #if    defined(unix)
                   3871:        { "z",          zhelp,          suspend,        1, 0 },
                   3872: #endif /* defined(unix) */
                   3873: #if    defined(TN3270)
                   3874:        { "!",          shellhelp,      shell,          1, 1 },
                   3875: #endif /* defined(TN3270) */
                   3876:        { "?",          helphelp,       help,           1, 0 },
                   3877:        0
                   3878: };
                   3879: 
                   3880: static char    crmodhelp[] =   "deprecated command -- use 'toggle crmod' instead";
                   3881: static char    escapehelp[] =  "deprecated command -- use 'set escape' instead";
                   3882: 
                   3883: static struct cmd cmdtab2[] = {
                   3884:        { "help",       helphelp,       help,           0, 0 },
                   3885:        { "escape",     escapehelp,     setescape,      1, 0 },
                   3886:        { "crmod",      crmodhelp,      togcrmod,       1, 0 },
                   3887:        0
                   3888: };
                   3889: 
                   3890: /*
                   3891:  * Call routine with argc, argv set from args (terminated by 0).
                   3892:  * VARARGS2
                   3893:  */
                   3894: static
                   3895: call(routine, args)
                   3896:        int (*routine)();
                   3897:        char *args;
                   3898: {
                   3899:        register char **argp;
                   3900:        register int argc;
                   3901: 
                   3902:        for (argc = 0, argp = &args; *argp++ != 0; argc++)
                   3903:                ;
                   3904:        return (*routine)(argc, &args);
                   3905: }
                   3906: 
                   3907: static char **
                   3908: getnextcmd(name)
                   3909: char *name;
                   3910: {
                   3911:     struct cmd *c = (struct cmd *) name;
                   3912: 
                   3913:     return (char **) (c+1);
                   3914: }
                   3915: 
                   3916: static struct cmd *
                   3917: getcmd(name)
                   3918: char *name;
                   3919: {
                   3920:     struct cmd *cm;
                   3921: 
                   3922:     if ((cm = (struct cmd *) genget(name, (char **) cmdtab, getnextcmd)) != 0) {
                   3923:        return cm;
                   3924:     } else {
                   3925:        return (struct cmd *) genget(name, (char **) cmdtab2, getnextcmd);
                   3926:     }
                   3927: }
                   3928: 
                   3929: void
                   3930: command(top)
                   3931:        int top;
                   3932: {
                   3933:     register struct cmd *c;
                   3934: 
                   3935:     setcommandmode();
                   3936:     if (!top) {
                   3937:        putchar('\n');
                   3938:     } else {
                   3939: #if    defined(unix)
                   3940:        signal(SIGINT, SIG_DFL);
                   3941:        signal(SIGQUIT, SIG_DFL);
                   3942: #endif /* defined(unix) */
                   3943:     }
                   3944:     for (;;) {
                   3945:        printf("%s> ", prompt);
                   3946:        if (gets(line) == NULL) {
                   3947:            if (feof(stdin) || ferror(stdin))
                   3948:                quit();
                   3949:            break;
                   3950:        }
                   3951:        if (line[0] == 0)
                   3952:            break;
                   3953:        makeargv();
                   3954:        c = getcmd(margv[0]);
                   3955:        if (c == Ambiguous(struct cmd *)) {
                   3956:            printf("?Ambiguous command\n");
                   3957:            continue;
                   3958:        }
                   3959:        if (c == 0) {
                   3960:            printf("?Invalid command\n");
                   3961:            continue;
                   3962:        }
                   3963:        if (c->needconnect && !connected) {
                   3964:            printf("?Need to be connected first.\n");
                   3965:            continue;
                   3966:        }
                   3967:        if ((*c->handler)(margc, margv)) {
                   3968:            break;
                   3969:        }
                   3970:     }
                   3971:     if (!top) {
                   3972:        if (!connected) {
                   3973:            longjmp(toplevel, 1);
                   3974:            /*NOTREACHED*/
                   3975:        }
                   3976: #if    defined(TN3270)
                   3977:        if (shell_active == 0) {
                   3978:            setconnmode();
                   3979:        }
                   3980: #else  /* defined(TN3270) */
                   3981:        setconnmode();
                   3982: #endif /* defined(TN3270) */
                   3983:     }
                   3984: }
                   3985: 
                   3986: /*
                   3987:  * Help command.
                   3988:  */
                   3989: static
                   3990: help(argc, argv)
                   3991:        int argc;
                   3992:        char *argv[];
                   3993: {
                   3994:        register struct cmd *c;
                   3995: 
                   3996:        if (argc == 1) {
                   3997:                printf("Commands may be abbreviated.  Commands are:\n\n");
                   3998:                for (c = cmdtab; c->name; c++)
                   3999:                        if (c->dohelp) {
                   4000:                                printf("%-*s\t%s\n", HELPINDENT, c->name,
                   4001:                                                                    c->help);
                   4002:                        }
                   4003:                return 0;
                   4004:        }
                   4005:        while (--argc > 0) {
                   4006:                register char *arg;
                   4007:                arg = *++argv;
                   4008:                c = getcmd(arg);
                   4009:                if (c == Ambiguous(struct cmd *))
                   4010:                        printf("?Ambiguous help command %s\n", arg);
                   4011:                else if (c == (struct cmd *)0)
                   4012:                        printf("?Invalid help command %s\n", arg);
                   4013:                else
                   4014:                        printf("%s\n", c->help);
                   4015:        }
                   4016:        return 0;
                   4017: }
                   4018: 
                   4019: /*
                   4020:  * main.  Parse arguments, invoke the protocol or command parser.
                   4021:  */
                   4022: 
                   4023: 
                   4024: void
                   4025: main(argc, argv)
                   4026:        int argc;
                   4027:        char *argv[];
                   4028: {
                   4029:     tninit();          /* Clear out things */
                   4030: 
                   4031:     NetTrace = stdout;
                   4032:     TerminalSaveState();
                   4033:     autoflush = TerminalAutoFlush();
                   4034: 
                   4035:     prompt = argv[0];
                   4036:     while ((argc > 1) && (argv[1][0] == '-')) {
                   4037:        if (!strcmp(argv[1], "-d")) {
                   4038:            debug = 1;
                   4039:        } else if (!strcmp(argv[1], "-n")) {
                   4040:            if ((argc > 1) && (argv[2][0] != '-')) {    /* get file name */
                   4041:                NetTrace = fopen(argv[2], "w");
                   4042:                argv++;
                   4043:                argc--;
                   4044:                if (NetTrace == NULL) {
                   4045:                    NetTrace = stdout;
                   4046:                }
                   4047:            }
                   4048:        } else {
                   4049: #if    defined(TN3270) && defined(unix)
                   4050:            if (!strcmp(argv[1], "-t")) {
                   4051:                if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */
                   4052:                    transcom = tline;
                   4053:                    (void) strcpy(transcom, argv[1]);
                   4054:                    argv++;
                   4055:                    argc--;
                   4056:                }
                   4057:            } else if (!strcmp(argv[1], "-noasynch")) {
                   4058:                noasynch = 1;
                   4059:            } else
                   4060: #endif /* defined(TN3270) && defined(unix) */
                   4061:            if (argv[1][1] != '\0') {
                   4062:                fprintf(stderr, "Unknown option *%s*.\n", argv[1]);
                   4063:            }
                   4064:        }
                   4065:        argc--;
                   4066:        argv++;
                   4067:     }
                   4068:     if (argc != 1) {
                   4069:        if (setjmp(toplevel) != 0)
                   4070:            Exit(0);
                   4071:        tn(argc, argv);
                   4072:     }
                   4073:     setjmp(toplevel);
                   4074:     for (;;) {
                   4075: #if    !defined(TN3270)
                   4076:        command(1);
                   4077: #else  /* !defined(TN3270) */
                   4078:        if (!shell_active) {
                   4079:            command(1);
                   4080:        } else {
                   4081: #if    defined(TN3270)
                   4082:            shell_continue();
                   4083: #endif /* defined(TN3270) */
                   4084:        }
                   4085: #endif /* !defined(TN3270) */
                   4086:     }
                   4087: }

unix.superglobalmegacorp.com

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