This is tipsz.c in view mode; [Download] [Up]
char *numeric_revision = "tipsz 1.00"; #define BUFFERED_WRITE /*+------------------------------------------------------------------------- tipsz.c - X/Y/ZMODEM send program Derived from public domain source by Chuck Forsberg, Omen Technologies wht%n4hgf@emory.mathcs.emory.edu Usage: tipsz [-X -Y -Z] [-12+abdefkLlNnquvwy] [-] file ... (Y) = Option applies to YMODEM only (Z) = Option applies to ZMODEM only a (ASCII) change NL to CR/LF b Binary file transfer override f send Full pathname (Y/Z) k Send 1024 byte packets (Y) L N Limit subpacket length to N bytes (Z) l N Limit frame length to N bytes (l>=L) (Z) n send file if source newer (Z) N send file if source newer or longer (Z) o Use 16 bit CRC instead of 32 bit CRC (Z) p Protect existing destination file (Z) r Resume/Recover interrupted file transfer (Z) q Quiet (no progress reports) u Unlink file after transmission w N Window is N bytes (Z) y Yes,overwrite existing file (Z) @file reads a list of filenames from 'file' Defined functions: SIGALRM_handler() bye_bye(sig) cancel_transaction(sig) determine_transaction_time() flushline() get_file_list_name(namep) getinsync(flag) getnak() getzrxinit() log_packet_buffer(buf,len) main(argc,argv) onintr() purgeline() readline(n) readock(timeout,count) report_rcvr_cancelled(place_happened) report_rcvr_skipped() report_send_stats(filepos) report_send_transaction() rewind_file_list() saybibi() send_cancel() sendline(ch) sendzsinit() set_file_list(pathc,pathv) substr(s,t) usage() wcputsec(buf,sectnum,cseclen) wcs(oname) wcsend() wctx(flen) wctxpn(name) xbuf_build(buf,count) xsendline(ch) zbuf_build(buf,count) zsendfdata() zsendfile(buf,blen) --------------------------------------------------------------------------*/ /*+:EDITS:*/ /*:05-21-1990-16:00-wht@tridom-adapt ecu xfer protocols for tipwht */ /* Error return conditions 255: usage 254: protocol failed (bad line conditions,brain dead remote) 253: could not open any files 128-192: process terminated with signal==code-128 (64 signals allowed for) signal 0 == program logic error (see cancel_transaction) 127: 127 or more files not transmitted (see ~/.tip/log) 1-126: count of files not transmitted (see ~/.tip/log) 0: file transfer completely successful */ char *substr(),*getenv(); #include <stdio.h> #include <signal.h> #include <setjmp.h> #include <ctype.h> #include <fcntl.h> #ifdef NeXT #include <sys/stat.h> #endif /* NeXT */ #include "zmodem.h" #include "zlint.h" #if defined(__STDC__) || defined(__cplusplus) # define P_A(s) s #else # define P_A(s) () #endif void log_packet_buffer P_A((unsigned char *buf, int len)); void rewind_file_list P_A((void)); void set_file_list P_A((int pathc, char **pathv)); int get_file_list_name P_A((char **namep)); void bye_bye P_A((int sig)); void cancel_transaction P_A((int sig)); int onintr P_A((void)); void report_send_transaction P_A((void)); void report_send_stats P_A((long filepos)); void report_rcvr_cancelled P_A((char *place_happened)); void report_rcvr_skipped P_A((void)); int xsendline P_A((int ch)); int sendline P_A((int ch)); int flushline P_A((void)); int main P_A((int argc, char *argv[])); int wcsend P_A((void)); int wcs P_A((char *oname)); int wctxpn P_A((char *name)); int getnak P_A((void)); int wctx P_A((long flen)); int wcputsec P_A((unsigned char *buf, int sectnum, int cseclen)); int xbuf_build P_A((char *buf, int count)); int zbuf_build P_A((char *buf, int count)); int SIGALRM_handler P_A((void)); int readock P_A((int timeout, int count)); int readline P_A((int n)); int purgeline P_A((void)); int send_cancel P_A((void)); char *substr P_A((char *str, char *substr)); int usage P_A((void)); int getzrxinit P_A((void)); int sendzsinit P_A((void)); int zsendfile P_A((char *buf, int blen)); int zsendfdata P_A((void)); int getinsync P_A((int flag)); int saybibi P_A((void)); void determine_transaction_time P_A((void)); #undef P_A extern char *sys_errlist[]; extern unsigned short crctab[]; /* wht */ extern unsigned long total_data_chars_xfered; /* zcurses.c */ extern int errno; extern int show_window; extern int Rxtimeout; /* Tenths of seconds to wait for something */ extern char Rxhdr[4]; /* Received header */ extern char Txhdr[4]; /* Transmitted header */ extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ extern long Rxpos; /* Received file position */ extern long Txpos; /* Transmitted file position */ extern char *frametypes[]; extern char Attn[]; /* Attention string rx sends to tx on err */ extern char s256[]; #define RETRYMAX 10 /* non-zmodem retry count on block send */ #define VMIN_COUNT 2 /* must not exceed 255 */ unsigned char vmin_count = VMIN_COUNT; int iofd = 0; /* line io fd */ #ifdef BUFFERED_WRITE FILE *iofp; char iofpbuf[256]; #endif /* * Attention string to be extipted by receiver to interrupt streaming data * when an error is detected. A pause (0336) may be needed before the * ^C (03) or after it. */ #if defined(READCHECK) char Myattn[] = { 0 }; #else #if defined(M_SYS5) char Myattn[] = { 03,0336,0 }; #else char Myattn[] = { 0 }; #endif #endif FILE *in; char *Cmdstr; /* Pointer to the command string */ char *bottom_label = (char *)0; char Crcflg; char Lastrx; char Lzconv; /* Local ZMODEM file conversion request */ char Lzmanag; /* Local ZMODEM file management request */ char Lztrans; char Pathname[PATHLEN]; char curr_dir[256]; char s128[128]; char txbuf[1024]; char zconv; /* ZMODEM file conversion request */ char zmanag; /* ZMODEM file management request */ char ztrans; /* ZMODEM file transport request */ int Ascii=0; /* Add CR's for brain damaged programs */ int Cmdack1; /* Rx ACKs command,then do it */ int Cmdtries = 11; int Command = 0; /* Send a command,then exit. */ int Dontread; /* Don't read the buffer,it's still there */ int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */ int Exitcode = 0; int Filcnt=0; /* count of number of files opened */ int FilesTotal; int Filesleft; int Fullname=0; /* transmit full pathname */ int Lastn; /* Count of last buffer read or -1 */ int Lfseen=0; int Noeofseen; int Nozmodem = 0; int Optiong; /* no wait for block ACK's */ int Quiet=0; /* overrides logic that would otherwise set verbose */ int Rxflags = 0; int SameZrposAgain=0; /* How many times we've been ZRPOS'd same place (wht) */ int Tframlen = 0; /* Override for tx frame length */ int Totsecs; /* total number of blocks this file */ int Twostop = 0; /* use two stop bits */ int Unlinkafter=0; /* Unlink file after it is sent */ int Wantfcs32 = TRUE; /* want to send 32 bit FCS */ int Xmodem=0; /* XMODEM Protocol - don't send pathnames */ int Zctlesc; /* Encode control characters */ int Zmodem=0; /* ZMODEM protocol requested by receiver */ int Zrwindow = 1400; /* RX window size (controls garbage count) */ int blklen=128; /* length of transmitted records */ int blklen_original; int blkopt=0; /* Override value for zmodem blklen */ int tipsz_flag = 1; int skip_count = 0; /* skipped files */ int errors; int firstsec; int log_packets = 0; int no_files = 0; int npats = 0; long Lastread; /* Beginning offset of last buffer read */ long Lastsync; /* Last offset to which we got a ZRPOS */ long Lrxpos; /* Receiver's last reported offset */ long TotalLeft; long TotalToSend; long bytcnt; long rx_char_count = 0L; long this_file_length; long tx_char_count = 0L; unsigned Baudrate; unsigned Rxbuflen = 16384; /* Receiver's max buffer length */ unsigned Txwcnt; /* Counter used to space ack requests */ unsigned Txwindow; /* Control the size of the transmitted window */ unsigned Txwspac; /* Spacing between zcrcq requests */ unsigned int bad_condx_blklen = 0; /* if <>0,blklen has been reduced (wht) */ unsigned int bad_condx_frame_count = 0; /* frame # last SameZrposAgain (wht) */ unsigned int this_file_frame_count; /* count of frames sent this file (wht) */ #define MAX_PATHS 512 char *paths[MAX_PATHS]; jmp_buf tohere; /* For the interrupt on RX timeout */ jmp_buf intrjmp; /* For the interrupt on RX CAN */ int file_list_pathc; int file_list_path_current; char **file_list_pathv; int required_type = 0; FILE *fpflst = (FILE *)0; /*+------------------------------------------------------------------------- log_packet_buffer(buf,len) --------------------------------------------------------------------------*/ void log_packet_buffer(buf,len) register unsigned char *buf; register int len; { char xbuf[32]; while(len--) { sprintf(xbuf,"%02x ",*buf++); write(log_packets,xbuf,strlen(xbuf)); } write(log_packets,"\n",1); } /* end of log_packet_buffer */ /*+------------------------------------------------------------------------- rewind_file_list() --------------------------------------------------------------------------*/ void rewind_file_list() { file_list_path_current = 0; if(fpflst) { fclose(fpflst); fpflst = (FILE *)0; } } /* end of rewind_file_list */ /*+------------------------------------------------------------------------- set_file_list(pathc,pathv) --------------------------------------------------------------------------*/ void set_file_list(pathc,pathv) int pathc; char **pathv; { file_list_pathc = pathc; file_list_pathv = pathv; rewind_file_list(); } /* end of set_file_list */ /*+------------------------------------------------------------------------- get_file_list_name(namep) --------------------------------------------------------------------------*/ get_file_list_name(namep) char **namep; { register char *cptr; static char name[256]; try_fpflst: if(fpflst) { if(fgets(name,sizeof(name),fpflst) != NULL) { name[strlen(name) - 1] = 0; *namep = name; return(1); } fclose(fpflst); fpflst = (FILE *)0; } next_arg: if(file_list_path_current == file_list_pathc) return(0); cptr = file_list_pathv[file_list_path_current++]; if(*cptr != '@') { *namep = cptr; return(1); } cptr++; if((fpflst = fopen(cptr,"r")) == NULL) goto next_arg; goto try_fpflst; } /* end of get_file_list_name */ /*+------------------------------------------------------------------------- bye_bye(sig) --------------------------------------------------------------------------*/ void bye_bye(sig) int sig; { exit(sig+128); } /* end of bye_bye */ /*+------------------------------------------------------------------------- cancel_transaction(sig) called by signal interrupt or terminate to clean things up --------------------------------------------------------------------------*/ void cancel_transaction(sig) { if(Zmodem) zmputs(Attn); send_cancel(); mode(0); if(sig >= 0) { sprintf(s128,"tipsz aborted (signal %d)",sig); report_str(s128,0); } report_tx_ind(0); report_rx_ind(0); report_uninit(0); bye_bye(sig); } /* end of cancel_transaction */ /* Called when ZMODEM gets an interrupt (^X) */ onintr() { signal(SIGINT,SIG_IGN); #if defined(M_SYS5) report_rx_ind(0); report_tx_ind(0); #endif longjmp(intrjmp,-1); } /*+------------------------------------------------------------------------- report_send_transaction() --------------------------------------------------------------------------*/ void report_send_transaction() { if(Xmodem) { long blocks = (TotalToSend >> 7) + ((TotalToSend % 128) != 0); long secs = 7 /* slightly worse than average first nak delay */ + (blocks / 5L) /* assume .2 sec ack time */ + ((blocks * (128L + 16L)) / (Baudrate / 10)); if(!secs) secs = 10L; sprintf(s128,"Sending %ld blocks time ~= %ld:%02ld", blocks,secs/60,secs % 60); } else { long min_100 = (FilesTotal * 2L) + (((TotalToSend * 11L)) * 10L) / (Baudrate * 6L); if(!min_100) min_100 = 4L; #if defined(M_I286) /* slower */ else if(Baudrate > 4800) { min_100 *= 13; min_100 /= 9; /* yech ... empirical */ } #endif sprintf(s128,"Sending %ld bytes total time ~= %2lu:%02lu", TotalToSend,min_100 / 100,((min_100 % 100) * 60L) / 100L); } report_transaction(s128); } /* end of report_send_transaction */ /*+------------------------------------------------------------------------- report_send_stats(filepos) --------------------------------------------------------------------------*/ void report_send_stats(filepos) long filepos; { if(Xmodem) sprintf(s128,"File %d%% complete", (this_file_length == 0) ? (int)100 : (int)((filepos * 100L) / this_file_length)); else sprintf(s128,"This file %d%%, transaction %d%% complete", (this_file_length == 0) ? (int)100 : (int)((filepos * 100L)/this_file_length), (TotalToSend == 0) ? (int)100 : (int)(((total_data_chars_xfered + filepos) * 100L) / TotalToSend)); report_str(s128,0); report_txpos(filepos); } /* end of report_send_stats */ /*+------------------------------------------------------------------------- report_rcvr_cancelled(place_happened) --------------------------------------------------------------------------*/ void report_rcvr_cancelled(place_happened) char *place_happened; { strcpy(s128,"SEND CANCELLED"); report_str(s128 + 5,1); skip_count++; report_error_count(); } /* end of report_rcvr_cancelled */ /*+------------------------------------------------------------------------- report_rcvr_skipped() --------------------------------------------------------------------------*/ void report_rcvr_skipped() { sprintf(s128,"SEND skipped: %s",Pathname); report_str(s128 + 5,-1); skip_count++; report_error_count(); TotalToSend -= this_file_length; report_send_transaction(); } /* end of report_rcvr_skipped */ /*+------------------------------------------------------------------------- xsendline(ch) --------------------------------------------------------------------------*/ xsendline(ch) char ch; { #ifdef BUFFERED_WRITE fputc(ch,iofp); #else write(iofd,&ch,1); #endif ++tx_char_count; } /* end of xsendline */ /*+------------------------------------------------------------------------- sendline(ch) --------------------------------------------------------------------------*/ sendline(ch) char ch; { xsendline(ch); } /* end of sendline */ flushline() { #ifdef BUFFERED_WRITE fflush(iofp); #endif } main(argc,argv) char *argv[]; { register char *cp; long min_100; char **patts = paths; char **gargv = argv; int gargc = argc; signal(SIGINT,bye_bye); signal(SIGTERM,bye_bye); get_curr_dir(curr_dir,sizeof(curr_dir)); Rxtimeout = 600; npats=0; if(argc<2) usage(); while(--argc) { cp = *++argv; if(*cp == '-') { cp++; switch(*cp++) { case 'X': required_type = 1; Xmodem = TRUE; break; case 'Y': required_type = 1; Nozmodem = TRUE; blklen=1024; break; case 'Z': show_window = 1; required_type = 1; break; case '+': Lzmanag = ZMAPND; break; case 'a': Lzconv = ZCNL; Ascii = TRUE; break; case 'b': Lzconv = ZCBIN; break; case 'd': ++Dottoslash; /* **** FALL THROUGH TO **** */ case 'f': Fullname=TRUE; break; case ',': log_packets = 1; break; case '/': if(--argc < 1) usage(); strcpy(curr_dir,*++argv); break; case '.': if(--argc < 1) usage(); iofd = atoi(*++argv); break; #ifdef HAYES case ':': if(--argc < 1) usage(); Baudrate = atoi(*++argv); break; #endif case 'C': if(--argc < 1) /* usage("no label after -C"); */ usage(); bottom_label = *++argv; break; case 'e': Zctlesc = 1; break; case 'k': blklen=1024; break; case 'L': if(--argc < 1) { usage(); } blkopt = atoi(*++argv); if(blkopt<24 || blkopt>1024) usage(); break; case 'l': if(--argc < 1) { usage(); } Tframlen = atoi(*++argv); if(Tframlen<32 || Tframlen>1024) usage(); break; case 'N': Lzmanag = ZMNEWL; break; case 'n': Lzmanag = ZMNEW; break; case 'o': Wantfcs32 = FALSE; break; case 'p': Lzmanag = ZMPROT; break; case 'r': Lzconv = ZCRESUM; case 't': if(--argc < 1) { usage(); } Rxtimeout = atoi(*++argv); if(Rxtimeout<10 || Rxtimeout>1000) usage(); break; case 'u': ++Unlinkafter; break; case 'w': if(--argc < 1) { usage(); } Txwindow = atoi(*++argv); if(Txwindow < 256) Txwindow = 256; Txwindow = (Txwindow/64) * 64; Txwspac = Txwindow/4; if(blkopt > Txwspac || (!blkopt && Txwspac < 1024)) blkopt = Txwspac; break; case 'y': Lzmanag = ZMCLOB; break; case 'z': Lztrans = ZTRLE; break; default: usage(); } } else if(argc > 0) { if(npats < MAX_PATHS) { npats++; *patts++ = cp; } else { printf("too many filenames to send\n"); exit(255); } } } if(!required_type || !iofd) { printf("can only be run by tip\n"); exit(255); } if(npats < 1 && !Command) usage(); set_file_list(npats,paths); sprintf(s128,"%s",numeric_revision); if(log_packets) { char log_packets_name[64]; FILE *ftmp; int iargv; sprintf(log_packets_name,"/tmp/sz%05d.plog",getpid()); unlink(log_packets_name); ftmp = fopen(log_packets_name,"w"); fclose(ftmp); log_packets = open(log_packets_name,O_WRONLY,0644); if(log_packets < 0) log_packets = 0; else { write(log_packets,"exec: ",6); for(iargv = 0; iargv < gargc; iargv++) { write(log_packets,gargv[iargv],strlen(gargv[iargv])); write(log_packets," ",1); } write(log_packets,"\n",1); } } report_init(s128); mode(1); if(signal(SIGINT,cancel_transaction) == SIG_IGN) signal(SIGINT,SIG_IGN); else signal(SIGINT,cancel_transaction); signal(SIGTERM,cancel_transaction); report_str("calculating transaction time",-1); determine_transaction_time(); #ifdef BUFFERED_WRITE iofp = fdopen(iofd,"w"); setbuffer(iofp,iofpbuf,sizeof(iofpbuf)); #endif if(!Xmodem) { TotalToSend = TotalLeft; report_send_transaction(); report_str("starting remote receiver",-1); if(!Nozmodem) write(iofd,"rz\r",3); else /* wht -- why not? */ write(iofd,"rb\r",3); /* wht */ sleep(2); report_str("beginning transfer",-1); if(!Nozmodem) { stohdr(0L); zshhdr(4,ZRQINIT,Txhdr); } } else report_str("beginning transfer",-1); if(wcsend()==ERROR) { Exitcode=254; /*wht was 0200 */ send_cancel(); } mode(0); report_uninit(0); if(no_files) Exitcode = 253; exit(Exitcode ? Exitcode : (skip_count > 127) ? 127 : skip_count); /*NOTREACHED*/ } /*+------------------------------------------------------------------------- wcsend(argc,argp) -- send group of files --------------------------------------------------------------------------*/ wcsend() { register n; char *name; Crcflg=FALSE; firstsec=TRUE; bytcnt = -1; rewind_file_list(); while(get_file_list_name(&name)) { Totsecs = 0; if(wcs(name)==ERROR) return(ERROR); } Totsecs = 0; if(Filcnt==0) { /* bitch if we couldn't open ANY files */ send_cancel(); strcpy(s128,"SEND cannot open any requested files"); report_str(s128 + 5,1); sleep(2); /* allow time for other rz to get ready */ no_files = 1; return(ERROR); /* ... then cancel */ } if(Zmodem) saybibi(); else if(!Xmodem) wctxpn(""); return(OK); } /*+------------------------------------------------------------------------- wcs(oname) -- send a file --------------------------------------------------------------------------*/ wcs(oname) char *oname; { register c; register char *p; struct stat f; strcpy(Pathname,oname); /* global copy of name */ if((in=fopen(oname,"r"))==NULL) { sprintf(s128,"SEND %s: %s",sys_errlist[errno],oname); report_str(s128 + 5,1); skip_count++; report_error_count(); return(OK); /* pass over it,there may be others */ } ++Noeofseen; Lastread = 0; Lastn = -1; Dontread = FALSE; /* Check for directory or block special files */ fstat(fileno(in),&f); c = f.st_mode & S_IFMT; if(c == S_IFDIR || c == S_IFBLK) { sprintf(s128,"SEND %s: %s", (c == S_IFDIR) ? "directory" : "block device",oname); report_str(s128 + 5,1); skip_count++; report_error_count(); fclose(in); return(OK); } f.st_mode &= ~(S_ISUID | S_ISGID); Filcnt++; report_file_send_open(oname,&f); this_file_length = f.st_size; report_send_stats(0L); switch(wctxpn(Pathname)) { case ERROR: sprintf(s128,"SEND protocol failure: %s",oname); report_str(s128 + 5,1); skip_count++; report_error_count(); report_file_close(); fclose(in); return(ERROR); case ZSKIP: report_rcvr_skipped(); return(OK); } if(!Zmodem && wctx(f.st_size)==ERROR) return(ERROR); if(Unlinkafter) unlink(oname); return(0); } /* * generate and transmit pathname block consisting of * pathname (null terminated), * file length,mode time and file mode in octal * as provided by the Unix fstat call. * N.B.: modifies the passed name,may extend it! */ wctxpn(name) char *name; { register char *p,*q; char name2[PATHLEN]; struct stat f; if(Xmodem) { if((in!=stdin) && *name && fstat(fileno(in),&f)!= -1) { TotalToSend = f.st_size; report_protocol_type("XMODEM"); report_send_transaction(); report_xfer_mode((Ascii) ? "ASCII" : "BINARY"); report_last_txhdr("Waiting on NAK",0); } return(OK); } if(!Zmodem) { report_last_txhdr("START PENDING",0); if(getnak()) { report_str("Timeout on pathname nak",1); return(ERROR); } } q = (char *) 0; if(Dottoslash) { /* change . to . */ for(p=name; *p; ++p) { if(*p == '/') q = p; else if(*p == '.') *(q=p) = '/'; } if(q && strlen(++q) > 8) { /* If name>8 chars */ q += 8; /* make it .ext */ strcpy(name2,q); /* save excess of name */ *q = '.'; strcpy(++q,name2); /* add it back */ } } for(p=name,q=txbuf ; *p; ) if((*q++ = *p++) == '/' && !Fullname) q = txbuf; *q++ = 0; p=q; while(q < (txbuf + 1024)) *q++ = 0; if(!Ascii && (in != stdin) && *name && !fstat(fileno(in),&f)) sprintf(p,"%lu %lo %o 0 %d %ld",f.st_size,f.st_mtime, f.st_mode &= ~(S_ISUID | S_ISGID), Filesleft,TotalLeft); report_xfer_mode((Lzconv == ZCNL) ? "ASCII" : "BINARY"); TotalLeft -= f.st_size; if(--Filesleft <= 0) TotalLeft = 0; if(TotalLeft < 0) TotalLeft = 0; /* force 1k blocks if name won't fit in 128 byte block */ if(txbuf[125]) blklen=1024; else { /* A little goodie for IMP/KMD */ txbuf[127] = (f.st_size + 127) >>7; txbuf[126] = (f.st_size + 127) >>15; } if(Zmodem) return(zsendfile(txbuf,1+strlen(p)+(p-txbuf))); report_protocol_type("YMODEM"); if(wcputsec(txbuf,0,128)==ERROR) return(ERROR); return(OK); } getnak() { register firstch; Lastrx = 0; for(;;) { switch(firstch = readock(50,1)) /* 50 was 800 (80 secs!!) wht */ { case ZPAD: if(getzrxinit()) return(ERROR); Ascii = 0; /* Receiver does the conversion */ return(FALSE); case TIMEOUT: report_str("Timeout",1); return(TRUE); case WANTG: #if defined(MODE2OK) mode(2); /* Set cbreak,XON/XOFF,etc. */ #endif Optiong = TRUE; blklen=1024; case WANTCRC: Crcflg = TRUE; case NAK: return(FALSE); case CAN: if((firstch = readock(20,1)) == CAN && Lastrx == CAN) return(TRUE); default: break; } Lastrx = firstch; } } /*+------------------------------------------------------------------------- wctx(flen) --------------------------------------------------------------------------*/ wctx(flen) long flen; { register int thisblklen; register int firstch; register int sectnum; register int attempts; long charssent; charssent = 0; firstsec=TRUE; thisblklen = blklen; report_txblklen(blklen); attempts = 8; while(((firstch = readock(Rxtimeout,2)) != NAK) && (firstch != WANTCRC) && (firstch != WANTG) && (firstch != TIMEOUT) && (firstch != CAN)) { if(!--attempts) { report_str("bad start stimulus",1); send_cancel(); return(ERROR); } } if(firstch==CAN) { report_str("receiver CAN",1); return(ERROR); } if((firstch==WANTCRC) || (firstch==WANTG)) Crcflg=TRUE; report_protocol_crc_type((Crcflg) ? ((firstch== WANTG) ? "/CRC-g" : "/CRC") : "/CHK"); sectnum=0; for(;;) { if(flen <= (charssent + 896L)) { thisblklen = 128; report_txblklen(thisblklen); } if(!xbuf_build(txbuf,thisblklen)) break; if(wcputsec(txbuf,++sectnum,thisblklen)==ERROR) return(ERROR); charssent += thisblklen; } /* file transfer completed */ report_file_byte_io(this_file_length); report_file_close(); fclose(in); attempts=0; do { purgeline(); sendline(EOT); flushline(); report_last_txhdr("EOT",0); ++attempts; } while((firstch=(readock(Rxtimeout,1)) != ACK) && attempts < RETRYMAX); if(attempts == RETRYMAX) { report_str("No ACK on EOT",1); return(ERROR); } else return(OK); } wcputsec(buf,sectnum,cseclen) unsigned char *buf; int sectnum; int cseclen; /* data length of this block to send */ { register int checksum; register int wcj; register unsigned char *cp; unsigned short oldcrc; int firstch; int attempts; firstch=0; /* part of logic to detect CAN CAN */ sprintf(s128,"Sending block %d",sectnum); report_last_txhdr(s128,0); if(log_packets) { log_packet_buffer(buf,cseclen); } for(attempts=0; attempts <= RETRYMAX; attempts++) { Lastrx= firstch; sendline(cseclen == 1024 ? STX : SOH); sendline(sectnum); sendline(-sectnum - 1); oldcrc=checksum=0; for(wcj = cseclen,cp = buf; --wcj >= 0; ) { sendline(*cp); oldcrc=updcrc(*cp,oldcrc); checksum += *cp++; } if(Crcflg) { oldcrc=updcrc(0,updcrc(0,oldcrc)); sendline((int)(oldcrc >> 8)); sendline((int)(oldcrc & 0xFF)); } else sendline(checksum); flushline(); if(Optiong) { firstsec = FALSE; return(OK); } firstch = readock(Rxtimeout,(Noeofseen&§num) ? 2:1); gotnak: switch(firstch) { case CAN: if(Lastrx == CAN) { cancan: report_last_rxhdr("CAN",1); return(ERROR); } break; case TIMEOUT: report_last_rxhdr("Timeout",1); continue; case WANTCRC: if(firstsec) Crcflg = TRUE; case NAK: report_last_rxhdr("NAK",1); continue; case ACK: report_last_rxhdr("ACK",0); firstsec=FALSE; Totsecs += (cseclen>>7); return(OK); case ERROR: report_last_rxhdr("Noise",0); break; default: sprintf(s128,"0x%02x ???",firstch); report_last_rxhdr(s128,1); break; } for(;;) { Lastrx = firstch; if((firstch = readock(Rxtimeout,2)) == TIMEOUT) break; if(firstch == NAK || firstch == WANTCRC) goto gotnak; if(firstch == CAN && Lastrx == CAN) goto cancan; } } report_str("retry count exceeded",1); return(ERROR); } /* fill buf with count chars padding with ^Z for CPM */ xbuf_build(buf,count) register char *buf; { register c,m; long lseek(); long X_txpos = lseek(fileno(in),0L,1); char diag_str[64]; report_send_stats(X_txpos); if( !Ascii) { m = read(fileno(in),buf,count); if(log_packets) { sprintf(diag_str,"read rtnd %d of %d",m,count); report_str(diag_str,1); } if(m <= 0) return(0); while(m < count) buf[m++] = 032; return(count); } m=count; if(Lfseen) { *buf++ = 012; --m; Lfseen = 0; } while((c=getc(in))!=EOF) { if(c == 012) { *buf++ = 015; if(--m == 0) { Lfseen = TRUE; break; } } *buf++ =c; if(--m == 0) break; } if(m==count) return(0); else while(--m>=0) *buf++ = CPMEOF; return(count); } /*+------------------------------------------------------------------------- zbuf_build(buf,count) - fill buf with count chars --------------------------------------------------------------------------*/ zbuf_build(buf,count) register char *buf; int count; { register c,m; m=count; while((c=getc(in))!=EOF) { *buf++ =c; if(--m == 0) break; } return(count - m); } /* end of zbuf_build */ /*+------------------------------------------------------------------------- SIGALRM_handler() --------------------------------------------------------------------------*/ SIGALRM_handler() { #if defined(M_SYS5) report_rx_ind(0); report_tx_ind(0); #endif longjmp(tohere,-1); } /* end of SIGALRM_handler */ /*+------------------------------------------------------------------------- readock(timeout,count) timeout is in tenths of seconds reads character(s) from file descriptor 'fd' read 'count' characters, (1 <= count <= 3) if more than one received, return ERROR unless all are CAN normal response is NAK, ACK, CAN, G or C --------------------------------------------------------------------------*/ readock(timeout,count) int timeout; int count; { register int c; static char byt[5]; if(setjmp(tohere)) { report_str("TIMEOUT",1); return(TIMEOUT); } c = timeout/10; if(c<2) c = 2; signal(SIGALRM,SIGALRM_handler); alarm(c); #if defined(ONEREAD) c=read(iofd,byt,1); /* regulus raw read is unique */ #else c=read(iofd,byt,count); #endif rx_char_count += c; alarm(0); if(c<1) return(TIMEOUT); if(c==1) return(byt[0]&0377); else while(c) if(byt[--c] != CAN) return(ERROR); return(CAN); } /* end of readock */ /*+------------------------------------------------------------------------- readline(n) --------------------------------------------------------------------------*/ readline(n) int n; { return(readock(n,1)); } /* end of readline */ /*+------------------------------------------------------------------------- purgeline() --------------------------------------------------------------------------*/ purgeline() { #if defined(M_SYS5) ioctl(iofd,TCFLSH,0); #else lseek(iofd,0L,2); #endif } /* end of purgeline */ /*+------------------------------------------------------------------------- send_cancel() - send cancel to remote --------------------------------------------------------------------------*/ send_cancel() { static char canistr[] = { 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 }; register char *cptr = canistr; report_last_txhdr("^X CAN",1); while(*cptr) sendline(*cptr++); flushline(); } /* end of send_cancel */ /*+------------------------------------------------------------------------- substr(str,substr) - searches for substr in string str --------------------------------------------------------------------------*/ char * substr(str,substr) register char *str,*substr; { register char *sptr; register char *ssptr; for(sptr = str; *str; str++) { if(*str == *substr) { sptr = str; ssptr = substr; while(1) { if(*ssptr == 0) return(str); if(*sptr++ != *ssptr++) break; } } } return(NULL); } /* end of substr */ /*+------------------------------------------------------------------------- usage() --------------------------------------------------------------------------*/ usage() { exit(255); } /* end of usage */ /*+------------------------------------------------------------------------- getzrxinit() - Get the receiver's init parameters --------------------------------------------------------------------------*/ getzrxinit() { register n; struct stat f; for(n=10; --n>=0; ) { switch(zgethdr(Rxhdr,1)) { case ZCHALLENGE: /* Echo receiver's challenge numbr */ stohdr(Rxpos); zshhdr(4,ZACK,Txhdr); continue; case ZCOMMAND: /* They didn't see out ZRQINIT */ stohdr(0L); zshhdr(4,ZRQINIT,Txhdr); continue; case ZRINIT: Rxflags = 0377 & Rxhdr[ZF0]; Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); report_protocol_type("ZMODEM"); report_protocol_crc_type((Txfcs32) ? "/CRC32" : "/CRC16"); Zctlesc |= Rxflags & TESCCTL; Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); if( !(Rxflags & CANFDX)) Txwindow = 0; #if defined(MODE2OK) mode(2); /* Set cbreak,XON/XOFF,etc. */ #endif #if !defined(READCHECK) #if !defined(M_SYS5) /* Use 1024 byte frames if no sample/interrupt */ if(Rxbuflen < 32 || Rxbuflen > 1024) { Rxbuflen = 1024; } #endif #endif /* Override to force shorter frame length */ if(Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32)) Rxbuflen = Tframlen; if( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024)) Rxbuflen = Tframlen; /* If using a pipe for testing set lower buf len */ fstat(iofd,&f); if((f.st_mode & S_IFMT) != S_IFCHR && (Rxbuflen == 0 || Rxbuflen > 4096)) Rxbuflen = 4096; sprintf(s128,"Remote: CRC32 %c duplex %c", (Rxflags & CANFC32) ? 'y' : 'n', (Rxflags & CANFDX) ? 'y' : 'n'); if(Rxbuflen) sprintf(&s128[strlen(s128)]," buflen %u",Rxbuflen); else strcat(s128," continuous stream y"); report_str(s128,2); /* * If input is not a regular file,force ACK's each 1024 * (A smarter strategey could be used here ...) */ if( !Command) { fstat(fileno(in),&f); if(((f.st_mode & S_IFMT) != S_IFREG) && (Rxbuflen == 0 || Rxbuflen > 1024)) Rxbuflen = 1024; } if(Baudrate > 300) /* Set initial subpacket len */ blklen = 256; if(Baudrate > 1200) blklen = 512; if(Baudrate >= 2400) /* original code had > 2400 here ****/ blklen = 1024; if(Rxbuflen && blklen>Rxbuflen) blklen = Rxbuflen; if(blkopt && blklen > blkopt) blklen = blkopt; blklen_original = blklen; report_txblklen(blklen); return(sendzsinit()); case ZCAN: case TIMEOUT: return(ERROR); case ZRQINIT: if(Rxhdr[ZF0] == ZCOMMAND) continue; default: zshhdr(4,ZNAK,Txhdr); continue; } } return(ERROR); } /* end of getzrxinit */ /*+------------------------------------------------------------------------- sendzsinit() - send send-init information --------------------------------------------------------------------------*/ sendzsinit() { register c; if(Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL))) return(OK); errors = 0; for(;;) { stohdr(0L); if(Zctlesc) { Txhdr[ZF0] |= TESCCTL; zshhdr(4,ZSINIT,Txhdr); } else zsbhdr(4, ZSINIT, Txhdr); zsdata(Myattn,1+strlen(Myattn),ZCRCW); c = zgethdr(Rxhdr,1); switch(c) { case ZCAN: return(ERROR); case ZACK: return(OK); default: if(++errors > 19) return(ERROR); continue; } } } /* end of sendzsinit */ /*+------------------------------------------------------------------------- zsendfile(buf,blen) - send file name & info --------------------------------------------------------------------------*/ zsendfile(buf,blen) char *buf; int blen; { register c; for(;;) { blklen = blklen_original; report_txblklen(blklen); Txhdr[ZF0] = Lzconv; /* file conversion request */ Txhdr[ZF1] = Lzmanag; /* file management request */ Txhdr[ZF2] = Lztrans; /* file transport request */ Txhdr[ZF3] = 0; zsbhdr(4, ZFILE, Txhdr); zsdata(buf,blen,ZCRCW); again: c = zgethdr(Rxhdr,1); switch(c) { case ZRINIT: while((c = readline(50)) > 0) if(c == ZPAD) { goto again; } /* **** FALL THRU TO **** */ default: continue; case ZCAN: case TIMEOUT: case ZABORT: case ZFIN: return(ERROR); case ZSKIP: report_file_close(); fclose(in); return(c); case ZRPOS: /* * Suppress zcrcw request otherwise triggered by * lastyunc==bytcnt */ Lastsync = (bytcnt = Txpos = Rxpos) -1; fseek(in,Rxpos,0); Dontread = FALSE; report_send_stats(Txpos); return(zsendfdata()); } } } /* end of zsendfile */ /*+------------------------------------------------------------------------- zsendfdata() - send data in the file --------------------------------------------------------------------------*/ zsendfdata() { register c,e,n; register newcnt; register long tcount = 0; int junkcount; /* Counts garbage chars received by TX */ static int tleft = 6; /* Counter for test mode */ int err; Lrxpos = 0; junkcount = 0; SameZrposAgain = FALSE; /* variable was named Beenhereb4 (wht) */ this_file_frame_count = 0; /* we've sent no frames (wht) */ somemore: if(setjmp(intrjmp)) { waitack: junkcount = 0; c = getinsync(0); gotack: switch(c) { default: case ZCAN: report_rcvr_cancelled("zfdata-1"); report_file_close(); fclose(in); return(ERROR); case ZSKIP: report_file_close(); fclose(in); return(c); case ZACK: case ZRPOS: break; case ZRINIT: return(OK); } #if defined(READCHECK) /* * If the reverse channel can be tested for data, * this logic may be used to detect error packets * sent by the receiver,in place of setjmp/longjmp * rdchk(fdes) returns non 0 if a character is available */ while(rdchk(iofd)) { switch(readline(1)) { case CAN: case ZPAD: c = getinsync(1); goto gotack; case XOFF: /* Wait a while for an XON */ case XOFF|0200: readline(100); } } #endif } newcnt = Rxbuflen; Txwcnt = 0; stohdr(Txpos); zsbhdr(4,ZDATA,Txhdr); do { if(Dontread) { n = Lastn; } else { n = zbuf_build(txbuf,blklen); Lastread = Txpos; Lastn = n; } Dontread = FALSE; if(n < blklen) e = ZCRCE; else if(junkcount > 3) e = ZCRCW; else if(bytcnt == Lastsync) e = ZCRCW; else if(Rxbuflen && (newcnt -= n) <= 0) e = ZCRCW; else if(Txwindow && (Txwcnt += n) >= Txwspac) { Txwcnt = 0; e = ZCRCQ; } else e = ZCRCG; zsdata(txbuf,n,e); this_file_frame_count++; /* wht */ if(bad_condx_blklen) /* wht */ { /* if we have sent four frames since last ZRPOS to same pos (wht)*/ if((this_file_frame_count - bad_condx_frame_count) > 4) /*wht*/ { if(blklen == bad_condx_blklen) bad_condx_blklen = 0; else { blklen *= 2; report_txblklen(blklen); } SameZrposAgain = 0; } } bytcnt = Txpos += n; report_send_stats(Txpos); if(e == ZCRCW) goto waitack; #if defined(READCHECK) /* * If the reverse channel can be tested for data, * this logic may be used to detect error packets * sent by the receiver,in place of setjmp/longjmp * rdchk(fdes) returns non 0 if a character is available */ while(rdchk(iofd)) { switch(readline(1)) { case CAN: case ZPAD: c = getinsync(1); if(c == ZACK) break; #if defined(TCFLSH) ioctl(iofd,TCFLSH,1); #endif /* zcrce - dinna wanna starta ping-pong game */ zsdata(txbuf,0,ZCRCE); goto gotack; case XOFF: /* Wait a while for an XON */ case XOFF|0200: readline(100); default: ++junkcount; } } #endif /* READCHECK */ if(Txwindow) { while((tcount = Txpos - Lrxpos) >= Txwindow) { if(e != ZCRCQ) zsdata(txbuf,0,e = ZCRCQ); c = getinsync(1); if(c != ZACK) { #if defined(TCFLSH) ioctl(iofd,TCFLSH,1); #endif zsdata(txbuf,0,ZCRCE); goto gotack; } } } } while(n == blklen); for(;;) { stohdr(Txpos); zsbhdr(4,ZEOF,Txhdr); switch(err = getinsync(0)) { case ZACK: continue; case ZRPOS: goto somemore; case ZRINIT: return(OK); case ZSKIP: report_file_close(); fclose(in); return(c); default: sprintf(s128,"SEND protocol sync error 0x%04x: %s",err,Pathname); report_str(s128 + 5,1); skip_count++; report_error_count(); report_file_byte_io(this_file_length); report_file_close(); fclose(in); return(ERROR); } } } /* end of zsendfdata */ /*+------------------------------------------------------------------------- getinsync(flag) - get back in sync with receiver --------------------------------------------------------------------------*/ getinsync(flag) { register c; for(;;) { switch(c = zgethdr(Rxhdr,0)) { case ZCAN: case ZABORT: case ZFIN: case TIMEOUT: sprintf(s128,"Receiver %s",frametypes[c+FTOFFSET]); report_str(s128,1); return(ERROR); case ZRPOS: report_str("Receiver ZRPOS",1); /* ************************************* */ /* If sending to a modem buffer,you */ /* might send a break at this point to */ /* dump the modem's buffer. */ /* ************************************* */ if(Lastn >= 0 && Lastread == Rxpos) { Dontread = TRUE; } else { clearerr(in); /* In case file EOF seen */ fseek(in,Rxpos,0); } bytcnt = Lrxpos = Txpos = Rxpos; if(Lastsync == Rxpos) /* wht - original code */ { /* wht - original code */ /* save frame count at time of each occurrence (wht) */ bad_condx_frame_count = this_file_frame_count; /* wht */ /* save block length at time of error (wht) */ if(++SameZrposAgain > 4) /* wht - original code */ { /* wht */ if(bad_condx_blklen == 0) /* wht */ bad_condx_blklen = blklen; /* wht */ if(blklen > 256) /* wht - 32->256 */ { blklen /= 2; /* wht - original code */ report_txblklen(blklen); } } /* wht */ } /* wht - original code */ Lastsync = Rxpos; report_send_stats(Txpos); return(c); case ZACK: Lrxpos = Rxpos; if(flag || Txpos == Rxpos) return(ZACK); continue; case ZRINIT: case ZSKIP: report_file_byte_io(this_file_length); report_file_close(); fclose(in); return(c); case ERROR: default: report_str("Sending ZNAK",1); zsbhdr(4,ZNAK,Txhdr); continue; } } } /* end of getinsync */ /*+------------------------------------------------------------------------- saybibi() - Say "bibi" to the receiver, try to do it cleanly --------------------------------------------------------------------------*/ saybibi() { for(;;) { stohdr(0L); /* CAF Was zsbhdr - minor change */ zshhdr(4,ZFIN,Txhdr); /* to make debugging easier */ switch(zgethdr(Rxhdr,0)) { case ZFIN: sendline('O'); sendline('O'); flushline(); case ZCAN: case TIMEOUT: return; } } } /* end of saybibi */ /*+------------------------------------------------------------------------- determine_transaction_time() --------------------------------------------------------------------------*/ void determine_transaction_time() { register c; struct stat f; char *name; rewind_file_list(); TotalLeft = 0; Filesleft = 0; while(get_file_list_name(&name)) { f.st_size = -1; if((access(name,04) >= 0) && (stat(name,&f) >= 0)) { c = f.st_mode & S_IFMT; if(c != S_IFDIR && c != S_IFBLK) { ++Filesleft; TotalLeft += f.st_size; } } } FilesTotal = Filesleft; rewind_file_list(); } /* end of determine_transaction_time */ /* vi: set tabstop=4 shiftwidth=4: */ /* end of tipsz.c */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.