#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'rz.c' <<'END_OF_FILE' X#define VERSION "3.00 4-19-89" X#define PUBDIR "/usr/spool/uucppublic" X X/*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz; X<-xtx-*> cc386 -Ox -DMD rz.c -o $B/rz; size $B/rz X * X * rz.c By Chuck Forsberg X * X * cc -O rz.c -o rz USG (3.0) Unix X * cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3 X * X * ln rz rb; ln rz rx For either system X * X * ln rz /usr/bin/rzrmail For remote mail. Make this the X * login shell. rzrmail then calls X * rmail(1) to deliver mail. X * X * To compile on VMS: X * X * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB X * cc rz.c X * cc vvmodem.c X * link rz,vvmodem X * rz :== $disk:[username.subdir]rz.exe X * For high speed, try increasing the SYSGEN parameter TTY_TYPAHDSZ to 256. X * X * X * Unix is a trademark of Western Electric Company X * X * A program for Unix to receive files and commands from computers running X * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. X * rz uses Unix buffered input to reduce wasted CPU time. X * X * This version implements ZMODEM Run Length Encoding X * and variable length headers. These features were not funded X * by the original Telenet development contract. This software, X * including these features, may be freely used for non X * commercial and educational purposes. This software may also X * be freely used to support file transfer operations to or from X * licensed Omen Technology products. Contact Omen Technology X * for licensing for other uses. Any programs which use part or X * all of this software must be provided in source form with this X * notice intact except by written permission from Omen X * Technology Incorporated. X * X * Omen Technology Inc FAX: 503-621-3745 X * Post Office Box 4681 X * Portland OR 97208 X * X * Previous versions of this program (not containing the extensions X * listed above) remain in the public domain. X * X * This code is made available in the hope it will be useful, X * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY X * DAMAGES OF ANY KIND. X * X * X * Iff the program is invoked by rzCOMMAND, output is piped to X * "COMMAND filename" (Unix only) X * X * Some systems (Venix, Coherent, Regulus) may not support tty raw mode X * read(2) the same way as Unix. ONEREAD must be defined to force one X * character reads for these systems. Added 7-01-84 CAF X * X * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF X * X * BIX added 6-30-87 to support BIX(TM) upload protocol used by the X * Byte Information Exchange. X * X * NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN] X * doesn't work properly (even though it compiles without error!), X * X * SEGMENTS=n added 2-21-88 as a model for CP/M programs X * for CP/M-80 systems that cannot overlap modem and disk I/O. X * X * VMS flavor hacks begin with rz version 2.00 X * X * -DMD may be added to compiler command line to compile in X * Directory-creating routines from Public Domain TAR by John Gilmore X * X * HOWMANY may be tuned for best performance X * X * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin X */ X X#ifdef vax11c X#include X#include X#define LOGFILE "rzlog.tmp" X#include X#include X#include X#include X#include X#define OS "VMS" X#define BUFREAD Xextern int errno; X#define SS_NORMAL SS$_NORMAL X X#ifndef PROGNAME X#define PROGNAME "rz" X#endif X X X#else X X X#define SS_NORMAL 0 X#define LOGFILE "/tmp/rzlog" X#include X#include X#include X#include X#include Xextern int errno; XFILE *popen(); X#endif X X#define OK 0 X#define FALSE 0 X#define TRUE 1 X#define ERROR (-1) X X/* X * Max value for HOWMANY is 255. X * A larger value reduces system overhead but may evoke kernel bugs. X * 133 corresponds to an XMODEM/CRC sector X */ X#ifndef HOWMANY X#define HOWMANY 133 X#endif X 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 TIMEOUT (-2) X#define RCDO (-3) X#define GCOUNT (-4) X#define ERRORMAX 5 X#define RETRYMAX 5 X#define WCEOT (-10) X#define PATHLEN 257 /* ready for 4.2 bsd ? */ X#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */ X Xint Zmodem=0; /* ZMODEM protocol requested */ Xint Nozmodem = 0; /* If invoked as "rb" */ Xunsigned Baudrate = 2400; Xunsigned Effbaud = 2400; 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 Xchar *substr(); XFILE *fout; X X/* X * Routine to calculate the free bytes on the current file system X * ~0 means many free bytes (unknown) X */ Xlong getfree() X{ X return(~0L); /* many free bytes ... */ X} X Xint Lastrx; Xint Crcflg; Xint Firstsec; Xint Eofseen; /* indicates cpm eof (^Z) has been received */ Xint errors; Xint Restricted=0; /* restricted; no /.. or ../ in filenames */ X#ifdef ONEREAD X/* Sorry, Regulus and some others don't work right in raw mode! */ Xint Readnum = 1; /* Number of bytes to ask for in read() from modem */ X#else Xint Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */ X#endif X X#define DEFBYTL 2000000000L /* default rx file size */ Xlong Bytesleft; /* number of bytes of incoming file left */ Xlong Modtime; /* Unix style mod time for incoming file */ Xint Filemode; /* Unix style mode for incoming file */ Xchar Pathname[PATHLEN]; Xchar *Progname; /* the name by which we were called */ X Xint Batch=0; Xint Topipe=0; Xint MakeLCPathname=TRUE; /* make received pathname lower case */ Xint Verbose=0; Xint Quiet=0; /* overrides logic that would otherwise set verbose */ Xint Nflag = 0; /* Don't really transfer files */ Xint Rxclob=FALSE; /* Clobber existing file */ Xint Rxbinary=FALSE; /* receive all files in bin mode */ Xint Rxascii=FALSE; /* receive files in ascii (translate) mode */ Xint Thisbinary; /* current file is to be received in bin mode */ Xint Blklen; /* record length of received packets */ X X#ifdef SEGMENTS Xint chinseg = 0; /* Number of characters received in this data seg */ Xchar secbuf[1+(SEGMENTS+1)*1024]; X#else Xchar secbuf[1025]; X#endif X X Xchar linbuf[HOWMANY]; Xint Lleft=0; /* number of characters in linbuf */ Xtime_t timep[2]; Xchar Lzmanag; /* Local file management request */ Xchar zconv; /* ZMODEM file conversion request */ Xchar zmanag; /* ZMODEM file management request */ Xchar ztrans; /* ZMODEM file transport request */ Xint Zctlesc; /* Encode control characters */ Xint Zrwindow = 1400; /* RX window size (controls garbage count) */ X Xjmp_buf tohere; /* For the interrupt on RX timeout */ X X#define xsendline(c) sendline(c) X X#include "zm.c" X X#include "zmr.c" X Xint tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */ X Xalrm() X{ X longjmp(tohere, -1); X} X X/* called by signal interrupt or terminate to clean things up */ Xbibi(n) X{ X if (Zmodem) X zmputs(Attn); X canit(); mode(0); X fprintf(stderr, "rz: caught signal %d; exiting", n); X cucheck(); X exit(128+n); X} X Xmain(argc, argv) Xchar *argv[]; X{ X register char *cp; X register npats; X char *virgin, **patts; X char *getenv(); X int exitcode; X X Rxtimeout = 100; X setbuf(stderr, NULL); X if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh"))) X Restricted=TRUE; X X from_cu(); X#ifdef vax11c X chkinvok(virgin = PROGNAME); X#else X chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */ X#endif X npats = 0; X while (--argc) { X cp = *++argv; X if (*cp == '-') { X while( *++cp) { X switch(*cp) { X case '\\': X cp[1] = toupper(cp[1]); continue; X case '+': X Lzmanag = ZMAPND; break; X case 'a': X Rxascii=TRUE; break; X case 'b': X Rxbinary=TRUE; break; X case 'c': X Crcflg=TRUE; break; X#ifndef vax11c X case 'D': X Nflag = TRUE; break; X#endif X case 'e': X Zctlesc = 1; break; X case 'p': X Lzmanag = ZMPROT; break; 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 'w': X if (--argc < 1) { X usage(); X } X Zrwindow = atoi(*++argv); X break; X case 'u': X MakeLCPathname=FALSE; break; X case 'v': X ++Verbose; break; X case 'y': X Rxclob=TRUE; 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 } X } X } X if (npats > 1) X usage(); X if (Batch && npats) 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 fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname); X } X if (Fromcu && !Quiet) { X if (Verbose == 0) X Verbose = 2; X } X vfile("%s %s for %s\n", Progname, VERSION, OS); X mode(1); X if (signal(SIGINT, bibi) == SIG_IGN) { X signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); X } X else { X signal(SIGINT, bibi); signal(SIGKILL, bibi); X } X signal(SIGTERM, bibi); X if (wcreceive(npats, patts)==ERROR) { X exitcode=0200; X canit(); X } X mode(0); X if (exitcode && !Zmodem) /* bellow again with all thy might. */ X canit(); X if (exitcode) X cucheck(); X exit(exitcode ? exitcode:SS_NORMAL); X} X X Xusage() X{ X cucheck(); X fprintf(stderr,"Usage: rz [-abeuvy] (ZMODEM)\n"); X fprintf(stderr,"or rb [-abuvy] (YMODEM)\n"); X fprintf(stderr,"or rx [-abcv] file (XMODEM or XMODEM-1k)\n"); X fprintf(stderr," -a ASCII transfer (strip CR)\n"); X fprintf(stderr," -b Binary transfer for all files\n"); X#ifndef vax11c X fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n"); X#endif X fprintf(stderr," -e Escape control characters (ZMODEM)\n"); X fprintf(stderr," -v Verbose more v's give more info\n"); X fprintf(stderr," -y Yes, clobber existing file if any\n"); X fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n", X Progname, VERSION, OS); X fprintf(stderr, "\t\t\042The High Reliability Software\042\n"); X exit(SS_NORMAL); X} X/* X * Debugging information output interface routine 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/* X * Let's receive something already. X */ X Xchar *rbmsg = X"%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n"; X Xwcreceive(argc, argp) Xchar **argp; X{ X register c; X X if (Batch || argc==0) { X Crcflg=1; X if ( !Quiet) X fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz"); 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 Modtime = 1; 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(0, 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(0, 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(0, TCFLSH, 0); X#else X lseek(0, 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 > 0) { 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#ifndef vax11c X if (name[0] == '!' || name[0] == '|') { X if ( !(fout = popen(name+1, "w"))) { X return ERROR; X } X Topipe = -1; return(OK); X } X#endif 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 char *strchr(); 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/* 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 = 1; X if (s[2] && s[0]=='r' && s[1]=='z') X Topipe = 1; X} 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 Txhdr[ZF0] |= CANRLE; X Txhdr[ZF1] = CANVHDR; X /* tryzhdrtype may == ZRINIT */ X zshhdr(4,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 if (Rxhdr[ZF3] & 0x80) X Usevhdrs = 1; /* we can var header */ 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 if (Rxhdr[ZF3] & ZCANVHDR) X Usevhdrs = TRUE; X tryzhdrtype = ZRINIT; X c = zrdata(secbuf, 1024); X mode(3); X if (c == GOTCRCW) X return ZFILE; X zshhdr(4,ZNAK, Txhdr); X goto again; X case ZSINIT: X Zctlesc = TESCCTL & Rxhdr[ZF0]; X if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { X stohdr(1L); X zshhdr(4,ZACK, Txhdr); X goto again; X } X zshhdr(4,ZNAK, Txhdr); X goto again; X case ZFREECNT: X stohdr(getfree()); X zshhdr(4,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(4,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(4,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(4,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 Modtime = 1; 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, Crc32r?" 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(4,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(4,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 time_t time(); 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(4,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 */ END_OF_FILE if test 32265 -ne `wc -c <'rz.c'`; then echo shar: \"'rz.c'\" unpacked with wrong size! fi # end of 'rz.c' fi if test -f 'zm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'zm.c'\" else echo shar: Extracting \"'zm.c'\" \(17884 characters\) sed "s/^X//" >'zm.c' <<'END_OF_FILE' X/* X * Z M . C X * ZMODEM protocol primitives X * 04-17-89 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 * This version implements ZMODEM Run Length Encoding, Comparision, X * and variable length headers. These features were not funded X * by the original Telenet development contract. This software, X * including these features, may be freely used for non X * commercial and educational purposes. This software may also X * be freely used to support file transfer operations to or from X * licensed Omen Technology products. Contact Omen Technology X * for licensing for other uses. Any programs which use part or X * all of this software must be provided in source form with this X * notice intact except by written permission from Omen X * Technology Incorporated. X * X * Omen Technology Inc FAX: 503-621-3745 X * Post Office Box 4681 X * Portland OR 97208 X * X * Previous versions of this program (not containing the extensions X * listed above) remain in the public domain. X * X * This code is made available in the hope it will be useful, X * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY X * DAMAGES OF ANY KIND. X * X */ X X#ifndef CANFDX X#include "zmodem.h" Xint Rxtimeout = 100; /* Tenths of seconds to wait for something */ X#endif X X#ifndef UNSL X#define UNSL X#endif X X X/* Globals used by ZMODEM functions */ Xint Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ Xint Rxtype; /* Type of header received */ Xint Rxhlen; /* Length of header received */ Xint Rxcount; /* Count of data bytes received */ Xchar Rxhdr[ZMAXHLEN]; /* Received header */ Xchar Txhdr[ZMAXHLEN]; /* Transmitted header */ Xlong Rxpos; /* Received file position */ Xlong Txpos; /* Transmitted file position */ Xint Txfcs32; /* TURE means send binary frames with 32 bit FCS */ Xint Crc32t; /* Controls 32 bit CRC being sent */ X /* 1 == CRC32, 2 == CRC32 + RLE */ Xint Crc32r; /* Indicates/controls 32 bit CRC being received */ X /* 0 == CRC16, 1 == CRC32, 2 == CRC32 + RLE */ Xint Usevhdrs; /* Use variable length headers */ Xint Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ Xchar Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ Xchar *Altcan; /* Alternate canit string */ X Xstatic lastsent; /* Last char we sent */ Xstatic Not8bit; /* Seven bits seen on header */ X Xstatic char *frametypes[] = { X "No Response to Error Correction Request", /* -4 */ X "No Carrier Detect", /* -3 */ X "TIMEOUT", /* -2 */ X "ERROR", /* -1 */ X#define FTOFFSET 4 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 Xstatic char badcrc[] = "Bad CRC"; X X/* Send ZMODEM binary header hdr of type type */ Xzsbhdr(len, type, hdr) Xregister char *hdr; X{ X register int n; X register unsigned short crc; X X#ifndef DSZ X vfile("zsbhdr: %c %d %s %lx", Usevhdrs?'v':'f', len, X frametypes[type+FTOFFSET], rclhdr(hdr)); X#endif X if (type == ZDATA) X for (n = Znulls; --n >=0; ) X xsendline(0); X X xsendline(ZPAD); xsendline(ZDLE); X X switch (Crc32t=Txfcs32) { X case 2: X zsbh32(len, hdr, type, Usevhdrs?ZVBINR32:ZBINR32); X flushmo(); break; X case 1: X zsbh32(len, hdr, type, Usevhdrs?ZVBIN32:ZBIN32); break; X default: X if (Usevhdrs) { X xsendline(ZVBIN); X zsendline(len); X } X else X xsendline(ZBIN); X zsendline(type); X crc = updcrc(type, 0); X X for (n=len; --n >= 0; ++hdr) { 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(len, hdr, type, flavour) Xregister char *hdr; X{ X register int n; X register UNSL long crc; X X xsendline(flavour); X if (Usevhdrs) X zsendline(len); X zsendline(type); X crc = 0xFFFFFFFFL; crc = UPDC32(type, crc); X X for (n=len; --n >= 0; ++hdr) { X crc = UPDC32((0377 & *hdr), crc); X zsendline(*hdr); X } X crc = ~crc; X for (n=4; --n >= 0;) { X zsendline((int)crc); X crc >>= 8; X } X} X X/* Send ZMODEM HEX header hdr of type type */ Xzshhdr(len, type, hdr) Xregister char *hdr; X{ X register int n; X register unsigned short crc; X X#ifndef DSZ X vfile("zshhdr: %c %d %s %lx", Usevhdrs?'v':'f', len, X frametypes[type+FTOFFSET], rclhdr(hdr)); X#endif X sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); X if (Usevhdrs) { X sendline(ZVHEX); X zputhex(len); X } X else X sendline(ZHEX); X zputhex(type); X Crc32t = 0; X X crc = updcrc(type, 0); X for (n=len; --n >= 0; ++hdr) { 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(0212); X /* X * Uncork the remote in case a fake XOFF has stopped data flow X */ X if (type != ZFIN && type != ZACK) X sendline(021); X flushmo(); X} X X/* X * Send binary array buf of length length, with ending ZDLE sequence frameend X */ Xstatic char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"}; Xzsdata(buf, length, frameend) Xregister char *buf; X{ X register unsigned short crc; X X#ifndef DSZ X vfile("zsdata: %d %s", length, Zendnames[frameend-ZCRCE&3]); X#endif X switch (Crc32t) { X case 1: X zsda32(buf, length, frameend); break; X case 2: X zsdar32(buf, length, frameend); break; X default: X crc = 0; X for (;--length >= 0; ++buf) { X zsendline(*buf); crc = updcrc((0377 & *buf), crc); X } X xsendline(ZDLE); xsendline(frameend); X crc = updcrc(frameend, crc); X X crc = updcrc(0,updcrc(0,crc)); X zsendline(crc>>8); zsendline(crc); X } X if (frameend == ZCRCW) { X xsendline(XON); flushmo(); X } X} X Xzsda32(buf, length, frameend) Xregister char *buf; X{ X register int c; X register UNSL long crc; X X crc = 0xFFFFFFFFL; X for (;--length >= 0; ++buf) { X c = *buf & 0377; X if (c & 0140) X xsendline(lastsent = c); X else X zsendline(c); X crc = UPDC32(c, crc); X } X xsendline(ZDLE); xsendline(frameend); X crc = UPDC32(frameend, crc); X X crc = ~crc; X for (c=4; --c >= 0;) { X zsendline((int)crc); crc >>= 8; X } X} X X/* X * Receive array buf of max length with ending ZDLE sequence X * and CRC. Returns the ending character or error code. X * NB: On errors may store length+1 bytes! X */ Xzrdata(buf, length) Xregister char *buf; X{ X register int c; X register unsigned short crc; X register char *end; X register int d; X X switch (Crc32r) { X case 1: X return zrdat32(buf, length); X case 2: X return zrdatr32(buf, length); X } X X crc = Rxcount = 0; end = buf + length; X while (buf <= end) { X if ((c = zdlread()) & ~0377) { Xcrcfoo: X switch (c) { X case GOTCRCE: X case GOTCRCG: X case GOTCRCQ: X case GOTCRCW: X crc = updcrc((d=c)&0377, crc); X if ((c = zdlread()) & ~0377) X goto crcfoo; X crc = updcrc(c, crc); X if ((c = zdlread()) & ~0377) X goto crcfoo; X crc = updcrc(c, crc); X if (crc & 0xFFFF) { X zperr(badcrc); X return ERROR; X } X Rxcount = length - (end - buf); X#ifndef DSZ X vfile("zrdata: %d %s", Rxcount, X Zendnames[d-GOTCRCE&3]); X#endif X return d; X case GOTCAN: X zperr("Sender Canceled"); X return ZCAN; X case TIMEOUT: X zperr("TIMEOUT"); X return c; X default: X garbitch(); return c; X } X } X *buf++ = c; X crc = updcrc(c, crc); X } X#ifdef DSZ X garbitch(); X#else X zperr("Data subpacket too long"); X#endif X return ERROR; X} X Xzrdat32(buf, length) Xregister char *buf; X{ X register int c; X register UNSL long crc; X register char *end; X register int d; X X crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; X while (buf <= end) { X if ((c = zdlread()) & ~0377) { Xcrcfoo: X switch (c) { X case GOTCRCE: X case GOTCRCG: X case GOTCRCQ: X case GOTCRCW: X d = c; c &= 0377; X crc = UPDC32(c, crc); X if ((c = zdlread()) & ~0377) X goto crcfoo; X crc = UPDC32(c, crc); X if ((c = zdlread()) & ~0377) X goto crcfoo; X crc = UPDC32(c, crc); X if ((c = zdlread()) & ~0377) X goto crcfoo; X crc = UPDC32(c, crc); X if ((c = zdlread()) & ~0377) X goto crcfoo; X crc = UPDC32(c, crc); X if (crc != 0xDEBB20E3) { X zperr(badcrc); X return ERROR; X } X Rxcount = length - (end - buf); X#ifndef DSZ X vfile("zrdat32: %d %s", Rxcount, X Zendnames[d-GOTCRCE&3]); X#endif X return d; X case GOTCAN: X zperr("Sender Canceled"); X return ZCAN; X case TIMEOUT: X zperr("TIMEOUT"); X return c; X default: X garbitch(); return c; X } X } X *buf++ = c; X crc = UPDC32(c, crc); X } X zperr("Data subpacket too long"); X return ERROR; X} X Xgarbitch() X{ X zperr("Garbled data subpacket"); X} X X/* X * Read a ZMODEM header to hdr, either binary or hex. X * eflag controls local display of non zmodem characters: X * 0: no display X * 1: display printing characters only X * 2: display all non ZMODEM characters X * On success, set Zmodem to 1, set Rxpos and return type of header. X * Otherwise return negative on error. X * Return ERROR instantly if ZCRCW sequence, for fast error recovery. X */ Xzgethdr(hdr, eflag) Xchar *hdr; X{ X register int c, n, cancount; X X n = Zrwindow + Effbaud; /* Max bytes before start of frame */ X Rxframeind = Rxtype = 0; X Xstartover: X cancount = 5; Xagain: X /* Return immediate ERROR if ZCRCW sequence seen */ X switch (c = readline(Rxtimeout)) { X case RCDO: X case TIMEOUT: X goto fifi; X case CAN: Xgotcan: X if (--cancount <= 0) { X c = ZCAN; goto fifi; X } X switch (c = readline(1)) { X case TIMEOUT: X goto again; X case ZCRCW: X switch (readline(1)) { X case TIMEOUT: X c = ERROR; goto fifi; X case RCDO: X goto fifi; X default: X goto agn2; X } X case RCDO: X goto fifi; X default: X break; X case CAN: X if (--cancount <= 0) { X c = ZCAN; goto fifi; X } X goto again; X } X /* **** FALL THRU TO **** */ X default: Xagn2: X if ( --n == 0) { X c = GCOUNT; goto fifi; X } X if (eflag && ((c &= 0177) & 0140)) X bttyout(c); X else if (eflag > 1) X bttyout(c); X#ifdef UNIX X fflush(stderr); X#endif X goto startover; X case ZPAD|0200: /* This is what we want. */ X Not8bit = c; X case ZPAD: /* This is what we want. */ X break; X } X cancount = 5; Xsplat: X switch (c = noxrd7()) { X case ZPAD: X goto splat; X case RCDO: X case TIMEOUT: X goto fifi; X default: X goto agn2; X case ZDLE: /* This is what we want. */ X break; X } X X X Rxhlen = 4; /* Set default length */ X Rxframeind = c = noxrd7(); X switch (c) { X case ZVBIN32: X if ((Rxhlen = c = readline(Rxtimeout)) < 0) X goto fifi; X if (c > ZMAXHLEN) X goto agn2; X Crc32r = 1; c = zrbhd32(hdr); break; X case ZBIN32: X if (Usevhdrs) X goto agn2; X Crc32r = 1; c = zrbhd32(hdr); break; X case ZVBINR32: X if ((Rxhlen = c = readline(Rxtimeout)) < 0) X goto fifi; X if (c > ZMAXHLEN) X goto agn2; X Crc32r = 2; c = zrbhd32(hdr); break; X case ZBINR32: X if (Usevhdrs) X goto agn2; X Crc32r = 2; c = zrbhd32(hdr); break; X case RCDO: X case TIMEOUT: X goto fifi; X case ZVBIN: X if ((Rxhlen = c = readline(Rxtimeout)) < 0) X goto fifi; X if (c > ZMAXHLEN) X goto agn2; X Crc32r = 0; c = zrbhdr(hdr); break; X case ZBIN: X if (Usevhdrs) X goto agn2; X Crc32r = 0; c = zrbhdr(hdr); break; X case ZVHEX: X if ((Rxhlen = c = zgethex()) < 0) X goto fifi; X if (c > ZMAXHLEN) X goto agn2; X Crc32r = 0; c = zrhhdr(hdr); break; X case ZHEX: X if (Usevhdrs) X goto agn2; X Crc32r = 0; c = zrhhdr(hdr); break; X case CAN: X goto gotcan; X default: X goto agn2; X } X Rxpos = hdr[ZP3] & 0377; X Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377); X Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377); X Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377); Xfifi: X switch (c) { X case GOTCAN: X c = ZCAN; X /* **** FALL THRU TO **** */ X case ZNAK: X case ZCAN: X case ERROR: X case TIMEOUT: X case RCDO: X case GCOUNT: X zperr("Got %s", frametypes[c+FTOFFSET]); X /* **** FALL THRU TO **** */ X#ifndef DSZ X default: X if (c >= -4 && c <= FRTYPES) X vfile("zgethdr: %c %d %s %lx", Rxframeind, Rxhlen, X frametypes[c+FTOFFSET], Rxpos); X else X vfile("zgethdr: %d %lx", c, Rxpos); X#endif X } X /* Use variable length headers if we got one */ X if (c >= 0 && c <= FRTYPES && Rxframeind & 040) X Usevhdrs = 1; X return c; X} X X/* Receive a binary style header (type and position) */ Xzrbhdr(hdr) Xregister char *hdr; X{ X register int c, n; X register unsigned short crc; X X if ((c = zdlread()) & ~0377) X return c; X Rxtype = c; X crc = updcrc(c, 0); X X for (n=Rxhlen; --n >= 0; ++hdr) { X if ((c = zdlread()) & ~0377) X return c; X crc = updcrc(c, crc); X *hdr = c; X } X if ((c = zdlread()) & ~0377) X return c; X crc = updcrc(c, crc); X if ((c = zdlread()) & ~0377) X return c; X crc = updcrc(c, crc); X if (crc & 0xFFFF) { X zperr(badcrc); X return ERROR; X } X#ifdef ZMODEM X Protocol = ZMODEM; X#endif X Zmodem = 1; X return Rxtype; X} X X/* Receive a binary style header (type and position) with 32 bit FCS */ Xzrbhd32(hdr) Xregister char *hdr; X{ X register int c, n; X register UNSL long crc; X X if ((c = zdlread()) & ~0377) X return c; X Rxtype = c; X crc = 0xFFFFFFFFL; crc = UPDC32(c, crc); X#ifdef DEBUGZ X vfile("zrbhd32 c=%X crc=%lX", c, crc); X#endif X X for (n=Rxhlen; --n >= 0; ++hdr) { X if ((c = zdlread()) & ~0377) X return c; X crc = UPDC32(c, crc); X *hdr = c; X#ifdef DEBUGZ X vfile("zrbhd32 c=%X crc=%lX", c, crc); X#endif X } X for (n=4; --n >= 0;) { X if ((c = zdlread()) & ~0377) X return c; X crc = UPDC32(c, crc); X#ifdef DEBUGZ X vfile("zrbhd32 c=%X crc=%lX", c, crc); X#endif X } X if (crc != 0xDEBB20E3) { X zperr(badcrc); X return ERROR; X } X#ifdef ZMODEM X Protocol = ZMODEM; X#endif X Zmodem = 1; X return Rxtype; X} X X X/* Receive a hex style header (type and position) */ Xzrhhdr(hdr) Xchar *hdr; X{ X register int c; X register unsigned short crc; X register int n; X X if ((c = zgethex()) < 0) X return c; X Rxtype = c; X crc = updcrc(c, 0); X X for (n=Rxhlen; --n >= 0; ++hdr) { X if ((c = zgethex()) < 0) X return c; X crc = updcrc(c, crc); X *hdr = c; X } X if ((c = zgethex()) < 0) X return c; X crc = updcrc(c, crc); X if ((c = zgethex()) < 0) X return c; X crc = updcrc(c, crc); X if (crc & 0xFFFF) { X zperr(badcrc); return ERROR; X } X switch ( c = readline(1)) { X case 0215: X Not8bit = c; X /* **** FALL THRU TO **** */ X case 015: X /* Throw away possible cr/lf */ X switch (c = readline(1)) { X case 012: X Not8bit |= c; X } X } X#ifdef ZMODEM X Protocol = ZMODEM; X#endif X Zmodem = 1; return Rxtype; X} X X/* Send a byte as two hex digits */ Xzputhex(c) Xregister int c; X{ X static char digits[] = "0123456789abcdef"; X X#ifdef DEBUGZ X if (Verbose>8) X vfile("zputhex: %02X", c); X#endif X sendline(digits[(c&0xF0)>>4]); X sendline(digits[(c)&0xF]); X} X X/* X * Send character c with ZMODEM escape sequence encoding. X * Escape XON, XOFF. Escape CR following @ (Telenet net escape) X */ Xzsendline(c) X{ X X /* Quick check for non control characters */ X if (c & 0140) X xsendline(lastsent = c); X else { X switch (c &= 0377) { X case ZDLE: X xsendline(ZDLE); X xsendline (lastsent = (c ^= 0100)); X break; X case 015: X case 0215: X if (!Zctlesc && (lastsent & 0177) != '@') X goto sendit; X /* **** FALL THRU TO **** */ X case 020: X case 021: X case 023: X case 0220: X case 0221: X case 0223: X xsendline(ZDLE); X c ^= 0100; X sendit: X xsendline(lastsent = c); X break; X default: X if (Zctlesc && ! (c & 0140)) { X xsendline(ZDLE); X c ^= 0100; X } X xsendline(lastsent = c); X } X } X} X X/* Decode two lower case hex digits into an 8 bit byte value */ Xzgethex() X{ X register int c; X X c = zgeth1(); X#ifdef DEBUGZ X if (Verbose>8) X vfile("zgethex: %02X", c); X#endif X return c; X} Xzgeth1() X{ X register int c, n; X X if ((c = noxrd7()) < 0) X return c; X n = c - '0'; X if (n > 9) X n -= ('a' - ':'); X if (n & ~0xF) X return ERROR; X if ((c = noxrd7()) < 0) X return c; X c -= '0'; X if (c > 9) X c -= ('a' - ':'); X if (c & ~0xF) X return ERROR; X c += (n<<4); X return c; X} X X/* X * Read a byte, checking for ZMODEM escape encoding X * including CAN*5 which represents a quick abort X */ Xzdlread() X{ X register int c; X Xagain: X /* Quick check for non control characters */ X if ((c = readline(Rxtimeout)) & 0140) X return c; X switch (c) { X case ZDLE: X break; X case 023: X case 0223: X case 021: X case 0221: X goto again; X default: X if (Zctlesc && !(c & 0140)) { X goto again; X } X return c; X } Xagain2: X if ((c = readline(Rxtimeout)) < 0) X return c; X if (c == CAN && (c = readline(Rxtimeout)) < 0) X return c; X if (c == CAN && (c = readline(Rxtimeout)) < 0) X return c; X if (c == CAN && (c = readline(Rxtimeout)) < 0) X return c; X switch (c) { X case CAN: X return GOTCAN; X case ZCRCE: X case ZCRCG: X case ZCRCQ: X case ZCRCW: X return (c | GOTOR); X case ZRUB0: X return 0177; X case ZRUB1: X return 0377; X case 023: X case 0223: X case 021: X case 0221: X goto again2; X default: X if (Zctlesc && ! (c & 0140)) { X goto again2; X } X if ((c & 0140) == 0100) X return (c ^ 0100); X break; X } X if (Verbose>1) X zperr("Bad escape sequence %x", c); X return ERROR; X} X X/* X * Read a character from the modem line with timeout. X * Eat parity, XON and XOFF characters. X */ Xnoxrd7() X{ X register int c; X X for (;;) { X if ((c = readline(Rxtimeout)) < 0) X return c; X switch (c &= 0177) { X case XON: X case XOFF: X continue; X default: X if (Zctlesc && !(c & 0140)) X continue; X case '\r': X case '\n': X case ZDLE: X return c; X } X } X} X X/* Store long integer pos in Txhdr */ Xstohdr(pos) Xlong pos; X{ X Txhdr[ZP0] = pos; X Txhdr[ZP1] = pos>>8; X Txhdr[ZP2] = pos>>16; X Txhdr[ZP3] = pos>>24; X} X X/* Recover a long integer from a header */ Xlong Xrclhdr(hdr) Xregister char *hdr; X{ X register long l; X X l = (hdr[ZP3] & 0377); X l = (l << 8) | (hdr[ZP2] & 0377); X l = (l << 8) | (hdr[ZP1] & 0377); X l = (l << 8) | (hdr[ZP0] & 0377); X return l; X} X X/* End of zm.c */ END_OF_FILE if test 17884 -ne `wc -c <'zm.c'`; then echo shar: \"'zm.c'\" unpacked with wrong size! fi # end of 'zm.c' fi echo shar: End of archive 3 \(of 4\). cp /dev/null ark3isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 .