home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume12 / zmodem / part03 < prev    next >
Encoding:
Internet Message Format  |  1987-10-18  |  56.2 KB

  1. Subject:  v12i023:  Zmodem file transfer programs, Part03/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: omen!caf
  7. Posting-number: Volume 12, Issue 23
  8. Archive-name: zmodem/part03
  9.  
  10. Source code for Unix ZMODEM programs rz.c and sz.c and related files follows.
  11. ZMODEM is the ideal protocol for file transfer to and from Unix systems
  12. using a serial port. The source code has also been used for numerous ZMODEM
  13. versions, including the Opus bulletin board (Fido replacemet).  ZMODEM's
  14. pleasant user interface with automatic file and command download allows a
  15. Makefile to control a DOS machine running Pro-YAM, dor example.
  16.  
  17. #!/bin/sh
  18. # to extract, remove the header and type "sh filename"
  19. if `test ! -s ./sz.c`
  20. then
  21. echo "Writing ./sz.c"
  22. cat > ./sz.c << '\Rogue\Monster\'
  23. #define VERSION "sz 1.36 08-31-87"
  24. #define PUBDIR "/usr/spool/uucppublic"
  25.  
  26. /*% cc -M0 -Ox -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz
  27.  *
  28.  * sz.c By Chuck Forsberg
  29.  *
  30.  *    cc -O sz.c -o sz        USG (SYS III/V) Unix
  31.  *    cc -O -DSVR2 sz.c -o sz        Sys V Release 2 with non-blocking input
  32.  *                    Define to allow reverse channel checking
  33.  *    cc -O -DV7  sz.c -o sz        Unix Version 7, 2.8 - 4.3 BSD
  34.  *
  35.  *    cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz    Xenix
  36.  *
  37.  *    ln sz sb            **** All versions ****
  38.  *    ln sz sx            **** All versions ****
  39.  *
  40.  *
  41.  *  ******* Some systems (Venix, Coherent, Regulus) do not *******
  42.  *  ******* support tty raw mode read(2) identically to    *******
  43.  *  ******* Unix. ONEREAD must be defined to force one     *******
  44.  *  ******* character reads for these systems.           *******
  45.  *
  46.  * A program for Unix to send files and commands to computers running
  47.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
  48.  *
  49.  *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
  50.  *
  51.  *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
  52.  *
  53.  * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS
  54.  * in accordance with the 7-31-87 ZMODEM Protocol Description
  55.  */
  56.  
  57.  
  58. char *substr(), *getenv();
  59.  
  60. #define LOGFILE "/tmp/szlog"
  61.  
  62. #include <stdio.h>
  63. #include <signal.h>
  64. #include <setjmp.h>
  65. #include <ctype.h>
  66.  
  67. #define PATHLEN 256
  68. #define OK 0
  69. #define FALSE 0
  70. #define TRUE 1
  71. #define ERROR (-1)
  72.  
  73. #define HOWMANY 2
  74. int Zmodem=0;        /* ZMODEM protocol requested */
  75. unsigned Baudrate;
  76. unsigned Txwindow;    /* Control the size of the transmitted window */
  77. unsigned Txwspac;    /* Spacing between zcrcq requests */
  78. unsigned Txwcnt;    /* Counter used to space ack requests */
  79. long Lrxpos;        /* Receiver's last reported offset */
  80. int Fromcu = 0;        /* Were called from cu or yam */
  81. int errors;
  82. #include "rbsb.c"    /* most of the system dependent stuff here */
  83.  
  84. /*
  85.  * Attention string to be executed by receiver to interrupt streaming data
  86.  *  when an error is detected.  A pause (0336) may be needed before the
  87.  *  ^C (03) or after it.
  88.  */
  89. #ifdef READCHECK
  90. char Myattn[] = { 0 };
  91. #else
  92. #ifdef USG
  93. char Myattn[] = { 03, 0336, 0 };
  94. #else
  95. char Myattn[] = { 0 };
  96. #endif
  97. #endif
  98.  
  99. FILE *in;
  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 WANTG 0107    /* Send G not NAK to get nonstop batch xmsn */
  114. #define TIMEOUT (-2)
  115. #define RCDO (-3)
  116. #define RETRYMAX 10
  117. #define SECSIZ 128    /* cp/m's Magic Number record size */
  118. #define KSIZE 1024
  119.  
  120. char Lastrx;
  121. char Crcflg;
  122. int Wcsmask=0377;
  123. int Verbose=0;
  124. int Modem2=0;        /* XMODEM Protocol - don't send pathnames */
  125. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  126. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  127. int Ascii=0;        /* Add CR's for brain damaged programs */
  128. int Fullname=0;        /* transmit full pathname */
  129. int Unlinkafter=0;    /* Unlink file after it is sent */
  130. int Dottoslash=0;    /* Change foo.bar.baz to foo/bar/baz */
  131. int firstsec;
  132. int errcnt=0;        /* number of files unreadable */
  133. int blklen=SECSIZ;        /* length of transmitted records */
  134. int Optiong;        /* Let it rip no wait for sector ACK's */
  135. int Noeofseen;
  136. int Totsecs;        /* total number of sectors this file */
  137. char txbuf[KSIZE];
  138. int Filcnt=0;        /* count of number of files opened */
  139. int Lfseen=0;
  140. unsigned Rxbuflen = 16384;    /* Receiver's max buffer length */
  141. int Tframlen = 0;    /* Override for tx frame length */
  142. int blkopt=0;        /* Override value for zmodem blklen */
  143. int Rxflags = 0;
  144. long bytcnt;
  145. int Wantfcs32 = TRUE;    /* want to send 32 bit FCS */
  146. char Lzconv;    /* Local ZMODEM file conversion request */
  147. char Lzmanag;    /* Local ZMODEM file management request */
  148. int Lskipnocor;
  149. char Lztrans;
  150. char zconv;        /* ZMODEM file conversion request */
  151. char zmanag;        /* ZMODEM file management request */
  152. char ztrans;        /* ZMODEM file transport request */
  153. int Command;        /* Send a command, then exit. */
  154. char *Cmdstr;        /* Pointer to the command string */
  155. int Cmdtries = 11;
  156. int Cmdack1;        /* Rx ACKs command, then do it */
  157. int Exitcode;
  158. int Testattn;        /* Force receiver to send Attn, etc with qbf. */
  159. char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
  160. long Lastread;        /* Beginning offset of last buffer read */
  161. int Lastn;        /* Count of last buffer read or -1 */
  162. int Dontread;        /* Don't read the buffer, it's still there */
  163. long Lastsync;        /* Last offset to which we got a ZRPOS */
  164. int Beenhereb4;        /* How many times we've been ZRPOS'd same place */
  165.  
  166. jmp_buf tohere;        /* For the interrupt on RX timeout */
  167. jmp_buf intrjmp;    /* For the interrupt on RX CAN */
  168.  
  169. /* called by signal interrupt or terminate to clean things up */
  170. bibi(n)
  171. {
  172.     canit(); fflush(stdout); mode(0);
  173.     fprintf(stderr, "sz: caught signal %d; exiting\n", n);
  174.     if (n == SIGQUIT)
  175.         abort();
  176.     exit(128+n);
  177. }
  178. /* Called when Zmodem gets an interrupt (^X) */
  179. onintr()
  180. {
  181.     signal(SIGINT, SIG_IGN);
  182.     longjmp(intrjmp, -1);
  183. }
  184.  
  185.  
  186. #define sendline(c) putchar(c & Wcsmask)
  187.  
  188. #define xsendline(c) putchar(c)
  189.  
  190. flushmo()
  191. {
  192.     fflush(stdout);
  193. }
  194.  
  195. int Zctlesc;    /* Encode control characters */
  196. int Nozmodem = 0;    /* If invoked as "sb" */
  197. char *Progname = "sz";
  198. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  199. #include "zm.c"
  200.  
  201.  
  202. main(argc, argv)
  203. char *argv[];
  204. {
  205.     register char *cp;
  206.     register npats;
  207.     int agcnt; char **agcv;
  208.     char **patts;
  209.     static char xXbuf[BUFSIZ];
  210.  
  211.     if ((cp = getenv("ZNULLS")) && *cp)
  212.         Znulls = atoi(cp);
  213.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  214.         Restricted=TRUE;
  215.     chkinvok(argv[0]);
  216.  
  217.     Rxtimeout = 600;
  218.     npats=0;
  219.     if (argc<2)
  220.         usage();
  221.     setbuf(stdout, xXbuf);        
  222.     while (--argc) {
  223.         cp = *++argv;
  224.         if (*cp++ == '-' && *cp) {
  225.             while ( *cp) {
  226.                 switch(*cp++) {
  227.                 case '+':
  228.                     Lzmanag = ZMAPND; break;
  229.                 case '1':
  230.                     iofd = 1; break;
  231. #ifdef CSTOPB
  232.                 case '2':
  233.                     Twostop = TRUE; break;
  234. #endif
  235.                 case '7':
  236.                     Wcsmask=0177; break;
  237.                 case 'a':
  238.                     Lzconv = ZCNL;
  239.                     Ascii = TRUE; break;
  240.                 case 'b':
  241.                     Lzconv = ZCBIN; break;
  242.                 case 'C':
  243.                     if (--argc < 1) {
  244.                         usage();
  245.                     }
  246.                     Cmdtries = atoi(*++argv);
  247.                     break;
  248.                 case 'i':
  249.                     Cmdack1 = ZCACK1;
  250.                     /* **** FALL THROUGH TO **** */
  251.                 case 'c':
  252.                     if (--argc != 1) {
  253.                         usage();
  254.                     }
  255.                     Command = TRUE;
  256.                     Cmdstr = *++argv;
  257.                     break;
  258.                 case 'd':
  259.                     ++Dottoslash;
  260.                     /* **** FALL THROUGH TO **** */
  261.                 case 'f':
  262.                     Fullname=TRUE; break;
  263.                 case 'e':
  264.                     Zctlesc = 1; break;
  265.                 case 'k':
  266.                     blklen=KSIZE; break;
  267.                 case 'L':
  268.                     if (--argc < 1) {
  269.                         usage();
  270.                     }
  271.                     blkopt = atoi(*++argv);
  272.                     if (blkopt<24 || blkopt>1024)
  273.                         usage();
  274.                     break;
  275.                 case 'l':
  276.                     if (--argc < 1) {
  277.                         usage();
  278.                     }
  279.                     Tframlen = atoi(*++argv);
  280.                     if (Tframlen<32 || Tframlen>1024)
  281.                         usage();
  282.                     break;
  283.                 case 'N':
  284.                     Lzmanag = ZMNEWL;  break;
  285.                 case 'n':
  286.                     Lzmanag = ZMNEW;  break;
  287.                 case 'o':
  288.                     Wantfcs32 = FALSE; break;
  289.                 case 'p':
  290.                     Lzmanag = ZMPROT;  break;
  291.                 case 'r':
  292.                     Lzconv = ZCRESUM;
  293.                 case 'q':
  294.                     Quiet=TRUE; Verbose=0; break;
  295.                 case 't':
  296.                     if (--argc < 1) {
  297.                         usage();
  298.                     }
  299.                     Rxtimeout = atoi(*++argv);
  300.                     if (Rxtimeout<10 || Rxtimeout>1000)
  301.                         usage();
  302.                     break;
  303.                 case 'T':
  304.                     Testattn = TRUE; break;
  305.                 case 'u':
  306.                     ++Unlinkafter; break;
  307.                 case 'v':
  308.                     ++Verbose; break;
  309.                 case 'w':
  310.                     if (--argc < 1) {
  311.                         usage();
  312.                     }
  313.                     Txwindow = atoi(*++argv);
  314.                     if (Txwindow < 256)
  315.                         Txwindow = 256;
  316.                     Txwindow = (Txwindow/64) * 64;
  317.                     Txwspac = Txwindow/4;
  318.                     if (blkopt > Txwspac
  319.                      || (!blkopt && Txwspac < 1024))
  320.                         blkopt = Txwspac;
  321.                     break;
  322.                 case 'X':
  323.                     ++Modem2; break;
  324.                 case 'Y':
  325.                     Lskipnocor = TRUE;
  326.                     /* **** FALLL THROUGH TO **** */
  327.                 case 'y':
  328.                     Lzmanag = ZMCLOB; break;
  329.                 default:
  330.                     usage();
  331.                 }
  332.             }
  333.         }
  334.         else if ( !npats && argc>0) {
  335.             if (argv[0][0]) {
  336.                 npats=argc;
  337.                 patts=argv;
  338.                 if ( !strcmp(*patts, "-"))
  339.                     iofd = 1;
  340.             }
  341.         }
  342.     }
  343.     if (npats < 1 && !Command) 
  344.         usage();
  345.     if (Verbose) {
  346.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  347.             printf("Can't open log file %s\n",LOGFILE);
  348.             exit(0200);
  349.         }
  350.         setbuf(stderr, NULL);
  351.     }
  352.     if ((Fromcu=from_cu()) && !Quiet) {
  353.         if (Verbose == 0)
  354.             Verbose = 2;
  355.     }
  356.  
  357.     mode(1);
  358.  
  359.     if (signal(SIGINT, bibi) == SIG_IGN) {
  360.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  361.     } else {
  362.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  363.     }
  364.     if ( !Fromcu)
  365.         signal(SIGQUIT, SIG_IGN);
  366.     signal(SIGTERM, bibi);
  367.  
  368.     if ( !Modem2) {
  369.         if (!Nozmodem) {
  370.             printf("rz\r");  fflush(stdout);
  371.         }
  372.         if (!Command && !Quiet && Verbose != 1) {
  373.             fprintf(stderr, "%s: %d file%s requested:\r\n",
  374.              Progname, npats, npats>1?"s":"");
  375.             for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
  376.                 fprintf(stderr, "%s ", *agcv++);
  377.             }
  378.             fprintf(stderr, "\r\n");
  379.             printf("\r\n\bSending in Batch Mode\r\n");
  380.         }
  381.         if (!Nozmodem) {
  382.             stohdr(0L);
  383.             if (Command)
  384.                 Txhdr[ZF0] = ZCOMMAND;
  385.             zshhdr(ZRQINIT, Txhdr);
  386.         }
  387.     }
  388.     fflush(stdout);
  389.  
  390.     if (Command) {
  391.         if (getzrxinit()) {
  392.             Exitcode=0200; canit();
  393.         }
  394.         else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  395.             Exitcode=0200; canit();
  396.         }
  397.     } else if (wcsend(npats, patts)==ERROR) {
  398.         Exitcode=0200;
  399.         canit();
  400.     }
  401.     fflush(stdout);
  402.     mode(0);
  403.     exit((errcnt != 0) | Exitcode);
  404.     /*NOTREACHED*/
  405. }
  406.  
  407. wcsend(argc, argp)
  408. char *argp[];
  409. {
  410.     register n;
  411.  
  412.     Crcflg=FALSE;
  413.     firstsec=TRUE;
  414.     bytcnt = -1;
  415.     for (n=0; n<argc; ++n) {
  416.         Totsecs = 0;
  417.         if (wcs(argp[n])==ERROR)
  418.             return ERROR;
  419.     }
  420.     Totsecs = 0;
  421.     if (Filcnt==0) {    /* bitch if we couldn't open ANY files */
  422.         if (1) {
  423.             Command = TRUE;
  424.             Cmdstr = "echo \"sz: Can't open any requested files\"";
  425.             if (getnak()) {
  426.                 Exitcode=0200; canit();
  427.             }
  428.             if (!Zmodem)
  429.                 canit();
  430.             else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  431.                 Exitcode=0200; canit();
  432.             }
  433.             Exitcode = 1; return OK;
  434.         }
  435.         canit();
  436.         fprintf(stderr,"\r\nCan't open any requested files.\r\n");
  437.         return ERROR;
  438.     }
  439.     if (Zmodem)
  440.         saybibi();
  441.     else if ( !Modem2)
  442.         wctxpn("");
  443.     return OK;
  444. }
  445.  
  446. wcs(oname)
  447. char *oname;
  448. {
  449.     register c;
  450.     register char *p;
  451.     struct stat f;
  452.     char name[PATHLEN];
  453.  
  454.     strcpy(name, oname);
  455.  
  456.     if (Restricted) {
  457.         /* restrict pathnames to current tree or uucppublic */
  458.         if ( substr(name, "../")
  459.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  460.             canit();
  461.             fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
  462.             return ERROR;
  463.         }
  464.     }
  465.  
  466.     if ( !strcmp(oname, "-")) {
  467.         if ((p = getenv("ONAME")) && *p)
  468.             strcpy(name, p);
  469.         else
  470.             sprintf(name, "s%d.sz", getpid());
  471.         in = stdin;
  472.     }
  473.     else if ((in=fopen(oname, "r"))==NULL) {
  474.         ++errcnt;
  475.         return OK;    /* pass over it, there may be others */
  476.     }
  477.     ++Noeofseen;  Lastread = 0;  Lastn = -1; Dontread = FALSE;
  478.     /* Check for directory or block special files */
  479.     fstat(fileno(in), &f);
  480.     c = f.st_mode & S_IFMT;
  481.     if (c == S_IFDIR || c == S_IFBLK) {
  482.         fclose(in);
  483.         return OK;
  484.     }
  485.  
  486.     ++Filcnt;
  487.     switch (wctxpn(name)) {
  488.     case ERROR:
  489.         return ERROR;
  490.     case ZSKIP:
  491.         return OK;
  492.     }
  493.     if (!Zmodem && wctx(f.st_size)==ERROR)
  494.         return ERROR;
  495.     if (Unlinkafter)
  496.         unlink(oname);
  497.     return 0;
  498. }
  499.  
  500. /*
  501.  * generate and transmit pathname block consisting of
  502.  *  pathname (null terminated),
  503.  *  file length, mode time and file mode in octal
  504.  *  as provided by the Unix fstat call.
  505.  *  N.B.: modifies the passed name, may extend it!
  506.  */
  507. wctxpn(name)
  508. char *name;
  509. {
  510.     register char *p, *q;
  511.     char name2[PATHLEN];
  512.     struct stat f;
  513.  
  514.     if (Modem2) {
  515.         if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
  516.             fprintf(stderr, "Sending %s, %ld blocks: ",
  517.               name, f.st_size>>7);
  518.         }
  519.         fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
  520.         return OK;
  521.     }
  522.     zperr("Awaiting pathname nak for %s", *name?name:"<END>");
  523.     if ( !Zmodem)
  524.         if (getnak())
  525.             return ERROR;
  526.  
  527.     q = (char *) 0;
  528.     if (Dottoslash) {        /* change . to . */
  529.         for (p=name; *p; ++p) {
  530.             if (*p == '/')
  531.                 q = p;
  532.             else if (*p == '.')
  533.                 *(q=p) = '/';
  534.         }
  535.         if (q && strlen(++q) > 8) {    /* If name>8 chars */
  536.             q += 8;            /*   make it .ext */
  537.             strcpy(name2, q);    /* save excess of name */
  538.             *q = '.';
  539.             strcpy(++q, name2);    /* add it back */
  540.         }
  541.     }
  542.  
  543.     for (p=name, q=txbuf ; *p; )
  544.         if ((*q++ = *p++) == '/' && !Fullname)
  545.             q = txbuf;
  546.     *q++ = 0;
  547.     p=q;
  548.     while (q < (txbuf + KSIZE))
  549.         *q++ = 0;
  550.     if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
  551.         sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
  552.     /* force 1k blocks if name won't fit in 128 byte block */
  553.     if (txbuf[125])
  554.         blklen=KSIZE;
  555.     else {        /* A little goodie for IMP/KMD */
  556.         if (Zmodem)
  557.             blklen = SECSIZ;
  558.         txbuf[127] = (f.st_size + 127) >>7;
  559.         txbuf[126] = (f.st_size + 127) >>15;
  560.     }
  561.     if (Zmodem)
  562.         return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
  563.     if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
  564.         return ERROR;
  565.     return OK;
  566. }
  567.  
  568. getnak()
  569. {
  570.     register firstch;
  571.  
  572.     Lastrx = 0;
  573.     for (;;) {
  574.         switch (firstch = readock(800,1)) {
  575.         case ZPAD:
  576.             if (getzrxinit())
  577.                 return ERROR;
  578.             Ascii = 0;
  579.             return FALSE;
  580.         case TIMEOUT:
  581.             zperr("Timeout on pathname");
  582.             return TRUE;
  583.         case WANTG:
  584. #ifdef USG
  585.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  586. #endif
  587.             Optiong = TRUE;
  588.             blklen=KSIZE;
  589.         case WANTCRC:
  590.             Crcflg = TRUE;
  591.         case NAK:
  592.             return FALSE;
  593.         case CAN:
  594.             if ((firstch = readock(20,1)) == CAN && Lastrx == CAN)
  595.                 return TRUE;
  596.         default:
  597.             break;
  598.         }
  599.         Lastrx = firstch;
  600.     }
  601. }
  602.  
  603.  
  604. wctx(flen)
  605. long flen;
  606. {
  607.     register int thisblklen;
  608.     register int sectnum, attempts, firstch;
  609.     long charssent;
  610.  
  611.     charssent = 0;  firstsec=TRUE;  thisblklen = blklen;
  612.     vfile("wctx:file length=%ld", flen);
  613.  
  614.     while ((firstch=readock(Rxtimeout, 2))!=NAK && firstch != WANTCRC
  615.       && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
  616.         ;
  617.     if (firstch==CAN) {
  618.         zperr("Receiver CANcelled");
  619.         return ERROR;
  620.     }
  621.     if (firstch==WANTCRC)
  622.         Crcflg=TRUE;
  623.     if (firstch==WANTG)
  624.         Crcflg=TRUE;
  625.     sectnum=0;
  626.     for (;;) {
  627.         if (flen <= (charssent + 896L))
  628.             thisblklen = 128;
  629.         if ( !filbuf(txbuf, thisblklen))
  630.             break;
  631.         if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
  632.             return ERROR;
  633.         charssent += thisblklen;
  634.     }
  635.     fclose(in);
  636.     attempts=0;
  637.     do {
  638.         purgeline();
  639.         sendline(EOT);
  640.         fflush(stdout);
  641.         ++attempts;
  642.     }
  643.         while ((firstch=(readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX);
  644.     if (attempts == RETRYMAX) {
  645.         zperr("No ACK on EOT");
  646.         return ERROR;
  647.     }
  648.     else
  649.         return OK;
  650. }
  651.  
  652. wcputsec(buf, sectnum, cseclen)
  653. char *buf;
  654. int sectnum;
  655. int cseclen;    /* data length of this sector to send */
  656. {
  657.     register checksum, wcj;
  658.     register char *cp;
  659.     unsigned oldcrc;
  660.     int firstch;
  661.     int attempts;
  662.  
  663.     firstch=0;    /* part of logic to detect CAN CAN */
  664.  
  665.     if (Verbose>2)
  666.         fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 );
  667.     else if (Verbose>1)
  668.         fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
  669.     for (attempts=0; attempts <= RETRYMAX; attempts++) {
  670.         Lastrx= firstch;
  671.         sendline(cseclen==KSIZE?STX:SOH);
  672.         sendline(sectnum);
  673.         sendline(-sectnum -1);
  674.         oldcrc=checksum=0;
  675.         for (wcj=cseclen,cp=buf; --wcj>=0; ) {
  676.             sendline(*cp);
  677.             oldcrc=updcrc((0377& *cp), oldcrc);
  678.             checksum += *cp++;
  679.         }
  680.         if (Crcflg) {
  681.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  682.             sendline((int)oldcrc>>8);
  683.             sendline((int)oldcrc);
  684.         }
  685.         else
  686.             sendline(checksum);
  687.  
  688.         if (Optiong) {
  689.             firstsec = FALSE; return OK;
  690.         }
  691.         firstch = readock(Rxtimeout, (Noeofseen&§num) ? 2:1);
  692. gotnak:
  693.         switch (firstch) {
  694.         case CAN:
  695.             if(Lastrx == CAN) {
  696. cancan:
  697.                 zperr("Cancelled");  return ERROR;
  698.             }
  699.             break;
  700.         case TIMEOUT:
  701.             zperr("Timeout on sector ACK"); continue;
  702.         case WANTCRC:
  703.             if (firstsec)
  704.                 Crcflg = TRUE;
  705.         case NAK:
  706.             zperr("NAK on sector"); continue;
  707.         case ACK: 
  708.             firstsec=FALSE;
  709.             Totsecs += (cseclen>>7);
  710.             return OK;
  711.         case ERROR:
  712.             zperr("Got burst for sector ACK"); break;
  713.         default:
  714.             zperr("Got %02x for sector ACK", firstch); break;
  715.         }
  716.         for (;;) {
  717.             Lastrx = firstch;
  718.             if ((firstch = readock(Rxtimeout, 2)) == TIMEOUT)
  719.                 break;
  720.             if (firstch == NAK || firstch == WANTCRC)
  721.                 goto gotnak;
  722.             if (firstch == CAN && Lastrx == CAN)
  723.                 goto cancan;
  724.         }
  725.     }
  726.     zperr("Retry Count Exceeded");
  727.     return ERROR;
  728. }
  729.  
  730. /* fill buf with count chars padding with ^Z for CPM */
  731. filbuf(buf, count)
  732. register char *buf;
  733. {
  734.     register c, m;
  735.  
  736.     if ( !Ascii) {
  737.         m = read(fileno(in), buf, count);
  738.         if (m <= 0)
  739.             return 0;
  740.         while (m < count)
  741.             buf[m++] = 032;
  742.         return count;
  743.     }
  744.     m=count;
  745.     if (Lfseen) {
  746.         *buf++ = 012; --m; Lfseen = 0;
  747.     }
  748.     while ((c=getc(in))!=EOF) {
  749.         if (c == 012) {
  750.             *buf++ = 015;
  751.             if (--m == 0) {
  752.                 Lfseen = TRUE; break;
  753.             }
  754.         }
  755.         *buf++ =c;
  756.         if (--m == 0)
  757.             break;
  758.     }
  759.     if (m==count)
  760.         return 0;
  761.     else
  762.         while (--m>=0)
  763.             *buf++ = CPMEOF;
  764.     return count;
  765. }
  766. /* fill buf with count chars */
  767. zfilbuf(buf, count)
  768. register char *buf;
  769. {
  770.     register c, m;
  771.  
  772.     m=count;
  773.     while ((c=getc(in))!=EOF) {
  774.         *buf++ =c;
  775.         if (--m == 0)
  776.             break;
  777.     }
  778.     return (count - m);
  779. }
  780.  
  781. /* VARARGS1 */
  782. vfile(f, a, b, c)
  783. register char *f;
  784. {
  785.     if (Verbose > 2) {
  786.         fprintf(stderr, f, a, b, c);
  787.         fprintf(stderr, "\n");
  788.     }
  789. }
  790.  
  791.  
  792. alrm()
  793. {
  794.     longjmp(tohere, -1);
  795. }
  796.  
  797.  
  798. /*
  799.  * readock(timeout, count) reads character(s) from file descriptor 0
  800.  *  (1 <= count <= 3)
  801.  * it attempts to read count characters. If it gets more than one,
  802.  * it is an error unless all are CAN
  803.  * (otherwise, only normal response is ACK, CAN, or C)
  804.  *  Only looks for one if Optiong, which signifies cbreak, not raw input
  805.  *
  806.  * timeout is in tenths of seconds
  807.  */
  808. readock(timeout, count)
  809. {
  810.     register int c;
  811.     static char byt[5];
  812.  
  813.     if (Optiong)
  814.         count = 1;    /* Special hack for cbreak */
  815.  
  816.     fflush(stdout);
  817.     if (setjmp(tohere)) {
  818.         zperr("TIMEOUT");
  819.         return TIMEOUT;
  820.     }
  821.     c = timeout/10;
  822.     if (c<2)
  823.         c=2;
  824.     if (Verbose>5) {
  825.         fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
  826.         byt[1] = 0;
  827.     }
  828.     signal(SIGALRM, alrm); alarm(c);
  829. #ifdef ONEREAD
  830.     c=read(iofd, byt, 1);        /* regulus raw read is unique */
  831. #else
  832.     c=read(iofd, byt, count);
  833. #endif
  834.     alarm(0);
  835.     if (Verbose>5)
  836.         fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
  837.     if (c<1)
  838.         return TIMEOUT;
  839.     if (c==1)
  840.         return (byt[0]&0377);
  841.     else
  842.         while (c)
  843.             if (byt[--c] != CAN)
  844.                 return ERROR;
  845.     return CAN;
  846. }
  847. readline(n)
  848. {
  849.     return (readock(n, 1));
  850. }
  851.  
  852.  
  853. purgeline()
  854. {
  855. #ifdef USG
  856.     ioctl(iofd, TCFLSH, 0);
  857. #else
  858.     lseek(iofd, 0L, 2);
  859. #endif
  860. }
  861.  
  862.  
  863. /* send cancel string to get the other end to shut up */
  864. canit()
  865. {
  866.     static char canistr[] = {
  867.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  868.     };
  869.  
  870.     printf(canistr);
  871.     fflush(stdout);
  872. }
  873.  
  874. /*
  875.  * Log an error
  876.  */
  877. /*VARARGS1*/
  878. zperr(s,p,u)
  879. char *s, *p, *u;
  880. {
  881.     if (Verbose <= 0)
  882.         return;
  883.     fprintf(stderr, "Retry %d: ", errors);
  884.     fprintf(stderr, s, p, u);
  885.     fprintf(stderr, "\n");
  886. }
  887.  
  888. /*
  889.  * return 1 iff stdout and stderr are different devices
  890.  *  indicating this program operating with a modem on a
  891.  *  different line
  892.  */
  893. from_cu()
  894. {
  895.     struct stat a, b;
  896.     fstat(1, &a); fstat(2, &b);
  897.     return (a.st_rdev != b.st_rdev);
  898. }
  899.  
  900. /*
  901.  * substr(string, token) searches for token in string s
  902.  * returns pointer to token within string if found, NULL otherwise
  903.  */
  904. char *
  905. substr(s, t)
  906. register char *s,*t;
  907. {
  908.     register char *ss,*tt;
  909.     /* search for first char of token */
  910.     for (ss=s; *s; s++)
  911.         if (*s == *t)
  912.             /* compare token with substring */
  913.             for (ss=s,tt=t; ;) {
  914.                 if (*tt == 0)
  915.                     return s;
  916.                 if (*ss++ != *tt++)
  917.                     break;
  918.             }
  919.     return NULL;
  920. }
  921.  
  922. char *babble[] = {
  923.     "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
  924.     "    (Y) = Option applies to YMODEM only",
  925.     "    (Z) = Option applies to ZMODEM only",
  926.     "Usage:    sz [-12+abdefkLlNnquvwYy] [-] file ...",
  927.     "    sz [-12Ceqv] -c COMMAND",
  928.     "    sb [-12adfkquv] [-] file ...",
  929.     "    sx [-12akquv] [-] file",
  930.     "    1 Use stdout for modem input",
  931. #ifdef CSTOPB
  932.     "    2 Use 2 stop bits",
  933. #endif
  934.     "    + Append to existing destination file (Z)",
  935.     "    a (ASCII) change NL to CR/LF",
  936.     "    b Binary file transfer override",
  937.     "    c send COMMAND (Z)",
  938.     "    d Change '.' to '/' in pathnames (Y/Z)",
  939.     "    e Escape all control characters (Z)",
  940.     "    f send Full pathname (Y/Z)",
  941.     "    i send COMMAND, ack Immediately (Z)",
  942.     "    k Send 1024 byte packets (Y)",
  943.     "    L N Limit subpacket length to N bytes (Z)",
  944.     "    l N Limit frame length to N bytes (l>=L) (Z)",
  945.     "    n send file if source newer (Z)",
  946.     "    N send file if source newer or longer (Z)",
  947.     "    o Use 16 bit CRC instead of 32 bit CRC (Z)",
  948.     "    p Protect existing destination file (Z)",
  949.     "    r Resume/Recover interrupted file transfer (Z)",
  950.     "    q Quiet (no progress reports)",
  951.     "    u Unlink file after transmission",
  952.     "    v Verbose - provide debugging information",
  953.     "    w N Window is N bytes (Z)",
  954.     "    Y Yes, overwrite existing file, skip if not present at rx (Z)",
  955.     "    y Yes, overwrite existing file (Z)",
  956.     "- as pathname sends standard input as sPID.sz or environment ONAME",
  957.     ""
  958. };
  959.  
  960. usage()
  961. {
  962.     char **pp;
  963.  
  964.     for (pp=babble; **pp; ++pp)
  965.         fprintf(stderr, "%s\n", *pp);
  966.     fprintf(stderr, "%s for %s by Chuck Forsberg  ", VERSION, OS);
  967.     exit(1);
  968. }
  969.  
  970. /*
  971.  * Get the receiver's init parameters
  972.  */
  973. getzrxinit()
  974. {
  975.     register n;
  976.     struct stat f;
  977.  
  978.     for (n=10; --n>=0; ) {
  979.         
  980.         switch (zgethdr(Rxhdr, 1)) {
  981.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  982.             stohdr(Rxpos);
  983.             zshhdr(ZACK, Txhdr);
  984.             continue;
  985.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  986.             stohdr(0L);
  987.             zshhdr(ZRQINIT, Txhdr);
  988.             continue;
  989.         case ZRINIT:
  990.             Rxflags = 0377 & Rxhdr[ZF0];
  991.             Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  992.             Zctlesc |= Rxflags & TESCCTL;
  993.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  994.             vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  995.             if ( !Fromcu)
  996.                 signal(SIGINT, SIG_IGN);
  997. #ifdef USG
  998.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  999. #endif
  1000. #ifndef READCHECK
  1001. #ifndef USG
  1002.             /* Use 1024 byte frames if no sample/interrupt */
  1003.             if (Rxbuflen < 32 || Rxbuflen > 1024) {
  1004.                 Rxbuflen = 1024;
  1005.                 vfile("Rxbuflen=%d", Rxbuflen);
  1006.             }
  1007. #endif
  1008. #endif
  1009.             /* Override to force shorter frame length */
  1010.             if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  1011.                 Rxbuflen = Tframlen;
  1012.             if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
  1013.                 Rxbuflen = Tframlen;
  1014.             vfile("Rxbuflen=%d", Rxbuflen);
  1015.  
  1016.             /* If using a pipe for testing set lower buf len */
  1017.             fstat(iofd, &f);
  1018.             if ((f.st_mode & S_IFMT) != S_IFCHR
  1019.               && (Rxbuflen == 0 || Rxbuflen > 4096))
  1020.                 Rxbuflen = 4096;
  1021.             /*
  1022.              * If input is not a regular file, force ACK's each 1024
  1023.              *  (A smarter strategey could be used here ...)
  1024.              */
  1025.             fstat(fileno(in), &f);
  1026.             if (((f.st_mode & S_IFMT) != S_IFREG)
  1027.               && (Rxbuflen == 0 || Rxbuflen > 1024))
  1028.                 Rxbuflen = 1024;
  1029.             vfile("Rxbuflen=%d", Rxbuflen);
  1030.  
  1031.             return (sendzsinit());
  1032.         case ZCAN:
  1033.         case TIMEOUT:
  1034.             return ERROR;
  1035.         case ZRQINIT:
  1036.             if (Rxhdr[ZF0] == ZCOMMAND)
  1037.                 continue;
  1038.         default:
  1039.             zshhdr(ZNAK, Txhdr);
  1040.             continue;
  1041.         }
  1042.     }
  1043.     return ERROR;
  1044. }
  1045.  
  1046. /* Send send-init information */
  1047. sendzsinit()
  1048. {
  1049.     register c;
  1050.  
  1051.     if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
  1052.         return OK;
  1053.     errors = 0;
  1054.     for (;;) {
  1055.         stohdr(0L);
  1056.         if (Zctlesc) {
  1057.             Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr);
  1058.         }
  1059.         else
  1060.             zsbhdr(ZSINIT, Txhdr);
  1061.         zsdata(Myattn, 1+strlen(Myattn), ZCRCW);
  1062.         c = zgethdr(Rxhdr, 1);
  1063.         switch (c) {
  1064.         case ZCAN:
  1065.             return ERROR;
  1066.         case ZACK:
  1067.             return OK;
  1068.         default:
  1069.             if (++errors > 19)
  1070.                 return ERROR;
  1071.             continue;
  1072.         }
  1073.     }
  1074. }
  1075.  
  1076. /* Send file name and related info */
  1077. zsendfile(buf, blen)
  1078. char *buf;
  1079. {
  1080.     register c;
  1081.  
  1082.     for (;;) {
  1083.         Txhdr[ZF0] = Lzconv;    /* file conversion request */
  1084.         Txhdr[ZF1] = Lzmanag;    /* file management request */
  1085.         if (Lskipnocor)
  1086.             Txhdr[ZF1] |= ZMSKNOLOC;
  1087.         Txhdr[ZF2] = Lztrans;    /* file transport request */
  1088.         Txhdr[ZF3] = 0;
  1089.         zsbhdr(ZFILE, Txhdr);
  1090.         zsdata(buf, blen, ZCRCW);
  1091. again:
  1092.         c = zgethdr(Rxhdr, 1);
  1093.         switch (c) {
  1094.         case ZRINIT:
  1095.             while ((c = readline(50)) > 0)
  1096.                 if (c == ZPAD) {
  1097.                     goto again;
  1098.                 }
  1099.             /* **** FALL THRU TO **** */
  1100.         default:
  1101.             continue;
  1102.         case ZCAN:
  1103.         case TIMEOUT:
  1104.         case ZABORT:
  1105.         case ZFIN:
  1106.             return ERROR;
  1107.         case ZSKIP:
  1108.             fclose(in); return c;
  1109.         case ZRPOS:
  1110.             /*
  1111.              * Suppress zcrcw request otherwise triggered by
  1112.              * lastyunc==bytcnt
  1113.              */
  1114.             Lastsync = (bytcnt = Txpos = Rxpos) -1;
  1115.             fseek(in, Rxpos, 0);
  1116.             Dontread = FALSE;
  1117.             return zsendfdata();
  1118.         }
  1119.     }
  1120. }
  1121.  
  1122. /* Send the data in the file */
  1123. zsendfdata()
  1124. {
  1125.     register c, e, n;
  1126.     register newcnt;
  1127.     register long tcount = 0;
  1128.     int junkcount;        /* Counts garbage chars received by TX */
  1129.     static int tleft = 6;    /* Counter for test mode */
  1130.  
  1131.     if (Baudrate > 300)
  1132.         blklen = 256;
  1133.     if (Baudrate > 1200)
  1134.         blklen = 512;
  1135.     if (Baudrate > 2400)
  1136.         blklen = KSIZE;
  1137.     if (Rxbuflen && blklen>Rxbuflen)
  1138.         blklen = Rxbuflen;
  1139.     if (blkopt && blklen > blkopt)
  1140.         blklen = blkopt;
  1141.     vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1142.     vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  1143.     Lrxpos = 0;
  1144.     junkcount = 0;
  1145.     Beenhereb4 = FALSE;
  1146. somemore:
  1147.     if (setjmp(intrjmp)) {
  1148. waitack:
  1149.         junkcount = 0;
  1150.         c = getinsync(0);
  1151. gotack:
  1152.         switch (c) {
  1153.         default:
  1154.         case ZCAN:
  1155.             fclose(in);
  1156.             return ERROR;
  1157.         case ZSKIP:
  1158.             fclose(in);
  1159.             return c;
  1160.         case ZACK:
  1161.         case ZRPOS:
  1162.             break;
  1163.         case ZRINIT:
  1164.             return OK;
  1165.         }
  1166. #ifdef READCHECK
  1167.         /*
  1168.          * If the reverse channel can be tested for data,
  1169.          *  this logic may be used to detect error packets
  1170.          *  sent by the receiver, in place of setjmp/longjmp
  1171.          *  rdchk(fdes) returns non 0 if a character is available
  1172.          */
  1173.         while (rdchk(iofd)) {
  1174. #ifdef SVR2
  1175.             switch (checked)
  1176. #else
  1177.             switch (readline(1))
  1178. #endif
  1179.             {
  1180.             case CAN:
  1181.             case ZPAD:
  1182.                 c = getinsync(1);
  1183.                 goto gotack;
  1184.             case XOFF:        /* Wait a while for an XON */
  1185.             case XOFF|0200:
  1186.                 readline(100);
  1187.             }
  1188.         }
  1189. #endif
  1190.     }
  1191.  
  1192.     if ( !Fromcu)
  1193.         signal(SIGINT, onintr);
  1194.     newcnt = Rxbuflen;
  1195.     Txwcnt = 0;
  1196.     stohdr(Txpos);
  1197.     zsbhdr(ZDATA, Txhdr);
  1198.  
  1199.     /*
  1200.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  1201.      *  many times.  Each time the signal should be caught, causing the
  1202.      *  file to be started over from the beginning.
  1203.      */
  1204.     if (Testattn) {
  1205.         if ( --tleft)
  1206.             while (tcount < 20000) {
  1207.                 printf(qbf); fflush(stdout);
  1208.                 tcount += strlen(qbf);
  1209. #ifdef READCHECK
  1210.                 while (rdchk(iofd)) {
  1211. #ifdef SVR2
  1212.                     switch (checked)
  1213. #else
  1214.                     switch (readline(1))
  1215. #endif
  1216.                     {
  1217.                     case CAN:
  1218.                     case ZPAD:
  1219. #ifdef TCFLSH
  1220.                         ioctl(iofd, TCFLSH, 1);
  1221. #endif
  1222.                         goto waitack;
  1223.                     case XOFF:    /* Wait for XON */
  1224.                     case XOFF|0200:
  1225.                         readline(100);
  1226.                     }
  1227.                 }
  1228. #endif
  1229.             }
  1230.         signal(SIGINT, SIG_IGN); canit();
  1231.         sleep(3); purgeline(); mode(0);
  1232.         printf("\nsz: Tcount = %ld\n", tcount);
  1233.         if (tleft) {
  1234.             printf("ERROR: Interrupts Not Caught\n");
  1235.             exit(1);
  1236.         }
  1237.         exit(0);
  1238.     }
  1239.  
  1240.     do {
  1241.         if (Dontread) {
  1242.             n = Lastn;
  1243.         } else {
  1244.             n = zfilbuf(txbuf, blklen);
  1245.             Lastread = Txpos;  Lastn = n;
  1246.         }
  1247.         Dontread = FALSE;
  1248.         if (n < blklen)
  1249.             e = ZCRCE;
  1250.         else if (junkcount > 3)
  1251.             e = ZCRCW;
  1252.         else if (bytcnt == Lastsync)
  1253.             e = ZCRCW;
  1254.         else if (Rxbuflen && (newcnt -= n) <= 0)
  1255.             e = ZCRCW;
  1256.         else if (Txwindow && (Txwcnt += n) >= Txwspac) {
  1257.             Txwcnt = 0;  e = ZCRCQ;
  1258.         }
  1259.         else
  1260.             e = ZCRCG;
  1261.         if (Verbose>1)
  1262.             fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1263.               Txpos, Crc32t?" CRC-32":"");
  1264.         zsdata(txbuf, n, e);
  1265.         bytcnt = Txpos += n;
  1266.         if (e == ZCRCW)
  1267.             goto waitack;
  1268. #ifdef READCHECK
  1269.         /*
  1270.          * If the reverse channel can be tested for data,
  1271.          *  this logic may be used to detect error packets
  1272.          *  sent by the receiver, in place of setjmp/longjmp
  1273.          *  rdchk(fdes) returns non 0 if a character is available
  1274.          */
  1275.         fflush(stdout);
  1276.         while (rdchk(iofd)) {
  1277. #ifdef SVR2
  1278.             switch (checked)
  1279. #else
  1280.             switch (readline(1))
  1281. #endif
  1282.             {
  1283.             case CAN:
  1284.             case ZPAD:
  1285.                 c = getinsync(1);
  1286.                 if (c == ZACK)
  1287.                     break;
  1288. #ifdef TCFLSH
  1289.                 ioctl(iofd, TCFLSH, 1);
  1290. #endif
  1291.                 /* zcrce - dinna wanna starta ping-pong game */
  1292.                 zsdata(txbuf, 0, ZCRCE);
  1293.                 goto gotack;
  1294.             case XOFF:        /* Wait a while for an XON */
  1295.             case XOFF|0200:
  1296.                 readline(100);
  1297.             default:
  1298.                 ++junkcount;
  1299.             }
  1300.         }
  1301. #endif    /* READCHECK */
  1302.         if (Txwindow) {
  1303.             while ((tcount = Txpos - Lrxpos) >= Txwindow) {
  1304.                 vfile("%ld window >= %u", tcount, Txwindow);
  1305.                 if (e != ZCRCQ)
  1306.                     zsdata(txbuf, 0, e = ZCRCQ);
  1307.                 c = getinsync(1);
  1308.                 if (c != ZACK) {
  1309. #ifdef TCFLSH
  1310.                     ioctl(iofd, TCFLSH, 1);
  1311. #endif
  1312.                     zsdata(txbuf, 0, ZCRCE);
  1313.                     goto gotack;
  1314.                 }
  1315.             }
  1316.             vfile("window = %ld", tcount);
  1317.         }
  1318.     } while (n == blklen);
  1319.     if ( !Fromcu)
  1320.         signal(SIGINT, SIG_IGN);
  1321.  
  1322.     for (;;) {
  1323.         stohdr(Txpos);
  1324.         zsbhdr(ZEOF, Txhdr);
  1325.         switch (getinsync(0)) {
  1326.         case ZACK:
  1327.             continue;
  1328.         case ZRPOS:
  1329.             goto somemore;
  1330.         case ZRINIT:
  1331.             return OK;
  1332.         case ZSKIP:
  1333.             fclose(in);
  1334.             return c;
  1335.         default:
  1336.             fclose(in);
  1337.             return ERROR;
  1338.         }
  1339.     }
  1340. }
  1341.  
  1342. /*
  1343.  * Respond to receiver's complaint, get back in sync with receiver
  1344.  */
  1345. getinsync(flag)
  1346. {
  1347.     register c;
  1348.  
  1349.     for (;;) {
  1350.         if (Testattn) {
  1351.             printf("\r\n\n\n***** Signal Caught *****\r\n");
  1352.             Rxpos = 0; c = ZRPOS;
  1353.         } else
  1354.             c = zgethdr(Rxhdr, 0);
  1355.         switch (c) {
  1356.         case ZCAN:
  1357.         case ZABORT:
  1358.         case ZFIN:
  1359.         case TIMEOUT:
  1360.             return ERROR;
  1361.         case ZRPOS:
  1362.             /* ************************************* */
  1363.             /*  If sending to a modem beuufer, you   */
  1364.             /*   might send a break at this point to */
  1365.             /*   dump the modem's buffer.         */
  1366.             if (Lastn >= 0 && Lastread == Rxpos) {
  1367.                 Dontread = TRUE;
  1368.             } else {
  1369.                 clearerr(in);    /* In case file EOF seen */
  1370.                 fseek(in, Rxpos, 0);
  1371.             }
  1372.             bytcnt = Lrxpos = Txpos = Rxpos;
  1373.             if (Lastsync == Rxpos) {
  1374.                 if (++Beenhereb4 > 4)
  1375.                     if (blklen > 256)
  1376.                         blklen /= 2;
  1377.             }
  1378.             Lastsync = Rxpos;
  1379.             return c;
  1380.         case ZACK:
  1381.             Lrxpos = Rxpos;
  1382.             if (flag || Txpos == Rxpos)
  1383.                 return ZACK;
  1384.             continue;
  1385.         case ZRINIT:
  1386.         case ZSKIP:
  1387.             fclose(in);
  1388.             return c;
  1389.         case ERROR:
  1390.         default:
  1391.             zsbhdr(ZNAK, Txhdr);
  1392.             continue;
  1393.         }
  1394.     }
  1395. }
  1396.  
  1397.  
  1398. /* Say "bibi" to the receiver, try to do it cleanly */
  1399. saybibi()
  1400. {
  1401.     for (;;) {
  1402.         stohdr(0L);        /* CAF Was zsbhdr - minor change */
  1403.         zshhdr(ZFIN, Txhdr);    /*  to make debugging easier */
  1404.         switch (zgethdr(Rxhdr, 0)) {
  1405.         case ZFIN:
  1406.             sendline('O'); sendline('O'); flushmo();
  1407.         case ZCAN:
  1408.         case TIMEOUT:
  1409.             return;
  1410.         }
  1411.     }
  1412. }
  1413.  
  1414. /* Local screen character display function */
  1415. bttyout(c)
  1416. {
  1417.     if (Verbose)
  1418.         putc(c, stderr);
  1419. }
  1420.  
  1421. /* Send command and related info */
  1422. zsendcmd(buf, blen)
  1423. char *buf;
  1424. {
  1425.     register c;
  1426.     long cmdnum;
  1427.  
  1428.     cmdnum = getpid();
  1429.     errors = 0;
  1430.     for (;;) {
  1431.         stohdr(cmdnum);
  1432.         Txhdr[ZF0] = Cmdack1;
  1433.         zsbhdr(ZCOMMAND, Txhdr);
  1434.         zsdata(buf, blen, ZCRCW);
  1435. listen:
  1436.         Rxtimeout = 100;        /* Ten second wait for resp. */
  1437.         c = zgethdr(Rxhdr, 1);
  1438.  
  1439.         switch (c) {
  1440.         case ZRINIT:
  1441.             goto listen;    /* CAF 8-21-87 */
  1442.         case ERROR:
  1443.         case TIMEOUT:
  1444.             if (++errors > Cmdtries)
  1445.                 return ERROR;
  1446.             continue;
  1447.         case ZCAN:
  1448.         case ZABORT:
  1449.         case ZFIN:
  1450.         case ZSKIP:
  1451.         case ZRPOS:
  1452.             return ERROR;
  1453.         default:
  1454.             if (++errors > 20)
  1455.                 return ERROR;
  1456.             continue;
  1457.         case ZCOMPL:
  1458.             Exitcode = Rxpos;
  1459.             saybibi();
  1460.             return OK;
  1461.         case ZRQINIT:
  1462.             vfile("******** RZ *******");
  1463.             system("rz");
  1464.             vfile("******** SZ *******");
  1465.             goto listen;
  1466.         }
  1467.     }
  1468. }
  1469.  
  1470. /*
  1471.  * If called as sb use YMODEM protocol
  1472.  */
  1473. chkinvok(s)
  1474. char *s;
  1475. {
  1476.     register char *p;
  1477.  
  1478.     p = s;
  1479.     while (*p == '-')
  1480.         s = ++p;
  1481.     while (*p)
  1482.         if (*p++ == '/')
  1483.             s = p;
  1484.     if (*s == 'v') {
  1485.         Verbose=1; ++s;
  1486.     }
  1487.     Progname = s;
  1488.     if (s[0]=='s' && s[1]=='b') {
  1489.         Nozmodem = TRUE; blklen=KSIZE;
  1490.     }
  1491.     if (s[0]=='s' && s[1]=='x') {
  1492.         Modem2 = TRUE;
  1493.     }
  1494. }
  1495. /* End of sz.c */
  1496. \Rogue\Monster\
  1497. else
  1498.   echo "will not over write ./sz.c"
  1499. fi
  1500. if [ `wc -c ./sz.c | awk '{printf $1}'` -ne 31161 ]
  1501. then
  1502. echo `wc -c ./sz.c | awk '{print "Got " $1 ", Expected " 31161}'`
  1503. fi
  1504. if `test ! -s ./rz.c`
  1505. then
  1506. echo "Writing ./rz.c"
  1507. cat > ./rz.c << '\Rogue\Monster\'
  1508. #define VERSION "1.26 08-21-87"
  1509. #define PUBDIR "/usr/spool/uucppublic"
  1510.  
  1511. /*% cc -M0 -Ox -K -i % -o rz; size rz;
  1512. <-xtx-*> cc386 -Ox rz.c -o $B/rz;  size $B/rz
  1513.  *
  1514.  * rz.c By Chuck Forsberg
  1515.  *
  1516.  *    cc -O rz.c -o rz        USG (3.0) Unix
  1517.  *     cc -O -DV7  rz.c -o rz        Unix V7, BSD 2.8 - 4.3
  1518.  *
  1519.  *    ln rz rb;  ln rz rx            For either system
  1520.  *
  1521.  *    ln rz /usr/bin/rzrmail        For remote mail.  Make this the
  1522.  *                    login shell. rzrmail then calls
  1523.  *                    rmail(1) to deliver mail.
  1524.  *
  1525.  *
  1526.  *  Unix is a trademark of Western Electric Company
  1527.  *
  1528.  * A program for Unix to receive files and commands from computers running
  1529.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
  1530.  *  rz uses Unix buffered input to reduce wasted CPU time.
  1531.  *
  1532.  * Iff the program is invoked by rzCOMMAND, output is piped to 
  1533.  * "COMMAND filename"
  1534.  *
  1535.  *  Some systems (Venix, Coherent, Regulus) may not support tty raw mode
  1536.  *  read(2) the same way as Unix. ONEREAD must be defined to force one
  1537.  *  character reads for these systems. Added 7-01-84 CAF
  1538.  *
  1539.  *  Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF 
  1540.  *
  1541.  *  BIX added 6-30-87 to support BIX(TM) upload protocol used by the
  1542.  *  Byte Information Exchange.
  1543.  *
  1544.  *  NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
  1545.  *  doesn't work properly (even though it compiles without error!),
  1546.  *
  1547.  *  HOWMANY may be tuned for best performance
  1548.  *
  1549.  *  USG UNIX (3.0) ioctl conventions courtesy  Jeff Martin
  1550.  */
  1551. #define LOGFILE "/tmp/rzlog"
  1552.  
  1553. #include <stdio.h>
  1554. #include <signal.h>
  1555. #include <setjmp.h>
  1556. #include <ctype.h>
  1557. FILE *popen();
  1558.  
  1559. #define OK 0
  1560. #define FALSE 0
  1561. #define TRUE 1
  1562. #define ERROR (-1)
  1563.  
  1564. /*
  1565.  * Max value for HOWMANY is 255.
  1566.  *   A larger value reduces system overhead but may evoke kernel bugs.
  1567.  *   133 corresponds to an XMODEM/CRC sector
  1568.  */
  1569. #ifndef HOWMANY
  1570. #define HOWMANY 133
  1571. #endif
  1572.  
  1573. int Zmodem=0;        /* ZMODEM protocol requested */
  1574. int Nozmodem = 0;    /* If invoked as "rb" */
  1575. unsigned Baudrate;
  1576. #include "rbsb.c"    /* most of the system dependent stuff here */
  1577.  
  1578. char *substr();
  1579. FILE *fout;
  1580.  
  1581. /*
  1582.  * Routine to calculate the free bytes on the current file system
  1583.  *  ~0 means many free bytes (unknown)
  1584.  */
  1585. long getfree()
  1586. {
  1587.     return(~0L);    /* many free bytes ... */
  1588. }
  1589.  
  1590. /* Ward Christensen / CP/M parameters - Don't change these! */
  1591. #define ENQ 005
  1592. #define CAN ('X'&037)
  1593. #define XOFF ('s'&037)
  1594. #define XON ('q'&037)
  1595. #define SOH 1
  1596. #define STX 2
  1597. #define EOT 4
  1598. #define ACK 6
  1599. #define NAK 025
  1600. #define CPMEOF 032
  1601. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  1602. #define TIMEOUT (-2)
  1603. #define RCDO (-3)
  1604. #define ERRORMAX 5
  1605. #define RETRYMAX 5
  1606. #define WCEOT (-10)
  1607. #define SECSIZ 128    /* cp/m's Magic Number record size */
  1608. #define PATHLEN 257    /* ready for 4.2 bsd ? */
  1609. #define KSIZE 1024    /* record size with k option */
  1610. #define UNIXFILE 0x8000    /* happens to the the S_IFREG file mask bit for stat */
  1611.  
  1612. int Lastrx;
  1613. int Crcflg;
  1614. int Firstsec;
  1615. int Eofseen;        /* indicates cpm eof (^Z) has been received */
  1616. int errors;
  1617. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  1618. #ifdef ONEREAD
  1619. /* Sorry, Regulus and some others don't work right in raw mode! */
  1620. int Readnum = 1;    /* Number of bytes to ask for in read() from modem */
  1621. #else
  1622. int Readnum = HOWMANY;    /* Number of bytes to ask for in read() from modem */
  1623. #endif
  1624.  
  1625. #define DEFBYTL 2000000000L    /* default rx file size */
  1626. long Bytesleft;        /* number of bytes of incoming file left */
  1627. long Modtime;        /* Unix style mod time for incoming file */
  1628. short Filemode;        /* Unix style mode for incoming file */
  1629. char Pathname[PATHLEN];
  1630. char *Progname;        /* the name by which we were called */
  1631.  
  1632. int Batch=0;
  1633. int Wcsmask=0377;
  1634. int Topipe=0;
  1635. int MakeLCPathname=TRUE;    /* make received pathname lower case */
  1636. int Verbose=0;
  1637. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  1638. int Nflag = 0;        /* Don't really transfer files */
  1639. int Rxbinary=FALSE;    /* receive all files in bin mode */
  1640. int Rxascii=FALSE;    /* receive files in ascii (translate) mode */
  1641. int Thisbinary;        /* current file is to be received in bin mode */
  1642. int Blklen;        /* record length of received packets */
  1643. char secbuf[KSIZE+1];
  1644. char linbuf[HOWMANY];
  1645. int Lleft=0;        /* number of characters in linbuf */
  1646. time_t timep[2];
  1647. char Lzmanag;        /* Local file management request */
  1648. char zconv;        /* ZMODEM file conversion request */
  1649. char zmanag;        /* ZMODEM file management request */
  1650. char ztrans;        /* ZMODEM file transport request */
  1651. int Zctlesc;        /* Encode control characters */
  1652. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  1653.  
  1654. jmp_buf tohere;        /* For the interrupt on RX timeout */
  1655.  
  1656. #include "zm.c"
  1657.  
  1658. int tryzhdrtype=ZRINIT;    /* Header type to send corresponding to Last rx close */
  1659.  
  1660. alrm()
  1661. {
  1662.     longjmp(tohere, -1);
  1663. }
  1664.  
  1665. /* called by signal interrupt or terminate to clean things up */
  1666. bibi(n)
  1667. {
  1668.     if (Zmodem)
  1669.         zmputs(Attn);
  1670.     canit(); mode(0);
  1671.     fprintf(stderr, "rz: caught signal %d; exiting", n);
  1672.     exit(128+n);
  1673. }
  1674.  
  1675. main(argc, argv)
  1676. char *argv[];
  1677. {
  1678.     register char *cp;
  1679.     register npats;
  1680.     char *virgin, **patts;
  1681.     char *getenv();
  1682.     int exitcode;
  1683.  
  1684.     Rxtimeout = 100;
  1685.     setbuf(stderr, NULL);
  1686.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  1687.         Restricted=TRUE;
  1688.  
  1689.     chkinvok(virgin=argv[0]);    /* if called as [-]rzCOMMAND set flag */
  1690.     npats = 0;
  1691.     while (--argc) {
  1692.         cp = *++argv;
  1693.         if (*cp == '-') {
  1694.             while( *++cp) {
  1695.                 switch(*cp) {
  1696.                 case '+':
  1697.                     Lzmanag = ZMAPND; break;
  1698.                 case '1':
  1699.                     iofd = 1; break;
  1700.                 case '7':
  1701.                     Wcsmask = 0177;
  1702.                 case 'a':
  1703.                     Rxascii=TRUE;  break;
  1704.                 case 'b':
  1705.                     Rxbinary=TRUE; break;
  1706.                 case 'c':
  1707.                     Crcflg=TRUE; break;
  1708.                 case 'D':
  1709.                     Nflag = TRUE; break;
  1710.                 case 'e':
  1711.                     Zctlesc = 1; break;
  1712.                 case 'p':
  1713.                     Lzmanag = ZMPROT;  break;
  1714.                 case 'q':
  1715.                     Quiet=TRUE; Verbose=0; break;
  1716.                 case 't':
  1717.                     if (--argc < 1) {
  1718.                         usage();
  1719.                     }
  1720.                     Rxtimeout = atoi(*++argv);
  1721.                     if (Rxtimeout<10 || Rxtimeout>1000)
  1722.                         usage();
  1723.                     break;
  1724.                 case 'w':
  1725.                     if (--argc < 1) {
  1726.                         usage();
  1727.                     }
  1728.                     Zrwindow = atoi(*++argv);
  1729.                     break;
  1730.                 case 'u':
  1731.                     MakeLCPathname=FALSE; break;
  1732.                 case 'v':
  1733.                     ++Verbose; break;
  1734.                 default:
  1735.                     usage();
  1736.                 }
  1737.             }
  1738.         }
  1739.         else if ( !npats && argc>0) {
  1740.             if (argv[0][0]) {
  1741.                 npats=argc;
  1742.                 patts=argv;
  1743.             }
  1744.         }
  1745.     }
  1746.     if (npats > 1)
  1747.         usage();
  1748.     if (Verbose) {
  1749.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  1750.             printf("Can't open log file %s\n",LOGFILE);
  1751.             exit(0200);
  1752.         }
  1753.         setbuf(stderr, NULL);
  1754.         fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
  1755.     }
  1756.     if (fromcu() && !Quiet) {
  1757.         if (Verbose == 0)
  1758.             Verbose = 2;
  1759.     }
  1760.     mode(1);
  1761.     if (signal(SIGINT, bibi) == SIG_IGN) {
  1762.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  1763.     }
  1764.     else {
  1765.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  1766.     }
  1767.     signal(SIGTERM, bibi);
  1768.     if (wcreceive(npats, patts)==ERROR) {
  1769.         exitcode=0200;
  1770.         canit();
  1771.     }
  1772.     mode(0);
  1773.     if (exitcode && !Zmodem)    /* bellow again with all thy might. */
  1774.         canit();
  1775.     exit(exitcode);
  1776. }
  1777.  
  1778.  
  1779. usage()
  1780. {
  1781.     fprintf(stderr,"%s %s for %s by Chuck Forsberg\n",
  1782.       Progname, VERSION, OS);
  1783.     fprintf(stderr,"Usage:    rz [-1abeuv]        (ZMODEM Batch)\n");
  1784.     fprintf(stderr,"or    rb [-1abuv]        (YMODEM Batch)\n");
  1785.     fprintf(stderr,"or    rx [-1abcv] file    (XMODEM or XMODEM-1k)\n");
  1786.     fprintf(stderr,"      -1 For cu(1): Use fd 1 for input\n");
  1787.     fprintf(stderr,"      -a ASCII transfer (strip CR)\n");
  1788.     fprintf(stderr,"      -b Binary transfer for all files\n");
  1789.     fprintf(stderr,"      -c Use 16 bit CRC    (XMODEM)\n");
  1790.     fprintf(stderr,"      -e Ignore control characters    (ZMODEM)\n");
  1791.     fprintf(stderr,"      -v Verbose more v's give more info\n");
  1792.     exit(1);
  1793. }
  1794. /*
  1795.  *  Debugging information output interface routine
  1796.  */
  1797. /* VARARGS1 */
  1798. vfile(f, a, b, c)
  1799. register char *f;
  1800. {
  1801.     if (Verbose > 2) {
  1802.         fprintf(stderr, f, a, b, c);
  1803.         fprintf(stderr, "\n");
  1804.     }
  1805. }
  1806.  
  1807. /*
  1808.  * Let's receive something already.
  1809.  */
  1810.  
  1811. char *rbmsg =
  1812. "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n";
  1813.  
  1814. wcreceive(argc, argp)
  1815. char **argp;
  1816. {
  1817.     register c;
  1818.  
  1819.     if (Batch || argc==0) {
  1820.         Crcflg=(Wcsmask==0377);
  1821.         if ( !Quiet)
  1822.             fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
  1823.         if (c=tryz()) {
  1824.             if (c == ZCOMPL)
  1825.                 return OK;
  1826.             if (c == ERROR)
  1827.                 goto fubar;
  1828.             c = rzfiles();
  1829.             if (c)
  1830.                 goto fubar;
  1831.         } else {
  1832.             for (;;) {
  1833.                 if (wcrxpn(secbuf)== ERROR)
  1834.                     goto fubar;
  1835.                 if (secbuf[0]==0)
  1836.                     return OK;
  1837.                 if (procheader(secbuf) == ERROR)
  1838.                     goto fubar;
  1839.                 if (wcrx()==ERROR)
  1840.                     goto fubar;
  1841.             }
  1842.         }
  1843.     } else {
  1844.         Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  1845.  
  1846.         procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
  1847.         fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
  1848.         if ((fout=fopen(Pathname, "w")) == NULL)
  1849.             return ERROR;
  1850.         if (wcrx()==ERROR)
  1851.             goto fubar;
  1852.     }
  1853.     return OK;
  1854. fubar:
  1855.     canit();
  1856.     if (Topipe && fout) {
  1857.         pclose(fout);  return ERROR;
  1858.     }
  1859.     if (fout)
  1860.         fclose(fout);
  1861.     if (Restricted) {
  1862.         unlink(Pathname);
  1863.         fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
  1864.     }
  1865.     return ERROR;
  1866. }
  1867.  
  1868.  
  1869. /*
  1870.  * Fetch a pathname from the other end as a C ctyle ASCIZ string.
  1871.  * Length is indeterminate as long as less than Blklen
  1872.  * A null string represents no more files (YMODEM)
  1873.  */
  1874. wcrxpn(rpn)
  1875. char *rpn;    /* receive a pathname */
  1876. {
  1877.     register c;
  1878.  
  1879. #ifdef NFGVMIN
  1880.     readline(1);
  1881. #else
  1882.     purgeline();
  1883. #endif
  1884.  
  1885. et_tu:
  1886.     Firstsec=TRUE;  Eofseen=FALSE;
  1887.     sendline(Crcflg?WANTCRC:NAK);
  1888.     Lleft=0;    /* Do read next time ... */
  1889.     while ((c = wcgetsec(rpn, 100)) != 0) {
  1890.         if (c == WCEOT) {
  1891.             zperr( "Pathname fetch returned %d", c);
  1892.             sendline(ACK);
  1893.             Lleft=0;    /* Do read next time ... */
  1894.             readline(1);
  1895.             goto et_tu;
  1896.         }
  1897.         return ERROR;
  1898.     }
  1899.     sendline(ACK);
  1900.     return OK;
  1901. }
  1902.  
  1903. /*
  1904.  * Adapted from CMODEM13.C, written by
  1905.  * Jack M. Wierda and Roderick W. Hart
  1906.  */
  1907.  
  1908. wcrx()
  1909. {
  1910.     register int sectnum, sectcurr;
  1911.     register char sendchar;
  1912.     register char *p;
  1913.     int cblklen;            /* bytes to dump this block */
  1914.  
  1915.     Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
  1916.     sendchar=Crcflg?WANTCRC:NAK;
  1917.  
  1918.     for (;;) {
  1919.         sendline(sendchar);    /* send it now, we're ready! */
  1920.         Lleft=0;    /* Do read next time ... */
  1921.         sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
  1922.         report(sectcurr);
  1923.         if (sectcurr==(sectnum+1 &Wcsmask)) {
  1924.             sectnum++;
  1925.             cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
  1926.             if (putsec(secbuf, cblklen)==ERROR)
  1927.                 return ERROR;
  1928.             if ((Bytesleft-=cblklen) < 0)
  1929.                 Bytesleft = 0;
  1930.             sendchar=ACK;
  1931.         }
  1932.         else if (sectcurr==(sectnum&Wcsmask)) {
  1933.             zperr( "Received dup Sector");
  1934.             sendchar=ACK;
  1935.         }
  1936.         else if (sectcurr==WCEOT) {
  1937.             if (closeit())
  1938.                 return ERROR;
  1939.             sendline(ACK);
  1940.             Lleft=0;    /* Do read next time ... */
  1941.             return OK;
  1942.         }
  1943.         else if (sectcurr==ERROR)
  1944.             return ERROR;
  1945.         else {
  1946.             zperr( "Sync Error");
  1947.             return ERROR;
  1948.         }
  1949.     }
  1950. }
  1951.  
  1952. /*
  1953.  * Wcgetsec fetches a Ward Christensen type sector.
  1954.  * Returns sector number encountered or ERROR if valid sector not received,
  1955.  * or CAN CAN received
  1956.  * or WCEOT if eot sector
  1957.  * time is timeout for first char, set to 4 seconds thereafter
  1958.  ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
  1959.  *    (Caller must do that when he is good and ready to get next sector)
  1960.  */
  1961.  
  1962. wcgetsec(rxbuf, maxtime)
  1963. char *rxbuf;
  1964. int maxtime;
  1965. {
  1966.     register checksum, wcj, firstch;
  1967.     register unsigned short oldcrc;
  1968.     register char *p;
  1969.     int sectcurr;
  1970.  
  1971.     for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
  1972.  
  1973.         if ((firstch=readline(maxtime))==STX) {
  1974.             Blklen=KSIZE; goto get2;
  1975.         }
  1976.         if (firstch==SOH) {
  1977.             Blklen=SECSIZ;
  1978. get2:
  1979.             sectcurr=readline(1);
  1980.             if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) {
  1981.                 oldcrc=checksum=0;
  1982.                 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
  1983.                     if ((firstch=readline(1)) < 0)
  1984.                         goto bilge;
  1985.                     oldcrc=updcrc(firstch, oldcrc);
  1986.                     checksum += (*p++ = firstch);
  1987.                 }
  1988.                 if ((firstch=readline(1)) < 0)
  1989.                     goto bilge;
  1990.                 if (Crcflg) {
  1991.                     oldcrc=updcrc(firstch, oldcrc);
  1992.                     if ((firstch=readline(1)) < 0)
  1993.                         goto bilge;
  1994.                     oldcrc=updcrc(firstch, oldcrc);
  1995.                     if (oldcrc & 0xFFFF)
  1996.                         zperr( "CRC");
  1997.                     else {
  1998.                         Firstsec=FALSE;
  1999.                         return sectcurr;
  2000.                     }
  2001.                 }
  2002.                 else if (((checksum-firstch)&Wcsmask)==0) {
  2003.                     Firstsec=FALSE;
  2004.                     return sectcurr;
  2005.                 }
  2006.                 else
  2007.                     zperr( "Checksum");
  2008.             }
  2009.             else
  2010.                 zperr("Sector number garbled");
  2011.         }
  2012.         /* make sure eot really is eot and not just mixmash */
  2013. #ifdef NFGVMIN
  2014.         else if (firstch==EOT && readline(1)==TIMEOUT)
  2015.             return WCEOT;
  2016. #else
  2017.         else if (firstch==EOT && Lleft==0)
  2018.             return WCEOT;
  2019. #endif
  2020.         else if (firstch==CAN) {
  2021.             if (Lastrx==CAN) {
  2022.                 zperr( "Sender CANcelled");
  2023.                 return ERROR;
  2024.             } else {
  2025.                 Lastrx=CAN;
  2026.                 continue;
  2027.             }
  2028.         }
  2029.         else if (firstch==TIMEOUT) {
  2030.             if (Firstsec)
  2031.                 goto humbug;
  2032. bilge:
  2033.             zperr( "TIMEOUT");
  2034.         }
  2035.         else
  2036.             zperr( "Got 0%o sector header", firstch);
  2037.  
  2038. humbug:
  2039.         Lastrx=0;
  2040.         while(readline(1)!=TIMEOUT)
  2041.             ;
  2042.         if (Firstsec) {
  2043.             sendline(Crcflg?WANTCRC:NAK);
  2044.             Lleft=0;    /* Do read next time ... */
  2045.         } else {
  2046.             maxtime=40; sendline(NAK);
  2047.             Lleft=0;    /* Do read next time ... */
  2048.         }
  2049.     }
  2050.     /* try to stop the bubble machine. */
  2051.     canit();
  2052.     return ERROR;
  2053. }
  2054.  
  2055. /*
  2056.  * This version of readline is reasoably well suited for
  2057.  * reading many characters.
  2058.  *  (except, currently, for the Regulus version!)
  2059.  *
  2060.  * timeout is in tenths of seconds
  2061.  */
  2062. readline(timeout)
  2063. int timeout;
  2064. {
  2065.     register n;
  2066.     static char *cdq;    /* pointer for removing chars from linbuf */
  2067.  
  2068.     if (--Lleft >= 0) {
  2069.         if (Verbose > 8) {
  2070.             fprintf(stderr, "%02x ", *cdq&0377);
  2071.         }
  2072.         return (*cdq++ & Wcsmask);
  2073.     }
  2074.     n = timeout/10;
  2075.     if (n < 2)
  2076.         n = 3;
  2077.     if (Verbose > 5)
  2078.         fprintf(stderr, "Calling read: alarm=%d  Readnum=%d ",
  2079.           n, Readnum);
  2080.     if (setjmp(tohere)) {
  2081. #ifdef TIOCFLUSH
  2082. /*        ioctl(iofd, TIOCFLUSH, 0); */
  2083. #endif
  2084.         Lleft = 0;
  2085.         if (Verbose>1)
  2086.             fprintf(stderr, "Readline:TIMEOUT\n");
  2087.         return TIMEOUT;
  2088.     }
  2089.     signal(SIGALRM, alrm); alarm(n);
  2090.     Lleft=read(iofd, cdq=linbuf, Readnum);
  2091.     alarm(0);
  2092.     if (Verbose > 5) {
  2093.         fprintf(stderr, "Read returned %d bytes\n", Lleft);
  2094.     }
  2095.     if (Lleft < 1)
  2096.         return TIMEOUT;
  2097.     --Lleft;
  2098.     if (Verbose > 8) {
  2099.         fprintf(stderr, "%02x ", *cdq&0377);
  2100.     }
  2101.     return (*cdq++ & Wcsmask);
  2102. }
  2103.  
  2104.  
  2105.  
  2106. /*
  2107.  * Purge the modem input queue of all characters
  2108.  */
  2109. purgeline()
  2110. {
  2111.     Lleft = 0;
  2112. #ifdef USG
  2113.     ioctl(iofd, TCFLSH, 0);
  2114. #else
  2115.     lseek(iofd, 0L, 2);
  2116. #endif
  2117. }
  2118.  
  2119.  
  2120. /*
  2121.  * Process incoming file information header
  2122.  */
  2123. procheader(name)
  2124. char *name;
  2125. {
  2126.     register char *openmode, *p, **pp;
  2127.  
  2128.     /* set default parameters and overrides */
  2129.     openmode = "w";
  2130.     Thisbinary = (!Rxascii) || Rxbinary;
  2131.     if (Lzmanag)
  2132.         zmanag = Lzmanag;
  2133.  
  2134.     /*
  2135.      *  Process ZMODEM remote file management requests
  2136.      */
  2137.     if (!Rxbinary && zconv == ZCNL)    /* Remote ASCII override */
  2138.         Thisbinary = 0;
  2139.     if (zconv == ZCBIN)    /* Remote Binary override */
  2140.         Thisbinary = TRUE;
  2141.     else if (zmanag == ZMAPND)
  2142.         openmode = "a";
  2143.  
  2144. #ifndef BIX
  2145.     /* ZMPROT check for existing file */
  2146.     if (zmanag == ZMPROT && (fout=fopen(name, "r"))) {
  2147.         fclose(fout);  return ERROR;
  2148.     }
  2149. #endif
  2150.  
  2151.     Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
  2152.  
  2153.     p = name + 1 + strlen(name);
  2154.     if (*p) {    /* file coming from Unix or DOS system */
  2155.         sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
  2156.         if (Filemode & UNIXFILE)
  2157.             ++Thisbinary;
  2158.         if (Verbose) {
  2159.             fprintf(stderr,  "Incoming: %s %ld %lo %o\n",
  2160.               name, Bytesleft, Modtime, Filemode);
  2161.         }
  2162.     }
  2163.  
  2164. #ifdef BIX
  2165.     if ((fout=fopen("scratchpad", openmode)) == NULL)
  2166.         return ERROR;
  2167.     return OK;
  2168. #else
  2169.  
  2170.     else {        /* File coming from CP/M system */
  2171.         for (p=name; *p; ++p)        /* change / to _ */
  2172.             if ( *p == '/')
  2173.                 *p = '_';
  2174.  
  2175.         if ( *--p == '.')        /* zap trailing period */
  2176.             *p = 0;
  2177.     }
  2178.  
  2179.     if (!Zmodem && MakeLCPathname && !IsAnyLower(name))
  2180.         uncaps(name);
  2181.     if (Topipe) {
  2182.         sprintf(Pathname, "%s %s", Progname+2, name);
  2183.         if (Verbose)
  2184.             fprintf(stderr,  "Topipe: %s %s\n",
  2185.               Pathname, Thisbinary?"BIN":"ASCII");
  2186.         if ((fout=popen(Pathname, "w")) == NULL)
  2187.             return ERROR;
  2188.     } else {
  2189.         strcpy(Pathname, name);
  2190.         if (Verbose) {
  2191.             fprintf(stderr,  "Receiving %s %s %s\n",
  2192.               name, Thisbinary?"BIN":"ASCII", openmode);
  2193.         }
  2194.         checkpath(name);
  2195.         if (Nflag)
  2196.             name = "/dev/null";
  2197.         if ((fout=fopen(name, openmode)) == NULL)
  2198.             return ERROR;
  2199.     }
  2200.     return OK;
  2201. #endif /* BIX */
  2202. }
  2203.  
  2204. /*
  2205.  * Putsec writes the n characters of buf to receive file fout.
  2206.  *  If not in binary mode, carriage returns, and all characters
  2207.  *  starting with CPMEOF are discarded.
  2208.  */
  2209. putsec(buf, n)
  2210. char *buf;
  2211. register n;
  2212. {
  2213.     register char *p;
  2214.  
  2215.     if (Thisbinary) {
  2216.         for (p=buf; --n>=0; )
  2217.             putc( *p++, fout);
  2218.     }
  2219.     else {
  2220.         if (Eofseen)
  2221.             return OK;
  2222.         for (p=buf; --n>=0; ++p ) {
  2223.             if ( *p == '\r')
  2224.                 continue;
  2225.             if (*p == CPMEOF) {
  2226.                 Eofseen=TRUE; return OK;
  2227.             }
  2228.             putc(*p ,fout);
  2229.         }
  2230.     }
  2231.     return OK;
  2232. }
  2233.  
  2234. /*
  2235.  *  Send a character to modem.  Small is beautiful.
  2236.  */
  2237. sendline(c)
  2238. {
  2239.     char d;
  2240.  
  2241.     d = c;
  2242.     if (Verbose>6)
  2243.         fprintf(stderr, "Sendline: %x\n", c);
  2244.     write(1, &d, 1);
  2245. }
  2246.  
  2247. xsendline(c)
  2248. {
  2249.     sendline(c);
  2250. }
  2251.  
  2252. flushmo() {}
  2253.  
  2254.  
  2255.  
  2256.  
  2257. /* make string s lower case */
  2258. uncaps(s)
  2259. register char *s;
  2260. {
  2261.     for ( ; *s; ++s)
  2262.         if (isupper(*s))
  2263.             *s = tolower(*s);
  2264. }
  2265. /*
  2266.  * IsAnyLower returns TRUE if string s has lower case letters.
  2267.  */
  2268. IsAnyLower(s)
  2269. register char *s;
  2270. {
  2271.     for ( ; *s; ++s)
  2272.         if (islower(*s))
  2273.             return TRUE;
  2274.     return FALSE;
  2275. }
  2276.  
  2277. /*
  2278.  * substr(string, token) searches for token in string s
  2279.  * returns pointer to token within string if found, NULL otherwise
  2280.  */
  2281. char *
  2282. substr(s, t)
  2283. register char *s,*t;
  2284. {
  2285.     register char *ss,*tt;
  2286.     /* search for first char of token */
  2287.     for (ss=s; *s; s++)
  2288.         if (*s == *t)
  2289.             /* compare token with substring */
  2290.             for (ss=s,tt=t; ;) {
  2291.                 if (*tt == 0)
  2292.                     return s;
  2293.                 if (*ss++ != *tt++)
  2294.                     break;
  2295.             }
  2296.     return NULL;
  2297. }
  2298.  
  2299. /*
  2300.  * Log an error
  2301.  */
  2302. /*VARARGS1*/
  2303. zperr(s,p,u)
  2304. char *s, *p, *u;
  2305. {
  2306.     if (Verbose <= 0)
  2307.         return;
  2308.     fprintf(stderr, "Retry %d: ", errors);
  2309.     fprintf(stderr, s, p, u);
  2310.     fprintf(stderr, "\n");
  2311. }
  2312.  
  2313. /* send cancel string to get the other end to shut up */
  2314. canit()
  2315. {
  2316.     static char canistr[] = {
  2317.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  2318.     };
  2319.  
  2320.     printf(canistr);
  2321.     Lleft=0;    /* Do read next time ... */
  2322.     fflush(stdout);
  2323. }
  2324.  
  2325.  
  2326. /*
  2327.  * Return 1 iff stdout and stderr are different devices
  2328.  *  indicating this program operating with a modem on a
  2329.  *  different line
  2330.  */
  2331. fromcu()
  2332. {
  2333.     struct stat a, b;
  2334.     fstat(1, &a); fstat(2, &b);
  2335.     return (a.st_rdev != b.st_rdev);
  2336. }
  2337.  
  2338. report(sct)
  2339. int sct;
  2340. {
  2341.     if (Verbose>1)
  2342.         fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
  2343. }
  2344.  
  2345. /*
  2346.  * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
  2347.  * If called as [-][dir/../]rzCOMMAND set the pipe flag
  2348.  * If called as rb use YMODEM protocol
  2349.  */
  2350. chkinvok(s)
  2351. char *s;
  2352. {
  2353.     register char *p;
  2354.  
  2355.     p = s;
  2356.     while (*p == '-')
  2357.         s = ++p;
  2358.     while (*p)
  2359.         if (*p++ == '/')
  2360.             s = p;
  2361.     if (*s == 'v') {
  2362.         Verbose=1; ++s;
  2363.     }
  2364.     Progname = s;
  2365.     if (s[0]=='r' && s[1]=='b')
  2366.         Nozmodem = TRUE;
  2367.     if (s[2] && s[0]=='r' && s[1]=='b')
  2368.         Topipe=TRUE;
  2369.     if (s[2] && s[0]=='r' && s[1]=='z')
  2370.         Topipe=TRUE;
  2371. }
  2372.  
  2373. /*
  2374.  * Totalitarian Communist pathname processing
  2375.  */
  2376. checkpath(name)
  2377. char *name;
  2378. {
  2379.     if (Restricted) {
  2380.         if (fopen(name, "r") != NULL) {
  2381.             canit();
  2382.             fprintf(stderr, "\r\nrz: %s exists\n", name);
  2383.             bibi(-1);
  2384.         }
  2385.         /* restrict pathnames to current tree or uucppublic */
  2386.         if ( substr(name, "../")
  2387.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  2388.             canit();
  2389.             fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
  2390.             bibi(-1);
  2391.         }
  2392.     }
  2393. }
  2394.  
  2395. /*
  2396.  * Initialize for Zmodem receive attempt, try to activate Zmodem sender
  2397.  *  Handles ZSINIT frame
  2398.  *  Return ZFILE if Zmodem filename received, -1 on error,
  2399.  *   ZCOMPL if transaction finished,  else 0
  2400.  */
  2401. tryz()
  2402. {
  2403.     register c, n;
  2404.     register cmdzack1flg;
  2405.  
  2406.     if (Nozmodem)        /* Check for "rb" program name */
  2407.         return 0;
  2408.  
  2409.  
  2410.     for (n=Zmodem?15:5; --n>=0; ) {
  2411.         /* Set buffer length (0) and capability flags */
  2412.         stohdr(0L);
  2413. #ifdef CANBREAK
  2414.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
  2415. #else
  2416.         Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
  2417. #endif
  2418.         if (Zctlesc)
  2419.             Txhdr[ZF0] |= TESCCTL;
  2420.         zshhdr(tryzhdrtype, Txhdr);
  2421.         if (tryzhdrtype == ZSKIP)    /* Don't skip too far */
  2422.             tryzhdrtype = ZRINIT;    /* CAF 8-21-87 */
  2423. again:
  2424.         switch (zgethdr(Rxhdr, 0)) {
  2425.         case ZRQINIT:
  2426.             continue;
  2427.         case ZEOF:
  2428.             continue;
  2429.         case TIMEOUT:
  2430.             continue;
  2431.         case ZFILE:
  2432.             zconv = Rxhdr[ZF0];
  2433.             zmanag = Rxhdr[ZF1];
  2434.             ztrans = Rxhdr[ZF2];
  2435.             tryzhdrtype = ZRINIT;
  2436.             c = zrdata(secbuf, KSIZE);
  2437.             mode(3);
  2438.             if (c == GOTCRCW)
  2439.                 return ZFILE;
  2440.             zshhdr(ZNAK, Txhdr);
  2441.             goto again;
  2442.         case ZSINIT:
  2443.             Zctlesc = TESCCTL & Rxhdr[ZF0];
  2444.             if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
  2445.                 zshhdr(ZACK, Txhdr);
  2446.                 goto again;
  2447.             }
  2448.             zshhdr(ZNAK, Txhdr);
  2449.             goto again;
  2450.         case ZFREECNT:
  2451.             stohdr(getfree());
  2452.             zshhdr(ZACK, Txhdr);
  2453.             goto again;
  2454.         case ZCOMMAND:
  2455.             cmdzack1flg = Rxhdr[ZF0];
  2456.             if (zrdata(secbuf, KSIZE) == GOTCRCW) {
  2457.                 if (cmdzack1flg & ZCACK1)
  2458.                     stohdr(0L);
  2459.                 else
  2460.                     stohdr((long)sys2(secbuf));
  2461.                 purgeline();    /* dump impatient questions */
  2462.                 do {
  2463.                     zshhdr(ZCOMPL, Txhdr);
  2464.                 }
  2465.                 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
  2466.                 ackbibi();
  2467.                 if (cmdzack1flg & ZCACK1)
  2468.                     exec2(secbuf);
  2469.                 return ZCOMPL;
  2470.             }
  2471.             zshhdr(ZNAK, Txhdr); goto again;
  2472.         case ZCOMPL:
  2473.             goto again;
  2474.         default:
  2475.             continue;
  2476.         case ZFIN:
  2477.             ackbibi(); return ZCOMPL;
  2478.         case ZCAN:
  2479.             return ERROR;
  2480.         }
  2481.     }
  2482.     return 0;
  2483. }
  2484.  
  2485. /*
  2486.  * Receive 1 or more files with ZMODEM protocol
  2487.  */
  2488. rzfiles()
  2489. {
  2490.     register c;
  2491.  
  2492.     for (;;) {
  2493.         switch (c = rzfile()) {
  2494.         case ZEOF:
  2495.         case ZSKIP:
  2496.             switch (tryz()) {
  2497.             case ZCOMPL:
  2498.                 return OK;
  2499.             default:
  2500.                 return ERROR;
  2501.             case ZFILE:
  2502.                 break;
  2503.             }
  2504.             continue;
  2505.         default:
  2506.             return c;
  2507.         case ERROR:
  2508.             return ERROR;
  2509.         }
  2510.     }
  2511. }
  2512.  
  2513. /*
  2514.  * Receive a file with ZMODEM protocol
  2515.  *  Assumes file name frame is in secbuf
  2516.  */
  2517. rzfile()
  2518. {
  2519.     register c, n;
  2520.     long rxbytes;
  2521.  
  2522.     Eofseen=FALSE;
  2523.     if (procheader(secbuf) == ERROR) {
  2524.         return (tryzhdrtype = ZSKIP);
  2525.     }
  2526.  
  2527.     n = 20; rxbytes = 0l;
  2528.  
  2529.     for (;;) {
  2530.         stohdr(rxbytes);
  2531.         zshhdr(ZRPOS, Txhdr);
  2532. nxthdr:
  2533.         switch (c = zgethdr(Rxhdr, 0)) {
  2534.         default:
  2535.             vfile("rzfile: zgethdr returned %d", c);
  2536.             return ERROR;
  2537.         case ZNAK:
  2538.         case TIMEOUT:
  2539.             if ( --n < 0) {
  2540.                 vfile("rzfile: zgethdr returned %d", c);
  2541.                 return ERROR;
  2542.             }
  2543.         case ZFILE:
  2544.             zrdata(secbuf, KSIZE);
  2545.             continue;
  2546.         case ZEOF:
  2547.             if (rclhdr(Rxhdr) != rxbytes) {
  2548.                 /*
  2549.                  * Ignore eof if it's at wrong place - force
  2550.                  *  a timeout because the eof might have gone
  2551.                  *  out before we sent our zrpos.
  2552.                  */
  2553.                 errors = 0;  goto nxthdr;
  2554.             }
  2555.             if (closeit()) {
  2556.                 tryzhdrtype = ZFERR;
  2557.                 vfile("rzfile: closeit returned <> 0");
  2558.                 return ERROR;
  2559.             }
  2560.             vfile("rzfile: normal EOF");
  2561.             return c;
  2562.         case ERROR:    /* Too much garbage in header search error */
  2563.             if ( --n < 0) {
  2564.                 vfile("rzfile: zgethdr returned %d", c);
  2565.                 return ERROR;
  2566.             }
  2567.             zmputs(Attn);
  2568.             continue;
  2569.         case ZDATA:
  2570.             if (rclhdr(Rxhdr) != rxbytes) {
  2571.                 if ( --n < 0) {
  2572.                     return ERROR;
  2573.                 }
  2574.                 zmputs(Attn);  continue;
  2575.             }
  2576. moredata:
  2577.             if (Verbose>1)
  2578.                 fprintf(stderr, "\r%7ld ZMODEM%s    ",
  2579.                   rxbytes, Crc32?" CRC-32":"");
  2580.             switch (c = zrdata(secbuf, KSIZE)) {
  2581.             case ZCAN:
  2582.                 vfile("rzfile: zgethdr returned %d", c);
  2583.                 return ERROR;
  2584.             case ERROR:    /* CRC error */
  2585.                 if ( --n < 0) {
  2586.                     vfile("rzfile: zgethdr returned %d", c);
  2587.                     return ERROR;
  2588.                 }
  2589.                 zmputs(Attn);
  2590.                 continue;
  2591.             case TIMEOUT:
  2592.                 if ( --n < 0) {
  2593.                     vfile("rzfile: zgethdr returned %d", c);
  2594.                     return ERROR;
  2595.                 }
  2596.                 continue;
  2597.             case GOTCRCW:
  2598.                 n = 20;
  2599.                 putsec(secbuf, Rxcount);
  2600.                 rxbytes += Rxcount;
  2601.                 stohdr(rxbytes);
  2602.                 zshhdr(ZACK, Txhdr);
  2603.                 sendline(XON);
  2604.                 goto nxthdr;
  2605.             case GOTCRCQ:
  2606.                 n = 20;
  2607.                 putsec(secbuf, Rxcount);
  2608.                 rxbytes += Rxcount;
  2609.                 stohdr(rxbytes);
  2610.                 zshhdr(ZACK, Txhdr);
  2611.                 goto moredata;
  2612.             case GOTCRCG:
  2613.                 n = 20;
  2614.                 putsec(secbuf, Rxcount);
  2615.                 rxbytes += Rxcount;
  2616.                 goto moredata;
  2617.             case GOTCRCE:
  2618.                 n = 20;
  2619.                 putsec(secbuf, Rxcount);
  2620.                 rxbytes += Rxcount;
  2621.                 goto nxthdr;
  2622.             }
  2623.         }
  2624.     }
  2625. }
  2626.  
  2627. /*
  2628.  * Send a string to the modem, processing for \336 (sleep 1 sec)
  2629.  *   and \335 (break signal)
  2630.  */
  2631. zmputs(s)
  2632. char *s;
  2633. {
  2634.     register c;
  2635.  
  2636.     while (*s) {
  2637.         switch (c = *s++) {
  2638.         case '\336':
  2639.             sleep(1); continue;
  2640.         case '\335':
  2641.             sendbrk(); continue;
  2642.         default:
  2643.             sendline(c);
  2644.         }
  2645.     }
  2646. }
  2647.  
  2648. /*
  2649.  * Close the receive dataset, return OK or ERROR
  2650.  */
  2651. closeit()
  2652. {
  2653.     if (Topipe) {
  2654.         if (pclose(fout)) {
  2655.             return ERROR;
  2656.         }
  2657.         return OK;
  2658.     }
  2659.     if (fclose(fout)==ERROR) {
  2660.         fprintf(stderr, "file close ERROR\n");
  2661.         return ERROR;
  2662.     }
  2663.     if (Modtime) {
  2664.         timep[0] = time(NULL);
  2665.         timep[1] = Modtime;
  2666.         utime(Pathname, timep);
  2667.     }
  2668.     if (Filemode)
  2669.         chmod(Pathname, (07777 & Filemode));
  2670.     return OK;
  2671. }
  2672.  
  2673. /*
  2674.  * Ack a ZFIN packet, let byegones be byegones
  2675.  */
  2676. ackbibi()
  2677. {
  2678.     register n;
  2679.  
  2680.     vfile("ackbibi:");
  2681.     Readnum = 1;
  2682.     stohdr(0L);
  2683.     for (n=3; --n>=0; ) {
  2684.         purgeline();
  2685.         zshhdr(ZFIN, Txhdr);
  2686.         switch (readline(100)) {
  2687.         case 'O':
  2688.             readline(1);    /* Discard 2nd 'O' */
  2689.             vfile("ackbibi complete");
  2690.             return;
  2691.         case RCDO:
  2692.             return;
  2693.         case TIMEOUT:
  2694.         default:
  2695.             break;
  2696.         }
  2697.     }
  2698. }
  2699.  
  2700.  
  2701.  
  2702. /*
  2703.  * Local console output simulation
  2704.  */
  2705. bttyout(c)
  2706. {
  2707.     if (Verbose || fromcu())
  2708.         putc(c, stderr);
  2709. }
  2710.  
  2711. /*
  2712.  * Strip leading ! if present, do shell escape. 
  2713.  */
  2714. sys2(s)
  2715. register char *s;
  2716. {
  2717.     if (*s == '!')
  2718.         ++s;
  2719.     return system(s);
  2720. }
  2721. /*
  2722.  * Strip leading ! if present, do exec.
  2723.  */
  2724. exec2(s)
  2725. register char *s;
  2726. {
  2727.     if (*s == '!')
  2728.         ++s;
  2729.     mode(0);
  2730.     execl("/bin/sh", "sh", "-c", s);
  2731. }
  2732. /* End of rz.c */
  2733. \Rogue\Monster\
  2734. else
  2735.   echo "will not over write ./rz.c"
  2736. fi
  2737. if [ `wc -c ./rz.c | awk '{printf $1}'` -ne 25038 ]
  2738. then
  2739. echo `wc -c ./rz.c | awk '{print "Got " $1 ", Expected " 25038}'`
  2740. fi
  2741. echo "Finished archive 2 of 3"
  2742. exit
  2743.  
  2744.