rework to make a bit clearer, minor man page syntax stuff;
[unix-history] / usr / src / usr.bin / telnet / telnet.c
index eb71c08..0d1d528 100644 (file)
@@ -1,42 +1,61 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, 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'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
- All rights reserved.\n";
-#endif not lint
+static char sccsid[] = "@(#)telnet.c   5.38 (Berkeley) %G%";
+#endif /* not lint */
 
 
-#ifndef lint
-static char sccsid[] = "@(#)telnet.c   5.2 (Berkeley) %G%";
-#endif not lint
-
-/*
- * User telnet program.
- */
 #include <sys/types.h>
 #include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
 
 
-#include <netinet/in.h>
+#if    defined(unix)
+#include <signal.h>
+/* 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>
+#endif /* defined(unix) */
 
 
-#define        TELOPTS
 #include <arpa/telnet.h>
 
 #include <arpa/telnet.h>
 
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <netdb.h>
+#if    defined(unix)
+#include <strings.h>
+#else  /* defined(unix) */
+#include <string.h>
+#endif /* defined(unix) */
+
+#include "ring.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "types.h"
+#include "general.h"
 
 
-#define        strip(x)        ((x)&0177)
+\f
+#define        strip(x)        ((x)&0x7f)
 
 
-char   ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf;
-char   netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf;
+
+static char    subbuffer[SUBBUFSIZE],
+               *subpointer, *subend;    /* buffer for sub-options */
+#define        SB_CLEAR()      subpointer = subbuffer;
+#define        SB_TERM()       subend = subpointer;
+#define        SB_ACCUM(c)     if (subpointer < (subbuffer+sizeof subbuffer)) { \
+                               *subpointer++ = (c); \
+                       }
 
 char   hisopts[256];
 char   myopts[256];
 
 char   hisopts[256];
 char   myopts[256];
@@ -46,654 +65,236 @@ char      dont[] = { IAC, DONT, '%', 'c', 0 };
 char   will[] = { IAC, WILL, '%', 'c', 0 };
 char   wont[] = { IAC, WONT, '%', 'c', 0 };
 
 char   will[] = { IAC, WILL, '%', 'c', 0 };
 char   wont[] = { IAC, WONT, '%', 'c', 0 };
 
-int    connected;
-int    net;
-int    showoptions = 0;
-int    options;
-int    debug = 0;
-int    crmod = 0;
-char   *prompt;
-char   escape = CTRL(]);
-
-char   line[200];
-int    margc;
-char   *margv[20];
-
-jmp_buf        toplevel;
-jmp_buf        peerdied;
-
-extern int errno;
-
-int    tn(), quit(), suspend(), bye(), help();
-int    setescape(), status(), toggle(), setoptions();
-int    setcrmod(), setdebug(), sendesc(), ayt(), intp();
-
-#define HELPINDENT (sizeof ("connect"))
-
-struct cmd {
-       char    *name;          /* command name */
-       char    *help;          /* help string */
-       int     (*handler)();   /* routine which executes command */
-};
-
-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";
-char   sendeschelp[] = "send escape character";
-char   aythelp[] =     "send Are You There";
-char   intphelp[] =    "send Interrupt Process";
-
-struct cmd cmdtab[] = {
-       { "open",       openhelp,       tn },
-       { "close",      closehelp,      bye },
-       { "quit",       quithelp,       quit },
-       { "z",          zhelp,          suspend },
-       { "escape",     escapehelp,     setescape },
-       { "status",     statushelp,     status },
-       { "options",    optionshelp,    setoptions },
-       { "crmod",      crmodhelp,      setcrmod },
-       { "debug",      debughelp,      setdebug },
-       { "ayt",        aythelp,        ayt },
-       { "interrupt",  intphelp,       intp },
-       { "passthru",   sendeschelp,    sendesc },
-       { "?",          helphelp,       help },
-       0
-};
-
-struct sockaddr_in sin;
-
-int    intr(), deadpeer();
-char   *control();
-struct cmd *getcmd();
-struct servent *sp;
-
-struct tchars otc;
-struct ltchars oltc;
-struct sgttyb ottyb;
-
-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, TIOCGETP, (char *)&ottyb);
-       ioctl(0, TIOCGETC, (char *)&otc);
-       ioctl(0, TIOCGLTC, (char *)&oltc);
-       setbuf(stdin, 0);
-       setbuf(stdout, 0);
-       prompt = argv[0];
-       if (argc > 1 && !strcmp(argv[1], "-d")) {
-               debug = 1;
-               argv++;
-               argc--;
-       }
-       if (argc != 1) {
-               if (setjmp(toplevel) != 0)
-                       exit(0);
-               tn(argc, argv);
-       }
-       setjmp(toplevel);
-       for (;;)
-               command(1);
-}
-
-char   *hostname;
-char   hnamebuf[32];
-
-tn(argc, argv)
-       int argc;
-       char *argv[];
-{
-       register int c;
-       register struct hostent *host;
-
-       if (connected) {
-               printf("?Already connected to %s\n", hostname);
-               return;
-       }
-       if (argc < 2) {
-               strcpy(line, "Connect ");
-               printf("(to) ");
-               gets(&line[strlen(line)]);
-               makeargv();
-               argc = margc;
-               argv = margv;
-       }
-       if (argc > 3) {
-               printf("usage: %s host-name [port]\n", argv[0]);
-               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;
-               }
-               sin.sin_port = htons(sin.sin_port);
-       }
-       net = socket(AF_INET, SOCK_STREAM, 0);
-       if (net < 0) {
-               perror("telnet: socket");
-               return;
-       }
-       if (debug &&
-           setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0)
-               perror("setsockopt (SO_DEBUG)");
-       signal(SIGINT, intr);
-       signal(SIGPIPE, deadpeer);
-       printf("Trying...\n");
-       if (connect(net, (caddr_t)&sin, sizeof (sin)) < 0) {
-               perror("telnet: connect");
-               signal(SIGINT, SIG_DFL);
-               return;
-       }
-       connected++;
-       call(status, "status", 0);
-       if (setjmp(peerdied) == 0)
-               telnet(net);
-       fprintf(stderr, "Connection closed by foreign host.\n");
-       exit(1);
-}
+int
+       connected,
+       showoptions,
+       In3270,         /* Are we in 3270 mode? */
+       ISend,          /* trying to send network data in */
+       debug = 0,
+       crmod,
+       netdata,        /* Print out network data flow */
+       crlf,           /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+#if    defined(TN3270)
+       noasynchtty = 0,/* User specified "-noasynch" on command line */
+       noasynchnet = 0,/* User specified "-noasynch" on command line */
+       askedSGA = 0,   /* We have talked about suppress go ahead */
+#endif /* defined(TN3270) */
+       telnetport,
+       SYNCHing,       /* we are in TELNET SYNCH mode */
+       flushout,       /* flush output */
+       autoflush = 0,  /* flush output when interrupting? */
+       autosynch,      /* send interrupt characters with SYNCH? */
+       localchars,     /* we recognize interrupt/quit */
+       donelclchars,   /* the user has set "localchars" */
+       donebinarytoggle,       /* the user has put us in binary */
+       dontlecho,      /* do we suppress local echoing right now? */
+       globalmode;
+
+#define        CONTROL(x)      ((x)&0x1f)              /* CTRL(x) is not portable */
+
+char
+       *prompt = 0,
+       escape,
+       echoc;
 
 /*
 
 /*
- * Print status about the connection.
+ * Telnet receiver states for fsm
  */
  */
