koreth@ssyx.ucsc.edu (Steven Grimm) (05/28/88)
Submitted-by: bammi@mandrill.ces.cwru.edu (Jwahar R. Bammi) Posting-number: Volume 1, Issue 39 Archive-name: rzsz/part04 #!/bin/sh # this is part 4 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file sz.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 sed 's/^X//' << 'SHAR_EOF' >> sz.c Xchar Lzconv; /* Local ZMODEM file conversion request */ Xchar Lzmanag; /* Local ZMODEM file management request */ Xchar Lztrans; Xchar zconv; /* ZMODEM file conversion request */ Xchar zmanag; /* ZMODEM file management request */ Xchar ztrans; /* ZMODEM file transport request */ Xint Command; /* Send a command, then exit. */ Xchar *Cmdstr; /* Pointer to the command string */ Xint Cmdtries = 11; Xint Cmdack1; /* Rx ACKs command, then do it */ Xint Exitcode; Xint Testattn; /* Force receiver to send Attn, etc with qbf. */ Xchar *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n"; Xlong Lastread; /* Beginning offset of last buffer read */ Xint Lastc; /* Count of last buffer read or -1 */ Xint Dontread; /* Don't read the buffer, it's still there */ X Xjmp_buf tohere; /* For the interrupt on RX timeout */ Xjmp_buf intrjmp; /* For the interrupt on RX CAN */ X X/* called by signal interrupt or terminate to clean things up */ Xbibi(n) X{ X canit(); fflush(stdout); mode(0); X fprintf(stderr, "sz: caught signal %d; exiting\n", n); X if (n == SIGQUIT) X abort(); X exit(128+n); X} X/* Called when Zmodem gets an interrupt (^X) */ Xonintr() X{ X signal(SIGINT, SIG_IGN); X longjmp(intrjmp, -1); X} X X X#define sendline(c) putchar(c & Wcsmask) X X#define xsendline(c) putchar(c) X Xflushmo() X{ X fflush(stdout); X} X X#define ZKER Xint Zctlesc; /* Encode control characters */ Xint Nozmodem = 0; /* If invoked as "sb" */ Xchar *Progname = "sz"; X#include "zm.c" X X X#ifdef CASE XMAIN(argc, argv) X#else Xmain(argc, argv) X#endif Xint argc; Xchar **argv; X{ X register char *cp; X register npats; X int agcnt; char **agcv; X char **patts; X static char xXbuf[BUFSIZ]; X X if ((cp = getenv("ZNULLS")) && *cp) X Znulls = atoi(cp); X if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh"))) X Restricted=TRUE; X chkinvok(argv[0]); X X Rxtimeout = 600; X npats=0; X if (argc<2) X usage(); X setbuf(stdout, xXbuf); X while (--argc) { X cp = *++argv; X if (*cp++ == '-' && *cp) { X while ( *cp) { X switch(*cp++) { X case '+': X Lzmanag = ZMAPND; break; X case '1': X iofd = 1; break; X#ifdef CSTOPB X case '2': X Twostop = TRUE; break; X#endif X case '7': X Wcsmask=0177; break; X case 'a': X Lzconv = ZCNL; X Ascii = TRUE; break; X case 'b': X Lzconv = ZCBIN; break; X case 'C': X if (--argc < 1) { X usage(); 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 usage(); 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 usage(); X } X blkopt = atoi(*++argv); X if (blkopt<24 || blkopt>1024) X usage(); X break; X case 'l': X if (--argc < 1) { X usage(); X } X Tframlen = atoi(*++argv); X if (Tframlen<32 || Tframlen>1024) X usage(); 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; X case 'q': X Quiet=TRUE; Verbose=0; break; X case 't': X if (--argc < 1) { X usage(); X } X Rxtimeout = atoi(*++argv); X if (Rxtimeout<10 || Rxtimeout>1000) X usage(); X break; X case 'T': X Testattn = TRUE; break; 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 usage(); X } X } X } X else if ( !npats && argc>0) { X if (argv[0][0]) { X npats=argc; X patts=argv; X if ( !strcmp(*patts, "-")) X iofd = 1; X } X } X } X if (npats < 1 && !Command) X usage(); X if (Verbose) { X if (freopen(LOGFILE, "a", stderr)==NULL) { X printf("Can't open log file %s\n",LOGFILE); X exit(0200); X } X setbuf(stderr, NULL); X } X if ((Fromcu=from_cu()) && !Quiet) { X if (Verbose == 0) X Verbose = 2; X } X X mode(1); X X if (signal(SIGINT, bibi) == SIG_IGN) { X signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); X } else { X signal(SIGINT, bibi); signal(SIGKILL, bibi); X } X if ( !Fromcu) X signal(SIGQUIT, SIG_IGN); X X if ( !Modem) { X if (!Nozmodem) { X printf("rz\r"); fflush(stdout); X } X if (!Command && !Quiet && Verbose != 1) { X fprintf(stderr, "%s: %d file%s requested:\r\n", X Progname, npats, npats>1?"s":""); X for ( agcnt=npats, agcv=patts; --agcnt>=0; ) { X fprintf(stderr, "%s ", *agcv++); X } X fprintf(stderr, "\r\n"); X printf("\r\n\bSending in Batch Mode\r\n"); X } X if (!Nozmodem) { X stohdr(0L); X if (Command) X Txhdr[ZF0] = ZCOMMAND; X zshhdr(ZRQINIT, Txhdr); X } X } X fflush(stdout); 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 fflush(stdout); X mode(0); X exit((errcnt != 0) | Exitcode); X /*NOTREACHED*/ X} X Xwcsend(argc, argp) Xchar *argp[]; X{ X register 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 (getnak()) { X Exitcode=0200; canit(); X } X if (!Zmodem) X canit(); X else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) { X Exitcode=0200; canit(); X } X Exitcode = 1; return OK; X } X canit(); X fprintf(stderr,"\r\nCan't open any requested files.\r\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 register c; X register char *p; X struct stat f; X char name[PATHLEN]; X X strcpy(name, oname); X X if (Restricted) { X /* restrict pathnames to current tree or uucppublic */ X if ( substr(name, "../") X || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) { X canit(); X fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n"); X return ERROR; X } X } X X if ( !strcmp(oname, "-")) { X if ((p = getenv("ONAME")) && *p) X strcpy(name, p); X else X sprintf(name, "s%d.sz", getpid()); X in = stdin; X } X else if ((in=fopen(oname, "r"))==NULL) { X ++errcnt; X return OK; /* pass over it, there may be others */ X } X ++Noeofseen; Lastread = 0; Lastc = -1; Dontread = FALSE; X /* Check for directory or block special files */ X fstat(fileno(in), &f); X c = f.st_mode & S_IFMT; X if (c == S_IFDIR || c == S_IFBLK) { X fclose(in); X return OK; 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/* 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 Unix fstat 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 struct stat f; X X if (Modem) { X#ifdef CASE X if (Verbose && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1) { X#else X if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) { X#endif X fprintf(stderr, "Sending %s, %ld blocks: ", X name, f.st_size>>7); X } X#ifdef CASE X if(Verbose) X#endif X fprintf(stderr, "Give your local XMODEM receive command now.\r\n"); X return OK; X } X logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>"); X if ( !Zmodem) X if (getnak()) X return ERROR; 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=txbuf ; *p; ) X if ((*q++ = *p++) == '/' && !Fullname) X q = txbuf; X *q++ = 0; X p=q; X while (q < (txbuf + KSIZE)) X *q++ = 0; X if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1) X sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode); X /* force 1k blocks if name won't fit in 128 byte block */ X if (txbuf[125]) X blklen=KSIZE; X else { /* A little goodie for IMP/KMD */ X if (Zmodem) X blklen = SECSIZ; X txbuf[127] = (f.st_size + 127) >>7; X txbuf[126] = (f.st_size + 127) >>15; X } X if (Zmodem) X return zsendfile(txbuf, 1+strlen(p)+(p-txbuf)); X if (wcputsec(txbuf, 0, SECSIZ)==ERROR) X return ERROR; X return OK; X} X Xgetnak() X{ X register 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 logent("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 logent("Receiver 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(txbuf, blklen)) { X if (wcputsec(txbuf, sectnum, blklen)==ERROR) { X return ERROR; X } else X sectnum++; X } X if (Verbose>1) X fprintf(stderr, " Closing "); X fclose(in); X attempts=0; X do { X logent(" EOT "); X purgeline(); X sendline(EOT); X fflush(stdout); X ++attempts; X } X while ((firstch=(readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX); X if (attempts == RETRYMAX) { X logent("No 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 checksum, wcj; X register char *cp; X unsigned oldcrc; X int firstch; X int attempts; X X firstch=0; /* part of logic to detect CAN CAN */ X X if (Verbose>1) X fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 ); 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 logent("Cancelled\n"); return ERROR; X } X break; X case TIMEOUT: X logent("Timeout on sector ACK\n"); continue; X case WANTCRC: X if (firstsec) X Crcflg = TRUE; X case NAK: X logent("NAK on sector\n"); continue; X case ACK: X firstsec=FALSE; X Totsecs += (cseclen>>7); X return OK; X case ERROR: X logent("Got burst for sector ACK\n"); break; X default: X logent("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 logent("Retry Count Exceeded\n"); X return ERROR; X} X X/* fill buf with count chars padding with ^Z for CPM */ Xfilbuf(buf, count) Xregister char *buf; X{ X register c, m; X X if ( !Ascii) { X m = read(fileno(in), buf, count); X if (m <= 0) X return 0; X while (m < count) X buf[m++] = 032; X return count; X } X m=count; X if (Lfseen) { X *buf++ = 012; --m; Lfseen = 0; X } X while ((c=getc(in))!=EOF) { X if (c == 012) { X *buf++ = 015; X if (--m == 0) { X Lfseen = TRUE; break; X } X } X *buf++ =c; X if (--m == 0) X break; X } X if (m==count) X return 0; X else X while (--m>=0) X *buf++ = CPMEOF; X return count; X} X/* fill buf with count chars */ Xzfilbuf(buf, count) Xregister char *buf; X{ X register c, m; X X m=count; X while ((c=getc(in))!=EOF) { X *buf++ =c; X if (--m == 0) X break; X } X return (count - m); X} X X/* VARARGS1 */ Xvfile(f, a, b, c) Xregister char *f; X{ X if (Verbose > 1) { X fprintf(stderr, f, a, b, c); X fprintf(stderr, "\n"); X } X} X X Xalrm() X{ X longjmp(tohere, -1); X} 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) X{ X register int c; X static char byt[5]; X X if (Optiong) X count = 1; /* Special hack for cbreak */ X X fflush(stdout); X if (setjmp(tohere)) { X logent("TIMEOUT\n"); X return TIMEOUT; X } X c = timeout/10; X if (c<2) X c=2; X if (Verbose>3) { X fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c); X byt[1] = 0; X } X signal(SIGALRM, alrm); alarm(c); X#ifdef ONEREAD X c=read(iofd, byt, 1); /* regulus raw read is unique */ X#else X c=read(iofd, byt, count); X#endif X alarm(0); X if (Verbose>5) X fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]); X if (c<1) X return TIMEOUT; X if (c==1) X return (byt[0]&0377); X else X while (c) X if (byt[--c] != CAN) X return ERROR; X return CAN; X} Xreadline(n) X{ X return (readock(n, 1)); X} X X Xpurgeline() X{ X#ifdef USG X ioctl(iofd, TCFLSH, 0); X#else X lseek(iofd, 0L, 2); X#endif X} X X X/* send cancel string to get the other end to shut up */ Xcanit() X{ X static char canistr[] = { X 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 X }; X X printf(canistr); X fflush(stdout); X} X X/*VARARGS1*/ Xlogent(a, b, c) Xchar *a, *b, *c; X{ X if(Verbose) X fprintf(stderr, a, b, c); X} X X/* X * return 1 iff stdout and stderr are different devices X * indicating this program operating with a modem on a X * different line X */ Xfrom_cu() X{ X struct stat a, b; X fstat(1, &a); fstat(2, &b); X return (a.st_rdev != b.st_rdev); X} X X/* X * substr(string, token) searches for token in string s X * returns pointer to token within string if found, NULL otherwise X */ Xchar * Xsubstr(s, t) Xregister char *s,*t; X{ X register char *ss,*tt; X /* search for first char of token */ X for (ss=s; *s; s++) X if (*s == *t) X /* compare token with substring */ X for (ss=s,tt=t; ;) { X if (*tt == 0) X return s; X if (*ss++ != *tt++) X break; X } X return NULL; X} X Xchar *babble[] = { X "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol", X " (Y) = Option applies to YMODEM only", X " (Z) = Option applies to ZMODEM only", X "Usage: sz [-12+aBbdefkLlNnquvXy] [-] file ...", X " sz [-1Beqv] -c COMMAND", X " 1 Use stdout for modem input", X#ifdef CSTOPB X " 2 Use 2 stop bits", X#endif X " + Append to existing destination file (Z)", X " a (ASCII) change NL to CR/LF", X " b Binary file transfer override", X " c send COMMAND (Z)", X " d Change '.' to '/' in pathnames (Y/Z)", X " e Escape all control characters (Z)", X " f send Full pathname (Y/Z)", X " i send COMMAND, ack Immediately (Z)", X " k Send 1024 byte packets (Y)", X " L N Limit subpacket length to N bytes (Z)", X " l N Limit frame length to N bytes (l>=L) (Z)", X " n send file if source Newer or longer (Z)", X " N send file if source different length or date (Z)", X " o Use 16 bit CRC instead of 32 bit CRC (Z)", X " p Protect existing destination file (Z)", X " r Resume/Recover interrupted file transfer (Z)", X " q Quiet (no progress reports)", X " u Unlink file after transmission", X " v Verbose - debugging information", X " X XMODEM protocol - send no pathnames", X " y Yes, overwrite existing file (Z)", X "- as pathname sends standard input as sPID.sz or environment ONAME", X "" X}; X Xusage() X{ X char **pp; X X for (pp=babble; **pp; ++pp) X fprintf(stderr, "%s\n", *pp); X fprintf(stderr, "%s for %s by Chuck Forsberg ", VERSION, OS); X exit(1); X} X X/* X * Get the receiver's init parameters X */ Xgetzrxinit() X{ X register n; X struct stat f; X X for (n=10; --n>=0; ) { X X switch (zgethdr(Rxhdr, 1)) { X case ZCHALLENGE: /* Echo receiver's challenge numbr */ X stohdr(Rxpos); X zshhdr(ZACK, Txhdr); X continue; X case ZCOMMAND: /* They didn't see out ZRQINIT */ X stohdr(0L); X zshhdr(ZRQINIT, Txhdr); X continue; X case ZRINIT: X Rxflags = 0377 & Rxhdr[ZF0]; X Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); X Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); X vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen); X if ( !Fromcu) X signal(SIGINT, SIG_IGN); X#ifdef USG X mode(2); /* Set cbreak, XON/XOFF, etc. */ X#endif X#ifndef READCHECK X#ifndef USG X /* Use 1024 byte frames if no sample/interrupt */ X if (Rxbuflen < 32 || Rxbuflen > 1024) { X Rxbuflen = 1024; X vfile("Rxbuflen=%d", Rxbuflen); X } X#endif X#endif X /* Override to force shorter frame length */ X if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32)) X Rxbuflen = Tframlen; X if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024)) X Rxbuflen = Tframlen; X vfile("Rxbuflen=%d", Rxbuflen); X X /* If using a pipe for testing set lower buf len */ X fstat(iofd, &f); X if ((f.st_mode & S_IFMT) != S_IFCHR X && (Rxbuflen == 0 || Rxbuflen > 4096)) X Rxbuflen = 4096; X /* X * If input is not a regular file, force ACK's each 1024 X * (A smarter strategey could be used here ...) X */ X fstat(fileno(in), &f); X if (((f.st_mode & S_IFMT) != S_IFREG) X && (Rxbuflen == 0 || Rxbuflen > 1024)) X Rxbuflen = 1024; X vfile("Rxbuflen=%d", Rxbuflen); X X return (sendzsinit()); X case ZCAN: X case TIMEOUT: X return ERROR; X case ZRQINIT: X if (Rxhdr[ZF0] == ZCOMMAND) X continue; X default: X zshhdr(ZNAK, Txhdr); X continue; X } X } X return ERROR; X} X X/* Send send-init information */ Xsendzsinit() X{ X register c; X register errors; X X if (Myattn[0] == '\0') X return OK; X errors = 0; X for (;;) { X stohdr(0L); X zsbhdr(ZSINIT, Txhdr); X zsdata(Myattn, 1+strlen(Myattn), ZCRCW); X c = zgethdr(Rxhdr, 1); X switch (c) { X case ZCAN: X return ERROR; X case ZACK: X return OK; X default: X if (++errors > 9) X return ERROR; X continue; X } X } X} X X/* Send file name and related info */ Xzsendfile(buf, blen) Xchar *buf; X{ X register c; X X for (;;) { X Txhdr[ZF0] = Lzconv; /* file conversion request */ X Txhdr[ZF1] = Lzmanag; /* file management request */ X Txhdr[ZF2] = Lztrans; /* file transport request */ X Txhdr[ZF3] = 0; X zsbhdr(ZFILE, Txhdr); X zsdata(buf, blen, ZCRCW); Xagain: X c = zgethdr(Rxhdr, 1); X switch (c) { X case ZRINIT: X goto again; X case ZCAN: X case TIMEOUT: X case ZABORT: X case ZFIN: X return ERROR; X case ZSKIP: X fclose(in); return c; X case ZRPOS: X fseek(in, Rxpos, 0); X Txpos = Rxpos; Lastc = -1; Dontread = FALSE; X return zsendfdata(); X default: X continue; X } X } X} X X/* Send the data in the file */ Xzsendfdata() X{ X register c, e; X register newcnt; X register long tcount = 0; X static int tleft = 6; /* Counter for test mode */ X extern int setjmp(); X X if (Baudrate > 300) X blklen = 256; X if (Baudrate > 2400) X blklen = KSIZE; X/* if (Rxbuflen && blklen>Rxbuflen) */ X if (Rxbuflen) X blklen = Rxbuflen; X if (blkopt && blklen > blkopt) X blklen = blkopt; X vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen); Xsomemore: X if (setjmp(intrjmp)) { Xwaitack: X c = getinsync(); X switch (c) { X default: X case ZCAN: X fclose(in); X return ERROR; X case ZSKIP: X fclose(in); X return c; X case ZACK: X case ZRPOS: X break; X case ZRINIT: X return OK; X } X#ifdef READCHECK X /* X * If the reverse channel can be tested for data, X * this logic may be used to detect error packets X * sent by the receiver, in place of setjmp/longjmp X * rdchk(fdes) returns non 0 if a character is available X */ X while (rdchk(iofd)) { X#ifdef SVR2 X switch (checked) X#else X switch (readline(1)) X#endif X { X case CAN: X case ZPAD: X goto waitack; X case XOFF: /* Wait a while for an XON */ X case XOFF|0200: X readline(100); X } X } X#endif X } X X if ( !Fromcu) X signal(SIGINT, onintr); X newcnt = Rxbuflen; X stohdr(Txpos); X zsbhdr(ZDATA, Txhdr); X X /* X * Special testing mode. This should force receiver to Attn,ZRPOS X * many times. Each time the signal should be caught, causing the X * file to be started over from the beginning. X */ X if (Testattn) { X if ( --tleft) X while (tcount < 20000) { X printf(qbf); fflush(stdout); X tcount += strlen(qbf); X#ifdef READCHECK X while (rdchk(iofd)) { X#ifdef SVR2 X switch (checked) X#else X switch (readline(1)) X#endif X { X case CAN: X case ZPAD: X#ifdef TCFLSH X ioctl(iofd, TCFLSH, 1); X#endif X goto waitack; X case XOFF: /* Wait for XON */ X case XOFF|0200: X readline(100); X } X } X#endif X } X signal(SIGINT, SIG_IGN); canit(); X sleep(3); purgeline(); mode(0); X printf("\nsz: Tcount = %ld\n", tcount); X if (tleft) { X printf("ERROR: Interrupts Not Caught\n"); X exit(1); X } X exit(0); X } X X do { X if (Dontread) { X c = Lastc; X } else { X c = zfilbuf(txbuf, blklen); X Lastread = Txpos; Lastc = c; X } X if (Verbose > 10) X vfile("Dontread=%d c=%d", Dontread, c); X Dontread = FALSE; X if (c < blklen) X e = ZCRCE; X else if (Rxbuflen && (newcnt -= c) <= 0) X e = ZCRCW; X else X e = ZCRCG; X zsdata(txbuf, c, e); X Txpos += c; X if (e == ZCRCW) X goto waitack; X#ifdef READCHECK X /* X * If the reverse channel can be tested for data, X * this logic may be used to detect error packets X * sent by the receiver, in place of setjmp/longjmp X * rdchk(fdes) returns non 0 if a character is available X */ X fflush(stdout); X while (rdchk(iofd)) { X#ifdef SVR2 X switch (checked) X#else X switch (readline(1)) X#endif X { X case CAN: X case ZPAD: X#ifdef TCFLSH X ioctl(iofd, TCFLSH, 1); X#endif X /* zcrce - dinna wanna start a ping-pong game */ X zsdata(txbuf, 0, ZCRCE); X goto waitack; X case XOFF: /* Wait a while for an XON */ X case XOFF|0200: X readline(100); X } X } X#endif X } while (c == blklen); X if ( !Fromcu) X signal(SIGINT, SIG_IGN); X X for (;;) { X stohdr(Txpos); X zsbhdr(ZEOF, Txhdr); X switch (getinsync()) { X case ZACK: X continue; X case ZRPOS: X goto somemore; X case ZRINIT: X return OK; X case ZSKIP: X fclose(in); X return c; X default: X fclose(in); X return ERROR; X } X } X} X X/* X * Respond to receiver's complaint, get back in sync with receiver X */ Xgetinsync() X{ X register c; X X for (;;) { X if (Testattn) { X printf("\r\n\n\n***** Signal Caught *****\r\n"); X Rxpos = 0; c = ZRPOS; X } else X c = zgethdr(Rxhdr, 0); X switch (c) { X case ZCAN: X case ZABORT: X case ZFIN: X case TIMEOUT: X return ERROR; X case ZRPOS: X if (Lastc >= 0 && Lastread == Rxpos) { X Dontread = TRUE; X } else { X clearerr(in); /* In case file EOF seen */ X fseek(in, Rxpos, 0); X } X Txpos = Rxpos; X return c; X case ZACK: X return c; X case ZRINIT: X case ZSKIP: X fclose(in); X return c; X case ERROR: X default: X zsbhdr(ZNAK, Txhdr); X continue; X } X } X} X/* Say "bibi" to the receiver, try to do it cleanly */ Xsaybibi() X{ X for (;;) { X stohdr(0L); X zsbhdr(ZFIN, Txhdr); X switch (zgethdr(Rxhdr, 0)) { X case ZFIN: X sendline('O'); sendline('O'); flushmo(); X case ZCAN: X case TIMEOUT: X return; X } X } X} X X/* Local screen character display function */ Xbttyout(c) X{ X if (Verbose) X putc(c, stderr); X} X X/* Send command and related info */ Xzsendcmd(buf, blen) Xchar *buf; X{ X register c, errors; X long cmdnum; X X cmdnum = getpid(); X errors = 0; X for (;;) { X stohdr(cmdnum); X Txhdr[ZF0] = Cmdack1; X zsbhdr(ZCOMMAND, Txhdr); X zsdata(buf, blen, ZCRCW); Xlisten: X Rxtimeout = 100; /* Ten second wait for resp. */ X c = zgethdr(Rxhdr, 1); X X switch (c) { X case ZRINIT: X continue; X case ERROR: X case TIMEOUT: X if (++errors > Cmdtries) X return ERROR; X continue; X case ZCAN: X case ZABORT: X case ZFIN: X case ZSKIP: X case ZRPOS: X return ERROR; X default: X if (++errors > 10) X return ERROR; X continue; X case ZCOMPL: X Exitcode = Rxpos; X saybibi(); X return OK; X case ZRQINIT: X vfile("******** RZ *******"); X system("rz"); X vfile("******** SZ *******"); X goto listen; X } X } X} X X/* X * If called as sb use YMODEM protocol X */ Xchkinvok(s) Xchar *s; X{ X register char *p; X X p = s; X while (*p == '-') X s = ++p; X while (*p) X if (*p++ == '/') X s = p; X if (*s == 'v') { X Verbose=1; ++s; X } X Progname = s; X if (s[0]=='s' && s[1]=='b') { X Nozmodem = TRUE; blklen=KSIZE; X } X} X SHAR_EOF chmod 0600 sz.c || echo "restore of sz.c fails" sed 's/^X//' << 'SHAR_EOF' > zm.c && X/* X * Z M . C X * ZMODEM protocol primitives X * 01-19-87 Chuck Forsberg Omen Technology Inc X * X * Entry point Functions: X * zsbhdr(type, hdr) send binary header X * zshhdr(type, hdr) send hex header X * zgethdr(hdr, eflag) receive header - binary or hex X * zsdata(buf, len, frameend) send data X * zrdata(buf, len) receive data X * stohdr(pos) store position data in Txhdr X * long rclhdr(hdr) recover position offset from header X */ X X#ifndef CANFDX X#include "zmodem.h" Xint Rxtimeout = 100; /* Tenths of seconds to wait for something */ X#endif X Xstatic char *frametypes[] = { X "Carrier Lost", /* -3 */ X "TIMEOUT", /* -2 */ X "ERROR", /* -1 */ X#define FTOFFSET 3 X "ZRQINIT", X "ZRINIT", X "ZSINIT", X "ZACK", X "ZFILE", X "ZSKIP", X "ZNAK", X "ZABORT", X "ZFIN", X "ZRPOS", X "ZDATA", X "ZEOF", X "ZFERR", X "ZCRC", X "ZCHALLENGE", X "ZCOMPL", X "ZCAN", X "ZFREECNT", X "ZCOMMAND", X "ZSTDERR", X "xxxxx" X#define FRTYPES 22 /* Total number of frame types in this array */ X /* not including psuedo negative entries */ X}; X X/* Send ZMODEM binary header hdr of type type */ Xzsbhdr(type, hdr) Xregister char *hdr; X{ X register n; X register unsigned short crc; X X vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr)); X if (type == ZDATA) X for (n = Znulls; --n >=0; ) X zsendline(0); X X xsendline(ZPAD); xsendline(ZDLE); X X if (Txfcs32) X zsbh32(hdr, type); X else { X xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0); X X for (n=4; --n >= 0;) { X zsendline(*hdr); X crc = updcrc((0377& *hdr++), crc); X } X crc = updcrc(0,updcrc(0,crc)); X zsendline(crc>>8); X zsendline(crc); X } X if (type != ZDATA) X flushmo(); X} X X X/* Send ZMODEM binary header hdr of type type */ Xzsbh32(hdr, type) Xregister char *hdr; X{ X register n; X register unsigned long crc; X X xsendline(ZBIN32); zsendline(type); X crc = 0xFFFFFFFF; crc = UPDC32(type, crc); X X for (n=4; --n >= 0;) { X zsendline(*hdr); X crc = UPDC32((0377& *hdr++), crc); X } X crc = ~crc; X for (n=4; --n >= 0;) { X zsendline(crc); crc >>= 8; X } X} X X/* Send ZMODEM HEX header hdr of type type */ Xzshhdr(type, hdr) Xregister char *hdr; X{ X register n; X register unsigned short crc; X X vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr)); X sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX); X zputhex(type); X X crc = updcrc(type, 0); X for (n=4; --n >= 0;) { X zputhex(*hdr); crc = updcrc((0377& *hdr++), crc); X } X crc = updcrc(0,updcrc(0,crc)); X zputhex(crc>>8); zputhex(crc); X X /* Make it printable on remote machine */ X sendline(015); sendline(012); X /* X * Uncork the remote in case a fake XOFF has stopped data flow X */ X if (type != ZFIN) X sendline(021); X flushmo(); X} X X/* X * Send binary array buf of length length, with ending ZDLE sequence frameend X */ Xzsdata(buf, length, frameend) Xregister char *buf; X{ X register unsigned short crc; X X vfile("zsdata: length=%d end=%x", length, frameend); X if (Txfcs32) X zsda32(buf, length, frameend); X else { SHAR_EOF echo "End of part 4, continue with part 5" echo "5" > s2_seq_.tmp exit 0