⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sftpcontrolsocket.cpp

📁 一个FTP下载的源代码。代码质量非常高
💻 CPP
📖 第 1 页 / 共 5 页
字号:
// FileZilla - a Windows ftp client

// Copyright (C) 2002 - Tim Kosse <tim.kosse@gmx.de>

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

// SftpControlSocket.cpp: Implementierung der Klasse CSFtpControlSocket.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SftpControlSocket.h"
#include "mainthread.h"
#include "AsyncProxySocketLayer.h"
#include "SFtpIpc.h"
#include "SFtpCommandIDs.h"
#include "FtpListResult.h"
#include "FileExistsDlg.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


class CSFtpControlSocket::CFileTransferData : public CSFtpControlSocket::t_operation::COpData
{
public:
	CFileTransferData(t_server server) 
	{
		pDirectoryListing=0;
		nWaitNextOpState=0;
		nMKDOpState=-1;
		pFileTime=0;
		transferdata.transferleft=-1;
		transferdata.transfersize=-1;
		transferdata.nTransferStart=0;
		pStartTime=0;
		bUseAbsolutePaths = FALSE;
		pParser = new CFtpListResult(server);
	};
	virtual ~CFileTransferData() 
	{
		if (pDirectoryListing)
			delete pDirectoryListing;
		pDirectoryListing=0;
		delete pFileTime;
		delete pStartTime;
		delete pParser;
	};
	CString rawpwd;
	CTime ListStartTime;
	t_transferfile transferfile;
	t_transferdata transferdata;
	t_directory *pDirectoryListing;
	int nWaitNextOpState;
	CServerPath MKDCurrent;
	std::list<CString> MKDSegments;
	int nMKDOpState;
	CTime *pFileTime; //Used when downloading and OPTION_PRESERVEDOWNLOADFILETIME is set or when LIST fails
	CTime *pStartTime;
	CFtpListResult *pParser;
	BOOL bUseAbsolutePaths;
};

class CSFtpControlSocket::CListData:public CSFtpControlSocket::t_operation::COpData
{
public:
	CListData(t_server server) 
	{
		pDirectoryListing=0;
		pParser = new CFtpListResult(server);
	}
	virtual ~CListData() 
	{
		if (pDirectoryListing)
			delete pDirectoryListing;
		delete pParser;
	}
	CString rawpwd;
	CTime ListStartTime;
	CServerPath path;
	CString subdir;
	CServerPath realpath;
	int nListMode;
	t_directory *pDirectoryListing;
	CFtpListResult *pParser;
};

#define MKD_INIT -1
#define MKD_FINDPARENT 0
#define MKD_MAKESUBDIRS 1
#define MKD_CHANGETOSUBDIR 2

//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////

CSFtpControlSocket::CSFtpControlSocket(CMainThread *pMainThread) : CControlSocket(pMainThread)
{
	ASSERT(pMainThread);
	m_pOwner=pMainThread;

	m_Operation.nOpMode=0;
	m_Operation.nOpState=-1;
	m_Operation.pData=0;

	m_pDataChannel=0;
	m_hSFtpProcess=0;

	m_bQuit=FALSE;
	m_bCheckForTimeout=TRUE;
	m_bError=FALSE;
}

CSFtpControlSocket::~CSFtpControlSocket()
{
	if (m_pDataChannel)
		delete m_pDataChannel;
	if (m_hSFtpProcess)
	{
		TerminateProcess(m_hSFtpProcess, 1);
		CloseHandle(m_hSFtpProcess);
	}
}

/////////////////////////////////////////////////////////////////////////////
// Member-Funktion CControlSocket 
#define CONNECT_INIT -1
#define CONNECT_GSS -3

extern CString GetProgramFile();