-/*VARARGS*/
-status()
-{
-       if (connected)
-               printf("Connected to %s.\n", hostname);
-       else
-               printf("No connection.\n");
-       printf("Escape character is '%s'.\n", control(escape));
-       fflush(stdout);
-}
+#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 */
 
 
-makeargv()
-{
-       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;
-}
+static int     telrcv_state;
 
 
-/*VARARGS*/
-suspend()
-{
-       register int save;
-
-       save = mode(0);
-       kill(0, SIGTSTP);
-       /* reget parameters in case they were changed */
-       ioctl(0, TIOCGETP, (char *)&ottyb);
-       ioctl(0, TIOCGETC, (char *)&otc);
-       ioctl(0, TIOCGLTC, (char *)&oltc);
-       (void) mode(save);
-}
-
-/*VARARGS*/
-bye()
-{
-       register char *op;
-
-       (void) mode(0);
-       if (connected) {
-               shutdown(net, 2);
-               printf("Connection closed.\n");
-               close(net);
-               connected = 0;
-               /* reset his options */
-               for (op = hisopts; op < &hisopts[256]; op++)
-                       *op = 0;
-       }
-}
+jmp_buf        toplevel = { 0 };
+jmp_buf        peerdied;
 
 
-/*VARARGS*/
-quit()
-{
-       call(bye, "bye", 0);
-       exit(0);
-}
+int    flushline;
 
 /*
 
 /*
- * Help command.
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
  */
  */
-help(argc, argv)
-       int argc;
-       char *argv[];
-{
-       register struct cmd *c;
 
 
-       if (argc == 1) {
-               printf("Commands may be abbreviated.  Commands are:\n\n");
-               for (c = cmdtab; c->name; c++)
-                       printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
-               return;
-       }
-       while (--argc > 0) {
-               register char *arg;
-               arg = *++argv;
-               c = getcmd(arg);
-               if (c == (struct cmd *)-1)
-                       printf("?Ambiguous help command %s\n", arg);
-               else if (c == (struct cmd *)0)
-                       printf("?Invalid help command %s\n", arg);
-               else
-                       printf("%s\n", c->help);
-       }
-}
+Clocks clocks;
+\f
+Modelist 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
 /*
 /*
- * Call routine with argc, argv set from args (terminated by 0).
- * VARARGS2
+ * Initialize telnet environment.
  */
  */
-call(routine, args)
-       int (*routine)();
-       int args;
-{
-       register int *argp;
-       register int argc;
-
-       for (argc = 0, argp = &args; *argp++ != 0; argc++)
-               ;
-       (*routine)(argc, &args);
-}
-
-struct tchars notc =   { -1, -1, -1, -1, -1, -1 };
-struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
 
 
-mode(f)
-       register int f;
+init_telnet()
 {
 {
-       static int prevmode = 0;
-       struct tchars *tc;
-       struct ltchars *ltc;
-       struct sgttyb sb;
-       int onoff, old;
-
-       if (prevmode == f)
-               return (f);
-       old = prevmode;
-       prevmode = f;
-       sb = ottyb;
-       switch (f) {
-
-       case 0:
-               onoff = 0;
-               tc = &otc;
-               ltc = &oltc;
-               break;
-
-       case 1:
-       case 2:
-               sb.sg_flags |= CBREAK;
-               if (f == 1)
-                       sb.sg_flags &= ~(ECHO|CRMOD);
-               else
-                       sb.sg_flags |= ECHO|CRMOD;
-               sb.sg_erase = sb.sg_kill = -1;
-               tc = &notc;
-               ltc = &noltc;
-               onoff = 1;
-               break;
-
-       default:
-               return;
-       }
-       ioctl(fileno(stdin), TIOCSLTC, (char *)ltc);
-       ioctl(fileno(stdin), TIOCSETC, (char *)tc);
-       ioctl(fileno(stdin), TIOCSETP, (char *)&sb);
-       ioctl(fileno(stdin), FIONBIO, &onoff);
-       ioctl(fileno(stdout), FIONBIO, &onoff);
-       return (old);
-}
-
-char   sibuf[BUFSIZ], *sbp;
-char   tibuf[BUFSIZ], *tbp;
-int    scc, tcc;
-
-/*
- * Select from tty and network...
- */
-telnet(s)
-       int s;
-{
-       register int c;
-       int tin = fileno(stdin), tout = fileno(stdout);
-       int on = 1;
-
-       (void) mode(2);
-       ioctl(s, FIONBIO, &on);
-       if (!hisopts[TELOPT_SGA])
-               willoption(TELOPT_SGA);
-       for (;;) {
-               int ibits = 0, obits = 0;
-
-               if (nfrontp - nbackp)
-                       obits |= (1 << s);
-               else
-                       ibits |= (1 << tin);
-               if (tfrontp - tbackp)
-                       obits |= (1 << tout);
-               else
-                       ibits |= (1 << s);
-               if (scc < 0 && tcc < 0)
-                       break;
-               select(16, &ibits, &obits, 0, 0);
-               if (ibits == 0 && obits == 0) {
-                       sleep(5);
-                       continue;
-               }
+    SB_CLEAR();
+    ClearArray(hisopts);
+    ClearArray(myopts);
 
 
-               /*
-                * Something to read from the network...
-                */
-               if (ibits & (1 << s)) {
-                       scc = read(s, sibuf, sizeof (sibuf));
-                       if (scc < 0 && errno == EWOULDBLOCK)
-                               scc = 0;
-                       else {
-                               if (scc <= 0)
-                                       break;
-                               sbp = sibuf;
-                       }
-               }
+    connected = In3270 = ISend = donebinarytoggle = 0;
 
 
-               /*
-                * Something to read from the tty...
-                */
-               if (ibits & (1 << tin)) {
-                       tcc = read(tin, tibuf, sizeof (tibuf));
-                       if (tcc < 0 && errno == EWOULDBLOCK)
-                               tcc = 0;
-                       else {
-                               if (tcc <= 0)
-                                       break;
-                               tbp = tibuf;
-                       }
-               }
+    SYNCHing = 0;
 
 
-               while (tcc > 0) {
-                       register int c;
+    /* Don't change NetTrace */
 
 
-                       if ((&netobuf[BUFSIZ] - nfrontp) < 2)
-                               break;
-                       c = *tbp++ & 0377, tcc--;
-                       if (strip(c) == escape) {
-                               command(0);
-                               tcc = 0;
-                               break;
-                       }
-                       switch (c) {
-                       case '\n':
-                               if (!hisopts[TELOPT_ECHO])
-                                       *nfrontp++ = '\r';
-                               *nfrontp++ = '\n';
-                               break;
-                       case '\r':
-                               *nfrontp++ = '\r';
-                               if (hisopts[TELOPT_ECHO])
-                                       *nfrontp++ = '\n';
-                               else
-                                       *nfrontp++ = '\0';
-                               break;
-                       case IAC:
-                               *nfrontp++ = IAC;
-                               /* fall into ... */
-                       default:
-                               *nfrontp++ = c;
-                               break;
-                       }
-               }
-               if ((obits & (1 << s)) && (nfrontp - nbackp) > 0)
-                       netflush(s);
-               if (scc > 0)
-                       telrcv();
-               if ((obits & (1 << tout)) && (tfrontp - tbackp) > 0)
-                       ttyflush(tout);
-       }
-       (void) mode(0);
-}
+    escape = CONTROL(']');
+    echoc = CONTROL('E');
 
 
-command(top)
-       int top;
-{
-       register struct cmd *c;
-       int oldmode, wasopen;
-
-       oldmode = mode(0);
-       if (!top)
-               putchar('\n');
-       else
-               signal(SIGINT, SIG_DFL);
-       for (;;) {
-               printf("%s> ", prompt);
-               if (gets(line) == 0) {
-                       if (feof(stdin)) {
-                               clearerr(stdin);
-                               putchar('\n');
-                       }
-                       break;
-               }
-               if (line[0] == 0)
-                       break;
-               makeargv();
-               c = getcmd(margv[0]);
-               if (c == (struct cmd *)-1) {
-                       printf("?Ambiguous command\n");
-                       continue;
-               }
-               if (c == 0) {
-                       printf("?Invalid command\n");
-                       continue;
-               }
-               (*c->handler)(margc, margv);
-               if (c->handler != help)
-                       break;
-       }
-       if (!top) {
-               if (!connected)
-                       longjmp(toplevel, 1);
-               (void) mode(oldmode);
-       }
+    flushline = 1;
+    telrcv_state = TS_DATA;
 }
 }
