Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1361 lines
30 KiB

/* 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 **************************/