void CSFtpControlSocket::Connect(t_server &server)
{
	USES_CONVERSION;

	ASSERT(!m_pOwner->IsConnected());
	ASSERT(!m_hSFtpProcess);
	
	ASSERT(!m_Operation.nOpMode);
	
	ASSERT(!m_pProxyLayer);
	
	if (!server.fwbypass)
	{
		int nProxyType=COptions::GetOptionVal(OPTION_PROXYTYPE);
		if (nProxyType!=PROXYTYPE_NOPROXY)
		{
			USES_CONVERSION;

			m_pProxyLayer=new CAsyncProxySocketLayer;
			if (nProxyType==PROXYTYPE_SOCKS4)
				m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS4, T2CA(COptions::GetOption(OPTION_PROXYHOST)), COptions::GetOptionVal(OPTION_PROXYPORT));
			else if (nProxyType==PROXYTYPE_SOCKS4A)
				m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS4A, T2CA(COptions::GetOption(OPTION_PROXYHOST)), COptions::GetOptionVal(OPTION_PROXYPORT));
			else if (nProxyType==PROXYTYPE_SOCKS5)
				if (COptions::GetOptionVal(OPTION_PROXYUSELOGON))
					m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS5, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
											COptions::GetOptionVal(OPTION_PROXYPORT),
											T2CA(COptions::GetOption(OPTION_PROXYUSER)),
											T2CA(CCrypt::decrypt(COptions::GetOption(OPTION_PROXYPASS))));
				else
					m_pProxyLayer->SetProxy(PROXYTYPE_SOCKS5, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
											COptions::GetOptionVal(OPTION_PROXYPORT));
			else if (nProxyType==PROXYTYPE_HTTP11)
				if (COptions::GetOptionVal(OPTION_PROXYUSELOGON))
					m_pProxyLayer->SetProxy(PROXYTYPE_HTTP11, T2CA(COptions::GetOption(OPTION_PROXYHOST)),
											COptions::GetOptionVal(OPTION_PROXYPORT),
											T2CA(COptions::GetOption(OPTION_PROXYUSER)),
											T2CA(CCrypt::decrypt(COptions::GetOption(OPTION_PROXYPASS))));
				else
					m_pProxyLayer->SetProxy(PROXYTYPE_HTTP11, T2CA(COptions::GetOption(OPTION_PROXYHOST)), COptions::GetOptionVal(OPTION_PROXYPORT));
			else
				ASSERT(FALSE);
			AddLayer(m_pProxyLayer);
		}
	}
		
	m_Operation.nOpMode=CSMODE_CONNECT;
	
	m_Operation.nOpState=CONNECT_INIT;

	//Create data channel
	ASSERT(!m_pDataChannel);
	m_pDataChannel=new CSFtpIpc(this);
	if (!m_pDataChannel->Init())
	{
		ShowStatus(IDS_ERRORMSG_SFTP_CANTCREATESFTPIPC, 1);
		DoClose();
		return;
	}

	CString path=GetProgramFile();
	int pos=path.ReverseFind('\\');
	ASSERT(pos!=-1 && pos!=(path.GetLength()-1) );
	path=path.Left(pos+1);
	STARTUPINFO StartupInfo={0};
	StartupInfo.cb=sizeof(StartupInfo);
	
	PROCESS_INFORMATION ProcessInformation={0};
	TCHAR HandleString[1000];
	_tcscpy(HandleString, _T("FzSFtp.exe ") + m_pDataChannel->GetHandleString());
	if (!CreateProcess(path + _T("FzSFtp.exe"), HandleString, 0, 0, TRUE, 0, 0, 0, &StartupInfo, &ProcessInformation))
	{
		ShowStatus(IDS_ERRORMSG_SFTP_CANTCREATESFTPPROCESS, 1);
		DoClose();
		return;
	}
	
	m_hSFtpProcess=ProcessInformation.hProcess;
	CloseHandle(ProcessInformation.hThread);
	if (!m_pDataChannel->AttachProcess(ProcessInformation.hProcess))
	{
		ShowStatus(IDS_ERRORMSG_SFTP_CANTCREATESFTPPROCESS, 1);
		DoClose();
		return;
	}
	
	if (!Create())
	{
		DoClose();
		return;
	}
	AsyncSelect();
	int port;
	CString temp;
	
	temp=server.host;
	port=server.port;
	
	m_CurrentServer=server;
	
	CString hostname=server.host;
	if(server.port!=21) 
		hostname.Format( _T("%s:%d"), hostname, server.port); // add port to hostname (only if port is not 21)
	CString str;
	str.Format(IDS_STATUSMSG_CONNECTING,hostname);
	ShowStatus(str,0);
	
	m_Operation.nOpMode=CSMODE_CONNECT;
	
	if (!CControlSocket::Connect(temp, port))
	{
		if (WSAGetLastError()!=WSAEWOULDBLOCK)
		{
			DoClose();
			return;
		}
	}

	/* Disable Nagle algorithm. Most of the time single short strings get 
	 * transferred over the control connection. Waiting for additional data
	 * where there will be most likely none affects performance.
	 */
	//BOOL value = TRUE;
	//SetSockOpt(TCP_NODELAY, &value, sizeof(value), IPPROTO_TCP);

	m_ServerName = hostname;
	m_LastRecvTime = m_LastSendTime = CTime::GetCurrentTime();
}