+\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
+#include <varargs.h>
 
 
-telrcv()
+/*VARARGS*/
+static void
+printring(va_alist)
+va_dcl
 {
 {
-       register int c;
-       static int state = TS_DATA;
-
-       while (scc > 0) {
-               c = *sbp++ & 0377, scc--;
-               switch (state) {
-
-               case TS_DATA:
-                       if (c == IAC) {
-                               state = TS_IAC;
-                               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:
-                       switch (c) {
-                       
-                       case WILL:
-                               state = TS_WILL;
-                               continue;
-
-                       case WONT:
-                               state = TS_WONT;
-                               continue;
-
-                       case DO:
-                               state = TS_DO;
-                               continue;
-
-                       case DONT:
-                               state = TS_DONT;
-                               continue;
-
-                       case DM:
-                               ioctl(fileno(stdout), TIOCFLUSH, 0);
-                               break;
-
-                       case NOP:
-                       case GA:
-                               break;
-
-                       default:
-                               break;
-                       }
-                       state = TS_DATA;
-                       continue;
-
-               case TS_WILL:
-                       printoption("RCVD", will, c, !hisopts[c]);
-                       if (!hisopts[c])
-                               willoption(c);
-                       state = TS_DATA;
-                       continue;
-
-               case TS_WONT:
-                       printoption("RCVD", wont, c, hisopts[c]);
-                       if (hisopts[c])
-                               wontoption(c);
-                       state = TS_DATA;
-                       continue;
-
-               case TS_DO:
-                       printoption("RCVD", doopt, c, !myopts[c]);
-                       if (!myopts[c])
-                               dooption(c);
-                       state = TS_DATA;
-                       continue;
-
-               case TS_DONT:
-                       printoption("RCVD", dont, c, myopts[c]);
-                       if (myopts[c]) {
-                               myopts[c] = 0;
-                               sprintf(nfrontp, wont, c);
-                               nfrontp += sizeof (wont) - 2;
-                               printoption("SENT", wont, c);
-                       }
-                       state = TS_DATA;
-                       continue;
-               }
+    va_list ap;
+    char buffer[100];          /* where things go */
+    char *ptr;
+    char *format;
+    char *string;
+    Ring *ring;
+    int i;
+
+    va_start(ap);
+
+    ring = va_arg(ap, Ring *);
+    format = va_arg(ap, char *);
+    ptr = buffer;
+
+    while ((i = *format++) != 0) {
+       if (i == '%') {
+           i = *format++;
+           switch (i) {
+           case 'c':
+               *ptr++ = va_arg(ap, int);
+               break;
+           case 's':
+               string = va_arg(ap, char *);
+               ring_supply_data(ring, buffer, ptr-buffer);
+               ring_supply_data(ring, string, strlen(string));
+               ptr = buffer;
+               break;
+           case 0:
+               ExitString("printring: trailing %%.\n", 1);
+               /*NOTREACHED*/
+           default:
+               ExitString("printring: unknown format character.\n", 1);
+               /*NOTREACHED*/
+           }
+       } else {
+           *ptr++ = i;
        }
        }
+    }
+    ring_supply_data(ring, buffer, ptr-buffer);
 }
 
 }
 
-willoption(option)
-       int option;
+
+void
+willoption(option, reply)
+       int option, reply;
 {
        char *fmt;
 
        switch (option) {
 
        case TELOPT_ECHO:
 {
        char *fmt;
 
        switch (option) {
 
        case TELOPT_ECHO:
-               (void) mode(1);
-
+#      if defined(TN3270)
+           /*
+            * The following is a pain in the rear-end.
+            * Various IBM servers (some versions of Wiscnet,
+            * possibly Fibronics/Spartacus, and who knows who
+            * else) will NOT allow us to send "DO SGA" too early
+            * in the setup proceedings.  On the other hand,
+            * 4.2 servers (telnetd) won't set SGA correctly.
+            * So, we are stuck.  Empirically (but, based on
+            * a VERY small sample), the IBM servers don't send
+            * out anything about ECHO, so we postpone our sending
+            * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
+            * DO send).
+            */
+           {
+               if (askedSGA == 0) {
+                   askedSGA = 1;
+                   if (!hisopts[TELOPT_SGA]) {
+                       willoption(TELOPT_SGA, 0);
+                   }
+               }
+           }
+               /* Fall through */
+       case TELOPT_EOR:
+       case TELOPT_BINARY:
+#endif /* defined(TN3270) */
        case TELOPT_SGA:
        case TELOPT_SGA:
+               settimer(modenegotiated);
                hisopts[option] = 1;
                fmt = doopt;
                hisopts[option] = 1;
                fmt = doopt;
+               setconnmode();          /* possibly set new tty mode */
                break;
 
        case TELOPT_TM:
                break;
 
        case TELOPT_TM:
-               fmt = dont;
-               break;
+               return;                 /* Never reply to TM will's/wont's */
 
        default:
                fmt = dont;
                break;
        }
 
        default:
                fmt = dont;
                break;
        }
-       sprintf(nfrontp, fmt, option);
-       nfrontp += sizeof (dont) - 2;
-       printoption("SENT", fmt, option);
+       printring(&netoring, fmt, option);
+       if (reply)
+               printoption(">SENT", fmt, option, reply);
+       else
+               printoption("<SENT", fmt, option, reply);
 }
 
 }
 
-wontoption(option)
-       int option;
+void
+wontoption(option, reply)
+       int option, reply;
 {
        char *fmt;
 
        switch (option) {
 
        case TELOPT_ECHO:
 {
        char *fmt;
 
        switch (option) {
 
        case TELOPT_ECHO:
-               (void) mode(2);
-
        case TELOPT_SGA:
        case TELOPT_SGA:
+               settimer(modenegotiated);
                hisopts[option] = 0;
                fmt = dont;
                hisopts[option] = 0;
                fmt = dont;
+               setconnmode();                  /* Set new tty mode */
                break;
 
                break;
 
+       case TELOPT_TM:
+               return;         /* Never reply to TM will's/wont's */
+
        default:
        default:
+               hisopts[option] = 0;
                fmt = dont;
        }
                fmt = dont;
        }
-       sprintf(nfrontp, fmt, option);
-       nfrontp += sizeof (doopt) - 2;
-       printoption("SENT", fmt, option);
+       printring(&netoring, fmt, option);
+       if (reply)
+               printoption(">SENT", fmt, option, reply);
+       else
+               printoption("<SENT", fmt, option, reply);
 }
 
 }
 
+static void
 dooption(option)
        int option;
 {
 dooption(option)
        int option;
 {
@@ -702,222 +303,750 @@ dooption(option)
        switch (option) {
 
        case TELOPT_TM:
        switch (option) {
 
        case TELOPT_TM:
-               fmt = wont;
-               break;
-
-       case TELOPT_ECHO:
-               (void) mode(2);
                fmt = will;
                fmt = will;
-               hisopts[option] = 0;
                break;
 
                break;
 
-       case TELOPT_SGA:
+#      if defined(TN3270)
+       case TELOPT_EOR:
+       case TELOPT_BINARY:
+#      endif   /* defined(TN3270) */
+       case TELOPT_TTYPE:              /* terminal type option */
+       case TELOPT_SGA:                /* no big deal */
                fmt = will;
                fmt = will;
+               myopts[option] = 1;
                break;
 
                break;
 
+       case TELOPT_ECHO:               /* We're never going to echo... */
        default:
                fmt = wont;
                break;
        }
        default:
                fmt = wont;
                break;
        }
-       sprintf(nfrontp, fmt, option);
-       nfrontp += sizeof (doopt) - 2;
-       printoption("SENT", fmt, option);
+       printring(&netoring, fmt, option);
+       printoption(">SENT", fmt, option, 0);
 }
 
 /*
 }
 
 /*
- * Set the escape character.
+ * suboption()
+ *
+ *     Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ *
+ *     Currently we recognize:
+ *
+ *             Terminal type, send request.
  */
  */
-setescape(argc, argv)
-       int argc;
-       char *argv[];
+
+static void
+suboption()
 {
 {
-       register char *arg;
-       char buf[50];
-
-       if (argc > 2)
-               arg = argv[1];
-       else {
-               printf("new escape character: ");
-               gets(buf);
-               arg = buf;
+    printsub("<", subbuffer, subend-subbuffer+1);
+    switch (subbuffer[0]&0xff) {
+    case TELOPT_TTYPE:
+       if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
+           ;
+       } else {
+           char *name;
+           char namebuf[41];
+           extern char *getenv();
+           int len;
+
+#if    defined(TN3270)
+           if (tn3270_ttype()) {
+               return;
+           }
+#endif /* defined(TN3270) */
+           name = getenv("TERM");
+           if ((name == 0) || ((len = strlen(name)) > 40)) {
+               name = "UNKNOWN";
+               len = strlen(name);
+           }
+           if ((len + 4+2) < NETROOM()) {
+               strcpy(namebuf, name);
+               upcase(namebuf);
+               printring(&netoring, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+                                   TELQUAL_IS, namebuf, IAC, SE);
+               /* XXX */
+               /* printsub(">", nfrontp+2, 4+strlen(namebuf)+2-2-2); */
+           } else {
+               ExitString("No room in buffer for terminal type.\n",
+                                                       1);
+               /*NOTREACHED*/
+           }
        }
        }
-       if (arg[0] != '\0')
-               escape = arg[0];
-       printf("Escape character is '%s'.\n", control(escape));
-       fflush(stdout);
+
+    default:
+       break;
+    }
 }
 }
+\f
 
 
-/*VARARGS*/
-setoptions()
+int
+telrcv()
 {
 {
+    register int c;
+    register int scc;
+    register char *sbp;
+    int count;
+    int returnValue = 0;
+
+    scc = 0;
+    count = 0;
+    while (TTYROOM() > 2) {
+       if (scc == 0) {
+           if (count) {
+               ring_consumed(&netiring, count);
+               returnValue = 1;
+               count = 0;
+           }
+           sbp = netiring.consume;
+           scc = ring_full_consecutive(&netiring);
+           if (scc == 0) {
+               /* No more data coming in */
+               break;
+           }
+       }
 
 
-       showoptions = !showoptions;
-       printf("%s show option processing.\n", showoptions ? "Will" : "Wont");
-       fflush(stdout);
-}
+       c = *sbp++ & 0xff, scc--; count++;
 
 
-/*VARARGS*/
-setcrmod()
-{
+       switch (telrcv_state) {
+
+       case TS_CR:
+           telrcv_state = TS_DATA;
+           if (c == '\0') {
+               break;  /* Ignore \0 after CR */
+           } else if ((c == '\n') && (!hisopts[TELOPT_ECHO]) && !crmod) {
+               TTYADD(c);
+               break;
+           }
+           /* Else, fall through */
+
+       case TS_DATA:
+           if (c == IAC) {
+               telrcv_state = TS_IAC;
+               break;
+           }
+#          if defined(TN3270)
+           if (In3270) {
+               *Ifrontp++ = c;
+               while (scc > 0) {
+                   c = *sbp++ & 0377, scc--; count++;
+                   if (c == IAC) {
+                       telrcv_state = TS_IAC;
+                       break;
+                   }
+                   *Ifrontp++ = c;
+               }
+           } else
+#          endif /* defined(TN3270) */
+                   /*
+                    * The 'crmod' hack (see following) 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') && !hisopts[TELOPT_BINARY]) {
+               if (scc > 0) {
+                   c = *sbp&0xff;
+                   if (c == 0) {
+                       sbp++, scc--; count++;
+                       /* a "true" CR */
+                       TTYADD('\r');
+                   } else if (!hisopts[TELOPT_ECHO] &&
+                                       (c == '\n')) {
+                       sbp++, scc--; count++;
+                       TTYADD('\n');
+                   } else {
+                       TTYADD('\r');
+                       if (crmod) {
+                               TTYADD('\n');
+                       }
+                   }
+               } else {
+                   telrcv_state = TS_CR;
+                   TTYADD('\r');
+                   if (crmod) {
+                           TTYADD('\n');
+                   }
+               }
+           } else {
+               TTYADD(c);
+           }
+           continue;
+
+       case TS_IAC:
+           switch (c) {
+           
+           case WILL:
+               telrcv_state = TS_WILL;
+               continue;
+
+           case WONT:
+               telrcv_state = TS_WONT;
+               continue;
+
+           case DO:
+               telrcv_state = TS_DO;
+               continue;
+
+           case DONT:
+               telrcv_state = TS_DONT;
+               continue;
+
+           case DM:
+                   /*
+                    * We may have missed an urgent notification,
+                    * so make sure we flush whatever is in the
+                    * buffer currently.
+                    */
+               SYNCHing = 1;
+               ttyflush(1);
+               SYNCHing = stilloob();
+               settimer(gotDM);
+               break;
 
 
-       crmod = !crmod;
-       printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont");
-       fflush(stdout);
+           case NOP:
+           case GA:
+               break;
+
+           case SB:
+               SB_CLEAR();
+               telrcv_state = TS_SB;
+               continue;
+
+#          if defined(TN3270)
+           case EOR:
+               if (In3270) {
+                   Ibackp += DataFromNetwork(Ibackp, Ifrontp-Ibackp, 1);
+                   if (Ibackp == Ifrontp) {
+                       Ibackp = Ifrontp = Ibuf;
+                       ISend = 0;      /* should have been! */
+                   } else {
+                       ISend = 1;
+                   }
+               }
+               break;
+#          endif /* defined(TN3270) */
+
+           case IAC:
+#          if !defined(TN3270)
+               TTYADD(IAC);
+#          else /* !defined(TN3270) */
+               if (In3270) {
+                   *Ifrontp++ = IAC;
+               } else {
+                   TTYADD(IAC);
+               }
+#          endif /* !defined(TN3270) */
+               break;
+
+           default:
+               break;
+           }
+           telrcv_state = TS_DATA;
+           continue;
+
+       case TS_WILL:
+           printoption(">RCVD", will, c, !hisopts[c]);
+           if (c == TELOPT_TM) {
+               if (flushout) {
+                   flushout = 0;
+               }
+           } else if (!hisopts[c]) {
+               willoption(c, 1);
+           }
+           SetIn3270();
+           telrcv_state = TS_DATA;
+           continue;
+
+       case TS_WONT:
+           printoption(">RCVD", wont, c, hisopts[c]);
+           if (c == TELOPT_TM) {
+               if (flushout) {
+                   flushout = 0;
+               }
+           } else if (hisopts[c]) {
+               wontoption(c, 1);
+           }
+           SetIn3270();
+           telrcv_state = TS_DATA;
+           continue;
+
+       case TS_DO:
+           printoption(">RCVD", doopt, c, !myopts[c]);
+           if (!myopts[c])
+               dooption(c);
+           SetIn3270();
+           telrcv_state = TS_DATA;
+           continue;
+
+       case TS_DONT:
+           printoption(">RCVD", dont, c, myopts[c]);
+           if (myopts[c]) {
+               myopts[c] = 0;
+               printring(&netoring, wont, c);
+               flushline = 1;
+               setconnmode();  /* set new tty mode (maybe) */
+               printoption(">SENT", wont, c, 0);
+           }
+           SetIn3270();
+           telrcv_state = TS_DATA;
+           continue;
+
+       case TS_SB:
+           if (c == IAC) {
+               telrcv_state = TS_SE;
+           } else {
+               SB_ACCUM(c);
+           }
+           continue;
+
+       case TS_SE:
+           if (c != SE) {
+               if (c != IAC) {
+                   SB_ACCUM(IAC);
+               }
+               SB_ACCUM(c);
+               telrcv_state = TS_SB;
+           } else {
+               SB_TERM();
+               suboption();    /* handle sub-option */
+               SetIn3270();
+               telrcv_state = TS_DATA;
+           }
+       }
+    }
+    if (count)
+       ring_consumed(&netiring, count);
+    return returnValue||count;
 }
 
 }
 
-/*VARARGS*/
-setdebug()
+static int
+telsnd()
 {
 {
+    int tcc;
+    int count;
+    int returnValue = 0;
+    char *tbp;
+
+    tcc = 0;
+    count = 0;
+    while (NETROOM() > 2) {
+       register int sc;
+       register int c;
 
 
-       debug = debug ? 0 : 1;
-       printf("%s turn on socket level debugging.\n",
-               debug ? "Will" : "Wont");
-       fflush(stdout);
-       if (net > 0 &&
-           setsockopt(net, SOL_SOCKET, SO_DEBUG, &debug, sizeof(debug)) < 0)
-               perror("setsockopt (SO_DEBUG)");
+       if (tcc == 0) {
+           if (count) {
+               ring_consumed(&ttyiring, count);
+               returnValue = 1;
+               count = 0;
+           }
+           tbp = ttyiring.consume;
+           tcc = ring_full_consecutive(&ttyiring);
+           if (tcc == 0) {
+               break;
+           }
+       }
+       c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
+       if (sc == escape) {
+           command(0);
+           tcc = 0;
+           flushline = 1;
+           break;
+       } else if (MODE_LINE(globalmode) && (sc == echoc)) {
+           if (tcc > 0 && strip(*tbp) == echoc) {
+               tcc--; tbp++; count++;
+           } else {
+               dontlecho = !dontlecho;
+               settimer(echotoggle);
+               setconnmode();
+               flushline = 1;
+               break;
+           }
+       }
+       if (localchars) {
+           if (TerminalSpecialChars(sc) == 0) {
+               break;
+           }
+       }
+       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;
+           case '\r':
+               if (!crlf) {
+                   NET2ADD('\r', '\0');
+               } else {
+                   NET2ADD('\r', '\n');
+               }
+               flushline = 1;
+               break;
+           case IAC:
+               NET2ADD(IAC, IAC);
+               break;
+           default:
+               NETADD(c);
+               break;
+           }
+       } else if (c == IAC) {
+           NET2ADD(IAC, IAC);
+       } else {
+           NETADD(c);
+       }
+    }
+    if (count)
+       ring_consumed(&ttyiring, count);
+    return returnValue||count;         /* Non-zero if we did anything */
 }
 }
