diff --git a/src/syncterm/GNUmakefile b/src/syncterm/GNUmakefile
index 3b3a23ee940bf9c65e1aeab8a2134ab7f59223b8..aa3824a2061330659fea7f37ae6502b0b89c3a8b 100644
--- a/src/syncterm/GNUmakefile
+++ b/src/syncterm/GNUmakefile
@@ -29,8 +29,9 @@ else
  OBJS += $(MTOBJODIR)$(DIRSEP)st_crypt$(OFILE)
  OBJS += $(MTOBJODIR)$(DIRSEP)ssh$(OFILE)
  OBJS += $(MTOBJODIR)$(DIRSEP)telnets$(OFILE)
- CFLAGS	+=	$(CRYPT_CFLAGS)
- EXTRA_LIBS	+=	$(CRYPT_LIBS)
+ CFLAGS	+=	$(CRYPT_CFLAGS) $(SFTP-MT_CFLAGS)
+ CRYPT_LDFLAGS += $(SFTP-MT_LDFLAGS)
+ EXTRA_LIBS	+=	$(CRYPT_LIBS) $(SFTP-MT_LIBS)
  STATIC_CRYPTLIB	:= true
 endif
 
diff --git a/src/syncterm/ssh.c b/src/syncterm/ssh.c
index 3d369e8454787febfdab0fd2d8949f0c6a6f85cb..07b1dfb6fadc8672b9e470fad2f96930ac7bc389 100644
--- a/src/syncterm/ssh.c
+++ b/src/syncterm/ssh.c
@@ -9,6 +9,7 @@
 #include "conn.h"
 #include "gen_defs.h"
 #include "genwrap.h"
+#include "sftp.h"
 #include "sockwrap.h"
 #include "st_crypt.h"
 #include "syncterm.h"
@@ -18,8 +19,12 @@
 
 SOCKET          ssh_sock;
 CRYPT_SESSION   ssh_session;
+int             ssh_channel;
 int             ssh_active = true;
 pthread_mutex_t ssh_mutex;
+int             sftp_channel = -1;
+bool            sftp_active;
+sftpc_state_t   sftp_state;
 
 void
 cryptlib_error_message(int status, const char *msg)
@@ -43,6 +48,19 @@ cryptlib_error_message(int status, const char *msg)
 	free(errmsg);
 }
 
+static void
+close_sftp_channel(void)
+{
+	pthread_mutex_lock(&ssh_mutex);
+	if (sftp_channel != -1) {
+		cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, sftp_channel);
+		cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 0);
+		sftp_channel = -1;
+	}
+	pthread_mutex_unlock(&ssh_mutex);
+	sftpc_finish(sftp_state);
+}
+
 void
 ssh_input_thread(void *args)
 {
@@ -50,6 +68,7 @@ ssh_input_thread(void *args)
 	int    rd;
 	size_t buffered;
 	size_t buffer;
+	int    chan;
 
 	SetThreadName("SSH Input");
 	conn_api.input_thread_running = 1;
@@ -58,8 +77,10 @@ ssh_input_thread(void *args)
 			continue;
 
 		pthread_mutex_lock(&ssh_mutex);
-		cl.FlushData(ssh_session);
+		status = cl.FlushData(ssh_session);
 		status = cl.PopData(ssh_session, conn_api.rd_buf, conn_api.rd_buf_size, &rd);
+		if (cryptStatusOK(status))
+			status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, &chan);
 		pthread_mutex_unlock(&ssh_mutex);
 
                 // Handle case where there was socket activity without readable data (ie: rekey)
