|
|
/* zmdm_snd.c -- Routines to handle zmodem sending for HyperACCESS
* * Copyright 1990 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 20 $ * $Date: 7/12/02 8:32a $ */
#include <windows.h>
#pragma hdrstop
#include <setjmp.h>
#include <tdll\stdtyp.h>
#include <tdll\mc.h>
#include <tdll\com.h>
#include <tdll\assert.h>
#include <tdll\session.h>
#include <tdll\load_res.h>
#include <term\res.h>
#include <tdll\globals.h>
#include <tdll\file_io.h>
#include <tdll\htchar.h>
#define BYTE unsigned char
#include "itime.h"
#include "xfr_dsp.h"
#include "xfr_todo.h"
#include "xfr_srvc.h"
#include "xfer.h"
#include "xfer.hh"
#include "xfer_tsc.h"
#include "foo.h"
#include "zmodem.hh"
#include "zmodem.h"
/*lint -e502*/ /* lint seems to want the ~ operator applied only
* only to unsigned, we're using uchar */
#define ZBUF_SIZE 1024
/* * * * * * * * * * * * * * * *
* local function prototypes * * * * * * * * * * * * * * * * */
VOID long_to_octal(LONG lVal, TCHAR *pszStr);
/* * * * * * * *
* Functions * * * * * * * * */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* zmdm_snd * * DESCRIPTION: * Sends a file using ZMODEM protocol. Does not support starting task * at other end (sending a "rz\r" text string) or remote commands. * * ARGUMENTS: * attended -- TRUE if user is probably in attendance. Controls the display * of some messages. * * RETURNS: * True if transfer completes successfully, FALSE otherwise. */ USHORT zmdm_snd(HSESSION h, int method, int attended, unsigned nfiles, long nbytes) { ZC *zc = NULL; TCHAR sfname[FNAME_LEN]; // file name of file being sent
BOOL got_file = FALSE; // controls when to complete batch op
int tries = 0; // number of retries for each packet
unsigned total_tries = 0; // number of retries for entire transfer
int xstatus = TSC_OK; // winds up with overall status of transfer
int override = FALSE; // set TRUE if comm. details changed to
unsigned int uiOldOptions = 0; // int hld_send_cdelay; // accomodate xmodem
// char hld_bits_per_char; // hld* vars. used to restore port after
// char hld_parity_type; // transfer if override is used
XFR_Z_PARAMS *pZ = NULL; #if defined(DEADWOOD)
DWORD nLen; #endif // defined(DEADWOOD)
// tzset();
if (xfer_set_comport(h, TRUE, &uiOldOptions) != TRUE) { goto done; } else { override = TRUE; }
// RemoteClear();
zc = malloc(sizeof(ZC)); if (zc == NULL) { goto done; } memset(zc, 0, sizeof(ZC));
zc->hSession = h; zc->hCom = sessQueryComHdl(h); zc->nMethod = method; zc->fSavePartial = TRUE; zc->ulOverride = (unsigned long)0;
zc->real_bytes = 0L; zc->file_bytes = 0L; zc->total_bytes = 0L; zc->actual_bytes = 0L; zc->nSkip = FALSE;
zc->flagkey = NULL; // zc->flagkey_buf = NULL;
// zc->intrjmp = NULL;
zc->fh = NULL; zc->basesize = 0L; zc->xfertimer = -1L; zc->xfertime = -1L; zc->nfiles = nfiles; /* make these available to display routines */ zc->filen = 0; zc->filesize = -1L; zc->nbytes = nbytes;
//zc->Rxtimeout = 0L; // Set below.
zc->z_crctab = NULL; #if defined(DEADWOOD)
resLoadDataBlock(glblQueryDllHinst(), IDT_CSB_CRC_TABLE, &zc->z_crctab, &nLen); assert(nLen != 0); #else // defined(DEADWOOD)
zc->z_crctab = usCrc16Lookup; #endif // defined(DEADWOOD)
if (zc->z_crctab == NULL) { xstatus = TSC_NO_MEM; goto done; }
zc->z_cr3tab = NULL; #if defined(DEADWOOD)
resLoadDataBlock(glblQueryDllHinst(), IDT_CRC_32_TAB, &zc->z_cr3tab, &nLen); assert(nLen != 0); #else // defined(DEADWOOD)
zc->z_cr3tab = ulCrc32Lookup; #endif // defined(DEADWOOD)
if (zc->z_cr3tab == NULL) { xstatus = TSC_NO_MEM; goto done; }
zc->Rxframeind = 0; // Not used in file sends.
//zc->Rxtype = 0; // Not used in file sends.
//memset(zc->Rxhdr, '\0', sizeof(zc->Rxhdr)); // Not used in file sends.
//memset(zc->Txdr, '\0', sizeof(zc->Txdr));
zc->Rxpos = 0L; zc->Txpos = 0L; //zc->Txfcs32 = TRUE; // Set below.
zc->Crc32t = TRUE; //zc->Crc32 = TRUE; // Set below.
memset(zc->Attn, '\0', sizeof(zc->Attn));
zc->lastsent = 0; zc->Not8bit = 0; zc->displayed_time = 0L; //zc->Zctlesc = 0; // Set below.
zc->Zrwindow = 0; zc->Eofseen = FALSE; zc->tryzhdrtype = ZRQINIT; zc->Thisbinary = FALSE; zc->Filemode = 0; zc->Modtime = 0L; zc->do_init = FALSE; //zc->zconv = TEXT('\0'); // Should be set here?
//zc->zmanag = TEXT('\0'); // Should be set here?
//zc->ztrans = TEXT('\0'); // Should be set here?
zc->secbuf = NULL; zc->fname = NULL; zc->our_fname = NULL;
//memset(zc->stP, 0, sizeof(zc->stP);
zc->txbuf = malloc(ZBUF_SIZE); if (zc->txbuf == NULL) { xstatus = TSC_NO_MEM; goto done; } TCHAR_Fill(zc->txbuf, TEXT('\0'), ZBUF_SIZE);
//zc->Filesleft = 0; // Set below.
//zc->Totalleft = 0; // Set below.
zc->blklen = ZBUF_SIZE; zc->blkopt = 0; zc->Beenhereb4 = 0; //zc->Wantfcs32 = FALSE; // Set below.
zc->Rxflags = 0; //zc->Rxbuflen = (unsigned)0; // Set below.
zc->Txwindow = (unsigned)0; zc->Txwcnt = (unsigned)0; zc->Txwspac = (unsigned)0; zc->Myattn[0] = '\0'; zc->errors = 0; zc->s_error = 0; zc->pstatus = -4; zc->last_event = -4; zc->Lskipnocor = FALSE; zc->Lastsync = zc->Rxpos; zc->Lrxpos = zc->Rxpos; // hp_report_xtime(0); /* make invalid in case transfer bombs */
if (setjmp(zc->flagkey_buf) != 0) { stohdr(zc, 0L); zshhdr(zc, ZCAN, zc->Txhdr); canit(zc); if (zc->fh) { fio_close(zc->fh); } zc->fh = NULL; zmdm_retval(zc, TRUE, ZABORT); xstatus = TSC_USER_CANNED; canit(zc); goto done; }
pZ = (XFR_Z_PARAMS *)xfer_get_params(zc->hSession, zc->nMethod); assert(pZ);
if (pZ == NULL) { xstatus = TSC_NO_MEM; goto done; }
zc->Zctlesc = pZ->nEscCtrlCodes; zc->Rxtimeout = pZ->nRetryWait; zc->Wantfcs32 = (pZ->nCrcType == ZP_CRC_32);
if (zc->Rxtimeout <= 0) { zc->Rxtimeout = 10; } zc->Rxtimeout *= 10;
zc->Txfcs32 = zc->Wantfcs32; zc->Rxbuflen = (unsigned)0;
total_tries = 0; zc->Filesleft = zc->nfiles; zc->Totalleft = zc->nbytes;
zmdmr_totalsize(zc, zc->nbytes); zmdmr_filecnt(zc, zc->nfiles); xferMsgErrorcnt(h, 0);
got_file = TRUE;
if (attended) { /* it might be necessary to start up the other end */ sendline(zc, &zc->stP, 'r'); sendline(zc, &zc->stP, 'z'); sendline(zc, &zc->stP, '\r'); flushmo(zc, &zc->stP); stohdr(zc, 0L); zshhdr(zc, ZRQINIT, zc->Txhdr); } else { stohdr(zc, 0L); }
switch (xstatus = getzrxinit (zc)) { case ZCAN: //
// Set the last error to the TSC_USER_CANNED for
// error reporting purposes. It seems as if the
// errors are reversed in the error array, but
// correcting them in the error array caused other
// undesirable side effects. REV: 02/23/2001
//
xstatus = zmdm_error(zc, ZABORT); break;
case ZABORT: //
// Set the last error to the TSC_RMT_CANNED for
// error reporting purposes. It seems as if the
// errors are reversed in the error array, but
// correcting them in the error array caused other
// undesirable side effects. REV: 02/23/2001
//
xstatus = zmdm_error(zc, ZCAN); break;
case TIMEOUT: case ZFERR: case ZBADFMT: case ERROR: case ZCARRIER_LOST: xstatus = zmdm_error(zc, xstatus); goto done;
default: xstatus = zmdm_error(zc, xstatus); break; }
while (got_file) { if ((got_file = xfer_nextfile(h, sfname)) == TRUE) { /* zc->total_bytes += zc->file_bytes; */ /* zc->actual_bytes += zc->file_bytes; */ /* zc->file_bytes = 0L; */ ++zc->filen; xstatus = wcs(zc, sfname); switch (xstatus) { case ZABORT: //
// Set the last error to the TSC_USER_CANNED for
// error reporting purposes. It seems as if the
// errors are reversed in the error array, but
// correcting them in the error array caused other
// undesirable side effects. REV: 02/23/2001
//
xstatus = zmdm_error(zc, ZCAN); goto done;
case ZCAN: //
// Set the last error to the TSC_RMT_CANNED for
// error reporting purposes. It seems as if the
// errors are reversed in the error array, but
// correcting them in the error array caused other
// undesirable side effects. REV: 02/23/2001
//
xstatus = zmdm_error(zc, ZABORT); goto done;
case TIMEOUT: case ZFERR: case ZCARRIER_LOST: xstatus = zmdm_error(zc, xstatus); goto done;
case ERROR: case ZBADFMT: case ZCOMPL: case ZSKIP: default: xstatus = zmdm_error(zc, xstatus); break;
case OK: xstatus = TSC_OK; break;
} /* end switch */ xfer_log_xfer(h, TRUE, sfname, NULL, xstatus); zmdms_progress(zc, FILE_DONE); zc->xfertime = (long)interval(zc->xfertimer); zc->total_bytes += zc->file_bytes; zc->actual_bytes += zc->real_bytes; zc->file_bytes = 0L; zc->real_bytes = 0L; } /* end if */
} /* end while */
done:
if (zc == NULL || zc->txbuf == NULL || zc->z_crctab == NULL || zc->z_cr3tab == NULL) { xstatus = TSC_NO_MEM; }
if (xstatus == TSC_OK) { if (zc != NULL) { /* if we recorded a previous error, use it, else check this */ if (zc->filen == 0) { xstatus = TSC_CANT_START; } else if (zc->filen != zc->nfiles) { xstatus = TSC_GEN_FAILURE; } } else { xstatus = TSC_GEN_FAILURE; } }
if (got_file) { xfer_log_xfer(h, TRUE, sfname, NULL, xstatus); }
if (zc != NULL) { if (xstatus != TSC_USER_CANNED && xstatus != TSC_RMT_CANNED && xstatus != TSC_LOST_CARRIER && xstatus != TSC_GEN_FAILURE && xstatus != TSC_NO_RESPONSE && xstatus != TSC_CANT_START) { saybibi(zc); } zmdms_progress(zc, TRANSFER_DONE); }
if (override) { xfer_restore_comport(h, uiOldOptions); }
if (zc != NULL) { // hp_report_xtime((unsigned)zc->xfertime);
if (zc->errors > 99) { xstatus = TSC_ERROR_LIMIT; }
if (zc->fh) { fio_close(zc->fh); }
if (zc->txbuf != NULL) { free(zc->txbuf); zc->txbuf = NULL; } if (zc->z_crctab != NULL) { #if defined(DEADWOOD)
resFreeDataBlock(h, zc->z_crctab); zc->z_crctab = NULL; #else // defined(DEADWOOD
//
// We don't need to free zc->z_crctab since it is pointing
// to a static constant array. REV: 4/10/2002
//
zc->z_crctab = NULL; #endif // defined(DEADWOOD)
} if (zc->z_cr3tab) { #if defined(DEADWOOD)
resFreeDataBlock(h, zc->z_cr3tab); zc->z_cr3tab = NULL; #else // defined(DEADWOOD
//
// We don't need to free zc->z_cr3tab since it is pointing
// to a static constant array. REV: 4/10/2002
//
zc->z_cr3tab = NULL; #endif // defined(DEADWOOD)
}
free(zc); zc = NULL; }
xferMsgClose(h);
return((unsigned)xstatus); }
/*----------------------------------------------------------------------+
| wcs +----------------------------------------------------------------------*/ int wcs(ZC *zc, TCHAR FAR *oname) { int c = OK; TCHAR name[PATHLEN];
StrCharCopyN(name, oname, PATHLEN);
if ((xfer_opensendfile(zc->hSession, &zc->fh, oname, /* full path name of file to open */ &zc->filesize, NULL, /* name to send not needed yet */ NULL)) != 0) { DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0); return ERROR; }
zmdms_newfile(zc, zc->filen, oname, zc->filesize);
zc->Eofseen = FALSE;
switch (c = wctxpn(zc, name)) { case ERROR: if (zc->fh != NULL) { fio_close(zc->fh); } DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0); break;
default: break; } return c; }
/*----------------------------------------------------------------------+
| long_to_octal +----------------------------------------------------------------------*/ VOID long_to_octal(LONG lVal, TCHAR *pszStr) { _ltoa(lVal, pszStr, 8); }
/*----------------------------------------------------------------------+
| wctxpn - Generate and transmit pathname block consisting of pathname | (null terminated), file length, mode time and file mode in | octal as povided by the Unix fstat call. | N.B.: modifies the passed name, may extend it! +----------------------------------------------------------------------*/ int wctxpn(ZC *zc, TCHAR FAR *name) { register char *p; register char *q; int serial_number = 0; XFR_Z_PARAMS *pZ;
pZ = (XFR_Z_PARAMS *)xfer_get_params(zc->hSession, zc->nMethod); assert(pZ);
if(pZ == NULL) { return ERROR; }
#if defined(UPPER_FEATURES)
/* TODO: fix the way blklen and txbuf don't work together correctly */ zc->blklen = 1 << (pZ->nBlkSize + 5); #endif // defined(UPPER_FEATURES)
xfer_name_to_send(zc->hSession, name, zc->txbuf);
q = &zc->txbuf[StrCharGetByteCount(zc->txbuf) + 1];
/*
* The ZMODEM spec says that file names must be send as lower case */ //MPT:12-11-97 spec-schmeck - this is the cause of microsoft bug #32233
// Since this character could be the second byte of a DBCS character
// we should just leave things alone. Otherwise, we end up changing
// the wide character.
#if 0
for (p = zc->txbuf; p < q; p++) { // Don't use this stuff in a Chicago DLL
// if (isupper(*p))
// *p = (char)tolower(*p);
if ((*p >= 'A') && (*p <= 'Z')) { *p |= 0x20; } } #else
//
// Modified to lowercase filename characters only if they are not
// DBCS characters. This way HyperTerminal will follow the Zmodem
// specification for lowercase filenames. REV: 11/12/2001
//
for (p = zc->txbuf; p < q; p++) { if ((*p >= 'A') && (*p <= 'Z')) { //
// Skip this character and the next if this is a DBCS
// character, otherwise lowercase the character.
//
if (isDBCSChar(*p)) { p++; } else { *p |= 0x20; } } } #endif
p = q; while (q < (zc->txbuf + ZBUF_SIZE)) { *q++ = 0; /* could be speeded up somewhat */ }
if (*name) { long lDosTime; BYTE acTime[32]; BYTE acMode[32];
lDosTime = itimeGetFileTime(name);
// lDosTime -= timezone;
long_to_octal(lDosTime, acTime); long_to_octal(0L, acMode); wsprintf(p, "%lu %s %s %d %d %ld", zc->filesize, acTime, acMode, serial_number, zc->Filesleft, zc->Totalleft); zc->Totalleft -= zc->filesize; }
if (--zc->Filesleft <= 0) { zc->Totalleft = 0; } if (zc->Totalleft < 0) { zc->Totalleft = 0; }
/* force 1k blocks if name won't fit in 128 byte block */ if (zc->txbuf[125]) zc->blklen=1024; else { /* A little goodie for IMP/KMD */ zc->txbuf[127] = (char)((zc->filesize + 127) >>7); zc->txbuf[126] = (char)((zc->filesize + 127) >>15); } return zsendfile(zc, zc->txbuf, (int)(1+StrCharGetByteCount(p)+(p - zc->txbuf))); }
/*----------------------------------------------------------------------+
| zfilbuf - Fill buffer with blklen chars. +----------------------------------------------------------------------*/ int zfilbuf(ZC *zc) { int n; int bsize;
bsize = ZBUF_SIZE;
if (zc->blklen <= ZBUF_SIZE) bsize = zc->blklen;
n = fio_read(zc->txbuf, 1, bsize, zc->fh);
if (n < bsize) { zc->Eofseen = TRUE; } return n; }
/*----------------------------------------------------------------------+
| canit - Send cancel string to get the other end to shut up. +----------------------------------------------------------------------*/ void canit(ZC *zc) { int ii;
for (ii = 0; ii < 10; ii++) { sendline(zc, &zc->stP, 24); } for (ii = 0; ii < 10; ii++) { sendline(zc, &zc->stP, 8); } flushmo(zc, &zc->stP); // purgeline(zc);
ComRcvBufrClear(zc->hCom); }
/*----------------------------------------------------------------------+
| getzrzinit - Get the receiver's init parameters. +----------------------------------------------------------------------*/ int getzrxinit(ZC *zc) { register int n; register int c = ERROR; int x; XFR_Z_PARAMS *pZ;
pZ = (XFR_Z_PARAMS *)xfer_get_params(zc->hSession, zc->nMethod); assert(pZ);
if (pZ == NULL) { return ERROR; }
if (pZ->nXferMthd == ZP_XM_STREAM) { zc->Txwindow = (unsigned)0; } else { zc->Txwindow = (pZ->nWinSize + 1) * 1024; }
for (n = 10; --n >= 0; ) { switch (x = xfer_user_interrupt(zc->hSession)) { case XFER_SKIP: case XFER_ABORT: zmdms_update(zc, ZCAN); longjmp(zc->flagkey_buf, 5); break;
default: break; }
if (xfer_carrier_lost(zc->hSession)) { return ZCARRIER_LOST; }
switch (c = zgethdr(zc, zc->Rxhdr, 'T')) { case ZCHALLENGE: /* Echo receiver's challenge numbr */ stohdr(zc, zc->Rxpos); zshhdr(zc, ZACK, zc->Txhdr); continue;
case ZCOMMAND: /* They didn't see out ZRQINIT */ stohdr(zc, 0L); zshhdr(zc, ZRQINIT, zc->Txhdr); continue;
case ZRINIT: zc->Rxflags = 0377 & zc->Rxhdr[ZF0]; zc->Txfcs32 = (zc->Wantfcs32 && (zc->Rxflags & CANFC32)); zc->Zctlesc |= zc->Rxflags & TESCCTL; zc->Rxbuflen = (0377 & zc->Rxhdr[ZP0])+((0377 & zc->Rxhdr[ZP1])<<8); if ( !(zc->Rxflags & CANFDX)) { zc->Txwindow = (unsigned)0; }
/* Set initial subpacket length */ if (zc->blklen < 1024) { /* Command line override? */ if (cnfgBitRate() > 2400) { zc->blklen = 1024; } else if (cnfgBitRate() > 1200) { zc->blklen = 512; } else if (cnfgBitRate() > 300) { zc->blklen = 256; } } if (zc->Rxbuflen && ((unsigned)zc->blklen > zc->Rxbuflen)) { zc->blklen = zc->Rxbuflen; } if (zc->blkopt && (zc->blklen > zc->blkopt)) { zc->blklen = zc->blkopt; }
return (sendzsinit(zc));
case TIMEOUT: continue;
case ZCAN: case ZCARRIER_LOST: case ZABORT: case ZFERR: return c;
case ZRQINIT: if (zc->Rxhdr[ZF0] == ZCOMMAND) { continue; } default: zshhdr(zc, ZNAK, zc->Txhdr); continue; } }
if (c == TIMEOUT) { return TIMEOUT; }
return ERROR; }
/*----------------------------------------------------------------------+
| sendzsinit - Send send-init information. +----------------------------------------------------------------------*/ int sendzsinit(ZC *zc) { register int c;
if (zc->Myattn[0] == '\0' && (!zc->Zctlesc || (zc->Rxflags & TESCCTL))) { return OK; } zc->errors = 0; for (;;) { stohdr(zc, 0L); if (zc->Zctlesc) { zc->Txhdr[ZF0] |= TESCCTL; zshhdr(zc, ZSINIT, zc->Txhdr); } else { zsbhdr(zc, ZSINIT, zc->Txhdr); } zsdata(zc, zc->Myattn, 1+StrCharGetByteCount(zc->Myattn), ZCRCW); c = zgethdr(zc, zc->Rxhdr, 'T'); switch (c) { case ZRPOS: return c;
case ZCAN: case ZABORT: case ZFERR: case TIMEOUT: case ZCARRIER_LOST: return c; case ZACK: return OK; default: if (++zc->errors > 99) { return ERROR; } xferMsgErrorcnt(zc->hSession, ++zc->errors); continue; } } }
/*----------------------------------------------------------------------+
| zsendfile - Send file name and releated info. +----------------------------------------------------------------------*/ int zsendfile(ZC *zc, char *buf, int blen) { unsigned char chr; register int c; register unsigned long crc; XFR_Z_PARAMS *pZ;
pZ = (XFR_Z_PARAMS *)xfer_get_params(zc->hSession, zc->nMethod); assert(pZ);
if (pZ == NULL) { return ERROR; }
for (;;) { zc->Txhdr[ZF0] = 0; if (zc->Txhdr[ZF0] == 0) { if (pZ->nCrashRecSend == ZP_CRS_ONCE || pZ->nCrashRecSend == ZP_CRS_ALWAYS) { zc->Txhdr[ZF0] = ZCRESUM; } } if (zc->Txhdr[ZF0] == 0) { if (pZ->nCrashRecSend == ZP_CRS_NEG) { zc->Txhdr[ZF0] = ZCBIN; } } if (zc->Txhdr[ZF0] == 0) { if (pZ->nEolConvert) { zc->Txhdr[ZF0] = ZCNL; } }
switch (pZ->nOverwriteOpt) { default: case ZP_OO_NONE: zc->Txhdr[ZF1] = 0; break; case ZP_OO_NEVER: zc->Txhdr[ZF1] = ZMPROT; break; case ZP_OO_L_D: zc->Txhdr[ZF1] = ZMDIFF; break; case ZP_OO_NEWER: zc->Txhdr[ZF1] = ZMNEW; break; case ZP_OO_ALWAYS: zc->Txhdr[ZF1] = ZMCLOB; break; case ZP_OO_APPEND: zc->Txhdr[ZF1] = ZMAPND; break; case ZP_OO_CRC: zc->Txhdr[ZF1] = ZMCRC; break; case ZP_OO_N_L: zc->Txhdr[ZF1] = ZMNEWL; break; }
if (zc->Lskipnocor) { zc->Txhdr[ZF1] |= ZMSKNOLOC; } /* ZF2 is for ZTCRYPT (encryption) and ZTRLE and ZTLZW (compression) */ zc->Txhdr[ZF2] = 0; /* ZF3 is for ZTSPARS (special sparse file option) */ zc->Txhdr[ZF3] = 0; zsbhdr(zc, ZFILE, zc->Txhdr); zsdata(zc, buf, blen, ZCRCW); if (zc->xfertimer == (-1L)) { zc->xfertimer = (long)startinterval(); }
again: c = zgethdr(zc, zc->Rxhdr, 'T'); switch (c) { case ZRINIT: while ((c = readline(zc, 300)) > 0) { if (c == ZPAD) { goto again; } } continue;
default: continue;
case TIMEOUT: case ZCARRIER_LOST: case ZCAN: case ZABORT: case ZFERR: DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0); return c;
case ZFIN: return ERROR;
case ZCRC: crc = 0xFFFFFFFFL; while (fio_read(&chr, 1, 1, zc->fh) && --zc->Rxpos) { crc = UPDC32(zc, (int)chr, crc); } crc = ~crc; fio_errclr(zc->fh); /* Clear EOF */ fio_seek(zc->fh, 1, FIO_SEEK_SET); stohdr(zc, crc); zsbhdr(zc, ZCRC, zc->Txhdr); goto again;
case ZSKIP: zc->total_bytes += zc->filesize; fio_close(zc->fh); zc->fh = NULL; return c;
case ZRPOS: /*
* Suppress zcrcw request otherwise triggered by * lastyunc==bytcnt */ if (zc->Rxpos) { if (fio_seek(zc->fh, zc->Rxpos, FIO_SEEK_SET) == (-1)) { DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0); return ERROR; } } zc->Lastsync = (zc->file_bytes = zc->Txpos = zc->Rxpos) -1; return zsendfdata(zc); } } }
/*----------------------------------------------------------------------+
| zsendfdata - Send the data in the file. +----------------------------------------------------------------------*/ int zsendfdata(ZC *zc) { int c, e, n; int newcnt; long tcount = 0; TCHAR ch; int junkcount; /* Counts garbage chars received by TX */ static int tleft = 6; /* Counter for test mode */ int x;
zc->Lrxpos = 0; junkcount = 0; zc->Beenhereb4 = 0; somemore:
if (setjmp(zc->intrjmp)) { waitack: junkcount = 0; c = getinsync(zc, 0); gotack: switch (c) { default: case ZSKIP: case ZCAN: case ZFERR: DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0); if (zc->fh) fio_close(zc->fh); zc->fh = NULL; return c;
case ZACK: case ZRPOS: break;
case ZRINIT: return OK; } /*
* If the reverse channel can be tested for data, * this logic may be used to detect error packets * sent by the receiver, in place of setjmp/longjmp * rdchk() returns non 0 if a character is available */ // while (rdchk(zc) != ERROR)
while (mComRcvBufrPeek(zc->hCom, &ch) != 0) { switch (readline(zc, 1)) { case CAN: case ZPAD: c = getinsync(zc, 1); goto gotack;
case XOFF: /* Wait a while for an XON */ case XOFF|0200: readline(zc, zc->Rxtimeout); break;
default: break; } } }
newcnt = zc->Rxbuflen; zc->Txwcnt = (unsigned)0; stohdr(zc, zc->Txpos); zsbhdr(zc, ZDATA, zc->Txhdr);
do { switch (x = xfer_user_interrupt(zc->hSession)) { case XFER_SKIP: case XFER_ABORT: zmdms_update(zc, ZCAN); longjmp(zc->flagkey_buf, 6); break;
default: break; }
if (xfer_carrier_lost(zc->hSession)) { return ZCARRIER_LOST; }
n = zfilbuf(zc); if (zc->Eofseen) { e = ZCRCE; } else if (junkcount > 3) { e = ZCRCW; } else if (zc->file_bytes == zc->Lastsync) { e = ZCRCW; } else if (zc->Rxbuflen && (newcnt -= n) <= 0) { e = ZCRCW; } else if (zc->Txwindow && (zc->Txwcnt += n) >= zc->Txwspac) { zc->Txwcnt = (unsigned)0; e = ZCRCQ; } else { e = ZCRCG; }
zsdata(zc, zc->txbuf, n, e); zc->file_bytes = zc->Txpos += n; zc->real_bytes += n;
zmdms_update(zc, ZRPOS); zmdms_progress(zc, 0);
if (e == ZCRCW) { goto waitack; } /*
* If the reverse channel can be tested for data, * this logic may be used to detect error packets * sent by the receiver, in place of setjmp/longjmp * rdchk() returns non 0 if a character is available */ // while (rdchk(zc) != ERROR)
while (mComRcvBufrPeek(zc->hCom, &ch) != 0) { switch (readline(zc, 1)) { case CAN: case ZPAD: c = getinsync(zc, 1); if (c == ZACK) { break; } /* zcrce - dinna wanna starta ping-pong game */ zsdata(zc, zc->txbuf, 0, ZCRCE); goto gotack;
case XOFF: /* Wait a while for an XON */ case XOFF|0200: readline(zc, zc->Rxtimeout); default: if (ch != ZFREECNT) { ++junkcount; } break; } } if (zc->Txwindow) { while ((unsigned)(tcount = zc->Txpos - zc->Lrxpos) >= zc->Txwindow) { if (e != ZCRCQ) { zsdata(zc, zc->txbuf, 0, e = ZCRCQ); } c = getinsync(zc, 1); if (c != ZACK) { zsdata(zc, zc->txbuf, 0, ZCRCE); goto gotack; } } } } while (!zc->Eofseen);
for (;;) { stohdr(zc, zc->Txpos); zsbhdr(zc, ZEOF, zc->Txhdr); switch (c = getinsync(zc, 0)) { case ZACK: continue;
case ZRPOS: goto somemore;
case ZRINIT: return OK;
case ZSKIP: default: fio_close(zc->fh); zc->fh = NULL; return c; } } }
/*----------------------------------------------------------------------+
| getinsync - Respond to receiver's complaint, get back in sync with receiver. +----------------------------------------------------------------------*/ int getinsync(ZC *zc, int flag) { register int c;
flushmo(zc, &zc->stP);
for (;;) { // xfer_idle(zc->hSession, XFER_IDLE_IO);
c = zgethdr(zc, zc->Rxhdr, 'T');
switch (c) { case ZCAN: case ZABORT: case ZFIN: case TIMEOUT: DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0); return c;
case ZRPOS: /* ************************************* */ /* If sending to a buffered modem, you */ /* might send a break at this point to */ /* dump the modem's buffer. */
fio_errclr(zc->fh); /* In case file EOF seen */ if (fio_seek(zc->fh, zc->Rxpos, FIO_SEEK_SET) == (-1)) { DbgOutStr("ZMODEM error %s %d\r\n", TEXT(__FILE__), __LINE__,0,0,0); return ERROR; } zc->Eofseen = FALSE; zc->file_bytes = zc->Lrxpos = zc->Txpos = zc->Rxpos; if (zc->Lastsync == zc->Rxpos) { if (++zc->Beenhereb4 > 4) { if (zc->blklen > 32) { zc->blklen /= 2; } } } zc->Lastsync = zc->Rxpos; zmdms_update(zc, ZRPOS); return c;
case ZACK: zc->Lrxpos = zc->Rxpos; if (flag || zc->Txpos == zc->Rxpos) { return c; } break;
case ZRINIT: case ZSKIP: fio_close(zc->fh); zc->fh = NULL; return c;
case ERROR: default: zsbhdr(zc, ZNAK, zc->Txhdr); break; } } }
/*----------------------------------------------------------------------+
| saybibi - Say "bibi" to the receiver, try to do it cleanly. +----------------------------------------------------------------------*/ void saybibi(ZC *zc) { for (;;) { stohdr(zc, 0L); /* CAF Was zsbhdr - minor change */ zshhdr(zc, ZFIN, zc->Txhdr); /* to make debugging easier */ switch (zgethdr(zc, zc->Rxhdr, 'T')) { case ZFIN: sendline(zc, &zc->stP, 'O'); sendline(zc, &zc->stP, 'O'); flushmo(zc, &zc->stP); return;
case ZCAN: case TIMEOUT: return;
case TSC_USER_CANNED: // These cases should not occur, but
case TSC_RMT_CANNED: // this code is placed here to ignore
case ZCARRIER_LOST: // these cases should they occur.
case ZMDM_CARRIER_LOST: assert(0); return;
default: break; } } }
/*********************** end of zmdm_snd.c **************************/
|