void CSFtpControlSocket::OnTimer()
{
    if ( m_Operation.nOpMode&(CSMODE_LIST|CSMODE_TRANSFER) )
	UpdateTransferstatus(0);
}

BOOL CSFtpControlSocket::IsReady()
{
	return TRUE;
}

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

	USES_CONVERSION;

	#define LIST_INIT	-1
	#define LIST_PWD	0
	#define LIST_CWD	1
	#define LIST_CWD2	2
	#define LIST_LIST	3

	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)
	{
		if (nError&CSMODE_TRANSFERTIMEOUT)
			DoClose();
		else
			ResetOperation(FZ_REPLY_ERROR);
		return;
	}

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

	if (m_Operation.nOpState!=LIST_INIT)
	{
		if (m_Operation.nOpState==LIST_PWD)
		{ //Reply to PWD command
			pData->realpath.SetServer(m_CurrentServer);
			if (m_Reply=="" || !pData->realpath.SetPath(m_Reply))
			{
				LogMessage(__FILE__, __LINE__, this,FZ_LOG_WARNING, _T("Can't parse path") );
				ResetOperation(FZ_REPLY_ERROR);
				return;
			}
			pData->rawpwd=m_Reply;
			m_pOwner->SetCurrentPath(pData->realpath);
			if (pData->nListMode&FZ_LIST_USECACHE)
			{
				t_directory dir;
				CDirectoryCache cache;
				BOOL res=cache.Lookup(pData->realpath,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=LIST_LIST;
		}
		else if (m_Operation.nOpState==LIST_CWD)
		{
			pData->realpath.SetServer(m_CurrentServer);
			if (m_Reply=="" || !pData->realpath.SetPath(m_Reply))
			{
				LogMessage(__FILE__, __LINE__, this,FZ_LOG_WARNING, _T("Can't parse path") );
				ResetOperation(FZ_REPLY_ERROR);
				return;
			}
			pData->rawpwd=m_Reply;
			m_pOwner->SetCurrentPath(pData->realpath);
			if (pData->nListMode&FZ_LIST_USECACHE && pData->subdir=="")
			{
				t_directory dir;
				CDirectoryCache cache;
				BOOL res=cache.Lookup(pData->realpath,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;
					}
				}
			}
			if (pData->subdir!="")
			{
				if (pData->path!=pData->realpath)
				{
					ResetOperation(FZ_REPLY_ERROR);
					return;
				}
				m_Operation.nOpState=LIST_CWD2;
			}
			else
				m_Operation.nOpState=LIST_LIST;
		}
		else if (m_Operation.nOpState==LIST_CWD2)
		{
			pData->realpath.SetServer(m_CurrentServer);
			if (m_Reply=="" || !pData->realpath.SetPath(m_Reply))
			{
				LogMessage(__FILE__, __LINE__, this,FZ_LOG_WARNING, _T("Can't parse path") );
				ResetOperation(FZ_REPLY_ERROR);
				return;
			}
			pData->rawpwd=m_Reply;
			m_pOwner->SetCurrentPath(pData->realpath);
			if (pData->nListMode&FZ_LIST_USECACHE)
			{
				t_directory dir;
				CDirectoryCache cache;
				cache.Lock();
				BOOL res=cache.Lookup(pData->realpath,m_CurrentServer,dir);
				if (res)
				{
					if (pData->subdir!="..")
						m_pOwner->m_pDirectoryCache->Store(dir,pData->path,pData->subdir,TRUE);
					cache.Unlock();
					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;
					}
				}
				else
					cache.Unlock();
			}
			m_Operation.nOpState=LIST_LIST;
		}
		else if (m_Operation.nOpState==LIST_LIST)
		{
			if (m_Reply!="")
			{
				char *data = new char[m_Reply.GetLength()+2+1];
				strcpy(data, T2CA(m_Reply+"\r\n"));
				pData->pParser->AddData(data, m_Reply.GetLength()+2);
			}
			else
			{
				int num = 0;
				delete pData->pDirectoryListing;
				pData->pDirectoryListing = new t_directory;
				if (COptions::GetOptionVal(OPTION_DEBUGSHOWLISTING))
					pData->pParser->SendToMessageLog(m_pOwner->m_hOwnerWnd, m_pOwner->m_nReplyMessageID);
				pData->pDirectoryListing->direntry = pData->pParser->getList(num, CTime::GetCurrentTime());
				pData->pDirectoryListing->num = num;
				if (pData->pParser->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!="")
				{

⌨️ 快捷键说明

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