1. patch from Søren Erland Vestø implementing wxFTP::GetFileSize()

with my fixes to the patch
2. significantly updated/cleaned FTP tests in the sample
3. don't log FTP passwords in wxLogTrace




git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9159 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2001-01-24 16:37:04 +00:00
parent e7fa076d94
commit b92fd37cb0
4 changed files with 482 additions and 156 deletions

View File

@@ -11,6 +11,7 @@ wxBase:
- wxMimeTypesManager now can create file associations too - wxMimeTypesManager now can create file associations too
- wxCopyFile() respects the file permissions (Roland Scholz) - wxCopyFile() respects the file permissions (Roland Scholz)
- wxFTP::GetFileSize() added (S<>ren Erland Vest<73>)
wxMSW: wxMSW:

View File

@@ -14,7 +14,7 @@
#define __WX_FTP_H__ #define __WX_FTP_H__
#ifdef __GNUG__ #ifdef __GNUG__
#pragma interface #pragma interface "ftp.h"
#endif #endif
#include "wx/object.h" #include "wx/object.h"
@@ -27,6 +27,7 @@ class WXDLLEXPORT wxFTP : public wxProtocol
public: public:
enum TransferMode enum TransferMode
{ {
NONE, // not set by user explicitly
ASCII, ASCII,
BINARY BINARY
}; };
@@ -77,6 +78,16 @@ public:
bool Rename(const wxString& src, const wxString& dst); bool Rename(const wxString& src, const wxString& dst);
bool RmFile(const wxString& path); bool RmFile(const wxString& path);
// Get the size of a file in the current dir.
// this function tries its best to deliver the size in bytes using BINARY
// (the SIZE command reports different sizes depending on whether
// type is set to ASCII or BINARY)
// returns -1 if file is non-existant or size could not be found
int GetFileSize(const wxString& fileName);
// Check to see if a file exists in the current dir
bool FileExists(const wxString& fileName);
// Download methods // Download methods
bool Abort(); bool Abort();
@@ -135,8 +146,9 @@ protected:
// true if there is an FTP transfer going on // true if there is an FTP transfer going on
bool m_streaming; bool m_streaming;
// true if the user had set the transfer mode // although this should be set to ASCII by default according to STD9,
bool m_modeSet; // we will use BINARY transfer mode by default for backwards compatibility
TransferMode m_currentTransfermode;
friend class wxInputFTPStream; friend class wxInputFTPStream;
friend class wxOutputFTPStream; friend class wxOutputFTPStream;
@@ -145,4 +157,8 @@ protected:
DECLARE_PROTOCOL(wxFTP) DECLARE_PROTOCOL(wxFTP)
}; };
// the trace mask used by assorted wxLogTrace() in ftp code, do
// wxLog::AddTraceMask(FTP_TRACE_MASK) to see them in output
#define FTP_TRACE_MASK _T("ftp")
#endif // __WX_FTP_H__ #endif // __WX_FTP_H__

View File

