Don't complain if !-escape entered, but no API using command is run.
[unix-history] / usr / src / usr.bin / tn3270 / telnet.c
index 2f4e860..4020ef7 100644 (file)
@@ -1,33 +1,24 @@
 /*
 /*
- *     Copyright (c) 1984, 1985, 1986 by the Regents of the
- *     University of California and by Gregory Glenn Minshall.
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
  *
  *
- *     Permission to use, copy, modify, and distribute these
- *     programs and their documentation for any purpose and
- *     without fee is hereby granted, provided that this
- *     copyright and permission appear on all copies and
- *     supporting documentation, the name of the Regents of
- *     the University of California not be used in advertising
- *     or publicity pertaining to distribution of the programs
- *     without specific prior permission, and notice be given in
- *     supporting documentation that copying and distribution is
- *     by permission of the Regents of the University of California
- *     and by Gregory Glenn Minshall.  Neither the Regents of the
- *     University of California nor Gregory Glenn Minshall make
- *     representations about the suitability of this software
- *     for any purpose.  It is provided "as is" without
- *     express or implied warranty.
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of California at Berkeley. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1984, 1985, 1986 Regents of the University of California.\n\
+char copyright[] =
+"@(#) Copyright (c) 1988 Regents of the University of California.\n\
  All rights reserved.\n";
  All rights reserved.\n";
-#endif /* not lint */
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)telnet.c   3.1  10/29/86";
-#endif /* not lint */
+static char sccsid[] = "@(#)telnet.c   1.18.1.1 (Berkeley) %G%";
+#endif /* not lint */
 
 /*
  * User telnet program, modified for use by tn3270.c.
 
 /*
  * User telnet program, modified for use by tn3270.c.
@@ -43,8 +34,6 @@ static char sccsid[] = "@(#)telnet.c  3.1  10/29/86";
  *
  *     TN3270          -       This is to be linked with tn3270.
  *
  *
  *     TN3270          -       This is to be linked with tn3270.
  *
- *     DEBUG           -       Allow for some extra debugging operations.
- *
  *     NOT43           -       Allows the program to compile and run on
  *                             a 4.2BSD system.
  *
  *     NOT43           -       Allows the program to compile and run on
  *                             a 4.2BSD system.
  *
@@ -68,7 +57,7 @@ static char sccsid[] = "@(#)telnet.c  3.1  10/29/86";
  *
  *     unix            -       Compiles in unix specific stuff.
  *
  *
  *     unix            -       Compiles in unix specific stuff.
  *
- *     msdos           -       Compiles in msdos specific stuff.
+ *     MSDOS           -       Compiles in MSDOS specific stuff.
  *
  */
 
  *
  */
 
@@ -81,13 +70,22 @@ void        setcommandmode(), command();    /* forward declarations */
 #endif /* !defined(TN3270) */
 
 #include <sys/types.h>
 #endif /* !defined(TN3270) */
 
 #include <sys/types.h>
+
+#if     defined(pyr)
+#define fd_set fdset_t
+#endif  /* defined(pyr) */
 #include <sys/socket.h>
 #include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
 
 #include <netinet/in.h>
 
 
 #include <netinet/in.h>
 
+#if    defined(unix)
+/* By the way, we need to include curses.h before telnet.h since,
+ * among other things, telnet.h #defines 'DO', which is a variable
+ * declared in curses.h.
+ */
 #include <curses.h>
 #include <curses.h>
+#endif /* defined(unix) */
 
 #define        TELOPTS
 #include <arpa/telnet.h>
 
 #define        TELOPTS
 #include <arpa/telnet.h>
@@ -102,20 +100,27 @@ extern char       *inet_ntoa();
 #include <stdio.h>
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <errno.h>
-#include <signal.h>
 #include <setjmp.h>
 #include <netdb.h>
 #include <setjmp.h>
 #include <netdb.h>
+
+#if    defined(unix)
 #include <strings.h>
 #include <strings.h>
+#else  /* defined(unix) */
+#include <string.h>
+#endif /* defined(unix) */
 
 #if    defined(TN3270)
 
 #if    defined(TN3270)
+#include "ascii/termin.ext"
 #include "ctlr/screen.h"
 #include "ctlr/screen.h"
-#include "system/globals.h"
-#include "telnet.ext"
+#include "ctlr/oia.h"
 #include "ctlr/options.ext"
 #include "ctlr/outbound.ext"
 #include "ctlr/options.ext"
 #include "ctlr/outbound.ext"
-#include "keyboard/termin.ext"
+#include "general/globals.h"
+#include "telnet.ext"
 #endif /* defined(TN3270) */
 
 #endif /* defined(TN3270) */
 
+#include "general/general.h"
+
 
 
 #ifndef        FD_SETSIZE
 
 
 #ifndef        FD_SETSIZE
@@ -202,7 +207,10 @@ static int
        ISend,          /* trying to send network data in */
        debug = 0,
        crmod,
        ISend,          /* trying to send network data in */
        debug = 0,
        crmod,
-       netdata,
+       netdata,        /* Print out network data flow */
+       crlf,           /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+       noasynch = 0,   /* User specified "-noasynch" on command line */
+       askedSGA = 0,   /* We have talked about suppress go ahead */
        telnetport = 1;
 
 static FILE    *NetTrace = 0;          /* Not in bss, since needs to stay */
        telnetport = 1;
 
 static FILE    *NetTrace = 0;          /* Not in bss, since needs to stay */
@@ -220,8 +228,10 @@ static int
        autoflush = 0,          /* flush output when interrupting? */
        autosynch,              /* send interrupt characters with SYNCH? */
        localchars,             /* we recognize interrupt/quit */
        autoflush = 0,          /* flush output when interrupting? */
        autosynch,              /* send interrupt characters with SYNCH? */
        localchars,             /* we recognize interrupt/quit */
-       donelclchars,   /* the user has set "localchars" */
-       dontlecho;              /* do we suppress local echoing right now? */
+       donelclchars,           /* the user has set "localchars" */
+       donebinarytoggle,       /* the user has put us in binary */
+       dontlecho,              /* do we suppress local echoing right now? */
+       globalmode;
 
 /*     The following are some tn3270 specific flags */
 #if    defined(TN3270)
 
 /*     The following are some tn3270 specific flags */
 #if    defined(TN3270)
@@ -231,59 +241,822 @@ static int
 
 /* Some real, live, globals. */
 int
 
 /* Some real, live, globals. */
 int
-#if    defined(unix)
-       HaveInput,              /* There is input available to scan */
-#endif /* defined(unix) */
        tout,                   /* Output file descriptor */
        tin;                    /* Input file descriptor */
        tout,                   /* Output file descriptor */
        tin;                    /* Input file descriptor */
-#if    defined(unix)
-char   *transcom = 0;  /* transparent mode command (default: none) */
-#endif /* defined(unix) */
 
 #else  /* defined(TN3270) */
 static int tin, tout;          /* file descriptors */
 #endif /* defined(TN3270) */
 
 
 #else  /* defined(TN3270) */
 static int tin, tout;          /* file descriptors */
 #endif /* defined(TN3270) */
 
+
+/*
+ * Telnet receiver states for fsm
+ */
+#define        TS_DATA         0
+#define        TS_IAC          1
+#define        TS_WILL         2
+#define        TS_WONT         3
+#define        TS_DO           4
+#define        TS_DONT         5
+#define        TS_CR           6
+#define        TS_SB           7               /* sub-option collection */
+#define        TS_SE           8               /* looking for sub-option end */
+
+static int     telrcv_state = TS_DATA;
+
 static char    line[200];
 static char    line[200];
-#if    defined(TN3270) && defined(unix)
-static char    tline[200];
-#endif /* defined(TN3270) && defined(unix) */
 static int     margc;
 static char    *margv[20];
 
 static int     margc;
 static char    *margv[20];
 
