1. wxFTP works (somehow)

2. wxSocket/GSocket wxBase support for Unix


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@6738 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-03-15 17:16:35 +00:00
parent 76990f630b
commit 8e907a13ea
9 changed files with 708 additions and 202 deletions

View File

@@ -15,6 +15,7 @@ File hierarchy:
wxBase: wxBase:
- wxSocket support
- wxDateTime replaces and extends old wxDate and wxTime classes (still - wxDateTime replaces and extends old wxDate and wxTime classes (still
available but strongly deprecated) with many new features available but strongly deprecated) with many new features
- wxLongLong class provides support for (signed) 64 bit integers - wxLongLong class provides support for (signed) 64 bit integers

View File

@@ -121,11 +121,11 @@ to specify a user and a password.
% ---------------------------------------------------------------------------- % ----------------------------------------------------------------------------
\membersection{wxFTP::GetList} \membersection{wxFTP::GetList}
\func{wxList *}{GetList}{\param{const wxString\&}{ wildcard}} \func{bool}{GetList}{\param{wxArrayString\& }{files}, \param{const wxString\&}{ wildcard = ""}}
The GetList function is quite low-level. It returns the list of the files in The GetList function is quite low-level. It returns the list of the files in
the current directory. The list can be filtered using the {\it wildcard} string. the current directory. The list can be filtered using the {\it wildcard} string.
If {\it wildcard} is a NULL string, it will return all files in directory. If {\it wildcard} is empty (default), it will return all files in directory.
The form of the list can change from one peer system to another. For example, The form of the list can change from one peer system to another. For example,
for a UNIX peer system, it will look like this: for a UNIX peer system, it will look like this:
@@ -146,7 +146,8 @@ winamp~1 exe 520196 02-25-1999 19:28 winamp204.exe
1 file(s) 520 196 bytes 1 file(s) 520 196 bytes
\end{verbatim} \end{verbatim}
The list is a string list and one node corresponds to a line sent by the peer. Return value: TRUE if the file list was successfully retrieved, FALSE
otherwise.
% ---------------------------------------------------------------------------- % ----------------------------------------------------------------------------

View File

@@ -8,6 +8,7 @@
// Copyright: (c) 1997, 1998 Guilhem Lavaux // Copyright: (c) 1997, 1998 Guilhem Lavaux
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef __WX_FTP_H__ #ifndef __WX_FTP_H__
#define __WX_FTP_H__ #define __WX_FTP_H__
@@ -20,28 +21,23 @@
#include "wx/protocol/protocol.h" #include "wx/protocol/protocol.h"
#include "wx/url.h" #include "wx/url.h"
class WXDLLEXPORT wxFTP : public wxProtocol { class WXDLLEXPORT wxFTP : public wxProtocol
DECLARE_DYNAMIC_CLASS(wxFTP) {
DECLARE_PROTOCOL(wxFTP)
public: public:
typedef enum { ASCII, BINARY } wxFTPmode; typedef enum { ASCII, BINARY } wxFTPmode;
wxFTP(); wxFTP();
~wxFTP(); virtual ~wxFTP();
bool Close();
bool Connect(wxSockAddress& addr, bool wait = TRUE); bool Connect(wxSockAddress& addr, bool wait = TRUE);
bool Connect(const wxString& host); bool Connect(const wxString& host);
// [forcibly] close the connection
bool Close(bool force = FALSE);
void SetUser(const wxString& user) { m_user = user; } void SetUser(const wxString& user) { m_user = user; }
void SetPassword(const wxString& passwd) { m_passwd = passwd; } void SetPassword(const wxString& passwd) { m_passwd = passwd; }
// Low-level methods
bool SendCommand(const wxString& command, char exp_ret);
inline virtual wxProtocolError GetError()
{ return m_lastError; }
const wxString& GetLastResult(); // Get the complete return
// Filesystem commands // Filesystem commands
bool ChDir(const wxString& dir); bool ChDir(const wxString& dir);
bool MkDir(const wxString& dir); bool MkDir(const wxString& dir);
@@ -56,6 +52,14 @@ public:
wxOutputStream *GetOutputStream(const wxString& path); wxOutputStream *GetOutputStream(const wxString& path);
// List method // List method
bool GetList(wxArrayString& files, const wxString& wildcard = wxEmptyString);
// Low-level methods
bool SendCommand(const wxString& command, char exp_ret);
virtual wxProtocolError GetError() { return m_lastError; }
const wxString& GetLastResult(); // Get the complete return
// deprecated
wxList *GetList(const wxString& wildcard); wxList *GetList(const wxString& wildcard);
protected: protected:
@@ -69,6 +73,9 @@ protected:
wxSocketClient *GetPort(); wxSocketClient *GetPort();
bool GetResult(char exp); bool GetResult(char exp);
DECLARE_DYNAMIC_CLASS(wxFTP)
DECLARE_PROTOCOL(wxFTP)
}; };
#endif #endif // __WX_FTP_H__

View File

