Category : C Source Code
Archive   : O_ZMODEM.ZIP
Filename : ZMISC.C

 
Output of file : ZMISC.C contained in archive : O_ZMODEM.ZIP

/*--------------------------------------------------------------------------*/
/* FILE: zmisc.c (Opus zmodem routines used by send and receive) */
/* */
/* */
/* The Opus Computer-Based Conversation System */
/* (c) Copyright 1986, Wynn Wagner III, All Rights Reserved */
/* */
/* This implementation of Chuck Forsberg's ZMODEM protocol was */
/* for Opus by Rick Huebner and Wynn Wagner III */
/* */
/* (MSC/4 with /Zp /Ox) */
/* */
/* */
/* */
/* */
/* This module is similar to a routine used by Opus-Cbcs (1.00). It is */
/* provided for your information only. You will find routines that need */
/* to be coded and identifiers to be resolved. */
/* */
/* There is absolutely no guarantee that anything here will work. If you */
/* break this routine, you own both pieces. */
/* */
/* USAGE: You may use this material in any program with no obligation */
/* as long as there is no charge for your program. For more */
/* information about commercial use, contact the "OPUSinfo HERE" */
/* BBS (124/111). */
/* */
/* NOTE: There are a couple of things the Opus implementation does that */
/* aren't part of the original ZModem protocol. They all deal */
/* with WaZOO type ("ZedZap") netmail and should only show up when */
/* used under that condition. */
/* */
/* * The maximum packet size can grow larger than 1k. It is */
/* sensitive to the baud rate. (2400b=2048k; 9600b=8192k) */
/* * The sender must be able to send nothing. In other words, */
/* the sending system must be able to initiate and terminate */
/* a zmodem send session without having to actually send a */
/* file. Normally this kind of thing would never happen in */
/* zmodem. */
/* */
/* */
/*--------------------------------------------------------------------------*/
#include "zmodem.h"



static int Rxtype; /* Type of header received */
static int Rxframeind; /* ZBIN ZBIN32,ZHEX type of frame received */

static char hex[] = "0123456789abcdef";

/* Send a byte as two hex digits */
#define Z_PUTHEX(i,c) {i=(c);SENDBYTE(hex[((i)&0xF0)>>4]);SENDBYTE(hex[(i)&0xF]);}



/*--------------------------------------------------------------------------*/
/* Routines used by other ZModem modules... */
/*--------------------------------------------------------------------------*/
int pascal Z_GetByte(int);
void pascal Z_PutString(unsigned char *);
void pascal Z_SendHexHeader(unsigned short,unsigned char *);
int pascal Z_GetHeader(unsigned char *);
int pascal Z_GetZDL(void);
void pascal Z_PutLongIntoHeader(long);
unsigned short pascal Z_UpdateCRC(unsigned short,unsigned short);


/*--------------------------------------------------------------------------*/
/* Private routines */
/*--------------------------------------------------------------------------*/
static int pascal _Z_qk_read(void);
static int pascal _Z_GetBinaryHeader(unsigned char *);
static int pascal _Z_GetHexHeader(unsigned char *);
static int pascal _Z_GetHex(void);
static int pascal _Z_TimedRead(void);
static long pascal _Z_PullLongFromHeader(unsigned char *);



extern byte *local_CEOL;
extern char *KBD_msg;


void pascal z_message( s )
byte *s;
begin
gotoxy( locate_x+20, locate_y );
if (s) cputs(s);
cputs( local_CEOL );
end


void z_log(s)
byte *s;
begin
word x, y;

z_message(s);

x = locate_x;
y = locate_y;
status_line(s); /* also does disk file logging */
locate_x = x;
locate_y = y;

end


void show_loc(l,w)
unsigned long l;
unsigned int w;
begin
gotoxy( locate_x+35, locate_y );
cprintf("Ofs=%ld Retries=%d%s",l,w,local_CEOL);
end


