windows-nt/Source/XPSP1/NT/shell/osshell/accesory/terminal/xmodem.c
2020-09-26 16:20:57 +08:00

827 lines
21 KiB
C

/*****************************************************************************/
/* Copyright (c) 1987 - 1988, Future Soft Engineering, Inc. */
/* Houston, Texas */
/*****************************************************************************/
#define NOLSTRING TRUE /* jtf win3 mod */
#include <windows.h>
#include "port1632.h"
#include "dcrc.h"
#include "dynacomm.h"
/*---------------------------------------------------------------------------*/
#define XM_ABORT 0x8000
#define XM_COMPLETE 0x4000
#define XM_BLKREPEAT 0x2000
#define XM_CRC 0x0800
#define YM_1KBLK 0x0400
#define YM_GOPTION 0x0200
#define XM_RETRYMASK 0x001F /* mbbx 1.04: relax 15 -> 31 */
#define XM_RETRIES 0x0014 /* mbbx 1.04: relax 10 -> 20 */
#define XM_RETRYINITCRC 4
#define XM_RETRYINITCKS 10
#define XM_WAITRCVINIT 50 /* mbbx 1.04: relax... */
#define XM_WAITNEXTBLK 100
#define XM_WAITNEXTCHAR 50 //sdj: was 20 to get rid of xmodem
//sdj: retries when moused moved..move to 50
#define XM_WAITSNDINIT 600
BOOL YM_RcvBatch(WORD);
BOOL NEAR YM_RcvFileInfo(WORD *, WORD *);
BOOL XM_RcvFile(WORD);
BOOL NEAR XM_RcvInit(WORD *, WORD *);
BOOL NEAR XM_RcvData(WORD *, WORD *);
BOOL NEAR XM_RcvBlockHeader(WORD *, WORD *);
BOOL NEAR XM_RcvBlockData(WORD *blockNumber, WORD blockSize,WORD *rcvStatus);
VOID NEAR XM_RcvBlockAbort(WORD *);
BOOL NEAR XM_RcvEnd();
VOID NEAR XM_RcvAbort();
BOOL YM_SndBatch(WORD);
BOOL NEAR YM_SndFileInfo(WORD *, BOOL);
BOOL XM_SndFile(WORD sndStatus);
BOOL NEAR XM_SndInit(WORD *);
BOOL NEAR XM_SndData(WORD *);
BOOL NEAR XM_SndBlockData(WORD *, WORD *, WORD *);
BOOL NEAR XM_SndEnd();
VOID NEAR XM_SndAbort();
BYTE XM_CheckSum(BYTE *dataBlock, WORD blockSize); /* mbbx 2.00: NEAR -> FAR */
WORD XM_CalcCRC(BYTE *, INT); /* mbbx 2.00: NEAR -> FAR */
/*---------------------------------------------------------------------------*/
/* UTILITIES --> RCVBFILE.C */
BOOL initXfrBuffer(WORD wBufSize);
VOID fillXfrBuffer(BYTE *, WORD);
WORD readXfrBuffer(BYTE *dataBlock,WORD blockSize,BOOL bBlkRepeat);
BOOL writeXfrBuffer(BYTE *dataBlock, WORD blockSize,BOOL bBlkRepeat);
VOID grabXfrBuffer(BYTE *, WORD);
BOOL clearXfrBuffer();
VOID freeXfrBuffer();
/*---------------------------------------------------------------------------*/
/* XM_RcvFile() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL XM_RcvFile(WORD rcvStatus)
{
WORD blockSize;
if(XM_RcvInit(&blockSize, &rcvStatus))
if(XM_RcvData(&blockSize, &rcvStatus))
if(XM_RcvEnd())
return(TRUE);
XM_RcvAbort();
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_RcvInit() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_RcvInit(WORD *blockSize, WORD *rcvStatus)
{
BYTE work[3];
WORD retry;
LoadString(hInst, STR_RI, (LPSTR) work, 4); /* mbbx 1.04: REZ... */
bSetup(work);
*blockSize = 128;
*rcvStatus |= XM_RETRIES;
if(*rcvStatus & (YM_1KBLK | YM_GOPTION))
*rcvStatus |= XM_CRC;
while(*rcvStatus & XM_CRC)
{
for(retry = XM_RETRYINITCRC; retry > 0; retry -= 1)
{
modemWr('C');
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
if(waitRcvChar(work, XM_WAITRCVINIT, 0, CHSTX, CHSOH, CHEOT, CHCAN, NULL))
{
switch(work[0])
{
case CHSTX:
*blockSize = 1024;
/* then fall thru... */
case CHSOH:
return(TRUE);
case CHEOT:
*rcvStatus |= XM_COMPLETE;
return(TRUE);
case CHCAN:
return(FALSE);
}
}
if(xferStopped)
return(FALSE);
}
*rcvStatus &= ((*rcvStatus & YM_GOPTION) ? ~YM_GOPTION : ~XM_CRC);
}
for(retry = XM_RETRYINITCKS; retry > 0; retry -= 1) /* mbbx 1.04: relax */
{
modemWr(CHNAK);
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
if(waitRcvChar(work, XM_WAITRCVINIT, 0, CHSTX, CHSOH, CHEOT, CHCAN, NULL))
{
switch(work[0])
{
case CHSTX:
*blockSize = 1024;
/* then fall thru... */
case CHSOH:
return(TRUE);
case CHEOT:
*rcvStatus |= XM_COMPLETE;
return(TRUE);
case CHCAN:
return(FALSE);
}
}
if(xferStopped)
break;
showBErrors(++xferErrors);
}
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_RcvData() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_RcvData(WORD *blockSize, WORD *rcvStatus)
{
BYTE work[3];
WORD blockNumber = 1;
if(*rcvStatus & XM_COMPLETE)
return(TRUE);
LoadString(hInst, STR_DF, (LPSTR) work, 4); /* mbbx 1.04: REZ... */
bSetup(work);
if(initXfrBuffer(12 * 1024))
{
XM_RcvBlockData(&blockNumber, *blockSize, rcvStatus);
while(!(*rcvStatus & (XM_COMPLETE | XM_ABORT)))
{
if(XM_RcvBlockHeader(blockSize, rcvStatus))
XM_RcvBlockData(&blockNumber, *blockSize, rcvStatus);
}
if(!(*rcvStatus & XM_ABORT))
if(!clearXfrBuffer())
*rcvStatus |= XM_ABORT;
freeXfrBuffer();
}
return(!(*rcvStatus & XM_ABORT));
}
/*---------------------------------------------------------------------------*/
/* XM_RcvBlockHeader() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_RcvBlockHeader(WORD *blockSize, WORD *rcvStatus)
{
BYTE work[1];
if(waitRcvChar(work, XM_WAITNEXTBLK, 0, CHSTX, CHSOH, CHEOT, CHCAN, NULL))
{
switch(work[0])
{
case CHSTX:
*blockSize = 1024;
return(TRUE);
case CHSOH:
*blockSize = 128;
return(TRUE);
case CHEOT:
*rcvStatus |= XM_COMPLETE;
return(FALSE);
case CHCAN:
xferStopped = TRUE;
break;
}
}
XM_RcvBlockAbort(rcvStatus);
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_RcvBlockData() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_RcvBlockData(WORD *blockNumber, WORD blockSize,WORD *rcvStatus)
{
BYTE work[2];
BOOL bBlkRepeat;
WORD ndx;
BYTE dataBlock[1024];
signed char i,j;
while(waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0) &&
waitRcvChar(work+1, XM_WAITNEXTCHAR, 0, 0) &&
( (j=(signed char)work[0]) == ~(i = (signed char)work[1]) ) )
//sdj: on mips xmodem rcv was broken due to (BYTE)~work[1]
{
if(bBlkRepeat = (work[0] != (BYTE) *blockNumber))
if(work[0] != (BYTE) (*blockNumber-1))
break;
for(ndx = 0; ndx < blockSize; ndx += 1)
if(!waitRcvChar(dataBlock+ndx, XM_WAITNEXTCHAR, 0, 0))
break;
if(ndx < blockSize)
break;
if(!waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0))
break;
if(!(*rcvStatus & XM_CRC))
{
if(XM_CheckSum(dataBlock, blockSize) != work[0])
break;
}
else
{
if(!waitRcvChar(work+1, XM_WAITNEXTCHAR, 0, 0) || (XM_CalcCRC(dataBlock, blockSize) != ((work[0] << 8) | work[1])))
break;
}
if(!writeXfrBuffer(dataBlock, blockSize, bBlkRepeat))
{
xferStopped = TRUE;
break;
}
if(!bBlkRepeat) /* mbb: reset retry counter */
{
*blockNumber += 1;
*rcvStatus = (*rcvStatus & ~XM_RETRYMASK) | XM_RETRIES;
if(*blockNumber > 1) /* mbb: skip block 0 */
{
if(xferOrig > 0)
{
xferBytes -= blockSize;
updateProgress(FALSE);
}
else
showBBytes(xferLength += blockSize, FALSE); /* mbbx 2.00: xfer ctrls */
}
}
if(!(*rcvStatus & YM_GOPTION))
{
modemWr(CHACK);
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
}
return(TRUE);
}
XM_RcvBlockAbort(rcvStatus);
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_RcvBlockAbort() - [mbb] */
/*---------------------------------------------------------------------------*/
VOID NEAR XM_RcvBlockAbort(WORD *rcvStatus)
{
BYTE work[1];
if(xferStopped || (((*rcvStatus -= 1) & XM_RETRYMASK) == 0))
*rcvStatus |= XM_ABORT;
else
{
while(waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0));
modemWr(CHNAK);
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
}
if(!xferStopped)
showBErrors(++xferErrors);
}
/*---------------------------------------------------------------------------*/
/* XM_RcvEnd() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_RcvEnd()
{
BYTE work[3];
WORD retry;
LoadString(hInst, STR_RE, (LPSTR) work, 4); /* mbbx 1.04: REZ... */
bSetup(work);
modemWr(CHACK);
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
for(retry = XM_RETRIES; retry > 0; retry -= 1) /* mbbx 1.04: relax */
{
if(waitRcvChar(work, XM_WAITNEXTBLK / 2, 0, CHEOT, CHCAN, NULL))
{
switch(work[0])
{
case CHEOT:
modemWr(CHACK);
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
showBErrors(++xferErrors);
continue;
case CHCAN:
xferStopped = TRUE;
break;
}
}
if(xferStopped)
break;
return(TRUE);
}
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_RcvAbort() - [mbb] */
/*---------------------------------------------------------------------------*/
VOID NEAR XM_RcvAbort()
{
BYTE work[1];
rcvAbort();
while(waitRcvChar(work, XM_WAITNEXTCHAR, 0, 0));
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(BS);
modemWr(BS);
modemWr(BS);
modemWr(BS);
modemWr(BS);
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
}
/*---------------------------------------------------------------------------*/
/* XM_SndFile() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL XM_SndFile(WORD sndStatus)
{
if(XM_SndInit(&sndStatus))
if(XM_SndData(&sndStatus))
if(XM_SndEnd())
return(TRUE);
XM_SndAbort();
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_SndInit() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_SndInit(WORD *sndStatus)
{
BYTE work[3];
LoadString(hInst, STR_SI, (LPSTR) work, 4); /* mbbx 1.04: REZ... */
bSetup(work);
*sndStatus |= XM_RETRIES;
if(waitRcvChar(work, XM_WAITSNDINIT, 0, 'C', CHNAK, CHCAN, 0))
{
switch(work[0])
{
case 'C':
*sndStatus |= XM_CRC;
if(!(*sndStatus & YM_1KBLK) && waitRcvChar(work, XM_WAITNEXTCHAR / 2, 0, 'K', 0))
*sndStatus |= YM_1KBLK;
return(TRUE);
case CHNAK:
*sndStatus &= ~(XM_CRC | YM_1KBLK);
return(TRUE);
case CHCAN:
break;
}
}
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_SndData() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_SndData(WORD *sndStatus)
{
BYTE work[3];
WORD blockNumber = 1;
WORD blockSize;
LoadString(hInst, STR_DF, (LPSTR) work, 4); /* mbbx 1.04: REZ... */
bSetup(work);
if(initXfrBuffer(12 * 1024))
{
blockSize = (!(*sndStatus & YM_1KBLK) ? 128 : 1024);
while(!(*sndStatus & (XM_COMPLETE | XM_ABORT)))
XM_SndBlockData(&blockNumber, &blockSize, sndStatus);
freeXfrBuffer();
}
return(!(*sndStatus & XM_ABORT));
}
/*---------------------------------------------------------------------------*/
/* XM_SndBlockData() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_SndBlockData(WORD *blockNumber, WORD *blockSize, WORD *sndStatus)
{
BYTE dataBlock[1024];
WORD dataBytes;
WORD wCRC;
BYTE work[1];
BOOL writeGood;
switch(dataBytes = readXfrBuffer(dataBlock, *blockSize, (*sndStatus & XM_BLKREPEAT)))
{
case (WORD)-1:
xferStopped = TRUE;
break;
case 0:
*sndStatus |= XM_COMPLETE;
return(TRUE);
default:
if((*blockSize == 1024) && (dataBytes <= (5 * 128)) && !(*sndStatus & XM_BLKREPEAT))
readXfrBuffer(dataBlock, *blockSize = 128, TRUE);
modemWr((*blockSize == 128) ? CHSOH : CHSTX);
modemWr((BYTE) *blockNumber);
modemWr((BYTE) ~*blockNumber);
writeGood = modemWrite((LPSTR) dataBlock, (INT)(*blockSize));
if(!writeGood)
{
wCRC = 0;
break;
}
if(!(*sndStatus & XM_CRC))
modemWr(XM_CheckSum(dataBlock, *blockSize));
else
{
wCRC = XM_CalcCRC(dataBlock, *blockSize);
modemWr(HIBYTE(wCRC));
modemWr(LOBYTE(wCRC));
}
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
if(!waitRcvChar(work, XM_WAITSNDINIT, 0, CHACK, CHNAK, CHCAN, (*blockNumber <= 1) ? 'C' : 0, 0))
{
xferStopped = TRUE;
break;
}
switch(work[0])
{
case CHACK:
*blockNumber += 1;
*sndStatus = (*sndStatus & ~(XM_BLKREPEAT | XM_RETRYMASK)) | XM_RETRIES;
if(*blockNumber > 1)
{
xferBytes -= *blockSize;
updateProgress(FALSE);
}
return(TRUE);
case CHNAK:
break;
case CHCAN:
xferStopped = TRUE;
break;
}
break;
}
if(xferStopped || (((*sndStatus -= 1) & XM_RETRYMASK) == 0))
*sndStatus |= XM_ABORT;
else
*sndStatus |= XM_BLKREPEAT;
if(!xferStopped)
showBErrors(++xferErrors);
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_SndEnd() - [mbb] */
/*---------------------------------------------------------------------------*/
BOOL NEAR XM_SndEnd()
{
BYTE work[3];
WORD retry;
LoadString(hInst, STR_SE, (LPSTR) work, 4); /* mbbx 1.04: REZ... */
bSetup(work);
for(retry = XM_RETRIES; retry > 0; retry -= 1) /* mbbx 1.04: relax */
{
modemWr(CHEOT);
if(xferPSChar) /* mbbx 1.02: packet switching... */
modemWr(xferPSChar);
if(waitRcvChar(work, XM_WAITNEXTBLK, 0, CHACK, CHCAN, 0)) /* mbbx 1.04: relax 15 -> 60 */
{
switch(work[0])
{
case CHACK:
return(TRUE);
case CHCAN:
xferStopped = TRUE;
break;
}
}
if(xferStopped)
break;
showBErrors(++xferErrors);
}
return(FALSE);
}
/*---------------------------------------------------------------------------*/
/* XM_SndAbort() - [mbb] */
/*---------------------------------------------------------------------------*/
VOID NEAR XM_SndAbort()
{
BYTE work[1];
sndAbort();
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(CHCAN);
modemWr(BS);
modemWr(BS);
modemWr(BS);
modemWr(BS);
modemWr(BS);
if(xferPSChar) /* mbbx 1.02: packet switching */
modemWr(xferPSChar);
}
/*---------------------------------------------------------------------------*/
/* XM_CheckSum() - [mbb] */
/*---------------------------------------------------------------------------*/
BYTE XM_CheckSum(BYTE *dataBlock, WORD blockSize) /* mbbx 2.00: NEAR -> FAR */
{
BYTE XM_CheckSum = 0;
while(blockSize > 0)
XM_CheckSum += dataBlock[--blockSize];
return(XM_CheckSum);
}
/*---------------------------------------------------------------------------*/
/* XM_CalcCRC() - [mbb] */
/*---------------------------------------------------------------------------*/
WORD XM_CalcCRC(BYTE *dataBlock, INT blockSize)
{
WORD XM_CalcCRC = 0;
INT ndx;
while(--blockSize >= 0)
{
XM_CalcCRC = XM_CalcCRC ^ (((WORD) *dataBlock++) << 8);
for(ndx = 0; ndx < 8; ndx += 1)
{
if(XM_CalcCRC & 0x8000)
XM_CalcCRC = (XM_CalcCRC << 1) ^ 0x1021;
else
XM_CalcCRC = (XM_CalcCRC << 1);
}
}
return(XM_CalcCRC & 0xFFFF);
}
/*---------------------------------------------------------------------------*/
/* UTILITIES --> file buffering to be used by all RCV protocols !!! [mbb] */
/*---------------------------------------------------------------------------*/
HANDLE hXfrBuf;
LPSTR lpXfrBuf;
WORD wXfrBufSize;
WORD wXfrBufBytes;
WORD wXfrBufIndex;
WORD wXfrBufExtend;
BOOL initXfrBuffer(WORD wBufSize)
{
wXfrBufSize = wBufSize;
if((hXfrBuf = GlobalAlloc(GMEM_MOVEABLE, (DWORD) wXfrBufSize)) != NULL)
{
#ifdef ORGCODE
if((lpXfrBuf = GlobalWire(hXfrBuf)) != NULL)
#else
if((lpXfrBuf = GlobalLock(hXfrBuf)) != NULL)
#endif
{
wXfrBufBytes = 0;
wXfrBufIndex = 0;
wXfrBufExtend = 0;
return(TRUE);
}
GlobalFree(hXfrBuf);
}
rcvFileErr();
return(FALSE);
}
WORD readXfrBuffer(BYTE *dataBlock, WORD blockSize, BOOL bBlkRepeat)
{
if(!bBlkRepeat)
wXfrBufIndex += wXfrBufExtend;
if((wXfrBufIndex+blockSize) > wXfrBufBytes)
{
if((wXfrBufBytes -= wXfrBufIndex) > 0)
lmovmem(lpXfrBuf+wXfrBufIndex, lpXfrBuf, wXfrBufBytes);
if((wXfrBufIndex = (WORD)_lread(xferRefNo, lpXfrBuf, wXfrBufSize-wXfrBufBytes)) == (WORD)-1)
{
return((WORD)-1);
}
wXfrBufBytes += wXfrBufIndex;
wXfrBufIndex = 0;
}
if((wXfrBufExtend = (wXfrBufBytes-wXfrBufIndex)) > 0)
{
if(wXfrBufExtend > blockSize)
wXfrBufExtend = blockSize;
lmovmem(lpXfrBuf+wXfrBufIndex, (LPSTR) dataBlock, wXfrBufExtend);
if(wXfrBufExtend < blockSize)
memset(dataBlock+wXfrBufExtend, CNTRLZ, blockSize-wXfrBufExtend);
}
return(wXfrBufExtend);
}
BOOL writeXfrBuffer(BYTE *dataBlock, WORD blockSize,BOOL bBlkRepeat)
{
if(!bBlkRepeat)
wXfrBufBytes += wXfrBufExtend;
if((wXfrBufBytes+blockSize) > wXfrBufSize)
{
if(_lwrite(xferRefNo, lpXfrBuf, wXfrBufBytes) != wXfrBufBytes)
{
rcvFileErr();
return(FALSE);
}
wXfrBufBytes = 0;
}
lmovmem((LPSTR) dataBlock, lpXfrBuf+wXfrBufBytes, wXfrBufExtend = blockSize);
return(TRUE);
}
BOOL clearXfrBuffer()
{
if(wXfrBufExtend > 0)
{
while(wXfrBufExtend > 0) /* mbbx 1.04 ... */
{
if(*(lpXfrBuf+(wXfrBufBytes+wXfrBufExtend-1)) != CNTRLZ)
break;
wXfrBufExtend -= 1;
}
wXfrBufBytes += wXfrBufExtend;
wXfrBufExtend = 0;
}
if(wXfrBufBytes > 0)
{
if(_lwrite(xferRefNo, lpXfrBuf, wXfrBufBytes) != wXfrBufBytes)
{
rcvFileErr();
return(FALSE);
}
wXfrBufBytes = 0;
}
return(TRUE);
}
VOID freeXfrBuffer()
{
#ifdef ORGCODE
GlobalUnWire(hXfrBuf);
#else
GlobalUnlock(hXfrBuf);
#endif
GlobalFree(hXfrBuf);
}