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

  1. #define VERSION "sz 1.07 06-05-86"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -O -K sz.c -o sz; size sz
  5.  
  6.  * sz.c By Chuck Forsberg
  7.  *
  8.  *    cc -O sz.c -o sz        USG (SYS III/V) Unix
  9.  *     cc -O -DV7  sz.c -o sz        Unix Version 7, 2.8 - 4.3 BSD
  10.  *
  11.  *  ******* Some systems (Venix, Coherent, Regulus) do not *******
  12.  *  ******* support tty raw mode read(2) identically to    *******
  13.  *  ******* Unix. ONEREAD must be defined to force one     *******
  14.  *  ******* character reads for these systems.           *******
  15.  *
  16.  * A program for Unix to send files and commands to computers running
  17.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
  18.  *
  19.  *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
  20.  *
  21.  *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
  22.  */
  23.  
  24.  
  25. unsigned updcrc();
  26. char *substr(), *getenv();
  27.  
  28. #define LOGFILE "/tmp/szlog"
  29. #define zperr vfile
  30.  
  31. #include <stdio.h>
  32. #include <signal.h>
  33. #include <setjmp.h>
  34. #include <ctype.h>
  35.  
  36. #define PATHLEN 256
  37. #define OK 0
  38. #define FALSE 0
  39. #define TRUE 1
  40. #define ERROR (-1)
  41.  
  42. #define HOWMANY 2
  43. int Zmodem=0;        /* ZMODEM protocol requested */
  44. unsigned Baudrate;
  45. #include "rbsb.c"    /* most of the system dependent stuff here */
  46.  
  47. /*
  48.  * Attention string to be executed by receiver to interrupt streaming data
  49.  *  when an error is detected.  A pause (0336) may be needed before the
  50.  *  ^C (03) or after it.
  51.  */
  52. #ifdef USG
  53. char Myattn[] = { 03, 0336, 0 };
  54. #else
  55. char Myattn[] = { 0 };
  56. #endif
  57.  
  58. FILE *in;
  59.  
  60. /* Ward Christensen / CP/M parameters - Don't change these! */
  61. #define ENQ 005
  62. #define CAN ('X'&037)
  63. #define XOFF ('s'&037)
  64. #define XON ('q'&037)
  65. #define SOH 1
  66. #define STX 2
  67. #define EOT 4
  68. #define ACK 6
  69. #define NAK 025
  70. #define CPMEOF 032
  71. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  72. #define WANTG 0107    /* Send G not NAK to get nonstop batch xmsn */
  73. #define TIMEOUT (-2)
  74. #define RETRYMAX 10
  75. #define SECSIZ 128    /* cp/m's Magic Number record size */
  76. #define KSIZE 1024
  77.  
  78. char Lastrx;
  79. char Crcflg;
  80. int Wcsmask=0377;
  81. int Verbose=0;
  82. int Modem=0;        /* MODEM - don't send pathnames */
  83. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  84. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  85. int Ascii=0;        /* Add CR's for brain damaged programs */
  86. int Fullname=0;        /* transmit full pathname */
  87. int Unlinkafter=0;    /* Unlink file after it is sent */
  88. int Dottoslash=0;    /* Change foo.bar.baz to foo/bar/baz */
  89. int firstsec;
  90. int errcnt=0;        /* number of files unreadable */
  91. int blklen=SECSIZ;        /* length of transmitted records */
  92. int Optiong;        /* Let it rip no wait for sector ACK's */
  93. int Noeofseen;
  94. int Totsecs;        /* total number of sectors this file */
  95. char txbuf[KSIZE];
  96. int Filcnt=0;        /* count of number of files opened */
  97. int Lfseen=0;
  98. unsigned Rxbuflen = 16384;    /* Receiver's max buffer length */
  99. int Tframlen = 0;    /* Override for tx frame length */
  100. int blkopt=0;        /* Override value for zmodem blklen */
  101. int Rxflags = 0;
  102. char Lzconv;    /* Local ZMODEM file conversion request */
  103. char Lzmanag;    /* Local ZMODEM file management request */
  104. char Lztrans;
  105. char zconv;        /* ZMODEM file conversion request */
  106. char zmanag;        /* ZMODEM file management request */
  107. char ztrans;        /* ZMODEM file transport request */
  108. int Command;        /* Send a command, then exit. */
  109. char *Cmdstr;        /* Pointer to the command string */
  110. int Cmdtries = 11;
  111. int Cmdack1;        /* Rx ACKs command, then do it */
  112. int Exitcode;
  113. int Testattn;        /* Force receiver to send Attn, etc with qbf. */
  114. char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
  115. long Lastread;        /* Beginning offset of last buffer read */
  116. int Lastc;        /* Count of last buffer read or -1 */
  117. int Dontread;        /* Don't read the buffer, it's still there */
  118.  
  119. jmp_buf tohere;        /* For the interrupt on RX timeout */
  120. jmp_buf intrjmp;    /* For the interrupt on RX CAN */
  121.  
  122. /* called by signal interrupt or terminate to clean things up */
  123. bibi(n)
  124. {
  125.     canit(); fflush(stdout); mode(0);
  126.     fprintf(stderr, "sz: caught signal %d; exiting\n", n);
  127.     if (n == SIGQUIT)
  128.         abort();
  129.     exit(128+n);
  130. }
  131. /* Called when Zmodem gets an interrupt (^X) */
  132. onintr()
  133. {
  134.     signal(SIGINT, SIG_IGN);
  135.     longjmp(intrjmp, -1);
  136. }
  137.  
  138.  
  139. #define sendline(c) putchar(c & Wcsmask)
  140.  
  141. #define xsendline(c) putchar(c)
  142.  
  143. flushmo()
  144. {
  145.     fflush(stdout);
  146. }
  147.  
  148. #include "zm.c"
  149.  
  150.  
  151. main(argc, argv)
  152. char *argv[];
  153. {
  154.     register char *cp;
  155.     register npats;
  156.     int agcnt; char **agcv;
  157.     char **patts;
  158.     static char xXbuf[BUFSIZ];
  159.  
  160.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh")))
  161.         Restricted=TRUE;
  162.  
  163.     Rxtimeout = 600;
  164.     npats=0;
  165.     if (argc<2)
  166.         usage();
  167.     setbuf(stdout, xXbuf);        
  168.     while (--argc) {
  169.         cp = *++argv;
  170.         if (*cp++ == '-' && *cp) {
  171.             while ( *cp) {
  172.                 switch(*cp++) {
  173.                 case '+':
  174.                     Lzmanag = ZMAPND; break;
  175.                 case '1':
  176.                     iofd = 1; break;
  177. #ifdef CSTOPB
  178.                 case '2':
  179.                     Twostop = TRUE; break;
  180. #endif
  181.                 case '7':
  182.                     Wcsmask=0177; break;
  183.                 case 'a':
  184.                     Lzconv = ZCNL;
  185.                     Ascii = TRUE; break;
  186.                 case 'b':
  187.                     Lzconv = ZCBIN; break;
  188.                 case 'C':
  189.                     if (--argc < 1) {
  190.                         usage();
  191.                     }
  192.                     Cmdtries = atoi(*++argv);
  193.                     break;
  194.                 case 'i':
  195.                     Cmdack1 = ZCACK1;
  196.                     /* **** FALL THROUGH TO **** */
  197.                 case 'c':
  198.                     if (--argc != 1) {
  199.                         usage();
  200.                     }
  201.                     Command = TRUE;
  202.                     Cmdstr = *++argv;
  203.                     break;
  204.                 case 'd':
  205.                     ++Dottoslash;
  206.                     /* **** FALL THROUGH TO **** */
  207.                 case 'f':
  208.                     Fullname=TRUE; break;
  209.                 case 'k':
  210.                     blklen=KSIZE; break;
  211.                 case 'L':
  212.                     if (--argc < 1) {
  213.                         usage();
  214.                     }
  215.                     blkopt = atoi(*++argv);
  216.                     if (blkopt<32 || blkopt>1024)
  217.                         usage();
  218.                     break;
  219.                 case 'l':
  220.                     if (--argc < 1) {
  221.                         usage();
  222.                     }
  223.                     Tframlen = atoi(*++argv);
  224.                     if (Tframlen<32 || Tframlen>1024)
  225.                         usage();
  226.                     break;
  227.                 case 'N':
  228.                     Lzmanag = ZMCRC;  break;
  229.                 case 'n':
  230.                     Lzmanag = ZMNEW;  break;
  231.                 case 'r':
  232.                     Lzconv = ZCRESUM;
  233.                 case 'q':
  234.                     Quiet=TRUE; Verbose=0; break;
  235.                 case 'T':
  236.                     Testattn = TRUE; break;
  237.                 case 'u':
  238.                     ++Unlinkafter; break;
  239.                 case 'v':
  240.                     ++Verbose; break;
  241.                 case 'X':
  242.                     ++Modem; break;
  243.                 case 'y':
  244.                     Lzmanag = ZMCLOB; break;
  245.                 default:
  246.                     usage();
  247.                 }
  248.             }
  249.         }
  250.         else if ( !npats && argc>0) {
  251.             if (argv[0][0]) {
  252.                 npats=argc;
  253.                 patts=argv;
  254.                 if ( !strcmp(*patts, "-"))
  255.                     iofd = 1;
  256.             }
  257.         }
  258.     }
  259.     if (npats < 1 && !Command) 
  260.         usage();
  261.     if (Verbose) {
  262.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  263.             printf("Can't open log file %s\n",LOGFILE);
  264.             exit(0200);
  265.         }
  266.         setbuf(stderr, NULL);
  267.     }
  268.     if (fromcu() && !Quiet) {
  269.         if (Verbose == 0)
  270.             Verbose = 2;
  271.     }
  272.  
  273.     mode(1);
  274.  
  275.     if (signal(SIGINT, bibi) == SIG_IGN) {
  276.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  277.     }
  278.     else {
  279.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  280.         signal(SIGQUIT, bibi);
  281.     }
  282.  
  283.     if ( !Modem) {
  284.         printf("rz\r");  fflush(stdout);
  285.         if (!Command && !Quiet && Verbose != 1) {
  286.             fprintf(stderr, "sz: %d file%s requested:\r\n",
  287.              npats, npats>1?"s":"");
  288.             for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
  289.                 fprintf(stderr, "%s ", *agcv++);
  290.             }
  291.             fprintf(stderr, "\r\n");
  292.             printf("\r\n\bSending in Batch Mode\r\n");
  293.         }
  294.         stohdr(0L);
  295.         if (Command)
  296.             Txhdr[ZF0] = ZCOMMAND;
  297.         zshhdr(ZRQINIT, Txhdr);
  298.     }
  299.     fflush(stdout);
  300.  
  301.     if (Command) {
  302.         if (getzrxinit()) {
  303.             Exitcode=0200; canit();
  304.         }
  305.         else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  306.             Exitcode=0200; canit();
  307.         }
  308.     } else if (wcsend(npats, patts)==ERROR) {
  309.         Exitcode=0200;
  310.         canit();
  311.     }
  312.     fflush(stdout);
  313.     mode(0);
  314.     exit((errcnt != 0) | Exitcode);
  315.     /*NOTREACHED*/
  316. }
  317.  
  318. wcsend(argc, argp)
  319. char *argp[];
  320. {
  321.     register n;
  322.  
  323.     Crcflg=FALSE;
  324.     firstsec=TRUE;
  325.     for (n=0; n<argc; ++n) {
  326.         Totsecs = 0;
  327.         if (wcs(argp[n])==ERROR)
  328.             return ERROR;
  329.     }
  330.     Totsecs = 0;
  331.     if (Filcnt==0) {    /* bitch if we couldn't open ANY files */
  332.         if (1) {
  333.             Command = TRUE;
  334.             Cmdstr = "echo \"sz: Can't open any requested files\"";
  335.             if (getzrxinit()) {
  336.                 Exitcode=0200; canit();
  337.             }
  338.             else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  339.                 Exitcode=0200; canit();
  340.             }
  341.             Exitcode = 1; return OK;
  342.         }
  343.         canit();
  344.         fprintf(stderr,"\r\nCan't open any requested files.\r\n");
  345.         return ERROR;
  346.     }
  347.     if (Zmodem)
  348.         saybibi();
  349.     else
  350.         wctxpn("");
  351.     return OK;
  352. }
  353.  
  354. wcs(oname)
  355. char *oname;
  356. {
  357.     register c;
  358.     register char *p;
  359.     struct stat f;
  360.     char name[PATHLEN];
  361.  
  362.     strcpy(name, oname);
  363.  
  364.     if (Restricted) {
  365.         /* restrict pathnames to current tree or uucppublic */
  366.         if ( substr(name, "../")
  367.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  368.             canit();
  369.             fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
  370.             return ERROR;
  371.         }
  372.     }
  373.  
  374.     if ( !strcmp(oname, "-")) {
  375.         if ((p = getenv("ONAME")) && *p)
  376.             strcpy(name, p);
  377.         else
  378.             sprintf(name, "s%d.sz", getpid());
  379.         in = stdin;
  380.     }
  381.     else if ((in=fopen(oname, "r"))==NULL) {
  382.         ++errcnt;
  383.         return OK;    /* pass over it, there may be others */
  384.     }
  385.     ++Noeofseen;  Lastread = 0;  Lastc = -1; Dontread = FALSE;
  386.     /* Check for directory or block special files */
  387.     fstat(fileno(in), &f);
  388.     c = f.st_mode & S_IFMT;
  389.     if (c == S_IFDIR || c == S_IFBLK) {
  390.         fclose(in);
  391.         return OK;
  392.     }
  393.  
  394.     ++Filcnt;
  395.     switch (wctxpn(name)) {
  396.     case ERROR:
  397.         return ERROR;
  398.     case ZSKIP:
  399.         return OK;
  400.     }
  401.     if (!Zmodem && wctx()==ERROR)
  402.         return ERROR;
  403.     if (Unlinkafter)
  404.         unlink(oname);
  405.     return 0;
  406. }
  407.  
  408. /*
  409.  * generate and transmit pathname block consisting of
  410.  *  pathname (null terminated),
  411.  *  file length, mode time and file mode in octal
  412.  *  as provided by the Unix fstat call.
  413.  *  N.B.: modifies the passed name, may extend it!
  414.  */
  415. wctxpn(name)
  416. char *name;
  417. {
  418.     register char *p, *q;
  419.     char name2[PATHLEN];
  420.     struct stat f;
  421.  
  422.     if (Modem) {
  423.         if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
  424.             fprintf(stderr, "Sending %s, %ld blocks: ",
  425.               name, f.st_size>>7);
  426.         }
  427.         fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
  428.         return OK;
  429.     }
  430.     logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
  431.     if ( !Zmodem)
  432.         if (getnak())
  433.             return ERROR;
  434.  
  435.     q = (char *) 0;
  436.     if (Dottoslash) {        /* change . to . */
  437.         for (p=name; *p; ++p) {
  438.             if (*p == '/')
  439.                 q = p;
  440.             else if (*p == '.')
  441.                 *(q=p) = '/';
  442.         }
  443.         if (q && strlen(++q) > 8) {    /* If name>8 chars */
  444.             q += 8;            /*   make it .ext */
  445.             strcpy(name2, q);    /* save excess of name */
  446.             *q = '.';
  447.             strcpy(++q, name2);    /* add it back */
  448.         }
  449.     }
  450.  
  451.     for (p=name, q=txbuf ; *p; )
  452.         if ((*q++ = *p++) == '/' && !Fullname)
  453.             q = txbuf;
  454.     *q++ = 0;
  455.     p=q;
  456.     while (q < (txbuf + KSIZE))
  457.         *q++ = 0;
  458.     if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
  459.         sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
  460.     /* force 1k blocks if name won't fit in 128 byte block */
  461.     if (txbuf[125])
  462.         blklen=KSIZE;
  463.     else {        /* A little goodie for IMP/KMD */
  464.         if (Zmodem)
  465.             blklen = SECSIZ;
  466.         txbuf[127] = f.st_size >>7;
  467.         txbuf[126] = f.st_size >>15;
  468.     }
  469.     if (Zmodem)
  470.         return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
  471.     if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
  472.         return ERROR;
  473.     return OK;
  474. }
  475.  
  476. getnak()
  477. {
  478.     register firstch;
  479.  
  480.     Lastrx = 0;
  481.     for (;;) {
  482.         switch (firstch = readock(800,1)) {
  483.         case ZPAD:
  484.             if (getzrxinit())
  485.                 return ERROR;
  486.             Ascii = 0;
  487.             return FALSE;
  488.         case TIMEOUT:
  489.             logent("Timeout on pathname\n");
  490.             return TRUE;
  491.         case WANTG:
  492. #ifdef USG
  493.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  494. #endif
  495.             Optiong = TRUE;
  496.             blklen=KSIZE;
  497.         case WANTCRC:
  498.             Crcflg = TRUE;
  499.         case NAK:
  500.             return FALSE;
  501.         case CAN:
  502.             if ((firstch = readock(20,1)) == CAN && Lastrx == CAN)
  503.                 return TRUE;
  504.         default:
  505.             break;
  506.         }
  507.         Lastrx = firstch;
  508.     }
  509. }
  510.  
  511.  
  512. wctx()
  513. {
  514.     register int sectnum, attempts, firstch;
  515.  
  516.     firstsec=TRUE;
  517.  
  518.     while ((firstch=readock(400, 2))!=NAK && firstch != WANTCRC
  519.       && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
  520.         ;
  521.     if (firstch==CAN) {
  522.         logent("Receiver CANcelled\n");
  523.         return ERROR;
  524.     }
  525.     if (firstch==WANTCRC)
  526.         Crcflg=TRUE;
  527.     if (firstch==WANTG)
  528.         Crcflg=TRUE;
  529.     sectnum=1;
  530.     while (filbuf(txbuf, blklen)) {
  531.         if (wcputsec(txbuf, sectnum, blklen)==ERROR) {
  532.             return ERROR;
  533.         } else
  534.             sectnum++;
  535.     }
  536.     if (Verbose>1)
  537.         fprintf(stderr, " Closing ");
  538.     fclose(in);
  539.     attempts=0;
  540.     do {
  541.         logent(" EOT ");
  542.         purgeline();
  543.         sendline(EOT);
  544.         fflush(stdout);
  545.         ++attempts;
  546.     }
  547.         while ((firstch=(readock(100, 1)) != ACK) && attempts < RETRYMAX);
  548.     if (attempts == RETRYMAX) {
  549.         logent("No ACK on EOT\n");
  550.         return ERROR;
  551.     }
  552.     else
  553.         return OK;
  554. }
  555.  
  556. wcputsec(buf, sectnum, cseclen)
  557. char *buf;
  558. int sectnum;
  559. int cseclen;    /* data length of this sector to send */
  560. {
  561.     register checksum, wcj;
  562.     register char *cp;
  563.     unsigned oldcrc;
  564.     int firstch;
  565.     int attempts;
  566.  
  567.     firstch=0;    /* part of logic to detect CAN CAN */
  568.  
  569.     if (Verbose>1)
  570.         fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
  571.     for (attempts=0; attempts <= RETRYMAX; attempts++) {
  572.         Lastrx= firstch;
  573.         sendline(cseclen==KSIZE?STX:SOH);
  574.         sendline(sectnum);
  575.         sendline(-sectnum -1);
  576.         oldcrc=checksum=0;
  577.         for (wcj=cseclen,cp=buf; --wcj>=0; ) {
  578.             sendline(*cp);
  579.             oldcrc=updcrc(*cp, oldcrc);
  580.             checksum += *cp++;
  581.         }
  582.         if (Crcflg) {
  583.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  584.             sendline((int)oldcrc>>8);
  585.             sendline((int)oldcrc);
  586.         }
  587.         else
  588.             sendline(checksum);
  589.  
  590.         if (Optiong) {
  591.             firstsec = FALSE; return OK;
  592.         }
  593.         firstch = readock(400, (Noeofseen&§num) ? 2:1);
  594. gotnak:
  595.         switch (firstch) {
  596.         case CAN:
  597.             if(Lastrx == CAN) {
  598. cancan:
  599.                 logent("Cancelled\n");  return ERROR;
  600.             }
  601.             break;
  602.         case TIMEOUT:
  603.             logent("Timeout on sector ACK\n"); continue;
  604.         case WANTCRC:
  605.             if (firstsec)
  606.                 Crcflg = TRUE;
  607.         case NAK:
  608.             logent("NAK on sector\n"); continue;
  609.         case ACK: 
  610.             firstsec=FALSE;
  611.             Totsecs += (cseclen>>7);
  612.             return OK;
  613.         case ERROR:
  614.             logent("Got burst for sector ACK\n"); break;
  615.         default:
  616.             logent("Got %02x for sector ACK\n", firstch); break;
  617.         }
  618.         for (;;) {
  619.             Lastrx = firstch;
  620.             if ((firstch = readock(400, 2)) == TIMEOUT)
  621.                 break;
  622.             if (firstch == NAK || firstch == WANTCRC)
  623.                 goto gotnak;
  624.             if (firstch == CAN && Lastrx == CAN)
  625.                 goto cancan;
  626.         }
  627.     }
  628.     logent("Retry Count Exceeded\n");
  629.     return ERROR;
  630. }
  631.  
  632. /* fill buf with count chars padding with ^Z for CPM */
  633. filbuf(buf, count)
  634. register char *buf;
  635. {
  636.     register c, m;
  637.  
  638.     if ( !Ascii) {
  639.         m = read(fileno(in), buf, count);
  640.         if (m <= 0)
  641.             return 0;
  642.         while (m < count)
  643.             buf[m++] = 032;
  644.         return count;
  645.     }
  646.     m=count;
  647.     if (Lfseen) {
  648.         *buf++ = 012; --m; Lfseen = 0;
  649.     }
  650.     while ((c=getc(in))!=EOF) {
  651.         if (c == 012) {
  652.             *buf++ = 015;
  653.             if (--m == 0) {
  654.                 Lfseen = TRUE; break;
  655.             }
  656.         }
  657.         *buf++ =c;
  658.         if (--m == 0)
  659.             break;
  660.     }
  661.     if (m==count)
  662.         return 0;
  663.     else
  664.         while (--m>=0)
  665.             *buf++ = CPMEOF;
  666.     return count;
  667. }
  668. /* fill buf with count chars */
  669. zfilbuf(buf, count)
  670. register char *buf;
  671. {
  672.     register c, m;
  673.  
  674.     m=count;
  675.     while ((c=getc(in))!=EOF) {
  676.         *buf++ =c;
  677.         if (--m == 0)
  678.             break;
  679.     }
  680.     return (count - m);
  681. }
  682.  
  683. /* VARARGS1 */
  684. vfile(f, a, b, c)
  685. register char *f;
  686. {
  687.     if (Verbose > 1) {
  688.         fprintf(stderr, f, a, b, c);
  689.         fprintf(stderr, "\n");
  690.     }
  691. }
  692.  
  693.  
  694. alrm()
  695. {
  696.     longjmp(tohere, -1);
  697. }
  698.  
  699.  
  700. /*
  701.  * readock(timeout, count) reads character(s) from file descriptor 0
  702.  *  (1 <= count <= 3)
  703.  * it attempts to read count characters. If it gets more than one,
  704.  * it is an error unless all are CAN
  705.  * (otherwise, only normal response is ACK, CAN, or C)
  706.  *  Only looks for one if Optiong, which signifies cbreak, not raw input
  707.  *
  708.  * timeout is in tenths of seconds
  709.  */
  710. readock(timeout, count)
  711. {
  712.     register int c;
  713.     static char byt[5];
  714.  
  715.     if (Optiong)
  716.         count = 1;    /* Special hack for cbreak */
  717.  
  718.     fflush(stdout);
  719.     if (setjmp(tohere)) {
  720.         logent("TIMEOUT\n");
  721.         return TIMEOUT;
  722.     }
  723.     c = timeout/10;
  724.     if (c<2)
  725.         c=2;
  726.     if (Verbose>3) {
  727.         fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
  728.         byt[1] = 0;
  729.     }
  730.     signal(SIGALRM, alrm); alarm(c);
  731. #ifdef ONEREAD
  732.     c=read(iofd, byt, 1);        /* regulus raw read is unique */
  733. #else
  734.     c=read(iofd, byt, count);
  735. #endif
  736.     alarm(0);
  737.     if (Verbose>5)
  738.         fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
  739.     if (c<1)
  740.         return TIMEOUT;
  741.     if (c==1)
  742.         return (byt[0]&0377);
  743.     else
  744.         while (c)
  745.             if (byt[--c] != CAN)
  746.                 return ERROR;
  747.     return CAN;
  748. }
  749. readline(n)
  750. {
  751.     return (readock(n, 1));
  752. }
  753.  
  754.  
  755. purgeline()
  756. {
  757. #ifdef USG
  758.     ioctl(iofd, TCFLSH, 0);
  759. #else
  760.     lseek(iofd, 0L, 2);
  761. #endif
  762. }
  763.  
  764. /* update CRC */
  765. unsigned
  766. updcrc(c, crc)
  767. register c;
  768. register unsigned crc;
  769. {
  770.     register count;
  771.  
  772.     for (count=8; --count>=0;) {
  773.         if (crc & 0x8000) {
  774.             crc <<= 1;
  775.             crc += (((c<<=1) & 0400)  !=  0);
  776.             crc ^= 0x1021;
  777.         }
  778.         else {
  779.             crc <<= 1;
  780.             crc += (((c<<=1) & 0400)  !=  0);
  781.         }
  782.     }
  783.     return crc;    
  784. }
  785.  
  786. /* send cancel string to get the other end to shut up */
  787. canit()
  788. {
  789.     static char canistr[] = {
  790.      ZPAD,ZPAD,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  791.     };
  792.  
  793.     printf(canistr);
  794.     fflush(stdout);
  795. }
  796.  
  797. /*VARARGS1*/
  798. logent(a, b, c)
  799. char *a, *b, *c;
  800. {
  801.     if(Verbose)
  802.         fprintf(stderr, a, b, c);
  803. }
  804.  
  805. /*
  806.  * return 1 iff stdout and stderr are different devices
  807.  *  indicating this program operating with a modem on a
  808.  *  different line
  809.  */
  810. fromcu()
  811. {
  812.     struct stat a, b;
  813.     fstat(1, &a); fstat(2, &b);
  814.     return (a.st_rdev != b.st_rdev);
  815. }
  816.  
  817. /*
  818.  * substr(string, token) searches for token in string s
  819.  * returns pointer to token within string if found, NULL otherwise
  820.  */
  821. char *
  822. substr(s, t)
  823. register char *s,*t;
  824. {
  825.     register char *ss,*tt;
  826.     /* search for first char of token */
  827.     for (ss=s; *s; s++)
  828.         if (*s == *t)
  829.             /* compare token with substring */
  830.             for (ss=s,tt=t; ;) {
  831.                 if (*tt == 0)
  832.                     return s;
  833.                 if (*ss++ != *tt++)
  834.                     break;
  835.             }
  836.     return NULL;
  837. }
  838.  
  839. usage()
  840. {
  841.     fprintf(stderr,"\nSend file(s) with ZMODEM/YMODEM/XMODEM Protocol\n");
  842.     fprintf(stderr,"    (Y) = Option applies to YMODEM only\n");
  843.     fprintf(stderr,"    (Z) = Option applies to ZMODEM only\n");
  844.     fprintf(stderr,"%s for %s by Chuck Forsberg\n", VERSION, OS);
  845.     fprintf(stderr,"Usage:    sz [-12+adfknquvXy] [-] file ...\n");
  846.     fprintf(stderr,"    sz [-1qv] -c COMMAND\n");
  847.     fprintf(stderr,"    1 Use stdout for modem input\n");
  848. #ifdef CSTOPB
  849.     fprintf(stderr,"    2 Use 2 stop bits\n");
  850. #endif
  851.     fprintf(stderr,"    + Append to existing destination file (Z)\n");
  852.     fprintf(stderr,"    a (ASCII) change NL to CR/LF\n");
  853.     fprintf(stderr,"    c send COMMAND (Z)\n");
  854.     fprintf(stderr,"\tC N (set command retries to N default=%d) (Z)\n",
  855.       Cmdtries);
  856.     fprintf(stderr,"    d Change '.' to '/' in pathnames (Y/Z)\n");
  857.     fprintf(stderr,"    f send Full pathname (Y/Z)\n");
  858.     fprintf(stderr,"    i send COMMAND, ack Immediately (Z)\n");
  859.     fprintf(stderr,"    k Send 1024 byte packets (Y)\n");
  860.     fprintf(stderr,"    L N Limit packet length to N bytes (Z)\n");
  861.     fprintf(stderr,"    l N Limit frame length to N bytes (l>=L) (Z)\n");
  862.     fprintf(stderr,"    n send file if Newer|different length (Z)\n");
  863.     fprintf(stderr,"    N send file if different length|CRC (Z)\n");
  864.     fprintf(stderr,"    r Resume/Recover interrupted file transfer (Z)\n");
  865.     fprintf(stderr,"    q Quiet (no progress reports)\n");
  866.     fprintf(stderr,"    u Unlink file after transmission\n");
  867.     fprintf(stderr,"    v Verbose - debugging information\n");
  868.     fprintf(stderr,"    X XMODEM protocol - send no pathnames\n");
  869.     fprintf(stderr,"    y Yes, overwrite existing file (Z)\n");
  870.     fprintf(stderr,"- as pathname sends standard input as sPID.sz or environment ONAME\n");
  871.     exit(1);
  872. }
  873.  
  874. /*
  875.  * Get the receiver's init parameters
  876.  */
  877. getzrxinit()
  878. {
  879.     register n;
  880.     struct stat f;
  881.  
  882.     for (n=10; --n>=0; ) {
  883.         
  884.         switch (zgethdr(Rxhdr, 1)) {
  885.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  886.             stohdr(Rxpos);
  887.             zshhdr(ZACK, Txhdr);
  888.             continue;
  889.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  890.             stohdr(0L);
  891.             zshhdr(ZRQINIT, Txhdr);
  892.             continue;
  893.         case ZRINIT:
  894.             Rxflags = 0377 & Rxhdr[ZF0];
  895.             Rxbuflen = (0337 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  896.             vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  897.             signal(SIGINT, SIG_IGN);
  898. #ifdef USG
  899.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  900. #else
  901. #ifndef READCHECK
  902.             /* Use 1024 byte frames if no sample/interrupt */
  903.             if (Rxbuflen < 64 || Rxbuflen > 1024) {
  904.                 Rxbuflen = 1024;
  905.                 vfile("Rxbuflen=%d", Rxbuflen);
  906.             }
  907. #endif
  908. #endif
  909.             /* Override to force shorter frame length */
  910.             if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=64))
  911.                 Rxbuflen = Tframlen;
  912.             if ( !Rxbuflen && (Tframlen>=64) && (Tframlen<=1024))
  913.                 Rxbuflen = Tframlen;
  914.             vfile("Rxbuflen=%d", Rxbuflen);
  915.  
  916.             /* If using a pipe for testing set lower buf len */
  917.             fstat(iofd, &f);
  918.             if ((f.st_mode & S_IFMT) != S_IFCHR
  919.               && (Rxbuflen == 0 || Rxbuflen > 4096))
  920.                 Rxbuflen = 4096;
  921.             /*
  922.              * If input is not a regular file, force ACK's each 1024
  923.              *  (A smarter strategey could be used here ...)
  924.              */
  925.             fstat(fileno(in), &f);
  926.             if (((f.st_mode & S_IFMT) != S_IFREG)
  927.               && (Rxbuflen == 0 || Rxbuflen > 1024))
  928.                 Rxbuflen = 1024;
  929.             vfile("Rxbuflen=%d", Rxbuflen);
  930.  
  931.             return (sendzsinit());
  932.         case ZCAN:
  933.         case TIMEOUT:
  934.             return ERROR;
  935.         case ZRQINIT:
  936.             if (Rxhdr[ZF0] == ZCOMMAND)
  937.                 continue;
  938.         default:
  939.             zshhdr(ZNAK, Txhdr);
  940.             continue;
  941.         }
  942.     }
  943.     return ERROR;
  944. }
  945.  
  946. /* Send send-init information */
  947. sendzsinit()
  948. {
  949.     register c;
  950.     register errors;
  951.  
  952.     errors = 0;
  953.     for (;;) {
  954.         stohdr(0L);
  955.         zsbhdr(ZSINIT, Txhdr);
  956.         zsdata(Myattn, 1+strlen(Myattn), ZCRCW);
  957.         c = zgethdr(Rxhdr, 1);
  958.         switch (c) {
  959.         case ZCAN:
  960.             return ERROR;
  961.         case ZACK:
  962.             return OK;
  963.         default:
  964.             if (++errors > 9)
  965.                 return ERROR;
  966.             continue;
  967.         }
  968.     }
  969. }
  970.  
  971. /* Send file name and related info */
  972. zsendfile(buf, blen)
  973. char *buf;
  974. {
  975.     register c;
  976.  
  977.     for (;;) {
  978.         Txhdr[ZF0] = Lzconv;    /* file conversion request */
  979.         Txhdr[ZF1] = Lzmanag;    /* file management request */
  980.         Txhdr[ZF2] = Lztrans;    /* file transport request */
  981.         Txhdr[ZF3] = 0;
  982.         zsbhdr(ZFILE, Txhdr);
  983.         zsdata(buf, blen, ZCRCW);
  984. again:
  985.         c = zgethdr(Rxhdr, 1);
  986.         switch (c) {
  987.         case ZRINIT:
  988.             goto again;
  989.         case ZCAN:
  990.         case TIMEOUT:
  991.         case ZABORT:
  992.         case ZFIN:
  993.             return ERROR;
  994.         case ZSKIP:
  995.             fclose(in); return c;
  996.         case ZRPOS:
  997.             fseek(in, Rxpos, 0);
  998.             Txpos = Rxpos; Lastc = -1; Dontread = FALSE;
  999.             return zsendfdata();
  1000.         case ERROR:
  1001.         default:
  1002.             continue;
  1003.         }
  1004.     }
  1005. }
  1006.  
  1007. /* Send the data in the file */
  1008. zsendfdata()
  1009. {
  1010.     register c, e;
  1011.     register newcnt;
  1012.     register long tcount = 0;
  1013.     static int tleft = 6;    /* Counter for test mode */
  1014.  
  1015.     if (Baudrate > 300)
  1016.         blklen = 256;
  1017.     if (Baudrate > 2400)
  1018.         blklen = KSIZE;
  1019.     if (Rxbuflen && blklen>Rxbuflen)
  1020.         blklen = Rxbuflen;
  1021.     if (blkopt && blklen > blkopt)
  1022.         blklen = blkopt;
  1023.     vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1024. somemore:
  1025.     if (setjmp(intrjmp)) {
  1026. waitack:
  1027.         switch (c = getinsync()) {
  1028.         default:
  1029.         case ZCAN:
  1030.             fclose(in);
  1031.             return ERROR;
  1032.         case ZSKIP:
  1033.             fclose(in);
  1034.             return c;
  1035.         case ZACK:
  1036.         case ZRPOS:
  1037.             break;
  1038.         }
  1039.     }
  1040.  
  1041.     signal(SIGINT, onintr);
  1042.     newcnt = Rxbuflen;
  1043.     stohdr(Txpos);
  1044.     zsbhdr(ZDATA, Txhdr);
  1045.  
  1046.     /*
  1047.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  1048.      *  many times.  Each time the signal should be caught, causing the
  1049.      *  file to be started over from the beginning.
  1050.      */
  1051.     if (Testattn) {
  1052.         if ( --tleft)
  1053.             while (tcount < 20000) {
  1054.                 printf(qbf); fflush(stdout);
  1055.                 tcount += strlen(qbf);
  1056.             }
  1057.         signal(SIGINT, SIG_IGN); canit();
  1058.         sleep(3); purgeline(); mode(0);
  1059.         printf("\nsz: Tcount = %ld\n", tcount);
  1060.         if (tleft) {
  1061.             printf("ERROR: Interrupts Not Caught\n");
  1062.             exit(1);
  1063.         }
  1064.         exit(0);
  1065.     }
  1066.  
  1067.     do {
  1068.         if (Dontread) {
  1069.             c = Lastc;
  1070.         } else {
  1071.             c = zfilbuf(txbuf, blklen);
  1072.             Lastread = Txpos;  Lastc = c;
  1073.         }
  1074.         vfile("Dontread=%d c=%d", Dontread, c);
  1075.         Dontread = FALSE;
  1076.         if (c < blklen)
  1077.             e = ZCRCE;
  1078.         else if (Rxbuflen && (newcnt -= c) <= 0)
  1079.             e = ZCRCW;
  1080.         else
  1081.             e = ZCRCG;
  1082.         zsdata(txbuf, c, e);
  1083.         Txpos += c;
  1084.         if (e == ZCRCW)
  1085.             goto waitack;
  1086. #ifdef READCHECK
  1087.         /*
  1088.          * If the reverse channel can be tested for data,
  1089.          *  this logic may be used to detect error packets
  1090.          *  sent by the receiver, in place of setjmp/longjmp
  1091.          *  rdchk(fdes) returns non 0 if a character is available
  1092.          */
  1093.         while (rdchk(iofd)) {
  1094.             switch (readline(1)) {
  1095.             case CAN:
  1096.             case ZPAD:
  1097.                 zsdata(txbuf, 0, ZCRCW);
  1098.                 goto somemore;
  1099.             }
  1100.         }
  1101. #endif
  1102.     } while (c == blklen);
  1103.     signal(SIGINT, SIG_IGN);
  1104.  
  1105.     for (;;) {
  1106.         stohdr(Txpos);
  1107.         zsbhdr(ZEOF, Txhdr);
  1108.         switch (getinsync()) {
  1109.         case ZRPOS:
  1110.             goto somemore;
  1111.         case ZRINIT:
  1112.             fclose(in);
  1113.             return OK;
  1114.         case ZSKIP:
  1115.             fclose(in);
  1116.             return c;
  1117.         default:
  1118.             fclose(in);
  1119.             return ERROR;
  1120.         }
  1121.     }
  1122. }
  1123.  
  1124. /*
  1125.  * Respond to receiver's complaint, get back in sync with receiver
  1126.  */
  1127. getinsync()
  1128. {
  1129.     register c;
  1130.  
  1131.     for (;;) {
  1132.         if (Testattn) {
  1133.             printf("\r\n\n\n***** Signal Caught *****\r\n");
  1134.             Rxpos = 0; c = ZRPOS;
  1135.         } else
  1136.             c = zgethdr(Rxhdr, 0);
  1137.         switch (c) {
  1138.         case ZCAN:
  1139.         case ZABORT:
  1140.         case ZFIN:
  1141.         case TIMEOUT:
  1142.             return ERROR;
  1143.         case ZRPOS:
  1144.             if (Lastc >= 0 && Lastread == Rxpos) {
  1145.                 Dontread = TRUE;
  1146.             } else {
  1147.                 clearerr(in);    /* In case file EOF seen */
  1148.                 fseek(in, Rxpos, 0);
  1149.             }
  1150.             Txpos = Rxpos;
  1151.             return c;
  1152.         case ZACK:
  1153.             return c;
  1154.         case ZRINIT:
  1155.         case ZSKIP:
  1156.             fclose(in);
  1157.             return c;
  1158.         case ERROR:
  1159.         default:
  1160.             zsbhdr(ZNAK, Txhdr);
  1161.             continue;
  1162.         }
  1163.     }
  1164. }
  1165. /* Say "bibi" to the receiver, try to do it cleanly */
  1166. saybibi()
  1167. {
  1168.     for (;;) {
  1169.         stohdr(0L);
  1170.         zsbhdr(ZFIN, Txhdr);
  1171.         switch (zgethdr(Rxhdr, 0)) {
  1172.         case ZFIN:
  1173.             sendline('O'); sendline('O'); flushmo();
  1174.         case ZCAN:
  1175.         case TIMEOUT:
  1176.             return;
  1177.         }
  1178.     }
  1179. }
  1180.  
  1181. /* Local screen character display function */
  1182. bttyout(c)
  1183. {
  1184.     if (Verbose)
  1185.         putc(c, stderr);
  1186. }
  1187.  
  1188. /* Send command and related info */
  1189. zsendcmd(buf, blen)
  1190. char *buf;
  1191. {
  1192.     register c, errors;
  1193.     long cmdnum;
  1194.  
  1195.     cmdnum = getpid();
  1196.     errors = 0;
  1197.     for (;;) {
  1198.         stohdr(cmdnum);
  1199.         Txhdr[ZF0] = Cmdack1;
  1200.         zsbhdr(ZCOMMAND, Txhdr);
  1201.         zsdata(buf, blen, ZCRCW);
  1202. listen:
  1203.         Rxtimeout = 100;        /* Ten second wait for resp. */
  1204.         c = zgethdr(Rxhdr, 1);
  1205.  
  1206.         switch (c) {
  1207.         case ZRINIT:
  1208.             continue;
  1209.         case ERROR:
  1210.         case TIMEOUT:
  1211.             if (++errors > Cmdtries)
  1212.                 return ERROR;
  1213.             continue;
  1214.         case ZCAN:
  1215.         case ZABORT:
  1216.         case ZFIN:
  1217.         case ZSKIP:
  1218.         case ZRPOS:
  1219.             return ERROR;
  1220.         default:
  1221.             if (++errors > 10)
  1222.                 return ERROR;
  1223.             continue;
  1224.         case ZCOMPL:
  1225.             Exitcode = Rxpos;
  1226.             saybibi();
  1227.             return OK;
  1228.         case ZRQINIT:
  1229.             vfile("******** RZ *******");
  1230.             system("rz");
  1231.             vfile("******** SZ *******");
  1232.             goto listen;
  1233.         }
  1234.     }
  1235. }
  1236.  
  1237.