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