Added GSocket for Unix (only GTK for the moment)
[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 if ((m_lastError = GetLine(this, m_lastResult)))
162 return FALSE;
163 if (m_lastResult.GetChar(0) != exp) {
164 m_lastError = wxPROTO_PROTERR;
165 return FALSE;
166 }
167
168 if (m_lastResult.GetChar(3) == '-') {
169 wxString key = m_lastResult.Left((size_t)3);
170
171 key += _T(' ');
172
173 while (m_lastResult.Index(key) != 0) {
174 if ((m_lastError = GetLine(this, m_lastResult)))
175 return FALSE;
176 }
177 }
178 return TRUE;
179 }
180
181 ////////////////////////////////////////////////////////////////
182 ////// wxFTP low-level methods /////////////////////////////////
183 ////////////////////////////////////////////////////////////////
184 bool wxFTP::ChDir(const wxString& dir)
185 {
186 wxString str = dir;
187
188 str.Prepend(_T("CWD "));
189 return SendCommand(str, '2');
190 }
191
192 bool wxFTP::MkDir(const wxString& dir)
193 {
194 wxString str = dir;
195 str.Prepend(_T("MKD "));
196 return SendCommand(str, '2');
197 }
198
199 bool wxFTP::RmDir(const wxString& dir)
200 {
201 wxString str = dir;
202
203 str.Prepend(_T("PWD "));
204 return SendCommand(str, '2');
205 }
206
207 wxString wxFTP::Pwd()
208 {
209 int beg, end;
210
211 if (!SendCommand(_T("PWD"), '2'))
212 return wxString((char *)NULL);
213
214 beg = m_lastResult.Find(_T('\"'),FALSE);
215 end = m_lastResult.Find(_T('\"'),TRUE);
216
217 return wxString(beg+1, end);
218 }
219
220 bool wxFTP::Rename(const wxString& src, const wxString& dst)
221 {
222 wxString str;
223
224 str = _T("RNFR ") + src;
225 if (!SendCommand(str, '3'))
226 return FALSE;
227
228 str = _T("RNTO ") + dst;
229 return SendCommand(str, '2');
230 }
231
232 bool wxFTP::RmFile(const wxString& path)
233 {
234 wxString str;
235
236 str = _T("DELE ");
237 str += path;
238 return SendCommand(str, '2');
239 }
240
241 ////////////////////////////////////////////////////////////////
242 ////// wxFTP download*upload ///////////////////////////////////
243 ////////////////////////////////////////////////////////////////
244
245 class wxInputFTPStream : public wxSocketInputStream {
246 public:
247 wxFTP *m_ftp;
248 size_t m_ftpsize;
249
250 wxInputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock)
251 : wxSocketInputStream(*sock), m_ftp(ftp_clt) {}
252 size_t StreamSize() const { return m_ftpsize; }
253 virtual ~wxInputFTPStream(void)
254 {
255 if (LastError() == wxStream_NOERROR)
256 m_ftp->GetResult('2');
257 else
258 m_ftp->Abort();
259 delete m_i_socket;
260 }
261 };
262
263 class wxOutputFTPStream : public wxSocketOutputStream {
264 public:
265 wxFTP *m_ftp;
266
267 wxOutputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock)
268 : wxSocketOutputStream(*sock), m_ftp(ftp_clt) {}
269 virtual ~wxOutputFTPStream(void)
270 {
271 if (LastError() != wxStream_NOERROR)
272 m_ftp->GetResult('2');
273 else
274 m_ftp->Abort();
275 delete m_o_socket;
276 }
277 };
278
279 wxSocketClient *wxFTP::GetPort()
280 {
281 wxIPV4address addr;
282 wxSocketClient *client;
283 int a[6];
284 wxString straddr;
285 int addr_pos;
286 wxUint16 port;
287 wxUint32 hostaddr;
288
289 if (!SendCommand(_T("PASV"), '2'))
290 return NULL;
291
292 addr_pos = m_lastResult.Find(_T('('));
293 if (addr_pos == -1) {
294 m_lastError = wxPROTO_PROTERR;
295 return NULL;
296 }
297 straddr = m_lastResult(addr_pos+1, m_lastResult.Length());
298 wxSscanf((const wxChar *)straddr,_T("%d,%d,%d,%d,%d,%d"),&a[2],&a[3],&a[4],&a[5],&a[0],&a[1]);
299
300 hostaddr = (wxUint16)a[5] << 24 | (wxUint16)a[4] << 16 |
301 (wxUint16)a[3] << 8 | a[2];
302 addr.Hostname(hostaddr);
303
304 port = (wxUint16)a[0] << 8 | a[1];
305 addr.Service(port);
306
307 client = new wxSocketClient();
308 if (!client->Connect(addr)) {
309 delete client;
310 return NULL;
311 }
312 client->Notify(FALSE);
313
314 return client;
315 }
316
317 bool wxFTP::Abort(void)
318 {
319 m_streaming = FALSE;
320 if (!SendCommand(_T("ABOR"), '4'))
321 return FALSE;
322 return GetResult('2');
323 }
324
325 wxInputStream *wxFTP::GetInputStream(const wxString& path)
326 {
327 wxString tmp_str;
328 int pos_size;
329 wxInputFTPStream *in_stream;
330
331 if (!SendCommand(_T("TYPE I"), '2'))
332 return NULL;
333
334 wxSocketClient *sock = GetPort();
335
336 if (!sock) {
337 m_lastError = wxPROTO_NETERR;
338 return NULL;
339 }
340
341 tmp_str = _T("RETR ") + path;
342 if (!SendCommand(tmp_str, '1'))
343 return NULL;
344
345 in_stream = new wxInputFTPStream(this, sock);
346
347 pos_size = m_lastResult.Index(_T('('));
348 if (pos_size != wxNOT_FOUND) {
349 wxString str_size = m_lastResult(pos_size+1, m_lastResult.Index(_T(')'))-1);
350
351 in_stream->m_ftpsize = wxAtoi(WXSTRINGCAST str_size);
352 }
353 sock->SetFlags(WAITALL);
354
355 return in_stream;
356 }
357
358 wxOutputStream *wxFTP::GetOutputStream(const wxString& path)
359 {
360 wxString tmp_str;
361
362 if (!SendCommand(_T("TYPE I"), '2'))
363 return NULL;
364
365 wxSocketClient *sock = GetPort();
366
367 tmp_str = _T("STOR ") + path;
368 if (!SendCommand(tmp_str, '1'))
369 return FALSE;
370
371 return new wxOutputFTPStream(this, sock);
372 }
373
374 wxList *wxFTP::GetList(const wxString& wildcard)
375 {
376 wxList *file_list = new wxList;
377 wxSocketBase *sock = GetPort();
378 wxString tmp_str = _T("NLST");
379
380 if (!wildcard.IsNull())
381 tmp_str += wildcard;
382
383 if (!SendCommand(tmp_str, '1')) {
384 delete sock;
385 delete file_list;
386 return NULL;
387 }
388
389 while (GetLine(sock, tmp_str) == wxPROTO_NOERR) {
390 file_list->Append((wxObject *)(new wxString(tmp_str)));
391 }
392
393 if (!GetResult('2')) {
394 delete sock;
395 file_list->DeleteContents(TRUE);
396 delete file_list;
397 return NULL;
398 }
399
400 return file_list;
401 }
402 #endif
403 // wxUSE_SOCKETS