diff --git a/src/sbbs3/sexyz.c b/src/sbbs3/sexyz.c index 67ecc0a454d86ae9abaae4b3a915ed88937d3a89..173b41bd5c5d5d85d45a177c516b87c4f0423662 100644 --- a/src/sbbs3/sexyz.c +++ b/src/sbbs3/sexyz.c @@ -844,9 +844,9 @@ static int send_files(char** fname, uint fnames) success=FALSE; startfile=time(NULL); - lprintf(LOG_INFO,"Sending %s (%lu KB) via %s" + lprintf(LOG_INFO,"Sending %s (%lu KB) via %cMODEM" ,path,fsize/1024 - ,mode&XMODEM ? "Xmodem" : mode&YMODEM ? "Ymodem" : "Zmodem"); + ,mode&XMODEM ? 'X' : mode&YMODEM ? 'Y' : 'Z'); if(mode&ZMODEM) success=zmodem_send_file(&zm, path, fp, /* ZRQINIT? */fnum==0, &startfile, &sent_bytes); @@ -924,11 +924,11 @@ static int send_files(char** fname, uint fnames) if(xmodem_get_mode(&xm)) { - lprintf(LOG_INFO,"Sending Ymodem termination block"); + lprintf(LOG_INFO,"Sending YMODEM termination block"); memset(block,0,XMODEM_MIN_BLOCK_SIZE); /* send short block for terminator */ xmodem_put_block(&xm, block, XMODEM_MIN_BLOCK_SIZE /* block_size */, 0 /* block_num */); - if(!xmodem_get_ack(&xm,6,0)) { + if(xmodem_get_ack(&xm, /* tries: */6, /* block_num: */0) != ACK) { lprintf(LOG_WARNING,"Failed to receive ACK after terminating block"); } } @@ -977,23 +977,25 @@ static int receive_files(char** fname_list, int fnames) else { if(mode&YMODEM) { - lprintf(LOG_INFO,"Fetching Ymodem header block"); + lprintf(LOG_INFO,"Fetching YMODEM header block"); for(errors=0;errors<=xm.max_errors && !xm.cancelled;errors++) { - if(errors>(xm.max_errors/2) && mode&CRC && !(mode&GMODE)) - mode&=~CRC; xmodem_put_nak(&xm, /* expected_block: */ 0); - if(xmodem_get_block(&xm, block, /* expected_block: */ 0) == 0) { + if(xmodem_get_block(&xm, block, /* expected_block: */ 0) == SUCCESS) { send_byte(NULL,ACK,10); break; } + if(errors+1>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) { + lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode"); + mode&=~CRC; + } } - if(errors>=xm.max_errors || xm.cancelled) { - lprintf(LOG_ERR,"Error fetching Ymodem header block"); + if(errors>xm.max_errors || xm.cancelled) { + lprintf(LOG_ERR,"Error fetching YMODEM header block"); xmodem_cancel(&xm); return(1); } if(!block[0]) { - lprintf(LOG_INFO,"Received Ymodem termination block"); + lprintf(LOG_INFO,"Received YMODEM termination block"); return(0); } file_bytes=ftime=total_files=total_bytes=0; @@ -1005,11 +1007,11 @@ static int receive_files(char** fname_list, int fnames) ,&total_files /* remaining files to be sent */ ,&total_bytes /* remaining bytes to be sent */ ); - lprintf(LOG_DEBUG,"Ymodem header (%u fields): %s", i, block+strlen(block)+1); + lprintf(LOG_DEBUG,"YMODEM header (%u fields): %s", i, block+strlen(block)+1); SAFECOPY(fname,block); } else { /* Zmodem */ - lprintf(LOG_INFO,"Waiting for Zmodem sender..."); + lprintf(LOG_INFO,"Waiting for ZMODEM sender..."); i=zmodem_recv_init(&zm); @@ -1105,14 +1107,15 @@ static int receive_files(char** fname_list, int fnames) } if(mode&XMODEM) - lprintf(LOG_INFO,"Receiving %s via Xmodem %s" + lprintf(LOG_INFO,"Receiving %s via XMODEM%s %s" ,str + ,mode&GMODE ? "-G" : "" ,mode&CRC ? "CRC-16":"Checksum"); else lprintf(LOG_INFO,"Receiving %s (%lu KB) via %s %s" ,str ,file_bytes/1024 - ,mode&YMODEM ? mode&GMODE ? "Ymodem-G" : "Ymodem" :"Zmodem" + ,mode&YMODEM ? mode&GMODE ? "YMODEM-G" : "YMODEM" :"ZMODEM" ,mode&ZMODEM ? "" : (mode&CRC ? "CRC-16" : "Checksum")); startfile=time(NULL); @@ -1138,7 +1141,7 @@ static int receive_files(char** fname_list, int fnames) xmodem_progress(NULL,block_num,ftell(fp),file_bytes,startfile); i=xmodem_get_block(&xm, block, block_num); - if(i!=0) { + if(i!=SUCCESS) { if(i==EOT) { /* end of transfer */ success=TRUE; xmodem_put_ack(&xm); @@ -1152,20 +1155,23 @@ static int receive_files(char** fname_list, int fnames) if(mode&GMODE) return(-1); - if(++errors>=xm.max_errors) { + if(++errors>xm.max_errors) { lprintf(LOG_ERR,"Too many errors (%u)",errors); xmodem_cancel(&xm); break; } - if(block_num==1 && errors>(xm.max_errors/2) && mode&CRC && !(mode&GMODE)) + if(i!=NOT_XMODEM + && block_num==1 && errors>xm.max_errors/3 && mode&CRC && !(mode&GMODE)) { + lprintf(LOG_NOTICE,"Falling back to 8-bit Checksum mode (error=%d)", i); mode&=~CRC; + } xmodem_put_nak(&xm, block_num); continue; } if(!(mode&GMODE)) send_byte(NULL,ACK,10); - if(file_bytes_left<=0L) { /* No more bytes to send */ - lprintf(LOG_WARNING,"Attempt to send more byte specified in header"); + if(file_bytes_left<=0L) { /* No more bytes to receive */ + lprintf(LOG_WARNING,"Sender attempted to send more bytes than were specified in header"); break; } wr=xm.block_size; @@ -1264,9 +1270,12 @@ static const char* usage= "socket = TCP socket descriptor\n" #endif "\n" - "opts = -y to overwrite files when receiving\n" + "opts = -y allow overwriting of existing files when receiving\n" " -o disable Zmodem CRC-32 mode (use CRC-16)\n" " -s disable Zmodem streaming (Slow Zmodem)\n" + " -k enable X/Ymodem-1K send mode\n" + " -c enable Xmodem-CRC receive mode\n" + " -g enable X/Ymodem-G receive mode (no error recovery)\n" " -2 set maximum Zmodem block size to 2K\n" " -4 set maximum Zmodem block size to 4K\n" " -8 set maximum Zmodem block size to 8K (ZedZap)\n" @@ -1275,11 +1284,11 @@ static const char* usage= " -rlogin or -ssh or -raw to disable Telnet mode\n" "\n" "cmd = v to display detailed version information\n" - " sx to send Xmodem rx to recv Xmodem\n" - " sX to send Xmodem-1K rc to recv Xmodem-CRC\n" - " sy to send Ymodem ry to recv Ymodem\n" - " sY to send Ymodem-1K rg to recv Ymodem-G\n" - " sz to send Zmodem rz to recv Zmodem\n" + " sx to send Xmodem rx to receive Xmodem\n" + " sX to send Xmodem-1K rc to receive Xmodem-CRC\n" + " sy to send Ymodem ry to receive Ymodem\n" + " sY to send Ymodem-1K rg to receive Ymodem-G\n" + " sz to send Zmodem rz to receive Zmodem\n" "\n" "file = filename to send or receive\n" "path = directory to receive files into\n" @@ -1316,7 +1325,7 @@ int main(int argc, char **argv) sscanf("$Revision$", "%*s %s", revision); - fprintf(statfp,"\nSynchronet External X/Y/Zmodem v%s-%s" + fprintf(statfp,"\nSynchronet External X/Y/ZMODEM v%s-%s" " Copyright %s Rob Swindell\n\n" ,revision ,PLATFORM_DESC @@ -1364,9 +1373,14 @@ int main(int argc, char **argv) xm.recv_timeout =iniReadInteger(fp,"Xmodem","RecvTimeout",xm.recv_timeout); /* seconds */ xm.byte_timeout =iniReadInteger(fp,"Xmodem","ByteTimeout",xm.byte_timeout); /* seconds */ xm.ack_timeout =iniReadInteger(fp,"Xmodem","AckTimeout",xm.ack_timeout); /* seconds */ - xm.block_size =iniReadInteger(fp,"Xmodem","BlockSize",xm.block_size); /* 128 or 1024 */ + xm.block_size =iniReadInteger(fp,"Xmodem","BlockSize",xm.block_size); /* 128 or 1024 */ + xm.max_block_size =iniReadInteger(fp,"Xmodem","MaxBlockSize",xm.max_block_size); /* 128 or 1024 */ xm.max_errors =iniReadInteger(fp,"Xmodem","MaxErrors",xm.max_errors); xm.g_delay =iniReadInteger(fp,"Xmodem","G_Delay",xm.g_delay); + xm.crc_mode_supported =iniReadBool(fp,"Xmodem","SendCRC",xm.crc_mode_supported); + xm.g_mode_supported =iniReadBool(fp,"Xmodem","SendG",xm.g_mode_supported); + + xm.fallback_to_xmodem =iniReadInteger(fp,"Ymodem","FallbackToXmodem", xm.fallback_to_xmodem); zm.init_timeout =iniReadInteger(fp,"Zmodem","InitTimeout",zm.init_timeout); /* seconds */ zm.send_timeout =iniReadInteger(fp,"Zmodem","SendTimeout",zm.send_timeout); /* seconds */ @@ -1445,6 +1459,9 @@ int main(int argc, char **argv) case 'Y': mode|=(YMODEM|CRC); break; + case 'k': /* Ymodem-Checksum for debug/test purposes only */ + mode|=YMODEM; + break; case 'g': case 'G': mode|=(YMODEM|CRC|GMODE); @@ -1516,8 +1533,8 @@ int main(int argc, char **argv) case 'S': /* disable Zmodem streaming */ zm.no_streaming=TRUE; break; - case 'G': /* Ymodem-G */ - mode|=GMODE; + case 'G': /* Ymodem-G or Xmodem-G (a.k.a. Qmodem-G) */ + mode|=(GMODE|CRC); break; case 'Y': mode|=OVERWRITE; diff --git a/src/sbbs3/sexyz.h b/src/sbbs3/sexyz.h index 143f78e04ad7b451104cd51511691c70488fdbe8..2bf63ebe32363a03fd4bd1c8ad88b4936ecf7026 100644 --- a/src/sbbs3/sexyz.h +++ b/src/sbbs3/sexyz.h @@ -8,7 +8,7 @@ * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2005 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2008 Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -46,7 +46,7 @@ #define YMODEM (1<<3) /* Use Ymodem */ #define ZMODEM (1<<4) /* Use Zmodem */ #define CRC (1<<5) /* Use CRC error correction */ -#define GMODE (1<<6) /* For Qmodem-G and Ymodem-G */ +#define GMODE (1<<6) /* For Xmodem-G and Ymodem-G */ #define RECVDIR (1<<7) /* Directory specified to download to */ #define OVERWRITE (1<<9) /* Overwrite receiving files */ @@ -54,5 +54,8 @@ #define CTRL_ESC (1<<0) /* Escape all control chars */ #define VAR_HDRS (1<<1) /* Use variable headers */ -#define NOINP -1 /* input buffer empty (incom only) */ -#define NOT_YMODEM -3 /* Expected block zero, got block one */ +#define SUCCESS 0 +#define NOINP -1 /* input buffer empty (incom only) */ +#define FAILURE -2 /* xmodem_get_block() failure */ +#define NOT_YMODEM -3 /* Expected block zero, got block one */ +#define NOT_XMODEM -4 /* Expected block one, got block zero */ diff --git a/src/sbbs3/xmodem.c b/src/sbbs3/xmodem.c index 3a8cce81db263aa8e58fa3ea91d5496bdfd97ab1..9c83fd5dd9a27922c12d59cd93c32d5c57fb2256 100644 --- a/src/sbbs3/xmodem.c +++ b/src/sbbs3/xmodem.c @@ -116,7 +116,7 @@ int xmodem_put_nak(xmodem_t* xm, unsigned block_num) ; /* wait for any trailing data */ if(block_num<=1) { - if(*(xm->mode)&GMODE) { /* G for Ymodem-G */ + if(*(xm->mode)&GMODE) { /* G for X/Ymodem-G */ lprintf(xm,LOG_INFO,"Requesting mode: Streaming, 16-bit CRC"); return putcom('G'); } else if(*(xm->mode)&CRC) { /* C for CRC */ @@ -145,7 +145,7 @@ int xmodem_cancel(xmodem_t* xm) xm->cancelled=TRUE; } - return 0; + return SUCCESS; } /****************************************************************************/ @@ -162,7 +162,7 @@ int xmodem_get_block(xmodem_t* xm, uchar* block, unsigned expected_block_num) for(errors=0;errors<=xm->max_errors && is_connected(xm);errors++) { - i=getcom(expected_block_num<=1 ? 5 : 10); + i=getcom(expected_block_num<=1 ? 3 : 10); if(eot && i!=EOT && i!=NOINP) eot=0; if(can && i!=CAN) @@ -172,10 +172,12 @@ int xmodem_get_block(xmodem_t* xm, uchar* block, unsigned expected_block_num) xm->block_size=XMODEM_MIN_BLOCK_SIZE; break; case STX: /* 1024 byte blocks */ + if(xm->max_block_size < XMODEM_MAX_BLOCK_SIZE) + return FAILURE; xm->block_size=XMODEM_MAX_BLOCK_SIZE; break; case EOT: - lprintf(xm,LOG_DEBUG,"EOT"); + lprintf(xm,LOG_DEBUG,"Block %u: EOT received", expected_block_num); if(/*((*xm->mode)&(YMODEM|GMODE))==YMODEM &&*/ !eot) { lprintf(xm,LOG_INFO,"NAKing first EOT"); eot=1; @@ -186,13 +188,15 @@ int xmodem_get_block(xmodem_t* xm, uchar* block, unsigned expected_block_num) case CAN: if(!can) { /* must get two CANs in a row */ can=1; - lprintf(xm,LOG_WARNING,"Received CAN Expected SOH, STX, or EOT"); + lprintf(xm,LOG_WARNING,"Block %u: Received CAN Expected SOH, STX, or EOT" + ,expected_block_num); continue; } - lprintf(xm,LOG_WARNING,"Cancelled remotely"); + lprintf(xm,LOG_WARNING,"Block %u: Cancelled remotely", expected_block_num); return(CAN); default: - lprintf(xm,LOG_WARNING,"Received %s Expected SOH, STX, or EOT",chr((uchar)i)); + lprintf(xm,LOG_WARNING,"Block %u: Received %s Expected SOH, STX, or EOT" + ,expected_block_num, chr((uchar)i)); case NOINP: /* Nothing came in */ if(eot) return(EOT); @@ -226,8 +230,8 @@ int xmodem_get_block(xmodem_t* xm, uchar* block, unsigned expected_block_num) chksum=getcom(xm->byte_timeout); if(block_num!=(uchar)~block_inv) { - lprintf(xm,LOG_WARNING,"Block number bit error (0x%02X vs 0x%02x)" - ,block_num,(uchar)~block_inv); + lprintf(xm,LOG_WARNING,"Block %u: Block number bit error (0x%02X vs 0x%02x)" + ,expected_block_num, block_num,(uchar)~block_inv); break; } @@ -248,6 +252,8 @@ int xmodem_get_block(xmodem_t* xm, uchar* block, unsigned expected_block_num) if(block_num!=(uchar)(expected_block_num&0xff)) { lprintf(xm,LOG_WARNING,"Block number error (%u received, expected %u)" ,block_num,expected_block_num&0xff); + if((*xm->mode)&XMODEM && expected_block_num==1 && block_num==0) + return(NOT_XMODEM); if(expected_block_num==0 && block_num==1) return(NOT_YMODEM); if(expected_block_num && block_num==(uchar)((expected_block_num-1)&0xff)) @@ -255,10 +261,10 @@ int xmodem_get_block(xmodem_t* xm, uchar* block, unsigned expected_block_num) break; } - return(0); /* Success */ + return SUCCESS; /* Success */ } - return(-2); /* Failure */ + return FAILURE; /* Failure */ } /*****************/ @@ -303,35 +309,35 @@ int xmodem_put_block(xmodem_t* xm, uchar* block, unsigned block_size, unsigned b /************************************************************/ /* Gets an acknowledgement - usually after sending a block */ -/* Returns 1 if ack received, 0 otherwise. */ +/* Returns ACK if ack received */ /************************************************************/ -BOOL xmodem_get_ack(xmodem_t* xm, unsigned tries, unsigned block_num) +int xmodem_get_ack(xmodem_t* xm, unsigned tries, unsigned block_num) { - int i,can=0; + int i=NOINP,can=0; unsigned errors; - for(errors=0;errors<tries && is_connected(xm);errors++) { + for(errors=0;errors<tries && is_connected(xm);) { - if((*xm->mode)&GMODE) { /* Don't wait for ACK on Ymodem-G */ + if((*xm->mode)&GMODE) { /* Don't wait for ACK on X/Ymodem-G */ SLEEP(xm->g_delay); if(getcom(0)==CAN) { lprintf(xm,LOG_WARNING,"Block %u: !Cancelled remotely", block_num); xmodem_cancel(xm); - return(FALSE); + return(CAN); } - return(TRUE); + return(ACK); } i=getcom(xm->ack_timeout); if(can && i!=CAN) can=0; if(i==ACK) - return(TRUE); + break; if(i==CAN) { - if(can) { + if(can) { /* 2 CANs in a row */ lprintf(xm,LOG_WARNING,"Block %u: !Cancelled remotely", block_num); xmodem_cancel(xm); - return(FALSE); + return(CAN); } can=1; } @@ -339,11 +345,13 @@ BOOL xmodem_get_ack(xmodem_t* xm, unsigned tries, unsigned block_num) lprintf(xm,LOG_WARNING,"Block %u: !Received %s Expected ACK" ,block_num, chr((uchar)i)); if(i!=CAN) - return(FALSE); - } + return(i); + } + if(i!=CAN) + errors++; } - return(FALSE); + return(i); } BOOL xmodem_get_mode(xmodem_t* xm) @@ -365,10 +373,14 @@ BOOL xmodem_get_mode(xmodem_t* xm) return(TRUE); case 'C': lprintf(xm,LOG_INFO,"Receiver requested mode: 16-bit CRC"); + if(!xm->crc_mode_supported) + continue; *(xm->mode)|=CRC; return(TRUE); case 'G': lprintf(xm,LOG_INFO,"Receiver requested mode: Streaming, 16-bit CRC"); + if(!xm->crc_mode_supported || !xm->g_mode_supported) + continue; *(xm->mode)|=(GMODE|CRC); return(TRUE); case CAN: @@ -462,17 +474,24 @@ BOOL xmodem_send_file(xmodem_t* xm, const char* fname, FILE* fp, time_t* start, ,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); + lprintf(xm,LOG_INFO,"Sending YMODEM header block: '%s'",block+strlen(block)+1); block_len=strlen(block)+1+i; for(xm->errors=0;xm->errors<=xm->max_errors && !is_cancelled(xm) && is_connected(xm);xm->errors++) { xmodem_put_block(xm, block, block_len <=XMODEM_MIN_BLOCK_SIZE ? XMODEM_MIN_BLOCK_SIZE:XMODEM_MAX_BLOCK_SIZE, 0 /* block_num */); - if(xmodem_get_ack(xm,1,0)) { + if((i=xmodem_get_ack(xm,/* tries: */1, /* block_num: */0)) == ACK) { sent_header=TRUE; break; } + if((i==NAK || i=='C' || i=='G') + && xm->fallback_to_xmodem && xm->errors+1 == xm->fallback_to_xmodem) { + lprintf(xm,LOG_NOTICE,"Falling back to XMODEM mode after %u attempts" + ,xm->fallback_to_xmodem); + *(xm->mode)&=~YMODEM; + break; + } } - if(xm->errors>=xm->max_errors || is_cancelled(xm)) { + if(xm->errors>xm->max_errors || is_cancelled(xm)) { lprintf(xm,LOG_ERR,"Failed to send header block"); break; } @@ -511,7 +530,7 @@ BOOL xmodem_send_file(xmodem_t* xm, const char* fname, FILE* fp, time_t* start, 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)) { + if(xmodem_get_ack(xm, /* tries: */5,block_num) != ACK) { xm->errors++; lprintf(xm,LOG_WARNING,"Error #%d at offset %ld" ,xm->errors,ftell(fp)-xm->block_size); @@ -576,11 +595,14 @@ void xmodem_init(xmodem_t* xm, void* cbdata, long* mode xm->ack_timeout=10; /* seconds */ xm->block_size=XMODEM_MAX_BLOCK_SIZE; + xm->max_block_size=XMODEM_MAX_BLOCK_SIZE; xm->max_errors=9; xm->g_delay=1; xm->cbdata=cbdata; xm->mode=mode; + xm->g_mode_supported=TRUE; + xm->crc_mode_supported=TRUE; xm->lputs=lputs; xm->progress=progress; xm->send_byte=send_byte; diff --git a/src/sbbs3/xmodem.h b/src/sbbs3/xmodem.h index 951031214649bf76a89bd460997c87acea12208a..aa9fa87e793783f253dadaf351d1ea12c24c5eea 100644 --- a/src/sbbs3/xmodem.h +++ b/src/sbbs3/xmodem.h @@ -49,13 +49,17 @@ typedef struct { void* cbdata; long* mode; BOOL cancelled; + BOOL crc_mode_supported; /* for send */ + BOOL g_mode_supported; /* for send */ unsigned block_size; + unsigned max_block_size; /* for recv */ unsigned ack_timeout; unsigned byte_timeout; unsigned send_timeout; unsigned recv_timeout; unsigned errors; unsigned max_errors; + unsigned fallback_to_xmodem; /* fallback to Xmodem after this many Ymodem send attempts */ unsigned g_delay; unsigned total_files; unsigned total_bytes; @@ -82,7 +86,7 @@ void xmodem_init(xmodem_t*, void* cbdata, long* mode char* xmodem_ver(char *buf); const char* xmodem_source(void); int xmodem_cancel(xmodem_t*); -BOOL xmodem_get_ack(xmodem_t*, unsigned tries, unsigned block_num); +int xmodem_get_ack(xmodem_t*, unsigned tries, unsigned block_num); BOOL xmodem_get_mode(xmodem_t*); BOOL xmodem_put_eot(xmodem_t*); int xmodem_put_ack(xmodem_t*);