@@ -45,12 +45,12 @@
//#define TEST_FILE //#define TEST_FILE
//#define TEST_FILECONF //#define TEST_FILECONF
//#define TEST_FILENAME //#define TEST_FILENAME
//#define TEST_FTP #define TEST_FTP
//#define TEST_HASH //#define TEST_HASH
//#define TEST_LIST //#define TEST_LIST
//#define TEST_LOG //#define TEST_LOG
//#define TEST_LONGLONG //#define TEST_LONGLONG
#define TEST_MIME //#define TEST_MIME
//#define TEST_INFO_FUNCTIONS //#define TEST_INFO_FUNCTIONS
//#define TEST_REGISTRY //#define TEST_REGISTRY
//#define TEST_SOCKETS //#define TEST_SOCKETS
@@ -1508,17 +1508,70 @@ static void TestSocketClient()
#endif // TEST_SOCKETS #endif // TEST_SOCKETS
// ----------------------------------------------------------------------------
// FTP
// ----------------------------------------------------------------------------
#ifdef TEST_FTP #ifdef TEST_FTP
#include <wx/protocol/ftp.h> #include <wx/protocol/ftp.h>
static void TestProtocolFtp() static wxFTP ftp;
#define FTP_ANONYMOUS
#ifdef FTP_ANONYMOUS
static const char *directory = "/pub";
static const char *filename = "welcome.msg";
#else
static const char *directory = "/etc";
static const char *filename = "issue";
#endif
static bool TestFtpConnect()
{ {
puts("*** Testing wxFTP download ***\n"); puts("*** Testing FTP connect ***");
#ifdef FTP_ANONYMOUS
static const char *hostname = "ftp.wxwindows.org";
printf("--- Attempting to connect to %s:21 anonymously...\n", hostname);
#else // !FTP_ANONYMOUS
static const char *hostname = "localhost";
char user[256];
fgets(user, WXSIZEOF(user), stdin);
user[strlen(user) - 1] = '\0'; // chop off '\n'
ftp.SetUser(user);
char password[256];
printf("Password for %s: ", password);
fgets(password, WXSIZEOF(password), stdin);
password[strlen(password) - 1] = '\0'; // chop off '\n'
ftp.SetPassword(password);
printf("--- Attempting to connect to %s:21 as %s...\n", hostname, user);
#endif // FTP_ANONYMOUS/!FTP_ANONYMOUS
if ( !ftp.Connect(hostname) )
{
printf("ERROR: failed to connect to %s\n", hostname);
return FALSE;
}
else
{
printf("--- Connected to %s, current directory is '%s'\n",
hostname, ftp.Pwd().c_str());
}
return TRUE;
}
// test (fixed?) wxFTP bug with wu-ftpd >= 2.6.0?
static void TestFtpWuFtpd()
{
wxFTP ftp; wxFTP ftp;
#ifdef TEST_WUFTPD // test (fixed?) wxFTP bug with wu-ftpd >= 2.6.0?
static const char *hostname = "ftp.eudora.com"; static const char *hostname = "ftp.eudora.com";
if ( !ftp.Connect(hostname) ) if ( !ftp.Connect(hostname) )
{ {
@@ -1551,33 +1604,11 @@ static void TestProtocolFtp()
delete in; delete in;
} }
} }
#else // !TEST_WUFTPD }
#if 1 static void TestFtpList()
static const char *hostname = "ftp.wxwindows.org"; {
static const char *directory = "pub"; puts("*** Testing wxFTP file listing ***\n");
static const char *filename = "welcome.msg";
printf("--- Attempting to connect to %s:21 anonymously...\n", hostname);
#else
static const char *hostname = "localhost";
static const char *user = "zeitlin";
static const char *directory = "/tmp";
ftp.SetUser(user);
ftp.SetPassword("password");
printf("--- Attempting to connect to %s:21 as %s...\n", hostname, user);
#endif
if ( !ftp.Connect(hostname) )
{
printf("ERROR: failed to connect to %s\n", hostname);
}
else
{
printf("--- Connected to %s, current directory is '%s'\n",
hostname, ftp.Pwd().c_str());
// test CWD // test CWD
if ( !ftp.ChDir(directory) ) if ( !ftp.ChDir(directory) )
@@ -1585,6 +1616,8 @@ static void TestProtocolFtp()
printf("ERROR: failed to cd to %s\n", directory); printf("ERROR: failed to cd to %s\n", directory);
} }
printf("Current directory is '%s'\n", ftp.Pwd().c_str());
// test NLIST and LIST // test NLIST and LIST
wxArrayString files; wxArrayString files;
if ( !ftp.GetFilesList(files) ) if ( !ftp.GetFilesList(files) )
@@ -1622,6 +1655,13 @@ static void TestProtocolFtp()
puts("ERROR: failed to cd to .."); puts("ERROR: failed to cd to ..");
} }
printf("Current directory is '%s'\n", ftp.Pwd().c_str());
}
static void TestFtpDownload()
{
puts("*** Testing wxFTP download ***\n");
// test RETR // test RETR
wxInputStream *in = ftp.GetInputStream(filename); wxInputStream *in = ftp.GetInputStream(filename);
if ( !in ) if ( !in )
@@ -1632,6 +1672,7 @@ static void TestProtocolFtp()
{ {
size_t size = in->StreamSize(); size_t size = in->StreamSize();
printf("Reading file %s (%u bytes)...", filename, size); printf("Reading file %s (%u bytes)...", filename, size);
fflush(stdout);
char *data = new char[size]; char *data = new char[size];
if ( !in->Read(data, size) ) if ( !in->Read(data, size) )
@@ -1646,8 +1687,37 @@ static void TestProtocolFtp()
delete [] data; delete [] data;
delete in; delete in;
} }
}
static void TestFtpFileSize()
{
puts("*** Testing FTP SIZE command ***");
if ( !ftp.ChDir(directory) )
{
printf("ERROR: failed to cd to %s\n", directory);
}
printf("Current directory is '%s'\n", ftp.Pwd().c_str());
if ( ftp.FileExists(filename) )
{
int size = ftp.GetFileSize(filename);
if ( size == -1 )
printf("ERROR: couldn't get size of '%s'\n", filename);
else
printf("Size of '%s' is %d bytes.\n", filename, size);
}
else
{
printf("ERROR: '%s' doesn't exist\n", filename);
}
}
static void TestFtpMisc()
{
puts("*** Testing miscellaneous wxFTP functions ***");
// test some other FTP commands
if ( ftp.SendCommand("STAT") != '2' ) if ( ftp.SendCommand("STAT") != '2' )
{ {
puts("ERROR: STAT failed"); puts("ERROR: STAT failed");
@@ -1666,29 +1736,68 @@ static void TestProtocolFtp()
printf("The list of site-specific commands:\n\n%s\n", printf("The list of site-specific commands:\n\n%s\n",
ftp.GetLastResult().c_str()); ftp.GetLastResult().c_str());
} }
}
#endif // TEST_WUFTPD/!TEST_WUFTPD
} }
static void TestProtocolFtpUpload() static void TestFtpInteractive()
{ {
puts("*** Testing wxFTP uploading ***\n"); puts("\n*** Interactive wxFTP test ***");
static const char *hostname = "localhost"; char buf[128];
printf("--- Attempting to connect to %s:21...\n", hostname); for ( ;; )
wxFTP ftp;
ftp.SetUser("zeitlin");
ftp.SetPassword("password");
if ( !ftp.Connect(hostname) )
{ {
printf("ERROR: failed to connect to %s\n", hostname); printf("Enter FTP command: ");
if ( !fgets(buf, WXSIZEOF(buf), stdin) )
break;
// kill the last '\n'
buf[strlen(buf) - 1] = 0;
// special handling of LIST and NLST as they require data connection
wxString start(buf, 4);
start.MakeUpper();
if ( start == "LIST" || start == "NLST" )
{
wxString wildcard;
if ( strlen(buf) > 4 )
wildcard = buf + 5;
wxArrayString files;
if ( !ftp.GetList(files, wildcard, start == "LIST") )
{
printf("ERROR: failed to get %s of files\n", start.c_str());
} }
else else
{ {
printf("--- Connected to %s, current directory is '%s'\n", printf("--- %s of '%s' under '%s':\n",
hostname, ftp.Pwd().c_str()); start.c_str(), wildcard.c_str(), ftp.Pwd().c_str());
size_t count = files.GetCount();
for ( size_t n = 0; n < count; n++ )
{
printf("\t%s\n", files[n].c_str());
}
puts("--- End of the file list");
}
}
else // !list
{
char ch = ftp.SendCommand(buf);
printf("Command %s", ch ? "succeeded" : "failed");
if ( ch )
{
printf(" (return code %c)", ch);
}
printf(", server reply:\n%s\n\n", ftp.GetLastResult().c_str());
}
}
puts("\n*** done ***");
}
static void TestFtpUpload()
{
puts("*** Testing wxFTP uploading ***\n");
// upload a file // upload a file
static const char *file1 = "test1"; static const char *file1 = "test1";
@@ -1719,7 +1828,6 @@ static void TestProtocolFtpUpload()
out->Write("Second hello", 12); out->Write("Second hello", 12);
delete out; delete out;
} }
}
} }
#endif // TEST_FTP #endif // TEST_FTP
@@ -2957,7 +3065,7 @@ static void TestTimeParse()
} }
} }
static void TestInteractive() static void TestDateTimeInteractive()
{ {
puts("\n*** interactive wxDateTime tests ***"); puts("\n*** interactive wxDateTime tests ***");
@@ -4121,10 +4229,24 @@ int main(int argc, char **argv)
#endif // TEST_SOCKETS #endif // TEST_SOCKETS
#ifdef TEST_FTP #ifdef TEST_FTP
wxLog::AddTraceMask(_T("ftp")); wxLog::AddTraceMask(FTP_TRACE_MASK);
TestProtocolFtp(); if ( TestFtpConnect() )
{
TestFtpFileSize();
if ( 0 ) if ( 0 )
TestProtocolFtpUpload(); {
TestFtpList();
TestFtpDownload();
TestFtpMisc();
TestFtpUpload();
}
if ( 0 )
TestFtpInteractive();
}
//else: connecting to the FTP server failed
if ( 0 )
TestFtpWuFtpd();
#endif // TEST_FTP #endif // TEST_FTP
#ifdef TEST_STREAMS #ifdef TEST_STREAMS
@@ -4156,7 +4278,7 @@ int main(int argc, char **argv)
TestTimeZoneBug(); TestTimeZoneBug();
} }
if ( 0 ) if ( 0 )
TestInteractive(); TestDateTimeInteractive();
#endif // TEST_DATETIME #endif // TEST_DATETIME
#ifdef TEST_VCARD #ifdef TEST_VCARD

