[comp.sources.amiga] v89i181: vt100 - terminal emulator v2.9, Part04/09

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