📄 ftpclient.cpp
字号:
}
/// Analyse the repy code of a ftp-server-response.
/// @param[in] Reply Reply of a ftp server.
/// @retval FTP_OK All runs perfect.
/// @retval FTP_ERROR Something went wrong. An other response was expected.
/// @retval NOT_OK The command was not accepted.
int CFTPClient::SimpleErrorCheck(const CReply& Reply) const
{
if( Reply.Code().IsNegativeReply() )
return FTP_NOTOK;
else if( Reply.Code().IsPositiveCompletionReply() )
return FTP_OK;
ASSERT( Reply.Code().IsPositiveReply() );
return FTP_ERROR;
}
/// Logs on to an ftp-server.
/// @param[in] logonInfo Structure with logon information.
bool CFTPClient::Login(const CLogonInfo& logonInfo)
{
m_LastLogonInfo = logonInfo;
enum {LO=-2, ///< Logged On
ER=-1, ///< Error
NUMLOGIN=9, ///< currently supports 9 different login sequences
};
int iLogonSeq[NUMLOGIN][18] = {
// this array stores all of the logon sequences for the various firewalls
// in blocks of 3 nums.
// 1st num is command to send,
// 2nd num is next point in logon sequence array if 200 series response
// is rec'd from server as the result of the command,
// 3rd num is next point in logon sequence if 300 series rec'd
{ 0,LO,3, 1,LO, 6, 2,LO,ER }, // no firewall
{ 3, 6,3, 4, 6,ER, 5,ER, 9, 0,LO,12, 1,LO,15, 2,LO,ER }, // SITE hostname
{ 3, 6,3, 4, 6,ER, 6,LO, 9, 1,LO,12, 2,LO,ER }, // USER after logon
{ 7, 3,3, 0,LO, 6, 1,LO, 9, 2,LO,ER }, // proxy OPEN
{ 3, 6,3, 4, 6,ER, 0,LO, 9, 1,LO,12, 2,LO,ER }, // Transparent
{ 6,LO,3, 1,LO, 6, 2,LO,ER }, // USER with no logon
{ 8, 6,3, 4, 6,ER, 0,LO, 9, 1,LO,12, 2,LO,ER }, // USER fireID@remotehost
{ 9,ER,3, 1,LO, 6, 2,LO,ER }, // USER remoteID@remotehost fireID
{10,LO,3, 11,LO, 6, 2,LO,ER } // USER remoteID@fireID@remotehost
};
// are we connecting directly to the host (logon type 0) or via a firewall? (logon type>0)
tstring strTemp;
USHORT ushPort=0;
if( logonInfo.FwType() == CFirewallType::None())
{
strTemp = logonInfo.Hostname();
ushPort = logonInfo.Hostport();
}
else
{
strTemp = logonInfo.FwHost();
ushPort = logonInfo.FwPort();
}
tstring strHostnamePort(logonInfo.Hostname());
if( logonInfo.Hostport()!=DEFAULT_FTP_PORT )
strHostnamePort = CMakeString() << logonInfo.Hostname() << _T(":") << logonInfo.Hostport(); // add port to hostname (only if port is not 21)
if( IsConnected() )
Logout();
if( !OpenControlChannel(strTemp, ushPort) )
return false;
// get initial connect msg off server
CReply Reply;
if( !GetResponse(Reply) || !Reply.Code().IsPositiveCompletionReply() )
return false;
int iLogonPoint=0;
// go through appropriate logon procedure
#pragma warning(disable:4127)
while( true )
#pragma warning(default:4127)
{
switch(iLogonSeq[logonInfo.FwType().AsEnum()][iLogonPoint])
{
case 0:
strTemp=_T("USER ") + logonInfo.Username();
break;
case 1:
strTemp=_T("PASS ") + logonInfo.Password();
break;
case 2:
strTemp=_T("ACCT ") + logonInfo.Account();
break;
case 3:
strTemp=_T("USER ") + logonInfo.FwUsername();
break;
case 4:
strTemp=_T("PASS ") + logonInfo.FwPassword();
break;
case 5:
strTemp=_T("SITE ") + strHostnamePort;
break;
case 6:
strTemp=_T("USER ") + logonInfo.Username() + _T("@") + strHostnamePort;
break;
case 7:
strTemp=_T("OPEN ") + strHostnamePort;
break;
case 8:
strTemp=_T("USER ") + logonInfo.FwUsername() + _T("@") + strHostnamePort;
break;
case 9:
strTemp=_T("USER ") + logonInfo.Username() + _T("@") + strHostnamePort + _T(" ") + logonInfo.FwUsername();
break;
case 10:
strTemp=_T("USER ") + logonInfo.Username() + _T("@") + logonInfo.FwUsername() + _T("@") + strHostnamePort;
break;
case 11:
strTemp=_T("PASS ") + logonInfo.Password() + _T("@") + logonInfo.FwPassword();
break;
}
// send command, get response
CReply Reply;
if( !SendCommand(strTemp, Reply) )
return false;
if( !Reply.Code().IsPositiveCompletionReply() && !Reply.Code().IsPositiveIntermediateReply() )
return false;
const unsigned int uiFirstDigitOfReplyCode = CCnv::TStringToLong(Reply.Code().Value())/100;
iLogonPoint=iLogonSeq[logonInfo.FwType().AsEnum()][iLogonPoint + uiFirstDigitOfReplyCode-1]; //get next command from array
switch(iLogonPoint)
{
case ER: // ER means somewhat has gone wrong
{
ReportError(_T("Logon failed."), CCnv::ConvertToTString(__FILE__), __LINE__);
}
return false;
case LO: // LO means we're fully logged on
if( ChangeWorkingDirectory(_T("/"))!=FTP_OK )
return false;
return true;
}
}
return false;
}
/// Rename a file on the ftp server.
/// @param[in] strOldName Name of the file to rename.
/// @param[in] strNewName The new name for the file.
/// @return see return values of CFTPClient::SimpleErrorCheck
int CFTPClient::Rename(const tstring& strOldName, const tstring& strNewName) const
{
CReply Reply;
if( !SendCommand(_T("RNFR ")+strOldName, Reply) )
return FTP_ERROR;
if( Reply.Code().IsNegativeReply() )
return FTP_NOTOK;
else if( !Reply.Code().IsPositiveIntermediateReply() )
{
ASSERT( Reply.Code().IsPositiveCompletionReply() || Reply.Code().IsPositivePreliminaryReply() );
return FTP_ERROR;
}
if( !SendCommand(_T("RNTO ")+strNewName, Reply) )
return FTP_ERROR;
return SimpleErrorCheck(Reply);
}
/// Gets the directory listing of the ftp-server. Sends the LIST command to
/// the ftp-server.
/// @param[in] strPath Starting path for the list command.
/// @param[out] vstrFileList Returns a simple list of the files and folders of the specified directory.
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::List(const tstring& strPath, TStringVector& vstrFileList, bool fPasv) const
{
COutputStream outputStream(mc_strEolCharacterSequence);
//if( !ExecuteDatachannelCommand(CDatachannelCmd::LIST(), strPath, CRepresentation(CType::ASCII()), fPasv, 0, &outputStream) )
if( !ExecuteDatachannelCommand(CDatachannelCmd::LIST(), strPath, CRepresentation(CType::ASCII()), true, 0, &outputStream) )
return false;
vstrFileList.clear();
tstring strLine;
outputStream.SetStartPosition();
while( outputStream.GetNextLine(strLine) )
vstrFileList.push_back(strPath + strLine.c_str());
return true;
}
/// Gets the directory listing of the ftp-server. Sends the NLST command to
/// the ftp-server.
/// @param[in] strPath Starting path for the list command.
/// @param[out] vstrFileList Returns a simple list of the files and folders of the specified the directory.
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::NameList(const tstring& strPath, TStringVector& vstrFileList, bool fPasv) const
{
COutputStream outputStream(mc_strEolCharacterSequence);
if( !ExecuteDatachannelCommand(CDatachannelCmd::NLST(), strPath, CRepresentation(CType::ASCII()), fPasv, 0, &outputStream) )
return false;
vstrFileList.clear();
tstring strLine;
outputStream.SetStartPosition();
while( outputStream.GetNextLine(strLine) )
vstrFileList.push_back(strPath + strLine.c_str());
return true;
}
/// Gets the directory listing of the ftp-server. Sends the LIST command to
/// the ftp-server.
/// @param[in] strPath Starting path for the list command.
/// @param[out] vFileList Returns a detailed list of the files and folders of the specified directory.
/// vFileList contains CFTPFileStatus-Objects. These Objects provide a lot of
/// information about the file/folder.
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::List(const tstring& strPath, TSpFTPFileStatusVector& vFileList, bool fPasv) const
{
COutputStream outputStream(mc_strEolCharacterSequence);
//if( !ExecuteDatachannelCommand(CDatachannelCmd::LIST(), strPath, CRepresentation(CType::ASCII()), fPasv, 0, &outputStream) )
if( !ExecuteDatachannelCommand(CDatachannelCmd::LIST(), strPath, CRepresentation(CType::ASCII()), true, 0, &outputStream) )
return false;
vFileList.clear();
tstring strLine;
CFTPListParse ftpListParser;
outputStream.SetStartPosition();
while( outputStream.GetNextLine(strLine) )
{
std::auto_ptr<CFTPFileStatus> pFtpFileStatus(new CFTPFileStatus());
if( ftpListParser.Parse(*pFtpFileStatus, strLine) )
{
pFtpFileStatus->Path() = strPath;
vFileList.push_back(pFtpFileStatus.release());
}
}
return true;
}
/// Gets the directory listing of the ftp-server. Sends the NLST command to
/// the ftp-server.
/// @param[in] strPath Starting path for the list command.
/// @param[out] vFileList Returns a simple list of the files and folders of the specified directory.
/// vFileList contains CFTPFileStatus-Objects. Normally these Objects provide
/// a lot of information about the file/folder. But the NLST-command provide
/// only a simple list of the directory content (no specific information).
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::NameList(const tstring& strPath, TSpFTPFileStatusVector& vFileList, bool fPasv) const
{
COutputStream outputStream(mc_strEolCharacterSequence);
if( !ExecuteDatachannelCommand(CDatachannelCmd::NLST(), strPath, CRepresentation(CType::ASCII()), fPasv, 0, &outputStream) )
return false;
vFileList.clear();
tstring strLine;
CFTPListParse ftpListParser;
outputStream.SetStartPosition();
while( outputStream.GetNextLine(strLine) )
{
std::auto_ptr<CFTPFileStatus> pFtpFileStatus(new CFTPFileStatus());
pFtpFileStatus->Path() = strPath;
pFtpFileStatus->Name() = strLine;
vFileList.push_back(pFtpFileStatus.release());
}
return true;
}
/// Gets a file from the ftp-server.
/// Uses C functions for file access (very fast).
/// @param[in] strRemoteFile Filename of the sourcefile on the ftp-server.
/// @param[in] strLocalFile Filename of the targetfile on the local computer.
/// @param[in] repType Representation Type (see documentation of CRepresentation)
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::DownloadFile(const tstring& strRemoteFile, const tstring& strLocalFile, const CRepresentation& repType, bool fPasv) const
{
CFile file;
if( !file.Open(strLocalFile, m_fResumeIfPossible?_T("ab"):_T("wb")) )
{
ReportError(CError::GetErrorDescription(), CCnv::ConvertToTString(__FILE__), __LINE__);
return false;
}
file.Seek(0, CFile::orEnd);
long lRemoteFileSize = 0;
FileSize(strRemoteFile, lRemoteFileSize);
for( TObserverSet::const_iterator it=m_setObserver.begin(); it!=m_setObserver.end(); it++ )
(*it)->OnPreReceiveFile(strRemoteFile, strLocalFile, lRemoteFileSize);
const bool fRet=ExecuteDatachannelCommand(CDatachannelCmd::RETR(), strRemoteFile, repType, fPasv, file.Tell(), &file);
for( TObserverSet::const_iterator it2=m_setObserver.begin(); it2!=m_setObserver.end(); it2++ )
(*it2)->OnPostReceiveFile(strRemoteFile, strLocalFile, lRemoteFileSize);
return fRet;
}
/// Puts a file on the ftp-server.
/// Uses C functions for file access (very fast).
/// @param[in] strLocalFile Filename of the the local sourcefile which to put on the ftp-server.
/// @param[in] strRemoteFile Filename of the targetfile on the ftp-server.
/// @param[in] fStoreUnique if true, the ftp command STOU is used for saving
/// else the ftp command STOR is used.
/// @param[in] repType Representation Type (see documentation of CRepresentation)
/// @param[in] fPasv see documentation of CFTPClient::Passive
bool CFTPClient::UploadFile(const tstring& strLocalFile, const tstring& strRemoteFile, bool fStoreUnique, const CRepresentation& repType, bool fPasv) const
{
CFile file;
if( !file.Open(strLocalFile, L"rb") )
{
ReportError(CError::GetErrorDescription(), CCnv::ConvertToTString(__FILE__), __LINE__);
return false;
}
long lRemoteFileSize = 0;
if( m_fResumeIfPossible )
FileSize(strRemoteFile, lRemoteFileSize);
CDatachannelCmd cmd(CDatachannelCmd::STOR());
if( lRemoteFileSize > 0 )
cmd = CDatachannelCmd::APPE();
else if( fStoreUnique )
cmd = CDatachannelCmd::STOU();
file.Seek(0, CFile::orEnd);
long lLocalFileSize = file.Tell();
file.Seek(lRemoteFileSize, CFile::orBegin);
TObserverSet::const_iterator it;
for( it=m_setObserver.begin(); it!=m_setObserver.end(); it++ )
(*it)->OnPreSendFile(strLocalFile, strRemoteFile, lLocalFileSize);
const bool fRet=ExecuteDatachannelCommand(cmd, strRemoteFile, repType, fPasv, 0, &file);
//const bool fRet=ExecuteDatachannelCommand(cmd, strRemoteFile, repType, true, 0, &file);
for( it=m_setObserver.begin(); it!=m_setObserver.end(); it++ )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -