diff --git a/src/syncterm/conn.c b/src/syncterm/conn.c
index 06d732c9106ee862a551b6f97f6ccea46e339a97..621f7b43b21b7bd614210a7ee8fd16aa688ad867 100644
--- a/src/syncterm/conn.c
+++ b/src/syncterm/conn.c
@@ -267,38 +267,46 @@ int conn_recv_upto(void *vbuffer, size_t buflen, unsigned timeout)
 {
 	char *buffer = (char *)vbuffer;
 	size_t	found=0;
+	size_t obuflen;
+	void *expanded;
+	size_t max_rx = buflen;
 
+	if (conn_api.rx_parse_cb != NULL) {
+		if (max_rx > 1)
+			max_rx /= 2;
+	}
 	pthread_mutex_lock(&(conn_inbuf.mutex));
 	if(conn_buf_wait_bytes(&conn_inbuf, 1, timeout))
-		found=conn_buf_get(&conn_inbuf, buffer, buflen);
+		found=conn_buf_get(&conn_inbuf, buffer, max_rx);
 	pthread_mutex_unlock(&(conn_inbuf.mutex));
-	return(found);
-}
-
 
-int conn_recv(void *vbuffer, size_t buflen, unsigned timeout)
-{
-	char *buffer = (char *)vbuffer;
-	size_t found;
+	if (found) {
+		if (conn_api.rx_parse_cb != NULL) {
+			expanded = conn_api.rx_parse_cb(buffer, found, &obuflen);
+			memcpy(vbuffer, expanded, obuflen);
+			free(expanded);
+			found = obuflen;
+		}
+		else {
+			expanded = buffer;
+			obuflen = buflen;
+		}
+	}
 
-	pthread_mutex_lock(&(conn_inbuf.mutex));
-	found=conn_buf_wait_bytes(&conn_inbuf, buflen, timeout);
-	if(found)
-		found=conn_buf_get(&conn_inbuf, buffer, found);
-	pthread_mutex_unlock(&(conn_inbuf.mutex));
 	return(found);
 }
 
-int conn_peek(void *vbuffer, size_t buflen)
+
+int conn_send_raw(const void *vbuffer, size_t buflen, unsigned int timeout)
 {
-	char *buffer = (char *)vbuffer;
+	const char *buffer = vbuffer;
 	size_t found;
 
-	pthread_mutex_lock(&(conn_inbuf.mutex));
-	found=conn_buf_wait_bytes(&conn_inbuf, buflen, 0);
+	pthread_mutex_lock(&(conn_outbuf.mutex));
+	found=conn_buf_wait_free(&conn_outbuf, buflen, timeout);
 	if(found)
-		found=conn_buf_peek(&conn_inbuf, buffer, found);
-	pthread_mutex_unlock(&(conn_inbuf.mutex));
+		found=conn_buf_put(&conn_outbuf, buffer, found);
+	pthread_mutex_unlock(&(conn_outbuf.mutex));
 	return(found);
 }
 
@@ -306,12 +314,27 @@ int conn_send(const void *vbuffer, size_t buflen, unsigned int timeout)
 {
 	const char *buffer = vbuffer;
 	size_t found;
+	size_t obuflen;
+	void *expanded;
+
+	if (conn_api.tx_parse_cb != NULL) {
+		expanded = conn_api.tx_parse_cb(buffer, buflen, &obuflen);
+	}
+	else {
+		expanded = (void *)buffer;
+		obuflen = buflen;
+	}
 
 	pthread_mutex_lock(&(conn_outbuf.mutex));
-	found=conn_buf_wait_free(&conn_outbuf, buflen, timeout);
+	found=conn_buf_wait_free(&conn_outbuf, obuflen, timeout);
 	if(found)
 		found=conn_buf_put(&conn_outbuf, buffer, found);
 	pthread_mutex_unlock(&(conn_outbuf.mutex));
+
+	if (conn_api.tx_parse_cb != NULL) {
+		free(expanded);
+	}
+
 	return(found);
 }
 
@@ -321,6 +344,8 @@ int conn_connect(struct bbslist *bbs)
 
 	memset(&conn_api, 0, sizeof(conn_api));
 
+	conn_api.nostatus = bbs->nostatus;
+	conn_api.emulation = get_emulation(bbs);
 	switch(bbs->conn_type) {
 		case CONN_TYPE_RLOGIN:
 		case CONN_TYPE_RLOGIN_REVERSED:
diff --git a/src/syncterm/conn.h b/src/syncterm/conn.h
index 5cdc79f76ab1fd8769183e670eb6ee8d82cc554f..f52ae165ca28076321dd125990f29a66d94b0b47 100644
--- a/src/syncterm/conn.h
+++ b/src/syncterm/conn.h
@@ -33,8 +33,12 @@ struct conn_api {
 	int (*close)(void);
 	void (*binary_mode_on)(void);
 	void (*binary_mode_off)(void);
+	void *(*rx_parse_cb)(const void* inbuf, size_t inlen, size_t *olen);
+	void *(*tx_parse_cb)(const void* inbuf, size_t inlen, size_t *olen);
 	int log_level;
 	int type;
+	int nostatus;
+	cterm_emulation_t emulation;
 	volatile int input_thread_running;
 	volatile int output_thread_running;
 	volatile int terminate;
@@ -59,9 +63,8 @@ struct conn_buffer {
  * Functions for stuff using connections
  */
 int conn_recv_upto(void *buffer, size_t buflen, unsigned int timeout);
-int conn_recv(void *buffer, size_t buflen, unsigned int timeout);
-int conn_peek(void *buffer, size_t buflen);
 int conn_send(const void *buffer, size_t buflen, unsigned int timeout);
+int conn_send_raw(const void *buffer, size_t buflen, unsigned int timeout);
 int conn_connect(struct bbslist *bbs);
 int conn_close(void);
 BOOL conn_connected(void);
diff --git a/src/syncterm/conn_telnet.c b/src/syncterm/conn_telnet.c
index a1ee81b877faa003184aeae55bca3a7511c2bf9d..224c693518e0f088b52a0d3de81cfafcd512c00e 100644
--- a/src/syncterm/conn_telnet.c
+++ b/src/syncterm/conn_telnet.c
@@ -15,117 +15,33 @@
 #include "uifcinit.h"
 
 #include "telnet_io.h"
+#include "rlogin.h"
 
-SOCKET telnet_sock=INVALID_SOCKET;
 extern int	telnet_log_level;
 
-#ifdef __BORLANDC__
-#pragma argsused
-#endif
-void telnet_input_thread(void *args)
+static void *telnet_rx_parse_cb(const void *buf, size_t inlen, size_t *olen)
 {
-	fd_set	rds;
-	int		rd;
-	int	buffered;
-	size_t	buffer;
-	char	rbuf[BUFFER_SIZE];
-	char	*buf;
-	struct bbslist *bbs = args;
-
-	SetThreadName("Telnet Input");
-	conn_api.input_thread_running=1;
-	while(telnet_sock != INVALID_SOCKET && !conn_api.terminate) {
-		FD_ZERO(&rds);
-		FD_SET(telnet_sock, &rds);
-#ifdef __linux__
-		{
-			struct timeval tv;
-			tv.tv_sec=0;
-			tv.tv_usec=500000;
-			rd=select(telnet_sock+1, &rds, NULL, NULL, &tv);
-		}
-#else
-		rd=select(telnet_sock+1, &rds, NULL, NULL, NULL);
-#endif
-		if(rd==-1) {
-			if(errno==EBADF)
-				break;
-			rd=0;
-		}
-		if(rd==1) {
-			rd=recv(telnet_sock, conn_api.rd_buf, conn_api.rd_buf_size, 0);
-			if(rd <= 0)
-				break;
-		}
-		if(rd>0)
-			buf=(char *)telnet_interpret(conn_api.rd_buf, rd, (BYTE *)rbuf, &rd, bbs);
-		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, buf+buffered, buffer);
-			pthread_mutex_unlock(&(conn_inbuf.mutex));
-		}
-	}
-	conn_api.input_thread_running=0;
+	void *ret = malloc(inlen);
+
+	if (ret == NULL)
+		return ret;
+	if (telnet_interpret((BYTE *)buf, inlen, ret, olen) != ret)
+		memcpy(ret, buf, *olen);
+	return ret;
 }
 
-#ifdef __BORLANDC__
-#pragma argsused
-#endif
-void telnet_output_thread(void *args)
+static void *telnet_tx_parse_cb(const void *buf, size_t len, size_t *olen)
 {
-	fd_set	wds;
-	size_t		wr;
-	int		ret;
-	size_t	sent;
-	char	ebuf[BUFFER_SIZE*2];
-	char	*buf;
-
-	SetThreadName("Telnet Output");
-	conn_api.output_thread_running=1;
-	while(telnet_sock != INVALID_SOCKET && !conn_api.terminate) {
-		pthread_mutex_lock(&(conn_outbuf.mutex));
-		ret=0;
-		wr=conn_buf_wait_bytes(&conn_outbuf, 1, 100);
-		if(wr) {
-			wr=conn_buf_get(&conn_outbuf, conn_api.wr_buf, conn_api.wr_buf_size);
-			pthread_mutex_unlock(&(conn_outbuf.mutex));
-			wr = telnet_expand(conn_api.wr_buf, wr, (BYTE *)ebuf, sizeof(ebuf)
-				,telnet_local_option[TELNET_BINARY_TX]!=TELNET_DO, (uchar**)&buf);
-			sent=0;
-			while(sent < wr) {
-				FD_ZERO(&wds);
-				FD_SET(telnet_sock, &wds);
-#ifdef __linux__
-				{
-					struct timeval tv;
-					tv.tv_sec=0;
-					tv.tv_usec=500000;
-					ret=select(telnet_sock+1, NULL, &wds, NULL, &tv);
-				}
-#else
-				ret=select(telnet_sock+1, NULL, &wds, NULL, NULL);
-#endif
-				if(ret==-1) {
-					if(errno==EBADF)
-						break;
-					ret=0;
-				}
-				if(ret==1) {
-					ret=sendsocket(telnet_sock, buf+sent, wr-sent);
-					if(ret==-1)
-						break;
-					sent+=ret;
-				}
-			}
-		}
-		else
-			pthread_mutex_unlock(&(conn_outbuf.mutex));
-		if(ret==-1)
-			break;
-	}
-	conn_api.output_thread_running=0;
+	void *ret = malloc(len * 2);
+	void *parsed;
+
+	*olen = telnet_expand(buf, len, ret, len * 2
+		,telnet_local_option[TELNET_BINARY_TX]!=TELNET_DO, (BYTE **)&parsed);
+
+	if (parsed != ret)
+		memcpy(ret, parsed, *olen);
+
+	return ret;
 }
 
 int telnet_connect(struct bbslist *bbs)
@@ -135,8 +51,8 @@ int telnet_connect(struct bbslist *bbs)
 
 	telnet_log_level = bbs->telnet_loglevel;
 
-	telnet_sock=conn_socket_connect(bbs);
-	if(telnet_sock==INVALID_SOCKET)
+	rlogin_sock=conn_socket_connect(bbs);
+	if(rlogin_sock==INVALID_SOCKET)
 		return(-1);
 
 	if(!create_conn_buf(&conn_inbuf, BUFFER_SIZE))
@@ -163,9 +79,11 @@ int telnet_connect(struct bbslist *bbs)
 
 	memset(telnet_local_option,0,sizeof(telnet_local_option));
 	memset(telnet_remote_option,0,sizeof(telnet_remote_option));
+	conn_api.rx_parse_cb = telnet_rx_parse_cb;
+	conn_api.tx_parse_cb = telnet_tx_parse_cb;
 
-	_beginthread(telnet_output_thread, 0, NULL);
-	_beginthread(telnet_input_thread, 0, bbs);
+	_beginthread(rlogin_output_thread, 0, NULL);
+	_beginthread(rlogin_input_thread, 0, bbs);
 
 	if (!bbs->hidepopups)
 		uifc.pop(NULL);
@@ -173,23 +91,6 @@ int telnet_connect(struct bbslist *bbs)
 	return(0);
 }
 
