home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / utility / unixtool / unixrzsz / sz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-17  |  35.4 KB  |  1,718 lines

  1. #define VERSION "sz 2.12 05-29-88"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -compat -M2 -Ox -K -i -DTXBSIZE=16384  -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz
  5.  
  6.     Following is used for testing, might not be reasonable for production
  7. <-xtx-*> cc -Osal -DTXBSIZE=32768  -DSV sz.c -lx -o $B/sz; size $B/sz
  8.  
  9.  ****************************************************************************
  10.  *
  11.  * sz.c By Chuck Forsberg,  Omen Technology INC
  12.  *
  13.  ****************************************************************************
  14.  *
  15.  * Typical Unix/Xenix/Clone compiles:
  16.  *
  17.  *    cc -O sz.c -o sz        USG (SYS III/V) Unix
  18.  *    cc -O -DSV sz.c -o sz        Sys V Release 2 with non-blocking input
  19.  *                    Define to allow reverse channel checking
  20.  *    cc -O -DV7  sz.c -o sz        Unix Version 7, 2.8 - 4.3 BSD
  21.  *
  22.  *    cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz    Classic Xenix
  23.  *
  24.  *    ln sz sb            **** All versions ****
  25.  *    ln sz sx            **** All versions ****
  26.  *
  27.  ****************************************************************************
  28.  *
  29.  * Typical VMS compile and install sequence:
  30.  *
  31.  *        define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
  32.  *        cc sz.c
  33.  *        cc vvmodem.c
  34.  *        link sz,vvmodem
  35.  *    sz :== $disk$user2:[username.subdir]sz.exe
  36.  *
  37.  *  If you feel adventureous, remove the #define BADSYNC line
  38.  *  immediately following the #ifdef vax11c line!  Some VMS
  39.  *  systems know how to fseek, some don't.
  40.  *
  41.  ****************************************************************************
  42.  *
  43.  *
  44.  * A program for Unix to send files and commands to computers running
  45.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
  46.  *
  47.  *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
  48.  *
  49.  *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
  50.  *
  51.  *  2.1x hacks to avoid VMS fseek() bogosity, allow input from pipe
  52.  *     -DBADSEEK -DTXBSIZE=32768  
  53.  *  2.x has mods for VMS flavor
  54.  *
  55.  * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS
  56.  * in accordance with the 7-31-87 ZMODEM Protocol Description
  57.  */
  58.  
  59.  
  60. char *substr(), *getenv();
  61.  
  62. #ifdef vax11c
  63. #define BADSEEK
  64. #define TXBSIZE 32768        /* Must be power of two, < MAXINT */
  65. #include <types.h>
  66. #include <stat.h>
  67. #define LOGFILE "szlog.tmp"
  68. #include <stdio.h>
  69. #include <signal.h>
  70. #include <setjmp.h>
  71. #include <ctype.h>
  72. #include <errno.h>
  73. #define OS "VMS"
  74. #define READCHECK
  75. #define BUFWRITE
  76. #define iofd
  77. extern int errno;
  78. #define SS_NORMAL SS$_NORMAL
  79. #define xsendline(c) sendline(c)
  80.  
  81.  
  82. #else    /* vax11c */
  83.  
  84.  
  85. #define SS_NORMAL 0
  86. #define LOGFILE "/tmp/szlog"
  87. #include <stdio.h>
  88. #include <signal.h>
  89. #include <setjmp.h>
  90. #include <ctype.h>
  91. #include <errno.h>
  92. extern int errno;
  93.  
  94. #define sendline(c) putchar(c & 0377)
  95. #define xsendline(c) putchar(c)
  96.  
  97. #endif
  98.  
  99. #define PATHLEN 256
  100. #define OK 0
  101. #define FALSE 0
  102. #define TRUE 1
  103. #undef ERROR
  104. #define ERROR (-1)
  105. /* Ward Christensen / CP/M parameters - Don't change these! */
  106. #define ENQ 005
  107. #define CAN ('X'&037)
  108. #define XOFF ('s'&037)
  109. #define XON ('q'&037)
  110. #define SOH 1
  111. #define STX 2
  112. #define EOT 4
  113. #define ACK 6
  114. #define NAK 025
  115. #define CPMEOF 032
  116. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  117. #define WANTG 0107    /* Send G not NAK to get nonstop batch xmsn */
  118. #define TIMEOUT (-2)
  119. #define RCDO (-3)
  120. #define RETRYMAX 10
  121.  
  122.  
  123. #define HOWMANY 2
  124. int Zmodem=0;        /* ZMODEM protocol requested by receiver */
  125. unsigned Baudrate=2400;    /* Default, should be set by first mode() call */
  126. unsigned Txwindow;    /* Control the size of the transmitted window */
  127. unsigned Txwspac;    /* Spacing between zcrcq requests */
  128. unsigned Txwcnt;    /* Counter used to space ack requests */
  129. long Lrxpos;        /* Receiver's last reported offset */
  130. int errors;
  131.  
  132. #ifdef vax11c
  133. #include "vrzsz.c"    /* most of the system dependent stuff here */
  134. #else
  135. #include "rbsb.c"    /* most of the system dependent stuff here */
  136. #endif
  137. #include "crctab.c"
  138.  
  139. int Filesleft;
  140. long Totalleft;
  141.  
  142. /*
  143.  * Attention string to be executed by receiver to interrupt streaming data
  144.  *  when an error is detected.  A pause (0336) may be needed before the
  145.  *  ^C (03) or after it.
  146.  */
  147. #ifdef READCHECK
  148. char Myattn[] = { 0 };
  149. #else
  150. #ifdef USG
  151. char Myattn[] = { 03, 0336, 0 };
  152. #else
  153. char Myattn[] = { 0 };
  154. #endif
  155. #endif
  156.  
  157. FILE *in;
  158.  
  159. #ifdef BADSEEK
  160. int Canseek = 0;    /* 1: Can seek 0: only rewind -1: neither (pipe) */
  161. #ifndef TXBSIZE
  162. #define TXBSIZE 16384        /* Must be power of two, < MAXINT */
  163. #endif
  164. #else
  165. int Canseek = 1;    /* 1: Can seek 0: only rewind -1: neither (pipe) */
  166. #endif
  167.  
  168. #ifdef TXBSIZE
  169. #define TXBMASK (TXBSIZE-1)
  170. char Txb[TXBSIZE];        /* Circular buffer for file reads */
  171. char *txbuf = Txb;        /* Pointer to current file segment */
  172. #else
  173. char txbuf[1024];
  174. #endif
  175. long vpos = 0;            /* Number of bytes read from file */
  176.  
  177. char Lastrx;
  178. char Crcflg;
  179. int Verbose=0;
  180. int Modem2=0;        /* XMODEM Protocol - don't send pathnames */
  181. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  182. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  183. int Ascii=0;        /* Add CR's for brain damaged programs */
  184. int Fullname=0;        /* transmit full pathname */
  185. int Unlinkafter=0;    /* Unlink file after it is sent */
  186. int Dottoslash=0;    /* Change foo.bar.baz to foo/bar/baz */
  187. int firstsec;
  188. int errcnt=0;        /* number of files unreadable */
  189. int blklen=128;        /* length of transmitted records */
  190. int Optiong;        /* Let it rip no wait for sector ACK's */
  191. int Eofseen;        /* EOF seen on input set by zfilbuf */
  192. int BEofseen;        /* EOF seen on input set by fooseek */
  193. int Totsecs;        /* total number of sectors this file */
  194. int Filcnt=0;        /* count of number of files opened */
  195. int Lfseen=0;
  196. unsigned Rxbuflen = 16384;    /* Receiver's max buffer length */
  197. int Tframlen = 0;    /* Override for tx frame length */
  198. int blkopt=0;        /* Override value for zmodem blklen */
  199. int Rxflags = 0;
  200. long bytcnt;
  201. int Wantfcs32 = TRUE;    /* want to send 32 bit FCS */
  202. char Lzconv;    /* Local ZMODEM file conversion request */
  203. char Lzmanag;    /* Local ZMODEM file management request */
  204. int Lskipnocor;
  205. char Lztrans;
  206. char zconv;        /* ZMODEM file conversion request */
  207. char zmanag;        /* ZMODEM file management request */
  208. char ztrans;        /* ZMODEM file transport request */
  209. int Command;        /* Send a command, then exit. */
  210. char *Cmdstr;        /* Pointer to the command string */
  211. int Cmdtries = 11;
  212. int Cmdack1;        /* Rx ACKs command, then do it */
  213. int Exitcode = 0;
  214. int Test;        /* 1= Force receiver to send Attn, etc with qbf. */
  215.             /* 2= Character transparency test */
  216. char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
  217. long Lastsync;        /* Last offset to which we got a ZRPOS */
  218. int Beenhereb4;        /* How many times we've been ZRPOS'd same place */
  219.  
  220. jmp_buf tohere;        /* For the interrupt on RX timeout */
  221. jmp_buf intrjmp;    /* For the interrupt on RX CAN */
  222.  
  223. /* called by signal interrupt or terminate to clean things up */
  224. bibi(n)
  225. {
  226.     canit(); fflush(stdout); mode(0);
  227.     fprintf(stderr, "sz: caught signal %d; exiting\n", n);
  228.     if (n == SIGQUIT)
  229.         abort();
  230.     if (n == 99)
  231.         fprintf(stderr, "mode(2) in rbsb.c not implemented!!\n");
  232.     cucheck();
  233.     exit(128+n);
  234. }
  235. /* Called when ZMODEM gets an interrupt (^X) */
  236. onintr()
  237. {
  238.     signal(SIGINT, SIG_IGN);
  239.     longjmp(intrjmp, -1);
  240. }
  241.  
  242. int Zctlesc;    /* Encode control characters */
  243. int Nozmodem = 0;    /* If invoked as "sb" */
  244. char *Progname = "sz";
  245. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  246. #include "zm.c"
  247.  
  248.  
  249. #ifdef CWRU
  250. MAIN(argc, argv)
  251. #else
  252. main(argc, argv)
  253. #endif
  254. int argc;
  255. char *argv[];
  256. {
  257.     register char *cp;
  258.     register npats;
  259.     int dm;
  260.     char **patts;
  261.     static char xXbuf[BUFSIZ];
  262.  
  263.     if ((cp = getenv("ZNULLS")) && *cp)
  264.         Znulls = atoi(cp);
  265.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  266.         Restricted=TRUE;
  267.     from_cu();
  268.     chkinvok(argv[0]);
  269.  
  270.     Rxtimeout = 600;
  271.     npats=0;
  272.     if (argc<2)
  273.         usage();
  274.     setbuf(stdout, xXbuf);        
  275.     while (--argc) {
  276.         cp = *++argv;
  277.         if (*cp++ == '-' && *cp) {
  278.             while ( *cp) {
  279.                 switch(*cp++) {
  280.                 case '\\':
  281.                      *cp = toupper(*cp);  continue;
  282.                 case '+':
  283.                     Lzmanag = ZMAPND; break;
  284. #ifdef CSTOPB
  285.                 case '2':
  286.                     Twostop = TRUE; break;
  287. #endif
  288.                 case 'a':
  289.                     Lzconv = ZCNL;
  290.                     Ascii = TRUE; break;
  291.                 case 'b':
  292.                     Lzconv = ZCBIN; break;
  293.                 case 'C':
  294.                     if (--argc < 1) {
  295.                         usage();
  296.                     }
  297.                     Cmdtries = atoi(*++argv);
  298.                     break;
  299.                 case 'i':
  300.                     Cmdack1 = ZCACK1;
  301.                     /* **** FALL THROUGH TO **** */
  302.                 case 'c':
  303.                     if (--argc != 1) {
  304.                         usage();
  305.                     }
  306.                     Command = TRUE;
  307.                     Cmdstr = *++argv;
  308.                     break;
  309.                 case 'd':
  310.                     ++Dottoslash;
  311.                     /* **** FALL THROUGH TO **** */
  312.                 case 'f':
  313.                     Fullname=TRUE; break;
  314.                 case 'e':
  315.                     Zctlesc = 1; break;
  316.                 case 'k':
  317.                     blklen=1024; break;
  318.                 case 'L':
  319.                     if (--argc < 1) {
  320.                         usage();
  321.                     }
  322.                     blkopt = atoi(*++argv);
  323.                     if (blkopt<24 || blkopt>1024)
  324.                         usage();
  325.                     break;
  326.                 case 'l':
  327.                     if (--argc < 1) {
  328.                         usage();
  329.                     }
  330.                     Tframlen = atoi(*++argv);
  331.                     if (Tframlen<32 || Tframlen>1024)
  332.                         usage();
  333.                     break;
  334.                 case 'N':
  335.                     Lzmanag = ZMNEWL;  break;
  336.                 case 'n':
  337.                     Lzmanag = ZMNEW;  break;
  338.                 case 'o':
  339.                     Wantfcs32 = FALSE; break;
  340.                 case 'p':
  341.                     Lzmanag = ZMPROT;  break;
  342.                 case 'r':
  343.                     Lzconv = ZCRESUM;
  344.                 case 'q':
  345.                     Quiet=TRUE; Verbose=0; break;
  346.                 case 't':
  347.                     if (--argc < 1) {
  348.                         usage();
  349.                     }
  350.                     Rxtimeout = atoi(*++argv);
  351.                     if (Rxtimeout<10 || Rxtimeout>1000)
  352.                         usage();
  353.                     break;
  354.                 case 'T':
  355.                     if (++Test > 1) {
  356.                         chartest(1); chartest(2);
  357.                         mode(0);  exit(0);
  358.                     }
  359.                     break;
  360. #ifndef vax11c
  361.                 case 'u':
  362.                     ++Unlinkafter; break;
  363. #endif
  364.                 case 'v':
  365.                     ++Verbose; break;
  366.                 case 'w':
  367.                     if (--argc < 1) {
  368.                         usage();
  369.                     }
  370.                     Txwindow = atoi(*++argv);
  371.                     if (Txwindow < 256)
  372.                         Txwindow = 256;
  373.                     Txwindow = (Txwindow/64) * 64;
  374.                     Txwspac = Txwindow/4;
  375.                     if (blkopt > Txwspac
  376.                      || (!blkopt && Txwspac < 1024))
  377.                         blkopt = Txwspac;
  378.                     break;
  379.                 case 'X':
  380.                     ++Modem2; break;
  381.                 case 'Y':
  382.                     Lskipnocor = TRUE;
  383.                     /* **** FALLL THROUGH TO **** */
  384.                 case 'y':
  385.                     Lzmanag = ZMCLOB; break;
  386.                 default:
  387.                     usage();
  388.                 }
  389.             }
  390.         }
  391.         else if ( !npats && argc>0) {
  392.             if (argv[0][0]) {
  393.                 npats=argc;
  394.                 patts=argv;
  395. #ifndef vax11c
  396.                 if ( !strcmp(*patts, "-"))
  397.                     iofd = 1;
  398. #endif
  399.             }
  400.         }
  401.     }
  402.     if (npats < 1 && !Command && !Test) 
  403.         usage();
  404.     if (Verbose) {
  405.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  406.             printf("Can't open log file %s\n",LOGFILE);
  407.             exit(0200);
  408.         }
  409.         setbuf(stderr, NULL);
  410.     }
  411.     if (Fromcu && !Quiet) {
  412.         if (Verbose == 0)
  413.             Verbose = 2;
  414.     }
  415.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  416.  
  417.     mode(1);
  418.  
  419.     if (signal(SIGINT, bibi) == SIG_IGN) {
  420.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  421.     } else {
  422.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  423.     }
  424.     if ( !Fromcu)
  425.         signal(SIGQUIT, SIG_IGN);
  426.     signal(SIGTERM, bibi);
  427.  
  428.     if ( !Modem2) {
  429.         if (!Nozmodem) {
  430.             printf("rz\r");  fflush(stdout);
  431.         }
  432.         countem(npats, patts);
  433.         if (!Nozmodem) {
  434.             stohdr(0L);
  435.             if (Command)
  436.                 Txhdr[ZF0] = ZCOMMAND;
  437.             zshhdr(ZRQINIT, Txhdr);
  438.         }
  439.     }
  440.     fflush(stdout);
  441.  
  442.     if (Command) {
  443.         if (getzrxinit()) {
  444.             Exitcode=0200; canit();
  445.         }
  446.         else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  447.             Exitcode=0200; canit();
  448.         }
  449.     } else if (wcsend(npats, patts)==ERROR) {
  450.         Exitcode=0200;
  451.         canit();
  452.     }
  453.     fflush(stdout);
  454.     mode(0);
  455.     dm = ((errcnt != 0) | Exitcode);
  456.     if (dm) {
  457.         cucheck();  exit(dm);
  458.     }
  459.     putc('\n',stderr);
  460.     exit(SS_NORMAL);
  461.     /*NOTREACHED*/
  462. }
  463.  
  464. wcsend(argc, argp)
  465. char *argp[];
  466. {
  467.     register n;
  468.  
  469.     Crcflg=FALSE;
  470.     firstsec=TRUE;
  471.     bytcnt = -1;
  472.     for (n=0; n<argc; ++n) {
  473.         Totsecs = 0;
  474.         if (wcs(argp[n])==ERROR)
  475.             return ERROR;
  476.     }
  477.     Totsecs = 0;
  478.     if (Filcnt==0) {    /* bitch if we couldn't open ANY files */
  479.         if ( !Modem2) {
  480.             Command = TRUE;
  481.             Cmdstr = "echo \"sz: Can't open any requested files\"";
  482.             if (getnak()) {
  483.                 Exitcode=0200; canit();
  484.             }
  485.             if (!Zmodem)
  486.                 canit();
  487.             else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  488.                 Exitcode=0200; canit();
  489.             }
  490.             Exitcode = 1; return OK;
  491.         }
  492.         canit();
  493.         fprintf(stderr,"\r\nCan't open any requested files.\r\n");
  494.         return ERROR;
  495.     }
  496.     if (Zmodem)
  497.         saybibi();
  498.     else if ( !Modem2)
  499.         wctxpn("");
  500.     return OK;
  501. }
  502.  
  503. wcs(oname)
  504. char *oname;
  505. {
  506.     register c;
  507.     register char *p;
  508.     struct stat f;
  509.     char name[PATHLEN];
  510.  
  511.     strcpy(name, oname);
  512.  
  513.     if (Restricted) {
  514.         /* restrict pathnames to current tree or uucppublic */
  515.         if ( substr(name, "../")
  516.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  517.             canit();
  518.             fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
  519.             return ERROR;
  520.         }
  521.     }
  522.  
  523.     if ( !strcmp(oname, "-")) {
  524.         if ((p = getenv("ONAME")) && *p)
  525.             strcpy(name, p);
  526.         else
  527.             sprintf(name, "s%d.sz", getpid());
  528.         in = stdin;
  529.     }
  530.     else if ((in=fopen(oname, "r"))==NULL) {
  531.         ++errcnt;
  532.         return OK;    /* pass over it, there may be others */
  533.     }
  534.     BEofseen = Eofseen = 0;  vpos = 0;
  535.     /* Check for directory or block special files */
  536.     fstat(fileno(in), &f);
  537.     c = f.st_mode & S_IFMT;
  538.     if (c == S_IFDIR || c == S_IFBLK) {
  539.         fclose(in);
  540.         return OK;
  541.     }
  542.  
  543.     ++Filcnt;
  544.     switch (wctxpn(name)) {
  545.     case ERROR:
  546.         return ERROR;
  547.     case ZSKIP:
  548.         return OK;
  549.     }
  550.     if (!Zmodem && wctx(f.st_size)==ERROR)
  551.         return ERROR;
  552. #ifndef vax11c
  553.     if (Unlinkafter)
  554.         unlink(oname);
  555. #endif
  556.     return 0;
  557. }
  558.  
  559. /*
  560.  * generate and transmit pathname block consisting of
  561.  *  pathname (null terminated),
  562.  *  file length, mode time and file mode in octal
  563.  *  as provided by the Unix fstat call.
  564.  *  N.B.: modifies the passed name, may extend it!
  565.  */
  566. wctxpn(name)
  567. char *name;
  568. {
  569.     register char *p, *q;
  570.     char name2[PATHLEN];
  571.     struct stat f;
  572.  
  573.     if (Modem2) {
  574.         if (Verbose && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
  575.             fprintf(stderr, "Sending %s, %ld blocks: ",
  576.               name, f.st_size>>7);
  577.         }
  578.         if(Verbose)
  579.           fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
  580.         return OK;
  581.     }
  582.     zperr("Awaiting pathname nak for %s", *name?name:"<END>");
  583.     if ( !Zmodem)
  584.         if (getnak())
  585.             return ERROR;
  586.  
  587.     q = (char *) 0;
  588.     if (Dottoslash) {        /* change . to . */
  589.         for (p=name; *p; ++p) {
  590.             if (*p == '/')
  591.                 q = p;
  592.             else if (*p == '.')
  593.                 *(q=p) = '/';
  594.         }
  595.         if (q && strlen(++q) > 8) {    /* If name>8 chars */
  596.             q += 8;            /*   make it .ext */
  597.             strcpy(name2, q);    /* save excess of name */
  598.             *q = '.';
  599.             strcpy(++q, name2);    /* add it back */
  600.         }
  601.     }
  602.  
  603.     for (p=name, q=txbuf ; *p; )
  604.         if ((*q++ = *p++) == '/' && !Fullname)
  605.             q = txbuf;
  606.     *q++ = 0;
  607.     p=q;
  608.     while (q < (txbuf + 1024))
  609.         *q++ = 0;
  610.     if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
  611.         sprintf(p, "%lu %lo %o 0 %d %ld", f.st_size, f.st_mtime,
  612.           f.st_mode, Filesleft, Totalleft);
  613.     Totalleft -= f.st_size;
  614.     if (--Filesleft <= 0)
  615.         Totalleft = 0;
  616.     if (Totalleft < 0)
  617.         Totalleft = 0;
  618.  
  619.     /* force 1k blocks if name won't fit in 128 byte block */
  620.     if (txbuf[125])
  621.         blklen=1024;
  622.     else {        /* A little goodie for IMP/KMD */
  623.         txbuf[127] = (f.st_size + 127) >>7;
  624.         txbuf[126] = (f.st_size + 127) >>15;
  625.     }
  626.     if (Zmodem)
  627.         return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
  628.     if (wcputsec(txbuf, 0, 128)==ERROR)
  629.         return ERROR;
  630.     return OK;
  631. }
  632.  
  633. getnak()
  634. {
  635.     register firstch;
  636.  
  637.     Lastrx = 0;
  638.     for (;;) {
  639.         switch (firstch = readline(800)) {
  640.         case ZPAD:
  641.             if (getzrxinit())
  642.                 return ERROR;
  643.             Ascii = 0;    /* Receiver does the conversion */
  644.             return FALSE;
  645.         case TIMEOUT:
  646.             zperr("Timeout on pathname");
  647.             return TRUE;
  648.         case WANTG:
  649. #ifdef MODE2OK
  650.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  651. #endif
  652.             Optiong = TRUE;
  653.             blklen=1024;
  654.         case WANTCRC:
  655.             Crcflg = TRUE;
  656.         case NAK:
  657.             return FALSE;
  658.         case CAN:
  659.             if ((firstch = readline(20)) == CAN && Lastrx == CAN)
  660.                 return TRUE;
  661.         default:
  662.             break;
  663.         }
  664.         Lastrx = firstch;
  665.     }
  666. }
  667.  
  668.  
  669. wctx(flen)
  670. long flen;
  671. {
  672.     register int thisblklen;
  673.     register int sectnum, attempts, firstch;
  674.     long charssent;
  675.  
  676.     charssent = 0;  firstsec=TRUE;  thisblklen = blklen;
  677.     vfile("wctx:file length=%ld", flen);
  678.  
  679.     while ((firstch=readline(Rxtimeout))!=NAK && firstch != WANTCRC
  680.       && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
  681.         ;
  682.     if (firstch==CAN) {
  683.         zperr("Receiver CANcelled");
  684.         return ERROR;
  685.     }
  686.     if (firstch==WANTCRC)
  687.         Crcflg=TRUE;
  688.     if (firstch==WANTG)
  689.         Crcflg=TRUE;
  690.     sectnum=0;
  691.     for (;;) {
  692.         if (flen <= (charssent + 896L))
  693.             thisblklen = 128;
  694.         if ( !filbuf(txbuf, thisblklen))
  695.             break;
  696.         if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
  697.             return ERROR;
  698.         charssent += thisblklen;
  699.     }
  700.     fclose(in);
  701.     attempts=0;
  702.     do {
  703.         purgeline();
  704.         sendline(EOT);
  705.         fflush(stdout);
  706.         ++attempts;
  707.     }
  708.         while ((firstch=(readline(Rxtimeout)) != ACK) && attempts < RETRYMAX);
  709.     if (attempts == RETRYMAX) {
  710.         zperr("No ACK on EOT");
  711.         return ERROR;
  712.     }
  713.     else
  714.         return OK;
  715. }
  716.  
  717. wcputsec(buf, sectnum, cseclen)
  718. char *buf;
  719. int sectnum;
  720. int cseclen;    /* data length of this sector to send */
  721. {
  722.     register checksum, wcj;
  723.     register char *cp;
  724.     unsigned oldcrc;
  725.     int firstch;
  726.     int attempts;
  727.  
  728.     firstch=0;    /* part of logic to detect CAN CAN */
  729.  
  730.     if (Verbose>2)
  731.         fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 );
  732.     else if (Verbose>1)
  733.         fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
  734.     for (attempts=0; attempts <= RETRYMAX; attempts++) {
  735.         Lastrx= firstch;
  736.         sendline(cseclen==1024?STX:SOH);
  737.         sendline(sectnum);
  738.         sendline(-sectnum -1);
  739.         oldcrc=checksum=0;
  740.         for (wcj=cseclen,cp=buf; --wcj>=0; ) {
  741.             sendline(*cp);
  742.             oldcrc=updcrc((0377& *cp), oldcrc);
  743.             checksum += *cp++;
  744.         }
  745.         if (Crcflg) {
  746.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  747.             sendline((int)oldcrc>>8);
  748.             sendline((int)oldcrc);
  749.         }
  750.         else
  751.             sendline(checksum);
  752.  
  753.         if (Optiong) {
  754.             firstsec = FALSE; return OK;
  755.         }
  756.         firstch = readline(Rxtimeout);
  757. gotnak:
  758.         switch (firstch) {
  759.         case CAN:
  760.             if(Lastrx == CAN) {
  761. cancan:
  762.                 zperr("Cancelled");  return ERROR;
  763.             }
  764.             break;
  765.         case TIMEOUT:
  766.             zperr("Timeout on sector ACK"); continue;
  767.         case WANTCRC:
  768.             if (firstsec)
  769.                 Crcflg = TRUE;
  770.         case NAK:
  771.             zperr("NAK on sector"); continue;
  772.         case ACK: 
  773.             firstsec=FALSE;
  774.             Totsecs += (cseclen>>7);
  775.             return OK;
  776.         case ERROR:
  777.             zperr("Got burst for sector ACK"); break;
  778.         default:
  779.             zperr("Got %02x for sector ACK", firstch); break;
  780.         }
  781.         for (;;) {
  782.             Lastrx = firstch;
  783.             if ((firstch = readline(Rxtimeout)) == TIMEOUT)
  784.                 break;
  785.             if (firstch == NAK || firstch == WANTCRC)
  786.                 goto gotnak;
  787.             if (firstch == CAN && Lastrx == CAN)
  788.                 goto cancan;
  789.         }
  790.     }
  791.     zperr("Retry Count Exceeded");
  792.     return ERROR;
  793. }
  794.  
  795. /* fill buf with count chars padding with ^Z for CPM */
  796. filbuf(buf, count)
  797. register char *buf;
  798. {
  799.     register c, m;
  800.  
  801.     if ( !Ascii) {
  802.         m = read(fileno(in), buf, count);
  803.         if (m <= 0)
  804.             return 0;
  805.         while (m < count)
  806.             buf[m++] = 032;
  807.         return count;
  808.     }
  809.     m=count;
  810.     if (Lfseen) {
  811.         *buf++ = 012; --m; Lfseen = 0;
  812.     }
  813.     while ((c=getc(in))!=EOF) {
  814.         if (c == 012) {
  815.             *buf++ = 015;
  816.             if (--m == 0) {
  817.                 Lfseen = TRUE; break;
  818.             }
  819.         }
  820.         *buf++ =c;
  821.         if (--m == 0)
  822.             break;
  823.     }
  824.     if (m==count)
  825.         return 0;
  826.     else
  827.         while (--m>=0)
  828.             *buf++ = CPMEOF;
  829.     return count;
  830. }
  831.  
  832. /* Fill buffer with blklen chars */
  833. zfilbuf()
  834. {
  835.     int n;
  836.  
  837. #ifdef TXBSIZE
  838.     /* We assume request is within buffer, or just beyond */
  839.     txbuf = Txb + (bytcnt & TXBMASK);
  840.     if (vpos <= bytcnt) {
  841.         n = fread(txbuf, 1, blklen, in);
  842.         vpos += n;
  843.         if (n < blklen)
  844.             Eofseen = 1;
  845.         return n;
  846.     }
  847.     if (vpos >= (bytcnt+blklen))
  848.         return blklen;
  849.     /* May be a short block if crash recovery etc. */
  850.     Eofseen = BEofseen;
  851.     return (vpos - bytcnt);
  852. #else
  853.     n = fread(txbuf, 1, blklen, in);
  854.     if (n < blklen)
  855.         Eofseen = 1;
  856.     return n;
  857. #endif
  858. }
  859.  
  860. #ifdef TXBSIZE
  861. fooseek(fptr, pos, whence)
  862. FILE *fptr;
  863. long pos;
  864. {
  865.     int m, n;
  866.  
  867.     vfile("fooseek: pos =%lu vpos=%lu Canseek=%d", pos, vpos, Canseek);
  868.     /* Seek offset < current buffer */
  869.     if (pos < (vpos -TXBSIZE +1024)) {
  870.         BEofseen = 0;
  871.         if (Canseek > 0) {
  872.             vpos = pos & ~TXBMASK;
  873.             if (vpos >= pos)
  874.                 vpos -= TXBSIZE;
  875.             if (fseek(fptr, vpos, 0))
  876.                 return 1;
  877.         }
  878.         else if (Canseek == 0)
  879.             if (fseek(fptr, vpos = 0L, 0))
  880.                 return 1;
  881.         else
  882.             return 1;
  883.         while (vpos <= pos) {
  884.             n = fread(Txb, 1, TXBSIZE, fptr);
  885.             vpos += n;
  886.             vfile("n=%d vpos=%ld", n, vpos);
  887.             if (n < TXBSIZE) {
  888.                 BEofseen = 1;
  889.                 break;
  890.             }
  891.         }
  892.         vfile("vpos=%ld", vpos);
  893.         return 0;
  894.     }
  895.     /* Seek offset > current buffer (crash recovery, etc.) */
  896.     if (pos > vpos) {
  897.         if (Canseek)
  898.             if (fseek(fptr, vpos = (pos & ~TXBMASK), 0))
  899.                 return 1;
  900.         while (vpos <= pos) {
  901.             txbuf = Txb + (vpos & TXBMASK);
  902.             m = TXBSIZE - (vpos & TXBMASK);
  903.             n = fread(txbuf, 1, m, fptr);
  904.             vpos += n;
  905.             vfile("bo=%d n=%d vpos=%ld", txbuf-Txb, n, vpos);
  906.             if (m < n) {
  907.                 BEofseen = 1;
  908.                 break;
  909.             }
  910.         }
  911.         return 0;
  912.     }
  913.     /* Seek offset is within current buffer */
  914.     vfile("vpos=%ld", vpos);
  915.     return 0;
  916. }
  917. #define fseek fooseek
  918. #endif
  919.  
  920.  
  921. /* VARARGS1 */
  922. vfile(f, a, b, c)
  923. register char *f;
  924. {
  925.     if (Verbose > 2) {
  926.         fprintf(stderr, f, a, b, c);
  927.         fprintf(stderr, "\n");
  928.     }
  929. }
  930.  
  931.  
  932. alrm()
  933. {
  934.     longjmp(tohere, -1);
  935. }
  936.  
  937.  
  938. #ifndef vax11c
  939. /*
  940.  * readline(timeout) reads character(s) from file descriptor 0
  941.  * timeout is in tenths of seconds
  942.  */
  943. readline(timeout)
  944. {
  945.     register int c;
  946.     static char byt[1];
  947.  
  948.     fflush(stdout);
  949.     if (setjmp(tohere)) {
  950.         zperr("TIMEOUT");
  951.         return TIMEOUT;
  952.     }
  953.     c = timeout/10;
  954.     if (c<2)
  955.         c=2;
  956.     if (Verbose>5) {
  957.         fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
  958.     }
  959.     signal(SIGALRM, alrm); alarm(c);
  960.     c=read(iofd, byt, 1);
  961.     alarm(0);
  962.     if (Verbose>5)
  963.         fprintf(stderr, "ret %x\n", byt[0]);
  964.     if (c<1)
  965.         return TIMEOUT;
  966.     return (byt[0]&0377);
  967. }
  968.  
  969. flushmo()
  970. {
  971.     fflush(stdout);
  972. }
  973.  
  974.  
  975. purgeline()
  976. {
  977. #ifdef USG
  978.     ioctl(iofd, TCFLSH, 0);
  979. #else
  980.     lseek(iofd, 0L, 2);
  981. #endif
  982. }
  983. #endif
  984.  
  985. /* send cancel string to get the other end to shut up */
  986. canit()
  987. {
  988.     static char canistr[] = {
  989.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  990.     };
  991.  
  992. #ifdef vax11c
  993.     raw_wbuf(strlen(canistr), canistr);
  994.     purgeline();
  995. #else
  996.     printf(canistr);
  997.     fflush(stdout);
  998. #endif
  999. }
  1000.  
  1001.  
  1002. /*
  1003.  * Log an error
  1004.  */
  1005. /*VARARGS1*/
  1006. zperr(s,p,u)
  1007. char *s, *p, *u;
  1008. {
  1009.     if (Verbose <= 0)
  1010.         return;
  1011.     fprintf(stderr, "\nRetry %d: ", errors);
  1012.     fprintf(stderr, s, p, u);
  1013.     fprintf(stderr, "\n");
  1014. }
  1015.  
  1016. /*
  1017.  * substr(string, token) searches for token in string s
  1018.  * returns pointer to token within string if found, NULL otherwise
  1019.  */
  1020. char *
  1021. substr(s, t)
  1022. register char *s,*t;
  1023. {
  1024.     register char *ss,*tt;
  1025.     /* search for first char of token */
  1026.     for (ss=s; *s; s++)
  1027.         if (*s == *t)
  1028.             /* compare token with substring */
  1029.             for (ss=s,tt=t; ;) {
  1030.                 if (*tt == 0)
  1031.                     return s;
  1032.                 if (*ss++ != *tt++)
  1033.                     break;
  1034.             }
  1035.     return NULL;
  1036. }
  1037.  
  1038. char *babble[] = {
  1039. #ifdef vax11c
  1040.     "    Send file(s) with ZMODEM Protocol",
  1041.     "Usage:    sz [-2+abdefkLlNnquvwYy] [-] file ...",
  1042.     "    sz [-2Ceqv] -c COMMAND",
  1043.     "    \\ Force next option letter to upper case",
  1044. #else
  1045.     "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
  1046.     "    (Y) = Option applies to YMODEM only",
  1047.     "    (Z) = Option applies to ZMODEM only",
  1048.     "Usage:    sz [-2+abdefkLlNnquvwYy] [-] file ...",
  1049.     "    sz [-2Ceqv] -c COMMAND",
  1050.     "    sb [-2adfkquv] [-] file ...",
  1051.     "    sx [-2akquv] [-] file",
  1052. #endif
  1053. #ifdef CSTOPB
  1054.     "    2 Use 2 stop bits",
  1055. #endif
  1056.     "    + Append to existing destination file (Z)",
  1057.     "    a (ASCII) change NL to CR/LF",
  1058.     "    b Binary file transfer override",
  1059.     "    c send COMMAND (Z)",
  1060. #ifndef vax11c
  1061.     "    d Change '.' to '/' in pathnames (Y/Z)",
  1062. #endif
  1063.     "    e Escape all control characters (Z)",
  1064.     "    f send Full pathname (Y/Z)",
  1065.     "    i send COMMAND, ack Immediately (Z)",
  1066.     "    k Send 1024 byte packets (Y)",
  1067.     "    L N Limit subpacket length to N bytes (Z)",
  1068.     "    l N Limit frame length to N bytes (l>=L) (Z)",
  1069.     "    n send file if source newer (Z)",
  1070.     "    N send file if source newer or longer (Z)",
  1071.     "    o Use 16 bit CRC instead of 32 bit CRC (Z)",
  1072.     "    p Protect existing destination file (Z)",
  1073.     "    r Resume/Recover interrupted file transfer (Z)",
  1074.     "    q Quiet (no progress reports)",
  1075. #ifndef vax11c
  1076.     "    u Unlink file after transmission",
  1077. #endif
  1078.     "    v Verbose - provide debugging information",
  1079.     "    w N Window is N bytes (Z)",
  1080.     "    Y Yes, overwrite existing file, skip if not present at rx (Z)",
  1081.     "    y Yes, overwrite existing file (Z)",
  1082.     "- as pathname sends standard input as sPID.sz or environment ONAME",
  1083.     ""
  1084. };
  1085.  
  1086. usage()
  1087. {
  1088.     char **pp;
  1089.  
  1090.     for (pp=babble; **pp; ++pp)
  1091.         fprintf(stderr, "%s\n", *pp);
  1092.     fprintf(stderr, "%s for %s by Chuck Forsberg, Omen Technology INC\n",
  1093.      VERSION, OS);
  1094.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
  1095.     cucheck();
  1096.     exit(SS_NORMAL);
  1097. }
  1098.  
  1099. /*
  1100.  * Get the receiver's init parameters
  1101.  */
  1102. getzrxinit()
  1103. {
  1104.     register n;
  1105.     struct stat f;
  1106.  
  1107.     for (n=10; --n>=0; ) {
  1108.         
  1109.         switch (zgethdr(Rxhdr, 1)) {
  1110.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  1111.             stohdr(Rxpos);
  1112.             zshhdr(ZACK, Txhdr);
  1113.             continue;
  1114.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  1115.             stohdr(0L);
  1116.             zshhdr(ZRQINIT, Txhdr);
  1117.             continue;
  1118.         case ZRINIT:
  1119.             Rxflags = 0377 & Rxhdr[ZF0];
  1120.             Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1121.             Zctlesc |= Rxflags & TESCCTL;
  1122.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  1123.             if ( !(Rxflags & CANFDX))
  1124.                 Txwindow = 0;
  1125.             vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  1126.             if ( !Fromcu)
  1127.                 signal(SIGINT, SIG_IGN);
  1128. #ifdef MODE2OK
  1129.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  1130. #endif
  1131. #ifndef READCHECK
  1132. #ifndef USG
  1133.             /* Use 1024 byte frames if no sample/interrupt */
  1134.             if (Rxbuflen < 32 || Rxbuflen > 1024) {
  1135.                 Rxbuflen = 1024;
  1136.                 vfile("Rxbuflen=%d", Rxbuflen);
  1137.             }
  1138. #endif
  1139. #endif
  1140.             /* Override to force shorter frame length */
  1141.             if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  1142.                 Rxbuflen = Tframlen;
  1143.             if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
  1144.                 Rxbuflen = Tframlen;
  1145.             vfile("Rxbuflen=%d", Rxbuflen);
  1146.  
  1147. #ifndef vax11c
  1148.             /* If using a pipe for testing set lower buf len */
  1149.             fstat(iofd, &f);
  1150.             if ((f.st_mode & S_IFMT) != S_IFCHR) {
  1151.                 Rxbuflen = 1024;
  1152.             }
  1153. #endif
  1154. #ifdef BADSEEK
  1155.             Canseek = 0;
  1156.             Txwindow = TXBSIZE - 1024;
  1157.             Txwspac = TXBSIZE/4;
  1158. #endif
  1159.             /*
  1160.              * If input is not a regular file, force ACK's to
  1161.              *  prevent running beyond the buffer limits
  1162.              */
  1163.             if ( !Command) {
  1164.                 fstat(fileno(in), &f);
  1165.                 if ((f.st_mode & S_IFMT) != S_IFREG) {
  1166.                     Canseek = -1;
  1167. #ifdef TXBSIZE
  1168.                     Txwindow = TXBSIZE - 1024;
  1169.                     Txwspac = TXBSIZE/4;
  1170. #else
  1171.                     return ERROR;
  1172. #endif
  1173.                 }
  1174.             }
  1175.             /* Set initial subpacket length */
  1176.             if (blklen < 1024) {    /* Command line override? */
  1177.                 if (Baudrate > 300)
  1178.                     blklen = 256;
  1179.                 if (Baudrate > 1200)
  1180.                     blklen = 512;
  1181.                 if (Baudrate > 2400)
  1182.                     blklen = 1024;
  1183.             }
  1184.             if (Rxbuflen && blklen>Rxbuflen)
  1185.                 blklen = Rxbuflen;
  1186.             if (blkopt && blklen > blkopt)
  1187.                 blklen = blkopt;
  1188.             vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1189.             vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  1190.  
  1191.             return (sendzsinit());
  1192.         case ZCAN:
  1193.         case TIMEOUT:
  1194.             return ERROR;
  1195.         case ZRQINIT:
  1196.             if (Rxhdr[ZF0] == ZCOMMAND)
  1197.                 continue;
  1198.         default:
  1199.             zshhdr(ZNAK, Txhdr);
  1200.             continue;
  1201.         }
  1202.     }
  1203.     return ERROR;
  1204. }
  1205.  
  1206. /* Send send-init information */
  1207. sendzsinit()
  1208. {
  1209.     register c;
  1210.  
  1211.     if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
  1212.         return OK;
  1213.     errors = 0;
  1214.     for (;;) {
  1215.         stohdr(0L);
  1216.         if (Zctlesc) {
  1217.             Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr);
  1218.         }
  1219.         else
  1220.             zsbhdr(ZSINIT, Txhdr);
  1221.         zsdata(Myattn, 1+strlen(Myattn), ZCRCW);
  1222.         c = zgethdr(Rxhdr, 1);
  1223.         switch (c) {
  1224.         case ZCAN:
  1225.             return ERROR;
  1226.         case ZACK:
  1227.             return OK;
  1228.         default:
  1229.             if (++errors > 19)
  1230.                 return ERROR;
  1231.             continue;
  1232.         }
  1233.     }
  1234. }
  1235.  
  1236. /* Send file name and related info */
  1237. zsendfile(buf, blen)
  1238. char *buf;
  1239. {
  1240.     register c;
  1241.     register UNSL long crc;
  1242.  
  1243.     for (;;) {
  1244.         Txhdr[ZF0] = Lzconv;    /* file conversion request */
  1245.         Txhdr[ZF1] = Lzmanag;    /* file management request */
  1246.         if (Lskipnocor)
  1247.             Txhdr[ZF1] |= ZMSKNOLOC;
  1248.         Txhdr[ZF2] = Lztrans;    /* file transport request */
  1249.         Txhdr[ZF3] = 0;
  1250.         zsbhdr(ZFILE, Txhdr);
  1251.         zsdata(buf, blen, ZCRCW);
  1252. again:
  1253.         c = zgethdr(Rxhdr, 1);
  1254.         switch (c) {
  1255.         case ZRINIT:
  1256.             while ((c = readline(50)) > 0)
  1257.                 if (c == ZPAD) {
  1258.                     goto again;
  1259.                 }
  1260.             /* **** FALL THRU TO **** */
  1261.         default:
  1262.             continue;
  1263.         case ZCAN:
  1264.         case TIMEOUT:
  1265.         case ZABORT:
  1266.         case ZFIN:
  1267.             return ERROR;
  1268.         case ZCRC:
  1269.             crc = 0xFFFFFFFFL;
  1270.             if (Canseek >= 0) {
  1271.                 while (((c = getc(in)) != EOF) && --Rxpos)
  1272.                     crc = UPDC32(c, crc);
  1273.                 crc = ~crc;
  1274.                 clearerr(in);    /* Clear EOF */
  1275.                 fseek(in, 0L, 0);
  1276.             }
  1277.             stohdr(crc);
  1278.             zsbhdr(ZCRC, Txhdr);
  1279.             goto again;
  1280.         case ZSKIP:
  1281.             fclose(in); return c;
  1282.         case ZRPOS:
  1283.             /*
  1284.              * Suppress zcrcw request otherwise triggered by
  1285.              * lastyunc==bytcnt
  1286.              */
  1287.             if (Rxpos && fseek(in, Rxpos, 0))
  1288.                 return ERROR;
  1289.             Lastsync = (bytcnt = Txpos = Rxpos) -1;
  1290.             return zsendfdata();
  1291.         }
  1292.     }
  1293. }
  1294.  
  1295. /* Send the data in the file */
  1296. zsendfdata()
  1297. {
  1298.     register c, e, n;
  1299.     register newcnt;
  1300.     register long tcount = 0;
  1301.     int junkcount;        /* Counts garbage chars received by TX */
  1302.     static int tleft = 6;    /* Counter for test mode */
  1303.  
  1304.     Lrxpos = 0;
  1305.     junkcount = 0;
  1306.     Beenhereb4 = FALSE;
  1307. somemore:
  1308.     if (setjmp(intrjmp)) {
  1309. waitack:
  1310.         junkcount = 0;
  1311.         c = getinsync(0);
  1312. gotack:
  1313.         switch (c) {
  1314.         default:
  1315.         case ZCAN:
  1316.             fclose(in);
  1317.             return ERROR;
  1318.         case ZSKIP:
  1319.             fclose(in);
  1320.             return c;
  1321.         case ZACK:
  1322.         case ZRPOS:
  1323.             break;
  1324.         case ZRINIT:
  1325.             return OK;
  1326.         }
  1327. #ifdef READCHECK
  1328.         /*
  1329.          * If the reverse channel can be tested for data,
  1330.          *  this logic may be used to detect error packets
  1331.          *  sent by the receiver, in place of setjmp/longjmp
  1332.          *  rdchk(fdes) returns non 0 if a character is available
  1333.          */
  1334.         while (rdchk(iofd)) {
  1335. #ifdef SV
  1336.             switch (checked)
  1337. #else
  1338.             switch (readline(1))
  1339. #endif
  1340.             {
  1341.             case CAN:
  1342.             case ZPAD:
  1343.                 c = getinsync(1);
  1344.                 goto gotack;
  1345.             case XOFF:        /* Wait a while for an XON */
  1346.             case XOFF|0200:
  1347.                 readline(100);
  1348.             }
  1349.         }
  1350. #endif
  1351.     }
  1352.  
  1353.     if ( !Fromcu)
  1354.         signal(SIGINT, onintr);
  1355.     newcnt = Rxbuflen;
  1356.     Txwcnt = 0;
  1357.     stohdr(Txpos);
  1358.     zsbhdr(ZDATA, Txhdr);
  1359.  
  1360.     /*
  1361.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  1362.      *  many times.  Each time the signal should be caught, causing the
  1363.      *  file to be started over from the beginning.
  1364.      */
  1365.     if (Test) {
  1366.         if ( --tleft)
  1367.             while (tcount < 20000) {
  1368.                 printf(qbf); fflush(stdout);
  1369.                 tcount += strlen(qbf);
  1370. #ifdef READCHECK
  1371.                 while (rdchk(iofd)) {
  1372. #ifdef SV
  1373.                     switch (checked)
  1374. #else
  1375.                     switch (readline(1))
  1376. #endif
  1377.                     {
  1378.                     case CAN:
  1379.                     case ZPAD:
  1380. #ifdef TCFLSH
  1381.                         ioctl(iofd, TCFLSH, 1);
  1382. #endif
  1383.                         goto waitack;
  1384.                     case XOFF:    /* Wait for XON */
  1385.                     case XOFF|0200:
  1386.                         readline(100);
  1387.                     }
  1388.                 }
  1389. #endif
  1390.             }
  1391.         signal(SIGINT, SIG_IGN); canit();
  1392.         sleep(3); purgeline(); mode(0);
  1393.         printf("\nsz: Tcount = %ld\n", tcount);
  1394.         if (tleft) {
  1395.             printf("ERROR: Interrupts Not Caught\n");
  1396.             exit(1);
  1397.         }
  1398.         exit(SS_NORMAL);
  1399.     }
  1400.  
  1401.     do {
  1402.         n = zfilbuf();
  1403.         if (Eofseen)
  1404.             e = ZCRCE;
  1405.         else if (junkcount > 3)
  1406.             e = ZCRCW;
  1407.         else if (bytcnt == Lastsync)
  1408.             e = ZCRCW;
  1409.         else if (Rxbuflen && (newcnt -= n) <= 0)
  1410.             e = ZCRCW;
  1411.         else if (Txwindow && (Txwcnt += n) >= Txwspac) {
  1412.             Txwcnt = 0;  e = ZCRCQ;
  1413.         }
  1414.         else
  1415.             e = ZCRCG;
  1416.         if (Verbose>1)
  1417.             fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1418.               Txpos, Crc32t?" CRC-32":"");
  1419.         zsdata(txbuf, n, e);
  1420.         bytcnt = Txpos += n;
  1421.         if (e == ZCRCW)
  1422.             goto waitack;
  1423. #ifdef READCHECK
  1424.         /*
  1425.          * If the reverse channel can be tested for data,
  1426.          *  this logic may be used to detect error packets
  1427.          *  sent by the receiver, in place of setjmp/longjmp
  1428.          *  rdchk(fdes) returns non 0 if a character is available
  1429.          */
  1430.         fflush(stdout);
  1431.         while (rdchk(iofd)) {
  1432. #ifdef SV
  1433.             switch (checked)
  1434. #else
  1435.             switch (readline(1))
  1436. #endif
  1437.             {
  1438.             case CAN:
  1439.             case ZPAD:
  1440.                 c = getinsync(1);
  1441.                 if (c == ZACK)
  1442.                     break;
  1443. #ifdef TCFLSH
  1444.                 ioctl(iofd, TCFLSH, 1);
  1445. #endif
  1446.                 /* zcrce - dinna wanna starta ping-pong game */
  1447.                 zsdata(txbuf, 0, ZCRCE);
  1448.                 goto gotack;
  1449.             case XOFF:        /* Wait a while for an XON */
  1450.             case XOFF|0200:
  1451.                 readline(100);
  1452.             default:
  1453.                 ++junkcount;
  1454.             }
  1455.         }
  1456. #endif    /* READCHECK */
  1457.         if (Txwindow) {
  1458.             while ((tcount = Txpos - Lrxpos) >= Txwindow) {
  1459.                 vfile("%ld window >= %u", tcount, Txwindow);
  1460.                 if (e != ZCRCQ)
  1461.                     zsdata(txbuf, 0, e = ZCRCQ);
  1462.                 c = getinsync(1);
  1463.                 if (c != ZACK) {
  1464. #ifdef TCFLSH
  1465.                     ioctl(iofd, TCFLSH, 1);
  1466. #endif
  1467.                     zsdata(txbuf, 0, ZCRCE);
  1468.                     goto gotack;
  1469.                 }
  1470.             }
  1471.             vfile("window = %ld", tcount);
  1472.         }
  1473.     } while (!Eofseen);
  1474.     if ( !Fromcu)
  1475.         signal(SIGINT, SIG_IGN);
  1476.  
  1477.     for (;;) {
  1478.         stohdr(Txpos);
  1479.         zsbhdr(ZEOF, Txhdr);
  1480.         switch (getinsync(0)) {
  1481.         case ZACK:
  1482.             continue;
  1483.         case ZRPOS:
  1484.             goto somemore;
  1485.         case ZRINIT:
  1486.             return OK;
  1487.         case ZSKIP:
  1488.             fclose(in);
  1489.             return c;
  1490.         default:
  1491.             fclose(in);
  1492.             return ERROR;
  1493.         }
  1494.     }
  1495. }
  1496.  
  1497. /*
  1498.  * Respond to receiver's complaint, get back in sync with receiver
  1499.  */
  1500. getinsync(flag)
  1501. {
  1502.     register c;
  1503.  
  1504.     for (;;) {
  1505.         if (Test) {
  1506.             printf("\r\n\n\n***** Signal Caught *****\r\n");
  1507.             Rxpos = 0; c = ZRPOS;
  1508.         } else
  1509.             c = zgethdr(Rxhdr, 0);
  1510.         switch (c) {
  1511.         case ZCAN:
  1512.         case ZABORT:
  1513.         case ZFIN:
  1514.         case TIMEOUT:
  1515.             return ERROR;
  1516.         case ZRPOS:
  1517.             /* ************************************* */
  1518.             /*  If sending to a buffered modem, you  */
  1519.             /*   might send a break at this point to */
  1520.             /*   dump the modem's buffer.         */
  1521.             clearerr(in);    /* In case file EOF seen */
  1522.             if (fseek(in, Rxpos, 0))
  1523.                 return ERROR;
  1524.             Eofseen = 0;
  1525.             bytcnt = Lrxpos = Txpos = Rxpos;
  1526.             if (Lastsync == Rxpos) {
  1527.                 if (++Beenhereb4 > 4)
  1528.                     if (blklen > 32)
  1529.                         blklen /= 2;
  1530.             }
  1531.             Lastsync = Rxpos;
  1532.             return c;
  1533.         case ZACK:
  1534.             Lrxpos = Rxpos;
  1535.             if (flag || Txpos == Rxpos)
  1536.                 return ZACK;
  1537.             continue;
  1538.         case ZRINIT:
  1539.         case ZSKIP:
  1540.             fclose(in);
  1541.             return c;
  1542.         case ERROR:
  1543.         default:
  1544.             zsbhdr(ZNAK, Txhdr);
  1545.             continue;
  1546.         }
  1547.     }
  1548. }
  1549.  
  1550.  
  1551. /* Say "bibi" to the receiver, try to do it cleanly */
  1552. saybibi()
  1553. {
  1554.     for (;;) {
  1555.         stohdr(0L);        /* CAF Was zsbhdr - minor change */
  1556.         zshhdr(ZFIN, Txhdr);    /*  to make debugging easier */
  1557.         switch (zgethdr(Rxhdr, 0)) {
  1558.         case ZFIN:
  1559.             sendline('O'); sendline('O'); flushmo();
  1560.         case ZCAN:
  1561.         case TIMEOUT:
  1562.             return;
  1563.         }
  1564.     }
  1565. }
  1566.  
  1567. /* Local screen character display function */
  1568. bttyout(c)
  1569. {
  1570.     if (Verbose)
  1571.         putc(c, stderr);
  1572. }
  1573.  
  1574. /* Send command and related info */
  1575. zsendcmd(buf, blen)
  1576. char *buf;
  1577. {
  1578.     register c;
  1579.     long cmdnum;
  1580.  
  1581.     cmdnum = getpid();
  1582.     errors = 0;
  1583.     for (;;) {
  1584.         stohdr(cmdnum);
  1585.         Txhdr[ZF0] = Cmdack1;
  1586.         zsbhdr(ZCOMMAND, Txhdr);
  1587.         zsdata(buf, blen, ZCRCW);
  1588. listen:
  1589.         Rxtimeout = 100;        /* Ten second wait for resp. */
  1590.         c = zgethdr(Rxhdr, 1);
  1591.  
  1592.         switch (c) {
  1593.         case ZRINIT:
  1594.             goto listen;    /* CAF 8-21-87 */
  1595.         case ERROR:
  1596.         case TIMEOUT:
  1597.             if (++errors > Cmdtries)
  1598.                 return ERROR;
  1599.             continue;
  1600.         case ZCAN:
  1601.         case ZABORT:
  1602.         case ZFIN:
  1603.         case ZSKIP:
  1604.         case ZRPOS:
  1605.             return ERROR;
  1606.         default:
  1607.             if (++errors > 20)
  1608.                 return ERROR;
  1609.             continue;
  1610.         case ZCOMPL:
  1611.             Exitcode = Rxpos;
  1612.             saybibi();
  1613.             return OK;
  1614.         case ZRQINIT:
  1615. #ifdef vax11c        /* YAMP :== Yet Another Missing Primitive */
  1616.             return ERROR;
  1617. #else
  1618.             vfile("******** RZ *******");
  1619.             system("rz");
  1620.             vfile("******** SZ *******");
  1621.             goto listen;
  1622. #endif
  1623.         }
  1624.     }
  1625. }
  1626.  
  1627. /*
  1628.  * If called as sb use YMODEM protocol
  1629.  */
  1630. chkinvok(s)
  1631. char *s;
  1632. {
  1633. #ifdef vax11c
  1634.     Progname = "sz";
  1635. #else
  1636.     register char *p;
  1637.  
  1638.     p = s;
  1639.     while (*p == '-')
  1640.         s = ++p;
  1641.     while (*p)
  1642.         if (*p++ == '/')
  1643.             s = p;
  1644.     if (*s == 'v') {
  1645.         Verbose=1; ++s;
  1646.     }
  1647.     Progname = s;
  1648.     if (s[0]=='s' && s[1]=='b') {
  1649.         Nozmodem = TRUE; blklen=1024;
  1650.     }
  1651.     if (s[0]=='s' && s[1]=='x') {
  1652.         Modem2 = TRUE;
  1653.     }
  1654. #endif
  1655. }
  1656.  
  1657. countem(argc, argv)
  1658. register char **argv;
  1659. {
  1660.     register c;
  1661.     struct stat f;
  1662.  
  1663.     for (Totalleft = 0, Filesleft = 0; --argc >=0; ++argv) {
  1664.         f.st_size = -1;
  1665.         if (Verbose>2) {
  1666.             fprintf(stderr, "\nCountem: %03d %s ", argc, *argv);
  1667.             fflush(stderr);
  1668.         }
  1669.         if (access(*argv, 04) >= 0 && stat(*argv, &f) >= 0) {
  1670.             c = f.st_mode & S_IFMT;
  1671.             if (c != S_IFDIR && c != S_IFBLK) {
  1672.                 ++Filesleft;  Totalleft += f.st_size;
  1673.             }
  1674.         }
  1675.         if (Verbose>2)
  1676.             fprintf(stderr, " %ld", f.st_size);
  1677.     }
  1678.     if (Verbose>2)
  1679.         fprintf(stderr, "\ncountem: Total %d %ld\n",
  1680.           Filesleft, Totalleft);
  1681. }
  1682.  
  1683. chartest(m)
  1684. {
  1685.     register n;
  1686.  
  1687.     mode(m);
  1688.     printf("\r\n\nCharacter Transparency Test Mode %d\r\n", m);
  1689.     printf("If Pro-YAM/ZCOMM is not displaying ^M hit ALT-V NOW.\r\n");
  1690.     printf("Hit Enter.\021");  fflush(stdout);
  1691.     readline(500);
  1692.  
  1693.     for (n = 0; n < 256; ++n) {
  1694.         if (!(n%8))
  1695.             printf("\r\n");
  1696.         printf("%02x ", n);  fflush(stdout);
  1697.         sendline(n);    flushmo();
  1698.         printf("  ");  fflush(stdout);
  1699.         if (n == 127) {
  1700.             printf("Hit Enter.\021");  fflush(stdout);
  1701.             readline(500);
  1702.             printf("\r\n");  fflush(stdout);
  1703.         }
  1704.     }
  1705.     printf("\021\r\nEnter Characters, echo is in hex.\r\n");
  1706.     printf("Hit SPACE or pause 40 seconds for exit.\r\n");
  1707.  
  1708.     while (n != TIMEOUT && n != ' ') {
  1709.         n = readline(400);
  1710.         printf("%02x\r\n", n);
  1711.         fflush(stdout);
  1712.     }
  1713.     printf("\r\nMode %d character transparency test ends.\r\n", m);
  1714.     fflush(stdout);
  1715. }
  1716.  
  1717. /* End of sz.c */
  1718.