Mercurial > gftp.yaz
annotate lib/rfc959.c @ 179:8d933999bba6
2003-6-14 Brian Masney <masneyb@gftp.org>
* lib/cache.c (gftp_delete_cache_entry) - fix for restoring newlines
* lib/gftp.h lib/protocols.c - added EOF flag for gftp_get_line()
* lib/gftp.h lib/pty.c - added get_pty_impl() function for each PTY
type
* src/text/gftp-text.c - after removing files, clear the cache for
that directory
author | masneyb |
---|---|
date | Sat, 14 Jun 2003 14:14:01 +0000 |
parents | aec4b4541d3a |
children | 33b394ebba68 |
rev | line source |
---|---|
1 | 1 /*****************************************************************************/ |
2 /* rfc959.c - General purpose routines for the FTP protocol (RFC 959) */ | |
122 | 3 /* Copyright (C) 1998-2003 Brian Masney <masneyb@gftp.org> */ |
1 | 4 /* */ |
5 /* This program is free software; you can redistribute it and/or modify */ | |
6 /* it under the terms of the GNU General Public License as published by */ | |
7 /* the Free Software Foundation; either version 2 of the License, or */ | |
8 /* (at your option) any later version. */ | |
9 /* */ | |
10 /* This program is distributed in the hope that it will be useful, */ | |
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ | |
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ | |
13 /* GNU General Public License for more details. */ | |
14 /* */ | |
15 /* You should have received a copy of the GNU General Public License */ | |
16 /* along with this program; if not, write to the Free Software */ | |
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */ | |
18 /*****************************************************************************/ | |
19 | |
20 #include "gftp.h" | |
33 | 21 static const char cvsid[] = "$Id$"; |
1 | 22 |
126 | 23 static gftp_textcomboedt_data gftp_proxy_type[] = { |
136 | 24 {N_("none"), "", 0}, |
25 {N_("SITE command"), "USER %pu\nPASS %pp\nSITE %hh\nUSER %hu\nPASS %hp\n", 0}, | |
26 {N_("user@host"), "USER %pu\nPASS %pp\nUSER %hu@%hh\nPASS %hp\n", 0}, | |
27 {N_("user@host:port"), "USER %hu@%hh:%ho\nPASS %hp\n", 0}, | |
28 {N_("AUTHENTICATE"), "USER %hu@%hh\nPASS %hp\nSITE AUTHENTICATE %pu\nSITE RESPONSE %pp\n", 0}, | |
29 {N_("user@host port"), "USER %hu@%hh %ho\nPASS %hp\n", 0}, | |
30 {N_("user@host NOAUTH"), "USER %hu@%hh\nPASS %hp\n", 0}, | |
31 {N_("HTTP Proxy"), "http", 0}, | |
32 {N_("Custom"), "", GFTP_TEXTCOMBOEDT_EDITABLE}, | |
126 | 33 {NULL, NULL} |
34 }; | |
35 | |
122 | 36 static gftp_config_vars config_vars[] = |
37 { | |
38 {"", N_("FTP"), gftp_option_type_notebook, NULL, NULL, 0, NULL, | |
39 GFTP_PORT_GTK, NULL}, | |
40 | |
41 {"email", N_("Email address:"), | |
42 gftp_option_type_text, "", NULL, 0, | |
43 N_("This is the password that will be used whenever you log into a remote FTP server as anonymous"), | |
44 GFTP_PORT_ALL, NULL}, | |
45 {"ftp_proxy_host", N_("Proxy hostname:"), | |
46 gftp_option_type_text, "", NULL, 0, | |
47 N_("Firewall hostname"), GFTP_PORT_ALL, NULL}, | |
48 {"ftp_proxy_port", N_("Proxy port:"), | |
49 gftp_option_type_int, GINT_TO_POINTER(21), NULL, 0, | |
50 N_("Port to connect to on the firewall"), GFTP_PORT_ALL, NULL}, | |
51 {"ftp_proxy_username", N_("Proxy username:"), | |
52 gftp_option_type_text, "", NULL, 0, | |
53 N_("Your firewall username"), GFTP_PORT_ALL, NULL}, | |
54 {"ftp_proxy_password", N_("Proxy password:"), | |
55 gftp_option_type_hidetext, "", NULL, 0, | |
56 N_("Your firewall password"), GFTP_PORT_ALL, NULL}, | |
57 {"ftp_proxy_account", N_("Proxy account:"), | |
58 gftp_option_type_text, "", NULL, 0, | |
59 N_("Your firewall account (optional)"), GFTP_PORT_ALL, NULL}, | |
60 | |
126 | 61 {"proxy_config", N_("Proxy server type:"), |
62 gftp_option_type_textcomboedt, "", gftp_proxy_type, 0, | |
149 | 63 /* xgettext:no-c-format */ |
126 | 64 N_("This specifies how your proxy server expects us to log in. You can specify a 2 character replacement string prefixed by a % that will be replaced with the proper data. The first character can be either p for proxy or h for the host of the FTP server. The second character can be u (user), p (pass), h (host), o (port) or a (account). For example, to specify the proxy user, you can you type in %pu"), |
65 GFTP_PORT_ALL, NULL}, | |
66 | |
136 | 67 {"passive_transfer", N_("Passive file transfers"), |
68 gftp_option_type_checkbox, GINT_TO_POINTER(1), NULL, 0, | |
69 N_("If this is enabled, then the remote FTP server will open up a port for the data connection. If you are behind a firewall, you will need to enable this. Generally, it is a good idea to keep this enabled unless you are connecting to an older FTP server that doesn't support this. If this is disabled, then gFTP will open up a port on the client side and the remote server will attempt to connect to it."), | |
70 GFTP_PORT_ALL, NULL}, | |
71 {"resolve_symlinks", N_("Resolve Remote Symlinks (LIST -L)"), | |
72 gftp_option_type_checkbox, GINT_TO_POINTER(1), NULL, 0, | |
73 N_("The remote FTP server will attempt to resolve symlinks in the directory listings. Generally, this is a good idea to leave enabled. The only time you will want to disable this is if the remote FTP server doesn't support the -L option to LIST"), | |
74 GFTP_PORT_ALL, NULL}, | |
75 {"ascii_transfers", N_("Transfer files in ASCII mode"), | |
76 gftp_option_type_checkbox, GINT_TO_POINTER(0), NULL, 0, | |
77 N_("If you are transfering a text file from Windows to UNIX box or vice versa, then you should enable this. Each system represents newlines differently for text files. If you are transfering from UNIX to UNIX, then it is safe to leave this off. If you are downloading binary data, you will want to disable this."), | |
78 GFTP_PORT_ALL, NULL}, | |
79 | |
122 | 80 {NULL, NULL, 0, NULL, NULL, 0, NULL, 0, NULL} |
81 }; | |
82 | |
83 | |
58 | 84 typedef struct rfc959_params_tag |
85 { | |
169 | 86 gftp_getline_buffer * datafd_rbuf, |
87 * dataconn_rbuf; | |
122 | 88 int is_ascii_transfer; |
169 | 89 int data_connection; |
58 | 90 } rfc959_parms; |
91 | |
92 | |
48 | 93 static int |
94 rfc959_read_response (gftp_request * request) | |
95 { | |
96 char tempstr[255], code[4]; | |
58 | 97 rfc959_parms * parms; |
98 ssize_t num_read; | |
48 | 99 |
84 | 100 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
101 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
169 | 102 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
48 | 103 |
104 *code = '\0'; | |
105 if (request->last_ftp_response) | |
106 { | |
107 g_free (request->last_ftp_response); | |
108 request->last_ftp_response = NULL; | |
109 } | |
110 | |
58 | 111 parms = request->protocol_data; |
112 | |
48 | 113 do |
114 { | |
169 | 115 if ((num_read = gftp_get_line (request, &parms->datafd_rbuf, tempstr, |
116 sizeof (tempstr), request->datafd)) <= 0) | |
48 | 117 break; |
58 | 118 |
48 | 119 if (isdigit ((int) *tempstr) && isdigit ((int) *(tempstr + 1)) |
120 && isdigit ((int) *(tempstr + 2))) | |
121 { | |
122 strncpy (code, tempstr, 3); | |
123 code[3] = ' '; | |
124 } | |
125 request->logging_function (gftp_logging_recv, request->user_data, | |
126 "%s\n", tempstr); | |
127 } | |
128 while (strncmp (code, tempstr, 4) != 0); | |
129 | |
58 | 130 if (num_read < 0) |
84 | 131 return ((int) num_read); |
48 | 132 |
105 | 133 request->last_ftp_response = g_strdup (tempstr); |
48 | 134 |
135 if (request->last_ftp_response[0] == '4' && | |
136 request->last_ftp_response[1] == '2') | |
137 gftp_disconnect (request); | |
138 | |
139 return (*request->last_ftp_response); | |
140 } | |
141 | |
142 | |
143 static int | |
144 rfc959_send_command (gftp_request * request, const char *command) | |
145 { | |
84 | 146 int ret; |
147 | |
148 g_return_val_if_fail (request != NULL, GFTP_EFATAL); | |
149 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
150 g_return_val_if_fail (command != NULL, GFTP_EFATAL); | |
169 | 151 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
48 | 152 |
153 if (strncmp (command, "PASS", 4) == 0) | |
154 { | |
155 request->logging_function (gftp_logging_send, request->user_data, | |
156 "PASS xxxx\n"); | |
157 } | |
158 else if (strncmp (command, "ACCT", 4) == 0) | |
159 { | |
160 request->logging_function (gftp_logging_send, request->user_data, | |
161 "ACCT xxxx\n"); | |
162 } | |
163 else | |
164 { | |
165 request->logging_function (gftp_logging_send, request->user_data, "%s", | |
166 command); | |
167 } | |
168 | |
168 | 169 if ((ret = gftp_fd_write (request, command, strlen (command), |
169 | 170 request->datafd)) < 0) |
84 | 171 return (ret); |
48 | 172 |
173 return (rfc959_read_response (request)); | |
174 } | |
175 | |
176 | |
177 static char * | |
178 parse_ftp_proxy_string (gftp_request * request) | |
179 { | |
126 | 180 char *startpos, *endpos, *newstr, *newval, tempport[6], *proxy_config, |
181 savechar; | |
182 size_t len; | |
122 | 183 int tmp; |
48 | 184 |
185 g_return_val_if_fail (request != NULL, NULL); | |
186 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, NULL); | |
1 | 187 |
122 | 188 gftp_lookup_request_option (request, "proxy_config", &proxy_config); |
126 | 189 |
190 newstr = g_malloc0 (1); | |
191 len = 0; | |
122 | 192 startpos = endpos = proxy_config; |
48 | 193 while (*endpos != '\0') |
194 { | |
195 if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'p') | |
196 { | |
197 switch (tolower ((int) *(endpos + 2))) | |
198 { | |
199 case 'u': | |
124 | 200 gftp_lookup_request_option (request, "ftp_proxy_username", &newval); |
48 | 201 break; |
202 case 'p': | |
124 | 203 gftp_lookup_request_option (request, "ftp_proxy_password", &newval); |
48 | 204 break; |
205 case 'h': | |
124 | 206 gftp_lookup_request_option (request, "ftp_proxy_host", &newval); |
48 | 207 break; |
208 case 'o': | |
124 | 209 gftp_lookup_request_option (request, "ftp_proxy_port", &tmp); |
126 | 210 g_snprintf (tempport, sizeof (tempport), "%d", tmp); |
48 | 211 newval = tempport; |
212 break; | |
213 case 'a': | |
124 | 214 gftp_lookup_request_option (request, "ftp_proxy_account", &newval); |
48 | 215 break; |
216 default: | |
217 endpos++; | |
218 continue; | |
219 } | |
220 } | |
221 else if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'h') | |
222 { | |
223 switch (tolower ((int) *(endpos + 2))) | |
224 { | |
225 case 'u': | |
226 newval = request->username; | |
227 break; | |
228 case 'p': | |
229 newval = request->password; | |
230 break; | |
231 case 'h': | |
232 newval = request->hostname; | |
233 break; | |
234 case 'o': | |
126 | 235 g_snprintf (tempport, sizeof (tempport), "%d", request->port); |
48 | 236 newval = tempport; |
237 break; | |
238 case 'a': | |
239 newval = request->account; | |
240 break; | |
241 default: | |
242 endpos++; | |
243 continue; | |
244 } | |
245 } | |
246 else if (*endpos == '%' && tolower ((int) *(endpos + 1)) == 'n') | |
247 { | |
126 | 248 savechar = *endpos; |
249 *endpos = '\0'; | |
250 | |
251 len += strlen (startpos) + 2; | |
252 newstr = g_realloc (newstr, sizeof (char) * (len + 1)); | |
253 strcat (newstr, startpos); | |
254 strcat (newstr, "\r\n"); | |
255 | |
256 *endpos = savechar; | |
48 | 257 endpos += 2; |
258 startpos = endpos; | |
259 continue; | |
260 } | |
261 else | |
262 { | |
263 endpos++; | |
264 continue; | |
265 } | |
1 | 266 |
126 | 267 savechar = *endpos; |
48 | 268 *endpos = '\0'; |
126 | 269 len += strlen (startpos); |
48 | 270 if (!newval) |
126 | 271 { |
272 newstr = g_realloc (newstr, sizeof (char) * (len + 1)); | |
273 strcat (newstr, startpos); | |
274 } | |
48 | 275 else |
126 | 276 { |
277 len += strlen (newval); | |
278 newstr = g_realloc (newstr, sizeof (char) * (len + 1)); | |
279 strcat (newstr, startpos); | |
280 strcat (newstr, newval); | |
281 } | |
282 | |
283 *endpos = savechar; | |
48 | 284 endpos += 3; |
285 startpos = endpos; | |
286 } | |
126 | 287 |
48 | 288 return (newstr); |
289 } | |
290 | |
291 | |
292 static int | |
58 | 293 rfc959_getcwd (gftp_request * request) |
294 { | |
295 char *pos, *dir; | |
296 int ret; | |
297 | |
298 ret = rfc959_send_command (request, "PWD\r\n"); | |
299 if (ret < 0) | |
84 | 300 return (ret); |
58 | 301 else if (ret != '2') |
302 { | |
303 request->logging_function (gftp_logging_error, request->user_data, | |
304 _("Received invalid response to PWD command: '%s'\n"), | |
305 request->last_ftp_response); | |
306 gftp_disconnect (request); | |
84 | 307 return (GFTP_ERETRYABLE); |
58 | 308 } |
309 | |
310 if ((pos = strchr (request->last_ftp_response, '"')) == NULL) | |
311 { | |
312 request->logging_function (gftp_logging_error, request->user_data, | |
313 _("Received invalid response to PWD command: '%s'\n"), | |
314 request->last_ftp_response); | |
315 gftp_disconnect (request); | |
84 | 316 return (GFTP_EFATAL); |
58 | 317 } |
318 | |
319 dir = pos + 1; | |
320 | |
321 if ((pos = strchr (dir, '"')) == NULL) | |
322 { | |
323 request->logging_function (gftp_logging_error, request->user_data, | |
324 _("Received invalid response to PWD command: '%s'\n"), | |
325 request->last_ftp_response); | |
326 gftp_disconnect (request); | |
84 | 327 return (GFTP_EFATAL); |
58 | 328 } |
329 | |
330 *pos = '\0'; | |
331 | |
332 if (request->directory) | |
333 g_free (request->directory); | |
334 | |
105 | 335 request->directory = g_strdup (dir); |
58 | 336 return (0); |
337 } | |
338 | |
339 | |
340 static int | |
48 | 341 rfc959_chdir (gftp_request * request, const char *directory) |
342 { | |
58 | 343 char ret, *tempstr; |
84 | 344 int r; |
48 | 345 |
84 | 346 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
347 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
348 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
48 | 349 |
350 if (strcmp (directory, "..") == 0) | |
351 ret = rfc959_send_command (request, "CDUP\r\n"); | |
352 else | |
353 { | |
354 tempstr = g_strconcat ("CWD ", directory, "\r\n", NULL); | |
355 ret = rfc959_send_command (request, tempstr); | |
356 g_free (tempstr); | |
357 } | |
358 | |
359 if (ret != '2') | |
84 | 360 return (GFTP_ERETRYABLE); |
48 | 361 |
362 if (directory != request->directory) | |
363 { | |
84 | 364 if ((r = rfc959_getcwd (request)) < 0) |
365 return (r); | |
48 | 366 } |
367 | |
368 return (0); | |
1 | 369 } |
370 | |
371 | |
372 static int | |
91 | 373 rfc959_syst (gftp_request * request) |
374 { | |
375 char *stpos, *endpos; | |
376 int ret; | |
377 | |
378 g_return_val_if_fail (request != NULL, GFTP_EFATAL); | |
379 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
169 | 380 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
91 | 381 |
382 ret = rfc959_send_command (request, "SYST\r\n"); | |
383 | |
384 if (ret < 0) | |
385 return (ret); | |
386 else if (ret != '2') | |
387 return (GFTP_ERETRYABLE); | |
388 | |
389 if ((stpos = strchr (request->last_ftp_response, ' ')) == NULL) | |
390 return (GFTP_ERETRYABLE); | |
391 | |
114 | 392 stpos++; |
393 | |
91 | 394 if ((endpos = strchr (stpos, ' ')) == NULL) |
395 return (GFTP_ERETRYABLE); | |
396 | |
397 *endpos = '\0'; | |
398 if (strcmp (stpos, "UNIX") == 0) | |
122 | 399 request->server_type = GFTP_DIRTYPE_UNIX; |
107 | 400 else if (strcmp (stpos, "VMS") == 0) |
122 | 401 request->server_type = GFTP_DIRTYPE_VMS; |
136 | 402 else if (strcmp (stpos, "CRAY") == 0) |
403 request->server_type = GFTP_DIRTYPE_CRAY; | |
91 | 404 else |
122 | 405 request->server_type = GFTP_DIRTYPE_OTHER; |
91 | 406 |
407 return (0); | |
408 } | |
409 | |
410 | |
411 static int | |
1 | 412 rfc959_connect (gftp_request * request) |
413 { | |
122 | 414 char tempchar, *startpos, *endpos, *tempstr, *email, *proxy_hostname; |
415 int ret, resp, ascii_transfers, proxy_port; | |
416 rfc959_parms * parms; | |
1 | 417 |
84 | 418 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
419 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
420 g_return_val_if_fail (request->hostname != NULL, GFTP_EFATAL); | |
1 | 421 |
169 | 422 if (request->datafd > 0) |
58 | 423 return (0); |
424 | |
122 | 425 parms = request->protocol_data; |
426 | |
427 gftp_lookup_request_option (request, "email", &email); | |
124 | 428 gftp_lookup_request_option (request, "ftp_proxy_host", &proxy_hostname); |
429 gftp_lookup_request_option (request, "ftp_proxy_port", &proxy_port); | |
122 | 430 |
7 | 431 if (request->username == NULL || *request->username == '\0') |
432 { | |
433 gftp_set_username (request, "anonymous"); | |
122 | 434 gftp_set_password (request, email); |
7 | 435 } |
436 else if (strcasecmp (request->username, "anonymous") == 0) | |
122 | 437 gftp_set_password (request, email); |
438 | |
177 | 439 if ((ret = gftp_connect_server (request, "ftp", proxy_hostname, proxy_port)) < 0) |
440 return (ret); | |
1 | 441 |
442 /* Get the banner */ | |
84 | 443 if ((ret = rfc959_read_response (request)) != '2') |
1 | 444 { |
445 gftp_disconnect (request); | |
84 | 446 return (ret); |
1 | 447 } |
448 | |
449 /* Login the proxy server if available */ | |
450 if (request->use_proxy) | |
451 { | |
452 resp = '3'; | |
453 startpos = endpos = tempstr = parse_ftp_proxy_string (request); | |
454 while ((resp == '3' || resp == '2') && *startpos != '\0') | |
455 { | |
456 if (*endpos == '\n' || *endpos == '\0') | |
457 { | |
458 tempchar = *(endpos + 1); | |
459 if (*endpos != '\0') | |
460 *(endpos + 1) = '\0'; | |
461 if ((resp = rfc959_send_command (request, startpos)) < 0) | |
84 | 462 return (resp); |
1 | 463 if (*endpos != '\0') |
464 *(endpos + 1) = tempchar; | |
465 else | |
466 break; | |
467 startpos = endpos + 1; | |
468 } | |
469 endpos++; | |
470 } | |
471 g_free (tempstr); | |
472 } | |
473 else | |
474 { | |
475 tempstr = g_strconcat ("USER ", request->username, "\r\n", NULL); | |
476 resp = rfc959_send_command (request, tempstr); | |
477 g_free (tempstr); | |
478 if (resp < 0) | |
84 | 479 return (GFTP_ERETRYABLE); |
1 | 480 if (resp == '3') |
481 { | |
482 tempstr = g_strconcat ("PASS ", request->password, "\r\n", NULL); | |
483 resp = rfc959_send_command (request, tempstr); | |
484 g_free (tempstr); | |
485 if (resp < 0) | |
84 | 486 return (GFTP_ERETRYABLE); |
1 | 487 } |
488 if (resp == '3' && request->account) | |
489 { | |
490 tempstr = g_strconcat ("ACCT ", request->account, "\r\n", NULL); | |
491 resp = rfc959_send_command (request, tempstr); | |
492 g_free (tempstr); | |
493 if (resp < 0) | |
84 | 494 return (GFTP_ERETRYABLE); |
1 | 495 } |
496 } | |
497 | |
498 if (resp != '2') | |
499 { | |
500 gftp_disconnect (request); | |
84 | 501 return (GFTP_EFATAL); |
1 | 502 } |
503 | |
169 | 504 if ((ret = rfc959_syst (request)) < 0 && request->datafd < 0) |
91 | 505 return (ret); |
506 | |
122 | 507 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); |
508 if (ascii_transfers) | |
509 { | |
510 tempstr = "TYPE A\r\n"; | |
511 parms->is_ascii_transfer = 1; | |
512 } | |
1 | 513 else |
122 | 514 { |
515 tempstr = "TYPE I\r\n"; | |
516 parms->is_ascii_transfer = 0; | |
517 } | |
1 | 518 |
84 | 519 if ((ret = rfc959_send_command (request, tempstr)) < 0) |
520 return (ret); | |
1 | 521 |
522 ret = -1; | |
523 if (request->directory != NULL && *request->directory != '\0') | |
524 { | |
525 ret = rfc959_chdir (request, request->directory); | |
169 | 526 if (request->datafd < 0) |
84 | 527 return (ret); |
1 | 528 } |
529 | |
530 if (ret != 0) | |
531 { | |
84 | 532 if ((ret = rfc959_getcwd (request)) < 0) |
533 return (ret); | |
1 | 534 } |
535 | |
169 | 536 if (request->datafd < 0) |
84 | 537 return (GFTP_EFATAL); |
1 | 538 |
539 return (0); | |
540 } | |
541 | |
542 | |
543 static void | |
544 rfc959_disconnect (gftp_request * request) | |
545 { | |
169 | 546 rfc959_parms * parms; |
547 | |
1 | 548 g_return_if_fail (request != NULL); |
549 g_return_if_fail (request->protonum == GFTP_FTP_NUM); | |
550 | |
169 | 551 parms = request->protocol_data; |
552 | |
553 if (request->datafd > 0) | |
1 | 554 { |
555 request->logging_function (gftp_logging_misc, request->user_data, | |
556 _("Disconnecting from site %s\n"), | |
557 request->hostname); | |
169 | 558 close (request->datafd); |
559 request->datafd = -1; | |
560 } | |
561 | |
562 if (parms->data_connection > 0) | |
563 { | |
564 close (parms->data_connection); | |
565 parms->data_connection = -1; | |
1 | 566 } |
567 } | |
568 | |
569 | |
48 | 570 static int |
146 | 571 rfc959_ipv4_data_connection_new (gftp_request * request) |
48 | 572 { |
573 char *pos, *pos1, resp, *command; | |
574 struct sockaddr_in data_addr; | |
122 | 575 int i, passive_transfer; |
169 | 576 rfc959_parms * parms; |
48 | 577 size_t data_addr_len; |
578 unsigned int temp[6]; | |
579 unsigned char ad[6]; | |
580 | |
169 | 581 parms = request->protocol_data; |
582 | |
583 if ((parms->data_connection = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
48 | 584 { |
585 request->logging_function (gftp_logging_error, request->user_data, | |
586 _("Failed to create a socket: %s\n"), | |
587 g_strerror (errno)); | |
588 gftp_disconnect (request); | |
84 | 589 return (GFTP_ERETRYABLE); |
48 | 590 } |
591 | |
592 data_addr_len = sizeof (data_addr); | |
593 memset (&data_addr, 0, data_addr_len); | |
594 data_addr.sin_family = AF_INET; | |
595 | |
122 | 596 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
597 if (passive_transfer) | |
48 | 598 { |
599 if ((resp = rfc959_send_command (request, "PASV\r\n")) != '2') | |
600 { | |
169 | 601 if (request->datafd < 0) |
84 | 602 return (resp); |
48 | 603 |
122 | 604 gftp_set_request_option (request, "passive_transfer", GINT_TO_POINTER(0)); |
146 | 605 return (rfc959_ipv4_data_connection_new (request)); |
48 | 606 } |
58 | 607 |
48 | 608 pos = request->last_ftp_response + 4; |
609 while (!isdigit ((int) *pos) && *pos != '\0') | |
610 pos++; | |
58 | 611 |
48 | 612 if (*pos == '\0') |
613 { | |
58 | 614 request->logging_function (gftp_logging_error, request->user_data, |
615 _("Cannot find an IP address in PASV response '%s'\n"), | |
616 request->last_ftp_response); | |
48 | 617 gftp_disconnect (request); |
84 | 618 return (GFTP_EFATAL); |
48 | 619 } |
58 | 620 |
48 | 621 if (sscanf (pos, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2], |
622 &temp[3], &temp[4], &temp[5]) != 6) | |
623 { | |
58 | 624 request->logging_function (gftp_logging_error, request->user_data, |
625 _("Cannot find an IP address in PASV response '%s'\n"), | |
626 request->last_ftp_response); | |
48 | 627 gftp_disconnect (request); |
84 | 628 return (GFTP_EFATAL); |
48 | 629 } |
58 | 630 |
48 | 631 for (i = 0; i < 6; i++) |
632 ad[i] = (unsigned char) (temp[i] & 0xff); | |
633 | |
634 memcpy (&data_addr.sin_addr, &ad[0], 4); | |
635 memcpy (&data_addr.sin_port, &ad[4], 2); | |
169 | 636 if (connect (parms->data_connection, (struct sockaddr *) &data_addr, |
58 | 637 data_addr_len) == -1) |
48 | 638 { |
639 request->logging_function (gftp_logging_error, request->user_data, | |
640 _("Cannot create a data connection: %s\n"), | |
641 g_strerror (errno)); | |
642 gftp_disconnect (request); | |
84 | 643 return (GFTP_ERETRYABLE); |
48 | 644 } |
645 } | |
646 else | |
647 { | |
169 | 648 if (getsockname (request->datafd, (struct sockaddr *) &data_addr, |
58 | 649 &data_addr_len) == -1) |
650 { | |
651 request->logging_function (gftp_logging_error, request->user_data, | |
652 _("Cannot get socket name: %s\n"), | |
653 g_strerror (errno)); | |
654 gftp_disconnect (request); | |
84 | 655 return (GFTP_ERETRYABLE); |
58 | 656 } |
657 | |
48 | 658 data_addr.sin_port = 0; |
169 | 659 if (bind (parms->data_connection, (struct sockaddr *) &data_addr, |
58 | 660 data_addr_len) == -1) |
48 | 661 { |
662 request->logging_function (gftp_logging_error, request->user_data, | |
663 _("Cannot bind a port: %s\n"), | |
664 g_strerror (errno)); | |
665 gftp_disconnect (request); | |
84 | 666 return (GFTP_ERETRYABLE); |
48 | 667 } |
668 | |
169 | 669 if (getsockname (parms->data_connection, (struct sockaddr *) &data_addr, |
58 | 670 &data_addr_len) == -1) |
671 { | |
672 request->logging_function (gftp_logging_error, request->user_data, | |
673 _("Cannot get socket name: %s\n"), | |
674 g_strerror (errno)); | |
675 gftp_disconnect (request); | |
84 | 676 return (GFTP_ERETRYABLE); |
58 | 677 } |
678 | |
169 | 679 if (listen (parms->data_connection, 1) == -1) |
48 | 680 { |
681 request->logging_function (gftp_logging_error, request->user_data, | |
682 _("Cannot listen on port %d: %s\n"), | |
683 ntohs (data_addr.sin_port), | |
684 g_strerror (errno)); | |
685 gftp_disconnect (request); | |
84 | 686 return (GFTP_ERETRYABLE); |
48 | 687 } |
58 | 688 |
48 | 689 pos = (char *) &data_addr.sin_addr; |
690 pos1 = (char *) &data_addr.sin_port; | |
691 command = g_strdup_printf ("PORT %u,%u,%u,%u,%u,%u\r\n", | |
692 pos[0] & 0xff, pos[1] & 0xff, pos[2] & 0xff, | |
693 pos[3] & 0xff, pos1[0] & 0xff, | |
694 pos1[1] & 0xff); | |
695 resp = rfc959_send_command (request, command); | |
696 g_free (command); | |
697 if (resp != '2') | |
698 { | |
699 gftp_disconnect (request); | |
84 | 700 return (GFTP_ERETRYABLE); |
48 | 701 } |
702 } | |
703 | |
704 return (0); | |
705 } | |
706 | |
707 | |
146 | 708 #ifdef HAVE_IPV6 |
709 | |
710 static int | |
711 rfc959_ipv6_data_connection_new (gftp_request * request) | |
712 { | |
713 char *pos, resp, buf[64], *command; | |
714 struct sockaddr_in6 data_addr; | |
715 int passive_transfer; | |
716 size_t data_addr_len; | |
169 | 717 rfc959_parms * parms; |
146 | 718 unsigned int port; |
719 | |
169 | 720 parms = request->protocol_data; |
721 if ((parms->data_connection = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0) | |
146 | 722 { |
723 request->logging_function (gftp_logging_error, request->user_data, | |
724 _("Failed to create a socket: %s\n"), | |
725 g_strerror (errno)); | |
726 gftp_disconnect (request); | |
727 return (GFTP_ERETRYABLE); | |
728 } | |
729 | |
730 data_addr_len = sizeof (data_addr); | |
731 /* This condition shouldn't happen. We better check anyway... */ | |
732 if (data_addr_len != request->hostp->ai_addrlen) | |
733 { | |
734 request->logging_function (gftp_logging_error, request->user_data, | |
735 _("Error: It doesn't look like we are connected via IPv6. Aborting connection.\n")); | |
736 gftp_disconnect (request); | |
737 return (GFTP_EFATAL); | |
738 } | |
739 | |
740 memset (&data_addr, 0, data_addr_len); | |
741 data_addr.sin6_family = AF_INET6; | |
742 | |
743 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); | |
744 if (passive_transfer) | |
745 { | |
746 if ((resp = rfc959_send_command (request, "EPSV\r\n")) != '2') | |
747 { | |
169 | 748 if (request->datafd < 0) |
146 | 749 return (resp); |
750 | |
751 gftp_set_request_option (request, "passive_transfer", | |
752 GINT_TO_POINTER(0)); | |
753 return (rfc959_ipv6_data_connection_new (request)); | |
754 } | |
755 | |
756 pos = request->last_ftp_response + 4; | |
757 while (*pos != '(' && *pos != '\0') | |
758 pos++; | |
759 pos++; | |
760 | |
761 if (*pos == '\0') | |
762 { | |
763 request->logging_function (gftp_logging_error, request->user_data, | |
764 _("Invalid EPSV response '%s'\n"), | |
765 request->last_ftp_response); | |
766 gftp_disconnect (request); | |
767 return (GFTP_EFATAL); | |
768 } | |
769 | |
770 if (sscanf (pos, "|||%d|", &port) != 1) | |
771 { | |
772 request->logging_function (gftp_logging_error, request->user_data, | |
773 _("Invalid EPSV response '%s'\n"), | |
774 request->last_ftp_response); | |
775 gftp_disconnect (request); | |
776 return (GFTP_EFATAL); | |
777 } | |
778 | |
779 memcpy (&data_addr, request->hostp->ai_addr, data_addr_len); | |
780 data_addr.sin6_port = htons (port); | |
781 | |
169 | 782 if (connect (parms->data_connection, (struct sockaddr *) &data_addr, |
146 | 783 data_addr_len) == -1) |
784 { | |
785 request->logging_function (gftp_logging_error, request->user_data, | |
786 _("Cannot create a data connection: %s\n"), | |
787 g_strerror (errno)); | |
788 gftp_disconnect (request); | |
789 return (GFTP_ERETRYABLE); | |
790 } | |
791 } | |
792 else | |
793 { | |
794 memcpy (&data_addr, request->hostp->ai_addr, data_addr_len); | |
795 data_addr.sin6_port = 0; | |
796 | |
169 | 797 if (bind (parms->data_connection, (struct sockaddr *) &data_addr, |
146 | 798 data_addr_len) == -1) |
799 { | |
800 request->logging_function (gftp_logging_error, request->user_data, | |
801 _("Cannot bind a port: %s\n"), | |
802 g_strerror (errno)); | |
803 gftp_disconnect (request); | |
804 return (GFTP_ERETRYABLE); | |
805 } | |
806 | |
169 | 807 if (getsockname (parms->data_connection, (struct sockaddr *) &data_addr, |
146 | 808 &data_addr_len) == -1) |
809 { | |
810 request->logging_function (gftp_logging_error, request->user_data, | |
811 _("Cannot get socket name: %s\n"), | |
812 g_strerror (errno)); | |
813 gftp_disconnect (request); | |
814 return (GFTP_ERETRYABLE); | |
815 } | |
816 | |
169 | 817 if (listen (parms->data_connection, 1) == -1) |
146 | 818 { |
819 request->logging_function (gftp_logging_error, request->user_data, | |
820 _("Cannot listen on port %d: %s\n"), | |
821 ntohs (data_addr.sin6_port), | |
822 g_strerror (errno)); | |
823 gftp_disconnect (request); | |
824 return (GFTP_ERETRYABLE); | |
825 } | |
826 | |
827 if (inet_ntop (AF_INET6, &data_addr.sin6_addr, buf, sizeof (buf)) == NULL) | |
828 { | |
829 request->logging_function (gftp_logging_error, request->user_data, | |
830 _("Cannot get address of local socket: %s\n"), | |
831 g_strerror (errno)); | |
832 gftp_disconnect (request); | |
833 return (GFTP_ERETRYABLE); | |
834 } | |
835 | |
836 command = g_strdup_printf ("EPRT |2|%s|%d|\n", buf, | |
837 ntohs (data_addr.sin6_port)); | |
838 | |
839 resp = rfc959_send_command (request, command); | |
840 g_free (command); | |
841 if (resp != '2') | |
842 { | |
843 gftp_disconnect (request); | |
844 return (GFTP_ERETRYABLE); | |
845 } | |
846 } | |
847 | |
848 return (0); | |
849 } | |
850 | |
851 #endif /* HAVE_IPV6 */ | |
852 | |
853 | |
854 static int | |
855 rfc959_data_connection_new (gftp_request * request) | |
856 { | |
857 g_return_val_if_fail (request != NULL, GFTP_EFATAL); | |
858 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
169 | 859 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
146 | 860 |
861 #ifdef HAVE_IPV6 | |
151 | 862 if (GFTP_GET_AI_FAMILY(request) == AF_INET6) |
146 | 863 return (rfc959_ipv6_data_connection_new (request)); |
864 else | |
151 | 865 return (rfc959_ipv4_data_connection_new (request)); |
866 #else | |
867 return (rfc959_ipv4_data_connection_new (request)); | |
146 | 868 #endif |
869 } | |
870 | |
871 | |
48 | 872 static int |
873 rfc959_accept_active_connection (gftp_request * request) | |
874 { | |
122 | 875 int infd, ret, passive_transfer; |
169 | 876 rfc959_parms * parms; |
146 | 877 #ifdef HAVE_IPV6 |
48 | 878 struct sockaddr_in cli_addr; |
146 | 879 #else |
880 struct sockaddr_in6 cli_addr; | |
881 #endif | |
48 | 882 size_t cli_addr_len; |
883 | |
169 | 884 parms = request->protocol_data; |
885 | |
84 | 886 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
887 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
169 | 888 g_return_val_if_fail (parms->data_connection > 0, GFTP_EFATAL); |
122 | 889 |
890 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); | |
891 g_return_val_if_fail (!passive_transfer, GFTP_EFATAL); | |
48 | 892 |
893 cli_addr_len = sizeof (cli_addr); | |
58 | 894 |
169 | 895 if ((ret = gftp_fd_set_sockblocking (request, parms->data_connection, 0)) < 0) |
84 | 896 return (ret); |
58 | 897 |
169 | 898 if ((infd = accept (parms->data_connection, (struct sockaddr *) &cli_addr, |
48 | 899 &cli_addr_len)) == -1) |
900 { | |
901 request->logging_function (gftp_logging_error, request->user_data, | |
902 _("Cannot accept connection from server: %s\n"), | |
903 g_strerror (errno)); | |
904 gftp_disconnect (request); | |
84 | 905 return (GFTP_ERETRYABLE); |
48 | 906 } |
907 | |
169 | 908 close (parms->data_connection); |
48 | 909 |
169 | 910 parms->data_connection = infd; |
911 if ((ret = gftp_fd_set_sockblocking (request, parms->data_connection, 1)) < 0) | |
84 | 912 return (ret); |
58 | 913 |
48 | 914 return (0); |
915 } | |
916 | |
917 | |
122 | 918 static int |
919 rfc959_is_ascii_transfer (const char *filename) | |
920 { | |
921 gftp_config_list_vars * tmplistvar; | |
922 gftp_file_extensions * tempext; | |
923 GList * templist; | |
924 int stlen, ret; | |
925 | |
926 gftp_lookup_global_option ("ext", &tmplistvar); | |
927 | |
928 ret = 0; | |
929 stlen = strlen (filename); | |
930 for (templist = tmplistvar->list; templist != NULL; templist = templist->next) | |
931 { | |
932 tempext = templist->data; | |
933 | |
934 if (stlen >= tempext->stlen && | |
935 strcmp (&filename[stlen - tempext->stlen], tempext->ext) == 0) | |
936 { | |
937 if (toupper (*tempext->ascii_binary == 'A')) | |
938 ret = 1; | |
939 break; | |
940 } | |
941 } | |
942 | |
943 return (ret); | |
944 } | |
945 | |
946 | |
947 static void | |
948 rfc959_set_data_type (gftp_request * request, const char *filename) | |
949 { | |
950 rfc959_parms * parms; | |
951 int new_ascii; | |
952 char *tempstr; | |
953 | |
954 g_return_if_fail (request != NULL); | |
955 g_return_if_fail (request->protonum == GFTP_FTP_NUM); | |
956 | |
957 parms = request->protocol_data; | |
958 new_ascii = rfc959_is_ascii_transfer (filename); | |
959 | |
169 | 960 if (request->datafd > 0 && new_ascii != parms->is_ascii_transfer) |
122 | 961 { |
962 if (new_ascii) | |
963 { | |
964 tempstr = "TYPE A\r\n"; | |
965 parms->is_ascii_transfer = 1; | |
966 } | |
967 else | |
968 { | |
969 tempstr = "TYPE I\r\n"; | |
970 parms->is_ascii_transfer = 1; | |
971 } | |
972 | |
973 rfc959_send_command (request, tempstr); | |
974 } | |
975 | |
976 return; | |
977 } | |
978 | |
979 | |
58 | 980 static off_t |
981 rfc959_get_file (gftp_request * request, const char *filename, int fd, | |
1 | 982 off_t startsize) |
983 { | |
984 char *command, *tempstr, resp; | |
122 | 985 int ret, passive_transfer; |
169 | 986 rfc959_parms * parms; |
1 | 987 |
84 | 988 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
989 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
990 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
169 | 991 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 992 |
169 | 993 parms = request->protocol_data; |
58 | 994 if (fd > 0) |
169 | 995 parms->data_connection = fd; |
1 | 996 |
122 | 997 rfc959_set_data_type (request, filename); |
998 | |
169 | 999 if (parms->data_connection < 0 && |
1 | 1000 (ret = rfc959_data_connection_new (request)) < 0) |
1001 return (ret); | |
1002 | |
169 | 1003 if ((ret = gftp_fd_set_sockblocking (request, parms->data_connection, 1)) < 0) |
84 | 1004 return (ret); |
1 | 1005 |
1006 if (startsize > 0) | |
1007 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1008 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1009 command = g_strdup_printf ("REST %lld\r\n", startsize); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1010 #else |
1 | 1011 command = g_strdup_printf ("REST %ld\r\n", startsize); |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1012 #endif |
1 | 1013 resp = rfc959_send_command (request, command); |
1014 g_free (command); | |
1015 | |
1016 if (resp != '3') | |
1017 { | |
169 | 1018 close (parms->data_connection); |
1019 parms->data_connection = -1; | |
84 | 1020 return (GFTP_ERETRYABLE); |
1 | 1021 } |
1022 } | |
1023 | |
1024 tempstr = g_strconcat ("RETR ", filename, "\r\n", NULL); | |
1025 ret = rfc959_send_command (request, tempstr); | |
1026 g_free (tempstr); | |
1027 | |
1028 if (ret != '1') | |
58 | 1029 { |
169 | 1030 close (parms->data_connection); |
1031 parms->data_connection = -1; | |
84 | 1032 return (GFTP_ERETRYABLE); |
58 | 1033 } |
1 | 1034 |
122 | 1035 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
1036 if (!passive_transfer && | |
1 | 1037 (ret = rfc959_accept_active_connection (request)) < 0) |
1038 return (ret); | |
1039 | |
1040 if ((tempstr = strrchr (request->last_ftp_response, '(')) == NULL) | |
1041 { | |
1042 tempstr = request->last_ftp_response + 4; | |
1043 while (!isdigit ((int) *tempstr) && *tempstr != '\0') | |
1044 tempstr++; | |
1045 } | |
1046 else | |
1047 tempstr++; | |
1048 | |
1049 return (strtol (tempstr, NULL, 10) + startsize); | |
1050 } | |
1051 | |
1052 | |
1053 static int | |
58 | 1054 rfc959_put_file (gftp_request * request, const char *filename, int fd, |
1 | 1055 off_t startsize, off_t totalsize) |
1056 { | |
1057 char *command, *tempstr, resp; | |
122 | 1058 int ret, passive_transfer; |
169 | 1059 rfc959_parms * parms; |
1 | 1060 |
84 | 1061 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1062 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1063 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
169 | 1064 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1065 |
169 | 1066 parms = request->protocol_data; |
58 | 1067 if (fd > 0) |
169 | 1068 fd = parms->data_connection; |
1 | 1069 |
122 | 1070 rfc959_set_data_type (request, filename); |
1071 | |
169 | 1072 if (parms->data_connection < 0 && |
1 | 1073 (ret = rfc959_data_connection_new (request)) < 0) |
1074 return (ret); | |
1075 | |
169 | 1076 if ((ret = gftp_fd_set_sockblocking (request, parms->data_connection, 1)) < 0) |
84 | 1077 return (ret); |
1 | 1078 |
1079 if (startsize > 0) | |
1080 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1081 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1082 command = g_strdup_printf ("REST %lld\r\n", startsize); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1083 #else |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1084 command = g_strdup_printf ("REST %ld\r\n", startsize); |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1085 #endif |
1 | 1086 resp = rfc959_send_command (request, command); |
1087 g_free (command); | |
1088 if (resp != '3') | |
1089 { | |
169 | 1090 close (parms->data_connection); |
1091 parms->data_connection = -1; | |
84 | 1092 return (GFTP_ERETRYABLE); |
1 | 1093 } |
1094 } | |
1095 | |
1096 tempstr = g_strconcat ("STOR ", filename, "\r\n", NULL); | |
1097 ret = rfc959_send_command (request, tempstr); | |
1098 g_free (tempstr); | |
1099 if (ret != '1') | |
58 | 1100 { |
169 | 1101 close (parms->data_connection); |
1102 parms->data_connection = -1; | |
84 | 1103 return (GFTP_ERETRYABLE); |
58 | 1104 } |
1 | 1105 |
122 | 1106 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
1107 if (!passive_transfer && | |
1 | 1108 (ret = rfc959_accept_active_connection (request)) < 0) |
1109 return (ret); | |
1110 | |
1111 return (0); | |
1112 } | |
1113 | |
58 | 1114 |
1 | 1115 static long |
1116 rfc959_transfer_file (gftp_request *fromreq, const char *fromfile, | |
1117 off_t fromsize, gftp_request *toreq, | |
1118 const char *tofile, off_t tosize) | |
1119 { | |
1120 char *tempstr, *pos, *endpos; | |
84 | 1121 int ret; |
1 | 1122 |
84 | 1123 g_return_val_if_fail (fromreq != NULL, GFTP_EFATAL); |
1124 g_return_val_if_fail (fromfile != NULL, GFTP_EFATAL); | |
1125 g_return_val_if_fail (toreq != NULL, GFTP_EFATAL); | |
1126 g_return_val_if_fail (tofile != NULL, GFTP_EFATAL); | |
169 | 1127 g_return_val_if_fail (fromreq->datafd > 0, GFTP_EFATAL); |
1128 g_return_val_if_fail (toreq->datafd > 0, GFTP_EFATAL); | |
1 | 1129 |
122 | 1130 gftp_set_request_option (fromreq, "passive_transfer", GINT_TO_POINTER(1)); |
1131 gftp_set_request_option (toreq, "passive_transfer", GINT_TO_POINTER(0)); | |
1 | 1132 |
84 | 1133 if ((ret = rfc959_send_command (fromreq, "PASV\r\n")) != '2') |
1134 return (ret); | |
1 | 1135 |
1136 pos = fromreq->last_ftp_response + 4; | |
1137 while (!isdigit ((int) *pos) && *pos != '\0') | |
1138 pos++; | |
1139 if (*pos == '\0') | |
84 | 1140 return (GFTP_EFATAL); |
1 | 1141 |
1142 endpos = pos; | |
1143 while (*endpos != ')' && *endpos != '\0') | |
1144 endpos++; | |
1145 if (*endpos == ')') | |
1146 *endpos = '\0'; | |
1147 | |
1148 tempstr = g_strconcat ("PORT ", pos, "\r\n", NULL); | |
84 | 1149 if ((ret = rfc959_send_command (toreq, tempstr)) != '2') |
15
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
1150 { |
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
1151 g_free (tempstr); |
84 | 1152 return (ret); |
15
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
1153 } |
1 | 1154 g_free (tempstr); |
1155 | |
1156 tempstr = g_strconcat ("RETR ", fromfile, "\r\n", NULL); | |
168 | 1157 if ((ret = gftp_fd_write (fromreq, tempstr, strlen (tempstr), |
169 | 1158 fromreq->datafd)) < 0) |
58 | 1159 { |
1160 g_free (tempstr); | |
84 | 1161 return (ret); |
58 | 1162 } |
1 | 1163 g_free (tempstr); |
1164 | |
1165 tempstr = g_strconcat ("STOR ", tofile, "\r\n", NULL); | |
168 | 1166 if ((ret = gftp_fd_write (toreq, tempstr, strlen (tempstr), |
169 | 1167 toreq->datafd)) < 0) |
58 | 1168 { |
1169 g_free (tempstr); | |
84 | 1170 return (ret); |
58 | 1171 } |
1 | 1172 g_free (tempstr); |
1173 | |
84 | 1174 if ((ret = rfc959_read_response (fromreq)) < 0) |
1175 return (ret); | |
1176 | |
1177 if ((ret = rfc959_read_response (toreq)) < 0) | |
1178 return (ret); | |
1 | 1179 |
1180 return (0); | |
1181 } | |
1182 | |
1183 | |
1184 static int | |
1185 rfc959_end_transfer (gftp_request * request) | |
1186 { | |
169 | 1187 rfc959_parms * parms; |
84 | 1188 int ret; |
1189 | |
1190 g_return_val_if_fail (request != NULL, GFTP_EFATAL); | |
1191 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
169 | 1192 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1193 |
169 | 1194 parms = request->protocol_data; |
1195 if (parms->data_connection > 0) | |
1 | 1196 { |
169 | 1197 close (parms->data_connection); |
1198 parms->data_connection = -1; | |
1 | 1199 } |
84 | 1200 |
1201 ret = rfc959_read_response (request); | |
1202 | |
1203 if (ret < 0) | |
1204 return (ret); | |
1205 else if (ret == '2') | |
1206 return (0); | |
1207 else | |
1208 return (GFTP_ERETRYABLE); | |
1 | 1209 } |
1210 | |
1211 | |
1212 static int | |
40 | 1213 rfc959_abort_transfer (gftp_request * request) |
1214 { | |
169 | 1215 rfc959_parms * parms; |
40 | 1216 int ret; |
1217 | |
84 | 1218 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1219 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
169 | 1220 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
40 | 1221 |
169 | 1222 parms = request->protocol_data; |
1223 if (parms->data_connection > 0) | |
40 | 1224 { |
169 | 1225 close (parms->data_connection); |
1226 parms->data_connection = -1; | |
40 | 1227 } |
1228 | |
1229 /* We need to read two lines of output. The first one is acknowleging | |
1230 the transfer and the second line acknowleges the ABOR command */ | |
84 | 1231 if ((ret = rfc959_send_command (request, "ABOR\r\n")) < 0) |
1232 return (ret); | |
40 | 1233 |
169 | 1234 if (request->datafd > 0) |
40 | 1235 { |
58 | 1236 if ((ret = rfc959_read_response (request)) < 0) |
40 | 1237 gftp_disconnect (request); |
1238 } | |
1239 | |
1240 return (0); | |
1241 } | |
1242 | |
1243 | |
1244 static int | |
1 | 1245 rfc959_list_files (gftp_request * request) |
1246 { | |
122 | 1247 int ret, show_hidden_files, resolve_symlinks, passive_transfer; |
1 | 1248 char *tempstr, parms[3]; |
1249 | |
84 | 1250 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1251 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
169 | 1252 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1253 |
1254 if ((ret = rfc959_data_connection_new (request)) < 0) | |
1255 return (ret); | |
1256 | |
122 | 1257 gftp_lookup_request_option (request, "show_hidden_files", &show_hidden_files); |
1258 gftp_lookup_request_option (request, "resolve_symlinks", &resolve_symlinks); | |
1259 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); | |
1260 | |
1 | 1261 *parms = '\0'; |
1262 strcat (parms, show_hidden_files ? "a" : ""); | |
1263 strcat (parms, resolve_symlinks ? "L" : ""); | |
1264 tempstr = g_strconcat ("LIST", *parms != '\0' ? " -" : "", parms, "\r\n", | |
1265 NULL); | |
1266 | |
1267 ret = rfc959_send_command (request, tempstr); | |
1268 g_free (tempstr); | |
1269 | |
1270 if (ret != '1') | |
84 | 1271 return (GFTP_ERETRYABLE); |
1 | 1272 |
1273 ret = 0; | |
122 | 1274 if (!passive_transfer) |
1 | 1275 ret = rfc959_accept_active_connection (request); |
1276 | |
1277 return (ret); | |
1278 } | |
1279 | |
1280 | |
122 | 1281 static ssize_t |
1282 rfc959_get_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1283 { | |
1284 int i, j, ascii_transfers; | |
169 | 1285 rfc959_parms * parms; |
122 | 1286 ssize_t num_read; |
1287 | |
169 | 1288 parms = request->protocol_data; |
1289 num_read = gftp_fd_read (request, buf, size, parms->data_connection); | |
122 | 1290 if (num_read < 0) |
1291 return (num_read); | |
1292 | |
1293 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); | |
1294 if (ascii_transfers) | |
1295 { | |
1296 for (i = 0, j = 0; i < num_read; i++) | |
1297 { | |
1298 if (buf[i] != '\r') | |
1299 buf[j++] = buf[i]; | |
1300 else | |
1301 num_read--; | |
1302 } | |
1303 } | |
1304 | |
1305 return (num_read); | |
1306 } | |
1307 | |
1308 | |
1309 static ssize_t | |
1310 rfc959_put_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1311 { | |
1312 int i, j, ascii_transfers; | |
169 | 1313 rfc959_parms * parms; |
122 | 1314 ssize_t num_wrote; |
1315 char *tempstr; | |
1316 size_t rsize; | |
1317 | |
1318 if (size == 0) | |
1319 return (0); | |
1320 | |
169 | 1321 parms = request->protocol_data; |
1322 | |
122 | 1323 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); |
1324 if (ascii_transfers) | |
1325 { | |
1326 rsize = 0; | |
1327 for (i = 0; i < size; i++) | |
1328 { | |
1329 rsize++; | |
1330 if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r') | |
1331 rsize++; | |
1332 } | |
1333 | |
1334 if (rsize != size) | |
1335 { | |
1336 tempstr = g_malloc (rsize); | |
1337 | |
1338 for (i = 0, j = 0; i < size; i++) | |
1339 { | |
1340 if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r') | |
1341 tempstr[j++] = '\r'; | |
1342 tempstr[j++] = buf[i]; | |
1343 } | |
1344 } | |
1345 else | |
1346 tempstr = buf; | |
1347 } | |
1348 else | |
1349 { | |
1350 rsize = size; | |
1351 tempstr = buf; | |
1352 } | |
1353 | |
169 | 1354 num_wrote = gftp_fd_write (request, tempstr, rsize, parms->data_connection); |
122 | 1355 |
1356 if (tempstr != buf) | |
1357 g_free (tempstr); | |
1358 | |
1359 return (num_wrote); | |
1360 } | |
1361 | |
1362 | |
1 | 1363 int |
58 | 1364 rfc959_get_next_file (gftp_request * request, gftp_file * fle, int fd) |
1 | 1365 { |
58 | 1366 rfc959_parms * parms; |
1 | 1367 char tempstr[255]; |
58 | 1368 ssize_t len; |
1 | 1369 |
84 | 1370 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1371 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1372 g_return_val_if_fail (fle != NULL, GFTP_EFATAL); | |
1373 g_return_val_if_fail (fd > 0, GFTP_EFATAL); | |
1 | 1374 |
1375 if (request->last_dir_entry) | |
1376 { | |
1377 g_free (request->last_dir_entry); | |
1378 request->last_dir_entry = NULL; | |
1379 } | |
58 | 1380 |
1381 parms = request->protocol_data; | |
1382 | |
169 | 1383 if (fd == request->datafd) |
1384 fd = parms->data_connection; | |
1385 | |
1 | 1386 do |
1387 { | |
169 | 1388 if ((len = gftp_get_line (request, &parms->dataconn_rbuf, |
60 | 1389 tempstr, sizeof (tempstr), fd)) <= 0) |
1 | 1390 { |
1391 gftp_file_destroy (fle); | |
58 | 1392 return ((int) len); |
1 | 1393 } |
1394 | |
91 | 1395 if (gftp_parse_ls (request, tempstr, fle) != 0) |
1 | 1396 { |
58 | 1397 if (strncmp (tempstr, "total", strlen ("total")) != 0 && |
1398 strncmp (tempstr, _("total"), strlen (_("total"))) != 0) | |
1399 request->logging_function (gftp_logging_error, request->user_data, | |
1 | 1400 _("Warning: Cannot parse listing %s\n"), |
1401 tempstr); | |
1402 gftp_file_destroy (fle); | |
1403 continue; | |
1404 } | |
1405 else | |
1406 break; | |
1407 } | |
1408 while (1); | |
1409 | |
1410 len = strlen (tempstr); | |
1411 if (!request->cached) | |
1412 { | |
60 | 1413 request->last_dir_entry = g_strdup_printf ("%s\n", tempstr); |
168 | 1414 request->last_dir_entry_len = strlen (tempstr) + 1; |
1 | 1415 } |
1416 return (len); | |
1417 } | |
1418 | |
1419 | |
1420 static off_t | |
1421 rfc959_get_file_size (gftp_request * request, const char *filename) | |
1422 { | |
1423 char *tempstr; | |
1424 int ret; | |
1425 | |
1426 g_return_val_if_fail (request != NULL, 0); | |
84 | 1427 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); |
1 | 1428 g_return_val_if_fail (filename != NULL, 0); |
169 | 1429 g_return_val_if_fail (request->datafd > 0, 0); |
1 | 1430 |
1431 tempstr = g_strconcat ("SIZE ", filename, "\r\n", NULL); | |
1432 ret = rfc959_send_command (request, tempstr); | |
1433 g_free (tempstr); | |
1434 if (ret < 0) | |
84 | 1435 return (ret); |
1 | 1436 |
1437 if (*request->last_ftp_response != '2') | |
1438 return (0); | |
1439 return (strtol (request->last_ftp_response + 4, NULL, 10)); | |
1440 } | |
1441 | |
1442 | |
1443 static int | |
1444 rfc959_rmdir (gftp_request * request, const char *directory) | |
1445 { | |
1446 char *tempstr, ret; | |
1447 | |
84 | 1448 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1449 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1450 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
169 | 1451 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1452 |
1453 tempstr = g_strconcat ("RMD ", directory, "\r\n", NULL); | |
1454 ret = rfc959_send_command (request, tempstr); | |
1455 g_free (tempstr); | |
84 | 1456 |
1457 if (ret < 0) | |
1458 return (ret); | |
1459 else if (ret == '2') | |
1460 return (0); | |
1461 else | |
1462 return (GFTP_ERETRYABLE); | |
1 | 1463 } |
1464 | |
1465 | |
1466 static int | |
1467 rfc959_rmfile (gftp_request * request, const char *file) | |
1468 { | |
1469 char *tempstr, ret; | |
1470 | |
84 | 1471 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1472 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1473 g_return_val_if_fail (file != NULL, GFTP_EFATAL); | |
169 | 1474 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1475 |
1476 tempstr = g_strconcat ("DELE ", file, "\r\n", NULL); | |
1477 ret = rfc959_send_command (request, tempstr); | |
1478 g_free (tempstr); | |
84 | 1479 |
1480 if (ret < 0) | |
1481 return (ret); | |
1482 else if (ret == '2') | |
1483 return (0); | |
1484 else | |
1485 return (GFTP_ERETRYABLE); | |
1 | 1486 } |
1487 | |
1488 | |
1489 static int | |
1490 rfc959_mkdir (gftp_request * request, const char *directory) | |
1491 { | |
1492 char *tempstr, ret; | |
1493 | |
84 | 1494 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1495 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1496 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
169 | 1497 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1498 |
1499 tempstr = g_strconcat ("MKD ", directory, "\r\n", NULL); | |
1500 ret = rfc959_send_command (request, tempstr); | |
1501 g_free (tempstr); | |
84 | 1502 |
1503 if (ret < 0) | |
1504 return (ret); | |
1505 else if (ret == '2') | |
1506 return (0); | |
1507 else | |
1508 return (GFTP_ERETRYABLE); | |
1 | 1509 } |
1510 | |
1511 | |
1512 static int | |
1513 rfc959_rename (gftp_request * request, const char *oldname, | |
1514 const char *newname) | |
1515 { | |
1516 char *tempstr, ret; | |
1517 | |
84 | 1518 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1519 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1520 g_return_val_if_fail (oldname != NULL, GFTP_EFATAL); | |
1521 g_return_val_if_fail (newname != NULL, GFTP_EFATAL); | |
169 | 1522 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1523 |
1524 tempstr = g_strconcat ("RNFR ", oldname, "\r\n", NULL); | |
1525 ret = rfc959_send_command (request, tempstr); | |
1526 g_free (tempstr); | |
84 | 1527 |
1528 if (ret < 0) | |
1529 return (ret); | |
1530 else if (ret != '2') | |
1531 return (GFTP_ERETRYABLE); | |
1 | 1532 |
1533 tempstr = g_strconcat ("RNTO ", newname, "\r\n", NULL); | |
1534 ret = rfc959_send_command (request, tempstr); | |
1535 g_free (tempstr); | |
84 | 1536 |
1537 if (ret < 0) | |
1538 return (ret); | |
1539 else if (ret == '2') | |
1540 return (0); | |
1541 else | |
1542 return (GFTP_ERETRYABLE); | |
1 | 1543 } |
1544 | |
1545 | |
1546 static int | |
1547 rfc959_chmod (gftp_request * request, const char *file, int mode) | |
1548 { | |
1549 char *tempstr, ret; | |
1550 | |
84 | 1551 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1552 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1553 g_return_val_if_fail (file != NULL, GFTP_EFATAL); | |
169 | 1554 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1555 |
1556 tempstr = g_malloc (strlen (file) + (mode / 10) + 16); | |
1557 sprintf (tempstr, "SITE CHMOD %d %s\r\n", mode, file); | |
1558 ret = rfc959_send_command (request, tempstr); | |
1559 g_free (tempstr); | |
84 | 1560 |
1561 if (ret < 0) | |
1562 return (ret); | |
1563 else if (ret == '2') | |
1564 return (0); | |
1565 else | |
1566 return (GFTP_ERETRYABLE); | |
1 | 1567 } |
1568 | |
1569 | |
1570 static int | |
1571 rfc959_site (gftp_request * request, const char *command) | |
1572 { | |
1573 char *tempstr, ret; | |
1574 | |
84 | 1575 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1576 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1577 g_return_val_if_fail (command != NULL, GFTP_EFATAL); | |
169 | 1578 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); |
1 | 1579 |
1580 tempstr = g_strconcat ("SITE ", command, "\r\n", NULL); | |
1581 ret = rfc959_send_command (request, tempstr); | |
1582 g_free (tempstr); | |
84 | 1583 |
1584 if (ret < 0) | |
1585 return (ret); | |
1586 else if (ret == '2') | |
1587 return (0); | |
1588 else | |
1589 return (GFTP_ERETRYABLE); | |
58 | 1590 } |
1591 | |
1592 | |
177 | 1593 static int |
58 | 1594 rfc959_set_config_options (gftp_request * request) |
1595 { | |
122 | 1596 char *proxy_config; |
177 | 1597 int ret; |
58 | 1598 |
122 | 1599 gftp_lookup_request_option (request, "proxy_config", &proxy_config); |
1600 if (strcmp (proxy_config, "http") == 0) | |
58 | 1601 { |
177 | 1602 if ((ret = gftp_protocols[GFTP_HTTP_NUM].init (request)) < 0) |
1603 return (ret); | |
173 | 1604 |
122 | 1605 gftp_set_request_option (request, "proxy_config", "ftp"); |
58 | 1606 } |
177 | 1607 |
1608 return (0); | |
122 | 1609 } |
58 | 1610 |
1611 | |
122 | 1612 void |
1613 rfc959_register_module (void) | |
1614 { | |
1615 struct hostent *hent; | |
1616 struct utsname unme; | |
1617 struct passwd *pw; | |
1618 char *tempstr; | |
1619 | |
1620 gftp_register_config_vars (config_vars); | |
1621 | |
1622 gftp_lookup_global_option ("email", &tempstr); | |
1623 if (tempstr == NULL || *tempstr == '\0') | |
1624 { | |
1625 /* If there is no email address specified, then we'll just use the | |
1626 currentuser@currenthost */ | |
1627 uname (&unme); | |
1628 pw = getpwuid (geteuid ()); | |
1629 hent = gethostbyname (unme.nodename); | |
1630 if (strchr (unme.nodename, '.') == NULL && hent != NULL) | |
1631 tempstr = g_strconcat (pw->pw_name, "@", hent->h_name, NULL); | |
1632 else | |
1633 tempstr = g_strconcat (pw->pw_name, "@", unme.nodename, NULL); | |
1634 gftp_set_global_option ("email", tempstr); | |
58 | 1635 } |
1 | 1636 } |
1637 | |
1638 | |
173 | 1639 int |
48 | 1640 rfc959_init (gftp_request * request) |
1 | 1641 { |
169 | 1642 rfc959_parms * parms; |
1643 | |
173 | 1644 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1 | 1645 |
48 | 1646 request->protonum = GFTP_FTP_NUM; |
1647 request->init = rfc959_init; | |
1648 request->destroy = NULL; | |
168 | 1649 request->read_function = gftp_fd_read; |
1650 request->write_function = gftp_fd_write; | |
48 | 1651 request->connect = rfc959_connect; |
168 | 1652 request->post_connect = NULL; |
48 | 1653 request->disconnect = rfc959_disconnect; |
1654 request->get_file = rfc959_get_file; | |
1655 request->put_file = rfc959_put_file; | |
1656 request->transfer_file = rfc959_transfer_file; | |
122 | 1657 request->get_next_file_chunk = rfc959_get_next_file_chunk; |
1658 request->put_next_file_chunk = rfc959_put_next_file_chunk; | |
48 | 1659 request->end_transfer = rfc959_end_transfer; |
1660 request->abort_transfer = rfc959_abort_transfer; | |
1661 request->list_files = rfc959_list_files; | |
1662 request->get_next_file = rfc959_get_next_file; | |
1663 request->get_file_size = rfc959_get_file_size; | |
1664 request->chdir = rfc959_chdir; | |
1665 request->rmdir = rfc959_rmdir; | |
1666 request->rmfile = rfc959_rmfile; | |
1667 request->mkdir = rfc959_mkdir; | |
1668 request->rename = rfc959_rename; | |
1669 request->chmod = rfc959_chmod; | |
1670 request->set_file_time = NULL; | |
1671 request->site = rfc959_site; | |
1672 request->parse_url = NULL; | |
63 | 1673 request->swap_socks = NULL; |
58 | 1674 request->set_config_options = rfc959_set_config_options; |
48 | 1675 request->url_prefix = "ftp"; |
1676 request->need_hostport = 1; | |
1677 request->need_userpass = 1; | |
1678 request->use_cache = 1; | |
1679 request->use_threads = 1; | |
1680 request->always_connected = 0; | |
169 | 1681 |
58 | 1682 request->protocol_data = g_malloc0 (sizeof (rfc959_parms)); |
169 | 1683 parms = request->protocol_data; |
1684 parms->data_connection = -1; | |
1685 | |
177 | 1686 return (gftp_set_config_options (request)); |
1 | 1687 } |
1688 |