iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / protocol / ftp / ftp.c
blobdd7dd105d6096c3dcde81643cd8034f9dd950568
1 /* Internal "ftp" protocol implementation */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/stat.h> /* For converting permissions to strings */
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_SOCKET_H
15 #include <sys/socket.h>
16 #endif
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
22 #endif
24 /* We need to have it here. Stupid BSD. */
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h>
27 #endif
28 #ifdef HAVE_ARPA_INET_H
29 #include <arpa/inet.h>
30 #endif
32 #include "elinks.h"
34 #include "cache/cache.h"
35 #include "config/options.h"
36 #include "intl/gettext/libintl.h"
37 #include "main/select.h"
38 #include "main/module.h"
39 #include "network/connection.h"
40 #include "network/progress.h"
41 #include "network/socket.h"
42 #include "osdep/osdep.h"
43 #include "osdep/stat.h"
44 #include "protocol/auth/auth.h"
45 #include "protocol/common.h"
46 #include "protocol/ftp/ftp.h"
47 #include "protocol/ftp/parse.h"
48 #include "protocol/uri.h"
49 #include "util/conv.h"
50 #include "util/error.h"
51 #include "util/memory.h"
52 #include "util/string.h"
55 union option_info ftp_options[] = {
56 INIT_OPT_TREE("protocol", N_("FTP"),
57 "ftp", 0,
58 N_("FTP specific options.")),
60 INIT_OPT_TREE("protocol.ftp", N_("Proxy configuration"),
61 "proxy", 0,
62 N_("FTP proxy configuration.")),
64 INIT_OPT_STRING("protocol.ftp.proxy", N_("Host and port-number"),
65 "host", 0, "",
66 N_("Host and port-number (host:port) of the FTP proxy, "
67 "or blank. If it's blank, FTP_PROXY environment variable "
68 "is checked as well.")),
70 INIT_OPT_STRING("protocol.ftp", N_("Anonymous password"),
71 "anon_passwd", 0, "some@host.domain",
72 N_("FTP anonymous password to be sent.")),
74 INIT_OPT_BOOL("protocol.ftp", N_("Use passive mode (IPv4)"),
75 "use_pasv", 0, 1,
76 N_("Use PASV instead of PORT (passive vs active mode, "
77 "IPv4 only).")),
78 #ifdef CONFIG_IPV6
79 INIT_OPT_BOOL("protocol.ftp", N_("Use passive mode (IPv6)"),
80 "use_epsv", 0, 0,
81 N_("Use EPSV instead of EPRT (passive vs active mode, "
82 "IPv6 only).")),
83 #endif /* CONFIG_IPV6 */
84 NULL_OPTION_INFO,
88 struct module ftp_protocol_module = struct_module(
89 /* name: */ N_("FTP"),
90 /* options: */ ftp_options,
91 /* hooks: */ NULL,
92 /* submodules: */ NULL,
93 /* data: */ NULL,
94 /* init: */ NULL,
95 /* done: */ NULL
99 /* Constants */
101 #define FTP_BUF_SIZE 16384
104 /* Types and structs */
106 struct ftp_connection_info {
107 int pending_commands; /* Num of commands queued */
108 int opc; /* Total num of commands queued */
109 int conn_state;
110 int buf_pos;
112 unsigned int dir:1; /* Directory listing in progress */
113 unsigned int rest_sent:1; /* Sent RESTore command */
114 unsigned int use_pasv:1; /* Use PASV (yes or no) */
115 #ifdef CONFIG_IPV6
116 unsigned int use_epsv:1; /* Use EPSV */
117 #endif
118 unsigned char ftp_buffer[FTP_BUF_SIZE];
119 unsigned char cmd_buffer[1]; /* Must be last field !! */
123 /* Prototypes */
124 static void ftp_login(struct socket *);
125 static void ftp_send_retr_req(struct connection *, struct connection_state);
126 static void ftp_got_info(struct socket *, struct read_buffer *);
127 static void ftp_got_user_info(struct socket *, struct read_buffer *);
128 static void ftp_pass(struct connection *);
129 static void ftp_pass_info(struct socket *, struct read_buffer *);
130 static void ftp_retr_file(struct socket *, struct read_buffer *);
131 static void ftp_got_final_response(struct socket *, struct read_buffer *);
132 static void got_something_from_data_connection(struct connection *);
133 static void ftp_end_request(struct connection *, struct connection_state);
134 static struct ftp_connection_info *add_file_cmd_to_str(struct connection *);
135 static void ftp_data_accept(struct connection *conn);
137 /* Parse EPSV or PASV response for address and/or port.
138 * int *n should point to a sizeof(int) * 6 space.
139 * It returns zero on error or count of parsed numbers.
140 * It returns an error if:
141 * - there's more than 6 or less than 1 numbers.
142 * - a number is strictly greater than max.
144 * On success, array of integers *n is filled with numbers starting
145 * from end of array (ie. if we found one number, you can access it using
146 * n[5]).
148 * Important:
149 * Negative numbers aren't handled so -123 is taken as 123.
150 * We don't take care about separators.
152 static int
153 parse_psv_resp(unsigned char *data, int *n, int max_value)
155 unsigned char *p = data;
156 int i = 5;
158 memset(n, 0, 6 * sizeof(*n));
160 if (*p < ' ') return 0;
162 /* Find the end. */
163 while (*p >= ' ') p++;
165 /* Ignore non-numeric ending chars. */
166 while (p != data && !isdigit(*p)) p--;
167 if (p == data) return 0;
169 while (i >= 0) {
170 int x = 1;
172 /* Parse one number. */
173 while (p != data && isdigit(*p)) {
174 n[i] += (*p - '0') * x;
175 if (n[i] > max_value) return 0;
176 x *= 10;
177 p--;
179 /* Ignore non-numeric chars. */
180 while (p != data && !isdigit(*p)) p--;
181 if (p == data) return (6 - i);
182 /* Get the next one. */
183 i--;
186 return 0;
189 /* Returns 0 if there's no numeric response, -1 if error, the positive response
190 * number otherwise. */
191 static int
192 get_ftp_response(struct connection *conn, struct read_buffer *rb, int part,
193 struct sockaddr_storage *sa, off_t *est_length)
195 unsigned char *eol;
196 unsigned char *num_end;
197 int response;
198 int pos;
200 again:
201 eol = memchr(rb->data, ASCII_LF, rb->length);
202 if (!eol) return 0;
204 pos = eol - rb->data;
206 errno = 0;
207 response = strtoul(rb->data, (char **) &num_end, 10);
209 if (errno || num_end != rb->data + 3 || response < 100)
210 return -1;
212 if (sa && response == 227) { /* PASV response parsing. */
213 struct sockaddr_in *s = (struct sockaddr_in *) sa;
214 int n[6];
216 if (parse_psv_resp(num_end, (int *) &n, 255) != 6)
217 return -1;
219 memset(s, 0, sizeof(*s));
220 s->sin_family = AF_INET;
221 s->sin_addr.s_addr = htonl((n[0] << 24) + (n[1] << 16) + (n[2] << 8) + n[3]);
222 s->sin_port = htons((n[4] << 8) + n[5]);
225 #ifdef CONFIG_IPV6
226 if (sa && response == 229) { /* EPSV response parsing. */
227 /* See RFC 2428 */
228 struct sockaddr_in6 *s = (struct sockaddr_in6 *) sa;
229 int sal = sizeof(*s);
230 int n[6];
232 if (parse_psv_resp(num_end, (int *) &n, 65535) != 1) {
233 return -1;
236 memset(s, 0, sizeof(*s));
237 if (getpeername(conn->socket->fd, (struct sockaddr *) sa, &sal)) {
238 return -1;
240 s->sin6_family = AF_INET6;
241 s->sin6_port = htons(n[5]);
243 #endif
245 if (*num_end == '-') {
246 int i;
248 for (i = 0; i < rb->length - 5; i++)
249 if (rb->data[i] == ASCII_LF
250 && !memcmp(rb->data+i+1, rb->data, 3)
251 && rb->data[i+4] == ' ') {
252 for (i++; i < rb->length; i++)
253 if (rb->data[i] == ASCII_LF)
254 goto ok;
255 return 0;
257 return 0;
259 pos = i;
262 if (response == 213 && est_length) {
263 off_t size = strtoull(num_end + 1, NULL, 10);
264 if (errno) {
265 return -1;
267 *est_length = size;
270 if (part != 2)
271 kill_buffer_data(rb, pos + 1);
273 if (!part && response >= 100 && response < 200) {
274 goto again;
277 return response;
281 /* Initialize or continue ftp connection. */
282 void
283 ftp_protocol_handler(struct connection *conn)
285 if (!has_keepalive_connection(conn)) {
286 make_connection(conn->socket, conn->uri, ftp_login,
287 conn->cache_mode >= CACHE_MODE_FORCE_RELOAD);
289 } else {
290 ftp_send_retr_req(conn, connection_state(S_SENT));
294 /* Send command, set connection state and free cmd string. */
295 static void
296 send_cmd(struct connection *conn, struct string *cmd, void *callback,
297 struct connection_state state)
299 request_from_socket(conn->socket, cmd->source, cmd->length, state,
300 SOCKET_RETRY_ONCLOSE, callback);
302 done_string(cmd);
305 /* Check if this auth token really belongs to this URI. */
306 static int
307 auth_user_matching_uri(struct auth_entry *auth, struct uri *uri)
309 if (!uri->userlen) /* Noone said it doesn't. */
310 return 1;
311 return !c_strlcasecmp(auth->user, -1, uri->user, uri->userlen);
315 /* Kill the current connection and ask for a username/password for the next
316 * try. */
317 static void
318 prompt_username_pw(struct connection *conn)
320 if (!conn->cached) {
321 conn->cached = get_cache_entry(conn->uri);
322 if (!conn->cached) {
323 abort_connection(conn, connection_state(S_OUT_OF_MEM));
324 return;
328 mem_free_set(&conn->cached->content_type, stracpy("text/html"));
329 if (!conn->cached->content_type) {
330 abort_connection(conn, connection_state(S_OUT_OF_MEM));
331 return;
334 add_auth_entry(conn->uri, "FTP Login", NULL, NULL, 0);
336 abort_connection(conn, connection_state(S_OK));
339 /* Send USER command. */
340 static void
341 ftp_login(struct socket *socket)
343 struct connection *conn = socket->conn;
344 struct string cmd;
345 struct auth_entry* auth;
347 auth = find_auth(conn->uri);
349 if (!init_string(&cmd)) {
350 abort_connection(conn, connection_state(S_OUT_OF_MEM));
351 return;
354 add_to_string(&cmd, "USER ");
355 if (conn->uri->userlen) {
356 struct uri *uri = conn->uri;
358 add_bytes_to_string(&cmd, uri->user, uri->userlen);
360 } else if (auth && auth->valid) {
361 add_to_string(&cmd, auth->user);
363 } else {
364 add_to_string(&cmd, "anonymous");
366 add_crlf_to_string(&cmd);
368 send_cmd(conn, &cmd, (void *) ftp_got_info, connection_state(S_SENT));
371 /* Parse connection response. */
372 static void
373 ftp_got_info(struct socket *socket, struct read_buffer *rb)
375 struct connection *conn = socket->conn;
376 int response = get_ftp_response(conn, rb, 0, NULL, NULL);
378 if (response == -1) {
379 abort_connection(conn, connection_state(S_FTP_ERROR));
380 return;
383 if (!response) {
384 read_from_socket(conn->socket, rb, conn->state, ftp_got_info);
385 return;
388 /* RFC959 says that possible response codes on connection are:
389 * 120 Service ready in nnn minutes.
390 * 220 Service ready for new user.
391 * 421 Service not available, closing control connection. */
393 if (response != 220) {
394 /* TODO? Retry in case of ... ?? */
395 retry_connection(conn, connection_state(S_FTP_UNAVAIL));
396 return;
399 ftp_got_user_info(socket, rb);
403 /* Parse USER response and send PASS command if needed. */
404 static void
405 ftp_got_user_info(struct socket *socket, struct read_buffer *rb)
407 struct connection *conn = socket->conn;
408 int response = get_ftp_response(conn, rb, 0, NULL, NULL);
410 if (response == -1) {
411 abort_connection(conn, connection_state(S_FTP_ERROR));
412 return;
415 if (!response) {
416 read_from_socket(conn->socket, rb, conn->state, ftp_got_user_info);
417 return;
420 /* RFC959 says that possible response codes for USER are:
421 * 230 User logged in, proceed.
422 * 331 User name okay, need password.
423 * 332 Need account for login.
424 * 421 Service not available, closing control connection.
425 * 500 Syntax error, command unrecognized.
426 * 501 Syntax error in parameters or arguments.
427 * 530 Not logged in. */
429 /* FIXME? Since ACCT command isn't implemented, login to a ftp server
430 * requiring it will fail (332). */
432 if (response == 332 || response >= 500) {
433 prompt_username_pw(conn);
434 return;
437 /* We don't require exact match here, as this is always error and some
438 * non-RFC compliant servers may return even something other than 421.
439 * --Zas */
440 if (response >= 400) {
441 abort_connection(conn, connection_state(S_FTP_UNAVAIL));
442 return;
445 if (response == 230) {
446 ftp_send_retr_req(conn, connection_state(S_GETH));
447 return;
450 ftp_pass(conn);
453 /* Send PASS command. */
454 static void
455 ftp_pass(struct connection *conn)
457 struct string cmd;
458 struct auth_entry *auth;
460 auth = find_auth(conn->uri);
462 if (!init_string(&cmd)) {
463 abort_connection(conn, connection_state(S_OUT_OF_MEM));
464 return;
467 add_to_string(&cmd, "PASS ");
468 if (conn->uri->passwordlen) {
469 struct uri *uri = conn->uri;
471 add_bytes_to_string(&cmd, uri->password, uri->passwordlen);
473 } else if (auth && auth->valid) {
474 if (!auth_user_matching_uri(auth, conn->uri)) {
475 prompt_username_pw(conn);
476 return;
478 add_to_string(&cmd, auth->password);
480 } else {
481 add_to_string(&cmd, get_opt_str("protocol.ftp.anon_passwd",
482 NULL));
484 add_crlf_to_string(&cmd);
486 send_cmd(conn, &cmd, (void *) ftp_pass_info, connection_state(S_LOGIN));
489 /* Parse PASS command response. */
490 static void
491 ftp_pass_info(struct socket *socket, struct read_buffer *rb)
493 struct connection *conn = socket->conn;
494 int response = get_ftp_response(conn, rb, 0, NULL, NULL);
496 if (response == -1) {
497 abort_connection(conn, connection_state(S_FTP_ERROR));
498 return;
501 if (!response) {
502 read_from_socket(conn->socket, rb, connection_state(S_LOGIN),
503 ftp_pass_info);
504 return;
507 /* RFC959 says that possible response codes for PASS are:
508 * 202 Command not implemented, superfluous at this site.
509 * 230 User logged in, proceed.
510 * 332 Need account for login.
511 * 421 Service not available, closing control connection.
512 * 500 Syntax error, command unrecognized.
513 * 501 Syntax error in parameters or arguments.
514 * 503 Bad sequence of commands.
515 * 530 Not logged in. */
517 if (response == 332 || response >= 500) {
518 /* If we didn't have a user, we tried anonymous. But it failed, so ask for a
519 * user and password */
520 prompt_username_pw(conn);
521 return;
524 if (response >= 400) {
525 abort_connection(conn, connection_state(S_FTP_UNAVAIL));
526 return;
529 ftp_send_retr_req(conn, connection_state(S_GETH));
532 /* Construct PORT command. */
533 static void
534 add_portcmd_to_string(struct string *string, unsigned char *pc)
536 /* From RFC 959: DATA PORT (PORT)
538 * The argument is a HOST-PORT specification for the data port
539 * to be used in data connection. There are defaults for both
540 * the user and server data ports, and under normal
541 * circumstances this command and its reply are not needed. If
542 * this command is used, the argument is the concatenation of a
543 * 32-bit internet host address and a 16-bit TCP port address.
544 * This address information is broken into 8-bit fields and the
545 * value of each field is transmitted as a decimal number (in
546 * character string representation). The fields are separated
547 * by commas. A port command would be:
549 * PORT h1,h2,h3,h4,p1,p2
551 * where h1 is the high order 8 bits of the internet host
552 * address. */
553 add_to_string(string, "PORT ");
554 add_long_to_string(string, pc[0]);
555 add_char_to_string(string, ',');
556 add_long_to_string(string, pc[1]);
557 add_char_to_string(string, ',');
558 add_long_to_string(string, pc[2]);
559 add_char_to_string(string, ',');
560 add_long_to_string(string, pc[3]);
561 add_char_to_string(string, ',');
562 add_long_to_string(string, pc[4]);
563 add_char_to_string(string, ',');
564 add_long_to_string(string, pc[5]);
567 #ifdef CONFIG_IPV6
568 /* Construct EPRT command. */
569 static void
570 add_eprtcmd_to_string(struct string *string, struct sockaddr_in6 *addr)
572 unsigned char addr_str[INET6_ADDRSTRLEN];
574 inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
576 /* From RFC 2428: EPRT
578 * The format of EPRT is:
580 * EPRT<space><d><net-prt><d><net-addr><d><tcp-port><d>
582 * <net-prt>:
583 * AF Number Protocol
584 * --------- --------
585 * 1 Internet Protocol, Version 4 [Pos81a]
586 * 2 Internet Protocol, Version 6 [DH96] */
587 add_to_string(string, "EPRT |2|");
588 add_to_string(string, addr_str);
589 add_char_to_string(string, '|');
590 add_long_to_string(string, ntohs(addr->sin6_port));
591 add_char_to_string(string, '|');
593 #endif
595 /* Depending on options, get proper ftp data socket and command.
596 * It appends ftp command (either PASV,PORT,EPSV or EPRT) to @command
597 * string.
598 * When PORT or EPRT are used, related sockets are created.
599 * It returns 0 on error (data socket creation failure). */
600 static int
601 get_ftp_data_socket(struct connection *conn, struct string *command)
603 struct ftp_connection_info *ftp = conn->info;
605 ftp->use_pasv = get_opt_bool("protocol.ftp.use_pasv", NULL);
607 #ifdef CONFIG_IPV6
608 ftp->use_epsv = get_opt_bool("protocol.ftp.use_epsv", NULL);
610 if (conn->socket->protocol_family == EL_PF_INET6) {
611 if (ftp->use_epsv) {
612 add_to_string(command, "EPSV");
614 } else {
615 struct sockaddr_storage data_addr;
616 int data_sock;
618 memset(&data_addr, 0, sizeof(data_addr));
619 data_sock = get_pasv_socket(conn->socket, &data_addr);
620 if (data_sock < 0) return 0;
622 conn->data_socket->fd = data_sock;
623 add_eprtcmd_to_string(command,
624 (struct sockaddr_in6 *) &data_addr);
627 } else
628 #endif
630 if (ftp->use_pasv) {
631 add_to_string(command, "PASV");
633 } else {
634 struct sockaddr_in sa;
635 unsigned char pc[6];
636 int data_sock;
638 memset(pc, 0, sizeof(pc));
639 data_sock = get_pasv_socket(conn->socket,
640 (struct sockaddr_storage *) &sa);
641 if (data_sock < 0) return 0;
643 memcpy(pc, &sa.sin_addr.s_addr, 4);
644 memcpy(pc + 4, &sa.sin_port, 2);
645 conn->data_socket->fd = data_sock;
646 add_portcmd_to_string(command, pc);
650 add_crlf_to_string(command);
652 return 1;
655 /* Check if the file or directory name @s can be safely sent to the
656 * FTP server. To prevent command injection attacks, this function
657 * must reject CR LF sequences. */
658 static int
659 is_ftp_pathname_safe(const struct string *s)
661 int i;
663 /* RFC 959 says the argument of CWD and RETR is a <pathname>,
664 * which consists of <char>s, "any of the 128 ASCII characters
665 * except <CR> and <LF>". So other control characters, such
666 * as 0x00 and 0x7F, are allowed here. Bytes 0x80...0xFF
667 * should not be allowed, but if we reject them, users will
668 * probably complain. */
669 for (i = 0; i < s->length; i++) {
670 if (s->source[i] == 0x0A || s->source[i] == 0x0D)
671 return 0;
673 return 1;
676 /* Create passive socket and add appropriate announcing commands to str. Then
677 * go and retrieve appropriate object from server.
678 * Returns NULL if error. */
679 static struct ftp_connection_info *
680 add_file_cmd_to_str(struct connection *conn)
682 int ok = 0;
683 struct ftp_connection_info *ftp = NULL;
684 struct string command = NULL_STRING;
685 struct string ftp_data_command = NULL_STRING;
686 struct string pathname = NULL_STRING;
688 if (!conn->uri->data) {
689 INTERNAL("conn->uri->data empty");
690 abort_connection(conn, connection_state(S_INTERNAL));
691 goto ret;
694 assert(conn->info == NULL);
695 assert(conn->done == NULL);
696 if_assert_failed {
697 abort_connection(conn, connection_state(S_INTERNAL));
698 goto ret;
701 /* This will be reallocated below when we know how long the
702 * command string should be. Error handling could be
703 * simplified a little by allocating this initial structure on
704 * the stack, but it's several kilobytes long so that might be
705 * risky. */
706 ftp = mem_calloc(1, sizeof(*ftp));
707 if (!ftp) {
708 abort_connection(conn, connection_state(S_OUT_OF_MEM));
709 goto ret;
712 /* conn->info and conn->done were asserted as NULL above. */
713 conn->info = ftp; /* Freed when connection is destroyed. */
715 if (!init_string(&command)
716 || !init_string(&ftp_data_command)
717 || !init_string(&pathname)) {
718 abort_connection(conn, connection_state(S_OUT_OF_MEM));
719 goto ret;
722 if (!get_ftp_data_socket(conn, &ftp_data_command)) {
723 INTERNAL("Ftp data socket failure");
724 abort_connection(conn, connection_state(S_INTERNAL));
725 goto ret;
728 if (!add_uri_to_string(&pathname, conn->uri, URI_PATH)) {
729 abort_connection(conn, connection_state(S_OUT_OF_MEM));
730 goto ret;
733 decode_uri_string(&pathname);
734 if (!is_ftp_pathname_safe(&pathname)) {
735 abort_connection(conn, connection_state(S_BAD_URL));
736 goto ret;
739 if (!conn->uri->datalen
740 || conn->uri->data[conn->uri->datalen - 1] == '/') {
741 /* Commands to get directory listing. */
743 ftp->dir = 1;
744 ftp->pending_commands = 4;
746 if (!add_to_string(&command, "TYPE A") /* ASCII */
747 || !add_crlf_to_string(&command)
749 || !add_string_to_string(&command, &ftp_data_command)
751 || !add_to_string(&command, "CWD ")
752 || !add_string_to_string(&command, &pathname)
753 || !add_crlf_to_string(&command)
755 || !add_to_string(&command, "LIST")
756 || !add_crlf_to_string(&command)) {
757 abort_connection(conn, connection_state(S_OUT_OF_MEM));
758 goto ret;
761 conn->from = 0;
763 } else {
764 /* Commands to get a file. */
766 ftp->dir = 0;
767 ftp->pending_commands = 4;
769 if (!add_to_string(&command, "TYPE I") /* BINARY */
770 || !add_crlf_to_string(&command)
772 || !add_string_to_string(&command, &ftp_data_command)) {
773 abort_connection(conn, connection_state(S_OUT_OF_MEM));
774 goto ret;
777 if (conn->from || conn->progress->start > 0) {
778 const off_t offset = conn->from
779 ? conn->from
780 : conn->progress->start;
782 if (!add_to_string(&command, "REST ")
783 || !add_long_to_string(&command, offset)
784 || !add_crlf_to_string(&command)) {
785 abort_connection(conn, connection_state(S_OUT_OF_MEM));
786 goto ret;
789 ftp->rest_sent = 1;
790 ftp->pending_commands++;
793 if (!add_to_string(&command, "SIZE ")
794 || !add_string_to_string(&command, &pathname)
795 || !add_crlf_to_string(&command)) {
796 abort_connection(conn, connection_state(S_OUT_OF_MEM));
797 goto ret;
800 if (!add_to_string(&command, "RETR ")
801 || !add_string_to_string(&command, &pathname)
802 || !add_crlf_to_string(&command)) {
803 abort_connection(conn, connection_state(S_OUT_OF_MEM));
804 goto ret;
808 ftp->opc = ftp->pending_commands;
810 /* 1 byte is already reserved for cmd_buffer in struct ftp_connection_info. */
811 ftp = mem_realloc(ftp, sizeof(*ftp) + command.length);
812 if (!ftp) {
813 abort_connection(conn, connection_state(S_OUT_OF_MEM));
814 goto ret;
816 conn->info = ftp; /* in case mem_realloc moved the buffer */
818 memcpy(ftp->cmd_buffer, command.source, command.length + 1);
819 ok = 1;
821 ret:
822 /* If @ok is false here, then abort_connection has already
823 * freed @ftp, which now is a dangling pointer. */
824 done_string(&pathname);
825 done_string(&ftp_data_command);
826 done_string(&command);
827 return ok ? ftp : NULL;
830 static void
831 send_it_line_by_line(struct connection *conn, struct string *cmd)
833 struct ftp_connection_info *ftp = conn->info;
834 unsigned char *nl = strchr(ftp->cmd_buffer, '\n');
836 if (!nl) {
837 add_to_string(cmd, ftp->cmd_buffer);
838 return;
841 nl++;
842 add_bytes_to_string(cmd, ftp->cmd_buffer, nl - ftp->cmd_buffer);
843 memmove(ftp->cmd_buffer, nl, strlen(nl) + 1);
846 /* Send commands to retrieve file or directory. */
847 static void
848 ftp_send_retr_req(struct connection *conn, struct connection_state state)
850 struct string cmd;
852 if (!init_string(&cmd)) {
853 abort_connection(conn, connection_state(S_OUT_OF_MEM));
854 return;
857 /* We don't save return value from add_file_cmd_to_str(), as it's saved
858 * in conn->info as well. */
859 if (!conn->info && !add_file_cmd_to_str(conn)) {
860 done_string(&cmd);
861 return;
864 /* Send it line-by-line. */
865 send_it_line_by_line(conn, &cmd);
867 send_cmd(conn, &cmd, (void *) ftp_retr_file, state);
870 /* Parse RETR response and return file size or -1 on error. */
871 static off_t
872 get_filesize_from_RETR(unsigned char *data, int data_len, int *resume)
874 off_t file_len;
875 int pos;
876 int pos_file_len = 0;
878 /* Getting file size from text response.. */
879 /* 150 Opening BINARY mode data connection for hello-1.0-1.1.diff.gz (16452 bytes). */
881 *resume = 0;
882 for (pos = 0; pos < data_len && data[pos] != ASCII_LF; pos++)
883 if (data[pos] == '(')
884 pos_file_len = pos;
886 if (!pos_file_len || pos_file_len == data_len - 1) {
887 /* Getting file size from ftp.task.gda.pl */
888 /* 150 5676.4 kbytes to download */
889 unsigned char tmp = data[data_len - 1];
890 unsigned char *kbytes;
891 char *endptr;
892 double size;
894 data[data_len - 1] = '\0';
895 kbytes = strstr(data, "kbytes");
896 data[data_len - 1] = tmp;
897 if (!kbytes) return -1;
899 for (kbytes -= 2; kbytes >= data; kbytes--) {
900 if (*kbytes == ' ') break;
902 if (*kbytes != ' ') return -1;
903 kbytes++;
904 size = strtod((const char *)kbytes, &endptr);
905 if (endptr == (char *)kbytes) return -1;
906 *resume = 1;
907 return (off_t)(size * 1024.0);
910 pos_file_len++;
911 if (!isdigit(data[pos_file_len]))
912 return -1;
914 for (pos = pos_file_len; pos < data_len; pos++)
915 if (!isdigit(data[pos]))
916 goto next;
918 return -1;
920 next:
921 for (; pos < data_len; pos++)
922 if (data[pos] != ' ')
923 break;
925 if (pos + 4 > data_len)
926 return -1;
928 if (c_strncasecmp(&data[pos], "byte", 4))
929 return -1;
931 errno = 0;
932 file_len = (off_t) strtoll(&data[pos_file_len], NULL, 10);
933 if (errno) return -1;
935 return file_len;
938 /* Connect to the host and port specified by a passive FTP server. */
939 static int
940 ftp_data_connect(struct connection *conn, int pf, struct sockaddr_storage *sa,
941 int size_of_sockaddr)
943 int fd;
945 if (conn->data_socket->fd != -1) {
946 /* The server maliciously sent multiple 227 or 229
947 * responses. Do not leak the previous data_socket. */
948 abort_connection(conn, connection_state(S_FTP_ERROR));
949 return -1;
952 fd = socket(pf, SOCK_STREAM, 0);
953 if (fd < 0 || set_nonblocking_fd(fd) < 0) {
954 abort_connection(conn, connection_state(S_FTP_ERROR));
955 return -1;
958 set_ip_tos_throughput(fd);
960 conn->data_socket->fd = fd;
961 /* XXX: We ignore connect() errors here. */
962 connect(fd, (struct sockaddr *) sa, size_of_sockaddr);
963 return 0;
966 static void
967 ftp_retr_file(struct socket *socket, struct read_buffer *rb)
969 struct connection *conn = socket->conn;
970 struct ftp_connection_info *ftp = conn->info;
971 int response;
972 off_t size = -1;
974 if (ftp->pending_commands > 1) {
975 struct sockaddr_storage sa;
977 response = get_ftp_response(conn, rb, 0, &sa, &size);
979 if (response == -1) {
980 abort_connection(conn, connection_state(S_FTP_ERROR));
981 return;
984 if (!response) {
985 read_from_socket(conn->socket, rb,
986 connection_state(S_GETH),
987 ftp_retr_file);
988 return;
991 if (response == 227) {
992 if (ftp_data_connect(conn, PF_INET, &sa, sizeof(struct sockaddr_in)))
993 return;
996 #ifdef CONFIG_IPV6
997 if (response == 229) {
998 if (ftp_data_connect(conn, PF_INET6, &sa, sizeof(struct sockaddr_in6)))
999 return;
1001 #endif
1003 ftp->pending_commands--;
1005 /* XXX: The case values are order numbers of commands. */
1006 switch (ftp->opc - ftp->pending_commands) {
1007 case 1: /* TYPE */
1008 break;
1010 case 2: /* PORT */
1011 if (response >= 400) {
1012 abort_connection(conn,
1013 connection_state(S_FTP_PORT));
1014 return;
1016 break;
1018 case 3: /* REST / CWD */
1019 case 4: /* SIZE */
1020 if (response == 213 && size != -1 && conn->est_length == -1) {
1021 conn->est_length = size;
1022 } else if (response >= 400) {
1023 if (ftp->dir) {
1024 abort_connection(conn,
1025 connection_state(S_FTP_NO_FILE));
1026 return;
1028 conn->from = 0;
1029 } else if (ftp->rest_sent) {
1030 /* Following code is related to resume
1031 * feature. */
1032 if (response == 350)
1033 conn->from = conn->progress->start;
1034 /* Come on, don't be nervous ;-). */
1035 if (conn->progress->start >= 0) {
1036 /* Update to the real value
1037 * which we've got from
1038 * Content-Range. */
1039 conn->progress->seek = conn->from;
1041 conn->progress->start = conn->from;
1043 break;
1045 default:
1046 INTERNAL("WHAT???");
1049 ftp_send_retr_req(conn, connection_state(S_GETH));
1050 return;
1053 response = get_ftp_response(conn, rb, 2, NULL, NULL);
1055 if (response == -1) {
1056 abort_connection(conn, connection_state(S_FTP_ERROR));
1057 return;
1060 if (!response) {
1061 read_from_socket(conn->socket, rb, connection_state(S_GETH),
1062 ftp_retr_file);
1063 return;
1066 if (response >= 100 && response < 200) {
1067 /* We only need to parse response after RETR to
1068 * get filesize if needed. */
1069 if (!ftp->dir && conn->est_length == -1) {
1070 off_t file_len;
1071 int res;
1073 file_len = get_filesize_from_RETR(rb->data, rb->length, &res);
1074 if (file_len > 0) {
1075 /* FIXME: ..when downloads resuming
1076 * implemented.. */
1077 /* This is right for vsftpd.
1078 * Show me urls where this is wrong. --witekfl */
1079 conn->est_length = res ?
1080 file_len + conn->progress->start : file_len;
1085 if (conn->data_socket->fd == -1) {
1086 /* The passive FTP server did not send a 227 or 229
1087 * response. We check this down here, rather than
1088 * immediately after getting the response to the PASV
1089 * or EPSV command, to make sure that nothing can
1090 * close the socket between the check and the
1091 * following set_handlers call.
1093 * If we were using active FTP, then
1094 * get_ftp_data_socket would have created the
1095 * data_socket without waiting for anything from the
1096 * server. */
1097 abort_connection(conn, connection_state(S_FTP_ERROR));
1098 return;
1100 set_handlers(conn->data_socket->fd, (select_handler_T) ftp_data_accept,
1101 NULL, NULL, conn);
1103 /* read_from_socket(conn->socket, rb, ftp_got_final_response); */
1104 ftp_got_final_response(socket, rb);
1107 static void
1108 ftp_got_final_response(struct socket *socket, struct read_buffer *rb)
1110 struct connection *conn = socket->conn;
1111 struct ftp_connection_info *ftp = conn->info;
1112 int response = get_ftp_response(conn, rb, 0, NULL, NULL);
1114 if (response == -1) {
1115 abort_connection(conn, connection_state(S_FTP_ERROR));
1116 return;
1119 if (!response) {
1120 struct connection_state state = !is_in_state(conn->state, S_TRANS)
1121 ? connection_state(S_GETH) : conn->state;
1123 read_from_socket(conn->socket, rb, state, ftp_got_final_response);
1124 return;
1127 if (response >= 550 || response == 450) {
1128 /* Requested action not taken.
1129 * File unavailable (e.g., file not found, no access). */
1131 if (!conn->cached)
1132 conn->cached = get_cache_entry(conn->uri);
1134 if (!conn->cached
1135 || !redirect_cache(conn->cached, "/", 1, 0)) {
1136 abort_connection(conn, connection_state(S_OUT_OF_MEM));
1137 return;
1140 abort_connection(conn, connection_state(S_OK));
1141 return;
1144 if (response >= 400) {
1145 abort_connection(conn, connection_state(S_FTP_FILE_ERROR));
1146 return;
1149 if (ftp->conn_state == 2) {
1150 ftp_end_request(conn, connection_state(S_OK));
1151 } else {
1152 ftp->conn_state = 1;
1153 if (!is_in_state(conn->state, S_TRANS))
1154 set_connection_state(conn, connection_state(S_GETH));
1159 /** How to format an FTP directory listing in HTML. */
1160 struct ftp_dir_html_format {
1161 /** Codepage used by C library functions such as strftime().
1162 * If the FTP server sends non-ASCII bytes in file names or
1163 * such, ELinks normally passes them straight through to the
1164 * generated HTML, which will eventually be parsed using the
1165 * codepage specified in the document.codepage.assume option.
1166 * However, when ELinks itself generates strings with
1167 * strftime(), it turns non-ASCII bytes into entity references
1168 * based on libc_codepage, to make sure they become the right
1169 * characters again. */
1170 int libc_codepage;
1172 /** Nonzero if directories should be displayed in a different
1173 * color. From the document.browse.links.color_dirs option. */
1174 int colorize_dir;
1176 /** The color of directories, in "#rrggbb" format. This is
1177 * initialized and used only if colorize_dir is nonzero. */
1178 unsigned char dircolor[8];
1181 /* Display directory entry formatted in HTML. */
1182 static int
1183 display_dir_entry(struct cache_entry *cached, off_t *pos, int *tries,
1184 const struct ftp_dir_html_format *format,
1185 struct ftp_file_info *ftp_info)
1187 struct string string;
1188 unsigned char permissions[10] = "---------";
1190 if (!init_string(&string)) return -1;
1192 add_char_to_string(&string, ftp_info->type);
1194 if (ftp_info->permissions) {
1195 mode_t p = ftp_info->permissions;
1197 #define FTP_PERM(perms, buffer, flag, index, id) \
1198 if ((perms) & (flag)) (buffer)[(index)] = (id);
1200 FTP_PERM(p, permissions, S_IRUSR, 0, 'r');
1201 FTP_PERM(p, permissions, S_IWUSR, 1, 'w');
1202 FTP_PERM(p, permissions, S_IXUSR, 2, 'x');
1203 FTP_PERM(p, permissions, S_ISUID, 2, (p & S_IXUSR ? 's' : 'S'));
1205 FTP_PERM(p, permissions, S_IRGRP, 3, 'r');
1206 FTP_PERM(p, permissions, S_IWGRP, 4, 'w');
1207 FTP_PERM(p, permissions, S_IXGRP, 5, 'x');
1208 FTP_PERM(p, permissions, S_ISGID, 5, (p & S_IXGRP ? 's' : 'S'));
1210 FTP_PERM(p, permissions, S_IROTH, 6, 'r');
1211 FTP_PERM(p, permissions, S_IWOTH, 7, 'w');
1212 FTP_PERM(p, permissions, S_IXOTH, 8, 'x');
1213 FTP_PERM(p, permissions, S_ISVTX, 8, (p & 0001 ? 't' : 'T'));
1215 #undef FTP_PERM
1219 add_to_string(&string, permissions);
1220 add_char_to_string(&string, ' ');
1222 add_to_string(&string, " 1 ftp ftp ");
1224 if (ftp_info->size != FTP_SIZE_UNKNOWN) {
1225 add_format_to_string(&string, "%12" OFF_PRINT_FORMAT " ",
1226 (off_print_T) ftp_info->size);
1227 } else {
1228 add_to_string(&string, " - ");
1231 #ifdef HAVE_STRFTIME
1232 if (ftp_info->mtime > 0) {
1233 time_t current_time = time(NULL);
1234 time_t when = ftp_info->mtime;
1235 struct tm *when_tm;
1236 unsigned char *fmt;
1237 /* LC_TIME=fi_FI.UTF_8 can generate "elo___ 31 23:59"
1238 * where each _ denotes U+00A0 encoded as 0xC2 0xA0,
1239 * thus needing a 19-byte buffer. */
1240 unsigned char date[80];
1241 int wr;
1243 if (ftp_info->local_time_zone)
1244 when_tm = localtime(&when);
1245 else
1246 when_tm = gmtime(&when);
1248 if (current_time > when + 6L * 30L * 24L * 60L * 60L
1249 || current_time < when - 60L * 60L)
1250 fmt = "%b %e %Y";
1251 else
1252 fmt = "%b %e %H:%M";
1254 wr = strftime(date, sizeof(date), fmt, when_tm);
1255 add_cp_html_to_string(&string, format->libc_codepage,
1256 date, wr);
1257 } else
1258 #endif
1259 add_to_string(&string, " ");
1260 /* TODO: Above, the number of spaces might not match the width
1261 * of the string generated by strftime. It depends on the
1262 * locale. So if ELinks knows the timestamps of some FTP
1263 * files but not others, it may misalign the file names.
1264 * Potential solutions:
1265 * - Pad the strings to a compile-time fixed width.
1266 * Con: If we choose a width that suffices for all known
1267 * locales, then it will be stupidly large for most of them.
1268 * - Generate an HTML table.
1269 * Con: Bloats the HTML source.
1270 * Any solution chosen here should also be applied to the
1271 * file: protocol handler. */
1273 add_char_to_string(&string, ' ');
1275 if (ftp_info->type == FTP_FILE_DIRECTORY && format->colorize_dir) {
1276 add_to_string(&string, "<font color=\"");
1277 add_to_string(&string, format->dircolor);
1278 add_to_string(&string, "\"><b>");
1281 add_to_string(&string, "<a href=\"");
1282 encode_uri_string(&string, ftp_info->name.source, ftp_info->name.length, 0);
1283 if (ftp_info->type == FTP_FILE_DIRECTORY)
1284 add_char_to_string(&string, '/');
1285 add_to_string(&string, "\">");
1286 add_html_to_string(&string, ftp_info->name.source, ftp_info->name.length);
1287 add_to_string(&string, "</a>");
1289 if (ftp_info->type == FTP_FILE_DIRECTORY && format->colorize_dir) {
1290 add_to_string(&string, "</b></font>");
1293 if (ftp_info->symlink.length) {
1294 add_to_string(&string, " -&gt; ");
1295 add_html_to_string(&string, ftp_info->symlink.source,
1296 ftp_info->symlink.length);
1299 add_char_to_string(&string, '\n');
1301 if (add_fragment(cached, *pos, string.source, string.length)) *tries = 0;
1302 *pos += string.length;
1304 done_string(&string);
1305 return 0;
1308 /* Get the next line of input and set *@len to the length of the line.
1309 * Return the number of newline characters at the end of the line or -1
1310 * if we must wait for more input. */
1311 static int
1312 ftp_get_line(struct cache_entry *cached, unsigned char *buf, int bufl,
1313 int last, int *len)
1315 unsigned char *newline;
1317 if (!bufl) return -1;
1319 newline = memchr(buf, ASCII_LF, bufl);
1321 if (newline) {
1322 *len = newline - buf;
1323 if (*len && buf[*len - 1] == ASCII_CR) {
1324 --*len;
1325 return 2;
1326 } else {
1327 return 1;
1331 if (last || bufl >= FTP_BUF_SIZE) {
1332 *len = bufl;
1333 return 0;
1336 return -1;
1339 /** Generate HTML for a line that was received from the FTP server but
1340 * could not be parsed. The caller is supposed to have added a \<pre>
1341 * start tag. (At the time of writing, init_directory_listing() was
1342 * used for that.)
1344 * @return -1 if out of memory, or 0 if successful. */
1345 static int
1346 ftp_add_unparsed_line(struct cache_entry *cached, off_t *pos, int *tries,
1347 const unsigned char *line, int line_length)
1349 int our_ret;
1350 struct string string;
1351 int frag_ret;
1353 our_ret = -1; /* assume out of memory if returning early */
1354 if (!init_string(&string)) goto out;
1355 if (!add_html_to_string(&string, line, line_length)) goto out;
1356 if (!add_char_to_string(&string, '\n')) goto out;
1358 frag_ret = add_fragment(cached, *pos, string.source, string.length);
1359 if (frag_ret == -1) goto out;
1360 *pos += string.length;
1361 if (frag_ret == 1) *tries = 0;
1363 our_ret = 0; /* success */
1365 out:
1366 done_string(&string); /* safe even if init_string failed */
1367 return our_ret;
1370 /** List a directory in html format.
1372 * @return the number of bytes used from the beginning of @a buffer,
1373 * or -1 if out of memory. */
1374 static int
1375 ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
1376 unsigned char *buffer, int buflen, int last,
1377 int *tries, const struct ftp_dir_html_format *format)
1379 int ret = 0;
1381 while (1) {
1382 struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO;
1383 unsigned char *buf = buffer + ret;
1384 int bufl = buflen - ret;
1385 int line_length, eol;
1387 eol = ftp_get_line(cached, buf, bufl, last, &line_length);
1388 if (eol == -1)
1389 return ret;
1391 ret += line_length + eol;
1393 /* Process line whose end we've already found. */
1395 if (parse_ftp_file_info(&ftp_info, buf, line_length)) {
1396 int retv;
1398 if (ftp_info.name.source[0] == '.'
1399 && (ftp_info.name.length == 1
1400 || (ftp_info.name.length == 2
1401 && ftp_info.name.source[1] == '.')))
1402 continue;
1404 retv = display_dir_entry(cached, pos, tries,
1405 format, &ftp_info);
1406 if (retv < 0) {
1407 return ret;
1410 } else {
1411 int retv = ftp_add_unparsed_line(cached, pos, tries,
1412 buf, line_length);
1414 if (retv == -1) /* out of memory; propagate to caller */
1415 return retv;
1420 /* This is the initial read handler for conn->data_socket->fd,
1421 * which may be either trying to connect to a passive FTP server or
1422 * listening for a connection from an active FTP server. In active
1423 * FTP, this function then accepts the connection and replaces
1424 * conn->data_socket->fd with the resulting socket. In any case,
1425 * this function does not read any data from the FTP server, but
1426 * rather hands the socket over to got_something_from_data_connection,
1427 * which then does the reads. */
1428 static void
1429 ftp_data_accept(struct connection *conn)
1431 struct ftp_connection_info *ftp = conn->info;
1432 int newsock;
1434 /* Because this function is called only as a read handler of
1435 * conn->data_socket->fd, the socket must be valid if we get
1436 * here. */
1437 assert(conn->data_socket->fd >= 0);
1438 if_assert_failed return;
1440 set_connection_timeout(conn);
1441 clear_handlers(conn->data_socket->fd);
1443 if ((conn->socket->protocol_family != EL_PF_INET6 && ftp->use_pasv)
1444 #ifdef CONFIG_IPV6
1445 || (conn->socket->protocol_family == EL_PF_INET6 && ftp->use_epsv)
1446 #endif
1448 newsock = conn->data_socket->fd;
1449 } else {
1450 newsock = accept(conn->data_socket->fd, NULL, NULL);
1451 if (newsock < 0) {
1452 retry_connection(conn, connection_state_for_errno(errno));
1453 return;
1455 close(conn->data_socket->fd);
1458 conn->data_socket->fd = newsock;
1460 set_handlers(newsock,
1461 (select_handler_T) got_something_from_data_connection,
1462 NULL, NULL, conn);
1465 /* A read handler for conn->data_socket->fd. This function reads
1466 * data from the FTP server, reformats it to HTML if it's a directory
1467 * listing, and adds the result to the cache entry. */
1468 static void
1469 got_something_from_data_connection(struct connection *conn)
1471 struct ftp_connection_info *ftp = conn->info;
1472 struct ftp_dir_html_format format;
1473 ssize_t len;
1475 /* Because this function is called only as a read handler of
1476 * conn->data_socket->fd, the socket must be valid if we get
1477 * here. */
1478 assert(conn->data_socket->fd >= 0);
1479 if_assert_failed return;
1481 /* XXX: This probably belongs rather to connect.c ? */
1483 set_connection_timeout(conn);
1485 if (!conn->cached) conn->cached = get_cache_entry(conn->uri);
1486 if (!conn->cached) {
1487 out_of_mem:
1488 abort_connection(conn, connection_state(S_OUT_OF_MEM));
1489 return;
1492 if (ftp->dir) {
1493 format.libc_codepage = get_cp_index("System");
1495 format.colorize_dir = get_opt_bool("document.browse.links.color_dirs", NULL);
1497 if (format.colorize_dir) {
1498 color_to_string(get_opt_color("document.colors.dirs", NULL),
1499 format.dircolor);
1503 if (ftp->dir && !conn->from) {
1504 struct string string;
1505 struct connection_state state;
1507 if (!conn->uri->data) {
1508 abort_connection(conn, connection_state(S_FTP_ERROR));
1509 return;
1512 state = init_directory_listing(&string, conn->uri);
1513 if (!is_in_state(state, S_OK)) {
1514 abort_connection(conn, state);
1515 return;
1518 add_fragment(conn->cached, conn->from, string.source, string.length);
1519 conn->from += string.length;
1521 done_string(&string);
1523 if (conn->uri->datalen) {
1524 struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO_ROOT;
1526 display_dir_entry(conn->cached, &conn->from, &conn->tries,
1527 &format, &ftp_info);
1530 mem_free_set(&conn->cached->content_type, stracpy("text/html"));
1533 len = safe_read(conn->data_socket->fd, ftp->ftp_buffer + ftp->buf_pos,
1534 FTP_BUF_SIZE - ftp->buf_pos);
1535 if (len < 0) {
1536 retry_connection(conn, connection_state_for_errno(errno));
1537 return;
1540 if (len > 0) {
1541 conn->received += len;
1543 if (!ftp->dir) {
1544 if (add_fragment(conn->cached, conn->from,
1545 ftp->ftp_buffer, len) == 1)
1546 conn->tries = 0;
1547 conn->from += len;
1549 } else {
1550 int proceeded;
1552 proceeded = ftp_process_dirlist(conn->cached,
1553 &conn->from,
1554 ftp->ftp_buffer,
1555 len + ftp->buf_pos,
1556 0, &conn->tries,
1557 &format);
1559 if (proceeded == -1) goto out_of_mem;
1561 ftp->buf_pos += len - proceeded;
1563 memmove(ftp->ftp_buffer, ftp->ftp_buffer + proceeded,
1564 ftp->buf_pos);
1568 set_connection_state(conn, connection_state(S_TRANS));
1569 return;
1572 if (ftp_process_dirlist(conn->cached, &conn->from,
1573 ftp->ftp_buffer, ftp->buf_pos, 1,
1574 &conn->tries, &format) == -1)
1575 goto out_of_mem;
1577 #define ADD_CONST(str) { \
1578 add_fragment(conn->cached, conn->from, str, sizeof(str) - 1); \
1579 conn->from += (sizeof(str) - 1); }
1581 if (ftp->dir) ADD_CONST("</pre>\n<hr/>\n</body>\n</html>");
1583 close_socket(conn->data_socket);
1585 if (ftp->conn_state == 1) {
1586 ftp_end_request(conn, connection_state(S_OK));
1587 } else {
1588 ftp->conn_state = 2;
1589 set_connection_state(conn, connection_state(S_TRANS));
1593 static void
1594 ftp_end_request(struct connection *conn, struct connection_state state)
1596 if (is_in_state(state, S_OK) && conn->cached) {
1597 normalize_cache_entry(conn->cached, conn->from);
1600 set_connection_state(conn, state);
1601 add_keepalive_connection(conn, FTP_KEEPALIVE_TIMEOUT, NULL);