+\f
+/*
+ * Scheduler()
+ *
+ * Try to do something.
+ *
+ * If we do something useful, return 1; else return 0.
+ *
+ */
 
 
-sendesc()
+
+int
+Scheduler(block)
+int    block;                  /* should we block in the select ? */
 {
 {
-       *nfrontp++ = escape;
+               /* One wants to be a bit careful about setting returnValue
+                * to one, since a one implies we did some useful work,
+                * and therefore probably won't be called to block next
+                * time (TN3270 mode only).
+                */
+    int returnValue;
+    int netin, netout, netex, ttyin, ttyout;
+
+    /* Decide which rings should be processed */
+
+    netout = ring_full_count(&netoring) &&
+           (!MODE_LINE(globalmode) || flushline || myopts[TELOPT_BINARY]);
+    ttyout = ring_full_count(&ttyoring);
+
+#if    defined(TN3270)
+    ttyin = ring_empty_count(&ttyiring) && (shell_active == 0);
+#else  /* defined(TN3270) */
+    ttyin = ring_empty_count(&ttyiring);
+#endif /* defined(TN3270) */
+
+#if    defined(TN3270)
+    netin = ring_empty_count(&netiring);
+#   else /* !defined(TN3270) */
+    netin = !ISend && ring_empty_count(&netiring);
+#   endif /* !defined(TN3270) */
+
+    netex = !SYNCHing;
+
+    /* If we have seen a signal recently, reset things */
+#   if defined(TN3270) && defined(unix)
+    if (HaveInput) {
+       HaveInput = 0;
+       signal(SIGIO, inputAvailable);
+    }
+#endif /* defined(TN3270) && defined(unix) */
+
+    /* Call to system code to process rings */
+
+    returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
+
+    /* Now, look at the input rings, looking for work to do. */
+
+    if (ring_full_count(&ttyiring)) {
+#   if defined(TN3270)
+       if (In3270) {
+           int c;
+
+           c = DataFromTerminal(ttyiring.consume,
+                                       ring_full_consecutive(&ttyiring));
+           if (c) {
+               returnValue = 1;
+               ring_consumed(&ttyiring, c);
+           }
+       } else {
+#   endif /* defined(TN3270) */
+           returnValue |= telsnd();
+#   if defined(TN3270)
+       }
+#   endif /* defined(TN3270) */
+    }
+
+    if (ring_full_count(&netiring)) {
+#      if !defined(TN3270)
+       returnValue |= telrcv();
+#      else /* !defined(TN3270) */
+       returnValue = Push3270();
+#      endif /* !defined(TN3270) */
+    }
+    return returnValue;
 }
 }
