partial RFC1143 implementation; only reacts to negotiation, cannot handle initiating it yet
diff --git a/README b/README
index de08386..51156ae 100644
--- a/README
+++ b/README
@@ -226,20 +226,76 @@
    The necessary processing depends on the specific commands; see
    the TELNET RFC for more information.
  
- LIBTELNET_EV_NEGOTIATE:
-   The NEGOTIATE event is sent when a TELNET neogitiation command
-   is received.
+ LIBTELNET_EV_WILL:
+ LIBTELNET_EV_DO:
+   The WILL and DO events are sent when a TELNET negotiation
+   command of the same name is received.
 
-   The event->command value will be one of LIBTELNET_WILL,
-   LIBTELNET_WONT, LIBTELNET_DO, or LIBTELNET_DONT.  The
-   event->telopt value will contain the option value being
-   negotiated.
+   WILL events are sent by the remote end when they wish to be
+   allowed to turn an option on on their end, or in confirmation
+   after you have sent a DO command to them.
 
-   libtelnet does not currently manage negotiation for you.  For
-   best practice in implementing TELNET negotiation, see:
+   DO events are sent by the remote end when they wish for you
+   to turn on an option on your end, or in confirmation after you
+   have sent a WILL command to them.
+
+   In either case, the TELNET option under negotiation will be in
+   event->telopt field.
+
+   If you support the option and wish for it to be enabled you
+   must set the event->accept field to 1, unless this event is
+   a confirmation for a previous WILL/DO command you sent to the
+   remote end.  If you do not set event->field to 1 then
+   libtelnet will send a rejection command back to the other end.
+
+   libtelnet manages some of the pecularities of negotiation for
+   you.  For information on libtelnet's negotiation method, see:
 
     http://www.faqs.org/rfcs/rfc1143.html
 
+   Examples:
+
+    You want remote end to use TTYPE, so you send DO TTYPE.
+    Remote accepts and sends WILL TTYPE.
+
+    Remote end wants you to use SGA, so they send DO_SGA.
+    You do not support SGA and set event->accept = 0.
+
+    Remote end wants to use ZMP, so they send WILL ZMP.
+    You support ZMP, so you set event->accept = 1 and enable
+    local ZMP support.
+
+    You want to use MCCP2, so you send WILL COMPRESS2.
+    Remote end accepts and sends DO COMPRESS2.
+
+   Note that in PROXY mode libtelnet will do no processing of its
+   own for you.
+
+ LIBTELNET_EV_WONT:
+ LIBTELNET_EV_DONT:
+   The WONT and DONT events are sent when the remote end of the
+   connection wishes to disable an option, when they are
+   refusing to a support an option that you have asked for, or
+   in confirmation of an option you have asked to be disabled.
+
+   Most commonly WONT and DONT events are sent as rejections of
+   features you requested by sending DO or WILL events.  Receiving
+   these events means the TELNET option is not or will not be
+   supported by the remote end, so give up.
+
+   Sometimes WONT or DONT will be sent for TELNET options that are
+   already enabled, but the remote end wishes to stop using.  You
+   cannot decline.  These events are demands that must be complied
+   with.  libtelnet will always send the appropriate response back
+   without consulting your application.  These events are sent to
+   allow your application to disable its own use of the features.
+
+   In either case, the TELNET option under negotiation will be in
+   event->telopt field.
+
+   Note that in PROXY mode libtelnet will do no processing of its
+   own for you.
+
  LIBTELNET_EV_SUBNEGOTIATION:
    Triggered whenever a TELNET sub-negotiation has been received.
    Sub-negotiations include the NAWS option for communicating
@@ -347,11 +403,9 @@
  libtelnet_send_negotiate(&telnet, LIBTELNET_WILL,
      LIBTELNET_OPTION_COMPRESS2, user_data);
 
-If a favorable DO COMPRESS2 is sent back from the client (processed
-in a LIBTELNET_EV_NEGOTIATE event, with event->command equal to
-LIBTELNET_DO and event->telopt equal to LIBTELNET_TELOPT_COMPRESS2),
-then the server application can begin compression at any time by
-calling libtelnet_begin_compress2().
+If a favorable DO COMPRESS2 is sent back from the client then the
+server application can begin compression at any time by calling
+libtelnet_begin_compress2().
 
 If a connection is in PROXY mode and COMPRESS2 support is enabled
 then libtelnet will automatically detect the start of a COMPRESS2