-static jmp_buf toplevel = 0;
-static jmp_buf peerdied;
+static jmp_buf toplevel = { 0 };
+static jmp_buf peerdied;
+
+extern int errno;
+
+
+static struct sockaddr_in sin;
+
+static struct  servent *sp = 0;
+
+static int     flushline;
+
+static char    *hostname;
+static char    hnamebuf[32];
+
+/*
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
+ */
+
+static struct {
+    int
+       system,                 /* what the current time is */
+       echotoggle,             /* last time user entered echo character */
+       modenegotiated,         /* last time operating mode negotiated */
+       didnetreceive,          /* last time we read data from network */
+       gotDM;                  /* when did we last see a data mark */
+} clocks;
+
+#define        settimer(x)     clocks.x = clocks.system++
+\f
+/*     Various modes */
+#define        MODE_LINE(m)    (modelist[m].modetype & LINE)
+#define        MODE_LOCAL_CHARS(m)     (modelist[m].modetype &  LOCAL_CHARS)
+#define        MODE_LOCAL_ECHO(m)      (modelist[m].modetype & LOCAL_ECHO)
+#define        MODE_COMMAND_LINE(m)    (modelist[m].modetype & COMMAND_LINE)
+
+#define        LOCAL_CHARS     0x01            /* Characters processed locally */
+#define        LINE            0x02            /* Line-by-line mode of operation */
+#define        LOCAL_ECHO      0x04            /* Echoing locally */
+#define        COMMAND_LINE    0x08            /* Command line mode */
+
+static struct {
+    char *modedescriptions;
+    char modetype;
+} modelist[] = {
+       { "telnet command mode", COMMAND_LINE },
+       { "character-at-a-time mode", 0 },
+       { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
+       { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
+       { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
+       { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
+       { "3270 mode", 0 },
+};
+
+\f
+/*
+ * The following routines try to encapsulate what is system dependent
+ * (at least between 4.x and dos) which is used in telnet.c.
+ */
+
+#if    defined(unix)
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <signal.h>
+
+int
+       HaveInput;              /* There is input available to scan */
+
+#if    defined(TN3270)
+static char    tline[200];
+char   *transcom = 0;  /* transparent mode command (default: none) */
+#endif /* defined(TN3270) */
+
+static struct  tchars otc = { 0 }, ntc = { 0 };
+static struct  ltchars oltc = { 0 }, nltc = { 0 };
+static struct  sgttyb ottyb = { 0 }, nttyb = { 0 };
+
+
+#define        TerminalWrite(fd,buf,n) write(fd,buf,n)
+#define        TerminalRead(fd,buf,n)  read(fd,buf,n)
+
+/*
+ *
+ */
+
+static int
+TerminalAutoFlush()                                    /* unix */
+{
+#if    defined(LNOFLSH)
+    ioctl(0, TIOCLGET, (char *)&autoflush);
+    return !(autoflush&LNOFLSH);       /* if LNOFLSH, no autoflush */
+#else  /* LNOFLSH */
+    return 1;
+#endif /* LNOFLSH */
+}
+
+/*
+ * TerminalSpecialChars()
+ *
+ * Look at an input character to see if it is a special character
+ * and decide what to do.
+ *
+ * Output:
+ *
+ *     0       Don't add this character.
+ *     1       Do add this character
+ */
+
+int
+TerminalSpecialChars(c)                        /* unix */
+int    c;
+{
+    void doflush(), intp(), sendbrk();
+
+    if (c == ntc.t_intrc) {
+       intp();
+       return 0;
+    } else if (c == ntc.t_quitc) {
+       sendbrk();
+       return 0;
+    } else if (c == nltc.t_flushc) {
+       NET2ADD(IAC, AO);
+       if (autoflush) {
+           doflush();
+       }
+       return 0;
+    } else if (!MODE_LOCAL_CHARS(globalmode)) {
+       if (c == nttyb.sg_kill) {
+           NET2ADD(IAC, EL);
+           return 0;
+       } else if (c == nttyb.sg_erase) {
+           NET2ADD(IAC, EC);
+           return 0;
+       }
+    }
+    return 1;
+}
+
+
+/*
+ * Flush output to the terminal
+ */
+static void
+TerminalFlushOutput()                          /* unix */
+{
+    (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
+}
+
+static void
+TerminalSaveState()                            /* unix */
+{
+    ioctl(0, TIOCGETP, (char *)&ottyb);
+    ioctl(0, TIOCGETC, (char *)&otc);
+    ioctl(0, TIOCGLTC, (char *)&oltc);
+
+    ntc = otc;
+    nltc = oltc;
+    nttyb = ottyb;
+}
+
+static void
+TerminalRestoreState()                         /* unix */
+{
+}
+
+/*
+ * TerminalNewMode - set up terminal to a specific mode.
+ */
+
+
+static void
+TerminalNewMode(f)                                     /* unix */
+register int f;
+{
+    static int prevmode = 0;
+    struct tchars *tc;
+    struct tchars tc3;
+    struct ltchars *ltc;
+    struct sgttyb sb;
+    int onoff;
+    int old;
+    struct     tchars notc2;
+    struct     ltchars noltc2;
+    static struct      tchars notc =   { -1, -1, -1, -1, -1, -1 };
+    static struct      ltchars noltc = { -1, -1, -1, -1, -1, -1 };
+
+    globalmode = f;
+    if (prevmode == f)
+       return;
+    old = prevmode;
+    prevmode = f;
+    sb = nttyb;
+
+    switch (f) {
+
+    case 0:
+       onoff = 0;
+       tc = &otc;
+       ltc = &oltc;
+       break;
+
+    case 1:            /* remote character processing, remote echo */
+    case 2:            /* remote character processing, local echo */
+    case 6:            /* 3270 mode - like 1, but with xon/xoff local */
+                   /* (might be nice to have "6" in telnet also...) */
+           sb.sg_flags |= CBREAK;
+           if ((f == 1) || (f == 6)) {
+               sb.sg_flags &= ~(ECHO|CRMOD);
+           } else {
+               sb.sg_flags |= ECHO|CRMOD;
+           }
+           sb.sg_erase = sb.sg_kill = -1;
+           if (f == 6) {
+               tc = &tc3;
+               tc3 = notc;
+                   /* get XON, XOFF characters */
+               tc3.t_startc = otc.t_startc;
+               tc3.t_stopc = otc.t_stopc;
+           } else {
+               /*
+                * If user hasn't specified one way or the other,
+                * then default to not trapping signals.
+                */
+               if (!donelclchars) {
+                   localchars = 0;
+               }
+               if (localchars) {
+                   notc2 = notc;
+                   notc2.t_intrc = ntc.t_intrc;
+                   notc2.t_quitc = ntc.t_quitc;
+                   tc = &notc2;
+               } else {
+                   tc = &notc;
+               }
+           }
+           ltc = &noltc;
+           onoff = 1;
+           break;
+    case 3:            /* local character processing, remote echo */
+    case 4:            /* local character processing, local echo */
+    case 5:            /* local character processing, no echo */
+           sb.sg_flags &= ~CBREAK;
+           sb.sg_flags |= CRMOD;
+           if (f == 4)
+               sb.sg_flags |= ECHO;
+           else
+               sb.sg_flags &= ~ECHO;
+           notc2 = ntc;
+           tc = &notc2;
+           noltc2 = oltc;
+           ltc = &noltc2;
+           /*
+            * If user hasn't specified one way or the other,
+            * then default to trapping signals.
+            */
+           if (!donelclchars) {
+               localchars = 1;
+           }
+           if (localchars) {
+               notc2.t_brkc = nltc.t_flushc;
+               noltc2.t_flushc = -1;
+           } else {
+               notc2.t_intrc = notc2.t_quitc = -1;
+           }
+           noltc2.t_suspc = escape;
+           noltc2.t_dsuspc = -1;
+           onoff = 1;
+           break;
+
+    default:
+           return;
+    }
+    ioctl(tin, TIOCSLTC, (char *)ltc);
+    ioctl(tin, TIOCSETC, (char *)tc);
+    ioctl(tin, TIOCSETP, (char *)&sb);
+#if    (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
+    ioctl(tin, FIONBIO, (char *)&onoff);
+    ioctl(tout, FIONBIO, (char *)&onoff);
+#endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
+#if    defined(TN3270)
+    if (noasynch == 0) {
+       ioctl(tin, FIOASYNC, (char *)&onoff);
+    }
+#endif /* defined(TN3270) */
+
+    if (MODE_LINE(f)) {
+       void doescape();
+
+       signal(SIGTSTP, doescape);
+    } else if (MODE_LINE(old)) {
+       signal(SIGTSTP, SIG_DFL);
+       sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
+    }
+}
+
+
+int
+NetClose(net)
+int    net;
+{
+    return close(net);
+}
+
+
+static void
+NetNonblockingIO(fd, onoff)                            /* unix */
+int
+       fd,
+       onoff;
+{
+    ioctl(net, FIONBIO, (char *)&onoff);
+}
+
+static void
+NetSigIO(fd, onoff)                            /* unix */
+int
+       fd,
+       onoff;
+{
+    ioctl(net, FIOASYNC, (char *)&onoff);      /* hear about input */
+}
+
+static void
+NetSetPgrp(fd)                         /* unix */
+int fd;
+{
+    int myPid;
+
+    myPid = getpid();
+#if    defined(NOT43)
+    myPid = -myPid;
+#endif /* defined(NOT43) */
+    ioctl(net, SIOCSPGRP, (char *)&myPid);     /* set my pid */
+}
+
+
+#endif /* defined(unix) */
+\f
+#if    defined(MSDOS)
+#include <time.h>
+#include <signal.h>
+#include <process.h>
+#include <fcntl.h>
+#include <io.h>
+#include <dos.h>
+
+#if    !defined(SO_OOBINLINE)
+#define        SO_OOBINLINE
+#endif /* !defined(SO_OOBINLINE) */
+
+
+static char
+    termEofChar,
+    termEraseChar,
+    termFlushChar,
+    termIntChar,
+    termKillChar,
+    termLiteralNextChar,
+    termQuitChar;
+
+static char
+    savedInState, savedOutState;
+\f
+/*
+ * MSDOS doesn't have anyway of deciding whether a full-edited line
+ * is ready to be read in, so we need to do character-by-character
+ * reads, and then do the editing in the program (in the case where
+ * we are supporting line-by-line mode).
+ *
+ * The following routines, which are internal to the MSDOS-specific
+ * code, accomplish this miracle.
+ */
+
+#define Hex(c) HEX[(c)&0xff]
+
+static survivorSetup = 0;              /* Do we have ^C hooks in? */
+
+static int
+       lineend = 0,            /* There is a line terminator */
+       ctrlCCount = 0;
+
+static char    linein[200],            /* Where input line is assembled */
+               *nextin = linein,       /* Next input character */
+               *nextout = linein;      /* Next character to be consumed */
+
+#define consumechar() \
+    if ((++nextout) >= nextin) { \
+       nextout = nextin = linein; \
+       lineend = 0; \
+    }
+
+#define        characteratatime()      (!MODE_LINE(globalmode))        /* one by one */
+
+
+/*
+ * killone()
+ *
+ *  Erase the last character on the line.
+ */
+
+static void
+killone()
+{
+    if (lineend) {
+       return;                 /* ??? XXX */
+    }
+    if (nextin == linein) {
+       return;                 /* Nothing to do */
+    }
+    nextin--;
+    if (!(isspace(*nextin) || isprint(*nextin))) {
+       putchar('\b');
+       putchar(' ');
+       putchar('\b');
+    }
+    putchar('\b');
+    putchar(' ');
+    putchar('\b');
+}
+
+
+/*
+ * setlineend()
+ *
+ *  Decide if it's time to send the current line up to the user
+ * process.
+ */
+
+static void
+setlineend()
+{
+    if (nextin == nextout) {
+       return;
+    }
+    if (characteratatime()) {
+       lineend = 1;
+    } else if (nextin >= (linein+sizeof linein)) {
+       lineend = 1;
+    } else {
+       int c = *(nextin-1);
+       if ((c == termIntChar)
+               || (c == termQuitChar)
+               || (c == termEofChar)) {
+           lineend = 1;
+       } else if (c == termFlushChar) {
+           lineend = 1;
+       } else if ((c == '\n') || (c == '\r')) {
+           lineend = 1;
+       }
+    }
+    /* Otherwise, leave it alone (reset by 'consumechar') */
+}
+
+/*
+ * OK, what we do here is:
+ *
+ *   o  If we are echoing, then
+ *     o  Look for character erase, line kill characters
+ *     o  Echo the character (using '^' if a control character)
+ *   o  Put the character in the input buffer
+ *   o  Set 'lineend' as necessary
+ */
+
+static void
+DoNextChar(c)
+int    c;                      /* Character to process */
+{
+    static char literalnextcharacter = 0;
+
+    if (nextin >= (linein+sizeof linein)) {
+       putchar('\7');          /* Ring bell */
+       setlineend();
+       return;
+    }
+    if (MODE_LOCAL_CHARS(globalmode)) {
+       /* Look for some special character */
+       if (!literalnextcharacter) {
+           if (c == termEraseChar) {
+               killone();
+               setlineend();
+               return;
+           } else if (c == termKillChar) {
+               while (nextin != linein) {
+                   killone();
+               }
+               setlineend();
+               return;
+           } else if (c == termLiteralNextChar) {
+               literalnextcharacter = 1;
+               return;
+           }
+       }
+
+       if (MODE_LOCAL_ECHO(globalmode)) {
+           if ((literalnextcharacter == 0) && ((c == '\r') || (c == '\n'))) {
+               putchar('\r');
+               putchar('\n');
+               c = '\n';
+           } else if (!isprint(c) && !isspace(c)) {
+               putchar('^');
+               putchar(c^0x40);
+           } else {
+               putchar(c);
+           }
+       }
+       literalnextcharacter = 0;
+    }
+    *nextin++ = c;
+    setlineend();
+}
+
+static int
+inputExists()
+{
+    int input;
+    static state = 0;
+
+    while (ctrlCCount) {
+       DoNextChar(0x03);
+       ctrlCCount--;
+    }
+    if (lineend) {
+       return 1;
+    }
+#if    1       /* For BIOS variety of calls */
+    if (kbhit() == 0) {
+       return lineend;
+    }
+    input = getch();                   /* MSC - get console character */
+    if ((input&0xff) == 0) {
+       DoNextChar(0x01);               /* ^A */
+    } else {
+       DoNextChar(input&0xff);
+    }
+#else  /* 0 */
+    if ((input = dirconio()) == -1) {
+       return lineend;
+    }
+    if ((input&0xff) == 0) {
+       if ((input&0xff00) == 0x0300) {         /* Null */
+           DoNextChar(0);
+       } else {
+           DoNextChar(0x01);
+           if (input&0x8000) {
+               DoNextChar(0x01);
+               DoNextChar((input>>8)&0x7f);
+           } else {
+               DoNextChar((input>>8)&0xff);
+           }
+       }
+    } else {
+       DoNextChar(input&0xff);
+    }
+#endif /* 0 */
+    return lineend;
+}
+
+
+void
+CtrlCInterrupt()
+{
+    if (!MODE_COMMAND_LINE(globalmode)) {
+       char far *Bios_Break = (char far *) (((long)0x40<<16)|0x71);
+
+       *Bios_Break = 0;
+       ctrlCCount++;           /* XXX */
+       signal(SIGINT, CtrlCInterrupt);
+    } else {
+       closeallsockets();
+       exit(1);
+    }
+}
+
+int
+dosbinary(fd, onoff)
+int    fd;
+int    onoff;
+{
+    union REGS regs;
+    int oldstate;
+
+    /* Get old stuff */
+    regs.h.ah = 0x44;
+    regs.h.al = 0;
+    regs.x.bx = fd;
+    intdos(&regs, &regs);
+    oldstate = regs.h.dl&(1<<5);               /* Save state */
+
+    /* Set correct bits in new mode */
+    regs.h.dh = 0;
+    if (onoff) {
+       regs.h.dl |= 1<<5;
+    } else {
+       regs.h.dl &= ~(1<<5);
+    }
+
+    /* Set in new mode */
+    regs.h.ah = 0x44;
+    regs.h.al = 1;
+    regs.x.bx = fd;
+    intdos(&regs, &regs);
+
+    return oldstate;
+}
+\f
+/*
+ * The MSDOS routines, called from elsewhere.
+ */
+
+
+static int
+TerminalAutoFlush()                            /* MSDOS */
+{
+    return 1;
+}
+
+static int
+TerminalCanRead()
+{
+    return inputExists();
+}
+
+
+/*
+ * Flush output to the terminal
+ */
+static void
+TerminalFlushOutput()                          /* MSDOS */
+{
+}
+
+
+static void
+TerminalNewMode(f)                             /* MSDOS */
+register int f;
+{
+    union REGS inregs;
+    struct SREGS segregs;
+    static old_1b_offset = 0, old_1b_segment = 0;
+
+    globalmode = f;
+    if (MODE_COMMAND_LINE(f)) {
+       signal(SIGINT, SIG_DFL);
+       if (old_1b_segment|old_1b_offset) {
+           inregs.h.ah = 0x25;
+           inregs.h.al = 0x1b;
+           inregs.x.dx = old_1b_offset;
+           segregs.ds = old_1b_segment;
+           intdosx(&inregs, &inregs, &segregs);
+           old_1b_segment = old_1b_offset = 0;
+       }
+       if (setmode(fileno(stdout), O_TEXT) == -1) {
+           ExitPerror("setmode (text)", 1);
+       }
+       (void) dosbinary(fileno(stdout), 0);
+       if (setmode(fileno(stdin), O_TEXT) == -1) {
+           ExitPerror("setmode (text)", 1);
+       }
+       (void) dosbinary(fileno(stdin), 0);
+    } else {
+       signal(SIGINT, CtrlCInterrupt);
+       if ((old_1b_segment|old_1b_offset) == 0) {
+           extern void iret_subr();
+           void (far *foo_subr)() = iret_subr;
+
+           inregs.h.ah = 0x35;
+           inregs.h.al = 0x1b;
+           intdosx(&inregs, &inregs, &segregs);
+           old_1b_segment = segregs.es;
+           old_1b_offset = inregs.x.bx;
+           inregs.h.ah = 0x25;
+           inregs.h.al = 0x1b;
+           inregs.x.dx = FP_OFF(foo_subr);
+           segregs.ds = FP_SEG(foo_subr);
+           intdosx(&inregs, &inregs, &segregs);
+       }
+       if (MODE_LOCAL_CHARS(f)) {
+           if (setmode(fileno(stdout), O_TEXT) == -1) {
+               ExitPerror("setmode (text)", 1);
+           }
+           (void) dosbinary(fileno(stdout), 0);
+           if (setmode(fileno(stdin), O_TEXT) == -1) {
+               ExitPerror("setmode (text)", 1);
+           }
+           (void) dosbinary(fileno(stdin), 0);
+       } else {
+           if (setmode(fileno(stdout), O_BINARY) == -1) {
+               ExitPerror("setmode (binary)", 1);
+           }
+           (void) dosbinary(fileno(stdout), 1);
+           if (setmode(fileno(stdin), O_BINARY) == -1) {
+               ExitPerror("setmode (binary)", 1);
+           }
+           (void) dosbinary(fileno(stdin), 1);
+       }
+    }
+}
+
+
+int
+TerminalRead(fd, buffer, count)
+int    fd;
+char   *buffer;
+int    count;
+{
+    int done = 0;
+
+    for (;;) {
+       while (inputExists() && (done < count)) {
+           *buffer++ = *nextout;
+           consumechar();
+           done++;
+       }
+       if (done) {
+           return(done);
+       } else {
+           return 0;
+       }
+    }
+}
+
+
+static void
+TerminalSaveState()                            /* MSDOS */
+{
+    savedInState = dosbinary(fileno(stdin), 0);
+    savedOutState = dosbinary(fileno(stdout), 0);
+}
+
+int
+TerminalSpecialChars(c)                        /* MSDOS */
+{
+    return 1;
+}
+
 
 
-extern int errno;
+static void
+TerminalRestoreState()                         /* MSDOS */
+{
+    (void) dosbinary(fileno(stdin), savedInState);
+    (void) dosbinary(fileno(stdout), savedOutState);
+}
 
 
 
 
-static struct sockaddr_in sin;
+static int
+TerminalWrite(fd, buffer, count)               /* MSDOS */
+int    fd;
+char   *buffer;
+int    count;
+{
+    return fwrite(buffer, sizeof (char), count, stdout);
+}
 
 
-static struct  servent *sp = 0;
 
 
-static struct  tchars otc = { 0 }, ntc = { 0 };
-static struct  ltchars oltc = { 0 }, nltc = { 0 };
-static struct  sgttyb ottyb = { 0 }, nttyb = { 0 };
-static int     flushline;
+static int
+NetClose(fd)
+{
+    return closesocket(fd);
+}
 
 
-static char    *hostname;
-static char    hnamebuf[32];
+static void
+NetNonblockingIO(fd, onoff)                            /* MSDOS */
+int
+       fd,
+       onoff;
+{
+    if (SetSockOpt(net, SOL_SOCKET, SO_NONBLOCKING, onoff)) {
+       perror("setsockop (SO_NONBLOCKING) ");
+       ExitString(stderr, "exiting\n", 1);
+    }
+}
 
 
-/*
- * The following are some clocks used to decide how to interpret
- * the relationship between various variables.
- */
+static void
+NetSigIO(fd)                           /* MSDOS */
+int fd;
+{
+}
 
 
-static struct {
-    int
-       system,                 /* what the current time is */
-       echotoggle,             /* last time user entered echo character */
-       modenegotiated,         /* last time operating mode negotiated */
-       didnetreceive,          /* last time we read data from network */
-       gotDM;                  /* when did we last see a data mark */
-} clocks;
+static void
+NetSetPgrp(fd)                         /* MSDOS */
+int fd;
+{
+}
 
 
-#define        settimer(x)     clocks.x = clocks.system++
+
+#endif /* defined(MSDOS) */
 \f
 /*
  * Initialize variables.
 \f
 /*
  * Initialize variables.
@@ -292,14 +1065,32 @@ static struct {
 static void
 tninit()
 {
 static void
 tninit()
 {
-    extern char edata, end;
-
-    bzero(&edata, &end - &edata);
+#if    defined(TN3270)
+    Sent3270TerminalType = 0;
     Ifrontp = Ibackp = Ibuf;
     Ifrontp = Ibackp = Ibuf;
+#endif /* defined(TN3270) */
+
     tfrontp = tbackp = ttyobuf;
     nfrontp = nbackp = netobuf;
     
     /* Don't change telnetport */
     tfrontp = tbackp = ttyobuf;
     nfrontp = nbackp = netobuf;
     
     /* Don't change telnetport */
+    SB_CLEAR();
+    ClearArray(hisopts);
+    ClearArray(myopts);
+    sbp = sibuf;
+    tbp = tibuf;
+
+    connected = net = scc = tcc = In3270 = ISend = donebinarytoggle = 0;
+    telnetport = 0;
+#if    defined(unix)
+    HaveInput = 0;
+#endif /* defined(unix) */
+
+    SYNCHing = 0;
+
+    errno = 0;
+
+    flushline = 0;
 
     /* Don't change NetTrace */
 
 
     /* Don't change NetTrace */
 
@@ -314,8 +1105,10 @@ tninit()
     }
 
 #if    defined(TN3270)
     }
 
 #if    defined(TN3270)
-    terminit();
-    ctlrinit();
+    init_ctlr();               /* Initialize some things */
+    init_keyboard();
+    init_screen();
+    init_system();
 #endif /* defined(TN3270) */
 }
 \f
 #endif /* defined(TN3270) */
 }
 \f
@@ -326,24 +1119,30 @@ tninit()
 static void
 makeargv()
 {
 static void
 makeargv()
 {
-       register char *cp;
-       register char **argp = margv;
+    register char *cp;
+    register char **argp = margv;
 
 
-       margc = 0;
-       for (cp = line; *cp;) {
-               while (isspace(*cp))
-                       cp++;
-               if (*cp == '\0')
-                       break;
-               *argp++ = cp;
-               margc += 1;
-               while (*cp != '\0' && !isspace(*cp))
-                       cp++;
-               if (*cp == '\0')
-                       break;
-               *cp++ = '\0';
-       }
-       *argp++ = 0;
+    margc = 0;
+    cp = line;
+    if (*cp == '!') {          /* Special case shell escape */
+       *argp++ = "!";          /* No room in string to get this */
+       margc++;
+       cp++;
+    }
+    while (*cp) {
+       while (isspace(*cp))
+           cp++;
+       if (*cp == '\0')
+           break;
+       *argp++ = cp;
+       margc += 1;
+       while (*cp != '\0' && !isspace(*cp))
+           cp++;
+       if (*cp == '\0')
+           break;
+       *cp++ = '\0';
+    }
+    *argp++ = 0;
 }
 
 static char *ambiguous;                /* special return value */
 }
 
 static char *ambiguous;                /* special return value */
@@ -360,6 +1159,9 @@ char       **(*next)();    /* routine to return next entry in table */
        register char **c, **found;
        register int nmatches, longest;
 
        register char **c, **found;
        register int nmatches, longest;
 
+       if (name == 0) {
+           return 0;
+       }
        longest = 0;
        nmatches = 0;
        found = 0;
        longest = 0;
        nmatches = 0;
        found = 0;
@@ -457,6 +1259,33 @@ register char *argument;
        argument++;
     }
 }
        argument++;
     }
 }
