Zmodem protocol changes

This commit is contained in:
Michiel Broek 2006-03-18 18:32:22 +00:00
parent de58423731
commit 9d82aca2c3
5 changed files with 218 additions and 140 deletions

View File

@ -52,7 +52,7 @@ struct tchars oldtch, tch;
#endif
int hanged_up = 0;
unsigned Baudrate = 2400;
unsigned Baudrate = 9600; /* Default, set by first io_mode() call */
int current_mode = -1;
@ -188,26 +188,29 @@ int io_mode(int fd, int n)
#ifdef USE_TERMIOS
case 2:
if (!did0) {
did0 = TRUE;
tcgetattr(fd,&oldtty);
}
tty = oldtty;
tty.c_iflag = 0; /* Transparant input */
tty.c_oflag = 0; /* Transparent output */
tty.c_cflag &= ~( CSIZE | CSTOPB | PARENB | PARODD); /* Disable parity and all character sizes */
tty.c_cflag |= CS8 | CREAD | HUPCL | CLOCAL;
tty.c_lflag = 0;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
tty.c_iflag = BRKINT | IXON;
tty.c_oflag = 0; /* Transparent output */
tty.c_cflag &= ~( CSIZE | PARENB ); /* Disable parity and all character sizes */
tty.c_cflag |= CS8 | CREAD;
tty.c_lflag = (protocol == ZM_ZMODEM) ? 0 : ISIG;
tty.c_cc[VINTR] = (protocol == ZM_ZMODEM) ? -1:030; /* Interrupt char */
tty.c_cc[VQUIT] = -1; /* Quit char */
tty.c_cc[VMIN] = 3; /* This many chars satisfies reads */
tty.c_cc[VTIME] = 1;
tcsetattr(fd,TCSADRAIN,&tty);
did0 = TRUE;
Baudrate = getspeed(cfgetospeed(&tty));
Syslog('t', "Baudrate = %d", Baudrate);
return 0;
case 1:
case 3:
if (!did0) {
did0 = TRUE;
tcgetattr(fd,&oldtty);
#ifdef __linux__
Syslog('t', "iflag%s%s%s%s%s%s%s%s%s%s%s%s%s",
@ -313,37 +316,37 @@ int io_mode(int fd, int n)
(oldtty.c_lflag & NOFLSH) ? " NOFLSH":"");
#endif
}
tty = oldtty;
tty.c_iflag = IGNBRK;
if (n == 3) { /* with flow control */
tty.c_iflag |= IXOFF; /* Enable XON/XOFF flow control on input */
tty.c_cflag |= CRTSCTS; /* hardware flowcontrol */
}
tty.c_iflag = n==3 ? (IXON|IXOFF) : IXOFF;
/*
* Setup raw mode: no echo, noncanonical (no edit chars),
* no signal generating chars, and no extended chars (^V,
* ^O, ^R, ^W).
*/
tty.c_lflag = 0; /* Transparant input */
tty.c_oflag = 0; /* Transparent output */
tty.c_cflag &= ~( CSIZE | CSTOPB | PARENB | PARODD); /* Same baud rate, disable parity */
tty.c_cflag |= CS8 | CREAD | HUPCL | CLOCAL;
tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */
tty.c_cc[VTIME] = 0;
tty.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN);
// tty.c_lflag = 0; /* Transparant input */
tty.c_oflag = 0; /* Transparent output */
tty.c_cflag &= ~( CSIZE | PARENB ); /* Same baud rate, disable parity */
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 2; /* This many chars satisfies reads */
tty.c_cc[VTIME] = 1;
tcsetattr(fd,TCSADRAIN,&tty);
Baudrate = getspeed(cfgetospeed(&tty));
Syslog('t', "Baudrate = %d", Baudrate);
did0 = TRUE;
return 0;
case 0:
if (!did0)
return -1;
tcdrain (fd); /* wait until everything is sent */
tcflush (fd,TCIOFLUSH); /* flush input queue */
tcsetattr (fd,TCSADRAIN,&oldtty);
tcflow (fd,TCOON); /* restart output */
tcdrain (fd); /* wait until everything is sent */
tcflush (fd,TCIOFLUSH); /* flush input queue */
tcsetattr (fd,TCSADRAIN,&oldtty); /* Restore */
tcflow (fd,TCOON); /* restart output */
return 0;
#endif
@ -383,7 +386,7 @@ void sendbrk(void)
if (isatty(0)) {
#ifdef USE_TERMIOS
tcsendbreak(0, 0);
tcsendbreak(0, 200);
#endif
#ifdef USE_TERMIO
ioctl(0, TCSBRK, 0);

View File

@ -77,7 +77,6 @@ int Rxtimeout = 10; /* Seconds to wait for something, receiver */
char *txbuf=NULL;
static int lastsent; /* Last char we sent */
static int Not8bit; /* Seven bits seen on header */
static char zsendline_tab[256];
extern unsigned Baudrate;
extern int zmodem_requested;
@ -200,6 +199,9 @@ void zsbhdr(int type, char *shdr)
}
BUFFER_FLUSH();
if (type != ZDATA)
fflush(stdout);
}
@ -272,6 +274,7 @@ void zshhdr(int type, char *shdr)
BUFFER_BYTE(021);
BUFFER_FLUSH();
fflush(stdout);
}
@ -308,6 +311,9 @@ void zsdata(register char *buf, int length, int frameend)
BUFFER_BYTE(XON);
BUFFER_FLUSH();
if (frameend != ZCRCG)
fflush(stdout);
}
@ -322,10 +328,7 @@ void zsda32(register char *buf, int length, int frameend)
crc = 0xFFFFFFFFL;
for (;--length >= 0; ++buf) {
c = *buf & 0377;
if (c & 0140)
BUFFER_BYTE(lastsent = c);
else
zsendline(c);
zsendline(c);
crc = updcrc32(c, crc);
}
BUFFER_BYTE(ZDLE);
@ -476,7 +479,7 @@ void garbitch(void)
int zgethdr(char *shdr)
{
register int c, n, cancount, tmcount;
int Zrwindow = 1024;
int Zrwindow = 1400;
n = Zrwindow + Baudrate;
Rxframeind = Rxtype = 0;
@ -488,10 +491,11 @@ again:
/*
* Return immediate ERROR if ZCRCW sequence seen
*/
if (((c = GETCHAR(Rxtimeout)) < 0) && (c != TIMEOUT))
goto fifi;
else {
switch(c) {
// if (((c = GETCHAR(Rxtimeout)) < 0) && (c != TIMEOUT))
// goto fifi;
// else {
// switch(c) {
switch (c = GETCHAR(Rxtimeout)) {
case 021:
case 0221: goto again;
case HANGUP: goto fifi;
@ -539,7 +543,7 @@ agn2:
case ZPAD: /* This is what we want. */
break;
}
}
// }
cancount = 5;
splat:
@ -566,7 +570,8 @@ splat:
c = zrhhdr(shdr);
break;
case CAN: goto gotcan;
default: goto agn2;
default: Syslog('z', "Zmodem: zgethdr got %d char", c);
goto agn2;
}
for (n = 4; ++n < ZMAXHLEN; ) /* Clear unused hdr bytes */
@ -739,68 +744,36 @@ void zputhex(int c)
*/
void zsendline(int c)
{
switch(zsendline_tab[(unsigned) (c&=0377)]) {
case 0: BUFFER_BYTE(lastsent = c);
break;
case 1: BUFFER_BYTE(ZDLE);
c ^= 0100;
BUFFER_BYTE(lastsent = c);
break;
case 2: if ((lastsent & 0177) != '@') {
switch (c &= 0377) {
case 0377:
lastsent = c;
if (Zctlesc || Zsendmask[32]) {
BUFFER_BYTE(ZDLE); c = ZRUB1;
}
BUFFER_BYTE(c);
break;
case ZDLE:
BUFFER_BYTE(ZDLE);
BUFFER_BYTE(lastsent = (c ^= 0100));
break;
case 021:
case 023:
case 0221:
case 0223:
BUFFER_BYTE(ZDLE);
c ^= 0100;
BUFFER_BYTE(lastsent = c);
} else {
BUFFER_BYTE(ZDLE);
c ^= 0100;
break;
default:
if (((c & 0140) == 0) && (Zctlesc || Zsendmask[c & 037])) {
BUFFER_BYTE(ZDLE); c ^= 0100;
}
BUFFER_BYTE(lastsent = c);
}
break;
}
}
void zsendline_init(void)
{
int i;
Syslog('z', "zsendline_init() Zctlesc=%d", Zctlesc);
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:
zsendline_tab[i]=1;
break;
case 015:
case 0215:
if (Zctlesc)
zsendline_tab[i]=1;
else
zsendline_tab[i]=2;
break;
default:
if (Zctlesc)
zsendline_tab[i]=1;
else
zsendline_tab[i]=0;
}
}
}
// zsendline_tab[255] = 1; /* IAC */
}
/* Decode two lower case hex digits into an 8 bit byte value */
int zgethex(void)
{

View File

@ -22,7 +22,14 @@
#define ZBIN 'A' /* Binary frame indicator (CRC-16) */
#define ZHEX 'B' /* HEX frame indicator */
#define ZBIN32 'C' /* Binary frame with 32 bit FCS */
#define ZBINR32 'D' /* RLE packed Binary frame with 32 bit FCS */
#define ZVBIN 'a' /* Binary frame indicator (CRC-16) */
#define ZVHEX 'b' /* HEX frame indicator */
#define ZVBIN32 'c' /* Binary frame with 32 bit FCS */
#define ZVBINR32 'd' /* RLE packed Binary frame with 32 bit FCS */
#define ZRESC 0176 /* RLE flag/escape character */
#define ZMAXHLEN 16 /* Max header information length NEVER CHANGE */
#define ZMAXSPLEN 1024 /* Max subpacket length NEVER CHANGE */
/* Frame types (see array "frametypes" in zm.c) */
@ -75,19 +82,28 @@
#define ZP3 3 /* High order 8 bits of file position */
/* Parameters for ZRINIT header */
#define ZRPXWN 8 /* 9th byte in header contains window size/256 */
#define ZRPXQQ 9 /* 10th to 14th bytes contain quote mask */
/* 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 CANRLE 010 /* Receiver can decode RLE */
#define CANLZW 020 /* Receiver can uncompress */
#define CANFC32 040 /* Receiver can use 32 bit Frame Check */
#define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */
#define ESC8 0200 /* Receiver expects 8th bit to be escaped */
/* Bit Masks for ZRINIT flags byte ZF1 */
#define CANVHDR 01 /* Variable headers OK */
#define ZRRQWN 8 /* Receiver specified window size in ZRPXWN */
#define ZRRQQQ 16 /* Additional control chars to quote in ZRPXQQ */
#define ZRQNVH (ZRRQWN|ZRRQQQ) /* Variable len hdr reqd to access info */
/* Parameters for ZSINIT frame */
#define ZATTNLEN 32 /* Max length of attention string */
#define ALTCOFF ZF1 /* Offset to alternate canit string, 0 if not used */
/* Bit Masks for ZSINIT flags byte ZF0 */
#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */
#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */
@ -115,7 +131,9 @@
#define ZTRLE 3 /* Run Length encoding */
/* Extended options for ZF3, bit encoded */
#define ZXSPARS 64 /* Encoding for sparse file operations */
#define ZCANVHDR 01 /* Variable headers OK */
/* Receiver window size override */
#define ZRWOVR 4 /* byte position for receive window override/256 */
/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */
#define ZCACK1 1 /* Acknowledge, then do command */
@ -134,7 +152,7 @@ char Rxhdr[ZMAXHLEN]; /* Received header */
char Txhdr[ZMAXHLEN]; /* Transmitted header */
char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */
char *Altcan; /* Alternate canit string */
//char Zsendmask[33]; /* Additional control characters to mask */
char Zsendmask[33]; /* Additional control characters to mask */
int Zctlesc;
enum zm_type_enum {
@ -159,7 +177,6 @@ int zdlread(void);
void stohdr(int);
int rclhdr(register char *);
char *protname(void);
void zsendline_init(void);
void purgeline(int);
void canit(int);

View File

@ -88,7 +88,6 @@ int zmrcvfiles(int want1k, int wantg)
Syslog('+', "%s: start receive", protname());
get_frame_buffer();
zsendline_init();
Rxtimeout = 10;
if (secbuf == NULL)

View File

@ -47,6 +47,7 @@ static int zfilbuf(void);
static int zsendfile(char*,int);
static int zsendfdata(void);
static int getinsync(int);
void initzsendmsk(char *p);
static FILE *in;
static int Eofseen; /* EOF seen on input set by zfilbuf */
@ -61,14 +62,23 @@ static int blkopt; /* Override value for zmodem blklen */
static int errors;
static int Lastsync;
static int bytcnt;
static int maxbytcnt;
static int Lrxpos=0;
static int Lztrans=0;
static int Lzmanag=0;
static int Lskipnocor=0;
static int Lzconv=0;
static int Beenhereb4;
static char Myattn[]={0};
static int Canseek = 1; /* 1: Can seek 0: only rewind -1: neither (pipe) */
/*
* 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.
*/
static char Myattn[]={ 0 };
static int skipsize;
static jmp_buf intrjmp; /* For the interrupt on RX CAN */
struct timeval starttime, endtime;
struct timezone tz;
static int use8k = FALSE;
@ -81,6 +91,16 @@ extern char *frametypes[];
extern unsigned Baudrate;
/* Called when ZMODEM gets an interrupt (^X) */
void onintr(int );
void onintr(int c)
{
signal(SIGINT, SIG_IGN);
Syslog('z', "Zmodem: got signal interrupt");
longjmp(intrjmp, -1);
}
int zmsndfiles(down_list *lst, int try8)
{
int rc, maxrc = 0;
@ -89,12 +109,12 @@ int zmsndfiles(down_list *lst, int try8)
Syslog('+', "Zmodem: start Zmodem%s send", try8 ? "-8K":"");
get_frame_buffer();
zsendline_init();
use8k = try8;
protocol = ZM_ZMODEM;
Rxtimeout = 60;
bytcnt = maxbytcnt = -1;
if ((rc = initsend())) {
if (txbuf)
free(txbuf);
@ -132,7 +152,7 @@ int zmsndfiles(down_list *lst, int try8)
free(txbuf);
txbuf = NULL;
del_frame_buffer();
// io_mode(0, 1);
io_mode(0, 1);
Syslog('z', "Zmodem: send rc=%d", maxrc);
return (maxrc < 2)?0:maxrc;
@ -144,7 +164,7 @@ static int initsend(void)
{
Syslog('z', "Zmodem: initsend");
// io_mode(0, 1);
io_mode(0, 1);
PUTSTR((char *)"rz\r");
stohdr(0L);
zshhdr(ZRQINIT, Txhdr);
@ -266,19 +286,19 @@ int getzrxinit(void)
case ZRINIT:
Rxflags = 0377 & Rxhdr[ZF0];
Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
{
int old = Zctlesc;
Zctlesc |= Rxflags & TESCCTL;
/* update table - was initialised to not escape */
if (Zctlesc && !old)
zsendline_init();
Zctlesc |= Rxflags & TESCCTL;
if (Rxhdr[ZF1] & ZRRQQQ) { /* Escape ctrls */
initzsendmsk(Rxhdr + ZRPXQQ);
Syslog('z', "Zmodem: requested ZRPXQQ");
}
Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
if ( !(Rxflags & CANFDX))
Txwindow = 0;
Syslog('z', "Zmodem: Remote allowed Rxbuflen=%d", Rxbuflen);
// io_mode(0, 2); /* Set cbreak, XON/XOFF, etc. */
Syslog('z', "Zmodem: Rxbuflen=%d", Rxbuflen);
signal(SIGINT, SIG_IGN);
io_mode(0, 2); /* Set cbreak, XON/XOFF, etc. */
/* Set initial subpacket length */
if (blklen < 1024) { /* Command line override? */
@ -288,6 +308,8 @@ int getzrxinit(void)
blklen = 512;
if (Baudrate > 2400)
blklen = 1024;
if (Baudrate < 300)
blklen = 1024;
}
if (Rxbuflen && blklen>Rxbuflen)
blklen = Rxbuflen;
@ -337,7 +359,8 @@ int sendzsinit(void)
} else
zsbhdr(ZSINIT, Txhdr);
Syslog('z', "sendzsinit Myattn \"%s\"", printable(Myattn, 0));
zsdata(Myattn, 1 + strlen(Myattn), ZCRCW);
// zsdata(Myattn, 1 + strlen(Myattn), ZCRCW);
zsdata(Myattn, ZATTNLEN, ZCRCW);
c = zgethdr(Rxhdr);
switch (c) {
case ZCAN: return TERROR;
@ -375,9 +398,12 @@ int zfilbuf(void)
*/
int zsendfile(char *buf, int blen)
{
int c;
int c, i, m, n;
register unsigned int crc = -1;
int lastcrcrq = -1;
int lastcrcof = -1;
int l;
char *p;
Syslog('z', "zsendfile %s (%d)", buf, blen);
for (errors=0; ++errors<11;) {
@ -414,15 +440,42 @@ again:
case ZNAK:
continue;
case ZCRC:
if (Rxpos != lastcrcrq) {
l = Rxhdr[9] & 0377;
l = (l<<8) + (Rxhdr[8] & 0377);
l = (l<<8) + (Rxhdr[7] & 0377);
l = (l<<8) + (Rxhdr[6] & 0377);
if (Rxpos != lastcrcrq || l != lastcrcof) {
lastcrcrq = Rxpos;
crc = 0xFFFFFFFFL;
fseek(in, 0L, 0);
while (((c = getc(in)) != EOF) && --lastcrcrq)
crc = updcrc32(c, crc);
crc = ~crc;
clearerr(in); /* Clear possible EOF */
lastcrcrq = Rxpos;
// fseek(in, 0L, 0);
// while (((c = getc(in)) != EOF) && --lastcrcrq)
// crc = updcrc32(c, crc);
// crc = ~crc;
// clearerr(in); /* Clear possible EOF */
// lastcrcrq = Rxpos;
if (Canseek >= 0) {
fseek(in, bytcnt = l, 0); i = 0;
Syslog('z', "Zmodem: CRC32 on %ld bytes", Rxpos);
do {
/* No rx timeouts! */
if (--i < 0) {
i = 32768L/blklen;
PUTCHAR(SYN);
fflush(stdout);
}
bytcnt += m = n = zfilbuf();
if (bytcnt > maxbytcnt)
maxbytcnt = bytcnt;
for (p = txbuf; --m >= 0; ++p) {
c = *p & 0377;
crc = updcrc32(c, crc);
}
Syslog('z', "bytcnt=%d crc=%08X", bytcnt, crc);
} while (n && bytcnt < lastcrcrq);
crc = ~crc;
clearerr(in); /* Clear possible EOF */
}
}
stohdr(crc);
zsbhdr(ZCRC, Txhdr);
@ -441,7 +494,7 @@ again:
skipsize = Rxpos;
if (fseek(in, Rxpos, 0))
return TERROR;
Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1;
Lastsync = (maxbytcnt = bytcnt = Txpos = Lrxpos = Rxpos) -1;
return zsendfdata();
}
}
@ -471,7 +524,8 @@ int zsendfdata(void)
junkcount = 0;
Beenhereb4 = 0;
somemore:
if (0) {
// if (0) {
if (setjmp(intrjmp)) {
waitack:
junkcount = 0;
c = getinsync(0);
@ -486,18 +540,18 @@ gotack:
return c;
case ZACK: Syslog('z', "zmsend: got ZACK");
break; // Possible bug, added 23-08-99
case ZRPOS: blklen = ((blklen >> 2) > 64) ? (blklen >> 2) : 64;
case ZRPOS: /* blklen = ((blklen >> 2) > 64) ? (blklen >> 2) : 64;
goodblks = 0;
goodneeded = ((goodneeded << 1) > 16) ? 16 : goodneeded << 1;
Syslog('z', "zmsend: blocklen now %d", blklen);
Syslog('z', "zmsend: blocklen now %d", blklen); */
break;
case TIMEOUT: /* Put back here 08-09-1999 mb */
Syslog('z', "zmsend: zsendfdata TIMEOUT");
goto to;
case HANGUP: /* New, added 08-09-1999 mb */
Syslog('z', "zmsend: zsendfdata HANGUP");
fclose(in);
return c;
// case TIMEOUT: /* Put back here 08-09-1999 mb */
// Syslog('z', "zmsend: zsendfdata TIMEOUT");
// goto to;
// case HANGUP: /* New, added 08-09-1999 mb */
// Syslog('z', "zmsend: zsendfdata HANGUP");
// fclose(in);
// return c;
}
/*
@ -520,7 +574,9 @@ gotack:
}
}
}
to:
//to:
signal(SIGINT, onintr);
newcnt = Rxbuflen;
Txwcnt = 0;
stohdr(Txpos);
@ -544,12 +600,14 @@ to:
alarm_on();
zsdata(txbuf, n, e);
bytcnt = Txpos += n;
if (bytcnt > maxbytcnt)
maxbytcnt = bytcnt;
if ((blklen < maxblklen) && (++goodblks > goodneeded)) {
blklen = ((blklen << 1) < maxblklen) ? blklen << 1 : maxblklen;
goodblks = 0;
Syslog('z', "zmsend: blocklen now %d", blklen);
}
// if ((blklen < maxblklen) && (++goodblks > goodneeded)) {
// blklen = ((blklen << 1) < maxblklen) ? blklen << 1 : maxblklen;
// goodblks = 0;
// Syslog('z', "zmsend: blocklen now %d", blklen);
// }
if (e == ZCRCW)
goto waitack;
@ -591,7 +649,8 @@ to:
Syslog('z', "window = %ld", tcount);
}
} while (!Eofseen);
signal(SIGINT, SIG_IGN);
for (;;) {
stohdr(Txpos);
zsbhdr(ZEOF, Txhdr);
@ -599,6 +658,7 @@ egotack:
switch (getinsync(0)) {
case ZACK: Syslog('z', "zsendfdata() ZACK");
goto egotack; // continue in old source
case ZNAK: continue;
case ZRPOS: goto somemore;
case ZRINIT: fclose(in);
return OK;
@ -630,10 +690,17 @@ int getinsync(int flag)
case ZCAN:
case ZABORT:
case ZFIN:
case TERROR:
/* case TERROR: */
case TIMEOUT: Syslog('+', "Zmodem: Got %s sending data", frametypes[c+FTOFFSET]);
return TERROR;
case ZRPOS: /* ************************************* */
case ZRPOS: if (Rxpos > bytcnt) {
Syslog('z', "Zmodem: getinsync: Rxpos=%lx bytcnt=%lx Maxbytcnt=%lx",
Rxpos, bytcnt, maxbytcnt);
if (Rxpos > maxbytcnt)
Syslog('+', "Nonstandard Protocol at %lX", Rxpos);
return ZRPOS;
}
/* ************************************* */
/* If sending to a buffered modem, you */
/* might send a break at this point to */
/* dump the modem's buffer. */
@ -667,6 +734,7 @@ int getinsync(int flag)
case ZRINIT: return c;
case ZSKIP: Syslog('+', "Zmodem: File skipped by receiver request");
return c;
case TERROR:
default: zsbhdr(ZNAK, Txhdr);
continue;
}
@ -674,3 +742,21 @@ int getinsync(int flag)
}
/*
* Set additional control chars to mask in Zsendmask
* according to bit array stored in char array at p
*/
void initzsendmsk(char *p)
{
int c;
for (c = 0; c < 33; ++c) {
if (p [c >> 3] & (1 << (c & 7))) {
Zsendmask[c] = 1;
Syslog('z', "Zmodem: escaping %02o", c);
}
}
}