diff --git a/3rdp/build/cl-server-term-support.patch b/3rdp/build/cl-server-term-support.patch
index 55cd92bc53e53bd0aa0358a41f277122b78e930d..4d4e62cfc4b6b686b9561b4e3f65eb8c1585eaa0 100644
--- a/3rdp/build/cl-server-term-support.patch
+++ b/3rdp/build/cl-server-term-support.patch
@@ -32,34 +32,40 @@
  			default:
  				retIntError();
  			}
-@@ -479,6 +497,14 @@
+@@ -479,6 +497,18 @@
  		case CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE:
  			*value = isActiveChannel( channelInfoPtr ) ? TRUE : FALSE;
  			return( CRYPT_OK );
 +
 +		case CRYPT_SESSINFO_SSH_CHANNEL_WIDTH:
++			if (channelInfoPtr->width == 0)
++				return CRYPT_ERROR_NOTFOUND;
 +			*value = channelInfoPtr->width;
 +			return( CRYPT_OK );
 +
 +		case CRYPT_SESSINFO_SSH_CHANNEL_HEIGHT:
++			if (channelInfoPtr->height == 0)
++				return CRYPT_ERROR_NOTFOUND;
 +			*value = channelInfoPtr->height;
 +			return( CRYPT_OK );
  		}
  
  	retIntError();
-@@ -532,6 +558,11 @@
+@@ -532,6 +562,13 @@
  			return( attributeCopyParams( data, dataMaxLength, dataLength,
  										 channelInfoPtr->arg2,
  										 channelInfoPtr->arg2Len ) );
 +
 +		case CRYPT_SESSINFO_SSH_CHANNEL_TERMINAL:
++			if (channelInfoPtr->terminalLen == 0)
++				return CRYPT_ERROR_NOTFOUND;
 +			return( attributeCopyParams( data, dataMaxLength, dataLength,
 +										 channelInfoPtr->terminal,
 +										 channelInfoPtr->terminalLen ) );
  		}
  
  	retIntError();
-@@ -596,7 +627,21 @@
+@@ -596,7 +633,21 @@
  		return( selectChannel( sessionInfoPtr, channelInfoPtr->writeChannelNo,
  							   CHANNEL_WRITE ) );
  		}
@@ -81,7 +87,7 @@
  	retIntError();
  	}
  
