diff --git a/src/sbbs3/zmodem.c b/src/sbbs3/zmodem.c
index f35a8d4623d3d8c11cce4c8605154dd1a87a31c9..cd0cff5a699734c1ed4ef7d353038083238d0a67 100644
--- a/src/sbbs3/zmodem.c
+++ b/src/sbbs3/zmodem.c
@@ -40,9 +40,10 @@
 #define FRAMEOK    1
 #define TIMEOUT   -1	/* rx routine did not receive a character within timeout */
 #define INVHDR    -2	/* invalid header received; but within timeout */
-#define INVDATA   -3	/* invalid data subpacket received */
 #define ZDLEESC 0x8000	/* one of ZCRCE; ZCRCG; ZCRCQ or ZCRCW was received; ZDLE escaped */
 
+#define BADSUBPKT	0x80
+
 #define HDRLEN     5	/* size of a zmodem header */
 
 static int lprintf(zmodem_t* zm, int level, const char *fmt, ...)
@@ -113,6 +114,50 @@ static char *chr(uchar ch)
 	return(str); 
 }
 
+static char* frame_desc(int frame)
+{
+	static char str[25];
+
+	if(frame==TIMEOUT)
+		return("TIMEOUT");
+
+	if(frame==INVHDR)
+		return("Invalid Header");
+
+	if(frame&BADSUBPKT)
+		strcpy(str,"BAD ");
+	else
+		str[0]=0;
+
+	switch(frame&~BADSUBPKT) {
+		case ZRQINIT:		strcat(str,"ZRQINIT");		break;
+		case ZRINIT:		strcat(str,"ZRINIT");		break;
+		case ZSINIT:		strcat(str,"ZSINIT");		break;
+		case ZACK:			strcat(str,"ZACK");			break;
+		case ZFILE:			strcat(str,"ZFILE");		break;
+		case ZSKIP:			strcat(str,"ZSKIP");		break;
+		case ZNAK:			strcat(str,"ZNAK");			break;
+		case ZABORT:		strcat(str,"ZABORT");		break;
+		case ZFIN:			strcat(str,"ZFIN");			break;
+		case ZRPOS:			strcat(str,"ZRPOS");		break;
+		case ZDATA:			strcat(str,"ZDATA");		break;
+		case ZEOF:			strcat(str,"ZEOF");			break;
+		case ZFERR:			strcat(str,"ZFERR");		break;
+		case ZCRC:			strcat(str,"ZCRC");			break;
+		case ZCHALLENGE:	strcat(str,"ZCHALLENGE");	break;
+		case ZCOMPL:		strcat(str,"ZCOMPL");		break;
+		case ZCAN:			strcat(str,"ZCAN");			break;
+		case ZFREECNT:		strcat(str,"ZFREECNT");		break;
+		case ZCOMMAND:		strcat(str,"ZCOMMAND");		break;	
+		case ZSTDERR:		strcat(str,"ZSTDERR");		break;		
+		default: 
+			sprintf(str,"Unknown (%08X)", frame);
+			break;
+	}
+	return(str); 
+}
+
+
 /*
  * read bytes as long as rdchk indicates that
  * more data is available.
@@ -357,12 +402,12 @@ int zmodem_send_bin_header(zmodem_t* zm, unsigned char * p)
  * data subpacket transmission
  */
 
