This is zmodem.c in view mode; [Download] [Up]
/*+-------------------------------------------------------------------------
zmodem.c - ZMODEM protocol primitives
based on code by Chuck Forsberg
tip adaptation by wht%n4hgf@emory.mathcs.emory.edu
Entry point Functions:
zsbhdr(len,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
Defined functions:
noxrd7()
rclhdr(hdr)
stohdr(pos)
zdlread()
zgeth1()
zgethdr(hdr,eflag)
zgethex()
zputhex(c)
zrbhdr(hdr)
zrbhdr32(hdr)
zrdat32(buf,length)
zrdata(buf,length)
zrhhdr(hdr)
zsbh32(hdr,type)
zsbhdr(len,type,hdr)
zsda32(buf,length,frameend)
zsdata(buf,length,frameend)
zsendline(c)
zshhdr(type,hdr)
--------------------------------------------------------------------------*/
/*+:EDITS:*/
/*:05-21-1990-16:00-wht@tridom-adapt ecu xfer protocols for tipwht */
#include "zmodem.h" /* wht */
#include "zlint.h"
extern char s128[]; /* wht */
extern int Zctlesc; /* wht */
extern int Zmodem; /* wht */
extern long cr3tab[]; /* wht */
extern unsigned Baudrate; /* wht */
extern unsigned short crctab[]; /* wht */
int Rxtimeout = 100; /* Tenths of seconds to wait for something */
#if !defined(UNSL)
#define UNSL
#endif
/* Globals used by ZMODEM functions */
int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */
int Rxtype; /* Type of header received */
int Rxhlen; /* Length of header received */
int Rxcount; /* Count of data bytes received */
char Rxhdr[ZMAXHLEN]; /* Received header */
char Txhdr[ZMAXHLEN]; /* Transmitted header */
long Rxpos; /* Received file position */
long Txpos; /* Transmitted file position */
int Txfcs32; /* TURE means send binary frames with 32 bit FCS */
int Crc32t; /* Controls 32 bit CRC being sent */
/* 1 == CRC32, 2 == CRC32 + RLE */
int Crc32r; /* Indicates/controls 32 bit CRC being received */
/* 0 == CRC16, 1 == CRC32, 2 == CRC32 + RLE */
int Usevhdrs; /* Use variable length headers */
int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
char *Altcan; /* Alternate canit string */
static lastsent; /* Last char we sent */
static Not8bit; /* Seven bits seen on header */
char *frametypes[] =
{
"No Response to Error Correction Request", /* -4 */
"Carrier Lost", /* -3 */
"TIMEOUT", /* -2 */
"ERROR", /* -1 */
/* #define FTOFFSET 3 moved to zmodem.h */
"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 */
};
static char masked[] = "8 bit transparent path required";
static char badcrc[] = "Bad CRC";
/* Send ZMODEM binary header hdr of type type */
zsbhdr(len, type, hdr)
register unsigned char *hdr;
{
register int n;
register unsigned crc;
report_tx_ind(1);
sprintf(s128,"hdr %s %ld",frametypes[type+FTOFFSET],rclhdr(hdr));
report_last_txhdr(s128,0);
xsendline(ZPAD);
xsendline(ZDLE);
switch (Crc32t=Txfcs32) {
case 2:
zsbh32(len, hdr, type, Usevhdrs?ZVBINR32:ZBINR32);
flushline(); break;
case 1:
zsbh32(len, hdr, type, Usevhdrs?ZVBIN32:ZBIN32); break;
default:
if (Usevhdrs) {
xsendline(ZVBIN);
zsendline(len);
}
else
xsendline(ZBIN);
zsendline(type);
crc = updcrc(type, 0);
for (n=len; --n >= 0; ++hdr) {
zsendline(*hdr);
crc = updcrc((0377& *hdr), crc);
}
crc = updcrc(0,updcrc(0,crc));
zsendline(crc>>8);
zsendline(crc);
}
if (type != ZDATA)
flushline();
report_tx_ind(0);
}
/* Send ZMODEM binary header hdr of type type */
zsbh32(len, hdr, type, flavour)
register char *hdr;
{
register int n;
register UNSL long crc;
report_tx_ind(1);
xsendline(flavour);
if (Usevhdrs)
zsendline(len);
zsendline(type);
crc = 0xFFFFFFFFL;
crc = UPDC32(type,crc);
for(n=len; --n >= 0; ++hdr)
{
crc = UPDC32((0377 & *hdr),crc);
zsendline(*hdr);
}
crc = ~crc;
for(n=len; --n >= 0;)
{
zsendline((int)crc);
crc >>= 8;
}
report_tx_ind(0);
}
/* Send ZMODEM HEX header hdr of type type */
zshhdr(len,type,hdr)
register unsigned char *hdr;
{
register int n;
register unsigned short crc;
report_tx_ind(1);
sprintf(s128,"hdr %s %ld",frametypes[type+FTOFFSET],rclhdr(hdr));
report_last_txhdr(s128,0);
sendline(ZPAD);
sendline(ZPAD);
sendline(ZDLE);
if (Usevhdrs) {
sendline(ZVHEX);
zputhex(len);
}
else
sendline(ZHEX);
zputhex(type);
Crc32t = 0;
crc = updcrc(type,0);
for(n=len; --n >= 0; ++hdr)
{
zputhex(*hdr);
crc = updcrc(*hdr,crc);
/* crc = updcrc((0377 & *hdr),crc); original - wht */
}
crc = updcrc(0,updcrc(0,crc));
zputhex(crc>>8);
zputhex(crc);
/* Make it printable on remote machine */
sendline(015);
sendline(0212);
/*
* Uncork the remote in case a fake XOFF has stopped data flow
*/
if(type != ZFIN && type != ZACK)
sendline(021);
flushline();
report_tx_ind(0);
}
/*
* Send binary array buf of length length,with ending ZDLE sequence frameend
*/
static char *Zendnames[] = { "ZCRCE","ZCRCG","ZCRCQ","ZCRCW"};
zsdata(buf,length,frameend)
register unsigned char *buf;
{
register unsigned short crc;
report_tx_ind(1);
sprintf(s128,"data %s %d bytes",Zendnames[frameend-ZCRCE&3],length);
report_last_txhdr(s128,0);
switch (Crc32t) {
case 1:
zsda32(buf, length, frameend); break;
case 2:
zsdar32(buf, length, frameend); break;
default:
crc = 0;
for(;--length >= 0; ++buf)
{
zsendline(*buf);
crc = updcrc(*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);
flushline();
}
report_tx_ind(0);
}
zsda32(buf,length,frameend)
register char *buf;
{
register int c;
register UNSL long crc;
report_tx_ind(1);
crc = 0xFFFFFFFFL;
for(;--length >= 0; ++buf)
{
c = *buf & 0377;
if(c & 0140)
xsendline(lastsent = c);
else
zsendline(c);
crc = UPDC32(c,crc);
}
xsendline(ZDLE);
xsendline(frameend);
crc = UPDC32(frameend,crc);
crc = ~crc;
for(c=4; --c >= 0;)
{
zsendline((int)crc);
crc >>= 8;
}
report_tx_ind(0);
}
/*
* Receive array buf of max length with ending ZDLE sequence
* and CRC. Returns the ending character or error code.
* NB: On errors may store length+1 bytes!
*/
zrdata(buf,length)
register char *buf;
{
register int c;
register unsigned short crc;
register char *end;
register int d;
report_rx_ind(1);
switch (Crc32r) {
case 1:
return zrdat32(buf, length);
case 2:
return zrdatr32(buf, length);
}
crc = Rxcount = 0;
end = buf + length;
while(buf <= end)
{
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)
{
report_str(badcrc,0);
report_rx_ind(0);
return(ERROR);
}
Rxcount = length - (end - buf);
report_rxblklen(Rxcount);
sprintf(s128,"data %s %d bytes",
Zendnames[d-GOTCRCE&3],Rxcount);
report_last_rxhdr(s128,0);
report_rx_ind(0);
return(d);
case GOTCAN:
report_str("Sender Cancelled",1);
report_rx_ind(0);
return(ZCAN);
case TIMEOUT:
report_str("TIMEOUT",1);
report_rx_ind(0);
return(c);
default:
report_str("Bad data subpacket",1);
report_rx_ind(0);
return(c);
}
}
*buf++ = c;
crc = updcrc(c,crc);
}
report_str("Data subpacket too long",1);
report_rx_ind(0);
return(ERROR);
}
zrdat32(buf,length)
register char *buf;
{
register int c;
register UNSL long crc;
register char *end;
register int d;
report_rx_ind(1);
crc = 0xFFFFFFFFL;
Rxcount = 0;
end = buf + length;
while(buf <= end)
{
if((c = zdlread()) & ~0377)
{
crcfoo:
switch(c)
{
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
d = c;
c &= 0377;
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((c = zdlread()) & ~0377)
goto crcfoo;
crc = UPDC32(c,crc);
if(crc != 0xDEBB20E3)
{
report_str(badcrc,0);
report_rx_ind(0);
return(ERROR);
}
Rxcount = length - (end - buf);
report_rxblklen(Rxcount);
sprintf(s128,"data %s %d bytes",
Zendnames[d-GOTCRCE&3],Rxcount);
report_last_rxhdr(s128,0);
report_rx_ind(0);
return(d);
case GOTCAN:
report_str("Sender Canceled",1);
report_rx_ind(0);
return(ZCAN);
case TIMEOUT:
report_str("TIMEOUT",1);
report_rx_ind(0);
return(c);
default:
report_str("Bad data subpacket",1);
report_rx_ind(0);
return(c);
}
}
*buf++ = c;
crc = UPDC32(c,crc);
}
report_str("Data subpacket too long",1);
report_rx_ind(0);
return(ERROR);
}
/*
* 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,set Rxpos and return type of header.
* Otherwise return negative on error.
* Return ERROR instantly if ZCRCW sequence,for fast error recovery.
*/
extern int Zrwindow;
zgethdr(hdr,eflag)
char *hdr;
{
register int c,n,cancount;
report_rx_ind(1);
n = Zrwindow + Baudrate; /* Max bytes before start of frame */
Rxframeind = Rxtype = 0;
startover:
cancount = 5;
again:
/* Return immediate ERROR if ZCRCW sequence seen */
switch(c = readline(Rxtimeout))
{
case RCDO:
case TIMEOUT:
goto fifi;
case CAN:
gotcan:
if(--cancount <= 0)
{
c = ZCAN;
goto fifi;
}
switch(c = readline(1))
{
case TIMEOUT:
goto again;
case ZCRCW:
c = ERROR;
/* **** FALL THRU TO **** */
case RCDO:
goto fifi;
default:
break;
case CAN:
if(--cancount <= 0)
{
c = ZCAN;
goto fifi;
}
goto again;
}
/* **** FALL THRU TO **** */
default:
agn2:
if( --n == 0)
{
report_str("Garbage count exceeded",1);
report_last_rxhdr("Noise",0);
report_rx_ind(0);
/* return(ERROR); */
goto fifi;
}
goto startover;
case ZPAD|0200: /* This is what we want. */
Not8bit = c;
case ZPAD: /* This is what we want. */
/* Not8bit = c & 0200; */
break;
}
cancount = 5;
splat:
switch(c = noxrd7())
{
case ZPAD:
goto splat;
case RCDO:
case TIMEOUT:
goto fifi;
default:
goto agn2;
case ZDLE: /* This is what we want. */
break;
}
Rxhlen = 4; /* Set default length */
Rxframeind = c = noxrd7();
switch (c) {
case ZVBIN32:
if ((Rxhlen = c = zdlread()) < 0)
goto fifi;
if (c > ZMAXHLEN)
goto agn2;
Crc32r = 1;
c = zrbhdr32(hdr);
break;
case ZBIN32:
if (Usevhdrs)
goto agn2;
Crc32r = 1;
c = zrbhdr32(hdr);
break;
case ZVBINR32:
if ((Rxhlen = c = zdlread()) < 0)
goto fifi;
if (c > ZMAXHLEN)
goto agn2;
Crc32r = 2;
c = zrbhdr32(hdr);
break;
case ZBINR32:
if (Usevhdrs)
goto agn2;
Crc32r = 2;
c = zrbhdr32(hdr);
break;
case RCDO:
case TIMEOUT:
goto fifi;
case ZVBIN:
if ((Rxhlen = c = zdlread()) < 0)
goto fifi;
if (c > ZMAXHLEN)
goto agn2;
Crc32r = 0;
c = zrbhdr(hdr);
break;
case ZBIN:
if (Usevhdrs)
goto agn2;
Crc32r = 0;
c = zrbhdr(hdr);
break;
case ZVHEX:
if ((Rxhlen = c = zgethex()) < 0)
goto fifi;
if (c > ZMAXHLEN)
goto agn2;
Crc32r = 0;
c = zrhhdr(hdr);
break;
case ZHEX:
if (Usevhdrs)
goto agn2;
Crc32r = 0;
c = zrhhdr(hdr);
break;
case CAN:
goto gotcan;
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:
sprintf(s128,"Got %s",frametypes[c+FTOFFSET]);
report_str(s128,1);
/* **** FALL THRU TO **** */
default:
if(c >= -4 && c <= FRTYPES)
sprintf(s128,"hdr %c %d %s %ld",
Rxframeind, Rxhlen,
frametypes[c+FTOFFSET], Rxpos);
else
sprintf(s128,"hdr %c 0x%02x? %ld",Rxframeind,c,Rxpos);
report_last_rxhdr(s128,0);
}
report_rx_ind(0);
/* Use variable length headers if we got one */
if (c >= 0 && c <= FRTYPES && Rxframeind & 040)
Usevhdrs = 1;
return(c);
}
/* Receive a binary style header (type and position) */
zrbhdr(hdr)
register char *hdr;
{
register int c,n;
register unsigned short crc;
if((c = zdlread()) & ~0377)
return(c);
Rxtype = c;
crc = updcrc(c,0);
for(n=Rxhlen; --n >= 0; ++hdr)
{
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)
{
if(Not8bit)
report_str(masked,1);
report_str(badcrc,0);
return(ERROR);
}
#if defined(ZMODEM)
Protocol = ZMODEM;
#endif
Zmodem = 1;
return(Rxtype);
}
/* Receive a binary style header (type and position) with 32 bit FCS */
zrbhdr32(hdr)
register char *hdr;
{
register int c,n;
register UNSL long crc;
if((c = zdlread()) & ~0377)
return(c);
Rxtype = c;
crc = 0xFFFFFFFFL;
crc = UPDC32(c,crc);
for(n=Rxhlen; --n >= 0; ++hdr)
{
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)
{
if(Not8bit)
report_str(masked,1);
report_str(badcrc,0);
return(ERROR);
}
#if defined(ZMODEM)
Protocol = ZMODEM;
#endif
Zmodem = 1;
return(Rxtype);
}
/* Receive a hex style header (type and position) */
zrhhdr(hdr)
char *hdr;
{
register int c;
register unsigned short crc;
register int n;
if((c = zgethex()) < 0)
return(c);
Rxtype = c;
crc = updcrc(c,0);
for(n=Rxhlen; --n >= 0; ++hdr)
{
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)
{
report_str(badcrc,0);
return(ERROR);
}
switch ( c = readline(2)) {
case 0215:
Not8bit = c;
/* **** FALL THRU TO **** */
case 015:
/* Throw away possible cr/lf */
switch (c = readline(2)) {
case 012:
Not8bit |= c;
}
}
#if defined(ZMODEM)
Protocol = ZMODEM;
#endif
Zmodem = 1;
return(Rxtype);
}
/* Send a byte as two hex digits */
zputhex(c)
register int c;
{
static char digits[] = "0123456789abcdef";
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)
{
/* Quick check for non control characters */
if(c & 0140)
xsendline(lastsent = c);
else
{
switch(c &= 0377)
{
case ZDLE:
xsendline(ZDLE);
xsendline(lastsent = (c ^= 0100));
break;
case 015:
case 0215:
if(!Zctlesc && (lastsent & 0177) != '@')
goto sendit;
/* **** FALL THRU TO **** */
case 020:
case 021:
case 023:
case 0220:
case 0221:
case 0223:
xsendline(ZDLE);
c ^= 0100;
sendit:
xsendline(lastsent = c);
break;
default:
if(Zctlesc && ! (c & 0140))
{
xsendline(ZDLE);
c ^= 0100;
}
xsendline(lastsent = c);
}
}
}
/* Decode two lower case hex digits into an 8 bit byte value */
zgethex()
{
register int c;
c = zgeth1();
return(c);
}
zgeth1()
{
register int c,n;
if((c = noxrd7()) < 0)
return(c);
n = c - '0';
if(n > 9)
n -= ('a' - ':');
if(n & ~0xF)
return(ERROR);
if((c = noxrd7()) < 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 int c;
again:
/* Quick check for non control characters */
if((c = readline(Rxtimeout)) & 0140)
return(c);
switch(c)
{
case ZDLE:
break;
case 023:
case 0223:
case 021:
case 0221:
goto again;
default:
if(Zctlesc && !(c & 0140))
{
goto again;
}
return(c);
}
again2:
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);
case 023:
case 0223:
case 021:
case 0221:
goto again2;
default:
if(Zctlesc && ! (c & 0140))
{
goto again2;
}
if((c & 0140) == 0100)
return(c ^ 0100);
break;
}
sprintf(s128,"Bad escape sequence %x",c);
report_str(s128,1);
return(ERROR);
}
/*
* Read a character from the modem line with timeout.
* Eat parity,XON and XOFF characters.
*/
noxrd7()
{
register int c;
for(;;)
{
if((c = readline(Rxtimeout)) < 0)
return(c);
switch(c &= 0177)
{
case XON:
case XOFF:
continue;
default:
if(Zctlesc && !(c & 0140))
continue;
case '\r':
case '\n':
case ZDLE:
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);
}
/*
* File: zmr.c 07-30-1989
* Copyright 1988, 1989 Omen Technology Inc All Rights Reserved
*
*
*
* This module implements ZMODEM Run Length Encoding, an
* extension that was not funded by the original Telenet
* development contract.
*
* This software may be freely used for non commercial and
* educational (didactic only) purposes. This software may also
* be freely used to support file transfer operations to or from
* licensed Omen Technology products. Any programs which use
* part or all of this software must be provided in source form
* with this notice intact except by written permission from Omen
* Technology Incorporated.
*
* Use of this software for commercial or administrative purposes
* except when exclusively limited to interfacing Omen Technology
* products requires a per port license payment of $20.00 US per
* port (less in quantity). Use of this code by inclusion,
* decompilation, reverse engineering or any other means
* constitutes agreement to these conditions and acceptance of
* liability to license the materials and payment of reasonable
* legal costs necessary to enforce this license agreement.
*
*
* Omen Technology Inc FAX: 503-621-3745
* Post Office Box 4681
* Portland OR 97208
*
* This code is made available in the hope it will be useful,
* BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
* DAMAGES OF ANY KIND.
*
* ZMODEM RLE compression and decompression functions
*/
/* Send data subpacket RLE encoded with 32 bit FCS */
zsdar32(buf, length, frameend)
char *buf;
{
register int c, l, n;
register UNSL long crc;
crc = 0xFFFFFFFFL; l = *buf++ & 0377;
if (length == 1) {
zsendline(l); crc = UPDC32(l, crc);
if (l == ZRESC) {
zsendline(1); crc = UPDC32(1, crc);
}
} else {
for (n = 0; --length >= 0; ++buf) {
if ((c = *buf & 0377) == l && n < 126 && length>0) {
++n; continue;
}
switch (n) {
case 0:
zsendline(l);
crc = UPDC32(l, crc);
if (l == ZRESC) {
zsendline(0100); crc = UPDC32(0100, crc);
}
l = c; break;
case 1:
if (l != ZRESC) {
zsendline(l); zsendline(l);
crc = UPDC32(l, crc);
crc = UPDC32(l, crc);
n = 0; l = c; break;
}
/* **** FALL THRU TO **** */
default:
zsendline(ZRESC); crc = UPDC32(ZRESC, crc);
if (l == 040 && n < 34) {
n += 036;
zsendline(n); crc = UPDC32(n, crc);
}
else {
n += 0101;
zsendline(n); crc = UPDC32(n, crc);
zsendline(l); crc = UPDC32(l, crc);
}
n = 0; l = c; break;
}
}
}
xsendline(ZDLE); xsendline(frameend);
crc = UPDC32(frameend, crc);
crc = ~crc;
for (length=4; --length >= 0;) {
zsendline((int)crc); crc >>= 8;
}
}
/* Receive data subpacket RLE encoded with 32 bit FCS */
zrdatr32(buf, length)
register char *buf;
{
register int c;
register UNSL long crc;
register char *end;
register int d;
crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length;
d = 0; /* Use for RLE decoder state */
while (buf <= end) {
if ((c = zdlread()) & ~0377) {
crcfoo:
switch (c) {
case GOTCRCE:
case GOTCRCG:
case GOTCRCQ:
case GOTCRCW:
d = c; c &= 0377;
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 ((c = zdlread()) & ~0377)
goto crcfoo;
crc = UPDC32(c, crc);
if (crc != 0xDEBB20E3) {
report_str(badcrc,0);
report_rx_ind(0);
return ERROR;
}
Rxcount = length - (end - buf);
#ifndef DSZ
sprintf(s128, "data %s %d bytes",
Zendnames[d-GOTCRCE&3], Rxcount);
report_last_rxhdr(s128,0);
report_rx_ind(0);
#endif
return d;
case GOTCAN:
report_str("Sender Cancelled",1);
report_rx_ind(0);
return ZCAN;
case TIMEOUT:
report_str("TIMEOUT",1);
report_rx_ind(0);
return c;
default:
report_str("Bad data subpacket",1);
report_rx_ind(0);
return c;
}
}
crc = UPDC32(c, crc);
switch (d) {
case 0:
if (c == ZRESC) {
d = -1; continue;
}
*buf++ = c; continue;
case -1:
if (c >= 040 && c < 0100) {
d = c - 035; c = 040; goto spaces;
}
if (c == 0100) {
d = 0;
*buf++ = ZRESC; continue;
}
d = c; continue;
default:
d -= 0100;
if (d < 1)
goto badpkt;
spaces:
if ((buf + d) > end)
goto badpkt;
while ( --d >= 0)
*buf++ = c;
d = 0; continue;
}
}
badpkt:
report_str("Data subpacket too long",1);
report_rx_ind(0);
return ERROR;
}
/* end of zmodem.c */
/* vi: set tabstop=4 shiftwidth=4: */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.