diff --git a/src/sbbs3/sexyz.c b/src/sbbs3/sexyz.c
index f18666f5e87dc3b4df87055251299c19f238c040..d8f8594ffed55c5c48c2dcf9e29e2f3f6d45f2cb 100644
--- a/src/sbbs3/sexyz.c
+++ b/src/sbbs3/sexyz.c
@@ -80,7 +80,6 @@ long	mode=0;							/* Program mode 					*/
 long	zmode=0L;						/* Zmodem mode						*/
 uchar	block[1024];					/* Block buffer 					*/
 ulong	block_num;						/* Block number 					*/
-time_t	startall;
 char*	dszlog;
 
 xmodem_t xm;
@@ -155,7 +154,7 @@ static BOOL winsock_startup(void)
 #endif
 
 
-int lputs(void* unused, int level, const char* str)
+static int lputs(void* unused, int level, const char* str)
 {
 	FILE*	fp=statfp;
 
@@ -172,7 +171,7 @@ int lputs(void* unused, int level, const char* str)
 		return fprintf(fp,"%s\n",str);
 }
 
-int lprintf(int level, const char *fmt, ...)
+static int lprintf(int level, const char *fmt, ...)
 {
 	char sbuf[1024];
 	va_list argptr;
@@ -184,12 +183,13 @@ int lprintf(int level, const char *fmt, ...)
     return(lputs(NULL,level,sbuf));
 }
 
-char *chr(uchar ch)
+static char *chr(uchar ch)
 {
 	static char str[25];
 
 	if(mode&ZMODEM) {
 		switch(ch) {
+			case ZACK:		return("ZACK");
 			case ZPAD:		return("ZPAD");
 			case ZDLE:		return("ZDLE");
 			case ZDLEE:		return("ZDLEE");
@@ -420,7 +420,7 @@ int send_byte(void* unused, uchar ch, unsigned timeout)
 }
 #endif
 
-void output_thread(void* arg)
+static void output_thread(void* arg)
 {
 	char		stats[128];
     BYTE		buf[IO_THREAD_BUF_SIZE];
@@ -653,7 +653,7 @@ void zmodem_progress(void* unused, ulong offset, ulong fsize, time_t start)
 	}
 }
 
-int send_files(char** fname, uint fnames)
+static int send_files(char** fname, uint fnames)
 {
 	char	path[MAX_PATH+1];
 	int		i;
@@ -663,17 +663,15 @@ int send_files(char** fname, uint fnames)
 	glob_t	g;
 	int		gi;
 	BOOL	success=TRUE;
-	long	l;
 	long	fsize;
-	long	block_len;
-	uint	total_files=0,sent_files=0;
-	ulong	total_bytes=0,sent_bytes=0;
-	ulong	total_blocks;
-	size_t	n;
+	ulong	sent_bytes;
+	ulong	total_bytes=0;
 	time_t	t,startfile;
-	time_t	now;
+	time_t	startall;
 	FILE*	fp;
 
+	startall=time(NULL);
+
 	/****************************************************/
 	/* Search through all to find total files and bytes */
 	/****************************************************/
@@ -685,18 +683,18 @@ int send_files(char** fname, uint fnames)
 		for(i=0;i<(int)g.gl_pathc;i++) {
 			if(isdir(g.gl_pathv[i]))
 				continue;
-			total_files++;
-			total_bytes+=flength(g.gl_pathv[i]);
+			xm.total_files++;
+			xm.total_bytes+=flength(g.gl_pathv[i]);
 		} 
 		globfree(&g);
 	}
 
-	if(fnames>1)
+	if(xm.total_files>1)
 		lprintf(LOG_INFO,"Sending %u files (%lu KB total)"
-			,total_files,total_bytes/1024);
+			,xm.total_files,xm.total_bytes/1024);
 
-	zm.n_files_remaining = total_files;
-	zm.n_bytes_remaining = total_bytes;
+	zm.n_files_remaining = xm.total_files;
+	zm.n_bytes_remaining = xm.total_bytes;
 
 	/***********************************************/
 	/* Send every file matching names or filespecs */
@@ -722,131 +720,53 @@ int send_files(char** fname, uint fnames)
 			success=FALSE;
 			startfile=time(NULL);
 
