fix shutdown problem; double IAC's on output; misc cleanups
[unix-history] / usr / src / usr.bin / telnet / telnet.c
index 37fdc10..5f17471 100644 (file)
@@ -1,30 +1,30 @@
-/*     telnet.c        4.2     82/03/01        */
+#ifndef lint
+static char sccsid[] = "@(#)telnet.c   4.18 (Berkeley) %G%";
+#endif
 
 /*
  * User telnet program.
  */
 
 /*
  * User telnet program.
  */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+
 #include <stdio.h>
 #include <ctype.h>
 #include <errno.h>
 #include <signal.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <errno.h>
 #include <signal.h>
-#include <sgtty.h>
 #include <setjmp.h>
 #include <setjmp.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <net/in.h>
+#include <netdb.h>
+
 #define        TELOPTS
 #include "telnet.h"
 
 #define        TELOPTS
 #include "telnet.h"
 
-#define        ctrl(x)         ((x) & 037)
 #define        strip(x)        ((x)&0177)
 #define        strip(x)        ((x)&0177)
-#define        INFINITY        10000000
-#define        swab(x)         ((((x) >> 8) | ((x) << 8)) & 0xffff)
 
 char   ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
 
 char   ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
-char   netobuf[BUFSIZ] =
-       { IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_SGA,
-         IAC, WONT, TELOPT_SGA },
-       *nfrontp = netobuf + 9, *nbackp = netobuf;
+char   netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
 
 char   hisopts[256];
 char   myopts[256];
 
 char   hisopts[256];
 char   myopts[256];
@@ -36,9 +36,12 @@ char wont[] = { IAC, WONT, '%', 'c', 0 };
 
 int    connected;
 int    net;
 
 int    connected;
 int    net;
-int    showoptions;
+int    showoptions = 0;
+int    options;
+int    debug = 0;
+int    crmod = 0;
 char   *prompt;
 char   *prompt;
-char   escape = ctrl('_');
+char   escape = CTRL(]);
 
 char   line[200];
 int    margc;
 
 char   line[200];
 int    margc;
@@ -51,49 +54,67 @@ extern      int errno;
 
 int    tn(), quit(), suspend(), bye(), help();
 int    setescape(), status(), toggle(), setoptions();
 
 int    tn(), quit(), suspend(), bye(), help();
 int    setescape(), status(), toggle(), setoptions();
+int    setcrmod(), setdebug();
 
 
-#define HELPINDENT (sizeof("connect"))
+#define HELPINDENT (sizeof ("connect"))
 
 struct cmd {
 
 struct cmd {
-       char    *name;
-       char    *help;
-       int     (*handler)();
+       char    *name;          /* command name */
+       char    *help;          /* help string */
+       int     (*handler)();   /* routine which executes command */
 };
 
 };
 
-char   ohelp[] = "connect to a site";
-char   chelp[] = "close current connection";
-char   qhelp[] = "exit telnet";
-char   zhelp[] = "suspend telnet";
-char   ehelp[] = "set escape character";
-char   shelp[] = "print status information";
-char   hhelp[] = "print help information";
-char   phelp[] = "toggle viewing of options processing";
+char   openhelp[] =    "connect to a site";
+char   closehelp[] =   "close current connection";
+char   quithelp[] =    "exit telnet";
+char   zhelp[] =       "suspend telnet";
+char   debughelp[] =   "toggle debugging";
+char   escapehelp[] =  "set escape character";
+char   statushelp[] =  "print status information";
+char   helphelp[] =    "print help information";
+char   optionshelp[] = "toggle viewing of options processing";
+char   crmodhelp[] =   "toggle mapping of received carriage returns";
 
 struct cmd cmdtab[] = {
 
 struct cmd cmdtab[] = {
-       { "open",       ohelp,          tn },
-       { "close",      chelp,          bye },
-       { "quit",       qhelp,          quit },
+       { "open",       openhelp,       tn },
+       { "close",      closehelp,      bye },
+       { "quit",       quithelp,       quit },
        { "z",          zhelp,          suspend },
        { "z",          zhelp,          suspend },
-       { "escape",     ehelp,          setescape },
-       { "status",     shelp,          status },
-       { "options",    phelp,          setoptions },
-       { "?",          hhelp,          help },
+       { "escape",     escapehelp,     setescape },
+       { "status",     statushelp,     status },
+       { "options",    optionshelp,    setoptions },
+       { "crmod",      crmodhelp,      setcrmod },
+       { "debug",      debughelp,      setdebug },
+       { "?",          helphelp,       help },
        0
 };
 
        0
 };
 
