#ifndef __CeFtp_h__
#define __CeFtp_h__
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#include <winsock.h> // Winsock (RAW)
#include "CeSocket.h" // Socket classes
#include "CeThread.h" // Thread and Control classes
#include "CeArray.h"
#include "CeString.h"
#ifndef MTU_SIZE
#define MTU_SIZE 1460
#endif
#define RESP_BUFSIZ 2048
typedef WIN32_FIND_DATA FileData;
typedef CeArray<FileData> CeFileAttrArray;
typedef CeArray<CeString> CeStringArray;
typedef CeArray<BYTE> CeByteArray;
#define WM_FTP_CALLBACK (WM_USER + 200)
class CeFtpClient
{
public:
enum FtpClientOptions
{
ftpOpt_ConnectTimeout, // DWORD, milliseconds, default INFINITE
ftpOpt_ConnectRetries, // SHORT, default 1
ftpOpt_CommandSendTimeout, // DWORD, milliseconds, default INFINITE
ftpOpt_CommandRecvTimeout, // DWORD, milliseconds, default INFINITE
ftpOpt_DataSendTimeout, // DWORD, milliseconds, default INFINITE
ftpOpt_DataRecvTimeout, // DWORD, milliseconds, default INFINITE
// Not implemented
//ftpOpt_CALLBACK, // BOOL, default FALSE
};
enum FtpTransferType
{
ftpTtype_ASCII,
ftpTtype_BINARY,
ftpTtype_EBCDIC, // not supported yet
ftpTtype_TENEX, // not supported yet
};
enum FtpReplyCodes
{
ftpRcNoError = 0,
// reply codes as defined in RFC 959
ftpRc_RESTART_MARKER_REPLY = 110,
ftpRc_SRV_START_PENDING = 120,
ftpRc_DATA_OPEN = 125,
ftpRc_FILE_OK_START_DATA = 150,
ftpRc_CMD_OK = 200,
ftpRc_CMD_NOT_REQUIRED = 202,
ftpRc_SYSTEM_HELP_REPLY = 211,
ftpRc_DIRECTORY_STATUS = 212,
ftpRc_FILE_STAT = 213,
ftpRc_HELP_REPLY = 214,
ftpRc_SYSTEM_TYPE = 215,
ftpRc_READY_FOR_USER = 220,
ftpRc_CLOSING_CNTL_CONN = 221,
ftpRc_DATA_OPEN_NO_TRANS = 225,
ftpRc_CLOSING_DATA = 226,
ftpRc_PASS_MODE = 227,
ftpRc_USER_LOGGED_IN = 230,
ftpRc_FILE_REQ_OK = 250,
ftpRc_DIR_REQ_OK = 257,
ftpRc_USER_OK_SEND_PASS = 331,
ftpRc_ACCT_REQUIRED = 332,
ftpRc_FILE_REQ_OK_PENDING = 350,
ftpRc_SERVICE_UNAVAILABLE = 421,
ftpRc_CANNOT_OPEN_DATA_CONNECT = 425,
ftpRc_CONNECT_CLOSED = 426,
ftpRc_FILE_UNAVAILABLE = 450,
ftpRc_SERVER_ERROR = 451,
ftpRc_NO_SPACE = 452,
ftpRc_SYNTAX_ERROR_CMD = 500,
ftpRc_SYNTAX_ERROR_ARG = 501,
ftpRc_COMMAND_NOT_IMPL = 502,
ftpRc_BAD_CMD_SEQ = 503,
ftpRc_CMD_NOT_IMPL_ARG = 504,
ftpRc_NOT_LOGGED_IN = 530,
ftpRc_ACCT_REQUIRED_FOR_FILE_STORAGE = 532,
ftpRc_FILE_REQUEST_DENIED = 550,
ftpRc_PAGE_TYPE_UNKNOWN = 551,
ftpRc_EXCEEDED_MAX = 552,
ftpRc_NOT_ALLOWED = 553,
// implied errors, for example, connection reset by server
// when an error occurred mid connection
// these codes are beyond those used in normal reply codes
ftpErrorConnectionReset = 1000,
ftpErrorBadServerResponse = 1001,
ftpErrorSocket = 1002,
ftpErrorInvalidArg = 1003,
ftpErrorClientFile = 1004,
ftpErrorNotConnected = 1005,
ftpErrorThreadCreate = 1006,
ftpErrorTimeout = 1007,
};
private:
// CeSockAddr m_saCtrlClient; // used to create the ClientData socket address
CeSockAddr m_saClientData; // for PORT command
CeSockAddr m_saServerCtrl; // remote control socket
CeSockAddr m_saServerData; // used for accept validation
CeSocket m_sockCtrl; // control/command socket
CeSocket m_sockListen; // listening/accept socket
CeSocket m_sockData; // data transfer socket
DWORD m_dwTimeoutConnect; // various timeouts
DWORD m_dwTimeoutCmdSend;
DWORD m_dwTimeoutCmdRecv;
DWORD m_dwTimeoutDataSend;
DWORD m_dwTimeoutDataRecv;
short m_sRetries;
BOOL m_bPassive;
BOOL m_bStaticPort;
int m_nFtpDataPort; // server ftp data port
int m_nFtpCtrlPort; // server ftp port
CeString m_strSystem; // system type connected to, as reported by SYST
int m_nBufInUse;
CeByteArray m_arCtrlRecv; // control socket receive buffer
CeByteArray m_arDataRecv; // data socket receive buffer
DWORD m_dwByteCount; // bytes in the data buffer
BOOL m_bConnected; // TRUE when connected
BOOL m_bDebug; // TRUE when in debug mode
FtpTransferType m_eTransferType; // BINARY or ASCII transfer mode
CeManualEvent m_eventAccept; // event for syncronizing data socket listen/accept
CeString m_strDir; // the current directory
CeString m_strRoot;
BOOL m_chSep;
// error/message reporting
void ClearFtpError();
void SetFtpError(int nFtpError, LPCTSTR lpszErr);
void SetSocketError(int nError);
int m_nLastFtpReply; // Last error code from FTP
TCHAR m_szLastFtpReply[RESP_BUFSIZ];
HWND m_hwnd;
// implementation methods
BOOL SetTransferType(FtpTransferType eTransferType);
BOOL SimpleCmd(int nFtpCmd, LPCTSTR szArg);
void ResetConnection();
BOOL InitDataConn();
BOOL StartDataConn();
BOOL AcceptDataConn();
static DWORD WINAPI StartAccept(LPVOID pVoid);
int SendFtpCmd(int nFtpCmd);
int SendFtpCmd(int nFtpCmd, LPCTSTR szArg);
int GetFtpReply();
DWORD RecvBuffer(BOOL bTerminate=FALSE, DWORD dwSize=0);
DWORD RecvFile(HANDLE hFile, DWORD dwSize);
DWORD RecvFileList(CeFileAttrArray& arFiles);
DWORD SendBuffer(BYTE* pBuf, DWORD dwLen);
DWORD SendFile(HANDLE hFile, DWORD dwSize);
int CleanupSocket();
int ColumnStrings(const CeString& strRow, CeStringArray& arCol, int nMaxCol);
static void SplitBuffer(LPCSTR szBuf, DWORD dwByteCount, CeStringArray& ar);
public:
// construction
CeFtpClient();
virtual ~CeFtpClient();
void SetPortUse(BOOL bStatic)
{ m_bStaticPort = bStatic; }
void SetPassive(BOOL bPassive)
{ m_bPassive = bPassive; }
BOOL GetPassive() const
{ return m_bPassive; }
// connect and operation settings commands
void SetOption(DWORD dwOption, DWORD dwValue);
DWORD GetOption(DWORD dwOption) const;
// connection
BOOL Connect(LPCTSTR szAddr, LPCTSTR pstrUserName = NULL, LPCTSTR pstrPassword = NULL);
BOOL Connect(const ULONG ulAddr, LPCTSTR pstrUserName = NULL, LPCTSTR pstrPassword = NULL);
BOOL Disconnect();
// status commands
BOOL IsConnected()
{ return m_bConnected; }
CeString& GetSystemType() const;
// file/buffer transfer commands
BOOL PutFile(LPCTSTR szFileName, LPCTSTR szRemoteName, DWORD dwSize = 0, FtpTransferType eTransType=ftpTtype_BINARY);
BOOL AppendFile(LPCTSTR szFileName, LPCTSTR szRemoteName, DWORD dwSize = 0, FtpTransferType eTransType=ftpTtype_BINARY);
BOOL GetFile(LPCTSTR szRemoteName, LPCTSTR szFileName, DWORD dwSize = 0, BOOL bFailIfExists = TRUE, DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL, FtpTransferType eTransType=ftpTtype_BINARY);
BOOL RenameFile(LPCTSTR szRemoteName, LPCTSTR szNewRemoteName);
BOOL DeleteFile(LPCTSTR szRemoteName);
BOOL GetFileAsBuffer(LPCTSTR szRemoteName, CeByteArray& arBuf, DWORD dwSize = 0, FtpTransferType eTransType=ftpTtype_BINARY);
BOOL PutBufferAsFile(LPCTSTR szRemoteName, BYTE* pBuf, DWORD dwSize = 0, FtpTransferType eTransType=ftpTtype_BINARY);
void CancelTransfer();
// directory commands
LPCTSTR GetRoot() const
{ return m_strRoot; }
CeString GetCurDir();
BOOL SetCurDir(LPCTSTR szPath);
BOOL DeleteDir(LPCTSTR szPath);
BOOL CreateDir(LPCTSTR szPath);
// directory listing
BOOL GetFileList(CeStringArray& strFiles);
BOOL GetFileList(CeFileAttrArray& arFiles, LPCTSTR lpszFileSpec=NULL);
// file info
BOOL GetFileInfo(LPCTSTR lpszFileName, WIN32_FIND_DATA& finddata);
// NOOP command for maintaining connection without sending commands
BOOL SendNoOp();
// Error and message handling
CeString GetFtpErrorReplyString() const
{ return CeString(m_szLastFtpReply); }
int GetLastFtpError() const
{ return m_nLastFtpReply; }
// user command support, returns the reply code if one was required
// the reply string can get retreived from get GetReplyString()
int SendUserCommand(LPCTSTR szUserCmd);
// Overrideables
virtual void OnStatusCallback();
virtual void OnTransferCallback(DWORD dwSent, DWORD dwTotal, LPCTSTR szFile);
virtual BOOL OnParseListFile(LPSTR szFile, PWIN32_FIND_DATA pFindData);
virtual void OnFtpMessage(int nResp, LPCSTR szMsg);
HWND SetCallbackHandle(HWND hWnd)
{ HWND hWndSave = hWnd; m_hwnd = hWnd; return hWndSave; }
};
#endif // __CeFtp_h__