+
+/*
+ * SetSockOpt()
+ *
+ * Compensate for differences in 4.2 and 4.3 systems.
+ */
+
+static int
+SetSockOpt(fd, level, option, yesno)
+int
+       fd,
+       level,
+       option,
+       yesno;
+{
+#ifndef        NOT43
+    return setsockopt(fd, level, option,
+                               (char *)&yesno, sizeof yesno);
+#else  /* NOT43 */
+    if (yesno == 0) {          /* Can't do that in 4.2! */
+       fprintf(stderr, "Error: attempt to turn off an option 0x%x.\n",
+                               option);
+       return -1;
+    }
+    return setsockopt(fd, level, option, 0, 0);
+#endif /* NOT43 */
+}
 \f
 /*
  * The following are routines used to print out debugging information.
 \f
 /*
  * The following are routines used to print out debugging information.
@@ -542,10 +1371,10 @@ int      length;                 /* length of suboption data */
            case TELQUAL_IS:
                {
                    char tmpbuf[sizeof subbuffer];
            case TELQUAL_IS:
                {
                    char tmpbuf[sizeof subbuffer];
-                   int minlen = min(length, sizeof tmpbuf);
+                   int minlen = min(length-4, sizeof tmpbuf-1);
 
 
-                   bcopy(pointer+2, tmpbuf, minlen);
-                   tmpbuf[minlen-1] = 0;
+                   memcpy(tmpbuf, pointer+2, minlen);
+                   tmpbuf[minlen] = 0;
                    fprintf(NetTrace, "is %s.\n", tmpbuf);
                }
                break;
                    fprintf(NetTrace, "is %s.\n", tmpbuf);
                }
                break;