-			do { /* try */
-
-				if(!(mode&ZMODEM)) { /* X/Ymodem */
-					if(!xmodem_get_mode(&xm)) {
-						xmodem_cancel(&xm);
-						break;
-					}
-				}
+			lprintf(LOG_INFO,"Sending %s (%lu KB) via %s"
+				,path,fsize/1024
+				,mode&XMODEM ? "Xmodem" : mode&YMODEM ? "Ymodem" : "Zmodem");
 
-				lprintf(LOG_INFO,"Sending %s (%lu KB) via %s"
-					,path,fsize/1024
-					,mode&XMODEM ? "Xmodem" : mode&YMODEM ? mode&GMODE ? "Ymodem-G"
-						: "Ymodem" : "Zmodem");
-
-				if(mode&ZMODEM) {
-
-					success=zmodem_send_file(&zm,getfname(path),fp,fnum==0);
-
-				} else {	/* X/Ymodem */
-
-					if(!(mode&XMODEM)) {
-						t=fdate(path);
-						memset(block,0,sizeof(block));
-						SAFECOPY(block,getfname(path));
-						i=sprintf(block+strlen(block)+1,"%lu %lo 0 0 %d %ld"
-							,fsize,t,total_files-sent_files,total_bytes-sent_bytes);
-						
-						lprintf(LOG_INFO,"Sending Ymodem header block: '%s'",block+strlen(block)+1);
-						
-						block_len=strlen(block)+1+i;
-						for(errors=0;errors<xm.max_errors;errors++) {
-							xmodem_put_block(&xm, block, block_len <=128 ? 128:1024, 0  /* block_num */);
-							if(xmodem_get_ack(&xm,1,0))
-								break; 
-						}
-						if(errors==xm.max_errors) {
-							lprintf(LOG_ERR,"Failed to send header block");
-							xmodem_cancel(&xm);
-							break; 
-						}
-						if(!xmodem_get_mode(&xm)) {
-							xmodem_cancel(&xm);
-							break;
-						}
-					}
-					startfile=time(NULL);	/* reset time, don't count header block */
-					block_num=1;
-					errors=0;
-					while((block_num-1)*xm.block_size<(ulong)fsize && errors<xm.max_errors) {
-						fseek(fp,(block_num-1)*(long)xm.block_size,SEEK_SET);
-						memset(block,CPMEOF,xm.block_size);
-						if((n=fread(block,1,xm.block_size,fp))!=xm.block_size
-							&& block_num*xm.block_size<(ulong)fsize) {
-							lprintf(LOG_ERR,"READ ERROR %d instead of %d at offset %lu"
-								,n,xm.block_size,(block_num-1)*(long)xm.block_size);
-							errors++;
-							continue;
-						}
-						xmodem_progress(xm.cbdata,block_num,ftell(fp),fsize,startfile);
-						xmodem_put_block(&xm, block, xm.block_size, block_num);
-						now=time(NULL);
-						total_blocks=num_blocks(fsize,xm.block_size);
-						if(!xmodem_get_ack(&xm,5,block_num)) {
-							errors++;
-							lprintf(LOG_WARNING,"Error #%d at offset %ld"
-								,errors,ftell(fp)-xm.block_size);
-						} else
-							block_num++; 
-					}
-					if((long)(block_num-1)*(long)xm.block_size>=fsize) {
+			if(mode&ZMODEM)
+					success=zmodem_send_file(&zm, path, fp, /* ZRQINIT? */fnum==0, &startfile, &sent_bytes);
+			else	/* X/Ymodem */
+					success=xmodem_send_file(&xm, path, fp, &startfile, &sent_bytes);
 
-#if !SINGLE_THREADED
-						lprintf(LOG_DEBUG,"Waiting for output buffer to empty... ");
-						if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0)
-							lprintf(LOG_WARNING,"FAILURE");
-#endif
-						success=xmodem_put_eot(&xm);	/* end-of-text, wait for ACK */
-					}
-				}
-			} while(0);
-			/* finally */
 			fclose(fp);
 
 			if((t=time(NULL)-startfile)<=0) 
 				t=1;
