]> git.saurik.com Git - wxWidgets.git/commitdiff
active mode support for wxFTP (extremely heavily modified patch 1006252)
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 18 Sep 2004 14:24:49 +0000 (14:24 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 18 Sep 2004 14:24:49 +0000 (14:24 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@29204 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
docs/latex/wx/ftp.tex
include/wx/protocol/ftp.h
src/common/ftp.cpp

index af2a77f1fc81e85c616b0a1598d4acae037f5f34..dd17b1bbde3018fca73c8ff2e544db5247fcda4f 100644 (file)
@@ -208,6 +208,8 @@ All:
 - basic UDP sockets support (Lenny Maiorani)
 - fixed wxDateTime::GetWeekDayName() for some dates (Daniel Kaps)
 - deprecated wxDateTime::SetToTheWeek() in favour of SetToWeekOfYear()
 - basic UDP sockets support (Lenny Maiorani)
 - fixed wxDateTime::GetWeekDayName() for some dates (Daniel Kaps)
 - deprecated wxDateTime::SetToTheWeek() in favour of SetToWeekOfYear()
+- active mode support in wxFTP (Randall Fox)
+- sped up wxHTTP and wxFTP
 
 All (GUI):
 
 
 All (GUI):
 
index b9a835791d8c0385e92a9942934810d99983bf0f..d098f5a6c3ef0e94011d156a3b11978f1b5272f6 100644 (file)
@@ -103,18 +103,21 @@ enum TransferMode
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
+
 \membersection{wxFTP::wxFTP}
 
 \func{}{wxFTP}{\void}
 
 Default constructor.
 
 \membersection{wxFTP::wxFTP}
 
 \func{}{wxFTP}{\void}
 
 Default constructor.
 
+
 \membersection{wxFTP::\destruct{wxFTP}}
 
 \func{}{\destruct{wxFTP}}{\void}
 
 Destructor will close the connection if connected.
 
 \membersection{wxFTP::\destruct{wxFTP}}
 
 \func{}{\destruct{wxFTP}}{\void}
 
 Destructor will close the connection if connected.
 
+
 \membersection{wxFTP::Abort}\label{wxftpabort}
 
 \func{bool}{Abort}{\void}
 \membersection{wxFTP::Abort}\label{wxftpabort}
 
 \func{bool}{Abort}{\void}
@@ -122,6 +125,7 @@ Destructor will close the connection if connected.
 Aborts the download currently in process, returns {\tt true} if ok, {\tt false} 
 if an error occured.
 
 Aborts the download currently in process, returns {\tt true} if ok, {\tt false} 
 if an error occured.
 
+
 \membersection{wxFTP::CheckCommand}
 
 \func{bool}{CheckCommand}{\param{const wxString\&}{ command}, \param{char }{ret}}
 \membersection{wxFTP::CheckCommand}
 
 \func{bool}{CheckCommand}{\param{const wxString\&}{ command}, \param{char }{ret}}
@@ -133,6 +137,7 @@ the expected result.
 
 true if the command has been sent successfully, else false.
 
 
 true if the command has been sent successfully, else false.
 
+
 \membersection{wxFTP::SendCommand}\label{wxftpsendcommand}
 
 \func{char}{SendCommand}{\param{const wxString\&}{ command}}
 \membersection{wxFTP::SendCommand}\label{wxftpsendcommand}
 
 \func{char}{SendCommand}{\param{const wxString\&}{ command}}
@@ -140,6 +145,7 @@ true if the command has been sent successfully, else false.
 Send the specified {\it command} to the FTP server and return the first
 character of the return code.
 
 Send the specified {\it command} to the FTP server and return the first
 character of the return code.
 
+
 \membersection{wxFTP::GetLastResult}
 
 \func{const wxString\&}{GetLastResult}{\void}
 \membersection{wxFTP::GetLastResult}
 
 \func{const wxString\&}{GetLastResult}{\void}
@@ -149,6 +155,7 @@ command.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::ChDir}
 
 \func{bool}{ChDir}{\param{const wxString\&}{ dir}}
 \membersection{wxFTP::ChDir}
 
 \func{bool}{ChDir}{\param{const wxString\&}{ dir}}
@@ -156,6 +163,7 @@ command.
 Change the current FTP working directory.
 Returns true if successful.
 
 Change the current FTP working directory.
 Returns true if successful.
 
+
 \membersection{wxFTP::MkDir}
 
 \func{bool}{MkDir}{\param{const wxString\&}{ dir}}
 \membersection{wxFTP::MkDir}
 
 \func{bool}{MkDir}{\param{const wxString\&}{ dir}}
@@ -163,6 +171,7 @@ Returns true if successful.
 Create the specified directory in the current FTP working directory.
 Returns true if successful.
 
 Create the specified directory in the current FTP working directory.
 Returns true if successful.
 
+
 \membersection{wxFTP::RmDir}
 
 \func{bool}{RmDir}{\param{const wxString\&}{ dir}}
 \membersection{wxFTP::RmDir}
 
 \func{bool}{RmDir}{\param{const wxString\&}{ dir}}
@@ -170,6 +179,7 @@ Returns true if successful.
 Remove the specified directory from the current FTP working directory.
 Returns true if successful.
 
 Remove the specified directory from the current FTP working directory.
 Returns true if successful.
 
+
 \membersection{wxFTP::Pwd}
 
 \func{wxString}{Pwd}{\void}
 \membersection{wxFTP::Pwd}
 
 \func{wxString}{Pwd}{\void}
@@ -178,6 +188,7 @@ Returns the current FTP working directory.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::Rename}
 
 \func{bool}{Rename}{\param{const wxString\&}{ src}, \param{const wxString\&}{ dst}}
 \membersection{wxFTP::Rename}
 
 \func{bool}{Rename}{\param{const wxString\&}{ src}, \param{const wxString\&}{ dst}}
