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