-
-ayt()
+\f
+/*
+ * Select from tty and network...
+ */
+void
+telnet()
 {
 {
-       *nfrontp++ = IAC;
-       *nfrontp++ = AYT;
+    sys_telnet_init();
+
+#   if !defined(TN3270)
+    if (telnetport) {
+       if (!hisopts[TELOPT_SGA]) {
+           willoption(TELOPT_SGA, 0);
+       }
+       if (!myopts[TELOPT_TTYPE]) {
+           dooption(TELOPT_TTYPE);
+       }
+    }
+#   endif /* !defined(TN3270) */
+
+#   if !defined(TN3270)
+    for (;;) {
+       int schedValue;
+
+       while ((schedValue = Scheduler(0)) != 0) {
+           if (schedValue == -1) {
+               setcommandmode();
+               return;
+           }
+       }
+
+       if (Scheduler(1) == -1) {
+           setcommandmode();
+           return;
+       }
+    }
+#   else /* !defined(TN3270) */
+    for (;;) {
+       int schedValue;
+
+       while (!In3270 && !shell_active) {
+           if (Scheduler(1) == -1) {
+               setcommandmode();
+               return;
+           }
+       }
+
+       while ((schedValue = Scheduler(0)) != 0) {
+           if (schedValue == -1) {
+               setcommandmode();
+               return;
+           }
+       }
+               /* If there is data waiting to go out to terminal, don't
+                * schedule any more data for the terminal.
+                */
+       if (ring_full_count(&ttyoring)) {
+           schedValue = 1;
+       } else {
+           if (shell_active) {
+               if (shell_continue() == 0) {
+                   ConnectScreen();
+               }
+           } else if (In3270) {
+               schedValue = DoTerminalOutput();
+           }
+       }
+       if (schedValue && (shell_active == 0)) {
+           if (Scheduler(1) == -1) {
+               setcommandmode();
+               return;
+           }
+       }
+    }
+#   endif /* !defined(TN3270) */
 }
 }
+\f
+#if    0       /* XXX - this not being in is a bug */
+/*
+ * nextitem()
+ *
+ *     Return the address of the next "item" in the TELNET data
+ * stream.  This will be the address of the next character if
+ * the current address is a user data character, or it will
+ * be the address of the character following the TELNET command
+ * if the current address is a TELNET IAC ("I Am a Command")
+ * character.
+ */
 
 
-intp()
+static char *
+nextitem(current)
+char   *current;
 {
 {
-       *nfrontp++ = IAC;
-       *nfrontp++ = IP;
+    if ((*current&0xff) != IAC) {
+       return current+1;
+    }
+    switch (*(current+1)&0xff) {
+    case DO:
+    case DONT:
+    case WILL:
+    case WONT:
+       return current+3;
+    case SB:           /* loop forever looking for the SE */
+       {
+           register char *look = current+2;
+
+           for (;;) {
+               if ((*look++&0xff) == IAC) {
+                   if ((*look++&0xff) == SE) {
+                       return look;
+                   }
+               }
+           }
+       }
+    default:
+       return current+2;
+    }
 }
 }
+#endif /* 0 */
 
 /*
 
 /*
- * Construct a control character sequence
- * for a special character.
+ * netclear()
+ *
+ *     We are about to do a TELNET SYNCH operation.  Clear
+ * the path to the network.
+ *
+ *     Things are a bit tricky since we may have sent the first
+ * byte or so of a previous TELNET command into the network.
+ * So, we have to scan the network buffer from the beginning
+ * until we are up to where we want to be.
+ *
+ *     A side effect of what we do, just to keep things
+ * simple, is to clear the urgent data pointer.  The principal
+ * caller should be setting the urgent data pointer AFTER calling
+ * us in any case.
  */
  */
