Mercurial > gftp.yaz
annotate lib/rfc959.c @ 149:dfc22cead576
2003-04-27 Christian Rose <menthos@menthos.com>
* lib/rfc959.c: Fix bug #111090 by adding
/* xgettext:no-c-format */ comment. This trivial bug prevented any
full localization of gftp.
author | menthos |
---|---|
date | Sun, 27 Apr 2003 14:34:16 +0000 |
parents | 782f84694489 |
children | 2f15b3000dbc |
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 if (GFTP_GET_AI_FAMILY(request) == AF_INET) | |
852 return (rfc959_ipv4_data_connection_new (request)); | |
853 #ifdef HAVE_IPV6 | |
854 else | |
855 return (rfc959_ipv6_data_connection_new (request)); | |
856 #else /* Shouldn't happen */ | |
857 else | |
858 { | |
859 request->logging_function (gftp_logging_error, request->user_data, | |
860 _("Error: IPV6 support was not completely compiled in\n")); | |
861 return (GFTP_EFATAL); | |
862 } | |
863 #endif | |
864 } | |
865 | |
866 | |
48 | 867 static int |
868 rfc959_accept_active_connection (gftp_request * request) | |
869 { | |
122 | 870 int infd, ret, passive_transfer; |
146 | 871 #ifdef HAVE_IPV6 |
48 | 872 struct sockaddr_in cli_addr; |
146 | 873 #else |
874 struct sockaddr_in6 cli_addr; | |
875 #endif | |
48 | 876 size_t cli_addr_len; |
877 | |
84 | 878 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
879 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
880 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); | |
122 | 881 |
882 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); | |
883 g_return_val_if_fail (!passive_transfer, GFTP_EFATAL); | |
48 | 884 |
885 cli_addr_len = sizeof (cli_addr); | |
58 | 886 |
84 | 887 if ((ret = gftp_set_sockblocking (request, request->datafd, 0)) < 0) |
888 return (ret); | |
58 | 889 |
890 if ((infd = accept (request->datafd, (struct sockaddr *) &cli_addr, | |
48 | 891 &cli_addr_len)) == -1) |
892 { | |
893 request->logging_function (gftp_logging_error, request->user_data, | |
894 _("Cannot accept connection from server: %s\n"), | |
895 g_strerror (errno)); | |
896 gftp_disconnect (request); | |
84 | 897 return (GFTP_ERETRYABLE); |
48 | 898 } |
899 | |
58 | 900 close (request->datafd); |
48 | 901 |
58 | 902 request->datafd = infd; |
84 | 903 if ((ret = gftp_set_sockblocking (request, request->datafd, 1)) < 0) |
904 return (ret); | |
58 | 905 |
48 | 906 return (0); |
907 } | |
908 | |
909 | |
122 | 910 static int |
911 rfc959_is_ascii_transfer (const char *filename) | |
912 { | |
913 gftp_config_list_vars * tmplistvar; | |
914 gftp_file_extensions * tempext; | |
915 GList * templist; | |
916 int stlen, ret; | |
917 | |
918 gftp_lookup_global_option ("ext", &tmplistvar); | |
919 | |
920 ret = 0; | |
921 stlen = strlen (filename); | |
922 for (templist = tmplistvar->list; templist != NULL; templist = templist->next) | |
923 { | |
924 tempext = templist->data; | |
925 | |
926 if (stlen >= tempext->stlen && | |
927 strcmp (&filename[stlen - tempext->stlen], tempext->ext) == 0) | |
928 { | |
929 if (toupper (*tempext->ascii_binary == 'A')) | |
930 ret = 1; | |
931 break; | |
932 } | |
933 } | |
934 | |
935 return (ret); | |
936 } | |
937 | |
938 | |
939 static void | |
940 rfc959_set_data_type (gftp_request * request, const char *filename) | |
941 { | |
942 rfc959_parms * parms; | |
943 int new_ascii; | |
944 char *tempstr; | |
945 | |
946 g_return_if_fail (request != NULL); | |
947 g_return_if_fail (request->protonum == GFTP_FTP_NUM); | |
948 | |
949 parms = request->protocol_data; | |
950 new_ascii = rfc959_is_ascii_transfer (filename); | |
951 | |
952 if (request->sockfd > 0 && new_ascii != parms->is_ascii_transfer) | |
953 { | |
954 if (new_ascii) | |
955 { | |
956 tempstr = "TYPE A\r\n"; | |
957 parms->is_ascii_transfer = 1; | |
958 } | |
959 else | |
960 { | |
961 tempstr = "TYPE I\r\n"; | |
962 parms->is_ascii_transfer = 1; | |
963 } | |
964 | |
965 rfc959_send_command (request, tempstr); | |
966 } | |
967 | |
968 return; | |
969 } | |
970 | |
971 | |
58 | 972 static off_t |
973 rfc959_get_file (gftp_request * request, const char *filename, int fd, | |
1 | 974 off_t startsize) |
975 { | |
976 char *command, *tempstr, resp; | |
122 | 977 int ret, passive_transfer; |
1 | 978 |
84 | 979 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
980 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
981 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
982 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 983 |
58 | 984 if (fd > 0) |
1 | 985 request->datafd = fd; |
986 | |
122 | 987 rfc959_set_data_type (request, filename); |
988 | |
58 | 989 if (request->datafd < 0 && |
1 | 990 (ret = rfc959_data_connection_new (request)) < 0) |
991 return (ret); | |
992 | |
84 | 993 if ((ret = gftp_set_sockblocking (request, request->datafd, 1)) < 0) |
994 return (ret); | |
1 | 995 |
996 if (startsize > 0) | |
997 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
998 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
999 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
|
1000 #else |
1 | 1001 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
|
1002 #endif |
1 | 1003 resp = rfc959_send_command (request, command); |
1004 g_free (command); | |
1005 | |
1006 if (resp != '3') | |
1007 { | |
58 | 1008 close (request->datafd); |
1009 request->datafd = -1; | |
84 | 1010 return (GFTP_ERETRYABLE); |
1 | 1011 } |
1012 } | |
1013 | |
1014 tempstr = g_strconcat ("RETR ", filename, "\r\n", NULL); | |
1015 ret = rfc959_send_command (request, tempstr); | |
1016 g_free (tempstr); | |
1017 | |
1018 if (ret != '1') | |
58 | 1019 { |
1020 close (request->datafd); | |
1021 request->datafd = -1; | |
84 | 1022 return (GFTP_ERETRYABLE); |
58 | 1023 } |
1 | 1024 |
122 | 1025 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
1026 if (!passive_transfer && | |
1 | 1027 (ret = rfc959_accept_active_connection (request)) < 0) |
1028 return (ret); | |
1029 | |
1030 if ((tempstr = strrchr (request->last_ftp_response, '(')) == NULL) | |
1031 { | |
1032 tempstr = request->last_ftp_response + 4; | |
1033 while (!isdigit ((int) *tempstr) && *tempstr != '\0') | |
1034 tempstr++; | |
1035 } | |
1036 else | |
1037 tempstr++; | |
1038 | |
1039 return (strtol (tempstr, NULL, 10) + startsize); | |
1040 } | |
1041 | |
1042 | |
1043 static int | |
58 | 1044 rfc959_put_file (gftp_request * request, const char *filename, int fd, |
1 | 1045 off_t startsize, off_t totalsize) |
1046 { | |
1047 char *command, *tempstr, resp; | |
122 | 1048 int ret, passive_transfer; |
1 | 1049 |
84 | 1050 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1051 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1052 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
1053 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1054 |
58 | 1055 if (fd > 0) |
1 | 1056 fd = request->datafd; |
1057 | |
122 | 1058 rfc959_set_data_type (request, filename); |
1059 | |
58 | 1060 if (request->datafd < 0 && |
1 | 1061 (ret = rfc959_data_connection_new (request)) < 0) |
1062 return (ret); | |
1063 | |
84 | 1064 if ((ret = gftp_set_sockblocking (request, request->datafd, 1)) < 0) |
1065 return (ret); | |
1 | 1066 |
1067 if (startsize > 0) | |
1068 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1069 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1070 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
|
1071 #else |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
1072 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
|
1073 #endif |
1 | 1074 resp = rfc959_send_command (request, command); |
1075 g_free (command); | |
1076 if (resp != '3') | |
1077 { | |
58 | 1078 close (request->datafd); |
1079 request->datafd = -1; | |
84 | 1080 return (GFTP_ERETRYABLE); |
1 | 1081 } |
1082 } | |
1083 | |
1084 tempstr = g_strconcat ("STOR ", filename, "\r\n", NULL); | |
1085 ret = rfc959_send_command (request, tempstr); | |
1086 g_free (tempstr); | |
1087 if (ret != '1') | |
58 | 1088 { |
1089 close (request->datafd); | |
1090 request->datafd = -1; | |
84 | 1091 return (GFTP_ERETRYABLE); |
58 | 1092 } |
1 | 1093 |
122 | 1094 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
1095 if (!passive_transfer && | |
1 | 1096 (ret = rfc959_accept_active_connection (request)) < 0) |
1097 return (ret); | |
1098 | |
1099 return (0); | |
1100 } | |
1101 | |
58 | 1102 |
1 | 1103 static long |
1104 rfc959_transfer_file (gftp_request *fromreq, const char *fromfile, | |
1105 off_t fromsize, gftp_request *toreq, | |
1106 const char *tofile, off_t tosize) | |
1107 { | |
1108 char *tempstr, *pos, *endpos; | |
84 | 1109 int ret; |
1 | 1110 |
84 | 1111 g_return_val_if_fail (fromreq != NULL, GFTP_EFATAL); |
1112 g_return_val_if_fail (fromfile != NULL, GFTP_EFATAL); | |
1113 g_return_val_if_fail (toreq != NULL, GFTP_EFATAL); | |
1114 g_return_val_if_fail (tofile != NULL, GFTP_EFATAL); | |
1115 g_return_val_if_fail (fromreq->sockfd > 0, GFTP_EFATAL); | |
1116 g_return_val_if_fail (toreq->sockfd > 0, GFTP_EFATAL); | |
1 | 1117 |
122 | 1118 gftp_set_request_option (fromreq, "passive_transfer", GINT_TO_POINTER(1)); |
1119 gftp_set_request_option (toreq, "passive_transfer", GINT_TO_POINTER(0)); | |
1 | 1120 |
84 | 1121 if ((ret = rfc959_send_command (fromreq, "PASV\r\n")) != '2') |
1122 return (ret); | |
1 | 1123 |
1124 pos = fromreq->last_ftp_response + 4; | |
1125 while (!isdigit ((int) *pos) && *pos != '\0') | |
1126 pos++; | |
1127 if (*pos == '\0') | |
84 | 1128 return (GFTP_EFATAL); |
1 | 1129 |
1130 endpos = pos; | |
1131 while (*endpos != ')' && *endpos != '\0') | |
1132 endpos++; | |
1133 if (*endpos == ')') | |
1134 *endpos = '\0'; | |
1135 | |
1136 tempstr = g_strconcat ("PORT ", pos, "\r\n", NULL); | |
84 | 1137 if ((ret = rfc959_send_command (toreq, tempstr)) != '2') |
15
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
1138 { |
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
1139 g_free (tempstr); |
84 | 1140 return (ret); |
15
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
1141 } |
1 | 1142 g_free (tempstr); |
1143 | |
1144 tempstr = g_strconcat ("RETR ", fromfile, "\r\n", NULL); | |
84 | 1145 if ((ret = gftp_write (fromreq, tempstr, strlen (tempstr), |
1146 fromreq->sockfd)) < 0) | |
58 | 1147 { |
1148 g_free (tempstr); | |
84 | 1149 return (ret); |
58 | 1150 } |
1 | 1151 g_free (tempstr); |
1152 | |
1153 tempstr = g_strconcat ("STOR ", tofile, "\r\n", NULL); | |
84 | 1154 if ((ret = gftp_write (toreq, tempstr, strlen (tempstr), toreq->sockfd)) < 0) |
58 | 1155 { |
1156 g_free (tempstr); | |
84 | 1157 return (ret); |
58 | 1158 } |
1 | 1159 g_free (tempstr); |
1160 | |
84 | 1161 if ((ret = rfc959_read_response (fromreq)) < 0) |
1162 return (ret); | |
1163 | |
1164 if ((ret = rfc959_read_response (toreq)) < 0) | |
1165 return (ret); | |
1 | 1166 |
1167 return (0); | |
1168 } | |
1169 | |
1170 | |
1171 static int | |
1172 rfc959_end_transfer (gftp_request * request) | |
1173 { | |
84 | 1174 int ret; |
1175 | |
1176 g_return_val_if_fail (request != NULL, GFTP_EFATAL); | |
1177 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1178 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1179 |
58 | 1180 if (request->datafd > 0) |
1 | 1181 { |
58 | 1182 close (request->datafd); |
1183 request->datafd = -1; | |
1 | 1184 } |
84 | 1185 |
1186 ret = rfc959_read_response (request); | |
1187 | |
1188 if (ret < 0) | |
1189 return (ret); | |
1190 else if (ret == '2') | |
1191 return (0); | |
1192 else | |
1193 return (GFTP_ERETRYABLE); | |
1 | 1194 } |
1195 | |
1196 | |
1197 static int | |
40 | 1198 rfc959_abort_transfer (gftp_request * request) |
1199 { | |
1200 int ret; | |
1201 | |
84 | 1202 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1203 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1204 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
40 | 1205 |
58 | 1206 if (request->datafd > 0) |
40 | 1207 { |
58 | 1208 close (request->datafd); |
1209 request->datafd = -1; | |
40 | 1210 } |
1211 | |
1212 /* We need to read two lines of output. The first one is acknowleging | |
1213 the transfer and the second line acknowleges the ABOR command */ | |
84 | 1214 if ((ret = rfc959_send_command (request, "ABOR\r\n")) < 0) |
1215 return (ret); | |
40 | 1216 |
58 | 1217 if (request->sockfd > 0) |
40 | 1218 { |
58 | 1219 if ((ret = rfc959_read_response (request)) < 0) |
40 | 1220 gftp_disconnect (request); |
1221 } | |
1222 | |
1223 return (0); | |
1224 } | |
1225 | |
1226 | |
1227 static int | |
1 | 1228 rfc959_list_files (gftp_request * request) |
1229 { | |
122 | 1230 int ret, show_hidden_files, resolve_symlinks, passive_transfer; |
1 | 1231 char *tempstr, parms[3]; |
1232 | |
84 | 1233 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1234 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1235 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1236 |
1237 if ((ret = rfc959_data_connection_new (request)) < 0) | |
1238 return (ret); | |
1239 | |
122 | 1240 gftp_lookup_request_option (request, "show_hidden_files", &show_hidden_files); |
1241 gftp_lookup_request_option (request, "resolve_symlinks", &resolve_symlinks); | |
1242 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); | |
1243 | |
1 | 1244 *parms = '\0'; |
1245 strcat (parms, show_hidden_files ? "a" : ""); | |
1246 strcat (parms, resolve_symlinks ? "L" : ""); | |
1247 tempstr = g_strconcat ("LIST", *parms != '\0' ? " -" : "", parms, "\r\n", | |
1248 NULL); | |
1249 | |
1250 ret = rfc959_send_command (request, tempstr); | |
1251 g_free (tempstr); | |
1252 | |
1253 if (ret != '1') | |
84 | 1254 return (GFTP_ERETRYABLE); |
1 | 1255 |
1256 ret = 0; | |
122 | 1257 if (!passive_transfer) |
1 | 1258 ret = rfc959_accept_active_connection (request); |
1259 | |
1260 return (ret); | |
1261 } | |
1262 | |
1263 | |
122 | 1264 static ssize_t |
1265 rfc959_get_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1266 { | |
1267 int i, j, ascii_transfers; | |
1268 ssize_t num_read; | |
1269 | |
1270 num_read = gftp_read (request, buf, size, request->datafd); | |
1271 if (num_read < 0) | |
1272 return (num_read); | |
1273 | |
1274 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); | |
1275 if (ascii_transfers) | |
1276 { | |
1277 for (i = 0, j = 0; i < num_read; i++) | |
1278 { | |
1279 if (buf[i] != '\r') | |
1280 buf[j++] = buf[i]; | |
1281 else | |
1282 num_read--; | |
1283 } | |
1284 } | |
1285 | |
1286 return (num_read); | |
1287 } | |
1288 | |
1289 | |
1290 static ssize_t | |
1291 rfc959_put_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1292 { | |
1293 int i, j, ascii_transfers; | |
1294 ssize_t num_wrote; | |
1295 char *tempstr; | |
1296 size_t rsize; | |
1297 | |
1298 if (size == 0) | |
1299 return (0); | |
1300 | |
1301 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); | |
1302 if (ascii_transfers) | |
1303 { | |
1304 rsize = 0; | |
1305 for (i = 0; i < size; i++) | |
1306 { | |
1307 rsize++; | |
1308 if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r') | |
1309 rsize++; | |
1310 } | |
1311 | |
1312 if (rsize != size) | |
1313 { | |
1314 tempstr = g_malloc (rsize); | |
1315 | |
1316 for (i = 0, j = 0; i < size; i++) | |
1317 { | |
1318 if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r') | |
1319 tempstr[j++] = '\r'; | |
1320 tempstr[j++] = buf[i]; | |
1321 } | |
1322 } | |
1323 else | |
1324 tempstr = buf; | |
1325 } | |
1326 else | |
1327 { | |
1328 rsize = size; | |
1329 tempstr = buf; | |
1330 } | |
1331 | |
1332 num_wrote = gftp_write (request, tempstr, rsize, request->datafd); | |
1333 | |
1334 if (tempstr != buf) | |
1335 g_free (tempstr); | |
1336 | |
1337 return (num_wrote); | |
1338 } | |
1339 | |
1340 | |
1 | 1341 int |
58 | 1342 rfc959_get_next_file (gftp_request * request, gftp_file * fle, int fd) |
1 | 1343 { |
58 | 1344 rfc959_parms * parms; |
1 | 1345 char tempstr[255]; |
58 | 1346 ssize_t len; |
1 | 1347 |
84 | 1348 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1349 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1350 g_return_val_if_fail (fle != NULL, GFTP_EFATAL); | |
1351 g_return_val_if_fail (fd > 0, GFTP_EFATAL); | |
1 | 1352 |
1353 if (request->last_dir_entry) | |
1354 { | |
1355 g_free (request->last_dir_entry); | |
1356 request->last_dir_entry = NULL; | |
1357 } | |
58 | 1358 |
1359 parms = request->protocol_data; | |
1360 | |
1 | 1361 do |
1362 { | |
58 | 1363 if ((len = gftp_get_line (request, &parms->datafd_rbuf, |
60 | 1364 tempstr, sizeof (tempstr), fd)) <= 0) |
1 | 1365 { |
1366 gftp_file_destroy (fle); | |
58 | 1367 return ((int) len); |
1 | 1368 } |
1369 | |
91 | 1370 if (gftp_parse_ls (request, tempstr, fle) != 0) |
1 | 1371 { |
58 | 1372 if (strncmp (tempstr, "total", strlen ("total")) != 0 && |
1373 strncmp (tempstr, _("total"), strlen (_("total"))) != 0) | |
1374 request->logging_function (gftp_logging_error, request->user_data, | |
1 | 1375 _("Warning: Cannot parse listing %s\n"), |
1376 tempstr); | |
1377 gftp_file_destroy (fle); | |
1378 continue; | |
1379 } | |
1380 else | |
1381 break; | |
1382 } | |
1383 while (1); | |
1384 | |
1385 len = strlen (tempstr); | |
1386 if (!request->cached) | |
1387 { | |
60 | 1388 request->last_dir_entry = g_strdup_printf ("%s\n", tempstr); |
1389 request->last_dir_entry_len = len + 1; | |
1 | 1390 } |
1391 return (len); | |
1392 } | |
1393 | |
1394 | |
1395 static off_t | |
1396 rfc959_get_file_size (gftp_request * request, const char *filename) | |
1397 { | |
1398 char *tempstr; | |
1399 int ret; | |
1400 | |
1401 g_return_val_if_fail (request != NULL, 0); | |
84 | 1402 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); |
1 | 1403 g_return_val_if_fail (filename != NULL, 0); |
58 | 1404 g_return_val_if_fail (request->sockfd > 0, 0); |
1 | 1405 |
1406 tempstr = g_strconcat ("SIZE ", filename, "\r\n", NULL); | |
1407 ret = rfc959_send_command (request, tempstr); | |
1408 g_free (tempstr); | |
1409 if (ret < 0) | |
84 | 1410 return (ret); |
1 | 1411 |
1412 if (*request->last_ftp_response != '2') | |
1413 return (0); | |
1414 return (strtol (request->last_ftp_response + 4, NULL, 10)); | |
1415 } | |
1416 | |
1417 | |
1418 static int | |
1419 rfc959_rmdir (gftp_request * request, const char *directory) | |
1420 { | |
1421 char *tempstr, ret; | |
1422 | |
84 | 1423 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1424 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1425 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
1426 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1427 |
1428 tempstr = g_strconcat ("RMD ", directory, "\r\n", NULL); | |
1429 ret = rfc959_send_command (request, tempstr); | |
1430 g_free (tempstr); | |
84 | 1431 |
1432 if (ret < 0) | |
1433 return (ret); | |
1434 else if (ret == '2') | |
1435 return (0); | |
1436 else | |
1437 return (GFTP_ERETRYABLE); | |
1 | 1438 } |
1439 | |
1440 | |
1441 static int | |
1442 rfc959_rmfile (gftp_request * request, const char *file) | |
1443 { | |
1444 char *tempstr, ret; | |
1445 | |
84 | 1446 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1447 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1448 g_return_val_if_fail (file != NULL, GFTP_EFATAL); | |
1449 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1450 |
1451 tempstr = g_strconcat ("DELE ", file, "\r\n", NULL); | |
1452 ret = rfc959_send_command (request, tempstr); | |
1453 g_free (tempstr); | |
84 | 1454 |
1455 if (ret < 0) | |
1456 return (ret); | |
1457 else if (ret == '2') | |
1458 return (0); | |
1459 else | |
1460 return (GFTP_ERETRYABLE); | |
1 | 1461 } |
1462 | |
1463 | |
1464 static int | |
1465 rfc959_mkdir (gftp_request * request, const char *directory) | |
1466 { | |
1467 char *tempstr, ret; | |
1468 | |
84 | 1469 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1470 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1471 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
1472 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1473 |
1474 tempstr = g_strconcat ("MKD ", directory, "\r\n", NULL); | |
1475 ret = rfc959_send_command (request, tempstr); | |
1476 g_free (tempstr); | |
84 | 1477 |
1478 if (ret < 0) | |
1479 return (ret); | |
1480 else if (ret == '2') | |
1481 return (0); | |
1482 else | |
1483 return (GFTP_ERETRYABLE); | |
1 | 1484 } |
1485 | |
1486 | |
1487 static int | |
1488 rfc959_rename (gftp_request * request, const char *oldname, | |
1489 const char *newname) | |
1490 { | |
1491 char *tempstr, ret; | |
1492 | |
84 | 1493 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1494 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1495 g_return_val_if_fail (oldname != NULL, GFTP_EFATAL); | |
1496 g_return_val_if_fail (newname != NULL, GFTP_EFATAL); | |
1497 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1498 |
1499 tempstr = g_strconcat ("RNFR ", oldname, "\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 (GFTP_ERETRYABLE); | |
1 | 1507 |
1508 tempstr = g_strconcat ("RNTO ", newname, "\r\n", NULL); | |
1509 ret = rfc959_send_command (request, tempstr); | |
1510 g_free (tempstr); | |
84 | 1511 |
1512 if (ret < 0) | |
1513 return (ret); | |
1514 else if (ret == '2') | |
1515 return (0); | |
1516 else | |
1517 return (GFTP_ERETRYABLE); | |
1 | 1518 } |
1519 | |
1520 | |
1521 static int | |
1522 rfc959_chmod (gftp_request * request, const char *file, int mode) | |
1523 { | |
1524 char *tempstr, ret; | |
1525 | |
84 | 1526 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1527 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1528 g_return_val_if_fail (file != NULL, GFTP_EFATAL); | |
1529 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1530 |
1531 tempstr = g_malloc (strlen (file) + (mode / 10) + 16); | |
1532 sprintf (tempstr, "SITE CHMOD %d %s\r\n", mode, file); | |
1533 ret = rfc959_send_command (request, tempstr); | |
1534 g_free (tempstr); | |
84 | 1535 |
1536 if (ret < 0) | |
1537 return (ret); | |
1538 else if (ret == '2') | |
1539 return (0); | |
1540 else | |
1541 return (GFTP_ERETRYABLE); | |
1 | 1542 } |
1543 | |
1544 | |
1545 static int | |
1546 rfc959_site (gftp_request * request, const char *command) | |
1547 { | |
1548 char *tempstr, ret; | |
1549 | |
84 | 1550 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1551 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1552 g_return_val_if_fail (command != NULL, GFTP_EFATAL); | |
1553 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1554 |
1555 tempstr = g_strconcat ("SITE ", command, "\r\n", NULL); | |
1556 ret = rfc959_send_command (request, tempstr); | |
1557 g_free (tempstr); | |
84 | 1558 |
1559 if (ret < 0) | |
1560 return (ret); | |
1561 else if (ret == '2') | |
1562 return (0); | |
1563 else | |
1564 return (GFTP_ERETRYABLE); | |
58 | 1565 } |
1566 | |
1567 | |
1568 static void | |
1569 rfc959_set_config_options (gftp_request * request) | |
1570 { | |
122 | 1571 char *proxy_config; |
58 | 1572 |
122 | 1573 gftp_lookup_request_option (request, "proxy_config", &proxy_config); |
1574 if (strcmp (proxy_config, "http") == 0) | |
58 | 1575 { |
122 | 1576 gftp_protocols[GFTP_HTTP_NUM].init (request); |
1577 gftp_set_request_option (request, "proxy_config", "ftp"); | |
58 | 1578 } |
122 | 1579 } |
58 | 1580 |
1581 | |
122 | 1582 void |
1583 rfc959_register_module (void) | |
1584 { | |
1585 struct hostent *hent; | |
1586 struct utsname unme; | |
1587 struct passwd *pw; | |
1588 char *tempstr; | |
1589 | |
1590 gftp_register_config_vars (config_vars); | |
1591 | |
1592 gftp_lookup_global_option ("email", &tempstr); | |
1593 if (tempstr == NULL || *tempstr == '\0') | |
1594 { | |
1595 /* If there is no email address specified, then we'll just use the | |
1596 currentuser@currenthost */ | |
1597 uname (&unme); | |
1598 pw = getpwuid (geteuid ()); | |
1599 hent = gethostbyname (unme.nodename); | |
1600 if (strchr (unme.nodename, '.') == NULL && hent != NULL) | |
1601 tempstr = g_strconcat (pw->pw_name, "@", hent->h_name, NULL); | |
1602 else | |
1603 tempstr = g_strconcat (pw->pw_name, "@", unme.nodename, NULL); | |
1604 gftp_set_global_option ("email", tempstr); | |
58 | 1605 } |
1 | 1606 } |
1607 | |
1608 | |
48 | 1609 void |
1610 rfc959_init (gftp_request * request) | |
1 | 1611 { |
48 | 1612 g_return_if_fail (request != NULL); |
1 | 1613 |
48 | 1614 request->protonum = GFTP_FTP_NUM; |
1615 request->init = rfc959_init; | |
1616 request->destroy = NULL; | |
1617 request->connect = rfc959_connect; | |
1618 request->disconnect = rfc959_disconnect; | |
1619 request->get_file = rfc959_get_file; | |
1620 request->put_file = rfc959_put_file; | |
1621 request->transfer_file = rfc959_transfer_file; | |
122 | 1622 request->get_next_file_chunk = rfc959_get_next_file_chunk; |
1623 request->put_next_file_chunk = rfc959_put_next_file_chunk; | |
48 | 1624 request->end_transfer = rfc959_end_transfer; |
1625 request->abort_transfer = rfc959_abort_transfer; | |
1626 request->list_files = rfc959_list_files; | |
1627 request->get_next_file = rfc959_get_next_file; | |
1628 request->get_file_size = rfc959_get_file_size; | |
1629 request->chdir = rfc959_chdir; | |
1630 request->rmdir = rfc959_rmdir; | |
1631 request->rmfile = rfc959_rmfile; | |
1632 request->mkdir = rfc959_mkdir; | |
1633 request->rename = rfc959_rename; | |
1634 request->chmod = rfc959_chmod; | |
1635 request->set_file_time = NULL; | |
1636 request->site = rfc959_site; | |
1637 request->parse_url = NULL; | |
63 | 1638 request->swap_socks = NULL; |
58 | 1639 request->set_config_options = rfc959_set_config_options; |
48 | 1640 request->url_prefix = "ftp"; |
1641 request->need_hostport = 1; | |
1642 request->need_userpass = 1; | |
1643 request->use_cache = 1; | |
1644 request->use_threads = 1; | |
1645 request->always_connected = 0; | |
58 | 1646 request->protocol_data = g_malloc0 (sizeof (rfc959_parms)); |
48 | 1647 gftp_set_config_options (request); |
1 | 1648 } |
1649 |