# Patch #9 for x3270 3.2.18.
# Corrects three separate problems:
# - A small memory leak each time a host is connected to and an LU name is
#   specified.
# - Incorrect display of the connection state in the data stream trace.
# - Use of the memccpy() function in the IAC-expansion logic.  memccpy() is
#   apparently broken on several platforms; IACs are not expanded in the
#   emulator's responses and (among other things) Query Replies are rejected
#   by the host.

--- x3270-3.2/telnet.c	2001/12/27 13:17:06	1.49
+++ x3270-3.2/telnet.c	2002/02/14 23:31:26
@@ -491,7 +491,8 @@
 	 * Allocate enough memory to construct an argv[] array for
 	 * the LUs.
 	 */
-	lus = (char **)Malloc((n_lus+1) * sizeof(char *) + strlen(luname) + 1);
+	Replace(lus,
+	    (char **)Malloc((n_lus+1) * sizeof(char *) + strlen(luname) + 1));
 
 	/* Copy each LU into the array. */
 	lu = (char *)(lus + n_lus + 1);
@@ -1069,6 +1070,27 @@
 }
 
 /*
+ * Back off of TN3270E.
+ */
+static void
+backoff_tn3270e(const char *why)
+{
+	trace_dsn("Aborting TN3270E: %s\n", why);
+
+	/* Tell the host 'no'. */
+	wont_opt[2] = TELOPT_TN3270E;
+	net_rawout(wont_opt, sizeof(wont_opt));
+	trace_dsn("SENT %s %s\n", cmd(WONT), opt(TELOPT_TN3270E));
+
+	/* Restore the LU list; we may need to run it again in TN3270 mode. */
+	setup_lus();
+
+	/* Reset our internal state. */
+	myopts[TELOPT_TN3270E] = 0;
+	check_in3270();
+}
+
+/*
  * Negotiation of TN3270E options.
  * Returns 0 if okay, -1 if we have to give up altogether.
  */
@@ -1156,6 +1178,12 @@
 			/* Device type failure. */
 
 			trace_dsn("REJECT REASON %s SE\n", rsn(sbbuf[4]));
+			if (sbbuf[4] == TN3270E_REASON_INV_DEVICE_TYPE ||
+			    sbbuf[4] == TN3270E_REASON_UNSUPPORTED_REQ) {
+				backoff_tn3270e("Host rejected device type or "
+				    "request type");
+				break;
+			}
 
 			next_lu();
 			if (try_lu != CN) {
@@ -1163,13 +1191,9 @@
 				tn3270e_request();
 			} else if (lus != (char **)NULL) {
 				/* No more LUs to try.  Give up. */
-				popup_an_error("Cannot connect to "
-					"specified LU:\n%s", rsn(sbbuf[4]));
-				return -1;
+				backoff_tn3270e("Host rejected resource(s)");
 			} else {
-				popup_an_error("Device type rejected:\n"
-					"%s", rsn(sbbuf[4]));
-				return -1;
+				backoff_tn3270e("Device type rejected");
 			}
 
 			break;
@@ -1231,15 +1255,8 @@
 					 * They've added something.  Abandon
 					 * TN3270E, they're brain dead.
 					 */
-					trace_dsn("Host illegally added "
-						"function(s), aborting "
-						"TN3270E\n");
-					wont_opt[2] = TELOPT_TN3270E;
-					net_rawout(wont_opt, sizeof(wont_opt));
-					trace_dsn("SENT %s %s\n", cmd(WONT),
-						opt(TELOPT_TN3270E));
-					myopts[TELOPT_TN3270E] = 0;
-					check_in3270();
+					backoff_tn3270e("Host illegally added "
+					    "function(s)");
 					break;
 				}
 			}
@@ -1860,6 +1877,7 @@
 #if defined(X3270_TRACE) /*[*/
 	static const char *state_name[] = {
 		"unconnected",
+		"resolving",
 		"pending",
 		"connected initial",
 		"TN3270 NVT",
@@ -2122,7 +2140,7 @@
 	static unsigned char *xobuf = NULL;
 	static int xobuf_len = 0;
 	int need_resize = 0;
-	unsigned char *balance, *nxoptr, *xoptr;
+	unsigned char *nxoptr, *xoptr;
 
 #if defined(X3270_TN3270E) /*[*/
 #define BSTART	((IN_TN3270E || IN_SSCP) ? obuf_base : obuf)
@@ -2167,13 +2185,12 @@
 
 	/* Copy and expand IACs. */
 	xoptr = xobuf;
-	balance = BSTART;
-	while ((nxoptr = memccpy(xoptr, balance, IAC, obptr-balance)) != NULL) {
-		balance += nxoptr - xoptr;
-		xoptr = nxoptr;
-		*xoptr++ = IAC;
+	nxoptr = BSTART;
+	while (nxoptr < obptr) {
+		if ((*xoptr++ = *nxoptr++) == IAC) {
+			*xoptr++ = IAC;
+		}
 	}
-	xoptr += obptr - balance;
 
 	/* Append the IAC EOR and transmit. */
 	*xoptr++ = IAC;
