ftpcontrolsocket.cpp
来自「一个支持FTP,SFTP的客户端程序」· C++ 代码 · 共 2,319 行 · 第 1/5 页
CPP
2,319 行
}
else if (m_Operation.nOpState==LIST_TYPE)
cmd=_T("TYPE A");
else if (m_Operation.nOpState==LIST_LIST)
{
if (!m_pTransferSocket)
{
LogMessage(__FILE__, __LINE__, this,FZ_LOG_APIERROR, _T("Error: m_pTransferSocket==NULL") );
ResetOperation(FZ_REPLY_ERROR);
return;
}
m_pTransferSocket->SetActive();
cmd = _T("LIST");
if (m_pOwner->GetOption(FZAPI_OPTION_SHOWHIDDEN) && !(m_CurrentServer.nServerType & (FZ_SERVERTYPE_SUB_FTP_MVS | FZ_SERVERTYPE_SUB_FTP_VMS | FZ_SERVERTYPE_SUB_FTP_BS2000)))
cmd += _T(" -a");
if (!Send(cmd))
return;
pData->ListStartTime=CTime::GetCurrentTime();
if (pData->bPasv)
{
// if PASV create the socket & initiate outbound data channel connection
if (!m_pTransferSocket->Connect(pData->host,pData->port))
{
if (GetLastError()!=WSAEWOULDBLOCK)
{
ResetOperation(FZ_REPLY_ERROR);
return;
}
}
}
return;
}
if (cmd != _T(""))
Send(cmd);
}
void CFtpControlSocket::TransferEnd(int nMode)
{
LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("TransferEnd(%d) OpMode=%d OpState=%d"), nMode, m_Operation.nOpMode, m_Operation.nOpState);
if (!m_Operation.nOpMode)
{
LogMessage(__FILE__, __LINE__, this,FZ_LOG_INFO, _T("Ignoring old TransferEnd message"));
return;
}
m_LastRecvTime=CTime::GetCurrentTime();
if (m_Operation.nOpMode&CSMODE_TRANSFER)
FileTransfer(0,TRUE,nMode&(CSMODE_TRANSFERERROR|CSMODE_TRANSFERTIMEOUT));
else if (m_Operation.nOpMode&CSMODE_LIST)
List(TRUE,nMode&(CSMODE_TRANSFERERROR|CSMODE_TRANSFERTIMEOUT));
}
void CFtpControlSocket::OnClose(int nErrorCode)
{
LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("OnClose(%d) OpMode=%d OpState=%d"), nErrorCode, m_Operation.nOpMode, m_Operation.nOpState);
ShowStatus(IDS_STATUSMSG_DISCONNECTED, 1);
if (m_pTransferSocket)
{
m_pTransferSocket->OnClose(0);
m_pTransferSocket->Close();
delete m_pTransferSocket;
m_pTransferSocket=0;
DoClose();
ShowStatus(IDS_ERRORMSG_TIMEOUT,1);
return;
}
if (m_bDidRejectCertificate)
DoClose(FZ_REPLY_CANCEL);
else
DoClose();
}
void CFtpControlSocket::FileTransfer(t_transferfile *transferfile/*=0*/,BOOL bFinish/*=FALSE*/,int nError/*=0*/)
{
LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("FileTransfer(%d, %s, %d) OpMode=%d OpState=%d"), transferfile,bFinish?_T("TRUE"):_T("FALSE"), nError, m_Operation.nOpMode, m_Operation.nOpState);
USES_CONVERSION;
#define FILETRANSFER_INIT -1
#define FILETRANSFER_PWD 0
#define FILETRANSFER_CWD 1
#define FILETRANSFER_MKD 2
#define FILETRANSFER_CWD2 3
#define FILETRANSFER_PWD2 4
#define FILETRANSFER_LIST_MODE 5
#define FILETRANSFER_LIST_OPTS 6
#define FILETRANSFER_LIST_PORTPASV 7
#define FILETRANSFER_LIST_TYPE 8
#define FILETRANSFER_LIST_LIST 9
#define FILETRANSFER_LIST_WAITFINISH 10
#define FILETRANSFER_NOLIST_SIZE 11
#define FILETRANSFER_NOLIST_MDTM 12
#define FILETRANSFER_TYPE 13
#define FILETRANSFER_REST 14
#define FILETRANSFER_MODE 15
#define FILETRANSFER_OPTS 16
#define FILETRANSFER_PORTPASV 17
#define FILETRANSFER_RETRSTOR 18
#define FILETRANSFER_WAITFINISH 19
#define FILETRANSFER_WAIT 20
//Partial flowchart of FileTransfer
//
// +----+
// /------|Init|--------\
// | +----+ |
// | | |
// | /---+ |
// | | | |
// | | +---+ |
// | | |PWD| |
// | | +---+ |
// | | | |
// | \---+ |
// | | |
// | +---+ |
// | |CWD|--\ |
// | +---+ | |
// | | | |
// | | | |
// | | +---+ |
// | | |MKD| |
// | | +---+ |
// | | | |
// | | | |
// | | +----+ |
// | | |CWD2| |
// | | +----+ |
// | | | |
// | +----/ |
// | | |
// | +---+ |
// +-------|PWD| |
// | +---+ |
// | | |
// | +----------/
// | |
// | +---------+
// | |LIST_TYPE|
// | +---------+
// | |
// | |
// | +-------------+
// | |LIST_PORTPASV|
// | +-------------+
// | |
// | |
// | +---------+
// | |LIST_LIST|-----\ //List failes, maybe folder is list protected
// | +---------+ | //Use SIZE and MDTM to get file information
// | | +----+
// | | |SIZE|
// | | +----+
// | | |
// | | +----+
// | | |MDTM|
// | | +----+
// | | |
// | | |
// | +---------------+ |
// | |LIST_WAITFINISH| |
// | +---------------+ |
// | | |
// | | |
// | +----------/
// | |
// \---------+
// |
// +----+
// |TYPE|
// +----+
// |
// |
// +--------+
// |PORTPASV|--\
// +--------+ |
// | |
// | |
// | +----+
// | |REST|
// | +----+
// | |
// +------/
// |
// +--------+
// |RETRSTOR|
// +--------+
// |
// |
// +----------+
// |WAITFINISH|
// +----------+
ASSERT(!m_Operation.nOpMode || m_Operation.nOpMode&CSMODE_TRANSFER);
if (!m_pOwner->IsConnected())
{
m_Operation.nOpMode=CSMODE_TRANSFER|(transferfile->get?CSMODE_DOWNLOAD:CSMODE_UPLOAD);
ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_DISCONNECTED);
return;
}
CFileTransferData *pData=static_cast<CFileTransferData *>(m_Operation.pData);
//Process finish and error messages
if (bFinish || nError)
{
ASSERT(m_Operation.nOpMode&CSMODE_TRANSFER);
// APPE failed, ignore this reply
if (m_Operation.nOpMode == FILETRANSFER_WAIT && bFinish)
return;
if (!(m_Operation.nOpMode&CSMODE_TRANSFER))
return;
if (nError)
{
if (m_Operation.nOpState == FILETRANSFER_LIST_LIST && nError & CSMODE_TRANSFERERROR)
{ //Don't abort operation, use fallback to SIZE and MDTM (when actual LIST reply comes in)
if (m_pTransferSocket)
m_pTransferSocket=0;
delete m_pDirectoryListing;
m_pDirectoryListing=0;
}
else if (nError&CSMODE_TRANSFERTIMEOUT)
DoClose();
else
ResetOperation(FZ_REPLY_ERROR);
return;
}
if (m_Operation.nOpState <= FILETRANSFER_LIST_PORTPASV)
{
ResetOperation(FZ_REPLY_ERROR);
return;
}
else if (m_Operation.nOpState<=FILETRANSFER_LIST_WAITFINISH)
{
if (!m_pTransferSocket || m_pTransferSocket->m_bListening)
{
delete m_pDirectoryListing;
m_pDirectoryListing=0;
ResetOperation(FZ_REPLY_ERROR);
return;
}
int num=0;
pData->pDirectoryListing=new t_directory;
if (COptions::GetOptionVal(OPTION_DEBUGSHOWLISTING))
m_pTransferSocket->m_pListResult->SendToMessageLog(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID);
pData->pDirectoryListing->direntry=m_pTransferSocket->m_pListResult->getList(num, pData->ListStartTime);
pData->pDirectoryListing->num=num;
if (m_pTransferSocket->m_pListResult->m_server.nServerType&FZ_SERVERTYPE_SUB_FTP_VMS && m_CurrentServer.nServerType&FZ_SERVERTYPE_FTP)
m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_VMS;
pData->pDirectoryListing->server = m_CurrentServer;
pData->pDirectoryListing->path.SetServer(m_CurrentServer);
pData->pDirectoryListing->path = pData->transferfile.remotepath;
if (pData->rawpwd!="")
{
if (!pData->pDirectoryListing->path.SetPath(pData->rawpwd))
{
delete m_pDirectoryListing;
m_pDirectoryListing=0;
delete m_pTransferSocket;
m_pTransferSocket=0;
ResetOperation(FZ_REPLY_ERROR);
return;
}
}
else
pData->pDirectoryListing->path=pData->transferfile.remotepath;
if (m_Operation.nOpState!=FILETRANSFER_LIST_WAITFINISH)
return;
}
else if (m_Operation.nOpState <= FILETRANSFER_PORTPASV)
{
ResetOperation(FZ_REPLY_ERROR);
return;
}
else if (m_Operation.nOpState<=FILETRANSFER_WAITFINISH)
{
if (m_pTransferSocket->m_bListening)
{
ResetOperation(FZ_REPLY_ERROR);
return;
}
pData->nGotTransferEndReply |= 2;
if (m_Operation.nOpState!=FILETRANSFER_WAITFINISH)
return;
else
{
delete m_pTransferSocket;
m_pTransferSocket=0;
}
}
}
//////////////////
//Initialization//
//////////////////
int nReplyError = 0;
if (m_Operation.nOpState == FILETRANSFER_INIT)
{
ASSERT(transferfile);
ASSERT(!m_Operation.nOpMode);
ASSERT(!m_Operation.pData);
CString str;
str.Format(transferfile->get?IDS_STATUSMSG_DOWNLOADSTART:IDS_STATUSMSG_UPLOADSTART,
transferfile->get ? transferfile->remotepath.FormatFilename(transferfile->remotefile) : transferfile->localfile);
ShowStatus(str,0);
m_Operation.nOpMode=CSMODE_TRANSFER|(transferfile->get?CSMODE_DOWNLOAD:CSMODE_UPLOAD);
m_Operation.pData=new CFileTransferData;
pData=static_cast<CFileTransferData *>(m_Operation.pData);
if (COptions::GetOptionVal(OPTION_PROXYTYPE)!=PROXYTYPE_NOPROXY && !m_CurrentServer.fwbypass)
pData->bPasv = TRUE;
else if (m_CurrentServer.nPasv == 1)
pData->bPasv = TRUE;
else if (m_CurrentServer.nPasv == 2)
pData->bPasv = FALSE;
else
pData->bPasv = COptions::GetOptionVal(OPTION_PASV);
//Replace invalid characters in the local filename
int pos=transferfile->localfile.ReverseFind('\\');
for (int i=(pos+1);i<transferfile->localfile.GetLength();i++)
if (transferfile->localfile[i]==':')
transferfile->localfile.SetAt(i, '_');
pData->transferfile=*transferfile;
pData->transferdata.transfersize=pData->transferfile.size;
pData->transferdata.transferleft=pData->transferfile.size;
pData->transferdata.bResume = FALSE;
pData->transferdata.bType = (pData->transferfile.nType == 1) ? TRUE : FALSE;
CServerPath path;
VERIFY(m_pOwner->GetCurrentPath(path));
if (path == pData->transferfile.remotepath)
{
if (m_pDirectoryListing)
{
m_Operation.nOpState=FILETRANSFER_TYPE;
CString remotefile=pData->transferfile.remotefile;
int i;
for (i=0; i<m_pDirectoryListing->num; i++)
{
if (m_pDirectoryListing->direntry[i].name==remotefile &&
( m_pDirectoryListing->direntry[i].bUnsure || m_pDirectoryListing->direntry[i].size==-1 ))
{
delete m_pDirectoryListing;
m_pDirectoryListing=0;
m_Operation.nOpState = NeedModeCommand() ? FILETRANSFER_LIST_MODE : (NeedOptsCommand() ? FILETRANSFER_LIST_OPTS : FILETRANSFER_LIST_TYPE);
break;
}
}
if (m_pDirectoryListing && i==m_pDirectoryListing->num)
{
nReplyError = CheckOverwriteFile();
if (!nReplyError)
{
if (pData->transferfile.get)
{
CString path=pData->transferfile.localfile;
if (path.ReverseFind('\\')!=-1)
{
path=path.Left(path.ReverseFind('\\')+1);
CString path2;
while (path!="")
{
path2+=path.Left(path.Find( _T("\\") )+1);
path=path.Mid(path.Find( _T("\\") )+1);
CreateDirectory(path2, 0);
}
}
}
}
}
}
else
{
CDirectoryCache cache;
t_server server;
m_pOwner->GetCurrentServer(server);
t_directory dir;
BOOL res = cache.Lookup(pData->transferfile.remotepath,server,dir);
if (res)
{
CString remotefile=pData->transferfile.remotefile;
int i;
for (i=0; i<dir.num; i++)
{
if (dir.direntry[i].name==remotefile &&
( dir.direntry[i].bUnsure || dir.direntry[i].size==-1 ))
{
m_Operation.nOpState = NeedModeCommand() ? FILETRANSFER_LIST_MODE : (NeedOptsCommand() ? FILETRANSFER_LIST_OPTS : FILETRANSFER_LIST_TYPE);
break;
}
}
if (i == dir.num)
{
SetDirectoryListing(&dir);
m_Operation.nOpState=FILETRANSFER_TYPE;
nReplyError = CheckOverwriteFile();
if (!nReplyError)
{
if (pData->transferfile.get)
{
CString path=pData->transferfile.localfile;
if (path.ReverseFind('\\')!=-1)
{
path=path.Left(path.ReverseFind('\\')+1);
CString path2;
while (path!="")
{
path2+=path.Left(path.Find( _T("\\") )+1);
path=path.Mid(path.Find(_T( "\\") )+1);
CreateDirectory(path2, 0);
}
}
}
}
}
}
else
m_Operation.nOpState = NeedModeCommand() ? FILETRANSFER_LIST_MODE : (NeedOptsCommand() ? FILETRANSFER_LIST_OPTS : FILETRANSFER_LIST_TYPE);
}
}
else
{
if (path.IsEmpty())
m_Operation.nOpState = FILETRANSFER_PWD;
else
m_Operation.nOpState = FILETRANSFER_CWD;
}
}
else
{
///////////
//Replies//
///////////
int code = GetReplyCode();
switch(m_Operation.nOpState)
{
case FILETRANSFER_PWD:
if (code != 2 && code != 3)
{
nReplyError = FZ_REPLY_ERROR;
break;
}
pData->rawpwd = GetReply();
if ((m_mayBeMvsFilesystem || m_mayBeBS2000Filesystem) && m_CurrentServer.nServerType & FZ_SERVERTYPE_FTP &&
pData->rawpw
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?