diff --git a/src/sbbs3/zmodem.c b/src/sbbs3/zmodem.c
index 4ebbb9a802616970dcffd88d5ec03c944bf55db4..d5e01b1586efae3eb4bf77b49bd18b2803ddcfe6 100755
--- a/src/sbbs3/zmodem.c
+++ b/src/sbbs3/zmodem.c
@@ -648,17 +648,20 @@ int zmodem_recv_raw(zmodem_t* zm)
 	int c;
 	unsigned attempt;
 
-	for(attempt=0;attempt<=zm->recv_timeout;attempt++) {
+	for(attempt=0; attempt < zm->recv_timeout; attempt++) {
 		if((c=zm->recv_byte(zm->cbdata,1 /* second timeout */)) >= 0)
 			break;
 		if(is_cancelled(zm))
 			return(ZCAN);
 		if(!is_connected(zm))
 			return(ABORTED);
-		lprintf(zm, LOG_ERR, "%s Received NO INPUT", __FUNCTION__);
+		lprintf(zm, LOG_DEBUG, "%lu %s Received NO INPUT (attempt %u of %u)",
+			(ulong)zm->current_file_pos, __FUNCTION__, attempt, zm->recv_timeout);
+	}
+	if(attempt >= zm->recv_timeout) {
+		lprintf(zm, LOG_WARNING, "%lu %s TIMEOUT", (ulong)zm->current_file_pos, __FUNCTION__);
+		return TIMEOUT;
 	}
-	if(attempt>zm->recv_timeout)
-		return(TIMEOUT);
 
 	if(c == CAN) {
 		zm->n_cans++;
@@ -707,9 +710,11 @@ int zmodem_rx(zmodem_t* zm)
 						,(ulong)zm->current_file_pos, chr(c));
 					continue;
 				default:
+					if(c < 0)
+						return c;
 					/*
 	 				 * if all control characters should be escaped and
-					 * this one wasnt then its spurious and should be dropped.
+					 * this one wasn't then its spurious and should be dropped.
 					 */
 					if(zm->escape_ctrl_chars && (c >= 0) && (c & 0x60) == 0) {
 						lprintf(zm,LOG_WARNING, "%lu Dropping unescaped ctrl char: %s"
@@ -772,7 +777,7 @@ int zmodem_rx(zmodem_t* zm)
 					}
 					/*
 					 * legitimate escape sequence.
-					 * rebuild the orignal and return it.
+					 * rebuild the original and return it.
 					 */
 					if((c & 0x60) == 0x40) {
 						return c ^ 0x40;
@@ -786,7 +791,7 @@ int zmodem_rx(zmodem_t* zm)
 	}
 
 	/*
-	 * not reached (unless cancelled).
+	 * not reached (unless canceled).
 	 */
 
 	return ABORTED;
@@ -806,7 +811,7 @@ int zmodem_rx(zmodem_t* zm)
  * data subpacket reception
  */
 
-int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigned* l)
+int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigned* l, int* type)
 {
 	int c;
 	uint32_t rxd_crc;
@@ -815,6 +820,7 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne
 
 //	lprintf(zm,LOG_DEBUG, __FUNCTION___);
 
+	*type = INVALIDSUBPKT;
 	crc = 0xffffffffl;
 
 	do {
@@ -836,6 +842,7 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne
 	} while(1);
 
 	subpkt_type = c & 0xff;
+	*type = subpkt_type;
 
 	crc = ucrc32(subpkt_type, crc);
 
@@ -859,7 +866,7 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne
 	return subpkt_type;
 }
 
-int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen, unsigned* l)
+int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen, unsigned* l, int* type)
 {
 	int c;
 	int subpkt_type;
@@ -869,6 +876,7 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen,
 //	lprintf(zm, LOG_DEBUG, __FUNCTION__);
 
 	crc = 0;
+	*type = INVALIDSUBPKT;
 
 	do {
 		c = zmodem_rx(zm);
@@ -887,6 +895,7 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen,
 	} while(1);
 
 	subpkt_type = c & 0xff;
+	*type = subpkt_type;
 
 	crc = ucrc16(subpkt_type,crc);
 
@@ -906,7 +915,7 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen,
 	return subpkt_type;
 }
 
