send data to input_cb in the biggest chunks we can
diff --git a/libtelnet.c b/libtelnet.c
index 4d47404..3bfd319 100644
--- a/libtelnet.c
+++ b/libtelnet.c
@@ -79,126 +79,142 @@
 }
 
 /* push a single byte into the state tracker */
-void libtelnet_push_byte(struct libtelnet_t *telnet, unsigned char byte,
-		void *user_data) {
-	switch (telnet->state) {
-	/* regular data */
-	case LIBTELNET_STATE_TEXT:
-		/* enter IAC state on IAC byte */
-		if (byte == LIBTELNET_IAC)
-			telnet->state = LIBTELNET_STATE_IAC;
-		/* regular input byte */
-		else
-			libtelnet_input_cb(telnet, &byte, 1, user_data);
-		break;
-
-	/* IAC command */
-	case LIBTELNET_STATE_IAC:
-		switch (byte) {
-		/* subrequest */
-		case LIBTELNET_SB:
-			telnet->state = LIBTELNET_STATE_SB;
-			break;
-		/* negotiation commands */
-		case LIBTELNET_WILL:
-			telnet->state = LIBTELNET_STATE_WILL;
-			break;
-		case LIBTELNET_WONT:
-			telnet->state = LIBTELNET_STATE_WONT;
-			break;
-		case LIBTELNET_DO:
-			telnet->state = LIBTELNET_STATE_DO;
-			break;
-		case LIBTELNET_DONT:
-			telnet->state = LIBTELNET_STATE_DONT;
-			break;
-		/* IAC escaping */
-		case LIBTELNET_IAC:
-			libtelnet_input_cb(telnet, &byte, 1, user_data);
-			telnet->state = LIBTELNET_STATE_TEXT;
-			break;
-		/* some other command */
-		default:
-			libtelnet_command_cb(telnet, byte, user_data);
-			telnet->state = LIBTELNET_STATE_TEXT;
-		}
-		break;
-
-	/* negotiation commands */
-	case LIBTELNET_STATE_DO:
-		libtelnet_negotiate_cb(telnet, LIBTELNET_DO, byte, user_data);
-		telnet->state = LIBTELNET_STATE_TEXT;
-		break;
-	case LIBTELNET_STATE_DONT:
-		libtelnet_negotiate_cb(telnet, LIBTELNET_DONT, byte, user_data);
-		telnet->state = LIBTELNET_STATE_TEXT;
-		break;
-	case LIBTELNET_STATE_WILL:
-		libtelnet_negotiate_cb(telnet, LIBTELNET_WILL, byte, user_data);
-		telnet->state = LIBTELNET_STATE_TEXT;
-		break;
-	case LIBTELNET_STATE_WONT:
-		libtelnet_negotiate_cb(telnet, LIBTELNET_WONT, byte, user_data);
-		telnet->state = LIBTELNET_STATE_TEXT;
-		break;
-
-	/* subrequest -- buffer bytes until end request */
-	case LIBTELNET_STATE_SB:
-		/* IAC command in subrequest -- either IAC SE or IAC IAC */
-		if (byte == LIBTELNET_IAC)
-			telnet->state = LIBTELNET_STATE_SB_IAC;
-		/* buffer the byte, or bail if we can't */
-		else if (_buffer_byte(telnet, LIBTELNET_IAC, user_data) !=
-				LIBTELNET_ERROR_OK)
-			telnet->state = LIBTELNET_STATE_TEXT;
-		else
-			telnet->state = LIBTELNET_STATE_SB;
-		break;
-
-	/* IAC escaping inside a subrequest */
-	case LIBTELNET_STATE_SB_IAC:
-		switch (byte) {
-		/* end subrequest */
-		case LIBTELNET_SE:
-			/* zero-size buffer is a protocol error */
-			if (telnet->length == 0) {
-				libtelnet_error_cb(telnet, LIBTELNET_ERROR_PROTOCOL,
-					user_data);
-			/* process */
-			} else {
-				libtelnet_subrequest_cb(telnet, telnet->buffer[0],
-					telnet->buffer + 1, telnet->length - 1, user_data);
-				telnet->length = 0;
-			}
-			
-			/* return to default state */
-			telnet->state = LIBTELNET_STATE_TEXT;
-			break;
-		/* escaped IAC byte */
-		case LIBTELNET_IAC:
-			/* push IAC into buffer */
-			if (_buffer_byte(telnet, LIBTELNET_IAC, user_data) !=
-					LIBTELNET_ERROR_OK)
-				telnet->state = LIBTELNET_STATE_TEXT;
-			else
-				telnet->state = LIBTELNET_STATE_SB;
-			break;
-		/* something else -- protocol error */
-		default:
-			libtelnet_error_cb(telnet, LIBTELNET_ERROR_PROTOCOL, user_data);
-			telnet->state = LIBTELNET_STATE_TEXT;
-			break;
-		}
-		break;
-	}
-}
-
-/* push a byte buffer into the state tracker */
-void libtelnet_push_buffer(struct libtelnet_t *telnet, unsigned char *buffer,
+void libtelnet_push(struct libtelnet_t *telnet, unsigned char *buffer,
 		unsigned int size, void *user_data) {
-	unsigned int i;
-	for (i = 0; i != size; ++i)
-		libtelnet_push_byte(telnet, buffer[i], user_data);
+	unsigned char byte;
+	unsigned int i, start;
+	for (i = start = 0; i != size; ++i) {
+		byte = buffer[i];
+		switch (telnet->state) {
+		/* regular data */
+		case LIBTELNET_STATE_TEXT:
+			/* on an IAC byte, pass through all pending bytes and
+			 * switch states */
+			if (byte == LIBTELNET_IAC) {
+				if (i != start)
+					libtelnet_input_cb(telnet, &buffer[start], i - start,
+							user_data);
+				telnet->state = LIBTELNET_STATE_IAC;
+			}
+			break;
+
+		/* IAC command */
+		case LIBTELNET_STATE_IAC:
+			switch (byte) {
+			/* subrequest */
+			case LIBTELNET_SB:
+				telnet->state = LIBTELNET_STATE_SB;
+				break;
+			/* negotiation commands */
+			case LIBTELNET_WILL:
+				telnet->state = LIBTELNET_STATE_WILL;
+				break;
+			case LIBTELNET_WONT:
+				telnet->state = LIBTELNET_STATE_WONT;
+				break;
+			case LIBTELNET_DO:
+				telnet->state = LIBTELNET_STATE_DO;
+				break;
+			case LIBTELNET_DONT:
+				telnet->state = LIBTELNET_STATE_DONT;
+				break;
+			/* IAC escaping */
+			case LIBTELNET_IAC:
+				libtelnet_input_cb(telnet, &byte, 1, user_data);
+				start = i + 1;
+				telnet->state = LIBTELNET_STATE_TEXT;
+				break;
+			/* some other command */
+			default:
+				libtelnet_command_cb(telnet, byte, user_data);
+				start = i + 1;
+				telnet->state = LIBTELNET_STATE_TEXT;
+			}
+			break;
+
+		/* negotiation commands */
+		case LIBTELNET_STATE_DO:
+			libtelnet_negotiate_cb(telnet, LIBTELNET_DO, byte, user_data);
+			start = i + 1;
+			telnet->state = LIBTELNET_STATE_TEXT;
+			break;
+		case LIBTELNET_STATE_DONT:
+			libtelnet_negotiate_cb(telnet, LIBTELNET_DONT, byte, user_data);
+			start = i + 1;
+			telnet->state = LIBTELNET_STATE_TEXT;
+			break;
+		case LIBTELNET_STATE_WILL:
+			libtelnet_negotiate_cb(telnet, LIBTELNET_WILL, byte, user_data);
+			start = i + 1;
+			telnet->state = LIBTELNET_STATE_TEXT;
+			break;
+		case LIBTELNET_STATE_WONT:
+			libtelnet_negotiate_cb(telnet, LIBTELNET_WONT, byte, user_data);
+			start = i + 1;
+			telnet->state = LIBTELNET_STATE_TEXT;
+			break;
+
+		/* subrequest -- buffer bytes until end request */
+		case LIBTELNET_STATE_SB:
+			/* IAC command in subrequest -- either IAC SE or IAC IAC */
+			if (byte == LIBTELNET_IAC) {
+				telnet->state = LIBTELNET_STATE_SB_IAC;
+			/* buffer the byte, or bail if we can't */
+			} else if (_buffer_byte(telnet, LIBTELNET_IAC, user_data) !=
+					LIBTELNET_ERROR_OK) {
+				start = i + 1;
+				telnet->state = LIBTELNET_STATE_TEXT;
+			} else {
+				telnet->state = LIBTELNET_STATE_SB;
+			}
+			break;
+
+		/* IAC escaping inside a subrequest */
+		case LIBTELNET_STATE_SB_IAC:
+			switch (byte) {
+			/* end subrequest */
+			case LIBTELNET_SE:
+				/* zero-size buffer is a protocol error */
+				if (telnet->length == 0) {
+					libtelnet_error_cb(telnet, LIBTELNET_ERROR_PROTOCOL,
+						user_data);
+				/* process */
+				} else {
+					libtelnet_subrequest_cb(telnet, telnet->buffer[0],
+						telnet->buffer + 1, telnet->length - 1, user_data);
+					telnet->length = 0;
+				}
+				
+				/* return to default state */
+				start = i + 1;
+				telnet->state = LIBTELNET_STATE_TEXT;
+				break;
+			/* escaped IAC byte */
+			case LIBTELNET_IAC:
+				/* push IAC into buffer */
+				if (_buffer_byte(telnet, LIBTELNET_IAC, user_data) !=
+						LIBTELNET_ERROR_OK) {
+					start = i + 1;
+					telnet->state = LIBTELNET_STATE_TEXT;
+				} else {
+					telnet->state = LIBTELNET_STATE_SB;
+				}
+				break;
+			/* something else -- protocol error */
+			default:
+				libtelnet_error_cb(telnet, LIBTELNET_ERROR_PROTOCOL,
+						user_data);
+				start = i + 1;
+				telnet->state = LIBTELNET_STATE_TEXT;
+				break;
+			}
+			break;
+		}
+	}
+
+	/* pass through any remaining bytes */ 
+	if (i != start)
+		libtelnet_input_cb(telnet, &buffer[start], i - start, user_data);
 }
 
 /* send an iac command */
diff --git a/libtelnet.h b/libtelnet.h
index a262bee..01ac509 100644
--- a/libtelnet.h
+++ b/libtelnet.h
@@ -80,12 +80,8 @@
 /* free up any memory allocated by a state tracker */
 extern void libtelnet_free(struct libtelnet_t *telnet);
 
-/* push a single byte into the state tracker */
-extern void libtelnet_push_byte(struct libtelnet_t *telnet,
-	unsigned char byte, void *user_data);
-
 /* push a byte buffer into the state tracker */
-extern void libtelnet_push_buffer(struct libtelnet_t *telnet,
+extern void libtelnet_push(struct libtelnet_t *telnet,
 	unsigned char *buffer, unsigned int size, void *user_data);
 
 /* send an iac command */