/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available Software. */ /* \ 1011 / */ /* ------ */ /* */ /* (C) Copyright 1987-96, Bit Bucket Software Co. */ /* */ /* */ /* */ /* Zmodem file transmission module */ /* */ /* */ /* 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" /*--------------------------------------------------------------------------*/ /* Private routines */ /*--------------------------------------------------------------------------*/ static void LOCALFUNC ZS_SendBinaryHeader (unsigned short, byte *); static void LOCALFUNC ZS_32SendBinaryHeader (unsigned short, byte *); static void LOCALFUNC ZS_SendData (byte *, int, unsigned short); static void LOCALFUNC ZS_32SendData (byte *, int, unsigned short); static void LOCALFUNC ZS_SendByte (byte); static int LOCALFUNC ZS_GetReceiverInfo (void); static int LOCALFUNC ZS_SendFile (int, int); static int LOCALFUNC ZS_SendFileData (int); static int LOCALFUNC ZS_SyncWithReceiver (int); static void LOCALFUNC ZS_EndSend (void); /*--------------------------------------------------------------------------*/ /* Private data */ /*--------------------------------------------------------------------------*/ static FILE *Infile; /* Handle of file being sent */ static long Strtpos; /* Starting byte position of */ /* download */ static long LastZRpos; /* Last error location */ static long ZRPosCount; /* ZRPOS repeat count */ static long Txpos; /* Transmitted file position */ static int Rxbuflen; /* Receiver's max buffer */ /* length */ static int Rxflags; /* Receiver's flags */ /*--------------------------------------------------------------------------*/ /* SEND ZMODEM (send a file) */ /* returns TRUE (1) for good xfer, FALSE (0) for bad */ /* sends one file per call; 'fsent' flags start and end of batch */ /*--------------------------------------------------------------------------*/ int Send_Zmodem (char *fname, char *alias, int fsent, int wazoo) { register byte *p; register byte *q; struct stat f; long ltemp; int rc = TRUE; char j[100]; time_t filetime; #ifdef DEBUG show_debug_name ("send_Zmodem"); #endif IN_XON_ENABLE (); z_size = 0; Infile = NULL; if (fname && !(fullscreen && un_attended)) set_xy (""); switch (fsent) { case 0: Z_PutString ((byte *) "rz\r"); Z_PutLongIntoHeader (0L); Z_SendHexHeader (ZRQINIT, (byte *) Txhdr); /* Fall through */ case NOTHING_TO_DO: Rxtimeout = 200; if (ZS_GetReceiverInfo () == ERROR) { XON_DISABLE (); CLEAR_OUTBOUND (); CLEAR_INBOUND (); XON_ENABLE (); return FALSE; } } Rxtimeout = (int) (614400L / (long) cur_baud.rate_value); if (Rxtimeout < 400) Rxtimeout = 400; if (fname == NULL) goto Done; /*--------------------------------------------------------------------*/ /* Prepare the file for transmission. Just ignore file open errors */ /* because there may be other files that can be sent. */ /*--------------------------------------------------------------------*/ Filename = fname; CLEAR_IOERR (); if ((Infile = share_fopen (Filename, read_binary, DENY_WRITE)) == NULL) { (void) got_error (MSG_TXT (M_OPEN_MSG), Filename); rc = OK; goto Done; } if (isatty (fileno (Infile))) { errno = 1; (void) got_error (MSG_TXT (M_DEVICE_MSG), Filename); rc = OK; goto Done; } /*--------------------------------------------------------------------*/ /* Send the file */ /* Display outbound filename, size, and ETA for sysop */ /*--------------------------------------------------------------------*/ (void) stat (Filename, &f); ltemp = (f.st_size * 10L / cur_baud.rate_value + 53L) / 54L; (void) sprintf (j, "Z-Send %s, %ldb, %ld min.", Filename, f.st_size, ltemp); file_length = f.st_size; if (un_attended && fullscreen) { clear_filetransfer (); sb_move (filewin, 1, 2); sb_puts (filewin, j); elapse_time (); (void) sprintf (j, "%3ld min", ltemp); sb_move (filewin, 2, 69); sb_puts (filewin, j); sb_show (); } else { (void) printf ("%s", j); #if defined __IBMC__ fflush(stdout) ; #endif set_xy (NULL); locate_x += 2; } /*--------------------------------------------------------------------*/ /* Get outgoing file name; no directory path, lower case */ /*--------------------------------------------------------------------*/ #ifndef NEW_PATH_STUFF for (p = (byte *) ((alias != NULL) ? alias : Filename), q = Txbuf; *p;) { if ((*p == '/') || (*p == '\\') || (*p == ':')) q = Txbuf; else *q++ = (char) tolower (*p); p++; } *q++ = '\0'; p = q; #else p = ZMdmFlNmCndtn (Txbuf, ((alias != NULL) ? alias : Filename), NULL, 0); p += strlen (p); q = ++p; #endif /*--------------------------------------------------------------------*/ /* Zero out remainder of file header packet */ /*--------------------------------------------------------------------*/ while (q < (Txbuf + KSIZE)) *q++ = '\0'; /*--------------------------------------------------------------------*/ /* Store filesize, time last modified, and file mode in header packet */ /*--------------------------------------------------------------------*/ #ifdef ANSI_TIME_T filetime = f.st_mtime - ANSI_TIME_T_DELTA; #else filetime = f.st_mtime; #endif (void) sprintf ((char *) p, "%lu %lo %o", f.st_size, filetime, f.st_mode); /*--------------------------------------------------------------------*/ /* Transmit the filename block and { the download */ /*--------------------------------------------------------------------*/ throughput (0, 0L); /*--------------------------------------------------------------------*/ /* Check the results */ /*--------------------------------------------------------------------*/ switch (ZS_SendFile (1 + strlen ((char *) p) + (int) (p - Txbuf), wazoo)) { case ERROR: /*--------------------------------------------------*/ /* Something tragic happened */ /*--------------------------------------------------*/ goto Err_Out; case OK: /*--------------------------------------------------*/ /* File was sent */ /*--------------------------------------------------*/ CLEAR_IOERR (); (void) fclose (Infile); Infile = NULL; goto Done; case ZSKIP: status_line (MSG_TXT (M_REMOTE_REFUSED), Filename); /* Backwards compatibility for a while */ rc = SPEC_COND; /* Success but don't truncate! */ goto Done; default: /*--------------------------------------------------*/ /* Ignore the problem, get next file, trust other */ /* error handling mechanisms to deal with problems */ /*--------------------------------------------------*/ goto Done; } /* switch */ Err_Out: rc = FALSE; Done: if (Infile) (void) fclose (Infile); if (fsent < 0) ZS_EndSend (); XON_DISABLE (); XON_ENABLE (); return rc; } /* send_Zmodem */ /*--------------------------------------------------------------------------*/ /* ZS SEND BINARY HEADER */ /* Send ZMODEM binary header hdr of type type */ /*--------------------------------------------------------------------------*/ static void LOCALFUNC ZS_SendBinaryHeader (unsigned short type, register byte * hdr) { register unsigned short crc; int n; #ifdef DEBUG show_debug_name ("ZS_SendBinaryHeader"); #endif BUFFER_BYTE (ZPAD); BUFFER_BYTE (ZDLE); if ((Crc32t = Txfcs32) != 0) ZS_32SendBinaryHeader (type, hdr); else { BUFFER_BYTE (ZBIN); ZS_SendByte ((byte) type); crc = Z_UpdateCRC (type, 0); for (n = 4; --n >= 0;) { ZS_SendByte (*hdr); crc = Z_UpdateCRC (((unsigned short) (*hdr++)), crc); } ZS_SendByte ((byte) (crc >> 8)); ZS_SendByte ((byte) crc); UNBUFFER_BYTES (); } if (type != ZDATA) { while (CARRIER && !OUT_EMPTY ()) time_release (); if (!CARRIER) CLEAR_OUTBOUND (); } } /* ZS_SendBinaryHeader */ /*--------------------------------------------------------------------------*/ /* ZS SEND BINARY HEADER */ /* Send ZMODEM binary header hdr of type type */ /*--------------------------------------------------------------------------*/ static void LOCALFUNC ZS_32SendBinaryHeader (unsigned short type, register byte * hdr) { unsigned long crc; int n; #ifdef DEBUG show_debug_name ("ZS_32SendBinaryHeader"); #endif BUFFER_BYTE (ZBIN32); ZS_SendByte ((byte) type); crc = 0xFFFFFFFF; crc = Z_32UpdateCRC (type, crc); for (n = 4; --n >= 0;) { ZS_SendByte (*hdr); crc = Z_32UpdateCRC (((unsigned short) (*hdr++)), crc); } crc = ~crc; for (n = 4; --n >= 0;) { ZS_SendByte ((byte) crc); crc >>= 8; } UNBUFFER_BYTES (); } /* ZS_SendBinaryHeader */ /*--------------------------------------------------------------------------*/ /* ZS SEND DATA */ /* Send binary array buf with ending ZDLE sequence frameend */ /*--------------------------------------------------------------------------*/ static void LOCALFUNC ZS_SendData (register byte * buf, int length, unsigned short frameend) { register unsigned short crc; #ifdef DEBUG show_debug_name ("ZS_SendData"); #endif if (Crc32t) ZS_32SendData (buf, length, frameend); else { crc = 0; for (; --length >= 0;) { ZS_SendByte (*buf); crc = Z_UpdateCRC (((unsigned short) (*buf++)), crc); } BUFFER_BYTE (ZDLE); BUFFER_BYTE ((unsigned char) frameend); crc = Z_UpdateCRC (frameend, crc); ZS_SendByte ((byte) (crc >> 8)); ZS_SendByte ((byte) crc); UNBUFFER_BYTES (); } if (frameend == ZCRCW) { SENDBYTE (XON); while (CARRIER && !OUT_EMPTY ()) time_release (); if (!CARRIER) CLEAR_OUTBOUND (); } } /* ZS_SendData */ /*--------------------------------------------------------------------------*/ /* ZS SEND DATA with 32 bit CRC */ /* Send binary array buf with ending ZDLE sequence frameend */ /*--------------------------------------------------------------------------*/ static void LOCALFUNC ZS_32SendData (register byte * buf, int length, unsigned short frameend) { unsigned long crc; #ifdef DEBUG show_debug_name ("ZS_32SendData"); #endif crc = 0xFFFFFFFF; for (; --length >= 0; ++buf) { ZS_SendByte (*buf); crc = Z_32UpdateCRC (((unsigned short) (*buf)), crc); } BUFFER_BYTE (ZDLE); BUFFER_BYTE ((unsigned char) frameend); crc = Z_32UpdateCRC (frameend, crc); crc = ~crc; for (length = 4; --length >= 0;) { ZS_SendByte ((byte) crc); crc >>= 8; } UNBUFFER_BYTES (); } /* ZS_SendData */ /*--------------------------------------------------------------------------*/ /* ZS SEND BYTE */ /* Send character c with ZMODEM escape sequence encoding. */ /* Escape XON, XOFF. Escape CR following @ (Telenet net escape) */ /*--------------------------------------------------------------------------*/ static void LOCALFUNC ZS_SendByte (register byte c) { static byte lastsent; switch (c) { case 015: case 0215: if ((lastsent & 0x7F) != '@') goto SendIt; /* else fall through */ case 020: case 021: case 023: case 0220: case 0221: case 0223: case ZDLE: /*--------------------------------------------------*/ /* Quoted characters */ /*--------------------------------------------------*/ BUFFER_BYTE (ZDLE); c ^= 0x40; /* Then fall through */ default: /*--------------------------------------------------*/ /* Normal character output */ /*--------------------------------------------------*/ SendIt: BUFFER_BYTE (lastsent = c); } /* switch */ } /* ZS_SendByte */ /*--------------------------------------------------------------------------*/ /* ZS GET RECEIVER INFO */ /* Get the receiver's init parameters */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC ZS_GetReceiverInfo () { int n; #ifdef DEBUG show_debug_name ("ZS_GetReceiverInfo"); #endif for (n = 10; --n >= 0;) { switch (Z_GetHeader ((byte *) Rxhdr)) { case ZCHALLENGE: /*--------------------------------------*/ /* Echo receiver's challenge number */ /*--------------------------------------*/ Z_PutLongIntoHeader (Rxpos); Z_SendHexHeader (ZACK, (byte *) Txhdr); continue; case ZCOMMAND: /*--------------------------------------*/ /* They didn't see our ZRQINIT */ /*--------------------------------------*/ Z_PutLongIntoHeader (0L); Z_SendHexHeader (ZRQINIT, (byte *) Txhdr); continue; case ZRINIT: /*--------------------------------------*/ /* */ /*--------------------------------------*/ Rxflags = 0377 & Rxhdr[ZF0]; Rxbuflen = ((word) Rxhdr[ZP1] << 8) | Rxhdr[ZP0]; Txfcs32 = Rxflags & CANFC32; return OK; case ZCAN: case RCDO: case TIMEOUT: return ERROR; case ZRQINIT: if (Rxhdr[ZF0] == ZCOMMAND) continue; /* else fall through */ default: Z_SendHexHeader (ZNAK, (byte *) Txhdr); continue; } /* switch */ } /* for */ return ERROR; } /* ZS_GetReceiverInfo */ /*--------------------------------------------------------------------------*/ /* ZS SEND FILE */ /* Send ZFILE frame and begin sending ZDATA frame */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC ZS_SendFile (int blen, int wazoo) { register int c; long t; #ifdef DEBUG show_debug_name ("ZS_SendFile"); #endif for (;;) { if (got_ESC ()) { CLEAR_OUTBOUND (); XON_DISABLE (); /* Make sure xmitter is unstuck */ send_can (); /* transmit at least 10 cans */ t = timerset (200); /* wait no more than 2 seconds */ while (!timeup (t) && !OUT_EMPTY () && CARRIER) time_release (); /* Give up slice while waiting */ XON_ENABLE (); /* Turn XON/XOFF back on... */ z_log (MSG_TXT (M_KBD_MSG)); return ERROR; } else if (!CARRIER) return ERROR; Txhdr[ZF0] = LZCONV; /* Default file conversion mode */ Txhdr[ZF1] = LZMANAG; /* Default file management mode */ Txhdr[ZF2] = LZTRANS; /* Default file transport mode */ Txhdr[ZF3] = 0; ZS_SendBinaryHeader (ZFILE, (byte *) Txhdr); ZS_SendData (Txbuf, blen, ZCRCW); Again: switch (c = Z_GetHeader ((byte *) Rxhdr)) { case ZRINIT: while ((c = Z_GetByte (50)) > 0) if (c == ZPAD) goto Again; /* if we run out, Fall thru to */ default: continue; case ZCAN: case RCDO: case TIMEOUT: case ZFIN: case ZFERR: case ZABORT: return ERROR; case ZSKIP: /*-----------------------------------------*/ /* Other system wants to skip this file */ /*-----------------------------------------*/ return c; case ZRPOS: /*-----------------------------------------*/ /* Resend from this position... */ /*-----------------------------------------*/ (void) fseek (Infile, Rxpos, SEEK_SET); if (Rxpos != 0L) { status_line (MSG_TXT (M_SYNCHRONIZING_OFFSET), Rxpos); CLEAR_OUTBOUND (); /* Get rid of queued data */ XON_DISABLE (); /* End XON/XOFF restraint */ SENDBYTE (XON); /* Send XON to remote */ XON_ENABLE (); /* Start XON/XOFF again */ } LastZRpos = Strtpos = Txpos = Rxpos; ZRPosCount = 10; CLEAR_INBOUND (); return ZS_SendFileData (wazoo); } /* switch */ } /* while */ } /* ZS_SendFile */ /*--------------------------------------------------------------------------*/ /* ZS SEND FILE DATA */ /* Send the data in the file */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC ZS_SendFileData (int wazoo) { register int c, e; unsigned long ulrate; char j[100]; word newcnt; word blklen; word maxblklen; word goodblks = 0; word goodneeded = 1; long lSize, lTime; long t; #ifdef DEBUG show_debug_name ("ZS_SendFileData"); #endif ulrate = cur_baud.rate_value; maxblklen = (ulrate >= 9600) ? WAZOOMAX : ((ulrate < 300) ? 128 : (int)ulrate / 300 * 256); if (maxblklen > WAZOOMAX) maxblklen = WAZOOMAX; if (!wazoo && maxblklen > KSIZE) maxblklen = KSIZE; if (Rxbuflen && maxblklen > (unsigned) Rxbuflen) maxblklen = Rxbuflen; if (wazoo && (remote_capabilities & ZED_ZIPPER)) maxblklen = KSIZE; blklen = (fstblklen != 0) ? fstblklen : maxblklen; goodneeded = (fstblklen != 0) ? 8 : 1; SomeMore: if (CHAR_AVAIL ()) { WaitAck: switch (c = ZS_SyncWithReceiver (1)) { case ZSKIP: /*-----------------------------------------*/ /* Skip this file */ /*-----------------------------------------*/ return c; case ZACK: break; case ZRPOS: /*-----------------------------------------*/ /* Resume at this position */ /*-----------------------------------------*/ blklen = ((blklen >> 2) > 64) ? blklen >> 2 : 64; goodblks = 0; goodneeded = ((goodneeded << 1) > 16) ? 16 : goodneeded << 1; break; case ZRINIT: /*-----------------------------------------*/ /* Receive init */ /*-----------------------------------------*/ goto file_sent; case TIMEOUT: /*-----------------------------------------*/ /* Timed out on message from other side */ /*-----------------------------------------*/ break; default: z_log (MSG_TXT (M_CAN_MSG)); (void) fclose (Infile); return ERROR; } /* switch */ /* * Noise probably got us here. Odds of surviving are not good. But we * have to get unstuck in any event. * */ Z_UncorkTransmitter (); /* Get our side free if need be */ SENDBYTE (XON); /* Send an XON to release other side */ while (CHAR_AVAIL ()) { switch (MODEM_IN ()) { case CAN: case RCDO: case ZPAD: goto WaitAck; } /* switch */ } /* while */ } /* while */ newcnt = Rxbuflen; Z_PutLongIntoHeader (Txpos); ZS_SendBinaryHeader (ZDATA, (byte *) Txhdr); do { if (got_ESC ()) { CLEAR_OUTBOUND (); XON_DISABLE (); /* Make sure xmitter is unstuck */ send_can (); /* transmit at least 10 cans */ t = timerset (200); /* wait no more than 2 seconds */ while (!timeup (t) && !OUT_EMPTY () && CARRIER) time_release (); /* Give up slice while waiting */ XON_ENABLE (); /* Turn XON/XOFF back on... */ z_log (MSG_TXT (M_KBD_MSG)); goto oops; } if (!CARRIER) goto oops; if ((unsigned) (c = fread (Txbuf, 1, blklen, Infile)) != z_size) { if (fullscreen && un_attended) { sb_move (filewin, 2, 12); sb_puts (filewin, ultoa (((unsigned long) (z_size = c)), e_input, 10)); sb_puts (filewin, " "); elapse_time (); sb_show (); } else { gotoxy (locate_x + 10, locate_y); (void) cputs (ultoa (((unsigned long) (z_size = c)), e_input, 10)); (void) putch (' '); } } if ((unsigned) c < blklen) e = ZCRCE; else if (Rxbuflen && (newcnt -= c) <= 0) e = ZCRCW; else e = ZCRCG; ZS_SendData (Txbuf, c, (unsigned short) e); (void) sprintf (j, "%3ld min", ((file_length - Txpos) * 10L / ulrate + 53L) / 54L); if (fullscreen && un_attended) { sb_move (filewin, 2, 2); sb_puts (filewin, ultoa (((unsigned long) Txpos), e_input, 10)); sb_puts (filewin, " "); sb_move (filewin, 2, 69); sb_puts (filewin, j); elapse_time (); sb_show (); } else { gotoxy (locate_x, locate_y); (void) cputs (ultoa (((unsigned long) Txpos), e_input, 10)); (void) putch (' '); (void) putch (' '); gotoxy (locate_x + 20, locate_y); (void) printf ("%s", j); (void) putch (' '); #if defined __IBMC__ fflush(stdout) ; #endif } Txpos += c; if (blklen < maxblklen && ++goodblks > goodneeded) { blklen = ((word) (blklen << 1) < maxblklen) ? blklen << 1 : maxblklen; goodblks = 0; } if (e == ZCRCW) goto WaitAck; while (CHAR_AVAIL ()) { switch (MODEM_IN ()) { case CAN: case RCDO: case ZPAD: /*--------------------------------------*/ /* Interruption detected; */ /* stop sending and process complaint */ /*--------------------------------------*/ z_message (MSG_TXT (M_TROUBLE)); CLEAR_OUTBOUND (); ZS_SendData (Txbuf, 0, ZCRCE); goto WaitAck; } /* switch */ } /* while */ } /* do */ while (e == ZCRCG); for (;;) { Z_PutLongIntoHeader (Txpos); ZS_SendBinaryHeader (ZEOF, (byte *) Txhdr); switch (ZS_SyncWithReceiver (7)) { case ZACK: continue; case ZRPOS: /*-----------------------------------------*/ /* Resume at this position... */ /*-----------------------------------------*/ goto SomeMore; case ZRINIT: /*-----------------------------------------*/ /* Receive init */ /*-----------------------------------------*/ file_sent: if (locate_y && !(fullscreen && un_attended)) gotoxy (2, (byte) locate_y - 1); lSize = Txpos - Strtpos; lTime = throughput (1, Txpos - Strtpos); status_line ("%s-Z%s %s", MSG_TXT (M_FILE_SENT), Crc32t ? "/32" : "", Filename); update_files (1, Filename, lSize, lTime, 0); return OK; case ZSKIP: /*-----------------------------------------*/ /* Request to skip the current file */ /*-----------------------------------------*/ z_log (MSG_TXT (M_SKIP_MSG)); CLEAR_IOERR (); (void) fclose (Infile); return c; default: oops: z_log (MSG_TXT (M_CAN_MSG)); (void) fclose (Infile); return ERROR; } /* switch */ } /* while */ } /* ZS_SendFileData */ /*--------------------------------------------------------------------------*/ /* ZS SYNC WITH RECEIVER */ /* Respond to receiver's complaint, get back in sync with receiver */ /*--------------------------------------------------------------------------*/ static int LOCALFUNC ZS_SyncWithReceiver (int num_errs) { register int c; char j[50]; #ifdef DEBUG show_debug_name ("ZS_SyncWithReceiver"); #endif for (;;) { c = Z_GetHeader ((byte *) Rxhdr); CLEAR_INBOUND (); switch (c) { case TIMEOUT: z_message (MSG_TXT (M_TIMEOUT)); if ((num_errs--) >= 0) break; /* else fall through */ case ZCAN: case ZABORT: case ZFIN: case RCDO: z_log (MSG_TXT (M_ERROR)); return ERROR; case ZRPOS: if (Rxpos == LastZRpos) /* Same as last time? */ { if (!(--ZRPosCount)) /* Yup, 10 times yet? */ return ERROR; /* Too many, get out */ } else ZRPosCount = 10; /* Reset repeat count */ LastZRpos = Rxpos; /* Keep track of this */ rewind (Infile); /* In case file EOF seen */ (void) fseek (Infile, Rxpos, SEEK_SET); Txpos = Rxpos; (void) sprintf (j, MSG_TXT (M_RESENDING_FROM), ultoa (((unsigned long) (Txpos)), e_input, 10)); z_message (j); return c; case ZSKIP: z_log (MSG_TXT (M_SKIP_MSG)); /* fall through */ case ZRINIT: CLEAR_IOERR (); (void) fclose (Infile); return c; case ZACK: z_message (NULL); return c; default: z_message (IDUNNO_msg); ZS_SendBinaryHeader (ZNAK, (byte *) Txhdr); continue; } /* switch */ } /* while */ } /* ZS_SyncWithReceiver */ /*--------------------------------------------------------------------------*/ /* ZS END SEND */ /* Say BIBI to the receiver, try to do it cleanly */ /*--------------------------------------------------------------------------*/ static void LOCALFUNC ZS_EndSend () { #ifdef DEBUG show_debug_name ("ZS_EndSend"); #endif CLEAR_OUTBOUND (); CLEAR_INBOUND (); for (;;) { Z_PutLongIntoHeader (0L); ZS_SendBinaryHeader (ZFIN, (byte *) Txhdr); switch (Z_GetHeader ((byte *) Rxhdr)) { case ZFIN: SENDBYTE ('O'); SENDBYTE ('O'); while (CARRIER && !OUT_EMPTY ()) time_release (); if (!CARRIER) CLEAR_OUTBOUND (); /* fallthrough... */ case ZCAN: case RCDO: case TIMEOUT: return; } /* switch */ } /* while */ } /* ZS_EndSend */