@@ -186,6 +197,7 @@ Rename the specified {\it src} element to {\it dst}. Returns true if successful.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::RmFile}
 
 \func{bool}{RmFile}{\param{const wxString\&}{ path}}
 \membersection{wxFTP::RmFile}
 
 \func{bool}{RmFile}{\param{const wxString\&}{ path}}
@@ -194,18 +206,31 @@ Delete the file specified by {\it path}. Returns true if successful.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::SetAscii}
 
 \func{bool}{SetAscii}{\void}
 
 Sets the transfer mode to ASCII. It will be used for the next transfer.
 
 \membersection{wxFTP::SetAscii}
 
 \func{bool}{SetAscii}{\void}
 
 Sets the transfer mode to ASCII. It will be used for the next transfer.
 
+
 \membersection{wxFTP::SetBinary}
 
 \func{bool}{SetBinary}{\void}
 
 Sets the transfer mode to binary (IMAGE). It will be used for the next transfer.
 
 \membersection{wxFTP::SetBinary}
 
 \func{bool}{SetBinary}{\void}
 
 Sets the transfer mode to binary (IMAGE). It will be used for the next transfer.
 
+
+\membersection{wxFTP::SetPassive}
+
+\func{void}{SetPassive}{\param{bool }{pasv}}
+
+If \arg{pasv} is \true, passive connection to the FTP server is used. This is
+the default as it works with practically all firewalls. If the server doesn't
+support passive move, you may call this function with \false argument to use
+active connection.
+
+
 \membersection{wxFTP::SetTransferMode}
 
 \func{bool}{SetTransferMode}{\param{TransferMode }{mode}}
 \membersection{wxFTP::SetTransferMode}
 
 \func{bool}{SetTransferMode}{\param{TransferMode }{mode}}
@@ -217,6 +242,7 @@ If this function is never called, binary transfer mode is used by default.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::SetUser}
 
 \func{void}{SetUser}{\param{const wxString\&}{ user}}
 \membersection{wxFTP::SetUser}
 
 \func{void}{SetUser}{\param{const wxString\&}{ user}}