diff --git a/libtelnet.c b/libtelnet.c
index 4d53d2a..700cca1 100644
--- a/libtelnet.c
+++ b/libtelnet.c
@@ -22,6 +22,18 @@
 
 #include "libtelnet.h"
 
+/* RFC1143 state names */
+#define RFC1143_NO 0x00
+#define RFC1143_YES 0x01
+
+#define RFC1143_WANT 0x02
+#define RFC1143_OP 0x04
+
+#define RFC1143_WANTNO (RFC1143_WANT|RFC1143_YES)
+#define RFC1143_WANTYES (RFC1143_WANT|RFC1143_NO)
+#define RFC1143_WANTNO_OP (RFC1143_WANTNO|RFC1143_OP)
+#define RFC1143_WANTYES_OP (RFC1143_WANTYES|RFC1143_OP)
+
 /* buffer sizes */
 static const unsigned int _buffer_sizes[] = {
 	0,
@@ -33,18 +45,22 @@
 static const unsigned int _buffer_sizes_count =
 	sizeof(_buffer_sizes) / sizeof(_buffer_sizes[0]);
 
-/* event dispatch helper */
-static void _event(struct libtelnet_t *telnet,
+/* event dispatch helper; return value is value of the accept field of the
+ * event struct after dispatch; used for the funky REQUEST event */
+static int _event(struct libtelnet_t *telnet,
 		enum libtelnet_event_type_t type, unsigned char command,
 		unsigned char telopt, unsigned char *buffer, unsigned int size) {
 	struct libtelnet_event_t ev;
+	ev.buffer = buffer;
+	ev.size = size;
 	ev.type = type;
 	ev.command = command;
 	ev.telopt = telopt;
-	ev.buffer = buffer;
-	ev.size = size;
+	ev.accept = 0;
 
 	telnet->eh(telnet, &ev, telnet->ud);
+
+	return ev.accept;
 }
 
 /* error generation function */
@@ -102,6 +118,182 @@
 	return zlib;
 }
 
+/* negotiation handling magic */
+static void _negotiate(struct libtelnet_t *telnet, unsigned char cmd,
+		unsigned char telopt) {
+	struct libtelnet_rfc1143_t *qtmp;
+	int q;
+
+	/* in PROXY mode, just pass it thru and do nothing */
+	if (telnet->mode == LIBTELNET_MODE_PROXY) {
+		switch (cmd) {
+		case LIBTELNET_WILL:
+			_event(telnet, LIBTELNET_EV_WILL, cmd, telopt, 0, 0);
+			break;
+		case LIBTELNET_WONT:
+			_event(telnet, LIBTELNET_EV_WONT, cmd, telopt, 0, 0);
+			break;
+		case LIBTELNET_DO:
+			_event(telnet, LIBTELNET_EV_DO, cmd, telopt, 0, 0);
+			break;
+		case LIBTELNET_DONT:
+			_event(telnet, LIBTELNET_EV_DONT, cmd, telopt, 0, 0);
+			break;
+		}
+		return;
+	}
+
+	/* lookup the current state of the option */
+	for (q = 0; q != telnet->q_size; ++q) {
+		if (telnet->q[q].telopt == telopt)
+			break;
+	}
+
+	/* not found */
+	if (q == telnet->q_size) {
+		/* if the option is unfound then it is off on both ends... and there
+		 * is no need thus to respond to a WONT/DONT */
+		if (cmd == LIBTELNET_WONT || cmd == LIBTELNET_DONT)
+			return;
+
+		/* we're going to need to track state for it, so grow the queue
+		 * and put the telopt into it; bail on allocation error
+		 */
+		if ((qtmp = (struct libtelnet_rfc1143_t *)malloc(sizeof(
+				struct libtelnet_rfc1143_t) * (telnet->q_size + 1))) == 0) {
+			_error(telnet, __LINE__, __func__, LIBTELNET_ENOMEM, 0,
+					"malloc() failed: %s", strerror(errno));
+			return;
+		}
+		telnet->q = qtmp;
+		memset(&telnet->q[telnet->q_size], 0,
+				sizeof(struct libtelnet_rfc1143_t));
+		telnet->q[telnet->q_size].telopt = telopt;
+		q = telnet->q_size;
+		++telnet->q_size;
+	}
+
+	/* start processing... */
+	switch (cmd) {
+	/* request to enable option on remote end or confirm DO */
+	case LIBTELNET_WILL:
+		switch (telnet->q[q].him) {
+		case RFC1143_NO:
+			if (_event(telnet, LIBTELNET_EV_WILL, cmd, telopt, 0, 0) == 1) {
+				telnet->q[q].him = RFC1143_YES;
+				libtelnet_send_negotiate(telnet, LIBTELNET_DO, telopt);
+			} else
+				libtelnet_send_negotiate(telnet, LIBTELNET_DONT, telopt);
+			break;
+		case RFC1143_YES:
+			break;
+		case RFC1143_WANTNO:
+			telnet->q[q].him = RFC1143_NO;
+			_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
+					"DONT answered by WILL");
+			break;
+		case RFC1143_WANTNO_OP:
+			telnet->q[q].him = RFC1143_YES;
+			_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
+					"DONT answered by WILL");
+			break;
+		case RFC1143_WANTYES:
+			telnet->q[q].him = RFC1143_YES;
+			break;
+		case RFC1143_WANTYES_OP:
+			telnet->q[q].him = RFC1143_WANTNO;
+			libtelnet_send_negotiate(telnet, LIBTELNET_DONT, telopt);
+			break;
+		}
+		break;
+
+	/* request to disable option on remote end, confirm DONT, reject DO */
+	case LIBTELNET_WONT:
+		switch (telnet->q[q].him) {
+		case RFC1143_NO:
+			break;
+		case RFC1143_YES:
+			telnet->q[q].him = RFC1143_NO;
+			libtelnet_send_negotiate(telnet, LIBTELNET_DONT, telopt);
+			_event(telnet, LIBTELNET_EV_WONT, 0, telopt,
+					0, 0);
+			break;
+		case RFC1143_WANTNO:
+			telnet->q[q].him = RFC1143_NO;
+			_event(telnet, LIBTELNET_EV_WONT, 0, telopt,
+					0, 0);
+			break;
+		case RFC1143_WANTNO_OP:
+			telnet->q[q].him = RFC1143_WANTYES;
+			_event(telnet, LIBTELNET_EV_DO, 0, telopt,
+					0, 0);
+			break;
+		case RFC1143_WANTYES:
+		case RFC1143_WANTYES_OP:
+			telnet->q[q].him = RFC1143_NO;
+			break;
+		}
+		break;
+
+	/* request to enable option on local end or confirm WILL */
+	case LIBTELNET_DO:
+		switch (telnet->q[q].us) {
+		case RFC1143_NO:
+			if (_event(telnet, LIBTELNET_EV_DO, cmd, telopt, 0, 0) == 1) {
+				telnet->q[q].us = RFC1143_YES;
+				libtelnet_send_negotiate(telnet, LIBTELNET_WILL, telopt);
+			} else
+				libtelnet_send_negotiate(telnet, LIBTELNET_WONT, telopt);
+			break;
+		case RFC1143_YES:
+			break;
+		case RFC1143_WANTNO:
+			telnet->q[q].us = RFC1143_NO;
+			_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
+					"WONT answered by DO");
+			break;
+		case RFC1143_WANTNO_OP:
+			telnet->q[q].us = RFC1143_YES;
+			_error(telnet, __LINE__, __func__, LIBTELNET_EPROTOCOL, 0,
+					"WONT answered by DO");
+			break;
+		case RFC1143_WANTYES:
+			telnet->q[q].us = RFC1143_YES;
+			break;
+		case RFC1143_WANTYES_OP:
+			telnet->q[q].us = RFC1143_WANTNO;
+			libtelnet_send_negotiate(telnet, LIBTELNET_WONT, telopt);
+			break;
+		}
+		break;
+
+	/* request to disable option on local end, confirm WONT, reject WILL */
+	case LIBTELNET_DONT:
+		switch (telnet->q[q].us) {
+		case RFC1143_NO:
+			break;
+		case RFC1143_YES:
+			telnet->q[q].us = RFC1143_NO;
+			libtelnet_send_negotiate(telnet, LIBTELNET_WONT, telopt);
+			_event(telnet, LIBTELNET_EV_DONT, 0, telopt, 0, 0);
+			break;
+		case RFC1143_WANTNO:
+			telnet->q[q].us = RFC1143_NO;
+			_event(telnet, LIBTELNET_EV_WONT, 0, telopt, 0, 0);
+			break;
+		case RFC1143_WANTNO_OP:
+			telnet->q[q].us = RFC1143_WANTYES;
+			_event(telnet, LIBTELNET_EV_WILL, 0, telopt, 0, 0);
+			break;
+		case RFC1143_WANTYES:
+		case RFC1143_WANTYES_OP:
+			telnet->q[q].us = RFC1143_NO;
+			break;
+		}
+		break;
+	}
+}
+
 /* initialize a telnet state tracker */
 void libtelnet_init(struct libtelnet_t *telnet, libtelnet_event_handler_t eh,
 		enum libtelnet_mode_t mode, void *user_data) {
@@ -117,8 +309,8 @@
 	if (telnet->buffer != 0) {
 		free(telnet->buffer);
 		telnet->buffer = 0;
-		telnet->size = 0;
-		telnet->length = 0;
+		telnet->buffer_size = 0;
+		telnet->buffer_pos = 0;
 	}
 
 	/* free zlib box(es) */
@@ -132,6 +324,13 @@
 		free(telnet->z_deflate);
 		telnet->z_deflate = 0;
 	}
