/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available Software. */ /* \ 1011 / */ /* ------ */ /* */ /* (C) Copyright 1987-96, Bit Bucket Software Co. */ /* */ /* */ /* */ /* Zmodem routines used by Zsend and Zreceive */ /* */ /* */ /* For complete details of the licensing restrictions, please refer */ /* to the License agreement, which is published in its entirety in */ /* the MAKEFILE and BT.C, and also contained in the file LICENSE.260. */ /* */ /* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */ /* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */ /* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */ /* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */ /* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */ /* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */ /* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */ /* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */ /* */ /* */ /* You can contact Bit Bucket Software Co. at any one of the following */ /* addresses: */ /* */ /* Bit Bucket Software Co. FidoNet 1:104/501, 1:343/491 */ /* P.O. Box 460398 AlterNet 7:42/1491 */ /* Aurora, CO 80046 BBS-Net 86:2030/1 */ /* Internet f491.n343.z1.fidonet.org */ /* */ /* Please feel free to contact us at any time to share your comments about */ /* our software and/or licensing policies. */ /* */ /* */ /* This module is based largely on a similar module in OPUS-CBCS V1.03b. */ /* The original work is (C) Copyright 1986, Wynn Wagner III. The original */ /* authors have graciously allowed us to use their code in this work. */ /* */ /*--------------------------------------------------------------------------*/ /* Include this file before any other includes or defines! */ #include "includes.h" static int Rxtype; /* Type of header 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]);} /*--------------------------------------------------------------------------*/ /* Private routines */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC _Z_GetBinaryHeader (unsigned char *); static int LOCALFUNC _Z_32GetBinaryHeader (unsigned char *); static int LOCALFUNC _Z_GetHexHeader (unsigned char *); static int LOCALFUNC _Z_GetHex (void); static int LOCALFUNC _Z_TimedRead (void); static long LOCALFUNC _Z_PullLongFromHeader (unsigned char *); void z_message (char *s) { if (fullscreen && un_attended) { if (s) { sb_move (filewin, 2, 27); sb_puts (filewin, s); } sb_puts (filewin, " "); sb_show (); } else { gotoxy (locate_x + 20, locate_y); if (s) { (void) cputs (s); } (void) cputs (" "); } } void z_log (char *s) { 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; } void show_loc (unsigned long l, unsigned int w) { char j[100]; if (fullscreen && un_attended) { (void) sprintf (j, "Ofs=%ld Retries=%d ", l, w); sb_move (filewin, 2, 37); sb_puts (filewin, j); sb_show (); } else { gotoxy (locate_x + 35, locate_y); (void) printf ("Ofs=%ld Retries=%d ", l, w); } } /*--------------------------------------------------------------------------*/ /* Z GET BYTE */ /* Get a byte from the modem; */ /* return TIMEOUT if no read within timeout tenths, */ /* return RCDO if carrier lost */ /*--------------------------------------------------------------------------*/ int Z_GetByte (int tenths) { long timeout; if (PEEKBYTE () >= 0) return (MODEM_IN ()); timeout = timerset (tenths * 10); do { if (PEEKBYTE () >= 0) return MODEM_IN (); if (!CARRIER) return RCDO; if (got_ESC ()) return -1; time_release (); } while (!timeup (timeout)); return TIMEOUT; } /*--------------------------------------------------------------------------*/ /* Z PUT STRING */ /* Send a string to the modem, processing for \336 (sleep 1 sec) */ /* and \335 (break signal, ignored) */ /*--------------------------------------------------------------------------*/ void Z_PutString (register unsigned char *s) { register unsigned c; while (*s) { switch (c = *s++) { case (unsigned int) '\336': big_pause (2); break; case (unsigned int) '\335': /* Should send a break on this */ break; default: SENDBYTE ((unsigned char) c); } /* switch */ } /* while */ Z_UncorkTransmitter (); } /* Z_PutString */ /*--------------------------------------------------------------------------*/ /* Z SEND HEX HEADER */ /* Send ZMODEM HEX header hdr of type type */ /*--------------------------------------------------------------------------*/ void Z_SendHexHeader (unsigned int type, register unsigned char *hdr) { register int n; register int i; register word crc; Z_UncorkTransmitter (); /* Get our transmitter going */ #ifdef DEBUG show_debug_name ("Z_SendHexHeader"); #endif SENDBYTE (ZPAD); SENDBYTE (ZPAD); SENDBYTE (ZDLE); SENDBYTE (ZHEX); Z_PUTHEX (i, type); Crc32t = 0; crc = Z_UpdateCRC (type, 0); for (n = 4; --n >= 0;) { Z_PUTHEX (i, (*hdr)); crc = Z_UpdateCRC (((unsigned short) (*hdr++)), 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 && type != ZACK) SENDBYTE (021); if (!CARRIER) CLEAR_OUTBOUND (); } /* Z_SendHexHeader */ /*--------------------------------------------------------------------------*/ /* Z UNCORK TRANSMITTER */ /* Wait a reasonable amount of time for transmitter buffer to clear. */ /* When it does, or when time runs out, turn XON/XOFF off then on. */ /* This should release a transmitter stuck by line errors. */ /*--------------------------------------------------------------------------*/ void Z_UncorkTransmitter () { long t; #ifdef DEBUG show_debug_name ("Z_UncorkTransmitter"); #endif if (!OUT_EMPTY () && CARRIER) { t = timerset (5 * Rxtimeout); /* Wait for silence */ while (!timeup (t) && !OUT_EMPTY () && CARRIER) time_release (); /* Give up slice while waiting */ } com_kick (); } /*--------------------------------------------------------------------------*/ /* 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 Z_GetHeader (byte * hdr) { register int c; unsigned long n; int cancount; #ifdef DEBUG show_debug_name ("Z_GetHeader"); #endif n = (unsigned long) cur_baud.rate_value; /* Max characters before * start of frame */ cancount = 5; Again: if (got_ESC ()) { send_can (); z_log (MSG_TXT (M_KBD_MSG)); return ZCAN; } Rxframeind = Rxtype = 0; switch (c = _Z_TimedRead ()) { case ZPAD: case ZPAD | 0200: /*-----------------------------------------------*/ /* This is what we want. */ /*-----------------------------------------------*/ break; case RCDO: case TIMEOUT: goto Done; case CAN: GotCan: if (--cancount <= 0) { c = ZCAN; goto Done; } switch (c = Z_GetByte (1)) { case TIMEOUT: goto Again; case ZCRCW: c = ERROR; /* fallthrough... */ case RCDO: goto Done; case CAN: if (--cancount <= 0) { c = ZCAN; goto Done; } goto Again; } /* fallthrough... */ default: Agn2: if (--n <= 0) { z_log (MSG_TXT (M_FUBAR_MSG)); return ERROR; } if (c != CAN) cancount = 5; goto Again; } /* switch */ cancount = 5; Splat: switch (c = _Z_TimedRead ()) { case ZDLE: /*-----------------------------------------------*/ /* This is what we want. */ /*-----------------------------------------------*/ break; case ZPAD: goto Splat; case RCDO: case TIMEOUT: goto Done; default: goto Agn2; } /* switch */ switch (c = _Z_TimedRead ()) { case ZBIN: Rxframeind = ZBIN; Crc32 = 0; c = _Z_GetBinaryHeader (hdr); break; case ZBIN32: Crc32 = Rxframeind = ZBIN32; c = _Z_32GetBinaryHeader (hdr); break; case ZHEX: Rxframeind = ZHEX; Crc32 = 0; c = _Z_GetHexHeader (hdr); break; case CAN: goto GotCan; case RCDO: case TIMEOUT: goto Done; default: goto Agn2; } /* switch */ Rxpos = _Z_PullLongFromHeader (hdr); Done: return c; } /* Z_GetHeader */ /*--------------------------------------------------------------------------*/ /* Z GET BINARY HEADER */ /* Receive a binary style header (type and position) */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC _Z_GetBinaryHeader (register unsigned char *hdr) { register int c; register word crc; register int n; #ifdef DEBUG show_debug_name ("Z_GetBinaryHeader"); #endif if ((c = Z_GetZDL ()) & ~0xFF) return c; Rxtype = c; crc = Z_UpdateCRC (c, 0); for (n = 4; --n >= 0;) { if ((c = Z_GetZDL ()) & ~0xFF) return c; crc = Z_UpdateCRC (c, crc); *hdr++ = (unsigned char) (c & 0xff); } 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) { z_message (MSG_TXT (M_CRC_MSG)); return ERROR; } return Rxtype; } /* _Z_GetBinaryHeader */ /*--------------------------------------------------------------------------*/ /* Z GET BINARY HEADER with 32 bit CRC */ /* Receive a binary style header (type and position) */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC _Z_32GetBinaryHeader (register unsigned char *hdr) { register int c; register unsigned long crc; register int n; #ifdef DEBUG show_debug_name ("Z_32GetBinaryHeader"); #endif if ((c = Z_GetZDL ()) & ~0xFF) return c; Rxtype = c; crc = 0xFFFFFFFF; crc = Z_32UpdateCRC (c, crc); for (n = 4; --n >= 0;) { if ((c = Z_GetZDL ()) & ~0xFF) return c; crc = Z_32UpdateCRC (c, crc); *hdr++ = (unsigned char) (c & 0xff); } for (n = 4; --n >= 0;) { if ((c = Z_GetZDL ()) & ~0xFF) return c; crc = Z_32UpdateCRC (c, crc); } if (crc != 0xDEBB20E3) { z_message (MSG_TXT (M_CRC_MSG)); return ERROR; } return Rxtype; } /* _Z_32GetBinaryHeader */ /*--------------------------------------------------------------------------*/ /* Z GET HEX HEADER */ /* Receive a hex style header (type and position) */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC _Z_GetHexHeader (register unsigned char *hdr) { register int c; register word crc; register int n; #ifdef DEBUG show_debug_name ("Z_GetHexHeader"); #endif if ((c = _Z_GetHex ()) < 0) return c; Rxtype = c; crc = Z_UpdateCRC (c, 0); for (n = 4; --n >= 0;) { if ((c = _Z_GetHex ()) < 0) return c; crc = Z_UpdateCRC (c, crc); *hdr++ = (unsigned char) c; } 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) { z_message (MSG_TXT (M_CRC_MSG)); return ERROR; } if (Z_GetByte (1) == '\r') (void) Z_GetByte (1); /* Throw away possible cr/lf */ return Rxtype; } /*--------------------------------------------------------------------------*/ /* Z GET HEX */ /* Decode two lower case hex digits into an 8 bit byte value */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC _Z_GetHex () { register int c, n; #ifdef DEBUG show_debug_name ("Z_GetHex"); #endif 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); } /*--------------------------------------------------------------------------*/ /* Z GET ZDL */ /* Read a byte, checking for ZMODEM escape encoding */ /* including CAN*5 which represents a quick abort */ /*--------------------------------------------------------------------------*/ int Z_GetZDL () { register int c; if ((c = Z_GetByte (Rxtimeout)) != ZDLE) return c; switch (c = Z_GetByte (Rxtimeout)) { case CAN: return ((c = Z_GetByte (Rxtimeout)) < 0) ? c : ((c == CAN) && ((c = Z_GetByte (Rxtimeout)) < 0)) ? c : ((c == CAN) && ((c = Z_GetByte (Rxtimeout)) < 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; } /* switch */ } /* Z_GetZDL */ /*--------------------------------------------------------------------------*/ /* Z TIMED READ */ /* Read a character from the modem line with timeout. */ /* Eat parity, XON and XOFF characters. */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC _Z_TimedRead () { register int c; #ifdef DEBUG show_debug_name ("Z_TimedRead"); #endif for (;;) { if ((c = Z_GetByte (Rxtimeout)) < 0) return c; switch (c &= 0x7F) { case XON: case XOFF: continue; default: if (!(c & 0x60)) continue; /* Else fall through */ case '\r': case '\n': case ZDLE: return c; } /* switch */ } /* for */ } /* _Z_TimedRead */ /*--------------------------------------------------------------------------*/ /* Z LONG TO HEADER */ /* Store long integer pos in Txhdr */ /*--------------------------------------------------------------------------*/ void Z_PutLongIntoHeader (long pos) { #ifndef GENERIC *((long *) Txhdr) = pos; #else Txhdr[ZP0] = pos; Txhdr[ZP1] = pos >> 8; Txhdr[ZP2] = pos >> 16; Txhdr[ZP3] = pos >> 24; #endif } /* Z_PutLongIntoHeader */ /*--------------------------------------------------------------------------*/ /* Z PULL LONG FROM HEADER */ /* Recover a long integer from a header */ /*--------------------------------------------------------------------------*/ static long LOCALFUNC _Z_PullLongFromHeader (unsigned char *hdr) { #ifndef GENERIC return (*((long *) hdr)); /*PLF Fri 05-05-1989 06:42:41 */ #else long l; l = hdr[ZP3]; l = (l << 8) | hdr[ZP2]; l = (l << 8) | hdr[ZP1]; l = (l << 8) | hdr[ZP0]; return l; #endif } /* _Z_PullLongFromHeader */ /* END OF FILE: zmisc.c */