-int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l, BOOL ack)
+int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l, BOOL ack, int* type)
 {
 	int subpkt_type;
 	unsigned n=0;
@@ -923,10 +932,10 @@ int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l,
 	*l = 0;
 
 	if(zm->receive_32bit_data) {
-		subpkt_type = zmodem_recv_data32(zm, p, maxlen, l);
+		subpkt_type = zmodem_recv_data32(zm, p, maxlen, l, type);
 	}
 	else {
-		subpkt_type = zmodem_recv_data16(zm, p, maxlen, l);
+		subpkt_type = zmodem_recv_data16(zm, p, maxlen, l, type);
 	}
 
 	if(subpkt_type <= 0) {	/* e.g. TIMEOUT, SUBPKTOVERFLOW, CRCFAILED */
@@ -968,13 +977,14 @@ int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l,
 	return INVALIDSUBPKT;
 }
 
-BOOL zmodem_recv_subpacket(zmodem_t* zm, BOOL ack)
+BOOL zmodem_recv_subpacket(zmodem_t* zm, BOOL ack, int* type)
 {
-	int type;
+	int	result;
 
-	type=zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket),NULL,ack);
-	if(type!=FRAMEOK && type!=ENDOFFRAME) {
-		lprintf(zm, LOG_ERR, "%lu %s ERROR: %s", (ulong)zm->ack_file_pos, __FUNCTION__, chr(type));
+	result = zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket),NULL,ack, type);
+	if(result != FRAMEOK && result != ENDOFFRAME) {
+		lprintf(zm, LOG_ERR, "%lu %s ERROR: %s (subpacket type: %s)"
+			,(ulong)zm->ack_file_pos, __FUNCTION__, chr(result), chr(*type));
 		zmodem_send_znak(zm);
 		return(FALSE);
 	}
@@ -1192,6 +1202,7 @@ BOOL zmodem_recv_bin32_header(zmodem_t* zm)
 int zmodem_recv_header_raw(zmodem_t* zm, int errors)
 {
 	int c;
+	int type = INVALIDSUBPKT;
 	int	frame_type;
 
 //	lprintf(zm,LOG_DEBUG, __FUNCTION__);
@@ -1290,13 +1301,17 @@ int zmodem_recv_header_raw(zmodem_t* zm, int errors)
 			break;
 		case ZFILE:
 			zm->ack_file_pos = 0l;
-			if(!zmodem_recv_subpacket(zm,/* ack? */FALSE))
+			if(!zmodem_recv_subpacket(zm,/* ack? */FALSE, &type)) {
+				lprintf(zm, LOG_WARNING, "%s bad %s subpacket: %s", __FUNCTION__, chr(frame_type), chr(type));
 				frame_type |= BADSUBPKT;
+			}
 			break;
 		case ZSINIT:
 		case ZCOMMAND:
-			if(!zmodem_recv_subpacket(zm,/* ack? */TRUE))
+			if(!zmodem_recv_subpacket(zm,/* ack? */TRUE, &type)) {
+				lprintf(zm, LOG_WARNING, "%s bad %s subpacket: %s", __FUNCTION__, chr(frame_type), chr(type));
 				frame_type |= BADSUBPKT;
+			}
 			break;
 		case ZFREECNT:
 			zmodem_send_pos_header(zm, ZACK, getfreediskspace(".",1), /* Hex? */ TRUE);
@@ -1587,7 +1602,7 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, uint64_t pos, uint64_t* sent)
 			}
 		}
 
-		/* Note: No support for sending ZCRCQ data sub-packets here */
+		/* Note: No support for sending ZCRCQ data subpackets here */
 
 		if(zmodem_send_data(zm, type, zm->tx_data_subpacket, n)!=0)
 			return(TIMEOUT);
@@ -1878,7 +1893,7 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti
 	zm->errors = 0;
 	zm->consecutive_errors = 0;
 
