diff --git a/src/syncterm/GNUmakefile b/src/syncterm/GNUmakefile
index 934f0d4153af9a32d600b5546a80f12a43e05c1e..e142d4b41e29f63d2e842d61e7dadc35ab4233d1 100644
--- a/src/syncterm/GNUmakefile
+++ b/src/syncterm/GNUmakefile
@@ -10,10 +10,15 @@ ifdef CHANNEL_CLIPPY
  CFLAGS +=	-DPCM
 endif
 
+ifdef USE_GUTS
+ CFLAGS +=	-I../guts -DGUTS_BUILTIN
+ OBJS	+=	$(MTOBJODIR)$(DIRSEP)gutsz$(OFILE)
+endif
+
 CFLAGS	+=	$(UIFC-MT_CFLAGS) $(CIOLIB-MT_CFLAGS) $(XPDEV-MT_CFLAGS) -I../sbbs3 -I../smblib
 LDFLAGS	+=	$(UIFC-MT_LDFLAGS) $(CIOLIB-MT_LDFLAGS) $(XPDEV-MT_LDFLAGS)
 
-vpath %.c ../sbbs3 ../smblib ../uifc
+vpath %.c ../sbbs3 ../smblib ../uifc ../guts
 
 $(SYNCTERM): $(EXEODIR) $(OBJS) $(BUILD_DEPENDS)
 	@echo Linking $@
diff --git a/src/syncterm/bbslist.c b/src/syncterm/bbslist.c
index 4e2ec93362e3a44d7c0709252bb05bd754eef415..261fc1f2c0e217f28e4850d30a27022129f9dd33 100644
--- a/src/syncterm/bbslist.c
+++ b/src/syncterm/bbslist.c
@@ -302,9 +302,11 @@ int edit_list(struct bbslist *item,char *listpath,int isdefault)
 				if(!confirm("Quit editing?", NULL))
 					continue;
 #endif
-				if((listfile=fopen(listpath,"w"))!=NULL) {
-					iniWriteFile(listfile,inifile);
-					fclose(listfile);
+				if(!safe_mode) {
+					if((listfile=fopen(listpath,"w"))!=NULL) {
+						iniWriteFile(listfile,inifile);
+						fclose(listfile);
+					}
 				}
 				strListFreeStrings(inifile);
 				return(changed);
@@ -534,6 +536,8 @@ void add_bbs(char *listpath, struct bbslist *bbs)
 	FILE *listfile;
 	str_list_t	inifile;
 
+	if(safe_mode)
+		return;
 	if((listfile=fopen(listpath,"r"))!=NULL) {
 		inifile=iniReadFile(listfile);
 		fclose(listfile);
@@ -574,6 +578,8 @@ void del_bbs(char *listpath, struct bbslist *bbs)
 	FILE *listfile;
 	str_list_t	inifile;
 
+	if(safe_mode)
+		return;
 	if((listfile=fopen(listpath,"r"))!=NULL) {
 		inifile=iniReadFile(listfile);
 		fclose(listfile);
@@ -657,9 +663,11 @@ void change_settings(void)
 		}
 	}
 write_ini:
-	if((inifile=fopen(inipath,"w"))!=NULL) {
-		iniWriteFile(inifile,inicontents);
-		fclose(inifile);
+	if(!safe_mode) {
+		if((inifile=fopen(inipath,"w"))!=NULL) {
+			iniWriteFile(inifile,inicontents);
+			fclose(inifile);
+		}
 	}
 }
 
@@ -800,6 +808,13 @@ struct bbslist *show_bbslist(int mode)
 								uifc.msg("Max List size reached!");
 								break;
 							}
+							if(safe_mode) {
+								uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
+												"SyncTERM is currently running in safe mode.  This means you cannot add to the\n"
+												"BBS list.";
+								uifc.msg("Cannot edit list in safe mode");
+								break;
+							}
 		#ifdef PCM
 							if(!confirm("Add new Entry?",NULL))
 								continue;
@@ -851,6 +866,13 @@ struct bbslist *show_bbslist(int mode)
 								uifc.msg("It's gone, calm down man!");
 								break;
 							}
