home *** CD-ROM | disk | FTP | other *** search
/ Share Gallery 1 / share_gal_1.zip / share_gal_1 / CO / CO004.ZIP / SZ.ZIP / RZ.C < prev    next >
Text File  |  1990-01-08  |  27KB  |  1,236 lines

  1. #define VERSION "1.26 08-21-87"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -M0 -Ox -K -i % -o rz; size rz;
  5. <-xtx-*> cc386 -Ox 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.  *
  19.  *  Unix is a trademark of Western Electric Company
  20.  *
  21.  * A program for Unix to receive files and commands from computers running
  22.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  23.  *  rz uses Unix buffered input to reduce wasted CPU time.
  24.  *
  25.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  26.  * "COMMAND filename"
  27.  *
  28.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  29.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  30.  *  character reads for these systems. Added 7-01-84 CAF
  31.  *
  32.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  33.  *
  34.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  35.  *  Byte Information Exchange.
  36.  *
  37.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  38.  *  doesn't work properly (even though it compiles without error!),
  39.  *
  40.  *  HOWMANY may be tuned for best performance
  41.  *
  42.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  43.  */
  44. #define LOGFILE "/tmp/rzlog"
  45.  
  46. #include <stdio.h>
  47. #include <signal.h>
  48. #include <setjmp.h>
  49. #include <ctype.h>
  50. FILE *popen();
  51.  
  52. #define OK 0
  53. #define FALSE 0
  54. #define TRUE 1
  55. #define ERROR (-1)
  56.  
  57. /*
  58.  * Max value for HOWMANY is 255.
  59.  *   A larger value reduces system overhead but may evoke kernel bugs.
  60.  *   133 corresponds to an XMODEM/CRC sector
  61.  */
  62. #ifndef HOWMANY
  63. #define HOWMANY 133
  64. #endif
  65.  
  66. int Zmodem=0;        /* ZMODEM protocol requested */
  67. int Nozmodem = 0;    /* If invoked as "rb" */
  68. unsigned Baudrate;
  69. #include "rbsb.c"    /* most of the system dependent stuff here */
  70.  
  71. char *substr();
  72. FILE *fout;
  73.  
  74. /*
  75.  * Routine to calculate the free bytes on the current file system
  76.  *  ~0 means many free bytes (unknown)
  77.  */
  78. long getfree()
  79. {
  80.     return(~0L);    /* many free bytes ... */
  81. }
  82.  
  83. /* Ward Christensen / CP/M parameters - Don't change these! */
  84. #define ENQ 005
  85. #define CAN ('X'&037)
  86. #define XOFF ('s'&037)
  87. #define XON ('q'&037)
  88. #define SOH 1
  89. #define STX 2
  90. #define EOT 4
  91. #define ACK 6
  92. #define NAK 025
  93. #define CPMEOF 032
  94. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  95. #define TIMEOUT (-2)
  96. #define RCDO (-3)
  97. #define ERRORMAX 5
  98. #define RETRYMAX 5
  99. #define WCEOT (-10)
  100. #define SECSIZ 128    /* cp/m's Magic Number record size */
  101. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  102. #define KSIZE 1024    /* record size with k option */
  103. #define UNIXFILE 0x8000    /* happens to the the S_IFREG file mask bit for stat */
  104.  
  105. int Lastrx;
  106. int Crcflg;
  107. int Firstsec;
  108. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  109. int errors;
  110. int pcvt = 0 ;        /* PC-VT Support Flag */
  111. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  112. #ifdef ONEREAD
  113. /* Sorry, Regulus and some others don't work right in raw mode! */
  114. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  115. #else
  116. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  117. #endif
  118.  
  119. #define DEFBYTL 2000000000L    /* default rx file size */
  120. long Bytesleft;        /* number of bytes of incoming file left */
  121. long Modtime;        /* Unix style mod time for incoming file */
  122. short Filemode;        /* Unix style mode for incoming file */
  123. char Pathname[PATHLEN];
  124. char *Progname;        /* the name by which we were called */
  125.  
  126. int Batch=0;
  127. int Wcsmask=0377;
  128. int Topipe=0;
  129. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  130. int Verbose=0;
  131. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  132. int Nflag = 0;        /* Don't really transfer files */
  133. int Rxbinary=FALSE;    /* receive all files in bin mode */
  134. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  135. int Thisbinary;        /* current file is to be received in bin mode */
  136. int Blklen;        /* record length of received packets */
  137. char secbuf[KSIZE+1];
  138. char linbuf[HOWMANY];
  139. int Lleft=0;        /* number of characters in linbuf */
  140. time_t timep[2];
  141. char Lzmanag;        /* Local file management request */
  142. char zconv;        /* ZMODEM file conversion request */
  143. char zmanag;        /* ZMODEM file management request */
  144. char ztrans;        /* ZMODEM file transport request */
  145. int Zctlesc;        /* Encode control characters */
  146. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  147.  
  148. jmp_buf tohere;        /* For the interrupt on RX timeout */
  149.  
  150. #include "zm.c"
  151.  
  152. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  153.  
  154. alrm()
  155. {
  156.     longjmp(tohere, -1);
  157. }
  158.  
  159. /* called by signal interrupt or terminate to clean things up */
  160. bibi(n)
  161. {
  162.     if (Zmodem)
  163.         zmputs(Attn);
  164.     canit(); mode(0);
  165.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  166.     exit(128+n);
  167. }
  168.  
  169. main(argc, argv)
  170. char *argv[];
  171. {
  172.     register char *cp;
  173.     register npats;
  174.     char *virgin, **patts;
  175.     char *getenv();
  176.     int exitcode;
  177.  
  178.     Rxtimeout = 100;
  179.     setbuf(stderr, NULL);
  180.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  181.         Restricted=TRUE;
  182.  
  183.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  184.     npats = 0;
  185.     while (--argc) {
  186.         cp = *++argv;
  187.         if (*cp == '-') {
  188.             while( *++cp) {
  189.                 switch(*cp) {
  190.                 case '+':
  191.                     Lzmanag = ZMAPND; break;
  192.                 case '0':
  193.                     pcvt = 1; break;
  194.                 case '1':
  195.                     iofd = 1; break;
  196.                 case '7':
  197.                     Wcsmask = 0177;
  198.                 case 'a':
  199.                     Rxascii=TRUE;  break;
  200.                 case 'b':
  201.                     Rxbinary=TRUE; break;
  202.                 case 'c':
  203.                     Crcflg=TRUE; break;
  204.                 case 'D':
  205.                     Nflag = TRUE; break;
  206.                 case 'e':
  207.                     Zctlesc = 1; break;
  208.                 case 'p':
  209.                     Lzmanag = ZMPROT;  break;
  210.                 case 'q':
  211.                     Quiet=TRUE; Verbose=0; break;
  212.                 case 't':
  213.                     if (--argc < 1) {
  214.                         usage();
  215.                     }
  216.                     Rxtimeout = atoi(*++argv);
  217.                     if (Rxtimeout<10 || Rxtimeout>1000)
  218.                         usage();
  219.                     break;
  220.                 case 'w':
  221.                     if (--argc < 1) {
  222.                         usage();
  223.                     }
  224.                     Zrwindow = atoi(*++argv);
  225.                     break;
  226.                 case 'u':
  227.                     MakeLCPathname=FALSE; break;
  228.                 case 'v':
  229.                     ++Verbose; break;
  230.                 default:
  231.                     usage();
  232.                 }
  233.             }
  234.         }
  235.         else if ( !npats && argc>0) {
  236.             if (argv[0][0]) {
  237.                 npats=argc;
  238.                 patts=argv;
  239.             }
  240.         }
  241.     }
  242.     if (npats > 1)
  243.         usage();
  244.     if (Verbose) {
  245.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  246.             printf("Can't open log file %s\n",LOGFILE);
  247.             exit(0200);
  248.         }
  249.         setbuf(stderr, NULL);
  250.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  251.     }
  252.     if (fromcu() && !Quiet) {
  253.         if (Verbose == 0)
  254.             Verbose = 2;
  255.     }
  256.     mode(1);
  257.     if (signal(SIGINT, bibi) == SIG_IGN) {
  258.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  259.     }
  260.     else {
  261.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  262.     }
  263.     signal(SIGTERM, bibi);
  264.     if (wcreceive(npats, patts)==ERROR) {
  265.         exitcode=0200;
  266.         canit();
  267.     }
  268.     mode(0);
  269.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  270.         canit();
  271.     exit(exitcode);
  272. }
  273.  
  274.  
  275. usage()
  276. {
  277.     fprintf(stderr,"%s %s for %s by Chuck Forsberg\n",
  278.       Progname, VERSION, OS);
  279.     fprintf(stderr,"Usage:    rz [-01abeuv]        (ZMODEM Batch)\n");
  280.     fprintf(stderr,"or    rb [-01abuv]        (YMODEM Batch)\n");
  281.     fprintf(stderr,"or    rx [-01abcv] file    (XMODEM or XMODEM-1k)\n");
  282.     fprintf(stderr,"      -0 Enable PC-VT Support\n");
  283.     fprintf(stderr,"      -1 For cu(1): Use fd 1 for input\n");
  284.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  285.     fprintf(stderr,"      -b Binary transfer for all files\n");
  286.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  287.     fprintf(stderr,"      -e Ignore control characters    (ZMODEM)\n");
  288.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  289.     exit(1);
  290. }
  291. /*
  292.  *  Debugging information output interface routine
  293.  */
  294. /* VARARGS1 */
  295. vfile(f, a, b, c)
  296. register char *f;
  297. {
  298.     if (Verbose > 2) {
  299.         fprintf(stderr, f, a, b, c);
  300.         fprintf(stderr, "\n");
  301.     }
  302. }
  303.  
  304. /*
  305.  * Let's receive something already.
  306.  */
  307.  
  308. char *rbmsg =
  309. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n";
  310.  
  311. wcreceive(argc, argp)
  312. char **argp;
  313. {
  314.     register c;
  315.  
  316.     if (Batch || argc==0) {
  317.         Crcflg=(Wcsmask==0377);
  318.         if ( !Quiet && !pcvt )
  319.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  320.         if (pcvt) {                                               
  321.             fprintf(stderr,"\033[?22h\n");
  322.             }
  323.         if (c=tryz()) {
  324.             if (c == ZCOMPL)
  325.                 return OK;
  326.             if (c == ERROR)
  327.                 goto fubar;
  328.             c = rzfiles();
  329.             if (c)
  330.                 goto fubar;
  331.         } else {
  332.             for (;;) {
  333.                 if (wcrxpn(secbuf)== ERROR)
  334.                     goto fubar;
  335.                 if (secbuf[0]==0)
  336.                     return OK;
  337.                 if (procheader(secbuf) == ERROR)
  338.                     goto fubar;
  339.                 if (wcrx()==ERROR)
  340.                     goto fubar;
  341.             }
  342.         }
  343.     } else {
  344.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  345.  
  346.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  347.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  348.         if (pcvt) {
  349.             fprintf(stderr,"\033[?24h%s=z\033[?24l\033[?22h\n",Pathname);
  350.             }
  351.         if ((fout=fopen(Pathname, "w")) == NULL)
  352.             return ERROR;
  353.         if (wcrx()==ERROR)
  354.             goto fubar;
  355.     }
  356.     return OK;
  357. fubar:
  358.     canit();
  359.     if (Topipe && fout) {
  360.         pclose(fout);  return ERROR;
  361.     }
  362.     if (fout)
  363.         fclose(fout);
  364.     if (Restricted) {
  365.         unlink(Pathname);
  366.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  367.     }
  368.     return ERROR;
  369. }
  370.  
  371.  
  372. /*
  373.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  374.  * Length is indeterminate as long as less than Blklen
  375.  * A null string represents no more files (YMODEM)
  376.  */
  377. wcrxpn(rpn)
  378. char *rpn;    /* receive a pathname */
  379. {
  380.     register c;
  381.  
  382. #ifdef NFGVMIN
  383.     readline(1);
  384. #else
  385.     purgeline();
  386. #endif
  387.  
  388. et_tu:
  389.     Firstsec=TRUE;  Eofseen=FALSE;
  390.     sendline(Crcflg?WANTCRC:NAK);
  391.     Lleft=0;    /* Do read next time ... */
  392.     while ((c = wcgetsec(rpn, 100)) != 0) {
  393.         if (c == WCEOT) {
  394.             zperr( "Pathname fetch returned %d", c);
  395.             sendline(ACK);
  396.             Lleft=0;    /* Do read next time ... */
  397.             readline(1);
  398.             goto et_tu;
  399.         }
  400.         return ERROR;
  401.     }
  402.     sendline(ACK);
  403.     return OK;
  404. }
  405.  
  406. /*
  407.  * Adapted from CMODEM13.C, written by
  408.  * Jack M. Wierda and Roderick W. Hart
  409.  */
  410.  
  411. wcrx()
  412. {
  413.     register int sectnum, sectcurr;
  414.     register char sendchar;
  415.     register char *p;
  416.     int cblklen;            /* bytes to dump this block */
  417.  
  418.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  419.     sendchar=Crcflg?WANTCRC:NAK;
  420.  
  421.     for (;;) {
  422.         sendline(sendchar);    /* send it now, we're ready! */
  423.         Lleft=0;    /* Do read next time ... */
  424.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  425.         report(sectcurr);
  426.         if (sectcurr==(sectnum+1 &Wcsmask)) {
  427.             sectnum++;
  428.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  429.             if (putsec(secbuf, cblklen)==ERROR)
  430.                 return ERROR;
  431.             if ((Bytesleft-=cblklen) < 0)
  432.                 Bytesleft = 0;
  433.             sendchar=ACK;
  434.         }
  435.         else if (sectcurr==(sectnum&Wcsmask)) {
  436.             zperr( "Received dup Sector");
  437.             sendchar=ACK;
  438.         }
  439.         else if (sectcurr==WCEOT) {
  440.             if (closeit())
  441.                 return ERROR;
  442.             sendline(ACK);
  443.             Lleft=0;    /* Do read next time ... */
  444.             return OK;
  445.         }
  446.         else if (sectcurr==ERROR)
  447.             return ERROR;
  448.         else {
  449.             zperr( "Sync Error");
  450.             return ERROR;
  451.         }
  452.     }
  453. }
  454.  
  455. /*
  456.  * Wcgetsec fetches a Ward Christensen type sector.
  457.  * Returns sector number encountered or ERROR if valid sector not received,
  458.  * or CAN CAN received
  459.  * or WCEOT if eot sector
  460.  * time is timeout for first char, set to 4 seconds thereafter
  461.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  462.  *    (Caller must do that when he is good and ready to get next sector)
  463.  */
  464.  
  465. wcgetsec(rxbuf, maxtime)
  466. char *rxbuf;
  467. int maxtime;
  468. {
  469.     register checksum, wcj, firstch;
  470.     register unsigned short oldcrc;
  471.     register char *p;
  472.     int sectcurr;
  473.  
  474.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  475.  
  476.         if ((firstch=readline(maxtime))==STX) {
  477.             Blklen=KSIZE; goto get2;
  478.         }
  479.         if (firstch==SOH) {
  480.             Blklen=SECSIZ;
  481. get2:
  482.             sectcurr=readline(1);
  483.             if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) {
  484.                 oldcrc=checksum=0;
  485.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  486.                     if ((firstch=readline(1)) < 0)
  487.                         goto bilge;
  488.                     oldcrc=updcrc(firstch, oldcrc);
  489.                     checksum += (*p++ = firstch);
  490.                 }
  491.                 if ((firstch=readline(1)) < 0)
  492.                     goto bilge;
  493.                 if (Crcflg) {
  494.                     oldcrc=updcrc(firstch, oldcrc);
  495.                     if ((firstch=readline(1)) < 0)
  496.                         goto bilge;
  497.                     oldcrc=updcrc(firstch, oldcrc);
  498.                     if (oldcrc & 0xFFFF)
  499.                         zperr( "CRC");
  500.                     else {
  501.                         Firstsec=FALSE;
  502.                         return sectcurr;
  503.                     }
  504.                 }
  505.                 else if (((checksum-firstch)&Wcsmask)==0) {
  506.                     Firstsec=FALSE;
  507.                     return sectcurr;
  508.                 }
  509.                 else
  510.                     zperr( "Checksum");
  511.             }
  512.             else
  513.                 zperr("Sector number garbled");
  514.         }
  515.         /* make sure eot really is eot and not just mixmash */
  516. #ifdef NFGVMIN
  517.         else if (firstch==EOT && readline(1)==TIMEOUT)
  518.             return WCEOT;
  519. #else
  520.         else if (firstch==EOT && Lleft==0)
  521.             return WCEOT;
  522. #endif
  523.         else if (firstch==CAN) {
  524.             if (Lastrx==CAN) {
  525.                 zperr( "Sender CANcelled");
  526.                 return ERROR;
  527.             } else {
  528.                 Lastrx=CAN;
  529.                 continue;
  530.             }
  531.         }
  532.         else if (firstch==TIMEOUT) {
  533.             if (Firstsec)
  534.                 goto humbug;
  535. bilge:
  536.             zperr( "TIMEOUT");
  537.         }
  538.         else
  539.             zperr( "Got 0%o sector header", firstch);
  540.  
  541. humbug:
  542.         Lastrx=0;
  543.         while(readline(1)!=TIMEOUT)
  544.             ;
  545.         if (Firstsec) {
  546.             sendline(Crcflg?WANTCRC:NAK);
  547.             Lleft=0;    /* Do read next time ... */
  548.         } else {
  549.             maxtime=40; sendline(NAK);
  550.             Lleft=0;    /* Do read next time ... */
  551.         }
  552.     }
  553.     /* try to stop the bubble machine. */
  554.     canit();
  555.     return ERROR;
  556. }
  557.  
  558. /*
  559.  * This version of readline is reasoably well suited for
  560.  * reading many characters.
  561.  *  (except, currently, for the Regulus version!)
  562.  *
  563.  * timeout is in tenths of seconds
  564.  */
  565. readline(timeout)
  566. int timeout;
  567. {
  568.     register n;
  569.     static char *cdq;    /* pointer for removing chars from linbuf */
  570.  
  571.     if (--Lleft >= 0) {
  572.         if (Verbose > 8) {
  573.             fprintf(stderr, "%02x ", *cdq&0377);
  574.         }
  575.         return (*cdq++ & Wcsmask);
  576.     }
  577.     n = timeout/10;
  578.     if (n < 2)
  579.         n = 3;
  580.     if (Verbose > 5)
  581.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  582.           n, Readnum);
  583.     if (setjmp(tohere)) {
  584. #ifdef TIOCFLUSH
  585. /*        ioctl(iofd, TIOCFLUSH, 0); */
  586. #endif
  587.         Lleft = 0;
  588.         if (Verbose>1)
  589.             fprintf(stderr, "Readline:TIMEOUT\n");
  590.         return TIMEOUT;
  591.     }
  592.     signal(SIGALRM, alrm); alarm(n);
  593.     Lleft=read(iofd, cdq=linbuf, Readnum);
  594.     alarm(0);
  595.     if (Verbose > 5) {
  596.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  597.     }
  598.     if (Lleft < 1)
  599.         return TIMEOUT;
  600.     --Lleft;
  601.     if (Verbose > 8) {
  602.         fprintf(stderr, "%02x ", *cdq&0377);
  603.     }
  604.     return (*cdq++ & Wcsmask);
  605. }
  606.  
  607.  
  608.  
  609. /*
  610.  * Purge the modem input queue of all characters
  611.  */
  612. purgeline()
  613. {
  614.     Lleft = 0;
  615. #ifdef USG
  616.     ioctl(iofd, TCFLSH, 0);
  617. #else
  618.     lseek(iofd, 0L, 2);
  619. #endif
  620. }
  621.  
  622.  
  623. /*
  624.  * Process incoming file information header
  625.  */
  626. procheader(name)
  627. char *name;
  628. {
  629.     register char *openmode, *p, **pp;
  630.  
  631.     /* set default parameters and overrides */
  632.     openmode = "w";
  633.     Thisbinary = (!Rxascii) || Rxbinary;
  634.     if (Lzmanag)
  635.         zmanag = Lzmanag;
  636.  
  637.     /*
  638.      *  Process ZMODEM remote file management requests
  639.      */
  640.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  641.         Thisbinary = 0;
  642.     if (zconv == ZCBIN)    /* Remote Binary override */
  643.         Thisbinary = TRUE;
  644.     else if (zmanag == ZMAPND)
  645.         openmode = "a";
  646.  
  647. #ifndef BIX
  648.     /* ZMPROT check for existing file */
  649.     if (zmanag == ZMPROT && (fout=fopen(name, "r"))) {
  650.         fclose(fout);  return ERROR;
  651.     }
  652. #endif
  653.  
  654.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  655.  
  656.     p = name + 1 + strlen(name);
  657.     if (*p) {    /* file coming from Unix or DOS system */
  658.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  659.         if (Filemode & UNIXFILE)
  660.             ++Thisbinary;
  661.         if (Verbose) {
  662.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  663.               name, Bytesleft, Modtime, Filemode);
  664.         }
  665.     }
  666.  
  667. #ifdef BIX
  668.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  669.         return ERROR;
  670.     return OK;
  671. #else
  672.  
  673.     else {        /* File coming from CP/M system */
  674.         for (p=name; *p; ++p)        /* change / to _ */
  675.             if ( *p == '/')
  676.                 *p = '_';
  677.  
  678.         if ( *--p == '.')        /* zap trailing period */
  679.             *p = 0;
  680.     }
  681.  
  682.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name))
  683.         uncaps(name);
  684.     if (Topipe) {
  685.         sprintf(Pathname, "%s %s", Progname+2, name);
  686.         if (Verbose)
  687.             fprintf(stderr,  "Topipe: %s %s\n",
  688.               Pathname, Thisbinary?"BIN":"ASCII");
  689.         if ((fout=popen(Pathname, "w")) == NULL)
  690.             return ERROR;
  691.     } else {
  692.         strcpy(Pathname, name);
  693.         if (Verbose) {
  694.             fprintf(stderr,  "Receiving %s %s %s\n",
  695.               name, Thisbinary?"BIN":"ASCII", openmode);
  696.         }
  697.         checkpath(name);
  698.         if (Nflag)
  699.             name = "/dev/null";
  700.         if ((fout=fopen(name, openmode)) == NULL)
  701.             return ERROR;
  702.     }
  703.     return OK;
  704. #endif /* BIX */
  705. }
  706.  
  707. /*
  708.  * Putsec writes the n characters of buf to receive file fout.
  709.  *  If not in binary mode, carriage returns, and all characters
  710.  *  starting with CPMEOF are discarded.
  711.  */
  712. putsec(buf, n)
  713. char *buf;
  714. register n;
  715. {
  716.     register char *p;
  717.  
  718.     if (Thisbinary) {
  719.         for (p=buf; --n>=0; )
  720.             putc( *p++, fout);
  721.     }
  722.     else {
  723.         if (Eofseen)
  724.             return OK;
  725.         for (p=buf; --n>=0; ++p ) {
  726.             if ( *p == '\r')
  727.                 continue;
  728.             if (*p == CPMEOF) {
  729.                 Eofseen=TRUE; return OK;
  730.             }
  731.             putc(*p ,fout);
  732.         }
  733.     }
  734.     return OK;
  735. }
  736.  
  737. /*
  738.  *  Send a character to modem.  Small is beautiful.
  739.  */
  740. sendline(c)
  741. {
  742.     char d;
  743.  
  744.     d = c;
  745.     if (Verbose>6)
  746.         fprintf(stderr, "Sendline: %x\n", c);
  747.     write(1, &d, 1);
  748. }
  749.  
  750. xsendline(c)
  751. {
  752.     sendline(c);
  753. }
  754.  
  755. flushmo() {}
  756.  
  757.  
  758.  
  759.  
  760. /* make string s lower case */
  761. uncaps(s)
  762. register char *s;
  763. {
  764.     for ( ; *s; ++s)
  765.         if (isupper(*s))
  766.             *s = tolower(*s);
  767. }
  768. /*
  769.  * IsAnyLower returns TRUE if string s has lower case letters.
  770.  */
  771. IsAnyLower(s)
  772. register char *s;
  773. {
  774.     for ( ; *s; ++s)
  775.         if (islower(*s))
  776.             return TRUE;
  777.     return FALSE;
  778. }
  779.  
  780. /*
  781.  * substr(string, token) searches for token in string s
  782.  * returns pointer to token within string if found, NULL otherwise
  783.  */
  784. char *
  785. substr(s, t)
  786. register char *s,*t;
  787. {
  788.     register char *ss,*tt;
  789.     /* search for first char of token */
  790.     for (ss=s; *s; s++)
  791.         if (*s == *t)
  792.             /* compare token with substring */
  793.             for (ss=s,tt=t; ;) {
  794.                 if (*tt == 0)
  795.                     return s;
  796.                 if (*ss++ != *tt++)
  797.                     break;
  798.             }
  799.     return NULL;
  800. }
  801.  
  802. /*
  803.  * Log an error
  804.  */
  805. /*VARARGS1*/
  806. zperr(s,p,u)
  807. char *s, *p, *u;
  808. {
  809.     if (Verbose <= 0)
  810.         return;
  811.     fprintf(stderr, "Retry %d: ", errors);
  812.     fprintf(stderr, s, p, u);
  813.     fprintf(stderr, "\n");
  814. }
  815.  
  816. /* send cancel string to get the other end to shut up */
  817. canit()
  818. {
  819.     static char canistr[] = {
  820.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  821.     };
  822.  
  823.     printf(canistr);
  824.     Lleft=0;    /* Do read next time ... */
  825.     fflush(stdout);
  826. }
  827.  
  828.  
  829. /*
  830.  * Return 1 iff stdout and stderr are different devices
  831.  *  indicating this program operating with a modem on a
  832.  *  different line
  833.  */
  834. fromcu()
  835. {
  836.     struct stat a, b;
  837.     fstat(1, &a); fstat(2, &b);
  838.     return (a.st_rdev != b.st_rdev);
  839. }
  840.  
  841. report(sct)
  842. int sct;
  843. {
  844.     if (Verbose>1)
  845.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  846. }
  847.  
  848. /*
  849.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  850.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  851.  * If called as rb use YMODEM protocol
  852.  */
  853. chkinvok(s)
  854. char *s;
  855. {
  856.     register char *p;
  857.  
  858.     p = s;
  859.     while (*p == '-')
  860.         s = ++p;
  861.     while (*p)
  862.         if (*p++ == '/')
  863.             s = p;
  864.     if (*s == 'v') {
  865.         Verbose=1; ++s;
  866.     }
  867.     Progname = s;
  868.     if (s[0]=='r' && s[1]=='b')
  869.         Nozmodem = TRUE;
  870.     if (s[2] && s[0]=='r' && s[1]=='b')
  871.         Topipe=TRUE;
  872.     if (s[2] && s[0]=='r' && s[1]=='z')
  873.         Topipe=TRUE;
  874. }
  875.  
  876. /*
  877.  * Totalitarian Communist pathname processing
  878.  */
  879. checkpath(name)
  880. char *name;
  881. {
  882.     if (Restricted) {
  883.         if (fopen(name, "r") != NULL) {
  884.             canit();
  885.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  886.             bibi(-1);
  887.         }
  888.         /* restrict pathnames to current tree or uucppublic */
  889.         if ( substr(name, "../")
  890.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  891.             canit();
  892.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  893.             bibi(-1);
  894.         }
  895.     }
  896. }
  897.  
  898. /*
  899.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  900.  *  Handles ZSINIT frame
  901.  *  Return ZFILE if Zmodem filename received, -1 on error,
  902.  *   ZCOMPL if transaction finished,  else 0
  903.  */
  904. tryz()
  905. {
  906.     register c, n;
  907.     register cmdzack1flg;
  908.  
  909.     if (Nozmodem)        /* Check for "rb" program name */
  910.         return 0;
  911.  
  912.  
  913.     for (n=Zmodem?15:5; --n>=0; ) {
  914.         /* Set buffer length (0) and capability flags */
  915.         stohdr(0L);
  916. #ifdef CANBREAK
  917.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  918. #else
  919.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  920. #endif
  921.         if (Zctlesc)
  922.             Txhdr[ZF0] |= TESCCTL;
  923.         zshhdr(tryzhdrtype, Txhdr);
  924.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  925.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  926. again:
  927.         switch (zgethdr(Rxhdr, 0)) {
  928.         case ZRQINIT:
  929.             continue;
  930.         case ZEOF:
  931.             continue;
  932.         case TIMEOUT:
  933.             continue;
  934.         case ZFILE:
  935.             zconv = Rxhdr[ZF0];
  936.             zmanag = Rxhdr[ZF1];
  937.             ztrans = Rxhdr[ZF2];
  938.             tryzhdrtype = ZRINIT;
  939.             c = zrdata(secbuf, KSIZE);
  940.             mode(3);
  941.             if (c == GOTCRCW)
  942.                 return ZFILE;
  943.             zshhdr(ZNAK, Txhdr);
  944.             goto again;
  945.         case ZSINIT:
  946.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  947.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  948.                 zshhdr(ZACK, Txhdr);
  949.                 goto again;
  950.             }
  951.             zshhdr(ZNAK, Txhdr);
  952.             goto again;
  953.         case ZFREECNT:
  954.             stohdr(getfree());
  955.             zshhdr(ZACK, Txhdr);
  956.             goto again;
  957.         case ZCOMMAND:
  958.             cmdzack1flg = Rxhdr[ZF0];
  959.             if (zrdata(secbuf, KSIZE) == GOTCRCW) {
  960.                 if (cmdzack1flg & ZCACK1)
  961.                     stohdr(0L);
  962.                 else
  963.                     stohdr((long)sys2(secbuf));
  964.                 purgeline();    /* dump impatient questions */
  965.                 do {
  966.                     zshhdr(ZCOMPL, Txhdr);
  967.                 }
  968.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  969.                 ackbibi();
  970.                 if (cmdzack1flg & ZCACK1)
  971.                     exec2(secbuf);
  972.                 return ZCOMPL;
  973.             }
  974.             zshhdr(ZNAK, Txhdr); goto again;
  975.         case ZCOMPL:
  976.             goto again;
  977.         default:
  978.             continue;
  979.         case ZFIN:
  980.             ackbibi(); return ZCOMPL;
  981.         case ZCAN:
  982.             return ERROR;
  983.         }
  984.     }
  985.     return 0;
  986. }
  987.  
  988. /*
  989.  * Receive 1 or more files with ZMODEM protocol
  990.  */
  991. rzfiles()
  992. {
  993.     register c;
  994.  
  995.     for (;;) {
  996.         switch (c = rzfile()) {
  997.         case ZEOF:
  998.         case ZSKIP:
  999.             switch (tryz()) {
  1000.             case ZCOMPL:
  1001.                 return OK;
  1002.             default:
  1003.                 return ERROR;
  1004.             case ZFILE:
  1005.                 break;
  1006.             }
  1007.             continue;
  1008.         default:
  1009.             return c;
  1010.         case ERROR:
  1011.             return ERROR;
  1012.         }
  1013.     }
  1014. }
  1015.  
  1016. /*
  1017.  * Receive a file with ZMODEM protocol
  1018.  *  Assumes file name frame is in secbuf
  1019.  */
  1020. rzfile()
  1021. {
  1022.     register c, n;
  1023.     long rxbytes;
  1024.  
  1025.     Eofseen=FALSE;
  1026.     if (procheader(secbuf) == ERROR) {
  1027.         return (tryzhdrtype = ZSKIP);
  1028.     }
  1029.  
  1030.     n = 20; rxbytes = 0l;
  1031.  
  1032.     for (;;) {
  1033.         stohdr(rxbytes);
  1034.         zshhdr(ZRPOS, Txhdr);
  1035. nxthdr:
  1036.         switch (c = zgethdr(Rxhdr, 0)) {
  1037.         default:
  1038.             vfile("rzfile: zgethdr returned %d", c);
  1039.             return ERROR;
  1040.         case ZNAK:
  1041.         case TIMEOUT:
  1042.             if ( --n < 0) {
  1043.                 vfile("rzfile: zgethdr returned %d", c);
  1044.                 return ERROR;
  1045.             }
  1046.         case ZFILE:
  1047.             zrdata(secbuf, KSIZE);
  1048.             continue;
  1049.         case ZEOF:
  1050.             if (rclhdr(Rxhdr) != rxbytes) {
  1051.                 /*
  1052.                  * Ignore eof if it's at wrong place - force
  1053.                  *  a timeout because the eof might have gone
  1054.                  *  out before we sent our zrpos.
  1055.                  */
  1056.                 errors = 0;  goto nxthdr;
  1057.             }
  1058.             if (closeit()) {
  1059.                 tryzhdrtype = ZFERR;
  1060.                 vfile("rzfile: closeit returned <> 0");
  1061.                 return ERROR;
  1062.             }
  1063.             vfile("rzfile: normal EOF");
  1064.             return c;
  1065.         case ERROR:    /* Too much garbage in header search error */
  1066.             if ( --n < 0) {
  1067.                 vfile("rzfile: zgethdr returned %d", c);
  1068.                 return ERROR;
  1069.             }
  1070.             zmputs(Attn);
  1071.             continue;
  1072.         case ZDATA:
  1073.             if (rclhdr(Rxhdr) != rxbytes) {
  1074.                 if ( --n < 0) {
  1075.                     return ERROR;
  1076.                 }
  1077.                 zmputs(Attn);  continue;
  1078.             }
  1079. moredata:
  1080.             if (Verbose>1)
  1081.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1082.                   rxbytes, Crc32?" CRC-32":"");
  1083.             switch (c = zrdata(secbuf, KSIZE)) {
  1084.             case ZCAN:
  1085.                 vfile("rzfile: zgethdr returned %d", c);
  1086.                 return ERROR;
  1087.             case ERROR:    /* CRC error */
  1088.                 if ( --n < 0) {
  1089.                     vfile("rzfile: zgethdr returned %d", c);
  1090.                     return ERROR;
  1091.                 }
  1092.                 zmputs(Attn);
  1093.                 continue;
  1094.             case TIMEOUT:
  1095.                 if ( --n < 0) {
  1096.                     vfile("rzfile: zgethdr returned %d", c);
  1097.                     return ERROR;
  1098.                 }
  1099.                 continue;
  1100.             case GOTCRCW:
  1101.                 n = 20;
  1102.                 putsec(secbuf, Rxcount);
  1103.                 rxbytes += Rxcount;
  1104.                 stohdr(rxbytes);
  1105.                 zshhdr(ZACK, Txhdr);
  1106.                 sendline(XON);
  1107.                 goto nxthdr;
  1108.             case GOTCRCQ:
  1109.                 n = 20;
  1110.                 putsec(secbuf, Rxcount);
  1111.                 rxbytes += Rxcount;
  1112.                 stohdr(rxbytes);
  1113.                 zshhdr(ZACK, Txhdr);
  1114.                 goto moredata;
  1115.             case GOTCRCG:
  1116.                 n = 20;
  1117.                 putsec(secbuf, Rxcount);
  1118.                 rxbytes += Rxcount;
  1119.                 goto moredata;
  1120.             case GOTCRCE:
  1121.                 n = 20;
  1122.                 putsec(secbuf, Rxcount);
  1123.                 rxbytes += Rxcount;
  1124.                 goto nxthdr;
  1125.             }
  1126.         }
  1127.     }
  1128. }
  1129.  
  1130. /*
  1131.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  1132.  *   and \335 (break signal)
  1133.  */
  1134. zmputs(s)
  1135. char *s;
  1136. {
  1137.     register c;
  1138.  
  1139.     while (*s) {
  1140.         switch (c = *s++) {
  1141.         case '\336':
  1142.             sleep(1); continue;
  1143.         case '\335':
  1144.             sendbrk(); continue;
  1145.         default:
  1146.             sendline(c);
  1147.         }
  1148.     }
  1149. }
  1150.  
  1151. /*
  1152.  * Close the receive dataset, return OK or ERROR
  1153.  */
  1154. closeit()
  1155. {
  1156.     if (Topipe) {
  1157.         if (pclose(fout)) {
  1158.             return ERROR;
  1159.         }
  1160.         return OK;
  1161.     }
  1162.     if (fclose(fout)==ERROR) {
  1163.         fprintf(stderr, "file close ERROR\n");
  1164.         return ERROR;
  1165.     }
  1166.     if (Modtime) {
  1167.         timep[0] = time(NULL);
  1168.         timep[1] = Modtime;
  1169.         utime(Pathname, timep);
  1170.     }
  1171.     if (Filemode)
  1172.         chmod(Pathname, (07777 & Filemode));
  1173.     return OK;
  1174. }
  1175.  
  1176. /*
  1177.  * Ack a ZFIN packet, let byegones be byegones
  1178.  */
  1179. ackbibi()
  1180. {
  1181.     register n;
  1182.  
  1183.     vfile("ackbibi:");
  1184.     Readnum = 1;
  1185.     stohdr(0L);
  1186.     for (n=3; --n>=0; ) {
  1187.         purgeline();
  1188.         zshhdr(ZFIN, Txhdr);
  1189.         switch (readline(100)) {
  1190.         case 'O':
  1191.             readline(1);    /* Discard 2nd 'O' */
  1192.             vfile("ackbibi complete");
  1193.             return;
  1194.         case RCDO:
  1195.             return;
  1196.         case TIMEOUT:
  1197.         default:
  1198.             break;
  1199.         }
  1200.     }
  1201. }
  1202.  
  1203.  
  1204.  
  1205. /*
  1206.  * Local console output simulation
  1207.  */
  1208. bttyout(c)
  1209. {
  1210.     if (Verbose || fromcu())
  1211.         putc(c, stderr);
  1212. }
  1213.  
  1214. /*
  1215.  * Strip leading ! if present, do shell escape. 
  1216.  */
  1217. sys2(s)
  1218. register char *s;
  1219. {
  1220.     if (*s == '!')
  1221.         ++s;
  1222.     return system(s);
  1223. }
  1224. /*
  1225.  * Strip leading ! if present, do exec.
  1226.  */
  1227. exec2(s)
  1228. register char *s;
  1229. {
  1230.     if (*s == '!')
  1231.         ++s;
  1232.     mode(0);
  1233.     execl("/bin/sh", "sh", "-c", s);
  1234. }
  1235. /* End of rz.c */
  1236.