386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sun, 28 Jun 1992 18:07:45 +0000 (10:07 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Sun, 28 Jun 1992 18:07:45 +0000 (10:07 -0800)
Work on file usr/othersrc/public/zmodem-3.03/zmodem-3.03/sz.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/othersrc/public/zmodem-3.03/zmodem-3.03/sz.c [new file with mode: 0644]

diff --git a/usr/othersrc/public/zmodem-3.03/zmodem-3.03/sz.c b/usr/othersrc/public/zmodem-3.03/zmodem-3.03/sz.c
new file mode 100644 (file)
index 0000000..de09d48
--- /dev/null
@@ -0,0 +1,2097 @@
+#define VERSION "sz 3.03 5-09-89"
+#define PUBDIR "/usr/spool/uucppublic"
+
+/*% cc -compat -M2 -Ox -K -i -DTXBSIZE=16384  -DNFGVMIN -DREADCHECK
+sz.c -lx -o sz; size sz
+
+/*% cc -Zi -DXX -DNFGVMIN -DREADCHECK sz.c -lx -o xsz; size xsz
+<-xtx-*> cc -Osal -DTXBSIZE=32768  -DSV sz.c -lx -o $B/sz; size $B/sz
+
+ ****************************************************************************
+ *
+ * sz.c By Chuck Forsberg,  Omen Technology INC
+ *
+ ****************************************************************************
+ *
+ * Typical Unix/Xenix/Clone compiles:
+ *
+ *     cc -O sz.c -o sz                USG (SYS III/V) Unix
+ *     cc -O -DSV sz.c -o sz           Sys V Release 2 with non-blocking input
+ *                                     Define to allow reverse channel checking
+ *     cc -O -DV7  sz.c -o sz          Unix Version 7, 2.8 - 4.3 BSD
+ *
+ *     cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz        Classic Xenix
+ *
+ *     ln sz sb                        **** All versions ****
+ *     ln sz sx                        **** All versions ****
+ *
+ ****************************************************************************
+ *
+ * Typical VMS compile and install sequence:
+ *
+ *             define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
+ *             cc sz.c
+ *             cc vvmodem.c
+ *             link sz,vvmodem
+ *     sz :== $disk$user2:[username.subdir]sz.exe
+ *
+ *  If you feel adventureous, remove the #define BADSEEK line
+ *  immediately following the #ifdef vax11c line!  Some VMS
+ *  systems know how to fseek, some don't.
+ *
+ ****************************************************************************
+ *
+ *
+ * A program for Unix to send files and commands to computers running
+ *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
+ *
+ *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
+ *
+ *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
+ *
+ *     This version implements ZMODEM Run Length Encoding, Comparision,
+ *     and variable length headers.  These features were not funded
+ *     by the original Telenet development contract.  This software,
+ *     including these features, may be freely used for non
+ *     commercial and educational purposes.  This software may also
+ *     be freely used to support file transfer operations to or from
+ *     licensed Omen Technology products.  Contact Omen Technology
+ *     for licensing for other uses.  Any programs which use part or
+ *     all of this software must be provided in source form with this
+ *     notice intact except by written permission from Omen
+ *     Technology Incorporated.
+ *
+ *             Omen Technology Inc             FAX: 503-621-3745
+ *             Post Office Box 4681
+ *             Portland OR 97208
+ *
+ *     Previous versions of this program (not containing the extensions
+ *     listed above) remain in the public domain.
+ *
+ *     This code is made available in the hope it will be useful,
+ *     BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
+ *     DAMAGES OF ANY KIND.
+ *
+ *  2.1x hacks to avoid VMS fseek() bogosity, allow input from pipe
+ *     -DBADSEEK -DTXBSIZE=32768  
+ *  2.x has mods for VMS flavor
+ *
+ * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS
+ * in accordance with the 7-31-87 ZMODEM Protocol Description
+ */
+
+#ifdef XX
+#define XARGSFILE "args"
+long Thisflen;
+#endif
+
+char *substr(), *getenv();
+
+#ifdef vax11c
+#define STATIC
+#define BADSEEK
+#define TXBSIZE 32768          /* Must be power of two, < MAXINT */
+#include <types.h>
+#include <stat.h>
+#define STAT
+#define LOGFILE "szlog.tmp"
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <errno.h>
+#define OS "VMS"
+#define ROPMODE "r"
+#define READCHECK
+#define BUFWRITE
+extern int errno;
+#define SS_NORMAL SS$_NORMAL
+#define xsendline(c) sendline(c)
+
+#ifndef PROGNAME
+#define PROGNAME "sz"
+#endif
+
+
+#else  /* vax11c */
+
+#ifdef GENIE
+#define STATIC static
+#define LOGFILE "szlog"
+#define BADSEEK
+#define TXBSIZE 32768          /* Must be power of two, < MAXINT */
+#define OS "GEnie"
+#define SS_NORMAL 0
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fildes.h>
+FILDES fdes;
+extern int errno;
+int Binfile;
+long Thisflen;
+
+#define sendline(c) putchar(c & 0377)
+#define xsendline(c) putchar(c)
+
+#else  /* GENIE */
+
+#define LOGFILE "/tmp/szlog"
+#define SS_NORMAL 0
+#include <stdio.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;
+#define STATIC
+
+#define sendline(c) putchar(c & 0377)
+#define xsendline(c) putchar(c)
+
+#endif
+#endif
+
+#define PATHLEN 256
+#define OK 0
+#define FALSE 0
+#ifdef TRUE
+#undef TRUE
+#endif
+#define TRUE 1
+#define ERROR (-1)
+/* Ward Christensen / CP/M parameters - Don't change these! */
+#define ENQ 005
+#define CAN ('X'&037)
+#define XOFF ('s'&037)
+#define XON ('q'&037)
+#define SOH 1
+#define STX 2
+#define EOT 4
+#define ACK 6
+#define NAK 025
+#define CPMEOF 032
+#define WANTCRC 0103   /* send C not NAK to get crc not checksum */
+#define WANTG 0107     /* Send G not NAK to get nonstop batch xmsn */
+#define TIMEOUT (-2)
+#define RCDO (-3)
+#define GCOUNT (-4)
+#define RETRYMAX 10
+
+
+#define HOWMANY 2
+STATIC int Zmodem=0;           /* ZMODEM protocol requested by receiver */
+unsigned Baudrate=4800;                /* Default, set by first mode() call */
+STATIC unsigned Effbaud = 4800;
+STATIC unsigned Txwindow;      /* Control the size of the transmitted window */
+STATIC unsigned Txwspac;       /* Spacing between zcrcq requests */
+STATIC unsigned Txwcnt;        /* Counter used to space ack requests */
+STATIC long Lrxpos;            /* Receiver's last reported offset */
+STATIC int errors;
+
+#ifdef vax11c
+#include "vrzsz.c"     /* most of the system dependent stuff here */
+#else
+#ifdef GENIE
+#include "genie.c"     /* most of the system dependent stuff here */
+#else
+#include "rbsb.c"      /* most of the system dependent stuff here */
+#ifdef XX
+#undef STAT
+#endif
+#endif
+#endif
+
+#include "crctab.c"
+
+STATIC int Filesleft;
+STATIC long Totalleft;
+
+/*
+ * Attention string to be executed by receiver to interrupt streaming data
+ *  when an error is detected.  A pause (0336) may be needed before the
+ *  ^C (03) or after it.
+ */
+#ifdef READCHECK
+STATIC char Myattn[] = { 0 };
+#else
+#ifdef USG
+STATIC char Myattn[] = { 03, 0336, 0 };
+#else
+#ifndef GENIE
+STATIC char Myattn[] = { 0 };
+#endif
+#endif
+#endif
+
+FILE *in;
+
+#ifdef BADSEEK
+STATIC int Canseek = 0;        /* 1: Can seek 0: only rewind -1: neither (pipe) */
+#ifndef TXBSIZE
+#define TXBSIZE 16384          /* Must be power of two, < MAXINT */
+#endif
+#else
+STATIC int Canseek = 1;        /* 1: Can seek 0: only rewind -1: neither (pipe) */
+#endif
+
+#ifdef TXBSIZE
+#define TXBMASK (TXBSIZE-1)
+STATIC char Txb[TXBSIZE];              /* Circular buffer for file reads */
+STATIC char *txbuf = Txb;              /* Pointer to current file segment */
+#else
+STATIC char txbuf[1024];
+#endif
+STATIC long vpos = 0;                  /* Number of bytes read from file */
+
+STATIC char Lastrx;
+STATIC char Crcflg;
+STATIC int Verbose=0;
+STATIC int Modem2=0;           /* XMODEM Protocol - don't send pathnames */
+STATIC int Restricted=0;       /* restricted; no /.. or ../ in filenames */
+STATIC int Quiet=0;            /* overrides logic that would otherwise
+set verbose */
+STATIC int Ascii=0;            /* Add CR's for brain damaged programs */
+STATIC int Fullname=0;         /* transmit full pathname */
+STATIC int Unlinkafter=0;      /* Unlink file after it is sent */
+STATIC int Dottoslash=0;       /* Change foo.bar.baz to foo/bar/baz */
+STATIC int firstsec;
+STATIC int errcnt=0;           /* number of files unreadable */
+STATIC int blklen=128;         /* length of transmitted records */
+STATIC int Optiong;            /* Let it rip no wait for sector ACK's */
+STATIC int Eofseen;            /* EOF seen on input set by zfilbuf */
+STATIC int BEofseen;           /* EOF seen on input set by fooseek */
+STATIC int Totsecs;            /* total number of sectors this file */
+STATIC int Filcnt=0;           /* count of number of files opened */
+STATIC int Lfseen=0;
+STATIC unsigned Rxbuflen = 16384;      /* Receiver's max buffer length */
+STATIC int Tframlen = 0;       /* Override for tx frame length */
+STATIC int blkopt=0;           /* Override value for zmodem blklen */
+STATIC int Rxflags = 0;
+STATIC long bytcnt;
+STATIC int Wantfcs32 = TRUE;   /* want to send 32 bit FCS */
+STATIC char Lzconv;    /* Local ZMODEM file conversion request */
+STATIC char Lzmanag;   /* Local ZMODEM file management request */
+STATIC int Lskipnocor;
+STATIC char Lztrans;
+STATIC int Command;            /* Send a command, then exit. */
+STATIC char *Cmdstr;           /* Pointer to the command string */
+STATIC int Cmdtries = 11;
+STATIC int Cmdack1;            /* Rx ACKs command, then do it */
+STATIC int Exitcode;
+STATIC int Test;               /* 1= Force receiver to send Attn, etc with qbf. */
+                       /* 2= Character transparency test */
+STATIC char *qbf=
+ "The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
+STATIC long Lastsync;          /* Last offset to which we got a ZRPOS */
+STATIC int Beenhereb4;         /* How many times we've been ZRPOS'd same place */
+
+STATIC jmp_buf tohere;         /* For the interrupt on RX timeout */
+STATIC jmp_buf intrjmp;        /* For the interrupt on RX CAN */
+
+#ifdef XARGSFILE
+char *
+mystrsave(s)
+char *s;
+{
+       register char *p;
+       char *malloc();
+
+       if (p = malloc(strlen(s)+1) ) {
+               strcpy(p, s); return p;
+       }
+       fprintf(stderr, "No memory for mystrsave!\n");
+       exit(1);
+}
+
+/* Remove (presumably) terminating CR and/or LF from string */
+uncrlf(s)
+register char *s;
+{
+       for ( ; *s; ++s)
+               switch (*s) {
+               case '\r':
+               case '\n':
+                       *s = 0;  return;
+               }
+}
+#endif
+
+
+/* called by signal interrupt or terminate to clean things up */
+SIGTYPE
+bibi(n)
+{
+       canit(); fflush(stdout); mode(0);
+       fprintf(stderr, "sz: caught signal %d; exiting\n", n);
+#ifndef GENIE
+       if (n == SIGQUIT)
+               abort();
+#endif
+       if (n == 99)
+               fprintf(stderr, "mode(2) in rbsb.c not implemented!!\n");
+       cucheck();
+       exit(128+n);
+}
+/* Called when ZMODEM gets an interrupt (^X) */
+onintr()
+{
+       signal(SIGINT, SIG_IGN);
+       longjmp(intrjmp, -1);
+}
+
+STATIC int Zctlesc;    /* Encode control characters */
+STATIC int Nozmodem = 0;       /* If invoked as "sb" */
+STATIC char *Progname = "sz";
+STATIC int Zrwindow = 1400;    /* RX window size (controls garbage count) */
+#include "zm.c"
+
+#include "zmr.c"
+
+#ifdef XARGSFILE
+#define XARGSMAX 256
+char *xargv[XARGSMAX+1];
+#endif
+
+main(argc, argv)
+char *argv[];
+{
+       register char *cp;
+       register npats;
+       int dm;
+       char **patts;
+       static char xXbuf[BUFSIZ];
+
+       if ((cp = getenv("ZNULLS")) && *cp)
+               Znulls = atoi(cp);
+       if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
+               Restricted=TRUE;
+       from_cu();
+#ifdef vax11c
+       chkinvok(PROGNAME);
+#else
+       chkinvok(argv[0]);
+#endif
+
+       Rxtimeout = 600;
+       npats=0;
+       if (argc<2)
+               usage();
+       setbuf(stdout, xXbuf);          
+       while (--argc) {
+               cp = *++argv;
+               if (*cp++ == '-' && *cp) {
+                       while ( *cp) {
+                               switch(*cp++) {
+                               case '\\':
+                                        *cp = toupper(*cp);  continue;
+                               case '+':
+                                       Lzmanag = ZMAPND; break;
+#ifdef CSTOPB
+                               case '2':
+                                       Twostop = TRUE; break;
+#endif
+                               case 'a':
+                                       Lzconv = ZCNL;
+                                       Ascii = TRUE; break;
+                               case 'b':
+                                       Lzconv = ZCBIN; break;
+                               case 'C':
+                                       if (--argc < 1) {
+                                               usage();
+                                       }
+                                       Cmdtries = atoi(*++argv);
+                                       break;
+                               case 'i':
+                                       Cmdack1 = ZCACK1;
+                                       /* **** FALL THROUGH TO **** */
+                               case 'c':
+                                       if (--argc != 1) {
+                                               usage();
+                                       }
+                                       Command = TRUE;
+                                       Cmdstr = *++argv;
+                                       break;
+                               case 'd':
+                                       ++Dottoslash;
+                                       /* **** FALL THROUGH TO **** */
+                               case 'f':
+                                       Fullname=TRUE; break;
+                               case 'e':
+                                       Zctlesc = 1; break;
+                               case 'k':
+                                       blklen=1024; break;
+                               case 'L':
+                                       if (--argc < 1) {
+                                               usage();
+                                       }
+                                       blkopt = atoi(*++argv);
+                                       if (blkopt<24 || blkopt>1024)
+                                               usage();
+                                       break;
+                               case 'l':
+                                       if (--argc < 1) {
+                                               usage();
+                                       }
+                                       Tframlen = atoi(*++argv);
+                                       if (Tframlen<32 || Tframlen>1024)
+                                               usage();
+                                       break;
+                               case 'N':
+                                       Lzmanag = ZMNEWL;  break;
+                               case 'n':
+                                       Lzmanag = ZMNEW;  break;
+                               case 'o':
+                                       Wantfcs32 = FALSE; break;
+                               case 'p':
+                                       Lzmanag = ZMPROT;  break;
+                               case 'r':
+                                       if (Lzconv == ZCRESUM)
+                                               Lzmanag = (Lzmanag &
+ZMMASK) | ZMCRC;
+                                       Lzconv = ZCRESUM; break;
+                               case 'q':
+                                       Quiet=TRUE; Verbose=0; break;
+                               case 't':
+                                       if (--argc < 1) {
+                                               usage();
+                                       }
+                                       Rxtimeout = atoi(*++argv);
+                                       if (Rxtimeout<10 || Rxtimeout>1000)
+                                               usage();
+                                       break;
+                               case 'T':
+                                       if (++Test > 1) {
+                                               chartest(1); chartest(2);
+                                               mode(0);  exit(0);
+                                       }
+                                       break;
+#ifndef vax11c
+                               case 'u':
+                                       ++Unlinkafter; break;
+#endif
+                               case 'v':
+                                       ++Verbose; break;
+                               case 'w':
+                                       if (--argc < 1) {
+                                               usage();
+                                       }
+                                       Txwindow = atoi(*++argv);
+                                       if (Txwindow < 256)
+                                               Txwindow = 256;
+                                       Txwindow = (Txwindow/64) * 64;
+                                       Txwspac = Txwindow/4;
+                                       if (blkopt > Txwspac
+                                        || (!blkopt && Txwspac < 1024))
+                                               blkopt = Txwspac;
+                                       break;
+                               case 'X':
+                                       ++Modem2; break;
+                               case 'Y':
+                                       Lskipnocor = TRUE;
+                                       /* **** FALLL THROUGH TO **** */
+                               case 'y':
+                                       Lzmanag = ZMCLOB; break;
+                               case 'Z':
+                               case 'z':
+                                       Lztrans = ZTRLE;  break;
+                               default:
+                                       usage();
+                               }
+                       }
+               }
+               else if ( !npats && argc>0) {
+                       if (argv[0][0]) {
+                               npats=argc;
+                               patts=argv;
+                       }
+               }
+       }
+       if (npats < 1 && !Command && !Test) 
+               usage();
+       if (Verbose) {
+               if (freopen(LOGFILE, "a", stderr)==NULL) {
+                       printf("Can't open log file %s\n",LOGFILE);
+                       exit(0200);
+               }
+               setbuf(stderr, NULL);
+       }
+       if (Fromcu && !Quiet) {
+               if (Verbose == 0)
+                       Verbose = 2;
+       }
+       vfile("%s %s for %s\n", Progname, VERSION, OS);
+
+#ifdef XARGSFILE
+       vfile("npats=%d *patts=%s", npats, *patts);
+       if (npats == 1 && !strcmp(XARGSFILE, *patts)) {
+               in = fopen(XARGSFILE, "r");
+               if (!in) {
+                       printf(stderr, "Can't open / control file!\n");
+                       exit(2);
+               }
+               for (npats=0,argv=patts=xargv; npats<XARGSMAX; ++npats,++argv) {
+                       if (fgets(txbuf, 1024, in) <= 0)
+                               break;
+                       uncrlf(txbuf);
+                       *argv = mystrsave(txbuf);
+               }
+               fclose(in);
+       }
+#endif
+
+       mode(1);
+
+#ifdef GENIE
+       signal(SIGINT, SIG_IGN);
+#else
+       if (signal(SIGINT, bibi) == SIG_IGN) {
+               signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
+       } else {
+               signal(SIGINT, bibi); signal(SIGKILL, bibi);
+       }
+#endif
+#ifdef SIGQUIT
+       if ( !Fromcu)
+               signal(SIGQUIT, SIG_IGN);
+#endif
+#ifdef SIGTERM
+       signal(SIGTERM, bibi);
+#endif
+
+       if ( !Modem2) {
+               if (!Nozmodem) {
+                       printf("rz\r");  fflush(stdout);
+               }
+               countem(npats, patts);
+               if (!Nozmodem) {
+                       stohdr(0L);
+                       if (Command)
+                               Txhdr[ZF0] = ZCOMMAND;
+                       zshhdr(4, ZRQINIT, Txhdr);
+               }
+       }
+       fflush(stdout);
+
+       if (Command) {
+               if (getzrxinit()) {
+                       Exitcode=0200; canit();
+               }
+               else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
+                       Exitcode=0200; canit();
+               }
+       } else if (wcsend(npats, patts)==ERROR) {
+               Exitcode=0200;
+               canit();
+       }
+       fflush(stdout);
+       mode(0);
+       dm = ((errcnt != 0) | Exitcode);
+       if (dm) {
+               cucheck();  exit(dm);
+       }
+       exit(SS_NORMAL);
+       /*NOTREACHED*/
+}
+
+wcsend(argc, argp)
+char *argp[];
+{
+       register n;
+
+       Crcflg=FALSE;
+       firstsec=TRUE;
+       bytcnt = -1;
+       if (Nozmodem) {
+               printf("Start your YMODEM receive. ");  fflush(stdout);
+       }
+       for (n=0; n<argc; ++n) {
+               Totsecs = 0;
+               if (wcs(argp[n])==ERROR)
+                       return ERROR;
+       }
+       Totsecs = 0;
+       if (Filcnt==0) {        /* bitch if we couldn't open ANY files */
+               if (!Nozmodem && !Modem2) {
+                       Command = TRUE;
+                       Cmdstr = "echo \"sz: Can't open any requested files\"";
+                       if (getnak()) {
+                               Exitcode=0200; canit();
+                       }
+                       if (!Zmodem)
+                               canit();
+                       else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
+                               Exitcode=0200; canit();
+                       }
+                       Exitcode = 1; return OK;
+               }
+               canit();
+               fprintf(stderr,"\r\nCan't open any requested files.\r\n");
+               return ERROR;
+       }
+       if (Zmodem)
+               saybibi();
+       else if ( !Modem2)
+               wctxpn("");
+       return OK;
+}
+
+wcs(oname)
+char *oname;
+{
+       register c;
+       register char *p, *q;
+#ifdef STAT
+       struct stat f;
+#endif
+       char name[PATHLEN];
+
+       strcpy(name, oname);
+
+#ifdef XARGSFILE
+       /* Parse GEniename:REALname:length pathname syntax */
+       Thisflen = -1;
+       for (p = oname; *p; ++p) {
+               if (*p == ':') {
+                       *p++ = 0;
+                       q = p;
+                       for (++p; *p; ++p) {
+                               if (*p == ':') {
+                                       *p++ = 0;
+                                       Thisflen = atol(p);
+                                       break;
+                               }
+                       }
+                       strcpy(name, q);
+                       break;
+               }
+       }
+#endif
+
+#ifdef GENIE
+       _describe(oname,&fdes);         /* An undocumented goodie */
+       if (fdes.type_file == 1) {      /* Fortran Sequential Binary */
+               Binfile = 1;
+               in = fopen(oname,"rB");
+       }
+       else if (fdes.type_file == 0)  { /* Ascii */
+               Binfile = 0;
+               in = fopen(oname,"r");
+       }
+       else {                          /* not a SL filetype */
+               fprintf(stderr, "\nUnknown file type %d\n",fdes.type_file);
+               ++errcnt;
+               return OK;              /* pass over it, there may be others */
+       }
+#else
+       if (Restricted) {
+               /* restrict pathnames to current tree or uucppublic */
+               if ( substr(name, "../")
+                || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
+                       canit();
+                       fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
+                       return ERROR;
+               }
+       }
+
+       in=fopen(oname, ROPMODE);
+#endif
+
+       if (in==NULL) {
+               ++errcnt;
+               return OK;      /* pass over it, there may be others */
+       }
+       BEofseen = Eofseen = 0;  vpos = 0;
+
+#ifdef STAT
+       /* Check for directory or block special files */
+       fstat(fileno(in), &f);
+       c = f.st_mode & S_IFMT;
+       if (c == S_IFDIR || c == S_IFBLK) {
+               fclose(in);
+               return OK;
+       }
+#endif
+
+       ++Filcnt;
+       switch (wctxpn(name)) {
+       case ERROR:
+               return ERROR;
+       case ZSKIP:
+               return OK;
+       }
+#ifdef STAT
+       if (!Zmodem && wctx(f.st_size)==ERROR)
+               return ERROR;
+#else
+       if (!Zmodem && wctx(1000000000L)==ERROR)
+               return ERROR;
+#endif
+
+#ifndef vax11c
+#ifndef GENIE
+       if (Unlinkafter)
+               unlink(oname);
+#endif
+#endif
+
+       return 0;
+}
+
+/*
+ * generate and transmit pathname block consisting of
+ *  pathname (null terminated),
+ *  file length, mode time and file mode in octal
+ *  as provided by the Unix fstat call.
+ *  N.B.: modifies the passed name, may extend it!
+ */
+wctxpn(name)
+char *name;
+{
+       register char *p, *q;
+       char name2[PATHLEN];
+#ifdef STAT
+       struct stat f;
+#endif
+
+       if (Modem2) {
+#ifdef STAT
+               if (*name && fstat(fileno(in), &f)!= -1) {
+                       fprintf(stderr, "Sending %s, %ld XMODEM blocks. ",
+                         name, (127+f.st_size)>>7);
+               }
+#endif
+               fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
+               fflush(stderr);
+               return OK;
+       }
+       zperr("Awaiting pathname nak for %s", *name?name:"<END>");
+       if ( !Zmodem)
+               if (getnak())
+                       return ERROR;
+
+       q = (char *) 0;
+       if (Dottoslash) {               /* change . to . */
+               for (p=name; *p; ++p) {
+                       if (*p == '/')
+                               q = p;
+                       else if (*p == '.')
+                               *(q=p) = '/';
+               }
+               if (q && strlen(++q) > 8) {     /* If name>8 chars */
+                       q += 8;                 /*   make it .ext */
+                       strcpy(name2, q);       /* save excess of name */
+                       *q = '.';
+                       strcpy(++q, name2);     /* add it back */
+               }
+       }
+
+       for (p=name, q=txbuf ; *p; )
+               if ((*q++ = *p++) == '/' && !Fullname)
+                       q = txbuf;
+       *q++ = 0;
+       p=q;
+       while (q < (txbuf + 1024))
+               *q++ = 0;
+       if (*name) {
+#ifdef XX
+               if (Thisflen >= 0) {
+                       sprintf(p, "%u 0 0 0 %d %ld",
+                         Thisflen, Filesleft, Totalleft);
+                       Totalleft -= Thisflen;
+               }
+#endif
+#ifdef GENIE
+               else
+                       sprintf(p, "%d", fdes.current_file_size * 1260);
+               vfile("%s open Binfile=%d size=%ld", name, Binfile,
+                 fdes.current_file_size * 1260);
+#endif
+
+#ifdef STAT
+#ifndef XX
+               if (fstat(fileno(in), &f)!= -1)
+                       sprintf(p, "%lu %lo %o 0 %d %ld", f.st_size, f.st_mtime,
+                         f.st_mode, Filesleft, Totalleft);
+               Totalleft -= f.st_size;
+#endif
+#endif
+
+       }
+       if (--Filesleft <= 0)
+               Totalleft = 0;
+       if (Totalleft < 0)
+               Totalleft = 0;
+
+#ifdef STAT
+       /* force 1k blocks if name won't fit in 128 byte block */
+       if (txbuf[125])
+               blklen=1024;
+       else {          /* A little goodie for IMP/KMD */
+               txbuf[127] = (f.st_size + 127) >>7;
+               txbuf[126] = (f.st_size + 127) >>15;
+       }
+#endif
+       if (Zmodem)
+               return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
+       if (wcputsec(txbuf, 0, 128)==ERROR)
+               return ERROR;
+       return OK;
+}
+
+getnak()
+{
+       register firstch;
+
+       Lastrx = 0;
+       for (;;) {
+               switch (firstch = readline(800)) {
+               case ZPAD:
+                       if (getzrxinit())
+                               return ERROR;
+                       Ascii = 0;      /* Receiver does the conversion */
+                       return FALSE;
+               case TIMEOUT:
+                       zperr("Timeout on pathname");
+                       return TRUE;
+               case WANTG:
+#ifdef MODE2OK
+                       mode(2);        /* Set cbreak, XON/XOFF, etc. */
+#endif
+                       Optiong = TRUE;
+                       blklen=1024;
+               case WANTCRC:
+                       Crcflg = TRUE;
+               case NAK:
+                       return FALSE;
+               case CAN:
+                       if ((firstch = readline(20)) == CAN && Lastrx == CAN)
+                               return TRUE;
+               default:
+                       break;
+               }
+               Lastrx = firstch;
+       }
+}
+
+
+wctx(flen)
+long flen;
+{
+       register int thisblklen;
+       register int sectnum, attempts, firstch;
+       long charssent;
+
+       charssent = 0;  firstsec=TRUE;  thisblklen = blklen;
+       vfile("wctx:file length=%ld", flen);
+
+       while ((firstch=readline(Rxtimeout))!=NAK && firstch != WANTCRC
+         && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
+               ;
+       if (firstch==CAN) {
+               zperr("Receiver CANcelled");
+               return ERROR;
+       }
+       if (firstch==WANTCRC)
+               Crcflg=TRUE;
+       if (firstch==WANTG)
+               Crcflg=TRUE;
+       sectnum=0;
+       for (;;) {
+               if (flen <= (charssent + 896L))
+                       thisblklen = 128;
+               if ( !filbuf(txbuf, thisblklen))
+                       break;
+               if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
+                       return ERROR;
+               charssent += thisblklen;
+       }
+       fclose(in);
+       attempts=0;
+       do {
+               purgeline();
+               sendline(EOT);
+               flushmo();
+               ++attempts;
+       }
+               while ((firstch=(readline(Rxtimeout)) != ACK) &&
+attempts < RETRYMAX);
+       if (attempts == RETRYMAX) {
+               zperr("No ACK on EOT");
+               return ERROR;
+       }
+       else
+               return OK;
+}
+
+wcputsec(buf, sectnum, cseclen)
+char *buf;
+int sectnum;
+int cseclen;   /* data length of this sector to send */
+{
+       register checksum, wcj;
+       register char *cp;
+       unsigned oldcrc;
+       int firstch;
+       int attempts;
+
+       firstch=0;      /* part of logic to detect CAN CAN */
+
+       if (Verbose>2)
+               fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 );
+       else if (Verbose>1)
+               fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
+       for (attempts=0; attempts <= RETRYMAX; attempts++) {
+               Lastrx= firstch;
+               sendline(cseclen==1024?STX:SOH);
+               sendline(sectnum);
+               sendline(-sectnum -1);
+               oldcrc=checksum=0;
+               for (wcj=cseclen,cp=buf; --wcj>=0; ) {
+                       sendline(*cp);
+                       oldcrc=updcrc((0377& *cp), oldcrc);
+                       checksum += *cp++;
+               }
+               if (Crcflg) {
+                       oldcrc=updcrc(0,updcrc(0,oldcrc));
+                       sendline((int)oldcrc>>8);
+                       sendline((int)oldcrc);
+               }
+               else
+                       sendline(checksum);
+               flushmo();
+
+               if (Optiong) {
+                       firstsec = FALSE; return OK;
+               }
+               firstch = readline(Rxtimeout);
+gotnak:
+               switch (firstch) {
+               case CAN:
+                       if(Lastrx == CAN) {
+cancan:
+                               zperr("Cancelled");  return ERROR;
+                       }
+                       break;
+               case TIMEOUT:
+                       zperr("Timeout on sector ACK"); continue;
+               case WANTCRC:
+                       if (firstsec)
+                               Crcflg = TRUE;
+               case NAK:
+                       zperr("NAK on sector"); continue;
+               case ACK: 
+                       firstsec=FALSE;
+                       Totsecs += (cseclen>>7);
+                       return OK;
+               case ERROR:
+                       zperr("Got burst for sector ACK"); break;
+               default:
+                       zperr("Got %02x for sector ACK", firstch); break;
+               }
+               for (;;) {
+                       Lastrx = firstch;
+                       if ((firstch = readline(Rxtimeout)) == TIMEOUT)
+                               break;
+                       if (firstch == NAK || firstch == WANTCRC)
+                               goto gotnak;
+                       if (firstch == CAN && Lastrx == CAN)
+                               goto cancan;
+               }
+       }
+       zperr("Retry Count Exceeded");
+       return ERROR;
+}
+
+/* fill buf with count chars padding with ^Z for CPM */
+filbuf(buf, count)
+register char *buf;
+{
+       register c, m;
+
+       if ( !Ascii) {
+               m = read(fileno(in), buf, count);
+               if (m <= 0)
+                       return 0;
+               while (m < count)
+                       buf[m++] = 032;
+               return count;
+       }
+       m=count;
+       if (Lfseen) {
+               *buf++ = 012; --m; Lfseen = 0;
+       }
+       while ((c=getc(in))!=EOF) {
+               if (c == 012) {
+                       *buf++ = 015;
+                       if (--m == 0) {
+                               Lfseen = TRUE; break;
+                       }
+               }
+               *buf++ =c;
+               if (--m == 0)
+                       break;
+       }
+       if (m==count)
+               return 0;
+       else
+               while (--m>=0)
+                       *buf++ = CPMEOF;
+       return count;
+}
+
+/* Fill buffer with blklen chars */
+zfilbuf()
+{
+       int n;
+
+#ifdef TXBSIZE
+       vfile("zfilbuf: bytcnt =%lu vpos=%lu blklen=%d", bytcnt, vpos, blklen);
+       /* We assume request is within buffer, or just beyond */
+       txbuf = Txb + (bytcnt & TXBMASK);
+       if (vpos <= bytcnt) {
+#ifdef GENIE
+               if (Binfile) {
+                       long l, m;  char *p;
+
+                       for (p=txbuf, n=0, l=blklen;  l;  l -= 128, p+= 128) {
+                               n += m = fgetb(p, 128, in);
+                               if (m == 0)
+                                       break;
+                       }
+               } else
+#endif
+               n = fread(txbuf, 1, blklen, in);
+
+               vpos += n;
+               if (n < blklen)
+                       Eofseen = 1;
+               vfile("zfilbuf: n=%d vpos=%lu Eofseen=%d", n, vpos, Eofseen);
+               return n;
+       }
+       if (vpos >= (bytcnt+blklen))
+               return blklen;
+       /* May be a short block if crash recovery etc. */
+       Eofseen = BEofseen;
+       return (vpos - bytcnt);
+#else
+       n = fread(txbuf, 1, blklen, in);
+       if (n < blklen)
+               Eofseen = 1;
+       return n;
+#endif
+}
+
+#ifdef TXBSIZE
+/* Replacement for brain damaged fseek function.  Returns 0==success */
+fooseek(fptr, pos, whence)
+FILE *fptr;
+long pos;
+{
+       long m, n;
+#ifdef GENIE
+       long l, k;  char *p;
+#endif
+
+       vfile("fooseek: pos =%lu vpos=%lu Canseek=%d", pos, vpos, Canseek);
+       /* Seek offset < current buffer */
+       if (pos < (vpos -TXBSIZE +1024)) {
+               BEofseen = 0;
+               if (Canseek > 0) {
+                       vpos = pos & ~TXBMASK;
+                       if (vpos >= pos)
+                               vpos -= TXBSIZE;
+                       if (fseek(fptr, vpos, 0))
+                               return 1;
+               }
+               else if (Canseek == 0) {
+#ifdef GENIE
+                       if (Binfile) {
+                               if (fseekb(fptr, vpos = 0L, 0))
+                                       return 1;
+                               } else
+#endif
+                       if (fseek(fptr, vpos = 0L, 0))
+                               return 1;
+               } else
+                       return 1;
+               while (vpos < pos) {
+#ifdef GENIE
+                       if (Binfile) {
+                               for (p=Txb,n=0,l=TXBSIZE; l; l -= 128,p+= 128) {
+                                       n += (k = fgetb(p, 128, fptr));
+                                       vfile("bsk1: l=%d k=%d", l, k);
+                                       if (k == 0)
+                                               break;
+                               }
+                       } else
+#endif
+                       n = fread(Txb, 1, TXBSIZE, fptr);
+                       vpos += n;
+                       vfile("n=%d vpos=%ld", n, vpos);
+                       if (n < TXBSIZE) {
+                               BEofseen = 1;
+                               break;
+                       }
+               }
+               vfile("vpos=%ld", vpos);
+               return 0;
+       }
+       /* Seek offset > current buffer (Crash Recovery, etc.) */
+       if (pos > vpos) {
+               if (Canseek)
+                       if (fseek(fptr, vpos = (pos & ~TXBMASK), 0))
+                               return 1;
+               while (vpos <= pos) {
+                       txbuf = Txb + (vpos & TXBMASK);
+                       m = TXBSIZE - (vpos & TXBMASK);
+                       vfile("m=%ld vpos=%ld", m,vpos);
+#ifdef GENIE
+                       if (Binfile) {
+                               for (p=txbuf,n=0,l=m; l; l -= 128,p+= 128) {
+                                       n += (k = fgetb(p, 128, fptr));
+                                       vfile("bsk2: l=%d k=%d n=%d", l, k, n);
+                                       if (k == 0)
+                                               break;
+                               }
+                       } else
+#endif
+                               n = fread(txbuf, 1, m, fptr);
+                       vfile("n=%ld vpos=%ld", n,vpos);
+                       vpos += n;
+                       vfile("bo=%d m=%ld vpos=%ld", txbuf-Txb,m,vpos);
+                       if (n < m) {
+                               BEofseen = 1;
+                               break;
+                       }
+               }
+               return 0;
+       }
+       /* Seek offset is within current buffer */
+       vfile("within buffer: vpos=%ld", vpos);
+       return 0;
+}
+#define fseek fooseek
+#endif
+
+
+/* VARARGS1 */
+vfile(f, a, b, c, d)
+register char *f;
+{
+       if (Verbose > 2) {
+               fprintf(stderr, f, a, b, c, d);
+               fprintf(stderr, "\n");
+       }
+}
+
+
+void
+alrm()
+{
+       longjmp(tohere, -1);
+}
+
+
+#ifndef GENIE
+#ifndef vax11c
+/*
+ * readline(timeout) reads character(s) from file descriptor 0
+ * timeout is in tenths of seconds
+ */
+readline(timeout)
+{
+       register int c;
+       static char byt[1];
+
+       fflush(stdout);
+       if (setjmp(tohere)) {
+               zperr("TIMEOUT");
+               return TIMEOUT;
+       }
+       c = timeout/10;
+       if (c<2)
+               c=2;
+       if (Verbose>5) {
+               fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
+       }
+       signal(SIGALRM, alrm); alarm(c);
+       c=read(0, byt, 1);
+       alarm(0);
+       if (Verbose>5)
+               fprintf(stderr, "ret %x\n", byt[0]);
+       if (c<1)
+               return TIMEOUT;
+       return (byt[0]&0377);
+}
+
+flushmo()
+{
+       fflush(stdout);
+}
+
+
+purgeline()
+{
+#ifdef USG
+       ioctl(0, TCFLSH, 0);
+#else
+       lseek(0, 0L, 2);
+#endif
+}
+#endif
+#endif
+
+/* send cancel string to get the other end to shut up */
+canit()
+{
+       static char canistr[] = {
+        24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
+       };
+
+#ifdef vax11c
+       raw_wbuf(strlen(canistr), canistr);
+       purgeline();
+#else
+       printf(canistr);
+       fflush(stdout);
+#endif
+}
+
+
+/*
+ * Log an error
+ */
+/*VARARGS1*/
+zperr(s,p,u)
+char *s, *p, *u;
+{
+       if (Verbose <= 0)
+               return;
+       fprintf(stderr, "Retry %d: ", errors);
+       fprintf(stderr, s, p, u);
+       fprintf(stderr, "\n");
+}
+
+/*
+ * substr(string, token) searches for token in string s
+ * returns pointer to token within string if found, NULL otherwise
+ */
+char *
+substr(s, t)
+register char *s,*t;
+{
+       register char *ss,*tt;
+       /* search for first char of token */
+       for (ss=s; *s; s++)
+               if (*s == *t)
+                       /* compare token with substring */
+                       for (ss=s,tt=t; ;) {
+                               if (*tt == 0)
+                                       return s;
+                               if (*ss++ != *tt++)
+                                       break;
+                       }
+       return NULL;
+}
+
+char *babble[] = {
+#ifdef vax11c
+       "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
+       "       (Y) = Option applies to YMODEM only",
+       "       (Z) = Option applies to ZMODEM only",
+       "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
+       "       sz [-2Ceqv] -c COMMAND",
+       "       \\ Force next option letter to upper case",
+       "       sb [-2adfkquv] [-] file ...",
+       "       sx [-2akquv] [-] file",
+#endif
+#ifndef vax11c
+       "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
+       "       (Y) = Option applies to YMODEM only",
+       "       (Z) = Option applies to ZMODEM only",
+       "Usage: sz [-2+abdefkLlNnquvwYy] [-] file ...",
+       "       sz [-2Ceqv] -c COMMAND",
+       "       sb [-2adfkquv] [-] file ...",
+       "       sx [-2akquv] [-] file",
+#endif
+#ifdef CSTOPB
+       "       2   Use 2 stop bits",
+#endif
+       "       +   Append to existing destination file (Z)",
+       "       a   (ASCII) change NL to CR/LF",
+       "       b   Binary file transfer override",
+       "       c   send COMMAND (Z)",
+#ifndef vax11c
+       "       d   Change '.' to '/' in pathnames (Y/Z)",
+#endif
+       "       e   Escape all control characters (Z)",
+       "       f   send Full pathname (Y/Z)",
+       "       i   send COMMAND, ack Immediately (Z)",
+       "       k   Send 1024 byte packets (Y)",
+       "       L N Limit subpacket length to N bytes (Z)",
+       "       l N Limit frame length to N bytes (l>=L) (Z)",
+       "       n   send file only if source newer (Z)",
+       "       N   send file only if source newer or longer (Z)",
+       "       o   Use 16 bit CRC instead of 32 bit CRC (Z)",
+       "       p   Protect existing destination file (Z)",
+       "       r   Resume/Recover interrupted file transfer (Z)",
+       "       q   Quiet (no progress reports)",
+#ifndef vax11c
+       "       u   Unlink (remove) file after transmission",
+#endif
+       "       v   Verbose - provide debugging information",
+       "       w N restrict Window to N bytes (Z)",
+       "       Y   Yes, overwrite existing file, skip if not present at rx (Z)",
+       "       y   Yes, overwrite existing file (Z)",
+       "       Z   Activate ZMODEM compression(Z)",
+       ""
+};
+
+usage()
+{
+       char **pp;
+
+       for (pp=babble; **pp; ++pp)
+               fprintf(stderr, "%s\n", *pp);
+       fprintf(stderr, "%s for %s by Chuck Forsberg, Omen Technology INC\n",
+        VERSION, OS);
+       fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
+       cucheck();
+       exit(SS_NORMAL);
+}
+
+/*
+ * Get the receiver's init parameters
+ */
+getzrxinit()
+{
+       register n;
+#ifdef STAT
+       struct stat f;
+#endif
+
+       for (n=10; --n>=0; ) {
+               
+               switch (zgethdr(Rxhdr, 1)) {
+               case ZCHALLENGE:        /* Echo receiver's challenge numbr */
+                       stohdr(Rxpos);
+                       zshhdr(4, ZACK, Txhdr);
+                       continue;
+               case ZCOMMAND:          /* They didn't see out ZRQINIT */
+                       stohdr(0L);
+                       zshhdr(4, ZRQINIT, Txhdr);
+                       continue;
+               case ZRINIT:
+                       Rxflags = 0377 & Rxhdr[ZF0];
+                       Usevhdrs = Rxhdr[ZF1] & CANVHDR;
+                       Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
+                       Zctlesc |= Rxflags & TESCCTL;
+                       Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
+                       if ( !(Rxflags & CANFDX))
+                               Txwindow = 0;
+                       vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
+                       if ( !Fromcu)
+                               signal(SIGINT, SIG_IGN);
+#ifdef MODE2OK
+                       mode(2);        /* Set cbreak, XON/XOFF, etc. */
+#endif
+
+#ifndef READCHECK
+#ifndef USG
+#ifndef GENIE
+                       /* Use 1024 byte frames if no sample/interrupt */
+                       if (Rxbuflen < 32 || Rxbuflen > 1024) {
+                               Rxbuflen = 1024;
+                               vfile("Rxbuflen=%d", Rxbuflen);
+                       }
+#endif
+#endif
+#endif
+
+                       /* Override to force shorter frame length */
+                       if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
+                               Rxbuflen = Tframlen;
+                       if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
+                               Rxbuflen = Tframlen;
+                       vfile("Rxbuflen=%d", Rxbuflen);
+
+#ifndef GENIE
+#ifndef vax11c
+#ifdef STAT
+                       /* If using a pipe for testing set lower buf len */
+                       fstat(0, &f);
+                       if ((f.st_mode & S_IFMT) != S_IFCHR) {
+                               Rxbuflen = 1024;
+                       }
+#endif
+#endif
+#endif
+
+#ifdef BADSEEK
+#ifdef GENIE
+                       if (Txwindow == 0) {
+                               Txwspac = (Txwindow = 4096)/4;
+                       }
+#else
+                       if (Txwindow == 0)
+                               Txwindow = TXBSIZE - 1024;
+                       Txwspac = TXBSIZE/4;
+#endif
+                       Canseek = 0;
+#endif
+
+                       /*
+                        * If input is not a regular file, force ACK's to
+                        *  prevent running beyond the buffer limits
+                        */
+#ifdef STAT
+                       if ( !Command) {
+                               fstat(fileno(in), &f);
+                               if ((f.st_mode & S_IFMT) != S_IFREG) {
+                                       Canseek = -1;
+#ifdef TXBSIZE
+                                       Txwindow = TXBSIZE - 1024;
+                                       Txwspac = TXBSIZE/4;
+#else
+                                       return ERROR;
+#endif
+                               }
+                       }
+#endif
+
+                       /* Set initial subpacket length */
+                       if (blklen < 1024) {    /* Command line override? */
+                               if (Effbaud > 300)
+                                       blklen = 256;
+                               if (Effbaud > 1200)
+                                       blklen = 512;
+                               if (Effbaud > 2400)
+                                       blklen = 1024;
+                       }
+                       if (Rxbuflen && blklen>Rxbuflen)
+                               blklen = Rxbuflen;
+                       if (blkopt && blklen > blkopt)
+                               blklen = blkopt;
+#ifdef GENIE
+                       blklen /= 128;  blklen *= 128;
+                       if (blklen < 128)
+                               blklen = 128;
+#endif
+                       vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
+                       vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
+
+
+                       if (Lztrans == ZTRLE && (Rxflags & CANRLE))
+                               Txfcs32 = 2;
+                       else
+                               Lztrans = 0;
+
+                       return (sendzsinit());
+               case ZCAN:
+               case TIMEOUT:
+                       return ERROR;
+               case ZRQINIT:
+                       if (Rxhdr[ZF0] == ZCOMMAND)
+                               continue;
+               default:
+                       zshhdr(4, ZNAK, Txhdr);
+                       continue;
+               }
+       }
+       return ERROR;
+}
+
+/* Send send-init information */
+sendzsinit()
+{
+       register c;
+
+       if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
+               return OK;
+       errors = 0;
+       for (;;) {
+               stohdr(0L);
+#ifdef ALTCANOFF
+               Txhdr[ALTCOFF] = ALTCANOFF;
+#endif
+               if (Zctlesc) {
+                       Txhdr[ZF0] |= TESCCTL; zshhdr(4, ZSINIT, Txhdr);
+               }
+               else
+                       zsbhdr(4, ZSINIT, Txhdr);
+               zsdata(Myattn, ZATTNLEN, ZCRCW);
+               c = zgethdr(Rxhdr, 1);
+               switch (c) {
+               case ZCAN:
+                       return ERROR;
+               case ZACK:
+                       return OK;
+               default:
+                       if (++errors > 19)
+                               return ERROR;
+                       continue;
+               }
+       }
+}
+
+/* Send file name and related info */
+zsendfile(buf, blen)
+char *buf;
+{
+       register c;
+       register UNSL long crc;
+       long lastcrcrq = -1;
+       char *p;
+
+       for (;;) {
+               Txhdr[ZF0] = Lzconv;    /* file conversion request */
+               Txhdr[ZF1] = Lzmanag;   /* file management request */
+               if (Lskipnocor)
+                       Txhdr[ZF1] |= ZMSKNOLOC;
+               Txhdr[ZF2] = Lztrans;   /* file transport request */
+               Txhdr[ZF3] = 0;
+               zsbhdr(4, ZFILE, Txhdr);
+               zsdata(buf, blen, ZCRCW);
+again:
+               c = zgethdr(Rxhdr, 1);
+               switch (c) {
+               case ZRINIT:
+                       while ((c = readline(50)) > 0)
+                               if (c == ZPAD) {
+                                       goto again;
+                               }
+                       /* **** FALL THRU TO **** */
+               default:
+                       continue;
+               case ZCAN:
+               case TIMEOUT:
+               case ZABORT:
+               case ZFIN:
+                       return ERROR;
+               case ZCRC:
+                       if (Rxpos != lastcrcrq) {
+                               lastcrcrq = Rxpos;
+                               crc = 0xFFFFFFFFL;
+                               if (Canseek >= 0) {
+                                       fseek(in, 0L, 0);
+                                       while (((c = getc(in)) != EOF)
+&& --lastcrcrq)
+                                               crc = UPDC32(c, crc);
+                                       crc = ~crc;
+                                       clearerr(in);   /* Clear possible EOF */
+                                       lastcrcrq = Rxpos;
+                               }
+                       }
+                       stohdr(crc);
+                       zsbhdr(4, ZCRC, Txhdr);
+                       goto again;
+               case ZSKIP:
+                       fclose(in); return c;
+               case ZRPOS:
+                       /*
+                        * Suppress zcrcw request otherwise triggered by
+                        * lastyunc==bytcnt
+                        */
+#ifdef GENIE
+                       /*
+                        *  Special case - turn on RLE if not archive, etc.
+                        *   otherwise turn off RLE unless cmd line specified
+                        */
+                       if (Rxflags & CANRLE) {         /* RX can do it */
+                               bytcnt = 0;
+                               zfilbuf();
+                               vfile("txbuf012: %x %x %x", txbuf[0], txbuf[1],
+                                 txbuf[2]);
+                               if ((txbuf[0] != 032)   /* .ARC file */
+                                && (txbuf[0] != 0x1f)  /* .Z file */
+                                && (txbuf[0] != 0x1c)  /* .LHZ file */
+                                && strncmp(txbuf, "ZOO", 3)
+                                && strncmp(txbuf, "GIF", 3)
+                                && (txbuf[2] != 3))    /* .ZIP file */
+                                       Txfcs32 = 2;
+                               else if ( !(Lztrans & ZTRLE))
+                                       Txfcs32 = 1;
+                       }
+                       /* GEnie binary can't seek to byte */
+                       if (Binfile) {
+                               Rxpos &= ~127L;
+                       }
+#endif
+                       if (fseek(in, Rxpos, 0))
+                               return ERROR;
+                       Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1;
+                       return zsendfdata();
+               }
+       }
+}
+
+/* Send the data in the file */
+zsendfdata()
+{
+       register c, e, n;
+       register newcnt;
+       register long tcount = 0;
+       int junkcount;          /* Counts garbage chars received by TX */
+       static int tleft = 6;   /* Counter for test mode */
+
+       junkcount = 0;
+       Beenhereb4 = FALSE;
+somemore:
+       if (setjmp(intrjmp)) {
+waitack:
+               junkcount = 0;
+               c = getinsync(0);
+gotack:
+               switch (c) {
+               default:
+               case ZCAN:
+                       fclose(in);
+                       return ERROR;
+               case ZSKIP:
+                       fclose(in);
+                       return c;
+               case ZACK:
+               case ZRPOS:
+                       break;
+               case ZRINIT:
+                       return OK;
+               }
+#ifdef READCHECK
+               /*
+                * If the reverse channel can be tested for data,
+                *  this logic may be used to detect error packets
+                *  sent by the receiver, in place of setjmp/longjmp
+                *  rdchk(fd) returns non 0 if a character is available
+                */
+               while (rdchk(0)) {
+#ifdef EATSIT
+                       switch (checked)
+#else
+                       switch (readline(1))
+#endif
+                       {
+                       case CAN:
+                       case ZPAD:
+                               c = getinsync(1);
+                               goto gotack;
+                       case XOFF:              /* Wait a while for an XON */
+                       case XOFF|0200:
+                               readline(100);
+                       }
+               }
+#endif
+       }
+
+       if ( !Fromcu)
+               signal(SIGINT, onintr);
+       newcnt = Rxbuflen;
+       Txwcnt = 0;
+       stohdr(Txpos);
+       zsbhdr(4, ZDATA, Txhdr);
+
+       /*
+        * Special testing mode.  This should force receiver to Attn,ZRPOS
+        *  many times.  Each time the signal should be caught, causing the
+        *  file to be started over from the beginning.
+        */
+       if (Test) {
+               if ( --tleft)
+                       while (tcount < 20000) {
+                               printf(qbf); fflush(stdout);
+                               tcount += strlen(qbf);
+#ifdef READCHECK
+                               while (rdchk(0)) {
+#ifdef EATSIT
+                                       switch (checked)
+#else
+                                       switch (readline(1))
+#endif
+                                       {
+                                       case CAN:
+                                       case ZPAD:
+#ifdef TCFLSH
+                                               ioctl(0, TCFLSH, 1);
+#endif
+                                               goto waitack;
+                                       case XOFF:      /* Wait for XON */
+                                       case XOFF|0200:
+                                               readline(100);
+                                       }
+                               }
+#endif
+                       }
+               signal(SIGINT, SIG_IGN); canit();
+               sleep(3); purgeline(); mode(0);
+               printf("\nsz: Tcount = %ld\n", tcount);
+               if (tleft) {
+                       printf("ERROR: Interrupts Not Caught\n");
+                       exit(1);
+               }
+               exit(SS_NORMAL);
+       }
+
+       do {
+               n = zfilbuf();
+               if (Eofseen)
+                       e = ZCRCE;
+               else if (junkcount > 3)
+                       e = ZCRCW;
+               else if (bytcnt == Lastsync)
+                       e = ZCRCW;
+               else if (Rxbuflen && (newcnt -= n) <= 0)
+                       e = ZCRCW;
+               else if (Txwindow && (Txwcnt += n) >= Txwspac) {
+                       Txwcnt = 0;  e = ZCRCQ;
+               } else
+                       e = ZCRCG;
+               if (Verbose>1)
+                       fprintf(stderr, "\r%7ld ZMODEM%s    ",
+                         Txpos, Crc32t?" CRC-32":"");
+               zsdata(txbuf, n, e);
+               bytcnt = Txpos += n;
+               if (e == ZCRCW)
+                       goto waitack;
+#ifdef READCHECK
+               /*
+                * If the reverse channel can be tested for data,
+                *  this logic may be used to detect error packets
+                *  sent by the receiver, in place of setjmp/longjmp
+                *  rdchk(fd) returns non 0 if a character is available
+                */
+               fflush(stdout);
+               while (rdchk(0)) {
+#ifdef EATSIT
+                       switch (checked)
+#else
+                       switch (readline(1))
+#endif
+                       {
+                       case CAN:
+                       case ZPAD:
+                               c = getinsync(1);
+                               if (c == ZACK)
+                                       break;
+#ifdef TCFLSH
+                               ioctl(0, TCFLSH, 1);
+#endif
+                               /* zcrce - dinna wanna starta ping-pong game */
+                               zsdata(txbuf, 0, ZCRCE);
+                               goto gotack;
+                       case XOFF:              /* Wait a while for an XON */
+                       case XOFF|0200:
+                               readline(100);
+                       default:
+                               ++junkcount;
+                       }
+               }
+#endif /* READCHECK */
+               if (Txwindow) {
+                       while ((tcount = Txpos - Lrxpos) >= Txwindow) {
+                               vfile("%ld window >= %u", tcount, Txwindow);
+                               if (e != ZCRCQ)
+                                       zsdata(txbuf, 0, e = ZCRCQ);
+                               c = getinsync(1);
+                               if (c != ZACK) {
+#ifdef TCFLSH
+                                       ioctl(0, TCFLSH, 1);
+#endif
+                                       zsdata(txbuf, 0, ZCRCE);
+                                       goto gotack;
+                               }
+                       }
+                       vfile("window = %ld", tcount);
+               }
+       } while (!Eofseen);
+       if ( !Fromcu)
+               signal(SIGINT, SIG_IGN);
+
+       for (;;) {
+               stohdr(Txpos);
+               zsbhdr(4, ZEOF, Txhdr);
+               switch (getinsync(0)) {
+               case ZACK:
+                       continue;
+               case ZRPOS:
+                       goto somemore;
+               case ZRINIT:
+                       return OK;
+               case ZSKIP:
+                       fclose(in);
+                       return c;
+               default:
+                       fclose(in);
+                       return ERROR;
+               }
+       }
+}
+
+/*
+ * Respond to receiver's complaint, get back in sync with receiver
+ */
+getinsync(flag)
+{
+       register c;
+
+       for (;;) {
+               if (Test) {
+                       printf("\r\n\n\n***** Signal Caught *****\r\n");
+                       Rxpos = 0; c = ZRPOS;
+               } else
+                       c = zgethdr(Rxhdr, 0);
+               switch (c) {
+               case ZCAN:
+               case ZABORT:
+               case ZFIN:
+               case TIMEOUT:
+                       return ERROR;
+               case ZRPOS:
+                       /* ************************************* */
+                       /*  If sending to a buffered modem, you  */
+                       /*   might send a break at this point to */
+                       /*   dump the modem's buffer.            */
+                       clearerr(in);   /* In case file EOF seen */
+                       if (fseek(in, Rxpos, 0))
+                               return ERROR;
+                       Eofseen = 0;
+                       bytcnt = Lrxpos = Txpos = Rxpos;
+#ifndef GENIE
+                       if (Lastsync == Rxpos) {
+                               if (++Beenhereb4 > 4)
+                                       if (blklen > 32)
+                                               blklen /= 2;
+                       }
+#endif
+                       Lastsync = Rxpos;
+                       return c;
+               case ZACK:
+                       Lrxpos = Rxpos;
+                       if (flag || Txpos == Rxpos)
+                               return ZACK;
+                       continue;
+               case ZRINIT:
+               case ZSKIP:
+                       fclose(in);
+                       return c;
+               case ERROR:
+               default:
+                       zsbhdr(4, ZNAK, Txhdr);
+                       continue;
+               }
+       }
+}
+
+
+/* Say "bibi" to the receiver, try to do it cleanly */
+saybibi()
+{
+       for (;;) {
+               stohdr(0L);             /* CAF Was zsbhdr - minor change */
+               zshhdr(4, ZFIN, Txhdr); /*  to make debugging easier */
+               switch (zgethdr(Rxhdr, 0)) {
+               case ZFIN:
+                       sendline('O'); sendline('O'); flushmo();
+               case ZCAN:
+               case TIMEOUT:
+                       return;
+               }
+       }
+}
+
+/* Local screen character display function */
+bttyout(c)
+{
+       if (Verbose)
+               putc(c, stderr);
+}
+
+/* Send command and related info */
+zsendcmd(buf, blen)
+char *buf;
+{
+       register c;
+       long cmdnum;
+
+#ifdef GENIE
+       cmdnum = 69;
+#else
+       cmdnum = getpid();
+#endif
+       errors = 0;
+       for (;;) {
+               stohdr(cmdnum);
+               Txhdr[ZF0] = Cmdack1;
+               zsbhdr(4, ZCOMMAND, Txhdr);
+               zsdata(buf, blen, ZCRCW);
+listen:
+               Rxtimeout = 100;                /* Ten second wait for resp. */
+               Usevhdrs = 0;           /* Allow rx to send fixed len headers */
+               c = zgethdr(Rxhdr, 1);
+
+               switch (c) {
+               case ZRINIT:
+                       goto listen;    /* CAF 8-21-87 */
+               case ERROR:
+               case GCOUNT:
+               case TIMEOUT:
+                       if (++errors > Cmdtries)
+                               return ERROR;
+                       continue;
+               case ZCAN:
+               case ZABORT:
+               case ZFIN:
+               case ZSKIP:
+               case ZRPOS:
+                       return ERROR;
+               default:
+                       if (++errors > 20)
+                               return ERROR;
+                       continue;
+               case ZCOMPL:
+                       Exitcode = Rxpos;
+                       saybibi();
+                       return OK;
+               case ZRQINIT:
+#ifdef vax11c          /* YAMP :== Yet Another Missing Primitive */
+                       return ERROR;
+#else
+                       vfile("******** RZ *******");
+                       system("rz");
+                       vfile("******** SZ *******");
+                       goto listen;
+#endif
+               }
+       }
+}
+
+/*
+ * If called as sb use YMODEM protocol
+ */
+chkinvok(s)
+char *s;
+{
+       register char *p;
+
+       p = s;
+       while (*p == '-')
+               s = ++p;
+       while (*p)
+               if (*p++ == '/')
+                       s = p;
+       if (*s == 'v') {
+               Verbose=1; ++s;
+       }
+       Progname = s;
+       if (s[0]=='s' && s[1]=='b') {
+               Nozmodem = TRUE; blklen=1024;
+       }
+       if (s[0]=='s' && s[1]=='x') {
+               Modem2 = TRUE;
+       }
+}
+
+#ifdef STAT
+countem(argc, argv)
+register char **argv;
+{
+       register c;
+       struct stat f;
+
+       for (Totalleft = 0, Filesleft = 0; --argc >=0; ++argv) {
+               f.st_size = -1;
+               if (Verbose>2) {
+                       fprintf(stderr, "\nCountem: %03d %s ", argc, *argv);
+                       fflush(stderr);
+               }
+               if (access(*argv, 04) >= 0 && stat(*argv, &f) >= 0) {
+                       c = f.st_mode & S_IFMT;
+                       if (c != S_IFDIR && c != S_IFBLK) {
+                               ++Filesleft;  Totalleft += f.st_size;
+                       }
+               }
+               if (Verbose>2)
+                       fprintf(stderr, " %ld", f.st_size);
+       }
+       if (Verbose>2)
+               fprintf(stderr, "\ncountem: Total %d %ld\n",
+                 Filesleft, Totalleft);
+}
+#else
+countem(argc, argv)
+register char **argv;
+{
+       register c;
+       register char *p;
+       long size;
+
+       for (Totalleft = 0, Filesleft = 0; --argc >=0; ++argv) {
+               size = -1;
+               if (Verbose>2) {
+                       fprintf(stderr, "\nCountem: %03d %s ", argc, *argv);
+                       fflush(stderr);
+               }
+               ++Filesleft;  
+#ifdef XARGSFILE
+               /* Look for file length in third colon sep field */
+               for (p = *argv; *p; ++p) {
+                       if (*p == ':') {
+                               for (++p; *p; ++p) {
+                                       if (*p == ':') {
+                                               ++p;
+                                               size = atol(p);
+                                               Totalleft += size;
+                                               break;
+                                       }
+                               }
+                       break;
+                       }
+               }
+#endif
+
+               if (Verbose>2)
+                       fprintf(stderr, " %ld", size);
+       }
+       if (Verbose>2)
+               fprintf(stderr, "\ncountem: Total %d %ld\n",
+                 Filesleft, Totalleft);
+}
+#endif
+
+chartest(m)
+{
+       register n;
+
+       mode(m);
+       printf("\r\n\nCharacter Transparency Test Mode %d\r\n", m);
+       printf("If Pro-YAM/ZCOMM is not displaying ^M hit ALT-V NOW.\r\n");
+       printf("Hit Enter.\021");  fflush(stdout);
+       readline(500);
+
+       for (n = 0; n < 256; ++n) {
+               if (!(n%8))
+                       printf("\r\n");
+               printf("%02x ", n);  fflush(stdout);
+               sendline(n);    flushmo();
+               printf("  ");  fflush(stdout);
+               if (n == 127) {
+                       printf("Hit Enter.\021");  fflush(stdout);
+                       readline(500);
+                       printf("\r\n");  fflush(stdout);
+               }
+       }
+       printf("\021\r\nEnter Characters, echo is in hex.\r\n");
+       printf("Hit SPACE or pause 40 seconds for exit.\r\n");
+
+       while (n != TIMEOUT && n != ' ') {
+               n = readline(400);
+               printf("%02x\r\n", n);
+               fflush(stdout);
+       }
+       printf("\r\nMode %d character transparency test ends.\r\n", m);
+       fflush(stdout);
+}
+
+/* End of sz.c */