-int zmodem_send_data32(zmodem_t* zm, uchar sub_frame_type, unsigned char * p, int l)
+int zmodem_send_data32(zmodem_t* zm, uchar subpkt_type, unsigned char * p, int l)
 {
 	int	result;
 	unsigned long crc;
 
-	lprintf(zm,LOG_DEBUG,"zmodem_send_data32: %s", chr(sub_frame_type));
+	lprintf(zm,LOG_DEBUG,"zmodem_send_data32: %s", chr(subpkt_type));
 
 	crc = 0xffffffffl;
 
@@ -373,11 +418,11 @@ int zmodem_send_data32(zmodem_t* zm, uchar sub_frame_type, unsigned char * p, in
 		l--;
 	}
 
-	crc = ucrc32(sub_frame_type, crc);
+	crc = ucrc32(subpkt_type, crc);
 
 	if((result=zmodem_send_raw(zm, ZDLE))!=0)
 		return result;
-	if((result=zmodem_send_raw(zm, sub_frame_type))!=0)
+	if((result=zmodem_send_raw(zm, subpkt_type))!=0)
 		return result;
 
 	crc = ~crc;
@@ -391,12 +436,12 @@ int zmodem_send_data32(zmodem_t* zm, uchar sub_frame_type, unsigned char * p, in
 	return		zmodem_tx(zm, (uchar) ((crc >> 24) & 0xff));
 }
 
-int zmodem_send_data16(zmodem_t* zm, uchar sub_frame_type,unsigned char * p,int l)
+int zmodem_send_data16(zmodem_t* zm, uchar subpkt_type,unsigned char * p,int l)
 {
 	int	result;
 	unsigned short crc;
 
-	lprintf(zm,LOG_DEBUG,"zmodem_send_data16: %s", chr(sub_frame_type));
+	lprintf(zm,LOG_DEBUG,"zmodem_send_data16: %s", chr(subpkt_type));
 
 	crc = 0;
 
@@ -407,11 +452,11 @@ int zmodem_send_data16(zmodem_t* zm, uchar sub_frame_type,unsigned char * p,int
 		l--;
 	}
 
-	crc = ucrc16(sub_frame_type,crc);
+	crc = ucrc16(subpkt_type,crc);
 
 	if((result=zmodem_send_raw(zm, ZDLE))!=0)
 		return result;
-	if((result=zmodem_send_raw(zm, sub_frame_type))!=0)
+	if((result=zmodem_send_raw(zm, subpkt_type))!=0)
 		return result;
 	
 	if((result=	zmodem_tx(zm, (uchar)(crc >> 8)))!=0)
@@ -423,20 +468,20 @@ int zmodem_send_data16(zmodem_t* zm, uchar sub_frame_type,unsigned char * p,int
  * send a data subpacket using crc 16 or crc 32 as desired by the receiver
  */
 
-int zmodem_send_data(zmodem_t* zm, uchar sub_frame_type, unsigned char * p, int l)
+int zmodem_send_data(zmodem_t* zm, uchar subpkt_type, unsigned char * p, int l)
 {
 	int result;
 
 	if(!zm->want_fcs_16 && zm->can_fcs_32) {
-		if((result=zmodem_send_data32(zm, sub_frame_type,p,l))!=0)
+		if((result=zmodem_send_data32(zm, subpkt_type,p,l))!=0)
 			return result;
 	}
 	else {	
-		if((result=zmodem_send_data16(zm, sub_frame_type,p,l))!=0)
+		if((result=zmodem_send_data16(zm, subpkt_type,p,l))!=0)
 			return result;
 	}
 
-	if(sub_frame_type == ZCRCW)
+	if(subpkt_type == ZCRCW)
 		result=zmodem_send_raw(zm, XON);
 
 	return result;
@@ -654,7 +699,7 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne
 	int c;
 	unsigned long rxd_crc;
 	unsigned long crc;
-	int sub_frame_type;
+	int subpkt_type;
 
 	lprintf(zm,LOG_DEBUG,"zmodem_recv_data32");
 
@@ -674,9 +719,9 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne
 		}
 	} while(c < 0x100);
 
-	sub_frame_type = c & 0xff;
+	subpkt_type = c & 0xff;
 
-	crc = ucrc32(sub_frame_type, crc);
+	crc = ucrc32(subpkt_type, crc);
 
 	crc = ~crc;
 
@@ -686,22 +731,22 @@ int zmodem_recv_data32(zmodem_t* zm, unsigned char * p, unsigned maxlen, unsigne
 	rxd_crc |= zmodem_rx(zm) << 24;
 
 	if(rxd_crc != crc) {
-		lprintf(zm,LOG_WARNING,"CRC32 ERROR (%08lX, expected: %08lX) Bytes=%u, sub-frame-type=%s"
-			,rxd_crc, crc, *l, chr((char)sub_frame_type));
+		lprintf(zm,LOG_WARNING,"CRC32 ERROR (%08lX, expected: %08lX) Bytes=%u, subpacket-type=%s"
+			,rxd_crc, crc, *l, chr((char)subpkt_type));
 		return FALSE;
 	}
-	lprintf(zm,LOG_DEBUG,"GOOD CRC32: %08lX (Bytes=%u, sub-frame-type=%s)"
-		,crc, *l, chr((char)sub_frame_type));
+	lprintf(zm,LOG_DEBUG,"GOOD CRC32: %08lX (Bytes=%u, subpacket-type=%s)"
+		,crc, *l, chr((char)subpkt_type));
 
 	zm->ack_file_pos += *l;
 
-	return sub_frame_type;
+	return subpkt_type;
 }
 
 int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen, unsigned* l)
 {
 	int c;
-	int sub_frame_type;
+	int subpkt_type;
  	unsigned short crc;
 	unsigned short rxd_crc;
 
@@ -722,9 +767,9 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen,
 		}
 	} while(c < 0x100);
 