@@ -233,6 +259,7 @@ This parameter can be included in a URL if you want to use the URL manager.
 For example, you can use: "ftp://a\_user:a\_password@a.host:service/a\_directory/a\_file"
 to specify a user and a password.
 
 For example, you can use: "ftp://a\_user:a\_password@a.host:service/a\_directory/a\_file"
 to specify a user and a password.
 
+
 \membersection{wxFTP::SetPassword}
 
 \func{void}{SetPassword}{\param{const wxString\&}{ passwd}}
 \membersection{wxFTP::SetPassword}
 
 \func{void}{SetPassword}{\param{const wxString\&}{ passwd}}
@@ -253,12 +280,14 @@ to specify a user and a password.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::FileExists}\label{wxftpfileexists}
 
 \func{bool}{FileExists}{\param{const wxString\&}{ filename}}
 
 Returns {\tt true} if the given remote file exists, {\tt false} otherwise.
 
 \membersection{wxFTP::FileExists}\label{wxftpfileexists}
 
 \func{bool}{FileExists}{\param{const wxString\&}{ filename}}
 
 Returns {\tt true} if the given remote file exists, {\tt false} otherwise.
 
+
 \membersection{wxFTP::GetFileSize}\label{wxftpgetfilesize}
 
 \func{int}{GetFileSize}{\param{const wxString\&}{ filename}}
 \membersection{wxFTP::GetFileSize}\label{wxftpgetfilesize}
 
 \func{int}{GetFileSize}{\param{const wxString\&}{ filename}}
@@ -268,6 +297,7 @@ couldn't be determined. Notice that this size can be approximative size only
 and shouldn't be used for allocating the buffer in which the remote file is
 copied, for example.
 
 and shouldn't be used for allocating the buffer in which the remote file is
 copied, for example.
 
+
 \membersection{wxFTP::GetDirList}\label{wxftpgetdirlist}
 
 \func{bool}{GetDirList}{\param{wxArrayString\& }{files}, \param{const wxString\&}{ wildcard = ""}}
 \membersection{wxFTP::GetDirList}\label{wxftpgetdirlist}
 
 \func{bool}{GetDirList}{\param{wxArrayString\& }{files}, \param{const wxString\&}{ wildcard = ""}}
@@ -302,6 +332,7 @@ otherwise.
 
 \helpref{GetFilesList}{wxftpgetfileslist}
 
 
 \helpref{GetFilesList}{wxftpgetfileslist}
 
+
 \membersection{wxFTP::GetFilesList}\label{wxftpgetfileslist}
 
 \func{bool}{GetFilesList}{\param{wxArrayString\& }{files}, \param{const wxString\&}{ wildcard = ""}}
 \membersection{wxFTP::GetFilesList}\label{wxftpgetfileslist}
 
 \func{bool}{GetFilesList}{\param{wxArrayString\& }{files}, \param{const wxString\&}{ wildcard = ""}}
@@ -316,6 +347,7 @@ otherwise.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::GetOutputStream}
 
 \func{wxOutputStream *}{GetOutputStream}{\param{const wxString\&}{ file}}
 \membersection{wxFTP::GetOutputStream}
 
 \func{wxOutputStream *}{GetOutputStream}{\param{const wxString\&}{ file}}
@@ -334,6 +366,7 @@ An initialized write-only stream.
 
 % ----------------------------------------------------------------------------
 
 
 % ----------------------------------------------------------------------------
 
+
 \membersection{wxFTP::GetInputStream}\label{wxftpgetinput}
 
 \func{wxInputStream *}{GetInputStream}{\param{const wxString\&}{ path}}
 \membersection{wxFTP::GetInputStream}\label{wxftpgetinput}
 
 \func{wxInputStream *}{GetInputStream}{\param{const wxString\&}{ path}}
