home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / ENTERPRS / CPM / TERMS / ZMODEM.ZIP / RZ.C < prev    next >
Text File  |  1987-09-28  |  25KB  |  1,226 lines

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