+
+	/* free RFC1143 queue */
+	if (telnet->q) {
+		free(telnet->q);
+		telnet->q = 0;
+		telnet->q_size = 0;
+	}
 }
 
 /* push a byte into the telnet buffer */
@@ -141,10 +340,10 @@
 	int i;
 
 	/* check if we're out of room */
-	if (telnet->length == telnet->size) {
+	if (telnet->buffer_pos == telnet->buffer_size) {
 		/* find the next buffer size */
 		for (i = 0; i != _buffer_sizes_count; ++i) {
-			if (_buffer_sizes[i] == telnet->size)
+			if (_buffer_sizes[i] == telnet->buffer_size)
 				break;
 		}
 
@@ -167,11 +366,11 @@
 		}
 
 		telnet->buffer = new_buffer;
-		telnet->size = _buffer_sizes[i + 1];
+		telnet->buffer_size = _buffer_sizes[i + 1];
 	}
 
 	/* push the byte, all set */
-	telnet->buffer[telnet->length++] = byte;
+	telnet->buffer[telnet->buffer_pos++] = byte;
 	return LIBTELNET_EOK;
 }
 
@@ -230,22 +429,22 @@
 
 		/* negotiation commands */
 		case LIBTELNET_STATE_DO:
-			_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_DO, byte, 0, 0);
+			_negotiate(telnet, LIBTELNET_DO, byte);
 			start = i + 1;
 			telnet->state = LIBTELNET_STATE_DATA;
 			break;
 		case LIBTELNET_STATE_DONT:
