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 + -
显示快捷键?