index 697557fc6f2c2c143f360deb46d64c1190498f1d..3f351f3664ed3e6e5e0346927500a1a42634151b 100644 (file)
@@ -42,7 +42,7 @@ public:
     void SetUser(const wxString& user) { m_user = user; }
     void SetPassword(const wxString& passwd) { m_passwd = passwd; }
 
     void SetUser(const wxString& user) { m_user = user; }
     void SetPassword(const wxString& passwd) { m_passwd = passwd; }
 
-    bool Connect(wxSockAddress& addr, bool wait = TRUE);
+    bool Connect(wxSockAddress& addr, bool wait = true);
     bool Connect(const wxString& host);
 
     // disconnect
     bool Connect(const wxString& host);
 
     // disconnect
@@ -51,6 +51,8 @@ public:
     // Parameters set up
 
     // set transfer mode now
     // Parameters set up
 
     // set transfer mode now
+    void SetPassive(bool pasv) { m_bPassive = pasv; };
+    void SetDefaultTimeout(wxUint32 Value);
     bool SetBinary() { return SetTransferMode(BINARY); }
     bool SetAscii() { return SetTransferMode(ASCII); }
     bool SetTransferMode(TransferMode mode);
     bool SetBinary() { return SetTransferMode(BINARY); }
     bool SetAscii() { return SetTransferMode(ASCII); }
     bool SetTransferMode(TransferMode mode);
@@ -104,7 +106,7 @@ public:
     bool GetFilesList(wxArrayString& files,
                       const wxString& wildcard = wxEmptyString)
     {
     bool GetFilesList(wxArrayString& files,
                       const wxString& wildcard = wxEmptyString)
     {
-        return GetList(files, wildcard, FALSE);
+        return GetList(files, wildcard, false);
     }
 
     // get a directory list in server dependent format - this can be shown
     }
 
     // get a directory list in server dependent format - this can be shown
@@ -112,17 +114,17 @@ public:
     bool GetDirList(wxArrayString& files,
                     const wxString& wildcard = wxEmptyString)
     {
     bool GetDirList(wxArrayString& files,
                     const wxString& wildcard = wxEmptyString)
     {
-        return GetList(files, wildcard, TRUE);
+        return GetList(files, wildcard, true);
     }
 
     // equivalent to either GetFilesList() (default) or GetDirList()
     bool GetList(wxArrayString& files,
                  const wxString& wildcard = wxEmptyString,
     }
 
     // equivalent to either GetFilesList() (default) or GetDirList()
     bool GetList(wxArrayString& files,
                  const wxString& wildcard = wxEmptyString,
-                 bool details = FALSE);
+                 bool details = false);
 
 protected:
     // this executes a simple ftp command with the given argument and returns
 
 protected:
     // this executes a simple ftp command with the given argument and returns
-    // TRUE if it its return code starts with '2'
+    // true if it its return code starts with '2'
     bool DoSimpleCommand(const wxChar *command,
                          const wxString& arg = wxEmptyString);
 
     bool DoSimpleCommand(const wxChar *command,
                          const wxString& arg = wxEmptyString);
 
@@ -133,7 +135,19 @@ protected:
     // check that the result is equal to expected value
     bool CheckResult(char ch) { return GetResult() == ch; }
 
     // check that the result is equal to expected value
     bool CheckResult(char ch) { return GetResult() == ch; }
 
-    wxSocketClient *GetPort();
+    // return the socket to be used, Passive/Active versions are used only by
+    // GetPort()
+    wxSocketBase *GetPort();
+    wxSocketBase *GetPassivePort();
+    wxSocketBase *GetActivePort();
+
+    // helper for GetPort()
+    wxString GetPortCmdArgument(wxIPV4address Local, wxIPV4address New);
+
+    // accept connection from server in active mode, returns the same socket as
+    // passed in in passive mode
+    wxSocketBase *AcceptIfActive(wxSocketBase *sock);
+
 
     wxString m_user,
              m_passwd;
 
     wxString m_user,
              m_passwd;
@@ -151,6 +165,14 @@ protected:
     friend class wxInputFTPStream;
     friend class wxOutputFTPStream;
 
     friend class wxInputFTPStream;
     friend class wxOutputFTPStream;
 
