+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 = ¬c2;
+ } else {
+ tc = ¬c;
+ }
+ }
+ 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 = ¬c2;
+ 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>
+
+#if !defined(SO_OOBINLINE)
+#define SO_OOBINLINE
+#endif /* !defined(SO_OOBINLINE) */
+
+
+static char
+ termEofChar,
+ termEraseChar,
+ termFlushChar,
+ termIntChar,
+ termKillChar,
+ termLiteralNextChar,
+ termQuitChar;
+
+\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)) {
+ ctrlCCount++; /* XXX */
+ signal(SIGINT, CtrlCInterrupt);
+ } else {
+ closeallsockets();
+ exit(1);
+ }
+}
+\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;
+{
+ globalmode = f;
+ signal(SIGINT, CtrlCInterrupt);
+}
+
+
+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 */
+{
+}
+
+int
+TerminalSpecialChars(c) /* MSDOS */
+{
+ return 1;
+}
+
+
+static void
+TerminalRestoreState() /* MSDOS */
+{
+}
+
+
+static int
+TerminalWrite(fd, buffer, count) /* MSDOS */
+int fd;
+char *buffer;
+int count;
+{
+ return fwrite(buffer, sizeof (char), count, stdout);
+}
+
+
+static int
+NetClose(fd)
+{
+ return closesocket(fd);
+}
+
+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);
+ }
+}
+
+static void
+NetSigIO(fd) /* MSDOS */
+int fd;
+{
+}
+
+static void
+NetSetPgrp(fd) /* MSDOS */
+int fd;
+{
+}
+
+
+#endif /* defined(MSDOS) */
+\f
+/*
+ * Initialize variables.
+ */
+
+static void
+tninit()
+{
+#if defined(TN3270)
+ Sent3270TerminalType = 0;
+ Ifrontp = Ibackp = Ibuf;
+#endif /* defined(TN3270) */