-	sub_frame_type = c & 0xff;
+	subpkt_type = c & 0xff;
 
-	crc = ucrc16(sub_frame_type,crc);
+	crc = ucrc16(subpkt_type,crc);
 
 	rxd_crc  = zmodem_rx(zm) << 8;
 	rxd_crc |= zmodem_rx(zm);
@@ -738,12 +783,12 @@ int zmodem_recv_data16(zmodem_t* zm, register unsigned char* p, unsigned maxlen,
 
 	zm->ack_file_pos += *l;
 
-	return sub_frame_type;
+	return subpkt_type;
 }
 
-int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l)
+int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l, BOOL ack)
 {
-	int sub_frame_type;
+	int subpkt_type;
 	long pos;
 	unsigned n=0;
 
@@ -767,22 +812,22 @@ int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l)
 	*l = 0;
 
 	if(zm->receive_32bit_data) {
-		sub_frame_type = zmodem_recv_data32(zm, p, maxlen, l);
+		subpkt_type = zmodem_recv_data32(zm, p, maxlen, l);
 	}
 	else {	
-		sub_frame_type = zmodem_recv_data16(zm, p, maxlen, l);
+		subpkt_type = zmodem_recv_data16(zm, p, maxlen, l);
 	}
 
-	if(sub_frame_type==FALSE)
+	if(subpkt_type==FALSE)
 		return(FALSE);
 	
-	if(sub_frame_type==TIMEOUT)
+	if(subpkt_type==TIMEOUT)
 		return(TIMEOUT);
 	
-	lprintf(zm,LOG_DEBUG,"zmodem_recv_data received sub-frame-type: %s"
-		,chr((uchar)sub_frame_type));
+	lprintf(zm,LOG_DEBUG,"zmodem_recv_data received subpacket-type: %s"
+		,chr((uchar)subpkt_type));
 
-	switch (sub_frame_type)  {
+	switch (subpkt_type)  {
 		/*
 		 * frame continues non-stop
 		 */
@@ -797,30 +842,34 @@ int zmodem_recv_data(zmodem_t* zm, unsigned char* p, size_t maxlen, unsigned* l)
  		 * frame continues; ZACK expected
 		 */
 		case ZCRCQ:		
-			zmodem_send_ack(zm, pos);
+			if(ack)
+				zmodem_send_ack(zm, pos);
 			return FRAMEOK;
 		/*
 		 * frame ends; ZACK expected
 		 */
 		case ZCRCW:
-			zmodem_send_ack(zm, pos);
+			if(ack)
+				zmodem_send_ack(zm, pos);
 			return ENDOFFRAME;
 	}
 
-	lprintf(zm,LOG_WARNING,"Invalid sub-frame-type: %s",chr((uchar)sub_frame_type));
+	lprintf(zm,LOG_WARNING,"Invalid subpacket-type: %s",chr((uchar)subpkt_type));
 
 	return FALSE;
 }
 
