* Doc updates
[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 #ifndef __MWERKS__
24 #include <memory.h>
25 #endif
26 #if defined(__WXMAC__)
27 #include "/wx/mac/macsock.h"
28 #endif
29
30 #include <stdlib.h>
31 #include "wx/string.h"
32 #include "wx/utils.h"
33 // #include "wx/data.h"
34 #define WXSOCK_INTERNAL
35 #include "wx/sckaddr.h"
36 #undef WXSOCK_INTERNAL
37 #include "wx/socket.h"
38 #include "wx/url.h"
39 #include "wx/sckstrm.h"
40 #include "wx/protocol/protocol.h"
41 #include "wx/protocol/ftp.h"
42
43 #ifdef __BORLANDC__
44 #pragma hdrstop
45 #endif
46
47 #define FTP_BSIZE 1024
48
49 #if !USE_SHARED_LIBRARY
50 IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol)
51 IMPLEMENT_PROTOCOL(wxFTP, "ftp", "ftp", TRUE)
52 #endif
53
54 ////////////////////////////////////////////////////////////////
55 ////// wxFTP constructor and destructor ////////////////////////
56 ////////////////////////////////////////////////////////////////
57
58 wxFTP::wxFTP()
59 : wxProtocol()
60 {
61 char tmp[256];
62
63 m_lastError = wxPROTO_NOERR;
64 m_streaming = FALSE;
65
66 m_user = "anonymous";
67 wxGetUserName(tmp, 256);
68 m_passwd.sprintf("%s@",tmp);
69 wxGetHostName(tmp, 256);
70 m_passwd += tmp;
71
72 SetNotify(0);
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 (!m_handler) {
86 m_lastError = wxPROTO_NOHNDLR;
87 return FALSE;
88 }
89
90 if (!wxProtocol::Connect(addr)) {
91 m_lastError = wxPROTO_NETERR;
92 return FALSE;
93 }
94
95 if (!m_user || !m_passwd) {
96 m_lastError = wxPROTO_CONNERR;
97 return FALSE;
98 }
99
100 wxString command;
101
102 if (!GetResult('2')) {
103 Close();
104 return FALSE;
105 }
106
107 command.sprintf("USER %s", (const char *)m_user);
108 if (!SendCommand(command, '3')) {
109 Close();
110 return FALSE;
111 }
112
113 command.sprintf("PASS %s", (const char *)m_passwd);
114 if (!SendCommand(command, '2')) {
115 Close();
116 return FALSE;
117 }
118
119 return TRUE;
120 }
121
122 bool wxFTP::Connect(const wxString& host)
123 {
124 wxIPV4address addr;
125 wxString my_host = host;
126
127 addr.Hostname(my_host);
128 addr.Service("ftp");
129
130 return Connect(addr);
131 }
132
133 bool wxFTP::Close()
134 {
135 if (m_streaming) {
136 m_lastError = wxPROTO_STREAMING;
137 return FALSE;
138 }
139 if (m_connected)
140 SendCommand(wxString("QUIT"), '2');
141 return wxSocketClient::Close();
142 }
143
144 ////////////////////////////////////////////////////////////////
145 ////// wxFTP low-level methods /////////////////////////////////
146 ////////////////////////////////////////////////////////////////
147 bool wxFTP::SendCommand(const wxString& command, char exp_ret)
148 {
149 wxString tmp_str;
150
151 if (m_streaming) {
152 m_lastError = wxPROTO_STREAMING;
153 return FALSE;
154 }
155 tmp_str = command + "\r\n";
156 if (Write((char *)tmp_str.GetData(), tmp_str.Length()).Error()) {
157 m_lastError = wxPROTO_NETERR;
158 return FALSE;
159 }
160 return GetResult(exp_ret);
161 }
162
163 bool wxFTP::GetResult(char exp)
164 {
165 if ((m_lastError = GetLine(this, m_lastResult)))
166 return FALSE;
167 if (m_lastResult.GetChar(0) != exp) {
168 m_lastError = wxPROTO_PROTERR;
169 return FALSE;
170 }
171
172 if (m_lastResult.GetChar(3) == '-') {
173 wxString key = m_lastResult.Left((size_t)3);
174
175 key += ' ';
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 ////////////////////////////////////////////////////////////////
188 bool wxFTP::ChDir(const wxString& dir)
189 {
190 wxString str = dir;
191
192 str.Prepend("CWD ");
193 return SendCommand(str, '2');
194 }
195
196 bool wxFTP::MkDir(const wxString& dir)
197 {
198 wxString str = dir;
199 str.Prepend("MKD ");
200 return SendCommand(str, '2');
201 }
202
203 bool wxFTP::RmDir(const wxString& dir)
204 {
205 wxString str = dir;
206
207 str.Prepend("PWD ");
208 return SendCommand(str, '2');
209 }
210
211 wxString wxFTP::Pwd()
212 {
213 int beg, end;
214
215 if (!SendCommand("PWD", '2'))
216 return wxString((char *)NULL);
217
218 beg = m_lastResult.Find('\"',FALSE);
219 end = m_lastResult.Find('\"',TRUE);
220
221 return wxString(beg+1, end);
222 }
223
224 bool wxFTP::Rename(const wxString& src, const wxString& dst)
225 {
226 wxString str;
227
228 str = "RNFR " + src;
229 if (!SendCommand(str, '3'))
230 return FALSE;
231
232 str = "RNTO " + dst;
233 return SendCommand(str, '2');
234 }
235
236 bool wxFTP::RmFile(const wxString& path)
237 {
238 wxString str;
239
240 str = "DELE ";
241 str += path;
242 return SendCommand(str, '2');
243 }
244
245 ////////////////////////////////////////////////////////////////
246 ////// wxFTP download*upload ///////////////////////////////////
247 ////////////////////////////////////////////////////////////////
248
249 class wxInputFTPStream : public wxSocketInputStream {
250 public:
251 wxFTP *m_ftp;
252
253 wxInputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock)
254 : wxSocketInputStream(*sock), m_ftp(ftp_clt) {}
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 struct sockaddr sin;
286 int a[6];
287 wxString straddr;
288 int addr_pos;
289
290 if (!SendCommand("PASV", '2'))
291 return NULL;
292
293 sin.sa_family = AF_INET;
294 addr_pos = m_lastResult.Find('(');
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 sscanf((const char *)straddr,"%d,%d,%d,%d,%d,%d",&a[2],&a[3],&a[4],&a[5],&a[0],&a[1]);
301 sin.sa_data[2] = (char)a[2];
302 sin.sa_data[3] = (char)a[3];
303 sin.sa_data[4] = (char)a[4];
304 sin.sa_data[5] = (char)a[5];
305 sin.sa_data[0] = (char)a[0];
306 sin.sa_data[1] = (char)a[1];
307
308 addr.Disassemble(&sin, sizeof(sin));
309
310 client = m_handler->CreateClient();
311 if (!client->Connect(addr)) {
312 delete client;
313 return NULL;
314 }
315 client->Notify(FALSE);
316
317 return client;
318 }
319
320 bool wxFTP::Abort(void)
321 {
322 m_streaming = FALSE;
323 if (!SendCommand("ABOR", '4'))
324 return FALSE;
325 return GetResult('2');
326 }
327
328 wxInputStream *wxFTP::GetInputStream(const wxString& path)
329 {
330 wxString tmp_str;
331 size_t calc_size;
332
333 if (!SendCommand("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 = "RETR " + path;
344 if (!SendCommand(tmp_str, '1'))
345 return NULL;
346
347 return new wxInputFTPStream(this, sock);
348 }
349
350 wxOutputStream *wxFTP::GetOutputStream(const wxString& path)
351 {
352 wxString tmp_str;
353
354 if (!SendCommand("TYPE I", '2'))
355 return NULL;
356
357 wxSocketClient *sock = GetPort();
358
359 tmp_str = "STOR " + path;
360 if (!SendCommand(tmp_str, '1'))
361 return FALSE;
362
363 return new wxOutputFTPStream(this, sock);
364 }
365
366 wxList *wxFTP::GetList(const wxString& wildcard)
367 {
368 wxList *file_list = new wxList;
369 wxSocketBase *sock = GetPort();
370 wxString tmp_str = "NLST";
371
372 if (!wildcard.IsNull())
373 tmp_str += wildcard;
374
375 if (!SendCommand(tmp_str, '1')) {
376 delete sock;
377 delete file_list;
378 return NULL;
379 }
380
381 while (GetLine(sock, tmp_str) == wxPROTO_NOERR) {
382 file_list->Append((wxObject *)(new wxString(tmp_str)));
383 }
384
385 if (!GetResult('2')) {
386 delete sock;
387 file_list->DeleteContents(TRUE);
388 delete file_list;
389 return NULL;
390 }
391
392 return file_list;
393 }