View File

@@ -83,7 +83,7 @@ wxFTP::wxFTP()
{ {
m_lastError = wxPROTO_NOERR; m_lastError = wxPROTO_NOERR;
m_streaming = FALSE; m_streaming = FALSE;
m_modeSet = FALSE; m_currentTransfermode = NONE;
m_user = wxT("anonymous"); m_user = wxT("anonymous");
m_passwd << wxGetUserId() << wxT('@') << wxGetFullHostName(); m_passwd << wxGetUserId() << wxT('@') << wxGetFullHostName();
@@ -204,7 +204,20 @@ char wxFTP::SendCommand(const wxString& command)
return 0; return 0;
} }
wxLogTrace(_T("ftp"), _T("==> %s"), command.c_str()); #ifdef __WXDEBUG__
// don't show the passwords in the logs (even in debug ones)
wxString cmd, password;
if ( command.Upper().StartsWith(_T("PASS "), &password) )
{
cmd << _T("PASS ") << wxString(_T('*'), password.length());
}
else
{
cmd = command;
}
wxLogTrace(FTP_TRACE_MASK, _T("==> %s"), cmd.c_str());
#endif // __WXDEBUG__
return GetResult(); return GetResult();
} }
@@ -256,7 +269,7 @@ char wxFTP::GetResult()
} }
else else
{ {
wxLogTrace(_T("ftp"), _T("<== %s %s"), wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
code.c_str(), line.c_str()); code.c_str(), line.c_str());
} }
} }
@@ -268,7 +281,7 @@ char wxFTP::GetResult()
if ( firstLine ) if ( firstLine )
{ {
code = wxString(line, LEN_CODE); code = wxString(line, LEN_CODE);
wxLogTrace(_T("ftp"), _T("<== %s %s"), wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
code.c_str(), line.c_str() + LEN_CODE + 1); code.c_str(), line.c_str() + LEN_CODE + 1);
switch ( chMarker ) switch ( chMarker )
@@ -295,13 +308,13 @@ char wxFTP::GetResult()
endOfReply = TRUE; endOfReply = TRUE;
} }
wxLogTrace(_T("ftp"), _T("<== %s %s"), wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
code.c_str(), line.c_str() + LEN_CODE + 1); code.c_str(), line.c_str() + LEN_CODE + 1);
} }
else else
{ {
// just part of reply // just part of reply
wxLogTrace(_T("ftp"), _T("<== %s %s"), wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
code.c_str(), line.c_str()); code.c_str(), line.c_str());
} }
} }
@@ -328,6 +341,12 @@ char wxFTP::GetResult()
bool wxFTP::SetTransferMode(TransferMode transferMode) bool wxFTP::SetTransferMode(TransferMode transferMode)
{ {
if ( transferMode == m_currentTransfermode )
{
// nothing to do
return TRUE;
}
wxString mode; wxString mode;
switch ( transferMode ) switch ( transferMode )
{ {
@@ -352,7 +371,9 @@ bool wxFTP::SetTransferMode(TransferMode transferMode)
return FALSE; return FALSE;
} }
m_modeSet = TRUE; // If we get here the operation has been succesfully completed
// Set the status-member
m_currentTransfermode = transferMode;
return TRUE; return TRUE;
} }
@@ -497,6 +518,8 @@ public:
{ {
m_ftp->Abort(); m_ftp->Abort();
} }
// delete m_i_socket; // moved to top of destructor to accomodate wu-FTPd >= 2.6.0
} }
wxFTP *m_ftp; wxFTP *m_ftp;
@@ -608,7 +631,7 @@ wxInputStream *wxFTP::GetInputStream(const wxString& path)
int pos_size; int pos_size;
wxInputFTPStream *in_stream; wxInputFTPStream *in_stream;
if ( !m_modeSet && !SetTransferMode(BINARY) ) if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) )
return NULL; return NULL;
wxSocketClient *sock = GetPort(); wxSocketClient *sock = GetPort();
@@ -642,7 +665,7 @@ wxInputStream *wxFTP::GetInputStream(const wxString& path)
wxOutputStream *wxFTP::GetOutputStream(const wxString& path) wxOutputStream *wxFTP::GetOutputStream(const wxString& path)
{ {
if ( !m_modeSet && !SetTransferMode(BINARY) ) if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) )
return NULL; return NULL;
wxSocketClient *sock = GetPort(); wxSocketClient *sock = GetPort();
@@ -697,6 +720,170 @@ bool wxFTP::GetList(wxArrayString& files,
return TRUE; return TRUE;
} }
bool wxFTP::FileExists(const wxString& fileName)
{
// This function checks if the file specified in fileName exists in the
// current dir. It does so by simply doing an NLST (via GetList).
// If this succeeds (and the list is not empty) the file exists.
bool retval = FALSE;
wxArrayString fileList;
if ( GetList(fileList, fileName, FALSE) )
{
// Some ftp-servers (Ipswitch WS_FTP Server 1.0.5 does this)
// displays this behaviour when queried on a non-existing file:
// NLST this_file_does_not_exist
// 150 Opening ASCII data connection for directory listing
// (no data transferred)
// 226 Transfer complete
// Here wxFTP::GetList(...) will succeed but it will return an empty
// list.
retval = !fileList.IsEmpty();
}
return retval;
}
// ----------------------------------------------------------------------------
// FTP GetSize
// ----------------------------------------------------------------------------
int wxFTP::GetFileSize(const wxString& fileName)
{
// return the filesize of the given file if possible
// return -1 otherwise (predominantly if file doesn't exist
// in current dir)
int filesize = -1;
// Check for existance of file via wxFTP::FileExists(...)
if ( FileExists(fileName) )
{
wxString command;
// First try "SIZE" command using BINARY(IMAGE) transfermode
// Especially UNIX ftp-servers distinguish between the different
// transfermodes and reports different filesizes accordingly.
// The BINARY size is the interesting one: How much memory
// will we need to hold this file?
TransferMode oldTransfermode = m_currentTransfermode;
SetTransferMode(BINARY);
command << _T("SIZE ") << fileName;
bool ok = CheckCommand(command, '2');
if ( ok )
{
// The answer should be one line: "213 <filesize>\n"
// 213 is File Status (STD9)
// "SIZE" is not described anywhere..? It works on most servers
int statuscode;
if ( wxSscanf(GetLastResult().c_str(), _T("%i %i"),
&statuscode, &filesize) == 2 )
{
// We've gotten a good reply.
ok = TRUE;
}
else
{
// Something bad happened.. A "2yz" reply with no size
// Fallback
ok = FALSE;
}
}
// Set transfermode back to the original. Only the "SIZE"-command
// is dependant on transfermode
if ( oldTransfermode != NONE )
{
SetTransferMode(oldTransfermode);
}
if ( !ok ) // this is not a direct else clause.. The size command might return an invalid "2yz" reply
{
// The server didn't understand the "SIZE"-command or it
// returned an invalid reply.
// We now try to get details for the file with a "LIST"-command
// and then parse the output from there..
wxArrayString fileList;
if ( GetList(fileList, fileName, TRUE) )
{
if ( !fileList.IsEmpty() )
{
// We _should_ only get one line in return, but just to be
// safe we run through the line(s) returned and look for a
// substring containing the name we are looking for. We
// stop the iteration at the first occurrence of the
// filename. The search is not case-sensitive.
bool foundIt = FALSE;
size_t i;
for ( i = 0; !foundIt && i < fileList.Count(); i++ )
{
foundIt = fileList[i].Upper().Contains(fileName.Upper());
}
if ( foundIt )
{
// The index i points to the first occurrence of
// fileName in the array Now we have to find out what
// format the LIST has returned. There are two
// "schools": Unix-like
//
// '-rw-rw-rw- owner group size month day time filename'
//
// or Windows-like
//
// 'date size filename'
// check if the first character is '-'. This would
// indicate Unix-style (this also limits this function
// to searching for files, not directories)
if ( fileList[i].Mid(0, 1) == _T("-") )
{
if ( wxSscanf(fileList[i].c_str(),
_("%*s %*s %*s %*s %i %*s %*s %*s %*s"),
&filesize) == 9 )
{
// We've gotten a good response
ok = TRUE;
}
else
{
// Hmm... Invalid response
wxLogTrace(FTP_TRACE_MASK,
_T("Invalid LIST response"));
}
}
else // Windows-style response (?)
{
if ( wxSscanf(fileList[i].c_str(),
_T("%*s %*s %i %*s"),
&filesize) == 4 )
{
// valid response
ok = TRUE;
}
else
{
// something bad happened..?
wxLogTrace(FTP_TRACE_MASK,
_T("Invalid or unknown LIST response"));
}
}
}
}
}
}
}
// filesize might still be -1 when exiting
return filesize;
}
#ifdef WXWIN_COMPATIBILITY_2 #ifdef WXWIN_COMPATIBILITY_2
// deprecated // deprecated
wxList *wxFTP::GetList(const wxString& wildcard, bool details) wxList *wxFTP::GetList(const wxString& wildcard, bool details)