-			_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_DONT, byte, 0, 0);
+			_negotiate(telnet, LIBTELNET_DONT, byte);
 			start = i + 1;
 			telnet->state = LIBTELNET_STATE_DATA;
 			break;
 		case LIBTELNET_STATE_WILL:
-			_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_WILL, byte, 0, 0);
+			_negotiate(telnet, LIBTELNET_WILL, byte);
 			start = i + 1;
 			telnet->state = LIBTELNET_STATE_DATA;
 			break;
 		case LIBTELNET_STATE_WONT:
-			_event(telnet, LIBTELNET_EV_NEGOTIATE, LIBTELNET_WONT, byte, 0, 0);
+			_negotiate(telnet, LIBTELNET_WONT, byte);
 			start = i + 1;
 			telnet->state = LIBTELNET_STATE_DATA;
 			break;
@@ -253,7 +452,7 @@
 		/* subnegotiation -- determine subnegotiation telopt */
 		case LIBTELNET_STATE_SB:
 			telnet->sb_telopt = byte;
-			telnet->length = 0;
+			telnet->buffer_pos = 0;
 			telnet->state = LIBTELNET_STATE_SB_DATA;
 			break;
 
@@ -280,7 +479,7 @@
 
 				/* invoke callback */
 				_event(telnet, LIBTELNET_EV_SUBNEGOTIATION, 0,
-						telnet->sb_telopt, telnet->buffer, telnet->length);
+						telnet->sb_telopt, telnet->buffer, telnet->buffer_pos);
 
 #ifdef HAVE_ZLIB
 				/* if we are a client or a proxy and just received the
@@ -355,7 +554,8 @@
 		telnet->z_inflate->avail_out = sizeof(inflate_buffer);
 
 		/* inflate until buffer exhausted and all output is produced */