-			cps=fsize/t;
+			cps=sent_bytes/t;
 			if(success) {
-				sent_files++;
-				sent_bytes+=fsize;
+				xm.sent_files++;
+				xm.sent_bytes+=fsize;
 				lprintf(LOG_INFO,"Successful - Time: %lu:%02lu  CPS: %lu"
 						,t/60,t%60,cps);
 			} else
 				lprintf(LOG_WARNING,"File Transfer Failure");
 
-			if(total_files>1)
+			if(xm.total_files-xm->sent_files)
 				lprintf(LOG_INFO,"Remaining - Time: %lu:%02lu  Files: %u  KBytes: %lu"
-					,((total_bytes-sent_bytes)/cps)/60
-					,((total_bytes-sent_bytes)/cps)%60
-					,total_files-sent_files
-					,(total_bytes-sent_bytes)/1024
+					,((xm.total_bytes-xm.sent_bytes)/cps)/60
+					,((xm.total_bytes-xm.sent_bytes)/cps)%60
+					,xm.total_files-xm.sent_files
+					,(xm.total_bytes-xm.sent_bytes)/1024
 					);
 
 			/* DSZLOG entry */
 			if(logfp) {
 				lprintf(LOG_DEBUG,"Updating DSZLOG: %s", dszlog);
-				if(mode&ZMODEM)
-					l=zm.sent_successfully;
-				else {
-					l=(block_num-1)*(long)xm.block_size;
-					if(l>fsize)
-						l=fsize;
-				}
 				fprintf(logfp,"%c %7lu %5u bps %6lu cps %3u errors %5u %4u "
 					"%s -1\n"
 					,success ? (mode&ZMODEM ? 'z':'S') 
 						: (mode&ZMODEM && zm.file_skipped) ? 's' 
 						: 'E'
-					,l
+					,sent_bytes
 					,115200 /* baud */
-					,l/t
+					,cps
 					,errors
 					,flows
 					,xm.block_size
 					,path); 
 			}
+			total_bytes += sent_bytes;
 		} /* while(gi<(int)g.gl_pathc) */
 
 		if(gi<(int)g.gl_pathc)/* error occurred */
@@ -875,16 +795,16 @@ int send_files(char** fname, uint fnames)
 			} 
 		}
 	}
-	if(total_files>1) {
+	if(xm.total_files>1) {
 		t=time(NULL)-startall;
 		if(!t) t=1;
 		lprintf(LOG_INFO,"Overall - Time %02lu:%02lu  KBytes: %lu  CPS: %lu"
-			,t/60,t%60,sent_bytes/1024,sent_bytes/t); 
+			,t/60,t%60,total_bytes/1024,total_bytes/t); 
 	}
 	return(0);	/* success */
 }
 
-int receive_files(char** fname, int fnames)
+static int receive_files(char** fname, int fnames)
 {
 	char	str[MAX_PATH+1];
 	int		i;
@@ -1551,8 +1471,6 @@ int main(int argc, char **argv)
 		}
 	}
 
-	startall=time(NULL);
-
 #if !SINGLE_THREADED
 	_beginthread(output_thread,0,NULL);
 #endif
diff --git a/src/sbbs3/sexyz.h b/src/sbbs3/sexyz.h
index 11554119b138ba9847f65c6697f7caad76576177..3e33e756375753171ecaa6cbeded5c1576adb996 100644
--- a/src/sbbs3/sexyz.h
+++ b/src/sbbs3/sexyz.h
@@ -58,5 +58,3 @@
 
 #define NOINP -1     			/* input buffer empty (incom only) */
 
-char*	chr(uchar ch);
-void	bail(int code);
\ No newline at end of file
diff --git a/src/sbbs3/xmodem.c b/src/sbbs3/xmodem.c
index 32050b89e541d24627f3f4f942e558bc47210660..8a91cb088e281cf61c7fe96573d49795d0374a4d 100644
--- a/src/sbbs3/xmodem.c
+++ b/src/sbbs3/xmodem.c
@@ -35,11 +35,20 @@
  * Note: If this box doesn't appear square, then you need to fix your tabs.	*
  ****************************************************************************/
 