-struct sockaddr_in sin = { AF_INET, swab(IPPORT_TELNET) };
+struct sockaddr_in sin;
 
 int    intr(), deadpeer();
 char   *control();
 struct cmd *getcmd();
 
 int    intr(), deadpeer();
 char   *control();
 struct cmd *getcmd();
+struct servent *sp;
+
+struct ttychars otc;
+int    oflags;
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
 
 main(argc, argv)
        int argc;
        char *argv[];
 {
+       sp = getservbyname("telnet", "tcp");
+       if (sp == 0) {
+               fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
+               exit(1);
+       }
+       ioctl(0, TIOCGET, (char *)&oflags);
+       ioctl(0, TIOCCGET, (char *)&otc);
        setbuf(stdin, 0);
        setbuf(stdout, 0);
        prompt = argv[0];
        setbuf(stdin, 0);
        setbuf(stdout, 0);
        prompt = argv[0];
+       if (argc > 1 && !strcmp(argv[1], "-d"))
+               options = SO_DEBUG, argv++, argc--;
        if (argc != 1) {
                if (setjmp(toplevel) != 0)
                        exit(0);
        if (argc != 1) {
                if (setjmp(toplevel) != 0)
                        exit(0);
@@ -104,16 +125,18 @@ main(argc, argv)
                command(1);
 }
 
                command(1);
 }
 
-char host_name[100];
+char   *hostname;
+char   hnamebuf[32];
 
 tn(argc, argv)
        int argc;
        char *argv[];
 {
        register int c;
 
 tn(argc, argv)
        int argc;
        char *argv[];
 {
        register int c;
+       register struct hostent *host;
 
        if (connected) {
 
        if (connected) {
-               printf("?Already connected to %s\n", host_name);
+               printf("?Already connected to %s\n", hostname);
                return;
        }
        if (argc < 2) {
                return;
        }
        if (argc < 2) {
@@ -128,31 +151,45 @@ tn(argc, argv)
                printf("usage: %s host-name [port]\n", argv[0]);
                return;
        }
                printf("usage: %s host-name [port]\n", argv[0]);
                return;
        }
-       sin.sin_addr.s_addr = rhost(&argv[1]);
-       if (sin.sin_addr.s_addr <= 0) {
-               printf("%s: unknown host\n", argv[1]);
-               return;
+       host = gethostbyname(argv[1]);
+       if (host) {
+               sin.sin_family = host->h_addrtype;
+               bcopy(host->h_addr, (caddr_t)&sin.sin_addr, host->h_length);
+               hostname = host->h_name;
+       } else {
+               sin.sin_family = AF_INET;
+               sin.sin_addr.s_addr = inet_addr(argv[1]);
+               if (sin.sin_addr.s_addr == -1) {
+                       printf("%s: unknown host\n", argv[1]);
+                       return;
+               }
+               strcpy(hnamebuf, argv[1]);
+               hostname = hnamebuf;
        }
        }
+       sin.sin_port = sp->s_port;
        if (argc == 3) {
                sin.sin_port = atoi(argv[2]);
                if (sin.sin_port < 0) {
                        printf("%s: bad port number\n", argv[2]);
                        return;
                }
        if (argc == 3) {
                sin.sin_port = atoi(argv[2]);
                if (sin.sin_port < 0) {
                        printf("%s: bad port number\n", argv[2]);
                        return;
                }
+               sin.sin_port = htons(sin.sin_port);
        }
        }
-       if ((net = socket(SOCK_STREAM, 0, 0, 0)) < 0) {
-               perror("socket");
+       net = socket(AF_INET, SOCK_STREAM, 0, 0);
+       if (net < 0) {
+               perror("telnet: socket");
                return;
        }
                return;
        }
+       if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
+               perror("setsockopt (SO_DEBUG)");
        sigset(SIGINT, intr);
        sigset(SIGPIPE, deadpeer);
        printf("Trying...\n");
        sigset(SIGINT, intr);
        sigset(SIGPIPE, deadpeer);
        printf("Trying...\n");
-       if (connect(net, &sin)) {
-               perror("connect");
+       if (connect(net, (caddr_t)&sin, sizeof (sin), 0) < 0) {
+               perror("telnet: connect");
                sigset(SIGINT, SIG_DFL);
                return;
        }
                sigset(SIGINT, SIG_DFL);
                return;
        }
-       strcpy(host_name, argv[1]);
        connected++;
        call(status, "status", 0);
        if (setjmp(peerdied) == 0)
        connected++;
        call(status, "status", 0);
        if (setjmp(peerdied) == 0)
@@ -168,10 +205,11 @@ tn(argc, argv)
 status()
 {
        if (connected)
 status()
 {
        if (connected)
-               printf("Connected to %s.\n", host_name);
+               printf("Connected to %s.\n", hostname);
        else
                printf("No connection.\n");
        printf("Escape character is '%s'.\n", control(escape));
        else
                printf("No connection.\n");
        printf("Escape character is '%s'.\n", control(escape));
+       fflush(stdout);
 }
 
 makeargv()
 }
 
 makeargv()
@@ -202,21 +240,27 @@ suspend()
        register int save;
 
        save = mode(0);
        register int save;
 
        save = mode(0);
-       kill(0, SIGTSTP);       /* get whole process group */
-       mode(save);
+       kill(0, SIGTSTP);
+       /* reget parameters in case they were changed */
+       ioctl(0, TIOCGET, (char *)&oflags);
+       ioctl(0, TIOCCGET, (char *)&otc);
+       (void) mode(save);
 }
 
 /*VARARGS*/
 bye()
 {
 }
 
 /*VARARGS*/
 bye()
 {
-       int how = 2;
+       register char *op;
 
 
-       mode(0);
+       (void) mode(0);
        if (connected) {
        if (connected) {
-               ioctl(net, SIOCDONE, &how);
+               shutdown(net, 2);
                printf("Connection closed.\n");
                close(net);
                connected = 0;
                printf("Connection closed.\n");
                close(net);
                connected = 0;
+               /* reset his options */
+               for (op = hisopts; op < &hisopts[256]; op++)
+                       *op = 0;
        }
 }
 
        }
 }
 
@@ -229,7 +273,6 @@ quit()
 
 /*
  * Help command.
 
 /*
  * Help command.
- * Call each command handler with argc == 0 and argv[0] == name.
  */
 help(argc, argv)
        int argc;
  */
 help(argc, argv)
        int argc;
@@ -272,36 +315,47 @@ call(routine, args)
        (*routine)(argc, &args);
 }
 
        (*routine)(argc, &args);
 }
 
