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