byte * pascal zalloc()
begin
byte *sptr;

sptr = malloc(WAZOOMAX);
if (!sptr)
begin
status_line("!Z-MEMOVFL");
adios(2);
end
return sptr;
end







/*--------------------------------------------------------------------------*/
/* Z GET BYTE */
/* Get a byte from the modem; */
/* return TIMEOUT if no read within timeout tenths, */
/* return RCDO if carrier lost */
/*--------------------------------------------------------------------------*/
int pascal Z_GetByte(tenths)
register int tenths;
begin
register int i;

i^=i;
do
begin
if (CHAR_AVAIL()) return MODEM_IN();
end
while((i++)<2000);


i = tenths/10;
if (i<1) i = 1;
if (i>58) i = 58;

i = set_timer(i);

while(!CHAR_AVAIL())
begin
if (!CARRIER) return RCDO;

time_release();
if (time_gone(i)) return TIMEOUT;
end

return MODEM_IN();

end







/*--------------------------------------------------------------------------*/
/* QK_READ (like Z_GetByte, but assumes the time to be Rxtimeout) */
/* Get a byte from the modem; */
/* return TIMEOUT if no read within timeout tenths, */
/* return RCDO if carrier lost */
/*--------------------------------------------------------------------------*/
static int pascal _Z_qk_read()
begin
register int i;
register int time_val;

time_val^=time_val;
do
begin
if ((i=MODEM_STATUS())&DATA_READY) return MODEM_IN();
if (!(i&ctl.carrier_mask)) return RCDO;
end
while((time_val++)<2000);

time_val = set_timer(Rxtimeout);
do
begin
if ((i=MODEM_STATUS())&DATA_READY) return MODEM_IN();
if (!(i&ctl.carrier_mask)) return RCDO;
time_release();
end
while(time_left(time_val));

return TIMEOUT;

end







/*--------------------------------------------------------------------------*/
/* Z PUT STRING */
/* Send a string to the modem, processing for \336 (sleep 1 sec) */
/* and \335 (break signal, ignored) */
/*--------------------------------------------------------------------------*/
void pascal Z_PutString(s)
register unsigned char *s;
begin
register int c;

while (*s)
begin
switch (c = *s++)
begin
case '\336': big_pause(2);
case '\335': break;
default: SENDBYTE(c);
end /* switch */

end /* while */

end /* Z_PutString */









/*--------------------------------------------------------------------------*/
/* Z UPDATE CRC */
/* update CRC */
/*--------------------------------------------------------------------------*/
unsigned short pascal Z_UpdateCRC(c, crc)
unsigned short c;
unsigned short crc;
begin
register int count;
register word temp;

temp = crc;

for (count=8; --count>=0; )
begin
if (temp & 0x8000)
begin
temp <<= 1;
temp += (((c<<=1) & 0400) != 0);
temp ^= 0x1021;
end
else
begin
temp <<= 1;
temp += (((c<<=1) & 0400) != 0);
end
end /* for */

return temp;

end /* z_crc update */




/*--------------------------------------------------------------------------*/
/* Z SEND HEX HEADER */
/* Send ZMODEM HEX header hdr of type type */
/*--------------------------------------------------------------------------*/
void pascal Z_SendHexHeader(type, hdr)
unsigned short type;
unsigned char *hdr;
begin
register int n;
register int i;
unsigned short crc;

SENDBYTE(ZPAD);
SENDBYTE(ZPAD);
SENDBYTE(ZDLE);
SENDBYTE(ZHEX);
Z_PUTHEX(i,type);

crc = Z_UpdateCRC(type, 0);
for (n=4; --n >= 0;)
begin
Z_PUTHEX(i,(*hdr));
crc = Z_UpdateCRC(((unsigned short)(*hdr++)), crc);
end
crc = Z_UpdateCRC(0,crc);
crc = Z_UpdateCRC(0,crc);
Z_PUTHEX(i,(crc>>8));
Z_PUTHEX(i,crc);

