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