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