-	lprintf(zm,LOG_DEBUG,"Sending %s from offset %"PRIu64, fname, pos);
+	lprintf(zm,LOG_DEBUG,"%lu Sending %s", (ulong)pos, fname);
 	do {
 		/*
 		 * and start sending
@@ -2186,25 +2201,32 @@ void zmodem_parse_zfile_subpacket(zmodem_t* zm)
 		zm->total_bytes = zm->bytes_remaining;
 }
 
+BOOL zmodem_waits_for_ack(int type)
+{
+	return type == ZCRCW;
+}
+
 /*
  * receive file data until the end of the file or until something goes wrong.
+ * returns error count (non-zero does not mean failure).
  */
 
 unsigned zmodem_recv_file_data(zmodem_t* zm, FILE* fp, int64_t offset)
 {
-	int			type=0;
+	int			type = INVALIDSUBPKT;	// data subpacket type
 	unsigned	errors=0;
-	off_t		pos;
+	off_t		pos = (off_t)offset;
 
 	zm->transfer_start_pos=offset;
 	zm->transfer_start_time=time(NULL);
 
-	if(fseeko(fp,(off_t)offset,SEEK_SET)!=0) {
+	if(fseeko(fp, pos, SEEK_SET)!=0) {
 		lprintf(zm,LOG_ERR, "%s ERROR %d seeking to file offset %"PRId64
 			,__FUNCTION__, errno, offset);
-		zmodem_send_pos_header(zm, ZFERR, (uint32_t)offset, /* Hex? */ TRUE);
+		zmodem_send_pos_header(zm, ZFERR, (uint32_t)pos, /* Hex? */ TRUE);
 		return 1; /* errors */
 	}
+	zmodem_send_pos_header(zm, ZRPOS, (uint32_t)pos, /* Hex? */ TRUE);
 
 	/*  zmodem.doc:
 
@@ -2217,54 +2239,47 @@ unsigned zmodem_recv_file_data(zmodem_t* zm, FILE* fp, int64_t offset)
 	*/
 	while(is_connected(zm) && !is_cancelled(zm)) {
 
-		if((pos=ftello(fp)) > zm->current_file_size)
+		if(pos > zm->current_file_size)
 			zm->current_file_size = pos;
 
 		if(zm->max_file_size!=0 && pos >= zm->max_file_size) {
-			lprintf(zm,LOG_WARNING, "Specified maximum file size (%"PRId64" bytes) reached at offset %"PRId64
-				,zm->max_file_size, pos);
+			lprintf(zm, LOG_ERR, "%lu Specified maximum file size (%"PRId64" bytes) reached"
+				,(ulong)pos, zm->max_file_size);
 			zmodem_send_pos_header(zm, ZFERR, (uint32_t)pos, /* Hex? */ TRUE);
+			++errors;
 			break;
 		}
 
-		if(type!=ENDOFFRAME) {
-			lprintf(zm, LOG_WARNING, "%lu Repositioning sender (sending ZRPOS)", (ulong)pos);
-			zmodem_send_pos_header(zm, ZRPOS, (uint32_t)pos, /* Hex? */ TRUE);
+		int result = zmodem_recv_file_frame(zm, fp, &type);
+		pos = ftello(fp);
+		if(result == ENDOFFRAME) {
+			lprintf(zm,LOG_DEBUG, "%lu Complete data frame received (type: %s)", (ulong)pos, chr(type));
+			continue;
 		}
-
-		type = zmodem_recv_file_frame(zm,fp);
-		if(type == ZEOF || type == ZFIN)
+		if(result == ZEOF || result == ZFIN) {
+			lprintf(zm, LOG_INFO, "%lu Received: %s", (ulong)pos, chr(result));
 			break;
-		if(type==ENDOFFRAME)
-			lprintf(zm,LOG_DEBUG, "%lu Complete frame received", (ulong)ftello(fp));
-		else {
-			errors++;
-			if(type>0 && !zm->local_abort)
-				lprintf(zm, LOG_ERR, "%lu ERROR #%d: %s", (ulong)ftello(fp), errors, chr(type));
 		}
+		errors++;
+		lprintf(zm, LOG_WARNING, "%lu ERROR #%d: %s (type: %s)", (ulong)pos, errors, chr(result), chr(type));
 		if(errors > zm->max_errors) {
-			lprintf(zm, LOG_ERR, "%lu Maximum errors (%lu) exceeded", (ulong)ftello(fp), zm->max_errors);
+			lprintf(zm, LOG_ERR, "%lu Maximum errors (%lu) exceeded", (ulong)pos, zm->max_errors);
 			break;
 		}
+		if(zmodem_waits_for_ack(type))
+			zmodem_recv_purge(zm);
+		lprintf(zm, LOG_NOTICE, "%lu Repositioning sender (sending ZRPOS)", (ulong)pos);
+		zmodem_send_pos_header(zm, ZRPOS, (uint32_t)pos, /* Hex? */ TRUE);
 	}
 
-	/*
- 	 * wait for the eof header
-	 */
-	for(;errors<=zm->max_errors && !is_cancelled(zm) && type!=ZEOF && type!=ZFIN; errors++) {
-		lprintf(zm, LOG_INFO, "%lu Waiting for EOF or FIN", (ulong)ftello(fp));
-		type = zmodem_recv_header_and_check(zm);
-		lprintf(zm, LOG_DEBUG, "%lu Received %s", (ulong)ftello(fp), chr(type));
-	}
-
-	return(errors);
+	return errors;
 }
 
 
-int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp)
+int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, int* type)
 {
+	int			result;
 	unsigned	n;
-	int			type;
 	unsigned	attempt;
 
 	/*
@@ -2275,29 +2290,29 @@ int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp)
 	for(attempt=0;;attempt++) {
 		if(attempt>=zm->max_errors)
 			return TIMEOUT;
-		type = zmodem_recv_header(zm);
-		switch(type) {
+		result = zmodem_recv_header(zm);
+		switch(result) {
 			case ZEOF:
 				/* ZMODEM.DOC:
 				   If the receiver has not received all the bytes of the file,
 				   the receiver ignores the ZEOF because a new ZDATA is coming.
 				*/
 				if(zm->rxd_header_pos==(uint32_t)ftello(fp))
-					return type;
+					return result;
 				lprintf(zm,LOG_WARNING,"Ignoring ZEOF as all bytes (%lu) have not been received"
 					,zm->rxd_header_pos);
 				continue;
 			case ZFIN:
 			case TIMEOUT:
-				return type;
+				return result;
 		}
 		if(is_cancelled(zm) || !is_connected(zm))
 			return ZCAN;
 
-		if(type==ZDATA)
+		if(result == ZDATA)
 			break;
 
-		lprintf(zm, LOG_WARNING, "%lu Received %s instead of ZDATA frame", (ulong)ftello(fp), frame_desc(type));
+		lprintf(zm, LOG_WARNING, "%lu Received %s instead of ZDATA frame", (ulong)ftello(fp), frame_desc(result));
 	}
 
 	if(zm->rxd_header_pos != (uint32_t)ftello(fp)) {
@@ -2307,11 +2322,11 @@ int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp)
 	}
 
 	do {
-		type = zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket),&n,TRUE);
+		result = zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket), &n, /* ack */TRUE, type);
 
 /*		fprintf(stderr,"packet len %d type %d\n",n,type);
 */
-		if (type == ENDOFFRAME || type == FRAMEOK) {
+		if (result == ENDOFFRAME || result == FRAMEOK) {
 			if(fwrite(zm->rx_data_subpacket,1,n,fp)!=n) {
 				lprintf(zm,LOG_ERR,"ERROR %d writing %u bytes at file offset %"PRIu64
 						,errno, n,(uint64_t)ftello(fp));
@@ -2320,18 +2335,18 @@ int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp)
 			}
 		}
 
-		if(type==FRAMEOK)
+		if(result == FRAMEOK)
 			zm->block_size = n;
 
 		if(zm->progress!=NULL)
 			zm->progress(zm->cbdata, ftello(fp));
 
 		if(is_cancelled(zm))
-			return(ZCAN);
+			return ZCAN;
 
-	} while(type == FRAMEOK);
+	} while(result == FRAMEOK);
 
-	return type;
+	return result;
 }
 
 const char* zmodem_source(void)