/* * I Z M . C * ZMODEM protocol primitives * Copyright 2002 Omen Technology INC All Rights Reserved * * Entry point Functions: * zsbhdr(type, hdr) send binary header * zshhdr(type, hdr) send hex header * zgethdr() 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 */ // COLETTI GLOBAL VARS, MISC //#define FLUSH #define ZSTAB #include "stdio.h" #include "izm.h" #include "icrctab.c" // #ifndef UNSL #define UNSL #endif #ifndef XEDCRC32 int zrdat32(), zrbhdr32(); #endif /* Globals used in ISZ and IZM functions */ extern char Rxhdr[4]; /* Received header */ extern char Txhdr[8]; /* Transmitted header */ extern int Zctlesc; /* Encode control characters */ extern int Zrwindow; /* RX window size (controls garbage count) */ extern int Rxtimeout; extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ extern long bytcnt; extern long Rxpos; /* Received file position */ extern long Txpos; /* Transmitted file position */ /* Globals used by IZM functions */ int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ int Rxtype; /* Type of header received */ int Rxcount; /* Count of data bytes received */ int Crc32t; /* Display flag indicating 32 bit CRC being sent */ #ifdef ZSTAB unsigned char zstable[256] = { 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0120,0121,0,0123,0,0,0,0, 0130,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0320,0321,0,0323,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0, #ifdef NOFF ZRUB1 #else 0 #endif }; #endif #ifndef XEDCRC32 /* Send ZMODEM binary header hdr of type type */ void zsbh32(hdr, type) register char *hdr; { register int n; register UNSL 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; } } #endif /* XEDCRC32 */ /* Send ZMODEM binary header hdr of type type */ void zsbhdr(type, hdr) register char *hdr; { register int n; register unsigned short crc; xsendline(ZPAD); xsendline(ZDLE); #ifndef XEDCRC32 Crc32t=Txfcs32; if (Crc32t) zsbh32(hdr, type); else #endif { 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); } } /* Send ZMODEM HEX header hdr of type type */ void zshhdr(type, hdr) register char *hdr; { register int n; register unsigned short crc; sendline(ZPAD); sendline(ZPAD); sendline(ZDLE); sendline(ZHEX); zputhex(type); #ifndef XEDCRC32 Crc32t = 0; #endif crc = updcrc(type, 0); for (n=4; --n >= 0; ++hdr) { zputhex(*hdr); crc = updcrc((0377 & *hdr), crc); } 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); #ifdef FLUSH flushmo(); #endif } /* * Send binary array buf of length length, with ending ZDLE sequence frameend */ #ifndef XEDCRC32 void zsda32(buf, length, frameend) char *buf; register length; { register char *p; register int c; register int d; register unsigned long crc; register unsigned long *pcrctab; p = (char *) buf; pcrctab = icr3tab; crc = 0xFFFFFFFFL; for (;--length >= 0;) { c = *p++ & 0377; crc = pcrctab[(crc ^ c) & 0xff] ^ ((crc >> 8) & 0x00FFFFFF); if (d = zstable[c]) { sendline(ZDLE); c = d; } //end zstable if sendline(c); } //end for loop xsendline(ZDLE); xsendline(frameend); crc = UPDC32(frameend, crc); crc = ~crc; for (length=4; --length >= 0;) { zsendline((int)crc); crc >>= 8; } if (frameend == ZCRCW) { xsendline(XON); #ifdef FLUSH flushmo(); #endif } #ifdef FLUSH else if (frameend != ZCRCG) flushmoc(); #endif } #endif /* XEDCRC32 */ /* * 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; #ifndef XEDCRC32 if (Rxframeind == ZBIN32) return zrdat32(buf, length); #endif crc = 0; 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) { return ERROR; } Rxcount = length - (end - buf); return d; case GOTCAN: return ZCAN; case TIMEOUT: return c; default: return c; } } *buf++ = c; crc = updcrc(c, crc); } return ERROR; } #ifndef XEDCRC32 zrdat32(buf, length) register char *buf; { register int c; register unsigned long crc; register char *end; register int d; 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) { return ERROR; } Rxcount = length - (end - buf); return d; case GOTCAN: return ZCAN; case TIMEOUT: return c; default: return c; } } *buf++ = c; crc = UPDC32(c, crc); } return ERROR; } #endif /* XEDCRC32 */ /* * Read a ZMODEM header to hdr, either binary or hex. * On success, set Rxpos and return type of header. * Otherwise return negative on error. * Return ERROR instantly if ZCRCW sequence, for fast error recovery. */ zgethdr() { register int c, n, cancount; n = Zrwindow + 19200; /* 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 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; /*FALLTHRU*/ goto fifi; default: break; case CAN: if (--cancount <= 0) { c = ZCAN; goto fifi; } goto again; } /*FALLTHRU*/ default: agn2: if ( --n == 0) { return(ERROR); } 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 TIMEOUT: goto fifi; default: goto agn2; case ZDLE: /* This is what we want. */ break; } switch (c = noxrd7()) { case TIMEOUT: goto fifi; case ZBIN: Rxframeind = ZBIN; c = zrbhdr(); break; #ifndef XEDCRC32 case ZBIN32: Rxframeind = ZBIN32; c = zrbhdr32(); break; #endif case ZHEX: Rxframeind = ZHEX; c = zrhhdr(); break; case CAN: goto gotcan; default: goto agn2; } Rxpos = Rxhdr[ZP3] & 0377; Rxpos = (Rxpos<<8) + (Rxhdr[ZP2] & 0377); Rxpos = (Rxpos<<8) + (Rxhdr[ZP1] & 0377); Rxpos = (Rxpos<<8) + (Rxhdr[ZP0] & 0377); fifi: switch (c) { case GOTCAN: c = ZCAN; /*FALLTHRU*/ default: ; } return c; } /* Receive a binary style header (type and position) */ zrbhdr() { register char *hdr = Rxhdr; 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) { return ERROR; } return Rxtype; } #ifndef XEDCRC32 /* Receive a binary style header (type and position) with 32 bit FCS */ zrbhdr32() { register char *hdr = Rxhdr; register int c, n; register unsigned long crc; if ((c = zdlread()) & ~0377) return c; Rxtype = c; crc = 0xFFFFFFFFL; crc = UPDC32(c, crc); for (n=4; --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) { return ERROR; } return Rxtype; } #endif /* XEDCRC32 */ /* Receive a hex style header (type and position) */ zrhhdr() { register int c; register char *hdr = Rxhdr; 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) { return ERROR; } switch ( c = readline(1)) { case 0215: case 015: /* Throw away possible cr/lf */ c = readline(1); } return Rxtype; } /* Send a byte as two hex digits */ void 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 DLE, XON, XOFF. */ void zsendline(c) register c; #ifdef ZSTAB { register d; c &= 0377; if (d = zstable[c]) { sendline(ZDLE); c = d; } sendline(c); } #else { #ifdef NOFF c &= 0377; if (c == 0377) { xsendline(ZDLE); c = ZRUB1; /* Passes the 0140 mask below !! */ } #endif /* Quick check for non control characters */ if (c & 0140) xsendline(c); else { switch (c &= 0377) { case ZDLE: case 020: case 021: case 023: case 0220: case 0221: case 0223: xsendline(ZDLE); c ^= 0100; xsendline(c); break; default: if (Zctlesc) { xsendline(ZDLE); c ^= 0100; } xsendline(c); } } } #endif /* 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); /* DO NOT REMOVE THIS ENTRY!!! */ case ZRUB0: return 0177; /* DO NOT REMOVE THIS ENTRY!!! (used for telnet) */ 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; } 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; /*FALLTHRU*/ case '\r': case '\n': case ZDLE: return c; } } } /* Store long integer pos in Txhdr */ void 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; } /* send cancel string to get the other end to shut up */ void canit() { static char canistr[] = { 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 }; mputs(canistr); purgeline(); } /* End of izm.c */