+    bool            m_bPassive;
+    wxUint32        m_uiDefaultTimeout;
+
+    // following is true when  a read or write times out, we then assume
+    // the connection is dead and abort. we avoid additional delays this way
+    bool            m_bEncounteredError;
+
+
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxFTP)
     DECLARE_PROTOCOL(wxFTP)
 };
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxFTP)
     DECLARE_PROTOCOL(wxFTP)
 };
index fbb119d4deb26d1c080103d326c70cd759b4f995..474a98a6dc0949f9b04d65b14aa436b70c03db4a 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
-// Name:        ftp.cpp
+// Name:        common/ftp.cpp
 // Purpose:     FTP protocol
 // Author:      Guilhem Lavaux
 // Modified by: Mark Johnson, wxWindows@mj10777.de
 // Purpose:     FTP protocol
 // Author:      Guilhem Lavaux
 // Modified by: Mark Johnson, wxWindows@mj10777.de
@@ -7,9 +7,11 @@
 //              Vadim Zeitlin (numerous fixes and rewrites to all part of the
 //              code, support ASCII/Binary modes, better error reporting, more
 //              robust Abort(), support for arbitrary FTP commands, ...)
 //              Vadim Zeitlin (numerous fixes and rewrites to all part of the
 //              code, support ASCII/Binary modes, better error reporting, more
 //              robust Abort(), support for arbitrary FTP commands, ...)
+//              Randall Fox (support for active mode)
 // Created:     07/07/1997
 // RCS-ID:      $Id$
 // Copyright:   (c) 1997, 1998 Guilhem Lavaux
 // Created:     07/07/1997
 // RCS-ID:      $Id$
 // Copyright:   (c) 1997, 1998 Guilhem Lavaux
+//              (c) 1998-2004 wxWidgets team
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
@@ -90,15 +92,21 @@ wxFTP::wxFTP()
 
     SetNotify(0);
     SetFlags(wxSOCKET_NONE);
 
     SetNotify(0);
     SetFlags(wxSOCKET_NONE);
+    m_bPassive = true;
+    SetDefaultTimeout(60); // Default is Sixty Seconds
+    m_bEncounteredError = false;
 }
 
 wxFTP::~wxFTP()
 {
     if ( m_streaming )
     {
 }
 
 wxFTP::~wxFTP()
 {
     if ( m_streaming )
     {
+        // if we are streaming, this will issue
+        // an FTP ABORT command, to tell the server we are aborting
         (void)Abort();
     }
 
         (void)Abort();
     }
 
+    // now this issues a "QUIT" command to tell the server we are
     Close();
 }
 
     Close();
 }
 
