Unix X/Y/ZMODEM programs w/32 bit CRC 1 of 2
caf at omen.UUCP
caf at omen.UUCP
Fri Jan 16 13:08:10 AEST 1987
The reliability of ZMODEM file transfers has been enhanced with the
addition of a table driven 32 bit CRC. ZMODEM downloads from Unix to
PC's are much more efficient than XMODEM or Kermit. For example, 9600
baud downloads from a 9 mHz PC-AT Xenix machine to Crosstalk XVI gave
343 characters per second throughput, Kermit gave 327 characters per
second, and ZMODEM gives 915 characters per second. At 19200 baud,
ZMODEM downloads to a 4.77 mHz PC hard disk attain 1870 characters per
second throughput. Note that the 343 cps throughput with Crosstalk was
with an 8 bit checksum while ZMODEM uses 32 bit CRC for orders of
magnitude better data reliability.
Chuck Forsberg WA7KGX Author of Pro-YAM communications Tools for PCDOS and Unix
...!tektronix!reed!omen!caf Omen Technology Inc "The High Reliability Software"
Voice: 503-621-3406 17505-V Northwest Sauvie Island Road Portland OR 97231
TeleGodzilla BBS: 621-3746 2400/1200 CIS:70007,2304 Genie:CAF Source:TCE022
omen Any ACU 1200 1-503-621-3746 se:--se: link ord: Giznoid in:--in: uucp
omen!/usr/spool/uucppublic/FILES lists all uucp-able files, updated hourly
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# zmodem.h
# zm.c
# sz.c
# This archive created: Thu Jan 15 17:36:05 1987
echo shar: extracting zmodem.h '(4595 characters)'
cat << \SHAR_EOF > zmodem.h
/*
* Z M O D E M . H Manifest constants for ZMODEM
* application to application file transfer protocol
* 01-15-87 Chuck Forsberg Omen Technology Inc
*/
#define ZPAD '*' /* 052 Padding character begins frames */
#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */
#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */
#define ZBIN 'A' /* Binary frame indicator */
#define ZHEX 'B' /* HEX frame indicator */
#define ZBIN32 'C' /* Binary frame with 32 bit FCS */
/* Frame types (see array "frametypes" in zm.c) */
#define ZRQINIT 0 /* Request receive init */
#define ZRINIT 1 /* Receive init */
#define ZSINIT 2 /* Send init sequence (optional) */
#define ZACK 3 /* ACK to above */
#define ZFILE 4 /* File name from sender */
#define ZSKIP 5 /* To sender: skip this file */
#define ZNAK 6 /* Last packet was garbled */
#define ZABORT 7 /* Abort batch transfers */
#define ZFIN 8 /* Finish session */
#define ZRPOS 9 /* Resume data trans at this position */
#define ZDATA 10 /* Data packet(s) follow */
#define ZEOF 11 /* End of file */
#define ZFERR 12 /* Fatal Read or Write error Detected */
#define ZCRC 13 /* Request for file CRC and response */
#define ZCHALLENGE 14 /* Receiver's Challenge */
#define ZCOMPL 15 /* Request is complete */
#define ZCAN 16 /* Other end canned session with CAN*5 */
#define ZFREECNT 17 /* Request for free bytes on filesystem */
#define ZCOMMAND 18 /* Command from sending program */
#define ZSTDERR 19 /* Output to standard error, data follows */
/* ZDLE sequences */
#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */
#define ZCRCG 'i' /* CRC next, frame continues nonstop */
#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */
#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */
#define ZRUB0 'l' /* Translate to rubout 0177 */
#define ZRUB1 'm' /* Translate to rubout 0377 */
/* zdlread return values (internal) */
/* -1 is general error, -2 is timeout */
#define GOTOR 0400
#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */
#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */
#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */
#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */
#define GOTCAN (GOTOR|030) /* CAN*5 seen */
/* Byte positions within header array */
#define ZF0 3 /* First flags byte */
#define ZF1 2
#define ZF2 1
#define ZF3 0
#define ZP0 0 /* Low order 8 bits of position */
#define ZP1 1
#define ZP2 2
#define ZP3 3 /* High order 8 bits of file position */
/* Bit Masks for ZRINIT flags byte ZF0 */
#define CANFDX 01 /* Rx can send and receive true FDX */
#define CANOVIO 02 /* Rx can receive data during disk I/O */
#define CANBRK 04 /* Rx can send a break signal */
#define CANCRY 010 /* Receiver can decrypt */
#define CANLZW 020 /* Receiver can uncompress */
#define CANFC32 040 /* Receiver can use 32 bit Frame Check */
/* Parameters for ZSINIT frame */
#define ZATTNLEN 32 /* Max length of attention string */
/* Parameters for ZFILE frame */
/* Conversion options one of these in ZF0 */
#define ZCBIN 1 /* Binary transfer - inhibit conversion */
#define ZCNL 2 /* Convert NL to local end of line convention */
#define ZCRESUM 3 /* Resume interrupted file transfer */
/* Management options, one of these in ZF1 */
#define ZMNEW 1 /* Transfer if source newer or longer */
#define ZMCRC 2 /* Transfer if different file CRC or length */
#define ZMAPND 3 /* Append contents to existing file (if any) */
#define ZMCLOB 4 /* Replace existing file */
#define ZMSPARS 5 /* Encoding for sparse file */
#define ZMDIFF 6 /* Transfer if dates or lengths different */
#define ZMPROT 7 /* Protect destination file */
/* Transport options, one of these in ZF2 */
#define ZTLZW 1 /* Lempel-Ziv compression */
#define ZTCRYPT 2 /* Encryption */
#define ZTRLE 3 /* Run Length encoding */
/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */
#define ZCACK1 1 /* Acknowledge, then do command */
long rclhdr();
/* Globals used by ZMODEM functions */
int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
int Rxtype; /* Type of header received */
int Rxcount; /* Count of data bytes received */
extern Rxtimeout; /* Tenths of seconds to wait for something */
char Rxhdr[4]; /* Received header */
char Txhdr[4]; /* Transmitted header */
long Rxpos; /* Received file position */
long Txpos; /* Transmitted file position */
int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
SHAR_EOF
echo shar: extracting zm.c '(12381 characters)'
cat << \SHAR_EOF > zm.c
/*
* Z M . C
* ZMODEM protocol primitives
* 01-15-87 Chuck Forsberg Omen Technology Inc
*
* Entry point Functions:
* zsbhdr(type, hdr) send binary header
* zshhdr(type, hdr) send hex header
* zgethdr(hdr, eflag) receive header - binary or hex
* zsdata(buf, len, frameend) send data
* zrdata(buf, len) receive data
* stohdr(pos) store position data in Txhdr
* long rclhdr(hdr) recover position offset from header
*/
#ifndef CANFDX
#include "zmodem.h"
int Rxtimeout = 100; /* Tenths of seconds to wait for something */
#endif
static char *frametypes[] = {
"Carrier Lost", /* -3 */
"TIMEOUT", /* -2 */
"ERROR", /* -1 */
#define FTOFFSET 3
"ZRQINIT",
"ZRINIT",
"ZSINIT",
"ZACK",
"ZFILE",
"ZSKIP",
"ZNAK",
"ZABORT",
"ZFIN",
"ZRPOS",
"ZDATA",
"ZEOF",
"ZFERR",
"ZCRC",
"ZCHALLENGE",
"ZCOMPL",
"ZCAN",
"ZFREECNT",
"ZCOMMAND",
"ZSTDERR",
"xxxxx"
#define FRTYPES 22 /* Total number of frame types in this array */
/* not including psuedo negative entries */
};
/* Send ZMODEM binary header hdr of type type */
zsbhdr(type, hdr)
register char *hdr;
{
register n;
register unsigned short crc;
vfile("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
if (type == ZDATA)
for (n = Znulls; --n >=0; )
zsendline(0);
xsendline(ZPAD); xsendline(ZDLE);
if (Txfcs32)
zsbh32(hdr, type);
else {
xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
for (n=4; --n >= 0;) {
zsendline(*hdr);
crc = updcrc((0377& *hdr++), crc);
}
crc = updcrc(0,updcrc(0,crc));
zsendline(crc>>8);
zsendline(crc);
}
if (type != ZDATA)
flushmo();
}
/* Send ZMODEM binary header hdr of type type */
zsbh32(hdr, type)
register char *hdr;
{
register n;
register unsigned long crc;
xsendline(ZBIN32); zsendline(type);
crc = UPDC32(type, 0xFFFFFFFF);
for (n=4; --n >= 0;) {
zsendline(*hdr);
crc = UPDC32((0377& *hdr++), crc);
}
crc = ~crc;
for (n=4; --n >= 0;) {
zsendline(crc); crc >>= 8;
}
}
/* Send ZMODEM HEX header hdr of type type */
zshhdr(type, hdr)
register char *hdr;
{
register n;
register unsigned short crc;
vfile("zshhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr));
sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX);
zputhex(type);
crc = updcrc(type, 0);
for (n=4; --n >= 0;) {
zputhex(*hdr); crc = updcrc((0377& *hdr++), crc);
}
crc = updcrc(0,updcrc(0,crc));
zputhex(crc>>8); zputhex(crc);
/* Make it printable on remote machine */
sendline(015); sendline(012);
/*
* Uncork the remote in case a fake XOFF has stopped data flow
*/
if (type != ZFIN)
sendline(021);
flushmo();
}
/*
* Send binary array buf of length length, with ending ZDLE sequence frameend
*/
zsdata(buf, length, frameend)
register char *buf;
{
register unsigned short crc;
vfile("zsdata: length=%d end=%x", length, frameend);
if (Txfcs32)
zsda32(buf, length, frameend);
else {
crc = 0;
for (;--length >= 0;) {
zsendline(*buf); crc = updcrc((0377& *buf++), crc);
}
xsendline(ZDLE); xsendline(frameend);
crc = updcrc(frameend, crc);
crc = updcrc(0,updcrc(0,crc));
zsendline(crc>>8); zsendline(crc);
}
if (frameend == ZCRCW) {
xsendline(XON); flushmo();
}
}
zsda32(buf, length, frameend)
register char *buf;
{
register unsigned long crc;
crc = 0xFFFFFFFF;
for (;--length >= 0;) {
zsendline(*buf); crc = UPDC32((0377& *buf++), crc);
}
xsendline(ZDLE); xsendline(frameend);
crc = UPDC32(frameend, crc);
crc = ~crc;
for (length=4; --length >= 0;) {
zsendline(crc); crc >>= 8;
}
}
/*
* Receive array buf of max length with ending ZDLE sequence
* and CRC. Returns the ending character or error code.
*/
zrdata(buf, length)
register char *buf;
{
register c;
register unsigned short crc;
register d;
if (Rxframeind == ZBIN32)
return zrdat32(buf, length);
crc = Rxcount = 0;
for (;;) {
if ((c = zdlread()) & ~0377) {
crcfoo:
switch (c) {
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
crc = updcrc((d=c)&0377, crc);
if ((c = zdlread()) & ~0377)
goto crcfoo;
crc = updcrc(c, crc);
if ((c = zdlread()) & ~0377)
goto crcfoo;
crc = updcrc(c, crc);
if (crc & 0xFFFF) {
zperr("Bad data CRC %x", crc);
return ERROR;
}
vfile("zrdata: cnt = %d ret = %x", Rxcount, d);
return d;
case GOTCAN:
zperr("ZMODEM: Sender Canceled");
return ZCAN;
case TIMEOUT:
zperr("ZMODEM data TIMEOUT");
return c;
default:
zperr("ZMODEM bad data subpacket ret=%x", c);
return c;
}
}
if (--length < 0) {
zperr("ZMODEM data subpacket too long");
return ERROR;
}
++Rxcount;
*buf++ = c;
crc = updcrc(c, crc);
continue;
}
}
zrdat32(buf, length)
register char *buf;
{
register c;
register unsigned long crc;
register d;
crc = 0xFFFFFFFF; Rxcount = 0;
for (;;) {
if ((c = zdlread()) & ~0377) {
crcfoo:
switch (c) {
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
crc = UPDC32((d=c)&0377, crc);
if ((c = zdlread()) & ~0377)
goto crcfoo;
crc = UPDC32(c, crc);
if ((c = zdlread()) & ~0377)
goto crcfoo;
crc = UPDC32(c, crc);
if ((c = zdlread()) & ~0377)
goto crcfoo;
crc = UPDC32(c, crc);
if ((c = zdlread()) & ~0377)
goto crcfoo;
crc = UPDC32(c, crc);
if (crc != 0xDEBB20E3) {
zperr("Bad data CRC %lX", crc);
return ERROR;
}
vfile("zrdat32: cnt = %d ret = %x", Rxcount, d);
return d;
case GOTCAN:
zperr("ZMODEM: Sender Canceled");
return ZCAN;
case TIMEOUT:
zperr("ZMODEM data TIMEOUT");
return c;
default:
zperr("ZMODEM bad data subpacket ret=%x", c);
return c;
}
}
if (--length < 0) {
zperr("ZMODEM data subpacket too long");
return ERROR;
}
++Rxcount;
*buf++ = c;
crc = UPDC32(c, crc);
continue;
}
}
/*
* Read a ZMODEM header to hdr, either binary or hex.
* eflag controls local display of non zmodem characters:
* 0: no display
* 1: display printing characters only
* 2: display all non ZMODEM characters
* On success, set Zmodem to 1 and return type of header.
* Otherwise return negative on error
*/
zgethdr(hdr, eflag)
char *hdr;
{
register c, n, cancount;
n = Baudrate; /* Max characters before start of frame */
cancount = 5;
again:
Rxframeind = Rxtype = 0;
switch (c = noxread7()) {
case RCDO:
case TIMEOUT:
goto fifi;
case CAN:
if (--cancount <= 0) {
c = ZCAN; goto fifi;
}
/* **** FALL THRU TO **** */
default:
agn2:
if ( --n == 0) {
zperr("ZMODEM Garbage count exceeded");
return(ERROR);
}
if (eflag && ((c &= 0177) & 0140))
bttyout(c);
else if (eflag > 1)
bttyout(c);
if (c != CAN)
cancount = 5;
goto again;
case ZPAD: /* This is what we want. */
break;
}
cancount = 5;
splat:
switch (c = noxread7()) {
case ZPAD:
goto splat;
case RCDO:
case TIMEOUT:
goto fifi;
default:
goto agn2;
case ZDLE: /* This is what we want. */
break;
}
switch (c = noxread7()) {
case RCDO:
case TIMEOUT:
goto fifi;
case ZBIN:
Rxframeind = ZBIN;
c = zrbhdr(hdr);
break;
case ZBIN32:
Rxframeind = ZBIN32;
c = zrbhdr32(hdr);
break;
case ZHEX:
Rxframeind = ZHEX;
c = zrhhdr(hdr);
break;
case CAN:
if (--cancount <= 0) {
c = ZCAN; goto fifi;
}
goto agn2;
default:
goto agn2;
}
Rxpos = hdr[ZP3] & 0377;
Rxpos = (Rxpos<<8) + (hdr[ZP2] & 0377);
Rxpos = (Rxpos<<8) + (hdr[ZP1] & 0377);
Rxpos = (Rxpos<<8) + (hdr[ZP0] & 0377);
fifi:
switch (c) {
case GOTCAN:
c = ZCAN;
/* **** FALL THRU TO **** */
case ZNAK:
case ZCAN:
case ERROR:
case TIMEOUT:
case RCDO:
zperr("ZMODEM: Got %s %s", frametypes[c+FTOFFSET],
(c >= 0) ? "header" : "error");
/* **** FALL THRU TO **** */
default:
if (c >= -3 && c <= FRTYPES)
vfile("zgethdr: %s %lx", frametypes[c+FTOFFSET], Rxpos);
else
vfile("zgethdr: %d %lx", c, Rxpos);
}
return c;
}
/* Receive a binary style header (type and position) */
zrbhdr(hdr)
register char *hdr;
{
register c, n;
register unsigned short crc;
if ((c = zdlread()) & ~0377)
return c;
Rxtype = c;
crc = updcrc(c, 0);
for (n=4; --n >= 0;) {
if ((c = zdlread()) & ~0377)
return c;
crc = updcrc(c, crc);
*hdr++ = c;
}
if ((c = zdlread()) & ~0377)
return c;
crc = updcrc(c, crc);
if ((c = zdlread()) & ~0377)
return c;
crc = updcrc(c, crc);
if (crc & 0xFFFF) {
zperr("Bad Header CRC"); return ERROR;
}
Zmodem = 1;
return Rxtype;
}
/* Receive a binary style header (type and position) with 32 bit FCS */
zrbhdr32(hdr)
register char *hdr;
{
register c, n;
register unsigned long crc;
if ((c = zdlread()) & ~0377)
return c;
Rxtype = c;
crc = UPDC32(c, 0xFFFFFFFF);
for (n=4; --n >= 0;) {
if ((c = zdlread()) & ~0377)
return c;
crc = UPDC32(c, crc);
*hdr++ = c;
}
for (n=4; --n >= 0;) {
if ((c = zdlread()) & ~0377)
return c;
crc = UPDC32(c, crc);
}
if (crc != 0xDEBB20E3) {
zperr("Bad Header CRC %lX", crc); return ERROR;
}
Zmodem = 1;
return Rxtype;
}
/* Receive a hex style header (type and position) */
zrhhdr(hdr)
char *hdr;
{
register c;
register unsigned short crc;
register n;
if ((c = zgethex()) < 0)
return c;
Rxtype = c;
crc = updcrc(c, 0);
for (n=4; --n >= 0;) {
if ((c = zgethex()) < 0)
return c;
crc = updcrc(c, crc);
*hdr++ = c;
}
if ((c = zgethex()) < 0)
return c;
crc = updcrc(c, crc);
if ((c = zgethex()) < 0)
return c;
crc = updcrc(c, crc);
if (crc & 0xFFFF) {
zperr("Bad Header CRC"); return ERROR;
}
if (readline(1) == '\r') /* Throw away possible cr/lf */
readline(1);
Zmodem = 1; return Rxtype;
}
/* Send a byte as two hex digits */
zputhex(c)
register c;
{
static char digits[] = "0123456789abcdef";
if (Verbose>4)
vfile("zputhex: %x", c);
sendline(digits[(c&0xF0)>>4]);
sendline(digits[(c)&0xF]);
}
/*
* Send character c with ZMODEM escape sequence encoding.
* Escape XON, XOFF. Escape CR following @ (Telenet net escape)
*/
zsendline(c)
register c;
{
static lastsent;
switch (c & 0377) {
case ZDLE:
xsendline(ZDLE);
xsendline (lastsent = (c ^= 0100));
break;
case 015:
case 0215:
if ((lastsent & 0177) != '@')
goto sendit;
/* **** FALL THRU TO **** */
case 020:
case 021:
case 023:
case 0220:
case 0221:
case 0223:
#ifdef ZKER
if (Zctlesc<0)
goto sendit;
#endif
xsendline(ZDLE);
c ^= 0100;
sendit:
xsendline(lastsent = c);
break;
default:
#ifdef ZKER
if (Zctlesc>0 && ! (c & 0140)) {
xsendline(ZDLE);
c ^= 0100;
}
#endif
xsendline(lastsent = c);
}
}
/* Decode two lower case hex digits into an 8 bit byte value */
zgethex()
{
register c;
c = zgeth1();
if (Verbose>4)
vfile("zgethex: %x", c);
return c;
}
zgeth1()
{
register c, n;
if ((c = noxread7()) < 0)
return c;
n = c - '0';
if (n > 9)
n -= ('a' - ':');
if (n & ~0xF)
return ERROR;
if ((c = noxread7()) < 0)
return c;
c -= '0';
if (c > 9)
c -= ('a' - ':');
if (c & ~0xF)
return ERROR;
c += (n<<4);
return c;
}
/*
* Read a byte, checking for ZMODEM escape encoding
* including CAN*5 which represents a quick abort
*/
zdlread()
{
register c;
if ((c = readline(Rxtimeout)) != ZDLE)
return c;
if ((c = readline(Rxtimeout)) < 0)
return c;
if (c == CAN && (c = readline(Rxtimeout)) < 0)
return c;
if (c == CAN && (c = readline(Rxtimeout)) < 0)
return c;
if (c == CAN && (c = readline(Rxtimeout)) < 0)
return c;
switch (c) {
case CAN:
return GOTCAN;
case ZCRCE:
case ZCRCG:
case ZCRCQ:
case ZCRCW:
return (c | GOTOR);
case ZRUB0:
return 0177;
case ZRUB1:
return 0377;
default:
if ((c & 0140) == 0100)
return (c ^ 0100);
break;
}
zperr("Got bad ZMODEM escape sequence %x", c);
return ERROR;
}
/*
* Read a character from the modem line with timeout.
* Eat parity, XON and XOFF characters.
*/
noxread7()
{
register c;
for (;;) {
if ((c = readline(Rxtimeout)) < 0)
return c;
switch (c &= 0177) {
case XON:
case XOFF:
continue;
default:
return c;
}
}
}
/* Store long integer pos in Txhdr */
stohdr(pos)
long pos;
{
Txhdr[ZP0] = pos;
Txhdr[ZP1] = pos>>8;
Txhdr[ZP2] = pos>>16;
Txhdr[ZP3] = pos>>24;
}
/* Recover a long integer from a header */
long
rclhdr(hdr)
register char *hdr;
{
register long l;
l = (hdr[ZP3] & 0377);
l = (l << 8) | (hdr[ZP2] & 0377);
l = (l << 8) | (hdr[ZP1] & 0377);
l = (l << 8) | (hdr[ZP0] & 0377);
return l;
}
SHAR_EOF
echo shar: extracting sz.c '(27639 characters)'
cat << \SHAR_EOF > sz.c
#define VERSION "sz 1.23 01-15-87"
#define PUBDIR "/usr/spool/uucppublic"
/*% cc -O -K -i -DCRCTABLE -DREADCHECK sz.c -lx -o sz; size sz
* sz.c By Chuck Forsberg
*
* cc -O sz.c -o sz USG (SYS III/V) Unix
* cc -O -DSVR2 sz.c -o sz Sys V Release 2 with non-blocking input
* Define to allow reverse channel checking
* cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD
*
* ln sz sb **** All versions ****
*
* define CRCTABLE to use table driven CRC
*
* ******* Some systems (Venix, Coherent, Regulus) do not *******
* ******* support tty raw mode read(2) identically to *******
* ******* Unix. ONEREAD must be defined to force one *******
* ******* character reads for these systems. *******
*
* A program for Unix to send files and commands to computers running
* Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
*
* Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
*
* USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
*/
char *substr(), *getenv();
#define LOGFILE "/tmp/szlog"
#define zperr vfile
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <ctype.h>
#define PATHLEN 256
#define OK 0
#define FALSE 0
#define TRUE 1
#define ERROR (-1)
#define HOWMANY 2
int Zmodem=0; /* ZMODEM protocol requested */
unsigned Baudrate;
int Fromcu = 0; /* Were called from cu or yam */
#include "rbsb.c" /* most of the system dependent stuff here */
/*
* Attention string to be executed by receiver to interrupt streaming data
* when an error is detected. A pause (0336) may be needed before the
* ^C (03) or after it.
*/
#ifdef READCHECK
char Myattn[] = { 0 };
#else
#ifdef USG
char Myattn[] = { 03, 0336, 0 };
#else
char Myattn[] = { 0 };
#endif
#endif
FILE *in;
/* Ward Christensen / CP/M parameters - Don't change these! */
#define ENQ 005
#define CAN ('X'&037)
#define XOFF ('s'&037)
#define XON ('q'&037)
#define SOH 1
#define STX 2
#define EOT 4
#define ACK 6
#define NAK 025
#define CPMEOF 032
#define WANTCRC 0103 /* send C not NAK to get crc not checksum */
#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */
#define TIMEOUT (-2)
#define RCDO (-3)
#define RETRYMAX 10
#define SECSIZ 128 /* cp/m's Magic Number record size */
#define KSIZE 1024
char Lastrx;
char Crcflg;
int Wcsmask=0377;
int Verbose=0;
int Modem=0; /* MODEM - don't send pathnames */
int Restricted=0; /* restricted; no /.. or ../ in filenames */
int Quiet=0; /* overrides logic that would otherwise set verbose */
int Ascii=0; /* Add CR's for brain damaged programs */
int Fullname=0; /* transmit full pathname */
int Unlinkafter=0; /* Unlink file after it is sent */
int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */
int firstsec;
int errcnt=0; /* number of files unreadable */
int blklen=SECSIZ; /* length of transmitted records */
int Optiong; /* Let it rip no wait for sector ACK's */
int Noeofseen;
int Totsecs; /* total number of sectors this file */
char txbuf[KSIZE];
int Filcnt=0; /* count of number of files opened */
int Lfseen=0;
unsigned Rxbuflen = 16384; /* Receiver's max buffer length */
int Tframlen = 0; /* Override for tx frame length */
int blkopt=0; /* Override value for zmodem blklen */
int Rxflags = 0;
int Wantfcs32 = TRUE; /* want to send 32 bit FCS */
char Lzconv; /* Local ZMODEM file conversion request */
char Lzmanag; /* Local ZMODEM file management request */
char Lztrans;
char zconv; /* ZMODEM file conversion request */
char zmanag; /* ZMODEM file management request */
char ztrans; /* ZMODEM file transport request */
int Command; /* Send a command, then exit. */
char *Cmdstr; /* Pointer to the command string */
int Cmdtries = 11;
int Cmdack1; /* Rx ACKs command, then do it */
int Exitcode;
int Testattn; /* Force receiver to send Attn, etc with qbf. */
char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
long Lastread; /* Beginning offset of last buffer read */
int Lastc; /* Count of last buffer read or -1 */
int Dontread; /* Don't read the buffer, it's still there */
jmp_buf tohere; /* For the interrupt on RX timeout */
jmp_buf intrjmp; /* For the interrupt on RX CAN */
/* called by signal interrupt or terminate to clean things up */
bibi(n)
{
canit(); fflush(stdout); mode(0);
fprintf(stderr, "sz: caught signal %d; exiting\n", n);
if (n == SIGQUIT)
abort();
exit(128+n);
}
/* Called when Zmodem gets an interrupt (^X) */
onintr()
{
signal(SIGINT, SIG_IGN);
longjmp(intrjmp, -1);
}
#define sendline(c) putchar(c & Wcsmask)
#define xsendline(c) putchar(c)
flushmo()
{
fflush(stdout);
}
#define ZKER
int Zctlesc; /* Encode control characters */
int Nozmodem = 0; /* If invoked as "sb" */
char *Progname = "sz";
#include "zm.c"
main(argc, argv)
char *argv[];
{
register char *cp;
register npats;
int agcnt; char **agcv;
char **patts;
static char xXbuf[BUFSIZ];
if ((cp = getenv("ZNULLS")) && *cp)
Znulls = atoi(cp);
if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
Restricted=TRUE;
chkinvok(argv[0]);
Rxtimeout = 600;
npats=0;
if (argc<2)
usage();
setbuf(stdout, xXbuf);
while (--argc) {
cp = *++argv;
if (*cp++ == '-' && *cp) {
while ( *cp) {
switch(*cp++) {
case '+':
Lzmanag = ZMAPND; break;
case '1':
iofd = 1; break;
#ifdef CSTOPB
case '2':
Twostop = TRUE; break;
#endif
case '7':
Wcsmask=0177; break;
case 'a':
Lzconv = ZCNL;
Ascii = TRUE; break;
case 'b':
Lzconv = ZCBIN; break;
case 'C':
if (--argc < 1) {
usage();
}
Cmdtries = atoi(*++argv);
break;
case 'i':
Cmdack1 = ZCACK1;
/* **** FALL THROUGH TO **** */
case 'c':
if (--argc != 1) {
usage();
}
Command = TRUE;
Cmdstr = *++argv;
break;
case 'd':
++Dottoslash;
/* **** FALL THROUGH TO **** */
case 'f':
Fullname=TRUE; break;
case 'E':
Zctlesc = -1; break;
case 'e':
Zctlesc = 1; break;
case 'k':
blklen=KSIZE; break;
case 'L':
if (--argc < 1) {
usage();
}
blkopt = atoi(*++argv);
if (blkopt<24 || blkopt>1024)
usage();
break;
case 'l':
if (--argc < 1) {
usage();
}
Tframlen = atoi(*++argv);
if (Tframlen<32 || Tframlen>1024)
usage();
break;
case 'N':
Lzmanag = ZMDIFF; break;
case 'n':
Lzmanag = ZMNEW; break;
case 'o':
Wantfcs32 = FALSE; break;
case 'p':
Lzmanag = ZMPROT; break;
case 'r':
Lzconv = ZCRESUM;
case 'q':
Quiet=TRUE; Verbose=0; break;
case 't':
if (--argc < 1) {
usage();
}
Rxtimeout = atoi(*++argv);
if (Rxtimeout<10 || Rxtimeout>1000)
usage();
break;
case 'T':
Testattn = TRUE; break;
case 'u':
++Unlinkafter; break;
case 'v':
++Verbose; break;
case 'X':
++Modem; break;
case 'y':
Lzmanag = ZMCLOB; break;
default:
usage();
}
}
}
else if ( !npats && argc>0) {
if (argv[0][0]) {
npats=argc;
patts=argv;
if ( !strcmp(*patts, "-"))
iofd = 1;
}
}
}
if (npats < 1 && !Command)
usage();
if (Verbose) {
if (freopen(LOGFILE, "a", stderr)==NULL) {
printf("Can't open log file %s\n",LOGFILE);
exit(0200);
}
setbuf(stderr, NULL);
}
if ((Fromcu=from_cu()) && !Quiet) {
if (Verbose == 0)
Verbose = 2;
}
mode(1);
if (signal(SIGINT, bibi) == SIG_IGN) {
signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
} else {
signal(SIGINT, bibi); signal(SIGKILL, bibi);
}
if ( !Fromcu)
signal(SIGQUIT, SIG_IGN);
if ( !Modem) {
if (!Nozmodem) {
printf("rz\r"); fflush(stdout);
}
if (!Command && !Quiet && Verbose != 1) {
fprintf(stderr, "%s: %d file%s requested:\r\n",
Progname, npats, npats>1?"s":"");
for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
fprintf(stderr, "%s ", *agcv++);
}
fprintf(stderr, "\r\n");
printf("\r\n\bSending in Batch Mode\r\n");
}
if (!Nozmodem) {
stohdr(0L);
if (Command)
Txhdr[ZF0] = ZCOMMAND;
zshhdr(ZRQINIT, Txhdr);
}
}
fflush(stdout);
if (Command) {
if (getzrxinit()) {
Exitcode=0200; canit();
}
else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
Exitcode=0200; canit();
}
} else if (wcsend(npats, patts)==ERROR) {
Exitcode=0200;
canit();
}
fflush(stdout);
mode(0);
exit((errcnt != 0) | Exitcode);
/*NOTREACHED*/
}
wcsend(argc, argp)
char *argp[];
{
register n;
Crcflg=FALSE;
firstsec=TRUE;
for (n=0; n<argc; ++n) {
Totsecs = 0;
if (wcs(argp[n])==ERROR)
return ERROR;
}
Totsecs = 0;
if (Filcnt==0) { /* bitch if we couldn't open ANY files */
if (1) {
Command = TRUE;
Cmdstr = "echo \"sz: Can't open any requested files\"";
if (getnak()) {
Exitcode=0200; canit();
}
if (!Zmodem)
canit();
else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
Exitcode=0200; canit();
}
Exitcode = 1; return OK;
}
canit();
fprintf(stderr,"\r\nCan't open any requested files.\r\n");
return ERROR;
}
if (Zmodem)
saybibi();
else
wctxpn("");
return OK;
}
wcs(oname)
char *oname;
{
register c;
register char *p;
struct stat f;
char name[PATHLEN];
strcpy(name, oname);
if (Restricted) {
/* restrict pathnames to current tree or uucppublic */
if ( substr(name, "../")
|| (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
canit();
fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
return ERROR;
}
}
if ( !strcmp(oname, "-")) {
if ((p = getenv("ONAME")) && *p)
strcpy(name, p);
else
sprintf(name, "s%d.sz", getpid());
in = stdin;
}
else if ((in=fopen(oname, "r"))==NULL) {
++errcnt;
return OK; /* pass over it, there may be others */
}
++Noeofseen; Lastread = 0; Lastc = -1; Dontread = FALSE;
/* Check for directory or block special files */
fstat(fileno(in), &f);
c = f.st_mode & S_IFMT;
if (c == S_IFDIR || c == S_IFBLK) {
fclose(in);
return OK;
}
++Filcnt;
switch (wctxpn(name)) {
case ERROR:
return ERROR;
case ZSKIP:
return OK;
}
if (!Zmodem && wctx()==ERROR)
return ERROR;
if (Unlinkafter)
unlink(oname);
return 0;
}
/*
* generate and transmit pathname block consisting of
* pathname (null terminated),
* file length, mode time and file mode in octal
* as provided by the Unix fstat call.
* N.B.: modifies the passed name, may extend it!
*/
wctxpn(name)
char *name;
{
register char *p, *q;
char name2[PATHLEN];
struct stat f;
if (Modem) {
if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
fprintf(stderr, "Sending %s, %ld blocks: ",
name, f.st_size>>7);
}
fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
return OK;
}
logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
if ( !Zmodem)
if (getnak())
return ERROR;
q = (char *) 0;
if (Dottoslash) { /* change . to . */
for (p=name; *p; ++p) {
if (*p == '/')
q = p;
else if (*p == '.')
*(q=p) = '/';
}
if (q && strlen(++q) > 8) { /* If name>8 chars */
q += 8; /* make it .ext */
strcpy(name2, q); /* save excess of name */
*q = '.';
strcpy(++q, name2); /* add it back */
}
}
for (p=name, q=txbuf ; *p; )
if ((*q++ = *p++) == '/' && !Fullname)
q = txbuf;
*q++ = 0;
p=q;
while (q < (txbuf + KSIZE))
*q++ = 0;
if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
/* force 1k blocks if name won't fit in 128 byte block */
if (txbuf[125])
blklen=KSIZE;
else { /* A little goodie for IMP/KMD */
if (Zmodem)
blklen = SECSIZ;
txbuf[127] = (f.st_size + 127) >>7;
txbuf[126] = (f.st_size + 127) >>15;
}
if (Zmodem)
return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
return ERROR;
return OK;
}
getnak()
{
register firstch;
Lastrx = 0;
for (;;) {
switch (firstch = readock(800,1)) {
case ZPAD:
if (getzrxinit())
return ERROR;
Ascii = 0;
return FALSE;
case TIMEOUT:
logent("Timeoutdefine ENQ 005
#define CAN ('X'&037)
#define XOFF ('s'&037)
#define XON ('q'&037)
#define SOH 1
#define STX 2
#define EOT 4
#define ACK 6
#define NAK 025
#define CPMEOF 032
#define WANTCRC 0103 /* send C not NAK to get crc not checksum */
#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */
#define TIMEOUT (-2)
#define RCDO (-3)
#define RETRYMAX 10
#define SECSIZ 128 /* cp/m's Magic Number record size */
#define KSIZE 1024
char Lastrx;
char Crcflg;
int Wcsmask=0377;
int Verbose=0;
int Modem=0; /* MODEM - don't send pathnames */
int Restricted=0; /* restricted; no /.. or ../ in filenames */
int Quiet=0; /* overrides logic that would otherwise set verbose */
int Ascii=0; /* Add CR's for brain damaged programs */
int Fullname=0; /* transmit full pathname */
int Unlinkafter=0; /* Unlink file after it is sent */
int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */
int firstsec;
int errcnt=0; /* number of files unreadable */
int blklen=SECSIZ; /* length of transmitted records */
int Optiong; /* Let it rip no wait for sector ACK's */
int Noeofseen;
int Totsecs; /* total number of sectors this file */
char txbuf[KSIZE];
int Filcnt=0; /* count of number of files opened */
int Lfseen=0;
unsigned Rxbuflen = 16384; /* Receiver's max buffer length */
int Tframlen = 0; /* Override for tx frame length */
int blkopt=0; /* Override value for zmodem blklen */
int Rxflags = 0;
int Wantfcs32 = TRUE; /* want to send 32 bit FCS */
char Lzconv; /* Local ZMODEM file conversion request */
char Lzmanag; /* Local ZMODEM file management request */
char Lztrans;
char zconv; /* ZMODEM file conversion request */
char zmanag; /* ZMODEM file management request */
char ztrans; /* ZMODEM file transport request */
int Command; /* Send a command, then exit. */
char *Cmdstr; /* Pointer to the command string */
int Cmdtries = 11;
int Cmdack1; /* Rx ACKs command, then do it */
int Exitcode;
int Testattn; /* Force receiver to send Attn, etc with qbf. */
char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
long Lastread; /* Beginning offset of last buffer read */
int Lastc; /* Count of last buffer read or -1 */
int Dontread; /* Don't read the buffer, it's still there */
jmp_buf tohere; /* For the interrupt on RX timeout */
jmp_buf intrjmp; /* For the interrupt on RX CAN */
/* called by signal interrupt or terminate to clean things up */
bibi(n)
{
canit(); fflush(stdout); mode(0);
fprintf(stderr, "sz: caught signal %d; exiting\n", n);
if (n == SIGQUIT)
abort();
exit(128+n);
}
/* Called when Zmodem gets an interrupt (^X) */
onintr()
{
signal(SIGINT, SIG_IGN);
longjmp(intrjmp, -1);
}
#define sendline(c) putchar(c & Wcsmask)
#define xsendline(c) putchar(c)
flushmo()
{
fflush(stdout);
}
#define ZKER
int Zctlesc; /* Encode control characters */
int Nozmodem = 0; /* If invoked as "sb" */
char *Progname = "sz";
#include "zm.c"
main(argc, argv)
char *argv[];
{
register char *cp;
register npats;
int agcnt; char **agcv;
char **patts;
static char xXbuf[BUFSIZ];
if ((cp = getenv("ZNULLS")) && *cp)
Znulls = atoi(cp);
if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
Restricted=TRUE;
chkinvok(argv[0]);
Rxtimeout = 600;
npats=0;
if (argc<2)
usage();
setbuf(stdout, xXbuf);
while (--argc) {
cp = *++argv;
if (*cp++ == '-' && *cp) {
while ( *cp) {
switch(*cp++) {
case '+':
Lzmanag = ZMAPND; break;
case '1':
iofd = 1; break;
#ifdef CSTOPB
case '2':
Twostop = TRUE; break;
#endif
case '7':
Wcsmask=0177; break;
case 'a':
Lzconv = ZCNL;
Ascii = TRUE; break;
case 'b':
Lzconv = ZCBIN; break;
case 'C':
if (--argc < 1) {
usage();
}
Cmdtries = atoi(*++argv);
break;
case 'i':
Cmdack1 = ZCACK1;
/* **** FALL THROUGH TO **** */
case 'c':
if (--argc != 1) {
usage();
}
Command = TRUE;
Cmdstr = *++argv;
break;
case 'd':
++Dottoslash;
/* **** FALL THROUGH TO **** */
case 'f':
Fullname=TRUE; break;
case 'E':
Zctlesc = -1; break;
case 'e':
Zctlesc = 1; break;
case 'k':
blklen=KSIZE; break;
case 'L':
if (--argc < 1) {
usage();
}
blkopt = atoi(*++argv);
if (blkopt<24 || blkopt>1024)
usage();
break;
case 'l':
if (--argc < 1) {
usage();
}
Tframlen = atoi(*++argv);
if (Tframlen<32 || Tframlen>1024)
usage();
break;
case 'N':
Lzmanag = ZMDIFF; break;
case 'n':
Lzmanag = ZMNEW; break;
case 'o':
Wantfcs32 = FALSE; break;
case 'p':
Lzmanag = ZMPROT; break;
case 'r':
Lzconv = ZCRESUM;
case 'q':
Quiet=TRUE; Verbose=0; break;
case 't':
if (--argc < 1) {
usage();
}
Rxtimeout = atoi(*++argv);
if (Rxtimeout<10 || Rxtimeout>1000)
usage();
break;
case 'T':
Testattn = TRUE; break;
case 'u':
++Unlinkafter; break;
case 'v':
++Verbose; break;
case 'X':
++Modem; break;
case 'y':
Lzmanag = ZMCLOB; break;
default:
usage();
}
}
}
else if ( !npats && argc>0) {
if (argv[0][0]) {
npats=argc;
patts=argv;
if ( !strcmp(*patts, "-"))
iofd = 1;
}
}
}
if (npats < 1 && !Command)
usage();
if (Verbose) {
if (freopen(LOGFILE, "a", stderr)==NULL) {
printf("Can't open log file %s\n",LOGFILE);
exit(0200);
}
setbuf(stderr, NULL);
}
if ((Fromcu=from_cu()) && !Quiet) {
if (Verbose == 0)
Verbose = 2;
}
mode(1);
if (signal(SIGINT, bibi) == SIG_IGN) {
signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
} else {
signal(SIGINT, bibi); signal(SIGKILL, bibi);
}
if ( !Fromcu)
signal(SIGQUIT, SIG_IGN);
if ( !Modem) {
if (!Nozmodem) {
printf("rz\r"); fflush(stdout);
}
if (!Command && !Quiet && Verbose != 1) {
fprintf(stderr, "%s: %d file%s requested:\r\n",
Progname, npats, npats>1?"s":"");
for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
fprintf(stderr, "%s ", *agcv++);
}
fprintf(stderr, "\r\n");
printf("\r\n\bSending in Batch Mode\r\n");
}
if (!Nozmodem) {
stohdr(0L);
if (Command)
Txhdr[ZF0] = ZCOMMAND;
zshhdr(ZRQINIT, Txhdr);
}
}
fflush(stdout);
if (Command) {
if (getzrxinit()) {
Exitcode=0200; canit();
}
else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
Exitcode=0200; canit();
}
} else if (wcsend(npats, patts)==ERROR) {
Exitcode=0200;
canit();
}
fflush(stdout);
mode(0);
exit((errcnt != 0) | Exitcode);
/*NOTREACHED*/
}
wcsend(argc, argp)
char *argp[];
{
register n;
Crcflg=FALSE;
firstsec=TRUE;
for (n=0; n<argc; ++n) {
Totsecs = 0;
if (wcs(argp[n])==ERROR)
return ERROR;
}
Totsecs = 0;
if (Filcnt==0) { /* bitch if we couldn't open ANY files */
if (1) {
Command = TRUE;
Cmdstr = "echo \"sz: Can't open any requested files\"";
if (getnak()) {
Exitcode=0200; canit();
}
if (!Zmodem)
canit();
else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
Exitcode=0200; canit();
}
Exitcode = 1; return OK;
}
canit();
fprintf(stderr,"\r\nCan't open any requested files.\r\n");
return ERROR;
}
if (Zmodem)
saybibi();
else
wctxpn("");
return OK;
}
wcs(oname)
char *oname;
{
register c;
register char *p;
struct stat f;
char name[PATHLEN];
strcpy(name, oname);
if (Restricted) {
/* restrict pathnames to current tree or uucppublic */
if ( substr(name, "../")
|| (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
canit();
fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
return ERROR;
}
}
if ( !strcmp(oname, "-")) {
if ((p = getenv("ONAME")) && *p)
strcpy(name, p);
else
sprintf(name, "s%d.sz", getpid());
in = stdin;
}
else if ((in=fopen(oname, "r"))==NULL) {
++errcnt;
return OK; /* pass over it, there may be others */
}
++Noeofseen; Lastread = 0; Lastc = -1; Dontread = FALSE;
/* Check for directory or block special files */
fstat(fileno(in), &f);
c = f.st_mode & S_IFMT;
if (c == S_IFDIR || c == S_IFBLK) {
fclose(in);
return OK;
}
++Filcnt;
switch (wctxpn(name)) {
case ERROR:
return ERROR;
case ZSKIP:
return OK;
}
if (!Zmodem && wctx()==ERROR)
return ERROR;
if (Unlinkafter)
unlink(oname);
return 0;
}
/*
* generate and transmit pathname block consisting of
* pathname (null terminated),
* file length, mode time and file mode in octal
* as provided by the Unix fstat call.
* N.B.: modifies the passed name, may extend it!
*/
wctxpn(name)
char *name;
{
register char *p, *q;
char name2[PATHLEN];
struct stat f;
if (Modem) {
if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
fprintf(stderr, "Sending %s, %ld blocks: ",
name, f.st_size>>7);
}
fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
return OK;
}
logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
if ( !Zmodem)
if (getnak())
return ERROR;
q = (char *) 0;
if (Dottoslash) { /* change . to . */
for (p=name; *p; ++p) {
if (*p == '/')
q = p;
else if (*p == '.')
*(q=p) = '/';
}
if (q && strlen(++q) > 8) { /* If name>8 chars */
q += 8; /* make it .ext */
strcpy(name2, q); /* save excess of name */
*q = '.';
strcpy(++q, name2); /* add it back */
}
}
for (p=name, q=txbuf ; *p; )
if ((*q++ = *p++) == '/' && !Fullname)
q = txbuf;
*q++ = 0;
p=q;
while (q < (txbuf + KSIZE))
*q++ = 0;
if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
/* force 1k blocks if name won't fit in 128 byte block */
if (txbuf[125])
blklen=KSIZE;
else { /* A little goodie for IMP/KMD */
if (Zmodem)
blklen = SECSIZ;
txbuf[127] = (f.st_size + 127) >>7;
txbuf[126] = (f.st_size + 127) >>15;
}
if (Zmodem)
return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
return ERROR;
return OK;
}
getnak()
{
register firstch;
Lastrx = 0;
for (;;) {
switch (firstch = readock(800,1)) {
case ZPAD:
if (getzrxinit())
return ERROR;
Ascii = 0;
return FALSE;
case TIMEOUT:
logent("Timeout on pathname\n");
return TRUE;
case WANTG:
#ifdef USG
mode(2); /* Set cbreak, XON/XOFF, etc. */
#endif
Optiong = TRUE;
blklen=KSIZE;
case WANTCRC:
Crcflg = TRUE;
case NAK:
return FALSE;
case CAN:
if ((firstch = readock(20,1)) == CAN && Lastrx == CAN)
return TRUE;
default:
break;
}
Lastrx = firstch;
}
}
wctx()
{
register int sectnum, attempts, firstch;
firstsec=TRUE;
while ((firstch=readock(Rxtimeout, 2))!=NAK && firstch != WANTCRC
&& firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
;
if (firstch==CAN) {
logent("Receiver CANcelled\n");
return ERROR;
}
if (firstch==WANTCRC)
Crcflg=TRUE;
if (firstch==WANTG)
Crcflg=TRUE;
sectnum=1;
while (filbuf(txbuf, blklen)) {
if (wcputsec(txbuf, sectnum, blklen)==ERROR) {
return ERROR;
} else
sectnum++;
}
if (Verbose>1)
fprintf(stderr, " Closing ");
fclose(in);
attempts=0;
do {
logent(" EOT ");
purgeline();
sendline(EOT);
fflush(stdout);
++attempts;
}
while ((firstch=(readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX);
if (attempts == RETRYMAX) {
logent("No ACK on EOT\n");
return ERROR;
}
else
return OK;
}
wcputsec(buf, sectnum, cseclen)
char *buf;
int sectnum;
int cseclen; /* data length of this sector to send */
{
register checksum, wcj;
register char *cp;
unsigned oldcrc;
int firstch;
int attempts;
firstch=0; /* part of logic to detect CAN CAN */
if (Verbose>1)
fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
for (attempts=0; attempts <= RETRYMAX; attempts++) {
Lastrx= firstch;
sendline(cseclen==KSIZE?STX:SOH);
sendline(sectnum);
sendline(-sectnum -1);
oldcrc=checksum=0;
for (wcj=cseclen,cp=buf; --wcj>=0; ) {
sendline(*cp);
oldcrc=updcrc((0377& *cp), oldcrc);
checksum += *cp++;
}
if (Crcflg) {
oldcrc=updcrc(0,updcrc(0,oldcrc));
sendline((int)oldcrc>>8);
sendline((int)oldcrc);
}
else
sendline(checksum);
if (Optiong) {
firstsec = FALSE; return OK;
}
firstch = readock(Rxtimeout, (Noeofseen&§num) ? 2:1);
gotnak:
switch (firstch) {
case CAN:
if(Lastrx == CAN) {
cancan:
logent("Cancelled\n"); return ERROR;
}
break;
case TIMEOUT:
logent("Timeout on sector ACK\n"); continue;
case WANTCRC:
if (firstsec)
Crcflg = TRUE;
case NAK:
logent("NAK on sector\n"); continue;
case ACK:
firstsec=FALSE;
Totsecs += (cseclen>>7);
return OK;
case ERROR:
logent("Got burst for sector ACK\n"); break;
default:
logent("Got %02x for sector ACK\n", firstch); break;
}
for (;;) {
Lastrx = firstch;
if ((firstch = readock(Rxtimeout, 2)) == TIMEOUT)
break;
if (firstch == NAK || firstch == WANTCRC)
goto gotnak;
if (firstch == CAN && Lastrx == CAN)
goto cancan;
}
}
logent("Retry Count Exceeded\n");
return ERROR;
}
/* fill buf with count chars padding with ^Z for CPM */
filbuf(buf, count)
register char *buf;
{
register c, m;
if ( !Ascii) {
m = read(fileno(in), buf, count);
if (m <= 0)
return 0;
while (m < count)
buf[m++] = 032;
return count;
}
m=count;
if (Lfseen) {
*buf++ = 012; --m; Lfseen = 0;
}
while ((c=getc(in))!=EOF) {
if (c == 012) {
*buf++ = 015;
if (--m == 0) {
Lfseen = TRUE; break;
}
}
*buf++ =c;
if (--m == 0)
break;
}
if (m==count)
return 0;
else
while (--m>=0)
*buf++ = CPMEOF;
return count;
}
/* fill buf with count chars */
zfilbuf(buf, count)
register char *buf;
{
register c, m;
m=count;
while ((c=getc(in))!=EOF) {
*buf++ =c;
if (--m == 0)
break;
}
return (count - m);
}
/* VARARGS1 */
vfile(f, a, b, c)
register char *f;
{
if (Verbose > 1) {
fprintf(stderr, f, a, b, c);
fprintf(stderr, "\n");
}
}
alrm()
{
longjmp(tohere, -1);
}
/*
* readock(timeout, count) reads character(s) from file descriptor 0
* (1 <= count <= 3)
* it attempts to read count characters. If it gets more than one,
* it is an error unless all are CAN
* (otherwise, only normal response is ACK, CAN, or C)
* Only looks for one if Optiong, which signifies cbreak, not raw input
*
* timeout is in tenths of seconds
*/
readock(timeout, count)
{
register int c;
static char byt[5];
if (Optiong)
count = 1; /* Special hack for cbreak */
fflush(stdout);
if (setjmp(tohere)) {
logent("TIMEOUT\n");
return TIMEOUT;
}
c = timeout/10;
if (c<2)
c=2;
if (Verbose>3) {
fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
byt[1] = 0;
}
signal(SIGALRM, alrm); alarm(c);
#ifdef ONEREAD
c=read(iofd, byt, 1); /* regulus raw read is unique */
#else
c=read(iofd, byt, count);
#endif
alarm(0);
if (Verbose>5)
fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
if (c<1)
return TIMEOUT;
if (c==1)
return (byt[0]&0377);
else
while (c)
if (byt[--c] != CAN)
return ERROR;
return CAN;
}
readline(n)
{
return (readock(n, 1));
}
purgeline()
{
#ifdef USG
ioctl(iofd, TCFLSH, 0);
#else
lseek(iofd, 0L, 2);
#endif
}
/* send cancel string to get the other end to shut up */
canit()
{
static char canistr[] = {
24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
};
printf(canistr);
fflush(stdout);
}
/*VARARGS1*/
logent(a, b, c)
char *a, *b, *c;
{
if(Verbose)
fprintf(stderr, a, b, c);
}
/*
* return 1 iff stdout and stderr are different devices
* indicating this pr
More information about the Comp.sources.unix
mailing list