+struct ttychars notc = {
+       -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1,     -1,
+       -1,     -1,     -1,     -1
+};
+
 mode(f)
        register int f;
 {
 mode(f)
        register int f;
 {
-       register int old;
-       struct sgttyb stbuf;
-       static int ttymode = 0;
-       int onoff;
-
-       ioctl(fileno(stdin), TIOCGETP, &stbuf);
-       old = ttymode;
-       ttymode = f;
+       static int prevmode = 0;
+       struct ttychars *tc;
+       int onoff, old, flags;
+
+       if (prevmode == f)
+               return (f);
+       old = prevmode;
+       prevmode = f;
+       flags = oflags;
        switch (f) {
        switch (f) {
+
        case 0:
        case 0:
-               stbuf.sg_flags &= ~RAW;
-               stbuf.sg_flags |= ECHO|CRMOD;
                onoff = 0;
                onoff = 0;
+               tc = &otc;
                break;
 
        case 1:
                break;
 
        case 1:
-               stbuf.sg_flags |= RAW;
-               stbuf.sg_flags &= ~(ECHO|CRMOD);
+       case 2:
+               flags |= CBREAK;
+               if (f == 1)
+                       flags &= ~(ECHO|CRMOD);
+               else
+                       flags |= ECHO|CRMOD;
+               tc = &notc;
                onoff = 1;
                break;
 
                onoff = 1;
                break;
 
-       case 2:
-               stbuf.sg_flags |= RAW;
-               stbuf.sg_flags |= ECHO|CRMOD;
-               onoff = 1;
+       default:
+               return;
        }
        }
-       ioctl(fileno(stdin), TIOCSETN, &stbuf);
+       ioctl(fileno(stdin), TIOCCSET, (char *)tc);
+       ioctl(fileno(stdin), TIOCSET, (char *)&flags);
        ioctl(fileno(stdin), FIONBIO, &onoff);
        ioctl(fileno(stdout), FIONBIO, &onoff);
        return (old);
        ioctl(fileno(stdin), FIONBIO, &onoff);
        ioctl(fileno(stdout), FIONBIO, &onoff);
        return (old);
@@ -321,19 +375,7 @@ telnet(s)
        int tin = fileno(stdin), tout = fileno(stdout);
        int on = 1;
 
        int tin = fileno(stdin), tout = fileno(stdout);
        int on = 1;
 
-       mode(1);
-       if (showoptions)
-               printoption("<--", doopt, TELOPT_ECHO);
-       sprintf(nfrontp, doopt, TELOPT_ECHO);
-       nfrontp += sizeof(doopt) - 2;
-       if (showoptions)
-               printoption("<--", doopt, TELOPT_SGA);
-       sprintf(nfrontp, doopt, TELOPT_SGA);
-       nfrontp += sizeof(doopt) - 2;
-       if (showoptions)
-               printoption("<--", will, TELOPT_SGA);
-       sprintf(nfrontp, will, TELOPT_SGA);
-       nfrontp += sizeof(doopt) - 2;
+       (void) mode(2);
        ioctl(s, FIONBIO, &on);
        for (;;) {
                int ibits = 0, obits = 0;
        ioctl(s, FIONBIO, &on);
        for (;;) {
                int ibits = 0, obits = 0;
@@ -348,7 +390,7 @@ telnet(s)
                        ibits |= (1 << s);
                if (scc < 0 && tcc < 0)
                        break;
                        ibits |= (1 << s);
                if (scc < 0 && tcc < 0)
                        break;
-               select(32, &ibits, &obits, INFINITY);
+               select(16, &ibits, &obits, 0, 0);
                if (ibits == 0 && obits == 0) {
                        sleep(5);
                        continue;
                if (ibits == 0 && obits == 0) {
                        sleep(5);
                        continue;
@@ -358,7 +400,7 @@ telnet(s)
                 * Something to read from the network...
                 */
                if (ibits & (1 << s)) {
                 * Something to read from the network...
                 */
                if (ibits & (1 << s)) {
-                       scc = read(s, sibuf, sizeof(sibuf));
+                       scc = read(s, sibuf, sizeof (sibuf));
                        if (scc < 0 && errno == EWOULDBLOCK)
                                scc = 0;
                        else {
                        if (scc < 0 && errno == EWOULDBLOCK)
                                scc = 0;
                        else {
@@ -372,7 +414,7 @@ telnet(s)
                 * Something to read from the tty...
                 */
                if (ibits & (1 << tin)) {
                 * Something to read from the tty...
                 */
                if (ibits & (1 << tin)) {
-                       tcc = read(tin, tibuf, sizeof(tibuf));
+                       tcc = read(tin, tibuf, sizeof (tibuf));
                        if (tcc < 0 && errno == EWOULDBLOCK)
                                tcc = 0;
                        else {
                        if (tcc < 0 && errno == EWOULDBLOCK)
                                tcc = 0;
                        else {
@@ -393,6 +435,8 @@ telnet(s)
                                tcc = 0;
                                break;
                        }
                                tcc = 0;
                                break;
                        }
+                       if (c == IAC)
+                               *nfrontp++ = c;
                        *nfrontp++ = c;
                }
                if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
                        *nfrontp++ = c;
                }
                if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
@@ -402,7 +446,7 @@ telnet(s)
                if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
                        ttyflush(tout);
        }
                if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
                        ttyflush(tout);
        }
-       mode(0);
+       (void) mode(0);
 }
 
 command(top)
 }
 
 command(top)
@@ -439,7 +483,7 @@ command(top)
        if (!top) {
                if (!connected)
                        longjmp(toplevel, 1);
        if (!top) {
                if (!connected)
                        longjmp(toplevel, 1);
-               mode(oldmode);
+               (void) mode(oldmode);
        }
 }
 
        }
 }
 
@@ -463,10 +507,20 @@ telrcv()
                switch (state) {
 
                case TS_DATA:
                switch (state) {
 
                case TS_DATA:
-                       if (c == IAC)
+                       if (c == IAC) {
                                state = TS_IAC;
                                state = TS_IAC;
-                       else
-                               *tfrontp++ = c;
+                               continue;
+                       }
+                       *tfrontp++ = c;
+                       /*
+                        * This hack is needed since we can't set
+                        * CRMOD on output only.  Machines like MULTICS
+                        * like to send \r without \n; since we must
+                        * turn off CRMOD to get proper input, the mapping
+                        * is done here (sigh).
+                        */
+                       if (c == '\r' && crmod)
+                               *tfrontp++ = '\n';
                        continue;
 
                case TS_IAC:
                        continue;
 
                case TS_IAC:
@@ -503,38 +557,33 @@ telrcv()
                        continue;
 
                case TS_WILL:
                        continue;
 
                case TS_WILL:
-                       if (showoptions)
-                               printoption("-->", will, c);
+                       printoption("RCVD", will, c, !hisopts[c]);
                        if (!hisopts[c])
                                willoption(c);
                        state = TS_DATA;
                        continue;
 
                case TS_WONT:
                        if (!hisopts[c])
                                willoption(c);
                        state = TS_DATA;
                        continue;
 
                case TS_WONT:
-                       if (showoptions)
-                               printoption("-->", wont, c);
+                       printoption("RCVD", wont, c, hisopts[c]);
                        if (hisopts[c])
                                wontoption(c);
                        state = TS_DATA;
                        continue;
 
                case TS_DO:
                        if (hisopts[c])
                                wontoption(c);
                        state = TS_DATA;
                        continue;
 
                case TS_DO:
-                       if (showoptions)
-                               printoption("-->", doopt, c);
+                       printoption("RCVD", doopt, c, !myopts[c]);
                        if (!myopts[c])
                                dooption(c);
                        state = TS_DATA;
                        continue;
 
                case TS_DONT:
                        if (!myopts[c])
                                dooption(c);
                        state = TS_DATA;
                        continue;
 
                case TS_DONT:
-                       if (showoptions)
-                               printoption("-->", dont, c);
+                       printoption("RCVD", dont, c, myopts[c]);
                        if (myopts[c]) {
                                myopts[c] = 0;
                                sprintf(nfrontp, wont, c);
                        if (myopts[c]) {
                                myopts[c] = 0;
                                sprintf(nfrontp, wont, c);
-                               nfrontp += sizeof(wont) - 2;
-                               if (showoptions)
-                                       printoption("<--", wont, c);
+                               nfrontp += sizeof (wont) - 2;
+                               printoption("SENT", wont, c);
                        }
                        state = TS_DATA;
                        continue;
                        }
                        state = TS_DATA;
                        continue;
@@ -550,7 +599,7 @@ willoption(option)
        switch (option) {
 
        case TELOPT_ECHO:
        switch (option) {
 
        case TELOPT_ECHO:
-               mode(1);
+               (void) mode(1);
 
        case TELOPT_SGA:
                hisopts[option] = 1;
 
        case TELOPT_SGA:
                hisopts[option] = 1;
@@ -566,9 +615,8 @@ willoption(option)
                break;
        }
        sprintf(nfrontp, fmt, option);
                break;
        }
        sprintf(nfrontp, fmt, option);
-       nfrontp += sizeof(dont) - 2;
-       if (showoptions)
-               printoption("<--", fmt, option);
+       nfrontp += sizeof (dont) - 2;
+       printoption("SENT", fmt, option);
 }
 
 wontoption(option)
 }
 
 wontoption(option)
@@ -579,7 +627,7 @@ wontoption(option)
        switch (option) {
 
        case TELOPT_ECHO:
        switch (option) {
 
        case TELOPT_ECHO:
-               mode(2);
+               (void) mode(2);
 
        case TELOPT_SGA:
                hisopts[option] = 0;
 
        case TELOPT_SGA:
                hisopts[option] = 0;
@@ -590,9 +638,8 @@ wontoption(option)
                fmt = dont;
        }
        sprintf(nfrontp, fmt, option);
                fmt = dont;
        }
        sprintf(nfrontp, fmt, option);
-       nfrontp += sizeof(doopt) - 2;
-       if (showoptions)
-               printoption("<--", fmt, option);
+       nfrontp += sizeof (doopt) - 2;
+       printoption("SENT", fmt, option);
 }
 
 dooption(option)
 }
 
 dooption(option)
@@ -615,9 +662,8 @@ dooption(option)
                break;
        }
        sprintf(nfrontp, fmt, option);
                break;
        }
        sprintf(nfrontp, fmt, option);