@@ -228,6 +236,11 @@ char wxFTP::SendCommand(const wxString& command)
 
 char wxFTP::GetResult()
 {
 
 char wxFTP::GetResult()
 {
+    // if we've already had a read or write timeout error, the connection is
+    // probably toast, so don't bother, it just wastes the users time
+    if ( m_bEncounteredError )
+        return 0;
+
     wxString code;
 
     // m_lastResult will contain the entire server response, possibly on
     wxString code;
 
     // m_lastResult will contain the entire server response, possibly on
@@ -247,9 +260,12 @@ char wxFTP::GetResult()
     while ( !endOfReply && !badReply )
     {
         wxString line;
     while ( !endOfReply && !badReply )
     {
         wxString line;
-        m_lastError = ReadLine(line);
+        m_lastError = ReadLine(this,line);
         if ( m_lastError )
         if ( m_lastError )
+        {
+            m_bEncounteredError = true;
             return 0;
             return 0;
+        }
 
         if ( !m_lastResult.empty() )
         {
 
         if ( !m_lastResult.empty() )
         {
@@ -494,36 +510,43 @@ public:
         : wxSocketInputStream(*sock)
     {
         m_ftp = ftp;
         : wxSocketInputStream(*sock)
     {
         m_ftp = ftp;
-
-        // FIXME make the timeout configurable
-
-        // set a shorter than default timeout
-        m_i_socket->SetTimeout(60); // 1 minute
+        // socket timeout automatically set in GetPort function
     }
 
     }
 
-    size_t GetSize() const { return m_ftpsize; }
-
     virtual ~wxInputFTPStream()
     {
     virtual ~wxInputFTPStream()
     {
-        delete m_i_socket;
+        delete m_i_socket;   // keep at top
 
 
-        if ( IsOk() )
-        {
-            // wait for "226 transfer completed"
-            m_ftp->CheckResult('2');
+        // when checking the result, the stream will
+        // almost always show an error, even if the file was
+        // properly transfered, thus, lets just grab the result
 
 
-            m_ftp->m_streaming = false;
+        // we are looking for "226 transfer completed"
+        char code = m_ftp->GetResult();
+        if ('2' == code)
+        {
+            // it was a good transfer.
+            // we're done!
+             m_ftp->m_streaming = false;
+            return;
         }
         }
-        else
+        // did we timeout?
+        if (0 == code)
         {
         {
+            // the connection is probably toast. issue an abort, and
+            // then a close. there won't be any more waiting
+            // for this connection
             m_ftp->Abort();
             m_ftp->Abort();
+            m_ftp->Close();
+            return;
         }
         }
-
-        // delete m_i_socket; // moved to top of destructor to accomodate wu-FTPd >= 2.6.0
+        // There was a problem with the transfer and the server
+        // has acknowledged it.  If we issue an "ABORT" now, the user
+        // would get the "226" for the abort and think the xfer was
+        // complete, thus, don't do anything here, just return
     }
 
     wxFTP *m_ftp;
     }
 
     wxFTP *m_ftp;
-    size_t m_ftpsize;
 
     DECLARE_NO_COPY_CLASS(wxInputFTPStream)
 };
 
     DECLARE_NO_COPY_CLASS(wxInputFTPStream)
 };
@@ -545,7 +568,7 @@ public:
             delete m_o_socket;
 
             // read this reply
             delete m_o_socket;
 
             // read this reply
-            m_ftp->CheckResult('2');
+            m_ftp->GetResult(); // save result so user can get to it
 
             m_ftp->m_streaming = false;
         }
 
             m_ftp->m_streaming = false;
         }
@@ -564,26 +587,130 @@ public:
     DECLARE_NO_COPY_CLASS(wxOutputFTPStream)
 };
 
     DECLARE_NO_COPY_CLASS(wxOutputFTPStream)
 };
 
