ftpcontrolsocket.cpp

来自「一个支持FTP,SFTP的客户端程序」· C++ 代码 · 共 2,319 行 · 第 1/5 页

CPP
2,319
字号
	else if (m_Operation.nOpMode&CSMODE_RENAME)
		Rename(_T(""), _T(""), CServerPath(), CServerPath());

	if (!m_RecvBuffer.empty())
		m_RecvBuffer.pop_front();
}

void CFtpControlSocket::OnConnect(int nErrorCode)
{
	LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("OnConnect(%d)  OpMode=%d OpState=%d"), nErrorCode, m_Operation.nOpMode, m_Operation.nOpState);

	if (!m_Operation.nOpMode)
	{
		if (!m_pOwner->IsConnected())
			DoClose();
		return;
	}
	if (!nErrorCode)
	{
		if (!m_pOwner->IsConnected())
		{
			m_MultiLine = "";
			m_pOwner->SetConnected(TRUE);
			CString str;
			str.Format(m_pSslLayer ? IDS_STATUSMSG_CONNECTEDWITHSSL : IDS_STATUSMSG_CONNECTEDWITH, m_ServerName);
			ShowStatus(str,0);
		}
	}
	else
	{
		if (nErrorCode == WSAHOST_NOT_FOUND)
			ShowStatus(IDS_ERRORMSG_CANTRESOLVEHOST, 1);
		DoClose();
	}
}

BOOL CFtpControlSocket::Send(CString str)
{
	USES_CONVERSION;

	ShowStatus(str, 2);
	str += "\r\n";
	int res = 0;
	if (m_bUTF8)
	{
		LPCWSTR unicode = T2CW(str);
		int len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, 0, 0, 0, 0);
		if (!len)
		{
			ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, 1);
			DoClose();
			return FALSE;
		}
		char* utf8 = new char[len + 1];
		WideCharToMultiByte(CP_UTF8, 0, unicode, -1, utf8, len + 1, 0, 0);

		int sendLen = strlen(utf8);
		if (!m_awaitsReply && !m_sendBuffer)
			res = CAsyncSocketEx::Send(utf8, strlen(utf8));
		else
			res = -2;
		if ((res == SOCKET_ERROR && GetLastError() != WSAEWOULDBLOCK) || !res)
		{
			delete [] utf8;
			ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, 1);
			DoClose();
			return FALSE;
		}
		if (res != sendLen)
		{
			if (res == -2)
				res = 0;
			if (!m_sendBuffer)
			{
				m_sendBuffer = new char[sendLen - res];
				memcpy(m_sendBuffer, utf8 + res, sendLen - res);
				m_sendBufferLen = sendLen - res;
			}
			else
			{
				char* tmp = new char[m_sendBufferLen + sendLen - res];
				memcpy(tmp, m_sendBuffer, m_sendBufferLen);
				memcpy(tmp + m_sendBufferLen, utf8 + res, sendLen - res);
				delete [] m_sendBuffer;
				m_sendBuffer = tmp;
				m_sendBufferLen += sendLen - res;
			}
		}
		delete [] utf8;
	}
	else
	{
		LPCSTR lpszAsciiSend = T2CA(str);

		int sendLen = strlen(lpszAsciiSend);
		if (!m_awaitsReply && !m_sendBuffer)
			res = CAsyncSocketEx::Send(lpszAsciiSend, strlen(lpszAsciiSend));
		else
			res = -2;
		if ((res == SOCKET_ERROR && GetLastError() != WSAEWOULDBLOCK) || !res)
		{
			ShowStatus(IDS_ERRORMSG_CANTSENDCOMMAND, 1);
			DoClose();
			return FALSE;
		}
		if (res != sendLen)
		{
			if (res == -2)
				res = 0;
			if (!m_sendBuffer)
			{
				m_sendBuffer = new char[sendLen - res];
				memcpy(m_sendBuffer, lpszAsciiSend, sendLen - res);
				m_sendBufferLen = sendLen - res;
			}
			else
			{
				char* tmp = new char[m_sendBufferLen + sendLen - res];
				memcpy(tmp, m_sendBuffer, m_sendBufferLen);
				memcpy(tmp + m_sendBufferLen, lpszAsciiSend + res, sendLen - res);
				delete [] m_sendBuffer;
				m_sendBuffer = tmp;
				m_sendBufferLen += sendLen - res;
			}
		}
	}
	if (res > 0)
	{
		m_awaitsReply = true;
		m_LastSendTime = CTime::GetCurrentTime();
		PostMessage(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_SOCKETSTATUS, FZ_SOCKETSTATUS_SEND), 0);
	}
	return TRUE;
}

int CFtpControlSocket::GetReplyCode()
{
	if (m_RecvBuffer.empty())
		return 0;
	CStringA str = m_RecvBuffer.front();
	if (str == "")
		return 0;
	else
		return str[0]-'0';
}

