📄 sftpcontrolsocket.cpp
字号:
// 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 + -