-wxSocketClient *wxFTP::GetPort()
+void wxFTP::SetDefaultTimeout(wxUint32 Value)
 {
 {
-    int a[6];
+    m_uiDefaultTimeout = Value;
+    SetTimeout(Value); // sets it for this socket
+}
 
 
-    if ( !DoSimpleCommand(_T("PASV")) )
+
+wxSocketBase *wxFTP::GetPort()
+{
+    /*
+    PASSIVE:    Client sends a "PASV" to the server.  The server responds with
+                an address and port number which it will be listening on. Then
+                the client connects to the server at the specified address and
+                port.
+
+    ACTIVE:     Client sends the server a PORT command which includes an
+                address and port number which the client will be listening on.
+                The server then connects to the client at that address and
+                port.
+    */
+
+    wxSocketBase *socket = m_bPassive ? GetPassivePort() : GetActivePort();
+    if ( !socket )
+    {
+        m_bEncounteredError = true;
+        return NULL;
+    }
+
+    // Now set the time for the new socket to the default or user selected
+    // timeout period
+    socket->SetTimeout(m_uiDefaultTimeout);
+
+    return socket;
+}
+
+wxSocketBase *wxFTP::AcceptIfActive(wxSocketBase *sock)
+{
+    if ( m_bPassive )
+        return sock;
+
+    // now wait for a connection from server
+    wxSocketServer *sockSrv = (wxSocketServer *)sock;
+    if ( !sockSrv->WaitForAccept() )
     {
     {
-        wxLogError(_("The FTP server doesn't support passive mode."));
+        m_lastError = wxPROTO_CONNERR;
+        wxLogError(_("Timeout while waiting for FTP server to connect, try passive mode."));
+        delete sock;
+        sock = NULL;
+    }
+    else
+    {
+        sock = sockSrv->Accept(true);
+        delete sockSrv;
+    }
+
+    return sock;
+}
+
+wxString wxFTP::GetPortCmdArgument(wxIPV4address addrLocal,
+                                   wxIPV4address addrNew)
+{
+    // Just fills in the return value with the local IP
+    // address of the current socket.  Also it fill in the
+    // PORT which the client will be listening on
 
 
+    wxString addrIP = addrLocal.IPAddress();
+    int portNew = addrNew.Service();
+
+    // We need to break the PORT number in bytes
+    addrIP.Replace(_T("."), _T(","));
+    addrIP << _T(',')
+           << wxString::Format(_T("%d"), portNew >> 8) << _T(',')
+           << wxString::Format(_T("%d"), portNew & 0xff);
+
+    // Now we have a value like "10,0,0,1,5,23"
+    return addrIP;
+}
+
+wxSocketBase *wxFTP::GetActivePort()
+{
+    // we need an address to listen on
+    wxIPV4address addrNew, addrLocal;
+    GetLocal(addrLocal);
+    addrNew.AnyAddress();
+    addrNew.Service(0); // pick an open port number.
+
+    wxSocketServer *sockSrv = new wxSocketServer(addrNew);
+    if (!sockSrv->Ok())
+    {
+        // We use Ok() here to see if everything is ok
+        m_lastError = wxPROTO_PROTERR;
+        delete sockSrv;
         return NULL;
     }
 
         return NULL;
     }
 
-    const wxChar *addrStart = wxStrchr(m_lastResult, _T('('));
-    if ( !addrStart )
+    //gets the new address, actually it is just the port number
+    sockSrv->GetLocal(addrNew);
+
+    // Now we create the argument of the PORT command, we send in both
+    // addresses because the addrNew has an IP of "0.0.0.0", so we need the
+    // value in addrLocal
+    wxString port = GetPortCmdArgument(addrLocal, addrNew);
+    if ( !DoSimpleCommand(_T("PORT "), port) )
     {
         m_lastError = wxPROTO_PROTERR;
     {
         m_lastError = wxPROTO_PROTERR;
+        delete sockSrv;
+        wxLogError(_("The FTP server doesn't support the PORT command."));
+        return NULL;
+    }
 
 
+    sockSrv->Notify(false); // Don't send any events
+    return sockSrv;
+}
+
+wxSocketBase *wxFTP::GetPassivePort()
+{
+    if ( !DoSimpleCommand(_T("PASV")) )
+    {
+        wxLogError(_("The FTP server doesn't support passive mode."));
         return NULL;
     }
 
         return NULL;
     }
 
-    const wxChar *addrEnd = wxStrchr(addrStart, _T(')'));
+    const wxChar *addrStart = wxStrchr(m_lastResult, _T('('));
+    const wxChar *addrEnd = addrStart ? wxStrchr(addrStart, _T(')')) : NULL;
     if ( !addrEnd )
     {
         m_lastError = wxPROTO_PROTERR;
     if ( !addrEnd )
     {
         m_lastError = wxPROTO_PROTERR;
@@ -591,8 +718,9 @@ wxSocketClient *wxFTP::GetPort()
         return NULL;
     }
 
         return NULL;
     }
 
+    // get the port number and address
+    int a[6];
     wxString straddr(addrStart + 1, addrEnd);
     wxString straddr(addrStart + 1, addrEnd);
-
     wxSscanf(straddr, wxT("%d,%d,%d,%d,%d,%d"),
              &a[2],&a[3],&a[4],&a[5],&a[0],&a[1]);
 
     wxSscanf(straddr, wxT("%d,%d,%d,%d,%d,%d"),
              &a[2],&a[3],&a[4],&a[5],&a[0],&a[1]);
 
@@ -632,13 +760,10 @@ bool wxFTP::Abort()
 
 wxInputStream *wxFTP::GetInputStream(const wxString& path)
 {
 
 wxInputStream *wxFTP::GetInputStream(const wxString& path)
 {
-    int pos_size;
-    wxInputFTPStream *in_stream;
-
     if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) )
         return NULL;
 
     if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) )
         return NULL;
 