void CFtpControlSocket::DoClose(int nError /*=0*/)
{
	LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("DoClose(%d)  OpMode=%d OpState=%d"), nError, m_Operation.nOpMode, m_Operation.nOpState);

	m_bCheckForTimeout=TRUE;
	m_pOwner->SetConnected(FALSE);
	m_bKeepAliveActive=FALSE;
	PostMessage(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID, FZ_MSG_MAKEMSG(FZ_MSG_SECURESERVER, FALSE), 0);
	if (nError & FZ_REPLY_CRITICALERROR)
		nError |= FZ_REPLY_ERROR;
	ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_DISCONNECTED|nError);
	m_RecvBuffer.clear();
	m_MultiLine = "";
	m_bDidRejectCertificate = FALSE;

	m_useZlib = false;
	m_zlibSupported = false;
	m_zlibLevel = 0;

	m_bUTF8 = false;
	m_hasClntCmd = false;

	m_awaitsReply = false;
	m_skipReply = false;

	delete [] m_sendBuffer;
	m_sendBuffer = 0;
	m_sendBufferLen = 0;

	m_bProtP = false;

	m_mayBeMvsFilesystem = false;
	m_mayBeBS2000Filesystem = false;

	CControlSocket::Close();
}

void CFtpControlSocket::Disconnect()
{
	ASSERT(!m_Operation.nOpMode);
	m_Operation.nOpMode=CSMODE_DISCONNECT;
	DoClose();
	ShowStatus(IDS_STATUSMSG_DISCONNECTED,0); //Send the disconnected message to the message log
}

void CFtpControlSocket::CheckForTimeout()
{
	if (!m_Operation.nOpMode && !m_bKeepAliveActive)
		return;
	if (!m_bCheckForTimeout)
		return;
	int delay=COptions::GetOptionVal(OPTION_TIMEOUTLENGTH);
	if (m_pTransferSocket)
	{
		int res=m_pTransferSocket->CheckForTimeout(delay);
		if (res)
			return;
	}
	CTimeSpan span=CTime::GetCurrentTime()-m_LastRecvTime;
	if (span.GetTotalSeconds()>=delay)
	{
		ShowStatus(IDS_ERRORMSG_TIMEOUT, 1);
		DoClose();
	}
}

void CFtpControlSocket::FtpCommand(LPCTSTR pCommand)
{
	LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("FtpCommand(%s)  OpMode=%d OpState=%d"), pCommand, m_Operation.nOpMode, m_Operation.nOpState);
	m_Operation.nOpMode=CSMODE_COMMAND;
	Send(pCommand);
}

