page%swap@Sun.COM (Bob Page) (10/20/89)
Submitted-by: acs@pccuts.pcc.amdahl.com (Tony Sumrall) Posting-number: Volume 89, Issue 181 Archive-name: comm/vt100r29.4 # This is a shell archive. # Remove anything above and including the cut line. # Then run the rest of the file through 'sh'. # Unpacked files will be owned by you and have default permissions. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: SHell ARchive # Run the following text through 'sh' to create: # Zmodem/rz.c # This is archive 4 of a 9-part kit. # This archive created: Thu Oct 19 22:30:30 1989 if `test ! -d Zmodem` then mkdir Zmodem echo "mkdir Zmodem" fi echo "extracting Zmodem/rz.c" sed 's/^X//' << \SHAR_EOF > Zmodem/rz.c X#define VERSION "1.26 08-21-87" X#define PUBDIR "/usr/spool/uucppublic" X X/*% cc -M0 -Ox -K -i % -o rz; size rz; X<-xtx-*> cc386 -Ox 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 * X * Amiga version by Frank Harper using Aztec C 3.4b X * X * cc +L rz.c;cc +L SerIO.c;cc +L term.c;ln rz.o SerIO.o term.o -lc32 X * or just use the makefile X * X * See Amiga.doc for more details on Amiga version 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 * Iff the program is invoked by rzCOMMAND, output is piped to X * "COMMAND filename" 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 * HOWMANY may be tuned for best performance X * X * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin X */ X#ifdef AMIGA X#define LOGFILE "rzlog" X#include <time.h> X#include <stdio.h> X#include <ctype.h> X#include <stat.h> X#include <devices/timer.h> X#include <devices/serial.h> X#include <libraries/dos.h> X#include "intuition/intuition.h" X#include <exec/memory.h> X X#define RZ X Xvoid *OpenLibrary(); Xstruct Window *OpenWindow(); X Xstruct IntuitionBase *IntuitionBase; Xstruct NewWindow nw = { X 0, 0, /* start position */ X 640, 120, /* width, height */ X -1, -1, /* detail pen, block pen */ X CLOSEWINDOW, /* IDCMP flags */ X ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | WINDOWCLOSE X | NOCAREREFRESH, /* window flags */ X NULL, /* pointer to first user gadget */ X NULL, /* pointer to user checkmark */ X (UBYTE *)"Rz", /* window title */ X NULL, /* pointer to screen (later) */ X NULL, /* pointer to superbitmap */ X 50,40,-1,-1, /* sizing limits min and max */ X WBENCHSCREEN /* type of screen in which to open */ X }; Xint InitSer = FALSE; Xint gmt_diff_set=FALSE; /* Has GMT offset been set? */ Xint gmt_diff; /* Local offset from GMT time */ Xint SetProtect=TRUE; Xint Term=FALSE; /* Use Terminal mode ? */ Xint WaitC=TRUE; /* Wait for confirmation before closing window?*/ Xstruct IOStdReq *ConWriteReq, *ConReadReq; Xstruct Window *Win; Xstruct MsgPort *ConReadPort,*ConWritePort; Xint WinOutPut; Xint FullDuplex=TRUE; Xstruct IOExtSer *InSer, *OutSer; Xstruct MsgPort *InSerPort, *OutSerPort; XULONG InSerSigMask, OutSerSigMask; XUBYTE SerOpen; Xstruct timerequest *IOTime; Xstruct MsgPort *TimerPort; XULONG IOTimeSigMask; X Xint Skip=TRUE; /* Skip files which are to big to fit on disk */ X#else X#define LOGFILE "/tmp/rzlog" X X#include <stdio.h> X#include <signal.h> X#include <setjmp.h> X#include <ctype.h> XFILE *popen(); X#endif X X#define OK 0 X X#ifndef AMIGA /* Already defined in <exec/types.h> */ X#define FALSE 0 X#define TRUE 1 X#endif X 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 * This isn't used in Amiga version X */ X#ifndef HOWMANY X#define HOWMANY 133 X#endif X Xint Zmodem=0; /* ZMODEM protocol requested */ Xint Nozmodem = 0; /* If invoked as "rb" */ Xunsigned Baudrate; X Xchar *substr(); XFILE *fout; 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 ERRORMAX 5 X#define RETRYMAX 5 X#define WCEOT (-10) X#define SECSIZ 128 /* cp/m's Magic Number record size */ X#define PATHLEN 257 /* ready for 4.2 bsd ? */ X#define KSIZE 1024 /* record size with k option */ X#define UNIXFILE 0x8000 /* happens to the the S_IFREG file mask bit for stat */ 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 */ X#ifndef AMIGA Xshort Filemode; /* Unix style mode for incoming file */ X#else Xint Filemode; /* This avoids a problem with the sscanf used to X read Filemode */ X#endif Xchar Pathname[PATHLEN]; Xchar *Progname; /* the name by which we were called */ X Xint Batch=0; Xint Wcsmask=0377; 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 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 */ Xchar secbuf[KSIZE+1]; 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 X#ifndef AMIGA Xjmp_buf tohere; /* For the interrupt on RX timeout */ X#endif X X#include "rbsb.c" /* most of the system dependent stuff here */ X#include "zm.c" X Xint tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */ X X#ifndef AMIGA 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#else Xstruct DPTR { /* Format of directory fetch pointer */ X struct FileLock *lock; /* lock on directory */ X struct FileInfoBlock *fib; /* mod'd fib for entry */ X}; X Xstruct DPTR *dopen(); Xstruct FileLock *Lock(); Xstruct FileLock *ParentDir(); Xstruct MsgPort *DeviceProc(); Xvoid *AllocMem(); Xvoid *malloc(); X X /* X * Calculate free bytes on current file system X * ~0L means number of free bytes unknown X * Adapted from shell 2.07's devinfo routine (Thanks Matt & Steve) X */ X Xlong getfree() X{ X struct DPTR *dp; X struct InfoData *info; X int stat; X long retc; X X if ((dp = dopen ("", &stat))!=NULL) { X info = (struct InfoData *)AllocMem((long)sizeof(struct InfoData), MEMF_PUBLIC); X if (Info (dp->lock, info)) X retc=(info->id_NumBlocks - info->id_NumBlocksUsed)*512; /* assume 512 byte blocks */ X else { X if(Verbose) fprintf(stderr,"getfree failed\n"); X retc=~0L; X } X } X FreeMem (info,(long) sizeof(*info)); X dclose(dp); X if(Verbose) fprintf(stderr,"%ld bytes free on disk\n",retc); X return(retc); X} X X /* X * Change a files date X * Lifted from Shell 2.07 X * X */ X Xfile_date(date,name) Xstruct DateStamp *date; Xchar *name; X{ X UBYTE *ptr; X struct MsgPort *task; X struct FileLock *dirlock; X struct DPTR *tmp; X int stat; X long ret, dos_packet(); X X if (!(task = (struct MsgPort *)DeviceProc(name))) X return(1); X if (tmp = dopen(name, &stat)) { X dirlock = (struct FileLock *)ParentDir(tmp->lock); X ptr = (UBYTE *)AllocMem(64L,MEMF_PUBLIC); X strcpy((ptr + 1),tmp->fib->fib_FileName); X *ptr = strlen(tmp->fib->fib_FileName); X dclose(tmp); X ret = dos_packet(task,34L,NULL,dirlock, X (ULONG)&ptr[0] >> 2L,date); X FreeMem(ptr,64L); X UnLock(dirlock); X } X} X X/* X * These routines come directly from shell 2.07 by Matt Dillon, X * Manx version by Steve Drew. X * X * Disk directory routines X * X * dptr = dopen(name, stat) X * struct DPTR *dptr; X * char *name; X * int *stat; X * X * dclose(dptr) -may be called with NULL without harm X * X * dopen() returns a struct DPTR, or NULL if the given file does not X * exist. stat will be set to 1 if the file is a directory. If the X * name is "", then the current directory is opened. X * X * dclose() closes a directory channel. X * X */ X Xstruct DPTR *dopen(name, stat) Xchar *name; Xint *stat; X{ X struct DPTR *dp; X int i; X X *stat = 0; X dp = (struct DPTR *)malloc(sizeof(struct DPTR)); X dp->lock = (struct FileLock *)Lock (name, ACCESS_READ); X if (dp->lock == NULL) { X free (dp); X if(Verbose) fprintf(stderr,"Couldn't lock dir\n"); X return (NULL); X } X dp->fib = (struct FileInfoBlock *) X AllocMem((long)sizeof(struct FileInfoBlock), MEMF_PUBLIC); X if (!Examine (dp->lock, dp->fib)) { X if(Verbose) fprintf(stderr,"dopen: Can't open current dir\n"); X dclose (dp); X return (NULL); X } X if (dp->fib->fib_DirEntryType >= 0) X *stat = 1; X return (dp); X} X Xdclose(dp) Xstruct DPTR *dp; X{ X if (dp == NULL) X return (1); X if (dp->fib) X FreeMem (dp->fib,(long)sizeof(*dp->fib)); X if (dp->lock) X UnLock (dp->lock); X free (dp); X return (1); X} Xbibi(n) X{ X if (Zmodem) X zmputs(Attn); X flushmo(); X canit(); mode(0); X if(fout) fclose(fout); X CleanUp(); X exit(128+n); X} X XWaitbibi(n) Xint n; X{ X ConPutChar(ConWriteReq,7); X ConPutStr(ConWriteReq,"\nsz: Transfer aborted"); X if( WaitC ) WaitClose(); X bibi(n); X} X XWaitClose() X{ X ULONG IntuiMask; X X IntuiMask = 1 << (Win->UserPort->mp_SigBit); X while(!CheckQuit()) Wait(IntuiMask); X} X XAmigaInit() X{ X IntuitionBase = (struct IntuitionBase *) X OpenLibrary("intuition.library", 33L); X if (IntuitionBase == NULL) { X puts("Unable to open 1.2 or higher intuition.library"); X exit(1); X } X Win = OpenWindow(&nw); X if ( Win == NULL ) { X puts("Unable to open window"); X CleanUp(); X exit(1); X } X WinOutPut=TRUE; X if( OpenConsole(&ConWriteReq,&ConReadReq,Win)) { X puts("Couldn't open console"); X CleanUp(); X exit(1); X } X} X XCleanUp() X{ X CloseConsole(ConReadReq,ConWriteReq); X if( Win ) CloseWindow(Win); X if(IntuitionBase) CloseLibrary(IntuitionBase); X} X X /* X * Send output to window X * X */ Xfprintf(f,s,a1,a2,a3,a4) XFILE *f; Xchar *s; Xchar *a1,*a2,*a3,*a4; X{ X char buf[256]; X X sprintf(buf,s,a1,a2,a3,a4); X if( WinOutPut ) ConPutStr(ConWriteReq,buf); X else fputs(buf,f); X} X#endif X X#ifndef AMIGA Xalrm() X{ X longjmp(tohere, -1); 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 exit(128+n); X} X#endif X Xmain(argc, argv) Xchar *argv[]; X{ X register char *cp; X register npats; X char *virgin, **patts; X char *getenv(); X int exitcode = 0; X X Rxtimeout = 100; X#ifndef AMIGA X setbuf(stderr, NULL); X if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh"))) X Restricted=TRUE; X#endif X X chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */ X npats = 0; X#ifdef AMIGA X AmigaInit(); X#endif X while (--argc) { X cp = *++argv; X if (*cp == '-') { X while( *++cp) { X switch(*cp) { X case '+': X Lzmanag = ZMAPND; break; X#ifndef AMIGA X case '1': X iofd = 1; break; X#else X case 'I': X InitSer = TRUE; break; X case 'B': X Nozmodem = TRUE; break; X#endif X case '7': X Wcsmask = 0177; X case 'a': X Rxascii=TRUE; break; X case 'b': X Rxbinary=TRUE; break; X case 'c': X Crcflg=TRUE; break; X case 'D': X Nflag = TRUE; break; X case 'e': X Zctlesc = 1; break; X#ifdef AMIGA X case 'h': X FullDuplex = FALSE; break; X case 'm': X SetProtect = FALSE; break; X case 'n': X Skip = FALSE; break; X#endif X case 'p': X Lzmanag = ZMPROT; break; X case 'q': X Quiet=TRUE; Verbose=0; break; X#ifdef AMIGA X case 'Q': X WaitC = FALSE; break; X#endif 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#ifdef AMIGA X case 'T': X Term=TRUE; break; X#endif 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 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#ifdef AMIGA X if( mode(1)==ERROR) { X fprintf(stderr,"Couldn't initialize serial port\n"); X Waitbibi(1); X } X if (Term) { X fprintf(stderr,"Entering terminal mode, click on close box when ready to start file transfer\n"); X term(); X } X#endif 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#ifdef AMIGA X WinOutPut=FALSE; X#endif 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#ifndef AMIGA 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#endif X if (wcreceive(npats, patts)==ERROR) { X exitcode=0200; X canit(); X#ifdef AMIGA X fprintf(stderr,"\n\007File transfer failed\n"); X#endif X } X#ifdef AMIGA X else fprintf(stderr,"\nFile transfer succesful\n"); X if (Term) { X fprintf(stderr,"Re-entering terminal mode. Click on close box to exit Rz.\n"); X term(); X } X else if( WaitC ) { X fprintf(stderr,"Click on close box to exit Rz\n"); X WaitClose(); X } X CleanUp(); X#endif X mode(0); X if (exitcode && !Zmodem) /* bellow again with all thy might. */ X canit(); X exit(exitcode); X} X X#ifdef AMIGA Xchar *babble[] = { X "Usage: rz [-BIYabehmnv] (ZMODEM Batch)", X "or rb [-Iabhv] (YMODEM Batch)", X "or rz [-Iabchv] file (XMODEM or XMODEM-1k)", X " -I Initialize serial port, using zmodem.init file", X " -B Force Ymodem Batch transfer", X " -a ASCII transfer (strip CR)", X " -b Binary transfer for all files", X " -c Use 16 bit CRC (XMODEM)", X " -e Ignore control characters (ZMODEM)", X " -h Half duplex mode (only for Terminal mode)", X " -m Don't set file modes", X " -n No skipping over files even if to large for disk", X " -Q Quit without waiting for click in close box", X " -T enter Terminal mode before transferring", X " -v Verbose more v's give more info", X "" X}; X Xusage() X{ X char **pp; X int i,n,rows,cols,height; X struct Screen Scr; X char rep[20]; X X /* Expand window, to show as many lines at once as possible */ X MoveWindow(Win,-Win->LeftEdge,-Win->TopEdge); X if( !GetScreenData(&Scr,sizeof(struct Screen),WBENCHSCREEN)) { X fprintf(stderr,"Couldn't get screen size"); X CleanUp(); X exit(1); X } X rows=Scr.Height; X cols=Scr.Width; X SizeWindow(Win,cols>640?640-Win->Width:cols-Win->Width, X rows-Win->Height); X Delay(15); /* Wait until window is resized */ X ConPutStr(ConWriteReq,"\2330 q"); /* get window bounds */ X n = 0; X while((rep[n] = ConGetC(ConReadReq)) != 'r' && n++ < 20) X ; X height=0; X i=5; X while(rep[i]>='0' && rep[i]<='9' && i<n) { X height*=10; X height+=rep[i++]-'0'; X } X for (pp=babble,i=1; **pp; ++pp,i++) { X fprintf(stderr, "%s\n", *pp); X if((i%height)==(height-1)) { X WaitKey(); X ConPutStr(ConWriteReq,"\2331\0731\110\233\112"); /* Erase screen */ X } X } X fprintf(stderr,"%s by Chuck Forsberg, amiga version 1.0 by Frank Harper\n",VERSION); X WaitKey(); X bibi(1); X} X XWaitKey() X{ X char ConChar; X ULONG mask,IntuiMask,ConInMask; X X IntuiMask = 1 << (Win->UserPort->mp_SigBit); X ConInMask = 1 << (ConReadPort->mp_SigBit); X ConPutStr(ConWriteReq,"\23307\155 Press a key \23300\155"); X QueueRead(ConReadReq,&ConChar); X mask=Wait(ConInMask|IntuiMask); X puts("Got something"); X if(CheckQuit()) { /* Hit close box? */ X KillIO(ConReadReq); X bibi(1); X } X GetMsg(ConReadPort); X} X#else Xusage() X{ X fprintf(stderr,"%s %s for %s by Chuck Forsberg\n", X Progname, VERSION, OS); X fprintf(stderr,"Usage: rz [-1abeuv] (ZMODEM Batch)\n"); X fprintf(stderr,"or rb [-1abuv] (YMODEM Batch)\n"); X fprintf(stderr,"or rx [-1abcv] file (XMODEM or XMODEM-1k)\n"); X fprintf(stderr," -1 For cu(1): Use fd 1 for input\n"); X fprintf(stderr," -a ASCII transfer (strip CR)\n"); X fprintf(stderr," -b Binary transfer for all files\n"); X fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n"); X fprintf(stderr," -e Ignore control characters (ZMODEM)\n"); X fprintf(stderr," -v Verbose more v's give more info\n"); X exit(1); X} X#endif 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"; X Xwcreceive(argc, argp) Xchar **argp; X{ X register c; X X if (Batch || argc==0) { X Crcflg=(Wcsmask==0377); 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); X#ifndef AMIGA X checkpath(Pathname); X#endif 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 AMIGA X if (Topipe && fout) { X pclose(fout); return ERROR; X } X#endif X if (fout) X fclose(fout); X if (Restricted) { X unlink(Pathname); X fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname); X } X return ERROR; X} X X X/* X * Fetch a pathname from the other end as a C ctyle ASCIZ string. X * Length is indeterminate as long as less than Blklen X * A null string represents no more files (YMODEM) X */ Xwcrxpn(rpn) Xchar *rpn; /* receive a pathname */ X{ X register 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 &Wcsmask)) { X sectnum++; X cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; X if (putsec(secbuf, cblklen)==ERROR) X return ERROR; X if ((Bytesleft-=cblklen) < 0) X Bytesleft = 0; X sendchar=ACK; X } X else if (sectcurr==(sectnum&Wcsmask)) { X 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<RETRYMAX; errors++) { X X if ((firstch=readline(maxtime))==STX) { X Blklen=KSIZE; goto get2; X } X if (firstch==SOH) { X Blklen=SECSIZ; Xget2: X sectcurr=readline(1); X if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) { X oldcrc=checksum=0; X for (p=rxbuf,wcj=Blklen; --wcj>=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)&Wcsmask)==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#ifndef AMIGA 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++ & Wcsmask); 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++ & Wcsmask); X} X#else Xreadline(timeout) Xint timeout; X{ X int c; X X c = ReadSer(timeout); X if(c<0) X { X switch(c) { X X case TIMEOUT: X Lleft = 0; X if (Verbose>1) X fprintf(stderr, "Readline:TIMEOUT\n"); X return TIMEOUT; X X default:if(Verbose) fprintf(stderr,"readline: unknown error\n"); X return -1;break; X } X } X else { if(Verbose>8) fprintf(stderr,"%02x ",c&0377); X return(c&Wcsmask); X } X} X X#endif /* ifndef AMIGA */ X X X/* X * Purge the modem input queue of all characters X */ Xpurgeline() X{ X Lleft = 0; X#ifdef AMIGA X PurgeSer(); X#else X#ifdef USG X ioctl(iofd, TCFLSH, 0); X#else X lseek(iofd, 0L, 2); X#endif X#endif /* AMIGA */ 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 /* ZMPROT check for existing file */ X if (zmanag == ZMPROT && (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 AMIGA /* if the user wants ascii conversion give it to him X even if file is coming from UNIX */ X if (Filemode & UNIXFILE) X ++Thisbinary; X#endif X if (Verbose) { X#ifndef AMIGA X fprintf(stderr, "Incoming: %s %ld %lo %o\n", X name, Bytesleft, Modtime, Filemode); X#else X fprintf(stderr, "\nIncoming: %s length=%ld\n", X name, Bytesleft); /* Trying to be a little less X cryptic than the UNIX version*/ X#endif 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 if (!Zmodem && MakeLCPathname && !IsAnyLower(name)) X uncaps(name); X if (Topipe) { X#ifndef AMIGA X sprintf(Pathname, "%s %s", Progname+2, name); X if (Verbose) X fprintf(stderr, "Topipe: %s %s\n", X Pathname, Thisbinary?"BIN":"ASCII"); X if ((fout=popen(Pathname, "w")) == NULL) X return ERROR; X#endif X } else { X strcpy(Pathname, name); X#ifndef AMIGA X if (Verbose) { X fprintf(stderr, "Receiving %s %s %s\n", X name, Thisbinary?"BIN":"ASCII", openmode); X } X checkpath(name); X#else X if (Verbose) { X fprintf(stderr, "file transfer mode is %s, file open mode is %s\n", X Thisbinary?"BIN":"ASCII", openmode); X } X#endif X if (Nflag) X name = "/dev/null"; X if ((fout=fopen(name, openmode)) == NULL) X return ERROR; X } X return OK; X#endif /* BIX */ X} 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 (Thisbinary) { X for (p=buf; --n>=0; ) X if( putc( *p++, fout)==EOF ) X return ERROR; 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 if( putc(*p ,fout)==EOF ) X return ERROR; X } X } X return OK; X} X X#ifndef AMIGA 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#else Xsendline(c) Xint c; X{ X char d; X int retc; X X d=c; X if(Verbose>6) X fprintf(stderr,"S:%02x\n",c); X if( (retc=LWriteSer(&d,1))!=0 ) X if(Verbose) fprintf(stderr,"sendline:Error sending character %d\n",retc); X} X#endif X Xxsendline(c) X{ X sendline(c); X} X Xflushmo() {} 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#ifndef AMIGA X printf(canistr); X#else X LWriteSer(canistr,strlen(canistr)); X#endif X Lleft=0; /* Do read next time ... */ X fflush(stdout); X} X X#ifndef AMIGA X/* X * Return 1 iff stdout and stderr are different devices X * indicating this program operating with a modem on a X * different line X */ Xfromcu() X{ X struct stat a, b; X fstat(1, &a); fstat(2, &b); X return (a.st_rdev != b.st_rdev); X} X#else /* AMIGA */ Xfromcu() X{ X return TRUE; X} X#endif 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]=='b') X Nozmodem = TRUE; X#ifndef AMIGA 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#endif X} X X#ifndef AMIGA 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#endif 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 stohdr(0L); 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, KSIZE); 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 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 cmdzack1flg = Rxhdr[ZF0]; X if (zrdata(secbuf, KSIZE) == 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 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#ifdef AMIGA /* skip over file if it won't fit on disk */ X if (Skip && Bytesleft!=DEFBYTL && Bytesleft>getfree()) { X fprintf(stderr,"rz:Not enough room left on disk for %s. (skipping it)\n",secbuf); X return (tryzhdrtype = ZSKIP); X } X#endif X n = 20; rxbytes = 0l; X X for (;;) { X stohdr(rxbytes); X zshhdr(ZRPOS, Txhdr); Xnxthdr: X switch (c = zgethdr(Rxhdr, 0)) { X default: X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X case ZNAK: X case TIMEOUT: X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X case ZFILE: X zrdata(secbuf, KSIZE); X continue; X case ZEOF: 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 if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case ZDATA: X if (rclhdr(Rxhdr) != rxbytes) { X if ( --n < 0) { X return ERROR; X } X zmputs(Attn); continue; X } Xmoredata: X if (Verbose>1) X fprintf(stderr, "\r%7ld ZMODEM%s ", X rxbytes, Crc32?" CRC-32":""); X switch (c = zrdata(secbuf, KSIZE)) { X case ZCAN: X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X case ERROR: /* CRC error */ X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case TIMEOUT: X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X continue; X case GOTCRCW: X n = 20; X putsec(secbuf, Rxcount); X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X sendline(XON); X goto nxthdr; X case GOTCRCQ: X n = 20; X putsec(secbuf, Rxcount); X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X goto moredata; X case GOTCRCG: X n = 20; X putsec(secbuf, Rxcount); X rxbytes += Rxcount; X goto moredata; X case GOTCRCE: X n = 20; X putsec(secbuf, Rxcount); 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#ifdef AMIGA X long attr; X int res; X struct DateStamp dss; X long time; X#else 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 AMIGA X if (Modtime) { X timep[0] = time(NULL); X timep[1] = Modtime; X utime(Pathname, timep); X } X if (Filemode) X chmod(Pathname, (07777 & Filemode)); X#else X if (Modtime && gmt_diff_set) { X time=Modtime-(2*366+6*365)*24*60*60 +(gmt_diff * 60 * 60); X dss.ds_Tick=(time%60)*TICKS_PER_SECOND; X time/=60; X dss.ds_Minute=time%(60*24); X time/=60; X dss.ds_Days=time/24; X file_date(&dss,Pathname); X } X if (SetProtect && Filemode) { X /* Turn off flag to allow the action. */ X#ifndef FIBF_SCRIPT X#define FIBF_SCRIPT (1 << 6) X#endif X#ifndef FIBF_PURE X#define FIBF_PURE (1 << 5) X#endif X#ifndef FIBF_HIDDEN X#define FIBF_HIDDEN (1 << 7) X#endif X attr = 0L; X if(!(Filemode & 0400)) attr |= FIBF_READ; X if(!(Filemode & 0200)) attr |= (FIBF_WRITE | FIBF_DELETE); X if(!(Filemode & 0100)) attr |= FIBF_EXECUTE; X res=SetProtection(Pathname, attr); X } X#endif 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#ifndef AMIGA X if (Verbose || fromcu()) X#else X if (Verbose>2) X#endif X putc(c, stderr); X} X X#ifndef AMIGA 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#else Xsys2(s) Xchar *s; X{ X if (*s == '!') X ++s; X /* if it's just an "echo" fake it */ X if(strncmp(s,"echo",4)==0) { printf("%s\n",s+5);return 0; } X else return(!Execute(s,0L,0L)); X} X X Xexec2(s) Xchar *s; X{ X char cmdbuf[256]; /* Anybody like nice long commands? */ X X if (*s == '!') X ++s; X sprintf(cmdbuf,"run %s",s); X Execute(cmdbuf,0L,0L); X} X#endif X/* End of rz.c */ SHAR_EOF echo "End of archive 4 (of 9)" # if you want to concatenate archives, remove anything after this line exit