/* Make it printable on remote machine */
SENDBYTE('\r');
SENDBYTE('\n');

/* Uncork the remote in case a fake XOFF has stopped data flow */
if (type != ZFIN) SENDBYTE(021);

wait_for_clear();

end /* Z_SendHexHeader */





/*--------------------------------------------------------------------------*/
/* Z GET HEADER */
/* Read a ZMODEM header to hdr, either binary or hex. */
/* On success, set Zmodem to 1 and return type of header. */
/* Otherwise return negative on error */
/*--------------------------------------------------------------------------*/
int pascal Z_GetHeader(hdr)
byte *hdr;
begin

register int c;
register int n;
int cancount;


n = cur_baud; /* Max characters before start of frame */
cancount = 5;

Again:

if (((KEYPRESS()) and (READKB()==27)))
begin
send_can();
z_log( KBD_msg );
return ZCAN;
end

Rxframeind = Rxtype = 0;

switch (c = _Z_TimedRead())
begin

case ZPAD: /*-----------------------------------------------*/
/* This is what we want. */
/*-----------------------------------------------*/
break;

case RCDO:
case TIMEOUT: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
goto Done;

case CAN: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
if (--cancount <= 0)
begin
c = ZCAN;
goto Done;
end

/* fallthrough... */

default: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
Agn2:

if (--n <= 0)
begin
z_log( FUBAR_msg );
send_can();
return ZCAN;
end

if (c != CAN) cancount = 5;
goto Again;

end /* switch */

cancount = 5;

Splat:

switch (c = _Z_TimedRead())
begin
case ZDLE: /*-----------------------------------------------*/
/* This is what we want. */
/*-----------------------------------------------*/
break;

case ZPAD: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
goto Splat;

case RCDO:
case TIMEOUT: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
goto Done;

default: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
goto Agn2;

end /* switch */


switch (c = _Z_TimedRead())
begin

case ZBIN: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
Rxframeind = ZBIN;
c = _Z_GetBinaryHeader(hdr);
break;

case ZHEX: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
Rxframeind = ZHEX;
c = _Z_GetHexHeader(hdr);
break;

case CAN: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
if (--cancount <= 0)
begin
c = ZCAN;
goto Done;
end
goto Agn2;

case RCDO:
case TIMEOUT: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
goto Done;

default: /*-----------------------------------------------*/
/* */
/*-----------------------------------------------*/
goto Agn2;

end /* switch */

Rxpos = _Z_PullLongFromHeader(hdr);

Done:

return c;

end /* Z_GetHeader */





/*--------------------------------------------------------------------------*/
/* Z GET BINARY HEADER */
/* Receive a binary style header (type and position) */
/*--------------------------------------------------------------------------*/
static int pascal _Z_GetBinaryHeader(hdr)
byte *hdr;
begin
register int c;
register word crc;
int n;

if ((c = Z_GetZDL()) & ~0xFF) return c;
Rxtype = c;
crc = Z_UpdateCRC(c, 0);

for (n=4; --n >= 0;)
begin
if ((c = Z_GetZDL()) & ~0xFF) return c;
crc = Z_UpdateCRC(c, crc);
*hdr++ = c;
end
if ((c = Z_GetZDL()) & ~0xFF) return c;

crc = Z_UpdateCRC(c, crc);
if ((c = Z_GetZDL()) & ~0xFF) return c;

crc = Z_UpdateCRC(c, crc);
if (crc & 0xFFFF)
begin
z_message( CRC_msg );
return ERROR;
end

return Rxtype;

end /* _Z_GetBinaryHeader */




/*--------------------------------------------------------------------------*/
/* Z GET HEX HEADER */
/* Receive a hex style header (type and position) */
/*--------------------------------------------------------------------------*/
static int pascal _Z_GetHexHeader(hdr)
unsigned char *hdr;
begin
register int c;
register word crc;
int n;