-       nfrontp += sizeof(doopt) - 2;
-       if (showoptions)
-               printoption("<--", fmt, option);
+       nfrontp += sizeof (doopt) - 2;
+       printoption("SENT", fmt, option);
 }
 
 /*
 }
 
 /*
@@ -640,13 +686,37 @@ setescape(argc, argv)
        if (arg[0] != '\0')
                escape = arg[0];
        printf("Escape character is '%s'.\n", control(escape));
        if (arg[0] != '\0')
                escape = arg[0];
        printf("Escape character is '%s'.\n", control(escape));
+       fflush(stdout);
 }
 
 /*VARARGS*/
 setoptions()
 {
 }
 
 /*VARARGS*/
 setoptions()
 {
+
        showoptions = !showoptions;
        printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
        showoptions = !showoptions;
        printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
+       fflush(stdout);
+}
+
+/*VARARGS*/
+setcrmod()
+{
+
+       crmod = !crmod;
+       printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont");
+       fflush(stdout);
+}
+
+/*VARARGS*/
+setdebug()
+{
+
+       debug = !debug;
+       printf("%s turn on socket level debugging.\n",
+               debug ? "Will" : "Wont");
+       fflush(stdout);
+       if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0)
+               perror("setsockopt (SO_DEBUG)");
 }
 
 /*
 }
 
 /*
@@ -704,14 +774,14 @@ getcmd(name)
 deadpeer()
 {
        sigset(SIGPIPE, deadpeer);
 deadpeer()
 {
        sigset(SIGPIPE, deadpeer);
-       mode(0);
+       (void) mode(0);
        longjmp(peerdied, -1);
 }
 
 intr()
 {
        sigset(SIGINT, intr);
        longjmp(peerdied, -1);
 }
 
 intr()
 {
        sigset(SIGINT, intr);
-       mode(0);
+       (void) mode(0);
        longjmp(toplevel, -1);
 }
 
        longjmp(toplevel, -1);
 }
 
@@ -721,8 +791,8 @@ ttyflush(fd)
 
        if ((n = tfrontp - tbackp) > 0)
                n = write(fd, tbackp, n);
 
        if ((n = tfrontp - tbackp) > 0)
                n = write(fd, tbackp, n);
-       if (n < 0 && errno == EWOULDBLOCK)
-               n = 0;
+       if (n < 0)
+               return;
        tbackp += n;
        if (tbackp == tfrontp)
                tbackp = tfrontp = ttyobuf;
        tbackp += n;
        if (tbackp == tfrontp)
                tbackp = tfrontp = ttyobuf;
@@ -734,17 +804,28 @@ netflush(fd)
 
        if ((n = nfrontp - nbackp) > 0)
                n = write(fd, nbackp, n);
 
        if ((n = nfrontp - nbackp) > 0)
                n = write(fd, nbackp, n);
-       if (n < 0 && errno == EWOULDBLOCK)
+       if (n < 0) {
+               if (errno != ENOBUFS && errno != EWOULDBLOCK) {
+                       (void) mode(0);
+                       perror(hostname);
+                       close(fd);
+                       longjmp(peerdied, -1);
+                       /*NOTREACHED*/
+               }
                n = 0;
                n = 0;