+/* Standard headers */
+#include <stdio.h>
+#include <sys/stat.h>	/* struct stat */
 #include <stdarg.h>		/* va_list */
-#include "sexyz.h"
+
+/* smblib */
 #include "crc16.h"
+
+/* xpdev */
 #include "genwrap.h"	/* YIELD */
-#include "conwrap.h"	/* kbhit */
+#include "dirwrap.h"	/* getfname */
+
+/* sexyz */
+#include "sexyz.h"
 
 #define getcom(t)	xm->recv_byte(xm->cbdata,t)
 #define putcom(ch)	xm->send_byte(xm->cbdata,ch,xm->send_timeout)
@@ -59,6 +68,27 @@ static int lprintf(xmodem_t* xm, int level, const char *fmt, ...)
     return(xm->lputs(xm->cbdata,level,sbuf));
 }
 
+static char *chr(uchar ch)
+{
+	static char str[25];
+
+	switch(ch) {
+		case SOH:	return("SOH");
+		case STX:	return("STX");
+		case ETX:	return("ETX");
+		case EOT:	return("EOT");
+		case ACK:	return("ACK");
+		case NAK:	return("NAK");
+		case CAN:	return("CAN");
+	}
+	if(ch>=' ' && ch<='~')
+		sprintf(str,"'%c' (%02Xh)",ch,ch);
+	else
+		sprintf(str,"%u (%02Xh)",ch,ch);
+	return(str); 
+}
+
+
 void xmodem_put_ack(xmodem_t* xm)
 {
 	while(getcom(0)!=NOINP)
@@ -272,6 +302,7 @@ BOOL xmodem_get_ack(xmodem_t* xm, unsigned tries, unsigned block_num)
 			return(TRUE);
 		if(i==CAN) {
 			if(can) {
+				xm->cancelled=TRUE;
 				lprintf(xm,LOG_WARNING,"Block %u: !Cancelled remotely", block_num);
 				xmodem_cancel(xm);
 				return(FALSE); 
@@ -341,7 +372,7 @@ BOOL xmodem_put_eot(xmodem_t* xm)
 
 	for(errors=0;errors<xm->max_errors;errors++) {
 
-		lprintf(xm,LOG_INFO,"Sending end-of-Text indicator (%d)",errors+1);
+		lprintf(xm,LOG_INFO,"Sending End-of-Text (EOT) indicator (%d)",errors+1);
 
 		while((ch=getcom(0))!=NOINP)
 			lprintf(xm,LOG_INFO,"Throwing out received: %s",chr((uchar)ch));
@@ -360,6 +391,112 @@ BOOL xmodem_put_eot(xmodem_t* xm)
 	return(FALSE);
 }
 
+BOOL xmodem_send_file(xmodem_t* xm, const char* fname, FILE* fp, time_t* start, ulong* sent)
+{
+	BOOL		success=FALSE;
+	ulong		sent_bytes=0;
+	char		block[1024];
+	size_t		block_len;
+	unsigned	block_num;
+	size_t		i;
+	size_t		rd;
+	time_t		startfile;
+	struct		stat st;
+	unsigned	errors;
+
+	if(sent!=NULL)	
+		*sent=0;
+
+	if(start!=NULL)		
+		*start=time(NULL);
+
+	fstat(fileno(fp),&st);
+
+	if(xm->total_files==0)
+		xm->total_files=1;
+
+	if(xm->total_bytes==0)
+		xm->total_bytes=st.st_size;
+
+	if(*(xm->mode)&YMODEM) {
+
+		if(!xmodem_get_mode(xm)) {
+			xmodem_cancel(xm);
+			return(0);
+		}
+
+		memset(block,0,sizeof(block));
+		SAFECOPY(block,getfname(fname));
+		i=sprintf(block+strlen(block)+1,"%lu %lo 0 0 %d %ld"
+			,st.st_size
+			,st.st_mtime
+			,xm->total_files-xm->sent_files
+			,xm->total_bytes-xm->sent_bytes);
+		
+		lprintf(xm,LOG_INFO,"Sending Ymodem header block: '%s'",block+strlen(block)+1);
+		
+		block_len=strlen(block)+1+i;
+		for(errors=0;errors<xm->max_errors;errors++) {
+			xmodem_put_block(xm, block, block_len <=128 ? 128:1024, 0  /* block_num */);
+			if(xmodem_get_ack(xm,1,0))
+				break; 
+		}
+		if(errors==xm->max_errors) {
+			lprintf(xm,LOG_ERR,"Failed to send header block");
+			xmodem_cancel(xm);
+			return(0); 
+		}
+		if(!xmodem_get_mode(xm)) {
+			xmodem_cancel(xm);
+			return(0);
+		}
+	}
+	startfile=time(NULL);	/* reset time, don't count header block */
+	if(start!=NULL)
+		*start=startfile;
+
+	block_num=1;
+	errors=0;
+	while(sent_bytes < (ulong)st.st_size && errors<xm->max_errors && !xm->cancelled) {
+		fseek(fp,sent_bytes,SEEK_SET);
+		memset(block,CPMEOF,xm->block_size);
+		if((rd=fread(block,1,xm->block_size,fp))!=xm->block_size 
+			&& (long)(block_num*xm->block_size) < st.st_size) {
+			lprintf(xm,LOG_ERR,"READ ERROR %d instead of %d at offset %lu"
+				,rd,xm->block_size,(block_num-1)*(long)xm->block_size);
+			errors++;
+			continue;
+		}
+		if(xm->progress!=NULL)
+			xm->progress(xm->cbdata,block_num,ftell(fp),st.st_size,startfile);
+		xmodem_put_block(xm, block, xm->block_size, block_num);
+		if(!xmodem_get_ack(xm,5,block_num)) {
+			errors++;
+			lprintf(xm,LOG_WARNING,"Error #%d at offset %ld"
+				,errors,ftell(fp)-xm->block_size);
+		} else {
+			block_num++; 
+			sent_bytes+=rd;
+		}
+	}
+	if(sent_bytes >= (ulong)st.st_size && !xm->cancelled) {
+
+#if 0 /* !SINGLE_THREADED */
+		lprintf(LOG_DEBUG,"Waiting for output buffer to empty... ");
+		if(WaitForEvent(outbuf_empty,5000)!=WAIT_OBJECT_0)
+			lprintf(xm,LOG_WARNING,"FAILURE");
+#endif
+		if(xmodem_put_eot(xm))	/* end-of-text, wait for ACK */
+			success=TRUE;
+	}
+
+	if(sent!=NULL)
+		*sent=sent_bytes;
+
+	return(success);
+}
+
+
 const char* xmodem_source(void)
 {
 	return(__FILE__);
diff --git a/src/sbbs3/xmodem.h b/src/sbbs3/xmodem.h
index f3984e25f271bebe5a7baf21007b017a96827be9..7ba6aaecbbd65a2d48a49b2262075ac7beba676e 100644
--- a/src/sbbs3/xmodem.h
+++ b/src/sbbs3/xmodem.h
@@ -46,6 +46,7 @@ typedef struct {
 
 	void*		cbdata;
 	long*		mode;
+	BOOL		cancelled;
 	unsigned	block_size;
 	unsigned	ack_timeout;
 	unsigned	byte_timeout;
@@ -53,6 +54,10 @@ typedef struct {
 	unsigned	recv_timeout;
 	unsigned	max_errors;
 	unsigned	g_delay;
+	unsigned	total_files;
+	unsigned	total_bytes;
+	unsigned	sent_files;
+	unsigned	sent_bytes;
 	int			(*lputs)(void*, int level, const char* str);
 	void		(*progress)(void*, unsigned block_num, ulong offset, ulong fsize, time_t t);
 	int			(*send_byte)(void*, uchar ch, unsigned timeout);
@@ -76,5 +81,6 @@ void		xmodem_put_ack(xmodem_t*);
 void		xmodem_put_nak(xmodem_t*, unsigned block_num);
 int			xmodem_get_block(xmodem_t*, uchar* block, unsigned block_num);
 void		xmodem_put_block(xmodem_t*, uchar* block, unsigned block_size, unsigned block_num);
+BOOL		xmodem_send_file(xmodem_t* xm, const char* fname, FILE* fp, time_t* start, ulong* sent);
 
 #endif	/* Don't add anything after this line */
\ No newline at end of file
diff --git a/src/sbbs3/zmodem.c b/src/sbbs3/zmodem.c
index e1fceda481733420ac9b7e90b27afa3e82eff42b..550a2a7e86a0859d39a1ed3739c8cee9586e19b4 100644
--- a/src/sbbs3/zmodem.c
+++ b/src/sbbs3/zmodem.c
@@ -27,14 +27,16 @@
 #include <stdarg.h>	/* va_list */
 #include <sys/stat.h>	/* struct stat */
 
-#include "sexyz.h"
 #include "genwrap.h"
+#include "dirwrap.h"
 #include "sockwrap.h"
 
 #include "zmodem.h"
 #include "crc16.h"
 #include "crc32.h"
 
+#include "sexyz.h"
+
 #define ENDOFFRAME 2
 #define FRAMEOK    1
 #define TIMEOUT   -1	/* rx routine did not receive a character within timeout */
@@ -62,6 +64,33 @@ static int lprintf(zmodem_t* zm, int level, const char *fmt, ...)
     return(zm->lputs(zm->cbdata,level,sbuf));
 }
 
+static char *chr(uchar ch)
+{
+	static char str[25];
+
+	switch(ch) {
+		case ZACK:		return("ZACK");
+		case ZEOF:		return("ZEOF");
+		case ZPAD:		return("ZPAD");
+		case ZDLE:		return("ZDLE");
+		case ZDLEE:		return("ZDLEE");
+		case ZBIN:		return("ZBIN");
+		case ZHEX:		return("ZHEX");
+		case ZBIN32:	return("ZBIN32");
+		case ZBINR32:	return("ZBINR32");
+		case ZVBIN:		return("ZVBIN");
+		case ZVHEX:		return("ZVHEX");
+		case ZVBIN32:	return("ZVBIN32");
+		case ZVBINR32:	return("ZVBINR32");
+		case ZRESC:		return("ZRESC");
+	}
+	if(ch>=' ' && ch<='~')
+		sprintf(str,"'%c' (%02Xh)",ch,ch);
+	else
+		sprintf(str,"%u (%02Xh)",ch,ch);
+	return(str); 
+}
+
 /*
  * read bytes as long as rdchk indicates that
  * more data is available.
@@ -1009,7 +1038,7 @@ zmodem_rx_header_raw(zmodem_t* zm, int to,int errors)
 		c = zmodem_rx(zm, to);
 
 		if(c == TIMEOUT) {
-			lprintf(zm,LOG_ERR,"\n!TIMEOUT %s %d",__FILE__,__LINE__);
+			lprintf(zm,LOG_ERR,"!TIMEOUT %s %d",__FILE__,__LINE__);
 			return c;
 		}
 
@@ -1256,19 +1285,26 @@ zmodem_send_from(zmodem_t* zm, FILE * fp)
  * (using ZABORT frame)
  */
 
-BOOL zmodem_send_file(zmodem_t* zm, char* name, FILE* fp, BOOL request_init)
+BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, time_t* start, ulong* sent)
 {
-	long pos;
-	struct stat s;
+	BOOL	success=FALSE;
+	ulong	sent_bytes=0;
+	long	pos;
+	struct	stat s;
 	unsigned char * p;
-	uchar zfile_frame[] = { ZFILE, 0, 0, 0, 0 };
-	uchar zeof_frame[] = { ZEOF, 0, 0, 0, 0 };
-	int type;
-	int i;
+	uchar	zfile_frame[] = { ZFILE, 0, 0, 0, 0 };
+	uchar	zeof_frame[] = { ZEOF, 0, 0, 0, 0 };
+	int		type;
+	int		i;
 	unsigned errors;
 
+	if(sent!=NULL)	
+		*sent=0;
+
+	if(start!=NULL)		
+		*start=time(NULL);
+
 	zm->file_skipped=FALSE;
-	zm->sent_successfully=0;
 
 	if(request_init) {
 		for(errors=0;errors<zm->max_errors;errors++) {
@@ -1347,7 +1383,7 @@ BOOL zmodem_send_file(zmodem_t* zm, char* name, FILE* fp, BOOL request_init)
 
 	p = zm->tx_data_subpacket;
 
-	strcpy(p,name);
+	strcpy(p,getfname(fname));
 
 	p += strlen(p) + 1;
 
@@ -1387,7 +1423,6 @@ BOOL zmodem_send_file(zmodem_t* zm, char* name, FILE* fp, BOOL request_init)
 
 		if(type == ZSKIP) {
 			zm->file_skipped=TRUE;
-			fclose(fp);
 			lprintf(zm,LOG_WARNING,"!File skipped by receiver");
 			return(FALSE);
 		}
@@ -1396,6 +1431,9 @@ BOOL zmodem_send_file(zmodem_t* zm, char* name, FILE* fp, BOOL request_init)
 
 	zm->transfer_start = time(NULL);
 
+	if(start!=NULL)		
+		*start=zm->transfer_start;
+
 	do {
 		/*
 		 * fetch pos from the ZRPOS header
@@ -1416,17 +1454,18 @@ BOOL zmodem_send_file(zmodem_t* zm, char* name, FILE* fp, BOOL request_init)
 
 		type = zmodem_send_from(zm,fp);
 
-		if(type == ZFERR || type == ZABORT || zm->cancelled) {
- 			fclose(fp);
+		if(type == ZFERR || type == ZABORT || zm->cancelled)
 			return(FALSE);
-		}
 
 		if(type==ZACK)
-			zm->sent_successfully = ftell(fp);
+			sent_bytes = ftell(fp);
+
+		if(sent!=NULL)	
+			*sent=sent_bytes;
 
 	} while (type == ZRPOS || type == ZNAK);
 
-	lprintf(zm,LOG_INFO,"\nFinishing transfer on rx of header type: %s", chr((uchar)type));
+	lprintf(zm,LOG_INFO,"Finishing transfer on rx of header type: %s", chr((uchar)type));
 
 	/*
 	 * file sent. send end of file frame
@@ -1439,20 +1478,16 @@ BOOL zmodem_send_file(zmodem_t* zm, char* name, FILE* fp, BOOL request_init)
 	zeof_frame[ZP3] = (s.st_size >> 24) & 0xff;
 
 	zm->raw_trace = FALSE;
-	for(errors=0;errors<zm->max_errors;errors++) {
-		lprintf(zm,LOG_INFO,"Sending EOF frame (%u of %u)", errors+1, zm->max_errors);
+	for(errors=0;errors<zm->max_errors && !zm->cancelled;errors++) {
+		lprintf(zm,LOG_INFO,"Sending End-of-File (ZEOF) frame (%u of %u)", errors+1, zm->max_errors);
 		zmodem_tx_hex_header(zm,zeof_frame);
-		if(zmodem_rx_header(zm,zm->recv_timeout==ZRINIT) || zm->cancelled)
+		if(zmodem_rx_header(zm,zm->recv_timeout==ZRINIT)) {
+			success=TRUE;
 			break;
+		}
 	}
 
-	/*
-	 * and close the input file
-	 */
-
-	fclose(fp);
-
-	return(TRUE);
+	return(success);
 }
 
 #if 0
diff --git a/src/sbbs3/zmodem.h b/src/sbbs3/zmodem.h
index 39d45a2cf391d6e22f6fa797a410c7a6f25a0e80..c6089ed925701e16a5768de2b01047b577311e0b 100644
--- a/src/sbbs3/zmodem.h
+++ b/src/sbbs3/zmodem.h
@@ -247,7 +247,6 @@ typedef struct {
 	/* Status */
 	BOOL		cancelled;
 	BOOL		file_skipped;
-	ulong		sent_successfully;
 
 	/* Configuration */
 	long*		mode;
@@ -274,7 +273,7 @@ const char* zmodem_source(void);
 int			zmodem_get_zrinit(zmodem_t*);
 void		zmodem_parse_zrinit(zmodem_t*);
 int			zmodem_send_zfin(zmodem_t*);
-int			zmodem_send_file(zmodem_t*, char* name, FILE* fp, BOOL request_init);
+BOOL		zmodem_send_file(zmodem_t*, char* name, FILE* fp, BOOL request_init, time_t* start, ulong* bytes_sent);
 
 #endif