]> git.saurik.com Git - wxWidgets.git/blame - src/common/ftp.cpp
tree ctrl sorting shouldn't crash when items don't have data
[wxWidgets.git] / src / common / ftp.cpp
CommitLineData
f4ada568
GL
1/////////////////////////////////////////////////////////////////////////////
2// Name: ftp.cpp
3// Purpose: FTP protocol
4// Author: Guilhem Lavaux
5// Modified by:
6// Created: 07/07/1997
7// RCS-ID: $Id$
8// Copyright: (c) 1997, 1998 Guilhem Lavaux
9// Licence: wxWindows license
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "ftp.h"
14#endif
ec45f8ee
UU
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19ae5cf0
UU
19#ifdef __BORLANDC__
20#pragma hdrstop
21#endif
22
35a4dab7
GL
23#if wxUSE_SOCKETS
24
469e1e5c 25#ifndef __MWERKS__
f4ada568 26#include <memory.h>
469e1e5c 27#endif
17dff81c
SC
28#if defined(__WXMAC__)
29#include "/wx/mac/macsock.h"
30#endif
31
f4ada568
GL
32#include <stdlib.h>
33#include "wx/string.h"
34#include "wx/utils.h"
35// #include "wx/data.h"
36#define WXSOCK_INTERNAL
37#include "wx/sckaddr.h"
38#undef WXSOCK_INTERNAL
39#include "wx/socket.h"
40#include "wx/url.h"
41#include "wx/sckstrm.h"
42#include "wx/protocol/protocol.h"
43#include "wx/protocol/ftp.h"
44
45#ifdef __BORLANDC__
46#pragma hdrstop
47#endif
48
49#define FTP_BSIZE 1024
50
51#if !USE_SHARED_LIBRARY
52IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol)
4846abaf 53IMPLEMENT_PROTOCOL(wxFTP, _T("ftp"), _T("ftp"), TRUE)
f4ada568
GL
54#endif
55
56////////////////////////////////////////////////////////////////
57////// wxFTP constructor and destructor ////////////////////////
58////////////////////////////////////////////////////////////////
59
60wxFTP::wxFTP()
61 : wxProtocol()
62{
f4ada568
GL
63 m_lastError = wxPROTO_NOERR;
64 m_streaming = FALSE;
65
4846abaf 66 m_user = _T("anonymous");
a737331d
GL
67 m_passwd = wxGetUserId();
68 m_passwd += '@';
69 m_passwd += wxGetHostName();
f4ada568
GL
70
71 SetNotify(0);
72}
73
74wxFTP::~wxFTP()
75{
76 SendCommand("QUIT", '2');
77}
78
79////////////////////////////////////////////////////////////////
80////// wxFTP connect and login methods /////////////////////////
81////////////////////////////////////////////////////////////////
8a2c6ef8 82bool wxFTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait))
f4ada568
GL
83{
84 if (!m_handler) {
85 m_lastError = wxPROTO_NOHNDLR;
86 return FALSE;
87 }
88
89 if (!wxProtocol::Connect(addr)) {
90 m_lastError = wxPROTO_NETERR;
91 return FALSE;
92 }
93
94 if (!m_user || !m_passwd) {
95 m_lastError = wxPROTO_CONNERR;
96 return FALSE;
97 }
98
99 wxString command;
100
101 if (!GetResult('2')) {
102 Close();
103 return FALSE;
104 }
105
4846abaf 106 command.sprintf(_T("USER %s"), (const wxChar *)m_user);
f4ada568
GL
107 if (!SendCommand(command, '3')) {
108 Close();
109 return FALSE;
110 }
111
4846abaf 112 command.sprintf(_T("PASS %s"), (const wxChar *)m_passwd);
f4ada568
GL
113 if (!SendCommand(command, '2')) {
114 Close();
115 return FALSE;
116 }
117
118 return TRUE;
119}
120
121bool wxFTP::Connect(const wxString& host)
122{
123 wxIPV4address addr;
124 wxString my_host = host;
125
126 addr.Hostname(my_host);
4846abaf 127 addr.Service(_T("ftp"));
f4ada568
GL
128
129 return Connect(addr);
130}
131
132bool wxFTP::Close()
133{
134 if (m_streaming) {
135 m_lastError = wxPROTO_STREAMING;
136 return FALSE;
137 }
138 if (m_connected)
4846abaf 139 SendCommand(wxString(_T("QUIT")), '2');
f4ada568
GL
140 return wxSocketClient::Close();
141}
142
143////////////////////////////////////////////////////////////////
144////// wxFTP low-level methods /////////////////////////////////
145////////////////////////////////////////////////////////////////
146bool wxFTP::SendCommand(const wxString& command, char exp_ret)
147{
148 wxString tmp_str;
149
150 if (m_streaming) {
151 m_lastError = wxPROTO_STREAMING;
152 return FALSE;
153 }
4846abaf 154 tmp_str = command + _T("\r\n");
fde7d98e 155 const wxWX2MBbuf tmp_buf = tmp_str.mb_str();
4846abaf 156 if (Write(MBSTRINGCAST tmp_buf, strlen(tmp_buf)).Error()) {
f4ada568
GL
157 m_lastError = wxPROTO_NETERR;
158 return FALSE;
159 }
160 return GetResult(exp_ret);
161}
162
163bool wxFTP::GetResult(char exp)
164{
165 if ((m_lastError = GetLine(this, m_lastResult)))
166 return FALSE;
4b5f3fe6 167 if (m_lastResult.GetChar(0) != exp) {
f4ada568
GL
168 m_lastError = wxPROTO_PROTERR;
169 return FALSE;
170 }
171
4b5f3fe6 172 if (m_lastResult.GetChar(3) == '-') {
f4ada568
GL
173 wxString key = m_lastResult.Left((size_t)3);
174
4846abaf 175 key += _T(' ');
f4ada568
GL
176
177 while (m_lastResult.Index(key) != 0) {
178 if ((m_lastError = GetLine(this, m_lastResult)))
179 return FALSE;
180 }
181 }
182 return TRUE;
183}
184
185////////////////////////////////////////////////////////////////
186////// wxFTP low-level methods /////////////////////////////////
187////////////////////////////////////////////////////////////////
188bool wxFTP::ChDir(const wxString& dir)
189{
190 wxString str = dir;
191
4846abaf 192 str.Prepend(_T("CWD "));
f4ada568
GL
193 return SendCommand(str, '2');
194}
195
196bool wxFTP::MkDir(const wxString& dir)
197{
198 wxString str = dir;
4846abaf 199 str.Prepend(_T("MKD "));
f4ada568
GL
200 return SendCommand(str, '2');
201}
202
203bool wxFTP::RmDir(const wxString& dir)
204{
205 wxString str = dir;
206
4846abaf 207 str.Prepend(_T("PWD "));
f4ada568
GL
208 return SendCommand(str, '2');
209}
210
211wxString wxFTP::Pwd()
212{
213 int beg, end;
214
4846abaf 215 if (!SendCommand(_T("PWD"), '2'))
f4ada568
GL
216 return wxString((char *)NULL);
217
4846abaf
OK
218 beg = m_lastResult.Find(_T('\"'),FALSE);
219 end = m_lastResult.Find(_T('\"'),TRUE);
f4ada568
GL
220
221 return wxString(beg+1, end);
222}
223
224bool wxFTP::Rename(const wxString& src, const wxString& dst)
225{
226 wxString str;
227
4846abaf 228 str = _T("RNFR ") + src;
f4ada568
GL
229 if (!SendCommand(str, '3'))
230 return FALSE;
231
4846abaf 232 str = _T("RNTO ") + dst;
f4ada568
GL
233 return SendCommand(str, '2');
234}
235
236bool wxFTP::RmFile(const wxString& path)
237{
238 wxString str;
239
4846abaf 240 str = _T("DELE ");
f4ada568
GL
241 str += path;
242 return SendCommand(str, '2');
243}
244
245////////////////////////////////////////////////////////////////
246////// wxFTP download*upload ///////////////////////////////////
247////////////////////////////////////////////////////////////////
248
249class wxInputFTPStream : public wxSocketInputStream {
250public:
251 wxFTP *m_ftp;
9a1b2c28 252 size_t m_ftpsize;
f4ada568
GL
253
254 wxInputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock)
255 : wxSocketInputStream(*sock), m_ftp(ftp_clt) {}
375abe3d 256 size_t StreamSize() const { return m_ftpsize; }
f4ada568
GL
257 virtual ~wxInputFTPStream(void)
258 {
75ed1d15 259 if (LastError() != wxStream_NOERROR)
f4ada568
GL
260 m_ftp->GetResult('2');
261 else
262 m_ftp->Abort();
263 delete m_i_socket;
264 }
265};
266
267class wxOutputFTPStream : public wxSocketOutputStream {
268public:
269 wxFTP *m_ftp;
270
271 wxOutputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock)
272 : wxSocketOutputStream(*sock), m_ftp(ftp_clt) {}
273 virtual ~wxOutputFTPStream(void)
274 {
75ed1d15 275 if (LastError() != wxStream_NOERROR)
f4ada568
GL
276 m_ftp->GetResult('2');
277 else
278 m_ftp->Abort();
279 delete m_o_socket;
280 }
281};
282
283wxSocketClient *wxFTP::GetPort()
284{
285 wxIPV4address addr;
286 wxSocketClient *client;
287 struct sockaddr sin;
288 int a[6];
289 wxString straddr;
290 int addr_pos;
291
4846abaf 292 if (!SendCommand(_T("PASV"), '2'))
f4ada568
GL
293 return NULL;
294
295 sin.sa_family = AF_INET;
4846abaf 296 addr_pos = m_lastResult.Find(_T('('));
f4ada568
GL
297 if (addr_pos == -1) {
298 m_lastError = wxPROTO_PROTERR;
299 return NULL;
300 }
301 straddr = m_lastResult(addr_pos+1, m_lastResult.Length());
4846abaf 302 wxSscanf((const wxChar *)straddr,_T("%d,%d,%d,%d,%d,%d"),&a[2],&a[3],&a[4],&a[5],&a[0],&a[1]);
f4ada568
GL
303 sin.sa_data[2] = (char)a[2];
304 sin.sa_data[3] = (char)a[3];
305 sin.sa_data[4] = (char)a[4];
306 sin.sa_data[5] = (char)a[5];
307 sin.sa_data[0] = (char)a[0];
308 sin.sa_data[1] = (char)a[1];
309
310 addr.Disassemble(&sin, sizeof(sin));
311
312 client = m_handler->CreateClient();
313 if (!client->Connect(addr)) {
314 delete client;
315 return NULL;
316 }
317 client->Notify(FALSE);
318
319 return client;
320}
321
322bool wxFTP::Abort(void)
323{
324 m_streaming = FALSE;
4846abaf 325 if (!SendCommand(_T("ABOR"), '4'))
f4ada568
GL
326 return FALSE;
327 return GetResult('2');
328}
329
330wxInputStream *wxFTP::GetInputStream(const wxString& path)
331{
332 wxString tmp_str;
9a1b2c28
GL
333 int pos_size;
334 wxInputFTPStream *in_stream;
f4ada568 335
4846abaf 336 if (!SendCommand(_T("TYPE I"), '2'))
f4ada568
GL
337 return NULL;
338
339 wxSocketClient *sock = GetPort();
340
341 if (!sock) {
342 m_lastError = wxPROTO_NETERR;
343 return NULL;
344 }
345
4846abaf 346 tmp_str = _T("RETR ") + path;
f4ada568
GL
347 if (!SendCommand(tmp_str, '1'))
348 return NULL;
349
9a1b2c28
GL
350 in_stream = new wxInputFTPStream(this, sock);
351
4846abaf 352 pos_size = m_lastResult.Index(_T('('));
9a1b2c28 353 if (pos_size != wxNOT_FOUND) {
4846abaf 354 wxString str_size = m_lastResult(pos_size+1, m_lastResult.Index(_T(')'))-1);
9a1b2c28 355
4846abaf 356 in_stream->m_ftpsize = wxAtoi(WXSTRINGCAST str_size);
9a1b2c28
GL
357 }
358
359 return in_stream;
f4ada568
GL
360}
361
362wxOutputStream *wxFTP::GetOutputStream(const wxString& path)
363{
364 wxString tmp_str;
365
4846abaf 366 if (!SendCommand(_T("TYPE I"), '2'))
f4ada568
GL
367 return NULL;
368
369 wxSocketClient *sock = GetPort();
370
4846abaf 371 tmp_str = _T("STOR ") + path;
f4ada568
GL
372 if (!SendCommand(tmp_str, '1'))
373 return FALSE;
374
375 return new wxOutputFTPStream(this, sock);
376}
377
378wxList *wxFTP::GetList(const wxString& wildcard)
379{
380 wxList *file_list = new wxList;
381 wxSocketBase *sock = GetPort();
4846abaf 382 wxString tmp_str = _T("NLST");
f4ada568
GL
383
384 if (!wildcard.IsNull())
385 tmp_str += wildcard;
386
387 if (!SendCommand(tmp_str, '1')) {
388 delete sock;
389 delete file_list;
390 return NULL;
391 }
392
393 while (GetLine(sock, tmp_str) == wxPROTO_NOERR) {
394 file_list->Append((wxObject *)(new wxString(tmp_str)));
395 }
396
397 if (!GetResult('2')) {
398 delete sock;
399 file_list->DeleteContents(TRUE);
400 delete file_list;
401 return NULL;
402 }
403
a737331d
GL
404 // Ininterresting ?!
405 /*
375abe3d
GL
406 sock->SetEventHandler(*GetNextHandler(), m_id);
407 sock->Notify(m_notifyme);
408 sock->SetNotify(m_neededreq);
a737331d 409 */
375abe3d 410
f4ada568
GL
411 return file_list;
412}
35a4dab7
GL
413#endif
414 // wxUSE_SOCKETS