-int telnet_close(void)
-{
-	char	garbage[1024];
-
-	conn_api.terminate=1;
-	closesocket(telnet_sock);
-	while(conn_api.input_thread_running || conn_api.output_thread_running) {
-		conn_recv_upto(garbage, sizeof(garbage), 0);
-		SLEEP(1);
-	}
-	destroy_conn_buf(&conn_inbuf);
-	destroy_conn_buf(&conn_outbuf);
-	FREE_AND_NULL(conn_api.rd_buf);
-	FREE_AND_NULL(conn_api.wr_buf);
-	return(0);
-}
-
 void telnet_binary_mode_on(void)
 {
 	request_telnet_opt(TELNET_DO,TELNET_BINARY_TX);
diff --git a/src/syncterm/conn_telnet.h b/src/syncterm/conn_telnet.h
index fa418545ea05fb6e53f54b4bdf123e7f7be10720..71e44092e977051f8d31159c9cec80842745f4d2 100644
--- a/src/syncterm/conn_telnet.h
+++ b/src/syncterm/conn_telnet.h
@@ -9,6 +9,6 @@ extern SOCKET telnet_sock;
 void telnet_binary_mode_on(void);
 void telnet_binary_mode_off(void);
 int telnet_connect(struct bbslist *bbs);
-int telnet_close(void);
+#define telnet_close rlogin_close
 
 #endif
diff --git a/src/syncterm/rlogin.c b/src/syncterm/rlogin.c
index 5fbb63ea652d8d4451dcc7e9c078596eab7991b1..e7886743240b6f6a175f3d88401ee1454044ed2a 100644
--- a/src/syncterm/rlogin.c
+++ b/src/syncterm/rlogin.c
@@ -10,7 +10,7 @@
 #include "conn.h"
 #include "uifcinit.h"
 
-static SOCKET sock=INVALID_SOCKET;
+SOCKET rlogin_sock=INVALID_SOCKET;
 
 #ifdef __BORLANDC__
 #pragma argsused
@@ -24,18 +24,18 @@ void rlogin_input_thread(void *args)
 
 	SetThreadName("RLogin Input");
 	conn_api.input_thread_running=1;
-	while(sock != INVALID_SOCKET && !conn_api.terminate) {
+	while(rlogin_sock != INVALID_SOCKET && !conn_api.terminate) {
 		FD_ZERO(&rds);
-		FD_SET(sock, &rds);
+		FD_SET(rlogin_sock, &rds);
 #ifdef __linux__
 		{
 			struct timeval tv;
 			tv.tv_sec=0;
 			tv.tv_usec=500000;
-			rd=select(sock+1, &rds, NULL, NULL, &tv);
+			rd=select(rlogin_sock+1, &rds, NULL, NULL, &tv);
 		}
 #else
-		rd=select(sock+1, &rds, NULL, NULL, NULL);
+		rd=select(rlogin_sock+1, &rds, NULL, NULL, NULL);
 #endif
 		if(rd==-1) {
 			if(errno==EBADF)
@@ -43,7 +43,7 @@ void rlogin_input_thread(void *args)
 			rd=0;
 		}
 		if(rd==1) {
-			rd=recv(sock, conn_api.rd_buf, conn_api.rd_buf_size, 0);
+			rd=recv(rlogin_sock, conn_api.rd_buf, conn_api.rd_buf_size, 0);
 			if(rd <= 0)
 				break;
 		}
@@ -70,7 +70,7 @@ void rlogin_output_thread(void *args)
 
 	SetThreadName("RLogin Output");
 	conn_api.output_thread_running=1;
-	while(sock != INVALID_SOCKET && !conn_api.terminate) {
+	while(rlogin_sock != INVALID_SOCKET && !conn_api.terminate) {
 		pthread_mutex_lock(&(conn_outbuf.mutex));
 		ret=0;
 		wr=conn_buf_wait_bytes(&conn_outbuf, 1, 100);
@@ -80,16 +80,16 @@ void rlogin_output_thread(void *args)
 			sent=0;
 			while(sent < wr) {
 				FD_ZERO(&wds);
-				FD_SET(sock, &wds);
+				FD_SET(rlogin_sock, &wds);
 #ifdef __linux__
 				{
 					struct timeval tv;
 					tv.tv_sec=0;
 					tv.tv_usec=500000;
-					ret=select(sock+1, NULL, &wds, NULL, &tv);
+					ret=select(rlogin_sock+1, NULL, &wds, NULL, &tv);
 				}
 #else
-				ret=select(sock+1, NULL, &wds, NULL, NULL);
+				ret=select(rlogin_sock+1, NULL, &wds, NULL, NULL);
 #endif
 				if(ret==-1) {
 					if(errno==EBADF)
@@ -97,7 +97,7 @@ void rlogin_output_thread(void *args)
 					ret=0;
 				}
 				if(ret==1) {
-					ret=sendsocket(sock, conn_api.wr_buf+sent, wr-sent);
+					ret=sendsocket(rlogin_sock, conn_api.wr_buf+sent, wr-sent);
 					if(ret==-1)
 						break;
 					sent+=ret;
@@ -127,8 +127,8 @@ int rlogin_connect(struct bbslist *bbs)
 		ruser=bbs->password;
 	}
 
-	sock=conn_socket_connect(bbs);
-	if(sock==INVALID_SOCKET)
+	rlogin_sock=conn_socket_connect(bbs);
+	if(rlogin_sock==INVALID_SOCKET)
 		return(-1);
 
 	if(!create_conn_buf(&conn_inbuf, BUFFER_SIZE))
@@ -178,17 +178,17 @@ int rlogin_connect(struct bbslist *bbs)
 		fd_set	rds;
 
 		FD_ZERO(&rds);
-		FD_SET(sock, &rds);
+		FD_SET(rlogin_sock, &rds);
 
 		tv.tv_sec=1;
 		tv.tv_usec=0;
 
 		/* Check to make sure GHost is actually listening */
-		sendsocket(sock, "\r\nMBBS: PING\r\n", 14);
+		sendsocket(rlogin_sock, "\r\nMBBS: PING\r\n", 14);
 
 		idx = 0;
-		while ((ret = select(sock+1, &rds, NULL, NULL, &tv))==1) {
-			recv(sock, rbuf+idx, 1, 0);
+		while ((ret = select(rlogin_sock+1, &rds, NULL, NULL, &tv))==1) {
+			recv(rlogin_sock, rbuf+idx, 1, 0);
 			rbuf[++idx] = 0;
 
 			/* It says ERROR, but this is a good response to PING. */
@@ -213,11 +213,11 @@ int rlogin_connect(struct bbslist *bbs)
 			999, /* Time remaining */
 			"GR" /* GR = ANSI, NG = ASCII */
 		);
-		sendsocket(sock, sbuf, strlen(sbuf));
+		sendsocket(rlogin_sock, sbuf, strlen(sbuf));
 
 		idx = 0;
-		while ((ret = select(sock+1, &rds, NULL, NULL, &tv))==1) {
-			recv(sock, rbuf+idx, 1, 0);
+		while ((ret = select(rlogin_sock+1, &rds, NULL, NULL, &tv))==1) {
+			recv(rlogin_sock, rbuf+idx, 1, 0);
 			rbuf[++idx] = 0;
 
 			/* GHost says it's launching the program, so pass terminal to user. */
@@ -252,7 +252,7 @@ int rlogin_close(void)
 	char garbage[1024];
 
 	conn_api.terminate=1;
-	closesocket(sock);
+	closesocket(rlogin_sock);
 	while(conn_api.input_thread_running || conn_api.output_thread_running) {
 		conn_recv_upto(garbage, sizeof(garbage), 0);
 		SLEEP(1);
diff --git a/src/syncterm/rlogin.h b/src/syncterm/rlogin.h
index 80fe28b2ef7788a99d6d7287c59a7be06e46799b..d273da984ac27d2eb123191b0a44fdb2ed9d6223 100644
--- a/src/syncterm/rlogin.h
+++ b/src/syncterm/rlogin.h
@@ -5,5 +5,8 @@
 
 int rlogin_connect(struct bbslist *bbs);
 int rlogin_close(void);
+void rlogin_input_thread(void *args);
+void rlogin_output_thread(void *args);
+extern SOCKET rlogin_sock;
 
 #endif
diff --git a/src/syncterm/telnet_io.c b/src/syncterm/telnet_io.c
index e11711536da0bbfb25cba9edf8de499048981007..a4b40d3afb62f4620394efb261a4173d5bcd647d 100644
--- a/src/syncterm/telnet_io.c
+++ b/src/syncterm/telnet_io.c
@@ -47,35 +47,8 @@ static int lprintf(int level, const char *fmt, ...)
 
 void putcom(char* buf, size_t len)
 {
-
-	fd_set	wds;
-	FD_ZERO(&wds);
-	FD_SET(telnet_sock, &wds);
-	struct timeval tv;
-	tv.tv_sec=10;
-	tv.tv_usec=0;
-	/*
-	 * Note, this select() call was added when debugging file transfer
-	 * issues presumably because something made it appear to "hang forever".
-	 * Since blocking sockets are used, this is very much not a complete
-	 * fix as the buffer size will usually be greater than the one byte
-	 * select() guarantees you will be able to send().
-	 *
-	 * The original fix waited 1ms in select(), which is unlikely to actually
-	 * allow the ACK to come back fast enough to clear a full output buffer.
-	 * I've increased it to 10s and left the select() in place.
-	 */
-	if(select(telnet_sock+1, NULL, &wds, NULL, &tv) == 1) {
-		char	str[128];
-		char*	p=str;
-		size_t i;
-		for(i=0;i<len;i++)
-			p+=sprintf(p,"%u ", ((BYTE)buf[i]));
-
-		lprintf(LOG_DEBUG,"TX: %s", str);
-		sendsocket(telnet_sock, buf, len);
-	} else
-		lprintf(LOG_WARNING, "TX: putcom(%d) timeout", len);
+	conn_send_raw(buf, len, 10000);
+	return;
 }
 
 static void send_telnet_cmd(uchar cmd, uchar opt)
@@ -109,7 +82,7 @@ void request_telnet_opt(uchar cmd, uchar opt)
 	send_telnet_cmd(cmd,opt);
 }
 
-BYTE* telnet_interpret(BYTE* inbuf, int inlen, BYTE* outbuf, int *outlen, struct bbslist *bbs)
+BYTE* telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen)
 {
 	BYTE	command;
 	BYTE	option;
@@ -177,7 +150,7 @@ BYTE* telnet_interpret(BYTE* inbuf, int inlen, BYTE* outbuf, int *outlen, struct
 					/* sub-option terminated */
 					if(option==TELNET_TERM_TYPE && telnet_cmd[3]==TELNET_TERM_SEND) {
 						char buf[32];
-						const char *emu = get_emulation_str(get_emulation(bbs));
+						const char *emu = get_emulation_str(conn_api.emulation);
 						int len=sprintf(buf,"%c%c%c%c%s%c%c"
 							,TELNET_IAC,TELNET_SB
 							,TELNET_TERM_TYPE,TELNET_TERM_IS
@@ -220,7 +193,7 @@ BYTE* telnet_interpret(BYTE* inbuf, int inlen, BYTE* outbuf, int *outlen, struct
 						int rows, cols;
 						BYTE buf[32];
 
-						get_cterm_size(&cols, &rows, bbs->nostatus);
+						get_cterm_size(&cols, &rows, conn_api.nostatus);
 						buf[0]=TELNET_IAC;
 						buf[1]=TELNET_SB;
 						buf[2]=TELNET_NEGOTIATE_WINDOW_SIZE;
diff --git a/src/syncterm/telnet_io.h b/src/syncterm/telnet_io.h
index 1f10e43c8615dbc359639a5e27d73f566bcaa63e..4ecc5e0e1564ba74e4a7ca55a40f14cfdf5c3cad 100644
--- a/src/syncterm/telnet_io.h
+++ b/src/syncterm/telnet_io.h
@@ -15,7 +15,7 @@
 extern uchar	telnet_local_option[0x100];
 extern uchar	telnet_remote_option[0x100];
 
-BYTE*	telnet_interpret(BYTE* inbuf, int inlen, BYTE* outbuf, int *outlen, struct bbslist *bbs);
+BYTE*	telnet_interpret(BYTE* inbuf, size_t inlen, BYTE* outbuf, size_t *outlen);
 void	request_telnet_opt(uchar cmd, uchar opt);
 
 #endif