koreth@ssyx.ucsc.edu (Steven Grimm) (05/30/88)
Submitted-by: bammi@mandrill.ces.cwru.edu (Jwahar R. Bammi) Posting-number: Volume 1, Issue 44 Archive-name: zmdm/part04 #!/bin/sh # this is part 4 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file RZ.C continued # CurArch=4 if test ! -r s2_seq_.tmp then echo "Please unpack part 1 first!" exit 1; fi ( read Scheck if test "$Scheck" != $CurArch then echo "Please unpack part $Scheck next!" exit 1; else exit 0; fi ) < s2_seq_.tmp || exit 1 echo "x - Continuing file RZ.C" sed 's/^X//' << 'SHAR_EOF' >> RZ.C X fprintf(STDERR," transfer if the dest. file exists (ZMODEM ONLY)\n\n"); X X X if(fout != -1) X { X if (stfclose(fout) != 0) X { X fprintf(STDERR, "\r\nfile close ERROR\n"); X } X fout = (-1); X } X X#ifdef RDEBUG X if(logf != (FILE *)NULL) X fclose(logf); X#endif X X return(1); X} X X X/* X * Let's receive something already. X */ Xwcreceive(argc, argp) Xint argc; Xchar **argp; X{ X register int c; X X if (Batch || argc==0) X { X Crcflg=(Wcsmask==0377); X if ( !Quiet) X#ifndef REMOTE X fprintf(STDERR, "\n%s: ready (CTRL-C to cancel)\n\n", X Progname); X#else X fprintf(STDERR, "\n%s: ready\n\n", X Progname); X#endif X if (c=tryz()) X { X if (c == ZCOMPL) X return OK; X if (c == ERROR) X goto fubar; X c = rzfiles(); X if (c) X goto fubar; X } X else X { X for (;;) X { X if (wcrxpn(secbuf)== ERROR) X goto fubar; X if (secbuf[0]==0) X return OK; X if (procheader(secbuf) == ERROR) X goto fubar; X if (wcrx()==ERROR) X goto fubar; X } X } X } X else X { X Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; X X strcpy(Pathname, *argp); X#ifndef REMOTE X fprintf(STDERR, "\n%s: ready to receive %s (CTRL-C to Cancel)\n\n", X Progname, Pathname); X#else X fprintf(STDERR, "\n%s: ready to receive %s\n\n", X Progname, Pathname); X#endif X X#ifdef RDEBUG X if(logf != (FILE *)NULL) X fprintf(logf, "\nrz: ready to receive %s ", Pathname); X#endif X X if((fout = stfopen(Pathname,"w")) <= 0) X return ERROR; X if (wcrx()==ERROR) X goto fubar; X } X return OK; X Xfubar: X canit(); X X if (fout != -1) X { X if (stfclose(fout) != 0) X { X fprintf(STDERR, "\r\nfile close ERROR\n"); X } X fout = (-1); X } X X return ERROR; X} X X X/* X * Fetch a pathname from the other end as a C ctyle ASCIZ string. X * Length is indeterminate as long as less than Blklen X * A null string represents no more files (YMODEM) X */ Xwcrxpn(rpn) Xchar *rpn; /* receive a pathname */ X{ X register int c; X X PURGELINE; X Xet_tu: X Firstsec=TRUE; Eofseen=FALSE; X sendline(Crcflg?WANTCRC:NAK); X Lleft=0; /* Do read next time ... */ X while ((c = wcgetsec(rpn, 100)) != 0) X { X llog( "Pathname fetch returned %d\n", c); X if (c == WCEOT) X { X sendline(ACK); X Lleft=0; /* Do read next time ... */ X readline(1); X goto et_tu; X } X return ERROR; X } X sendline(ACK); X return OK; X} X X/* X * Adapted from CMODEM13.C, written by X * Jack M. Wierda and Roderick W. Hart X */ X Xwcrx() X{ X register int sectnum, sectcurr; X register char sendchar; X int cblklen; /* bytes to dump this block */ X X Firstsec=TRUE;sectnum=0; Eofseen=FALSE; X sendchar=Crcflg?WANTCRC:NAK; X X for (;;) X { X sendline(sendchar); /* send it now, we're ready! */ X Lleft=0; /* Do read next time ... */ X sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130); X report(sectcurr); X if (sectcurr==(sectnum+1 &Wcsmask)) X { X sectnum++; X cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; X if (putsec(secbuf, cblklen)==ERROR) X return ERROR; X if ((Bytesleft-=cblklen) < 0) X Bytesleft = 0; X sendchar=ACK; X } X else if (sectcurr==(sectnum&Wcsmask)) X { X log2( "Received dup Sector\n"); X sendchar=ACK; X } X else if (sectcurr==WCEOT) X { X if (closeit(0L)) X return ERROR; X sendline(ACK); X Lleft=0; /* Do read next time ... */ X return OK; X } X else if (sectcurr==ERROR) X return ERROR; X else X { X log2( "Sync Error\n"); X return ERROR; X } X } X} X X X/* X * Wcgetsec fetches a Ward Christensen type sector. X * Returns sector number encountered or ERROR if valid sector not received, X * or CAN CAN received X * or WCEOT if eot sector X * time is timeout for first char, set to 4 seconds thereafter X ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** X * (Caller must do that when he is good and ready to get next sector) X */ Xwcgetsec(rxbuf, maxtime) Xchar *rxbuf; Xint maxtime; X{ X register int checksum, wcj, firstch; X register unsigned int oldcrc; X register char *p; X int sectcurr; X X for (Lastrx=errors=0; errors<RETRYMAX; errors++) X { X X if ((firstch=readline(maxtime))==STX) X { X Blklen=KSIZE; goto get2; X } X if (firstch==SOH) X { X Blklen=SECSIZ; Xget2: X sectcurr=readline(1); X if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) X { X oldcrc=checksum=0; X for (p=rxbuf,wcj=Blklen; --wcj>=0; ) X { X if ((firstch=readline(1)) < 0) X goto bilge; X oldcrc=updcrc(firstch, oldcrc); X checksum += (*p++ = firstch); X } X if ((firstch=readline(1)) < 0) X goto bilge; X if (Crcflg) X { X oldcrc=updcrc(firstch, oldcrc); X if ((firstch=readline(1)) < 0) X goto bilge; X oldcrc=updcrc(firstch, oldcrc); X if (oldcrc & 0xFFFF) X llog("CRC=0%o\n", oldcrc); X else X { X Firstsec=FALSE; X return sectcurr; X } X } X else if (((checksum-firstch)&Wcsmask)==0) X { X Firstsec=FALSE; X return sectcurr; X } X else X log2( "Checksum Error\n"); X } X else X log2("Sector number garbled 0%o 0%o\n", X sectcurr, oldcrc); X } X /* make sure eot really is eot and not just mixmash */ X X else if (firstch==EOT && Lleft==0) X return WCEOT; X X else if (firstch==CAN) X { X if (Lastrx==CAN) X { X log2( "Sender CANcelled\n"); X return ERROR; X } X else X { X Lastrx=CAN; X continue; X } X } X else if (firstch==TIMEOUT) X { X if (Firstsec) X goto humbug; Xbilge: X log2( "Timeout\n"); X } X else X llog( "Got 0%o sector header\n", firstch); X Xhumbug: X Lastrx=0; X while(readline(1)!=TIMEOUT) X ; X if (Firstsec) X { X sendline(Crcflg?WANTCRC:NAK); X Lleft=0; /* Do read next time ... */ X } X else X { X maxtime=40; sendline(NAK); X Lleft=0; /* Do read next time ... */ X } X } X /* try to stop the bubble machine. */ X canit(); X return ERROR; X} X X X X X/* X * Process incoming file information header X */ Xprocheader(name) Xchar *name; X{ X register char *p; X register int dot; X char openmode[4]; X extern int strlen(); X X /* convert to ST style path names */ X for( p = name; *p != '\0'; p++) X { X if(*p == '/') X *p = '\\'; X } X X /* pick out the last extention in the filename in each part of path */ X while(p != name) X { X dot = 0; p-- ; X while((p != name) && (*p != '\\')) X { X if(*p == '.') X { X if(dot == 0) X { X dot = 1; X } X else X { X /* replace all but the last dot with '_' */ X *p = '_'; X } X } X p--; X } X } X X /* set default parameters and overrides */ X strcpy(openmode,"w"); X X Thisbinary = isbinary(name); X X if (Lzmanag) X zmanag = Lzmanag; X X /* X * Process ZMODEM remote file management requests X */ X if ( zconv == ZCNL) /* Remote ASCII override */ X Thisbinary = 0; X if (zconv == ZCBIN) /* Remote Binary override */ X ++Thisbinary; X else if (zmanag == ZMAPND) X strcpy(openmode, "a"); X X if (ForceBinary == TRUE ) /* local binary force override */ X ++Thisbinary; X X /* ZMPROT check for existing file */ X if (zmanag == ZMPROT && existf(name, "r")) X { X return ERROR; X } X X/* ATARI ST NOTE: X * We will not accept rooted paths ie. paths that begin in '\' or '.\' X * If the incoming filename is rooted, we skip the beginning X * '\' '.\' or '..\' X */ X X if( (name[0] == '\\') || (name[0] == '.') ) X { X /* skip over the leading stuff */ X if(name[0] == '\\') X name = &name[1]; X else X { X if(name[1] == '.') X name = &name[3]; /* Skip the "..\" */ X else X name = &name[2]; /* Skip the ".\" */ X } X } X X /* ST addition, create any dierctories in the path that don't exist */ X if( pathensure(name) == ERROR) X return ERROR; X X Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; X X p = name + 1 + strlen(name); X if (*p) X { /* file coming from Unix or DOS system */ X sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode); X/* NA to atari X if (Filemode & UNIXFILE) X ++Thisbinary; X*/ X#ifndef REMOTE X if (Verbose) X { X fprintf(STDERR, X "\nIncoming:\n\tName:\t%s\n\tBytes:\t%ld\n\ X\tModTime: %ld\n\tMode:\t%o\n\tBufSize: %ld\n\n", X name, Bytesleft, Modtime, Filemode, (long)BBUFSIZ); X X#ifdef RDEBUG X if(logf != (FILE *)NULL) X fprintf(logf, "Incoming: %s %ld %lo %o\n", X name, Bytesleft, Modtime, Filemode); X#endif X X } X#endif /* REMOTE */ X X } X else X { /* File coming from CP/M system */ X for (p=name; *p; ++p) /* change / to _ */ X if ( *p == '/') X *p = '_'; X X if ( *--p == '.') /* zap trailing period */ X *p = 0; X } X X strcpy(Pathname, name); X#ifndef REMOTE X if (Verbose) X { X fprintf(STDERR, "Receiving %s %s [mode %s]\n\n", X name, Thisbinary?"BIN":"ASCII", openmode); X X#ifdef RDEBUG X if(logf != (FILE *)NULL) X fprintf(logf, "Receiving %s %s %s\n", X name, Thisbinary?"BIN":"ASCII", openmode); X#endif X X } X#endif /* REMOTE */ X X if ((fout=stfopen(name, openmode)) <= 0) X return ERROR; X X return OK; X} X X/* X * Putsec writes the n characters of buf to receive file fout. X * If not in binary mode, all characters X * starting with CPMEOF are discarded. X */ Xputsec(buf, n) Xunsigned char *buf; Xregister int n; X{ X register unsigned char *p; X X if (Thisbinary) X { X for (p=buf; --n>=0; p++ ) X { X if(stputc( *p, fout) < 0) X { X fprintf(STDERR, "\r\nError while Writing file\n"); X return ERROR; X } X } X } X else X { X if (Eofseen) X return OK; X X for (p=buf; --n>=0; p++ ) X { X if (*p == CPMEOF) X { X Eofseen=TRUE; X return OK; X } X if(*p == '\n') X { X if(stputc('\r' ,fout) < 0) X { X fprintf(STDERR, "\r\nError while Writing file\n"); X return ERROR; X } X } X if(stputc(*p ,fout) < 0) X { X fprintf(STDERR,"\r\nError while Writing file\n"); X return ERROR; X } X } X } X X return OK; X} X X/* X * Log an error only if high verbose X */ X/*VARARGS1*/ Xllog(s,p,u) Xchar *s; Xint p, u; X{ X if (Verbose < 3) X return; X#ifdef RDEBUG X fprintf(logf, "error %d: ", errors); X fprintf(logf, s, p, u); X#endif X X fprintf(STDERR, "\nerror %d: ", errors); X fprintf(STDERR, s, p, u); X} X X X X#ifndef STANDALONE X/* X * If called as rb use YMODEM protocol X */ Xchkinvok(s) Xchar *s; X{ X Progname = s; X if (s[0]=='r' && s[1]=='b') X Nozmodem = TRUE; X} X#endif X X/* X * Initialize for Zmodem receive attempt, try to activate Zmodem sender X * Handles ZSINIT frame X * Return ZFILE if Zmodem filename received, -1 on error, X * ZCOMPL if transaction finished, else 0 X */ Xtryz() X{ X register int n; X register int cmdzack1flg; X X if (Nozmodem) /* Check for "rb" program name */ X return 0; X X X for (n=Zmodem?10:5; --n>=0; ) X { X /* Set buffer length (0) and capability flags */ X stohdr(0L); X Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; /* of course we can break */ X X zshhdr(tryzhdrtype, Txhdr); X/* zshhdr(Badclose?ZFERR:ZRINIT, Txhdr); */ Xagain: X switch (zgethdr(Rxhdr, 0)) X { X case ZRQINIT: X continue; X case ZEOF: X continue; X case TIMEOUT: X continue; X case ZFILE: X zconv = Rxhdr[ZF0]; X zmanag = Rxhdr[ZF1]; X ztrans = Rxhdr[ZF2]; X tryzhdrtype = ZRINIT; X Badclose = FALSE; X if (zrdata(secbuf, KSIZE) == GOTCRCW) X return ZFILE; X zshhdr(ZNAK, Txhdr); X goto again; X case ZSINIT: X if (zrdata(Attn, ZATTNLEN) == GOTCRCW) X { X zshhdr(ZACK, Txhdr); X goto again; X } X zshhdr(ZNAK, Txhdr); X goto again; X case ZFREECNT: X stohdr(~0L); X zshhdr(ZACK, Txhdr); X goto again; X case ZCOMMAND: X cmdzack1flg = Rxhdr[ZF0]; X if (zrdata(secbuf, KSIZE) == GOTCRCW) X { X if (cmdzack1flg & ZCACK1) X stohdr(0L); X else X stohdr((long)sys2(secbuf)); X PURGELINE; /* dump impatient questions */ X do { X zshhdr(ZCOMPL, Txhdr); X } X while (++errors<10 && zgethdr(Rxhdr,1) != ZFIN); X ackbibi(); X if (cmdzack1flg & ZCACK1) X exec2(secbuf); X return ZCOMPL; X } X zshhdr(ZNAK, Txhdr); goto again; X case ZCOMPL: X goto again; X default: X continue; X case ZFIN: X ackbibi(); return ZCOMPL; X case ZCAN: X return ERROR; X } X } X return 0; X} X X/* X * Receive 1 or more files with ZMODEM protocol X */ Xrzfiles() X{ X register int c; X X for (;;) { X switch (c = rzfile()) { X case ZEOF: X case ZSKIP: X switch (tryz()) { X case ZCOMPL: X return OK; X default: X return ERROR; X case ZFILE: X break; X } X continue; X default: X return c; X case ERROR: X return ERROR; X } X } X} X X/* X * Receive a file with ZMODEM protocol X * Assumes file name frame is in secbuf X */ Xrzfile() X{ X register int c, n; X long rxbytes; X extern void rd_time(); X X Eofseen=FALSE; X if (procheader(secbuf) == ERROR) { X return (tryzhdrtype = ZSKIP); X/* zshhdr(ZSKIP, Txhdr); X return ZSKIP; */ X } X X n = 10; rxbytes = 0L; X X Supexec(rd_time); X start_time = pr_time; X X for (;;) X { X stohdr(rxbytes); X zshhdr(ZRPOS, Txhdr); Xnxthdr: X switch (c = zgethdr(Rxhdr, 0)) { X default: X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X case ZNAK: X case TIMEOUT: X if ( --n < 0) X { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X case ZFILE: X zrdata(secbuf, KSIZE); X continue; X case ZEOF: X /* ++jrb */ X if (rclhdr(Rxhdr) != rxbytes) X { X /* X * Ignore eof if it's at wrong place - force X * a timeout because the eof might have gone X * out before we sent our zrpos. X */ X X errors = 0; goto nxthdr; X } X/* --jrb X if (rclhdr(Rxhdr) != rxbytes) X { X continue; X } X-- */ X if (closeit(rxbytes)) X { X tryzhdrtype = ZFERR; X Badclose = TRUE; X vfile("rzfile: closeit returned <> 0"); X return ERROR; X } X vfile("rzfile: normal EOF"); X return c; X case ERROR: /* Too much garbage in header search error */ X if ( --n < 0) X { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case ZDATA: X n = 10; X if (rclhdr(Rxhdr) != rxbytes) X { X zmputs(Attn); X continue; X } Xmoredata: X switch (c = zrdata(secbuf, KSIZE)) X { X case ZCAN: X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X case ERROR: /* CRC error */ X if ( --n < 0) X { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case TIMEOUT: X if ( --n < 0) X { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X continue; X case GOTCRCW: X if(putsec(secbuf, Rxcount) == ERROR) X return ERROR; X rxbytes += Rxcount; X lreport(rxbytes); X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X goto nxthdr; X case GOTCRCQ: X if(putsec(secbuf, Rxcount) == ERROR) X return ERROR; X rxbytes += Rxcount; X lreport(rxbytes); X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X goto moredata; X case GOTCRCG: X if(putsec(secbuf, Rxcount) == ERROR) X return ERROR; X rxbytes += Rxcount; X lreport(rxbytes); X goto moredata; X case GOTCRCE: X if(putsec(secbuf, Rxcount) == ERROR) X return ERROR; X rxbytes += Rxcount; X lreport(rxbytes); X goto nxthdr; X } X } X } X} X X/* X * Send a string to the modem, processing for \336 (sleep 1 sec) X * and \335 (break signal) X */ Xzmputs(s) Xchar *s; X{ X register int c; X X while (*s) { X switch (c = *s++) { X case '\336': X stsleep(1); continue; X case '\335': X sendbrk(); continue; X default: X sendline(c); X } X } X} X X X X/* X * Close the receive dataset, return OK or ERROR X */ Xcloseit(rxbytes) Xlong rxbytes; X{ X unsigned int timep[2]; X long end_time; X extern void rd_time(); X X if (stfclose(fout) != 0) { X fprintf(STDERR, "\r\nfile close ERROR\n"); X return ERROR; X } X fout = (-1); X X Supexec(rd_time); X end_time = pr_time; X X if (Modtime) { X unix2st(Modtime, &timep[0], &timep[1]); X touch(Pathname, timep); X } X X /* if it is read only by owner on remote, then it is set X * to read only on the ST, all other file modes are X * irrelevant. X */ X if (Filemode) X { X unsigned int fmode; X X fmode = (unsigned int)(Filemode & 000777); X if( ((fmode & 0200) == 0) && ((fmode & 0400) != 0) ) X { X /* it is readonly by owner on the remote, so X * make it read only on the ST too X */ X Fattrib(Pathname, 1, 0x01); X } X } X#ifndef REMOTE X if(rxbytes != 0L) X fprintf(STDERR,"\n\n%s Closed\nTransfer Time %ld secs.\tfor %ld bytes\ X\tApprox %ld cps\n\n", Pathname, (end_time - start_time)/200L, rxbytes, Xrxbytes/((end_time - start_time)/200L)); X else X fprintf(STDERR,"\n\n%s Closed\n\n", Pathname); X#endif X lsct = 1; X return OK; X} X X/* X * Ack a ZFIN packet, let byegones be byegones X */ Xackbibi() X{ X register int n; X X vfile("ackbibi:"); X Readnum = 1; X stohdr(0L); X for (n=4; --n>=0; ) X { X zshhdr(ZFIN, Txhdr); X for (;;) { X switch (readline(100)) X { X case 'O': X readline(1); /* Discard 2nd 'O' */ X /* ***** FALL THRU TO ***** */ X case TIMEOUT: X vfile("ackbibi complete"); X return; X default: X break; X } X } X } X} X X X/* X * Strip leading ! if present, do shell escape. X */ Xsys2(s) Xregister char *s; X{ X if (*s == '!') X ++s; X return stsystem(s); X} X/* X * Strip leading ! if present, do exec. X */ Xexec2(s) Xchar *s; X{ X/** Are you kidding X if (*s == '!') X ++s; X mode(0); X execl("/bin/sh", "sh", "-c", s); X**/ X} X X/* X * Touch a file X */ X#ifndef MANX X#undef Fdatime /* There exist brain damaged versions of osbind.h */ X#define Fdatime(a,b,c) gemdos(0x57,a,b,c) X#endif /* MANX has its _Gemdos stuff */ X Xtouch(name, timep) Xchar *name; Xunsigned int *timep; X{ X register int handl; X X if((handl = Fopen(name, 0)) < 0) X { X#ifndef REMOTE X fprintf(STDERR,"*WARNING* Could not set file modification time for %s\n", X name); X#endif X return; X } X X X Fdatime(timep, handl, 1); X Fclose(handl); X} X X/* -eof- */ SHAR_EOF echo "File RZ.C is complete" chmod 0600 RZ.C || echo "restore of RZ.C fails" echo "x - extracting RZLNK (Text)" sed 's/^X//' << 'SHAR_EOF' > RZLNK && Xc:\lib\gemstart.o common.o rz.o util.o tyme.o zm.o fileio.o Xc:\lib\osbind.o c:\lib\gemlib c:\lib\libf SHAR_EOF chmod 0600 RZLNK || echo "restore of RZLNK fails" echo "x - extracting SZ.C (Text)" sed 's/^X//' << 'SHAR_EOF' > SZ.C && X/* X * ACKNOWLEDGEMENTS X * X * ZMDM was derived from rz/sz for Unix posted by X * Chuck Forsberg (...!tektronix!reed!omen!caf ). We X * thank him for his excellent code, and for giving X * us permission to use and distribute his code and X * documentation. X * X * Atari St version by: X * Jwahar Bammi X * usenet: mandrill!bammi@{decvax,sun}.UUCP X * csnet: bammi@mandrill.ces.CWRU.edu X * arpa: bammi@mandrill.ces.CWRU.edu X * CompuServe: 71515,155 X */ X X#include "config.h" X#define SVERSION "sz 1.23 01-15-87" X#define SSTVERSION "sz 1.01 03-07-87" X#define OS "Unix V7/BSD" X X#ifndef STANDALONE X#define RETURN return X#else Xint bibi() {} /* dummy */ X#endif X X/* #define SDEBUG */ X X/* X * sz.c By Chuck Forsberg X * X * cc -O sz.c -o sz USG (SYS III/V) Unix X * cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD X * X * define CRCTABLE to use table driven CRC X * X * ******* Some systems (Venix, Coherent, Regulus) do not ******* X * ******* support tty raw mode read(2) identically to ******* X * ******* Unix. ONEREAD must be defined to force one ******* X * ******* character reads for these systems. ******* X * X * A program for Unix to send files and commands to computers running X * Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM. X * X * Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM. X * X * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin X * X * St v 1.01 X * added support for 32 bit CRC's (Zmodem) ++jrb X * X */ X X#include "zmdm.h" X#include "common.h" X#include "zmodem.h" X X#ifndef Vsync /* Atari forgot these in osbind.h */ X#define Vsync() xbios(37) X#endif X X#ifndef Supexec X /* Some versions of osbind don't define Supexec */ X#define Supexec(X) xbios(38,X) X#endif X X#define SLOGFILE "szlog" X X#define purgeline() while(Bconstat(1)) Bconin(1) X#define S_IFDIR 0x0010 X X/* X * Attention string to be executed by receiver to interrupt streaming data X * when an error is detected. A pause (0336) may be needed before the X * ^C (03) or after it. X */ X#ifdef READCHECK Xchar Myattn[] = { 0 }; X#else X#ifdef USG Xchar Myattn[] = { 03, 0336, 0 }; X#else Xchar Myattn[] = { 0 }; X#endif X#endif X X#if (MWC || MANX) XFILE *fopen(); X#else XFILE *fopen(), *fopenb(); X#endif Xstatic unsigned long SaveIntr; Xstatic int Resuming, ForceBin; Xstatic int in; X X/* called by signal interrupt or terminate to clean things up */ Xbibis(n) Xint n; X{ X canit(); flush_modem(); mode(0); X fprintf(STDERR, "\r\nsz: caught signal %d; exiting\n", n); X X aexit(128+n); X} X X/* Called when Zmodem gets an interrupt (^X) */ X#ifdef ONINTR Xonintr() X{ X siggi = 0; X longjmp(intrjmp, -1); X} X#endif X X#define ZKER Xint Zctlesc; /* Encode control characters */ X X#ifdef STANDALONE Xint main(argc, argv) X#else Xint dosz(argc, argv) X#endif Xint argc; Xchar **argv; X{ X register char *cp; X register int npats; X int agcnt; char **agcv; X char **patts; X X#ifdef STANDALONE X#ifdef MWC X extern char *lmalloc(); X#endif X X /* Set up Dta */ X Fsetdta(&statbuf); X X /* Get screen rez */ X rez = Getrez(); X drv_map = Drvmap(); X X#if (MWC || MANX) X#ifndef DYNABUF X#ifdef MWC X if((bufr = (unsigned char *)lmalloc((unsigned long)BBUFSIZ)) X == (unsigned char *)NULL) X#else X if((bufr = (unsigned char *)Malloc((unsigned long)BBUFSIZ)) X == (unsigned char *)NULL) X#endif X#else X if((bufr = dalloc()) == (unsigned char *)NULL) X#endif /* DYNABUF */ X { X#ifdef REMOTE X Bauxws("Sorry, could not allocate enough memory\r\n"); X#else X Bconws("Sorry, could not allocate enough memory\r\n"); X#endif X X Pterm(4); X } X#else /* MWC || MANX */ X#ifdef DYNABUF X if((bufr = dalloc()) == (unsigned char *)NULL) X { X#ifdef REMOTE X Bauxws("Sorry, could not allocate enough memory\r\n"); X#else X Bconws("Sorry, could not allocate enough memory\r\n"); X#endif X Pterm(5); X } X#endif /* DYNABUF */ X#endif /* MWC || MANX */ X X#ifndef REMOTE X STDERR = stderr; X#else X#ifndef DLIBS X if((STDERR = fopen("aux:", "rw")) == (FILE *)NULL) X { X Bauxws("Could not Open Aux Stream for Stderr\r\n"); X finish(); X } X setbuf(STDERR, (char *)NULL); X#else X STDERR = stdaux; X#endif /* DLIBS */ X X#endif /* REMOTE */ X { X int speed; X speed = getbaud(); X Baudrate = BAUD_RATE(speed); X SetIoBuf(); X Rsconf(speed, 0,-1,-1,-1,-1); X Vsync(); Vsync(); X } X#endif /* STANDALONE */ X X SendType = 1; X Rxtimeout = 600; X npats=0; X if (argc<2) X { X susage(); X RETURN(1); X } X X initz(); X#ifndef STANDALONE X schkinvok(argv[0]); X#else X Progname = "sz"; X#endif X X SaveIntr = Setexc(0x0102, -1L); X BusErr = Setexc(2, -1L); X AddrErr = Setexc(3, -1L); X X Verbose = 0; X Resuming = FALSE; X ForceBin = FALSE; X in = (-1); X vdebug = 0; X X#ifdef SDEBUG X logf = (FILE *)NULL; X#endif X while (--argc) { X cp = *++argv; X if (*cp++ == '-' && *cp) { X while ( *cp) { X switch(*cp++) { X case '+': X Lzmanag = ZMAPND; break; X#ifdef CSTOPB X case '2': X Twostop = TRUE; break; X#endif X case '7': X Wcsmask=0177; break; X X/* X On the St we look up the ext and decide. For Xmodem X transfers, the file is always sent in binary mode X and it is the responsibility of the receiver to X strip CR if so desired. X case 'a': X Lzconv = ZCNL; X Ascii = TRUE; break; X case 'b': X Lzconv = ZCBIN; break; X*/ X X/* ST extention, force binary, useful to back up every thing X * in image mode, see -B option of rz too +jrb X */ X case 'B': X ForceBin = TRUE; X Lzconv = ZCBIN; X break; X case 'C': X if (--argc < 1) { X susage(); X RETURN(1); X } X Cmdtries = atoi(*++argv); X break; X case 'i': X Cmdack1 = ZCACK1; X /* **** FALL THROUGH TO **** */ X case 'c': X if (--argc != 1) { X susage(); X RETURN(1); X } X Command = TRUE; X Cmdstr = *++argv; X break; X case 'd': X ++Dottoslash; X /* **** FALL THROUGH TO **** */ X case 'f': X Fullname=TRUE; break; X case 'E': X Zctlesc = (-1); break; X case 'e': X Zctlesc = 1; break; X case 'k': X Blklen=KSIZE; break; X case 'L': X if (--argc < 1) { X susage(); X RETURN(1); X } X blkopt = atoi(*++argv); X if (blkopt<32 || blkopt>1024) X { X susage(); X RETURN(1); X } X break; X case 'l': X if (--argc < 1) { X susage(); X RETURN(1); X } X Tframlen = atoi(*++argv); X if (Tframlen<32 || Tframlen>1024) X { X susage(); X RETURN(1); X } X break; X case 'N': X Lzmanag = ZMDIFF; break; X case 'n': X Lzmanag = ZMNEW; break; X case 'o': X Wantfcs32 = FALSE; break; X case 'p': X Lzmanag = ZMPROT; break; X case 'r': X Lzconv = ZCRESUM; Resuming = TRUE; break; X case 'q': X Quiet=TRUE; Verbose=0; break; X case 't': X if (--argc < 1) { X susage(); X RETURN(1); X } X Rxtimeout = atoi(*++argv); X if (Rxtimeout<10 || Rxtimeout>1000) X { X susage(); X RETURN(1); X } X break; X#ifdef TESTATTN X case 'T': X Testattn = TRUE; break; X#endif X case 'u': X ++Unlinkafter; break; X case 'v': X ++Verbose; break; X case 'X': X ++Modem; break; X case 'y': X Lzmanag = ZMCLOB; break; X default: X susage(); X RETURN(1); X } X } X } X else if ( !npats && argc>0) { X if (argv[0][0]) { X npats=argc; X patts=argv; X } X } X } X if (npats < 1 && !Command) X { X susage(); X RETURN(1); X } X X#ifdef SDEBUG X if (Verbose > 2) X { X if ((logf = fopen(SLOGFILE, "a"))== (FILE *)NULL) X { X fprintf(STDERR, "Can't open log file %s\n",SLOGFILE); X RETURN(0200); X } X fprintf(logf, "Progname=%s\n", Progname); X vdebug = 1; X fflush(logf); X } X#endif X X if ( !Quiet) X { X if (Verbose < 2) X Verbose = 2; X } X X X Setexc(0x0102, bibis); X Setexc(2, buserr); X Setexc(3, addrerr); X X if(setjmp(busjmp)) X { X /* On a bus error - instead of 2 bombs */ X fprintf(STDERR,"\r\nFATAL: Bus Error\n\n"); X#ifdef SDEBUG X if(logf != (FILE *)NULL) X fclose(logf); X#endif X if(in != -1) X { X stfclose(in); X in = (-1); X } X canit(); X Setexc(2, BusErr); X Setexc(3, AddrErr); X Setexc(0x0102, SaveIntr); X RETURN(2); X } X X if(setjmp(addrjmp)) X { X /* On address error - instead of 3 bombs */ X fprintf(STDERR,"\r\nFATAL: Address Error\n\n"); X#ifdef SDEBUG X if(logf != (FILE *)NULL) X fclose(logf); X#endif X if(in != -1) X { X stfclose(in); X in = (-1); X } X canit(); X Setexc(2, BusErr); X Setexc(3, AddrErr); X Setexc(0x0102, SaveIntr); X RETURN(3); X } X X if((Exitcode = setjmp(abrtjmp))) X { X fprintf(STDERR,"\nTransfer ABORT\n\n"); X#ifdef SDEBUG X if(logf != (FILE *)NULL) X fclose(logf); X#endif X if(in != -1) X { X stfclose(in); X in = (-1); X } X Setexc(2, BusErr); X Setexc(3, AddrErr); X Setexc(0x0102, SaveIntr); X RETURN(Exitcode); X } X X mode(1); X X X if ( !Modem) { X if (!Command && !Quiet && Verbose != 1) X { X fprintf(STDERR, "sz: %d file%s requested:\n", X npats, npats>1?"s":""); X for ( agcnt=npats, agcv=patts; --agcnt>=0; ) X { X fprintf(STDERR, "%s ", *agcv++); X } X fprintf(STDERR, "\n\n"); X X#ifdef SDEBUG X if(Verbose > 2) X { X fprintf(logf, "sz: %d file%s requested:\n", X npats, npats>1?"s":""); X for ( agcnt=npats, agcv=patts; --agcnt>=0; ) X { X fprintf(logf, "%s ", *agcv++); X } X fprintf(logf, "\n"); X fflush(logf); X } X#endif X } X if (!Nozmodem) { X stohdr(0L); X if (Command) X Txhdr[ZF0] = ZCOMMAND; X zshhdr(ZRQINIT, Txhdr); X } X } X flush_modem(); X X if (Command) { X if (getzrxinit()) { X Exitcode=0200; canit(); X } X else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) { X Exitcode=0200; canit(); X } X } else if (wcsend(npats, patts)==ERROR) { X Exitcode=0200; X canit(); X } X flush_modem(); X mode(0); X X#ifdef SDEBUG X if(logf != (FILE *)NULL) X fclose(logf); X#endif X if(in != -1) X { X fclose(in); X in = (-1); X } X X putc('\n', STDERR); X Setexc(2, BusErr); X Setexc(3, AddrErr); X Setexc(0x0102, SaveIntr); X RETURN((errcnt != 0) | Exitcode); X X} X X#ifdef STANDALONE XRETURN(n) Xint n; X{ X ResetIoBuf(); X#if (MWC || MANX) X#ifndef DYNABUF X free(bufr); X#else X Mfree(bufr); X#endif X#else X#ifdef DYNABUF X Mfree(bufr); X#endif X#endif X exit(n); X} X#endif /* STANDALONE */ X Xwcsend(argc, argp) Xchar *argp[]; X{ X register int n; X X Crcflg=FALSE; X Firstsec=TRUE; X for (n=0; n<argc; ++n) { X Totsecs = 0; X if (wcs(argp[n])==ERROR) X return ERROR; X } X Totsecs = 0; X if (Filcnt==0) { /* bitch if we couldn't open ANY files */ X if (1) { X Command = TRUE; X Cmdstr = "echo \"sz: Can't open any requested files\""; X if (getzrxinit()) { X Exitcode=0200; canit(); X } X else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) { X Exitcode=0200; canit(); X } X Exitcode = 1; return OK; X } X canit(); X fprintf(STDERR,"\n\nCan't open any requested files.\n\n"); X return ERROR; X } X if (Zmodem) X saybibi(); X else X wctxpn(""); X return OK; X} X Xwcs(oname) Xchar *oname; X{ X extern struct stat statbuf; X char name[PATHLEN]; X X strcpy(name, oname); X ++Noeofseen; Lastread = 0; Lastc = (-1); Dontread = FALSE; X X /* Check for directory or block special files */ X if(Fsfirst(name,(int)(0x01 | 0x010 | 0x020)) != 0) X { X ++errcnt; X return OK; /* may be others */ X } X X if (statbuf.st_mode & S_IFDIR ) { X return OK; X } X X if((in = stfopen(oname,"r")) <= 0){ X ++errcnt; X return OK; /* pass over it, there may be others */ X } X X ++Filcnt; X switch (wctxpn(name)) { X case ERROR: X return ERROR; X case ZSKIP: X return OK; X } X if (!Zmodem && wctx()==ERROR) X return ERROR; X if (Unlinkafter) X unlink(oname); X return 0; X} X X#define ISDRIVE(X) ( (((X >= 'a') && (X <= 'n'))) || ((X >= 'A') && (X <= 'N'))) X/* X * generate and transmit pathname block consisting of X * pathname (null terminated), X * file length, mode time and file mode in octal X * as provided by the St's Fsfirst() call. X * N.B.: modifies the passed name, may extend it! X */ Xwctxpn(name) Xchar *name; X{ X register char *p, *q; X char name2[PATHLEN]; X unsigned long unixtime; X extern struct stat statbuf; X extern unsigned long st2unix(); /* Convert St's date and time to unix X time (seconds since Jan 1 1970 00:00:00) */ X X if(*name) X if(Fsfirst(name,(int)(0x01 | 0x020)) != 0) X return ERROR; X X if (Modem) { X#ifndef REMOTE X if (*name) { X fprintf(STDERR, X "Outgoing:\n\t Name: %s\n\t Size: %ld Bytes\n\ X\tBlocks: %ld\n\tBufSize: %ld\n\n", X name, statbuf.st_size, statbuf.st_size>>7, (long)BBUFSIZ); X } X#endif /* REMOTE */ X return OK; X } X X vfile2("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>"); X X if ( !Zmodem) X if (getnak()) X return ERROR; X X /* convert to Unix style path names */ X /* skip any device identifier */ X if(ISDRIVE(name[0]) && (name[1] == ':')) X name = &name[2]; X X for(p = name; *p != '\0'; p++) X { X if(*p == '\\') X *p = '/'; X } X X if(!Resuming) X { X if(ForceBin) X { X Lzconv = ZCBIN; X Ascii = FALSE; X } X else X { X if(!isbinary(name)) X { X /* We indicate to the other side */ X Lzconv = ZCNL; X Ascii = TRUE; X } X else X { X Lzconv = ZCBIN; X Ascii = FALSE; X } X } X } X X q = (char *) 0; X if (Dottoslash) { /* change . to . */ X for (p=name; *p; ++p) { X if (*p == '/') X q = p; X else if (*p == '.') X *(q=p) = '/'; X } X if (q && strlen(++q) > 8) { /* If name>8 chars */ X q += 8; /* make it .ext */ X strcpy(name2, q); /* save excess of name */ X *q = '.'; X strcpy(++q, name2); /* add it back */ X } X } X X for (p=name, q=secbuf ; *p; ) X if ((*q++ = *p++) == '/' && !Fullname) X q = secbuf; X *q++ = 0; X p=q; X while (q < (secbuf + KSIZE)) X *q++ = 0; X if (*name) X { X unixtime = st2unix(statbuf.st_time, statbuf.st_date); X sprintf(p, "%lu %lo %o", statbuf.st_size, X unixtime, X ((statbuf.st_mode & 0x01)?0444:0644)); X } X X if(Verbose) X#ifndef REMOTE X fprintf(STDERR, X"Outgoing: [Hit CTRL-C to Cancel]\n\tName: %s\n\tSize: %ld Bytes\n\tBufSize:\ X %ld\n", X name, statbuf.st_size, (long)BBUFSIZ); X if(!Resuming) X { X fprintf(STDERR,"\tMode: %s\n\n", (Ascii)?"ASCII":"BINARY"); X } X else X { X fprintf(STDERR,"\tMode: Resume Transfer Mode\n\n"); X } X#endif X X#ifdef SDEBUG X if(Verbose > 2) X { X fprintf(STDERR,"File: %s (%s)\n", name, p); X fprintf(logf,"File: %s (%s)\n", name, p); X fflush(logf); X } X#endif X X /* force 1k blocks if name won't fit in 128 byte block */ X if (secbuf[125]) X Blklen=KSIZE; X else { /* A little goodie for IMP/KMD */ X if (Zmodem) X Blklen = SECSIZ; X secbuf[127] = (statbuf.st_size + 127) >>7; X secbuf[126] = (statbuf.st_size + 127) >>15; X } X if (Zmodem) X return zsendfile(secbuf, (int)(1+strlen(p)+ X (int)((long)p-(long)secbuf)), statbuf.st_size); X if (wcputsec(secbuf, 0, SECSIZ)==ERROR) X return ERROR; X return OK; X} X Xgetnak() X{ X register int firstch; X X Lastrx = 0; X for (;;) { X switch (firstch = readock(800,1)) { X case ZPAD: X if (getzrxinit()) X return ERROR; X Ascii = 0; X return FALSE; X case TIMEOUT: X vfile("Timeout on pathname\n"); X return TRUE; X case WANTG: X#ifdef USG X mode(2); /* Set cbreak, XON/XOFF, etc. */ X#endif X Optiong = TRUE; X Blklen=KSIZE; X case WANTCRC: X Crcflg = TRUE; X case NAK: X return FALSE; X case CAN: X if ((firstch = readock(20,1)) == CAN && Lastrx == CAN) X return TRUE; X default: X break; X } X Lastrx = firstch; X } X} X X Xwctx() X{ X register int sectnum, attempts, firstch; X X Firstsec=TRUE; X X while ((firstch=readock(Rxtimeout, 2))!=NAK && firstch != WANTCRC X && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN) X ; X if (firstch==CAN) { X fprintf(STDERR, "\r\nReceiver CANcelled\n"); X return ERROR; X } X if (firstch==WANTCRC) X Crcflg=TRUE; X if (firstch==WANTG) X Crcflg=TRUE; X sectnum=1; X while (filbuf(secbuf, Blklen)) { X if (wcputsec(secbuf, sectnum, Blklen)==ERROR) { X return ERROR; X } else X sectnum++; X } X X#ifndef REMOTE X if (Verbose>1) X { X fprintf(STDERR, "\nClosing\n\n"); X#ifdef SDEBUG X if(Verbose > 2) X { X fprintf(logf, " Closing\n"); X fflush(logf); X } X#endif X } X#endif /* REMOTE */ X X stfclose(in); X in = (-1); X X attempts=0; X do { X vfile(" EOT "); X purgeline(); X sendline(EOT); X flush_modem(); X ++attempts; X } X while ((firstch=(readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX); X if (attempts == RETRYMAX) { X fprintf(STDERR, "\r\nNo ACK on EOT\n"); X return ERROR; X } X else X return OK; X} X Xwcputsec(buf, sectnum, cseclen) Xchar *buf; Xint sectnum; Xint cseclen; /* data length of this sector to send */ X{ X register int checksum, wcj; X register char *cp; X unsigned int oldcrc; X int firstch; X int attempts; X X firstch=0; /* part of logic to detect CAN CAN */ X X#ifndef REMOTE X if (Verbose>1) X { X fprintf(STDERR, "\rBlock %06d %04dK ", Totsecs, (Totsecs>>3)); X#ifdef SDEBUG X if(Verbose > 2) X { X fprintf(logf, "\rBlock %d %dK ", Totsecs, (Totsecs>>3) ); X fflush(logf); X } X#endif X } X#endif /* REMOTE */ X X for (attempts=0; attempts <= RETRYMAX; attempts++) { X Lastrx= firstch; X sendline(cseclen==KSIZE?STX:SOH); X sendline(sectnum); X sendline(-sectnum -1); X oldcrc=checksum=0; X for (wcj=cseclen,cp=buf; --wcj>=0; ) { X sendline(*cp); X oldcrc=updcrc((0377& *cp), oldcrc); X checksum += *cp++; X } X if (Crcflg) { X oldcrc=updcrc(0,updcrc(0,oldcrc)); X sendline((int)oldcrc>>8); X sendline((int)oldcrc); X } X else X sendline(checksum); X X if (Optiong) { X Firstsec = FALSE; return OK; X } X firstch = readock(Rxtimeout, (Noeofseen&§num) ? 2:1); Xgotnak: X switch (firstch) { X case CAN: X if(Lastrx == CAN) { Xcancan: X fprintf(STDERR, "\r\nCancelled\n"); return ERROR; X } X break; X case TIMEOUT: X vfile("Timeout on sector ACK\n"); continue; X case WANTCRC: X if (Firstsec) X Crcflg = TRUE; X case NAK: X vfile("NAK on sector\n"); continue; X case ACK: X Firstsec=FALSE; X Totsecs += (cseclen>>7); X return OK; X case ERROR: X vfile("Got burst for sector ACK\n"); break; X default: X vfile("Got %02x for sector ACK\n", firstch); break; X } X for (;;) { X Lastrx = firstch; X if ((firstch = readock(Rxtimeout, 2)) == TIMEOUT) X break; X if (firstch == NAK || firstch == WANTCRC) X goto gotnak; X if (firstch == CAN && Lastrx == CAN) X goto cancan; X } X } X fprintf(STDERR, "\r\nRetry Count Exceeded\n"); X return ERROR; X} X X/* fill buf with count chars padding with ^Z for CPM */ Xfilbuf(buf, count) Xregister unsigned char *buf; Xregister int count; X{ X register int m; X X if((buf[0] = stgetc(in)) == EOF) X return 0; X X for(m = 1; (m < count) && ((buf[m] = stgetc(in)) != EOF); m++) X /* loop */ ; X X while (m < count) X buf[m++] = 032; X X return count; X X} X/* fill buf with count chars */ Xzfilbuf(buf, count) Xregister char *buf; X{ X register int c, m; X X m=count; X while ((c=stgetc(in))!=EOF) { X *buf++ =c; X if (--m == 0) X break; X } X return (count - m); X} X X/* X * readock(timeout, count) reads character(s) from file descriptor 0 X * (1 <= count <= 3) X * it attempts to read count characters. If it gets more than one, X * it is an error unless all are CAN X * (otherwise, only normal response is ACK, CAN, or C) X * Only looks for one if Optiong, which signifies cbreak, not raw input X * X * timeout is in tenths of seconds X */ Xreadock(timeout, count) Xint timeout, count; X{ X register int c; X static char byt[5]; X X if (Optiong) X count = 1; /* Special hack for cbreak */ X X if (setjmp(tohere)) { X vfile("TIMEOUT\n"); X return TIMEOUT; X } X c = timeout >> 3; X if (c<2) X c=2; X#ifdef SDEBUG X if (Verbose>3) { X fprintf(STDERR, "Timeout=%d Calling alarm(%d) ", timeout, c); X byt[1] = 0; X fprintf(logf, "Timeout=%d Calling alarm(%d) ", timeout, c); SHAR_EOF echo "End of part 4" echo "File SZ.C is continued in part 5" echo "5" > s2_seq_.tmp exit 0