diff --git a/src/sbbs3/sexyz.c b/src/sbbs3/sexyz.c index 6f2006058190185170042e3cdef787cfa9e29c8b..58cd098d324461ad51c00d46d3b6ffcdb28bfb4a 100644 --- a/src/sbbs3/sexyz.c +++ b/src/sbbs3/sexyz.c @@ -189,6 +189,9 @@ static char *chr(uchar ch) if(mode&ZMODEM) { switch(ch) { + case ZRQINIT: return("ZRQINIT"); + case ZRINIT: return("ZRINIT"); + case ZSINIT: return("ZSINIT"); case ZACK: return("ZACK"); case ZPAD: return("ZPAD"); case ZDLE: return("ZDLE"); @@ -622,6 +625,7 @@ void xmodem_progress(void* unused, unsigned block_num, ulong offset, ulong fsize void zmodem_progress(void* unused, ulong start_pos, ulong current_pos ,ulong fsize, time_t start) { + char orig[128]; unsigned cps; long l; long t; @@ -633,13 +637,20 @@ void zmodem_progress(void* unused, ulong start_pos, ulong current_pos t=now-start; if(t<=0) t=1; + if(start_pos>current_pos) + start_pos=0; if((cps=(current_pos-start_pos)/t)==0) cps=1; /* cps so far */ l=fsize/cps; /* total transfer est time */ l-=t; /* now, it's est time left */ if(l<0) l=0; - fprintf(statfp,"\rKByte: %lu/%lu " + if(start_pos) + sprintf(orig,"From: %lu ", start_pos); + else + orig[0]=0; + fprintf(statfp,"\r%sKByte: %lu/%lu " "Time: %lu:%02lu/%lu:%02lu CPS: %u %lu%% " + ,orig ,current_pos/1024 ,fsize/1024 ,t/60L @@ -805,9 +816,10 @@ static int send_files(char** fname, uint fnames) return(0); /* success */ } -static int receive_files(char** fname, int fnames) +static int receive_files(char** fname_list, int fnames) { char str[MAX_PATH+1]; + char fname[MAX_PATH+1]; int i; int fnum=0; uint errors; @@ -828,41 +840,91 @@ static int receive_files(char** fname, int fnames) outbuf.highwater_mark=0; /* don't delay ACK/NAK transmits */ + /* Purge input buffer */ + while((i=getcom(0))!=NOINP) + lprintf(LOG_WARNING,"Throwing out received: %s",chr((uchar)i)); + while(!terminate && !cancelled) { if(mode&XMODEM) { - SAFECOPY(str,fname[0]); + SAFECOPY(str,fname_list[0]); /* we'll have at least one fname */ file_bytes=file_bytes_left=0x7fffffff; } - else if(mode&YMODEM) { - lprintf(LOG_INFO,"Fetching Ymodem header block"); - for(errors=0;errors<xm.max_errors;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) { - putcom(ACK); - break; - } - } - if(errors==xm.max_errors) { - lprintf(LOG_ERR,"Error fetching Ymodem header block"); - xmodem_cancel(&xm); - return(1); - } - if(!block[0]) { - lprintf(LOG_INFO,"Received Ymodem termination block"); - return(0); + else { + if(mode&YMODEM) { + lprintf(LOG_INFO,"Fetching Ymodem header block"); + for(errors=0;errors<xm.max_errors;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) { + putcom(ACK); + break; + } + } + if(errors>=xm.max_errors) { + lprintf(LOG_ERR,"Error fetching Ymodem header block"); + xmodem_cancel(&xm); + return(1); + } + if(!block[0]) { + lprintf(LOG_INFO,"Received Ymodem termination block"); + return(0); + } + file_bytes=ftime=total_files=total_bytes=0; + i=sscanf(block+strlen(block)+1,"%ld %lo %lo %lo %d %ld" + ,&file_bytes /* file size (decimal) */ + ,&ftime /* file time (octal unix format) */ + ,&fmode /* file mode (not used) */ + ,&serial_num /* program serial number */ + ,&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); + SAFECOPY(fname,block); + fprintf(statfp,"Incoming filename: %.64s ",fname); + + } else { /* Zmodem */ + i=zmodem_recv_init(&zm); + if(zm.cancelled) + return(1); + if(i<0) + return(-1); + lprintf(LOG_DEBUG,"Received header: %s",chr((uchar)i)); + switch(i) { + case ZFREECNT: + zmodem_send_pos_header(&zm, ZACK, getfreediskspace(".",1), /* Hex? */ TRUE) ; + continue; + case ZCOMMAND: + lprintf(LOG_WARNING,"Remote command attempted and rejected"); + zmodem_send_nak(&zm); + continue; + case ZFILE: + if(!zmodem_recv_file_info(&zm + ,fname,sizeof(fname) + ,&file_bytes + ,&ftime + ,&fmode + ,&serial_num + ,&total_files + ,&total_bytes)) + continue; + break; + case ZSINIT: + lprintf(LOG_WARNING,"Remote attempted ZSINIT (not supported)"); + zmodem_send_nak(&zm); + break; + case ZFIN: + zmodem_send_zfin(&zm); + /* fall-through */ + case ZCOMPL: + return(0); + case ZRQINIT: + case ZCAN: + return(-1); + } } - i=sscanf(block+strlen(block)+1,"%ld %lo %lo %lo %d %ld" - ,&file_bytes /* file size (decimal) */ - ,&ftime /* file time (octal unix format) */ - ,&fmode /* file mode (not used) */ - ,&serial_num /* program serial number */ - ,&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); + if(!file_bytes) file_bytes=0x7fffffff; file_bytes_left=file_bytes; @@ -872,30 +934,28 @@ static int receive_files(char** fname, int fnames) total_files=1; if(total_bytes<file_bytes) total_bytes=file_bytes; - if(!serial_num) - serial_num=-1; - fprintf(statfp,"Incoming filename: %.64s ",block); - if(mode&DIR) - sprintf(str,"%s%s",fname[0],getfname(block)); + + if(mode&RECVDIR) + sprintf(str,"%s%s",fname_list[0],getfname(fname)); else { - SAFECOPY(str,getfname(block)); + SAFECOPY(str,getfname(fname)); for(i=0;i<fnames;i++) { - if(!fname[i][0]) /* name blank or already used */ + if(!fname_list[i][0]) /* name blank or already used */ continue; - if(!stricmp(getfname(fname[i]),str)) { - SAFECOPY(str,fname[i]); - fname[i][0]=0; + if(!stricmp(getfname(fname_list[i]),str)) { + SAFECOPY(str,fname_list[i]); + fname_list[i][0]=0; break; } } if(i==fnames) { /* Not found in list */ if(fnames) fprintf(statfp," - Not in receive list!"); - if(!fnames || fnum>=fnames || !fname[fnum][0]) - SAFECOPY(str,getfname(block)); /* worst case */ + if(!fnames || fnum>=fnames || !fname_list[fnum][0]) + SAFECOPY(str,getfname(fname)); /* worst case */ else { - SAFECOPY(str,fname[fnum]); - fname[fnum][0]=0; + SAFECOPY(str,fname_list[fnum]); + fname_list[fnum][0]=0; } } } @@ -905,94 +965,10 @@ static int receive_files(char** fname, int fnames) // getchar(); } - else { /* Zmodem */ -#if 0 - tryzhdrtype=ZRINIT; - while(1) { - Txhdr[ZF0]=(CANFC32|CANFDX|CANOVIO|CANRLE); - /* add CANBRK if we can send break signal */ - if(zmode&CTRL_ESC) - Txhdr[ZF0]|=TESCCTL; - Txhdr[ZF1]=CANVHDR; - Txhdr[ZP0]=0; - Txhdr[ZP1]=0; - putzhhdr(tryzhdrtype); - done=0; - while(!done) { - done=1; - switch(getzhdr()) { - case ZRQINIT: - if(Rxhdr[ZF3]&0x80) - zmode|=VAR_HDRS; /* we can var header */ - break; - case ZFILE: - zconv=Rxhdr[ZF0]; - zmanag=Rxhdr[ZF1]; - ztrans=Rxhdr[ZF2]; - if(Rxhdr[ZF3]&ZCANVHDR) - zmode|=VAR_HDRS; - tryzhdrtype=ZRINIT; - if(getzdata(block, 1024)==GOTCRCW) { - /* something */ - done=1; - } - putzhhdr(ZNAK); - done=0; - break; - case ZSINIT: - if(Rxhdr[ZF0]&TESCCTL) - zmode|=CTRL_ESC; - if (getzdata(attn,ZATTNLEN)==GOTCRCW) { - ltohdr(1L); - putzhhdr(ZACK); - } - else - putzhhdr(ZNAK); - done=0; - break; - case ZFREECNT: - ltohdr(0); /* should be free disk space */ - putzhhdr(ZACK); - done=0; - break; - case ZCOMMAND: -/*** - cmdzack1flg = Rxhdr[ZF0]; - if(getzdata(block,1024)==GOTCRCW) { - if (cmdzack1flg & ZCACK1) - ltohdr(0L); - else - ltohdr((long)sys2(block)); - purgeline(); /* dump impatient questions */ - do { - zshhdr(4,ZCOMPL, Txhdr); - } - while (++errors<20 && zgethdr(Rxhdr,1)!=ZFIN); - ackbibi(); - if (cmdzack1flg & ZCACK1) - exec2(block); - return ZCOMPL; - } -***/ - putzhhdr(ZNAK); - done=0; - break; - case ZCOMPL: - done=0; - break; - case ZFIN: - ackbibi(); - return ZCOMPL; - case ZCAN: - return ERROR; - } - } -#endif - } fnum++; - if(!(mode&DIR) && fnames && fnum>fnames) { + if(!(mode&RECVDIR) && fnames && fnum>fnames) { lprintf(LOG_WARNING,"Attempt to send more files than specified"); xmodem_cancel(&xm); break; @@ -1000,16 +976,23 @@ static int receive_files(char** fname, int fnames) if(fexist(str) && !(mode&OVERWRITE)) { lprintf(LOG_WARNING,"%s already exists",str); + if(mode&ZMODEM) { + zmodem_send_zskip(&zm); + continue; + } xmodem_cancel(&xm); return(1); } if((fp=fopen(str,"wb"))==NULL) { lprintf(LOG_ERR,"Error creating %s",str); + if(mode&ZMODEM) { + zmodem_send_zskip(&zm); + continue; + } xmodem_cancel(&xm); return(1); } - setvbuf(fp,NULL,_IOFBF,8*1024); - startfile=time(NULL); + if(mode&XMODEM) lprintf(LOG_INFO,"Receiving %s via Xmodem %s" ,str @@ -1021,55 +1004,76 @@ static int receive_files(char** fname, int fnames) ,mode&YMODEM ? mode&GMODE ? "Ymodem-G" : "Ymodem" :"Zmodem" ,mode&CRC ? "CRC-16" : "Checksum"); - errors=0; - block_num=1; + startfile=time(NULL); success=FALSE; - xmodem_put_nak(&xm, block_num); - while(1) { - xmodem_progress(NULL,block_num,ftell(fp),file_bytes,startfile); - i=xmodem_get_block(&xm, block, block_num); + if(mode&ZMODEM) { - if(i!=0) { - if(i==EOT) { /* end of transfer */ - success=TRUE; - xmodem_put_ack(&xm); - break; - } - if(i==CAN) { /* Cancel */ - cancelled=TRUE; + for(errors=0; errors<zm.max_errors + && (ulong)ftell(fp) < file_bytes && !zm.cancelled; errors++) { + if((i = zmodem_recv_file_data(&zm,fp,0,file_bytes,startfile)) == ZEOF) break; - } + lprintf(LOG_WARNING,"Error at byte %lu: %s", ftell(fp), chr((uchar)i)); + } - if(mode&GMODE) - return(-1); + /* + * wait for the eof header + */ + + for(;errors<zm.max_errors && !success && !zm.cancelled; errors++) { + if(zmodem_rx_header_and_check(&zm,zm.recv_timeout)) + success=TRUE; + } + + } else { + errors=0; + block_num=1; + xmodem_put_nak(&xm, block_num); + while(1) { + xmodem_progress(NULL,block_num,ftell(fp),file_bytes,startfile); + i=xmodem_get_block(&xm, block, block_num); + + if(i!=0) { + if(i==EOT) { /* end of transfer */ + success=TRUE; + xmodem_put_ack(&xm); + break; + } + if(i==CAN) { /* Cancel */ + cancelled=TRUE; + break; + } - if(++errors>=xm.max_errors) { - lprintf(LOG_ERR,"Too many errors (%u)",errors); + if(mode&GMODE) + return(-1); + + 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)) + mode&=~CRC; + xmodem_put_nak(&xm, block_num); + continue; + } + if(!(mode&GMODE)) + putcom(ACK); + if(file_bytes_left<=0L) { /* No more bytes to send */ + lprintf(LOG_WARNING,"Attempt to send more byte specified in header"); + break; + } + wr=xm.block_size; + if(wr>file_bytes_left) + wr=file_bytes_left; + if(fwrite(block,1,wr,fp)!=wr) { + lprintf(LOG_ERR,"Error writing %u bytes to file at offset %lu" + ,wr,ftell(fp)); xmodem_cancel(&xm); - break; + return(1); } - if(block_num==1 && errors>(xm.max_errors/2) && mode&CRC && !(mode&GMODE)) - mode&=~CRC; - xmodem_put_nak(&xm, block_num); - continue; - } - if(!(mode&GMODE)) - putcom(ACK); - if(file_bytes_left<=0L) { /* No more bytes to send */ - lprintf(LOG_WARNING,"Attempt to send more byte specified in header"); - break; + file_bytes_left-=wr; + block_num++; } - wr=xm.block_size; - if(wr>file_bytes_left) - wr=file_bytes_left; - if(fwrite(block,1,wr,fp)!=wr) { - lprintf(LOG_ERR,"Error writing %u bytes to file at offset %lu" - ,wr,ftell(fp)); - xmodem_cancel(&xm); - return(1); - } - file_bytes_left-=wr; - block_num++; } /* Use correct file size */ @@ -1106,7 +1110,7 @@ static int receive_files(char** fname, int fnames) ,str ,serial_num); } - if(mode&XMODEM) + if(mode&XMODEM) /* maximum of one file */ break; if((cps=file_bytes/t)==0) cps=1; @@ -1351,7 +1355,7 @@ int main(int argc, char **argv) } else if(argv[i][0]=='+') { - if(mode&DIR) { + if(mode&RECVDIR) { fprintf(statfp,"!Cannot specify both directory and filename\n"); exit(1); } @@ -1371,7 +1375,7 @@ int main(int argc, char **argv) else if(mode&(SEND|RECV)){ if(isdir(argv[i])) { /* is a directory */ - if(mode&DIR) { + if(mode&RECVDIR) { fprintf(statfp,"!Only one directory can be specified\n"); exit(1); } @@ -1383,7 +1387,7 @@ int main(int argc, char **argv) fprintf(statfp,"!Cannot send directory '%s'\n",argv[i]); exit(1); } - mode|=DIR; + mode|=RECVDIR; } strListAppend(&fname_list,argv[i],fnames++); } @@ -1439,7 +1443,7 @@ int main(int argc, char **argv) } #endif -// if(mode&DIR) +// if(mode&RECVDIR) // backslash(fname[0]); if(mode&ALARM) { diff --git a/src/sbbs3/sexyz.h b/src/sbbs3/sexyz.h index 3e33e756375753171ecaa6cbeded5c1576adb996..70dfcc89c50fab14480a20baa7e53092497988ee 100644 --- a/src/sbbs3/sexyz.h +++ b/src/sbbs3/sexyz.h @@ -47,7 +47,7 @@ #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 DIR (1<<7) /* Directory specified to download to */ +#define RECVDIR (1<<7) /* Directory specified to download to */ #define DEBUG (1<<8) /* Debug output */ #define OVERWRITE (1<<9) /* Overwrite receiving files */ #define ALARM (1<<11) /* Alarm when starting and stopping xfer */ diff --git a/src/sbbs3/zmodem.c b/src/sbbs3/zmodem.c index b6636e6f906564644ddf57dd7388cc188864678c..7560b7d03f6056f6511a97c4d705fc21a460996e 100644 --- a/src/sbbs3/zmodem.c +++ b/src/sbbs3/zmodem.c @@ -69,6 +69,9 @@ static char *chr(uchar ch) static char str[25]; switch(ch) { + case ZRQINIT: return("ZRQINIT"); + case ZRINIT: return("ZRINIT"); + case ZSINIT: return("ZSINIT"); case ZACK: return("ZACK"); case ZEOF: return("ZEOF"); case ZPAD: return("ZPAD"); @@ -426,8 +429,7 @@ zmodem_tx_data(zmodem_t* zm, uchar sub_frame_type,unsigned char * p, int l) // YIELD(); } -void -zmodem_tx_pos_header(zmodem_t* zm, int type, long pos, BOOL hex) +void zmodem_send_pos_header(zmodem_t* zm, int type, long pos, BOOL hex) { uchar header[5]; @@ -448,13 +450,12 @@ zmodem_tx_znak(zmodem_t* zm) { // lprintf(zm,LOG_INFO,"tx_znak"); - zmodem_tx_pos_header(zm, ZNAK, zm->ack_file_pos, /* Hex? */ TRUE); + zmodem_send_pos_header(zm, ZNAK, zm->ack_file_pos, /* Hex? */ TRUE); } -void -zmodem_tx_zskip(zmodem_t* zm) +void zmodem_send_zskip(zmodem_t* zm) { - zmodem_tx_pos_header(zm, ZSKIP, 0L, /* Hex? */ TRUE); + zmodem_send_pos_header(zm, ZSKIP, 0L, /* Hex? */ TRUE); } /* @@ -494,7 +495,7 @@ zmodem_rx_raw(zmodem_t* zm, int to) zm->n_cans++; if(zm->n_cans == 5) { zm->cancelled=TRUE; - lprintf(zm,LOG_WARNING,"Cancelled Remotely"); + lprintf(zm,LOG_WARNING,"Cancelled remotely"); return(TIMEOUT); } } @@ -513,7 +514,6 @@ zmodem_rx_raw(zmodem_t* zm, int to) * is relatively short. */ - int zmodem_rx(zmodem_t* zm, int to) { @@ -634,7 +634,7 @@ zmodem_rx(zmodem_t* zm, int to) */ int -zmodem_rx_32_data(zmodem_t* zm, unsigned char * p,int * l) +zmodem_rx_32_data(zmodem_t* zm, unsigned char * p, int* l) { int c; unsigned long rxd_crc; @@ -673,6 +673,7 @@ zmodem_rx_32_data(zmodem_t* zm, unsigned char * p,int * l) rxd_crc |= zmodem_rx(zm, 1) << 24; if(rxd_crc != crc) { + lprintf(zm,LOG_WARNING,"CRC-32 ERROR"); return FALSE; } @@ -682,7 +683,7 @@ zmodem_rx_32_data(zmodem_t* zm, unsigned char * p,int * l) } int -zmodem_rx_16_data(zmodem_t* zm, register unsigned char * p,int * l) +zmodem_rx_16_data(zmodem_t* zm, register unsigned char * p, int* l) { register int c; int sub_frame_type; @@ -696,7 +697,7 @@ zmodem_rx_16_data(zmodem_t* zm, register unsigned char * p,int * l) crc = 0; do { - c = zmodem_rx(zm, 5); + c = zmodem_rx(zm, zm->recv_timeout); if(c == TIMEOUT) { return TIMEOUT; @@ -715,10 +716,12 @@ zmodem_rx_16_data(zmodem_t* zm, register unsigned char * p,int * l) // crc = ucrc16(0,crc); // crc = ucrc16(0,crc); - rxd_crc = zmodem_rx(zm, 1) << 8; - rxd_crc |= zmodem_rx(zm, 1); + rxd_crc = zmodem_rx(zm, zm->recv_timeout) << 8; + rxd_crc |= zmodem_rx(zm, zm->recv_timeout); if(rxd_crc != crc) { + lprintf(zm,LOG_WARNING,"CRC-16 ERROR (%04hX vs %04hX)" + ,rxd_crc, crc); return FALSE; } @@ -772,16 +775,18 @@ zmodem_rx_data(zmodem_t* zm, unsigned char * p, int * l) * frame continues; ZACK expected */ case ZCRCQ: - zmodem_tx_pos_header(zm, ZACK, pos, /* Hex? */ TRUE); + zmodem_send_pos_header(zm, ZACK, pos, /* Hex? */ TRUE); return FRAMEOK; /* * frame ends; ZACK expected */ case ZCRCW: - zmodem_tx_pos_header(zm, ZACK, pos, /* Hex? */ TRUE); + zmodem_send_pos_header(zm, ZACK, pos, /* Hex? */ TRUE); return ENDOFFRAME; } + lprintf(zm,LOG_WARNING,"Invalid sub-frame type: %s",chr((uchar)sub_frame_type)); + return FALSE; } @@ -1002,7 +1007,7 @@ zmodem_rx_bin32_header(zmodem_t* zm, int to) */ int -zmodem_rx_header_raw(zmodem_t* zm, int to,int errors) +zmodem_rx_header_raw(zmodem_t* zm, int to, int errors) { int c; @@ -1030,7 +1035,7 @@ zmodem_rx_header_raw(zmodem_t* zm, int to,int errors) */ if(c != ZDLE) { - lprintf(zm,LOG_ERR,"expected ZDLE; got %c",c); + lprintf(zm,LOG_WARNING,"Expected ZDLE, received: %s", chr((uchar)c)); continue; } @@ -1065,7 +1070,7 @@ zmodem_rx_header_raw(zmodem_t* zm, int to,int errors) /* * unrecognized header style */ - lprintf(zm,LOG_ERR,"UNRECOGNIZED header style %c",c); + lprintf(zm,LOG_ERR,"UNRECOGNIZED header style: %s",chr((uchar)c)); if(errors) { return INVHDR; } @@ -1154,7 +1159,19 @@ int zmodem_get_zrinit(zmodem_t* zm) zmodem_tx_raw(zm,'\r'); zmodem_tx_hex_header(zm,zrqinit_header); - return zmodem_rx_header(zm,7); + return zmodem_rx_header(zm,zm->recv_timeout); +} + +void zmodem_send_zrinit(zmodem_t* zm) +{ + unsigned char zrinit_header[] = { ZRINIT, 0, 0, 0, ZF0_CANFDX | ZF0_CANOVIO | ZF0_CANFC32 }; + + zmodem_tx_hex_header(zm, zrinit_header); +} + +void zmodem_send_nak(zmodem_t* zm) +{ + zmodem_send_pos_header(zm, ZNAK, 0, /* Hex? */ TRUE); } int zmodem_send_zfin(zmodem_t* zm) @@ -1199,7 +1216,7 @@ zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong fsize, ulong* sent) fseek(fp,pos,SEEK_SET); - zmodem_tx_pos_header(zm, ZDATA, pos, /* Hex? */ FALSE); + zmodem_send_pos_header(zm, ZDATA, pos, /* Hex? */ FALSE); /* * send the data in the file @@ -1218,8 +1235,9 @@ zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong fsize, ulong* sent) */ break; } - - zm->progress(zm->cbdata, pos, ftell(fp), fsize, zm->transfer_start); + + if(zm->progress!=NULL) + zm->progress(zm->cbdata, pos, ftell(fp), fsize, zm->transfer_start); /* * at end of file wait for an ACK @@ -1236,7 +1254,7 @@ zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong fsize, ulong* sent) if(type == ZCRCW) { int type; do { - type = zmodem_rx_header(zm, 10); + type = zmodem_rx_header(zm, zm->recv_timeout); if(type == ZNAK || type == ZRPOS || type == TIMEOUT) { return type; } @@ -1307,7 +1325,7 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti zm->file_skipped=FALSE; if(request_init) { - for(errors=0;errors<zm->max_errors;errors++) { + for(errors=0; errors<zm->max_errors && !zm->cancelled; errors++) { lprintf(zm,LOG_INFO,"Sending ZRQINIT (%u of %u)",errors+1,zm->max_errors); i = zmodem_get_zrinit(zm); if(i == ZRINIT) { @@ -1316,7 +1334,7 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti } lprintf(zm,LOG_WARNING,"RX header type: %d 0x%02X", i, i); } - if(errors>=zm->max_errors) + if(errors>=zm->max_errors || zm->cancelled) return(FALSE); } @@ -1601,6 +1619,126 @@ zmodem_send_files(char** fname, int total_files) #endif +int zmodem_recv_init(zmodem_t* zm) +{ + int ch; + int type=CAN; + unsigned errors; + + while(!zm->cancelled && (ch=zm->recv_byte(zm,0))!=NOINP) + lprintf(zm,LOG_WARNING,"Throwing out received: %s",chr((uchar)ch)); + + for(errors=0; errors<zm->max_errors && !zm->cancelled; errors++) { + zmodem_send_zrinit(zm); + type = zmodem_rx_header(zm, zm->recv_timeout); + if(type!=TIMEOUT && type!=ZRQINIT) + break; + } + + return(type); +} + +BOOL zmodem_recv_file_info(zmodem_t* zm + ,char* fname, size_t maxlen + ,ulong* p_size + ,time_t* p_time + ,long* p_mode + ,long* p_serial + ,ulong* p_total_files + ,ulong* p_total_bytes) +{ + uchar block[8192]; + int i; + ulong size=0; + ulong time=0; + ulong total_files=0; + ulong total_bytes=0; + long mode=0; + long serial=-1; + unsigned l; + + i=zmodem_rx_data(zm, block, &l); + + if(i!=FRAMEOK && i!=ENDOFFRAME) + return(FALSE); + + if(fname!=NULL) + safe_snprintf(fname,maxlen,"%s",block); + + i=sscanf(block+strlen(block)+1,"%lu %lo %lo %lo %lu %lu" + ,&size /* file size (decimal) */ + ,&time /* file time (octal unix format) */ + ,&mode /* file mode */ + ,&serial /* program serial number */ + ,&total_files /* remaining files to be sent */ + ,&total_bytes /* remaining bytes to be sent */ + ); + + lprintf(zm,LOG_DEBUG,"Zmodem header (%u fields): %s" + ,i, block+strlen(block)+1); + + if(p_size) *p_size=size; + if(p_time) *p_time=time; + if(p_mode) *p_mode=mode; + if(p_serial) *p_serial=serial; + if(p_total_files) *p_total_files=total_files; + if(p_total_bytes) *p_total_bytes=total_bytes; + + return(TRUE); +} + +/* + * receive file data until the end of the file or until something goes wrong. + * the name is only used to show progress + */ + +int zmodem_recv_file_data(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize, time_t start) +{ + static int first = TRUE; + long pos; + int n; + int type; + + /* + * create a ZRPOS frame and send it to the other side + */ + zmodem_send_pos_header(zm, ZRPOS, ftell(fp), /* Hex? */ TRUE); + + /* + * wait for a ZDATA header with the right file offset + * or a timeout or a ZFIN + */ + + do { + do { + type = zmodem_rx_header(zm,zm->recv_timeout); + if (type == TIMEOUT) { + return TIMEOUT; + } + } while (type != ZDATA && !zm->cancelled); + + pos = zm->rxd_header[ZP0] | (zm->rxd_header[ZP1] << 8) | + (zm->rxd_header[ZP2] << 16) | (zm->rxd_header[ZP3] << 24); + } while (pos != ftell(fp) && !zm->cancelled); + + do { + type = zmodem_rx_data(zm,zm->rx_data_subpacket,&n); + +/* fprintf(stderr,"packet len %d type %d\n",n,type); +*/ + if (type == ENDOFFRAME || type == FRAMEOK) { + fwrite(zm->rx_data_subpacket,1,n,fp); + } + + if(zm->progress!=NULL) + zm->progress(zm->cbdata,offset,ftell(fp),fsize,start); + + } while (type == FRAMEOK && !zm->cancelled); + + return type; +} + + const char* zmodem_source(void) { return(__FILE__); diff --git a/src/sbbs3/zmodem.h b/src/sbbs3/zmodem.h index d8bf62fda4f89bb454f1dcf37e31a4256c9c7c00..045bf5f9df57fc3ee890606131f934f86d2797f6 100644 --- a/src/sbbs3/zmodem.h +++ b/src/sbbs3/zmodem.h @@ -227,6 +227,7 @@ typedef struct { int n_files_remaining; int n_bytes_remaining; unsigned char tx_data_subpacket[MAX_SUBPACKETSIZE]; + unsigned char rx_data_subpacket[8192]; /* zzap = 8192 */ ulong current_file_size; time_t transfer_start; @@ -270,11 +271,25 @@ void zmodem_init(zmodem_t*, void* cbdata, long* mode ,int (*recv_byte)(void*, unsigned timeout)); char* zmodem_ver(char *buf); const char* zmodem_source(void); +void zmodem_send_nak(zmodem_t*); +void zmodem_send_zskip(zmodem_t* zm); +void zmodem_send_zrinit(zmodem_t*); +void zmodem_send_pos_header(zmodem_t* zm, int type, long pos, BOOL hex); int zmodem_get_zrinit(zmodem_t*); void zmodem_parse_zrinit(zmodem_t*); int zmodem_send_zfin(zmodem_t*); BOOL zmodem_send_file(zmodem_t*, char* name, FILE* fp, BOOL request_init, time_t* start, ulong* bytes_sent); - +int zmodem_recv_init(zmodem_t* zm); +BOOL zmodem_recv_file_info(zmodem_t* zm + ,char* fname, size_t maxlen + ,ulong* size + ,time_t* time + ,long* mode + ,long* serial_num + ,ulong* total_files + ,ulong* total_bytes); +int zmodem_recv_file_data(zmodem_t*, FILE*, ulong offset, ulong fsize, time_t start); +int zmodem_rx_header_and_check(zmodem_t* zm, int timeout); #endif