You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1181 lines
24 KiB
C
1181 lines
24 KiB
C
/*
|
|
* binkleyforce -- unix FTN mailer project
|
|
*
|
|
* Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
|
|
*
|
|
* 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 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "confread.h"
|
|
#include "logger.h"
|
|
#include "util.h"
|
|
#include "io.h"
|
|
#include "prot_zmodem.h"
|
|
|
|
int Z_Rxexp; /* True means timer expired */
|
|
int Z_Rxtout; /* Seconds to wait for receiving whole block */
|
|
int Z_Rxwait; /* Seconds to wait for character available */
|
|
int Z_Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */
|
|
int Z_Rxtype; /* Type of header received */
|
|
int Z_Rxcount; /* Count of data bytes received */
|
|
int Z_Txnulls; /* Number of nulls to send at beginning of ZDATA hdr */
|
|
char Z_Rxhdr[4]; /* Received header */
|
|
char Z_Txhdr[4]; /* Transmitted header */
|
|
long Z_Rxpos; /* Received file position */
|
|
int Z_Txfcs32; /* TRUE means send binary frames with 32 bit FCS */
|
|
int Z_Txcrc32; /* Display flag indicating 32 bit CRC being sent */
|
|
int Z_Rxcrc32; /* Display flag indicating 32 bit CRC being received */
|
|
char Z_Attn[ZATTNLEN+1];/* Attention string rx sends to tx on err */
|
|
int Z_Ctlesc; /* Encode control characters */
|
|
int Z_Lastsent; /* Character we sent last */
|
|
|
|
#ifdef DEBUG
|
|
static const char *FrameTypes[] =
|
|
{
|
|
"Unused", /* (-7) */
|
|
"Unused", /* (-6) */
|
|
"CRC error", /* ZCRCERR (-5) */
|
|
"Bad frame", /* ZERROR (-4) */
|
|
"I/O Error", /* ZEXIT (-3) */
|
|
"Carrier Lost", /* ZHANGUP (-2) */
|
|
"Timer out", /* ZTIMER (-1) */
|
|
#define FTOFFSET 7
|
|
"ZRQINIT",
|
|
"ZRINIT",
|
|
"ZSINIT",
|
|
"ZACK",
|
|
"ZFILE",
|
|
"ZSKIP",
|
|
"ZNAK",
|
|
"ZABORT",
|
|
"ZFIN",
|
|
"ZRPOS",
|
|
"ZDATA",
|
|
"ZEOF",
|
|
"ZFERR",
|
|
"ZCRC",
|
|
"ZCHALLENGE",
|
|
"ZCOMPL",
|
|
"ZCAN",
|
|
"ZFREECNT",
|
|
"ZCOMMAND",
|
|
"ZSTDERR",
|
|
"Unused"
|
|
#define FRTYPES 22 /* Total number of frame types in this array */
|
|
/* not including psuedo negative entries */
|
|
};
|
|
#endif
|
|
|
|
static int zrbhdr16(char *hdr);
|
|
static int zrbhdr32(char *hdr);
|
|
static int zrhhdr(char *hdr);
|
|
static int zrdat32(char *buf, int length, long pos);
|
|
static int zrdat16(char *buf, int length, long pos);
|
|
static int zgethex(void);
|
|
static int noxrd7(void);
|
|
static int zdlread(void);
|
|
static int zputhex(int c);
|
|
static void zsendline_init(char *);
|
|
|
|
static void zalarmh(int sig_no)
|
|
{
|
|
DEB((D_PROT, "zalarmh: got SIGALRM (timer expired!)"));
|
|
Z_Rxexp = 1;
|
|
}
|
|
|
|
void setalarm(int sec)
|
|
{
|
|
static int allready = 0;
|
|
|
|
if( !sec )
|
|
{
|
|
alarm(0); return;
|
|
}
|
|
|
|
Z_Rxexp = 0;
|
|
|
|
if( allready == 0 )
|
|
{
|
|
if( signal(SIGALRM, zalarmh) == SIG_ERR )
|
|
{
|
|
logerr("can't setup SIGALRM handler");
|
|
return;
|
|
}
|
|
allready = 1;
|
|
}
|
|
|
|
alarm(sec);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Read a byte, checking for ZMODEM escape encoding */
|
|
/* including five CAN which represents a quick abort */
|
|
/* ------------------------------------------------------------------------- */
|
|
static int zmodem_getbyte(void)
|
|
{
|
|
int c;
|
|
int cancount = 0;
|
|
int gotdle = 0;
|
|
|
|
while(1)
|
|
{
|
|
if( Z_Rxexp )
|
|
return ZTIMER;
|
|
|
|
if( (c = GETCHAR(Z_Rxwait)) < 0 )
|
|
return c;
|
|
|
|
if( gotdle )
|
|
{
|
|
if( c != CAN )
|
|
cancount = 0;
|
|
|
|
switch( c ) {
|
|
case CAN:
|
|
if( ++cancount > 5 )
|
|
return GOTCAN;
|
|
break;
|
|
case ZCRCE:
|
|
case ZCRCG:
|
|
case ZCRCQ:
|
|
case ZCRCW:
|
|
return c|GOTOR;
|
|
case ZRUB0:
|
|
return 0177;
|
|
case ZRUB1:
|
|
return 0377;
|
|
case XON:
|
|
case XOFF:
|
|
case XON|0200:
|
|
case XOFF|0200:
|
|
break;
|
|
default:
|
|
if( !Z_Ctlesc || (c & 140) )
|
|
{
|
|
if( (c & 0140) == 0100 )
|
|
return c^0100;
|
|
else
|
|
log("zmodem: got bad escape sequence 0x%x", c);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(c) {
|
|
case ZDLE:
|
|
gotdle = 1;
|
|
break;
|
|
case XON:
|
|
case XOFF:
|
|
case XON|0200:
|
|
case XOFF|0200:
|
|
break;
|
|
default:
|
|
if( !Z_Ctlesc || (c & 0140) )
|
|
{
|
|
return c;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int zmodem_getbyte_raw(void)
|
|
{
|
|
int c;
|
|
|
|
while(1)
|
|
{
|
|
if( Z_Rxexp )
|
|
return ZTIMER;
|
|
|
|
if( (c = GETCHAR(Z_Rxwait)) < 0 )
|
|
return c;
|
|
|
|
c &= 0177;
|
|
|
|
switch(c) {
|
|
case XON:
|
|
case XOFF:
|
|
break;
|
|
case '\r':
|
|
case '\n':
|
|
case ZDLE:
|
|
return c;
|
|
default:
|
|
if( !Z_Ctlesc || (c & 0140) )
|
|
return c;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int zmodem_putbyte(int c)
|
|
{
|
|
static int last_esc = -2;
|
|
static char tab[256];
|
|
int rc;
|
|
|
|
if( Z_Ctlesc != last_esc )
|
|
{
|
|
zsendline_init(tab);
|
|
last_esc = Z_Ctlesc;
|
|
}
|
|
|
|
switch( tab[(unsigned char)(c)] ) {
|
|
case 0:
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return rc;
|
|
break;
|
|
|
|
case 1:
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 )
|
|
return rc;
|
|
c ^= 0100;
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return rc;
|
|
break;
|
|
|
|
case 2:
|
|
/* Escape for telnet escape sequence */
|
|
if( (Z_Lastsent & 0177) != '@' )
|
|
{
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return rc;
|
|
}
|
|
else
|
|
{
|
|
c ^= 0100;
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 )
|
|
return rc;
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return rc;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT_MSG();
|
|
}
|
|
|
|
return ZOK;
|
|
}
|
|
|
|
static int zdlread(void)
|
|
{
|
|
int c, cancnt = 0;
|
|
|
|
/* Quick check for non control characters */
|
|
for(;;)
|
|
{
|
|
if( Z_Rxexp )
|
|
return(ZTIMER);
|
|
|
|
c = GETCHAR(Z_Rxwait);
|
|
|
|
if( (c & 0140) || (c < 0) )
|
|
return(c);
|
|
|
|
switch( c ) {
|
|
case ZDLE:
|
|
break;
|
|
case XON:
|
|
case XOFF:
|
|
case XON|0200:
|
|
case XOFF|0200:
|
|
continue;
|
|
default:
|
|
if( Z_Ctlesc && !(c & 0140) )
|
|
continue;
|
|
return(c);
|
|
}
|
|
break;
|
|
}
|
|
|
|
for(;;)
|
|
{
|
|
if( Z_Rxexp )
|
|
return(ZTIMER);
|
|
|
|
if( (c = GETCHAR(Z_Rxwait)) < 0 )
|
|
return(c);
|
|
|
|
if( c != CAN )
|
|
cancnt = 0;
|
|
|
|
switch( c ) {
|
|
case CAN:
|
|
if( ++cancnt >= 5 )
|
|
return(GOTCAN);
|
|
continue;
|
|
case ZCRCE:
|
|
case ZCRCG:
|
|
case ZCRCQ:
|
|
case ZCRCW:
|
|
return(c | GOTOR);
|
|
case ZRUB0:
|
|
return(0177);
|
|
case ZRUB1:
|
|
return(0377);
|
|
case XON:
|
|
case XOFF:
|
|
case XON|0200:
|
|
case XOFF|0200:
|
|
continue;
|
|
default:
|
|
if( Z_Ctlesc && !(c & 0140) )
|
|
continue;
|
|
if( (c & 0140) == 0100 )
|
|
return(c^0100);
|
|
|
|
/* It was unknown escape sequence */
|
|
DEB((D_PROT, "zdlread: bad escape sequence 0x%x", c));
|
|
|
|
return(ZERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Read a character from the modem line with timeout. */
|
|
/* Eat parity, XON and XOFF characters. */
|
|
/* ------------------------------------------------------------------------- */
|
|
static int noxrd7(void)
|
|
{
|
|
int c;
|
|
|
|
for(;;)
|
|
{
|
|
if( Z_Rxexp )
|
|
return(ZTIMER);
|
|
|
|
if( (c = GETCHAR(Z_Rxwait)) < 0 )
|
|
return(c);
|
|
|
|
switch( c &= 0177 ) {
|
|
case XON:
|
|
case XOFF:
|
|
continue;
|
|
default:
|
|
if( Z_Ctlesc && !(c & 0140) )
|
|
continue;
|
|
case '\r':
|
|
case '\n':
|
|
case ZDLE:
|
|
return(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Send character $c with ZMODEM escape sequence encoding. */
|
|
/* Escape XON, XOFF. Escape CR following @ (Telenet net escape) */
|
|
/* Warning: Put result to buffer with BUFCHAR function! Use FLUSHBUF later! */
|
|
/* ------------------------------------------------------------------------- */
|
|
int zsendline(char c)
|
|
{
|
|
static int last_esc = -2;
|
|
static char tab[256];
|
|
int rc;
|
|
|
|
if( Z_Ctlesc != last_esc )
|
|
{
|
|
zsendline_init(tab);
|
|
last_esc = Z_Ctlesc;
|
|
}
|
|
|
|
switch( tab[(unsigned char)(c)] ) {
|
|
case 0:
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return(rc);
|
|
break;
|
|
case 1:
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 )
|
|
return(rc);
|
|
c ^= 0100;
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return(rc);
|
|
break;
|
|
case 2:
|
|
/* Escape for telnet escape sequence */
|
|
if( (Z_Lastsent & 0177) != '@' )
|
|
{
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return(rc);
|
|
}
|
|
else
|
|
{
|
|
c ^= 0100;
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 )
|
|
return(rc);
|
|
if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 )
|
|
return(rc);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return(ZOK);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Send ZMODEM binary header hdr of type $type */
|
|
/* ------------------------------------------------------------------------- */
|
|
int zsbhdr(int type, char *hdr)
|
|
{
|
|
int n, rc;
|
|
unsigned short crc;
|
|
unsigned long crc32;
|
|
|
|
DEB((D_PROT, "zsbhdr: %s %lx (CRC%s)", FrameTypes[type+FTOFFSET],
|
|
rclhdr(hdr), Z_Txfcs32?"32":"16"));
|
|
|
|
if( type == ZDATA )
|
|
for( n=Z_Txnulls; --n >= 0; )
|
|
{
|
|
if( (rc = BUFCHAR('\0')) < 0 )
|
|
return(rc);
|
|
}
|
|
|
|
if( (rc = BUFCHAR(ZPAD)) < 0 )
|
|
return(rc);
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 )
|
|
return(rc);
|
|
|
|
Z_Txcrc32 = Z_Txfcs32;
|
|
|
|
if( Z_Txcrc32 )
|
|
{
|
|
/* Use CRC32 */
|
|
crc32 = 0xFFFFFFFFL;
|
|
|
|
if( (rc = BUFCHAR(ZBIN32)) < 0 )
|
|
return(rc);
|
|
if( (rc = zsendline(type)) < 0 )
|
|
return(rc);
|
|
crc32 = updcrc32(type, crc32);
|
|
|
|
for( n = 4; --n >= 0; ++hdr )
|
|
{
|
|
crc32 = updcrc32((0377 & *hdr), crc32);
|
|
if( (rc = zsendline((*hdr) & 0377)) < 0 )
|
|
return(rc);
|
|
}
|
|
|
|
crc32 = ~crc32;
|
|
|
|
for( n = 4; --n >= 0; )
|
|
{
|
|
if( (rc = zsendline(crc32 & 0377)) < 0 )
|
|
return(rc);
|
|
crc32 >>= 8;
|
|
}
|
|
}
|
|
else /* CRC-16 */
|
|
{
|
|
crc = 0;
|
|
|
|
if( (rc = BUFCHAR(ZBIN)) < 0 )
|
|
return rc;
|
|
if( (rc = zsendline(type)) < 0 )
|
|
return(rc);
|
|
crc = updcrc16(type, crc);
|
|
|
|
for( n = 4; --n >= 0; ++hdr )
|
|
{
|
|
if( (rc = zsendline((*hdr) & 0377)) < 0 )
|
|
return(rc);
|
|
crc = updcrc16(((*hdr) & 0377), crc);
|
|
}
|
|
|
|
crc = updcrc16(0,updcrc16(0,crc));
|
|
if( (rc = zsendline((crc>>8) & 0377)) < 0 )
|
|
return(rc);
|
|
if( (rc = zsendline((crc ) & 0377)) < 0 )
|
|
return(rc);
|
|
}
|
|
|
|
if( (rc = FLUSHBUF()) < 0 )
|
|
return(rc);
|
|
if( type != ZDATA && (rc = FLUSHOUT()) < 0 )
|
|
return rc;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Send ZMODEM HEX header hdr of type $type */
|
|
/* ------------------------------------------------------------------------- */
|
|
int zshhdr(int type, char *hdr)
|
|
{
|
|
int n, rc;
|
|
unsigned short crc;
|
|
|
|
DEB((D_PROT, "zshhdr: %s %lx (CRC16)",
|
|
FrameTypes[(type & 0x7f)+FTOFFSET], rclhdr(hdr)));
|
|
|
|
Z_Txcrc32 = 0;
|
|
|
|
if( (rc = BUFCHAR(ZPAD)) < 0 ) return(rc);
|
|
if( (rc = BUFCHAR(ZPAD)) < 0 ) return(rc);
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 ) return(rc);
|
|
if( (rc = BUFCHAR(ZHEX)) < 0 ) return(rc);
|
|
if( (rc = zputhex(type)) < 0 ) return(rc);
|
|
|
|
crc = updcrc16(type, 0);
|
|
for( n = 4; --n >= 0; ++hdr )
|
|
{
|
|
if( (rc = zputhex(*hdr & 0377)) < 0 )
|
|
return(rc);
|
|
crc = updcrc16((*hdr & 0377), crc);
|
|
}
|
|
|
|
crc = updcrc16(0, updcrc16(0,crc));
|
|
if( (rc = zputhex((crc>>8)&0377)) < 0 ) return(rc);
|
|
if( (rc = zputhex((crc )&0377)) < 0 ) return(rc);
|
|
|
|
/* Make it printable on remote machine */
|
|
if( (rc = BUFCHAR('\r')) < 0 ) return(rc);
|
|
if( (rc = BUFCHAR('\n')) < 0 ) return(rc);
|
|
|
|
/* Uncork the remote in case a fake XOFF has stopped data flow */
|
|
if( type != ZFIN && type != ZACK )
|
|
{
|
|
if( (rc = BUFCHAR(XON)) < 0 )
|
|
return(rc);
|
|
}
|
|
|
|
if( (rc = FLUSHBUF()) < 0 ) return(rc);
|
|
if( (rc = FLUSHOUT()) < 0 ) return(rc);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Send binary array buf of length length, with ending ZDLE sequence frameend*/
|
|
/* $pos must point to current offset of sending file (for logging only) */
|
|
/* ------------------------------------------------------------------------- */
|
|
#ifdef DEBUG
|
|
static const char *Zendnames[] = {"ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"};
|
|
#endif
|
|
|
|
int zsdata(const char *buf, int length, int frameend, long pos)
|
|
{
|
|
int n, rc;
|
|
unsigned short crc;
|
|
unsigned long crc32;
|
|
|
|
DEB((D_PROT, "zsdata: %d %s (CRC%s) from %d pos", length,
|
|
Zendnames[(frameend-ZCRCE)&3], Z_Txcrc32?"32":"16", pos));
|
|
|
|
if( Z_Txcrc32 )
|
|
{
|
|
crc32 = 0xFFFFFFFFL;
|
|
|
|
for( ; --length >= 0; ++buf )
|
|
{
|
|
if( (rc = zsendline((*buf) & 0377)) < 0 )
|
|
return(rc);
|
|
crc32 = updcrc32(((*buf) & 0377), crc32);
|
|
}
|
|
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 )
|
|
return(rc);
|
|
if( (rc = BUFCHAR(frameend)) < 0 )
|
|
return(rc);
|
|
crc32 = updcrc32(frameend, crc32);
|
|
|
|
crc32 = ~crc32;
|
|
for( n = 4; --n >= 0; )
|
|
{
|
|
if( (rc = zsendline(crc32 & 0377)) < 0 )
|
|
return(rc);
|
|
crc32 >>= 8;
|
|
}
|
|
}
|
|
else /* CRC-16 */
|
|
{
|
|
crc = 0;
|
|
for( ; --length >= 0; ++buf )
|
|
{
|
|
if( (rc = zsendline((*buf) & 0377)) < 0 )
|
|
return(rc);
|
|
crc = updcrc16((*buf & 0377), crc);
|
|
}
|
|
|
|
if( (rc = BUFCHAR(ZDLE)) < 0 )
|
|
return(rc);
|
|
if( (rc = BUFCHAR(frameend)) < 0 )
|
|
return(rc);
|
|
crc = updcrc16(frameend, crc);
|
|
|
|
crc = updcrc16(0, updcrc16(0, crc));
|
|
if( (rc = zsendline((crc>>8) & 0377)) < 0
|
|
|| (rc = zsendline((crc ) & 0377)) < 0 )
|
|
return(rc);
|
|
}
|
|
|
|
if( (rc = FLUSHBUF()) < 0 )
|
|
return(rc);
|
|
|
|
if( frameend == ZCRCW )
|
|
{
|
|
if( (rc = PUTCHAR(XON)) < 0 )
|
|
return(rc);
|
|
if( (rc = FLUSHOUT()) < 0 )
|
|
return(rc);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Receive array buf of max length+1 with ending ZDLE sequence */
|
|
/* and CRC. Returns the ending character or error code. */
|
|
/* $pos must contatain current offset of receiving file (for logging only!) */
|
|
/* ------------------------------------------------------------------------- */
|
|
int zrdata(char *buf, int length, long pos)
|
|
{
|
|
return (Z_Rxframeind == ZBIN32) ? zrdat32(buf, length, pos)
|
|
: zrdat16(buf, length, pos);
|
|
}
|
|
|
|
static int zrdat16(char *buf, int length, long pos)
|
|
{
|
|
int c;
|
|
unsigned short crc;
|
|
char *end;
|
|
int d;
|
|
|
|
Z_Rxcount = 0;
|
|
crc = 0;
|
|
end = buf + length;
|
|
|
|
while( buf <= end )
|
|
{
|
|
if( (c=zdlread()) & ~0377 )
|
|
{
|
|
switch_again:
|
|
switch( c ) {
|
|
case GOTCRCE:
|
|
case GOTCRCG:
|
|
case GOTCRCQ:
|
|
case GOTCRCW:
|
|
d = c;
|
|
c &= 0377;
|
|
crc = updcrc16(c, crc);
|
|
|
|
if( (c=zdlread()) & ~0377 ) goto switch_again;
|
|
crc = updcrc16(c, crc);
|
|
|
|
if( (c=zdlread()) & ~0377 ) goto switch_again;
|
|
crc = updcrc16(c, crc);
|
|
|
|
Z_Rxcount = length - (end - buf);
|
|
|
|
if( crc & 0xFFFF )
|
|
{
|
|
DEB((D_PROT, "zrdat16: %d %s : Bad CRC",
|
|
Z_Rxcount, Zendnames[(d-GOTCRCE)&3]));;
|
|
log("ZDATA with bad CRC");
|
|
|
|
return ZCRCERR;
|
|
}
|
|
|
|
DEB((D_PROT, "zrdat16: %d %s (CRC16) at %d pos",
|
|
Z_Rxcount, Zendnames[(d-GOTCRCE)&3], pos));
|
|
|
|
return d;
|
|
|
|
case GOTCAN:
|
|
DEB((D_PROT, "zrdat16: Sender CANceled"));
|
|
return ZCAN;
|
|
|
|
case ZHANGUP:
|
|
case ZTIMER:
|
|
case ZEXIT:
|
|
DEB((D_PROT, "zrdat16: zdlread() return %s",
|
|
( c == ZHANGUP ) ? "ZHANGUP":
|
|
( c == ZEXIT ) ? "ZEXIT":
|
|
( c == ZTIMER ) ? "ZTIMER" : "Unknown"));
|
|
return c;
|
|
|
|
default:
|
|
DEB((D_PROT, "zrdat16: $zdlread return %d", c));
|
|
return c;
|
|
}
|
|
}
|
|
*buf++ = c;
|
|
crc = updcrc16(c, crc);
|
|
}
|
|
|
|
log("zmodem: data packet too long");
|
|
DEB((D_PROT, "zrdat16: data packet too long"));
|
|
|
|
return ZERROR;
|
|
}
|
|
|
|
static int zrdat32(char *buf, int length, long pos)
|
|
{
|
|
int c, d;
|
|
unsigned long crc;
|
|
char *end;
|
|
|
|
Z_Rxcount = 0;
|
|
crc = 0xFFFFFFFFL;
|
|
end = buf + length;
|
|
|
|
while( buf <= end )
|
|
{
|
|
if( (c = zdlread()) & ~0377 )
|
|
{
|
|
switch_again:
|
|
switch( c ) {
|
|
case GOTCRCE:
|
|
case GOTCRCG:
|
|
case GOTCRCQ:
|
|
case GOTCRCW:
|
|
d = c;
|
|
c &= 0377;
|
|
crc = updcrc32(c, crc);
|
|
if( (c = zdlread()) & ~0377 ) goto switch_again;
|
|
crc = updcrc32(c, crc);
|
|
|
|
if( (c = zdlread()) & ~0377 ) goto switch_again;
|
|
crc = updcrc32(c, crc);
|
|
|
|
if( (c = zdlread()) & ~0377 ) goto switch_again;
|
|
crc = updcrc32(c, crc);
|
|
|
|
if( (c = zdlread()) & ~0377 ) goto switch_again;
|
|
crc = updcrc32(c, crc);
|
|
|
|
Z_Rxcount = length - (end - buf);
|
|
|
|
if( crc != 0xDEBB20E3 )
|
|
{
|
|
DEB((D_PROT, "zrdat32: %d %s : Bad CRC",
|
|
Z_Rxcount, Zendnames[(d-GOTCRCE)&3]));
|
|
log("DATA with bad CRC");
|
|
|
|
return ZCRCERR;
|
|
}
|
|
|
|
DEB((D_PROT, "zrdat32: %d %s (CRC32) at %d pos",
|
|
Z_Rxcount, Zendnames[(d-GOTCRCE)&3], pos));
|
|
|
|
return d;
|
|
|
|
case GOTCAN:
|
|
DEB((D_PROT, "zrdat32: Sender CANceled"));
|
|
return ZCAN;
|
|
|
|
case ZEXIT:
|
|
case ZTIMER:
|
|
case ZHANGUP:
|
|
DEB((D_PROT, "zrdat32: zdlread() return %s",
|
|
( c == ZHANGUP ) ? "ZHANGUP":
|
|
( c == ZEXIT ) ? "ZEXIT":
|
|
( c == ZTIMER ) ? "ZTIMER" : "Unknown"));
|
|
return c;
|
|
|
|
default:
|
|
DEB((D_PROT, "zrdat32: $zdlread return %d", c));
|
|
return c;
|
|
}
|
|
}
|
|
*buf++ = c;
|
|
crc = updcrc32(c, crc);
|
|
}
|
|
|
|
log("zmodem: data packet too long");
|
|
DEB((D_PROT, "zrdat32: data packet too long"));
|
|
|
|
return ZERROR;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Read a ZMODEM header to hdr, either binary or hex. */
|
|
/* On success, set Z_Rxpos and return type of header. */
|
|
/* Otherwise return negative on error. */
|
|
/* Return ZERROR instantly if ZCRCW sequence, for fast error recovery. */
|
|
/* ------------------------------------------------------------------------- */
|
|
int zgethdr(char *hdr)
|
|
{
|
|
int c, n, cancount;
|
|
|
|
n = 8192; /* Maximum number of garbage chars */
|
|
cancount = 5; /* CANcel on this can number */
|
|
|
|
Z_Rxframeind = 0;
|
|
Z_Rxtype = 0;
|
|
|
|
again:
|
|
if( Z_Rxexp ) { c = ZTIMER; goto fifi; }
|
|
|
|
switch( c = GETCHAR(Z_Rxwait) ) {
|
|
case ZEXIT:
|
|
case ZHANGUP:
|
|
case ZTIMER:
|
|
goto fifi;
|
|
case CAN:
|
|
gotcan:
|
|
if( --cancount == 0 )
|
|
{
|
|
c = ZCAN; goto fifi;
|
|
}
|
|
|
|
if( Z_Rxexp ) { c = ZTIMER; goto fifi; }
|
|
|
|
switch( c = GETCHAR(Z_Rxwait) ) {
|
|
case ZCRCW:
|
|
/* Return immediate ERROR if ZCRCW sequence seen */
|
|
c = ZERROR;
|
|
case ZEXIT:
|
|
case ZHANGUP:
|
|
case ZTIMER:
|
|
goto fifi;
|
|
default:
|
|
break;
|
|
case CAN:
|
|
if( --cancount == 0 )
|
|
{
|
|
c = ZCAN; goto fifi;
|
|
}
|
|
goto again;
|
|
}
|
|
default:
|
|
if( --n == 0 ) {
|
|
DEB((D_PROT, "zgethdr: garbage count exceeded"));
|
|
c = ZERROR; goto fifi;
|
|
}
|
|
cancount = 5;
|
|
goto again;
|
|
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 ZEXIT:
|
|
case ZHANGUP:
|
|
case ZTIMER:
|
|
goto fifi;
|
|
default:
|
|
if( --n == 0 ) {
|
|
DEB((D_PROT, "zgethdr: garbage count exceeded"));
|
|
c = ZERROR; goto fifi;
|
|
}
|
|
goto again;
|
|
case ZDLE: /* This is what we want. */
|
|
break;
|
|
}
|
|
|
|
switch( c=noxrd7() ) {
|
|
case ZEXIT:
|
|
case ZHANGUP:
|
|
case ZTIMER:
|
|
goto fifi;
|
|
case ZBIN:
|
|
/* receive binary header with crc16 */
|
|
Z_Rxcrc32 = 0;
|
|
Z_Rxframeind = ZBIN;
|
|
c = zrbhdr16(hdr);
|
|
break;
|
|
case ZBIN32:
|
|
/* receive binary header with crc32 */
|
|
Z_Rxcrc32 = 1;
|
|
Z_Rxframeind = ZBIN32;
|
|
c = zrbhdr32(hdr);
|
|
break;
|
|
case ZHEX:
|
|
/* receive hex header (all hex headers have crc16) */
|
|
Z_Rxcrc32 = 0;
|
|
Z_Rxframeind = ZHEX;
|
|
c = zrhhdr(hdr);
|
|
break;
|
|
case CAN:
|
|
goto gotcan;
|
|
default:
|
|
if( --n == 0 ) {
|
|
DEB((D_PROT, "zgethdr: garbage count exceeded"));
|
|
c = ZERROR; goto fifi;
|
|
}
|
|
goto again;
|
|
}
|
|
|
|
if( c >= 0 )
|
|
{
|
|
Z_Rxpos = hdr[ZP3] & 0377;
|
|
Z_Rxpos = (Z_Rxpos<<8) + (hdr[ZP2] & 0377);
|
|
Z_Rxpos = (Z_Rxpos<<8) + (hdr[ZP1] & 0377);
|
|
Z_Rxpos = (Z_Rxpos<<8) + (hdr[ZP0] & 0377);
|
|
}
|
|
|
|
fifi:
|
|
if( c == GOTCAN )
|
|
c = ZCAN;
|
|
|
|
#ifdef DEBUG
|
|
if( (c >= -7) && (c <= FRTYPES) )
|
|
DEB((D_PROT, "zgethdr: %s %lx", FrameTypes[c+FTOFFSET], Z_Rxpos));
|
|
else
|
|
DEB((D_PROT, "zgethdr: %d %lx", c, Z_Rxpos));
|
|
#endif
|
|
|
|
return(c);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Receive a binary style header (type and position) */
|
|
/* ------------------------------------------------------------------------- */
|
|
static int zrbhdr16(char *hdr)
|
|
{
|
|
int c, n;
|
|
unsigned short crc;
|
|
|
|
if( (c = zdlread()) < 0 )
|
|
return(c);
|
|
Z_Rxtype = c;
|
|
crc = updcrc16(c, 0);
|
|
|
|
for( n = 4; --n >= 0; ++hdr )
|
|
{
|
|
if( (c = zdlread()) < 0 )
|
|
return(c);
|
|
crc = updcrc16(c, crc);
|
|
*hdr = c;
|
|
}
|
|
|
|
if( (c = zdlread()) < 0 )
|
|
return(c);
|
|
crc = updcrc16(c, crc);
|
|
|
|
if( (c = zdlread()) < 0 )
|
|
return(c);
|
|
crc = updcrc16(c, crc);
|
|
|
|
if( crc & 0xFFFF )
|
|
{
|
|
DEB((D_PROT, "zrbhdr: Bad CRC"));
|
|
log("Bad CRC");
|
|
return(ZCRCERR);
|
|
}
|
|
|
|
return(Z_Rxtype);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Receive a binary style header (type and position) with 32 bit FCS */
|
|
/* ------------------------------------------------------------------------- */
|
|
static int zrbhdr32(char *hdr)
|
|
{
|
|
int c, n;
|
|
unsigned long crc;
|
|
|
|
if( (c = zdlread()) < 0 )
|
|
return c;
|
|
Z_Rxtype = c;
|
|
crc = 0xFFFFFFFFL;
|
|
crc = updcrc32(c, crc);
|
|
|
|
for( n = 4; --n >= 0; ++hdr )
|
|
{
|
|
if( (c = zdlread()) < 0 )
|
|
return(c);
|
|
crc = updcrc32(c, crc);
|
|
*hdr = c;
|
|
}
|
|
|
|
for( n = 4; --n >= 0; )
|
|
{
|
|
if( (c = zdlread()) < 0 )
|
|
return(c);
|
|
crc = updcrc32(c, crc);
|
|
}
|
|
|
|
if( crc != 0xDEBB20E3 )
|
|
{
|
|
DEB((D_PROT, "zrbhdr32: Bad CRC"));
|
|
log("Bad CRC");
|
|
return(ZCRCERR);
|
|
}
|
|
|
|
return(Z_Rxtype);
|
|
}
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Receive a hex style header (type and position) */
|
|
/* ------------------------------------------------------------------------- */
|
|
static int zrhhdr(char *hdr)
|
|
{
|
|
int c, n;
|
|
unsigned short crc;
|
|
|
|
if( (c = zgethex()) < 0 )
|
|
return(c);
|
|
Z_Rxtype = c; crc = updcrc16(c, 0);
|
|
|
|
for( n = 4; --n >= 0; )
|
|
{
|
|
if( (c = zgethex()) < 0 )
|
|
return(c);
|
|
crc = updcrc16(c, crc);
|
|
*hdr++ = c;
|
|
}
|
|
|
|
if( (c = zgethex()) < 0 )
|
|
return(c);
|
|
crc = updcrc16(c, crc);
|
|
|
|
if( (c = zgethex()) < 0 )
|
|
return(c);
|
|
crc = updcrc16(c, crc);
|
|
|
|
if( crc & 0xFFFF )
|
|
{
|
|
DEB((D_PROT, "zrhhdr: Bad CRC"));
|
|
log("Bad CRC");
|
|
return(ZCRCERR);
|
|
}
|
|
|
|
if( CHARWAIT(0) )
|
|
{
|
|
/* There is some characters available.. */
|
|
|
|
switch( (c = GETCHAR(1)) ) {
|
|
case 0215:
|
|
case 015:
|
|
/* Throw away possible cr/lf */
|
|
if( (c = GETCHAR(1)) < 0 && c != ZTIMER )
|
|
return(c);
|
|
break;
|
|
case ZEXIT:
|
|
case ZHANGUP:
|
|
return(c);
|
|
}
|
|
}
|
|
|
|
return(Z_Rxtype);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Write a byte as two hex digits */
|
|
/* ------------------------------------------------------------------------- */
|
|
static int zputhex(int c)
|
|
{
|
|
static char digits[] = "0123456789abcdef";
|
|
int rc;
|
|
|
|
if( (rc = BUFCHAR(digits[(c&0xF0)>>4])) < 0
|
|
|| (rc = BUFCHAR(digits[(c&0x0F) ])) < 0 )
|
|
return rc;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Init an array of 256 entries, mark codes we must escape with value > 0 */
|
|
/* ------------------------------------------------------------------------- */
|
|
static void zsendline_init(char *tab)
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < 256; i++ )
|
|
{
|
|
if( i & 0140 )
|
|
tab[i] = 0;
|
|
else
|
|
{
|
|
switch( i ) {
|
|
case ZDLE:
|
|
case XOFF: /* ^Q */
|
|
case XON: /* ^S */
|
|
case 020: /* ^P */
|
|
case (XOFF | 0200):
|
|
case (XON | 0200):
|
|
case (020 | 0200):
|
|
tab[i] = 1;
|
|
break;
|
|
case 015:
|
|
case (015 | 0200):
|
|
if( Z_Ctlesc )
|
|
tab[i] = 1;
|
|
else
|
|
tab[i] = 2;
|
|
break;
|
|
default:
|
|
if( Z_Ctlesc )
|
|
tab[i] = 1;
|
|
else
|
|
tab[i] = 0;
|
|
}
|
|
} /* end of if */
|
|
} /* end of for */
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Decode two lower case hex digits into an 8 bit byte value */
|
|
/* ------------------------------------------------------------------------- */
|
|
static int zgethex(void)
|
|
{
|
|
int c, n;
|
|
|
|
if( (c = noxrd7()) < 0 )
|
|
return(c);
|
|
|
|
n = c - '0';
|
|
if( n > 9 ) n -= ('a' - ':');
|
|
|
|
if( n & ~0xF )
|
|
return(ZERROR);
|
|
if( (c = noxrd7()) < 0 )
|
|
return(c);
|
|
|
|
c -= '0';
|
|
if( c > 9 ) c -= ('a' - ':');
|
|
if( c & ~0xF )
|
|
return(ZERROR);
|
|
|
|
c += (n<<4);
|
|
|
|
return(c);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Store long integer pos in hdr */
|
|
/* ------------------------------------------------------------------------- */
|
|
void stohdr(char *hdr, long pos)
|
|
{
|
|
hdr[ZP0] = (pos ) & 0377;
|
|
hdr[ZP1] = (pos>>8 ) & 0377;
|
|
hdr[ZP2] = (pos>>16) & 0377;
|
|
hdr[ZP3] = (pos>>24) & 0377;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* Recover a long integer from a header */
|
|
/* ------------------------------------------------------------------------- */
|
|
long rclhdr(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);
|
|
}
|