home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 260_01 / sz.c < prev    next >
Text File  |  1988-02-25  |  40KB  |  1,636 lines

  1. #define VERSION "sz 1.23 01-15-87"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -O -K -i -DCRCTABLE -DREADCHECK sz.c -lx -o sz; size sz
  5.  
  6.  * sz.c By Chuck Forsberg
  7.  *      MS-DOS version by Francois Bergeon
  8.  *
  9.  *      cc -O sz.c -o sz                USG (SYS III/V) Unix
  10.  *      cc -O -DSVR2 sz.c -o sz         Sys V Release 2 with non-blocking input
  11.  *                                      Define to allow reverse channel checking
  12.  *      cc -O -DV7  sz.c -o sz          Unix Version 7, 2.8 - 4.3 BSD
  13.  *      cl rz.c -link stty              MS-DOS, MS-C 4.00+
  14.  *
  15.  *      ln sz sb                        USG & V7
  16.  *
  17.  *              define CRCTABLE to use table driven CRC
  18.  *
  19.  *  ******* Some systems (Venix, Coherent, Regulus) do not *******
  20.  *  ******* support tty raw mode read(2) identically to    *******
  21.  *  ******* Unix. ONEREAD must be defined to force one     *******
  22.  *  ******* character reads for these systems.             *******
  23.  *
  24.  * A program for Unix to send files and commands to computers running
  25.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
  26.  *
  27.  *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
  28.  *
  29.  *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
  30.  *
  31.  *  MS-DOS Adaptation 10-19-87 for the MS-C compiler rev 4.00+
  32.  *  using Francois Bergeon's tty library
  33.  */
  34.  
  35.  
  36. char *substr(), *getenv();
  37.  
  38. #define LOGFILE "/tmp/szlog"
  39.  
  40. #include <stdio.h>
  41. #include <signal.h>
  42. #include <setjmp.h>
  43. #include <ctype.h>
  44.  
  45. #ifdef MSDOS
  46. #include <time.h>
  47. #define CRCTABLE
  48. #define JAN1ST70  315532800      /* difference in seconds between */
  49.                                  /* Jan 1st 1980 & Jan 1st 1970   */
  50. #endif
  51.  
  52. #define PATHLEN 256
  53. #define OK 0
  54. #define FALSE 0
  55. #define TRUE 1
  56. #define ERROR (-1)
  57.  
  58. #define HOWMANY 2
  59. int Zmodem = 0;         /* ZMODEM protocol requested */
  60. unsigned Baudrate;
  61. int Fromcu = 0;         /* Were called from cu or yam */
  62. #include "rbsb.c"       /* most of the system dependent stuff here */
  63.  
  64. /*
  65.  * Attention string to be executed by receiver to interrupt streaming data
  66.  *  when an error is detected.  A pause (0336) may be needed before the
  67.  *  ^C (03) or after it.
  68.  */
  69. #ifdef READCHECK
  70. char Myattn[] = { 0 };
  71. #else
  72. #ifdef USG
  73. char Myattn[] = { 03, 0336, 0 };
  74. #else
  75. char Myattn[] = { 0 };
  76. #endif
  77. #endif
  78.  
  79. FILE *in;
  80.  
  81. /* Ward Christensen / CP/M parameters - Don't change these! */
  82. #define ENQ 005
  83. #define CAN ('X'&037)
  84. #define XOFF ('s'&037)
  85. #define XON ('q'&037)
  86. #define SOH 1
  87. #define STX 2
  88. #define EOT 4
  89. #define ACK 6
  90. #define NAK 025
  91. #define CPMEOF 032
  92. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  93. #define WANTG 0107      /* Send G not NAK to get nonstop batch xmsn */
  94. #define TIMEOUT (-2)
  95. #define RCDO (-3)
  96. #define RETRYMAX 10
  97. #define SECSIZ 128      /* cp/m's Magic Number record size */
  98. #define KSIZE 1024
  99.  
  100. char Lastrx;
  101. char Crcflg;
  102. int Wcsmask = 0377;
  103. int Verbose = 0;
  104. int Modem = 0;          /* MODEM - don't send pathnames */
  105. int Restricted = 0;     /* restricted; no /.. or ../ in filenames */
  106. int Quiet = 0;          /* overrides logic that would otherwise set verbose */
  107. int Ascii = 0;          /* Add CR's for brain damaged programs */
  108. int Fullname = 0;       /* transmit full pathname */
  109. int Unlinkafter = 0;    /* Unlink file after it is sent */
  110. int Dottoslash = 0;     /* Change foo.bar.baz to foo/bar/baz */
  111. int firstsec;
  112. int errcnt = 0;         /* number of files unreadable */
  113. int blklen = SECSIZ;    /* length of transmitted records */
  114. int Optiong;            /* Let it rip no wait for sector ACK's */
  115. int Noeofseen;
  116. int Totsecs;            /* total number of sectors this file */
  117. char txbuf[KSIZE];
  118. int Filcnt = 0;         /* count of number of files opened */
  119. int Lfseen = 0;
  120. unsigned Rxbuflen = 16384;      /* Receiver's max buffer length */
  121. int Tframlen = 0;       /* Override for tx frame length */
  122. int blkopt = 0;         /* Override value for zmodem blklen */
  123. int Rxflags = 0;
  124. int Wantfcs32 = TRUE;   /* want to send 32 bit FCS */
  125. char Lzconv;            /* Local ZMODEM file conversion request */
  126. char Lzmanag;           /* Local ZMODEM file management request */
  127. char Lztrans;
  128. char zconv;             /* ZMODEM file conversion request */
  129. char zmanag;            /* ZMODEM file management request */
  130. char ztrans;            /* ZMODEM file transport request */
  131. int Command;            /* Send a command, then exit. */
  132. char *Cmdstr;           /* Pointer to the command string */
  133. int Cmdtries = 11;
  134. int Cmdack1;            /* Rx ACKs command, then do it */
  135. int Exitcode;
  136. int Testattn;           /* Force receiver to send Attn, etc with qbf. */
  137. char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
  138. long Lastread;          /* Beginning offset of last buffer read */
  139. int Lastc;              /* Count of last buffer read or -1 */
  140. int Dontread;           /* Don't read the buffer, it's still there */
  141.  
  142. #ifndef MSDOS
  143. jmp_buf tohere;         /* For the interrupt on RX timeout */
  144. #endif
  145.  
  146. jmp_buf intrjmp;        /* For the interrupt on RX CAN */
  147.  
  148. /* called by signal interrupt or terminate to clean things up */
  149. bibi(n)
  150.    {
  151.    canit();
  152.    fflush(stdout);
  153.    mode(0);
  154.    fprintf(stderr, "sz: caught signal %d; exiting\n", n);
  155. #ifndef MSDOS
  156.    if (n == SIGQUIT)
  157.       abort();
  158. #endif
  159.    exit(128+n);
  160.    }
  161. /* Called when Zmodem gets an interrupt (^X) */
  162.  
  163. onintr()
  164.    {
  165.    signal(SIGINT, SIG_IGN);
  166.    longjmp(intrjmp, -1);
  167.    }
  168.  
  169. #ifndef MSDOS
  170. #define sendline(c) putchar(c & Wcsmask)
  171. #define xsendline(c) putchar(c)
  172.  
  173. flushmo()
  174.    {
  175.    fflush(stdout);
  176.    }
  177.  
  178. #else /* MSDOS */
  179.  
  180. #define sendline(c) xsendline(c & Wcsmask)
  181.  
  182. xsendline(c)
  183. int c;
  184.    {
  185.    tty_write(iofd, &c, 1);
  186.    }
  187.  
  188. flushmo()
  189.    {
  190.    }
  191. #endif
  192.  
  193. #define ZKER
  194. int Zctlesc;    /* Encode control characters */
  195. int Nozmodem = 0;       /* If invoked as "sb" */
  196. char *Progname = "sz";
  197. #include "zm.c"
  198.  
  199.  
  200. main(argc, argv)
  201. char *argv[];
  202.    {
  203.    char *cp;
  204.    int npats;
  205.    int agcnt;
  206.    char **agcv;
  207.    char **patts;
  208.    static char xXbuf[BUFSIZ];
  209.  
  210.    if ((cp = getenv("ZNULLS")) && *cp)
  211.       Znulls = atoi(cp);
  212.    if ((cp = getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  213.       Restricted = TRUE;
  214. #ifndef MSDOS
  215.    chkinvok(argv[0]);
  216. #else
  217.    Progname = "sz";
  218. #endif
  219.  
  220.    Rxtimeout = 600;
  221.    npats = 0;
  222.    if (argc < 2)
  223.       usage();
  224.    setbuf(stdout, xXbuf);          
  225.    while (--argc)
  226.       {
  227.       cp = *++argv;
  228.       if (*cp++ == '-' && *cp)
  229.          {
  230.          while (*cp)
  231.             {
  232.             switch (*cp++)
  233.                {
  234.                case '+':
  235.                   Lzmanag = ZMAPND;
  236.                   break;
  237. #ifndef MSDOS
  238.                case '1':
  239.                   iofd = 1;
  240.                   break;
  241. #ifdef CSTOPB
  242.                case '2':
  243.                   Twostop = TRUE;
  244.                   break;
  245. #endif
  246. #else
  247.                case '2':
  248.                   port = "COM2";
  249.                   break;
  250.                case 's':
  251.                   Baudrate = atoi(cp);
  252.                   if ((speed = getspeed(Baudrate)) < 0)
  253.                      usage();
  254.                   cp = '\0';
  255.                   break;
  256.                case 'Y':
  257.                   Nozmodem = TRUE;
  258.                   break;
  259. #endif
  260.                case '7':
  261.                   Wcsmask=0177;
  262.                   break;
  263.                case 'a':
  264.                   Lzconv = ZCNL;
  265.                   Ascii = TRUE;
  266.                   break;
  267.                case 'b':
  268.                   Lzconv = ZCBIN;
  269.                   break;
  270.                case 'C':
  271.                   if (--argc < 1)
  272.                      usage();
  273.                   Cmdtries = atoi(*++argv);
  274.                   break;
  275.                case 'i':
  276.                   Cmdack1 = ZCACK1;
  277.                /* **** FALL THROUGH TO **** */
  278.                case 'c':
  279.                   if (--argc != 1)
  280.                      usage();
  281.                   Command = TRUE;
  282.                   Cmdstr = *++argv;
  283.                   break;
  284.                case 'd':
  285.                   ++Dottoslash;
  286.                /* **** FALL THROUGH TO **** */
  287.                case 'f':
  288.                   Fullname=TRUE;
  289.                   break;
  290.                case 'E':
  291.                   Zctlesc = -1;
  292.                   break;
  293.                case 'e':
  294.                   Zctlesc = 1;
  295.                   break;
  296.                case 'k':
  297.                   blklen = KSIZE;
  298.                   break;
  299.                case 'L':
  300.                   if (--argc < 1)
  301.                      usage();
  302.                   blkopt = atoi(*++argv);
  303.                   if (blkopt < 24 || blkopt > 1024)
  304.                      usage();
  305.                   break;
  306.                case 'l':
  307.                   if (--argc < 1)
  308.                      usage();
  309.                   Tframlen = atoi(*++argv);
  310.                   if (Tframlen < 32 || Tframlen > 1024)
  311.                      usage();
  312.                   break;
  313.                case 'N':
  314.                   Lzmanag = ZMDIFF;
  315.                   break;
  316.                case 'n':
  317.                   Lzmanag = ZMNEW;
  318.                   break;
  319.                case 'o':
  320.                   Wantfcs32 = FALSE;
  321.                   break;
  322.                case 'p':
  323.                   Lzmanag = ZMPROT;
  324.                   break;
  325.                case 'r':
  326.                   Lzconv = ZCRESUM;
  327.                case 'q':
  328.                   Quiet = TRUE;
  329.                   Verbose = 0;
  330.                   break;
  331.                case 't':
  332.                   if (--argc < 1) 
  333.                      usage();
  334.                   Rxtimeout = atoi(*++argv);
  335.                   if (Rxtimeout < 10 || Rxtimeout > 1000)
  336.                      usage();
  337.                   break;
  338.                case 'T':
  339.                   Testattn = TRUE;
  340.                   break;
  341.                case 'u':
  342.                   ++Unlinkafter;
  343.                   break;
  344.                case 'v':
  345.                   ++Verbose;
  346.                   break;
  347.                case 'X':
  348.                   ++Modem;
  349.                   break;
  350.                case 'y':
  351.                   Lzmanag = ZMCLOB;
  352.                   break;
  353.                default:
  354.                   usage();
  355.                }
  356.             }
  357.          }
  358.       else if (!npats && argc > 0)
  359.          {
  360.          if (argv[0][0])
  361.             {
  362.             npats = argc;
  363.             patts = argv;
  364. #ifndef MSDOS
  365.             if (!strcmp(*patts, "-"))
  366.                iofd = 1;
  367. #endif
  368.             }
  369.          }
  370.       }
  371.    if (npats < 1 && !Command) 
  372.       usage();
  373.    if (Verbose)
  374.       {
  375.       if (freopen(LOGFILE, "a", stderr) == NULL)
  376.          {
  377.          printf("Can't open log file %s\n",LOGFILE);
  378.          exit(0200);
  379.          }
  380.       setbuf(stderr, NULL);
  381.       }
  382.    if ((Fromcu = from_cu()) && !Quiet)
  383.       if (!Verbose)
  384.          Verbose = 2;
  385.  
  386.    mode(1);
  387.  
  388.    if (signal(SIGINT, bibi) == SIG_IGN)
  389.       {
  390.       signal(SIGINT, SIG_IGN);
  391. #ifndef MSDOS
  392.       signal(SIGKILL, SIG_IGN);
  393. #endif
  394.       }
  395.    else
  396.       {
  397.       signal(SIGINT, bibi);
  398. #ifndef MSDOS
  399.       signal(SIGKILL, bibi);
  400. #endif
  401.       }
  402. #ifndef MSDOS
  403.    if (!Fromcu)
  404.       signal(SIGQUIT, SIG_IGN);
  405. #endif
  406.  
  407.    if (!Modem)
  408.       {
  409.       if (!Nozmodem)
  410.          {
  411. #ifndef MSDOS
  412.          printf("rz\r");
  413.          fflush(stdout);
  414. #else
  415.          tty_write(iofd, "rz\r", 3);
  416. #endif
  417.          }
  418.       if (!Command && !Quiet && Verbose != 1)
  419.          {
  420.          fprintf(stderr, "%s: %d file%s requested:\r\n",
  421.                  Progname, npats, (npats > 1 ? "s" : ""));
  422.          for (agcnt = npats, agcv = patts; --agcnt >= 0; )
  423.             fprintf(stderr, "%s ", *agcv++);
  424.          fprintf(stderr, "\r\n");
  425. #ifndef MSDOS
  426.          printf("\r\n\bSending in Batch Mode\r\n");
  427. #else
  428.          tty_write(iofd, "\r\n\bSending in Batch Mode\r\n", 26);
  429. #endif
  430.          }
  431.       if (!Nozmodem)
  432.          {
  433.          stohdr(0L);
  434.          if (Command)
  435.             Txhdr[ZF0] = ZCOMMAND;
  436.          zshhdr(ZRQINIT, Txhdr);
  437.          }
  438.       }
  439.    fflush(stdout);
  440.  
  441.    if (Command)
  442.       {
  443.       if (getzrxinit())
  444.          {
  445.          Exitcode=0200;
  446.          canit();
  447.          }
  448.       else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr)))
  449.          {
  450.          Exitcode=0200;
  451.          canit();
  452.          }
  453.       }
  454.    else if (wcsend(npats, patts) == ERROR)
  455.       {
  456.       Exitcode=0200;
  457.       canit();
  458.       }
  459.    fflush(stdout);
  460.    mode(0);
  461.    exit((errcnt != 0) | Exitcode);
  462.    /*NOTREACHED*/
  463.    }
  464.  
  465. wcsend(argc, argp)
  466. char *argp[];
  467.    {
  468.    int n;
  469.  
  470.    Crcflg = FALSE;
  471.    firstsec = TRUE;
  472.    for (n = 0; n < argc; ++n)
  473.       {
  474.       Totsecs = 0;
  475.       if (wcs(argp[n]) == ERROR)
  476.          return(ERROR);
  477.       }
  478.    Totsecs = 0;
  479.    if (Filcnt == 0)
  480.       {
  481.       /* bitch if we couldn't open ANY files */
  482.       if (1)
  483.          {
  484.          Command = TRUE;
  485.          Cmdstr = "echo \"sz: Can't open any requested files\"";
  486.          if (getnak())
  487.             {
  488.             Exitcode = 0200;
  489.             canit();
  490.             }
  491.          if (!Zmodem)
  492.             canit();
  493.          else if (zsendcmd(Cmdstr, 1 + strlen(Cmdstr)))
  494.             {
  495.             Exitcode=0200;
  496.             canit();
  497.             }
  498.          Exitcode = 1;
  499.          return(OK);
  500.          }
  501.       canit();
  502.       fprintf(stderr, "\r\nCan't open any requested files.\r\n");
  503.       return(ERROR);
  504.       }
  505.    if (Zmodem)
  506.       saybibi();
  507.    else
  508.       wctxpn("");
  509.    return(OK);
  510.    }
  511.  
  512. wcs(oname)
  513. char *oname;
  514.    {
  515.    int c;
  516.    char *p;
  517.    struct stat f;
  518.    char name[PATHLEN];
  519.  
  520.    strcpy(name, oname);
  521.  
  522.    if (Restricted)
  523.       {
  524.       /* restrict pathnames to current tree or uucppublic */
  525.       if (substr(name, "../")
  526.             || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))))
  527.          {
  528.          canit();
  529.          fprintf(stderr, "\r\nsz:\tSecurity Violation\r\n");
  530.          return(ERROR);
  531.          }
  532.       }
  533.  
  534.    if (!strcmp(oname, "-"))
  535.       {
  536.       if ((p = getenv("ONAME")) && *p)
  537.          strcpy(name, p);
  538.       else
  539.          sprintf(name, "s%d.sz", getpid());
  540.       in = stdin;
  541.       }
  542. #ifndef MSDOS
  543.    else if ((in = fopen(oname, "r")) == NULL)
  544. #else
  545.    else if ((in = fopen(oname, "rb")) == NULL)
  546. #endif
  547.       {
  548.       ++errcnt;
  549.       return(OK);      /* pass over it, there may be others */
  550.       }
  551.    ++Noeofseen;
  552.    Lastread = 0;
  553.    Lastc = -1;
  554.    Dontread = FALSE;
  555.    /* Check for directory or block special files */
  556.    fstat(fileno(in), &f);
  557.    c = f.st_mode & S_IFMT;
  558. #ifndef MSDOS
  559.    if (c == S_IFDIR || c == S_IFBLK)
  560. #else
  561.    if (c == S_IFDIR)
  562. #endif
  563.       {
  564.       fclose(in);
  565.       return(OK);
  566.       }
  567.  
  568.    ++Filcnt;
  569.    switch (wctxpn(name))
  570.       {
  571.       case ERROR:
  572.          return(ERROR);
  573.       case ZSKIP:
  574.          return(OK);
  575.       }
  576.    if (!Zmodem && wctx() == ERROR)
  577.       return(ERROR);
  578.    if (Unlinkafter)
  579.       unlink(oname);
  580.    return(0);
  581.    }
  582.  
  583. /*
  584.  * generate and transmit pathname block consisting of
  585.  *  pathname (null terminated),
  586.  *  file length, mode time and file mode in octal
  587.  *  as provided by the Unix fstat call.
  588.  *  N.B.: modifies the passed name, may extend it!
  589.  */
  590. wctxpn(name)
  591. char *name;
  592.    {
  593.    char *p, *q;
  594.    char name2[PATHLEN];
  595.    struct stat f;
  596.  
  597.    if (Modem)
  598.       {
  599.       if ((in != stdin) && *name && fstat(fileno(in), &f) != -1)
  600.          fprintf(stderr, "Sending %s, %ld blocks: ", name, f.st_size >> 7);
  601.       fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
  602.       return(OK);
  603.       }
  604.    logent("\r\nAwaiting pathname nak for %s\r\n", *name ? name : "<END>");
  605.    if (!Zmodem)
  606.       if (getnak())
  607.          return(ERROR);
  608.  
  609.    q = (char *) 0;
  610.    if (Dottoslash)
  611.       {
  612.       /* change . to . */
  613.       for (p = name; *p; ++p)
  614.          {
  615.          if (*p == '/')
  616.             q = p;
  617.          else if (*p == '.')
  618.             *(q=p) = '/';
  619.          }
  620.       if (q && strlen(++q) > 8)
  621.          {
  622.          /* If name>8 chars */
  623.          q += 8;                 /*   make it .ext */
  624.          strcpy(name2, q);       /* save excess of name */
  625.          *q = '.';
  626.          strcpy(++q, name2);     /* add it back */
  627.          }
  628.       }
  629.  
  630.    for (p = name, q = txbuf; *p; )
  631.       if ((*q++ = *p++) == '/' && !Fullname)
  632.          q = txbuf;
  633.    *q++ = 0;
  634.    p = q;
  635.    while (q < (txbuf + KSIZE))
  636.       *q++ = 0;
  637.    if (!Ascii && (in != stdin) && *name && fstat(fileno(in), &f) != -1)
  638. #ifndef MSDOS
  639.       sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
  640. #else
  641.       sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime + JAN1ST70, f.st_mode);
  642. #endif
  643.    /* force 1k blocks if name won't fit in 128 byte block */
  644.    if (txbuf[125])
  645.       blklen = KSIZE;
  646.    else
  647.       {
  648.       /* A little goodie for IMP/KMD */
  649.       if (Zmodem)
  650.          blklen = SECSIZ;
  651.       txbuf[127] = (f.st_size + 127) >>  7;
  652.       txbuf[126] = (f.st_size + 127) >> 15;
  653.       }
  654.    if (Zmodem)
  655.       return(zsendfile(txbuf, 1+strlen(p)+(p-txbuf)));
  656.    if (wcputsec(txbuf, 0, SECSIZ) == ERROR)
  657.       return(ERROR);
  658.    return(OK);
  659.    }
  660.  
  661. getnak()
  662.    {
  663.    int firstch;
  664.  
  665.    Lastrx = 0;
  666.    for (;;)
  667.       {
  668.       switch (firstch = readock(800,1))
  669.          {
  670.          case ZPAD:
  671.             if (getzrxinit())
  672.                return(ERROR);
  673.             Ascii = 0;
  674.             return(FALSE);
  675.          case TIMEOUT:
  676.             logent("Timeout on pathname\n");
  677.             return(TRUE);
  678.          case WANTG:
  679. #ifdef USG
  680.             mode(2);        /* Set cbreak, XON/XOFF, etc. */
  681. #endif
  682.             Optiong = TRUE;
  683.             blklen = KSIZE;
  684.          case WANTCRC:
  685.             Crcflg = TRUE;
  686.          case NAK:
  687.             return(FALSE);
  688.          case CAN:
  689.             if ((firstch = readock(20,1)) == CAN && Lastrx == CAN)
  690.                return(TRUE);
  691.          default:
  692.             break;
  693.          }
  694.       Lastrx = firstch;
  695.       }
  696.    }
  697.  
  698.  
  699. wctx()
  700.    {
  701.    int sectnum, attempts, firstch;
  702.  
  703.    firstsec = TRUE;
  704.  
  705.    while ((firstch = readock(Rxtimeout, 2)) !=NAK && firstch != WANTCRC
  706.           && firstch != WANTG && firstch != TIMEOUT && firstch != CAN)
  707.       {;}
  708.    if (firstch == CAN)
  709.       {
  710.       logent("Receiver CANcelled\n");
  711.       return(ERROR);
  712.       }
  713.    if (firstch == WANTCRC)
  714.       Crcflg = TRUE;
  715.    if (firstch == WANTG)
  716.       Crcflg = TRUE;
  717.    sectnum = 1;
  718.    while (filbuf(txbuf, blklen))
  719.       if (wcputsec(txbuf, sectnum, blklen) == ERROR)
  720.          return(ERROR);
  721.       else
  722.          sectnum++;
  723.    if (Verbose > 1)
  724.       fprintf(stderr, " Closing ");
  725.    fclose(in);
  726.    attempts = 0;
  727.    do
  728.       {
  729.       logent(" EOT ");
  730.       purgeline();
  731.       sendline(EOT);
  732.       fflush(stdout);
  733.       ++attempts;
  734.       }
  735.    while ((firstch = (readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX);
  736.    if (attempts == RETRYMAX)
  737.       {
  738.       logent("No ACK on EOT\n");
  739.       return(ERROR);
  740.       }
  741.    else
  742.       return(OK);
  743.    }
  744.  
  745. wcputsec(buf, sectnum, cseclen)
  746. char *buf;
  747. int sectnum;
  748. int cseclen;    /* data length of this sector to send */
  749.    {
  750.    int checksum, wcj;
  751.    char *cp;
  752.    unsigned oldcrc;
  753.    int firstch;
  754.    int attempts;
  755.  
  756.    firstch = 0;      /* part of logic to detect CAN CAN */
  757.  
  758.    if (Verbose > 1)
  759.       fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
  760.    for (attempts = 0; attempts <= RETRYMAX; attempts++)
  761.       {
  762.       Lastrx = firstch;
  763.       sendline(cseclen == KSIZE ? STX : SOH);
  764.       sendline(sectnum);
  765.       sendline(-sectnum -1);
  766.       oldcrc = checksum = 0;
  767.       for (wcj = cseclen, cp = buf; --wcj >= 0; )
  768.          {
  769.          sendline(*cp);
  770.          oldcrc = updcrc((0377& *cp), oldcrc);
  771.          checksum += *cp++;
  772.          }
  773.       if (Crcflg)
  774.          {
  775.          oldcrc = updcrc(0, updcrc(0, oldcrc));
  776.          sendline((int)oldcrc >> 8);
  777.          sendline((int)oldcrc);
  778.          }
  779.       else
  780.          sendline(checksum);
  781.  
  782.       if (Optiong)
  783.          {
  784.          firstsec = FALSE;
  785.          return(OK);
  786.          }
  787.       firstch = readock(Rxtimeout, (Noeofseen && sectnum) ? 2 : 1);
  788. gotnak:
  789.       switch (firstch)
  790.          {
  791.          case CAN:
  792.             if (Lastrx == CAN)
  793.                {
  794. cancan:
  795.                logent("Cancelled\n");
  796.                return(ERROR);
  797.                }
  798.             break;
  799.          case TIMEOUT:
  800.             logent("Timeout on sector ACK\n");
  801.             continue;
  802.          case WANTCRC:
  803.             if (firstsec)
  804.                Crcflg = TRUE;
  805.          case NAK:
  806.             logent("NAK on sector\n");
  807.             continue;
  808.          case ACK: 
  809.             firstsec = FALSE;
  810.             Totsecs += (cseclen >> 7);
  811.             return(OK);
  812.          case ERROR:
  813.             logent("Got burst for sector ACK\n");
  814.             break;
  815.          default:
  816.             logent("Got %02x for sector ACK\n", firstch);
  817.             break;
  818.          }
  819.       for (;;)
  820.          {
  821.          Lastrx = firstch;
  822.          if ((firstch = readock(Rxtimeout, 2)) == TIMEOUT)
  823.             break;
  824.          if (firstch == NAK || firstch == WANTCRC)
  825.             goto gotnak;
  826.          if (firstch == CAN && Lastrx == CAN)
  827.             goto cancan;
  828.          }
  829.       }
  830.    logent("Retry Count Exceeded\n");
  831.    return(ERROR);
  832.    }
  833.  
  834. /* fill buf with count chars padding with ^Z for CPM */
  835. filbuf(buf, count)
  836. char *buf;
  837.    {
  838.    int c, m;
  839.  
  840.    if (!Ascii)
  841.       {
  842.       m = read(fileno(in), buf, count);
  843.       if (m <= 0)
  844.          return(0);
  845.       while (m < count)
  846.          buf[m++] = 032;
  847.       return(count);
  848.       }
  849.    m = count;
  850.    if (Lfseen)
  851.       {
  852.       *buf++ = 012;
  853.       --m;
  854.       Lfseen = 0;
  855.       }
  856.    while ((c = getc(in)) != EOF)
  857.       {
  858.       if (c == 012)
  859.          {
  860.          *buf++ = 015;
  861.          if (--m == 0)
  862.             {
  863.             Lfseen = TRUE;
  864.             break;
  865.             }
  866.          }
  867.       *buf++ = c;
  868.       if (--m == 0)
  869.          break;
  870.       }
  871.    if (m == count)
  872.       return(0);
  873.    else
  874.       while (--m >= 0)
  875.          *buf++ = CPMEOF;
  876.    return(count);
  877.    }
  878.  
  879. /* fill buf with count chars */
  880. zfilbuf(buf, count)
  881. char *buf;
  882.    {
  883.    int c, m;
  884.  
  885.    m = count;
  886.    while ((c = getc(in)) != EOF)
  887.       {
  888.       *buf++ =c;
  889.       if (--m == 0)
  890.          break;
  891.       }
  892.    return(count - m);
  893.    }
  894.  
  895. /* VARARGS1 */
  896. vfile(f, a, b, c)
  897. char *f;
  898.    {
  899.    if (Verbose > 2)
  900.       {
  901.       fprintf(stderr, f, a, b, c);
  902.       fprintf(stderr, "\n");
  903.       }
  904.    }
  905.  
  906. zperr(f, a, b, c)
  907. char *f;
  908.    {
  909.    if (Verbose > 1)
  910.       {
  911.       fprintf(stderr, f, a, b, c);
  912.       fprintf(stderr, "\n");
  913.       }
  914.    }
  915.  
  916. #ifndef MSDOS
  917. alrm()
  918.    {
  919.    longjmp(tohere, -1);
  920.    }
  921. #endif
  922.  
  923. /*
  924.  * readock(timeout, count) reads character(s) from file descriptor 0
  925.  *  (1 <= count <= 3)
  926.  * it attempts to read count characters. If it gets more than one,
  927.  * it is an error unless all are CAN
  928.  * (otherwise, only normal response is ACK, CAN, or C)
  929.  *  Only looks for one if Optiong, which signifies cbreak, not raw input
  930.  *
  931.  * timeout is in tenths of seconds
  932.  */
  933. readock(timeout, count)
  934. int timeout, count;
  935.    {
  936.    int c, n;
  937.    static char byt[5];
  938. #ifdef MSDOS
  939.    time_t start;
  940. #endif
  941.  
  942.    if (Optiong)
  943.       count = 1;      /* Special hack for cbreak */
  944.  
  945.    fflush(stdout);
  946.    n = timeout/10;
  947.    if (n < 2)
  948.       n = 2;
  949.    if (Verbose > 3)
  950.       {
  951.       fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, n);
  952.       byt[1] = 0;
  953.       }
  954. #ifndef MSDOS
  955.    if (setjmp(tohere))
  956.       {
  957.       logent("TIMEOUT\n");
  958.       return(TIMEOUT);
  959.       }
  960.    signal(SIGALRM, alrm);
  961.    alarm(n);
  962. #ifdef ONEREAD
  963.    c = read(iofd, byt, 1);           /* regulus raw read is unique */
  964. #else
  965.    c = read(iofd, byt, count);
  966. #endif
  967.    alarm(0);
  968. #else /* MSDOS */
  969.    time(&start);
  970. #ifdef ONEREAD
  971.    while (!(c = tty_read(iofd, byt, 1)) &&    /* regulus raw read is unique */
  972.           (int)difftime(time(NULL), start) < n)
  973.       {;}
  974. #else
  975.    while (!(c = tty_read(iofd, byt, count)) &&
  976.           (int)difftime(time(NULL), start) < n)
  977.       {;}
  978. #endif
  979.    if (!c)
  980.       {
  981.       logent("TIMEOUT\n");
  982.       return(TIMEOUT);
  983.       }
  984. #endif /* MSDOS */
  985.    if (Verbose > 5)
  986.       fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
  987.    if (c < 1)
  988.       return(TIMEOUT);
  989.    if (c == 1)
  990.       return (byt[0] & 0377);
  991.    else
  992.       while (c)
  993.          if (byt[--c] != CAN)
  994.             return(ERROR);
  995.    return(CAN);
  996.    }
  997.  
  998. readline(n)
  999.    {
  1000.    return(readock(n, 1));
  1001.    }
  1002.  
  1003.  
  1004. purgeline()
  1005.    {
  1006. #ifdef USG
  1007.    ioctl(iofd, TCFLSH, 0);
  1008. #endif
  1009. #ifdef V7
  1010.    lseek(iofd, 0L, 2);
  1011. #endif
  1012. #ifdef MSDOS
  1013.    char c;
  1014.  
  1015.    while (tty_read(iofd, &c, 1))
  1016.       {;}
  1017. #endif
  1018.    }
  1019.  
  1020.  
  1021. /* send cancel string to get the other end to shut up */
  1022. canit()
  1023.    {
  1024.    static char canistr[] =
  1025.       {
  1026.       24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  1027.       };
  1028.  
  1029. #ifndef MSDOS
  1030.    printf(canistr);
  1031.    fflush(stdout);
  1032. #else
  1033.    tty_write(iofd, canistr, strlen(canistr));
  1034. #endif
  1035. }
  1036.  
  1037. /*VARARGS1*/
  1038. logent(a, b, c)
  1039. char *a, *b, *c;
  1040.    {
  1041.    if (Verbose > 1)
  1042.       fprintf(stderr, a, b, c);
  1043.    }
  1044.  
  1045. /*
  1046.  * return 1 iff stdout and stderr are different devices
  1047.  *  indicating this program operating with a modem on a
  1048.  *  different line
  1049.  */
  1050. from_cu()
  1051.    {
  1052. #ifndef MSDOS
  1053.    struct stat a, b;
  1054.    fstat(1, &a);
  1055.    fstat(2, &b);
  1056.    return(a.st_rdev != b.st_rdev);
  1057. #else
  1058.    return(1);
  1059. #endif
  1060.    }
  1061.  
  1062. /*
  1063.  * substr(string, token) searches for token in string s
  1064.  * returns pointer to token within string if found, NULL otherwise
  1065.  */
  1066. char *substr(s, t)
  1067. char *s,*t;
  1068.    {
  1069.    char *ss,*tt;
  1070.    /* search for first char of token */
  1071.    for (ss = s; *s; s++)
  1072.       if (*s == *t)
  1073.          /* compare token with substring */
  1074.          for (ss = s, tt = t; ; )
  1075.             {
  1076.             if (*tt == 0)
  1077.                return(s);
  1078.             if (*ss++ != *tt++)
  1079.                break;
  1080.             }
  1081.    return(NULL);
  1082.    }
  1083.  
  1084. char *babble[] =
  1085.    {
  1086.    "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
  1087.    "       (Y) = Option applies to YMODEM only",
  1088.    "       (Z) = Option applies to ZMODEM only",
  1089. #ifndef MSDOS
  1090.    "Usage: sz [-12+aBbdefkLlNnquvXy] [-] file ...",
  1091.    "       sz [-1Beqv] -c COMMAND",
  1092.    "       1 Use stdout for modem input",
  1093. #ifdef CSTOPB
  1094.    "       2 Use 2 stop bits",
  1095. #endif
  1096. #else
  1097.    "Usage: sz [-2+aBbdefkLlNnquvXYy] [-s<speed>] [-] file ...",
  1098.    "       sz [-2Beqv] [-s<speed>] -c COMMAND",
  1099.    "       2 Use COM2 instead of COM1",
  1100. #endif
  1101.    "       + Append to existing destination file (Z)",
  1102.    "       a (ASCII) change NL to CR/LF",
  1103.    "       b Binary file transfer override",
  1104.    "       c send COMMAND (Z)",
  1105.    "       d Change '.' to '/' in pathnames (Y/Z)",
  1106.    "       e Escape all control characters (Z)",
  1107.    "       f send Full pathname (Y/Z)",
  1108.    "       i send COMMAND, ack Immediately (Z)",
  1109.    "       k Send 1024 byte packets (Y)",
  1110.    "       L N Limit subpacket length to N bytes (Z)",
  1111.    "       l N Limit frame length to N bytes (l>=L) (Z)",
  1112.    "       n send file if source Newer or longer (Z)",
  1113.    "       N send file if source different length or date (Z)",
  1114.    "       o Use 16 bit CRC instead of 32 bit CRC (Z)",
  1115.    "       p Protect existing destination file (Z)",
  1116.    "       r Resume/Recover interrupted file transfer (Z)",
  1117.    "       q Quiet (no progress reports)",
  1118.    "       u Unlink file after transmission",
  1119.    "       v Verbose - debugging information",
  1120.    "       X XMODEM protocol - send no pathnames",
  1121. #ifdef MSDOS
  1122.    "       Y YMODEM protocol",
  1123. #endif
  1124.    "       y Yes, overwrite existing file (Z)",
  1125.    "- as pathname sends standard input as sPID.sz or environment ONAME",
  1126.    ""
  1127.    };
  1128.  
  1129. usage()
  1130.    {
  1131.    char **pp;
  1132.  
  1133.    for (pp = babble; **pp; ++pp)
  1134.       fprintf(stderr, "%s\n", *pp);
  1135.    fprintf(stderr, "%s for %s by Chuck Forsberg\n", VERSION, OS);
  1136.    exit(1);
  1137.    }
  1138.  
  1139. /*
  1140.  * Get the receiver's init parameters
  1141.  */
  1142. getzrxinit()
  1143.    {
  1144.    int n;
  1145.    struct stat f;
  1146.  
  1147.    for (n = 10; --n >= 0; )
  1148.       {
  1149.                 
  1150.       switch (zgethdr(Rxhdr, 1))
  1151.          {
  1152.          case ZCHALLENGE:        /* Echo receiver's challenge numbr */
  1153.             stohdr(Rxpos);
  1154.             zshhdr(ZACK, Txhdr);
  1155.             continue;
  1156.          case ZCOMMAND:          /* They didn't see out ZRQINIT */
  1157.             stohdr(0L);
  1158.             zshhdr(ZRQINIT, Txhdr);
  1159.             continue;
  1160.          case ZRINIT:
  1161.             Rxflags = 0377 & Rxhdr[ZF0];
  1162.             if (Wantfcs32 && (Rxflags & CANFC32))
  1163.                Txfcs32 = TRUE;
  1164.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1]) << 8);
  1165.             vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  1166.             if (!Fromcu)
  1167.                signal(SIGINT, SIG_IGN);
  1168. #ifndef READCHECK
  1169. #ifdef USG
  1170.             mode(2);        /* Set cbreak, XON/XOFF, etc. */
  1171. #else
  1172.             /* Use 1024 byte frames if no sample/interrupt */
  1173.             if (Rxbuflen < 32 || Rxbuflen > 1024)
  1174.                {
  1175.                Rxbuflen = 1024;
  1176.                vfile("Rxbuflen=%d", Rxbuflen);
  1177.                }
  1178. #endif
  1179. #endif
  1180.             /* Override to force shorter frame length */
  1181.             if (Rxbuflen && (Rxbuflen > Tframlen) && (Tframlen >= 32))
  1182.                Rxbuflen = Tframlen;
  1183.             if (!Rxbuflen && (Tframlen >= 32) && (Tframlen <= 1024))
  1184.                Rxbuflen = Tframlen;
  1185.             vfile("Rxbuflen=%d", Rxbuflen);
  1186. #ifndef MSDOS
  1187.             /* If using a pipe for testing set lower buf len */
  1188.             fstat(iofd, &f);
  1189.             if ((f.st_mode & S_IFMT) != S_IFCHR
  1190.                 && (Rxbuflen == 0 || Rxbuflen > 4096))
  1191.                Rxbuflen = 4096;
  1192. #endif
  1193.             /*
  1194.              * If input is not a regular file, force ACK's each 1024
  1195.              *  (A smarter strategey could be used here ...)
  1196.              */
  1197.             fstat(fileno(in), &f);
  1198.             if (((f.st_mode & S_IFMT) != S_IFREG)
  1199.                 && (Rxbuflen == 0 || Rxbuflen > 1024))
  1200.                Rxbuflen = 1024;
  1201.             vfile("Rxbuflen=%d", Rxbuflen);
  1202.  
  1203.             return(sendzsinit());
  1204.          case ZCAN:
  1205.          case TIMEOUT:
  1206.             return(ERROR);
  1207.          case ZRQINIT:
  1208.             if (Rxhdr[ZF0] == ZCOMMAND)
  1209.                continue;
  1210.          default:
  1211.             zshhdr(ZNAK, Txhdr);
  1212.             continue;
  1213.          }
  1214.       }
  1215.    return(ERROR);
  1216.    }
  1217.  
  1218. /* Send send-init information */
  1219. sendzsinit()
  1220.    {
  1221.    int c;
  1222.    int errors;
  1223.  
  1224.    if (Myattn[0] == '\0')
  1225.       return(OK);
  1226.    errors = 0;
  1227.    for (;;)
  1228.       {
  1229.       stohdr(0L);
  1230.       zsbhdr(ZSINIT, Txhdr);
  1231.       zsdata(Myattn, 1+strlen(Myattn), ZCRCW);
  1232.       c = zgethdr(Rxhdr, 1);
  1233.       switch (c)
  1234.          {
  1235.          case ZCAN:
  1236.             return(ERROR);
  1237.          case ZACK:
  1238.             return(OK);
  1239.          default:
  1240.             if (++errors > 9)
  1241.                return(ERROR);
  1242.             continue;
  1243.          }
  1244.       }
  1245.    }
  1246.  
  1247. /* Send file name and related info */
  1248. zsendfile(buf, blen)
  1249. char *buf;
  1250.    {
  1251.    int c;
  1252.  
  1253.    for (;;)
  1254.       {
  1255.       Txhdr[ZF0] = Lzconv;    /* file conversion request */
  1256.       Txhdr[ZF1] = Lzmanag;   /* file management request */
  1257.       Txhdr[ZF2] = Lztrans;   /* file transport request */
  1258.       Txhdr[ZF3] = 0;
  1259.       zsbhdr(ZFILE, Txhdr);
  1260.       zsdata(buf, blen, ZCRCW);
  1261. again:
  1262.       c = zgethdr(Rxhdr, 1);
  1263.       switch (c)
  1264.          {
  1265.          case ZRINIT:
  1266.             goto again;
  1267.          case ZCAN:
  1268.          case TIMEOUT:
  1269.          case ZABORT:
  1270.          case ZFIN:
  1271.             return(ERROR);
  1272.          case ZSKIP:
  1273.             fclose(in);
  1274.             return(c);
  1275.          case ZRPOS:
  1276.             fseek(in, Rxpos, 0);
  1277.             Txpos = Rxpos;
  1278.             Lastc = -1;
  1279.             Dontread = FALSE;
  1280.             return zsendfdata();
  1281.          case ERROR:
  1282.          default:
  1283.             continue;
  1284.          }
  1285.       }
  1286.    }
  1287.  
  1288. /* Send the data in the file */
  1289. zsendfdata()
  1290.    {
  1291.    int c, e;
  1292.    int newcnt;
  1293.    long tcount = 0;
  1294.    static int tleft = 6;   /* Counter for test mode */
  1295.  
  1296.    if (Baudrate > 300)
  1297.       blklen = 256;
  1298.    if (Baudrate > 2400)
  1299.       blklen = KSIZE;
  1300.    if (Rxbuflen && blklen>Rxbuflen)
  1301.       blklen = Rxbuflen;
  1302.    if (blkopt && blklen > blkopt)
  1303.       blklen = blkopt;
  1304.    vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1305. somemore:
  1306.    if (setjmp(intrjmp))
  1307.       {
  1308. waitack:
  1309.       c = getinsync();
  1310.       switch (c)
  1311.          {
  1312.          default:
  1313.          case ZCAN:
  1314.             fclose(in);
  1315.             return(ERROR);
  1316.          case ZSKIP:
  1317.             fclose(in);
  1318.             return(c);
  1319.          case ZACK:
  1320.          case ZRPOS:
  1321.             break;
  1322.          case ZRINIT:
  1323.             return(OK);
  1324.          }
  1325. #ifdef READCHECK
  1326.       /*
  1327.        * If the reverse channel can be tested for data,
  1328.        *  this logic may be used to detect error packets
  1329.        *  sent by the receiver, in place of setjmp/longjmp
  1330.        *  rdchk(fdes) returns non 0 if a character is available
  1331.        */
  1332.       while (rdchk(iofd))
  1333.          {
  1334. #ifdef SVR2
  1335.          switch (checked)
  1336. #else
  1337.          switch (readline(1))
  1338. #endif
  1339.             {
  1340.             case CAN:
  1341.             case ZPAD:
  1342.                goto waitack;
  1343.             }
  1344.          }
  1345. #endif
  1346.       }
  1347.  
  1348.    if (!Fromcu)
  1349.       signal(SIGINT, onintr);
  1350.    newcnt = Rxbuflen;
  1351.    stohdr(Txpos);
  1352.    zsbhdr(ZDATA, Txhdr);
  1353.  
  1354.    /*
  1355.     * Special testing mode.  This should force receiver to Attn,ZRPOS
  1356.     *  many times.  Each time the signal should be caught, causing the
  1357.     *  file to be started over from the beginning.
  1358.     */
  1359.    if (Testattn)
  1360.       {
  1361.       if ( --tleft)
  1362.          while (tcount < 20000)
  1363.             {
  1364. #ifndef MSDOS
  1365.             printf(qbf);
  1366.             fflush(stdout);
  1367. #else
  1368.             tty_write(iofd, qbf, strlen(qbf));
  1369. #endif      
  1370.             tcount += strlen(qbf);
  1371. #ifdef READCHECK
  1372.             while (rdchk(iofd))
  1373.                {
  1374. #ifdef SVR2
  1375.                switch (checked)
  1376. #else
  1377.                switch (readline(1))
  1378. #endif
  1379.                   {
  1380.                   case CAN:
  1381.                   case ZPAD:
  1382. #ifdef TCFLSH
  1383.                      ioctl(iofd, TCFLSH, 1);
  1384. #endif
  1385.                      goto waitack;
  1386.                   }
  1387.                }
  1388. #endif
  1389.             }
  1390.            signal(SIGINT, SIG_IGN);
  1391.            canit();
  1392.            sleep(3);
  1393.            purgeline();
  1394.            mode(0);
  1395.            printf("\nsz: Tcount = %ld\n", tcount);
  1396.            if (tleft)
  1397.               {
  1398.               printf("ERROR: Interrupts Not Caught\n");
  1399.               exit(1);
  1400.               }
  1401.            exit(0);
  1402.       }
  1403.  
  1404.    do
  1405.       {
  1406.       if (Dontread)
  1407.          c = Lastc;
  1408.       else
  1409.          {
  1410.          c = zfilbuf(txbuf, blklen);
  1411.          Lastread = Txpos;
  1412.          Lastc = c;
  1413.          }
  1414.       if (Verbose > 10)
  1415.          vfile("Dontread=%d c=%d", Dontread, c);
  1416.       Dontread = FALSE;
  1417.       if (c < blklen)
  1418.          e = ZCRCE;
  1419.       else if (Rxbuflen && (newcnt -= c) <= 0)
  1420.          e = ZCRCW;
  1421.       else
  1422.          e = ZCRCG;
  1423.       zsdata(txbuf, c, e);
  1424.       Txpos += c;
  1425.       if (e == ZCRCW)
  1426.          goto waitack;
  1427. #ifdef READCHECK
  1428.       /*
  1429.        * If the reverse channel can be tested for data,
  1430.        *  this logic may be used to detect error packets
  1431.        *  sent by the receiver, in place of setjmp/longjmp
  1432.        *  rdchk(fdes) returns non 0 if a character is available
  1433.        */
  1434.       fflush(stdout);
  1435.       while (rdchk(iofd))
  1436.          {
  1437. #ifdef SVR2
  1438.          switch (checked)
  1439. #else
  1440.          switch (readline(1))
  1441. #endif
  1442.             {
  1443.             case CAN:
  1444.             case ZPAD:
  1445. #ifdef TCFLSH
  1446.                ioctl(iofd, TCFLSH, 1);
  1447. #endif
  1448.                /* zcrce - dinna wanna start a ping-pong game */
  1449.                zsdata(txbuf, 0, ZCRCE);
  1450.                goto waitack;
  1451.             }
  1452.          }
  1453. #endif
  1454.       }
  1455.    while (c == blklen);
  1456.    if (!Fromcu)
  1457.       signal(SIGINT, SIG_IGN);
  1458.  
  1459.    for (;;)
  1460.       {
  1461.       stohdr(Txpos);
  1462.       zsbhdr(ZEOF, Txhdr);
  1463.       switch (getinsync())
  1464.          {
  1465.          case ZACK:
  1466.             continue;
  1467.          case ZRPOS:
  1468.             goto somemore;
  1469.          case ZRINIT:
  1470.             return(OK);
  1471.          case ZSKIP:
  1472.             fclose(in);
  1473.             return(c);
  1474.          default:
  1475.             fclose(in);
  1476.             return(ERROR);
  1477.          }
  1478.       }
  1479.    }
  1480.  
  1481. /*
  1482.  * Respond to receiver's complaint, get back in sync with receiver
  1483.  */
  1484. getinsync()
  1485.    {
  1486.    int c;
  1487.  
  1488.    for (;;)
  1489.       {
  1490.       if (Testattn)
  1491.          {
  1492. #ifndef MSDOS
  1493.          printf("\r\n\n\n***** Signal Caught *****\r\n");
  1494. #else
  1495.          tty_write(iofd, "\r\n\n\n***** Signal Caught *****\r\n", 31);
  1496. #endif
  1497.          Rxpos = 0;
  1498.          c = ZRPOS;
  1499.          }
  1500.       else
  1501.          c = zgethdr(Rxhdr, 0);
  1502.       switch (c)
  1503.          {
  1504.          case ZCAN:
  1505.          case ZABORT:
  1506.          case ZFIN:
  1507.          case TIMEOUT:
  1508.             return(ERROR);
  1509.          case ZRPOS:
  1510.               if (Lastc >= 0 && Lastread == Rxpos)
  1511.                  Dontread = TRUE;
  1512.               else
  1513.                  {
  1514.                  clearerr(in);   /* In case file EOF seen */
  1515.                  fseek(in, Rxpos, 0);
  1516.                  }
  1517.               Txpos = Rxpos;
  1518.               return(c);
  1519.          case ZACK:
  1520.             return(c);
  1521.          case ZRINIT:
  1522.          case ZSKIP:
  1523.             fclose(in);
  1524.             return(c);
  1525.          case ERROR:
  1526.          default:
  1527.             zsbhdr(ZNAK, Txhdr);
  1528.             continue;
  1529.          }
  1530.       }
  1531.    }
  1532. /* Say "bibi" to the receiver, try to do it cleanly */
  1533. saybibi()
  1534.    {
  1535.    for (;;)
  1536.       {
  1537.       stohdr(0L);
  1538.       zsbhdr(ZFIN, Txhdr);
  1539.       switch (zgethdr(Rxhdr, 0))
  1540.          {
  1541.          case ZFIN:
  1542.             sendline('O');
  1543.             sendline('O');
  1544.             flushmo();
  1545.          case ZCAN:
  1546.          case TIMEOUT:
  1547.             return;
  1548.          }
  1549.       }
  1550.    }
  1551.  
  1552. /* Local screen character display function */
  1553. bttyout(c)
  1554.    {
  1555.    if (Verbose)
  1556.       putc(c, stderr);
  1557.    }
  1558.  
  1559. /* Send command and related info */
  1560. zsendcmd(buf, blen)
  1561. char *buf;
  1562.    {
  1563.    int c, errors;
  1564.    long cmdnum;
  1565.  
  1566.    cmdnum = getpid();
  1567.    errors = 0;
  1568.    for (;;)
  1569.       {
  1570.       stohdr(cmdnum);
  1571.       Txhdr[ZF0] = Cmdack1;
  1572.       zsbhdr(ZCOMMAND, Txhdr);
  1573.       zsdata(buf, blen, ZCRCW);
  1574. listen:
  1575.       Rxtimeout = 100;                /* Ten second wait for resp. */
  1576.       c = zgethdr(Rxhdr, 1);
  1577.  
  1578.       switch (c)
  1579.          {
  1580.          case ZRINIT:
  1581.             continue;
  1582.          case ERROR:
  1583.          case TIMEOUT:
  1584.             if (++errors > Cmdtries)
  1585.                return(ERROR);
  1586.             continue;
  1587.          case ZCAN:
  1588.          case ZABORT:
  1589.          case ZFIN:
  1590.          case ZSKIP:
  1591.          case ZRPOS:
  1592.             return(ERROR);
  1593.          default:
  1594.             if (++errors > 10)
  1595.                return(ERROR);
  1596.             continue;
  1597.          case ZCOMPL:
  1598.             Exitcode = Rxpos;
  1599.             saybibi();
  1600.             return(OK);
  1601.          case ZRQINIT:
  1602.             vfile("******** RZ *******");
  1603.             system("rz");
  1604.             vfile("******** SZ *******");
  1605.             goto listen;
  1606.          }
  1607.       }
  1608.    }
  1609.  
  1610. /*
  1611.  * If called as sb use YMODEM protocol
  1612.  */
  1613. chkinvok(s)
  1614. char *s;
  1615.    {
  1616.    char *p;
  1617.  
  1618.    p = s;
  1619.    while (*p == '-')
  1620.       s = ++p;
  1621.    while (*p)
  1622.       if (*p++ == '/')
  1623.          s = p;
  1624.    if (*s == 'v')
  1625.       {
  1626.       Verbose=1;
  1627.       ++s;
  1628.       }
  1629.    Progname = s;
  1630.    if (s[0] == 's' && s[1] == 'b')
  1631.       {
  1632.       Nozmodem = TRUE;
  1633.       blklen=KSIZE;
  1634.       }
  1635.    }
  1636.