-int zmodem_recv_subpacket(zmodem_t* zm)
+BOOL zmodem_recv_subpacket(zmodem_t* zm, BOOL ack)
 {
 	int type;
 
-	type=zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket),NULL);
-	if(type!=FRAMEOK && type!=ENDOFFRAME)
+	type=zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket),NULL,ack);
+	if(type!=FRAMEOK && type!=ENDOFFRAME) {
 		zmodem_send_nak(zm);
+		return(FALSE);
+	}
 
-	return(type);
+	return(TRUE);
 }
 
 int zmodem_recv_nibble(zmodem_t* zm) 
@@ -1033,6 +1082,7 @@ BOOL zmodem_recv_bin32_header(zmodem_t* zm)
 int zmodem_recv_header_raw(zmodem_t* zm, int errors)
 {
 	int c;
+	int	frame_type;
 
 	lprintf(zm,LOG_DEBUG,"zmodem_recv_header_raw");
 
@@ -1109,7 +1159,9 @@ int zmodem_recv_header_raw(zmodem_t* zm, int errors)
 	 * return its type.
 	 */
 
-	switch(zm->rxd_header[0]) {
+	frame_type = zm->rxd_header[0];
+
+	switch(frame_type) {
 		case ZCRC:
 			zm->crc_request = zm->rxd_header[ZP0] | (zm->rxd_header[ZP1] << 8) |
 				(zm->rxd_header[ZP2] << 16) | (zm->rxd_header[ZP3] << 24);
@@ -1120,14 +1172,25 @@ 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))
+				frame_type |= BADSUBPKT;
+			break;
+		case ZSINIT:
+		case ZCOMMAND:
+			if(!zmodem_recv_subpacket(zm,/* ack? */TRUE))
+				frame_type |= BADSUBPKT;
+			break;
+		case ZFREECNT:
+			zmodem_send_pos_header(zm, ZACK, getfreediskspace(".",1), /* Hex? */ TRUE);
 			break;
 	}
 
 #if 0 //def _DEBUG
-	lprintf(zm,LOG_DEBUG,"zmodem_recv_header_raw received header type: %s",chr(zm->rxd_header[0]));
+	lprintf(zm,LOG_DEBUG,"zmodem_recv_header_raw received header type: %s"
+		,frame_desc(frame_type));
 #endif
 
-	return zm->rxd_header[0];
+	return frame_type;
 }
 
 int zmodem_recv_header(zmodem_t* zm)
@@ -1137,7 +1200,7 @@ int zmodem_recv_header(zmodem_t* zm)
 	if(ret == TIMEOUT)
 		lprintf(zm,LOG_WARNING,"zmodem_recv_header TIMEOUT");
 	else
-		lprintf(zm,LOG_DEBUG,"zmodem_recv_header returning: %s", chr((uchar)ret));
+		lprintf(zm,LOG_DEBUG,"zmodem_recv_header returning: %s", frame_desc(ret));
 
 	if(ret==ZCAN)
 		zm->cancelled=TRUE;