@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: protocol.h // Name: wx/protocol/protocol.h
// Purpose: Protocol base class // Purpose: Protocol base class
// Author: Guilhem Lavaux // Author: Guilhem Lavaux
// Modified by: // Modified by:
@@ -8,6 +8,7 @@
// Copyright: (c) 1997, 1998 Guilhem Lavaux // Copyright: (c) 1997, 1998 Guilhem Lavaux
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PROTOCOL_PROTOCOL_H #ifndef _WX_PROTOCOL_PROTOCOL_H
#define _WX_PROTOCOL_PROTOCOL_H #define _WX_PROTOCOL_PROTOCOL_H
@@ -17,29 +18,79 @@
#include "wx/defs.h" #include "wx/defs.h"
#include "wx/object.h" #include "wx/object.h"
#include "wx/string.h" #include "wx/string.h"
#include "wx/stream.h" #include "wx/stream.h"
#if wxUSE_SOCKETS #if wxUSE_SOCKETS
#include "wx/socket.h" #include "wx/socket.h"
#endif #endif
typedef enum { // ----------------------------------------------------------------------------
wxPROTO_NOERR = 0, // constants
wxPROTO_NETERR, // ----------------------------------------------------------------------------
wxPROTO_PROTERR,
wxPROTO_CONNERR, typedef enum
wxPROTO_INVVAL, {
wxPROTO_NOHNDLR, wxPROTO_NOERR = 0,
wxPROTO_NOFILE, wxPROTO_NETERR,
wxPROTO_ABRT, wxPROTO_PROTERR,
wxPROTO_RCNCT, wxPROTO_CONNERR,
wxPROTO_STREAMING wxPROTO_INVVAL,
wxPROTO_NOHNDLR,
wxPROTO_NOFILE,
wxPROTO_ABRT,
wxPROTO_RCNCT,
wxPROTO_STREAMING
} wxProtocolError; } wxProtocolError;
// For protocols // ----------------------------------------------------------------------------
// wxProtocol: abstract base class for all protocols
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxProtocol
#if wxUSE_SOCKETS
: public wxSocketClient
#else
: public wxObject
#endif
{
public:
wxProtocol();
#if wxUSE_SOCKETS
bool Reconnect();
virtual bool Connect( const wxString& WXUNUSED(host) ) { return FALSE; }
virtual bool Connect( wxSockAddress& addr, bool WXUNUSED(wait) = TRUE) { return wxSocketClient::Connect(addr); }
// read a '\r\n' terminated line from the given socket and put it in
// result (without the terminators)
static wxProtocolError ReadLine(wxSocketBase *socket, wxString& result);
// read a line from this socket - this one can be overridden in the
// derived classes if different line termination convention is to be used
virtual wxProtocolError ReadLine(wxString& result);
#endif // wxUSE_SOCKETS
virtual bool Abort() = 0;
virtual wxInputStream *GetInputStream(const wxString& path) = 0;
virtual wxProtocolError GetError() = 0;
virtual wxString GetContentType() { return wxEmptyString; }
virtual void SetUser(const wxString& WXUNUSED(user)) {}
virtual void SetPassword(const wxString& WXUNUSED(passwd) ) {}
private:
DECLARE_ABSTRACT_CLASS(wxProtocol)
};
#if wxUSE_SOCKETS
wxProtocolError WXDLLEXPORT GetLine(wxSocketBase *sock, wxString& result);
#endif
// ----------------------------------------------------------------------------
// macros for protocol classes
// ----------------------------------------------------------------------------
#define DECLARE_PROTOCOL(class) \ #define DECLARE_PROTOCOL(class) \
public: \ public: \
static wxProtoInfo g_proto_##class; static wxProtoInfo g_proto_##class;
@@ -47,48 +98,25 @@ public: \
#define IMPLEMENT_PROTOCOL(class, name, serv, host) \ #define IMPLEMENT_PROTOCOL(class, name, serv, host) \
wxProtoInfo class::g_proto_##class(name, serv, host, CLASSINFO(class)); wxProtoInfo class::g_proto_##class(name, serv, host, CLASSINFO(class));
class WXDLLEXPORT wxProtoInfo : public wxObject { class WXDLLEXPORT wxProtoInfo : public wxObject
DECLARE_DYNAMIC_CLASS(wxProtoInfo) {
public:
wxProtoInfo(const wxChar *name,
const wxChar *serv_name,
const bool need_host1,
wxClassInfo *info);
protected: protected:
wxProtoInfo *next; wxProtoInfo *next;
wxString m_protoname; wxString m_protoname;
wxString prefix; wxString prefix;
wxString m_servname; wxString m_servname;
wxClassInfo *m_cinfo; wxClassInfo *m_cinfo;
bool m_needhost; bool m_needhost;
friend class wxURL; friend class wxURL;
public:
wxProtoInfo(const wxChar *name, const wxChar *serv_name, const bool need_host1, DECLARE_DYNAMIC_CLASS(wxProtoInfo)
wxClassInfo *info);
}; };
class WXDLLEXPORT wxProtocol
#if wxUSE_SOCKETS
: public wxSocketClient {
#else
: public wxObject {
#endif
DECLARE_ABSTRACT_CLASS(wxProtocol)
public:
wxProtocol();
#if wxUSE_SOCKETS
bool Reconnect();
virtual bool Connect( const wxString& WXUNUSED(host) ) { return FALSE; }
virtual bool Connect( wxSockAddress& addr, bool WXUNUSED(wait) = TRUE) { return wxSocketClient::Connect(addr); }
#endif
virtual bool Abort() = 0;
virtual wxInputStream *GetInputStream(const wxString& path) = 0;
virtual wxProtocolError GetError() = 0;
virtual wxString GetContentType() { return wxEmptyString; }
virtual void SetUser(const wxString& WXUNUSED(user)) {}
virtual void SetPassword(const wxString& WXUNUSED(passwd) ) {}
};
#if wxUSE_SOCKETS
wxProtocolError WXDLLEXPORT GetLine(wxSocketBase *sock, wxString& result);
#endif
#endif // _WX_PROTOCOL_PROTOCOL_H #endif // _WX_PROTOCOL_PROTOCOL_H

View File

@@ -45,15 +45,34 @@
//#define TEST_LOG //#define TEST_LOG
//#define TEST_LONGLONG //#define TEST_LONGLONG
//#define TEST_MIME //#define TEST_MIME
//#define TEST_SOCKETS #define TEST_SOCKETS
//#define TEST_STRINGS //#define TEST_STRINGS
//#define TEST_THREADS //#define TEST_THREADS
#define TEST_TIMER //#define TEST_TIMER
// ============================================================================ // ============================================================================
// implementation // implementation
// ============================================================================ // ============================================================================
// ----------------------------------------------------------------------------
// helper functions
// ----------------------------------------------------------------------------
#if defined(TEST_STRINGS) || defined(TEST_SOCKETS)
// replace TABs with \t and CRs with \n
static wxString MakePrintable(const wxChar *s)
{
wxString str(s);
(void)str.Replace(_T("\t"), _T("\\t"));
(void)str.Replace(_T("\n"), _T("\\n"));
(void)str.Replace(_T("\r"), _T("\\r"));
return str;
}
#endif // MakePrintable() is used
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxCmdLineParser // wxCmdLineParser
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -696,27 +715,129 @@ static void TestBitOperations()
#ifdef TEST_SOCKETS #ifdef TEST_SOCKETS
#include <wx/socket.h> #include <wx/socket.h>
#include <wx/protocol/protocol.h>
#include <wx/protocol/ftp.h>
#include <wx/protocol/http.h>
static void TestSocketServer()
{
puts("*** Testing wxSocketServer ***\n");
// we want to launch a server
wxIPV4address addr;
addr.Service(3000);
wxSocketServer *server = new wxSocketServer(addr);
if ( !server->Ok() )
{
puts("ERROR: failed to bind");
}
}
static void TestSocketClient() static void TestSocketClient()
{ {
puts("*** Testing wxSocketClient ***\n"); puts("*** Testing wxSocketClient ***\n");
wxIPV4address addrDst; static const char *hostname = "www.wxwindows.org";
addrDst.Hostname("www.wxwindows.org");
addrDst.Service(80); wxIPV4address addr;
addr.Hostname(hostname);
addr.Service(80);
printf("--- Attempting to connect to %s:80...\n", hostname);
wxSocketClient client; wxSocketClient client;
if ( !client.Connect(addrDst) ) if ( !client.Connect(addr) )
{ {
printf("ERROR: failed to connect to %s\n", addrDst.Hostname().c_str()); printf("ERROR: failed to connect to %s\n", hostname);
} }
else else
{ {
printf("--- Connected to %s:%u...\n",
addr.Hostname().c_str(), addr.Service());
char buf[8192]; char buf[8192];
client.Write("get /front.htm\n", 17); // could use simply "GET" here I suppose
wxString cmdGet =
wxString::Format("GET http://%s/\r\n", hostname);
client.Write(cmdGet, cmdGet.length());
printf("--- Sent command '%s' to the server\n",
MakePrintable(cmdGet).c_str());
client.Read(buf, WXSIZEOF(buf)); client.Read(buf, WXSIZEOF(buf));
printf("Server replied:\n%s", buf); printf("--- Server replied:\n%s", buf);
}
}
static void TestProtocolFtp()
{
puts("*** Testing wxFTP ***\n");
wxLog::AddTraceMask(_T("ftp"));
static const char *hostname = "ftp.wxwindows.org";
printf("--- Attempting to connect to %s:21...\n", hostname);
wxFTP ftp;
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());
if ( !ftp.ChDir(_T("pub")) )
{
puts("ERROR: failed to cd to pub");
}
wxArrayString files;
if ( !ftp.GetList(files) )
{
puts("ERROR: failed to get list of files");
}
else
{
printf("List of files under '%s':\n", 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");
}
if ( !ftp.ChDir(_T("..")) )
{
puts("ERROR: failed to cd to ..");
}
static const char *filename = "welcome.msg";
wxInputStream *in = ftp.GetInputStream(filename);
if ( !in )
{
puts("ERROR: couldn't get input stream");
}
else
{
size_t size = in->StreamSize();
printf("Reading file %s (%u bytes)...", filename, size);
char *data = new char[size];
if ( !in->Read(data, size) )
{
puts("ERROR: read error");
}
else
{
printf("\nContents of %s:\n%s\n", filename, data);
}
delete [] data;
delete in;
}
} }
} }
@@ -2139,17 +2260,6 @@ static void TestStringFind()
puts(""); puts("");
} }
// replace TABs with \t and CRs with \n
static wxString MakePrintable(const wxChar *s)
{
wxString str(s);
(void)str.Replace(_T("\t"), _T("\\t"));
(void)str.Replace(_T("\n"), _T("\\n"));
(void)str.Replace(_T("\r"), _T("\\r"));
return str;
}
static void TestStringTokenizer() static void TestStringTokenizer()
{ {
puts("*** Testing wxStringTokenizer ***"); puts("*** Testing wxStringTokenizer ***");
@@ -2443,7 +2553,12 @@ int main(int argc, char **argv)
#endif // TEST_MIME #endif // TEST_MIME
#ifdef TEST_SOCKETS #ifdef TEST_SOCKETS
TestSocketClient(); if ( 0 )
{
TestSocketServer();
TestSocketClient();
}
TestProtocolFtp();
#endif // TEST_SOCKETS #endif // TEST_SOCKETS
#ifdef TEST_TIMER #ifdef TEST_TIMER

View File

@@ -38,11 +38,15 @@
#include "wx/sckstrm.h" #include "wx/sckstrm.h"
#include "wx/protocol/protocol.h" #include "wx/protocol/protocol.h"
#include "wx/protocol/ftp.h" #include "wx/protocol/ftp.h"
#include "wx/log.h"
#ifdef __BORLANDC__ #ifdef __BORLANDC__
#pragma hdrstop #pragma hdrstop
#endif #endif
// the length of FTP status code (3 digits)
static const size_t LEN_CODE = 3;
#define FTP_BSIZE 1024 #define FTP_BSIZE 1024
IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol) IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol)
@@ -53,23 +57,21 @@ IMPLEMENT_PROTOCOL(wxFTP, wxT("ftp"), wxT("ftp"), TRUE)
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
wxFTP::wxFTP() wxFTP::wxFTP()
: wxProtocol() : wxProtocol()
{ {
m_lastError = wxPROTO_NOERR; m_lastError = wxPROTO_NOERR;
m_streaming = FALSE; m_streaming = FALSE;
m_user = wxT("anonymous"); m_user = wxT("anonymous");
m_passwd = wxGetUserId(); m_passwd << wxGetUserId() << wxT('@') << wxGetFullHostName();
m_passwd += wxT('@');
m_passwd += wxGetHostName();
SetNotify(0); SetNotify(0);
SetFlags(wxSOCKET_NONE); SetFlags(wxSOCKET_NONE);
} }
wxFTP::~wxFTP() wxFTP::~wxFTP()
{ {
SendCommand("QUIT", '2'); Close();
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@@ -120,60 +122,160 @@ bool wxFTP::Connect(const wxString& host)
return Connect(addr); return Connect(addr);
} }
bool wxFTP::Close() bool wxFTP::Close(bool force)
{ {
if (m_streaming) { if ( m_streaming )
m_lastError = wxPROTO_STREAMING; {
return FALSE; if ( !force )
} {
if (IsConnected()) m_lastError = wxPROTO_STREAMING;
SendCommand(wxString(wxT("QUIT")), '2'); return FALSE;
}
return wxSocketClient::Close(); (void)Abort();
}
if ( IsConnected() )
SendCommand(wxT("QUIT"), '2');
return wxSocketClient::Close();
} }
//////////////////////////////////////////////////////////////// // ============================================================================
////// wxFTP low-level methods ///////////////////////////////// // low level methods
//////////////////////////////////////////////////////////////// // ============================================================================
// ----------------------------------------------------------------------------
// Send command to FTP server
// ----------------------------------------------------------------------------
bool wxFTP::SendCommand(const wxString& command, char exp_ret) bool wxFTP::SendCommand(const wxString& command, char exp_ret)
{ {
wxString tmp_str; wxString tmp_str;
if (m_streaming) { if (m_streaming)
m_lastError = wxPROTO_STREAMING; {
return FALSE; m_lastError = wxPROTO_STREAMING;
} return FALSE;
tmp_str = command + wxT("\r\n"); }
const wxWX2MBbuf tmp_buf = tmp_str.mb_str();
if (Write(wxMBSTRINGCAST tmp_buf, strlen(tmp_buf)).Error()) { tmp_str = command + wxT("\r\n");
m_lastError = wxPROTO_NETERR; const wxWX2MBbuf tmp_buf = tmp_str.mb_str();
return FALSE; if ( Write(wxMBSTRINGCAST tmp_buf, strlen(tmp_buf)).Error())
} {
return GetResult(exp_ret); m_lastError = wxPROTO_NETERR;
return FALSE;
}
wxLogTrace(_T("ftp"), _T("==> %s"), command.c_str());
return GetResult(exp_ret);
} }
// ----------------------------------------------------------------------------
// Recieve servers reply
// ----------------------------------------------------------------------------
bool wxFTP::GetResult(char exp) bool wxFTP::GetResult(char exp)
{ {
m_lastError = GetLine(this, m_lastResult); wxString code;
if ( m_lastError )
return FALSE;
if (m_lastResult.GetChar(0) != exp) {
m_lastError = wxPROTO_PROTERR;
return FALSE;
}
if (m_lastResult.GetChar(3) == '-') { // we handle multiline replies here according to RFC 959: it says that a
wxString key = m_lastResult.Left((size_t)3); // reply may either be on 1 line of the form "xyz ..." or on several lines
// in whuch case it looks like
// xyz-...
// ...
// xyz ...
// and the intermeidate lines may start with xyz or not
bool badReply = FALSE;
bool firstLine = TRUE;
bool endOfReply = FALSE;
while ( !endOfReply && !badReply )
{
m_lastError = ReadLine(m_lastResult);
if ( m_lastError )
return FALSE;
key += wxT(' '); // unless this is an intermediate line of a multiline reply, it must
// contain the code in the beginning and '-' or ' ' following it
if ( m_lastResult.Len() < LEN_CODE + 1 )
{
if ( firstLine )
{
badReply = TRUE;
}
else
{
wxLogTrace(_T("ftp"), _T("<== %s %s"),
code.c_str(), m_lastResult.c_str());
}
}
else // line has at least 4 chars
{
// this is the char which tells us what we're dealing with
wxChar chMarker = m_lastResult.GetChar(LEN_CODE);
if ( firstLine )
{
code = wxString(m_lastResult, LEN_CODE);
wxLogTrace(_T("ftp"), _T("<== %s %s"),
code.c_str(), m_lastResult.c_str() + LEN_CODE + 1);
switch ( chMarker )
{
case _T(' '):
endOfReply = TRUE;
break;
case _T('-'):
firstLine = FALSE;
break;
default:
// unexpected
badReply = TRUE;
}
}
else // subsequent line of multiline reply
{
if ( wxStrncmp(m_lastResult, code, LEN_CODE) == 0 )
{
if ( chMarker == _T(' ') )
{
endOfReply = TRUE;
}
wxLogTrace(_T("ftp"), _T("<== %s %s"),
code.c_str(), m_lastResult.c_str() + LEN_CODE + 1);
}
else
{
// just part of reply
wxLogTrace(_T("ftp"), _T("<== %s %s"),
code.c_str(), m_lastResult.c_str());
}
}
}
}
if ( badReply )
{
wxLogDebug(_T("Broken FTP server: '%s' is not a valid reply."),
m_lastResult.c_str());
m_lastError = wxPROTO_PROTERR;
while (m_lastResult.Index(key) != 0) {
m_lastError = GetLine(this, m_lastResult);
if ( m_lastError )
return FALSE; return FALSE;
} }
}
return TRUE; if ( code.GetChar(0) != exp )
{
m_lastError = wxPROTO_PROTERR;
return FALSE;
}
return TRUE;
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@@ -204,15 +306,45 @@ bool wxFTP::RmDir(const wxString& dir)
wxString wxFTP::Pwd() wxString wxFTP::Pwd()
{ {
int beg, end; wxString path;
if (!SendCommand(wxT("PWD"), '2')) if ( SendCommand(wxT("PWD"), '2') )
return wxString((char *)NULL); {
// the result is at least that long if SendCommand() succeeded
beg = m_lastResult.Find(wxT('\"'),FALSE); const wxChar *p = m_lastResult.c_str() + LEN_CODE + 1;
end = m_lastResult.Find(wxT('\"'),TRUE); if ( *p != _T('"') )
{
wxLogDebug(_T("Missing starting quote in reply for PWD: %s"), p);
}
else
{
for ( p++; *p; p++ )
{
if ( *p == _T('"') )
{
// check if the quote is doubled
p++;
if ( !*p || *p != _T('"') )
{
// no, this is the end
break;
}
//else: yes, it is: this is an embedded quote in the
// filename, treat as normal char
}
return wxString(beg+1, end); path += *p;
}
if ( !*p )
{
wxLogDebug(_T("Missing ending quote in reply for PWD: %s"),
m_lastResult.c_str() + LEN_CODE + 1);
}
}
}
return path;
} }
bool wxFTP::Rename(const wxString& src, const wxString& dst) bool wxFTP::Rename(const wxString& src, const wxString& dst)
@@ -312,12 +444,16 @@ wxSocketClient *wxFTP::GetPort()
return client; return client;
} }
bool wxFTP::Abort(void) bool wxFTP::Abort()
{ {
m_streaming = FALSE; if ( !m_streaming )
if (!SendCommand(wxT("ABOR"), '4')) return TRUE;
return FALSE;
return GetResult('2'); m_streaming = FALSE;
if ( !SendCommand(wxT("ABOR"), '4') )
return FALSE;
return GetResult('2');
} }
wxInputStream *wxFTP::GetInputStream(const wxString& path) wxInputStream *wxFTP::GetInputStream(const wxString& path)
@@ -369,6 +505,42 @@ wxOutputStream *wxFTP::GetOutputStream(const wxString& path)
return new wxOutputFTPStream(this, sock); return new wxOutputFTPStream(this, sock);
} }
bool wxFTP::GetList(wxArrayString& files, const wxString& wildcard)
{
wxSocketBase *sock = GetPort();
if ( !sock )
{
return FALSE;
}
wxString line = _T("NLST");
if ( !!wildcard )
{
// notice that there is no space here
line += wildcard;
}
if ( !SendCommand(line, '1') )
{
return FALSE;
}
files.Empty();
while ( ReadLine(sock, line) == wxPROTO_NOERR )
{
files.Add(line);
}
delete sock;
// the file list should be terminated by "226 Transfer complete""
if ( !GetResult('2') )
return FALSE;
return TRUE;
}
wxList *wxFTP::GetList(const wxString& wildcard) wxList *wxFTP::GetList(const wxString& wildcard)
{ {
wxList *file_list = new wxList; wxList *file_list = new wxList;

View File

@@ -82,6 +82,56 @@ bool wxProtocol::Reconnect()
return TRUE; return TRUE;
} }
// ----------------------------------------------------------------------------
// Read a line from socket
// ----------------------------------------------------------------------------
// TODO ReadLine() should use buffers private to wxProtocol for efficiency!
// static
wxProtocolError wxProtocol::ReadLine(wxSocketBase *socket, wxString& result)
{
result.Empty();
char ch, chLast = '\0';
while ( !socket->Read(&ch, sizeof(ch)).Error() )
{
switch ( ch )
{
case '\r':
// remember it, if the following is '\n', we're done
chLast = '\r';
break;
case '\n':
// only ends line if the previous character was '\r'
if ( chLast == '\r' )
{
// EOL found
return wxPROTO_NOERR;
}
//else: fall through
default:
// normal char
if ( chLast )
{
result += chLast;
chLast = '\0';
}
result += ch;
}
}
return wxPROTO_NETERR;
}
wxProtocolError wxProtocol::ReadLine(wxString& result)
{
return ReadLine(this, result);
}
// old function which only chops '\n' and not '\r\n'
wxProtocolError GetLine(wxSocketBase *sock, wxString& result) { wxProtocolError GetLine(wxSocketBase *sock, wxString& result) {
#define PROTO_BSIZE 2048 #define PROTO_BSIZE 2048
size_t avail, size; size_t avail, size;

View File

@@ -1,4 +1,4 @@
# This file was automatically generated by tmake at 15:55, 2000/03/14 # This file was automatically generated by tmake at 09:19, 2000/03/15
# DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE BASE.T! # DO NOT CHANGE THIS FILE, YOUR CHANGES WILL BE LOST! CHANGE BASE.T!
ALL_SOURCES = \ ALL_SOURCES = \
common/init.cpp \ common/init.cpp \
@@ -19,7 +19,9 @@ ALL_SOURCES = \
common/fs_inet.cpp \ common/fs_inet.cpp \
common/fs_mem.cpp \ common/fs_mem.cpp \
common/fs_zip.cpp \ common/fs_zip.cpp \
common/ftp.cpp \
common/hash.cpp \ common/hash.cpp \
common/http.cpp \
common/intl.cpp \ common/intl.cpp \
common/list.cpp \ common/list.cpp \
common/log.cpp \ common/log.cpp \
@@ -30,7 +32,13 @@ ALL_SOURCES = \
common/object.cpp \ common/object.cpp \
common/objstrm.cpp \ common/objstrm.cpp \
common/process.cpp \ common/process.cpp \
common/protocol.cpp \
common/sckaddr.cpp \
common/sckfile.cpp \
common/sckipc.cpp \
common/sckstrm.cpp \
common/serbase.cpp \ common/serbase.cpp \
common/socket.cpp \
common/strconv.cpp \ common/strconv.cpp \
common/stream.cpp \ common/stream.cpp \
common/string.cpp \ common/string.cpp \
@@ -39,6 +47,7 @@ ALL_SOURCES = \
common/tokenzr.cpp \ common/tokenzr.cpp \
common/txtstrm.cpp \ common/txtstrm.cpp \
common/unzip.c \ common/unzip.c \
common/url.cpp \
common/utilscmn.cpp \ common/utilscmn.cpp \
common/variant.cpp \ common/variant.cpp \
common/wfstream.cpp \ common/wfstream.cpp \
@@ -118,6 +127,8 @@ ALL_HEADERS = \
protocol/protocol.h protocol/protocol.h
BASE_OBJS = \ BASE_OBJS = \
ipcbase.o \
gsocket.o \
init.o \ init.o \
appcmn.o \ appcmn.o \
cmdline.o \ cmdline.o \
@@ -136,7 +147,9 @@ BASE_OBJS = \
fs_inet.o \ fs_inet.o \
fs_mem.o \ fs_mem.o \
fs_zip.o \ fs_zip.o \
ftp.o \
hash.o \ hash.o \
http.o \
intl.o \ intl.o \
list.o \ list.o \
log.o \ log.o \
@@ -147,7 +160,13 @@ BASE_OBJS = \
object.o \ object.o \
objstrm.o \ objstrm.o \
process.o \ process.o \
protocol.o \
sckaddr.o \
sckfile.o \
sckipc.o \
sckstrm.o \
serbase.o \ serbase.o \
socket.o \
strconv.o \ strconv.o \
stream.o \ stream.o \
string.o \ string.o \
@@ -156,6 +175,7 @@ BASE_OBJS = \
tokenzr.o \ tokenzr.o \
txtstrm.o \ txtstrm.o \
unzip.o \ unzip.o \
url.o \
utilscmn.o \ utilscmn.o \
variant.o \ variant.o \
wfstream.o \ wfstream.o \
@@ -182,7 +202,9 @@ BASE_DEPS = \
fs_inet.d \ fs_inet.d \
fs_mem.d \ fs_mem.d \
fs_zip.d \ fs_zip.d \
ftp.d \
hash.d \ hash.d \
http.d \
intl.d \ intl.d \
list.d \ list.d \
log.d \ log.d \
@@ -193,7 +215,13 @@ BASE_DEPS = \
object.d \ object.d \
objstrm.d \ objstrm.d \
process.d \ process.d \
protocol.d \
sckaddr.d \
sckfile.d \
sckipc.d \
sckstrm.d \
serbase.d \ serbase.d \
socket.d \
strconv.d \ strconv.d \
stream.d \ stream.d \
string.d \ string.d \
@@ -202,6 +230,7 @@ BASE_DEPS = \
tokenzr.d \ tokenzr.d \
txtstrm.d \ txtstrm.d \
unzip.d \ unzip.d \
url.d \
utilscmn.d \ utilscmn.d \
variant.d \ variant.d \
wfstream.d \ wfstream.d \
@@ -234,7 +263,9 @@ BASE_DEPS = \
fs_inet.d \ fs_inet.d \
fs_mem.d \ fs_mem.d \
fs_zip.d \ fs_zip.d \
ftp.d \
hash.d \ hash.d \
http.d \
intl.d \ intl.d \
list.d \ list.d \
log.d \ log.d \
@@ -245,7 +276,13 @@ BASE_DEPS = \
object.d \ object.d \
objstrm.d \ objstrm.d \
process.d \ process.d \
protocol.d \
sckaddr.d \
sckfile.d \
sckipc.d \
sckstrm.d \
serbase.d \ serbase.d \
socket.d \
strconv.d \ strconv.d \
stream.d \ stream.d \
string.d \ string.d \
@@ -254,6 +291,7 @@ BASE_DEPS = \
tokenzr.d \ tokenzr.d \
txtstrm.d \ txtstrm.d \
unzip.d \ unzip.d \
url.d \
utilscmn.d \ utilscmn.d \
variant.d \ variant.d \
wfstream.d \ wfstream.d \

View File

@@ -90,27 +90,30 @@ struct sockaddr_un {
#ifndef __GSOCKET_STANDALONE__ #ifndef __GSOCKET_STANDALONE__
# include "wx/unix/gsockunx.h"
#include "wx/unix/gsockunx.h" # include "wx/gsocket.h"
#include "wx/gsocket.h"
#else #else
# include "gsockunx.h"
#include "gsockunx.h" # include "gsocket.h"
#include "gsocket.h"
#endif /* __GSOCKET_STANDALONE__ */ #endif /* __GSOCKET_STANDALONE__ */
/* redefine some GUI-only functions to do nothing in console mode */ /* redefine some GUI-only functions to do nothing in console mode */
#if defined(wxUSE_GUI) && !wxUSE_GUI #if defined(wxUSE_GUI) && !wxUSE_GUI
#define _GSocket_GUI_Init(socket) # define _GSocket_GUI_Init(socket) (1)
#define _GSocket_GUI_Destroy(socket) # define _GSocket_GUI_Destroy(socket)
#define _GSocket_Enable_Events(socket) # define _GSocket_Enable_Events(socket)
#define _GSocket_Disable_Events(socket) # define _GSocket_Disable_Events(socket)
#define _GSocket_Install_Callback(socket, event) # define _GSocket_Install_Callback(socket, event)
#define _GSocket_Uninstall_Callback(socket, event) # define _GSocket_Uninstall_Callback(socket, event)
#endif /* wxUSE_GUI */ #endif /* wxUSE_GUI */
/* debugging helpers */
#ifdef __GSOCKET_DEBUG__
#define GSocket_Debug(args) printf args
#else
#define GSocket_Debug(args)
#endif // __GSOCKET_DEBUG__
/* Global initialisers */ /* Global initialisers */
bool GSocket_Init(void) bool GSocket_Init(void)
@@ -126,7 +129,7 @@ void GSocket_Cleanup(void)
GSocket *GSocket_new(void) GSocket *GSocket_new(void)
{ {
int i; int i, success;
GSocket *socket; GSocket *socket;
socket = (GSocket *)malloc(sizeof(GSocket)); socket = (GSocket *)malloc(sizeof(GSocket));
@@ -152,7 +155,8 @@ GSocket *GSocket_new(void)
socket->m_establishing = FALSE; socket->m_establishing = FALSE;
/* Per-socket GUI-specific initialization */ /* Per-socket GUI-specific initialization */
if (!_GSocket_GUI_Init(socket)) success = _GSocket_GUI_Init(socket);
if (!success)
{ {
free(socket); free(socket);
return NULL; return NULL;
@@ -719,7 +723,7 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size)
assert(socket != NULL); assert(socket != NULL);
printf( "GSocket_Write #1, size %d\n", size ); GSocket_Debug(( "GSocket_Write #1, size %d\n", size ));
if (socket->m_fd == -1 || socket->m_server) if (socket->m_fd == -1 || socket->m_server)
{ {
@@ -727,13 +731,13 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size)
return -1; return -1;
} }
printf( "GSocket_Write #2, size %d\n", size ); GSocket_Debug(( "GSocket_Write #2, size %d\n", size ));
/* If the socket is blocking, wait for writability (with a timeout) */ /* If the socket is blocking, wait for writability (with a timeout) */
if (_GSocket_Output_Timeout(socket) == GSOCK_TIMEDOUT) if (_GSocket_Output_Timeout(socket) == GSOCK_TIMEDOUT)
return -1; return -1;
printf( "GSocket_Write #3, size %d\n", size ); GSocket_Debug(( "GSocket_Write #3, size %d\n", size ));
/* Write the data */ /* Write the data */
if (socket->m_stream) if (socket->m_stream)
@@ -741,19 +745,19 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size)
else else
ret = _GSocket_Send_Dgram(socket, buffer, size); ret = _GSocket_Send_Dgram(socket, buffer, size);
printf( "GSocket_Write #4, size %d\n", size ); GSocket_Debug(( "GSocket_Write #4, size %d\n", size ));
if (ret == -1) if (ret == -1)
{ {
if (errno == EWOULDBLOCK) if (errno == EWOULDBLOCK)
{ {
socket->m_error = GSOCK_WOULDBLOCK; socket->m_error = GSOCK_WOULDBLOCK;
printf( "GSocket_Write error WOULDBLOCK\n" ); GSocket_Debug(( "GSocket_Write error WOULDBLOCK\n" ));
} }
else else
{ {
socket->m_error = GSOCK_IOERR; socket->m_error = GSOCK_IOERR;
printf( "GSocket_Write error IOERR\n" ); GSocket_Debug(( "GSocket_Write error IOERR\n" ));
} }
/* Only reenable OUTPUT events after an error (just like WSAAsyncSelect /* Only reenable OUTPUT events after an error (just like WSAAsyncSelect
@@ -765,7 +769,7 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size)
return -1; return -1;
} }
printf( "GSocket_Write #5, size %d ret %d\n", size, ret ); GSocket_Debug(( "GSocket_Write #5, size %d ret %d\n", size, ret ));
return ret; return ret;
} }
@@ -779,9 +783,104 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size)
*/ */
GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags) GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags)
{ {
#if defined(wxUSE_GUI) && !wxUSE_GUI
GSocketEventFlags result = 0;
fd_set readfds;
fd_set writefds;
fd_set exceptfds;
struct timeval tv;
/* Do not use a static struct, Linux can garble it */
tv.tv_sec = 0;
tv.tv_usec = 0;
assert(socket != NULL); assert(socket != NULL);
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
FD_SET(socket->m_fd, &readfds);
FD_SET(socket->m_fd, &writefds);
FD_SET(socket->m_fd, &exceptfds);
/* Check known state first */
result |= (GSOCK_CONNECTION_FLAG & socket->m_detected & flags);
result |= (GSOCK_LOST_FLAG & socket->m_detected & flags);
/* Try select now */
if (select(socket->m_fd + 1, &readfds, &writefds, &exceptfds, &tv) <= 0)
return result;
/* Check for readability */
if (FD_ISSET(socket->m_fd, &readfds))
{
char c;
if (recv(socket->m_fd, &c, 1, MSG_PEEK) > 0)
{
result |= (GSOCK_INPUT_FLAG & flags);
}
else
{
if (socket->m_server && socket->m_stream)
{
result |= (GSOCK_CONNECTION_FLAG & flags);
socket->m_detected |= GSOCK_CONNECTION_FLAG;
}
else
{
result |= (GSOCK_LOST_FLAG & flags);
socket->m_detected = GSOCK_LOST_FLAG;
}
}
}
/* Check for writability */
if (FD_ISSET(socket->m_fd, &writefds))
{
if (socket->m_establishing && !socket->m_server)
{
int error;
SOCKLEN_T len = sizeof(error);
socket->m_establishing = FALSE;
getsockopt(socket->m_fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
if (error)
{
result |= (GSOCK_LOST_FLAG & flags);
socket->m_detected = GSOCK_LOST_FLAG;
}
else
{
result |= (GSOCK_CONNECTION_FLAG & flags);
socket->m_detected |= GSOCK_CONNECTION_FLAG;
}
}
else
{
result |= (GSOCK_OUTPUT_FLAG & flags);
}
}
/* Check for exceptions and errors (is this useful in Unices?) */
if (FD_ISSET(socket->m_fd, &exceptfds))
{
result |= (GSOCK_LOST_FLAG & flags);
socket->m_establishing = FALSE;
socket->m_detected = GSOCK_LOST_FLAG;
}
return result;
#else
assert(socket != NULL);
return flags & socket->m_detected; return flags & socket->m_detected;
#endif /* !wxUSE_GUI */
} }
/* Flags */ /* Flags */
@@ -928,17 +1027,17 @@ GSocketError _GSocket_Input_Timeout(GSocket *socket)
ret = select(socket->m_fd + 1, &readfds, NULL, NULL, &tv); ret = select(socket->m_fd + 1, &readfds, NULL, NULL, &tv);
if (ret == 0) if (ret == 0)
{ {
printf( "GSocket_Input_Timeout, select returned 0\n" ); GSocket_Debug(( "GSocket_Input_Timeout, select returned 0\n" ));
socket->m_error = GSOCK_TIMEDOUT; socket->m_error = GSOCK_TIMEDOUT;
return GSOCK_TIMEDOUT; return GSOCK_TIMEDOUT;
} }
if (ret == -1) if (ret == -1)
{ {
printf( "GSocket_Input_Timeout, select returned -1\n" ); GSocket_Debug(( "GSocket_Input_Timeout, select returned -1\n" ));
if (errno == EBADF) printf( "Invalid file descriptor\n" ); if (errno == EBADF) GSocket_Debug(( "Invalid file descriptor\n" ));
if (errno == EINTR) printf( "A non blocked signal was caught\n" ); if (errno == EINTR) GSocket_Debug(( "A non blocked signal was caught\n" ));
if (errno == EINVAL) printf( "The highest number descriptor is negative\n" ); if (errno == EINVAL) GSocket_Debug(( "The highest number descriptor is negative\n" ));
if (errno == ENOMEM) printf( "Not enough memory\n" ); if (errno == ENOMEM) GSocket_Debug(( "Not enough memory\n" ));
socket->m_error = GSOCK_TIMEDOUT; socket->m_error = GSOCK_TIMEDOUT;
return GSOCK_TIMEDOUT; return GSOCK_TIMEDOUT;
} }
@@ -967,17 +1066,17 @@ GSocketError _GSocket_Output_Timeout(GSocket *socket)
ret = select(socket->m_fd + 1, NULL, &writefds, NULL, &tv); ret = select(socket->m_fd + 1, NULL, &writefds, NULL, &tv);
if (ret == 0) if (ret == 0)
{ {
printf( "GSocket_Output_Timeout, select returned 0\n" ); GSocket_Debug(( "GSocket_Output_Timeout, select returned 0\n" ));
socket->m_error = GSOCK_TIMEDOUT; socket->m_error = GSOCK_TIMEDOUT;
return GSOCK_TIMEDOUT; return GSOCK_TIMEDOUT;
} }
if (ret == -1) if (ret == -1)
{ {
printf( "GSocket_Output_Timeout, select returned -1\n" ); GSocket_Debug(( "GSocket_Output_Timeout, select returned -1\n" ));
if (errno == EBADF) printf( "Invalid file descriptor\n" ); if (errno == EBADF) GSocket_Debug(( "Invalid file descriptor\n" ));
if (errno == EINTR) printf( "A non blocked signal was caught\n" ); if (errno == EINTR) GSocket_Debug(( "A non blocked signal was caught\n" ));
if (errno == EINVAL) printf( "The highest number descriptor is negative\n" ); if (errno == EINVAL) GSocket_Debug(( "The highest number descriptor is negative\n" ));
if (errno == ENOMEM) printf( "Not enough memory\n" ); if (errno == ENOMEM) GSocket_Debug(( "Not enough memory\n" ));
socket->m_error = GSOCK_TIMEDOUT; socket->m_error = GSOCK_TIMEDOUT;
return GSOCK_TIMEDOUT; return GSOCK_TIMEDOUT;
} }
@@ -1069,26 +1168,21 @@ int _GSocket_Send_Dgram(GSocket *socket, const char *buffer, int size)
void _GSocket_Detected_Read(GSocket *socket) void _GSocket_Detected_Read(GSocket *socket)
{ {
char c; char c;
int ret;
ret = recv(socket->m_fd, &c, 1, MSG_PEEK); if (recv(socket->m_fd, &c, 1, MSG_PEEK) > 0)
if (socket->m_stream)
{
if (ret < 0 && socket->m_server)
{
CALL_CALLBACK(socket, GSOCK_CONNECTION);
return;
}
}
if (ret > 0)
{ {
CALL_CALLBACK(socket, GSOCK_INPUT); CALL_CALLBACK(socket, GSOCK_INPUT);
} }
else else
{ {
CALL_CALLBACK(socket, GSOCK_LOST); if (socket->m_server && socket->m_stream)
{
CALL_CALLBACK(socket, GSOCK_CONNECTION);
}
else
{
CALL_CALLBACK(socket, GSOCK_LOST);
}
} }
} }
@@ -1101,7 +1195,7 @@ void _GSocket_Detected_Write(GSocket *socket)
socket->m_establishing = FALSE; socket->m_establishing = FALSE;
getsockopt(socket->m_fd, SOL_SOCKET, SO_ERROR, (void*) &error, &len); getsockopt(socket->m_fd, SOL_SOCKET, SO_ERROR, (void*)&error, &len);
if (error) if (error)
{ {