void CFtpControlSocket::List(BOOL bFinish, int nError /*=FALSE*/, CServerPath path /*=CServerPath()*/, CString subdir /*=""*/,int nListMode/*=0*/)
{
	LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("List(%s,%d,\"%s\",\"%s\",%d)  OpMode=%d OpState=%d"), bFinish?_T("TRUE"):_T("FALSE"), nError, path.GetPath(), subdir, nListMode,
				m_Operation.nOpMode, m_Operation.nOpState);

	USES_CONVERSION;

	#define LIST_INIT	-1
	#define LIST_PWD	0
	#define LIST_CWD	1
	#define LIST_PWD2	2
	#define LIST_CWD2	3
	#define LIST_PWD3	4
	#define LIST_MODE	5
	#define LIST_OPTS	6
	#define LIST_PORT_PASV	7
	#define LIST_TYPE	8
	#define LIST_LIST	9
	#define LIST_WAITFINISH	10

	ASSERT(!m_Operation.nOpMode || m_Operation.nOpMode&CSMODE_LIST);

	m_Operation.nOpMode|=CSMODE_LIST;

	if (!m_pOwner->IsConnected())
	{
		ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_NOTCONNECTED);
		return;
	}

	if (bFinish || nError)
		if (m_Operation.nOpMode!=CSMODE_LIST)
			return; //Old message coming in

	if (nError)
	{
		delete m_pTransferSocket;
		m_pTransferSocket=0;
		if (nError&CSMODE_TRANSFERTIMEOUT)
			DoClose();
		else
			ResetOperation(FZ_REPLY_ERROR);
		return;
	}

	CListData *pData = static_cast<CListData *>(m_Operation.pData);

	if (bFinish)
	{
		if (!m_pTransferSocket || m_pTransferSocket->m_bListening)
		{
			delete m_pDirectoryListing;
			m_pDirectoryListing = 0;
			delete m_pTransferSocket;
			m_pTransferSocket = 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(pData->pDirectoryListing->server);
		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;
			}
			m_pOwner->SetCurrentPath(pData->pDirectoryListing->path);
		}
		else
			pData->pDirectoryListing->path = m_pOwner->GetCurrentPath();

		if (m_Operation.nOpState!=LIST_WAITFINISH)
			return;
		else
		{
			delete m_pTransferSocket;
			m_pTransferSocket=0;
		}
	}

	if (m_Operation.nOpState==LIST_WAITFINISH)
	{
		if (!bFinish)
		{
			if (pData->nFinish==-1)
			{
				int code=GetReplyCode();
				if (code== 2)
				{
					pData->nFinish=1;
				}
				else
					pData->nFinish=0;
			}
		}
		else
		{
			if (m_pTransferSocket)
				delete m_pTransferSocket;
			m_pTransferSocket=0;
		}
		if (pData->nFinish==0)
		{
			ResetOperation(FZ_REPLY_ERROR);
			return;
		}
		else if (pData->pDirectoryListing && pData->nFinish==1)
		{
			ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,0);
			CDirectoryCache cache;
			cache.Lock();
			t_directory dir;
			if (!pData->path.IsEmpty() && pData->subdir!="")
			{
				if (cache.Lookup(pData->pDirectoryListing->path, pData->pDirectoryListing->server, dir))
					pData->pDirectoryListing->Merge(dir, pData->ListStartTime);
				cache.Store(*pData->pDirectoryListing,pData->path,pData->subdir);
			}
			else
			{
				if (cache.Lookup(pData->pDirectoryListing->path, pData->pDirectoryListing->server, dir))
					pData->pDirectoryListing->Merge(dir, pData->ListStartTime);
				cache.Store(*pData->pDirectoryListing);
			}
			cache.Unlock();
			SetDirectoryListing(pData->pDirectoryListing);
			ResetOperation(FZ_REPLY_OK);
			return;
		}
		return;
	}
	else if (m_Operation.nOpState != LIST_INIT)
	{
		CString retmsg = GetReply();
		BOOL error = FALSE;
		int code = GetReplyCode();
		switch (m_Operation.nOpState)
		{
		case LIST_PWD: //Reply to PWD command
			if (code != 2 && code !=3 )
			{
				error = TRUE;
				break;
			}

			pData->rawpwd = retmsg;
			if ((m_mayBeMvsFilesystem || m_mayBeBS2000Filesystem) && m_CurrentServer.nServerType & FZ_SERVERTYPE_FTP &&
				pData->rawpwd[0] != '/')
			{
				m_mayBeMvsFilesystem = false;
				m_mayBeBS2000Filesystem = false;
				if (m_mayBeBS2000Filesystem)
					m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_BS2000;
				else
					m_CurrentServer.nServerType |= FZ_SERVERTYPE_SUB_FTP_MVS;

				if (!pData->path.IsEmpty())
					pData->path.SetServer(m_CurrentServer);
			}
			if (!ParsePwdReply(pData->rawpwd))
				return;
			if (pData->path.IsEmpty() || pData->path == m_pOwner->GetCurrentPath())
			{
				if (pData->nListMode & FZ_LIST_USECACHE)
				{
					t_directory dir;
					CDirectoryCache cache;
					BOOL res = cache.Lookup(m_pOwner->GetCurrentPath(), m_CurrentServer, dir);
					if (res)
					{
						BOOL bExact = TRUE;
						if (pData->nListMode & FZ_LIST_EXACT)
							for (int i=0; i<dir.num; i++)
								if (dir.direntry[i].bUnsure || (dir.direntry[i].size==-1 && !dir.direntry[i].dir))
								{
									bExact = FALSE;
									break;
								}
						if (bExact)
						{
							ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL, 0);
							SetDirectoryListing(&dir);
							ResetOperation(FZ_REPLY_OK);
							return;
						}
					}
				}
				m_Operation.nOpState = NeedModeCommand() ? LIST_MODE : (NeedOptsCommand() ? LIST_OPTS : LIST_TYPE);
			}
			else
				m_Operation.nOpState = LIST_CWD;
			break;
		case LIST_CWD:
			if (code != 2 && code != 3)
				error = TRUE;
			m_Operation.nOpState = LIST_PWD2;
			break;
		case LIST_PWD2: //Reply to PWD command
			if (code !=2 && code != 3)
				error = TRUE;
			else
			{
				pData->rawpwd = retmsg;
				if (!ParsePwdReply(pData->rawpwd))
					return;
			}
			if (pData->subdir != "")
			{
				if (pData->path != m_pOwner->GetCurrentPath())
				{
					ResetOperation(FZ_REPLY_ERROR);
					return;
				}
				m_Operation.nOpState = LIST_CWD2;
			}
			else
			{
				if (pData->nListMode & FZ_LIST_USECACHE)
				{
					t_directory dir;
					CDirectoryCache cache;
					BOOL res = cache.Lookup(m_pOwner->GetCurrentPath(), m_CurrentServer, dir);
					if (res)
					{
						BOOL bExact = TRUE;
						if (pData->nListMode & FZ_LIST_EXACT)
							for (int i=0; i<dir.num; i++)
								if (dir.direntry[i].bUnsure || (dir.direntry[i].size==-1 && !dir.direntry[i].dir))
								{
									bExact = FALSE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?