diff --git a/src/syncterm/modem.c b/src/syncterm/modem.c
new file mode 100644
index 0000000000000000000000000000000000000000..b8f7b47013e06eab696f2d0a961378f7b9006196
--- /dev/null
+++ b/src/syncterm/modem.c
@@ -0,0 +1,216 @@
+/* $Id$ */
+
+#include <stdlib.h>
+
+#include "comio.h"
+
+#include "sockwrap.h"
+
+#include "syncterm.h"
+#include "bbslist.h"
+#include "conn.h"
+#include "uifcinit.h"
+
+static COM_HANDLE com=INVALID_SOCKET;
+
+#ifdef __BORLANDC__
+#pragma argsused
+#endif
+void modem_input_thread(void *args)
+{
+	int		rd;
+	int	buffered;
+	size_t	buffer;
+
+	conn_api.input_thread_running=1;
+	while(com != COM_HANDLE_INVALID && !conn_api.terminate) {
+		rd=comReadBuf(com, conn_api.rd_buf, conn_api.rd_buf_size, NULL, 100);
+		if(rd <= 0) {
+			if(comGetModemStatus(com)&COM_DCD)
+				break;
+		}
+		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));
+		}
+	}
+	conn_api.input_thread_running=0;
+}
+
+#ifdef __BORLANDC__
+#pragma argsused
+#endif
+void modem_output_thread(void *args)
+{
+	int		wr;
+	int		ret;
+	int	sent;
+
+	conn_api.output_thread_running=1;
+	while(com != COM_HANDLE_INVALID && !conn_api.terminate) {
+		pthread_mutex_lock(&(conn_outbuf.mutex));
+		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));
+			sent=0;
+			while(sent < wr) {
+				ret=comWriteBuf(com, conn_api.wr_buf+sent, wr-sent);
+				if(ret==COM_ERROR) {
+					if(comGetModemStatus(com)&COM_DCD == 0)
+						break;
+				}
+				sent+=ret;
+			}
+		}
+		else
+			pthread_mutex_unlock(&(conn_outbuf.mutex));
+		if(ret==-1)
+			break;
+	}
+	conn_api.output_thread_running=0;
+}
+
+int modem_response(char *str, size_t maxlen, int timeout)
+{
+	char	ch;
+	size_t	len=0;
+	time_t	start;
+
+	start=time(NULL);
+	while(1){
+		if(time(NULL)-start >= timeout)
+			return(-1);
+		if(len >= maxlen)
+			return(-1);
+		if(!comReadByte(com, &ch)) {
+			YIELD();
+			continue;
+		}
+		if(ch<' ' && len==0)	/* ignore prepended control chars */
+			continue;
+
+		if(ch=='\r') {
+			while(comReadByte(com,&ch));	/* eat trailing ctrl chars (e.g. 'LF') */
+			break;
+		}
+		str[len++]=ch;
+	}
+	str[len]=0;
+
+	return(0);
+}
+
+int modem_connect(struct bbslist *bbs)
+{
+	char	respbuf[1024];
+
+	init_uifc(TRUE, TRUE);
+
+	if((com=comOpen(settings.mdm.device_name)) == COM_HANDLE_INVALID) {
+		uifcmsg("Cannot Open Modem",	"`Cannot Open Modem`\n\n"
+						"Cannot open the specified modem device.\n");
+		conn_api.terminate=-1;
+		return(-1);
+	}
+
+	uifc.pop("Initializing...");
+	comWriteString(com, settings.mdm.init_string);
+	comWriteString(com, "\r");
+
+	/* Wait for "OK" */
+	if(modem_response(respbuf, sizeof(respbuf), 5)) {
+		modem_close();
+		uifc.pop(NULL);
+		uifcmsg("Modem Not Responding",	"`Modem Not Responding`\n\n"
+						"The modem did not respond to the initializtion string\n"
+						"Check your init string and phone number.\n");
+		conn_api.terminate=-1;
+		return(INVALID_SOCKET);
+	}
+	if(!strstr(respbuf, "OK")) {
+		modem_close();
+		uifc.pop(NULL);
+		uifcmsg("Initialization Error",	"`Initialization Error`\n\n"
+						"Your initialization string caused an error.\n");
+		conn_api.terminate=-1;
+		return(INVALID_SOCKET);
+	}
+
+	uifc.pop(NULL);
+	uifc.pop("Dialing...");
+	comWriteString(com, "ATD");
+	comWriteString(com, bbs->addr);
+	comWriteString(com, "\r");
+	
+	/* Wait for "CONNECT" */
+	if(modem_response(respbuf, sizeof(respbuf), 30)) {
+		modem_close();
+		uifc.pop(NULL);
+		uifcmsg("No Answer",	"`No Answer`\n\n"
+						"The modem did not connect withing 30 seconds.\n");
+		conn_api.terminate=-1;
+		return(INVALID_SOCKET);
+	}
+	if(!strstr(respbuf, "CONNECT")) {
+		modem_close();
+		uifc.pop(NULL);
+		uifcmsg("Connection Failed",	"`Connection Failed`\n\n"
+						"SyncTERM was unable to establish a connection.\n");
+		conn_api.terminate=-1;
+		return(INVALID_SOCKET);
+	}
+
+	uifc.pop(NULL);
+
+	create_conn_buf(&conn_inbuf, BUFFER_SIZE);
+	create_conn_buf(&conn_outbuf, BUFFER_SIZE);
+	conn_api.rd_buf=(unsigned char *)malloc(BUFFER_SIZE);
+	conn_api.rd_buf_size=BUFFER_SIZE;
+	conn_api.wr_buf=(unsigned char *)malloc(BUFFER_SIZE);
+	conn_api.wr_buf_size=BUFFER_SIZE;
+
+	_beginthread(modem_output_thread, 0, NULL);
+	_beginthread(modem_input_thread, 0, NULL);
+
+	uifc.pop(NULL);
+
+	return(0);
+}
+
+int modem_close(void)
+{
+	time_t start;
+
+	conn_api.terminate=1;
+
+	if((comGetModemStatus(com)&COM_DCD)==0)	/* DCD already low */
+		goto CLOSEIT;
+
+	/* TODO:  We need a drain function */
+	SLEEP(500);
+
+	if(!comLowerDTR(com))
+		goto CLOSEIT;
+
+	start=time(NULL);
+	while(time(NULL)-start <= 10) {
+		if((comGetModemStatus(com)&COM_DCD) == 0)
+			goto CLOSEIT;
+		SLEEP(1000); 
+	}
+
+CLOSEIT:
+	comClose(com);
+
+	while(conn_api.input_thread_running || conn_api.output_thread_running)
+		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);
+}
diff --git a/src/syncterm/modem.h b/src/syncterm/modem.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a778e49c0d6f9a94b57b5636a1a667619deb545
--- /dev/null
+++ b/src/syncterm/modem.h
@@ -0,0 +1,7 @@
+#ifndef _MODEM_H_
+#define _MODEM_H_
+
+int modem_connect(struct bbslist *bbs);
+int modem_close(void);
+
+#endif