📄 zmodemcore.cpp
字号:
//-----------------------------------------------------------------------------
// project: ZModem
// author: Frank Weiler, Genshagen, Germany
// version: 0.91
// date: October 10, 2000
// email: frank@weilersplace.de
// copyright: This Software is OpenSource.
// file: ZModemCore.cpp
// description: A class that implements a basic ZModem protocol.
// Not all possible features are supported, especially
// no support for buffersizes greater than 1024.
// Sending data is done with 1024 buffersize,
// receiving is event-driven using overlapped I/O.
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "ZModemCore.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//-----------------------------------------------------------------------------
// purpose: construction
// params: howner -> handle of the Owner Window
// hcomm -> handle of the modem ressource, got from TAPI
// hcancelevent -> handle of an event signaling user-break
CZModemCore::CZModemCore(HWND howner,HANDLE hcomm,HANDLE hcancelevent)
//-----------------------------------------------------------------------------
{
m_hOwner = howner;
m_hcomm = hcomm;
m_hCancelEvent = hcancelevent;
m_ZModemComm = new CZModemComm(m_hcomm,m_hCancelEvent);
m_ZModemFile = new CZModemFile(howner);
maxTx = ZMCORE_MAXTX;
}
//-----------------------------------------------------------------------------
// purpose: destruction
CZModemCore::~CZModemCore()
//-----------------------------------------------------------------------------
{
delete m_ZModemComm;
delete m_ZModemFile;
}
//-----------------------------------------------------------------------------
// purpose: sending files
// params: filelist -> Array of filenames (full path) to send
// returns: success
bool CZModemCore::Send(CStringArray* filelist)
//-----------------------------------------------------------------------------
{ //
bool fin=false,quit=false,ok=true;
int tries=0;
//
this->ResetAll();
if(filelist == NULL)
return false;
if(filelist->GetSize() == 0)
return false;
m_Filelist = filelist;
bufTop = mainBuf + (sizeof mainBuf);
m_ZModemComm->ClearInbound();//clear all pending data from modem
sendrz();//send initialization string
while(ALLOK && !fin && (tries < 100))
{
quit=false;
sendZRQINIT();//send ZRQINIT
getZMHeader();
if(ALLOK)
{
switch(headerType)
{
case ZCAN://canceled from other side
{
TRACE("set error %s\n","ZMODEM_GOTZCAN");
SetLastError(ZMODEM_GOTZCAN);
::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)ZMODEM_GOTZCAN,0L);
quit=true;
fin=true;
break;
}
case ZRINIT:// ok, let's communicate
{
TRACE("ZRINIT erhalten");
//validate CRC-32-property and CANFX-property
static int Rxflags = 0377 & headerData[3];
bcrc32 = (Rxflags & CANFC32) != 0;
bcanfdx = Rxflags & CANFDX;
TRACE("bcanfdx ist %s\n",bcanfdx ? "true" : "false");
TRACE("bcrc32 ist %s\n",bcrc32 ? "true" : "false");
// start sending all files
ok=sendFiles();
fin=true;
break;
}
case ZCHALLENGE:
{
TRACE("got ZCHALLENGE");
sendZACK();
break;
}
default:
{
TRACE("got unexpected header");
tries++;
break;
}
}//switch
}//if(ALLOK)
else
{
DWORD err=GetLastError();
if((err==ZMODEM_TIMEOUT) || (err==ZMODEM_CRCXM) ||
(err==ZMODEM_CRC32) || (err==ZMODEM_BADHEX))
{
::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)err,0L);
if(tries < 100)
{
SetLastError(0);
tries++;
}
}
}
}//while(...)
// sendig is over, finish session
if(ALLOK)
{
quit=false;
tries=0;
sendZFIN();
while(ALLOK && !quit)
{
getZMHeader();
if(ALLOK && (headerType == ZFIN))
quit=true;//other side has finish accepted
else
{
if(tries < 100)
{
SetLastError(0);
sendZFIN();
tries++;
}
}
}
if(ALLOK)
sendOO();//over and out
}
return(quit && fin && ok);
}
//-----------------------------------------------------------------------------
// purpose: receiving files
// params: filelist -> Array of filenames received
// receivedir -> folder to save the received files
// returns: success
bool CZModemCore::Receive(CStringArray* filelist,CString receivedir)
//-----------------------------------------------------------------------------
{ //
bool fin,quit;
int tries;
//
this->ResetAll();
if(filelist == NULL)
return false;
if(filelist->GetSize() == 0)
return false;
m_Filelist = filelist;
if(!receivedir.IsEmpty())
m_ZModemFile->SetReceivingDir(receivedir);
bufTop = mainBuf + (sizeof mainBuf);
m_ZModemComm->ClearInbound();
skip = false;
fin = false;
while(ALLOK && !fin)
{
sendZRINIT();
quit = false;
tries = 0;
while(ALLOK && !quit)
{
getZMHeader();
if(ALLOK)
{
if(headerType == ZFIN)//other side has finish signaled
{
sendZFIN();//reply
getOO();//try to get over and out signal
quit = true;
fin = true;
}
else if(headerType == ZRQINIT)
{
if(tries < 100)
{
sendZRINIT();
tries++;
}
else
{
TRACE("set error %s\n","ZMODEM_INIT");
SetLastError(ZMODEM_INIT);
}
}
else if(headerType == ZFILE)//file transfer signaled
{
skip = false;
getFILEINFO();//extract the FILEINFO from data block
if(ALLOK)
{
receiveFile();//receive current file
if(ALLOK)
m_Filelist->Add(m_ZModemFile->GetReceivedFileName());
quit = true;
}
else if(GetLastError()==ZMODEM_CRC32)
{
::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)ZMODEM_CRC32,0L);
if(tries < 100)
{
SetLastError(0);
sendZRINIT();
tries++;
}
}
}
}
else
{
DWORD err=GetLastError();
if((err==ZMODEM_TIMEOUT) || (err==ZMODEM_CRCXM) ||
(err==ZMODEM_CRC32) || (err==ZMODEM_BADHEX))
{
::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,(WPARAM)err,0L);
if(tries < 100)
{
SetLastError(0);
sendZRINIT();
tries++;
}
}
}
}
}
Sleep(4000);//wait 4 seconds tu ensure that the other side really get our ZEOF
return(ALLOK);
}
// Layer 3 ####################################################################
//-----------------------------------------------------------------------------
void CZModemCore::ResetAll()
//-----------------------------------------------------------------------------
{
ch = 0;
gotSpecial =0;
m_bWait = true;
gotHeader =0;
frameType =0;
headerType =0;
memset(headerData,0,4);
moreData=0;
memset(mainBuf,0,sizeof mainBuf);
bufPos = NULL;
bufTop = NULL;
goodOffset=0;
bytes=0;
bcrc32=false,bcanfdx=false;
skip=false;
m_ZModemFile->ResetAll();
m_ZModemComm->ResetAll();
}
//-----------------------------------------------------------------------------
bool CZModemCore::sendFiles()
//-----------------------------------------------------------------------------
{ //
bool gotfile;
int count = 0;
int tries;
bool sent;
bool rw=true;
DWORD offset;
int i=0;
bool fileinfosent=false;
//
int nSize=m_Filelist->GetSize();
while(ALLOK && ( i < nSize))
{
gotfile = m_ZModemFile->Open(m_Filelist->GetAt(i),OPEN_EXISTING);
if(gotfile)
TRACE("SendFiles filename %s",m_Filelist->GetAt(i));
else
break;
goodOffset = 0;
tries = 0;
sent = false;
while(ALLOK && (tries < 10) && !sent)
{
if(!fileinfosent)
{
sendZFILE();
sendFILEINFO();
fileinfosent=true;
}
getZMHeader();
if(ALLOK)
{
if(headerType == ZRINIT)
{
TRACE("got ZRINIT");
tries++;
}
else if (headerType == ZRPOS)
{
TRACE("got ZRPOS");
offset=(headerData[3] << 24) | (headerData[2] << 16) |
(headerData[1] << 8) | headerData[0];
m_ZModemFile->SetPos(offset);
goodOffset = offset;
rw=sendFile();
sent = true;
}
else if(headerType == ZNAK)//nochmal senden
{
TRACE("got ZNAK");
fileinfosent=false;
}
else if(headerType == ZSKIP)//bitte n鋍hstes file
{
TRACE("got ZSKIP");
sent=true;
}
else if(headerType== ZCRC)
{
TRACE("got ZCRC, no action");
}
}
else
{
DWORD err=GetLastError();
if(err==ZMODEM_TIMEOUT)
{
SetLastError(0);
}
tries++;
}
}
m_ZModemFile->Finish();
i++;//next file
}
return rw;
}
//-----------------------------------------------------------------------------
bool CZModemCore::sendFile()
//-----------------------------------------------------------------------------
{ //
int tries = 0;
DWORD lastpos = 0;
DWORD newpos;
int state;
bool sentfile = false;
bool rw=true;
//
state = SM_SENDZDATA;
while(ALLOK && !sentfile)
{
switch(state)
{
case SM_SENDZDATA:
{
moreData = 1;
int erg=m_ZModemFile->GetData(mainBuf,maxTx,&bytes);
if(erg==ZMODEMFILE_NOMOREDATA)
{
state = SM_SENDZEOF;
moreData = 0;
}
else if(erg == ZMODEMFILE_OK)
{
sendZDATA();
state = SM_SENDDATA;
}
else//ZMODEMFILE_ERROR
{
TRACE("set error ZMODEM_ERROR_FILE");
SetLastError(ZMODEM_ERROR_FILE);
}
break;
}
case SM_SENDDATA:
while (ALLOK && (state == SM_SENDDATA))
{
sendData();
getZMHeaderImmediate();
DWORD err=GetLastError();
if(ALLOK && (headerType == ZRPOS))
{
state = SM_ACTIONRPOS;
}
else
{
DWORD err=GetLastError();
if(err==ZMODEM_TIMEOUT)//got no header
SetLastError(0);
if(ALLOK)
{
if(!moreData)
{
state = SM_SENDZEOF;
break;
}
else
m_ZModemFile->GetData(mainBuf,maxTx,&bytes);
}
}
}//while
break;
case SM_ACTIONRPOS:
newpos=headerData[0] | (headerData[1] << 8) |
(headerData[2] << 16) | (headerData[3] << 24);
TRACE("in SM_ACTIONRPOS\n");
#ifdef _DEBUG
char out[1000];
wsprintf(out,"newpos: %lu",newpos);
TRACE(out);
#endif
if(newpos <= lastpos)
tries++;
else
tries = 0;
m_ZModemFile->SetPos(newpos);
::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,ZMODEM_POS,0L);
::PostMessage(m_hOwner,WM_USER_ZMODEMRPOS,newpos,0L);
goodOffset = newpos;
state = SM_SENDZDATA;
break;
case SM_SENDZEOF:
TRACE("in SM_SENDZEOF\n");
sendZEOF();
tries = 0;
state = SM_WAITZRINIT;
break;
case SM_WAITZRINIT:
TRACE("in SM_WAITZRINIT\n");
getZMHeader();
if(ALLOK && (headerType == ZRINIT))
sentfile = true;
else if (ALLOK && (headerType == ZRPOS))
{
state = SM_ACTIONRPOS;
}
//erweitert ...
else if(ALLOK && (headerType == ZFERR))
{
TRACE("got ZFERR, finish sending");
sentfile = true;
rw=false;
}
else if(ALLOK && (headerType == ZFIN))
{
TRACE("got ZFIN, finish sending");
sentfile = true;
}
else
{
tries++;
if(tries < 100)
SetLastError(0);
}
break;
}//switch
}//while
return rw;
}
//-----------------------------------------------------------------------------
void CZModemCore::receiveFile()
//-----------------------------------------------------------------------------
{ //
bool quit;
int tries;
//
goodOffset = 0;
m_ZModemFile->OpenReceivingFile(&goodOffset,&skip);
if(skip)
sendZSKIP();
else
{
sendZRPOS();
quit = false;
tries = 0;
while(ALLOK && !quit)
{
getZMHeader();
if(ALLOK)
{
if(headerType == ZFILE)
{
if(tries < 100)
{
sendZRPOS();
tries++;
}
else
{
TRACE("set error %s\n","ZMODEM_POS");
SetLastError(ZMODEM_POS);
::PostMessage(m_hOwner,WM_USER_ZMODEMERROR,ZMODEM_POS,0L);
}
}
else if(headerType == ZDATA)
{
receiveData();
quit = true;
}
}
else
{
DWORD err=GetLastError();
if((err==ZMODEM_TIMEOUT) || (err==ZMODEM_CRCXM) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -