home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / utility / unixtool / unixrzsz / rz.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-14  |  34.1 KB  |  1,699 lines

  1. #define VERSION "2.03 05-17-88"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -compat -M2 -Ox -K -i -DMD -DOMEN % -o rz; size rz;
  5. <-xtx-*> cc386 -Ox -DMD -DOMEN -DSEGMENTS=8 rz.c -o $B/rz;  size $B/rz
  6.  *
  7.  * rz.c By Chuck Forsberg
  8.  *
  9.  *    cc -O rz.c -o rz        USG (3.0) Unix
  10.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  11.  *
  12.  *    ln rz rb;  ln rz rx            For either system
  13.  *
  14.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  15.  *                    login shell. rzrmail then calls
  16.  *                    rmail(1) to deliver mail.
  17.  *
  18.  * To compile on VMS:
  19.  *
  20.  *    define LNK$LIBRARY   SYS$LIBRARY:VAXCRTL.OLB
  21.  *    cc rz.c
  22.  *    cc vvmodem.c
  23.  *    link rz,vvmodem
  24.  *    rz :== $disk:[username.subdir]rz.exe
  25.  *
  26.  *
  27.  *  Unix is a trademark of Western Electric Company
  28.  *
  29.  * A program for Unix to receive files and commands from computers running
  30.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  31.  *  rz uses Unix buffered input to reduce wasted CPU time.
  32.  *
  33.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  34.  * "COMMAND filename"  (Unix only)
  35.  *
  36.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  37.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  38.  *  character reads for these systems. Added 7-01-84 CAF
  39.  *
  40.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  41.  *
  42.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  43.  *  Byte Information Exchange.
  44.  *
  45.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  46.  *  doesn't work properly (even though it compiles without error!),
  47.  *
  48.  *  SEGMENTS=n added 2-21-88 as a model for CP/M programs
  49.  *    for CP/M-80 systems that cannot overlap modem and disk I/O.
  50.  *
  51.  *  VMS flavor hacks begin with rz version 2.00
  52.  *
  53.  *  -DMD may be added to compiler command line to compile in
  54.  *    Directory-creating routines from Public Domain TAR by John Gilmore
  55.  *
  56.  *  HOWMANY may be tuned for best performance
  57.  *
  58.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  59.  */
  60.  
  61. #ifdef vax11c
  62. #include <types.h>
  63. #include <stat.h>
  64. #define LOGFILE "rzlog.tmp"
  65. #include <stdio.h>
  66. #include <signal.h>
  67. #include <setjmp.h>
  68. #include <ctype.h>
  69. #include <errno.h>
  70. #define OS "VMS"
  71. #define BUFREAD
  72. extern int errno;
  73. #define SS_NORMAL SS$_NORMAL
  74. #else
  75. #define SS_NORMAL 0
  76. #define LOGFILE "/tmp/rzlog"
  77. #include <stdio.h>
  78. #include <signal.h>
  79. #include <setjmp.h>
  80. #include <ctype.h>
  81. #include <errno.h>
  82. extern int errno;
  83. FILE *popen();
  84. #endif
  85.  
  86. #define OK 0
  87. #define FALSE 0
  88. #define TRUE 1
  89. #undef ERROR
  90. #define ERROR (-1)
  91.  
  92. /*
  93.  * Max value for HOWMANY is 255.
  94.  *   A larger value reduces system overhead but may evoke kernel bugs.
  95.  *   133 corresponds to an XMODEM/CRC sector
  96.  */
  97. #ifndef HOWMANY
  98. #define HOWMANY 133
  99. #endif
  100.  
  101. /* Ward Christensen / CP/M parameters - Don't change these! */
  102. #define ENQ 005
  103. #define CAN ('X'&037)
  104. #define XOFF ('s'&037)
  105. #define XON ('q'&037)
  106. #define SOH 1
  107. #define STX 2
  108. #define EOT 4
  109. #define ACK 6
  110. #define NAK 025
  111. #define CPMEOF 032
  112. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  113. #define TIMEOUT (-2)
  114. #define RCDO (-3)
  115. #define ERRORMAX 5
  116. #define RETRYMAX 5
  117. #define WCEOT (-10)
  118. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  119. #define UNIXFILE 0xF000    /* The S_IFMT file mask bit for stat */
  120.  
  121. int Zmodem=0;        /* ZMODEM protocol requested */
  122. int Nozmodem = 0;    /* If invoked as "rb" */
  123. unsigned Baudrate = 2400;
  124. #ifdef vax11c
  125. #include "vrzsz.c"    /* most of the system dependent stuff here */
  126. #else
  127. #include "rbsb.c"    /* most of the system dependent stuff here */
  128. #endif
  129. #include "crctab.c"
  130.  
  131. char *substr();
  132. FILE *fout;
  133.  
  134. /*
  135.  * Routine to calculate the free bytes on the current file system
  136.  *  ~0 means many free bytes (unknown)
  137.  */
  138. long getfree()
  139. {
  140.     return(~0L);    /* many free bytes ... */
  141. }
  142.  
  143. int Lastrx;
  144. int Crcflg;
  145. int Firstsec;
  146. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  147. int errors;
  148. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  149. #ifdef ONEREAD
  150. /* Sorry, Regulus and some others don't work right in raw mode! */
  151. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  152. #else
  153. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  154. #endif
  155.  
  156. #define DEFBYTL 2000000000L    /* default rx file size */
  157. long Bytesleft;        /* number of bytes of incoming file left */
  158. long Modtime;        /* Unix style mod time for incoming file */
  159. int Filemode;        /* Unix style mode for incoming file */
  160. char Pathname[PATHLEN];
  161. char *Progname;        /* the name by which we were called */
  162.  
  163. int Batch=0;
  164. int Topipe=0;
  165. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  166. int Verbose=0;
  167. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  168. int Nflag = 0;        /* Don't really transfer files */
  169. int Rxclob=TRUE;    /* Clobber existing file */
  170. int Rxbinary=FALSE;    /* receive all files in bin mode */
  171. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  172. int Thisbinary;        /* current file is to be received in bin mode */
  173. int Blklen;        /* record length of received packets */
  174.  
  175. #ifdef SEGMENTS
  176. int chinseg = 0;    /* Number of characters received in this data seg */
  177. char secbuf[1+(SEGMENTS+1)*1024];
  178. #else
  179. char secbuf[1025];
  180. #endif
  181.  
  182.  
  183. char linbuf[HOWMANY];
  184. int Lleft=0;        /* number of characters in linbuf */
  185. time_t timep[2];
  186. char Lzmanag;        /* Local file management request */
  187. char zconv;        /* ZMODEM file conversion request */
  188. char zmanag;        /* ZMODEM file management request */
  189. char ztrans;        /* ZMODEM file transport request */
  190. int Zctlesc;        /* Encode control characters */
  191. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  192.  
  193. jmp_buf tohere;        /* For the interrupt on RX timeout */
  194.  
  195. #define xsendline(c) sendline(c)
  196. #include "zm.c"
  197.  
  198. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  199.  
  200. #ifdef CWRU
  201. char myfilebuf[16384];
  202. #endif
  203.  
  204. alrm()
  205. {
  206.     longjmp(tohere, -1);
  207. }
  208.  
  209. /* called by signal interrupt or terminate to clean things up */
  210. bibi(n)
  211. {
  212.     if (Zmodem)
  213.         zmputs(Attn);
  214.     canit(); mode(0);
  215.     fprintf(stderr, "rz: caught signal %d; exiting\n", n);
  216.     cucheck();
  217.     exit(128+n);
  218. }
  219.  
  220. main(argc, argv)
  221. char *argv[];
  222. {
  223.     register char *cp;
  224.     register npats;
  225.     char *virgin, **patts;
  226.     char *getenv();
  227.     int exitcode = 0;
  228.  
  229.     Rxtimeout = 100;
  230.     setbuf(stderr, NULL);
  231.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  232.         Restricted=TRUE;
  233.  
  234.     from_cu();
  235. #ifdef vax11c
  236.     Progname = virgin = "rz";
  237. #else
  238.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  239. #endif
  240.     npats = 0;
  241.     while (--argc) {
  242.         cp = *++argv;
  243.         if (*cp == '-') {
  244.             while( *++cp) {
  245.                 switch(*cp) {
  246.                 case '\\':
  247.                      cp[1] = toupper(cp[1]);  continue;
  248.                 case '+':
  249.                     Lzmanag = ZMAPND; break;
  250.                 case 'a':
  251.                     Rxascii=TRUE;  break;
  252.                 case 'b':
  253.                     Rxbinary=TRUE; break;
  254.                 case 'c':
  255.                     Crcflg=TRUE; break;
  256. #ifndef vax11c
  257.                 case 'D':
  258.                     Nflag = TRUE; break;
  259. #endif
  260.                 case 'e':
  261.                     Zctlesc = 1; break;
  262.                 case 'p':
  263.                     Lzmanag = ZMPROT;  break;
  264.                 case 'q':
  265.                     Quiet=TRUE; Verbose=0; break;
  266.                 case 't':
  267.                     if (--argc < 1) {
  268.                         usage();
  269.                     }
  270.                     Rxtimeout = atoi(*++argv);
  271.                     if (Rxtimeout<10 || Rxtimeout>1000)
  272.                         usage();
  273.                     break;
  274.                 case 'w':
  275.                     if (--argc < 1) {
  276.                         usage();
  277.                     }
  278.                     Zrwindow = atoi(*++argv);
  279.                     break;
  280.                 case 'u':
  281.                     MakeLCPathname=FALSE; break;
  282.                 case 'v':
  283.                     ++Verbose; break;
  284.                 case 'y':
  285.                     Rxclob=FALSE; break;
  286.                 default:
  287.                     usage();
  288.                 }
  289.             }
  290.         }
  291.         else if ( !npats && argc>0) {
  292.             if (argv[0][0]) {
  293.                 npats=argc;
  294.                 patts=argv;
  295.             }
  296.         }
  297.     }
  298.     if (npats > 1)
  299.         usage();
  300.     if (Batch && npats)
  301.         usage();
  302.     if (Verbose) {
  303.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  304.             printf("Can't open log file %s\n",LOGFILE);
  305.             exit(0200);
  306.         }
  307.         setbuf(stderr, NULL);
  308.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  309.     }
  310.     if (Fromcu && !Quiet) {
  311.         if (Verbose == 0)
  312.             Verbose = 2;
  313.     }
  314.     vfile("%s %s for %s\n", Progname, VERSION, OS);
  315.     mode(1);
  316.     if (signal(SIGINT, bibi) == SIG_IGN) {
  317.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  318.     }
  319.     else {
  320.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  321.     }
  322.     signal(SIGTERM, bibi);
  323.     if (wcreceive(npats, patts)==ERROR) {
  324.         exitcode=0200;
  325.         canit();
  326.     }
  327.     mode(0);
  328.     vfile("exitcode = %d\n",exitcode);
  329.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  330.         canit();
  331.     if (exitcode)
  332.         cucheck();
  333.     if (Verbose) putc('\n', stderr);
  334.     exit(exitcode ? exitcode:SS_NORMAL);
  335. }
  336.  
  337.  
  338. usage()
  339. {
  340.     cucheck();
  341. #ifdef vax11c
  342.     fprintf(stderr,"Usage:    rz [-abeuvy]\n");
  343. #else
  344.     fprintf(stderr,"Usage:    rz [-abeuvy]        (ZMODEM)\n");
  345.     fprintf(stderr,"or    rb [-abuvy]        (YMODEM)\n");
  346.     fprintf(stderr,"or    rx [-abcv] file    (XMODEM or XMODEM-1k)\n");
  347. #endif
  348.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  349.     fprintf(stderr,"      -b Binary transfer for all files\n");
  350. #ifndef vax11c
  351.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  352. #endif
  353.     fprintf(stderr,"      -e Escape control characters    (ZMODEM)\n");
  354.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  355.     fprintf(stderr,"      -y Yes, clobber existing file if any\n");
  356.     fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  357.       Progname, VERSION, OS);
  358.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
  359.     exit(SS_NORMAL);
  360. }
  361. /*
  362.  *  Debugging information output interface routine
  363.  */
  364. /* VARARGS1 */
  365. vfile(f, a, b, c)
  366. register char *f,*a,*b,*c;
  367.  
  368. {
  369.     if (Verbose > 2) {
  370.         fprintf(stderr, f, a, b, c);
  371.         fprintf(stderr, "\n");
  372.     }
  373. }
  374.  
  375. /*
  376.  * Let's receive something already.
  377.  */
  378.  
  379. char *rbmsg =
  380. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
  381.  
  382. wcreceive(argc, argp)
  383. char **argp;
  384. {
  385.     register c;
  386.  
  387.     if (Batch || argc==0) {
  388.         Crcflg=1;
  389.         if ( !Quiet)
  390.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  391.         if (c=tryz()) {
  392.             if (c == ZCOMPL)
  393.                 return OK;
  394.             if (c == ERROR)
  395.                 goto fubar;
  396.             c = rzfiles();
  397.             if (c)
  398.                 goto fubar;
  399.         } else {
  400.             for (;;) {
  401.                 if (wcrxpn(secbuf)== ERROR)
  402.                     goto fubar;
  403.                 if (secbuf[0]==0)
  404.                     return OK;
  405.                 if (procheader(secbuf) == ERROR)
  406.                     goto fubar;
  407.                 if (wcrx()==ERROR)
  408.                     goto fubar;
  409.             }
  410.         }
  411.     } else {
  412.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  413.         Thisbinary = Rxbinary;
  414.  
  415.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  416. #ifdef CWRU
  417.         if(Verbose)
  418.             fprintf(stderr, "\nrz: ready to receive %s [%s mode]\r\n",
  419.              Pathname, Thisbinary?"BIN":"ASCII");
  420. #else
  421.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  422. #endif
  423.         if ((fout=fopen(Pathname, "w")) == NULL)
  424.             return ERROR;
  425. #ifdef CWRU
  426.          setbuffer(fout, myfilebuf, sizeof(myfilebuf));
  427. #endif
  428.         if (wcrx()==ERROR)
  429.             goto fubar;
  430.     }
  431.     return OK;
  432. fubar:
  433.     canit();
  434. #ifndef vax11c
  435.     if (Topipe && fout) {
  436.         pclose(fout);  return ERROR;
  437.     }
  438. #endif
  439.     if (fout)
  440.         fclose(fout);
  441. #ifndef vax11c
  442.     if (Restricted) {
  443.         unlink(Pathname);
  444.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  445.     }
  446. #endif
  447.     return ERROR;
  448. }
  449.  
  450.  
  451. /*
  452.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  453.  * Length is indeterminate as long as less than Blklen
  454.  * A null string represents no more files (YMODEM)
  455.  */
  456. wcrxpn(rpn)
  457. char *rpn;    /* receive a pathname */
  458. {
  459.     register c;
  460.  
  461. #ifdef NFGVMIN
  462.     readline(1);
  463. #else
  464.     purgeline();
  465. #endif
  466.  
  467. et_tu:
  468.     Firstsec=TRUE;  Eofseen=FALSE;
  469.     sendline(Crcflg?WANTCRC:NAK);
  470.     Lleft=0;    /* Do read next time ... */
  471.     while ((c = wcgetsec(rpn, 100)) != 0) {
  472.         if (c == WCEOT) {
  473.             zperr( "Pathname fetch returned %d", c);
  474.             sendline(ACK);
  475.             Lleft=0;    /* Do read next time ... */
  476.             readline(1);
  477.             goto et_tu;
  478.         }
  479.         return ERROR;
  480.     }
  481.     sendline(ACK);
  482.     return OK;
  483. }
  484.  
  485. /*
  486.  * Adapted from CMODEM13.C, written by
  487.  * Jack M. Wierda and Roderick W. Hart
  488.  */
  489.  
  490. wcrx()
  491. {
  492.     register int sectnum, sectcurr;
  493.     register char sendchar;
  494.     register char *p;
  495.     int cblklen;            /* bytes to dump this block */
  496.  
  497.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  498.     sendchar=Crcflg?WANTCRC:NAK;
  499.  
  500.     for (;;) {
  501.         sendline(sendchar);    /* send it now, we're ready! */
  502.         Lleft=0;    /* Do read next time ... */
  503.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  504.         report(sectcurr);
  505.         if (sectcurr==(sectnum+1 &0377)) {
  506.             sectnum++;
  507.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  508.             if (putsec(secbuf, cblklen)==ERROR)
  509.                 return ERROR;
  510.             if ((Bytesleft-=cblklen) < 0)
  511.                 Bytesleft = 0;
  512.             sendchar=ACK;
  513.         }
  514.         else if (sectcurr==(sectnum&0377)) {
  515.             zperr( "Received dup Sector");
  516.             sendchar=ACK;
  517.         }
  518.         else if (sectcurr==WCEOT) {
  519.             if (closeit())
  520.                 return ERROR;
  521.             sendline(ACK);
  522.             Lleft=0;    /* Do read next time ... */
  523.             return OK;
  524.         }
  525.         else if (sectcurr==ERROR)
  526.             return ERROR;
  527.         else {
  528.             zperr( "Sync Error");
  529.             return ERROR;
  530.         }
  531.     }
  532. }
  533.  
  534. /*
  535.  * Wcgetsec fetches a Ward Christensen type sector.
  536.  * Returns sector number encountered or ERROR if valid sector not received,
  537.  * or CAN CAN received
  538.  * or WCEOT if eot sector
  539.  * time is timeout for first char, set to 4 seconds thereafter
  540.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  541.  *    (Caller must do that when he is good and ready to get next sector)
  542.  */
  543.  
  544. wcgetsec(rxbuf, maxtime)
  545. char *rxbuf;
  546. int maxtime;
  547. {
  548.     register checksum, wcj, firstch;
  549.     register unsigned short oldcrc;
  550.     register char *p;
  551.     int sectcurr;
  552.  
  553.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  554.  
  555.         if ((firstch=readline(maxtime))==STX) {
  556.             Blklen=1024; goto get2;
  557.         }
  558.         if (firstch==SOH) {
  559.             Blklen=128;
  560. get2:
  561.             sectcurr=readline(1);
  562.             if ((sectcurr+(oldcrc=readline(1)))==0377) {
  563.                 oldcrc=checksum=0;
  564.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  565.                     if ((firstch=readline(1)) < 0)
  566.                         goto bilge;
  567.                     oldcrc=updcrc(firstch, oldcrc);
  568.                     checksum += (*p++ = firstch);
  569.                 }
  570.                 if ((firstch=readline(1)) < 0)
  571.                     goto bilge;
  572.                 if (Crcflg) {
  573.                     oldcrc=updcrc(firstch, oldcrc);
  574.                     if ((firstch=readline(1)) < 0)
  575.                         goto bilge;
  576.                     oldcrc=updcrc(firstch, oldcrc);
  577.                     if (oldcrc & 0xFFFF)
  578.                         zperr( "CRC");
  579.                     else {
  580.                         Firstsec=FALSE;
  581.                         return sectcurr;
  582.                     }
  583.                 }
  584.                 else if (((checksum-firstch)&0377)==0) {
  585.                     Firstsec=FALSE;
  586.                     return sectcurr;
  587.                 }
  588.                 else
  589.                     zperr( "Checksum");
  590.             }
  591.             else
  592.                 zperr("Sector number garbled");
  593.         }
  594.         /* make sure eot really is eot and not just mixmash */
  595. #ifdef NFGVMIN
  596.         else if (firstch==EOT && readline(1)==TIMEOUT)
  597.             return WCEOT;
  598. #else
  599.         else if (firstch==EOT && Lleft==0)
  600.             return WCEOT;
  601. #endif
  602.         else if (firstch==CAN) {
  603.             if (Lastrx==CAN) {
  604.                 zperr( "Sender CANcelled");
  605.                 return ERROR;
  606.             } else {
  607.                 Lastrx=CAN;
  608.                 continue;
  609.             }
  610.         }
  611.         else if (firstch==TIMEOUT) {
  612.             if (Firstsec)
  613.                 goto humbug;
  614. bilge:
  615.             zperr( "TIMEOUT");
  616.         }
  617.         else
  618.             zperr( "Got 0%o sector header", firstch);
  619.  
  620. humbug:
  621.         Lastrx=0;
  622.         while(readline(1)!=TIMEOUT)
  623.             ;
  624.         if (Firstsec) {
  625.             sendline(Crcflg?WANTCRC:NAK);
  626.             Lleft=0;    /* Do read next time ... */
  627.         } else {
  628.             maxtime=40; sendline(NAK);
  629.             Lleft=0;    /* Do read next time ... */
  630.         }
  631.     }
  632.     /* try to stop the bubble machine. */
  633.     canit();
  634.     return ERROR;
  635. }
  636.  
  637. #ifndef vax11c
  638. /*
  639.  * This version of readline is reasoably well suited for
  640.  * reading many characters.
  641.  *  (except, currently, for the Regulus version!)
  642.  *
  643.  * timeout is in tenths of seconds
  644.  */
  645. readline(timeout)
  646. int timeout;
  647. {
  648.     register n;
  649.     static char *cdq;    /* pointer for removing chars from linbuf */
  650.  
  651.     if (--Lleft >= 0) {
  652.         if (Verbose > 8) {
  653.             fprintf(stderr, "%02x ", *cdq&0377);
  654.         }
  655.         return (*cdq++ & 0377);
  656.     }
  657.     n = timeout/10;
  658.     if (n < 2)
  659.         n = 3;
  660.     if (Verbose > 5)
  661.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  662.           n, Readnum);
  663.     if (setjmp(tohere)) {
  664. #ifdef TIOCFLUSH
  665. /*        ioctl(iofd, TIOCFLUSH, 0); */
  666. #endif
  667.         Lleft = 0;
  668.         if (Verbose>1)
  669.             fprintf(stderr, "Readline:TIMEOUT\n");
  670.         return TIMEOUT;
  671.     }
  672.     signal(SIGALRM, alrm); alarm(n);
  673.     Lleft=read(iofd, cdq=linbuf, Readnum);
  674.     alarm(0);
  675.     if (Verbose > 5) {
  676.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  677.     }
  678.     if (Lleft < 1)
  679.         return TIMEOUT;
  680.     --Lleft;
  681.     if (Verbose > 8) {
  682.         fprintf(stderr, "%02x ", *cdq&0377);
  683.     }
  684.     return (*cdq++ & 0377);
  685. }
  686.  
  687.  
  688.  
  689. /*
  690.  * Purge the modem input queue of all characters
  691.  */
  692. purgeline()
  693. {
  694.     Lleft = 0;
  695. #ifdef USG
  696.     ioctl(iofd, TCFLSH, 0);
  697. #else
  698.     lseek(iofd, 0L, 2);
  699. #endif
  700. }
  701. #endif
  702.  
  703.  
  704. /*
  705.  * Process incoming file information header
  706.  */
  707. procheader(name)
  708. char *name;
  709. {
  710.     register char *openmode, *p, **pp;
  711.  
  712.     /* set default parameters and overrides */
  713.     openmode = "w";
  714.     Thisbinary = (!Rxascii) || Rxbinary;
  715.     if (Lzmanag)
  716.         zmanag = Lzmanag;
  717.  
  718.     /*
  719.      *  Process ZMODEM remote file management requests
  720.      */
  721.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  722.         Thisbinary = 0;
  723.     if (zconv == ZCBIN)    /* Remote Binary override */
  724.         Thisbinary = TRUE;
  725.     else if (zmanag == ZMAPND)
  726.         openmode = "a";
  727.  
  728. #ifndef BIX
  729.     /* Check for existing file */
  730.     if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
  731.         fclose(fout);  return ERROR;
  732.     }
  733. #endif
  734.  
  735. #ifdef CWRU
  736. #ifdef MD
  737. #undef MD    /* do it our way */
  738. #endif
  739. /* CWRU NOTE:
  740.  *    We will not accept rooted paths ie. paths that begin in '/' or './'
  741.  *    If the incoming filename is rooted, we skip the beginning
  742.  *    '/'   './'  or  '../'. If you want to allow rooted paths just
  743.  *    remove the next block. NOTE that the code does not handle
  744.  *    the '../../foo' case, which is unlikely to occur as normally
  745.  *    you would be sending (with -f) from using something like
  746.  *    sz -f foo/* or similar reg. expressions.
  747.  */
  748.  
  749.     if( (name[0] == '/') || (name[0] == '.')  )
  750.     {
  751.         /* skip over the leading stuff */
  752.         if(name[0] == '/')
  753.             name = &name[1];
  754.         else
  755.         {
  756.             if((name[1] == '.') && (name[2] == '/'))
  757.                 name = &name[3];  /* Skip the "../" */
  758.             else
  759.                 if(name[1] == '/')
  760.                 name = &name[2];  /* Skip the "./"  */
  761.         }
  762.     }
  763.  
  764.      /* CWRU addition, create any dierctories in the path that don't exist */
  765.     if( pathensure(name) == ERROR)
  766.         return ERROR;
  767. #endif
  768.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  769.  
  770.     p = name + 1 + strlen(name);
  771.     if (*p) {    /* file coming from Unix or DOS system */
  772.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  773. #ifndef vax11c
  774.         if (Filemode & UNIXFILE)
  775.             ++Thisbinary;
  776. #endif
  777.         if (Verbose) {
  778.             fprintf(stderr,  "\nIncoming: %s %ld %lo %o\n",
  779.               name, Bytesleft, Modtime, Filemode);
  780.         }
  781.     }
  782.  
  783. #ifdef BIX
  784.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  785.         return ERROR;
  786.     return OK;
  787. #else
  788.  
  789.     else {        /* File coming from CP/M system */
  790.         for (p=name; *p; ++p)        /* change / to _ */
  791.             if ( *p == '/')
  792.                 *p = '_';
  793.  
  794.         if ( *--p == '.')        /* zap trailing period */
  795.             *p = 0;
  796.     }
  797.  
  798. #ifndef vax11c
  799.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
  800.       && !(Filemode&UNIXFILE))
  801.         uncaps(name);
  802. #endif
  803.     if (Topipe > 0) {
  804.         sprintf(Pathname, "%s %s", Progname+2, name);
  805.         if (Verbose)
  806.             fprintf(stderr,  "Topipe: %s %s\n",
  807.               Pathname, Thisbinary?"BIN":"ASCII");
  808. #ifndef vax11c
  809.         if ((fout=popen(Pathname, "w")) == NULL)
  810.             return ERROR;
  811. #ifdef CWRU
  812.         setbuffer(fout, myfilebuf, sizeof(myfilebuf));
  813. #endif
  814. #endif
  815.     } else {
  816.         strcpy(Pathname, name);
  817.         if (Verbose) {
  818.             fprintf(stderr,  "Receiving %s %s %s\n",
  819.               name, Thisbinary?"BIN":"ASCII", openmode);
  820.         }
  821.         checkpath(name);
  822.         if (Nflag)
  823.             name = "/dev/null";
  824. #ifndef vax11c
  825. #ifdef OMEN
  826.         if (name[0] == '!' || name[0] == '|') {
  827.             if ( !(fout = popen(name+1, "w"))) {
  828.                 return ERROR;
  829.             }
  830.             Topipe = -1;  return(OK);
  831.         }
  832. #endif
  833. #endif
  834.  
  835. #ifdef MD
  836.         fout = fopen(name, openmode);
  837.         if ( !fout)
  838.             if (make_dirs(name))
  839.                 fout = fopen(name, openmode);
  840. #else
  841.         fout = fopen(name, openmode);
  842. #endif
  843.         if ( !fout)
  844.             return ERROR;
  845.     }
  846.     return OK;
  847. #endif /* BIX */
  848. }
  849.  
  850. #ifdef MD
  851. /*
  852.  *  Directory-creating routines from Public Domain TAR by John Gilmore
  853.  */
  854.  
  855. /*
  856.  * After a file/link/symlink/dir creation has failed, see if
  857.  * it's because some required directory was not present, and if
  858.  * so, create all required dirs.
  859.  */
  860. make_dirs(pathname)
  861. register char *pathname;
  862. {
  863.     register char *p;        /* Points into path */
  864.     int madeone = 0;        /* Did we do anything yet? */
  865.     int save_errno = errno;        /* Remember caller's errno */
  866.     char *strchr();
  867.  
  868.     if (errno != ENOENT)
  869.         return 0;        /* Not our problem */
  870.  
  871.     for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
  872.         /* Avoid mkdir of empty string, if leading or double '/' */
  873.         if (p == pathname || p[-1] == '/')
  874.             continue;
  875.         /* Avoid mkdir where last part of path is '.' */
  876.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  877.             continue;
  878.         *p = 0;                /* Truncate the path there */
  879.         if ( !mkdir(pathname, 0777)) {    /* Try to create it as a dir */
  880.             vfile("Made directory %s\n", pathname);
  881.             madeone++;        /* Remember if we made one */
  882.             *p = '/';
  883.             continue;
  884.         }
  885.         *p = '/';
  886.         if (errno == EEXIST)        /* Directory already exists */
  887.             continue;
  888.         /*
  889.          * Some other error in the mkdir.  We return to the caller.
  890.          */
  891.         break;
  892.     }
  893.     errno = save_errno;        /* Restore caller's errno */
  894.     return madeone;            /* Tell them to retry if we made one */
  895. }
  896.  
  897. #if (MD != 2)
  898. #define    TERM_SIGNAL(status)    ((status) & 0x7F)
  899. #define TERM_COREDUMP(status)    (((status) & 0x80) != 0)
  900. #define TERM_VALUE(status)    ((status) >> 8)
  901. /*
  902.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  903.  */
  904. mkdir(dpath, dmode)
  905. char *dpath;
  906. int dmode;
  907. {
  908.     int cpid, status;
  909.     struct stat statbuf;
  910.  
  911.     if (stat(dpath,&statbuf) == 0) {
  912.         errno = EEXIST;        /* Stat worked, so it already exists */
  913.         return -1;
  914.     }
  915.  
  916.     /* If stat fails for a reason other than non-existence, return error */
  917.     if (errno != ENOENT) return -1; 
  918.  
  919.     switch (cpid = fork()) {
  920.  
  921.     case -1:            /* Error in fork() */
  922.         return(-1);        /* Errno is set already */
  923.  
  924.     case 0:                /* Child process */
  925.         /*
  926.          * Cheap hack to set mode of new directory.  Since this
  927.          * child process is going away anyway, we zap its umask.
  928.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  929.          * directory.  Does anybody care?
  930.          */
  931.         status = umask(0);    /* Get current umask */
  932.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  933.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  934.         _exit(-1);        /* Can't exec /bin/mkdir */
  935.     
  936.     default:            /* Parent process */
  937.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  938.     }
  939.  
  940.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  941.         errno = EIO;        /* We don't know why, but */
  942.         return -1;        /* /bin/mkdir failed */
  943.     }
  944.  
  945.     return 0;
  946. }
  947. #endif /* MD != 2 */
  948. #endif /* MD */
  949.  
  950. /*
  951.  * Putsec writes the n characters of buf to receive file fout.
  952.  *  If not in binary mode, carriage returns, and all characters
  953.  *  starting with CPMEOF are discarded.
  954.  */
  955. putsec(buf, n)
  956. char *buf;
  957. register n;
  958. {
  959.     register char *p;
  960.  
  961.     if (n == 0)
  962.         return OK;
  963.     if (Thisbinary) {
  964.         for (p=buf; --n>=0; )
  965.             putc( *p++, fout);
  966.     }
  967.     else {
  968.         if (Eofseen)
  969.             return OK;
  970.         for (p=buf; --n>=0; ++p ) {
  971.             if ( *p == '\r')
  972.                 continue;
  973.             if (*p == CPMEOF) {
  974.                 Eofseen=TRUE; return OK;
  975.             }
  976.             putc(*p ,fout);
  977.         }
  978.     }
  979.     return OK;
  980. }
  981.  
  982. #ifndef vax11c
  983. /*
  984.  *  Send a character to modem.  Small is beautiful.
  985.  */
  986. sendline(c)
  987. {
  988.     char d;
  989.  
  990.     d = c;
  991.     if (Verbose>6)
  992.         fprintf(stderr, "Sendline: %x\n", c);
  993.     write(1, &d, 1);
  994. }
  995.  
  996. flushmo() {}
  997. #endif
  998.  
  999.  
  1000.  
  1001.  
  1002.  
  1003. /* make string s lower case */
  1004. uncaps(s)
  1005. register char *s;
  1006. {
  1007.     for ( ; *s; ++s)
  1008.         if (isupper(*s))
  1009.             *s = tolower(*s);
  1010. }
  1011. /*
  1012.  * IsAnyLower returns TRUE if string s has lower case letters.
  1013.  */
  1014. IsAnyLower(s)
  1015. register char *s;
  1016. {
  1017.     for ( ; *s; ++s)
  1018.         if (islower(*s))
  1019.             return TRUE;
  1020.     return FALSE;
  1021. }
  1022.  
  1023. /*
  1024.  * substr(string, token) searches for token in string s
  1025.  * returns pointer to token within string if found, NULL otherwise
  1026.  */
  1027. char *
  1028. substr(s, t)
  1029. register char *s,*t;
  1030. {
  1031.     register char *ss,*tt;
  1032.     /* search for first char of token */
  1033.     for (ss=s; *s; s++)
  1034.         if (*s == *t)
  1035.             /* compare token with substring */
  1036.             for (ss=s,tt=t; ;) {
  1037.                 if (*tt == 0)
  1038.                     return s;
  1039.                 if (*ss++ != *tt++)
  1040.                     break;
  1041.             }
  1042.     return NULL;
  1043. }
  1044.  
  1045. /*
  1046.  * Log an error
  1047.  */
  1048. /*VARARGS1*/
  1049. zperr(s,p,u)
  1050. char *s, *p, *u;
  1051. {
  1052.     if (Verbose <= 0)
  1053.         return;
  1054.     fprintf(stderr, "Retry %d: ", errors);
  1055.     fprintf(stderr, s, p, u);
  1056.     fprintf(stderr, "\n");
  1057. }
  1058.  
  1059. /* send cancel string to get the other end to shut up */
  1060. canit()
  1061. {
  1062.     static char canistr[] = {
  1063.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  1064.     };
  1065.  
  1066. #ifdef vax11c
  1067.     raw_wbuf(strlen(canistr), canistr);
  1068.     purgeline();
  1069. #else
  1070.     printf(canistr);
  1071.     Lleft=0;    /* Do read next time ... */
  1072.     fflush(stdout);
  1073. #endif
  1074. }
  1075.  
  1076.  
  1077. report(sct)
  1078. int sct;
  1079. {
  1080.     if (Verbose>1)
  1081.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  1082. }
  1083.  
  1084. #ifndef vax11c
  1085. /*
  1086.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  1087.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  1088.  * If called as rb use YMODEM protocol
  1089.  */
  1090. chkinvok(s)
  1091. char *s;
  1092. {
  1093.     register char *p;
  1094.  
  1095.     p = s;
  1096.     while (*p == '-')
  1097.         s = ++p;
  1098.     while (*p)
  1099.         if (*p++ == '/')
  1100.             s = p;
  1101.     if (*s == 'v') {
  1102.         Verbose=1; ++s;
  1103.     }
  1104.     Progname = s;
  1105.     if (s[0]=='r' && s[1]=='z')
  1106.         Batch = TRUE;
  1107.     if (s[0]=='r' && s[1]=='b')
  1108.         Batch = Nozmodem = TRUE;
  1109.     if (s[2] && s[0]=='r' && s[1]=='b')
  1110.         Topipe = 1;
  1111.     if (s[2] && s[0]=='r' && s[1]=='z')
  1112.         Topipe = 1;
  1113. }
  1114. #endif
  1115.  
  1116. /*
  1117.  * Totalitarian Communist pathname processing
  1118.  */
  1119. checkpath(name)
  1120. char *name;
  1121. {
  1122.     if (Restricted) {
  1123.         if (fopen(name, "r") != NULL) {
  1124.             canit();
  1125.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  1126.             bibi(-1);
  1127.         }
  1128.         /* restrict pathnames to current tree or uucppublic */
  1129.         if ( substr(name, "../")
  1130.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  1131.             canit();
  1132.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  1133.             bibi(-1);
  1134.         }
  1135.     }
  1136. }
  1137.  
  1138. /*
  1139.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  1140.  *  Handles ZSINIT frame
  1141.  *  Return ZFILE if Zmodem filename received, -1 on error,
  1142.  *   ZCOMPL if transaction finished,  else 0
  1143.  */
  1144. tryz()
  1145. {
  1146.     register c, n;
  1147.     register cmdzack1flg;
  1148.  
  1149.     if (Nozmodem)        /* Check for "rb" program name */
  1150.         return 0;
  1151.  
  1152.  
  1153.     for (n=Zmodem?15:5; --n>=0; ) {
  1154.         /* Set buffer length (0) and capability flags */
  1155. #ifdef SEGMENTS
  1156.         stohdr(SEGMENTS*1024L);
  1157. #else
  1158.         stohdr(0L);
  1159. #endif
  1160. #ifdef CANBREAK
  1161.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  1162. #else
  1163.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  1164. #endif
  1165.         if (Zctlesc)
  1166.             Txhdr[ZF0] |= TESCCTL;
  1167.         zshhdr(tryzhdrtype, Txhdr);
  1168.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  1169.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  1170. again:
  1171.         switch (zgethdr(Rxhdr, 0)) {
  1172.         case ZRQINIT:
  1173.             continue;
  1174.         case ZEOF:
  1175.             continue;
  1176.         case TIMEOUT:
  1177.             continue;
  1178.         case ZFILE:
  1179.             zconv = Rxhdr[ZF0];
  1180.             zmanag = Rxhdr[ZF1];
  1181.             ztrans = Rxhdr[ZF2];
  1182.             tryzhdrtype = ZRINIT;
  1183.             c = zrdata(secbuf, 1024);
  1184.             mode(3);
  1185.             if (c == GOTCRCW)
  1186.                 return ZFILE;
  1187.             zshhdr(ZNAK, Txhdr);
  1188.             goto again;
  1189.         case ZSINIT:
  1190.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  1191.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  1192.                 stohdr(1L);
  1193.                 zshhdr(ZACK, Txhdr);
  1194.                 goto again;
  1195.             }
  1196.             zshhdr(ZNAK, Txhdr);
  1197.             goto again;
  1198.         case ZFREECNT:
  1199.             stohdr(getfree());
  1200.             zshhdr(ZACK, Txhdr);
  1201.             goto again;
  1202.         case ZCOMMAND:
  1203. #ifdef vax11c
  1204.             return ERROR;
  1205. #else
  1206.             cmdzack1flg = Rxhdr[ZF0];
  1207.             if (zrdata(secbuf, 1024) == GOTCRCW) {
  1208.                 if (cmdzack1flg & ZCACK1)
  1209.                     stohdr(0L);
  1210.                 else
  1211.                     stohdr((long)sys2(secbuf));
  1212.                 purgeline();    /* dump impatient questions */
  1213.                 do {
  1214.                     zshhdr(ZCOMPL, Txhdr);
  1215.                 }
  1216.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  1217.                 ackbibi();
  1218.                 if (cmdzack1flg & ZCACK1)
  1219.                     exec2(secbuf);
  1220.                 return ZCOMPL;
  1221.             }
  1222.             zshhdr(ZNAK, Txhdr); goto again;
  1223. #endif
  1224.         case ZCOMPL:
  1225.             goto again;
  1226.         default:
  1227.             continue;
  1228.         case ZFIN:
  1229.             ackbibi(); return ZCOMPL;
  1230.         case ZCAN:
  1231.             return ERROR;
  1232.         }
  1233.     }
  1234.     return 0;
  1235. }
  1236.  
  1237. /*
  1238.  * Receive 1 or more files with ZMODEM protocol
  1239.  */
  1240. rzfiles()
  1241. {
  1242.     register c;
  1243.  
  1244.     for (;;) {
  1245.         switch (c = rzfile()) {
  1246.         case ZEOF:
  1247.         case ZSKIP:
  1248.             switch (tryz()) {
  1249.             case ZCOMPL:
  1250.                 return OK;
  1251.             default:
  1252.                 return ERROR;
  1253.             case ZFILE:
  1254.                 break;
  1255.             }
  1256.             continue;
  1257.         default:
  1258.             return c;
  1259.         case ERROR:
  1260.             return ERROR;
  1261.         }
  1262.     }
  1263. }
  1264.  
  1265. /*
  1266.  * Receive a file with ZMODEM protocol
  1267.  *  Assumes file name frame is in secbuf
  1268.  */
  1269. rzfile()
  1270. {
  1271.     register c, n;
  1272.     long rxbytes;
  1273.  
  1274.     Eofseen=FALSE;
  1275.     if (procheader(secbuf) == ERROR) {
  1276.         return (tryzhdrtype = ZSKIP);
  1277.     }
  1278.  
  1279.     n = 20; rxbytes = 0l;
  1280.  
  1281.     for (;;) {
  1282. #ifdef SEGMENTS
  1283.         chinseg = 0;
  1284. #endif
  1285.         stohdr(rxbytes);
  1286.         zshhdr(ZRPOS, Txhdr);
  1287. nxthdr:
  1288.         switch (c = zgethdr(Rxhdr, 0)) {
  1289.         default:
  1290.             vfile("rzfile: zgethdr returned %d", c);
  1291.             return ERROR;
  1292.         case ZNAK:
  1293.         case TIMEOUT:
  1294. #ifdef SEGMENTS
  1295.             putsec(secbuf, chinseg);
  1296.             chinseg = 0;
  1297. #endif
  1298.             if ( --n < 0) {
  1299.                 vfile("rzfile: zgethdr returned %d", c);
  1300.                 return ERROR;
  1301.             }
  1302.         case ZFILE:
  1303.             zrdata(secbuf, 1024);
  1304.             continue;
  1305.         case ZEOF:
  1306. #ifdef SEGMENTS
  1307.             putsec(secbuf, chinseg);
  1308.             chinseg = 0;
  1309. #endif
  1310.             if (rclhdr(Rxhdr) != rxbytes) {
  1311.                 /*
  1312.                  * Ignore eof if it's at wrong place - force
  1313.                  *  a timeout because the eof might have gone
  1314.                  *  out before we sent our zrpos.
  1315.                  */
  1316.                 errors = 0;  goto nxthdr;
  1317.             }
  1318.             if (closeit()) {
  1319.                 tryzhdrtype = ZFERR;
  1320.                 vfile("rzfile: closeit returned <> 0");
  1321.                 return ERROR;
  1322.             }
  1323.             vfile("rzfile: normal EOF");
  1324.             return c;
  1325.         case ERROR:    /* Too much garbage in header search error */
  1326. #ifdef SEGMENTS
  1327.             putsec(secbuf, chinseg);
  1328.             chinseg = 0;
  1329. #endif
  1330.             if ( --n < 0) {
  1331.                 vfile("rzfile: zgethdr returned %d", c);
  1332.                 return ERROR;
  1333.             }
  1334.             zmputs(Attn);
  1335.             continue;
  1336.         case ZSKIP:
  1337. #ifdef SEGMENTS
  1338.             putsec(secbuf, chinseg);
  1339.             chinseg = 0;
  1340. #endif
  1341.             closeit();
  1342.             vfile("rzfile: Sender SKIPPED file");
  1343.             return c;
  1344.         case ZDATA:
  1345.             if (rclhdr(Rxhdr) != rxbytes) {
  1346.                 if ( --n < 0) {
  1347.                     return ERROR;
  1348.                 }
  1349. #ifdef SEGMENTS
  1350.                 putsec(secbuf, chinseg);
  1351.                 chinseg = 0;
  1352. #endif
  1353.                 zmputs(Attn);  continue;
  1354.             }
  1355. moredata:
  1356.             if (Verbose>1)
  1357.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1358.                   rxbytes, Crc32?" CRC-32":"");
  1359. #ifdef SEGMENTS
  1360.             if (chinseg >= (1024 * SEGMENTS)) {
  1361.                 putsec(secbuf, chinseg);
  1362.                 chinseg = 0;
  1363.             }
  1364.             switch (c = zrdata(secbuf+chinseg, 1024))
  1365. #else
  1366.             switch (c = zrdata(secbuf, 1024))
  1367. #endif
  1368.             {
  1369.             case ZCAN:
  1370. #ifdef SEGMENTS
  1371.                 putsec(secbuf, chinseg);
  1372.                 chinseg = 0;
  1373. #endif
  1374.                 vfile("rzfile: zgethdr returned %d", c);
  1375.                 return ERROR;
  1376.             case ERROR:    /* CRC error */
  1377. #ifdef SEGMENTS
  1378.                 putsec(secbuf, chinseg);
  1379.                 chinseg = 0;
  1380. #endif
  1381.                 if ( --n < 0) {
  1382.                     vfile("rzfile: zgethdr returned %d", c);
  1383.                     return ERROR;
  1384.                 }
  1385.                 zmputs(Attn);
  1386.                 continue;
  1387.             case TIMEOUT:
  1388. #ifdef SEGMENTS
  1389.                 putsec(secbuf, chinseg);
  1390.                 chinseg = 0;
  1391. #endif
  1392.                 if ( --n < 0) {
  1393.                     vfile("rzfile: zgethdr returned %d", c);
  1394.                     return ERROR;
  1395.                 }
  1396.                 continue;
  1397.             case GOTCRCW:
  1398.                 n = 20;
  1399. #ifdef SEGMENTS
  1400.                 chinseg += Rxcount;
  1401.                 putsec(secbuf, chinseg);
  1402.                 chinseg = 0;
  1403. #else
  1404.                 putsec(secbuf, Rxcount);
  1405. #endif
  1406.                 rxbytes += Rxcount;
  1407.                 stohdr(rxbytes);
  1408.                 zshhdr(ZACK, Txhdr);
  1409.                 sendline(XON);
  1410.                 goto nxthdr;
  1411.             case GOTCRCQ:
  1412.                 n = 20;
  1413. #ifdef SEGMENTS
  1414.                 chinseg += Rxcount;
  1415. #else
  1416.                 putsec(secbuf, Rxcount);
  1417. #endif
  1418.                 rxbytes += Rxcount;
  1419.                 stohdr(rxbytes);
  1420.                 zshhdr(ZACK, Txhdr);
  1421.                 goto moredata;
  1422.             case GOTCRCG:
  1423.                 n = 20;
  1424. #ifdef SEGMENTS
  1425.                 chinseg += Rxcount;
  1426. #else
  1427.                 putsec(secbuf, Rxcount);
  1428. #endif
  1429.                 rxbytes += Rxcount;
  1430.                 goto moredata;
  1431.             case GOTCRCE:
  1432.                 n = 20;
  1433. #ifdef SEGMENTS
  1434.                 chinseg += Rxcount;
  1435. #else
  1436.                 putsec(secbuf, Rxcount);
  1437. #endif
  1438.                 rxbytes += Rxcount;
  1439.                 goto nxthdr;
  1440.             }
  1441.         }
  1442.     }
  1443. }
  1444.  
  1445. /*
  1446.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1447.  *   and \335 (break signal)
  1448.  */
  1449. zmputs(s)
  1450. char *s;
  1451. {
  1452.     register c;
  1453.  
  1454.     while (*s) {
  1455.         switch (c = *s++) {
  1456.         case '\336':
  1457.             sleep(1); continue;
  1458.         case '\335':
  1459.             sendbrk(); continue;
  1460.         default:
  1461.             sendline(c);
  1462.         }
  1463.     }
  1464. }
  1465.  
  1466. /*
  1467.  * Close the receive dataset, return OK or ERROR
  1468.  */
  1469. closeit()
  1470. {
  1471.     time_t time(), q;
  1472.  
  1473. #ifndef vax11c
  1474.     if (Topipe) {
  1475.         if (pclose(fout)) {
  1476.             return ERROR;
  1477.         }
  1478.         return OK;
  1479.     }
  1480. #endif
  1481.     if (fclose(fout)==ERROR) {
  1482.         fprintf(stderr, "file close ERROR\n");
  1483.         return ERROR;
  1484.     }
  1485. #ifndef vax11c
  1486.     if (Modtime) {
  1487.         timep[0] = time(&q);
  1488.         timep[1] = Modtime;
  1489.         utime(Pathname, timep);
  1490.     }
  1491. #endif
  1492.     if ((Filemode&S_IFMT) == S_IFREG)
  1493.         chmod(Pathname, (07777 & Filemode));
  1494.     return OK;
  1495. }
  1496.  
  1497. /*
  1498.  * Ack a ZFIN packet, let byegones be byegones
  1499.  */
  1500. ackbibi()
  1501. {
  1502.     register n;
  1503.  
  1504.     vfile("ackbibi:");
  1505.     Readnum = 1;
  1506.     stohdr(0L);
  1507.     for (n=3; --n>=0; ) {
  1508.         purgeline();
  1509.         zshhdr(ZFIN, Txhdr);
  1510.         switch (readline(100)) {
  1511.         case 'O':
  1512.             readline(1);    /* Discard 2nd 'O' */
  1513.             vfile("ackbibi complete");
  1514.             return;
  1515.         case RCDO:
  1516.             return;
  1517.         case TIMEOUT:
  1518.         default:
  1519.             break;
  1520.         }
  1521.     }
  1522. }
  1523.  
  1524.  
  1525.  
  1526. /*
  1527.  * Local console output simulation
  1528.  */
  1529. bttyout(c)
  1530. {
  1531.     if (Verbose || Fromcu)
  1532.         putc(c, stderr);
  1533. }
  1534.  
  1535. #ifndef vax11c
  1536. /*
  1537.  * Strip leading ! if present, do shell escape. 
  1538.  */
  1539. sys2(s)
  1540. register char *s;
  1541. {
  1542.     if (*s == '!')
  1543.         ++s;
  1544.     return system(s);
  1545. }
  1546. /*
  1547.  * Strip leading ! if present, do exec.
  1548.  */
  1549. exec2(s)
  1550. register char *s;
  1551. {
  1552.     if (*s == '!')
  1553.         ++s;
  1554.     mode(0);
  1555.     execl("/bin/sh", "sh", "-c", s);
  1556. }
  1557. #endif
  1558.  
  1559. #ifdef CWRU
  1560. /* CWRU enhancement- create all subdirectories as required
  1561.  * Author : jrbammi
  1562.  * tested on Unix 4.3BSD / SunOs 3.X, 4.X ONLY.
  1563.  */
  1564.  
  1565. #ifdef USG
  1566. #define index strchr
  1567. #endif
  1568.  
  1569. /* default directory creation mode, note that this is modified by
  1570.    umask */
  1571. #define DIRMODE 0755
  1572.  
  1573. /*
  1574.  * Ensure that each subdirectory in the pathname exists.
  1575.  * If one doesn'nt, make the rest of the directory
  1576.  * Returns ERROR if it has trouble creating a path
  1577.  *
  1578.  */
  1579. int pathensure(name)
  1580. char *name;
  1581. {
  1582.     extern char *index();
  1583.  
  1584.     if(index(name, '/') == (char *)NULL)
  1585.         /* nothing to check */
  1586.         return OK;
  1587.  
  1588.     return pathrest(name, (char *)NULL);
  1589. }
  1590.  
  1591. /*
  1592.  * check rest of the path recursively
  1593.  *
  1594.  */
  1595. int pathrest(name, prev)
  1596. char *name, *prev;
  1597. {
  1598.     char previous[256];
  1599.     char component[33];
  1600.     register char *p, *q, *r;
  1601.     register int i;
  1602.     extern char *index();
  1603.  
  1604.     if((r = index(name, '/')) == (char *)NULL)
  1605.         /* nothing more to check */
  1606.         return OK;
  1607.  
  1608.     /* pick up the next component of the path name, 32 chars max  */
  1609.     for(p = name, q = component, i = 0; (p != r) && (i < 32); i++)
  1610.         *q++ = *p++;
  1611.     *q = '\0';
  1612.  
  1613.     if(i >= 32)
  1614.     {
  1615.         vfile("A component of the path name is longer than 32 characters\n");
  1616.         return ERROR;
  1617.     }
  1618.  
  1619.     if(prev == (char *)NULL)
  1620.         strcpy(previous, component);
  1621.     else
  1622.     {
  1623.         strcpy(previous, prev);
  1624.         strcat(previous, "/");
  1625.         strcat(previous, component);        
  1626.     }
  1627.  
  1628.     if(existd(previous))
  1629.         /* it exists - go do rest */
  1630.         return pathrest(++r, previous);
  1631.  
  1632.     /* does not exist,                 */
  1633.     /* make this component and all its children */
  1634.     return makesubtree(++r, previous);
  1635. }
  1636.  
  1637. /*
  1638.  * make a subtree
  1639.  */
  1640. int makesubtree(name, prev)
  1641. char *name, *prev;
  1642. {
  1643.     char previous[256];
  1644.     char component[33];
  1645.     register char *p, *q, *r;
  1646.     register int i;
  1647.     extern char *index();
  1648.  
  1649.     if(mkdir(prev,DIRMODE) != 0)
  1650.     {
  1651.         vfile("Trouble trying to create subtree\n");
  1652.         return ERROR;
  1653.     }
  1654.     if(Verbose > 2)
  1655.         fprintf(stderr,"Made directory %s\n",prev);
  1656.     
  1657.  
  1658.     if((r = index(name, '/')) == (char *)NULL)
  1659.         /* nothing more to do */
  1660.         return OK;
  1661.  
  1662.     /* pick up the next component of the path name, 32 chars max */
  1663.     for(p = name, q = component, i = 0; (p != r) && (i < 32); i++)
  1664.         *q++ = *p++;
  1665.  
  1666.     *q = '\0';
  1667.  
  1668.     if(i >= 32)
  1669.     {
  1670.         vfile("A component of the path name is longer than 32 characters\n");
  1671.         return ERROR;
  1672.     }
  1673.  
  1674.     strcpy(previous, prev);
  1675.     strcat(previous, "/");
  1676.     strcat(previous, component);        
  1677.  
  1678.     /* go do the rest of them */
  1679.     return makesubtree(++r, previous);
  1680. }
  1681.  
  1682.  
  1683. /*
  1684.  * test if a subdirectory exists
  1685.  */
  1686. int existd(name)
  1687. register char *name;
  1688. {
  1689.     struct stat statbuf;
  1690.     
  1691.     if(stat(name, &statbuf) != 0)
  1692.         return FALSE;
  1693.     
  1694.     return (statbuf.st_mode & S_IFMT) == S_IFDIR;
  1695.     
  1696. }
  1697. #endif
  1698. /* End of rz.c */
  1699.