+wxSocketBase *wxFTP::GetPassivePort()
+{
+ if ( !DoSimpleCommand(wxT("PASV")) )
+ {
+ m_lastError = wxPROTO_PROTERR;
+ wxLogError(_("The FTP server doesn't support passive mode."));
+ return NULL;
+ }
+
+ size_t addrStart = m_lastResult.find(wxT('('));
+ size_t addrEnd = (addrStart == wxString::npos)
+ ? wxString::npos
+ : m_lastResult.find(wxT(')'), addrStart);
+
+ if ( addrEnd == wxString::npos )
+ {
+ m_lastError = wxPROTO_PROTERR;
+ return NULL;
+ }
+
+ // get the port number and address
+ int a[6];
+ wxString straddr(m_lastResult, addrStart + 1, addrEnd - (addrStart + 1));
+ wxSscanf(straddr, wxT("%d,%d,%d,%d,%d,%d"),
+ &a[2],&a[3],&a[4],&a[5],&a[0],&a[1]);
+
+ wxUint32 hostaddr = (wxUint16)a[2] << 24 |
+ (wxUint16)a[3] << 16 |
+ (wxUint16)a[4] << 8 |
+ a[5];
+ wxUint16 port = (wxUint16)(a[0] << 8 | a[1]);
+
+ wxIPV4address addr;
+ addr.Hostname(hostaddr);
+ addr.Service(port);
+
+ wxSocketClient *client = new wxSocketClient();
+ if ( !client->Connect(addr) )
+ {
+ m_lastError = wxPROTO_CONNERR;
+ delete client;
+ return NULL;
+ }
+
+ client->Notify(false);
+
+ m_lastError = wxPROTO_NOERR;
+ return client;
+}
+
+
+// ----------------------------------------------------------------------------
+// wxFTP download and upload
+// ----------------------------------------------------------------------------
+
+class wxInputFTPStream : public wxSocketInputStream
+{
+public:
+ wxInputFTPStream(wxFTP *ftp, wxSocketBase *sock)
+ : wxSocketInputStream(*sock)
+ {
+ m_ftp = ftp;
+ // socket timeout automatically set in GetPort function
+ }
+
+ virtual ~wxInputFTPStream()
+ {
+ delete m_i_socket; // keep at top
+
+ // when checking the result, the stream will
+ // almost always show an error, even if the file was
+ // properly transferred, thus, let's just grab the result
+
+ // 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;
+ }
+ // 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->Close();
+ return;
+ }
+ // 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;
+
+ wxDECLARE_NO_COPY_CLASS(wxInputFTPStream);
+};
+
+class wxOutputFTPStream : public wxSocketOutputStream
+{
+public:
+ wxOutputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock)
+ : wxSocketOutputStream(*sock), m_ftp(ftp_clt)
+ {
+ }
+
+ virtual ~wxOutputFTPStream(void)
+ {
+ if ( IsOk() )
+ {
+ // close data connection first, this will generate "transfer
+ // completed" reply
+ delete m_o_socket;
+
+ // read this reply
+ m_ftp->GetResult(); // save result so user can get to it
+
+ m_ftp->m_streaming = false;
+ }
+ else
+ {
+ // abort data connection first
+ m_ftp->Abort();
+
+ // and close it after
+ delete m_o_socket;
+ }
+ }
+
+ wxFTP *m_ftp;
+
+ wxDECLARE_NO_COPY_CLASS(wxOutputFTPStream);
+};
+