if ((c = _Z_GetHex()) < 0) return c;
Rxtype = c;
crc = Z_UpdateCRC(c, 0);

for (n=4; --n >= 0;)
begin
if ((c = _Z_GetHex()) < 0) return c;
crc = Z_UpdateCRC(c, crc);
*hdr++ = c;
end

if ((c = _Z_GetHex()) < 0) return c;
crc = Z_UpdateCRC(c, crc);
if ((c = _Z_GetHex()) < 0) return c;
crc = Z_UpdateCRC(c, crc);
if (crc & 0xFFFF)
begin
z_message( CRC_msg );
return ERROR;
end
if (Z_GetByte(1) == '\r') Z_GetByte(1); /* Throw away possible cr/lf */

return Rxtype;

end





/*--------------------------------------------------------------------------*/
/* Z GET HEX */
/* Decode two lower case hex digits into an 8 bit byte value */
/*--------------------------------------------------------------------------*/
static int pascal _Z_GetHex()
begin
register int c, n;

if ((n = _Z_TimedRead()) < 0) return n;
n -= '0';
if (n > 9) n -= ('a' - ':');
if (n & ~0xF) return ERROR;

if ((c = _Z_TimedRead()) < 0) return c;
c -= '0';
if (c > 9) c -= ('a' - ':');
if (c & ~0xF) return ERROR;

return (n<<4 | c);
end




/*--------------------------------------------------------------------------*/
/* Z GET ZDL */
/* Read a byte, checking for ZMODEM escape encoding */
/* including CAN*5 which represents a quick abort */
/*--------------------------------------------------------------------------*/
int pascal Z_GetZDL()
begin
register int c;

if ((c = _Z_qk_read()) != ZDLE) return c;

switch (c=_Z_qk_read())
begin
case CAN: return ((c=_Z_qk_read())<0)? c :
((c==CAN) && ((c=_Z_qk_read())<0))? c :
((c==CAN) && ((c=_Z_qk_read())<0))? c : (GOTCAN);

case ZCRCE:
case ZCRCG:
case ZCRCQ:
case ZCRCW: return (c | GOTOR);

case ZRUB0: return 0x7F;

case ZRUB1: return 0xFF;

default: return (c<0)? c :
((c&0x60)==0x40)? (c ^ 0x40) : ERROR;

end /* switch */

end /* Z_GetZDL */





/*--------------------------------------------------------------------------*/
/* Z TIMED READ */
/* Read a character from the modem line with timeout. */
/* Eat parity, XON and XOFF characters. */
/*--------------------------------------------------------------------------*/
static int pascal _Z_TimedRead()
begin
register int c;

for (;;)
begin
if ((c = _Z_qk_read()) < 0) return c;

switch (c &= 0x7F)
begin
case XON:
case XOFF: continue;

default: return c;
end /* switch */

end /* for */

end /* _Z_TimedRead */




/*--------------------------------------------------------------------------*/
/* Z LONG TO HEADER */
/* Store long integer pos in Txhdr */
/*--------------------------------------------------------------------------*/
void pascal Z_PutLongIntoHeader(pos)
long pos;
begin
Txhdr[ZP0] = pos;
Txhdr[ZP1] = pos>>8;
Txhdr[ZP2] = pos>>16;
Txhdr[ZP3] = pos>>24;
end /* Z_PutLongIntoHeader */




/*--------------------------------------------------------------------------*/
/* Z PULL LONG FROM HEADER */
/* Recover a long integer from a header */
/*--------------------------------------------------------------------------*/
static long pascal _Z_PullLongFromHeader(hdr)
unsigned char *hdr;
begin
long l;

l = hdr[ZP3];
l = (l << 8) | hdr[ZP2];
l = (l << 8) | hdr[ZP1];
l = (l << 8) | hdr[ZP0];
return l;
end /* _Z_PullLongFromHeader */


/* END OF FILE: n_zmodem.c */