-    wxSocketClient *sock = GetPort();
+    wxSocketBase *sock = GetPort();
 
     if ( !sock )
     {
 
     if ( !sock )
     {
@@ -650,19 +775,15 @@ wxInputStream *wxFTP::GetInputStream(const wxString& path)
     if ( !CheckCommand(tmp_str, '1') )
         return NULL;
 
     if ( !CheckCommand(tmp_str, '1') )
         return NULL;
 
-    m_streaming = true;
-
-    in_stream = new wxInputFTPStream(this, sock);
+    sock = AcceptIfActive(sock);
+    if ( !sock )
+        return NULL;
 
 
-    pos_size = m_lastResult.Index(wxT('('));
-    if ( pos_size != wxNOT_FOUND )
-    {
-        wxString str_size = m_lastResult(pos_size+1, m_lastResult.Index(wxT(')'))-1);
+    sock->SetFlags(wxSOCKET_WAITALL);
 
 
-        in_stream->m_ftpsize = wxAtoi(WXSTRINGCAST str_size);
-    }
+    m_streaming = true;
 
 
-    sock->SetFlags(wxSOCKET_WAITALL);
+    wxInputFTPStream *in_stream = new wxInputFTPStream(this, sock);
 
     return in_stream;
 }
 
     return in_stream;
 }
@@ -672,12 +793,14 @@ wxOutputStream *wxFTP::GetOutputStream(const wxString& path)
     if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) )
         return NULL;
 
     if ( ( m_currentTransfermode == NONE ) && !SetTransferMode(BINARY) )
         return NULL;
 
-    wxSocketClient *sock = GetPort();
+    wxSocketBase *sock = GetPort();
 
     wxString tmp_str = wxT("STOR ") + path;
     if ( !CheckCommand(tmp_str, '1') )
         return NULL;
 
 
     wxString tmp_str = wxT("STOR ") + path;
     if ( !CheckCommand(tmp_str, '1') )
         return NULL;
 
+    sock = AcceptIfActive(sock);
+
     m_streaming = true;
 
     return new wxOutputFTPStream(this, sock);
     m_streaming = true;
 
     return new wxOutputFTPStream(this, sock);
@@ -706,22 +829,28 @@ bool wxFTP::GetList(wxArrayString& files,
         line << _T(' ') << wildcard;
     }
 
         line << _T(' ') << wildcard;
     }
 
-    if (!CheckCommand(line, '1'))
+    if ( !CheckCommand(line, '1') )
     {
     {
+        m_lastError = wxPROTO_PROTERR;
+        wxLogDebug("FTP 'LIST' command returned unexpected result from server");
+        delete sock;
         return false;
     }
         return false;
     }
+
+    sock = AcceptIfActive(sock);
+    if ( !sock )
+        return false;
+
     files.Empty();
     files.Empty();
-    while ( ReadLine(sock, line) == wxPROTO_NOERR )
+    while (ReadLine(sock, line) == wxPROTO_NOERR )
     {
         files.Add(line);
     }
     {
         files.Add(line);
     }
+
     delete sock;
 
     // the file list should be terminated by "226 Transfer complete""
     delete sock;
 
     // the file list should be terminated by "226 Transfer complete""
-    if ( !CheckResult('2') )
-        return false;
-
-    return true;
+    return CheckResult('2');
 }
 
 bool wxFTP::FileExists(const wxString& fileName)
 }
 
 bool wxFTP::FileExists(const wxString& fileName)