@@ -67,7 +88,7 @@ ssh_input_thread(void *args)
 			continue;
 
 		if (cryptStatusError(status)) {
-			if ((status == CRYPT_ERROR_COMPLETE) || (status == CRYPT_ERROR_READ)) { /* connection closed */
+			if ((status == CRYPT_ERROR_COMPLETE) || (status == CRYPT_ERROR_READ) || (status == CRYPT_ERROR_NOTFOUND)) { /* connection closed */
 				ssh_active = true;
 				break;
 			}
@@ -76,12 +97,21 @@ ssh_input_thread(void *args)
 			break;
 		}
 		else {
-			buffered = 0;
-			while (buffered < rd) {
-				pthread_mutex_lock(&(conn_inbuf.mutex));
-				buffer = conn_buf_wait_free(&conn_inbuf, rd - buffered, 100);
-				buffered += conn_buf_put(&conn_inbuf, conn_api.rd_buf + buffered, buffer);
-				pthread_mutex_unlock(&(conn_inbuf.mutex));
+			if (chan == sftp_channel) {
+				if (!sftpc_recv(sftp_state, conn_api.rd_buf, rd)) {
+					ssh_active = true;
+					close_sftp_channel();
+					continue;
+				}
+			}
+			else {
+				buffered = 0;
+				while (buffered < rd) {
+					pthread_mutex_lock(&(conn_inbuf.mutex));
+					buffer = conn_buf_wait_free(&conn_inbuf, rd - buffered, 100);
+					buffered += conn_buf_put(&conn_inbuf, conn_api.rd_buf + buffered, buffer);
+					pthread_mutex_unlock(&(conn_inbuf.mutex));
+				}
 			}
 		}
 	}
@@ -106,11 +136,14 @@ ssh_output_thread(void *args)
 			pthread_mutex_unlock(&(conn_outbuf.mutex));
 			sent = 0;
 			while (ssh_active && sent < wr) {
+				ret = 0;
 				pthread_mutex_lock(&ssh_mutex);
-				status = cl.PushData(ssh_session, conn_api.wr_buf + sent, wr - sent, &ret);
+				status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, ssh_channel);
+				if (cryptStatusOK(status))
+					status = cl.PushData(ssh_session, conn_api.wr_buf + sent, wr - sent, &ret);
 				pthread_mutex_unlock(&ssh_mutex);
 				if (cryptStatusError(status)) {
-					if (status == CRYPT_ERROR_COMPLETE) { /* connection closed */
+					if ((status == CRYPT_ERROR_COMPLETE) || (status == CRYPT_ERROR_NOTFOUND)) { /* connection closed */
 						ssh_active = true;
 						break;
 					}
@@ -133,6 +166,40 @@ ssh_output_thread(void *args)
 	conn_api.output_thread_running = 2;
 }
 
+#if NOTYET
+static bool
+sftp_send(uint8_t *buf, size_t sz, void *cb_data)
+{
+	size_t sent = 0;
+	while (ssh_active && sent < sz) {
+		int status;
+		int ret;
+		pthread_mutex_lock(&ssh_mutex);
+		status = cl.FlushData(ssh_session);
+		status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, sftp_channel);
+		if (cryptStatusOK(status)) {
+			status = cl.PushData(ssh_session, buf + sent, sz - sent, &ret);
+			if (cryptStatusOK(status))
+				status = cl.FlushData(ssh_session);
+		}
+		pthread_mutex_unlock(&ssh_mutex);
+		if (cryptStatusError(status))
+			cryptlib_error_message(status, "sending sftp data");
+		if (cryptStatusError(status)) {
+			if (status == CRYPT_ERROR_COMPLETE) { /* connection closed */
+				ssh_active = true;	// TODO: Why are we doing this?
+				break;
+			}
+			cryptlib_error_message(status, "sending sftp data");
+			ssh_active = true;
+			break;
+		}
+		sent += ret;
+	}
+	return sent == sz;
+}
+#endif
+
 int
 ssh_connect(struct bbslist *bbs)
 {
@@ -143,6 +210,8 @@ ssh_connect(struct bbslist *bbs)
 	int         rows, cols;
 	const char *term;
 
+	ssh_channel = -1;
+	sftp_channel = -1;
 	if (!bbs->hidepopups)
 		init_uifc(true, true);
 	pthread_mutex_init(&ssh_mutex, NULL);
@@ -274,20 +343,6 @@ ssh_connect(struct bbslist *bbs)
 		return -1;
 	}
 
-	if (!bbs->hidepopups) {
-		uifc.pop(NULL);
-		uifc.pop("Setting Channel");
-	}
-
-	cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED);
-
-	if (!bbs->hidepopups) {
-		uifc.pop(NULL);
-		uifc.pop("Setting Channel Type");
-	}
-
-	cl.SetAttributeString(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_TYPE, "session", 7);
-
 	if (!bbs->hidepopups) {
 		uifc.pop(NULL);
 		uifc.pop("Setting Terminal Type");
@@ -329,7 +384,6 @@ ssh_connect(struct bbslist *bbs)
 	ssh_active = true;
 	if (!bbs->hidepopups) {
                 /* Clear ownership */
-		uifc.pop(NULL); // TODO: Why is this called twice?
 		uifc.pop(NULL);
 		uifc.pop("Clearing Ownership");
 	}
@@ -342,6 +396,21 @@ ssh_connect(struct bbslist *bbs)
 			uifc.pop(NULL);
 		return -1;
 	}
+	if (!bbs->hidepopups) {
+                /* Clear ownership */
+		uifc.pop(NULL);
+		uifc.pop("Getting SSH Channel");
+	}
+	status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, &ssh_channel);
+	if (cryptStatusError(status)) {
+		if (!bbs->hidepopups)
+			cryptlib_error_message(status, "getting ssh channel");
+		conn_api.terminate = 1;
+		if (!bbs->hidepopups)
+			uifc.pop(NULL);
+		return -1;
+	}
+
 	if (!bbs->hidepopups)
 		uifc.pop(NULL);
 
@@ -355,6 +424,68 @@ ssh_connect(struct bbslist *bbs)
 	_beginthread(ssh_output_thread, 0, NULL);
 	_beginthread(ssh_input_thread, 0, NULL);
 
+#if NOTYET
+	// TODO: Without this sleep, all is woe.
+	SLEEP(10);
+	if (cryptStatusOK(status)) {
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		if (!bbs->hidepopups) {
+			/* Clear ownership */
+			uifc.pop(NULL);
+			uifc.pop("Creating SFTP Channel");
+		}
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		pthread_mutex_lock(&ssh_mutex);
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED);
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		if (cryptStatusError(status))
+			cryptlib_error_message(status, "setting new channel");
+		if (cryptStatusOK(status)) {
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+			status = cl.SetAttributeString(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_TYPE, "subsystem", 9);
+			if (cryptStatusError(status))
+				cryptlib_error_message(status, "setting channel type");
+			if (cryptStatusOK(status)) {
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+				status = cl.SetAttributeString(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ARG1, "sftp", 4);
+				if (cryptStatusError(status))
+					cryptlib_error_message(status, "setting subsystem");
+				if (cryptStatusOK(status)) {
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+					status = cl.GetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, &sftp_channel);
+					if (cryptStatusError(status))
+						cryptlib_error_message(status, "getting new channel");
+					if (cryptStatusOK(status)) {
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+						// TODO: Do something...
+					}
+				}
+			}
+		}
+		pthread_mutex_unlock(&ssh_mutex);
+	}
+	if (sftp_channel != -1) {
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		pthread_mutex_lock(&ssh_mutex);
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		status = cl.SetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 1);
+		pthread_mutex_unlock(&ssh_mutex);
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		if (cryptStatusError(status))
+			cryptlib_error_message(status, "activating sftp session");
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+		if (cryptStatusOK(status)) {
+fprintf(stderr, "%s:%d\n", __FILE__, __LINE__);
+			sftp_state = sftpc_begin(sftp_send, NULL);
+			if (sftp_state == NULL)
+				fprintf(stderr, "Failure!\n");
+			else if (sftpc_init(sftp_state))
+				fprintf(stderr, "Success!\n");
+		}
+	}
+#endif
+
 	if (!bbs->hidepopups)
 		uifc.pop(NULL); // TODO: Why is this called twice?
 
diff --git a/src/syncterm/ssh.h b/src/syncterm/ssh.h
index 55c2467d4fa850adab9a1bb339d68779dcccb891..9b17eae60f5088214f99bd374b55692f4bf90a24 100644
--- a/src/syncterm/ssh.h
+++ b/src/syncterm/ssh.h
@@ -13,8 +13,11 @@ void ssh_output_thread(void *args);
 
 extern SOCKET          ssh_sock;
 extern CRYPT_SESSION   ssh_session;
+extern int             ssh_channel;
 extern bool            ssh_active;
 extern pthread_mutex_t ssh_mutex;
+extern int             sftp_channel;
+extern bool            sftp_active;
 void cryptlib_error_message(int status, const char *msg);
 
 #endif // ifndef _SSH_H_
diff --git a/src/syncterm/targets.mk b/src/syncterm/targets.mk
index 458174db42a601d7599a8906bd28d8a884cc814d..e8f970c1916a5606698abb7c94ae906d219fb9ac 100644
--- a/src/syncterm/targets.mk
+++ b/src/syncterm/targets.mk
@@ -1,6 +1,5 @@
 SYNCTERM	=	$(EXEODIR)$(DIRSEP)syncterm$(EXEFILE)
 
-all: xpdev-mt ciolib-mt uifc-mt $(MTOBJODIR) $(EXEODIR) $(SYNCTERM)
-
-$(SYNCTERM):	$(XPDEV-MT_LIB) $(CIOLIB-MT) $(UIFCLIB-MT) $(ENCODE_LIB) $(HASH_LIB)
+all: xpdev-mt ciolib-mt uifc-mt sftp-mt $(MTOBJODIR) $(EXEODIR) $(SYNCTERM)
 
+$(SYNCTERM):	$(XPDEV-MT_LIB) $(SFTP-MT) $(CIOLIB-MT) $(UIFCLIB-MT) $(ENCODE_LIB) $(HASH_LIB)