home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / rzsz_3_24_3_src.lzh / rz.c < prev    next >
C/C++ Source or Header  |  1993-12-25  |  32KB  |  1,541 lines

  1. #define VERSION "3.24 5-5-93"
  2. #ifdef OS9
  3. #define PUBDIR "/dd/SPOOL/UUCPPUBLIC"
  4. #else /* !OS9 */
  5. #define PUBDIR "/usr/spool/uucppublic"
  6. #endif
  7.  
  8. /*
  9.  *
  10.  * rz.c By Chuck Forsberg
  11.  *    Copyright 1993 Omen Technology Inc All Rights Reserved
  12.  *
  13.  * A program for Unix to receive files and commands from computers running
  14.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  15.  *  rz uses Unix buffered input to reduce wasted CPU time.
  16.  *
  17.  *
  18.  *    This version implements numerous enhancements including ZMODEM
  19.  *    Run Length Encoding and variable length headers.  These
  20.  *    features were not funded by the original Telenet development
  21.  *    contract.
  22.  * 
  23.  *  This software may be freely used for educational (didactic
  24.  *  only) purposes.  This software may also be freely used to
  25.  *  support file transfer operations to or from licensed Omen
  26.  *  Technology products.  Use with other commercial or shareware
  27.  *  programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION.
  28.  *
  29.  *  Any programs which use part or all of this software must be
  30.  *  provided in source form with this notice intact except by
  31.  *  written permission from Omen Technology Incorporated.
  32.  *
  33.  * 
  34.  * Use of this software for commercial or administrative purposes
  35.  * except when exclusively limited to interfacing Omen Technology
  36.  * products requires a per port license payment of $20.00 US per
  37.  * port (less in quantity, see mailer.rz).  Use of this code by
  38.  * inclusion, decompilation, reverse engineering or any other means
  39.  * constitutes agreement to these conditions and acceptance of
  40.  * liability to license the materials and payment of reasonable
  41.  * legal costs necessary to enforce this license agreement.
  42.  *
  43.  *
  44.  *        Omen Technology Inc
  45.  *        Post Office Box 4681
  46.  *        Portland OR 97208
  47.  *
  48.  *    This code is made available in the hope it will be useful,
  49.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  50.  *    DAMAGES OF ANY KIND.
  51.  *
  52.  *
  53.  *
  54.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  55.  *
  56.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  57.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  58.  *
  59.  *  -DMD may be added to compiler command line to compile in
  60.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  61.  *
  62.  *  HOWMANY may be tuned for best performance
  63.  *
  64.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  65.  */
  66.  
  67. char *Copyrrz = "Copyright 1993 Omen Technology Inc All Rights Reserved";
  68.  
  69.  
  70. #include <stdio.h>
  71. #include <signal.h>
  72. #include <ctype.h>
  73. #include <errno.h>
  74. extern int errno;
  75.  
  76. #ifdef OS9
  77. #include <direct.h>
  78. #include <modes.h>
  79. #include <sgstat.h>
  80. #include "os9.h"
  81. #define LOGFILE "/dd/TMP/rzlog"
  82. char logfile[128];
  83. struct sgbuf stty;
  84. struct sgbuf sttyold;
  85. int u2oattr();
  86. int getuid();
  87.  
  88. #ifndef m6809
  89. long outime();
  90. long c4tol();
  91. #endif /* !m6809 */
  92.  
  93. #else /* !OS9 */
  94. #define LOGFILE "/tmp/rzlog"
  95. #endif /* !OS9 */
  96.  
  97. #define LOGFILE2 "rzlog"
  98.  
  99. #ifndef OS9
  100. #define OK 0
  101. #define FALSE 0
  102. #define TRUE 1
  103. #define ERROR (-1)
  104.  
  105. /*
  106.  * Max value for HOWMANY is 255.
  107.  *   A larger value reduces system overhead but may evoke kernel bugs.
  108.  */
  109. #ifndef HOWMANY
  110. #define HOWMANY 96
  111. #endif
  112.  
  113. /* Ward Christensen / CP/M parameters - Don't change these! */
  114. #define ENQ 005
  115. #define CAN ('X'&037)
  116. #define XOFF ('s'&037)
  117. #define XON ('q'&037)
  118. #define SOH 1
  119. #define STX 2
  120. #define EOT 4
  121. #define ACK 6
  122. #define NAK 025
  123. #define CPMEOF 032
  124. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  125. #define TIMEOUT (-2)
  126. #define RCDO (-3)
  127. #define GCOUNT (-4)
  128. #define ERRORMAX 5
  129. #define RETRYMAX 5
  130. #define WCEOT (-10)
  131. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  132. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  133. #endif /* !OS9 */
  134.  
  135. int Zmodem=0;        /* ZMODEM protocol requested */
  136. int Nozmodem = 0;    /* If invoked as "rb" */
  137. unsigned Baudrate = 9600;
  138. unsigned Effbaud = 9600;
  139.  
  140.  
  141. #ifdef OS9
  142. extern int Lleft;
  143. extern int Readnum;
  144. extern FILE *Ttystream;
  145. extern int Verbose;
  146.  
  147. #ifdef m6809
  148. unsigned updcrc();
  149. #else /* !m6809 */
  150. unsigned long updcrc();
  151. #endif /* !m6809 */
  152. #else /* !OS9 */
  153. #include "rbsb.c"    /* most of the system dependent stuff here */
  154.  
  155. #include "crctab.c"
  156. #endif /* !OS9 */
  157.  
  158. char endmsg[90] = {0};    /* Possible message to display on exit */
  159.  
  160. char *substr();
  161. FILE *fout;
  162.  
  163. /*
  164.  * Routine to calculate the free bytes on the current file system
  165.  *  ~0 means many free bytes (unknown)
  166.  */
  167. #ifdef m6809
  168. long getfree()
  169. #else
  170. unsigned long getfree()
  171. #endif
  172. {
  173.     return(~0L);    /* many free bytes ... */
  174. }
  175.  
  176. int Lastrx;
  177. #ifdef m6809
  178. long rxbytes;
  179. #else
  180. unsigned long rxbytes;
  181. #endif
  182. int Crcflg;
  183. int Firstsec;
  184. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  185. int errors;
  186. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  187.  
  188. #ifndef OS9
  189. #define DEFBYTL 2000000000L    /* default rx file size */
  190. #endif
  191.  
  192. #ifdef m6809
  193. long Bytesleft;    /* number of bytes of incoming file left */
  194. #else
  195. unsigned long Bytesleft;    /* number of bytes of incoming file left */
  196. #endif
  197. long Modtime;        /* Unix style mod time for incoming file */
  198. int Filemode;        /* Unix style mode for incoming file */
  199. #ifdef m6809
  200. long Totalleft;
  201. long Filesleft;
  202. #else
  203. unsigned long Totalleft;
  204. unsigned long Filesleft;
  205. #endif
  206. char Pathname[PATHLEN];
  207. char *Progname;        /* the name by which we were called */
  208.  
  209. int Batch=0;
  210. int Thisbinary;        /* current file is to be received in bin mode */
  211. int Rxbinary=FALSE;    /* receive all files in bin mode */
  212. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  213. int Blklen;        /* record length of received packets */
  214.  
  215. #ifdef SEGMENTS
  216. int chinseg = 0;    /* Number of characters received in this data seg */
  217. char secbuf[1+(SEGMENTS+1)*1024];
  218. #else
  219. char secbuf[1025];
  220. #endif
  221.  
  222.  
  223. #ifdef OS9
  224. long timep[2];
  225. #else
  226. time_t timep[2];
  227. #endif /* OS9 */
  228. char Lzmanag;        /* Local file management request */
  229. char Lzconv;        /* Local ZMODEM file conversion request */
  230. char zconv;        /* ZMODEM file conversion request */
  231. char zmanag;        /* ZMODEM file management request */
  232. char ztrans;        /* ZMODEM file transport request */
  233. int Zctlesc;        /* Encode control characters */
  234. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  235.  
  236.  
  237. #ifdef OS9
  238. #include "zmodem.h"
  239. extern int Crc32r;
  240. extern char Rxhdr[];
  241. extern char Txhdr[];
  242. extern Usevhdrs;
  243. int zgethdr();
  244. int zrdata();
  245. #else /* !OS9 */
  246. #include "zm.c"
  247. #include "zmr.c"
  248. #endif
  249.  
  250. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  251.  
  252. /* called by signal interrupt or terminate to clean things up */
  253. void
  254. bibi(n)
  255. {
  256.     if (Zmodem)
  257.         zmputs(Attn);
  258.     canit(); mode(0);
  259.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  260. #ifdef OS9
  261.     if(Verbose < 3)
  262.         _ss_opt(fileno(stderr), &sttyold);
  263. #endif
  264.     exit(3);
  265. }
  266.  
  267. main(argc, argv)
  268. char *argv[];
  269. {
  270.     register char *cp;
  271.     register npats;
  272.     char *virgin, **patts;
  273.     char *getenv();
  274.     int exitcode = 0;
  275.  
  276. #ifdef OS9
  277. #ifdef m6809
  278.     pflinit();
  279. #endif /* m6809 */
  280.  
  281.     _gs_opt(fileno(stderr), &sttyold);
  282. #ifdef m6809
  283.     _strass(&stty, &sttyold, sizeof(struct sgbuf));
  284. #else
  285.     stty = sttyold;
  286. #endif
  287.     stty.sg_pause = 0;
  288.     _ss_opt(fileno(stderr), &stty);
  289. #endif
  290.  
  291.     Rxtimeout = 100;
  292.     setbuf(stderr, NULL);
  293. #ifdef OS9
  294. #ifdef m6809
  295.     Restricted=TRUE;
  296. #else
  297.     if ((cp=getenv("SHELL")) && (substr(cp, "shell") == 0))
  298.         Restricted=TRUE;
  299. #endif
  300. #else
  301.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  302.         Restricted=TRUE;
  303. #endif
  304.  
  305.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  306.     inittty();
  307.     npats = 0;
  308.     while (--argc) {
  309.         cp = *++argv;
  310.         if (*cp == '-') {
  311.             while( *++cp) {
  312.                 switch(*cp) {
  313.                 case '\\':
  314.                      cp[1] = toupper(cp[1]);  continue;
  315.                 case 'a':
  316.                     if (!Batch || Nozmodem)
  317.                         Rxascii=TRUE;
  318.                     else
  319.                         usage();
  320.                     break;
  321.                 case 't':
  322.                     if (--argc < 1) {
  323.                         usage();
  324.                     }
  325.                     Rxtimeout = atoi(*++argv);
  326.                     if (Rxtimeout<10 || Rxtimeout>1000)
  327.                         usage();
  328.                     break;
  329.                 case 'w':
  330.                     if (--argc < 1) {
  331.                         usage();
  332.                     }
  333.                     Zrwindow = atoi(*++argv);
  334.                     break;
  335.                 case 'v':
  336.                     ++Verbose; break;
  337.                 default:
  338.                     usage();
  339.                 }
  340.             }
  341.         }
  342.         else if ( !npats && argc>0) {
  343.             if (argv[0][0]) {
  344.                 npats=argc;
  345.                 patts=argv;
  346.             }
  347.         }
  348.     }
  349.     if (npats > 1)
  350.         usage();
  351.     if (Batch && npats)
  352.         usage();
  353. #ifdef OS9
  354.     if (Verbose > 2) {
  355.         sprintf(logfile, "%s.%d", LOGFILE, getuid());
  356.         if (freopen(logfile, "a", stderr)==NULL)
  357.             if (freopen(LOGFILE2, "a", stderr)==NULL) {
  358.                 printf("Can't open log file!");
  359.                 _ss_opt(fileno(stderr), &sttyold);
  360.                 exit(2);
  361.             }
  362.         setbuf(stderr, NULL);
  363.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  364.     }
  365. #else
  366.     if (Verbose) {
  367.         if (freopen(LOGFILE, "a", stderr)==NULL)
  368.             if (freopen(LOGFILE2, "a", stderr)==NULL) {
  369.                 printf("Can't open log file!");
  370.                 exit(2);
  371.             }
  372.         setbuf(stderr, NULL);
  373.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  374.     }
  375. #endif
  376.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  377.     mode(1);
  378.     if (signal(SIGINT, bibi) == SIG_IGN) {
  379.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  380. #ifdef OS9
  381.         signal(SIGQUIT, SIG_IGN);
  382. #endif
  383.     }
  384.     else {
  385.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  386. #ifdef OS9
  387.         signal(SIGQUIT, bibi);
  388. #endif
  389.     }
  390.     signal(SIGTERM, bibi);
  391.     if (wcreceive(npats, patts)==ERROR) {
  392.         exitcode=1;
  393.         canit();
  394.     }
  395.     mode(0);
  396.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  397.         canit();
  398.     if (endmsg[0])
  399.         fprintf(stderr, "  %s: %s\n", Progname, endmsg);
  400.     fprintf(stderr, "\n%s %s finished.\n", Progname, VERSION);
  401. #ifdef OS9
  402.     if (Verbose < 3)
  403.         _ss_opt(fileno(stderr), &sttyold);
  404. #endif
  405.     fflush(stderr);
  406.     if(exitcode)
  407.         exit(1);
  408. #ifndef REGISTERED
  409.     /* Removing or disabling this code without registering is theft */
  410.     if (!Usevhdrs)  {
  411.         fprintf(stderr, "\n\n\nPlease read the License Agreement in rz.doc\n");
  412.         fflush(stderr);
  413.         sleep(2);
  414.     }
  415. #endif
  416.     exit(0);
  417. }
  418.  
  419.  
  420. usage()
  421. {
  422.     fprintf(stderr,
  423.     "Receive Files and Commands with ZMODEM/YMODEM/XMODEM Protocol\n\n");
  424.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  425.       Progname, VERSION, OS);
  426. #ifdef m6809
  427.     fprintf(stderr, "               \042The High Reliability Software\042\n\n");
  428. #else
  429.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n\n");
  430. #endif
  431.     fprintf(stderr,"Usage:    rz [-v]        (ZMODEM)\n");
  432.     fprintf(stderr,"or    rb [-av]    (YMODEM)\n");
  433.     fprintf(stderr,"or    rc [-av] file    (XMODEM-CRC)\n");
  434.     fprintf(stderr,"or    rx [-av] file    (XMODEM)\n\n");
  435.     fprintf(stderr,
  436. "Supports incoming ZMODEM binary (-b), ASCII CR/LF>NL (-a), newer(-n),\n");
  437.     fprintf(stderr,
  438. "newer+longer(-N), protect (-p), Crash Recovery (-r),\n");
  439.     fprintf(stderr,
  440. "clobber (-y), match+clobber (-Y), compression (-Z), and append (-+).\n\n");
  441.     fprintf(stderr,"Copyright 1993 Omen Technology INC All Rights Reserved\n");
  442.     fprintf(stderr,
  443.     "See rz.doc for option descriptions and licensing information.\n\n");
  444.     exit(2);
  445. }
  446.  
  447. /*
  448.  * Let's receive something already.
  449.  */
  450.  
  451. char *rbmsg = "%s ready. Type \"%s file ...\" to your modem program\n\r";
  452.  
  453. wcreceive(argc, argp)
  454. char **argp;
  455. {
  456.     register c;
  457.  
  458.     if (Batch || argc==0) {
  459.         Crcflg=1;
  460.         fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  461.         if (c=tryz()) {
  462.             if (c == ZCOMPL)
  463.                 return OK;
  464.             if (c == ERROR)
  465.                 goto fubar;
  466.             c = rzfiles();
  467.             if (c)
  468.                 goto fubar;
  469.         } else {
  470.             for (;;) {
  471.                 if (wcrxpn(secbuf)== ERROR)
  472.                     goto fubar;
  473.                 if (secbuf[0]==0)
  474.                     return OK;
  475.                 if (procheader(secbuf) == ERROR)
  476.                     goto fubar;
  477.                 if (wcrx()==ERROR)
  478.                     goto fubar;
  479.             }
  480.         }
  481.     } else {
  482.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  483.  
  484.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  485.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  486.         if ((fout=fopen(Pathname, "w")) == NULL)
  487.             return ERROR;
  488.         if (wcrx()==ERROR)
  489.             goto fubar;
  490.     }
  491.     return OK;
  492. fubar:
  493.     canit();
  494.     Modtime = 1;
  495.     if (fout)
  496. #ifdef OS9
  497.     {
  498.         fflush(fout);
  499.         fclose(fout);
  500.     }
  501. #else
  502.         fclose(fout);
  503. #endif
  504.     if (Restricted) {
  505.         unlink(Pathname);
  506.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  507.     }
  508.     return ERROR;
  509. }
  510.  
  511.  
  512. /*
  513.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  514.  * Length is indeterminate as long as less than Blklen
  515.  * A null string represents no more files (YMODEM)
  516.  */
  517. wcrxpn(rpn)
  518. char *rpn;    /* receive a pathname */
  519. {
  520.     register c;
  521.  
  522.     purgeline();
  523.  
  524. et_tu:
  525.     Firstsec=TRUE;  Eofseen=FALSE;
  526.     sendline(Crcflg?WANTCRC:NAK);  flushmo();
  527.     Lleft=0;    /* Do read next time ... */
  528.     while ((c = wcgetsec(rpn, 100)) != 0) {
  529.         if (c == WCEOT) {
  530.             zperr( "Pathname fetch returned %d", c);
  531.             sendline(ACK);  flushmo();
  532.             Lleft=0;    /* Do read next time ... */
  533.             readline(1);
  534.             goto et_tu;
  535.         }
  536.         return ERROR;
  537.     }
  538.     sendline(ACK);  flushmo();
  539.     return OK;
  540. }
  541.  
  542. /*
  543.  * Adapted from CMODEM13.C, written by
  544.  * Jack M. Wierda and Roderick W. Hart
  545.  */
  546.  
  547. wcrx()
  548. {
  549.     register int sectnum, sectcurr;
  550.     register char sendchar;
  551.     register char *p;
  552.     int cblklen;            /* bytes to dump this block */
  553.  
  554.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  555.     sendchar=Crcflg?WANTCRC:NAK;
  556.  
  557.     for (;;) {
  558.         sendline(sendchar);    /* send it now, we're ready! */
  559.         flushmo();
  560.         Lleft=0;    /* Do read next time ... */
  561.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  562.         if (sectcurr==(sectnum+1 &0377)) {
  563.             sectnum++;
  564.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  565.             if (putsec(secbuf, cblklen)==ERROR)
  566.                 return ERROR;
  567.             if (((int)(Bytesleft-=cblklen)) < 0)
  568.                 Bytesleft = 0;
  569.             sendchar=ACK;
  570.         }
  571.         else if (sectcurr==(sectnum&0377)) {
  572.             zperr( "Received dup Sector");
  573.             sendchar=ACK;
  574.         }
  575.         else if (sectcurr==WCEOT) {
  576.             if (closeit())
  577.                 return ERROR;
  578.             sendline(ACK); flushmo();
  579.             Lleft=0;    /* Do read next time ... */
  580.             return OK;
  581.         }
  582.         else if (sectcurr==ERROR)
  583.             return ERROR;
  584.         else {
  585.             zperr( "Sync Error");
  586.             return ERROR;
  587.         }
  588.     }
  589. }
  590.  
  591. /*
  592.  * Wcgetsec fetches a Ward Christensen type sector.
  593.  * Returns sector number encountered or ERROR if valid sector not received,
  594.  * or CAN CAN received
  595.  * or WCEOT if eot sector
  596.  * time is timeout for first char, set to 4 seconds thereafter
  597.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  598.  *    (Caller must do that when he is good and ready to get next sector)
  599.  */
  600.  
  601. wcgetsec(rxbuf, maxtime)
  602. char *rxbuf;
  603. int maxtime;
  604. {
  605.     register checksum, wcj, firstch;
  606. #ifdef m6809
  607.     register unsigned oldcrc;
  608. #else
  609.     register unsigned short oldcrc;
  610. #endif
  611.     register char *p;
  612.     int sectcurr;
  613.  
  614.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  615.  
  616.         if ((firstch=readline(maxtime))==STX) {
  617.             Blklen=1024; goto get2;
  618.         }
  619.         if (firstch==SOH) {
  620.             Blklen=128;
  621. get2:
  622.             sectcurr=readline(1);
  623.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  624.                 oldcrc=checksum=0;
  625.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  626.                     if ((firstch=readline(1)) < 0)
  627.                         goto bilge;
  628.                     oldcrc=updcrc(firstch, oldcrc);
  629.                     checksum += (*p++ = firstch);
  630.                 }
  631.                 if ((firstch=readline(1)) < 0)
  632.                     goto bilge;
  633.                 if (Crcflg) {
  634.                     oldcrc=updcrc(firstch, oldcrc);
  635.                     if ((firstch=readline(1)) < 0)
  636.                         goto bilge;
  637.                     oldcrc=updcrc(firstch, oldcrc);
  638.                     if (oldcrc & 0xFFFF)
  639.                         zperr( "CRC");
  640.                     else {
  641.                         Firstsec=FALSE;
  642.                         return sectcurr;
  643.                     }
  644.                 }
  645.                 else if (((checksum-firstch)&0377)==0) {
  646.                     Firstsec=FALSE;
  647.                     return sectcurr;
  648.                 }
  649.                 else
  650.                     zperr( "Checksum");
  651.             }
  652.             else
  653.                 zperr("Sector number garbled");
  654.         }
  655.         /* make sure eot really is eot and not just mixmash */
  656.         else if (firstch==EOT && Lleft==0)
  657.             return WCEOT;
  658.         else if (firstch==CAN) {
  659.             if (Lastrx==CAN) {
  660.                 zperr( "Sender CANcelled");
  661.                 return ERROR;
  662.             } else {
  663.                 Lastrx=CAN;
  664.                 continue;
  665.             }
  666.         }
  667.         else if (firstch==TIMEOUT) {
  668.             if (Firstsec)
  669.                 goto humbug;
  670. bilge:
  671.             zperr( "TIMEOUT");
  672.         }
  673.         else
  674.             zperr( "Got 0%o sector header", firstch);
  675.  
  676. humbug:
  677.         Lastrx=0;
  678.         while(readline(1)!=TIMEOUT)
  679.             ;
  680.         if (Firstsec) {
  681.             sendline(Crcflg?WANTCRC:NAK);  flushmo();
  682.             Lleft=0;    /* Do read next time ... */
  683.         } else {
  684.             maxtime=40; sendline(NAK);  flushmo();
  685.             Lleft=0;    /* Do read next time ... */
  686.         }
  687.     }
  688.     /* try to stop the bubble machine. */
  689.     canit();
  690.     return ERROR;
  691. }
  692.  
  693.  
  694. /*
  695.  * Process incoming file information header
  696.  */
  697. procheader(name)
  698. char *name;
  699. {
  700.     register char *openmode, *p, **pp;
  701.     static dummy;
  702. #ifdef OS9
  703.     int pn;
  704.     struct fildes f;
  705. #else
  706.     struct stat f;
  707. #endif
  708.  
  709.     /* set default parameters and overrides */
  710.     openmode = "w";
  711.     Thisbinary = (!Rxascii) || Rxbinary;
  712.     if (zconv == ZCBIN && Lzconv != ZCRESUM)
  713.         Lzconv = zconv;            /* Remote Binary override */
  714.     if (Lzconv)
  715.         zconv = Lzconv;
  716.     if (Lzmanag)
  717.         zmanag = Lzmanag;
  718.  
  719.     /*
  720.      *  Process ZMODEM remote file management requests
  721.      */
  722.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  723.         Thisbinary = 0;
  724.     if (zconv == ZCBIN)    /* Remote Binary override */
  725.         Thisbinary = TRUE;
  726.     else if (zmanag == ZMAPND)
  727.         openmode = "a";
  728.  
  729.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  730.  
  731.     if (!name || !*name)
  732.         return OK;
  733.  
  734.     p = name + 1 + strlen(name);
  735.     if (*p) {    /* file coming from Unix or DOS system */
  736.         sscanf(p, "%ld%lo%lo%o%ld%ld%d%d",
  737.           &Bytesleft, &Modtime, &Filemode,
  738.           &dummy, &Filesleft, &Totalleft, &dummy, &dummy);
  739. #ifdef OS9
  740.         if (!(Filemode & UNIXFILE))
  741. #else
  742.         if (Filemode & UNIXFILE)
  743. #endif
  744.             ++Thisbinary;
  745.         if (Verbose) {
  746.             fprintf(stderr,  "\nIncoming: %s %ld %lo %o\n",
  747.               name, Bytesleft, Modtime, Filemode);
  748.             fprintf(stderr,  "YMODEM header: %s\n", p);
  749.         }
  750.     }
  751.  
  752.  
  753.     else {        /* File coming from CP/M system */
  754.         for (p=name; *p; ++p)        /* change / to _ */
  755.             if ( *p == '/')
  756.                 *p = '_';
  757.  
  758.         if ( *--p == '.')        /* zap trailing period */
  759.             *p = 0;
  760.     }
  761.  
  762.     strcpy(Pathname, name);
  763.     checkpath(name);
  764.  
  765. #ifdef OS9
  766.         openit(name, "r");
  767.         if (*name && _gs_gfd(fileno(fout), &f, sizeof(struct fildes)) != -1) {
  768.         closeit();
  769. #else
  770.     if (*name && stat(name, &f)!= -1) {
  771. #endif
  772.         zmanag &= ZMMASK;
  773. #ifdef OS9
  774. #ifdef m6809
  775.         vfile("Current %s is %ld %lo", name, f.fd_fsize, outime(f.fd_date));
  776. #else
  777.         vfile("Current %s is %ld %lo", name, c4tol(f.fd_fsize), outime(f.fd_date));
  778. #endif
  779. #else
  780.         vfile("Current %s is %ld %lo", name, f.st_size, f.st_mtime);
  781. #endif
  782.         if (Thisbinary && zconv==ZCRESUM) {
  783. #ifdef OS9
  784. #ifdef m6809
  785.             rxbytes = f.fd_fsize & ~511;
  786. #else
  787.             rxbytes = c4tol(f.fd_fsize) & ~511;
  788. #endif
  789. #else
  790.             rxbytes = f.st_size & ~511;
  791. #endif
  792.             if (Bytesleft < rxbytes) {
  793.                 rxbytes = 0;  goto doopen;
  794.             } else
  795.                 openit(name, "r+");
  796.             if ( !fout)
  797.                 return ZFERR;
  798.             if (fseek(fout, rxbytes, 0)) {
  799.                 closeit();
  800.                 return ZFERR;
  801.             }
  802.             vfile("Crash recovery at %ld", rxbytes);
  803.             return 0;
  804.         }
  805. #ifdef OS9
  806. #ifdef m6809
  807.         else if ((zmanag==ZMNEW) ||
  808.           ((zmanag==ZMNEWL) && Bytesleft <= f.fd_fsize) ) {
  809.             if ((outime(f.fd_date)+60) >= Modtime)
  810. #else
  811.         else if ((zmanag==ZMNEW) ||
  812.           ((zmanag==ZMNEWL) && Bytesleft <= c4tol(f.fd_fsize)) ) {
  813.             if ((outime(f.fd_date)+60) >= Modtime)
  814. #endif
  815. #else
  816.         else if ((zmanag==ZMNEW) ||
  817.           ((zmanag==ZMNEWL) && Bytesleft <= f.st_size) ) {
  818.             if ((f.st_mtime+1) >= Modtime)
  819. #endif
  820.                 goto skipfile;
  821.             goto doopen;
  822.         }
  823.         switch (zmanag & ZMMASK) {
  824.         case ZMCLOB:
  825.         case ZMAPND:
  826.             goto doopen;
  827.         default:
  828.             goto skipfile;
  829.         }
  830.     } else if (zmanag & ZMSKNOLOC) {
  831. skipfile:
  832.         vfile("Skipping %s", name);
  833.         return ZSKIP;
  834.     }
  835. doopen:
  836.     openit(name, openmode);
  837. #ifdef MD
  838.     if ( !fout)
  839.         if (make_dirs(name))
  840.             openit(name, openmode);
  841. #endif
  842.     if ( !fout)
  843.         return ZFERR;
  844.     return 0;
  845. }
  846.  
  847. openit(name, openmode)
  848. char *name, *openmode;
  849. {
  850.     fout = fopen(name, openmode);
  851. }
  852.  
  853. #ifdef MD
  854. /*
  855.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  856.  */
  857.  
  858. /*
  859.  * After a file/link/symlink/dir creation has failed, see if
  860.  * it's because some required directory was not present, and if
  861.  * so, create all required dirs.
  862.  */
  863. make_dirs(pathname)
  864. register char *pathname;
  865. {
  866.     register char *p;        /* Points into path */
  867.     int madeone = 0;        /* Did we do anything yet? */
  868.     int save_errno = errno;        /* Remember caller's errno */
  869.     char *strchr();
  870.  
  871. #ifdef OS9
  872.     if (errno != E_PNNF)
  873. #else
  874.     if (errno != ENOENT)
  875. #endif
  876.         return 0;        /* Not our problem */
  877.  
  878.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  879.         /* Avoid mkdir of empty string, if leading or double '/' */
  880.         if (p == pathname || p[-1] == '/')
  881.             continue;
  882.         /* Avoid mkdir where last part of path is '.' */
  883.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  884.             continue;
  885.         *p = 0;                /* Truncate the path there */
  886. #ifdef OS9
  887.         if ( !mknod(pathname, S_IREAD | S_IWRITE | S_IEXEC |
  888.             S_IOREAD | S_IOWRITE | S_IOEXEC)) {    /* Try to create it as a dir */
  889. #else
  890.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  891. #endif
  892.             vfile("Made directory %s\n", pathname);
  893.             madeone++;        /* Remember if we made one */
  894.             *p = '/';
  895.             continue;
  896.         }
  897.         *p = '/';
  898. #ifdef OS9
  899.         if (errno == E_CEF)        /* Directory already exists */
  900. #else
  901.         if (errno == EEXIST)        /* Directory already exists */
  902. #endif
  903.             continue;
  904.         /*
  905.          * Some other error in the mkdir.  We return to the caller.
  906.          */
  907.         break;
  908.     }
  909.     errno = save_errno;        /* Restore caller's errno */
  910.     return madeone;            /* Tell them to retry if we made one */
  911. }
  912.  
  913. #ifndef MD2 /* #if (MD != 2) */
  914. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  915. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  916. #define TERM_VALUE(status)    ((status) >> 8)
  917. /*
  918.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  919.  */
  920. mkdir(dpath, dmode)
  921. char *dpath;
  922. int dmode;
  923. {
  924.     int cpid, status;
  925.     struct stat statbuf;
  926.  
  927.     if (stat(dpath,&statbuf) == 0) {
  928.         errno = EEXIST;        /* Stat worked, so it already exists */
  929.         return -1;
  930.     }
  931.  
  932.     /* If stat fails for a reason other than non-existence, return error */
  933.     if (errno != ENOENT) return -1; 
  934.  
  935.     switch (cpid = fork()) {
  936.  
  937.     case -1:            /* Error in fork() */
  938.         return(-1);        /* Errno is set already */
  939.  
  940.     case 0:                /* Child process */
  941.         /*
  942.          * Cheap hack to set mode of new directory.  Since this
  943.          * child process is going away anyway, we zap its umask.
  944.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  945.          * directory.  Does anybody care?
  946.          */
  947.         status = umask(0);    /* Get current umask */
  948.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  949.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  950.         _exit(2);        /* Can't exec /bin/mkdir */
  951.     
  952.     default:            /* Parent process */
  953.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  954.     }
  955.  
  956.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  957.         errno = EIO;        /* We don't know why, but */
  958.         return -1;        /* /bin/mkdir failed */
  959.     }
  960.  
  961.     return 0;
  962. }
  963. #endif /* MD != 2 */
  964. #endif /* MD */
  965.  
  966. /*
  967.  * Putsec writes the n characters of buf to receive file fout.
  968.  *  If not in binary mode, carriage returns, and all characters
  969.  *  starting with CPMEOF are discarded.
  970.  */
  971. putsec(buf, n)
  972. char *buf;
  973. register n;
  974. {
  975.     register char *p;
  976.  
  977.     if (n == 0)
  978.         return OK;
  979.     if (Thisbinary) {
  980.         for (p=buf; --n>=0; )
  981.             putc( *p++, fout);
  982.     }
  983.     else {
  984.         if (Eofseen)
  985.             return OK;
  986.         for (p=buf; --n>=0; ++p ) {
  987. #ifdef OS9
  988.             if ( *p == '\l')
  989. #else
  990.             if ( *p == '\r')
  991. #endif
  992.                 continue;
  993.             if (*p == CPMEOF) {
  994.                 Eofseen=TRUE; return OK;
  995.             }
  996.             putc(*p ,fout);
  997.         }
  998.     }
  999.     return OK;
  1000. }
  1001.  
  1002. /*
  1003.  * substr(string, token) searches for token in string s
  1004.  * returns pointer to token within string if found, NULL otherwise
  1005.  */
  1006. char *
  1007. substr(s, t)
  1008. register char *s,*t;
  1009. {
  1010.     register char *ss,*tt;
  1011.     /* search for first char of token */
  1012.     for (ss=s; *s; s++)
  1013.         if (*s == *t)
  1014.             /* compare token with substring */
  1015.             for (ss=s,tt=t; ;) {
  1016.                 if (*tt == 0)
  1017.                     return s;
  1018.                 if (*ss++ != *tt++)
  1019.                     break;
  1020.             }
  1021.     return NULL;
  1022. }
  1023.  
  1024.  
  1025. /*
  1026.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  1027.  * If called as rb use YMODEM protocol
  1028.  */
  1029. chkinvok(s)
  1030. char *s;
  1031. {
  1032.     register char *p;
  1033.  
  1034.     p = s;
  1035.     while (*p == '-')
  1036.         s = ++p;
  1037.     while (*p)
  1038.         if (*p++ == '/')
  1039.             s = p;
  1040.     if (*s == 'v') {
  1041.         Verbose=1; ++s;
  1042.     }
  1043.     Progname = s;
  1044.     if (s[0]=='r' && s[1]=='z')
  1045.         Batch = TRUE;
  1046.     if (s[0]=='r' && s[1]=='c')
  1047.         Crcflg = TRUE;
  1048.     if (s[0]=='r' && s[1]=='b')
  1049.         Batch = Nozmodem = TRUE;
  1050. }
  1051.  
  1052. /*
  1053.  * Totalitarian Communist pathname processing
  1054.  */
  1055. checkpath(name)
  1056. char *name;
  1057. {
  1058. #ifdef OS9
  1059.     char *p;
  1060.  
  1061.     for (p = name; *p; ++p)
  1062.     {
  1063.         if (isalnum(*p))
  1064.             continue;
  1065.         switch(*p)
  1066.         {
  1067.             case '.':
  1068.             case '/':
  1069. #ifndef m6809
  1070.             case '$':
  1071. #endif
  1072.                 continue;
  1073.             default:
  1074.                 *p = '_';
  1075.         }
  1076.     }
  1077. #endif
  1078.     if (Restricted) {
  1079.         if (fopen(name, "r") != NULL) {
  1080.             canit();
  1081.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  1082.             bibi(-1);
  1083.         }
  1084.         /* restrict pathnames to current tree or uucppublic */
  1085.         if ( substr(name, "../")
  1086.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  1087.             canit();
  1088. #ifdef m6809
  1089.             fprintf(stderr,"\r\nrz:     Security Violation\r\n");
  1090. #else
  1091.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  1092. #endif
  1093.             bibi(-1);
  1094.         }
  1095.     }
  1096. }
  1097. /*
  1098.  * Ack a ZFIN packet, let byegones be byegones
  1099.  */
  1100. void
  1101. ackbibi()
  1102. {
  1103.     register n;
  1104.  
  1105.     vfile("ackbibi:");
  1106.     Readnum = 1;
  1107.     stohdr(0L);
  1108.     for (n=3; --n>=0; ) {
  1109.         purgeline();
  1110.         zshhdr(4,ZFIN, Txhdr);
  1111.         switch (readline(100)) {
  1112.         case 'O':
  1113.             readline(1);    /* Discard 2nd 'O' */
  1114.             vfile("ackbibi complete");
  1115.             return;
  1116.         case RCDO:
  1117.             return;
  1118.         case TIMEOUT:
  1119.         default:
  1120.             break;
  1121.         }
  1122.     }
  1123. }
  1124.  
  1125.  
  1126. /*
  1127.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1128.  *  Handles ZSINIT frame
  1129.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1130.  *   ZCOMPL if transaction finished,  else 0
  1131.  */
  1132. tryz()
  1133. {
  1134.     register c, n;
  1135.     register cmdzack1flg;
  1136.  
  1137.     if (Nozmodem)        /* Check for "rb" program name */
  1138.         return 0;
  1139.  
  1140.  
  1141.     for (n=15; --n>=0; ) {
  1142.         /* Set buffer length (0) and capability flags */
  1143. #ifdef SEGMENTS
  1144.         stohdr(SEGMENTS*1024L);
  1145. #else
  1146.         stohdr(0L);
  1147. #endif
  1148. #ifdef OS9
  1149.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1150. #else
  1151. #ifdef CANBREAK
  1152.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1153. #else
  1154.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1155. #endif
  1156. #endif
  1157.         if (Zctlesc)
  1158.             Txhdr[ZF0] |= TESCCTL;
  1159.         Txhdr[ZF0] |= CANRLE;
  1160.         Txhdr[ZF1] = CANVHDR;
  1161.         /* tryzhdrtype may == ZRINIT */
  1162.         zshhdr(4,tryzhdrtype, Txhdr);
  1163.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1164.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1165. again:
  1166.         switch (zgethdr(Rxhdr, 0)) {
  1167.         case ZRQINIT:
  1168.             if (Rxhdr[ZF3] & 0x80)
  1169.                 Usevhdrs = 1;    /* we can var header */
  1170.             continue;
  1171.         case ZEOF:
  1172.             continue;
  1173.         case TIMEOUT:
  1174.             continue;
  1175.         case ZFILE:
  1176.             zconv = Rxhdr[ZF0];
  1177.             zmanag = Rxhdr[ZF1];
  1178.             ztrans = Rxhdr[ZF2];
  1179.             if (Rxhdr[ZF3] & ZCANVHDR)
  1180.                 Usevhdrs = TRUE;
  1181.             tryzhdrtype = ZRINIT;
  1182.             c = zrdata(secbuf, 1024);
  1183.             if (c == GOTCRCW)
  1184.                 return ZFILE;
  1185.             zshhdr(4,ZNAK, Txhdr);
  1186.             goto again;
  1187.         case ZSINIT:
  1188.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1189.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  1190.                 stohdr(1L);
  1191.                 zshhdr(4,ZACK, Txhdr);
  1192.                 goto again;
  1193.             }
  1194.             zshhdr(4,ZNAK, Txhdr);
  1195.             goto again;
  1196.         case ZFREECNT:
  1197.             stohdr(getfree());
  1198.             zshhdr(4,ZACK, Txhdr);
  1199.             goto again;
  1200.         case ZCOMMAND:
  1201.             cmdzack1flg = Rxhdr[ZF0];
  1202.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1203.                 if (cmdzack1flg & ZCACK1)
  1204.                     stohdr(0L);
  1205.                 else
  1206.                     stohdr((long)sys2(secbuf));
  1207.                 purgeline();    /* dump impatient questions */
  1208.                 do {
  1209.                     zshhdr(4,ZCOMPL, Txhdr);
  1210.                 }
  1211.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1212.                 ackbibi();
  1213.                 if (cmdzack1flg & ZCACK1)
  1214.                     exec2(secbuf);
  1215.                 return ZCOMPL;
  1216.             }
  1217.             zshhdr(4,ZNAK, Txhdr); goto again;
  1218.         case ZCOMPL:
  1219.             goto again;
  1220.         default:
  1221.             continue;
  1222.         case ZFIN:
  1223.             ackbibi(); return ZCOMPL;
  1224.         case ZCAN:
  1225.             return ERROR;
  1226.         }
  1227.     }
  1228.     return 0;
  1229. }
  1230.  
  1231. /*
  1232.  * Receive 1 or more files with ZMODEM protocol
  1233.  */
  1234. rzfiles()
  1235. {
  1236.     register c;
  1237.  
  1238.     for (;;) {
  1239.         switch (c = rzfile()) {
  1240.         case ZEOF:
  1241.         case ZSKIP:
  1242.             switch (tryz()) {
  1243.             case ZCOMPL:
  1244.                 return OK;
  1245.             default:
  1246.                 return ERROR;
  1247.             case ZFILE:
  1248.                 break;
  1249.             }
  1250.             continue;
  1251.         default:
  1252.             return c;
  1253.         case ERROR:
  1254.             return ERROR;
  1255.         }
  1256.     }
  1257. }
  1258.  
  1259. rpt()
  1260. {
  1261.     if (Verbose>1)
  1262. #ifdef OS9
  1263. #ifdef m6809
  1264.         fprintf(stderr, "\r\t%7ld ZMODEM%s    ",
  1265.           rxbytes, Crc32r?" CRC-32":"");
  1266. #else
  1267.         fprintf(stderr, "\r\x1b\x5b A%7ld ZMODEM%s    ",
  1268.           rxbytes, Crc32r?" CRC-32":"");
  1269. #endif
  1270. #else
  1271.         fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1272.           rxbytes, Crc32r?" CRC-32":"");
  1273. #endif
  1274. }
  1275. /*
  1276.  * Receive a file with ZMODEM protocol
  1277.  *  Assumes file name frame is in secbuf
  1278.  */
  1279. rzfile()
  1280. {
  1281.     register c, n;
  1282.  
  1283.     Eofseen=FALSE;
  1284.     n = 20; rxbytes = 0l;
  1285.  
  1286.     if (c = procheader(secbuf)) {
  1287.         return (tryzhdrtype = c);
  1288.     }
  1289.  
  1290.     for (;;) {
  1291. #ifdef SEGMENTS
  1292.         chinseg = 0;
  1293. #endif
  1294.         stohdr(rxbytes);
  1295.         zshhdr(4,ZRPOS, Txhdr);
  1296. nxthdr:
  1297.         switch (c = zgethdr(Rxhdr, 0)) {
  1298.         default:
  1299.             vfile("rzfile: Wrong header %d", c);
  1300.             if ( --n < 0) {
  1301.                 sprintf(endmsg, "rzfile: Wrong header %d", c);
  1302.                 return ERROR;
  1303.             }
  1304.             continue;
  1305.         case ZCAN:
  1306.             sprintf(endmsg, "Sender CANcelled");
  1307.             return ERROR;
  1308.         case ZNAK:
  1309. #ifdef SEGMENTS
  1310.             putsec(secbuf, chinseg);
  1311.             chinseg = 0;
  1312. #endif
  1313.             if ( --n < 0) {
  1314.                 sprintf(endmsg, "rzfile: got ZNAK", c);
  1315.                 return ERROR;
  1316.             }
  1317.             continue;
  1318.         case TIMEOUT:
  1319. #ifdef SEGMENTS
  1320.             putsec(secbuf, chinseg);
  1321.             chinseg = 0;
  1322. #endif
  1323.             if ( --n < 0) {
  1324.                 sprintf(endmsg, "rzfile: TIMEOUT", c);
  1325.                 return ERROR;
  1326.             }
  1327.             continue;
  1328.         case ZFILE:
  1329.             zrdata(secbuf, 1024);
  1330.             continue;
  1331.         case ZEOF:
  1332. #ifdef SEGMENTS
  1333.             putsec(secbuf, chinseg);
  1334.             chinseg = 0;
  1335. #endif
  1336.             if (rclhdr(Rxhdr) != rxbytes) {
  1337.                 /*
  1338.                  * Ignore eof if it's at wrong place - force
  1339.                  *  a timeout because the eof might have gone
  1340.                  *  out before we sent our zrpos.
  1341.                  */
  1342.                 errors = 0;  goto nxthdr;
  1343.             }
  1344.             if (closeit()) {
  1345.                 tryzhdrtype = ZFERR;
  1346.                 vfile("rzfile: closeit returned <> 0");
  1347.                 sprintf(endmsg,"Error closing file");
  1348.                 return ERROR;
  1349.             }
  1350.             vfile("rzfile: normal EOF");
  1351.             return c;
  1352.         case ERROR:    /* Too much garbage in header search error */
  1353. #ifdef SEGMENTS
  1354.             putsec(secbuf, chinseg);
  1355.             chinseg = 0;
  1356. #endif
  1357.             if ( --n < 0) {
  1358.                 sprintf(endmsg, "Persistent CRC or other ERROR");
  1359.                 return ERROR;
  1360.             }
  1361.             zmputs(Attn);
  1362.             continue;
  1363.         case ZSKIP:
  1364. #ifdef SEGMENTS
  1365.             putsec(secbuf, chinseg);
  1366.             chinseg = 0;
  1367. #endif
  1368.             Modtime = 1;
  1369.             closeit();
  1370.             sprintf(endmsg, "Sender SKIPPED file");
  1371.             return c;
  1372.         case ZDATA:
  1373.             if (rclhdr(Rxhdr) != rxbytes) {
  1374.                 if ( --n < 0) {
  1375.                     sprintf(endmsg,"Data has bad addr");
  1376.                     return ERROR;
  1377.                 }
  1378. #ifdef SEGMENTS
  1379.                 putsec(secbuf, chinseg);
  1380.                 chinseg = 0;
  1381. #endif
  1382.                 zmputs(Attn);  continue;
  1383.             }
  1384. moredata:
  1385. #ifdef SEGMENTS
  1386.             if (chinseg >= (1024 * SEGMENTS)) {
  1387.                 putsec(secbuf, chinseg);
  1388.                 chinseg = 0;
  1389.             }
  1390.             switch (c = zrdata(secbuf+chinseg, 1024))
  1391. #else
  1392.             switch (c = zrdata(secbuf, 1024))
  1393. #endif
  1394.             {
  1395.             case ZCAN:
  1396. #ifdef SEGMENTS
  1397.                 putsec(secbuf, chinseg);
  1398.                 chinseg = 0;
  1399. #endif
  1400.                 sprintf(endmsg, "Sender CANcelled");
  1401.                 return ERROR;
  1402.             case ERROR:    /* CRC error */
  1403. #ifdef SEGMENTS
  1404.                 putsec(secbuf, chinseg);
  1405.                 chinseg = 0;
  1406. #endif
  1407.                 if ( --n < 0) {
  1408.                     sprintf(endmsg, "Persistent CRC or other ERROR");
  1409.                     return ERROR;
  1410.                 }
  1411.                 zmputs(Attn);
  1412.                 continue;
  1413.             case TIMEOUT:
  1414. #ifdef SEGMENTS
  1415.                 putsec(secbuf, chinseg);
  1416.                 chinseg = 0;
  1417. #endif
  1418.                 if ( --n < 0) {
  1419.                     sprintf(endmsg, "TIMEOUT");
  1420.                     return ERROR;
  1421.                 }
  1422.                 continue;
  1423.             case GOTCRCW:
  1424.                 n = 20;
  1425. #ifdef SEGMENTS
  1426.                 chinseg += Rxcount;
  1427.                 putsec(secbuf, chinseg);
  1428.                 chinseg = 0;
  1429. #else
  1430.                 putsec(secbuf, Rxcount);
  1431. #endif
  1432.                 rxbytes += Rxcount;
  1433.                 rpt();
  1434.                 stohdr(rxbytes);
  1435.                 sendline(XON);
  1436.                 zshhdr(4,ZACK, Txhdr);
  1437.                 goto nxthdr;
  1438.             case GOTCRCQ:
  1439.                 n = 20;
  1440. #ifdef SEGMENTS
  1441.                 chinseg += Rxcount;
  1442. #else
  1443.                 putsec(secbuf, Rxcount);
  1444. #endif
  1445.                 rxbytes += Rxcount;
  1446.                 rpt();
  1447.                 stohdr(rxbytes);
  1448.                 zshhdr(4,ZACK, Txhdr);
  1449.                 goto moredata;
  1450.             case GOTCRCG:
  1451.                 n = 20;
  1452. #ifdef SEGMENTS
  1453.                 chinseg += Rxcount;
  1454. #else
  1455.                 putsec(secbuf, Rxcount);
  1456. #endif
  1457.                 rxbytes += Rxcount;
  1458.                 rpt();
  1459.                 goto moredata;
  1460.             case GOTCRCE:
  1461.                 n = 20;
  1462. #ifdef SEGMENTS
  1463.                 chinseg += Rxcount;
  1464. #else
  1465.                 putsec(secbuf, Rxcount);
  1466. #endif
  1467.                 rxbytes += Rxcount;
  1468.                 rpt();
  1469.                 goto nxthdr;
  1470.             }
  1471.         }
  1472.     }
  1473. }
  1474.  
  1475.  
  1476. /*
  1477.  * Close the receive dataset, return OK or ERROR
  1478.  */
  1479. closeit()
  1480. {
  1481. #ifdef OS9
  1482.     long time();
  1483.  
  1484.     fflush(fout);
  1485.     if (Filemode & 0777)
  1486.         _ss_attr(fileno(fout), u2oattr(Filemode));
  1487. #else
  1488.     time_t time();
  1489. #endif
  1490.  
  1491.     if (fclose(fout)==ERROR) {
  1492.         fprintf(stderr, "file close ERROR\n");
  1493.         return ERROR;
  1494.     }
  1495.     if (Modtime) {
  1496.         timep[0] = time(NULL);
  1497.         timep[1] = Modtime;
  1498.         utime(Pathname, timep);
  1499.     }
  1500. #ifndef OS9
  1501.     if (
  1502. #ifdef POSIX
  1503.     S_ISREG(Filemode)
  1504. #else
  1505.     (Filemode&S_IFMT) == S_IFREG
  1506. #endif
  1507.     )
  1508.         chmod(Pathname, (unsigned short)(07777 & Filemode));
  1509. #endif
  1510.     return OK;
  1511. }
  1512.  
  1513.  
  1514. /*
  1515.  * Strip leading ! if present, do shell escape. 
  1516.  */
  1517. sys2(s)
  1518. register char *s;
  1519. {
  1520.     if (*s == '!')
  1521.         ++s;
  1522.     return system(s);
  1523. }
  1524. /*
  1525.  * Strip leading ! if present, do exec.
  1526.  */
  1527. exec2(s)
  1528. register char *s;
  1529. {
  1530.     if (*s == '!')
  1531.         ++s;
  1532.     mode(0);
  1533. #ifdef OS9
  1534.     system(s);
  1535. #else
  1536.     execl("/bin/sh", "sh", "-c", s);
  1537. #endif
  1538. }
  1539.  
  1540. /* End of rz.c */
  1541.