-char *
-control(c)
-       register int c;
-{
-       static char buf[3];
 
 
-       if (c == 0177)
-               return ("^?");
-       if (c >= 040) {
-               buf[0] = c;
-               buf[1] = 0;
+static void
+netclear()
+{
+#if    0       /* XXX */
+    register char *thisitem, *next;
+    char *good;
+#define        wewant(p)       ((nfrontp > p) && ((*p&0xff) == IAC) && \
+                               ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
+
+    thisitem = netobuf;
+
+    while ((next = nextitem(thisitem)) <= netobuf.send) {
+       thisitem = next;
+    }
+
+    /* Now, thisitem is first before/at boundary. */
+
+    good = netobuf;    /* where the good bytes go */
+
+    while (netoring.add > thisitem) {
+       if (wewant(thisitem)) {
+           int length;
+
+           next = thisitem;
+           do {
+               next = nextitem(next);
+           } while (wewant(next) && (nfrontp > next));
+           length = next-thisitem;
+           memcpy(good, thisitem, length);
+           good += length;
+           thisitem = next;
        } else {
        } else {
-               buf[0] = '^';
-               buf[1] = '@'+c;
-               buf[2] = 0;
+           thisitem = nextitem(thisitem);
        }
        }
-       return (buf);
+    }
+
+#endif /* 0 */
 }
 }
+\f
+/*
+ * These routines add various telnet commands to the data stream.
+ */
 
 
-struct cmd *
-getcmd(name)
-       register char *name;
+static void
+doflush()
 {
 {
-       register char *p, *q;
-       register struct cmd *c, *found;
-       register int nmatches, longest;
-
-       longest = 0;
-       nmatches = 0;
-       found = 0;
-       for (c = cmdtab; p = c->name; c++) {
-               for (q = name; *q == *p++; q++)
-                       if (*q == 0)            /* exact match? */
-                               return (c);
-               if (!*q) {                      /* the name was a prefix */
-                       if (q - name > longest) {
-                               longest = q - name;
-                               nmatches = 1;
-                               found = c;
-                       } else if (q - name == longest)
-                               nmatches++;
-               }
-       }
-       if (nmatches > 1)
-               return ((struct cmd *)-1);
-       return (found);
+    NET2ADD(IAC, DO);
+    NETADD(TELOPT_TM);
+    flushline = 1;
+    flushout = 1;
+    ttyflush(1);                       /* Flush/drop output */
+    /* do printoption AFTER flush, otherwise the output gets tossed... */
+    printoption("<SENT", doopt, TELOPT_TM, 0);
 }
 
 }
 
-deadpeer()
+void
+xmitAO()
 {
 {
-       (void) mode(0);
-       longjmp(peerdied, -1);
+    NET2ADD(IAC, AO);
+    if (autoflush) {
+       doflush();
+    }
 }
 
 }
 
-intr()
+
+void
+xmitEL()
 {
 {
-       (void) mode(0);
-       longjmp(toplevel, -1);
+    NET2ADD(IAC, EL);
 }
 
 }
 
-ttyflush(fd)
+void
+xmitEC()
 {
 {
-       int n;
+    NET2ADD(IAC, EC);
+}
 
 
-       if ((n = tfrontp - tbackp) > 0)
-               n = write(fd, tbackp, n);
-       if (n < 0)
-               return;
-       tbackp += n;
-       if (tbackp == tfrontp)
-               tbackp = tfrontp = ttyobuf;
+
+#if    defined(NOT43)
+int
+#else  /* defined(NOT43) */
+void
+#endif /* defined(NOT43) */
+dosynch()
+{
+    netclear();                        /* clear the path to the network */
+    NETADD(IAC);
+    setneturg();
+    NETADD(DM);
+
+#if    defined(NOT43)
+    return 0;
+#endif /* defined(NOT43) */
 }
 
 }
 
-netflush(fd)
+void
+intp()
 {
 {
-       int n;
-
-       if ((n = nfrontp - nbackp) > 0)
-               n = write(fd, nbackp, n);
-       if (n < 0) {
-               if (errno != ENOBUFS && errno != EWOULDBLOCK) {
-                       (void) mode(0);
-                       perror(hostname);
-                       close(fd);
-                       longjmp(peerdied, -1);
-                       /*NOTREACHED*/
-               }
-               n = 0;
-       }
-       nbackp += n;
-       if (nbackp == nfrontp)
-               nbackp = nfrontp = netobuf;
+    NET2ADD(IAC, IP);
+    flushline = 1;
+    if (autoflush) {
+       doflush();
+    }
+    if (autosynch) {
+       dosynch();
+    }
 }
 
 }
 
-/*VARARGS*/
-printoption(direction, fmt, option, what)
-       char *direction, *fmt;
-       int option, what;
+void
+sendbrk()
 {
 {
-       if (!showoptions)
-               return;
-       printf("%s ", direction);
-       if (fmt == doopt)
-               fmt = "do";
-       else if (fmt == dont)
-               fmt = "dont";
-       else if (fmt == will)
-               fmt = "will";
-       else if (fmt == wont)
-               fmt = "wont";
-       else
-               fmt = "???";
-       if (option < TELOPT_SUPDUP)
-               printf("%s %s", fmt, telopts[option]);
-       else
-               printf("%s %d", fmt, option);
-       if (*direction == '<') {
-               printf("\r\n");
-               return;
-       }
-       printf(" (%s)\r\n", what ? "reply" : "don't reply");
+    NET2ADD(IAC, BREAK);
+    flushline = 1;
+    if (autoflush) {
+       doflush();
+    }
+    if (autosynch) {
+       dosynch();
+    }
 }
 }