Path: utzoo!mnetor!uunet!husc6!cmcl2!brl-adm!brl-smoke!w8sdz From: w8sdz@brl-smoke.ARPA (Keith B. Petersen ) Newsgroups: comp.binaries.ibm.pc Subject: Zmodem for Unix and VAX/VMS (repost) part 2of3 Message-ID: <7815@brl-smoke.ARPA> Date: 3 May 88 04:16:56 GMT Reply-To: w8sdz@brl-smoke.UUCP (Keith B. Petersen (WSMR|towson) ) Followup-To: comp.binaries.ibm.pc.d Organization: Ballistic Research Lab (BRL), APG, MD. Lines: 2485 Keywords: xmodem,ymodem,zmodem,unix,vax/vms Summary: Chuck Forsberg's Zmodem now supports VAX/VMS as well as Unix This is a repost of Zmodem for Unix and VAX/VMS, by Chuck Forsberg. Sorry for the problems with the previous posting. To extract the files, use the unshar script or unshar.c program previously posted to this newsgroup. ---- Cut Here and unpack ---- #!/bin/sh # this is part 2 of a multipart archive # do not concatenate these parts, unpack them in order with /bin/sh # file rz.c continued # CurArch=2 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 if (c=tryz()) { X if (c == ZCOMPL) X return OK; X if (c == ERROR) X goto fubar; X c = rzfiles(); X if (c) X goto fubar; X } else { X for (;;) { 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 } else { X Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; X X procheader(""); strcpy(Pathname, *argp); checkpath(Pathname); X fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname); X if ((fout=fopen(Pathname, "w")) == NULL) X return ERROR; X if (wcrx()==ERROR) X goto fubar; X } X return OK; Xfubar: X canit(); X#ifndef vax11c X if (Topipe && fout) { X pclose(fout); return ERROR; X } X#endif X if (fout) X fclose(fout); X#ifndef vax11c X if (Restricted) { X unlink(Pathname); X fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname); X } X#endif 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 c; X X#ifdef NFGVMIN X readline(1); X#else X purgeline(); X#endif 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 if (c == WCEOT) { X zperr( "Pathname fetch returned %d", c); 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 register char *p; 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 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 &0377)) { 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&0377)) { X zperr( "Received dup Sector"); X sendchar=ACK; X } X else if (sectcurr==WCEOT) { X if (closeit()) 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 zperr( "Sync Error"); X return ERROR; 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 */ X Xwcgetsec(rxbuf, maxtime) Xchar *rxbuf; Xint maxtime; X{ X register checksum, wcj, firstch; X register unsigned short oldcrc; X register char *p; X int sectcurr; X X for (Lastrx=errors=0; errors=0; ) { 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 oldcrc=updcrc(firstch, oldcrc); X if ((firstch=readline(1)) < 0) X goto bilge; X oldcrc=updcrc(firstch, oldcrc); X if (oldcrc & 0xFFFF) X zperr( "CRC"); X else { X Firstsec=FALSE; X return sectcurr; X } X } X else if (((checksum-firstch)&0377)==0) { X Firstsec=FALSE; X return sectcurr; X } X else X zperr( "Checksum"); X } X else X zperr("Sector number garbled"); X } X /* make sure eot really is eot and not just mixmash */ X#ifdef NFGVMIN X else if (firstch==EOT && readline(1)==TIMEOUT) X return WCEOT; X#else X else if (firstch==EOT && Lleft==0) X return WCEOT; X#endif X else if (firstch==CAN) { X if (Lastrx==CAN) { X zperr( "Sender CANcelled"); X return ERROR; X } else { X Lastrx=CAN; X continue; X } X } X else if (firstch==TIMEOUT) { X if (Firstsec) X goto humbug; Xbilge: X zperr( "TIMEOUT"); X } X else X zperr( "Got 0%o sector header", firstch); X Xhumbug: X Lastrx=0; X while(readline(1)!=TIMEOUT) X ; X if (Firstsec) { X sendline(Crcflg?WANTCRC:NAK); X Lleft=0; /* Do read next time ... */ X } else { 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#ifndef vax11c X/* X * This version of readline is reasoably well suited for X * reading many characters. X * (except, currently, for the Regulus version!) X * X * timeout is in tenths of seconds X */ Xreadline(timeout) Xint timeout; X{ X register n; X static char *cdq; /* pointer for removing chars from linbuf */ X X if (--Lleft >= 0) { X if (Verbose > 8) { X fprintf(stderr, "%02x ", *cdq&0377); X } X return (*cdq++ & 0377); X } X n = timeout/10; X if (n < 2) X n = 3; X if (Verbose > 5) X fprintf(stderr, "Calling read: alarm=%d Readnum=%d ", X n, Readnum); X if (setjmp(tohere)) { X#ifdef TIOCFLUSH X/* ioctl(iofd, TIOCFLUSH, 0); */ X#endif X Lleft = 0; X if (Verbose>1) X fprintf(stderr, "Readline:TIMEOUT\n"); X return TIMEOUT; X } X signal(SIGALRM, alrm); alarm(n); X Lleft=read(iofd, cdq=linbuf, Readnum); X alarm(0); X if (Verbose > 5) { X fprintf(stderr, "Read returned %d bytes\n", Lleft); X } X if (Lleft < 1) X return TIMEOUT; X --Lleft; X if (Verbose > 8) { X fprintf(stderr, "%02x ", *cdq&0377); X } X return (*cdq++ & 0377); X} X X X X/* X * Purge the modem input queue of all characters X */ Xpurgeline() X{ X Lleft = 0; X#ifdef USG X ioctl(iofd, TCFLSH, 0); X#else X lseek(iofd, 0L, 2); X#endif X} X#endif X X X/* X * Process incoming file information header X */ Xprocheader(name) Xchar *name; X{ X register char *openmode, *p, **pp; X X /* set default parameters and overrides */ X openmode = "w"; X Thisbinary = (!Rxascii) || Rxbinary; X if (Lzmanag) X zmanag = Lzmanag; X X /* X * Process ZMODEM remote file management requests X */ X if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */ X Thisbinary = 0; X if (zconv == ZCBIN) /* Remote Binary override */ X Thisbinary = TRUE; X else if (zmanag == ZMAPND) X openmode = "a"; X X#ifndef BIX X /* Check for existing file */ X if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) { X fclose(fout); return ERROR; X } X#endif X X Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; X X p = name + 1 + strlen(name); X if (*p) { /* file coming from Unix or DOS system */ X sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode); X#ifndef vax11c X if (Filemode & UNIXFILE) X ++Thisbinary; X#endif X if (Verbose) { X fprintf(stderr, "Incoming: %s %ld %lo %o\n", X name, Bytesleft, Modtime, Filemode); X } X } X X#ifdef BIX X if ((fout=fopen("scratchpad", openmode)) == NULL) X return ERROR; X return OK; X#else X X else { /* 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#ifndef vax11c X if (!Zmodem && MakeLCPathname && !IsAnyLower(name) X && !(Filemode&UNIXFILE)) X uncaps(name); X#endif X if (Topipe) { X sprintf(Pathname, "%s %s", Progname+2, name); X if (Verbose) X fprintf(stderr, "Topipe: %s %s\n", X Pathname, Thisbinary?"BIN":"ASCII"); X#ifndef vax11c X if ((fout=popen(Pathname, "w")) == NULL) X return ERROR; X#endif X } else { X strcpy(Pathname, name); X if (Verbose) { X fprintf(stderr, "Receiving %s %s %s\n", X name, Thisbinary?"BIN":"ASCII", openmode); X } X checkpath(name); X if (Nflag) X name = "/dev/null"; X#ifdef MD X fout = fopen(name, openmode); X if ( !fout) X if (make_dirs(name)) X fout = fopen(name, openmode); X#else X fout = fopen(name, openmode); X#endif X if ( !fout) X return ERROR; X } X return OK; X#endif /* BIX */ X} X X#ifdef MD X/* X * Directory-creating routines from Public Domain TAR by John Gilmore X */ X X/* X * After a file/link/symlink/dir creation has failed, see if X * it's because some required directory was not present, and if X * so, create all required dirs. X */ Xmake_dirs(pathname) Xregister char *pathname; X{ X register char *p; /* Points into path */ X int madeone = 0; /* Did we do anything yet? */ X int save_errno = errno; /* Remember caller's errno */ X X if (errno != ENOENT) X return 0; /* Not our problem */ X X for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) { X /* Avoid mkdir of empty string, if leading or double '/' */ X if (p == pathname || p[-1] == '/') X continue; X /* Avoid mkdir where last part of path is '.' */ X if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/')) X continue; X *p = 0; /* Truncate the path there */ X if ( !mkdir(pathname, 0777)) { /* Try to create it as a dir */ X vfile("Made directory %s\n", pathname); X madeone++; /* Remember if we made one */ X *p = '/'; X continue; X } X *p = '/'; X if (errno == EEXIST) /* Directory already exists */ X continue; X /* X * Some other error in the mkdir. We return to the caller. X */ X break; X } X errno = save_errno; /* Restore caller's errno */ X return madeone; /* Tell them to retry if we made one */ X} X X#if (MD != 2) X#define TERM_SIGNAL(status) ((status) & 0x7F) X#define TERM_COREDUMP(status) (((status) & 0x80) != 0) X#define TERM_VALUE(status) ((status) >> 8) X/* X * Make a directory. Compatible with the mkdir() system call on 4.2BSD. X */ Xmkdir(dpath, dmode) Xchar *dpath; Xint dmode; X{ X int cpid, status; X struct stat statbuf; X X if (stat(dpath,&statbuf) == 0) { X errno = EEXIST; /* Stat worked, so it already exists */ X return -1; X } X X /* If stat fails for a reason other than non-existence, return error */ X if (errno != ENOENT) return -1; X X switch (cpid = fork()) { X X case -1: /* Error in fork() */ X return(-1); /* Errno is set already */ X X case 0: /* Child process */ X /* X * Cheap hack to set mode of new directory. Since this X * child process is going away anyway, we zap its umask. X * FIXME, this won't suffice to set SUID, SGID, etc. on this X * directory. Does anybody care? X */ X status = umask(0); /* Get current umask */ X status = umask(status | (0777 & ~dmode)); /* Set for mkdir */ X execl("/bin/mkdir", "mkdir", dpath, (char *)0); X _exit(-1); /* Can't exec /bin/mkdir */ X X default: /* Parent process */ X while (cpid != wait(&status)) ; /* Wait for kid to finish */ X } X X if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) { X errno = EIO; /* We don't know why, but */ X return -1; /* /bin/mkdir failed */ X } X X return 0; X} X#endif /* MD != 2 */ X#endif /* MD */ X X/* X * Putsec writes the n characters of buf to receive file fout. X * If not in binary mode, carriage returns, and all characters X * starting with CPMEOF are discarded. X */ Xputsec(buf, n) Xchar *buf; Xregister n; X{ X register char *p; X X if (n == 0) X return OK; X if (Thisbinary) { X for (p=buf; --n>=0; ) X putc( *p++, fout); X } X else { X if (Eofseen) X return OK; X for (p=buf; --n>=0; ++p ) { X if ( *p == '\r') X continue; X if (*p == CPMEOF) { X Eofseen=TRUE; return OK; X } X putc(*p ,fout); X } X } X return OK; X} X X#ifndef vax11c X/* X * Send a character to modem. Small is beautiful. X */ Xsendline(c) X{ X char d; X X d = c; X if (Verbose>6) X fprintf(stderr, "Sendline: %x\n", c); X write(1, &d, 1); X} X Xflushmo() {} X#endif X X X X X X/* make string s lower case */ Xuncaps(s) Xregister char *s; X{ X for ( ; *s; ++s) X if (isupper(*s)) X *s = tolower(*s); X} X/* X * IsAnyLower returns TRUE if string s has lower case letters. X */ XIsAnyLower(s) Xregister char *s; X{ X for ( ; *s; ++s) X if (islower(*s)) X return TRUE; X return FALSE; 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 X/* X * Log an error X */ X/*VARARGS1*/ Xzperr(s,p,u) Xchar *s, *p, *u; X{ X if (Verbose <= 0) X return; X fprintf(stderr, "Retry %d: ", errors); X fprintf(stderr, s, p, u); X fprintf(stderr, "\n"); 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#ifdef vax11c X raw_wbuf(strlen(canistr), canistr); X purgeline(); X#else X printf(canistr); X Lleft=0; /* Do read next time ... */ X fflush(stdout); X#endif X} X X Xreport(sct) Xint sct; X{ X if (Verbose>1) X fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r'); X} X X#ifndef vax11c X/* X * If called as [-][dir/../]vrzCOMMAND set Verbose to 1 X * If called as [-][dir/../]rzCOMMAND set the pipe flag X * If called as rb 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]=='r' && s[1]=='z') X Batch = TRUE; X if (s[0]=='r' && s[1]=='b') X Batch = Nozmodem = TRUE; X if (s[2] && s[0]=='r' && s[1]=='b') X Topipe=TRUE; X if (s[2] && s[0]=='r' && s[1]=='z') X Topipe=TRUE; X} X#endif X X/* X * Totalitarian Communist pathname processing X */ Xcheckpath(name) Xchar *name; X{ X if (Restricted) { X if (fopen(name, "r") != NULL) { X canit(); X fprintf(stderr, "\r\nrz: %s exists\n", name); X bibi(-1); X } 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\nrz:\tSecurity Violation\r\n"); X bibi(-1); X } X } X} 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 c, n; X register cmdzack1flg; X X if (Nozmodem) /* Check for "rb" program name */ X return 0; X X X for (n=Zmodem?15:5; --n>=0; ) { X /* Set buffer length (0) and capability flags */ X#ifdef SEGMENTS X stohdr(SEGMENTS*1024L); X#else X stohdr(0L); X#endif X#ifdef CANBREAK X Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; X#else X Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; X#endif X if (Zctlesc) X Txhdr[ZF0] |= TESCCTL; X zshhdr(tryzhdrtype, Txhdr); X if (tryzhdrtype == ZSKIP) /* Don't skip too far */ X tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ Xagain: X switch (zgethdr(Rxhdr, 0)) { 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 c = zrdata(secbuf, 1024); X mode(3); X if (c == GOTCRCW) X return ZFILE; X zshhdr(ZNAK, Txhdr); X goto again; X case ZSINIT: X Zctlesc = TESCCTL & Rxhdr[ZF0]; X if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { X stohdr(1L); X zshhdr(ZACK, Txhdr); X goto again; X } X zshhdr(ZNAK, Txhdr); X goto again; X case ZFREECNT: X stohdr(getfree()); X zshhdr(ZACK, Txhdr); X goto again; X case ZCOMMAND: X#ifdef vax11c X return ERROR; X#else X cmdzack1flg = Rxhdr[ZF0]; X if (zrdata(secbuf, 1024) == GOTCRCW) { 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<20 && zgethdr(Rxhdr,1) != ZFIN); X ackbibi(); X if (cmdzack1flg & ZCACK1) X exec2(secbuf); X return ZCOMPL; X } X zshhdr(ZNAK, Txhdr); goto again; X#endif 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 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 c, n; X long rxbytes; X X Eofseen=FALSE; X if (procheader(secbuf) == ERROR) { X return (tryzhdrtype = ZSKIP); X } X X n = 20; rxbytes = 0l; X X for (;;) { X#ifdef SEGMENTS X chinseg = 0; X#endif 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#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X case ZFILE: X zrdata(secbuf, 1024); X continue; X case ZEOF: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if (rclhdr(Rxhdr) != rxbytes) { 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 errors = 0; goto nxthdr; X } X if (closeit()) { X tryzhdrtype = ZFERR; 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#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case ZSKIP: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X closeit(); X vfile("rzfile: Sender SKIPPED file"); X return c; X case ZDATA: X if (rclhdr(Rxhdr) != rxbytes) { X if ( --n < 0) { X return ERROR; X } X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X zmputs(Attn); continue; X } Xmoredata: X if (Verbose>1) X fprintf(stderr, "\r%7ld ZMODEM%s ", X rxbytes, Crc32?" CRC-32":""); X#ifdef SEGMENTS X if (chinseg >= (1024 * SEGMENTS)) { X putsec(secbuf, chinseg); X chinseg = 0; X } X switch (c = zrdata(secbuf+chinseg, 1024)) X#else X switch (c = zrdata(secbuf, 1024)) X#endif X { X case ZCAN: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X case ERROR: /* CRC error */ X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case TIMEOUT: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X continue; X case GOTCRCW: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X putsec(secbuf, chinseg); X chinseg = 0; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X sendline(XON); X goto nxthdr; X case GOTCRCQ: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X goto moredata; X case GOTCRCG: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; X goto moredata; X case GOTCRCE: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; 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 c; X X while (*s) { X switch (c = *s++) { X case '\336': X sleep(1); continue; X case '\335': X sendbrk(); continue; X default: X sendline(c); X } X } X} X X/* X * Close the receive dataset, return OK or ERROR X */ Xcloseit() X{ X#ifndef vax11c X if (Topipe) { X if (pclose(fout)) { X return ERROR; X } X return OK; X } X#endif X if (fclose(fout)==ERROR) { X fprintf(stderr, "file close ERROR\n"); X return ERROR; X } X#ifndef vax11c X if (Modtime) { X timep[0] = time(NULL); X timep[1] = Modtime; X utime(Pathname, timep); X } X#endif X if ((Filemode&S_IFMT) == S_IFREG) X chmod(Pathname, (07777 & Filemode)); X return OK; X} X X/* X * Ack a ZFIN packet, let byegones be byegones X */ Xackbibi() X{ X register n; X X vfile("ackbibi:"); X Readnum = 1; X stohdr(0L); X for (n=3; --n>=0; ) { X purgeline(); X zshhdr(ZFIN, Txhdr); X switch (readline(100)) { X case 'O': X readline(1); /* Discard 2nd 'O' */ X vfile("ackbibi complete"); X return; X case RCDO: X return; X case TIMEOUT: X default: X break; X } X } X} X X X X/* X * Local console output simulation X */ Xbttyout(c) X{ X if (Verbose || Fromcu) X putc(c, stderr); X} X X#ifndef vax11c X/* X * Strip leading ! if present, do shell escape. X */ Xsys2(s) Xregister char *s; X{ X if (*s == '!') X ++s; X return system(s); X} X/* X * Strip leading ! if present, do exec. X */ Xexec2(s) Xregister char *s; X{ X if (*s == '!') X ++s; X mode(0); X execl("/bin/sh", "sh", "-c", s); X} X#endif X/* End of rz.c */ SHAR_EOF echo "File rz.c is complete" chmod 0644 rz.c || echo "restore of rz.c fails" echo "x - extracting sz.1 (Text)" sed 's/^X//' << 'SHAR_EOF' > sz.1 && X'\" Revision Level X'\" Last Delta 04-21-88 X.TH SZ 1 OMEN X.SH NAME Xsx, sb, sz \- XMODEM, YMODEM, ZMODEM file send X.SH SYNOPSIS Xsz X.RB [\- +abdefkLlNnopqTtuvyY ] X.I file ... X.br Xsb X.RB [\- adfkqtuv ] X.I file ... X.br Xsx X.RB [\- akqtuv ] X.I file X.br Xsz X.RB [\- oqtv ] X.B "-c COMMAND" X.br Xsz X.RB [\- oqtv ] X.B "-i COMMAND" X.br Xsz -TT X.SH DESCRIPTION X.B Sz Xuses the ZMODEM, YMODEM or XMODEM error correcting protocol to send Xone or more files over a dial-in serial port to a variety of programs running under XPC-DOS, CP/M, Unix, VMS, and other operating systems. X XWhile X.I rz Xis smart enough to be called from X.I cu(1), Xvery few versions of X.I cu(1) Xare smart enough to allow X.I sz Xto work properly. XUnix flavors of Professional-YAM are available for such dial-out application. X X X.B Sz Xsends one or more files with ZMODEM protocol. X XZMODEM Xgreatly simplifies file transfers compared to XMODEM. XIn addition to a friendly user interface, ZMODEM Xprovides Personal Computer and other users Xan efficient, accurate, and robust file transfer method. X XZMODEM provides complete X.B "END-TO-END" Xdata integrity between application programs. XZMODEM's 32 bit CRC catches errors Xthat sneak into even the most advanced networks. X XAdvanced file management features include XAutoDownload (Automatic file Download initiated without user intervention), XDisplay of individual and total file lengths and transmission time estimates, XCrash Recovery, Xselective file transfers, Xand preservation of Xexact file date and length. X XOutput from another program may be piped to X.B sz Xfor transmission by denoting standard input with "-": X.ce Xls -l | sz - XThe program output is transmitted with the filename sPID.sz Xwhere PID is the process ID of the X.B sz Xprogram. XIf the environment variable X.B ONAME Xis set, that is used instead. XIn this case, the Unix command: X.ce Xls -l | ONAME=con sz -ay - Xwill send a "file" to the PC-DOS console display. XThe X.B -y Xoption instructs the receiver to open the file for writing unconditionally. XThe X.B -a Xoption Xcauses the receiver to convert Unix newlines to PC-DOS carriage returns Xand linefeeds. X X X.B Sb Xbatch sends one or more files with YMODEM or ZMODEM protocol. XThe initial ZMODEM initialization is not sent. XWhen requested by the receiver, X.B sb Xsupports X.B YMODEM-g Xwith "cbreak" tty mode, XON/XOFF flow control, Xand interrupt character set to CAN (^X). X.B YMODEM-g X(Professional-YAM X.B g Xoption) Xincreases throughput over error free channels X(direct connection, X.PC, etc.) Xby not acknowledging each transmitted sector. X XOn X.SM Unix Xsystems, additional information about the file is transmitted. XIf the receiving program uses this information, Xthe transmitted file length controls the exact number of bytes written to Xthe output dataset, Xand the modify time and file mode Xare set accordingly. X X X.B Sx Xsends a single X.I file Xwith X.B XMODEM Xor X.B XMODEM-1k Xprotocol X(sometimes incorrectly called "ymodem"). XThe user must supply the file name to both sending and receiving programs. X XIff X.B sz Xis invoked with $SHELL set and iff that variable contains the Xstring X.I "rsh" Xor X.I "rksh" X(restricted shell), X.B sz Xoperates in restricted mode. XRestricted mode restricts pathnames to the current directory and XPUBDIR (usually /usr/spool/uucppublic) and/or subdirectories Xthereof. X X XThe fourth form sends a single COMMAND to a ZMODEM receiver for execution. X.B Sz Xexits with the COMMAND return value. XIf COMMAND includes spaces or characters special to the shell, Xit must be quoted. X X XThe fifth form sends a single COMMAND to a ZMODEM receiver for execution. X.B Sz Xexits as soon as the receiver has correctly received the command, Xbefore it is executed. X X XThe sixth form (sz -TT) Xattempts to output all 256 code combinations to the terminal. XIn you are having difficulty sending files, Xthis command lets you see which character codes are being Xeaten by the operating system. X X XIf X.B sz Xis invoked with stdout and stderr to different datasets, XVerbose is set to 2, causing frame by frame progress reports Xto stderr. XThis may be disabled with the X.B q Xoption. X.PP XThe meanings of the available options are: X.PP X.PD 0 X.TP X.B X\\ X.R X(VMS) Force the next option letter to upper case. X.TP X.B + XInstruct the receiver to append transmitted data to an existing file X(ZMODEM only). X.TP X.B a XConvert NL characters in the transmitted file to CR/LF. XThis is done by the sender for XMODEM and YMODEM, by the receiver Xfor ZMODEM. X.TP X.B b X(ZMODEM) Binary override: transfer file without any translation. X.TP X.B "c COMMAND" XSend COMMAND to the receiver for execution, return with COMMAND\'s exit status. X.TP X.B d XChange all instances of "." to "/" in the transmitted pathname. XThus, C.omenB0000 (which is unacceptable to MSDOS or CP/M) Xis transmitted as C/omenB0000. XIf the resultant filename has more than 8 characters in the stem, Xa "." is inserted to allow a total of eleven. X.TP X.B e XEscape all control characters; Xnormally XON, XOFF, DLE, CR-@-CR, and Ctrl-X are escaped. X.TP X.B f XSend Full pathname. XNormally directory prefixes are stripped from the transmitted Xfilename. X.TP X.B "i COMMAND" XSend COMMAND to the receiver for execution, return Immediately Xupon the receiving program's successful recption of the command. X.TP X.B k X(XMODEM/YMODEM) Send files using 1024 byte blocks Xrather than the default 128 byte blocks. X1024 byte packets speed file transfers at high bit rates. X(ZMODEM streams the data for the best possible throughput.) X.TP X.B "L N" XUse ZMODEM sub-packets of length N. XA larger N (32 <= N <= 1024) gives slightly higher throughput, Xa smaller N speeds error recovery. XThe default is 128 below 300 baud, 256 above 300 baud, or 1024 above 2400 baud. X.TP X.B "l N" XWait for the receiver to acknowledge correct data every X.B N X(32 <= N <= 1024) Xcharacters. XThis may be used to avoid network overrun when XOFF flow control is lacking. X.TP X.B n X(ZMODEM) Send each file if Xdestination file does not exist. XOverwrite destination file if Xsource file is newer than the destination file. X.TP X.B N X(ZMODEM) Send each file if Xdestination file does not exist. XOverwrite destination file if Xsource file is newer or longer than the destination file. X.TP X.B o X(ZMODEM) Disable automatic selection of 32 bit CRC. X.TP X.B p X(ZMODEM) Protect existing destination files by skipping transfer if the Xdestination file exists. X.TP X.B q XQuiet suppresses verbosity. X.TP X.B r X(ZMODEM) Resume interrupted file transfer. XIf the source file is longer than the destination file, Xthe transfer commences at the offset in the source file that equals Xthe length of the destination file. X.TP X.B "t tim" XChange timeout to X.I tim Xtenths of seconds. X.TP X.B u XUnlink the file after successful transmission. X.TP X.B "w N" XLimit the transmit window size to N bytes (ZMODEM). X.TP X.B v XVerbose Xcauses a list of file Xnames to be appended to X/tmp/szlog . XMore v's generate more output. X.TP X.B y XInstruct a ZMODEM receiving program to overwrite any existing file Xwith the same name. X.TP X.B Y XInstruct a ZMODEM receiving program to overwrite any existing file Xwith the same name, Xand to skip any source files that do have a file with the same Xpathname on the destination system. X.PD X.SH EXAMPLES X.ne 7 X.B "ZMODEM File Transfer" X(Unix to DSZ/ZCOMM/Professional-YAM) X.br X.B "% sz \-a *.c" X.br XThis single command transfers all .c files in the current Unix directory Xwith conversion X.RB ( \-a ) Xto end of line conventions appropriate to the receiving environment. XWith ZMODEM AutoDownload enabled, Professional-YAM and ZCOMM Xwill automatically recieve Xthe files after performing a security check. X X.br X.B "% sz \-Yan *.c *.h" X.br XSend only the .c and .h files that exist on both systems, Xand are newer on the sending system than the Xcorresponding version on the receiving system, converting Unix to XDOS text format. X.br X.B X$ sz -\\Yan file1.c file2.c file3.c foo.h baz.h X.R X(for VMS) X.br X X.B "ZMODEM Command Download" X(Unix to Professional-YAM) X.br X cpszall:all X sz \-c "c:;cd /yam/dist" X sz \-ya $(YD)/*.me X sz \-yqb y*.exe X sz \-c "cd /yam" X sz \-i "!insms" X.br XThis Makefile fragment uses X.B sz Xto issue commands to Professional-YAM to change current disk and directory. XNext, X.B sz Xtransfers the X.I .me Xfiles from the $YD directory, commanding the receiver to overwrite the old files Xand to convert from Unix end of line conventions to PC-DOS conventions. XThe third line transfers some X.I .exe Xfiles. XThe fourth and fifth lines command Pro-YAM to Xchange directory and execute a PC-DOS batch file X.I insms . XSince the batch file takes considerable time, the X.B "\-i" Xform is used to allow X.B sz Xto exit immediately. X X.B "XMODEM File Transfer" X(Unix to Crosstalk) X.br X% X.B "sx \-a foo.c" X.br X.B "ESC" X.br X.B "rx foo.c" X.br XThe above three commands transfer a single file Xfrom Unix to a PC and Crosstalk with X.I sz Xtranslating Unix newlines to DOS CR/LF. XThis combination is much slower and far less reliable than ZMODEM. X.SH ERROR MESSAGES X"Caught signal 99" Xindicates the program was not properly compiled, Xrefer to "bibi(99)" in rbsb.c for details. X.SH SEE ALSO Xrz(omen), XZMODEM.DOC, XYMODEM.DOC, XProfessional-YAM, Xcrc(omen), Xsq(omen), Xtodos(omen), Xtocpm(omen), Xtomac(omen), Xyam(omen) X XCompile time options required for various operating systems are described in Xthe source file. X.SH "VMS VERSION" XThe VMS version does not support wild cards. XBecause of VMS DCL, upper case option letters muse be represented Xby \\ proceding the letter. X XThe current VMS version does not support XMODEM, XMODEM-1k, or YMODEM. X XVMS C Standard I/O and RMS may interact to modify the file contents. X.SH FILES X32 bit CRC code courtesy Gary S. Brown. X Xsz.c, crctab.c, rbsb.c, zm.c, zmodem.h Unix source files X Xsz.c, crctab.c, vrzsz.c, zm.c, zmodem.h, vmodem.h, vvmodem.c, XVMS source files. X X/tmp/szlog stores debugging output (sz -vv) X(szlog on VMS). X.SH "TESTING FEATURE" XThe command "sz -T file" Xexercises the X.B Attn Xsequence error recovery by commanding Xerrors with unterminated packets. XThe receiving program should complain five times about Xbinary data packets being too long. XEach time X.B sz Xis interrupted, Xit should send a ZDATA header followed by another defective packet. XIf the receiver does not detect five long data packets, Xthe X.B Attn Xsequence is not interrupting the sender, and the X.B Myattn Xstring in X.B sz.c Xmust be modified. X XAfter 5 packets, X.B sz Xstops the "transfer" and Xprints the total number of characters "sent" (Tcount). XThe difference between Tcount and 5120 represents the number of characters Xstored in various buffers when the Attn sequence is generated. X.SH BUGS XCalling X.I sz Xfrom most versions of cu(1) doesn't work because cu's receive process Xfights X.I sz Xfor characters from the modem. X XPrograms that do not properly implement the specified file transfer protocol Xmay cause X.I sz Xto "hang" the port for a minute or two. XEvery reported instance of this problem has been corrected by using XZCOMM, Pro-YAM, or other program with a correct implementation Xof the specified protocol. X XMany programs claiming to support YMODEM only support XMODEM with 1k blocks, Xand they often don't get that quite right. X XXMODEM transfers add up to 127 garbage bytes per file. XXMODEM-1k and YMODEM-1k transfers use 128 byte blocks Xto avoid extra padding. X XYMODEM programs use the file length transmitted at the beginning of the Xtransfer to prune the file to the correct length; this may cause problems with Xsource files that grow during the course of the transfer. XThis problem does not pertain to ZMODEM transfers, which preserve the exact Xfile length unconditionally. X XMost ZMODEM options are merely passed to the receiving program; Xsome do not implement all these options. X XCircular buffering and a ZMODEM sliding window should be used Xwhen input is from pipes instead of acknowledging frames each 1024 bytes. XIf no files can be opened, X.B sz Xsends a ZMODEM command to echo a suitable complaint; Xperhaps it should check for the presence of at least one accessible file before Xgetting hot and bothered. XThe test mode leaves a zero length file on the receiving system. X XA few high speed modems have a firmware bug that drops characters when the Xdirection of high speed transmissson is reversed. XThe environment variable ZNULLS may be used to specify the number of nulls to Xsend before a ZDATA frame. XValues of 101 for a 4.77 mHz PC and 124 for an AT are typical. SHAR_EOF chmod 0644 sz.1 || echo "restore of sz.1 fails" echo "x - extracting sz.c (Text)" sed 's/^X//' << 'SHAR_EOF' > sz.c && X#define VERSION "sz 2.02 04-27-88" X#define PUBDIR "/usr/spool/uucppublic" X X/*% cc -compat -M2 -Ox -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz X<-xtx-*> cc -Osal -K -i -DSV sz.c -lx -o $B/sz; size $B/sz X * X * sz.c By Chuck Forsberg X * X * cc -O sz.c -o sz USG (SYS III/V) Unix X * cc -O -DSV sz.c -o sz Sys V Release 2 with non-blocking input X * Define to allow reverse channel checking X * cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD X * X * cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz Xenix X * X * ln sz sb **** All versions **** X * ln sz sx **** All versions **** X * X * X * Typical VMS compile and install sequence: X * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB X * cc sz.c X * cc vvmodem.c X * link sz,vvmodem X * X * sz :== $disk$user2:[username.subdir]sz.exe X * 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 * 2.x has mods for VMS flavor X * X * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS X * in accordance with the 7-31-87 ZMODEM Protocol Description X */ X X Xchar *substr(), *getenv(); X X#ifdef vax11c X#include X#include X#define LOGFILE "szlog.tmp" X#include X#include X#include X#include X#include X#define OS "VMS" X#define READCHECK X#define BUFWRITE X#define iofd Xextern int errno; X#define SS_NORMAL SS$_NORMAL X#define xsendline(c) sendline(c) X X X#else /* vax11c */ X X X#define SS_NORMAL 0 X#define LOGFILE "/tmp/szlog" X#include X#include X#include X#include X#include Xextern int errno; X X#define sendline(c) putchar(c & 0377) X#define xsendline(c) putchar(c) X X#endif X X#define PATHLEN 256 X#define OK 0 X#define FALSE 0 X#define TRUE 1 X#define ERROR (-1) X/* Ward Christensen / CP/M parameters - Don't change these! */ X#define ENQ 005 X#define CAN ('X'&037) X#define XOFF ('s'&037) X#define XON ('q'&037) X#define SOH 1 X#define STX 2 X#define EOT 4 X#define ACK 6 X#define NAK 025 X#define CPMEOF 032 X#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ X#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */ X#define TIMEOUT (-2) X#define RCDO (-3) X#define RETRYMAX 10 X X X#define HOWMANY 2 Xint Zmodem=0; /* ZMODEM protocol requested by receiver */ Xunsigned Baudrate=2400; /* Default, should be set by first mode() call */ Xunsigned Txwindow; /* Control the size of the transmitted window */ Xunsigned Txwspac; /* Spacing between zcrcq requests */ Xunsigned Txwcnt; /* Counter used to space ack requests */ Xlong Lrxpos; /* Receiver's last reported offset */ Xint errors; X X#ifdef vax11c X#include "vrzsz.c" /* most of the system dependent stuff here */ X#else X#include "rbsb.c" /* most of the system dependent stuff here */ X#endif X#include "crctab.c" X Xint Filesleft; Xlong Totalleft; 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 XFILE *in; Xchar Lastrx; Xchar Crcflg; Xint Verbose=0; Xint Modem2=0; /* XMODEM Protocol - don't send pathnames */ Xint Restricted=0; /* restricted; no /.. or ../ in filenames */ Xint Quiet=0; /* overrides logic that would otherwise set verbose */ Xint Ascii=0; /* Add CR's for brain damaged programs */ Xint Fullname=0; /* transmit full pathname */ Xint Unlinkafter=0; /* Unlink file after it is sent */ Xint Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */ Xint firstsec; Xint errcnt=0; /* number of files unreadable */ Xint blklen=128; /* length of transmitted records */ Xint Optiong; /* Let it rip no wait for sector ACK's */ Xint Noeofseen; Xint Totsecs; /* total number of sectors this file */ Xchar txbuf[1024]; Xint Filcnt=0; /* count of number of files opened */ Xint Lfseen=0; Xunsigned Rxbuflen = 16384; /* Receiver's max buffer length */ Xint Tframlen = 0; /* Override for tx frame length */ Xint blkopt=0; /* Override value for zmodem blklen */ Xint Rxflags = 0; Xlong bytcnt; Xint Wantfcs32 = TRUE; /* want to send 32 bit FCS */ Xchar Lzconv; /* Local ZMODEM file conversion request */ Xchar Lzmanag; /* Local ZMODEM file management request */ Xint Lskipnocor; 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 Test; /* 1= Force receiver to send Attn, etc with qbf. */ X /* 2= Character transparency test */ 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 Lastn; /* Count of last buffer read or -1 */ Xint Dontread; /* Don't read the buffer, it's still there */ Xlong Lastsync; /* Last offset to which we got a ZRPOS */ Xint Beenhereb4; /* How many times we've been ZRPOS'd same place */ 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 if (n == 99) X fprintf(stderr, "mode(2) in rbsb.c not implemented!!\n"); X cucheck(); 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 Xint Zctlesc; /* Encode control characters */ Xint Nozmodem = 0; /* If invoked as "sb" */ Xchar *Progname = "sz"; Xint Zrwindow = 1400; /* RX window size (controls garbage count) */ X#include "zm.c" X X Xmain(argc, argv) Xchar *argv[]; X{ X register char *cp; X register npats; X int dm; 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 from_cu(); 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 *cp = toupper(*cp); continue; X case '+': X Lzmanag = ZMAPND; break; X#ifdef CSTOPB X case '2': X Twostop = TRUE; break; X#endif 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 'k': X blklen=1024; 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 = ZMNEWL; 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 if (++Test > 1) { X chartest(1); chartest(2); X mode(0); exit(0); X } X break; X#ifndef vax11c X case 'u': X ++Unlinkafter; break; X#endif X case 'v': X ++Verbose; break; X case 'w': X if (--argc < 1) { X usage(); X } X Txwindow = atoi(*++argv); X if (Txwindow < 256) X Txwindow = 256; X Txwindow = (Txwindow/64) * 64; X Txwspac = Txwindow/4; X if (blkopt > Txwspac X || (!blkopt && Txwspac < 1024)) X blkopt = Txwspac; X break; X case 'X': X ++Modem2; break; X case 'Y': X Lskipnocor = TRUE; X /* **** FALLL THROUGH TO **** */ 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#ifndef vax11c X if ( !strcmp(*patts, "-")) X iofd = 1; X#endif X } X } X } X if (npats < 1 && !Command && !Test) 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 && !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 signal(SIGTERM, bibi); X X if ( !Modem2) { X if (!Nozmodem) { X printf("rz\r"); fflush(stdout); X } X countem(npats, patts); 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 dm = ((errcnt != 0) | Exitcode); X if (dm) { X cucheck(); exit(dm); X } X exit(SS_NORMAL); X /*NOTREACHED*/ X} X Xwcsend(argc, argp) Xchar *argp[]; X{ X register n; X X Crcflg=FALSE; X firstsec=TRUE; X bytcnt = -1; X for (n=0; n>7); X } X fprintf(stderr, "Give your local XMODEM receive command now.\r\n"); X return OK; X } X zperr("Awaiting pathname nak for %s", *name?name:""); 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 + 1024)) X *q++ = 0; X if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1) X sprintf(p, "%lu %lo %o 0 %d %ld", f.st_size, f.st_mtime, X f.st_mode, Filesleft, Totalleft); X Totalleft -= f.st_size; X if (--Filesleft <= 0) X Totalleft = 0; X if (Totalleft < 0) X Totalleft = 0; X X /* force 1k blocks if name won't fit in 128 byte block */ X if (txbuf[125]) X blklen=1024; X else { /* A little goodie for IMP/KMD */ 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, 128)==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; /* Receiver does the conversion */ X return FALSE; X case TIMEOUT: X zperr("Timeout on pathname"); X return TRUE; X case WANTG: X#ifdef MODE2OK X mode(2); /* Set cbreak, XON/XOFF, etc. */ X#endif X Optiong = TRUE; X blklen=1024; 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(flen) Xlong flen; X{ X register int thisblklen; X register int sectnum, attempts, firstch; X long charssent; X X charssent = 0; firstsec=TRUE; thisblklen = blklen; X vfile("wctx:file length=%ld", flen); X X while ((firstch=readock(Rxtimeout, 2))!=NAK && firstch != WANTCRC X && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN) X ; X if (firstch==CAN) { X zperr("Receiver CANcelled"); X return ERROR; X } X if (firstch==WANTCRC) X Crcflg=TRUE; X if (firstch==WANTG) X Crcflg=TRUE; X sectnum=0; X for (;;) { X if (flen <= (charssent + 896L)) X thisblklen = 128; X if ( !filbuf(txbuf, thisblklen)) X break; X if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR) X return ERROR; X charssent += thisblklen; X } X fclose(in); X attempts=0; X do { 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 zperr("No ACK on EOT"); 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>2) X fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 ); X else 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==1024?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 zperr("Cancelled"); return ERROR; X } X break; X case TIMEOUT: X zperr("Timeout on sector ACK"); continue; X case WANTCRC: X if (firstsec) X Crcflg = TRUE; X case NAK: X zperr("NAK on sector"); continue; X case ACK: X firstsec=FALSE; X Totsecs += (cseclen>>7); X return OK; X case ERROR: X zperr("Got burst for sector ACK"); break; X default: X zperr("Got %02x for sector ACK", 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 zperr("Retry Count Exceeded"); 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 > 2) { 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#ifndef vax11c 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 zperr("TIMEOUT"); X return TIMEOUT; X } X c = timeout/10; X if (c<2) X c=2; X if (Verbose>5) { X fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c); X byt[1] = 0; X } X signal(SIGALRM, alrm); alarm(c); SHAR_EOF echo "End of part 2" echo "File sz.c is continued in part 3" echo "3" > s2_seq_.tmp exit 0 -- Keith Petersen Arpa: W8SDZ@SIMTEL20.ARPA Uucp: {bellcore,decwrl,harvard,lll-crg,ucbvax,uw-beaver}!simtel20.arpa!w8sdz GEnie: W8SDZ