diff --git a/src/sbbs3/sexyz.c b/src/sbbs3/sexyz.c index 5f59c1275b23461ed56e99501cbce357fb1e222b..1b9ef471b1eb84925a72f540a0ada657e835ec63 100644 --- a/src/sbbs3/sexyz.c +++ b/src/sbbs3/sexyz.c @@ -696,8 +696,7 @@ void xmodem_progress(void* unused, unsigned block_num, ulong offset, ulong fsize * show the progress of the transfer like this: * zmtx: sending file "garbage" 4096 bytes ( 20%) */ -void zmodem_progress(void* unused, ulong start_pos, ulong current_pos - ,ulong fsize, time_t start) +void zmodem_progress(void* cbdata, ulong start_pos, ulong current_pos) { char orig[128]; unsigned cps; @@ -705,17 +704,18 @@ void zmodem_progress(void* unused, ulong start_pos, ulong current_pos long t; time_t now; static time_t last_progress; + zmodem_t* zm = (zmodem_t*)cbdata; now=time(NULL); - if(now-last_progress>=progress_interval || current_pos >= fsize || newline) { - t=now-start; + if(now-last_progress>=progress_interval || current_pos >= zm->current_file_size || newline) { + t=now-zm->transfer_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=zm->current_file_size/cps; /* total transfer est time */ l-=t; /* now, it's est time left */ if(l<0) l=0; if(start_pos) @@ -726,13 +726,13 @@ void zmodem_progress(void* unused, ulong start_pos, ulong current_pos "Time: %lu:%02lu/%lu:%02lu CPS: %u %lu%% " ,orig ,current_pos/1024 - ,fsize/1024 + ,zm->current_file_size/1024 ,t/60L ,t%60L ,l/60L ,l%60L ,cps - ,(long)(((float)current_pos/(float)fsize)*100.0) + ,(long)(((float)current_pos/(float)zm->current_file_size)*100.0) ); newline=FALSE; last_progress=now; @@ -783,8 +783,8 @@ static int send_files(char** fname, uint fnames) lprintf(LOG_INFO,"Sending %u files (%lu KB total)" ,xm.total_files,xm.total_bytes/1024); - zm.n_files_remaining = xm.total_files; - zm.n_bytes_remaining = xm.total_bytes; + zm.files_remaining = xm.total_files; + zm.bytes_remaining = xm.total_bytes; /***********************************************/ /* Send every file matching names or filespecs */ @@ -976,20 +976,20 @@ static int receive_files(char** fname_list, int fnames) } else { /* Zmodem */ lprintf(LOG_INFO,"Waiting for Zmodem sender..."); - i=zmodem_recv_init(&zm - ,fname,sizeof(fname) - ,&file_bytes - ,&ftime - ,&fmode - ,&serial_num - ,&total_files - ,&total_bytes); + + i=zmodem_recv_init(&zm); + if(zm.cancelled) return(1); if(i<0) return(-1); switch(i) { case ZFILE: + SAFECOPY(fname,zm.current_file_name); + file_bytes = zm.current_file_size; + ftime = zm.current_file_time; + total_files = zm.files_remaining; + total_bytes = zm.bytes_remaining; break; case ZFIN: case ZCOMPL: @@ -1084,7 +1084,7 @@ static int receive_files(char** fname_list, int fnames) success=FALSE; if(mode&ZMODEM) { - errors=zmodem_recv_file_data(&zm,fp,0,file_bytes,startfile); + errors=zmodem_recv_file_data(&zm,fp,0); /* * wait for the eof header diff --git a/src/sbbs3/zmodem.c b/src/sbbs3/zmodem.c index 7d8771cafec97a7b1c1c13e94aa97c425509d5b0..3ecb99830d7ef4bdc5dafbd061fcba44444b8184 100644 --- a/src/sbbs3/zmodem.c +++ b/src/sbbs3/zmodem.c @@ -28,7 +28,8 @@ #include <sys/stat.h> /* struct stat */ #include "genwrap.h" -#include "dirwrap.h" +#include "dirwrap.h" /* getfname() */ +#include "filewrap.h" /* filelength() */ #include "zmodem.h" #include "crc16.h" @@ -1326,7 +1327,7 @@ int zmodem_get_zfin(zmodem_t* zm) * the name is only used to show progress */ -int zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong fsize, ulong* sent) +int zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong* sent) { int n; uchar type; @@ -1360,7 +1361,7 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong fsize, ulong* sent } #endif if(zm->progress!=NULL) - zm->progress(zm->cbdata, pos, ftell(fp), fsize, zm->transfer_start); + zm->progress(zm->cbdata, pos, ftell(fp)); type = ZCRCG; @@ -1376,7 +1377,7 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong fsize, ulong* sent buf_sent=0; } - if((ulong)ftell(fp) >= fsize || n==0) // can't use feof() here! + if((ulong)ftell(fp) >= zm->current_file_size || n==0) // can't use feof() here! type = ZCRCE; zmodem_send_data(zm, type, zm->tx_data_subpacket, n); @@ -1404,8 +1405,8 @@ int zmodem_send_from(zmodem_t* zm, FILE* fp, ulong pos, ulong fsize, ulong* sent } } - if((ulong)ftell(fp) >= fsize) { - lprintf(zm,LOG_DEBUG,"zmodem_send_from: end of file (%ld)", fsize ); + if((ulong)ftell(fp) >= zm->current_file_size) { + lprintf(zm,LOG_DEBUG,"zmodem_send_from: end of file (%ld)", zm->current_file_size ); return ZACK; } if(n==0) { @@ -1561,8 +1562,8 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti ,s.st_mtime ,0 /* file mode */ ,0 /* serial number */ - ,zm->n_files_remaining - ,zm->n_bytes_remaining + ,zm->files_remaining + ,zm->bytes_remaining ,0 /* file type */ ); @@ -1637,7 +1638,7 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti * and start sending */ - type = zmodem_send_from(zm, fp, pos, s.st_size, &sent_bytes); + type = zmodem_send_from(zm, fp, pos, &sent_bytes); if(!is_connected(zm)) return(FALSE); @@ -1679,14 +1680,127 @@ BOOL zmodem_send_file(zmodem_t* zm, char* fname, FILE* fp, BOOL request_init, ti return(success); } -int zmodem_recv_init(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) +int zmodem_recv_files(zmodem_t* zm, const char* download_dir, ulong* bytes_received) +{ + char fpath[MAX_PATH+1]; + FILE* fp; + long l; + BOOL skip; + ulong b; + ulong crc; + ulong rcrc; + ulong bytes; + ulong kbytes; + ulong start_bytes; + unsigned files_received=0; + time_t t; + unsigned cps; + unsigned timeout; + unsigned errors=0; + + if(bytes_received!=NULL) + *bytes_received=0; + zm->current_file_num=1; + while(zmodem_recv_init(zm)==ZFILE) { + bytes=zm->current_file_size; + kbytes=bytes/1024; + if(kbytes<1) kbytes=0; + lprintf(zm,LOG_INFO,"Downloading %s (%lu KBytes) via Zmodem", zm->current_file_name, kbytes); + + do { /* try */ + skip=TRUE; + + sprintf(fpath,"%s/%s",download_dir,zm->current_file_name); + lprintf(zm,LOG_DEBUG,"fpath=%s",fpath); + if(fexist(fpath)) { + lprintf(zm,LOG_WARNING,"%s already exists",fpath); + l=flength(fpath); + if(l>=(long)bytes) { + lprintf(zm,LOG_WARNING,"Local file size (%lu bytes) >= remote file size (%ld)" + ,l, bytes); + break; + } + if((fp=fopen(fpath,"rb"))==NULL) { + lprintf(zm,LOG_ERR,"Error %d opening %s",errno,fpath); + break; + } + crc=fcrc32(fp,l); + fclose(fp); + if(!zmodem_get_crc(zm,l,&rcrc)) { + lprintf(zm,LOG_ERR,"Failed to get CRC of remote file: %s", fpath); + break; + } + if(crc!=rcrc) { + lprintf(zm,LOG_WARNING,"Remote file has different CRC value"); + lprintf(zm,LOG_DEBUG,"Remote CRC: %08lx vs Local CRC: %08lx)", rcrc, crc); + break; + } + lprintf(zm,LOG_INFO,"Resuming download of %s",fpath); + } + + if((fp=fopen(fpath,"ab"))==NULL) { + lprintf(zm,LOG_ERR,"Error %d opening/creating/appending %s",errno,fpath); + break; + } + start_bytes=filelength(fileno(fp)); + + skip=FALSE; + errors=zmodem_recv_file_data(zm,fp,flength(fpath)); + + for(;errors<=zm->max_errors && !zm->cancelled; errors++) { + if(zmodem_recv_header_and_check(zm)) + break; + } + fclose(fp); + l=flength(fpath); + if(errors && l==0) { /* aborted/failed download */ + if(remove(fpath)) /* don't save 0-byte file */ + lprintf(zm,LOG_ERR,"Error %d removing %s",errno,fpath); + else + lprintf(zm,LOG_INFO,"Deleted 0-byte file %s",fpath); + } + else { + if(l!=(long)bytes) { + lprintf(zm,LOG_WARNING,"Incomplete download (%ld bytes received, expected %lu)" + ,l,bytes); + } else { + if((t=time(NULL)-zm->transfer_start)<=0) + t=1; + b=l-start_bytes; + if((cps=b/t)==0) + cps=1; + lprintf(zm,LOG_INFO,"Received %lu bytes successfully (%u CPS)",b,cps); + files_received++; + if(bytes_received!=NULL) + *bytes_received+=b; + } + if(zm->current_file_time) + setfdate(fpath,zm->current_file_time); + } + + } while(0); + /* finally */ + + if(skip) { + lprintf(zm,LOG_WARNING,"Skipping file"); + zmodem_send_zskip(zm); + } + zm->current_file_num++; + } + if(zm->local_abort) + zmodem_abort_receive(zm); + + /* wait for "over-and-out" */ + timeout=zm->recv_timeout; + zm->recv_timeout=2; + if(zmodem_rx(zm)=='O') + zmodem_rx(zm); + zm->recv_timeout=timeout; + + return(files_received); +} + +int zmodem_recv_init(zmodem_t* zm) { int type=CAN; unsigned errors; @@ -1709,15 +1823,7 @@ int zmodem_recv_init(zmodem_t* zm lprintf(zm,LOG_DEBUG,"Received header: %s",chr((uchar)type)); if(type==ZFILE) { - if(!zmodem_recv_file_info(zm - ,fname,maxlen - ,p_size - ,p_time - ,p_mode - ,p_serial - ,p_total_files - ,p_total_bytes)) - continue; + zmodem_parse_zfile_subpacket(zm); return(type); } @@ -1735,51 +1841,40 @@ int zmodem_recv_init(zmodem_t* zm 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) +void zmodem_parse_zfile_subpacket(zmodem_t* zm) { int i; - ulong size=0; - ulong time=0; - ulong total_files=0; - ulong total_bytes=0; long mode=0; long serial=-1; - if(fname!=NULL) - safe_snprintf(fname,maxlen,"%s",zm->rx_data_subpacket); + SAFECOPY(zm->current_file_name,getfname(zm->rx_data_subpacket)); + + zm->current_file_size = 0; + zm->current_file_time = 0; + zm->files_remaining = 0; + zm->bytes_remaining = 0; 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 */ + ,&zm->current_file_size /* file size (decimal) */ + ,&zm->current_file_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 */ + ,&zm->files_remaining /* remaining files to be sent */ + ,&zm->bytes_remaining /* remaining bytes to be sent */ ); lprintf(zm,LOG_DEBUG,"Zmodem header (%u fields): %s" ,i, zm->rx_data_subpacket+strlen(zm->rx_data_subpacket)+1); - if(!total_files) - total_files=1; - if(!total_bytes) - total_bytes=size; + if(!zm->files_remaining) + zm->files_remaining = 1; + if(!zm->bytes_remaining) + zm->bytes_remaining = zm->current_file_size; - 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); + if(!zm->total_files) + zm->total_files = zm->files_remaining; + if(!zm->total_bytes) + zm->total_bytes = zm->bytes_remaining; } /* @@ -1787,24 +1882,23 @@ BOOL zmodem_recv_file_info(zmodem_t* zm * the name is only used to show progress */ -unsigned zmodem_recv_file_data(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize, time_t start) +unsigned zmodem_recv_file_data(zmodem_t* zm, FILE* fp, ulong offset) { int i=0; unsigned errors=0; - if(start==0) - start=time(NULL); + zm->transfer_start=time(NULL); fseek(fp,offset,SEEK_SET); offset=ftell(fp); while(errors<=zm->max_errors && is_connected(zm) - && (ulong)ftell(fp) < fsize && !zm->cancelled) { + && (ulong)ftell(fp) < zm->current_file_size && !zm->cancelled) { if(i!=ENDOFFRAME) zmodem_send_pos_header(zm, ZRPOS, ftell(fp), /* Hex? */ TRUE); - if((i = zmodem_recv_file_frame(zm,fp,offset,fsize,start)) == ZEOF) + if((i = zmodem_recv_file_frame(zm,fp,offset)) == ZEOF) break; if(i!=ENDOFFRAME) { if(i>0) @@ -1816,7 +1910,7 @@ unsigned zmodem_recv_file_data(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize } -int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize, time_t start) +int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, ulong offset) { unsigned n; int type; @@ -1853,7 +1947,7 @@ int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize, ti } if(zm->progress!=NULL) - zm->progress(zm->cbdata,offset,ftell(fp),fsize,start); + zm->progress(zm->cbdata,offset,ftell(fp)); if(zm->cancelled) return(ZCAN); @@ -1878,7 +1972,7 @@ char* zmodem_ver(char *buf) void zmodem_init(zmodem_t* zm, void* cbdata ,int (*lputs)(void*, int level, const char* str) - ,void (*progress)(void* unused, ulong, ulong, ulong, time_t) + ,void (*progress)(void* unused, ulong, ulong) ,int (*send_byte)(void*, uchar ch, unsigned timeout) ,int (*recv_byte)(void*, unsigned timeout) ,BOOL (*is_connected)(void*) diff --git a/src/sbbs3/zmodem.h b/src/sbbs3/zmodem.h index 53b520d9c271b40b785d88a36ae897617227ec40..1866d07cc7c71f3070adaceec518c682e99beda3 100644 --- a/src/sbbs3/zmodem.h +++ b/src/sbbs3/zmodem.h @@ -223,14 +223,18 @@ typedef struct { #define MAX_SUBPACKETSIZE 1024 - int n_files_remaining; - int n_bytes_remaining; BYTE tx_data_subpacket[MAX_SUBPACKETSIZE]; BYTE rx_data_subpacket[8192]; /* zzap = 8192 */ - ulong current_file_size; - time_t transfer_start; - time_t last_status; + char current_file_name[MAX_PATH+1]; + ulong current_file_size; + time_t current_file_time; + unsigned current_file_num; + unsigned total_files; + ulong total_bytes; + unsigned files_remaining; + unsigned bytes_remaining; + time_t transfer_start; int receive_32bit_data; int use_crc16; @@ -262,7 +266,7 @@ typedef struct { int (*lputs)(void*, int level, const char* str); int (*send_byte)(void*, BYTE ch, unsigned timeout); int (*recv_byte)(void*, unsigned timeout); - void (*progress)(void*, ulong start_pos, ulong current_pos, ulong fsize, time_t start); + void (*progress)(void*, ulong start_pos, ulong current_pos); BOOL (*is_connected)(void*); BOOL (*data_waiting)(void*); @@ -270,7 +274,7 @@ typedef struct { void zmodem_init(zmodem_t*, void* cbdata ,int (*lputs)(void*, int level, const char* str) - ,void (*progress)(void*, ulong, ulong, ulong, time_t) + ,void (*progress)(void*, ulong, ulong) ,int (*send_byte)(void*, BYTE ch, unsigned timeout) ,int (*recv_byte)(void*, unsigned timeout) ,BOOL (*is_connected)(void*) @@ -290,26 +294,13 @@ int zmodem_get_zrinit(zmodem_t*); int zmodem_get_zfin(zmodem_t* zm); BOOL zmodem_get_crc(zmodem_t*, long length, ulong* crc); void zmodem_parse_zrinit(zmodem_t*); +void zmodem_parse_zfile_subpacket(zmodem_t* zm); 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 - ,char* fname, size_t maxlen - ,ulong* size - ,time_t* time - ,long* mode - ,long* serial_num - ,ulong* total_files - ,ulong* total_bytes); -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); -unsigned zmodem_recv_file_data(zmodem_t*, FILE*, ulong offset, ulong fsize, time_t start); -int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, ulong offset, ulong fsize, time_t start); +int zmodem_recv_files(zmodem_t* zm, const char* download_dir, ulong* bytes_received); +int zmodem_recv_init(zmodem_t* zm); +unsigned zmodem_recv_file_data(zmodem_t*, FILE*, ulong offset); +int zmodem_recv_file_frame(zmodem_t* zm, FILE* fp, ulong offset); int zmodem_recv_header_and_check(zmodem_t* zm); #endif