+       }
        nbackp += n;
        if (nbackp == nfrontp)
                nbackp = nfrontp = netobuf;
 }
 
        nbackp += n;
        if (nbackp == nfrontp)
                nbackp = nfrontp = netobuf;
 }
 
-printoption(direction, fmt, option)
+/*VARARGS*/
+printoption(direction, fmt, option, what)
        char *direction, *fmt;
        char *direction, *fmt;
-       int option;
+       int option, what;
 {
 {
+       if (!showoptions)
+               return;
        printf("%s ", direction);
        if (fmt == doopt)
                fmt = "do";
        printf("%s ", direction);
        if (fmt == doopt)
                fmt = "do";
@@ -757,7 +838,12 @@ printoption(direction, fmt, option)
        else
                fmt = "???";
        if (option < TELOPT_SUPDUP)
        else
                fmt = "???";
        if (option < TELOPT_SUPDUP)
-               printf("%s %s\r\n", fmt, telopts[option]);
+               printf("%s %s", fmt, telopts[option]);
        else
        else
-               printf("%s %d\r\n", fmt, option);
+               printf("%s %d", fmt, option);
+       if (*direction == '<') {
+               printf("\r\n");
+               return;
+       }
+       printf(" (%s)\r\n", what ? "reply" : "don't reply");
 }
 }