You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
983 lines
19 KiB
983 lines
19 KiB
/*
|
|
zm.c - zmodem protocol handling lowlevelstuff
|
|
Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc)
|
|
Copyright (C) 1996, 1997 Uwe Ohse
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
originally written by Chuck Forsberg
|
|
*/
|
|
/* historical comment: -- uwe
|
|
* Z M . C
|
|
* ZMODEM protocol primitives
|
|
* 05-09-88 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, bytes_received) receive data
|
|
* stohdr(pos) store position data in Txhdr
|
|
* long rclhdr(hdr) recover position offset from header
|
|
*/
|
|
|
|
|
|
#include "zglobal.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
unsigned int Rxtimeout = 100; /* Tenths of seconds to wait for something */
|
|
|
|
/* Globals used by ZMODEM functions */
|
|
int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
|
|
int Rxtype; /* Type of header received */
|
|
char Rxhdr[4]; /* Received header */
|
|
char Txhdr[4]; /* Transmitted header */
|
|
long Txpos; /* Transmitted file position */
|
|
int Txfcs32; /* TRUE means send binary frames with 32 bit FCS */
|
|
int Crc32t; /* Display flag indicating 32 bit CRC being sent */
|
|
int Crc32; /* Display flag indicating 32 bit CRC being received */
|
|
int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */
|
|
char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
|
|
|
|
static char lastsent; /* Last char we sent */
|
|
int turbo_escape;
|
|
int bytes_per_error=0;
|
|
|
|
static const 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 */
|
|
};
|
|
|
|
#define badcrc _("Bad CRC")
|
|
/* static char *badcrc = "Bad CRC"; */
|
|
static inline int noxrd7 __P ((void));
|
|
static inline int zdlread __P ((void));
|
|
static int zdlread2 __P ((int)) LRZSZ_ATTRIB_REGPARM(1);
|
|
static inline int zgeth1 __P ((void));
|
|
static void zputhex __P ((int c, char *pos));
|
|
static inline int zgethex __P ((void));
|
|
static int zrbhdr __P ((char *hdr));
|
|
static int zrbhdr32 __P ((char *hdr));
|
|
static int zrhhdr __P ((char *hdr));
|
|
static char zsendline_tab[256];
|
|
static int zrdat32 __P ((char *buf, int length, size_t *));
|
|
static void zsbh32 __P ((char *hdr, int type));
|
|
|
|
extern int zmodem_requested;
|
|
extern void xsendline(int c);
|
|
extern void send_data(int fd, char *buf, int size);
|
|
extern void flushmo(void);
|
|
|
|
/*
|
|
* Read a character from the modem line with timeout.
|
|
* Eat parity, XON and XOFF characters.
|
|
*/
|
|
static inline int
|
|
noxrd7(void)
|
|
{
|
|
register int c;
|
|
|
|
for (;;) {
|
|
if ((c = READLINE_PF(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;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
zgeth1(void)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* Decode two lower case hex digits into an 8 bit byte value */
|
|
static inline int
|
|
zgethex(void)
|
|
{
|
|
register int c;
|
|
|
|
c = zgeth1();
|
|
VPRINTF(9,("zgethex: %02X", c));
|
|
return c;
|
|
}
|
|
|
|
/*
|
|
* Read a byte, checking for ZMODEM escape encoding
|
|
* including CAN*5 which represents a quick abort
|
|
*/
|
|
static inline int
|
|
zdlread(void)
|
|
{
|
|
int c;
|
|
/* Quick check for non control characters */
|
|
if ((c = READLINE_PF(Rxtimeout)) & 0140)
|
|
return c;
|
|
return zdlread2(c);
|
|
}
|
|
/* no, i don't like gotos. -- uwe */
|
|
static int
|
|
zdlread2(int c)
|
|
{
|
|
goto jump_over; /* bad style */
|
|
|
|
again:
|
|
/* Quick check for non control characters */
|
|
if ((c = READLINE_PF(Rxtimeout)) & 0140)
|
|
return c;
|
|
jump_over:
|
|
switch (c) {
|
|
case ZDLE:
|
|
break;
|
|
case XON:
|
|
case (XON|0200):
|
|
case XOFF:
|
|
case (XOFF|0200):
|
|
goto again;
|
|
default:
|
|
if (Zctlesc && !(c & 0140)) {
|
|
goto again;
|
|
}
|
|
return c;
|
|
}
|
|
again2:
|
|
if ((c = READLINE_PF(Rxtimeout)) < 0)
|
|
return c;
|
|
if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0)
|
|
return c;
|
|
if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0)
|
|
return c;
|
|
if (c == CAN && (c = READLINE_PF(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 XON:
|
|
case (XON|0200):
|
|
case XOFF:
|
|
case (XOFF|0200):
|
|
goto again2;
|
|
default:
|
|
if (Zctlesc && ! (c & 0140)) {
|
|
goto again2;
|
|
}
|
|
if ((c & 0140) == 0100)
|
|
return (c ^ 0100);
|
|
break;
|
|
}
|
|
VPRINTF(2,(_("Bad escape sequence %x"), c));
|
|
return ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Send character c with ZMODEM escape sequence encoding.
|
|
* Escape XON, XOFF. Escape CR following @ (Telenet net escape)
|
|
*/
|
|
inline void
|
|
zsendline(int c)
|
|
{
|
|
|
|
switch(zsendline_tab[(unsigned) (c&=0377)])
|
|
{
|
|
case 0:
|
|
xsendline(lastsent = c);
|
|
break;
|
|
case 1:
|
|
xsendline(ZDLE);
|
|
c ^= 0100;
|
|
xsendline(lastsent = c);
|
|
break;
|
|
case 2:
|
|
if ((lastsent & 0177) != '@') {
|
|
xsendline(lastsent = c);
|
|
} else {
|
|
xsendline(ZDLE);
|
|
c ^= 0100;
|
|
xsendline(lastsent = c);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
zsendline_s(const char *s, size_t count)
|
|
{
|
|
const char *end=s+count;
|
|
while(s!=end) {
|
|
int last_esc=0;
|
|
const char *t=s;
|
|
while (t!=end) {
|
|
last_esc=zsendline_tab[(unsigned) ((*t) & 0377)];
|
|
if (last_esc)
|
|
break;
|
|
t++;
|
|
}
|
|
if (t!=s) {
|
|
//fwrite(s,(size_t)(t-s),1,stdout);
|
|
send_data(1, (char *)s, t-s);
|
|
lastsent=t[-1];
|
|
s=t;
|
|
}
|
|
if (last_esc) {
|
|
int c=*s;
|
|
switch(last_esc) {
|
|
case 0:
|
|
xsendline(lastsent = c);
|
|
break;
|
|
case 1:
|
|
xsendline(ZDLE);
|
|
c ^= 0100;
|
|
xsendline(lastsent = c);
|
|
break;
|
|
case 2:
|
|
if ((lastsent & 0177) != '@') {
|
|
xsendline(lastsent = c);
|
|
} else {
|
|
xsendline(ZDLE);
|
|
c ^= 0100;
|
|
xsendline(lastsent = c);
|
|
}
|
|
break;
|
|
}
|
|
s++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Send ZMODEM binary header hdr of type type */
|
|
void
|
|
zsbhdr(int type, char *hdr)
|
|
{
|
|
register int n;
|
|
register unsigned short crc;
|
|
|
|
VPRINTF(3,("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr)));
|
|
if (type == ZDATA)
|
|
for (n = Znulls; --n >=0; )
|
|
xsendline(0);
|
|
|
|
xsendline(ZPAD); xsendline(ZDLE);
|
|
|
|
Crc32t=Txfcs32;
|
|
if (Crc32t)
|
|
zsbh32(hdr, type);
|
|
else {
|
|
xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0);
|
|
|
|
for (n=4; --n >= 0; ++hdr) {
|
|
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 */
|
|
static void
|
|
zsbh32(char *hdr, int type)
|
|
{
|
|
register int n;
|
|
register unsigned long crc;
|
|
|
|
xsendline(ZBIN32); zsendline(type);
|
|
crc = 0xFFFFFFFFL; crc = UPDC32(type, crc);
|
|
|
|
for (n=4; --n >= 0; ++hdr) {
|
|
crc = UPDC32((0377 & *hdr), crc);
|
|
zsendline(*hdr);
|
|
}
|
|
crc = ~crc;
|
|
for (n=4; --n >= 0;) {
|
|
zsendline((int)crc);
|
|
crc >>= 8;
|
|
}
|
|
}
|
|
|
|
/* Send ZMODEM HEX header hdr of type type */
|
|
void
|
|
zshhdr(int type, char *hdr)
|
|
{
|
|
register int n;
|
|
register unsigned short crc;
|
|
char s[30];
|
|
size_t len;
|
|
|
|
VPRINTF(3,("zshhdr: %s %lx", frametypes[(type & 0x7f)+FTOFFSET], rclhdr(hdr)));
|
|
s[0]=ZPAD;
|
|
s[1]=ZPAD;
|
|
s[2]=ZDLE;
|
|
s[3]=ZHEX;
|
|
zputhex(type & 0x7f ,s+4);
|
|
len=6;
|
|
Crc32t = 0;
|
|
|
|
crc = updcrc((type & 0x7f), 0);
|
|
for (n=4; --n >= 0; ++hdr) {
|
|
zputhex(*hdr,s+len);
|
|
len += 2;
|
|
crc = updcrc((0377 & *hdr), crc);
|
|
}
|
|
crc = updcrc(0,updcrc(0,crc));
|
|
zputhex(crc>>8,s+len);
|
|
zputhex(crc,s+len+2);
|
|
len+=4;
|
|
|
|
/* Make it printable on remote machine */
|
|
s[len++]=015;
|
|
s[len++]=0212;
|
|
/*
|
|
* Uncork the remote in case a fake XOFF has stopped data flow
|
|
*/
|
|
if (type != ZFIN && type != ZACK)
|
|
{
|
|
s[len++]=021;
|
|
}
|
|
flushmo();
|
|
send_data(1,s,len);
|
|
}
|
|
|
|
/*
|
|
* Send binary array buf of length length, with ending ZDLE sequence frameend
|
|
*/
|
|
static const char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
|
|
void
|
|
zsdata(const char *buf, size_t length, int frameend)
|
|
{
|
|
register unsigned short crc;
|
|
|
|
VPRINTF(3,("zsdata: %lu %s", (unsigned long) length,
|
|
Zendnames[(frameend-ZCRCE)&3]));
|
|
crc = 0;
|
|
do {
|
|
zsendline(*buf); crc = updcrc((0377 & *buf), crc);
|
|
buf++;
|
|
} while (--length>0);
|
|
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();
|
|
}
|
|
}
|
|
|
|
void
|
|
zsda32(const char *buf, size_t length, int frameend)
|
|
{
|
|
int c;
|
|
unsigned long crc;
|
|
int i;
|
|
VPRINTF(3,("zsdat32: %d %s", (u32)length, Zendnames[(frameend-ZCRCE)&3]));
|
|
|
|
crc = 0xFFFFFFFFL;
|
|
zsendline_s(buf,length);
|
|
for (; length; length--) {
|
|
c = *buf & 0377;
|
|
crc = UPDC32(c, crc);
|
|
buf++;
|
|
}
|
|
xsendline(ZDLE); xsendline(frameend);
|
|
crc = UPDC32(frameend, crc);
|
|
|
|
crc = ~crc;
|
|
for (i=4; --i >= 0;) {
|
|
c=(int) crc;
|
|
if (c & 0140)
|
|
xsendline(lastsent = c);
|
|
else
|
|
zsendline(c);
|
|
crc >>= 8;
|
|
}
|
|
if (frameend == ZCRCW) {
|
|
xsendline(XON); flushmo();
|
|
}
|
|
}
|
|
|
|
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 4)
|
|
# undef DEBUG_BLOCKSIZE
|
|
#endif
|
|
|
|
#ifdef DEBUG_BLOCKSIZE
|
|
struct debug_blocksize {
|
|
int size;
|
|
long count;
|
|
};
|
|
struct debug_blocksize blocksizes[]={
|
|
{32,0},
|
|
{64,0},
|
|
{128,0},
|
|
{256,0},
|
|
{512,0},
|
|
{1024,0},
|
|
{2048,0},
|
|
{4096,0},
|
|
{8192,0},
|
|
{0,0}
|
|
};
|
|
static inline void
|
|
count_blk(int size)
|
|
{
|
|
int i;
|
|
for (i=0;blocksizes[i].size;i++) {
|
|
if (blocksizes[i].size==size) {
|
|
blocksizes[i].count++;
|
|
return;
|
|
}
|
|
}
|
|
blocksizes[i].count++;
|
|
}
|
|
|
|
static void printout_blocksizes(void) __attribute__((__destructor__));
|
|
static void
|
|
printout_blocksizes(void)
|
|
{
|
|
int i;
|
|
for (i=0;blocksizes[i].size;i++) {
|
|
if (blocksizes[i].count) {
|
|
lsyslog(LOG_DEBUG,"%4d byte: %ld blocks\n",
|
|
blocksizes[i].size,blocksizes[i].count);
|
|
}
|
|
}
|
|
if (blocksizes[i].count) {
|
|
lsyslog(LOG_DEBUG,"unk. byte: %ld blocks",
|
|
blocksizes[i].count);
|
|
}
|
|
}
|
|
#define COUNT_BLK(x) count_blk(x)
|
|
#else
|
|
#define COUNT_BLK(x)
|
|
#endif
|
|
|
|
/*
|
|
* 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!
|
|
*/
|
|
int
|
|
zrdata(char *buf, int length, size_t *bytes_received)
|
|
{
|
|
register int c;
|
|
register unsigned short crc;
|
|
register char *end;
|
|
register int d;
|
|
|
|
*bytes_received=0;
|
|
if (Rxframeind == ZBIN32)
|
|
return zrdat32(buf, length, bytes_received);
|
|
|
|
crc = 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 = updcrc(c, 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(badcrc);
|
|
return ERROR;
|
|
}
|
|
*bytes_received = length - (end - buf);
|
|
COUNT_BLK(*bytes_received);
|
|
VPRINTF(3,("zrdata: %lu %s", (unsigned long) (*bytes_received),
|
|
Zendnames[(d-GOTCRCE)&3]));
|
|
return d;
|
|
}
|
|
case GOTCAN:
|
|
zperr(_("Sender Canceled"));
|
|
return ZCAN;
|
|
case TIMEOUT:
|
|
zperr(_("TIMEOUT"));
|
|
return c;
|
|
default:
|
|
zperr(_("Bad data subpacket"));
|
|
return c;
|
|
}
|
|
}
|
|
*buf++ = c;
|
|
crc = updcrc(c, crc);
|
|
}
|
|
zperr(_("Data subpacket too long"));
|
|
return ERROR;
|
|
}
|
|
|
|
static int
|
|
zrdat32(char *buf, int length, size_t *bytes_received)
|
|
{
|
|
register int c;
|
|
register unsigned long crc;
|
|
register char *end;
|
|
register int d;
|
|
|
|
crc = 0xFFFFFFFFL; 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) {
|
|
zperr(badcrc);
|
|
return ERROR;
|
|
}
|
|
*bytes_received = length - (end - buf);
|
|
COUNT_BLK(*bytes_received);
|
|
VPRINTF(3,("zrdat32: %lu %s", (unsigned long) *bytes_received,
|
|
Zendnames[(d-GOTCRCE)&3]));
|
|
return d;
|
|
case GOTCAN:
|
|
zperr(_("Sender Canceled"));
|
|
return ZCAN;
|
|
case TIMEOUT:
|
|
zperr(_("TIMEOUT"));
|
|
return c;
|
|
default:
|
|
zperr(_("Bad data subpacket"));
|
|
return c;
|
|
}
|
|
}
|
|
*buf++ = c;
|
|
crc = UPDC32(c, crc);
|
|
}
|
|
zperr(_("Data subpacket too long"));
|
|
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.
|
|
*/
|
|
int
|
|
zgethdr(char *hdr, int eflag, size_t *Rxpos)
|
|
{
|
|
register int c, cancount;
|
|
unsigned int max_garbage; /* Max bytes before start of frame */
|
|
size_t rxpos=0; /* keep gcc happy */
|
|
|
|
max_garbage = Zrwindow + Baudrate;
|
|
Rxframeind = Rxtype = 0;
|
|
|
|
startover:
|
|
cancount = 5;
|
|
again:
|
|
/* Return immediate ERROR if ZCRCW sequence seen */
|
|
switch (c = READLINE_PF(Rxtimeout)) {
|
|
case RCDO:
|
|
case TIMEOUT:
|
|
goto fifi;
|
|
case CAN:
|
|
gotcan:
|
|
if (--cancount <= 0) {
|
|
c = ZCAN; goto fifi;
|
|
}
|
|
switch (c = READLINE_PF(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 ( --max_garbage == 0) {
|
|
zperr(_("Garbage count exceeded"));
|
|
return(ERROR);
|
|
}
|
|
//if (eflag && ((c &= 0177) & 0140) && Verbose)
|
|
// vchar(c);
|
|
//else if (eflag > 1 && Verbose)
|
|
// vchar(c);
|
|
goto startover;
|
|
case ZPAD|0200: /* This is what we want. */
|
|
case ZPAD: /* This is what we want. */
|
|
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;
|
|
}
|
|
|
|
switch (c = noxrd7()) {
|
|
case RCDO:
|
|
case TIMEOUT:
|
|
goto fifi;
|
|
case ZBIN:
|
|
Rxframeind = ZBIN; Crc32 = FALSE;
|
|
c = zrbhdr(hdr);
|
|
break;
|
|
case ZBIN32:
|
|
Crc32 = Rxframeind = ZBIN32;
|
|
c = zrbhdr32(hdr);
|
|
break;
|
|
case ZHEX:
|
|
Rxframeind = ZHEX; Crc32 = FALSE;
|
|
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:
|
|
zperr(_("Got %s"), frametypes[c+FTOFFSET]);
|
|
/* **** FALL THRU TO **** */
|
|
default:
|
|
if (c >= -3 && c <= FRTYPES)
|
|
VPRINTF(3,("zgethdr: %s %lx", frametypes[c+FTOFFSET], (unsigned long) rxpos));
|
|
else
|
|
VPRINTF(3,("zgethdr: %d %lx", c, (unsigned long) rxpos));
|
|
}
|
|
if (Rxpos)
|
|
*Rxpos=rxpos;
|
|
return c;
|
|
}
|
|
|
|
/* Receive a binary style header (type and position) */
|
|
static int
|
|
zrbhdr(char *hdr)
|
|
{
|
|
register int c, n;
|
|
register unsigned short crc;
|
|
|
|
if ((c = zdlread()) & ~0377)
|
|
return c;
|
|
Rxtype = c;
|
|
crc = updcrc(c, 0);
|
|
|
|
for (n=4; --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) {
|
|
zperr(badcrc);
|
|
return ERROR;
|
|
}
|
|
protocol = ZM_ZMODEM;
|
|
zmodem_requested=TRUE;
|
|
return Rxtype;
|
|
}
|
|
|
|
/* Receive a binary style header (type and position) with 32 bit FCS */
|
|
static int
|
|
zrbhdr32(char *hdr)
|
|
{
|
|
register int c, n;
|
|
register unsigned long crc;
|
|
|
|
if ((c = zdlread()) & ~0377)
|
|
return c;
|
|
Rxtype = c;
|
|
crc = 0xFFFFFFFFL; crc = UPDC32(c, crc);
|
|
#ifdef DEBUGZ
|
|
VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)i);
|
|
#endif
|
|
|
|
for (n=4; --n >= 0; ++hdr) {
|
|
if ((c = zdlread()) & ~0377)
|
|
return c;
|
|
crc = UPDC32(c, crc);
|
|
*hdr = c;
|
|
#ifdef DEBUGZ
|
|
VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc));
|
|
#endif
|
|
}
|
|
for (n=4; --n >= 0;) {
|
|
if ((c = zdlread()) & ~0377)
|
|
return c;
|
|
crc = UPDC32(c, crc);
|
|
#ifdef DEBUGZ
|
|
VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc));
|
|
#endif
|
|
}
|
|
if (crc != 0xDEBB20E3) {
|
|
zperr(badcrc);
|
|
return ERROR;
|
|
}
|
|
protocol = ZM_ZMODEM;
|
|
zmodem_requested=TRUE;
|
|
return Rxtype;
|
|
}
|
|
|
|
|
|
/* Receive a hex style header (type and position) */
|
|
static int
|
|
zrhhdr(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=4; --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) {
|
|
zperr(badcrc); return ERROR;
|
|
}
|
|
switch ( c = READLINE_PF(1)) {
|
|
case 0215:
|
|
/* **** FALL THRU TO **** */
|
|
case 015:
|
|
/* Throw away possible cr/lf */
|
|
READLINE_PF(1);
|
|
break;
|
|
}
|
|
protocol = ZM_ZMODEM;
|
|
zmodem_requested=TRUE;
|
|
return Rxtype;
|
|
}
|
|
|
|
/* Write a byte as two hex digits */
|
|
static void
|
|
zputhex(int c, char *pos)
|
|
{
|
|
static char digits[] = "0123456789abcdef";
|
|
|
|
VPRINTF(9,("zputhex: %02X", c));
|
|
pos[0]=digits[(c&0xF0)>>4];
|
|
pos[1]=digits[c&0x0F];
|
|
}
|
|
|
|
void
|
|
zsendline_init(void)
|
|
{
|
|
int i;
|
|
for (i=0;i<256;i++) {
|
|
if (i & 0140)
|
|
zsendline_tab[i]=0;
|
|
else {
|
|
switch(i)
|
|
{
|
|
case ZDLE:
|
|
case XOFF: /* ^Q */
|
|
case XON: /* ^S */
|
|
case (XOFF | 0200):
|
|
case (XON | 0200):
|
|
zsendline_tab[i]=1;
|
|
break;
|
|
case 020: /* ^P */
|
|
case 0220:
|
|
if (turbo_escape)
|
|
zsendline_tab[i]=0;
|
|
else
|
|
zsendline_tab[i]=1;
|
|
break;
|
|
case 015:
|
|
case 0215:
|
|
if (Zctlesc)
|
|
zsendline_tab[i]=1;
|
|
else if (!turbo_escape)
|
|
zsendline_tab[i]=2;
|
|
else
|
|
zsendline_tab[i]=0;
|
|
break;
|
|
default:
|
|
if (Zctlesc)
|
|
zsendline_tab[i]=1;
|
|
else
|
|
zsendline_tab[i]=0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Store pos in Txhdr */
|
|
void
|
|
stohdr(size_t pos)
|
|
{
|
|
long lpos=(long) pos;
|
|
Txhdr[ZP0] = lpos;
|
|
Txhdr[ZP1] = lpos>>8;
|
|
Txhdr[ZP2] = lpos>>16;
|
|
Txhdr[ZP3] = lpos>>24;
|
|
}
|
|
|
|
/* Recover a long integer from a header */
|
|
long
|
|
rclhdr(char *hdr)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* End of zm.c */
|