@@ -1151,7 +1214,7 @@ int zmodem_recv_header_and_check(zmodem_t* zm)
 	while(is_connected(zm)) {
 		type = zmodem_recv_header_raw(zm,TRUE);		
 
-		if(type != INVHDR) {
+		if(type != INVHDR && (type&BADSUBPKT) == 0) {
 			break;
 		}
 
@@ -1505,6 +1568,11 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti
 		}
 
 		if(type == ZCRC) {
+			if(zm->crc_request==0)
+				lprintf(zm,LOG_NOTICE,"Receiver requested CRC of entire file");
+			else
+				lprintf(zm,LOG_NOTICE,"Receiver requested CRC of first %lu bytes"
+					,zm->crc_request);
 			zmodem_send_pos_header(zm,ZCRC,fcrc32(fp,zm->crc_request),TRUE);
 			type = zmodem_recv_header(zm);
 		}
@@ -1622,21 +1690,10 @@ int zmodem_recv_init(zmodem_t* zm
 			return(type);
 		}
 
-		lprintf(zm,LOG_WARNING,"Received header type: %s, expected ZFILE or ZFIN"
-			,chr((uchar)type));
+		lprintf(zm,LOG_WARNING,"Received frame: %s, expected ZFILE or ZFIN"
+			,frame_desc(type));
 		lprintf(zm,LOG_DEBUG,"ZF0=%02X ZF1=%02X ZF2=%02X ZF3=%02X"
 			,zm->rxd_header[ZF0],zm->rxd_header[ZF1],zm->rxd_header[ZF2],zm->rxd_header[ZF3]);
-
-		switch(type) {
-			case ZFREECNT:
-				zmodem_send_pos_header(zm, ZACK, getfreediskspace(".",1), /* Hex? */ TRUE);
-				break;
-			case ZSINIT:
-			case ZCOMMAND:
-				/* unsupported headers, receive and ignore data subpacket to follow */
-				zmodem_recv_subpacket(zm);
-				break;
-		}
 	}
 
 	return(type);
@@ -1651,7 +1708,6 @@ BOOL zmodem_recv_file_info(zmodem_t* zm
 						   ,ulong* p_total_files
 						   ,ulong* p_total_bytes)
 {
-	uchar		block[8192];
 	int			i;
 	ulong		size=0;
 	ulong		time=0;
@@ -1659,20 +1715,11 @@ BOOL zmodem_recv_file_info(zmodem_t* zm
 	ulong		total_bytes=0;
 	long		mode=0;
 	long		serial=-1;
-	unsigned	l;
-
-	memset(block,0,sizeof(block));
-	i=zmodem_recv_data(zm, block, sizeof(block), &l);
-
-	if(i!=FRAMEOK && i!=ENDOFFRAME) {
-		zmodem_send_nak(zm);
-		return(FALSE);
-	}
 
 	if(fname!=NULL)
-		safe_snprintf(fname,maxlen,"%s",block);
+		safe_snprintf(fname,maxlen,"%s",zm->rx_data_subpacket);
 
-	i=sscanf(block+strlen(block)+1,"%lu %lo %lo %lo %lu %lu"
+	i=sscanf(zm->rx_data_subpacket+strlen(zm->rx_data_subpacket)+1,"%lu %lo %lo %lo %lu %lu"
 		,&size					/* file size (decimal) */
 		,&time 					/* file time (octal unix format) */
 		,&mode 					/* file mode */
@@ -1682,7 +1729,7 @@ BOOL zmodem_recv_file_info(zmodem_t* zm
 		);
 
 	lprintf(zm,LOG_DEBUG,"Zmodem header (%u fields): %s"
-		,i, block+strlen(block)+1);
+		,i, zm->rx_data_subpacket+strlen(zm->rx_data_subpacket)+1);
 
 	if(!total_files)
 		total_files=1;
@@ -1753,9 +1800,6 @@ int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize, ti
 			if(zm->cancelled)
 				return(ZCAN);
 
-			if(type == ZFILE)	/* rrs: what? Ignore following data block! */
-				zmodem_recv_subpacket(zm);
-
 		} while(type != ZDATA);
 
 		pos = zm->rxd_header[ZP0] | (zm->rxd_header[ZP1] << 8) |
@@ -1767,7 +1811,7 @@ int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize, ti
 	} while(!zm->cancelled && is_connected(zm));
 		
 	do {
-		type = zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket),&n);
+		type = zmodem_recv_data(zm,zm->rx_data_subpacket,sizeof(zm->rx_data_subpacket),&n,TRUE);
 
 /*		fprintf(stderr,"packet len %d type %d\n",n,type);
 */