@@ -612,7 +1441,7 @@ netflush()
 
     if ((n = nfrontp - nbackp) > 0) {
        if (!neturg) {
 
     if ((n = nfrontp - nbackp) > 0) {
        if (!neturg) {
-           n = write(net, nbackp, n);  /* normal write */
+           n = send(net, nbackp, n, 0);        /* normal write */
        } else {
            n = neturg - nbackp;
            /*
        } else {
            n = neturg - nbackp;
            /*
@@ -634,7 +1463,7 @@ netflush()
        if (errno != ENOBUFS && errno != EWOULDBLOCK) {
            setcommandmode();
            perror(hostname);
        if (errno != ENOBUFS && errno != EWOULDBLOCK) {
            setcommandmode();
            perror(hostname);
-           close(net);
+           NetClose(net);
            neturg = 0;
            longjmp(peerdied, -1);
            /*NOTREACHED*/
            neturg = 0;
            longjmp(peerdied, -1);
            /*NOTREACHED*/
@@ -738,7 +1567,7 @@ netclear()
                next = nextitem(next);
            } while (wewant(next) && (nfrontp > next));
            length = next-thisitem;
                next = nextitem(next);
            } while (wewant(next) && (nfrontp > next));
            length = next-thisitem;
-           bcopy(thisitem, good, length);
+           memcpy(good, thisitem, length);
            good += length;
            thisitem = next;
        } else {
            good += length;
            thisitem = next;
        } else {
@@ -822,9 +1651,9 @@ ttyflush()
 
     if ((n = tfrontp - tbackp) > 0) {
        if (!(SYNCHing||flushout)) {
 
     if ((n = tfrontp - tbackp) > 0) {
        if (!(SYNCHing||flushout)) {
-           n = write(tout, tbackp, n);
+           n = TerminalWrite(tout, tbackp, n);
        } else {
        } else {
-           ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
+           TerminalFlushOutput();
            /* we leave 'n' alone! */
        }
     }
            /* we leave 'n' alone! */
        }
     }
@@ -841,220 +1670,64 @@ ttyflush()
 
 #if    defined(unix)
 static void
 
 #if    defined(unix)
 static void
-inputAvailable()
-{
-    HaveInput = 1;
-}
-#endif /* defined(unix) */
-
-void
-outputPurge()
-{
-    int tmp = flushout;
-
-    flushout = 1;
-
-    ttyflush();
-
-    flushout = tmp;
-}
-
-#endif /* defined(TN3270) */
-\f
-#if    defined(unix)
-/*
- * Various signal handling routines.
- */
-
-static void
-deadpeer()
-{
-       setcommandmode();
-       longjmp(peerdied, -1);
-}
-
-static void
-intr()
-{
-    if (localchars) {
-       intp();
-       return;
-    }
-    setcommandmode();
-    longjmp(toplevel, -1);
-}
-
-static void
-intr2()
-{
-    if (localchars) {
-       sendbrk();
-       return;
-    }
-}
-
-static void
-doescape()
-{
-    command(0);
-}
-#endif /* defined(unix) */
-\f
-static int     globalmode = 0;
-/*     Various modes */
-#define        MODE_LINE(m)    (modelist[m].modetype & LINE)
-#define        MODE_LOCAL_CHARS(m)     (modelist[m].modetype &  LOCAL_CHARS)
-
-#define        LOCAL_CHARS     0x01            /* Characters processed locally */
-#define        LINE            0x02            /* Line-by-line mode of operation */
-
-static struct {
-    char *modedescriptions;
-    char modetype;
-} modelist[] = {
-       { "telnet command mode", 0 },
-       { "character-at-a-time mode", 0 },
-       { "character-at-a-time mode (local echo)", LOCAL_CHARS },
-       { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
-       { "line-by-line mode", LINE | LOCAL_CHARS },
-       { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
-       { "3270 mode", 0 },
-};
-/*
- * Mode - set up terminal to a specific mode.
- */
-
-
-static void
-mode(f)
-       register int f;
-{
-    static int prevmode = 0;
-    struct tchars *tc;
-    struct tchars tc3;
-    struct ltchars *ltc;
-    struct sgttyb sb;
-    int onoff;
-#if    defined(unix)
-    int old;
-#endif /* defined(unix) */
-    struct     tchars notc2;
-    struct     ltchars noltc2;
-    static struct      tchars notc =   { -1, -1, -1, -1, -1, -1 };
-    static struct      ltchars noltc = { -1, -1, -1, -1, -1, -1 };
-
-    globalmode = f;
-    if (prevmode == f)
-       return;
-#if    defined(unix)
-    old = prevmode;
-#endif /* defined(unix) */
-    prevmode = f;
-    sb = nttyb;
-
-    switch (f) {
-
-    case 0:
-       onoff = 0;
-       tc = &otc;
-       ltc = &oltc;
-       break;
-
-    case 1:            /* remote character processing, remote echo */
-    case 2:            /* remote character processing, local echo */
-    case 6:            /* 3270 mode - like 1, but with xon/xoff local */
-                   /* (might be nice to have "6" in telnet also...) */
-           sb.sg_flags |= CBREAK;
-           if ((f == 1) || (f == 6)) {
-               sb.sg_flags &= ~(ECHO|CRMOD);
-           } else {
-               sb.sg_flags |= ECHO|CRMOD;
-           }
-           sb.sg_erase = sb.sg_kill = -1;
-           if (f == 6) {
-               tc = &tc3;
-               tc3 = notc;
-                   /* get XON, XOFF characters */
-               tc3.t_startc = otc.t_startc;
-               tc3.t_stopc = otc.t_stopc;
-           } else {
-               /*
-                * If user hasn't specified one way or the other,
-                * then default to not trapping signals.
-                */
-               if (!donelclchars) {
-                   localchars = 0;
-               }
-               if (localchars) {
-                   notc2 = notc;
-                   notc2.t_intrc = ntc.t_intrc;
-                   notc2.t_quitc = ntc.t_quitc;
-                   tc = &notc2;
-               } else {
-                   tc = &notc;
-               }
-           }
-           ltc = &noltc;
-           onoff = 1;
-           break;
-    case 3:            /* local character processing, remote echo */
-    case 4:            /* local character processing, local echo */
-    case 5:            /* local character processing, no echo */
-           sb.sg_flags &= ~CBREAK;
-           sb.sg_flags |= CRMOD;
-           if (f == 4)
-               sb.sg_flags |= ECHO;
-           else
-               sb.sg_flags &= ~ECHO;
-           notc2 = ntc;
-           tc = &notc2;
-           noltc2 = oltc;
-           ltc = &noltc2;
-#if defined(unix)
-           /*
-            * If user hasn't specified one way or the other,
-            * then default to trapping signals.
-            */
-           if (!donelclchars) {
-               localchars = 1;
-           }
-           if (localchars) {
-               notc2.t_brkc = nltc.t_flushc;
-               noltc2.t_flushc = -1;
-           } else {
-               notc2.t_intrc = notc2.t_quitc = -1;
-           }
-#else  /* defined(unix) */
-           notc2.t_intrc = -1;
+inputAvailable()
+{
+    HaveInput = 1;
+}
 #endif /* defined(unix) */
 #endif /* defined(unix) */
-           noltc2.t_suspc = escape;
-           noltc2.t_dsuspc = -1;
-           onoff = 1;
-           break;
 
 
-    default:
-           return;
-    }
-    ioctl(tin, TIOCSLTC, (char *)ltc);
-    ioctl(tin, TIOCSETC, (char *)tc);
-    ioctl(tin, TIOCSETP, (char *)&sb);
-#if    (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
-    ioctl(tin, FIONBIO, (char *)&onoff);
-    ioctl(tout, FIONBIO, (char *)&onoff);
-#endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
-#if    defined(TN3270) && !defined(DEBUG)
-    ioctl(tin, FIOASYNC, (char *)&onoff);
-#endif /* defined(TN3270) && !defined(DEBUG) */
+void
+outputPurge()
+{
+    int tmp = flushout;
+
+    flushout = 1;
 
 
+    ttyflush();
+
+    flushout = tmp;
+}
+
+#endif /* defined(TN3270) */
+\f
 #if    defined(unix)
 #if    defined(unix)
-    if (MODE_LINE(f)) {
-       signal(SIGTSTP, doescape);
-    } else if (MODE_LINE(old)) {
-       signal(SIGTSTP, SIG_DFL);
-       sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
+/*
+ * Various signal handling routines.
+ */
+
+static void
+deadpeer()
+{
+       setcommandmode();
+       longjmp(peerdied, -1);
+}
+
+static void
+intr()
+{
+    if (localchars) {
+       intp();
+       return;
     }
     }
-#endif /* defined(unix) */
+    setcommandmode();
+    longjmp(toplevel, -1);
+}
+
+static void
+intr2()
+{
+    if (localchars) {
+       sendbrk();
+       return;
+    }
+}
+
+static void
+doescape()
+{
+    command(0);
 }
 }
+#endif /* defined(unix) */
 \f
 /*
  * These routines decides on what the mode should be (based on the values
 \f
 /*
  * These routines decides on what the mode should be (based on the values
@@ -1087,14 +1760,14 @@ getconnmode()
 void
 setconnmode()
 {
 void
 setconnmode()
 {
-    mode(getconnmode());
+    TerminalNewMode(getconnmode());
 }
 
 
 void
 setcommandmode()
 {
 }
 
 
 void
 setcommandmode()
 {
-    mode(0);
+    TerminalNewMode(0);
 }
 \f
 static void
 }
 \f
 static void
@@ -1121,8 +1794,6 @@ willoption(option, reply)
             * DO send).
             */
            {
             * DO send).
             */
            {
-               static int askedSGA = 0;
-
                if (askedSGA == 0) {
                    askedSGA = 1;
                    if (!hisopts[TELOPT_SGA]) {
                if (askedSGA == 0) {
                    askedSGA = 1;
                    if (!hisopts[TELOPT_SGA]) {
@@ -1177,6 +1848,8 @@ wontoption(option, reply)
 
        default:
                fmt = dont;
 
        default:
                fmt = dont;
+               hisopts[option] = 0;
+               break;
        }
        sprintf(nfrontp, fmt, option);
        nfrontp += sizeof (doopt) - 2;
        }
        sprintf(nfrontp, fmt, option);
        nfrontp += sizeof (doopt) - 2;
@@ -1249,18 +1922,25 @@ suboption()
             * on the format of our screen, and (in the future) color
             * capaiblities.
             */
             * on the format of our screen, and (in the future) color
             * capaiblities.
             */
-           if ((initscr() != ERR) &&   /* Initialize curses to get line size */
-               (LINES >= 24) && (COLS >= 80)) {
+#if    defined(unix)
+           if (initscr() != ERR) {     /* Initialize curses to get line size */
+               MaxNumberLines = LINES;
+               MaxNumberColumns = COLS;
+           }
+#else  /* defined(unix) */
+           InitTerminal();
+#endif /* defined(unix) */
+           if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
                Sent3270TerminalType = 1;
                Sent3270TerminalType = 1;
-               if ((LINES >= 27) && (COLS >= 132)) {
+               if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
                    MaxNumberLines = 27;
                    MaxNumberColumns = 132;
                    sb_terminal[SBTERMMODEL] = '5';
                    MaxNumberLines = 27;
                    MaxNumberColumns = 132;
                    sb_terminal[SBTERMMODEL] = '5';
-               } else if (LINES >= 43) {
+               } else if (MaxNumberLines >= 43) {
                    MaxNumberLines = 43;
                    MaxNumberColumns = 80;
                    sb_terminal[SBTERMMODEL] = '4';
                    MaxNumberLines = 43;
                    MaxNumberColumns = 80;
                    sb_terminal[SBTERMMODEL] = '4';
-               } else if (LINES >= 32) {
+               } else if (MaxNumberLines >= 32) {
                    MaxNumberLines = 32;
                    MaxNumberColumns = 80;
                    sb_terminal[SBTERMMODEL] = '3';
                    MaxNumberLines = 32;
                    MaxNumberColumns = 80;
                    sb_terminal[SBTERMMODEL] = '3';
@@ -1277,7 +1957,7 @@ suboption()
                        "Programming error:  MAXSCREENSIZE too small.\n", 1);
                    /*NOTREACHED*/
                }
                        "Programming error:  MAXSCREENSIZE too small.\n", 1);
                    /*NOTREACHED*/
                }
-               bcopy(sb_terminal, nfrontp, sizeof sb_terminal);
+               memcpy(nfrontp, sb_terminal, sizeof sb_terminal);
                printsub(">", nfrontp+2, sizeof sb_terminal-2);
                nfrontp += sizeof sb_terminal;
                return;
                printsub(">", nfrontp+2, sizeof sb_terminal-2);
                nfrontp += sizeof sb_terminal;
                return;
@@ -1312,42 +1992,32 @@ static void
 SetIn3270()
 {
     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
 SetIn3270()
 {
     if (Sent3270TerminalType && myopts[TELOPT_BINARY]
-                                       && hisopts[TELOPT_BINARY]) {
+                           && hisopts[TELOPT_BINARY] && !donebinarytoggle) {
        if (!In3270) {
            In3270 = 1;
            Init3270();         /* Initialize 3270 functions */
            /* initialize terminal key mapping */
            InitTerminal();     /* Start terminal going */
        if (!In3270) {
            In3270 = 1;
            Init3270();         /* Initialize 3270 functions */
            /* initialize terminal key mapping */
            InitTerminal();     /* Start terminal going */
+           LocalClearScreen(); /* Make sure the screen is clear */
            setconnmode();
        }
     } else {
        if (In3270) {
            StopScreen(1);
            In3270 = 0;
            setconnmode();
        }
     } else {
        if (In3270) {
            StopScreen(1);
            In3270 = 0;
+           Stop3270();         /* Tell 3270 we aren't here anymore */
            setconnmode();
        }
     }
 }
 #endif /* defined(TN3270) */
 \f
            setconnmode();
        }
     }
 }
 #endif /* defined(TN3270) */
 \f
-/*
- * Telnet receiver states for fsm
- */
-#define        TS_DATA         0
-#define        TS_IAC          1
-#define        TS_WILL         2
-#define        TS_WONT         3
-#define        TS_DO           4
-#define        TS_DONT         5
-#define        TS_CR           6
-#define        TS_SB           7               /* sub-option collection */
-#define        TS_SE           8               /* looking for sub-option end */
 
 static void
 telrcv()
 {
     register int c;
 
 static void
 telrcv()
 {
     register int c;
-    static int state = TS_DATA;
+    static int telrcv_state = TS_DATA;
 #   if defined(TN3270)
     register int Scc;
     register char *Sbp;
 #   if defined(TN3270)
     register int Scc;
     register char *Sbp;
@@ -1355,10 +2025,10 @@ telrcv()
 
     while ((scc > 0) && (TTYROOM() > 2)) {
        c = *sbp++ & 0xff, scc--;
 
     while ((scc > 0) && (TTYROOM() > 2)) {
        c = *sbp++ & 0xff, scc--;
-       switch (state) {
+       switch (telrcv_state) {
 
        case TS_CR:
 
        case TS_CR:
-           state = TS_DATA;
+           telrcv_state = TS_DATA;
            if (c == '\0') {
                break;  /* Ignore \0 after CR */
            } else if (c == '\n') {
            if (c == '\0') {
                break;  /* Ignore \0 after CR */
            } else if (c == '\n') {
@@ -1371,7 +2041,7 @@ telrcv()
 
        case TS_DATA:
            if (c == IAC) {
 
        case TS_DATA:
            if (c == IAC) {
-               state = TS_IAC;
+               telrcv_state = TS_IAC;
                continue;
            }
 #          if defined(TN3270)
                continue;
            }
 #          if defined(TN3270)
@@ -1382,7 +2052,7 @@ telrcv()
                while (Scc > 0) {
                    c = *Sbp++ & 0377, Scc--;
                    if (c == IAC) {
                while (Scc > 0) {
                    c = *Sbp++ & 0377, Scc--;
                    if (c == IAC) {
-                       state = TS_IAC;
+                       telrcv_state = TS_IAC;
                        break;
                    }
                    *Ifrontp++ = c;
                        break;
                    }
                    *Ifrontp++ = c;
@@ -1398,7 +2068,7 @@ telrcv()
                     * \n; since we must turn off CRMOD to get proper
                     * input, the mapping is done here (sigh).
                     */
                     * \n; since we must turn off CRMOD to get proper
                     * input, the mapping is done here (sigh).
                     */
-           if (c == '\r') {
+           if ((c == '\r') && !hisopts[TELOPT_BINARY]) {
                if (scc > 0) {
                    c = *sbp&0xff;
                    if (c == 0) {
                if (scc > 0) {
                    c = *sbp&0xff;
                    if (c == 0) {
@@ -1416,7 +2086,7 @@ telrcv()
                        }
                    }
                } else {
                        }
                    }
                } else {
-                   state = TS_CR;
+                   telrcv_state = TS_CR;
                    TTYADD('\r');
                    if (crmod) {
                            TTYADD('\n');
                    TTYADD('\r');
                    if (crmod) {
                            TTYADD('\n');
@@ -1431,19 +2101,19 @@ telrcv()
            switch (c) {
            
            case WILL:
            switch (c) {
            
            case WILL:
-               state = TS_WILL;
+               telrcv_state = TS_WILL;
                continue;
 
            case WONT:
                continue;
 
            case WONT:
-               state = TS_WONT;
+               telrcv_state = TS_WONT;
                continue;
 
            case DO:
                continue;
 
            case DO:
-               state = TS_DO;
+               telrcv_state = TS_DO;
                continue;
 
            case DONT:
                continue;
 
            case DONT:
-               state = TS_DONT;
+               telrcv_state = TS_DONT;
                continue;
 
            case DM:
                continue;
 
            case DM:
@@ -1464,7 +2134,7 @@ telrcv()
 
            case SB:
                SB_CLEAR();
 
            case SB:
                SB_CLEAR();
-               state = TS_SB;
+               telrcv_state = TS_SB;
                continue;
 
 #          if defined(TN3270)
                continue;
 
 #          if defined(TN3270)
@@ -1496,7 +2166,7 @@ telrcv()
            default:
                break;
            }
            default:
                break;
            }
-           state = TS_DATA;
+           telrcv_state = TS_DATA;
            continue;
 
        case TS_WILL:
            continue;
 
        case TS_WILL:
@@ -1509,7 +2179,7 @@ telrcv()
                willoption(c, 1);
            }
            SetIn3270();
                willoption(c, 1);
            }
            SetIn3270();
-           state = TS_DATA;
+           telrcv_state = TS_DATA;
            continue;
 
        case TS_WONT:
            continue;
 
        case TS_WONT:
@@ -1522,7 +2192,7 @@ telrcv()
                wontoption(c, 1);
            }
            SetIn3270();
                wontoption(c, 1);
            }
            SetIn3270();
-           state = TS_DATA;
+           telrcv_state = TS_DATA;
            continue;
 
        case TS_DO:
            continue;
 
        case TS_DO:
@@ -1530,7 +2200,7 @@ telrcv()
            if (!myopts[c])
                dooption(c);
            SetIn3270();
            if (!myopts[c])
                dooption(c);
            SetIn3270();
-           state = TS_DATA;
+           telrcv_state = TS_DATA;
            continue;
 
        case TS_DONT:
            continue;
 
        case TS_DONT:
@@ -1544,12 +2214,12 @@ telrcv()
                printoption(">SENT", wont, c, 0);
            }
            SetIn3270();
                printoption(">SENT", wont, c, 0);
            }
            SetIn3270();
-           state = TS_DATA;
+           telrcv_state = TS_DATA;
            continue;
 
        case TS_SB:
            if (c == IAC) {
            continue;
 
        case TS_SB:
            if (c == IAC) {
-               state = TS_SE;
+               telrcv_state = TS_SE;
            } else {
                SB_ACCUM(c);
            }
            } else {
                SB_ACCUM(c);
            }
@@ -1561,12 +2231,12 @@ telrcv()
                    SB_ACCUM(IAC);
                }
                SB_ACCUM(c);
                    SB_ACCUM(IAC);
                }
                SB_ACCUM(c);
-               state = TS_SB;
+               telrcv_state = TS_SB;
            } else {
                SB_TERM();
                suboption();    /* handle sub-option */
                SetIn3270();
            } else {
                SB_TERM();
                suboption();    /* handle sub-option */
                SetIn3270();
-               state = TS_DATA;
+               telrcv_state = TS_DATA;
            }
        }
     }
            }
        }
     }
@@ -1643,18 +2313,22 @@ register char   *buffer;                /* where the data is */
 register int   count;                  /* how much to send */
 {
     int origCount;
 register int   count;                  /* how much to send */
 {
     int origCount;
+#if    defined(unix)
     fd_set     o;
 
     fd_set     o;
 
-    origCount = count;
     FD_ZERO(&o);
     FD_ZERO(&o);
+#endif /* defined(unix) */
+    origCount = count;
 
     while (count) {
        if (tfrontp >= ttyobuf+sizeof ttyobuf) {
            ttyflush();
            while (tfrontp >= ttyobuf+sizeof ttyobuf) {
 
     while (count) {
        if (tfrontp >= ttyobuf+sizeof ttyobuf) {
            ttyflush();
            while (tfrontp >= ttyobuf+sizeof ttyobuf) {
+#if    defined(unix)
                FD_SET(tout, &o);
                (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
                                                (struct timeval *) 0);
                FD_SET(tout, &o);
                (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
                                                (struct timeval *) 0);
+#endif /* defined(unix) */
                ttyflush();
            }
        }
                ttyflush();
            }
        }
@@ -1672,20 +2346,26 @@ register int    count;                  /* how much to send */
 void
 EmptyTerminal()
 {
 void
 EmptyTerminal()
 {
+#if    defined(unix)
     fd_set     o;
 
     FD_ZERO(&o);
     fd_set     o;
 
     FD_ZERO(&o);
+#endif /* defined(unix) */
 
     if (tfrontp == tbackp) {
 
     if (tfrontp == tbackp) {
+#if    defined(unix)
        FD_SET(tout, &o);
        (void) select(tout+1, (int *) 0, &o, (int *) 0,
                        (struct timeval *) 0);  /* wait for TTLOWAT */
        FD_SET(tout, &o);
        (void) select(tout+1, (int *) 0, &o, (int *) 0,
                        (struct timeval *) 0);  /* wait for TTLOWAT */
+#endif /* defined(unix) */
     } else {
        while (tfrontp != tbackp) {
            ttyflush();
     } else {
        while (tfrontp != tbackp) {
            ttyflush();
+#if    defined(unix)
            FD_SET(tout, &o);
            (void) select(tout+1, (int *) 0, &o, (int *) 0,
                                (struct timeval *) 0);  /* wait for TTLOWAT */
            FD_SET(tout, &o);
            (void) select(tout+1, (int *) 0, &o, (int *) 0,
                                (struct timeval *) 0);  /* wait for TTLOWAT */
+#endif /* defined(unix) */
        }
     }
 }
        }
     }
 }
@@ -1702,7 +2382,7 @@ Push3270()
     if (scc) {
        if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
            if (Ibackp != Ibuf) {
     if (scc) {
        if (Ifrontp+scc > Ibuf+sizeof Ibuf) {
            if (Ibackp != Ibuf) {
-               bcopy(Ibackp, Ibuf, Ifrontp-Ibackp);
+               memcpy(Ibuf, Ibackp, Ifrontp-Ibackp);
                Ifrontp -= (Ibackp-Ibuf);
                Ibackp = Ibuf;
            }
                Ifrontp -= (Ibackp-Ibuf);
                Ibackp = Ibuf;
            }
@@ -1724,6 +2404,9 @@ static void
 Finish3270()
 {
     while (Push3270() || !DoTerminalOutput()) {
 Finish3270()
 {
     while (Push3270() || !DoTerminalOutput()) {
+#if    defined(unix)
+       HaveInput = 0;
+#endif /* defined(unix) */
        ;
     }
 }
        ;
     }
 }
@@ -1810,7 +2493,17 @@ int returnCode;
 
 #endif /* defined(TN3270) */
 \f
 
 #endif /* defined(TN3270) */
 \f
-static
+/*
+ * Scheduler()
+ *
+ * Try to do something.
+ *
+ * If we do something useful, return 1; else return 0.
+ *
+ */
+
+
+int
 Scheduler(block)
 int    block;                  /* should we block in the select ? */
 {
 Scheduler(block)
 int    block;                  /* should we block in the select ? */
 {
@@ -1830,12 +2523,20 @@ int     block;                  /* should we block in the select ? */
     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
        FD_SET(net, &obits);
     } 
     if ((!MODE_LINE(globalmode) || flushline) && NETBYTES()) {
        FD_SET(net, &obits);
     } 
+#if    !defined(MSDOS)
     if (TTYBYTES()) {
        FD_SET(tout, &obits);
     }
     if (TTYBYTES()) {
        FD_SET(tout, &obits);
     }
+#if    defined(TN3270)
+    if ((tcc == 0) && NETROOM() && (shell_active == 0)) {
+       FD_SET(tin, &ibits);
+    }
+#else  /* defined(TN3270) */
     if ((tcc == 0) && NETROOM()) {
        FD_SET(tin, &ibits);
     }
     if ((tcc == 0) && NETROOM()) {
        FD_SET(tin, &ibits);
     }
+#endif /* defined(TN3270) */
+#endif /* !defined(MSDOS) */
 #   if !defined(TN3270)
     if (TTYROOM()) {
        FD_SET(net, &ibits);
 #   if !defined(TN3270)
     if (TTYROOM()) {
        FD_SET(net, &ibits);
@@ -1855,7 +2556,7 @@ int       block;                  /* should we block in the select ? */
     }
 #endif /* defined(TN3270) && defined(unix) */
     if ((c = select(16, &ibits, &obits, &xbits,
     }
 #endif /* defined(TN3270) && defined(unix) */
     if ((c = select(16, &ibits, &obits, &xbits,
-                       block? (struct timeval *)0 : &TimeValue)) < 1) {
+                       block? (struct timeval *)0 : &TimeValue)) < 0) {
        if (c == -1) {
                    /*
                     * we can get EINTR if we are in line mode,
        if (c == -1) {
                    /*
                     * we can get EINTR if we are in line mode,
@@ -1953,20 +2654,20 @@ int     block;                  /* should we block in the select ? */
            if (atmark) {
                c = recv(net, sbp+scc, canread, MSG_OOB);
                if ((c == -1) && (errno == EINVAL)) {
            if (atmark) {
                c = recv(net, sbp+scc, canread, MSG_OOB);
                if ((c == -1) && (errno == EINVAL)) {
-                   c = read(net, sbp+scc, canread);
+                   c = recv(net, sbp+scc, canread, 0);
                    if (clocks.didnetreceive < clocks.gotDM) {
                        SYNCHing = stilloob(net);
                    }
                }
            } else {
                    if (clocks.didnetreceive < clocks.gotDM) {
                        SYNCHing = stilloob(net);
                    }
                }
            } else {
-               c = read(net, sbp+scc, canread);
+               c = recv(net, sbp+scc, canread, 0);
            }
        } else {
            }
        } else {
-           c = read(net, sbp+scc, canread);
+           c = recv(net, sbp+scc, canread, 0);
        }
        settimer(didnetreceive);
 #else  /* !defined(SO_OOBINLINE) */
        }
        settimer(didnetreceive);
 #else  /* !defined(SO_OOBINLINE) */
-       c = read(net, sbp+scc, canread);
+       c = recv(net, sbp+scc, canread, 0);
 #endif /* !defined(SO_OOBINLINE) */
        if (c < 0 && errno == EWOULDBLOCK) {
            c = 0;
 #endif /* !defined(SO_OOBINLINE) */
        if (c < 0 && errno == EWOULDBLOCK) {
            c = 0;
@@ -1983,21 +2684,28 @@ int     block;                  /* should we block in the select ? */
     /*
      * Something to read from the tty...
      */
     /*
      * Something to read from the tty...
      */
-    if (FD_ISSET(tin, &ibits)) {
+#if    defined(MSDOS)
+    if ((tcc == 0) && NETROOM() && (shell_active == 0) && TerminalCanRead())
+#else  /* defined(MSDOS) */
+    if (FD_ISSET(tin, &ibits))
+#endif /* defined(MSDOS) */
+                                   {
        FD_CLR(tin, &ibits);
        if (tcc == 0) {
            tbp = tibuf;        /* nothing left, reset */
        }
        FD_CLR(tin, &ibits);
        if (tcc == 0) {
            tbp = tibuf;        /* nothing left, reset */
        }
-       c = read(tin, tbp, tibuf+sizeof tibuf - tbp);
+       c = TerminalRead(tin, tbp, tibuf+sizeof tibuf - tbp);
        if (c < 0 && errno == EWOULDBLOCK) {
            c = 0;
        } else {
        if (c < 0 && errno == EWOULDBLOCK) {
            c = 0;
        } else {
+#if    defined(unix)
            /* EOF detection for line mode!!!! */
            if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
                        /* must be an EOF... */
                *tbp = ntc.t_eofc;
                c = 1;
            }
            /* EOF detection for line mode!!!! */
            if (c == 0 && MODE_LOCAL_CHARS(globalmode)) {
                        /* must be an EOF... */
                *tbp = ntc.t_eofc;
                c = 1;
            }
+#endif /* defined(unix) */
            if (c <= 0) {
                tcc = c;
                return -1;
            if (c <= 0) {
                tcc = c;
                return -1;
@@ -2046,51 +2754,43 @@ int     block;                  /* should we block in the select ? */
                    }
                }
                if (localchars) {
                    }
                }
                if (localchars) {
-                   if (sc == ntc.t_intrc) {
-                       intp();
+                   if (TerminalSpecialChars(sc) == 0) {
                        break;
                        break;
-                   } else if (sc == ntc.t_quitc) {
-                       sendbrk();
+                   }
+               }
+               if (!myopts[TELOPT_BINARY]) {
+                   switch (c) {
+                   case '\n':
+                           /*
+                            * If we are in CRMOD mode (\r ==> \n)
+                            * on our local machine, then probably
+                            * a newline (unix) is CRLF (TELNET).
+                            */
+                       if (MODE_LOCAL_CHARS(globalmode)) {
+                           NETADD('\r');
+                       }
+                       NETADD('\n');
+                       flushline = 1;
                        break;
                        break;
-                   } else if (sc == nltc.t_flushc) {
-                       NET2ADD(IAC, AO);
-                       if (autoflush) {
-                           doflush();
+                   case '\r':
+                       if (!crlf) {
+                           NET2ADD('\r', '\0');
+                       } else {
+                           NET2ADD('\r', '\n');
                        }
                        }
+                       flushline = 1;
                        break;
                        break;
-                   } else if (MODE_LOCAL_CHARS(globalmode)) {
-                       ;
-                   } else if (sc == nttyb.sg_kill) {
-                       NET2ADD(IAC, EL);
+                   case IAC:
+                       NET2ADD(IAC, IAC);
                        break;
                        break;
-                   } else if (sc == nttyb.sg_erase) {
-                       NET2ADD(IAC, EC);
+                   default:
+                       NETADD(c);
                        break;
                    }
                        break;
                    }
-               }
-               switch (c) {
-               case '\n':
-                       /*
-                        * If we are in CRMOD mode (\r ==> \n)
-                        * on our local machine, then probably
-                        * a newline (unix) is CRLF (TELNET).
-                        */
-                   if (MODE_LOCAL_CHARS(globalmode)) {
-                       NETADD('\r');
-                   }
-                   NETADD('\n');
-                   flushline = 1;
-                   break;
-               case '\r':
-                   NET2ADD('\r', '\0');
-                   flushline = 1;
-                   break;
-               case IAC:
+               } else if (c == IAC) {
                    NET2ADD(IAC, IAC);
                    NET2ADD(IAC, IAC);
-                   break;
-               default:
+               } else {
                    NETADD(c);
                    NETADD(c);
-                   break;
                }
            }
 #   if defined(TN3270)
                }
            }
 #   if defined(TN3270)
@@ -2098,7 +2798,7 @@ int       block;                  /* should we block in the select ? */
     }
 #   endif /* defined(TN3270) */
 
     }
 #   endif /* defined(TN3270) */
 
-    if ((!MODE_LINE(globalmode) || flushline) &&
+    if ((!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]) &&
        FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
        FD_CLR(net, &obits);
        returnValue = netflush();
        FD_ISSET(net, &obits) && (NETBYTES() > 0)) {
        FD_CLR(net, &obits);
        returnValue = netflush();
@@ -2111,7 +2811,12 @@ int      block;                  /* should we block in the select ? */
        returnValue = Push3270();
 #      endif /* !defined(TN3270) */
     }
        returnValue = Push3270();
 #      endif /* !defined(TN3270) */
     }
-    if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0)) {
+#if    defined(MSDOS)
+    if (TTYBYTES())
+#else  /* defined(MSDOS) */
+    if (FD_ISSET(tout, &obits) && (TTYBYTES() > 0))
+#endif /* defined(MSDOS) */
+                                                   {
        FD_CLR(tout, &obits);
        returnValue = ttyflush();
     }
        FD_CLR(tout, &obits);
        returnValue = ttyflush();
     }
@@ -2124,7 +2829,12 @@ int      block;                  /* should we block in the select ? */
 static void
 telnet()
 {
 static void
 telnet()
 {
-    int on = 1;
+#if    defined(MSDOS)
+#define        SCHED_BLOCK     0               /* Don't block in MSDOS */
+#else  /* defined(MSDOS) */
+#define        SCHED_BLOCK     1
+#endif /* defined(MSDOS) */
+
 #if    defined(TN3270) && defined(unix)
     int myPid;
 #endif /* defined(TN3270) */
 #if    defined(TN3270) && defined(unix)
     int myPid;
 #endif /* defined(TN3270) */
@@ -2138,26 +2848,19 @@ telnet()
     FD_ZERO(&obits);
     FD_ZERO(&xbits);
 
     FD_ZERO(&obits);
     FD_ZERO(&xbits);
 
-    ioctl(net, FIONBIO, (char *)&on);
+    NetNonblockingIO(net, 1);
 
 #if    defined(TN3270)
 
 #if    defined(TN3270)
-#if    !defined(DEBUG)         /* DBX can't handle! */
-    ioctl(net, FIOASYNC, (char *)&on); /* hear about input */
-#endif /* !defined(DEBUG) */
-
-#if    defined(unix)
-    myPid = getpid();
-#if    defined(NOT43)
-    myPid = -myPid;
-#endif /* defined(NOT43) */
-    ioctl(net, SIOCSPGRP, (char *)&myPid);     /* set my pid */
-#endif /* defined(unix) */
-
+    if (noasynch == 0) {                       /* DBX can't handle! */
+       NetSigIO(net, 1);
+    }
+    NetSetPgrp(net);
 #endif /* defined(TN3270) */
 
 #endif /* defined(TN3270) */
 
-#if    defined(SO_OOBINLINE)
-    setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
-#endif /* defined(SO_OOBINLINE) */
+
+#if    defined(SO_OOBINLINE) && !defined(MSDOS)
+    SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1);
+#endif /* defined(SO_OOBINLINE) && !defined(MSDOS) */
 
 #   if !defined(TN3270)
     if (telnetport) {
 
 #   if !defined(TN3270)
     if (telnetport) {
@@ -2172,7 +2875,7 @@ telnet()
 
 #   if !defined(TN3270)
     for (;;) {
 
 #   if !defined(TN3270)
     for (;;) {
-       if (Scheduler(1) == -1) {
+       if (Scheduler(SCHED_BLOCK) == -1) {
            setcommandmode();
            return;
        }
            setcommandmode();
            return;
        }
@@ -2181,8 +2884,8 @@ telnet()
     for (;;) {
        int schedValue;
 
     for (;;) {
        int schedValue;
 
-       while (!In3270) {
-           if (Scheduler(1) == -1) {
+       while (!In3270 && !shell_active) {
+           if (Scheduler(SCHED_BLOCK) == -1) {
                setcommandmode();
                return;
            }
                setcommandmode();
                return;
            }
@@ -2200,10 +2903,16 @@ telnet()
        if (tfrontp-tbackp) {
            schedValue = 1;
        } else {
        if (tfrontp-tbackp) {
            schedValue = 1;
        } else {
-           schedValue = DoTerminalOutput();
+           if (shell_active) {
+               if (shell_continue() == 0) {
+                   ConnectScreen();
+               }
+           } else if (In3270) {
+               schedValue = DoTerminalOutput();
+           }
        }
        }
-       if (schedValue) {
-           if (Scheduler(1) == -1) {
+       if (schedValue && (shell_active == 0)) {
+           if (Scheduler(SCHED_BLOCK) == -1) {
                setcommandmode();
                return;
            }
                setcommandmode();
                return;
            }
@@ -2394,13 +3103,12 @@ togdebug()
 {
 #ifndef        NOT43
     if (net > 0 &&
 {
 #ifndef        NOT43
     if (net > 0 &&
-       setsockopt(net, SOL_SOCKET, SO_DEBUG, (char *)&debug, sizeof(debug))
-                                                                       < 0) {
+       (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
            perror("setsockopt (SO_DEBUG)");
     }
 #else  /* NOT43 */
     if (debug) {
            perror("setsockopt (SO_DEBUG)");
     }
 #else  /* NOT43 */
     if (debug) {
-       if (net > 0 && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
+       if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
            perror("setsockopt (SO_DEBUG)");
     } else
        printf("Cannot turn off socket debugging\n");
            perror("setsockopt (SO_DEBUG)");
     } else
        printf("Cannot turn off socket debugging\n");
@@ -2409,6 +3117,46 @@ togdebug()
 }
 
 
 }
 
 
+static int
+togcrlf()
+{
+    if (crlf) {
+       printf("Will send carriage returns as telnet <CR><LF>.\n");
+    } else {
+       printf("Will send carriage returns as telnet <CR><NUL>.\n");
+    }
+    return 1;
+}
+
+
+static int
+togbinary()
+{
+    donebinarytoggle = 1;
+
+    if (myopts[TELOPT_BINARY] == 0) {  /* Go into binary mode */
+       NET2ADD(IAC, DO);
+       NETADD(TELOPT_BINARY);
+       printoption("<SENT", doopt, TELOPT_BINARY, 0);
+       NET2ADD(IAC, WILL);
+       NETADD(TELOPT_BINARY);
+       printoption("<SENT", doopt, TELOPT_BINARY, 0);
+       hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 1;
+       printf("Negotiating binary mode with remote host.\n");
+    } else {                           /* Turn off binary mode */
+       NET2ADD(IAC, DONT);
+       NETADD(TELOPT_BINARY);
+       printoption("<SENT", dont, TELOPT_BINARY, 0);
+       NET2ADD(IAC, DONT);
+       NETADD(TELOPT_BINARY);
+       printoption("<SENT", dont, TELOPT_BINARY, 0);
+       hisopts[TELOPT_BINARY] = myopts[TELOPT_BINARY] = 0;
+       printf("Negotiating network ascii mode with remote host.\n");
+    }
+    return 1;
+}
+
+
 
 extern int togglehelp();
 
 
 extern int togglehelp();
 
@@ -2434,6 +3182,18 @@ static struct togglelist Togglelist[] = {
                1,
                    &autosynch,
                        "send interrupt characters in urgent mode" },
                1,
                    &autosynch,
                        "send interrupt characters in urgent mode" },
+    { "binary",
+       "toggle sending and receiving of binary data",
+           togbinary,
+               1,
+                   0,
+                       0 },
+    { "crlf",
+       "toggle sending carriage returns as telnet <CR><LF>",
+           togcrlf,
+               1,
+                   &crlf,
+                       0 },
     { "crmod",
        "toggle mapping of received carriage returns",
            0,
     { "crmod",
        "toggle mapping of received carriage returns",
            0,
@@ -2537,8 +3297,10 @@ char     *argv[];
        } else {
            if (c->variable) {
                *c->variable = !*c->variable;           /* invert it */
        } else {
            if (c->variable) {
                *c->variable = !*c->variable;           /* invert it */
-               printf("%s %s.\n", *c->variable? "Will" : "Won't",
+               if (c->actionexplanation) {
+                   printf("%s %s.\n", *c->variable? "Will" : "Won't",
                                                        c->actionexplanation);
                                                        c->actionexplanation);
+               }
            }
            if (c->handler) {
                retval &= (*c->handler)(c);
            }
            if (c->handler) {
                retval &= (*c->handler)(c);
@@ -2563,12 +3325,22 @@ static struct setlist Setlist[] = {
     { "escape",        "character to escape back to telnet command mode", &escape },
     { " ", "" },
     { " ", "The following need 'localchars' to be toggled true", 0 },
     { "escape",        "character to escape back to telnet command mode", &escape },
     { " ", "" },
     { " ", "The following need 'localchars' to be toggled true", 0 },
+#if    defined(unix)
     { "erase", "character to cause an Erase Character", &nttyb.sg_erase },
     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
     { "kill",  "character to cause an Erase Line", &nttyb.sg_kill },
     { "quit",  "character to cause a Break", &ntc.t_quitc },
     { "eof",   "character to cause an EOF ", &ntc.t_eofc },
     { "erase", "character to cause an Erase Character", &nttyb.sg_erase },
     { "flushoutput", "character to cause an Abort Oubput", &nltc.t_flushc },
     { "interrupt", "character to cause an Interrupt Process", &ntc.t_intrc },
     { "kill",  "character to cause an Erase Line", &nttyb.sg_kill },
     { "quit",  "character to cause a Break", &ntc.t_quitc },
     { "eof",   "character to cause an EOF ", &ntc.t_eofc },
+#endif /* defined(unix) */
+#if    defined(MSDOS)
+    { "erase", "character to cause an Erase Character", &termEraseChar },
+    { "flushoutput", "character to cause an Abort Oubput", &termFlushChar },
+    { "interrupt", "character to cause an Interrupt Process", &termIntChar },
+    { "kill",  "character to cause an Erase Line", &termKillChar },
+    { "quit",  "character to cause a Break", &termQuitChar },
+    { "eof",   "character to cause an EOF ", &termEofChar },
+#endif /* defined(MSDOS) */
     { 0 }
 };
 
     { 0 }
 };
 
@@ -2825,9 +3597,8 @@ suspend()
        kill(0, SIGTSTP);
 #endif /* defined(unix) */
        /* reget parameters in case they were changed */
        kill(0, SIGTSTP);
 #endif /* defined(unix) */
        /* reget parameters in case they were changed */
-       ioctl(0, TIOCGETP, (char *)&ottyb);
-       ioctl(0, TIOCGETC, (char *)&otc);
-       ioctl(0, TIOCGLTC, (char *)&oltc);
+       TerminalSaveState();
+       setconnmode();
        return 1;
 }
 
        return 1;
 }
 
@@ -2840,7 +3611,7 @@ char      *argv[];        /* arguments */
     if (connected) {
        shutdown(net, 2);
        printf("Connection closed.\n");
     if (connected) {
        shutdown(net, 2);
        printf("Connection closed.\n");
-       close(net);
+       NetClose(net);
        connected = 0;
        /* reset options */
        tninit();
        connected = 0;
        /* reset options */
        tninit();
@@ -2932,15 +3703,16 @@ settranscom(argc, argv)
 #endif /* defined(TN3270) && defined(unix) */
 
 
 #endif /* defined(TN3270) && defined(unix) */
 
 
+
 static
 tn(argc, argv)
        int argc;
        char *argv[];
 {
     register struct hostent *host = 0;
 static
 tn(argc, argv)
        int argc;
        char *argv[];
 {
     register struct hostent *host = 0;
-#if defined(msdos)
+#if defined(MSDOS)
     char *cp;
     char *cp;
-#endif /* defined(msdos) */
+#endif /* defined(MSDOS) */
 
     if (connected) {
        printf("?Already connected to %s\n", hostname);
 
     if (connected) {
        printf("?Already connected to %s\n", hostname);
@@ -2954,17 +3726,17 @@ tn(argc, argv)
        argc = margc;
        argv = margv;
     }
        argc = margc;
        argv = margv;
     }
-    if (argc > 3) {
+    if ((argc < 2) || (argc > 3)) {
        printf("usage: %s host-name [port]\n", argv[0]);
        return 0;
     }
        printf("usage: %s host-name [port]\n", argv[0]);
        return 0;
     }
-#if    defined(msdos)
+#if    defined(MSDOS)
     for (cp = argv[1]; *cp; cp++) {
        if (isupper(*cp)) {
            *cp = tolower(*cp);
        }
     }
     for (cp = argv[1]; *cp; cp++) {
        if (isupper(*cp)) {
            *cp = tolower(*cp);
        }
     }
-#endif /* defined(msdos) */
+#endif /* defined(MSDOS) */
     sin.sin_addr.s_addr = inet_addr(argv[1]);
     if (sin.sin_addr.s_addr != -1) {
        sin.sin_family = AF_INET;
     sin.sin_addr.s_addr = inet_addr(argv[1]);
     if (sin.sin_addr.s_addr != -1) {
        sin.sin_family = AF_INET;
@@ -2975,9 +3747,10 @@ tn(argc, argv)
        if (host) {
            sin.sin_family = host->h_addrtype;
 #if    defined(h_addr)         /* In 4.3, this is a #define */
        if (host) {
            sin.sin_family = host->h_addrtype;
 #if    defined(h_addr)         /* In 4.3, this is a #define */
-           bcopy(host->h_addr_list[0], (caddr_t)&sin.sin_addr, host->h_length);
+           memcpy((caddr_t)&sin.sin_addr,
+                               host->h_addr_list[0], host->h_length);
 #else  /* defined(h_addr) */
 #else  /* defined(h_addr) */
-           bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
+           memcpy((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
 #endif /* defined(h_addr) */
            hostname = host->h_name;
        } else {
 #endif /* defined(h_addr) */
            hostname = host->h_name;
        } else {
@@ -3016,13 +3789,9 @@ tn(argc, argv)
            perror("telnet: socket");
            return 0;
        }
            perror("telnet: socket");
            return 0;
        }
-#ifndef        NOT43
-       if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG,
-                               (char *)&debug, sizeof(debug)) < 0)
-#else  /* NOT43 */
-       if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
-#endif /* NOT43 */
+       if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
                perror("setsockopt (SO_DEBUG)");
                perror("setsockopt (SO_DEBUG)");
+       }
 
        if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
 #if    defined(h_addr)         /* In 4.3, this is a #define */
 
        if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
 #if    defined(h_addr)         /* In 4.3, this is a #define */
@@ -3034,11 +3803,11 @@ tn(argc, argv)
                errno = oerrno;
                perror((char *)0);
                host->h_addr_list++;
                errno = oerrno;
                perror((char *)0);
                host->h_addr_list++;
-               bcopy(host->h_addr_list[0],
-                   (caddr_t)&sin.sin_addr, host->h_length);
+               memcpy((caddr_t)&sin.sin_addr, 
+                       host->h_addr_list[0], host->h_length);
                fprintf(stderr, "Trying %s...\n",
                        inet_ntoa(sin.sin_addr));
                fprintf(stderr, "Trying %s...\n",
                        inet_ntoa(sin.sin_addr));
-               (void) close(net);
+               (void) NetClose(net);
                continue;
            }
 #endif /* defined(h_addr) */
                continue;
            }
 #endif /* defined(h_addr) */
@@ -3054,6 +3823,7 @@ tn(argc, argv)
     call(status, "status", "notmuch", 0);
     if (setjmp(peerdied) == 0)
        telnet();
     call(status, "status", "notmuch", 0);
     if (setjmp(peerdied) == 0)
        telnet();
+    NetClose(net);
     ExitString(stderr, "Connection closed by foreign host.\n",1);
     /*NOTREACHED*/
 }
     ExitString(stderr, "Connection closed by foreign host.\n",1);
     /*NOTREACHED*/
 }
@@ -3065,7 +3835,6 @@ static char
        openhelp[] =    "connect to a site",
        closehelp[] =   "close current connection",
        quithelp[] =    "exit telnet",
        openhelp[] =    "connect to a site",
        closehelp[] =   "close current connection",
        quithelp[] =    "exit telnet",
-       zhelp[] =       "suspend telnet",
        statushelp[] =  "print status information",
        helphelp[] =    "print help information",
        sendhelp[] =    "transmit special characters ('send ?' for more)",
        statushelp[] =  "print status information",
        helphelp[] =    "print help information",
        sendhelp[] =    "transmit special characters ('send ?' for more)",
@@ -3075,9 +3844,15 @@ static char
 #if    defined(TN3270) && defined(unix)
        transcomhelp[] = "specify Unix command for transparent mode pipe",
 #endif /* defined(TN3270) && defined(unix) */
 #if    defined(TN3270) && defined(unix)
        transcomhelp[] = "specify Unix command for transparent mode pipe",
 #endif /* defined(TN3270) && defined(unix) */
+#if    defined(unix)
+       zhelp[] =       "suspend telnet",
+#endif /* defined(unix */
+#if    defined(TN3270)
+       shellhelp[] =   "invoke a subshell",
+#endif /* defined(TN3270) */
        modehelp[] = "try to enter line-by-line or character-at-a-time mode";
 
        modehelp[] = "try to enter line-by-line or character-at-a-time mode";
 
-extern int     help();
+extern int     help(), shell();
 
 static struct cmd cmdtab[] = {
        { "close",      closehelp,      bye,            1, 1 },
 
 static struct cmd cmdtab[] = {
        { "close",      closehelp,      bye,            1, 1 },
@@ -3092,7 +3867,12 @@ static struct cmd cmdtab[] = {
 #if    defined(TN3270) && defined(unix)
        { "transcom",   transcomhelp,   settranscom,    1, 0 },
 #endif /* defined(TN3270) && defined(unix) */
 #if    defined(TN3270) && defined(unix)
        { "transcom",   transcomhelp,   settranscom,    1, 0 },
 #endif /* defined(TN3270) && defined(unix) */
+#if    defined(unix)
        { "z",          zhelp,          suspend,        1, 0 },
        { "z",          zhelp,          suspend,        1, 0 },
+#endif /* defined(unix) */
+#if    defined(TN3270)
+       { "!",          shellhelp,      shell,          1, 1 },
+#endif /* defined(TN3270) */
        { "?",          helphelp,       help,           1, 0 },
        0
 };
        { "?",          helphelp,       help,           1, 0 },
        0
 };
@@ -3150,51 +3930,57 @@ void
 command(top)
        int top;
 {
 command(top)
        int top;
 {
-       register struct cmd *c;
+    register struct cmd *c;
 
 
-       setcommandmode();
-       if (!top) {
-               putchar('\n');
-       } else {
+    setcommandmode();
+    if (!top) {
+       putchar('\n');
+    } else {
 #if    defined(unix)
 #if    defined(unix)
-               signal(SIGINT, SIG_DFL);
-               signal(SIGQUIT, SIG_DFL);
+       signal(SIGINT, SIG_DFL);
+       signal(SIGQUIT, SIG_DFL);
 #endif /* defined(unix) */
 #endif /* defined(unix) */
+    }
+    for (;;) {
+       printf("%s> ", prompt);
+       if (gets(line) == NULL) {
+           if (feof(stdin) || ferror(stdin))
+               quit();
+           break;
        }
        }
-       for (;;) {
-               printf("%s> ", prompt);
-               if (gets(line) == NULL) {
-                       if (feof(stdin) || ferror(stdin))
-                               quit();
-                       break;
-               }
-               if (line[0] == 0)
-                       break;
-               makeargv();
-               c = getcmd(margv[0]);
-               if (c == Ambiguous(struct cmd *)) {
-                       printf("?Ambiguous command\n");
-                       continue;
-               }
-               if (c == 0) {
-                       printf("?Invalid command\n");
-                       continue;
-               }
-               if (c->needconnect && !connected) {
-                       printf("?Need to be connected first.\n");
-                       continue;
-               }
-               if ((*c->handler)(margc, margv)) {
-                       break;
-               }
+       if (line[0] == 0)
+           break;
+       makeargv();
+       c = getcmd(margv[0]);
+       if (c == Ambiguous(struct cmd *)) {
+           printf("?Ambiguous command\n");
+           continue;
        }
        }
-       if (!top) {
-               if (!connected) {
-                       longjmp(toplevel, 1);
-                       /*NOTREACHED*/
-               }
-               setconnmode();
+       if (c == 0) {
+           printf("?Invalid command\n");
+           continue;
+       }
+       if (c->needconnect && !connected) {
+           printf("?Need to be connected first.\n");
+           continue;
        }
        }
+       if ((*c->handler)(margc, margv)) {
+           break;
+       }
+    }
+    if (!top) {
+       if (!connected) {
+           longjmp(toplevel, 1);
+           /*NOTREACHED*/
+       }
+#if    defined(TN3270)
+       if (shell_active == 0) {
+           setconnmode();
+       }
+#else  /* defined(TN3270) */
+       setconnmode();
+#endif /* defined(TN3270) */
+    }
 }
 \f
 /*
 }
 \f
 /*
@@ -3243,56 +4029,59 @@ main(argc, argv)
     tninit();          /* Clear out things */
 
     NetTrace = stdout;
     tninit();          /* Clear out things */
 
     NetTrace = stdout;
-    ioctl(0, TIOCGETP, (char *)&ottyb);
-    ioctl(0, TIOCGETC, (char *)&otc);
-    ioctl(0, TIOCGLTC, (char *)&oltc);
-#if    defined(LNOFLSH)
-    ioctl(0, TIOCLGET, (char *)&autoflush);
-    autoflush = !(autoflush&LNOFLSH);  /* if LNOFLSH, no autoflush */
-#else  /* LNOFLSH */
-    autoflush = 1;
-#endif /* LNOFLSH */
-    ntc = otc;
-    nltc = oltc;
-    nttyb = ottyb;
-    setbuf(stdin, (char *)0);
-    setbuf(stdout, (char *)0);
+    TerminalSaveState();
+    autoflush = TerminalAutoFlush();
+
     prompt = argv[0];
     prompt = argv[0];
-    if (argc > 1 && !strcmp(argv[1], "-d")) {
-       debug = 1;
-       argv++;
-       argc--;
-    }
-    if (argc > 1 && !strcmp(argv[1], "-n")) {
-       argv++;
-       argc--;
-       if (argc > 1) {         /* get file name */
-           NetTrace = fopen(argv[1], "w");
-           argv++;
-           argc--;
-           if (NetTrace == NULL) {
-               NetTrace = stdout;
+    while ((argc > 1) && (argv[1][0] == '-')) {
+       if (!strcmp(argv[1], "-d")) {
+           debug = 1;
+       } else if (!strcmp(argv[1], "-n")) {
+           if ((argc > 1) && (argv[2][0] != '-')) {    /* get file name */
+               NetTrace = fopen(argv[2], "w");
+               argv++;
+               argc--;
+               if (NetTrace == NULL) {
+                   NetTrace = stdout;
+               }
            }
            }
-       }
-    }
+       } else {
 #if    defined(TN3270) && defined(unix)
 #if    defined(TN3270) && defined(unix)
-    if (argc > 1 && !strcmp(argv[1], "-t")) {
-       argv++;
-       argc--;
-       if (argc > 1) {         /* get command name */
-           transcom = tline;
-           (void) strcpy(transcom, argv[1]);
-           argv++;
-           argc--;
+           if (!strcmp(argv[1], "-t")) {
+               if ((argc > 1) && (argv[2][0] != '-')) { /* get file name */
+                   transcom = tline;
+                   (void) strcpy(transcom, argv[1]);
+                   argv++;
+                   argc--;
+               }
+           } else if (!strcmp(argv[1], "-noasynch")) {
+               noasynch = 1;
+           } else
+#endif /* defined(TN3270) && defined(unix) */
+           if (argv[1][1] != '\0') {
+               fprintf(stderr, "Unknown option *%s*.\n", argv[1]);
+           }
        }
        }
+       argc--;
+       argv++;
     }
     }
-#endif /* defined(TN3270) && defined(unix) */
     if (argc != 1) {
        if (setjmp(toplevel) != 0)
            Exit(0);
        tn(argc, argv);
     }
     setjmp(toplevel);
     if (argc != 1) {
        if (setjmp(toplevel) != 0)
            Exit(0);
        tn(argc, argv);
     }
     setjmp(toplevel);
-    for (;;)
+    for (;;) {
+#if    !defined(TN3270)
        command(1);
        command(1);
+#else  /* !defined(TN3270) */
+       if (!shell_active) {
+           command(1);
+       } else {
+#if    defined(TN3270)
+           shell_continue();
+#endif /* defined(TN3270) */
+       }
+#endif /* !defined(TN3270) */
+    }
 }
 }