📄 rz.c
字号:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "zmodem.h"
#include "rbsb.h"
#include "zm.h"
#include "zport.h"
#include "v2cfg.h"
#if defined(RZ_MODULE)
#define MAXZTRY 5 // max number of zTry() in receiving
extern int gzCtlEsc; // encode control chacracters
extern int gfUseVHdrs;
extern int gfCrc32;
extern char gszAttn[]; // Attention string rx sends to tx on err
//int gfBinary; /* binary transfer */
/* file operation */
//char gcLFileManage; /* Local file management request */
//char gcLFileConversion; /* Local ZMODEM file conversion reqeust */
//char gcFileConversion; /* ZMODEM file conversion reqeust */
//char gcFileManage; /* ZMODEM file management reqeust */
//char gcFileTrans; /* ZMODEM file transport request */
#define DEFBYTL 2000000000L; /* default rx file size */
long glBytesLeft; /* number of bytes of incoming file left */
long glModTime; /* Unix style modified time for incoming file */
int gnFileMode; /* Unix style mode for incoming file */
long glTotalBytes, glTotalLeft;
long glTotalFiles, glFilesLeft;
//#define PATHLEN 257 /* ready for 4.2 bsd ? */
#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */
//char gszPathname[PATHLEN];
char gcaSecBuf[ZMAXSPLEN+1];
#ifdef ZD_FILESAVE
static char *pzFileSave;
static long lFileSavePos;
#endif
///////////////////////////////////////////////////////////////////////////////
// int zProcFileHeader(char *szFilename)
// Process incoming file information header
// returns 0 for sucess, other codes for errors or skip conditions.
int zProcFileHeader(char *szFilename)
{
char *pFileInfo;
// static int dummy;
/* set default parameters and overrides */
// if(gcFileConversion == ZCBIN && gcLFileConversion != ZCRESUM)
// gcLFileConversion = gcFileConversion; /* remote binary override */
// if(gcLFileConversion)
// gcFileConversion = gcLFileConversion;
// if(gcLFileManage)
// gcFileManage = gcLFileManage;
/* process ZMODEM remote file management req */
// if(gcFileConversion == ZCNL) /* remote ASCII override */
// gfBinary = 0;
// if(gcFileConversion == ZCBIN)
// gfBinary = 1;
if(!szFilename || !(*szFilename))
return 0;
pFileInfo = szFilename + (1 + strlen(szFilename)); /* +1 is trailing '\0' */
if(*pFileInfo)
{ /* file incoming from Unix or DOS system */
/* YYY
sscanf(pFileInfo, "%ld%lo%o%lo%d%ld%d%d", \
&glBytesLeft, &glModTime, &gnFileMode, &dummy, &glFilesLeft, &glTotalLeft, &dummy, &dummy);
*/
glBytesLeft = strtoul(pFileInfo, &pFileInfo, 10);
// if(gnFileMode & UNIXFILE)
// {
// ++gfBinary;
// }
++glTotalFiles;
glTotalBytes += glBytesLeft;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Ack a ZFIN packet.
//
void zAckFin(void)
{
int i, c;
char caTxHdrFlag[ZMAXHLEN];
zLongToChar4(caTxHdrFlag, 0l);
// try 3 times
for(i=0; i<3; i++)
{
zSndHexHdr(4, ZFIN, caTxHdrFlag);
switch((c = ReadLine(10000)))
{
case 'O' : /* two "00" (Over and Out) */
ReadLine(1000); /* discard 2nd '0' */
return;
case RCD0 :
return;
case TIMEOUT :
break;
default :
break;
}
}
}
///////////////////////////////////////////////////////////////////////////////
// initialize for Zmodem receive attempt, try to activate Zmodem sender.
// handles ZSINIT frame.
// return ZFILE if Zmodem filename received.
// ZCOMPL if transaction finished.
// -1 on error.
// 0 otherwise.
int zTry(void)
{
register int c, n;
int nzTryHdrType = ZRINIT; // Header type to send corresponding to Last rx close
char caTxHdrFlag[ZMAXHLEN], caRxHdrFlag[ZMAXHLEN];
int bSkipSendHeader = 1; // send header at first
int nRxCnt;
char cFileConversion;
char cFileManage;
char cFileTrans;
// zFPrintf_T("zTry init\n");
for(n=0; n<=MAXZTRY; n++)
{ /* set buffer length (0) and capability flags */
if(!bSkipSendHeader)
{
zLongToChar4(caTxHdrFlag, 0L);
// caTxHdrFlag[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
caTxHdrFlag[ZF0] = CANFC32|CANFDX|CANOVIO;
if(gzCtlEsc)
caTxHdrFlag[ZF0] |= TESCCTL;
caTxHdrFlag[ZF0] |= CANRLE;
caTxHdrFlag[ZF1] = CANVHDR;
// nzTryHdrType may be ZRINIT
zSndHexHdr(4, nzTryHdrType, caTxHdrFlag);
}
switch(c = zGetHeader(caRxHdrFlag))
{
case ZRQINIT :
if(caRxHdrFlag[ZF3] & 0x80)
gfUseVHdrs = 1;
bSkipSendHeader = 0; // send header again.
continue;
case ZEOF :
bSkipSendHeader = 0; // send header again.
continue;
case TIMEOUT :
bSkipSendHeader = 0; // send header again.
continue;
case ZFILE :
cFileConversion = caRxHdrFlag[ZF0];
cFileManage = caRxHdrFlag[ZF1];
cFileTrans = caRxHdrFlag[ZF2];
if(caRxHdrFlag[ZF3] & ZCANVHDR)
gfUseVHdrs = 1;
nzTryHdrType = ZRINIT;
c = zRcvData(gcaSecBuf, ZMAXSPLEN, &nRxCnt);
if(c == GOTCRCW)
{
return ZFILE;
}
zSndHexHdr(4, ZNAK, caTxHdrFlag);
bSkipSendHeader = 1; // skip send header next time.
break;
case ZSINIT :
gzCtlEsc = TESCCTL & caRxHdrFlag[ZF0];
if(zRcvData(gszAttn, ZATTNLEN, &nRxCnt) == GOTCRCW)
{
zLongToChar4(caTxHdrFlag, 1l);
zSndHexHdr(4, ZACK, caTxHdrFlag);
}
else
{
zLongToChar4(caTxHdrFlag, 0l);
zSndHexHdr(4, ZNAK, caTxHdrFlag);
}
bSkipSendHeader = 1; // skip send header next time.
break;
case ZFREECNT :
zLongToChar4(caTxHdrFlag, 2147483647); /* many free cnt. this is just guess. */
zSndHexHdr(4, ZACK, caTxHdrFlag);
bSkipSendHeader = 1; // skip send header next time.
break;
case ZCOMMAND :
break;
case ZCOMPL :
bSkipSendHeader = 1; // skip send header.
break;
case ZFIN :
zAckFin();
return ZCOMPL;
case ZCAN :
return ERROR;
default :
bSkipSendHeader = 0; // send header again.
break;
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Receive a file with ZMODEM porotocol.
// Assumes fileaname frame is in gcaSecBuf.
int zRcvFile(void)
{
int c;
char caTxHdrFlag[ZMAXHLEN], caRxHdrFlag[ZMAXHLEN];
long lRxBytes;
int nRcvFileTry;
int bSkipHdrSend;
int bMoreData; // remains more data without header
int nRxCnt; // count of data bytes received actually
if((c = zProcFileHeader(gcaSecBuf)) != 0)
return (c);
#ifdef ZD_FILESAVE
// malloc for file save
if(pzFileSave == NULL)
{
pzFileSave = (char *)zMalloc(glBytesLeft);
// no check for NULL.
// Anyway, the z procedure must be retained. but you can't save the file if NULL.
// and after all, the (lFilePos == 0) is returned.
}
#endif
nRcvFileTry = 20;
lRxBytes = 0l;
bSkipHdrSend = 0; // send header at first
while(1)
{
if(!bSkipHdrSend)
{
zLongToChar4(caTxHdrFlag, lRxBytes);
zSndHexHdr(4, ZRPOS, caTxHdrFlag);
}
switch(c = zGetHeader(caRxHdrFlag))
{
case ZCAN :
return ERROR;
case ZNAK :
if(--nRcvFileTry < 0)
return ERROR;
bSkipHdrSend = 0;
break;
case TIMEOUT :
if(--nRcvFileTry < 0)
return ERROR;
bSkipHdrSend = 0;
break;
case ZFILE :
zRcvData(gcaSecBuf, ZMAXSPLEN, &nRxCnt);
bSkipHdrSend = 0;
break;
case ZEOF :
if(zChar4ToLong(caRxHdrFlag) != lRxBytes)
{
// Ignore EOF if it's at wrong place - force a timeout
// because the EOF might have gone out before we sent our ZRPOS
bSkipHdrSend = 1;
continue;
}
return c;
case ERROR : // too much garbage in header search error
if(--nRcvFileTry < 0)
return ERROR;
zPuts(gszAttn);
bSkipHdrSend = 0;
break;
case ZSKIP :
return c;
case ZDATA :
if(zChar4ToLong(caRxHdrFlag) != lRxBytes)
{
if(--nRcvFileTry < 0)
return ERROR;
zPuts(gszAttn);
bSkipHdrSend = 0;
continue;
}
bMoreData = 1; // at first, it is initilaized to 1. one time true
while(bMoreData)
{
switch(c = zRcvData(gcaSecBuf, ZMAXSPLEN, &nRxCnt))
{
case ZCAN :
return ERROR;
case ERROR :
if(--nRcvFileTry < 0)
return ERROR;
zPuts(gszAttn);
bSkipHdrSend = 0; // send header
bMoreData = 0; // escape from while
break;
case TIMEOUT :
if(--nRcvFileTry < 0)
return ERROR;
bSkipHdrSend = 0; // send header
bMoreData = 0; // escape from while
break;
case GOTCRCW :
// CRC next, ZACK expected, end of frame
// zFPrintf_T("zRF(zDATA) : GOTCRCW\n");
nRcvFileTry = 20;
// move gcaSecBuf to safe addr. later
#ifdef ZD_FILESAVE
if(pzFileSave)
{
memcpy(pzFileSave+lFileSavePos, gcaSecBuf, nRxCnt);
lFileSavePos += nRxCnt;
}
#endif
lRxBytes += nRxCnt;
zLongToChar4(caTxHdrFlag, lRxBytes);
SendLine(XON);
zSndHexHdr(4, ZACK, caTxHdrFlag);
bSkipHdrSend = 1; // do not send header
bMoreData = 0; // escape from while
break;
case GOTCRCQ :
// CRC next, frame continues, ZACK expected
// zFPrintf_T("zRF(zDATA) : GOTCRCQ\n");
nRcvFileTry = 20;
// move gcaSecBuf to safe addr. later
#ifdef ZD_FILESAVE
if(pzFileSave)
{
memcpy(pzFileSave+lFileSavePos, gcaSecBuf, nRxCnt);
lFileSavePos += nRxCnt;
}
#endif
lRxBytes += nRxCnt;
zLongToChar4(caTxHdrFlag, lRxBytes);
zSndHexHdr(4, ZACK, caTxHdrFlag);
bSkipHdrSend = 0; // send header
bMoreData = 1; // more data without header
break;
case GOTCRCG :
// CRC next, frame continues nonstop
// zFPrintf_T("zRF(zDATA) : GOTCRCG\n");
nRcvFileTry = 20;
// move gcaSecBuf to safe addr. later
#ifdef ZD_FILESAVE
if(pzFileSave)
{
memcpy(pzFileSave+lFileSavePos, gcaSecBuf, nRxCnt);
lFileSavePos += nRxCnt;
}
#endif
lRxBytes += nRxCnt;
bSkipHdrSend = 0; // send header
bMoreData = 1; // more data without header
break;
case GOTCRCE :
// CRC next, frame ends, header packet follows
// zFPrintf_T("zRF(zDATA) : GOTCRCE\n");
nRcvFileTry = 20;
// move gcaSecBuf to safe addr. later
#ifdef ZD_FILESAVE
if(pzFileSave)
{
memcpy(pzFileSave+lFileSavePos, gcaSecBuf, nRxCnt);
lFileSavePos += nRxCnt;
}
#endif
lRxBytes += nRxCnt;
bSkipHdrSend = 1; // skip next header
bMoreData = 0; // escape from while
break;
} // switch()
} /* while(bMoreData) ? */
break;
default :
if(--nRcvFileTry < 0)
return ERROR;
bSkipHdrSend = 1; // skip next header
break;
} // switch(hdrType)
} /* while(1) */
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Receive 1 or more files with ZMODEM protocol.
int zRcvFiles(void)
{
int c;
while(1)
{
switch(c = zRcvFile())
{
case ZEOF :
case ZSKIP :
case ZFERR :
switch(zTry())
{
case ZCOMPL :
return OK;
case ZFILE :
break;
default :
return ERROR;
}
continue;
case ERROR :
return ERROR;
default :
return c;
}
}
return 0;
}
#ifdef ZD_FILESAVE
long zGetFileSize(void)
{
return lFileSavePos;
}
char* zGetFiles(void)
{
return pzFileSave;
}
///////////////////////////////////////////////////////////////////////////////
// free buffer to save receiving files.
void zFreeFiles(void)
{
if(pzFileSave)
{
zFree(pzFileSave);
pzFileSave = (char *)NULL;
}
lFileSavePos = 0;
}
#endif // ZD_FILESAVE
///////////////////////////////////////////////////////////////////////////////
// long zReceive(unsigned char **pRcvFiles)
//
// *pRcvFiles == NULL, buffer is malloced inside this function and *pRcvFiles is replaced with the start of buffer.
// *pRcvFiles != NULL, then *pRcvFiles is filled.
//
// Remark : if you invoke by NULL, then buffer is malloced in the z module.
// so, It's the programmer's resposibility freeing *pRcvFiles after the zReceive().
// In that case, use the function zFreeFiles();
//
// Note that zReceive file doesn't free the buffer unless zFreeFiles() is called.
// return : pRcvFiles's length.
long zReceive(unsigned char **pRcvFiles)
{
register int c;
// initialize the variable
// glBytesLeft = 0; /* number of bytes of incoming file left */
// glTotalBytes = 0, glTotalLeft = 0;
// glTotalFiles = 0, glFilesLeft = 0;
// initialize file pointer
pzFileSave = (char *)(*pRcvFiles);
lFileSavePos = 0;
// XXX : must delete after you implement malloc
if(pzFileSave == NULL)
return 0;
/* XXX */
TtyMode(1); // mode to ZMODEM
while(1)
{
c = ReadLine(0); // forever
if(c == 0x18)
goto zEnd;
if(c == ZPAD)
break;
}
if((c = zTry()) != 0)
{
if(c == ZCOMPL)
{
goto zEnd;
}
if(c == ERROR)
{
goto zEnd;
}
c = zRcvFiles();
}
else
{
}
zEnd :
// update for return value
if(*pRcvFiles == NULL)
*pRcvFiles = (unsigned char *)pzFileSave;
TtyMode(0); // STDOUT is possible now
return lFileSavePos;
}
#endif//zmodem
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -