Mercurial > gftp.yaz
annotate lib/rfc959.c @ 126:1e65871fdfa1
2003-4-9 Brian Masney <masneyb@gftp.org>
* lib/gftp.h lib/config_file.c - reordered config option types. Added
gftp_option_type_textcomboedt type
* lib/options.h lib/rfc959.c - moved gftp_proxy_type to rfc959.c
* lib/rfc959.c - added proxy_type that is
gftp_option_type_textcomboedt. Consolidated help text into comment.
In parse_ftp_proxy_string(), improve parsing of proxy config
author | masneyb |
---|---|
date | Thu, 10 Apr 2003 02:29:44 +0000 |
parents | 65048c959029 |
children | 84b3e69807a2 |
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[] = { |
24 {N_("none"), ""}, | |
25 {N_("SITE command"), "USER %pu\nPASS %pp\nSITE %hh\nUSER %hu\nPASS %hp\n"}, | |
26 {N_("user@host"), "USER %pu\nPASS %pp\nUSER %hu@%hh\nPASS %hp\n"}, | |
27 {N_("user@host:port"), "USER %hu@%hh:%ho\nPASS %hp\n"}, | |
28 {N_("AUTHENTICATE"), "USER %hu@%hh\nPASS %hp\nSITE AUTHENTICATE %pu\nSITE RESPONSE %pp\n"}, | |
29 {N_("user@host port"), "USER %hu@%hh %ho\nPASS %hp\n"}, | |
30 {N_("user@host NOAUTH"), "USER %hu@%hh\nPASS %hp\n"}, | |
31 {N_("HTTP Proxy"), "http"}, | |
32 {N_("Custom"), ""}, | |
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 {"passive_transfer", N_("Passive file transfers"), | |
46 gftp_option_type_checkbox, GINT_TO_POINTER(1), NULL, 0, | |
47 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."), | |
48 GFTP_PORT_ALL, NULL}, | |
49 {"resolve_symlinks", N_("Resolve Remote Symlinks (LIST -L)"), | |
50 gftp_option_type_checkbox, GINT_TO_POINTER(1), NULL, 0, | |
51 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"), | |
52 GFTP_PORT_ALL, NULL}, | |
53 {"ascii_transfers", N_("Transfer files in ASCII mode"), | |
54 gftp_option_type_checkbox, GINT_TO_POINTER(0), NULL, 0, | |
126 | 55 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."), |
122 | 56 GFTP_PORT_ALL, NULL}, |
57 {"ftp_proxy_host", N_("Proxy hostname:"), | |
58 gftp_option_type_text, "", NULL, 0, | |
59 N_("Firewall hostname"), GFTP_PORT_ALL, NULL}, | |
60 {"ftp_proxy_port", N_("Proxy port:"), | |
61 gftp_option_type_int, GINT_TO_POINTER(21), NULL, 0, | |
62 N_("Port to connect to on the firewall"), GFTP_PORT_ALL, NULL}, | |
63 {"ftp_proxy_username", N_("Proxy username:"), | |
64 gftp_option_type_text, "", NULL, 0, | |
65 N_("Your firewall username"), GFTP_PORT_ALL, NULL}, | |
66 {"ftp_proxy_password", N_("Proxy password:"), | |
67 gftp_option_type_hidetext, "", NULL, 0, | |
68 N_("Your firewall password"), GFTP_PORT_ALL, NULL}, | |
69 {"ftp_proxy_account", N_("Proxy account:"), | |
70 gftp_option_type_text, "", NULL, 0, | |
71 N_("Your firewall account (optional)"), GFTP_PORT_ALL, NULL}, | |
72 | |
73 {"", "", gftp_option_type_newtable, "", NULL, 0, "", GFTP_PORT_GTK, NULL}, | |
74 | |
126 | 75 {"proxy_config", N_("Proxy server type:"), |
76 gftp_option_type_textcomboedt, "", gftp_proxy_type, 0, | |
77 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"), | |
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; |
91 | 401 else |
122 | 402 request->server_type = GFTP_DIRTYPE_OTHER; |
91 | 403 |
404 return (0); | |
405 } | |
406 | |
407 | |
408 static int | |
1 | 409 rfc959_connect (gftp_request * request) |
410 { | |
122 | 411 char tempchar, *startpos, *endpos, *tempstr, *email, *proxy_hostname; |
412 int ret, resp, ascii_transfers, proxy_port; | |
413 rfc959_parms * parms; | |
1 | 414 |
84 | 415 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
416 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
417 g_return_val_if_fail (request->hostname != NULL, GFTP_EFATAL); | |
1 | 418 |
58 | 419 if (request->sockfd > 0) |
420 return (0); | |
421 | |
122 | 422 parms = request->protocol_data; |
423 | |
424 gftp_lookup_request_option (request, "email", &email); | |
124 | 425 gftp_lookup_request_option (request, "ftp_proxy_host", &proxy_hostname); |
426 gftp_lookup_request_option (request, "ftp_proxy_port", &proxy_port); | |
122 | 427 |
7 | 428 if (request->username == NULL || *request->username == '\0') |
429 { | |
430 gftp_set_username (request, "anonymous"); | |
122 | 431 gftp_set_password (request, email); |
7 | 432 } |
433 else if (strcasecmp (request->username, "anonymous") == 0) | |
122 | 434 gftp_set_password (request, email); |
435 | |
436 if ((request->sockfd = gftp_connect_server (request, "ftp", proxy_hostname, | |
437 proxy_port)) < 0) | |
84 | 438 return (request->sockfd); |
1 | 439 |
440 /* Get the banner */ | |
84 | 441 if ((ret = rfc959_read_response (request)) != '2') |
1 | 442 { |
443 gftp_disconnect (request); | |
84 | 444 return (ret); |
1 | 445 } |
446 | |
447 /* Login the proxy server if available */ | |
448 if (request->use_proxy) | |
449 { | |
450 resp = '3'; | |
451 startpos = endpos = tempstr = parse_ftp_proxy_string (request); | |
452 while ((resp == '3' || resp == '2') && *startpos != '\0') | |
453 { | |
454 if (*endpos == '\n' || *endpos == '\0') | |
455 { | |
456 tempchar = *(endpos + 1); | |
457 if (*endpos != '\0') | |
458 *(endpos + 1) = '\0'; | |
459 if ((resp = rfc959_send_command (request, startpos)) < 0) | |
84 | 460 return (resp); |
1 | 461 if (*endpos != '\0') |
462 *(endpos + 1) = tempchar; | |
463 else | |
464 break; | |
465 startpos = endpos + 1; | |
466 } | |
467 endpos++; | |
468 } | |
469 g_free (tempstr); | |
470 } | |
471 else | |
472 { | |
473 tempstr = g_strconcat ("USER ", request->username, "\r\n", NULL); | |
474 resp = rfc959_send_command (request, tempstr); | |
475 g_free (tempstr); | |
476 if (resp < 0) | |
84 | 477 return (GFTP_ERETRYABLE); |
1 | 478 if (resp == '3') |
479 { | |
480 tempstr = g_strconcat ("PASS ", request->password, "\r\n", NULL); | |
481 resp = rfc959_send_command (request, tempstr); | |
482 g_free (tempstr); | |
483 if (resp < 0) | |
84 | 484 return (GFTP_ERETRYABLE); |
1 | 485 } |
486 if (resp == '3' && request->account) | |
487 { | |
488 tempstr = g_strconcat ("ACCT ", request->account, "\r\n", NULL); | |
489 resp = rfc959_send_command (request, tempstr); | |
490 g_free (tempstr); | |
491 if (resp < 0) | |
84 | 492 return (GFTP_ERETRYABLE); |
1 | 493 } |
494 } | |
495 | |
496 if (resp != '2') | |
497 { | |
498 gftp_disconnect (request); | |
84 | 499 return (GFTP_EFATAL); |
1 | 500 } |
501 | |
91 | 502 if ((ret = rfc959_syst (request)) < 0 && request->sockfd < 0) |
503 return (ret); | |
504 | |
122 | 505 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); |
506 if (ascii_transfers) | |
507 { | |
508 tempstr = "TYPE A\r\n"; | |
509 parms->is_ascii_transfer = 1; | |
510 } | |
1 | 511 else |
122 | 512 { |
513 tempstr = "TYPE I\r\n"; | |
514 parms->is_ascii_transfer = 0; | |
515 } | |
1 | 516 |
84 | 517 if ((ret = rfc959_send_command (request, tempstr)) < 0) |
518 return (ret); | |
1 | 519 |
520 ret = -1; | |
521 if (request->directory != NULL && *request->directory != '\0') | |
522 { | |
523 ret = rfc959_chdir (request, request->directory); | |
58 | 524 if (request->sockfd < 0) |
84 | 525 return (ret); |
1 | 526 } |
527 | |
528 if (ret != 0) | |
529 { | |
84 | 530 if ((ret = rfc959_getcwd (request)) < 0) |
531 return (ret); | |
1 | 532 } |
533 | |
58 | 534 if (request->sockfd < 0) |
84 | 535 return (GFTP_EFATAL); |
1 | 536 |
537 return (0); | |
538 } | |
539 | |
540 | |
541 static void | |
542 rfc959_disconnect (gftp_request * request) | |
543 { | |
544 g_return_if_fail (request != NULL); | |
545 g_return_if_fail (request->protonum == GFTP_FTP_NUM); | |
546 | |
58 | 547 if (request->sockfd > 0) |
1 | 548 { |
549 request->logging_function (gftp_logging_misc, request->user_data, | |
550 _("Disconnecting from site %s\n"), | |
551 request->hostname); | |
58 | 552 close (request->sockfd); |
553 request->sockfd = -1; | |
554 if (request->datafd > 0) | |
1 | 555 { |
58 | 556 close (request->datafd); |
557 request->datafd = -1; | |
1 | 558 } |
559 } | |
560 } | |
561 | |
562 | |
48 | 563 static int |
564 rfc959_data_connection_new (gftp_request * request) | |
565 { | |
566 char *pos, *pos1, resp, *command; | |
567 struct sockaddr_in data_addr; | |
122 | 568 int i, passive_transfer; |
48 | 569 size_t data_addr_len; |
570 unsigned int temp[6]; | |
571 unsigned char ad[6]; | |
572 | |
84 | 573 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
574 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
575 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
48 | 576 |
58 | 577 if ((request->datafd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) |
48 | 578 { |
579 request->logging_function (gftp_logging_error, request->user_data, | |
580 _("Failed to create a socket: %s\n"), | |
581 g_strerror (errno)); | |
582 gftp_disconnect (request); | |
84 | 583 return (GFTP_ERETRYABLE); |
48 | 584 } |
585 | |
586 data_addr_len = sizeof (data_addr); | |
587 memset (&data_addr, 0, data_addr_len); | |
588 data_addr.sin_family = AF_INET; | |
589 | |
122 | 590 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
591 if (passive_transfer) | |
48 | 592 { |
593 if ((resp = rfc959_send_command (request, "PASV\r\n")) != '2') | |
594 { | |
58 | 595 if (request->sockfd < 0) |
84 | 596 return (resp); |
48 | 597 |
122 | 598 gftp_set_request_option (request, "passive_transfer", GINT_TO_POINTER(0)); |
48 | 599 return (rfc959_data_connection_new (request)); |
600 } | |
58 | 601 |
48 | 602 pos = request->last_ftp_response + 4; |
603 while (!isdigit ((int) *pos) && *pos != '\0') | |
604 pos++; | |
58 | 605 |
48 | 606 if (*pos == '\0') |
607 { | |
58 | 608 request->logging_function (gftp_logging_error, request->user_data, |
609 _("Cannot find an IP address in PASV response '%s'\n"), | |
610 request->last_ftp_response); | |
48 | 611 gftp_disconnect (request); |
84 | 612 return (GFTP_EFATAL); |
48 | 613 } |
58 | 614 |
48 | 615 if (sscanf (pos, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2], |
616 &temp[3], &temp[4], &temp[5]) != 6) | |
617 { | |
58 | 618 request->logging_function (gftp_logging_error, request->user_data, |
619 _("Cannot find an IP address in PASV response '%s'\n"), | |
620 request->last_ftp_response); | |
48 | 621 gftp_disconnect (request); |
84 | 622 return (GFTP_EFATAL); |
48 | 623 } |
58 | 624 |
48 | 625 for (i = 0; i < 6; i++) |
626 ad[i] = (unsigned char) (temp[i] & 0xff); | |
627 | |
628 memcpy (&data_addr.sin_addr, &ad[0], 4); | |
629 memcpy (&data_addr.sin_port, &ad[4], 2); | |
58 | 630 if (connect (request->datafd, (struct sockaddr *) &data_addr, |
631 data_addr_len) == -1) | |
48 | 632 { |
633 request->logging_function (gftp_logging_error, request->user_data, | |
634 _("Cannot create a data connection: %s\n"), | |
635 g_strerror (errno)); | |
636 gftp_disconnect (request); | |
84 | 637 return (GFTP_ERETRYABLE); |
48 | 638 } |
639 } | |
640 else | |
641 { | |
58 | 642 if (getsockname (request->sockfd, (struct sockaddr *) &data_addr, |
643 &data_addr_len) == -1) | |
644 { | |
645 request->logging_function (gftp_logging_error, request->user_data, | |
646 _("Cannot get socket name: %s\n"), | |
647 g_strerror (errno)); | |
648 gftp_disconnect (request); | |
84 | 649 return (GFTP_ERETRYABLE); |
58 | 650 } |
651 | |
48 | 652 data_addr.sin_port = 0; |
58 | 653 if (bind (request->datafd, (struct sockaddr *) &data_addr, |
654 data_addr_len) == -1) | |
48 | 655 { |
656 request->logging_function (gftp_logging_error, request->user_data, | |
657 _("Cannot bind a port: %s\n"), | |
658 g_strerror (errno)); | |
659 gftp_disconnect (request); | |
84 | 660 return (GFTP_ERETRYABLE); |
48 | 661 } |
662 | |
58 | 663 if (getsockname (request->datafd, (struct sockaddr *) &data_addr, |
664 &data_addr_len) == -1) | |
665 { | |
666 request->logging_function (gftp_logging_error, request->user_data, | |
667 _("Cannot get socket name: %s\n"), | |
668 g_strerror (errno)); | |
669 gftp_disconnect (request); | |
84 | 670 return (GFTP_ERETRYABLE); |
58 | 671 } |
672 | |
673 if (listen (request->datafd, 1) == -1) | |
48 | 674 { |
675 request->logging_function (gftp_logging_error, request->user_data, | |
676 _("Cannot listen on port %d: %s\n"), | |
677 ntohs (data_addr.sin_port), | |
678 g_strerror (errno)); | |
679 gftp_disconnect (request); | |
84 | 680 return (GFTP_ERETRYABLE); |
48 | 681 } |
58 | 682 |
48 | 683 pos = (char *) &data_addr.sin_addr; |
684 pos1 = (char *) &data_addr.sin_port; | |
685 command = g_strdup_printf ("PORT %u,%u,%u,%u,%u,%u\r\n", | |
686 pos[0] & 0xff, pos[1] & 0xff, pos[2] & 0xff, | |
687 pos[3] & 0xff, pos1[0] & 0xff, | |
688 pos1[1] & 0xff); | |
689 resp = rfc959_send_command (request, command); | |
690 g_free (command); | |
691 if (resp != '2') | |
692 { | |
693 gftp_disconnect (request); | |
84 | 694 return (GFTP_ERETRYABLE); |
48 | 695 } |
696 } | |
697 | |
698 return (0); | |
699 } | |
700 | |
701 | |
702 static int | |
703 rfc959_accept_active_connection (gftp_request * request) | |
704 { | |
122 | 705 int infd, ret, passive_transfer; |
48 | 706 struct sockaddr_in cli_addr; |
707 size_t cli_addr_len; | |
708 | |
84 | 709 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
710 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
711 g_return_val_if_fail (request->datafd > 0, GFTP_EFATAL); | |
122 | 712 |
713 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); | |
714 g_return_val_if_fail (!passive_transfer, GFTP_EFATAL); | |
48 | 715 |
716 cli_addr_len = sizeof (cli_addr); | |
58 | 717 |
84 | 718 if ((ret = gftp_set_sockblocking (request, request->datafd, 0)) < 0) |
719 return (ret); | |
58 | 720 |
721 if ((infd = accept (request->datafd, (struct sockaddr *) &cli_addr, | |
48 | 722 &cli_addr_len)) == -1) |
723 { | |
724 request->logging_function (gftp_logging_error, request->user_data, | |
725 _("Cannot accept connection from server: %s\n"), | |
726 g_strerror (errno)); | |
727 gftp_disconnect (request); | |
84 | 728 return (GFTP_ERETRYABLE); |
48 | 729 } |
730 | |
58 | 731 close (request->datafd); |
48 | 732 |
58 | 733 request->datafd = infd; |
84 | 734 if ((ret = gftp_set_sockblocking (request, request->datafd, 1)) < 0) |
735 return (ret); | |
58 | 736 |
48 | 737 return (0); |
738 } | |
739 | |
740 | |
122 | 741 static int |
742 rfc959_is_ascii_transfer (const char *filename) | |
743 { | |
744 gftp_config_list_vars * tmplistvar; | |
745 gftp_file_extensions * tempext; | |
746 GList * templist; | |
747 int stlen, ret; | |
748 | |
749 gftp_lookup_global_option ("ext", &tmplistvar); | |
750 | |
751 ret = 0; | |
752 stlen = strlen (filename); | |
753 for (templist = tmplistvar->list; templist != NULL; templist = templist->next) | |
754 { | |
755 tempext = templist->data; | |
756 | |
757 if (stlen >= tempext->stlen && | |
758 strcmp (&filename[stlen - tempext->stlen], tempext->ext) == 0) | |
759 { | |
760 if (toupper (*tempext->ascii_binary == 'A')) | |
761 ret = 1; | |
762 break; | |
763 } | |
764 } | |
765 | |
766 return (ret); | |
767 } | |
768 | |
769 | |
770 static void | |
771 rfc959_set_data_type (gftp_request * request, const char *filename) | |
772 { | |
773 rfc959_parms * parms; | |
774 int new_ascii; | |
775 char *tempstr; | |
776 | |
777 g_return_if_fail (request != NULL); | |
778 g_return_if_fail (request->protonum == GFTP_FTP_NUM); | |
779 | |
780 parms = request->protocol_data; | |
781 new_ascii = rfc959_is_ascii_transfer (filename); | |
782 | |
783 if (request->sockfd > 0 && new_ascii != parms->is_ascii_transfer) | |
784 { | |
785 if (new_ascii) | |
786 { | |
787 tempstr = "TYPE A\r\n"; | |
788 parms->is_ascii_transfer = 1; | |
789 } | |
790 else | |
791 { | |
792 tempstr = "TYPE I\r\n"; | |
793 parms->is_ascii_transfer = 1; | |
794 } | |
795 | |
796 rfc959_send_command (request, tempstr); | |
797 } | |
798 | |
799 return; | |
800 } | |
801 | |
802 | |
58 | 803 static off_t |
804 rfc959_get_file (gftp_request * request, const char *filename, int fd, | |
1 | 805 off_t startsize) |
806 { | |
807 char *command, *tempstr, resp; | |
122 | 808 int ret, passive_transfer; |
1 | 809 |
84 | 810 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
811 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
812 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
813 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 814 |
58 | 815 if (fd > 0) |
1 | 816 request->datafd = fd; |
817 | |
122 | 818 rfc959_set_data_type (request, filename); |
819 | |
58 | 820 if (request->datafd < 0 && |
1 | 821 (ret = rfc959_data_connection_new (request)) < 0) |
822 return (ret); | |
823 | |
84 | 824 if ((ret = gftp_set_sockblocking (request, request->datafd, 1)) < 0) |
825 return (ret); | |
1 | 826 |
827 if (startsize > 0) | |
828 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
829 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
830 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
|
831 #else |
1 | 832 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
|
833 #endif |
1 | 834 resp = rfc959_send_command (request, command); |
835 g_free (command); | |
836 | |
837 if (resp != '3') | |
838 { | |
58 | 839 close (request->datafd); |
840 request->datafd = -1; | |
84 | 841 return (GFTP_ERETRYABLE); |
1 | 842 } |
843 } | |
844 | |
845 tempstr = g_strconcat ("RETR ", filename, "\r\n", NULL); | |
846 ret = rfc959_send_command (request, tempstr); | |
847 g_free (tempstr); | |
848 | |
849 if (ret != '1') | |
58 | 850 { |
851 close (request->datafd); | |
852 request->datafd = -1; | |
84 | 853 return (GFTP_ERETRYABLE); |
58 | 854 } |
1 | 855 |
122 | 856 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
857 if (!passive_transfer && | |
1 | 858 (ret = rfc959_accept_active_connection (request)) < 0) |
859 return (ret); | |
860 | |
861 if ((tempstr = strrchr (request->last_ftp_response, '(')) == NULL) | |
862 { | |
863 tempstr = request->last_ftp_response + 4; | |
864 while (!isdigit ((int) *tempstr) && *tempstr != '\0') | |
865 tempstr++; | |
866 } | |
867 else | |
868 tempstr++; | |
869 | |
870 return (strtol (tempstr, NULL, 10) + startsize); | |
871 } | |
872 | |
873 | |
874 static int | |
58 | 875 rfc959_put_file (gftp_request * request, const char *filename, int fd, |
1 | 876 off_t startsize, off_t totalsize) |
877 { | |
878 char *command, *tempstr, resp; | |
122 | 879 int ret, passive_transfer; |
1 | 880 |
84 | 881 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
882 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
883 g_return_val_if_fail (filename != NULL, GFTP_EFATAL); | |
884 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 885 |
58 | 886 if (fd > 0) |
1 | 887 fd = request->datafd; |
888 | |
122 | 889 rfc959_set_data_type (request, filename); |
890 | |
58 | 891 if (request->datafd < 0 && |
1 | 892 (ret = rfc959_data_connection_new (request)) < 0) |
893 return (ret); | |
894 | |
84 | 895 if ((ret = gftp_set_sockblocking (request, request->datafd, 1)) < 0) |
896 return (ret); | |
1 | 897 |
898 if (startsize > 0) | |
899 { | |
14
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
900 #if defined (_LARGEFILE_SOURCE) |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
901 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
|
902 #else |
83090328581e
* More largefile support. Hopefully all that is left is the configure stuff
masneyb
parents:
7
diff
changeset
|
903 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
|
904 #endif |
1 | 905 resp = rfc959_send_command (request, command); |
906 g_free (command); | |
907 if (resp != '3') | |
908 { | |
58 | 909 close (request->datafd); |
910 request->datafd = -1; | |
84 | 911 return (GFTP_ERETRYABLE); |
1 | 912 } |
913 } | |
914 | |
915 tempstr = g_strconcat ("STOR ", filename, "\r\n", NULL); | |
916 ret = rfc959_send_command (request, tempstr); | |
917 g_free (tempstr); | |
918 if (ret != '1') | |
58 | 919 { |
920 close (request->datafd); | |
921 request->datafd = -1; | |
84 | 922 return (GFTP_ERETRYABLE); |
58 | 923 } |
1 | 924 |
122 | 925 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); |
926 if (!passive_transfer && | |
1 | 927 (ret = rfc959_accept_active_connection (request)) < 0) |
928 return (ret); | |
929 | |
930 return (0); | |
931 } | |
932 | |
58 | 933 |
1 | 934 static long |
935 rfc959_transfer_file (gftp_request *fromreq, const char *fromfile, | |
936 off_t fromsize, gftp_request *toreq, | |
937 const char *tofile, off_t tosize) | |
938 { | |
939 char *tempstr, *pos, *endpos; | |
84 | 940 int ret; |
1 | 941 |
84 | 942 g_return_val_if_fail (fromreq != NULL, GFTP_EFATAL); |
943 g_return_val_if_fail (fromfile != NULL, GFTP_EFATAL); | |
944 g_return_val_if_fail (toreq != NULL, GFTP_EFATAL); | |
945 g_return_val_if_fail (tofile != NULL, GFTP_EFATAL); | |
946 g_return_val_if_fail (fromreq->sockfd > 0, GFTP_EFATAL); | |
947 g_return_val_if_fail (toreq->sockfd > 0, GFTP_EFATAL); | |
1 | 948 |
122 | 949 gftp_set_request_option (fromreq, "passive_transfer", GINT_TO_POINTER(1)); |
950 gftp_set_request_option (toreq, "passive_transfer", GINT_TO_POINTER(0)); | |
1 | 951 |
84 | 952 if ((ret = rfc959_send_command (fromreq, "PASV\r\n")) != '2') |
953 return (ret); | |
1 | 954 |
955 pos = fromreq->last_ftp_response + 4; | |
956 while (!isdigit ((int) *pos) && *pos != '\0') | |
957 pos++; | |
958 if (*pos == '\0') | |
84 | 959 return (GFTP_EFATAL); |
1 | 960 |
961 endpos = pos; | |
962 while (*endpos != ')' && *endpos != '\0') | |
963 endpos++; | |
964 if (*endpos == ')') | |
965 *endpos = '\0'; | |
966 | |
967 tempstr = g_strconcat ("PORT ", pos, "\r\n", NULL); | |
84 | 968 if ((ret = rfc959_send_command (toreq, tempstr)) != '2') |
15
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
969 { |
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
970 g_free (tempstr); |
84 | 971 return (ret); |
15
82fabd6ef1c4
FXP fixes (from Tobias Gruetzmacher <tobias@portfolio16.de>)
masneyb
parents:
14
diff
changeset
|
972 } |
1 | 973 g_free (tempstr); |
974 | |
975 tempstr = g_strconcat ("RETR ", fromfile, "\r\n", NULL); | |
84 | 976 if ((ret = gftp_write (fromreq, tempstr, strlen (tempstr), |
977 fromreq->sockfd)) < 0) | |
58 | 978 { |
979 g_free (tempstr); | |
84 | 980 return (ret); |
58 | 981 } |
1 | 982 g_free (tempstr); |
983 | |
984 tempstr = g_strconcat ("STOR ", tofile, "\r\n", NULL); | |
84 | 985 if ((ret = gftp_write (toreq, tempstr, strlen (tempstr), toreq->sockfd)) < 0) |
58 | 986 { |
987 g_free (tempstr); | |
84 | 988 return (ret); |
58 | 989 } |
1 | 990 g_free (tempstr); |
991 | |
84 | 992 if ((ret = rfc959_read_response (fromreq)) < 0) |
993 return (ret); | |
994 | |
995 if ((ret = rfc959_read_response (toreq)) < 0) | |
996 return (ret); | |
1 | 997 |
998 return (0); | |
999 } | |
1000 | |
1001 | |
1002 static int | |
1003 rfc959_end_transfer (gftp_request * request) | |
1004 { | |
84 | 1005 int ret; |
1006 | |
1007 g_return_val_if_fail (request != NULL, GFTP_EFATAL); | |
1008 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1009 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1010 |
58 | 1011 if (request->datafd > 0) |
1 | 1012 { |
58 | 1013 close (request->datafd); |
1014 request->datafd = -1; | |
1 | 1015 } |
84 | 1016 |
1017 ret = rfc959_read_response (request); | |
1018 | |
1019 if (ret < 0) | |
1020 return (ret); | |
1021 else if (ret == '2') | |
1022 return (0); | |
1023 else | |
1024 return (GFTP_ERETRYABLE); | |
1 | 1025 } |
1026 | |
1027 | |
1028 static int | |
40 | 1029 rfc959_abort_transfer (gftp_request * request) |
1030 { | |
1031 int ret; | |
1032 | |
84 | 1033 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1034 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1035 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
40 | 1036 |
58 | 1037 if (request->datafd > 0) |
40 | 1038 { |
58 | 1039 close (request->datafd); |
1040 request->datafd = -1; | |
40 | 1041 } |
1042 | |
1043 /* We need to read two lines of output. The first one is acknowleging | |
1044 the transfer and the second line acknowleges the ABOR command */ | |
84 | 1045 if ((ret = rfc959_send_command (request, "ABOR\r\n")) < 0) |
1046 return (ret); | |
40 | 1047 |
58 | 1048 if (request->sockfd > 0) |
40 | 1049 { |
58 | 1050 if ((ret = rfc959_read_response (request)) < 0) |
40 | 1051 gftp_disconnect (request); |
1052 } | |
1053 | |
1054 return (0); | |
1055 } | |
1056 | |
1057 | |
1058 static int | |
1 | 1059 rfc959_list_files (gftp_request * request) |
1060 { | |
122 | 1061 int ret, show_hidden_files, resolve_symlinks, passive_transfer; |
1 | 1062 char *tempstr, parms[3]; |
1063 | |
84 | 1064 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1065 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1066 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1067 |
1068 if ((ret = rfc959_data_connection_new (request)) < 0) | |
1069 return (ret); | |
1070 | |
122 | 1071 gftp_lookup_request_option (request, "show_hidden_files", &show_hidden_files); |
1072 gftp_lookup_request_option (request, "resolve_symlinks", &resolve_symlinks); | |
1073 gftp_lookup_request_option (request, "passive_transfer", &passive_transfer); | |
1074 | |
1 | 1075 *parms = '\0'; |
1076 strcat (parms, show_hidden_files ? "a" : ""); | |
1077 strcat (parms, resolve_symlinks ? "L" : ""); | |
1078 tempstr = g_strconcat ("LIST", *parms != '\0' ? " -" : "", parms, "\r\n", | |
1079 NULL); | |
1080 | |
1081 ret = rfc959_send_command (request, tempstr); | |
1082 g_free (tempstr); | |
1083 | |
1084 if (ret != '1') | |
84 | 1085 return (GFTP_ERETRYABLE); |
1 | 1086 |
1087 ret = 0; | |
122 | 1088 if (!passive_transfer) |
1 | 1089 ret = rfc959_accept_active_connection (request); |
1090 | |
1091 return (ret); | |
1092 } | |
1093 | |
1094 | |
122 | 1095 static ssize_t |
1096 rfc959_get_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1097 { | |
1098 int i, j, ascii_transfers; | |
1099 ssize_t num_read; | |
1100 | |
1101 num_read = gftp_read (request, buf, size, request->datafd); | |
1102 if (num_read < 0) | |
1103 return (num_read); | |
1104 | |
1105 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); | |
1106 if (ascii_transfers) | |
1107 { | |
1108 for (i = 0, j = 0; i < num_read; i++) | |
1109 { | |
1110 if (buf[i] != '\r') | |
1111 buf[j++] = buf[i]; | |
1112 else | |
1113 num_read--; | |
1114 } | |
1115 } | |
1116 | |
1117 return (num_read); | |
1118 } | |
1119 | |
1120 | |
1121 static ssize_t | |
1122 rfc959_put_next_file_chunk (gftp_request * request, char *buf, size_t size) | |
1123 { | |
1124 int i, j, ascii_transfers; | |
1125 ssize_t num_wrote; | |
1126 char *tempstr; | |
1127 size_t rsize; | |
1128 | |
1129 if (size == 0) | |
1130 return (0); | |
1131 | |
1132 gftp_lookup_request_option (request, "ascii_transfers", &ascii_transfers); | |
1133 if (ascii_transfers) | |
1134 { | |
1135 rsize = 0; | |
1136 for (i = 0; i < size; i++) | |
1137 { | |
1138 rsize++; | |
1139 if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r') | |
1140 rsize++; | |
1141 } | |
1142 | |
1143 if (rsize != size) | |
1144 { | |
1145 tempstr = g_malloc (rsize); | |
1146 | |
1147 for (i = 0, j = 0; i < size; i++) | |
1148 { | |
1149 if (i > 0 && buf[i] == '\n' && buf[i - 1] != '\r') | |
1150 tempstr[j++] = '\r'; | |
1151 tempstr[j++] = buf[i]; | |
1152 } | |
1153 } | |
1154 else | |
1155 tempstr = buf; | |
1156 } | |
1157 else | |
1158 { | |
1159 rsize = size; | |
1160 tempstr = buf; | |
1161 } | |
1162 | |
1163 num_wrote = gftp_write (request, tempstr, rsize, request->datafd); | |
1164 | |
1165 if (tempstr != buf) | |
1166 g_free (tempstr); | |
1167 | |
1168 return (num_wrote); | |
1169 } | |
1170 | |
1171 | |
1 | 1172 int |
58 | 1173 rfc959_get_next_file (gftp_request * request, gftp_file * fle, int fd) |
1 | 1174 { |
58 | 1175 rfc959_parms * parms; |
1 | 1176 char tempstr[255]; |
58 | 1177 ssize_t len; |
1 | 1178 |
84 | 1179 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1180 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1181 g_return_val_if_fail (fle != NULL, GFTP_EFATAL); | |
1182 g_return_val_if_fail (fd > 0, GFTP_EFATAL); | |
1 | 1183 |
1184 if (request->last_dir_entry) | |
1185 { | |
1186 g_free (request->last_dir_entry); | |
1187 request->last_dir_entry = NULL; | |
1188 } | |
58 | 1189 |
1190 parms = request->protocol_data; | |
1191 | |
1 | 1192 do |
1193 { | |
58 | 1194 if ((len = gftp_get_line (request, &parms->datafd_rbuf, |
60 | 1195 tempstr, sizeof (tempstr), fd)) <= 0) |
1 | 1196 { |
1197 gftp_file_destroy (fle); | |
58 | 1198 return ((int) len); |
1 | 1199 } |
1200 | |
91 | 1201 if (gftp_parse_ls (request, tempstr, fle) != 0) |
1 | 1202 { |
58 | 1203 if (strncmp (tempstr, "total", strlen ("total")) != 0 && |
1204 strncmp (tempstr, _("total"), strlen (_("total"))) != 0) | |
1205 request->logging_function (gftp_logging_error, request->user_data, | |
1 | 1206 _("Warning: Cannot parse listing %s\n"), |
1207 tempstr); | |
1208 gftp_file_destroy (fle); | |
1209 continue; | |
1210 } | |
1211 else | |
1212 break; | |
1213 } | |
1214 while (1); | |
1215 | |
1216 len = strlen (tempstr); | |
1217 if (!request->cached) | |
1218 { | |
60 | 1219 request->last_dir_entry = g_strdup_printf ("%s\n", tempstr); |
1220 request->last_dir_entry_len = len + 1; | |
1 | 1221 } |
1222 return (len); | |
1223 } | |
1224 | |
1225 | |
1226 static off_t | |
1227 rfc959_get_file_size (gftp_request * request, const char *filename) | |
1228 { | |
1229 char *tempstr; | |
1230 int ret; | |
1231 | |
1232 g_return_val_if_fail (request != NULL, 0); | |
84 | 1233 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); |
1 | 1234 g_return_val_if_fail (filename != NULL, 0); |
58 | 1235 g_return_val_if_fail (request->sockfd > 0, 0); |
1 | 1236 |
1237 tempstr = g_strconcat ("SIZE ", filename, "\r\n", NULL); | |
1238 ret = rfc959_send_command (request, tempstr); | |
1239 g_free (tempstr); | |
1240 if (ret < 0) | |
84 | 1241 return (ret); |
1 | 1242 |
1243 if (*request->last_ftp_response != '2') | |
1244 return (0); | |
1245 return (strtol (request->last_ftp_response + 4, NULL, 10)); | |
1246 } | |
1247 | |
1248 | |
1249 static int | |
1250 rfc959_rmdir (gftp_request * request, const char *directory) | |
1251 { | |
1252 char *tempstr, ret; | |
1253 | |
84 | 1254 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1255 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1256 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
1257 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1258 |
1259 tempstr = g_strconcat ("RMD ", directory, "\r\n", NULL); | |
1260 ret = rfc959_send_command (request, tempstr); | |
1261 g_free (tempstr); | |
84 | 1262 |
1263 if (ret < 0) | |
1264 return (ret); | |
1265 else if (ret == '2') | |
1266 return (0); | |
1267 else | |
1268 return (GFTP_ERETRYABLE); | |
1 | 1269 } |
1270 | |
1271 | |
1272 static int | |
1273 rfc959_rmfile (gftp_request * request, const char *file) | |
1274 { | |
1275 char *tempstr, ret; | |
1276 | |
84 | 1277 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1278 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1279 g_return_val_if_fail (file != NULL, GFTP_EFATAL); | |
1280 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1281 |
1282 tempstr = g_strconcat ("DELE ", file, "\r\n", NULL); | |
1283 ret = rfc959_send_command (request, tempstr); | |
1284 g_free (tempstr); | |
84 | 1285 |
1286 if (ret < 0) | |
1287 return (ret); | |
1288 else if (ret == '2') | |
1289 return (0); | |
1290 else | |
1291 return (GFTP_ERETRYABLE); | |
1 | 1292 } |
1293 | |
1294 | |
1295 static int | |
1296 rfc959_mkdir (gftp_request * request, const char *directory) | |
1297 { | |
1298 char *tempstr, ret; | |
1299 | |
84 | 1300 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1301 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1302 g_return_val_if_fail (directory != NULL, GFTP_EFATAL); | |
1303 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1304 |
1305 tempstr = g_strconcat ("MKD ", directory, "\r\n", NULL); | |
1306 ret = rfc959_send_command (request, tempstr); | |
1307 g_free (tempstr); | |
84 | 1308 |
1309 if (ret < 0) | |
1310 return (ret); | |
1311 else if (ret == '2') | |
1312 return (0); | |
1313 else | |
1314 return (GFTP_ERETRYABLE); | |
1 | 1315 } |
1316 | |
1317 | |
1318 static int | |
1319 rfc959_rename (gftp_request * request, const char *oldname, | |
1320 const char *newname) | |
1321 { | |
1322 char *tempstr, ret; | |
1323 | |
84 | 1324 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1325 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1326 g_return_val_if_fail (oldname != NULL, GFTP_EFATAL); | |
1327 g_return_val_if_fail (newname != NULL, GFTP_EFATAL); | |
1328 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1329 |
1330 tempstr = g_strconcat ("RNFR ", oldname, "\r\n", NULL); | |
1331 ret = rfc959_send_command (request, tempstr); | |
1332 g_free (tempstr); | |
84 | 1333 |
1334 if (ret < 0) | |
1335 return (ret); | |
1336 else if (ret != '2') | |
1337 return (GFTP_ERETRYABLE); | |
1 | 1338 |
1339 tempstr = g_strconcat ("RNTO ", newname, "\r\n", NULL); | |
1340 ret = rfc959_send_command (request, tempstr); | |
1341 g_free (tempstr); | |
84 | 1342 |
1343 if (ret < 0) | |
1344 return (ret); | |
1345 else if (ret == '2') | |
1346 return (0); | |
1347 else | |
1348 return (GFTP_ERETRYABLE); | |
1 | 1349 } |
1350 | |
1351 | |
1352 static int | |
1353 rfc959_chmod (gftp_request * request, const char *file, int mode) | |
1354 { | |
1355 char *tempstr, ret; | |
1356 | |
84 | 1357 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1358 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1359 g_return_val_if_fail (file != NULL, GFTP_EFATAL); | |
1360 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1361 |
1362 tempstr = g_malloc (strlen (file) + (mode / 10) + 16); | |
1363 sprintf (tempstr, "SITE CHMOD %d %s\r\n", mode, file); | |
1364 ret = rfc959_send_command (request, tempstr); | |
1365 g_free (tempstr); | |
84 | 1366 |
1367 if (ret < 0) | |
1368 return (ret); | |
1369 else if (ret == '2') | |
1370 return (0); | |
1371 else | |
1372 return (GFTP_ERETRYABLE); | |
1 | 1373 } |
1374 | |
1375 | |
1376 static int | |
1377 rfc959_site (gftp_request * request, const char *command) | |
1378 { | |
1379 char *tempstr, ret; | |
1380 | |
84 | 1381 g_return_val_if_fail (request != NULL, GFTP_EFATAL); |
1382 g_return_val_if_fail (request->protonum == GFTP_FTP_NUM, GFTP_EFATAL); | |
1383 g_return_val_if_fail (command != NULL, GFTP_EFATAL); | |
1384 g_return_val_if_fail (request->sockfd > 0, GFTP_EFATAL); | |
1 | 1385 |
1386 tempstr = g_strconcat ("SITE ", command, "\r\n", NULL); | |
1387 ret = rfc959_send_command (request, tempstr); | |
1388 g_free (tempstr); | |
84 | 1389 |
1390 if (ret < 0) | |
1391 return (ret); | |
1392 else if (ret == '2') | |
1393 return (0); | |
1394 else | |
1395 return (GFTP_ERETRYABLE); | |
58 | 1396 } |
1397 | |
1398 | |
1399 static void | |
1400 rfc959_set_config_options (gftp_request * request) | |
1401 { | |
122 | 1402 char *proxy_config; |
58 | 1403 |
122 | 1404 gftp_lookup_request_option (request, "proxy_config", &proxy_config); |
1405 if (strcmp (proxy_config, "http") == 0) | |
58 | 1406 { |
122 | 1407 gftp_protocols[GFTP_HTTP_NUM].init (request); |
1408 gftp_set_request_option (request, "proxy_config", "ftp"); | |
58 | 1409 } |
122 | 1410 } |
58 | 1411 |
1412 | |
122 | 1413 void |
1414 rfc959_register_module (void) | |
1415 { | |
1416 struct hostent *hent; | |
1417 struct utsname unme; | |
1418 struct passwd *pw; | |
1419 char *tempstr; | |
1420 | |
1421 gftp_register_config_vars (config_vars); | |
1422 | |
1423 gftp_lookup_global_option ("email", &tempstr); | |
1424 if (tempstr == NULL || *tempstr == '\0') | |
1425 { | |
1426 /* If there is no email address specified, then we'll just use the | |
1427 currentuser@currenthost */ | |
1428 uname (&unme); | |
1429 pw = getpwuid (geteuid ()); | |
1430 hent = gethostbyname (unme.nodename); | |
1431 if (strchr (unme.nodename, '.') == NULL && hent != NULL) | |
1432 tempstr = g_strconcat (pw->pw_name, "@", hent->h_name, NULL); | |
1433 else | |
1434 tempstr = g_strconcat (pw->pw_name, "@", unme.nodename, NULL); | |
1435 gftp_set_global_option ("email", tempstr); | |
58 | 1436 } |
1 | 1437 } |
1438 | |
1439 | |
48 | 1440 void |
1441 rfc959_init (gftp_request * request) | |
1 | 1442 { |
48 | 1443 g_return_if_fail (request != NULL); |
1 | 1444 |
48 | 1445 request->protonum = GFTP_FTP_NUM; |
1446 request->init = rfc959_init; | |
1447 request->destroy = NULL; | |
1448 request->connect = rfc959_connect; | |
1449 request->disconnect = rfc959_disconnect; | |
1450 request->get_file = rfc959_get_file; | |
1451 request->put_file = rfc959_put_file; | |
1452 request->transfer_file = rfc959_transfer_file; | |
122 | 1453 request->get_next_file_chunk = rfc959_get_next_file_chunk; |
1454 request->put_next_file_chunk = rfc959_put_next_file_chunk; | |
48 | 1455 request->end_transfer = rfc959_end_transfer; |
1456 request->abort_transfer = rfc959_abort_transfer; | |
1457 request->list_files = rfc959_list_files; | |
1458 request->get_next_file = rfc959_get_next_file; | |
1459 request->get_file_size = rfc959_get_file_size; | |
1460 request->chdir = rfc959_chdir; | |
1461 request->rmdir = rfc959_rmdir; | |
1462 request->rmfile = rfc959_rmfile; | |
1463 request->mkdir = rfc959_mkdir; | |
1464 request->rename = rfc959_rename; | |
1465 request->chmod = rfc959_chmod; | |
1466 request->set_file_time = NULL; | |
1467 request->site = rfc959_site; | |
1468 request->parse_url = NULL; | |
63 | 1469 request->swap_socks = NULL; |
58 | 1470 request->set_config_options = rfc959_set_config_options; |
48 | 1471 request->url_prefix = "ftp"; |
1472 request->need_hostport = 1; | |
1473 request->need_userpass = 1; | |
1474 request->use_cache = 1; | |
1475 request->use_threads = 1; | |
1476 request->always_connected = 0; | |
58 | 1477 request->protocol_data = g_malloc0 (sizeof (rfc959_parms)); |
48 | 1478 gftp_set_config_options (request); |
1 | 1479 } |
1480 |