481 lines
16 KiB
C++
481 lines
16 KiB
C++
#include <ftp/ftp.hpp>
|
|
#include <common/stdio.hpp>
|
|
#include <socket/hostent.hpp>
|
|
#include <socket/servent.hpp>
|
|
#include <socket/socket.hpp>
|
|
|
|
FTPClient::FTPClient(void)
|
|
: mIsLoggedIn(FALSE), mCurrentType('A')
|
|
{
|
|
createCommands();
|
|
buildResponseStrings();
|
|
}
|
|
|
|
FTPClient::~FTPClient()
|
|
{
|
|
}
|
|
|
|
WORD FTPClient::open(String hostName)
|
|
{
|
|
HostEnt hostEntry;
|
|
ServEnt serverEntry;
|
|
|
|
message(String("trying ")+hostName+String("..."));
|
|
if(!mWSASystem.isInitialized()){message("WINSOCK initialization failure.");return FALSE;}
|
|
InternetAddress internetAddress(hostName);
|
|
if(!internetAddress.isZero()){if(!hostEntry.hostByAddress(internetAddress)){message(String("no DNS entry for ")+hostName);return FALSE;}}
|
|
else if(!hostEntry.hostByName(hostName)){message(String("no DNS entry for ")+hostName);return FALSE;}
|
|
message(String("connect...")+String("'")+hostEntry.hostName()+String("' (")+(String)(hostEntry.addresses())[0]+String(")"));
|
|
INETSocketAddress::internetAddress((hostEntry.addresses())[0]);
|
|
if(!serverEntry.serviceByName("ftp","tcp")){message("cannot determine port number for ftp daemon.");return FALSE;}
|
|
if(!mFTPControl.create()){message("unable to create socket.");return FALSE;}
|
|
INETSocketAddress::family(PF_INET);
|
|
INETSocketAddress::port(serverEntry.port());
|
|
if(!mFTPControl.connect((INETSocketAddress&)*this)){message("unable to connect to ftp daemon");return FALSE;}
|
|
if(!receive(mAckConnectionResponseStrings))return FALSE;
|
|
mFTPControl.getSocketName((INETSocketAddress&)*this);
|
|
return mFTPControl.isConnected();
|
|
}
|
|
|
|
WORD FTPClient::login(String userName,String password)
|
|
{
|
|
String blank(" ");
|
|
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(isLoggedIn())logout();
|
|
putControlData(mFTPCommands[User]+blank+userName,FALSE);
|
|
if(!receive(mAckLoginResponseStrings))return FALSE;
|
|
putControlData(mFTPCommands[Password]+blank+password,FALSE);
|
|
if(!receive(mAckLoginResponseStrings))return FALSE;
|
|
isLoggedIn(TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::logout(void)
|
|
{
|
|
isLoggedIn(FALSE);
|
|
if(!mFTPControl.isConnected()){message("Not connected.");return FALSE;}
|
|
if(!putControlData(mFTPCommands[Logout],FALSE))return FALSE;
|
|
if(!receive(mAckLogoutResponseStrings))return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::port(FTPData &ftpData)
|
|
{
|
|
InternetAddress inetAddr;
|
|
String portString;
|
|
String workString;
|
|
WORD dataPort;
|
|
|
|
inetAddr=((INETSocketAddress&)*this).internetAddress();
|
|
portString=(String)inetAddr;
|
|
portString.replaceToken('.',',');
|
|
dataPort=ntohs(((INETSocketAddress&)ftpData).port());
|
|
::sprintf(workString,",%d,%d",(short)HIBYTE(dataPort),(short)LOBYTE(dataPort));
|
|
putControlData(mFTPCommands[DataPort]+String(" ")+portString+workString,FALSE);
|
|
if(!receive(mAckPortResponseStrings))return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::changeWorkingDirectory(String workingDirectory)
|
|
{
|
|
Block<String> responseLines;
|
|
|
|
if(!mFTPControl.isConnected()||workingDirectory.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[ChangeWorkingDirectory]+String(" ")+workingDirectory,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseLines))return FALSE;
|
|
message(responseLines);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::printWorkingDirectory(void)
|
|
{
|
|
String workingDirectory;
|
|
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(!putControlData(mFTPCommands[PrintWorkingDirectory],FALSE))return FALSE;
|
|
if(!mFTPControl.receive(workingDirectory))return FALSE;
|
|
message(workingDirectory);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::list(String pathName)
|
|
{
|
|
String controlData;
|
|
String responseLine;
|
|
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(pathName.isNull())controlData=mFTPCommands[List];
|
|
else controlData=mFTPCommands[List]+String(" ")+pathName;
|
|
if(!putControlData(controlData,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseLine))return FALSE;
|
|
if(!(responseLine.betweenString(0,' ')==String("150")))return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::nameList(String pathName,WORD showResponse)
|
|
{
|
|
String controlData;
|
|
String responseLine;
|
|
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(pathName.isNull())controlData=mFTPCommands[NameList];
|
|
else controlData=mFTPCommands[NameList]+String(" ")+pathName;
|
|
if(!putControlData(controlData,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseLine))return FALSE;
|
|
if(showResponse)message(responseLine);
|
|
if(!(responseLine.betweenString(0,' ')==String("150")))return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::type(BYTE type,BYTE storage)
|
|
{
|
|
String representationType;
|
|
String responseLine;
|
|
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if('A'==type||'E'==type)
|
|
{
|
|
if(storage)::sprintf(representationType,"%c %c",type,storage);
|
|
else ::sprintf(representationType,"%c",type);
|
|
}
|
|
else if('I'==type)::sprintf(representationType,"%c",type);
|
|
else if('L'==type)::sprintf(representationType,"%c %d",type,(int)storage);
|
|
else return FALSE;
|
|
if(!putControlData(mFTPCommands[RepresentationType]+String(" ")+representationType,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseLine))return FALSE;
|
|
message(responseLine);
|
|
mCurrentType=type;
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::retrieve(String pathFileName,DWORD &sizeData)
|
|
{
|
|
String responseString;
|
|
char *lpChar;
|
|
|
|
sizeData=0;
|
|
if(!mFTPControl.isConnected()||pathFileName.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[Retrieve]+String(" ")+pathFileName,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
message(responseString);
|
|
if(!(responseString.betweenString(0,' ')==String("150")))return FALSE;
|
|
lpChar=(char*)responseString.strstr("bytes");
|
|
if(!lpChar)return TRUE;
|
|
while(*lpChar!='(')lpChar--;
|
|
String sizeString(++lpChar);
|
|
sizeString=sizeString.betweenString(0,' ');
|
|
if(sizeString.isNull())return FALSE;
|
|
sizeData=(DWORD)(sizeString.toInt());
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::store(String pathFileName)
|
|
{
|
|
String responseString;
|
|
if(!mFTPControl.isConnected()||pathFileName.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[Store]+String(" ")+pathFileName,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
message(responseString);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::mode(BYTE transferMode)
|
|
{
|
|
String modeString;
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if('S'!=transferMode&&'B'!=transferMode&&'C'!=transferMode)return FALSE;
|
|
::sprintf(modeString,"%c",transferMode);
|
|
return putControlData(mFTPCommands[TransferMode]+String(" ")+modeString);
|
|
}
|
|
|
|
WORD FTPClient::renameFrom(String oldPathFileName)
|
|
{
|
|
String responseString;
|
|
if(!mFTPControl.isConnected()||oldPathFileName.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[RenameFrom]+String(" ")+oldPathFileName,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
if(!(responseString.betweenString(0,' ')==String("350"))){message(responseString);return FALSE;}
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::renameTo(String newPathFileName)
|
|
{
|
|
String responseString;
|
|
if(!mFTPControl.isConnected()||newPathFileName.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[RenameTo]+String(" ")+newPathFileName,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
message(responseString);
|
|
if(!(responseString.betweenString(0,' ')==String("250")))return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::account(String accountInfo)
|
|
{
|
|
if(!mFTPControl.isConnected()||accountInfo.isNull())return FALSE;
|
|
return putControlData(mFTPCommands[Account]+String(" ")+accountInfo);
|
|
}
|
|
|
|
WORD FTPClient::changeToParentDirectory(void)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
return putControlData(mFTPCommands[ChangeToParentDirectory]);
|
|
}
|
|
|
|
WORD FTPClient::structureMount(String systemFileGroupDesignator)
|
|
{
|
|
if(!mFTPControl.isConnected()||systemFileGroupDesignator.isNull())return FALSE;
|
|
return putControlData(mFTPCommands[StructureMount]+String(" ")+systemFileGroupDesignator);
|
|
}
|
|
|
|
WORD FTPClient::reinitialize(void)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
return putControlData(mFTPCommands[Reinitialize]);
|
|
}
|
|
|
|
WORD FTPClient::passive(void)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
return putControlData(mFTPCommands[Passive]);
|
|
}
|
|
|
|
WORD FTPClient::fileStructure(BYTE structure)
|
|
{
|
|
String structureString;
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if('F'!=structure&&'R'!=structure&&'P'!=structure)return FALSE;
|
|
::sprintf(structureString,"%c",structure);
|
|
return putControlData(mFTPCommands[FileStructure]+String(" ")+structureString);
|
|
}
|
|
|
|
WORD FTPClient::storeUnique(String pathFileName)
|
|
{
|
|
if(!mFTPControl.isConnected()||pathFileName.isNull())return FALSE;
|
|
return putControlData(mFTPCommands[StoreUnique]+String(" ")+pathFileName);
|
|
}
|
|
|
|
WORD FTPClient::append(String pathFileName)
|
|
{
|
|
if(!mFTPControl.isConnected()||pathFileName.isNull())return FALSE;
|
|
return putControlData(mFTPCommands[Append]+String(" ")+pathFileName);
|
|
}
|
|
|
|
WORD FTPClient::allocate(DWORD numBytes,DWORD maxRecord)
|
|
{
|
|
String allocationString;
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(maxRecord)::sprintf(allocationString,"%ld R %ld",numBytes,maxRecord);
|
|
else ::sprintf(allocationString,"%ld",numBytes);
|
|
return putControlData(mFTPCommands[Allocate]+String(" ")+allocationString);
|
|
}
|
|
|
|
WORD FTPClient::restart(String serverMarker)
|
|
{
|
|
if(!mFTPControl.isConnected()||serverMarker.isNull())return FALSE;
|
|
return putControlData(mFTPCommands[Restart]+String(" ")+serverMarker);
|
|
}
|
|
|
|
WORD FTPClient::abort(void)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
return putControlData(mFTPCommands[Abort]);
|
|
}
|
|
|
|
WORD FTPClient::remove(String pathFileName)
|
|
{
|
|
String responseString;
|
|
if(!mFTPControl.isConnected()||pathFileName.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[Delete]+String(" ")+pathFileName,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
message(responseString);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::removeDirectory(String pathDirectoryName)
|
|
{
|
|
String responseString;
|
|
if(!mFTPControl.isConnected()||pathDirectoryName.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[RemoveDirectory]+String(" ")+pathDirectoryName,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
message(responseString);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::makeDirectory(String pathDirectoryName)
|
|
{
|
|
String responseString;
|
|
if(!mFTPControl.isConnected()||pathDirectoryName.isNull())return FALSE;
|
|
if(!putControlData(mFTPCommands[MakeDirectory]+String(" ")+pathDirectoryName,FALSE))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
message(responseString);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::siteParameters(void)
|
|
{
|
|
String responseString;
|
|
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(!putControlData(mFTPCommands[SiteParameters]))return FALSE;
|
|
if(!mFTPControl.receive(responseString))return FALSE;
|
|
message(responseString);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::system(void)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
return putControlData(mFTPCommands[System]);
|
|
}
|
|
|
|
WORD FTPClient::status(String pathName)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(!pathName.isNull())return putControlData(mFTPCommands[Status]+String(" ")+pathName);
|
|
return putControlData(mFTPCommands[Status]);
|
|
}
|
|
|
|
WORD FTPClient::help(String commandName)
|
|
{
|
|
Block<String> receiveStrings;
|
|
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(!commandName.isNull()){if(!putControlData(mFTPCommands[Help]+String(" ")+commandName,FALSE))return FALSE;}
|
|
else if(!putControlData(mFTPCommands[Help],FALSE))return FALSE;
|
|
mFTPControl.receive(receiveStrings);
|
|
for(short itemIndex=0;itemIndex<receiveStrings.size();itemIndex++)message(receiveStrings[itemIndex]);
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::noop(void)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
return putControlData(mFTPCommands[Noop]);
|
|
}
|
|
|
|
WORD FTPClient::putControlData(String stringData,WORD waitForResponse)
|
|
{
|
|
if(!mFTPControl.isConnected())return FALSE;
|
|
if(!mFTPControl.send(stringData)){message("error sending data to ftp daemon");return FALSE;}
|
|
if(waitForResponse&&!getControlData()){message("error reading data from ftp daemon");return FALSE;}
|
|
return TRUE;
|
|
}
|
|
|
|
WORD FTPClient::getControlData(void)
|
|
{
|
|
mResponseStrings.remove();
|
|
mFTPControl.receive(mResponseStrings);
|
|
return mResponseStrings.size();
|
|
}
|
|
|
|
void FTPClient::receiveStrings(WORD displayStrings)
|
|
{
|
|
Block<String> receiveStrings;
|
|
|
|
if(!mFTPControl.isConnected())return;
|
|
if(!mFTPControl.receive(receiveStrings))return;
|
|
if(!displayStrings||!receiveStrings.size())return;
|
|
message(receiveStrings);
|
|
}
|
|
|
|
void FTPClient::createCommands(void)
|
|
{
|
|
mFTPCommands.insert(&String("USER")); // user name
|
|
mFTPCommands.insert(&String("PASS")); // password
|
|
mFTPCommands.insert(&String("ACCT")); // account
|
|
mFTPCommands.insert(&String("CWD")); // change working directory
|
|
mFTPCommands.insert(&String("CDUP")); // change to parent directory
|
|
mFTPCommands.insert(&String("SMNT")); // structure mount
|
|
mFTPCommands.insert(&String("REIN")); // reinitialize
|
|
mFTPCommands.insert(&String("QUIT")); // quit
|
|
mFTPCommands.insert(&String("PORT")); // data port
|
|
mFTPCommands.insert(&String("PASV")); // passive
|
|
mFTPCommands.insert(&String("TYPE")); // representation type
|
|
mFTPCommands.insert(&String("STRU")); // file structure
|
|
mFTPCommands.insert(&String("MODE")); // transfer mode
|
|
mFTPCommands.insert(&String("RETR")); // retrieve
|
|
mFTPCommands.insert(&String("STOR")); // store
|
|
mFTPCommands.insert(&String("STOU")); // store unique
|
|
mFTPCommands.insert(&String("APPE")); // append (with create)
|
|
mFTPCommands.insert(&String("ALLO")); // allocate
|
|
mFTPCommands.insert(&String("REST")); // restart
|
|
mFTPCommands.insert(&String("RNFR")); // rename from
|
|
mFTPCommands.insert(&String("RNTO")); // rename to
|
|
mFTPCommands.insert(&String("ABOR")); // abort
|
|
mFTPCommands.insert(&String("DELE")); // delete
|
|
mFTPCommands.insert(&String("RMD")); // remove directory
|
|
mFTPCommands.insert(&String("MKD")); // make directory
|
|
mFTPCommands.insert(&String("PWD")); // print working directory
|
|
mFTPCommands.insert(&String("LIST")); // list
|
|
mFTPCommands.insert(&String("NLST")); // name list
|
|
mFTPCommands.insert(&String("SITE")); // site parameters
|
|
mFTPCommands.insert(&String("SYST")); // system
|
|
mFTPCommands.insert(&String("STAT")); // status
|
|
mFTPCommands.insert(&String("HELP")); // help
|
|
mFTPCommands.insert(&String("NOOP")); // noop
|
|
}
|
|
|
|
void FTPClient::buildResponseStrings(void)
|
|
{
|
|
mAckConnectionResponseStrings.insert(&String("220"));
|
|
mAckLoginResponseStrings.insert(&String("230"));
|
|
mAckLoginResponseStrings.insert(&String("331"));
|
|
mAckLogoutResponseStrings.insert(&String("221"));
|
|
mAckPortResponseStrings.insert(&String("200"));
|
|
}
|
|
|
|
WORD FTPClient::receive(Block<String> &responseStrings)
|
|
{
|
|
Block<String> responseLines;
|
|
return receive(responseLines,responseStrings);
|
|
}
|
|
|
|
WORD FTPClient::receive(Block<String> &receiveStrings,Block<String> &responseStrings)
|
|
{
|
|
WORD isInMultiLine(FALSE);
|
|
BOOL returnCode(TRUE);
|
|
String seriesItem;
|
|
String stringData;
|
|
|
|
receiveStrings.remove();
|
|
while(TRUE)
|
|
{
|
|
if(!mFTPControl.receive(stringData))break;
|
|
message(stringData);
|
|
if(!receiveStrings.size())
|
|
{
|
|
seriesItem=stringData.substr(0,2);
|
|
if(!isInResponse(seriesItem,responseStrings))
|
|
{
|
|
message(String(">>")+seriesItem+String(" is not in the valid response set."));
|
|
returnCode=FALSE;
|
|
}
|
|
isInMultiLine=stringData.operator[](3)=='-';
|
|
}
|
|
if(receiveStrings.size()&&isInMultiLine&&stringData.operator[](3)!='-'&&stringData.substr(0,2)==seriesItem)break;
|
|
receiveStrings.insert(&stringData);
|
|
if(!isInMultiLine)break;
|
|
}
|
|
return returnCode;
|
|
}
|
|
|
|
WORD FTPClient::isInResponse(const String &responseString,Block<String> &responseStrings)
|
|
{
|
|
if(responseString.isNull())return FALSE;
|
|
for(int itemIndex=0;itemIndex<responseStrings.size();itemIndex++)
|
|
if(responseString==responseStrings[itemIndex])return TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
// *** virtual overloads
|
|
|
|
void FTPClient::message(const String &/*messageString*/)
|
|
{
|
|
}
|
|
|
|
void FTPClient::message(Block<String> &/*messageStrings*/)
|
|
{
|
|
}
|
|
|