various telnet-client updates making it capable of real use for vim/nethack/etc. on a real telnet server
diff --git a/telnet-client.c b/telnet-client.c
index b8e1a69..ba81f00 100644
--- a/telnet-client.c
+++ b/telnet-client.c
@@ -19,6 +19,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
+#include <termios.h>
 #include <unistd.h>
 
 #ifdef HAVE_ZLIB
@@ -27,6 +28,13 @@
 
 #include "libtelnet.h"
 
+static struct termios orig_tios;
+static int do_echo;
+
+static void _cleanup(void) {
+	tcsetattr(STDOUT_FILENO, TCSADRAIN, &orig_tios);
+}
+
 static void _send(int sock, unsigned char *buffer, unsigned int size) {
 	int rs;
 
@@ -61,10 +69,67 @@
 		break;
 	/* accept any options we want */
 	case LIBTELNET_EV_NEGOTIATE:
-		/* enable COMPRESS2 */
-		if (ev->command == LIBTELNET_WILL &&
-				ev->telopt == LIBTELNET_TELOPT_COMPRESS2)
-			libtelnet_send_negotiate(telnet, LIBTELNET_DO, ev->telopt);
+		switch (ev->command) {
+		case LIBTELNET_WILL:
+			switch (ev->telopt) {
+			/* accept request to enable compression */
+			case LIBTELNET_TELOPT_COMPRESS2:
+				libtelnet_send_negotiate(telnet, LIBTELNET_DO, ev->telopt);
+				break;
+			/* server "promises" to echo, so turn off local echo */
+			case LIBTELNET_TELOPT_ECHO:
+				do_echo = 0;
+				libtelnet_send_negotiate(telnet, LIBTELNET_DO, ev->telopt);
+				break;
+			/* unknown -- reject */
+			default:
+				libtelnet_send_negotiate(telnet, LIBTELNET_DONT, ev->telopt);
+				break;
+			}
+			break;
+
+		case LIBTELNET_WONT:
+			switch (ev->telopt) {
+			/* server wants us to do echoing, by telling us it won't */
+			case LIBTELNET_TELOPT_ECHO:
+				do_echo = 1;
+				libtelnet_send_negotiate(telnet, LIBTELNET_DONT, ev->telopt);
+				break;
+			}
+			break;
+
+		case LIBTELNET_DO:
+			switch (ev->telopt) {
+			/* accept request to enable terminal-type requests */
+			case LIBTELNET_TELOPT_TTYPE:
+				libtelnet_send_negotiate(telnet, LIBTELNET_WILL, ev->telopt);
+				break;
+			/* unknown - reject */
+			default:
+				libtelnet_send_negotiate(telnet, LIBTELNET_WONT, ev->telopt);
+				break;
+			}
+			break;
+
+		case LIBTELNET_DONT:
+			/* ignore for now */
+			break;
+		}
+		break;
+	/* respond to particular subnegotiations */
+	case LIBTELNET_EV_SUBNEGOTIATION:
+		/* respond with our terminal type */
+		if (ev->telopt == LIBTELNET_TELOPT_TTYPE) {
+			/* NOTE: we just assume the server sent a legitimate
+			 * sub-negotiation, as there really isn't anything else
+			 * it's allowed to send
+			 */
+			char buffer[64];
+			buffer[0] = 0; /* IS code for RFC 1091 */
+			snprintf(buffer + 1, sizeof(buffer) - 1, "%s", getenv("TERM"));
+			libtelnet_send_subnegotiation(telnet, LIBTELNET_TELOPT_TTYPE,
+					(unsigned char *)buffer, 1 + strlen(buffer + 1));
+		}
 		break;
 	/* error */
 	case LIBTELNET_EV_ERROR:
@@ -85,6 +150,7 @@
 	struct libtelnet_t telnet;
 	struct addrinfo *ai;
 	struct addrinfo hints;
+	struct termios tios;
 
 	/* check usage */
 	if (argc != 3) {
@@ -125,6 +191,18 @@
 	/* free address lookup info */
 	freeaddrinfo(ai);
 
+	/* get current terminal settings, set raw mode, make sure we
+	 * register atexit handler to restore terminal settings
+	 */
+	tcgetattr(STDOUT_FILENO, &orig_tios);
+	atexit(_cleanup);
+	tios = orig_tios;
+	cfmakeraw(&tios);
+	tcsetattr(STDOUT_FILENO, TCSADRAIN, &tios);
+
+	/* set input echoing on by default */
+	do_echo = 1;
+
 	/* initialize telnet box */
 	libtelnet_init(&telnet, _event_handler, LIBTELNET_MODE_CLIENT, &sock);
 
@@ -140,6 +218,11 @@
 		/* read from stdin */
 		if (pfd[0].revents & POLLIN) {
 			if ((rs = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) {
+				/* local echo */
+				if (do_echo)
+					write(STDOUT_FILENO, buffer, rs);
+
+				/* send over the wire */
 				libtelnet_send_data(&telnet, buffer, rs);
 			} else if (rs == 0) {
 				break;