-@@ -639,6 +684,11 @@
+@@ -639,6 +688,11 @@
  			return( attributeCopyParams( channelInfoPtr->arg2, 
  										 CRYPT_MAX_TEXTSIZE,
  										 &channelInfoPtr->arg2Len, 
diff --git a/src/sftp/sftp.h b/src/sftp/sftp.h
index 2d12851cded3225da2b6c88443cc807c583582d1..2eec8caae361e2abc1ed0fe8992ba7c81330c6b1 100644
--- a/src/sftp/sftp.h
+++ b/src/sftp/sftp.h
@@ -58,7 +58,7 @@
 #define SSH_FILEXFER_ATTR_PERMISSIONS UINT32_C(0x00000004)
 #define SSH_FILEXFER_ATTR_ACMODTIME   UINT32_C(0x00000008)
 #define SSH_FILEXFER_ATTR_EXTENDED    UINT32_C(0x80000000)
-        
+
 #define SFTP_MIN_PACKET_ALLOC 4096
 #define SFTP_VERSION 3
 
diff --git a/src/sftp/sftp_client.c b/src/sftp/sftp_client.c
index 012db6e674351231b77cff51b5dd836a0f195f28..8fb6b8ce6d3fdbd5b48614f75b6dd05ebe5b7dc4 100644
--- a/src/sftp/sftp_client.c
+++ b/src/sftp/sftp_client.c
@@ -188,7 +188,6 @@ static void
 handle_error(sftpc_state_t state)
 {
 	if (state->rxp->type == SSH_FXP_STATUS) {
-		state->err_id = get32(state);
 		state->err_code = get32(state);
 		if (state->err_msg != NULL)
 			free_sftp_str(state->err_msg);
@@ -358,6 +357,7 @@ sftpc_read(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, uint3
 		return false;
 	if (state->rxp->type == SSH_FXP_DATA) {
 		*ret = getstring(state);
+		response_handled(state);
 		return *ret != NULL;
 	}
 	handle_error(state);
diff --git a/src/sftp/sftp_pkt.c b/src/sftp/sftp_pkt.c
index 4c2cc82db726392d24debd235bb6214f2c1a047b..c567740efcd2625bd10ee4ea3d49066cce757c60 100644
--- a/src/sftp/sftp_pkt.c
+++ b/src/sftp/sftp_pkt.c
@@ -154,7 +154,7 @@ sftp_get64(sftp_rx_pkt_t pkt)
 {
 	uint64_t ret;
 	GET_FUNC_BODY;
-	return BE_INT32(ret);
+	return BE_INT64(ret);
 }
 
 /*
diff --git a/src/sftp/sftp_str.c b/src/sftp/sftp_str.c
index 10aa3fa103ad395c74998f3f3bf783c4cf45ee5e..7f743a5eae8a38b31624a41824de2befcd0ebba6 100644
--- a/src/sftp/sftp_str.c
+++ b/src/sftp/sftp_str.c
@@ -36,7 +36,7 @@ sftp_asprintf(const char *format, ...)
 	va_list va;
 
 	va_start(va, format);
-	char *str = xp_asprintf(format, va);
+	char *str = xp_vasprintf(format, va);
 	va_end(va);
 	if (str == NULL)
 		return NULL;
diff --git a/src/syncterm/ssh.c b/src/syncterm/ssh.c
index d389c564ec89a33865b89fde4e712fd45b2f2785..df7be2d4fee851f86e7c4285a147d6b1a4be2c6e 100644
--- a/src/syncterm/ssh.c
+++ b/src/syncterm/ssh.c
@@ -256,15 +256,14 @@ get_public_key(CRYPT_CONTEXT ctx)
 
 	status = cl.GetAttributeString(ctx, CRYPT_CTXINFO_SSH_PUBLIC_KEY, NULL, &sz);
 	if (cryptStatusOK(status)) {
-		fprintf(stderr, "Size: %d\n", sz);
 		raw = malloc(sz);
 		if (raw != NULL) {
 			status = cl.GetAttributeString(ctx, CRYPT_CTXINFO_SSH_PUBLIC_KEY, raw, &sz);
 			if (cryptStatusOK(status)) {
-				rsz = sz * 4 / 3 + 3;
+				rsz = (sz - 4) * 4 / 3 + 3;
 				ret = malloc(rsz);
 				if (ret != NULL) {
-					b64_encode(ret, rsz, raw, sz);
+					b64_encode(ret, rsz, raw + 4, sz - 4);
 					free(raw);
 					return ret;
 				}
@@ -272,10 +271,75 @@ get_public_key(CRYPT_CONTEXT ctx)
 			free(raw);
 		}
 	}
-	fprintf(stderr, "Error %d\n", status);
 	return NULL;
 }
 
+static bool
+key_not_present(sftp_filehandle_t f, const char *priv)
+{
+	size_t bufsz = 0;
+	size_t old_bufpos = 0;
+	size_t bufpos = 0;
+	size_t off = 0;
+	size_t eol;
+	char *buf = NULL;
+	char *newbuf;
+	char *eolptr;
+	sftp_str_t r = NULL;
+	bool skipread = false;
+
+	do {
+		if (skipread) {
+			old_bufpos = 0;
+			skipread = false;
+		}
+		else {
+			if (bufsz - bufpos < 1024) {
+				newbuf = realloc(buf, bufsz + 4096);
+				if (newbuf == NULL) {
+					free(buf);
+					return false;
+				}
+				buf = newbuf;
+				bufsz += 4096;
+			}
+			if (!sftpc_read(sftp_state, f, off, (bufsz - bufpos > 1024) ? 1024 : bufsz - bufpos, &r)) {
+				if (sftp_state->err_code == SSH_FX_EOF) {
+					free(buf);
+					free_sftp_str(r);
+					return true;
+				}
+				free(buf);
+				return false;
+			}
+			memcpy(&buf[bufpos], r->c_str, r->len);
+			old_bufpos = bufpos;
+			bufpos += r->len;
+			off += r->len;
+			free_sftp_str(r);
+			r = NULL;
+		}
+		for (eol = old_bufpos; eol < bufpos; eol++) {
+			if (buf[eol] == '\r' || buf[eol] == '\n')
+				break;
+		}
+		if (eol < bufpos) {
+			skipread = true;
+			eolptr = &buf[eol];
+			*eolptr = 0;
+			if (strstr(buf, priv) != NULL) {
+				free(buf);
+				return false;
+			}
+			*eolptr = '\n';
+			while (eol < bufpos && (buf[eol] == '\r' || buf[eol] == '\n'))
+				eol++;
+			memmove(buf, &buf[eol], bufpos - eol);
+			bufpos = bufpos - eol;
+		}
+	} while(1);
+}
+
 static bool
 add_public_key(struct bbslist *bbs, char *priv)
 {
@@ -325,14 +389,17 @@ add_public_key(struct bbslist *bbs, char *priv)
 			sftp_state = sftpc_begin(sftp_send, NULL);
 			if (sftp_state != NULL) {
 				if (sftpc_init(sftp_state)) {
-					sftp_str_t ret = NULL;
 					sftp_filehandle_t f = NULL;
-
-					if (sftpc_open(sftp_state, ".ssh/authorized_keys", SSH_FXF_READ, NULL, &f)) {
-						if (sftpc_read(sftp_state, f, 0, 1024, &ret)) {
-							fprintf(stderr, "First lines... %s\n", ret->c_str);
-							free_sftp_str(ret);
-							added = true;
+					// TODO: Add permissions?
+
+					if (sftpc_open(sftp_state, ".ssh/authorized_keys", SSH_FXF_READ | SSH_FXF_WRITE | SSH_FXF_APPEND | SSH_FXF_CREAT, NULL, &f)) {
+						/* Read through the file looking for our key */
+						if (key_not_present(f, priv)) {
+							// TODO: Types other than RSA...
+							sftp_str_t ln =  sftp_asprintf("ssh-rsa %s Added by SyncTERM\n", priv);
+							if (ln != NULL) {
+								sftpc_write(sftp_state, f, 0, ln);
+							}
 						}
 						sftpc_close(sftp_state, &f);
 					}
@@ -479,7 +546,7 @@ ssh_connect(struct bbslist *bbs)
 		return -1;
 	}
 
-        /* we need to disable Nagle on the socket. */
+	/* we need to disable Nagle on the socket. */
 	if (setsockopt(ssh_sock, IPPROTO_TCP, TCP_NODELAY, (char *)&off, sizeof(off)))
 		fprintf(stderr, "%s:%d: Error %d calling setsockopt()\n", __FILE__, __LINE__, errno);
 
@@ -500,7 +567,7 @@ ssh_connect(struct bbslist *bbs)
 	if (!bbs->hidepopups)
 		uifc.pop("Setting Username");
 
-        /* Add username/password */
+	/* Add username/password */
 	status = cl.SetAttributeString(ssh_session, CRYPT_SESSINFO_USERNAME, username, strlen(username));
 	if (cryptStatusError(status)) {
 		error_popup(bbs, "setting username", status);
@@ -517,7 +584,7 @@ ssh_connect(struct bbslist *bbs)
 		}
 	}
 	else {
-		if (!password[0]) {
+		if (!password[0]/* && ssh_context == -1*/) {
 			if (bbs->hidepopups)
 				init_uifc(false, false);
 			uifcinput("Password", MAX_PASSWD_LEN, password, K_PASSWORD, "Incorrect password.  Try again.");
@@ -525,12 +592,14 @@ ssh_connect(struct bbslist *bbs)
 				uifcbail();
 		}
 
-		if (!bbs->hidepopups)
-			uifc.pop("Setting Password");
-		status = cl.SetAttributeString(ssh_session, CRYPT_SESSINFO_PASSWORD, password, strlen(password));
-		if (cryptStatusError(status)) {
-			error_popup(bbs, "setting password", status);
-			return -1;
+		if (password[0]) {
+			if (!bbs->hidepopups)
+				uifc.pop("Setting Password");
+			status = cl.SetAttributeString(ssh_session, CRYPT_SESSINFO_PASSWORD, password, strlen(password));
+			if (cryptStatusError(status)) {
+				error_popup(bbs, "setting password", status);
+				return -1;
+			}
 		}
 
 		if (ssh_context != -1) {
@@ -539,6 +608,7 @@ ssh_connect(struct bbslist *bbs)
 			pubkey = get_public_key(ssh_context);
 			status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_PRIVATEKEY, ssh_context);
 			cl.DestroyContext(ssh_context);
+			ssh_context = -1;
 			if (cryptStatusError(status)) {
 				free(pubkey);
 				error_popup(bbs, "setting private key", status);
@@ -552,7 +622,7 @@ ssh_connect(struct bbslist *bbs)
 		uifc.pop("Setting Username");
 	}
 
-        /* Pass socket to cryptlib */
+	/* Pass socket to cryptlib */
 	status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_NETWORKSOCKET, ssh_sock);
 	if (cryptStatusError(status)) {
 		free(pubkey);
@@ -560,6 +630,9 @@ ssh_connect(struct bbslist *bbs)
 		return -1;
 	}
 
+	// We need to set the channel so we can set channel attributes.
+	status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED);
+
 	if (!bbs->hidepopups) {
 		uifc.pop(NULL);
 		uifc.pop("Setting Terminal Type");
@@ -583,7 +656,7 @@ ssh_connect(struct bbslist *bbs)
 
 	cl.SetAttribute(ssh_session, CRYPT_OPTION_NET_READTIMEOUT, 1);
 
-        /* Activate the session */
+	/* Activate the session */
 	if (!bbs->hidepopups) {
 		uifc.pop(NULL);
 		uifc.pop("Activating Session");
@@ -674,8 +747,6 @@ ssh_connect(struct bbslist *bbs)
 			}
 		}
 		bbs->has_fingerprint = true;
-	} else {
-		fprintf(stderr, "Failed to get fingerprint. :(\n");
 	}
 
 	if (!bbs->hidepopups)