CW Win32 support
[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 #include <stdlib.h>
27 #include "wx/string.h"
28 #include "wx/utils.h"
29 // #include "wx/data.h"
30 #define WXSOCK_INTERNAL
31 #include "wx/sckaddr.h"
32 #undef WXSOCK_INTERNAL
33 #include "wx/socket.h"
34 #include "wx/url.h"
35 #include "wx/sckstrm.h"
36 #include "wx/protocol/protocol.h"
37 #include "wx/protocol/ftp.h"
38
39 #ifdef __BORLANDC__
40 #pragma hdrstop
41 #endif
42
43 #define FTP_BSIZE 1024
44
45 #if !USE_SHARED_LIBRARY
46 IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol)
47 IMPLEMENT_PROTOCOL(wxFTP, "ftp", "ftp", TRUE)
48 #endif
49
50 ////////////////////////////////////////////////////////////////
51 ////// wxFTP constructor and destructor ////////////////////////
52 ////////////////////////////////////////////////////////////////
53
54 wxFTP::wxFTP()
55 : wxProtocol()
56 {
57 char tmp[256];
58
59 m_lastError = wxPROTO_NOERR;
60 m_streaming = FALSE;
61
62 m_user = "anonymous";
63 wxGetUserName(tmp, 256);
64 m_passwd.sprintf("%s@",tmp);
65 wxGetHostName(tmp, 256);
66 m_passwd += tmp;
67
68 SetNotify(0);
69 }
70
71 wxFTP::~wxFTP()
72 {
73 SendCommand("QUIT", '2');
74 }
75
76 ////////////////////////////////////////////////////////////////
77 ////// wxFTP connect and login methods /////////////////////////
78 ////////////////////////////////////////////////////////////////
79 bool wxFTP::Connect(wxSockAddress& addr)
80 {
81 if (!m_handler) {
82 m_lastError = wxPROTO_NOHNDLR;
83 return FALSE;
84 }
85
86 if (!wxProtocol::Connect(addr)) {
87 m_lastError = wxPROTO_NETERR;
88 return FALSE;
89 }
90
91 if (!m_user || !m_passwd) {
92 m_lastError = wxPROTO_CONNERR;
93 return FALSE;
94 }
95
96 wxString command;
97
98 if (!GetResult('2')) {
99 Close();
100 return FALSE;
101 }
102
103 command.sprintf("USER %s", (const char *)m_user);
104 if (!SendCommand(command, '3')) {
105 Close();
106 return FALSE;
107 }
108
109 command.sprintf("PASS %s", (const char *)m_passwd);
110 if (!SendCommand(command, '2')) {
111 Close();
112 return FALSE;
113 }
114
115 return TRUE;
116 }
117
118 bool wxFTP::Connect(const wxString& host)
119 {
120 wxIPV4address addr;
121 wxString my_host = host;
122
123 addr.Hostname(my_host);
124 addr.Service("ftp");
125
126 return Connect(addr);
127 }
128
129 bool wxFTP::Close()
130 {
131 if (m_streaming) {
132 m_lastError = wxPROTO_STREAMING;
133 return FALSE;
134 }
135 if (m_connected)
136 SendCommand(wxString("QUIT"), '2');
137 return wxSocketClient::Close();
138 }
139
140 ////////////////////////////////////////////////////////////////
141 ////// wxFTP low-level methods /////////////////////////////////
142 ////////////////////////////////////////////////////////////////
143 bool wxFTP::SendCommand(const wxString& command, char exp_ret)
144 {
145 wxString tmp_str;
146
147 if (m_streaming) {
148 m_lastError = wxPROTO_STREAMING;
149 return FALSE;
150 }
151 tmp_str = command + "\r\n";
152 if (Write((char *)tmp_str.GetData(), tmp_str.Length()).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 += ' ';
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("CWD ");
189 return SendCommand(str, '2');
190 }
191
192 bool wxFTP::MkDir(const wxString& dir)
193 {
194 wxString str = dir;
195 str.Prepend("MKD ");
196 return SendCommand(str, '2');
197 }
198
199 bool wxFTP::RmDir(const wxString& dir)
200 {
201 wxString str = dir;
202
203 str.Prepend("PWD ");
204 return SendCommand(str, '2');
205 }
206
207 wxString wxFTP::Pwd()
208 {
209 int beg, end;
210
211 if (!SendCommand("PWD", '2'))
212 return wxString((char *)NULL);
213
214 beg = m_lastResult.Find('\"',FALSE);
215 end = m_lastResult.Find('\"',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 = "RNFR " + src;
225 if (!SendCommand(str, '3'))
226 return FALSE;
227
228 str = "RNTO " + dst;
229 return SendCommand(str, '2');
230 }
231
232 bool wxFTP::RmFile(const wxString& path)
233 {
234 wxString str;
235
236 str = "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
249 wxInputFTPStream(wxFTP *ftp_clt, wxSocketBase *sock)
250 : wxSocketInputStream(*sock), m_ftp(ftp_clt) {}
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 struct sockaddr sin;
282 int a[6];
283 wxString straddr;
284 int addr_pos;
285
286 if (!SendCommand("PASV", '2'))
287 return NULL;
288
289 sin.sa_family = AF_INET;
290 addr_pos = m_lastResult.Find('(');
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 sscanf((const char *)straddr,"%d,%d,%d,%d,%d,%d",&a[2],&a[3],&a[4],&a[5],&a[0],&a[1]);
297 sin.sa_data[2] = (char)a[2];
298 sin.sa_data[3] = (char)a[3];
299 sin.sa_data[4] = (char)a[4];
300 sin.sa_data[5] = (char)a[5];
301 sin.sa_data[0] = (char)a[0];
302 sin.sa_data[1] = (char)a[1];
303
304 addr.Disassemble(&sin, sizeof(sin));
305
306 client = m_handler->CreateClient();
307 if (!client->Connect(addr)) {
308 delete client;
309 return NULL;
310 }
311 client->Notify(FALSE);
312
313 return client;
314 }
315
316 bool wxFTP::Abort(void)
317 {
318 m_streaming = FALSE;
319 if (!SendCommand("ABOR", '4'))
320 return FALSE;
321 return GetResult('2');
322 }
323
324 wxInputStream *wxFTP::GetInputStream(const wxString& path)
325 {
326 wxString tmp_str;
327
328 if (!SendCommand("TYPE I", '2'))
329 return NULL;
330
331 wxSocketClient *sock = GetPort();
332
333 if (!sock) {
334 m_lastError = wxPROTO_NETERR;
335 return NULL;
336 }
337
338 tmp_str = "RETR " + path;
339 if (!SendCommand(tmp_str, '1'))
340 return NULL;
341
342 return new wxInputFTPStream(this, sock);
343 }
344
345 wxOutputStream *wxFTP::GetOutputStream(const wxString& path)
346 {
347 wxString tmp_str;
348
349 if (!SendCommand("TYPE I", '2'))
350 return NULL;
351
352 wxSocketClient *sock = GetPort();
353
354 tmp_str = "STOR " + path;
355 if (!SendCommand(tmp_str, '1'))
356 return FALSE;
357
358 return new wxOutputFTPStream(this, sock);
359 }
360
361 wxList *wxFTP::GetList(const wxString& wildcard)
362 {
363 wxList *file_list = new wxList;
364 wxSocketBase *sock = GetPort();
365 wxString tmp_str = "NLST";
366
367 if (!wildcard.IsNull())
368 tmp_str += wildcard;
369
370 if (!SendCommand(tmp_str, '1')) {
371 delete sock;
372 delete file_list;
373 return NULL;
374 }
375
376 while (GetLine(sock, tmp_str) == wxPROTO_NOERR) {
377 file_list->Append((wxObject *)(new wxString(tmp_str)));
378 }
379
380 if (!GetResult('2')) {
381 delete sock;
382 file_list->DeleteContents(TRUE);
383 delete file_list;
384 return NULL;
385 }
386
387 return file_list;
388 }