+							if(safe_mode) {
+								uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
+												"SyncTERM is currently running in safe mode.  This means you cannot remove from the\n"
+												"BBS list.";
+								uifc.msg("Cannot edit list in safe mode");
+								break;
+							}
 							sprintf(str,"Delete %s?",list[opt]->name);
 							i=1;
 							if(uifc.list(WIN_MID|WIN_SAV,0,0,0,&i,NULL,str,YesNo)!=0)
@@ -867,6 +889,13 @@ struct bbslist *show_bbslist(int mode)
 							oldopt=-1;
 							break;
 						case MSK_EDIT:
+							if(safe_mode) {
+								uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
+												"SyncTERM is currently running in safe mode.  This means you cannot edit the\n"
+												"BBS list.";
+								uifc.msg("Cannot edit list in safe mode");
+								break;
+							}
 		#ifdef PCM
 							if(!confirm("Edit this entry?",NULL))
 								continue;
@@ -885,6 +914,13 @@ struct bbslist *show_bbslist(int mode)
 				}
 				else {
 					if(mode==BBSLIST_EDIT) {
+						if(safe_mode) {
+							uifc.helpbuf=	"`Cannot edit list in safe mode`\n\n"
+											"SyncTERM is currently running in safe mode.  This means you cannot edit the\n"
+											"BBS list.";
+							uifc.msg("Cannot edit list in safe mode");
+							break;
+						}
 		#ifdef PCM
 						if(!confirm("Edit this entry?",NULL))
 							continue;
@@ -996,7 +1032,7 @@ struct bbslist *show_bbslist(int mode)
 						}
 						break;
 					case 3:			/* Font management */
-						font_management();
+						if(!safe_mode) font_management();
 						break;
 					case 4:			/* Program settings */
 						change_settings();
diff --git a/src/syncterm/fonts.c b/src/syncterm/fonts.c
index 5a77941588012e2a44878bd0c5c9febf8409f512..14acc9711a71239fef34e576aab8877f56dfb65d 100644
--- a/src/syncterm/fonts.c
+++ b/src/syncterm/fonts.c
@@ -40,6 +40,8 @@ void save_font_files(struct font_files *fonts)
 	str_list_t	fontnames;
 	int		i;
 
+	if(safe_mode)
+		return;
 	get_syncterm_filename(inipath, sizeof(inipath), SYNCTERM_PATH_INI, FALSE);
 	if((inifile=fopen(inipath,"r"))!=NULL) {
 		ini_file=iniReadFile(inifile);
@@ -316,7 +318,7 @@ void font_management(void)
 					show_filepick=1;
 					break;
 			}
-			if(show_filepick) {
+			if(show_filepick && !safe_mode) {
 				int result;
 				struct file_pick fpick;
 				char	*savbuf;
diff --git a/src/syncterm/syncterm.c b/src/syncterm/syncterm.c
index b0fe63f1519d24208eac398c97cd33194f9afd0d..4b053c76e9362dbe4dda374ba12f855629df9a02 100644
--- a/src/syncterm/syncterm.c
+++ b/src/syncterm/syncterm.c
@@ -39,6 +39,7 @@ struct syncterm_settings settings;
 char *font_names[sizeof(conio_fontdata)/sizeof(struct conio_font_data_struct)];
 unsigned char *scrollback_buf=NULL;
 unsigned int  scrollback_lines=0;
+int	safe_mode=0;
 
 #ifdef _WINSOCKAPI_
 
@@ -355,6 +356,9 @@ int main(int argc, char **argv)
 				case 'T':
 					conn_type=CONN_TYPE_TELNET;
 					break;
+				case 'S':
+					safe_mode=1;
+					break;
                 default:
 					goto USAGE;
            }
@@ -533,6 +537,7 @@ int main(int argc, char **argv)
         "-l# =  set screen lines to # (default=auto-detect)\n"
 		"-t  =  use telnet mode if URL does not include the scheme\n"
 		"-r  =  use rlogin mode if URL does not include the scheme\n"
+		"-s  =  enable \"Safe Mode\" which prevents writing/browsing local files\n"
 		"\n"
 		"URL format is: [(rlogin|telnet)://][user[:password]@]domainname[:port]\n"
 		"examples: rlogin://deuce:password@nix.synchro.net:5885\n"
diff --git a/src/syncterm/syncterm.h b/src/syncterm/syncterm.h
index b82d002714740bae7309f9489893bb876dfbe3f3..ecbc56c3fdb446a7926e1b7f23e04625528a8b43 100644
--- a/src/syncterm/syncterm.h
+++ b/src/syncterm/syncterm.h
@@ -23,6 +23,7 @@ extern struct syncterm_settings settings;
 void parse_url(char *url, struct bbslist *bbs, int dflt_conn_type, int force_defaults);
 extern int default_font;
 extern char *font_names[];
+extern int safe_mode;
 char *get_syncterm_filename(char *fn, int fnlen, int type, int shared);
 void load_settings(struct syncterm_settings *set);
 
diff --git a/src/syncterm/term.c b/src/syncterm/term.c
index 2071a5bf76692fd010577e9de26c5d49bcf52c2a..0452e7ee39317965476ea3b4990d7771e21cc8eb 100644
--- a/src/syncterm/term.c
+++ b/src/syncterm/term.c
@@ -16,7 +16,15 @@
 #include "zmodem.h"
 #include "crc32.h"
 
+#ifdef GUTS_BUILTIN
+#include "gutsz.h"
+#endif
+
+#ifdef GUTS_BUILTIN
+#define	BUFSIZE	1
+#else
 #define	BUFSIZE	2048
+#endif
 static char recvbuf[BUFSIZE];
 
 #define DUMP
@@ -119,6 +127,7 @@ void update_status(struct bbslist *bbs, int speed)
 {
 	char buf[160];
 	char nbuf[LIST_NAME_MAX+10+11+1];	/* Room for "Name (Logging) (115300)" and terminator */
+						/* SAFE and Logging should me be possible. */
 	int oldscroll;
 	int olddmc;
 	struct	text_info txtinfo;
@@ -143,6 +152,8 @@ void update_status(struct bbslist *bbs, int speed)
 	gotoxy(1,1);
 	_wscroll=0;
 	strcpy(nbuf, bbs->name);
+	if(safe_mode)
+		strcat(nbuf, " (SAFE)");
 	if(cterm.log)
 		strcat(nbuf, " (Logging)");
 	if(speed)
@@ -535,6 +546,9 @@ void begin_upload(char *uldir, BOOL autozm)
 			,""
 		};
 
+	if(safe_mode)
+		return;
+
 	init_uifc(FALSE, FALSE);
 	result=filepick(&uifc, "Upload", &fpick, uldir, NULL, UIFC_FP_ALLOWENTRY);
 	
@@ -570,6 +584,191 @@ void begin_upload(char *uldir, BOOL autozm)
 	uifcbail();
 }
 
+#ifdef GUTS_BUILTIN
+static int guts_lputs(void* cbdata, int level, const char* str)
+{
+	struct GUTS_info *gi=cbdata;
+	/* ToDo: Do something usefull here. */
+	/* fprintf(stderr,"%s\n",str); */
+	return(0);
+}
+
+void guts_zmodem_progress(void* cbdata, ulong current_pos)
+{
+	struct GUTS_info *gi=cbdata;
+	/* ToDo: Do something usefull here. */
+	return;
+}
+
+static int guts_send_byte(void* cbdata, uchar ch, unsigned timeout)
+{
+	int	i;
+	struct GUTS_info *gi=cbdata;
+
+	if(!socket_check(gi->oob_socket, NULL, &i, timeout*1000))
+		return(-1);
+
+	if(!i)
+		return(-1);
+
+	if(send(gi->oob_socket,&ch,1,0)==-1)
+		return(-1);
+
+	return(0);
+}
+
+static int guts_recv_byte(void* cbdata, unsigned timeout)
+{
+	BOOL	data_waiting;
+	BYTE	ch;
+	struct GUTS_info *gi=cbdata;
+
+	if(!socket_check(gi->oob_socket, &data_waiting, NULL, timeout*1000))
+		return(-1);
+
+	if(!data_waiting)
+		return(-1);
+
+	if(recv(gi->oob_socket,&ch,1,0)!=1)
+		return(-1);
+
+	return(ch);
+}
+
+static BOOL guts_is_connected(void* cbdata)
+{
+	struct GUTS_info *gi=cbdata;
+	return socket_check(gi->oob_socket,NULL,NULL,0);
+}
+
+BOOL guts_data_waiting(void* cbdata, unsigned timeout)
+{
+	BOOL rd;
+	struct GUTS_info *gi=cbdata;
+
+	if(!socket_check(gi->oob_socket,&rd,NULL,timeout*1000))
+		return(FALSE);
+	return(rd);
+}
+
+void zmodem_download(char *download_dir);
+
+void guts_background_download(void *cbdata)
+{
+	struct GUTS_info gi=*(struct GUTS_info *)cbdata;
+
+	zmodem_t	zm;
+	ulong		bytes_received;
+
+	zmodem_init(&zm
+		,&gi
+		,guts_lputs, guts_zmodem_progress
+		,guts_send_byte,guts_recv_byte,guts_is_connected
+		,guts_data_waiting);
+
+	/* ToDo: This would be a good time to detach or something. */
+	zmodem_recv_files(&zm,gi.files[0],&bytes_received);
+
+	oob_close(&gi);
+}
+
+void guts_background_upload(void *cbdata)
+{
+	struct GUTS_info gi=*(struct GUTS_info *)cbdata;
+
+	zmodem_t	zm;
+	ulong	fsize;
+	FILE*	fp;
+
+	if((fp=fopen(gi.files[0],"rb"))==NULL) {
+		fprintf(stderr,"Error %d opening %s for read",errno,gi.files[0]);
+		return;
+	}
+
+	setvbuf(fp,NULL,_IOFBF,0x10000);
+
+	zmodem_init(&zm
+		,&gi
+		,guts_lputs, guts_zmodem_progress
+		,guts_send_byte,guts_recv_byte,guts_is_connected
+		,guts_data_waiting);
+
+	zm.current_file_num = zm.total_files = 1;	/* ToDo: support multi-file/batch uploads */
+
+	fsize=filelength(fileno(fp));
+
+	if(zmodem_send_file(&zm, gi.files[0], fp
+		,/* ZRQINIT? */TRUE, /* start_time */NULL, /* sent_bytes */ NULL))
+		zmodem_get_zfin(&zm);
+
+	fclose(fp);
+
+	oob_close(&gi);
+}
+
+void guts_transfer(struct bbslist *bbs)
+{
+	struct GUTS_info gi;
+
+	if(safe_mode)
+		return;
+	setup_defaults(&gi);
+	gi.socket=conn_socket;
+	gi.telnet=bbs->conn_type==CONN_TYPE_TELNET;
+	gi.server=FALSE;
+	gi.use_daemon=FALSE;
+	gi.orig=FALSE;
+
+	if(negotiation(&gi)) {
+		oob_close(&gi);
+		return;
+	}
+
+	/* Authentication Phase */
+	if(!gi.inband) {
+		if(authenticate(&gi)) {
+			oob_close(&gi);
+			return;
+		}
+	}
+
+	if(gi.inband) {
+		if(gi.direction==UPLOAD)
+			begin_upload(bbs->uldir, TRUE);
+		else
+			zmodem_download(bbs->dldir);
+		oob_close(&gi);
+	}
+	else {
+		if(gi.direction==UPLOAD) {
+			int		result;
+			struct file_pick fpick;
+
+			init_uifc(FALSE, FALSE);
+			result=filepick(&uifc, "Upload", &fpick, bbs->uldir, NULL, UIFC_FP_ALLOWENTRY);
+
+			if(result==-1 || fpick.files<1) {
+				filepick_free(&fpick);
+				uifcbail();
+				return;
+			}
+			strListPush(&gi.files, fpick.selected[0]);
+			filepick_free(&fpick);
+
+			uifcbail();
+
+			_beginthread(guts_background_upload, 0, &gi);
+		}
+		else {
+			strListPush(&gi.files, bbs->dldir);
+			_beginthread(guts_background_download, 0, &gi);
+		}
+	}
+
+	return;
+}
+#endif
+
 void ascii_upload(FILE *fp, char *path)
 {
 	char linebuf[1024+2];	/* One extra for terminator, one extra for added CR */
@@ -645,6 +844,8 @@ void zmodem_download(char *download_dir)
 	int			files_received;
 	ulong		bytes_received;
 
+	if(safe_mode)
+		return;
 #if 0
 	bufbot=buftop=0;	/* purge our receive buffer */
 #endif
@@ -720,6 +921,8 @@ void font_control(struct bbslist *bbs)
 	struct	text_info txtinfo;
 	int i,j,k;
 
+	if(safe_mode)
+		return;
    	gettextinfo(&txtinfo);
 	buf=(char *)malloc(txtinfo.screenheight*txtinfo.screenwidth*2);
 	gettext(1,1,txtinfo.screenwidth,txtinfo.screenheight,buf);
@@ -755,6 +958,8 @@ void capture_control(struct bbslist *bbs)
 	struct	text_info txtinfo;
 	int i,j;
 
+	if(safe_mode)
+		return;
    	gettextinfo(&txtinfo);
 	buf=(char *)malloc(txtinfo.screenheight*txtinfo.screenwidth*2);
 	gettext(1,1,txtinfo.screenwidth,txtinfo.screenheight,buf);
@@ -835,13 +1040,21 @@ void capture_control(struct bbslist *bbs)
 BOOL doterm(struct bbslist *bbs)
 {
 	unsigned char ch[2];
+#ifdef GUTS_BUILTIN
+	unsigned char prn[1024];
+#else
 	unsigned char prn[BUFSIZE];
+#endif
 	int	key;
 	int i,j,k;
 	unsigned char *p;
 	BYTE zrqinit[] = { ZDLE, ZHEX, '0', '0', 0 };	/* for Zmodem auto-downloads */
 	BYTE zrinit[] = { ZDLE, ZHEX, '0', '1', 0 };	/* for Zmodem auto-uploads */
 	BYTE zrqbuf[5];
+#ifdef GUTS_BUILTIN
+	BYTE gutsinit[] = { ESC, '[', '{' };	/* For GUTS auto-transfers */
+	BYTE gutsbuf[3];
+#endif
 	int	inch;
 	long double nextchar=0;
 	long double lastchar=0;
@@ -865,6 +1078,9 @@ BOOL doterm(struct bbslist *bbs)
 	cterm.music_enable=bbs->music;
 	ch[1]=0;
 	zrqbuf[0]=0;
+#ifdef GUTS_BUILTIN
+	gutsbuf[0]=0;
+#endif
 
 	/* Main input loop */
 	oldmc=hold_update;
@@ -899,6 +1115,35 @@ BOOL doterm(struct bbslist *bbs)
 						lastchar = xp_timer();
 						nextchar = lastchar + 1/(long double)(speed/10);
 					}
+
+#ifdef GUTS_BUILTIN
+					if(!gutsbuf[0]) {
+						if(inch == gutsinit[0]) {
+							gutsbuf[0]=inch;
+							gutsbuf[1]=0;
+							continue;
+						}
+					}
+					else {		/* Already have the start of the sequence */
+						j=strlen(gutsbuf);
+						if(inch == gutsinit[j]) {
+							gutsbuf[j]=inch;
+							gutsbuf[++j]=0;
+							if(j==sizeof(gutsinit)) /* Have full sequence */
+								guts_transfer(bbs);
+						}
+						else {
+							gutsbuf[j++]=inch;
+							cterm_write(gutsbuf, j, prn, sizeof(prn), &speed);
+							if(prn[0])
+								conn_send(prn,strlen(prn),0);
+							updated=TRUE;
+							gutsbuf[0]=0;
+						}
+						continue;
+					}
+#endif
+
 					if(!zrqbuf[0]) {
 						if(inch == zrqinit[0] || inch == zrinit[0]) {
 							zrqbuf[0]=inch;
@@ -911,7 +1156,7 @@ BOOL doterm(struct bbslist *bbs)
 						if(inch == zrqinit[j] || inch == zrinit[j]) {
 							zrqbuf[j]=inch;
 							zrqbuf[++j]=0;
-							if(j==sizeof(zrqinit)-1) {	/* Have full sequence (Assumes zrinit and zrqinit are same length */
+							if(j==sizeof(zrqinit)) {	/* Have full sequence (Assumes zrinit and zrqinit are same length */
 								if(!strcmp(zrqbuf, zrqinit))
 									zmodem_download(bbs->dldir);
 								else