mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
[sftp] Sort entries
This commit is contained in:
parent
88a5fb1512
commit
efaebe2010
@ -106,9 +106,11 @@ struct ftpes_connection_info {
|
|||||||
char error[CURL_ERROR_SIZE];
|
char error[CURL_ERROR_SIZE];
|
||||||
int conn_state;
|
int conn_state;
|
||||||
int buf_pos;
|
int buf_pos;
|
||||||
|
size_t info_number;
|
||||||
|
|
||||||
unsigned int dir:1; /* Directory listing in progress */
|
unsigned int dir:1; /* Directory listing in progress */
|
||||||
char ftp_buffer[FTP_BUF_SIZE];
|
char ftp_buffer[FTP_BUF_SIZE];
|
||||||
|
struct ftp_file_info **infos;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** How to format an FTP directory listing in HTML. */
|
/** How to format an FTP directory listing in HTML. */
|
||||||
@ -327,7 +329,7 @@ out:
|
|||||||
static int
|
static int
|
||||||
ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
|
ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
|
||||||
char *buffer, int buflen, int last,
|
char *buffer, int buflen, int last,
|
||||||
int *tries, const struct ftp_dir_html_format *format)
|
int *tries, const struct ftp_dir_html_format *format, struct ftpes_connection_info *sftp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@ -354,13 +356,41 @@ ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
|
|||||||
&& ftp_info.name.source[1] == '.')))
|
&& ftp_info.name.source[1] == '.')))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
retv = display_dir_entry(cached, pos, tries,
|
if (sftp) {
|
||||||
format, &ftp_info);
|
char *str = memacpy(ftp_info.name.source, ftp_info.name.length);
|
||||||
if (retv < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct ftp_file_info *copy = mem_calloc(1, sizeof(*copy));
|
||||||
|
|
||||||
|
if (!copy) {
|
||||||
|
mem_free(str);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct ftp_file_info **tmp = mem_realloc(sftp->infos, (sftp->info_number + 1) * sizeof(*tmp));
|
||||||
|
|
||||||
|
if (!tmp) {
|
||||||
|
mem_free(str);
|
||||||
|
mem_free(copy);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*copy = ftp_info;
|
||||||
|
copy->name.source = str;
|
||||||
|
sftp->infos = tmp;
|
||||||
|
sftp->infos[sftp->info_number] = copy;
|
||||||
|
sftp->info_number++;
|
||||||
|
} else {
|
||||||
|
retv = display_dir_entry(cached, pos, tries,
|
||||||
|
format, &ftp_info);
|
||||||
|
if (retv < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (sftp) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int retv = ftp_add_unparsed_line(cached, pos, tries,
|
int retv = ftp_add_unparsed_line(cached, pos, tries,
|
||||||
buf, line_length);
|
buf, line_length);
|
||||||
|
|
||||||
@ -371,6 +401,7 @@ ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ftpes_got_data(void *stream, void *buffer, size_t len);
|
static void ftpes_got_data(void *stream, void *buffer, size_t len);
|
||||||
|
static void sftp_got_data(void *stream, void *buffer, size_t len);
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
|
my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
|
||||||
@ -379,6 +410,26 @@ my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
|
|||||||
return nmemb;
|
return nmemb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
my_fwrite_sftp(void *buffer, size_t size, size_t nmemb, void *stream)
|
||||||
|
{
|
||||||
|
sftp_got_data(stream, buffer, size * nmemb);
|
||||||
|
return nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
done_ftp_infos(struct ftpes_connection_info *ftp)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < ftp->info_number; i++) {
|
||||||
|
done_string(&ftp->infos[i]->name);
|
||||||
|
mem_free(ftp->infos[i]);
|
||||||
|
}
|
||||||
|
mem_free_set(&ftp->infos, NULL);
|
||||||
|
ftp->info_number = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
done_ftpes(struct connection *conn)
|
done_ftpes(struct connection *conn)
|
||||||
{
|
{
|
||||||
@ -387,6 +438,7 @@ done_ftpes(struct connection *conn)
|
|||||||
if (!ftp || !ftp->easy) {
|
if (!ftp || !ftp->easy) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
done_ftp_infos(ftp);
|
||||||
|
|
||||||
if (!program.terminate) {
|
if (!program.terminate) {
|
||||||
curl_multi_remove_handle(g.multi, ftp->easy);
|
curl_multi_remove_handle(g.multi, ftp->easy);
|
||||||
@ -451,7 +503,7 @@ do_ftpes(struct connection *conn)
|
|||||||
conn->progress->seek = conn->from = offset;
|
conn->progress->seek = conn->from = offset;
|
||||||
ftp->easy = curl;
|
ftp->easy = curl;
|
||||||
/* Define our callback to get called when there's data to be written */
|
/* Define our callback to get called when there's data to be written */
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, conn->uri->protocol == PROTOCOL_SFTP ? my_fwrite_sftp : my_fwrite);
|
||||||
/* Set a pointer to our struct to pass to the callback */
|
/* Set a pointer to our struct to pass to the callback */
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, conn);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, conn);
|
||||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ftp->error);
|
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ftp->error);
|
||||||
@ -606,7 +658,7 @@ again:
|
|||||||
ftp->ftp_buffer,
|
ftp->ftp_buffer,
|
||||||
len + ftp->buf_pos,
|
len + ftp->buf_pos,
|
||||||
0, &conn->tries,
|
0, &conn->tries,
|
||||||
&format);
|
&format, NULL);
|
||||||
|
|
||||||
if (proceeded == -1) goto out_of_mem;
|
if (proceeded == -1) goto out_of_mem;
|
||||||
|
|
||||||
@ -623,8 +675,9 @@ again:
|
|||||||
|
|
||||||
if (ftp_process_dirlist(conn->cached, &conn->from,
|
if (ftp_process_dirlist(conn->cached, &conn->from,
|
||||||
ftp->ftp_buffer, ftp->buf_pos, 1,
|
ftp->ftp_buffer, ftp->buf_pos, 1,
|
||||||
&conn->tries, &format) == -1)
|
&conn->tries, &format, NULL) == -1) {
|
||||||
goto out_of_mem;
|
goto out_of_mem;
|
||||||
|
}
|
||||||
|
|
||||||
#define ADD_CONST(str) { \
|
#define ADD_CONST(str) { \
|
||||||
add_fragment(conn->cached, conn->from, str, sizeof(str) - 1); \
|
add_fragment(conn->cached, conn->from, str, sizeof(str) - 1); \
|
||||||
@ -634,11 +687,192 @@ again:
|
|||||||
abort_connection(conn, connection_state(S_OK));
|
abort_connection(conn, connection_state(S_OK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_file_ftp_info(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
struct ftp_file_info *a1 = *(struct ftp_file_info **)a;
|
||||||
|
struct ftp_file_info *b1 = *(struct ftp_file_info **)b;
|
||||||
|
|
||||||
|
int res = b1->type - a1->type;
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
size_t min = b1->name.length < a1->name.length ? b1->name.length : a1->name.length;
|
||||||
|
|
||||||
|
return memcmp(a1->name.source, b1->name.source, min + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sort_ftp_infos(struct ftpes_connection_info *ftp)
|
||||||
|
{
|
||||||
|
qsort(&ftp->infos[0], ftp->info_number, sizeof(struct ftp_file_info *), compare_file_ftp_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* A read handler for conn->data_socket->fd. This function reads
|
||||||
|
* data from the FTP server, reformats it to HTML if it's a directory
|
||||||
|
* listing, and adds the result to the cache entry. */
|
||||||
|
static void
|
||||||
|
sftp_got_data(void *stream, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct connection *conn = (struct connection *)stream;
|
||||||
|
char *buffer = (char *)buf;
|
||||||
|
struct ftpes_connection_info *ftp = (struct ftpes_connection_info *)conn->info;
|
||||||
|
struct ftp_dir_html_format format;
|
||||||
|
size_t len2 = len;
|
||||||
|
size_t copied = 0;
|
||||||
|
|
||||||
|
/* XXX: This probably belongs rather to connect.c ? */
|
||||||
|
set_connection_timeout(conn);
|
||||||
|
|
||||||
|
if (!conn->cached) {
|
||||||
|
conn->cached = get_cache_entry(conn->uri);
|
||||||
|
|
||||||
|
if (!conn->cached) {
|
||||||
|
out_of_mem:
|
||||||
|
abort_connection(conn, connection_state(S_OUT_OF_MEM));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len < 0) {
|
||||||
|
abort_connection(conn, connection_state_for_errno(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftp->dir) {
|
||||||
|
format.libc_codepage = get_cp_index("System");
|
||||||
|
|
||||||
|
format.colorize_dir = get_opt_bool("document.browse.links.color_dirs", NULL);
|
||||||
|
|
||||||
|
if (format.colorize_dir) {
|
||||||
|
color_to_string(get_opt_color("document.colors.dirs", NULL),
|
||||||
|
format.dircolor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftp->dir && !conn->from) {
|
||||||
|
struct string string;
|
||||||
|
struct connection_state state;
|
||||||
|
|
||||||
|
if (!conn->uri->data) {
|
||||||
|
abort_connection(conn, connection_state(S_FTP_ERROR));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = init_directory_listing(&string, conn->uri);
|
||||||
|
if (!is_in_state(state, S_OK)) {
|
||||||
|
abort_connection(conn, state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
add_fragment(conn->cached, conn->from, string.source, string.length);
|
||||||
|
conn->from += string.length;
|
||||||
|
|
||||||
|
done_string(&string);
|
||||||
|
|
||||||
|
if (conn->uri->datalen) {
|
||||||
|
struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO_ROOT;
|
||||||
|
|
||||||
|
display_dir_entry(conn->cached, &conn->from, &conn->tries,
|
||||||
|
&format, &ftp_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_free_set(&conn->cached->content_type, stracpy("text/html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ftp->dir && (len > 0)) {
|
||||||
|
if (add_fragment(conn->cached, conn->from, buffer, len) == 1) {
|
||||||
|
conn->tries = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((conn->from == 0 || conn->progress->start > 0) && conn->est_length == -1) {
|
||||||
|
curl_easy_getinfo(ftp->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &conn->est_length);
|
||||||
|
|
||||||
|
if (conn->est_length != -1) {
|
||||||
|
conn->est_length += conn->from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn->from += len;
|
||||||
|
conn->received += len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
|
len = len2;
|
||||||
|
|
||||||
|
if (FTP_BUF_SIZE - ftp->buf_pos < len) {
|
||||||
|
len = FTP_BUF_SIZE - ftp->buf_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len2 > 0) {
|
||||||
|
int proceeded;
|
||||||
|
|
||||||
|
memcpy(ftp->ftp_buffer + ftp->buf_pos, buffer + copied, len);
|
||||||
|
conn->received += len;
|
||||||
|
copied += len;
|
||||||
|
proceeded = ftp_process_dirlist(conn->cached,
|
||||||
|
&conn->from,
|
||||||
|
ftp->ftp_buffer,
|
||||||
|
len + ftp->buf_pos,
|
||||||
|
0, &conn->tries,
|
||||||
|
&format, ftp);
|
||||||
|
|
||||||
|
if (proceeded == -1) goto out_of_mem;
|
||||||
|
|
||||||
|
ftp->buf_pos += len - proceeded;
|
||||||
|
memmove(ftp->ftp_buffer, ftp->ftp_buffer + proceeded, ftp->buf_pos);
|
||||||
|
|
||||||
|
len2 -= len;
|
||||||
|
|
||||||
|
if (len2 <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ftp_process_dirlist(conn->cached, &conn->from,
|
||||||
|
ftp->ftp_buffer, ftp->buf_pos, 1,
|
||||||
|
&conn->tries, &format, ftp) == -1) {
|
||||||
|
goto out_of_mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADD_CONST(str) { \
|
||||||
|
add_fragment(conn->cached, conn->from, str, sizeof(str) - 1); \
|
||||||
|
conn->from += (sizeof(str) - 1); }
|
||||||
|
|
||||||
|
if (ftp->dir) {
|
||||||
|
size_t i;
|
||||||
|
sort_ftp_infos(ftp);
|
||||||
|
|
||||||
|
for (i = 0; i < ftp->info_number; i++) {
|
||||||
|
display_dir_entry(conn->cached, &conn->from, &conn->tries,
|
||||||
|
&format, ftp->infos[i]);
|
||||||
|
}
|
||||||
|
done_ftp_infos(ftp);
|
||||||
|
|
||||||
|
ADD_CONST("</pre>\n<hr/>\n</body>\n</html>");
|
||||||
|
}
|
||||||
|
abort_connection(conn, connection_state(S_OK));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ftp_curl_handle_error(struct connection *conn, CURLcode res)
|
ftp_curl_handle_error(struct connection *conn, CURLcode res)
|
||||||
{
|
{
|
||||||
if (res == CURLE_OK) {
|
if (res == CURLE_OK) {
|
||||||
abort_connection(conn, connection_state(S_OK));
|
struct ftpes_connection_info *ftp = (struct ftpes_connection_info *)conn->info;
|
||||||
|
|
||||||
|
if (ftp->dir) {
|
||||||
|
if (conn->uri->protocol == PROTOCOL_SFTP) {
|
||||||
|
sftp_got_data(conn, NULL, 0);
|
||||||
|
} else {
|
||||||
|
ftpes_got_data(conn, NULL, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
abort_connection(conn, connection_state(S_OK));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user