-		while (telnet->z_inflate->avail_in > 0 || telnet->z_inflate->avail_out == 0) {
+		while (telnet->z_inflate->avail_in > 0 ||
+				telnet->z_inflate->avail_out == 0) {
 			/* reset output buffer */
 
 			/* decompress */
@@ -405,7 +605,8 @@
 		telnet->z_deflate->avail_out = sizeof(deflate_buffer);
 
 		/* deflate until buffer exhausted and all output is produced */
-		while (telnet->z_deflate->avail_in > 0 || telnet->z_deflate->avail_out == 0) {
+		while (telnet->z_deflate->avail_in > 0 ||
+				telnet->z_deflate->avail_out == 0) {
 			/* compress */
 			if ((rs = deflate(telnet->z_deflate, Z_SYNC_FLUSH)) != Z_OK) {
 				_error(telnet, __LINE__, __func__, LIBTELNET_ECOMPRESS, 1,
@@ -519,3 +720,29 @@
 	telnet->z_deflate = zlib;
 #endif /* HAVE_ZLIB */
 }
+
+/* get local state of specific telopt */
+int libtelnet_get_telopt_local (struct libtelnet_t *telnet,
+		unsigned char telopt) {
+	int i;
+	/* search for entry, return state if found */
+	for (i = 0; i != telnet->q_size; ++i)
+		if (telnet->q[i].telopt == telopt)
+			return telnet->q[i].us & RFC1143_YES;
+
+	/* not found... so it's off */
+	return 0;
+}
+
+/* get remote state of specific telopt */
+int libtelnet_get_telopt_remote (struct libtelnet_t *telnet,
+		unsigned char telopt) {
+	int i;
+	/* search for entry, return state if found */
+	for (i = 0; i != telnet->q_size; ++i)
+		if (telnet->q[i].telopt == telopt)
+			return telnet->q[i].him & RFC1143_YES;
+
+	/* not found... so it's off */
+	return 0;
+}
diff --git a/libtelnet.h b/libtelnet.h
index 972f601..6c872b8 100644
--- a/libtelnet.h
+++ b/libtelnet.h
@@ -120,7 +120,10 @@
 	LIBTELNET_EV_DATA = 0,
 	LIBTELNET_EV_SEND,
 	LIBTELNET_EV_IAC,
-	LIBTELNET_EV_NEGOTIATE,
+	LIBTELNET_EV_WILL,
+	LIBTELNET_EV_WONT,
+	LIBTELNET_EV_DO,
+	LIBTELNET_EV_DONT,
 	LIBTELNET_EV_SUBNEGOTIATION,
 	LIBTELNET_EV_COMPRESS,
 	LIBTELNET_EV_WARNING,
@@ -129,15 +132,23 @@
 
 /* event information */
 struct libtelnet_event_t {
-	/* type of event */ 
-	enum libtelnet_event_type_t type;
-	/* command info: only for IAC event */
-	unsigned char command;
-	/* telopt info: for NEGOTIATE and SUBNEGOTIATION events */
-	unsigned char telopt;
 	/* data buffer: for DATA, SEND, SUBNEGOTIATION, and ERROR events */
 	unsigned char *buffer;
 	unsigned int size;
+	/* type of event */ 
+	enum libtelnet_event_type_t type;
+	/* IAC command */
+	unsigned char command;
+	/* telopt info: for negotiation events SUBNEGOTIATION */
+	unsigned char telopt;
+	/* accept status: for WILL and DO events */
+	unsigned char accept;
+};
+
+/* option negotiation state (RFC 1143) */
+struct libtelnet_rfc1143_t {
+	unsigned char telopt;
+	char us:4, him:4;
 };
 
 /* event handler declaration */
@@ -155,18 +166,22 @@
 	z_stream *z_deflate;
 	z_stream *z_inflate;
 #endif
+	/* RFC1143 option negotiation states */
+	struct libtelnet_rfc1143_t *q;
 	/* sub-request buffer */
 	unsigned char *buffer;
 	/* current size of the buffer */
-	unsigned int size;
-	/* length of data in the buffer */
-	unsigned int length;
+	unsigned int buffer_size;
+	/* current buffer write position (also length of buffer data) */
+	unsigned int buffer_pos;
 	/* current state */
 	enum libtelnet_state_t state;
 	/* processing mode */
 	enum libtelnet_mode_t mode;
 	/* current subnegotiation telopt */
 	unsigned char sb_telopt;
+	/* length of RFC1143 queue */
+	unsigned char q_size;
 };
 
 /* initialize a telnet state tracker */
@@ -200,4 +215,12 @@
 /* begin sending compressed data (server only) */
 extern void libtelnet_begin_compress2(struct libtelnet_t *telnet);
 
+/* return the status of a specific TELNET option on our end (US) */
+extern int libtelnet_get_telopt_local(struct libtelnet_t *telnet,
+		unsigned char telopt);
+
+/* return the status of a specific TELNET option on remote end (HIM) */
+extern int libtelnet_get_telopt_remote(struct libtelnet_t *telnet,
+		unsigned char telopt);
+
 #endif /* !defined(LIBTELNET_INCLUDE) */
diff --git a/telnet-client.c b/telnet-client.c
index 099a846..3e5f645 100644
--- a/telnet-client.c
+++ b/telnet-client.c
@@ -89,55 +89,32 @@
 	case LIBTELNET_EV_SEND:
 		_send(sock, ev->buffer, ev->size);
 		break;
-	/* accept any options we want */
-	case LIBTELNET_EV_NEGOTIATE:
-		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;
+	/* request to enable remote feature (or receipt) */
+	case LIBTELNET_EV_WILL:
+		/* we accept COMPRESS2 (MCCP) */
+		if (ev->telopt == LIBTELNET_TELOPT_COMPRESS2)
+			ev->accept = 1;
 
-		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;
+		/* we'll agree to turn off our echo if server wants us to stop */
+		else if (ev->telopt == LIBTELNET_TELOPT_ECHO) {
+			do_echo = 0;
+			ev->accept = 1;
 		}
 		break;
+	/* notification of disabling remote feature (or receipt) */
+	case LIBTELNET_EV_WONT:
+		if (ev->telopt == LIBTELNET_TELOPT_ECHO)
+			do_echo = 1;
+		break;
+	/* request to enable local feature (or receipt) */
+	case LIBTELNET_EV_DO:
+		/* we support the TTYPE option */
+		if (ev->telopt == LIBTELNET_TELOPT_TTYPE)
+			ev->accept = 1;
+		break;
+	/* demand to disable local feature (or receipt) */
+	case LIBTELNET_EV_DONT:
+		break;
 	/* respond to particular subnegotiations */
 	case LIBTELNET_EV_SUBNEGOTIATION:
 		/* respond with our terminal type */
diff --git a/telnet-proxy.c b/telnet-proxy.c
index 9678d10..34b2aa1 100644
--- a/telnet-proxy.c
+++ b/telnet-proxy.c
@@ -191,12 +191,31 @@
 
 		libtelnet_send_command(&conn->remote->telnet, ev->command);
 		break;
-	/* negotiation */
-	case LIBTELNET_EV_NEGOTIATE:
-		printf("%s IAC %s %d (%s)" COLOR_NORMAL "\n", conn->name,
-				get_cmd(ev->command), (int)ev->telopt, get_opt(ev->telopt));
-
-		libtelnet_send_negotiate(&conn->remote->telnet, ev->command,
+	/* negotiation, WILL */
+	case LIBTELNET_EV_WILL:
+		printf("%s IAC WILL %d (%s)" COLOR_NORMAL "\n", conn->name,
+				(int)ev->telopt, get_opt(ev->telopt));
+		libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_WILL,
+				ev->telopt);
+		break;
+	/* negotiation, WONT */
+	case LIBTELNET_EV_WONT:
+		printf("%s IAC WONT %d (%s)" COLOR_NORMAL "\n", conn->name,
+				(int)ev->telopt, get_opt(ev->telopt));
+		libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_WONT,
+				ev->telopt);
+		break;
+	/* negotiation, DO */
+	case LIBTELNET_EV_DO:
+		printf("%s IAC DO %d (%s)" COLOR_NORMAL "\n", conn->name,
+				(int)ev->telopt, get_opt(ev->telopt));
+		libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_DO,
+				ev->telopt);
+		break;
+	case LIBTELNET_EV_DONT:
+		printf("%s IAC DONT %d (%s)" COLOR_NORMAL "\n", conn->name,
+				(int)ev->telopt, get_opt(ev->telopt));
+		libtelnet_send_negotiate(&conn->remote->telnet, LIBTELNET_DONT,
 				ev->telopt);
 		break;
 	/* subnegotiation */