From a67188413c2121e1fde45aa570dfa58b62c3918c Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Mon, 19 Jun 2023 18:43:53 +0200 Subject: [PATCH] [lists] LIST_HEAD -> LIST_HEAD_EL to not clash with libevent's LIST_HEAD. Also added curl implementation of ftpes and sftp Implementation of ftpes and sftp is based on curl's hiperfifo example. It requires libevent. ftpes only encrypts control channel. There were problems when both control and data were encrypted. It stucked on SIZE. Only successful connections work, errors are not handled properly. --- src/bfu/hierbox.h | 10 +- src/bfu/inphist.h | 4 +- src/bfu/listbox.h | 4 +- src/bookmarks/backend/xbel.c | 2 +- src/cache/cache.h | 2 +- src/config/domain.h | 2 +- src/config/options.h | 2 +- src/cookies/cookies.c | 2 +- src/document/css/parser.c | 2 +- src/document/css/property.h | 2 +- src/document/css/stylesheet.h | 4 +- src/document/document.h | 6 +- src/document/forms.h | 4 +- src/document/html/internal.h | 2 +- src/document/html/parser.h | 2 +- src/document/html/renderer.c | 2 +- src/document/view.h | 2 +- src/ecmascript/ecmascript.h | 2 +- src/ecmascript/libdom/mujs/element.c | 2 +- src/ecmascript/libdom/mujs/window.c | 2 +- src/ecmascript/libdom/quickjs/element.c | 2 +- src/ecmascript/libdom/quickjs/window.c | 2 +- .../libdom/spidermonkey/element.cpp | 2 +- src/ecmascript/libdom/spidermonkey/window.cpp | 2 +- src/ecmascript/libdom/spidermonkey/xhr.cpp | 2 +- src/ecmascript/mujs/xhr.h | 2 +- src/ecmascript/quickjs/heartbeat.h | 2 +- src/ecmascript/quickjs/xhr.h | 2 +- src/ecmascript/spidermonkey/heartbeat.h | 2 +- src/main/object.h | 2 +- src/main/select.c | 272 +++++++- src/main/select.h | 40 ++ src/main/timer.h | 2 +- src/mime/backend/dgi.c | 2 +- src/mime/backend/mailcap.c | 2 +- src/network/connection.c | 2 +- src/network/connection.h | 2 +- src/network/dns.c | 2 +- src/network/socket.c | 2 +- src/network/state.c | 2 +- src/osdep/beos/beos.c | 2 +- src/protocol/bittorrent/bittorrent.c | 2 +- src/protocol/bittorrent/common.c | 2 +- src/protocol/bittorrent/common.h | 12 +- src/protocol/bittorrent/piececache.h | 2 +- src/protocol/{ftpes/ftpes.c => curl/ftp.c} | 247 +++++--- src/protocol/{ftpes => curl}/ftpes.h | 4 +- src/protocol/curl/meson.build | 1 + src/protocol/{sftp => curl}/sftp.h | 4 +- src/protocol/ftpes/meson.build | 1 - src/protocol/http/blacklist.c | 2 +- src/protocol/meson.build | 9 +- src/protocol/protocol.cpp | 4 +- src/protocol/sftp/meson.build | 1 - src/protocol/sftp/sftp.c | 592 ------------------ src/session/download.h | 4 +- src/session/location.h | 2 +- src/session/session.cpp | 6 +- src/session/session.h | 6 +- src/terminal/screen.c | 2 +- src/terminal/sixel.h | 2 +- src/terminal/terminal.h | 2 +- src/terminal/window.h | 2 +- src/util/hash.h | 2 +- src/util/lists.h | 16 +- src/util/memdebug.c | 2 +- src/util/string.h | 4 +- src/viewer/text/form.cpp | 2 +- src/viewer/text/form.h | 6 +- src/viewer/text/textarea.c | 2 +- 70 files changed, 554 insertions(+), 799 deletions(-) rename src/protocol/{ftpes/ftpes.c => curl/ftp.c} (78%) rename src/protocol/{ftpes => curl}/ftpes.h (82%) create mode 100644 src/protocol/curl/meson.build rename src/protocol/{sftp => curl}/sftp.h (81%) delete mode 100644 src/protocol/ftpes/meson.build delete mode 100644 src/protocol/sftp/meson.build delete mode 100644 src/protocol/sftp/sftp.c diff --git a/src/bfu/hierbox.h b/src/bfu/hierbox.h index 3a567ccc..48065699 100644 --- a/src/bfu/hierbox.h +++ b/src/bfu/hierbox.h @@ -102,11 +102,11 @@ struct hierbox_browser { NULL, \ buttons, \ sizeof_array(buttons), \ - { D_LIST_HEAD(name.boxes) }, \ - { D_LIST_HEAD(name.dialogs) }, \ + { D_LIST_HEAD_EL(name.boxes) }, \ + { D_LIST_HEAD_EL(name.dialogs) }, \ { \ - NULL_LIST_HEAD, \ - { D_LIST_HEAD(name.root.child) }, \ + NULL_LIST_HEAD_EL, \ + { D_LIST_HEAD_EL(name.root.child) }, \ BI_FOLDER, \ -1, \ 1, \ @@ -116,7 +116,7 @@ struct hierbox_browser { } struct hierbox_dialog_list_item { - LIST_HEAD(struct hierbox_dialog_list_item); + LIST_HEAD_EL(struct hierbox_dialog_list_item); struct dialog_data *dlg_data; }; diff --git a/src/bfu/inphist.h b/src/bfu/inphist.h index a51962e9..8404470a 100644 --- a/src/bfu/inphist.h +++ b/src/bfu/inphist.h @@ -11,7 +11,7 @@ struct dialog_data; struct input_history_entry { - LIST_HEAD(struct input_history_entry); + LIST_HEAD_EL(struct input_history_entry); char data[1]; /* Must be last. */ }; @@ -24,7 +24,7 @@ struct input_history { #define INIT_INPUT_HISTORY(history) \ struct input_history history = { \ - /* items: */ { D_LIST_HEAD(history.entries) }, \ + /* items: */ { D_LIST_HEAD_EL(history.entries) }, \ /* size: */ 0, \ /* dirty: */ 0, \ /* nosave: */ 0, \ diff --git a/src/bfu/listbox.h b/src/bfu/listbox.h index 6227f73b..e55c66d4 100644 --- a/src/bfu/listbox.h +++ b/src/bfu/listbox.h @@ -102,7 +102,7 @@ struct listbox_ops { /* Stores display information about a box. Kept in cdata. */ struct listbox_data { - LIST_HEAD(struct listbox_data); + LIST_HEAD_EL(struct listbox_data); const struct listbox_ops *ops; /* Backend-provided operations */ struct listbox_item *sel; /* Item currently selected */ @@ -120,7 +120,7 @@ enum listbox_item_type { /* An item in a box */ struct listbox_item { - LIST_HEAD(struct listbox_item); + LIST_HEAD_EL(struct listbox_item); /* The list may be empty for leaf nodes or non-hiearchic listboxes */ LIST_OF(struct listbox_item) child; diff --git a/src/bookmarks/backend/xbel.c b/src/bookmarks/backend/xbel.c index 9d50834d..39ba360a 100644 --- a/src/bookmarks/backend/xbel.c +++ b/src/bookmarks/backend/xbel.c @@ -36,7 +36,7 @@ /* Elements' attributes */ struct attributes { - LIST_HEAD(struct attributes); + LIST_HEAD_EL(struct attributes); char *name; char *value; diff --git a/src/cache/cache.h b/src/cache/cache.h index 368face8..7f7abff0 100644 --- a/src/cache/cache.h +++ b/src/cache/cache.h @@ -78,7 +78,7 @@ struct cache_entry { }; struct fragment { - LIST_HEAD(struct fragment); + LIST_HEAD_EL(struct fragment); off_t offset; off_t length; diff --git a/src/config/domain.h b/src/config/domain.h index 8c550c1f..019c29fa 100644 --- a/src/config/domain.h +++ b/src/config/domain.h @@ -12,7 +12,7 @@ struct session; struct domain_tree { - LIST_HEAD(struct domain_tree); + LIST_HEAD_EL(struct domain_tree); struct option *tree; diff --git a/src/config/options.h b/src/config/options.h index a962dcad..5c7c8261 100644 --- a/src/config/options.h +++ b/src/config/options.h @@ -219,7 +219,7 @@ struct option { * with ::INIT_OPT_INT or a similar macro. * @relates option */ #define INIT_OPTION(name, flags, type, min, max, value, desc, capt) \ - { NULL_LIST_HEAD, INIT_OBJECT("option"), {name}, flags, type, min, max, { (LIST_OF(struct option) *) (value) }, desc, capt } + { NULL_LIST_HEAD_EL, INIT_OBJECT("option"), {name}, flags, type, min, max, { (LIST_OF(struct option) *) (value) }, desc, capt } extern struct option *config_options; extern struct option *cmdline_options; diff --git a/src/cookies/cookies.c b/src/cookies/cookies.c index 69392852..58873da8 100644 --- a/src/cookies/cookies.c +++ b/src/cookies/cookies.c @@ -53,7 +53,7 @@ static int cookies_nosave = 0; static INIT_LIST_OF(struct cookie, cookies); struct c_domain { - LIST_HEAD(struct c_domain); + LIST_HEAD_EL(struct c_domain); char domain[1]; /* Must be at end of struct. */ }; diff --git a/src/document/css/parser.c b/src/document/css/parser.c index ff82b306..5d31a476 100644 --- a/src/document/css/parser.c +++ b/src/document/css/parser.c @@ -269,7 +269,7 @@ skip_rest_of_atrule: struct selector_pkg { - LIST_HEAD(struct selector_pkg); + LIST_HEAD_EL(struct selector_pkg); struct css_selector *selector; }; diff --git a/src/document/css/property.h b/src/document/css/property.h index ea2d43a6..99916d22 100644 --- a/src/document/css/property.h +++ b/src/document/css/property.h @@ -91,7 +91,7 @@ union css_property_value { * being basically a parsed instance of struct css_property_info. One list of * these contains all the declarations contained in one rule. */ struct css_property { - LIST_HEAD(struct css_property); + LIST_HEAD_EL(struct css_property); /** Declared property. The enum item name is derived from the * property name, just uppercase it and tr/-/_/. */ diff --git a/src/document/css/stylesheet.h b/src/document/css/stylesheet.h index ecdb774b..7cab9c6d 100644 --- a/src/document/css/stylesheet.h +++ b/src/document/css/stylesheet.h @@ -66,7 +66,7 @@ struct css_selector_set { * to LIST_OF(struct css_selector) * and get away with it. */ LIST_OF(struct css_selector) list; }; -#define INIT_CSS_SELECTOR_SET(set) { 0, { D_LIST_HEAD(set.list) } } +#define INIT_CSS_SELECTOR_SET(set) { 0, { D_LIST_HEAD_EL(set.list) } } enum css_selector_relation { CSR_ROOT, /**< First class stylesheet member. */ @@ -89,7 +89,7 @@ typedef unsigned char css_selector_type_T; * document structure to properties. See README for some hints about how the * trees of these span. */ struct css_selector { - LIST_HEAD(struct css_selector); + LIST_HEAD_EL(struct css_selector); /** This defines relation between this selector fragment and its * parent in the selector tree. diff --git a/src/document/document.h b/src/document/document.h index 9de0b73f..cf3a08a8 100644 --- a/src/document/document.h +++ b/src/document/document.h @@ -28,7 +28,7 @@ struct screen_char; /** Nodes are used for marking areas of text on the document canvas as * searchable. */ struct node { - LIST_HEAD(struct node); + LIST_HEAD_EL(struct node); struct el_box box; }; @@ -73,7 +73,7 @@ struct point { /* Tags are used for ``id''s or anchors in the document referenced by the * fragment part of the URI. */ struct tag { - LIST_HEAD(struct tag); + LIST_HEAD_EL(struct tag); int x, y; char name[1]; /* must be last of struct. --Zas */ @@ -105,7 +105,7 @@ enum script_event_hook_type { extern const char *script_event_hook_name[]; struct script_event_hook { - LIST_HEAD(struct script_event_hook); + LIST_HEAD_EL(struct script_event_hook); enum script_event_hook_type type; char *src; diff --git a/src/document/forms.h b/src/document/forms.h index 5c15d19c..194691e0 100644 --- a/src/document/forms.h +++ b/src/document/forms.h @@ -24,7 +24,7 @@ enum form_method { }; struct form { - LIST_HEAD(struct form); + LIST_HEAD_EL(struct form); /** The value of @c form_num serves both as a unique ID of the form. * However @c form_num and #form_end also stores information about where @@ -91,7 +91,7 @@ enum form_wrap { }; struct el_form_control { - LIST_HEAD(struct el_form_control); + LIST_HEAD_EL(struct el_form_control); struct form *form; int g_ctrl_num; diff --git a/src/document/html/internal.h b/src/document/html/internal.h index a3311b0a..a61740f0 100644 --- a/src/document/html/internal.h +++ b/src/document/html/internal.h @@ -58,7 +58,7 @@ typedef struct nscss_select_ctx } nscss_select_ctx; struct el_sheet { - LIST_HEAD(struct el_sheet); + LIST_HEAD_EL(struct el_sheet); css_stylesheet *sheet; }; #endif diff --git a/src/document/html/parser.h b/src/document/html/parser.h index 4a0955a5..b6373982 100644 --- a/src/document/html/parser.h +++ b/src/document/html/parser.h @@ -144,7 +144,7 @@ enum html_element_pseudo_class { typedef unsigned char html_element_pseudo_class_T; struct html_element { - LIST_HEAD(struct html_element); + LIST_HEAD_EL(struct html_element); enum html_element_mortality_type type; diff --git a/src/document/html/renderer.c b/src/document/html/renderer.c index 3f813aec..36120d2e 100644 --- a/src/document/html/renderer.c +++ b/src/document/html/renderer.c @@ -82,7 +82,7 @@ struct table_cache_entry_key { }; struct table_cache_entry { - LIST_HEAD(struct table_cache_entry); + LIST_HEAD_EL(struct table_cache_entry); struct table_cache_entry_key key; struct part part; diff --git a/src/document/view.h b/src/document/view.h index 06d4b888..00f2b3dc 100644 --- a/src/document/view.h +++ b/src/document/view.h @@ -13,7 +13,7 @@ struct document; struct view_state; struct document_view { - LIST_HEAD(struct document_view); + LIST_HEAD_EL(struct document_view); char *name; char **search_word; diff --git a/src/ecmascript/ecmascript.h b/src/ecmascript/ecmascript.h index 34ee199b..7cb819a0 100644 --- a/src/ecmascript/ecmascript.h +++ b/src/ecmascript/ecmascript.h @@ -115,7 +115,7 @@ struct ecmascript_interpreter { }; struct ecmascript_timeout { - LIST_HEAD(struct ecmascript_timeout); + LIST_HEAD_EL(struct ecmascript_timeout); struct string code; #ifdef CONFIG_QUICKJS JSValueConst fun; diff --git a/src/ecmascript/libdom/mujs/element.c b/src/ecmascript/libdom/mujs/element.c index ff5393bb..dc953444 100644 --- a/src/ecmascript/libdom/mujs/element.c +++ b/src/ecmascript/libdom/mujs/element.c @@ -57,7 +57,7 @@ #include "viewer/text/vs.h" struct listener { - LIST_HEAD(struct listener); + LIST_HEAD_EL(struct listener); char *typ; const char *fun; }; diff --git a/src/ecmascript/libdom/mujs/window.c b/src/ecmascript/libdom/mujs/window.c index c172de53..d4b3e627 100644 --- a/src/ecmascript/libdom/mujs/window.c +++ b/src/ecmascript/libdom/mujs/window.c @@ -46,7 +46,7 @@ #include "viewer/text/vs.h" struct listener { - LIST_HEAD(struct listener); + LIST_HEAD_EL(struct listener); char *typ; const char *fun; }; diff --git a/src/ecmascript/libdom/quickjs/element.c b/src/ecmascript/libdom/quickjs/element.c index 4b47a6f3..699c6f5d 100644 --- a/src/ecmascript/libdom/quickjs/element.c +++ b/src/ecmascript/libdom/quickjs/element.c @@ -34,7 +34,7 @@ static JSClassID js_element_class_id; struct element_listener { - LIST_HEAD(struct element_listener); + LIST_HEAD_EL(struct element_listener); char *typ; JSValue fun; }; diff --git a/src/ecmascript/libdom/quickjs/window.c b/src/ecmascript/libdom/quickjs/window.c index 09a1a170..882d670c 100644 --- a/src/ecmascript/libdom/quickjs/window.c +++ b/src/ecmascript/libdom/quickjs/window.c @@ -35,7 +35,7 @@ static JSClassID js_window_class_id; struct win_listener { - LIST_HEAD(struct win_listener); + LIST_HEAD_EL(struct win_listener); char *typ; JSValue fun; }; diff --git a/src/ecmascript/libdom/spidermonkey/element.cpp b/src/ecmascript/libdom/spidermonkey/element.cpp index a320b86a..8f1fc1b1 100644 --- a/src/ecmascript/libdom/spidermonkey/element.cpp +++ b/src/ecmascript/libdom/spidermonkey/element.cpp @@ -97,7 +97,7 @@ static bool element_get_property_title(JSContext *ctx, unsigned int argc, JS::Va static bool element_set_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp); struct listener { - LIST_HEAD(struct listener); + LIST_HEAD_EL(struct listener); char *typ; JS::RootedValue fun; }; diff --git a/src/ecmascript/libdom/spidermonkey/window.cpp b/src/ecmascript/libdom/spidermonkey/window.cpp index c4a096b1..4f64a9e3 100644 --- a/src/ecmascript/libdom/spidermonkey/window.cpp +++ b/src/ecmascript/libdom/spidermonkey/window.cpp @@ -58,7 +58,7 @@ static bool window_set_property_status(JSContext *ctx, unsigned int argc, JS::Va static bool window_get_property_top(JSContext *ctx, unsigned int argc, JS::Value *vp); struct listener { - LIST_HEAD(struct listener); + LIST_HEAD_EL(struct listener); char *typ; JS::RootedValue fun; }; diff --git a/src/ecmascript/libdom/spidermonkey/xhr.cpp b/src/ecmascript/libdom/spidermonkey/xhr.cpp index b1a00131..6796c22e 100644 --- a/src/ecmascript/libdom/spidermonkey/xhr.cpp +++ b/src/ecmascript/libdom/spidermonkey/xhr.cpp @@ -109,7 +109,7 @@ enum { }; struct listener { - LIST_HEAD(struct listener); + LIST_HEAD_EL(struct listener); char *typ; JS::RootedValue fun; }; diff --git a/src/ecmascript/mujs/xhr.h b/src/ecmascript/mujs/xhr.h index e4905216..0208ccb0 100644 --- a/src/ecmascript/mujs/xhr.h +++ b/src/ecmascript/mujs/xhr.h @@ -16,7 +16,7 @@ enum { }; struct xhr_listener { - LIST_HEAD(struct xhr_listener); + LIST_HEAD_EL(struct xhr_listener); char *typ; const char *fun; }; diff --git a/src/ecmascript/quickjs/heartbeat.h b/src/ecmascript/quickjs/heartbeat.h index cd82bfde..bd0fc767 100644 --- a/src/ecmascript/quickjs/heartbeat.h +++ b/src/ecmascript/quickjs/heartbeat.h @@ -8,7 +8,7 @@ extern "C" { #endif struct heartbeat { - LIST_HEAD(struct heartbeat); + LIST_HEAD_EL(struct heartbeat); int ttl; /* Time to live. This value is assigned when the * script begins execution and is decremented every diff --git a/src/ecmascript/quickjs/xhr.h b/src/ecmascript/quickjs/xhr.h index 18d23ead..0917d654 100644 --- a/src/ecmascript/quickjs/xhr.h +++ b/src/ecmascript/quickjs/xhr.h @@ -39,7 +39,7 @@ enum { struct emcascript_interpreter; struct xhr_listener { - LIST_HEAD(struct xhr_listener); + LIST_HEAD_EL(struct xhr_listener); char *typ; JSValue fun; }; diff --git a/src/ecmascript/spidermonkey/heartbeat.h b/src/ecmascript/spidermonkey/heartbeat.h index 079e0498..3f2c90eb 100644 --- a/src/ecmascript/spidermonkey/heartbeat.h +++ b/src/ecmascript/spidermonkey/heartbeat.h @@ -6,7 +6,7 @@ #include "ecmascript/spidermonkey.h" struct heartbeat { - LIST_HEAD(struct heartbeat); + LIST_HEAD_EL(struct heartbeat); int ttl; /* Time to live. This value is assigned when the * script begins execution and is decremented every diff --git a/src/main/object.h b/src/main/object.h index e6248c3b..f53020df 100644 --- a/src/main/object.h +++ b/src/main/object.h @@ -19,7 +19,7 @@ struct object { }; #define OBJECT_HEAD(type) \ - LIST_HEAD(type); \ + LIST_HEAD_EL(type); \ struct object object struct object_head { diff --git a/src/main/select.c b/src/main/select.c index 84571423..d4d0d4b7 100644 --- a/src/main/select.c +++ b/src/main/select.c @@ -57,6 +57,8 @@ do { \ #define EINTRLOOP(ret_, call_) EINTRLOOPX(ret_, call_, -1) +#include + #include "elinks.h" #include "intl/libintl.h" @@ -76,6 +78,248 @@ do { \ #endif #ifdef USE_LIBEVENT + +/* Information associated with a specific easy handle */ +typedef struct _ConnInfo +{ + CURL *easy; + char *url; + GlobalInfo *global; + char error[CURL_ERROR_SIZE]; +} ConnInfo; + +/* Information associated with a specific socket */ +typedef struct _SockInfo +{ + curl_socket_t sockfd; + CURL *easy; + int action; + long timeout; + struct event ev; + GlobalInfo *global; +} SockInfo; + +#define mycase(code) \ + case code: s = __STRING(code) + +/* Die if we get a bad CURLMcode somewhere */ +void +mcode_or_die(const char *where, CURLMcode code) +{ + if (CURLM_OK != code) { + const char *s; + + switch(code) { + mycase(CURLM_BAD_HANDLE); break; + mycase(CURLM_BAD_EASY_HANDLE); break; + mycase(CURLM_OUT_OF_MEMORY); break; + mycase(CURLM_INTERNAL_ERROR); break; + mycase(CURLM_UNKNOWN_OPTION); break; + mycase(CURLM_LAST); break; + default: s = "CURLM_unknown"; break; + mycase(CURLM_BAD_SOCKET); + fprintf(stderr, "ERROR: %s returns %s\n", where, s); + /* ignore this error */ + return; + } + fprintf(stderr, "ERROR: %s returns %s\n", where, s); + //exit(code); + } +} + +/* Update the event timer after curl_multi library calls */ +static int +multi_timer_cb(CURLM *multi, long timeout_ms, GlobalInfo *g) +{ + struct timeval timeout; + (void)multi; + + timeout.tv_sec = timeout_ms/1000; + timeout.tv_usec = (timeout_ms%1000)*1000; + //fprintf(stderr, "multi_timer_cb: Setting timeout to %ld ms\n", timeout_ms); + + /* + * if timeout_ms is -1, just delete the timer + * + * For all other values of timeout_ms, this should set or *update* the timer + * to the new value + */ + + if (timeout_ms == -1) { + evtimer_del(&g->timer_event); + } else { /* includes timeout zero */ + evtimer_add(&g->timer_event, &timeout); + } + + return 0; +} + +/* Called by libevent when we get action on a multi socket */ +static void +event_cb(int fd, short kind, void *userp) +{ + GlobalInfo *g = (GlobalInfo*) userp; + CURLMcode rc; + + int action = ((kind & EV_READ) ? CURL_CSELECT_IN : 0) | ((kind & EV_WRITE) ? CURL_CSELECT_OUT : 0); + + rc = curl_multi_socket_action(g->multi, fd, action, &g->still_running); + mcode_or_die("event_cb: curl_multi_socket_action", rc); + check_multi_info(g); + +#if 0 + if (g->still_running <= 0) { + //fprintf(stderr, "last transfer done, kill timeout\n"); + if (evtimer_pending(&g->timer_event, NULL)) { + evtimer_del(&g->timer_event); + } + } +#endif +} + +/* Called by libevent when our timeout expires */ +static void +timer_cb(int fd, short kind, void *userp) +{ + GlobalInfo *g = (GlobalInfo *)userp; + CURLMcode rc; + (void)fd; + (void)kind; + + rc = curl_multi_socket_action(g->multi, CURL_SOCKET_TIMEOUT, 0, &g->still_running); + mcode_or_die("timer_cb: curl_multi_socket_action", rc); + check_multi_info(g); +} + +/* Clean up the SockInfo structure */ +static void +remsock(SockInfo *f) +{ + //fprintf(stderr, "remsock f=%p\n", f); + + if (f) { + if (event_initialized(&f->ev)) { + event_del(&f->ev); + } + mem_free(f); + } +} + +/* Assign information to a SockInfo structure */ +static void +setsock(SockInfo *f, curl_socket_t s, CURL *e, int act, GlobalInfo *g) +{ + int kind = ((act & CURL_POLL_IN) ? EV_READ : 0) | ((act & CURL_POLL_OUT) ? EV_WRITE : 0) | EV_PERSIST; + + f->sockfd = s; + f->action = act; + f->easy = e; + + //fprintf(stderr, "setsock f=%p\n", f); + + + if (event_initialized(&f->ev)) { + event_del(&f->ev); + } + event_assign(&f->ev, g->evbase, f->sockfd, kind, event_cb, g); + event_add(&f->ev, NULL); +} + +/* Initialize a new SockInfo structure */ +static void +addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g) +{ + //fprintf(stderr, "addsock easy=%p\n", easy); + + SockInfo *fdp = mem_calloc(1, sizeof(SockInfo)); + fdp->global = g; + setsock(fdp, s, easy, action, g); + curl_multi_assign(g->multi, s, fdp); +} + +/* CURLMOPT_SOCKETFUNCTION */ +static int +sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) +{ + GlobalInfo *g = (GlobalInfo*) cbp; + SockInfo *fdp = (SockInfo*) sockp; + const char *whatstr[]={ "none", "IN", "OUT", "INOUT", "REMOVE" }; + + //fprintf(stderr, "socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]); + + if (what == CURL_POLL_REMOVE) { + //fprintf(stderr, "\n"); + remsock(fdp); + } else { + if (!fdp) { + //fprintf(stderr, "Adding data: %s\n", whatstr[what]); + addsock(s, e, what, g); + } else { + //fprintf(stderr, "Changing action from %s to %s\n", whatstr[fdp->action], whatstr[what]); + setsock(fdp, s, e, what, g); + } + } + + return 0; +} + +/* CURLOPT_WRITEFUNCTION */ +static size_t +write_cb(void *ptr, size_t size, size_t nmemb, void *data) +{ + (void)ptr; + (void)data; + return size * nmemb; +} + + +/* CURLOPT_PROGRESSFUNCTION */ +static int +prog_cb(void *p, double dltotal, double dlnow, double ult, double uln) +{ + ConnInfo *conn = (ConnInfo *)p; + (void)ult; + (void)uln; + + //fprintf(stderr, "Progress: %s (%g/%g)\n", conn->url, dlnow, dltotal); + return 0; +} + +/* Create a new easy handle, and add it to the global curl_multi */ +static void +new_conn(char *url, GlobalInfo *g) +{ + ConnInfo *conn; + CURLMcode rc; + + conn = mem_calloc(1, sizeof(ConnInfo)); + conn->error[0]='\0'; + conn->easy = curl_easy_init(); + + if (!conn->easy) { + fprintf(stderr, "curl_easy_init() failed, exiting!\n"); + return; + //exit(2); + } + conn->global = g; + conn->url = strdup(url); + curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url); + curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error); + curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn); + curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb); + curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn); + curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L); + //fprintf(stderr, "Adding easy %p to multi %p (%s)\n", conn->easy, g->multi, url); + rc = curl_multi_add_handle(g->multi, conn->easy); + mcode_or_die("new_conn: curl_multi_add_handle", rc); + + /* note that the add_handle() will set a time-out to trigger very soon so that the necessary socket_action() call will be called by this app */ +} + const char * get_libevent_version(void) { @@ -138,7 +382,7 @@ get_file_handles_count(void) } struct bottom_half { - LIST_HEAD(struct bottom_half); + LIST_HEAD_EL(struct bottom_half); select_handler_T fn; void *data; @@ -498,9 +742,12 @@ periodic_redraw_all_terminals(void *data) install_timer(&periodic_redraw_timer, DISPLAY_TIME_REFRESH, periodic_redraw_all_terminals, NULL); } +GlobalInfo g; + void select_loop(void (*init)(void)) { + timeval_T last_time; int select_errors = 0; @@ -527,6 +774,23 @@ select_loop(void (*init)(void)) periodic_redraw_all_terminals(NULL); #ifdef USE_LIBEVENT if (event_enabled) { + memset(&g, 0, sizeof(GlobalInfo)); + g.evbase = event_base; + curl_global_init(CURL_GLOBAL_DEFAULT); + g.multi = curl_multi_init(); + +//fprintf(stderr, "multi_init\n"); + + evtimer_assign(&g.timer_event, g.evbase, timer_cb, &g); + + /* setup the generic multi interface options we want */ + curl_multi_setopt(g.multi, CURLMOPT_SOCKETFUNCTION, sock_cb); + curl_multi_setopt(g.multi, CURLMOPT_SOCKETDATA, &g); + curl_multi_setopt(g.multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb); + curl_multi_setopt(g.multi, CURLMOPT_TIMERDATA, &g); + + /* we do not call any curl_multi_socket*() function yet as we have no handles added! */ + while (!program.terminate) { check_signals(); if (1 /*(!F)*/) { @@ -537,6 +801,12 @@ select_loop(void (*init)(void)) do_event_loop(EVLOOP_ONCE); } kill_timer(&periodic_redraw_timer); + + event_del(&g.timer_event); + //event_base_free(g.evbase); + curl_multi_cleanup(g.multi); + curl_global_cleanup(); + return; } else #endif diff --git a/src/main/select.h b/src/main/select.h index dd2f9a2c..d5116920 100644 --- a/src/main/select.h +++ b/src/main/select.h @@ -1,10 +1,50 @@ #ifndef EL__MAIN_SELECT_H #define EL__MAIN_SELECT_H +#if defined(HAVE_LIBEV) && !defined(OPENVMS) && !defined(DOS) +#ifdef HAVE_LIBEV_EVENT_H +#include +#elif defined(HAVE_EVENT_H) +#include +#endif +#define USE_LIBEVENT +#endif + +#if (defined(HAVE_EVENT_H) || defined(HAVE_EV_EVENT_H) || defined(HAVE_LIBEV_EVENT_H)) && defined(HAVE_LIBEVENT) && !defined(OPENVMS) && !defined(DOS) +#if defined(HAVE_EVENT_H) +#include +#elif defined(HAVE_EV_EVENT_H) +#include +#endif +#define USE_LIBEVENT +#endif + +#include + #ifdef __cplusplus extern "C" { #endif +#ifdef USE_LIBEVENT +/* Global information, common to all connections */ +typedef struct _GlobalInfo +{ + struct event_base *evbase; + struct event fifo_event; + struct event timer_event; + CURLM *multi; + int still_running; + FILE *input; + int stopped; +} GlobalInfo; + +extern GlobalInfo g; + +void check_multi_info(GlobalInfo *g); + +void mcode_or_die(const char *where, CURLMcode code); +#endif + typedef void (*select_handler_T)(void *); /* Start the select loop after calling the passed @init() function. */ diff --git a/src/main/timer.h b/src/main/timer.h index 3c9fabf4..7e0e64d6 100644 --- a/src/main/timer.h +++ b/src/main/timer.h @@ -9,7 +9,7 @@ extern "C" { #endif struct timer { - LIST_HEAD(struct timer); + LIST_HEAD_EL(struct timer); timeval_T interval; void (*func)(void *); diff --git a/src/mime/backend/dgi.c b/src/mime/backend/dgi.c index 3b143533..d5f9980e 100644 --- a/src/mime/backend/dgi.c +++ b/src/mime/backend/dgi.c @@ -32,7 +32,7 @@ struct dgi_hash_item { }; struct dgi_entry { - LIST_HEAD(struct dgi_entry); + LIST_HEAD_EL(struct dgi_entry); char *type; char *inpext; diff --git a/src/mime/backend/mailcap.c b/src/mime/backend/mailcap.c index 75af4d7a..0df01587 100644 --- a/src/mime/backend/mailcap.c +++ b/src/mime/backend/mailcap.c @@ -49,7 +49,7 @@ struct mailcap_hash_item { }; struct mailcap_entry { - LIST_HEAD(struct mailcap_entry); + LIST_HEAD_EL(struct mailcap_entry); /* To verify if command qualifies. Cannot contain %s formats. */ char *testcommand; diff --git a/src/network/connection.c b/src/network/connection.c index f829bf5c..827aed83 100644 --- a/src/network/connection.c +++ b/src/network/connection.c @@ -42,7 +42,7 @@ struct keepalive_connection { - LIST_HEAD(struct keepalive_connection); + LIST_HEAD_EL(struct keepalive_connection); /* XXX: This is just the URI of the connection that registered the * keepalive connection so only rely on the protocol, user, password, diff --git a/src/network/connection.h b/src/network/connection.h index ff1e0e69..49aabcb0 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -18,7 +18,7 @@ struct uri; struct connection { - LIST_HEAD(struct connection); + LIST_HEAD_EL(struct connection); LIST_OF(struct download) downloads; struct progress *progress; diff --git a/src/network/dns.c b/src/network/dns.c index aecf7875..3b5b21d5 100644 --- a/src/network/dns.c +++ b/src/network/dns.c @@ -48,7 +48,7 @@ struct dnsentry { - LIST_HEAD(struct dnsentry); + LIST_HEAD_EL(struct dnsentry); struct sockaddr_storage *addr; /* Pointer to array of addresses. */ int addrno; /* Adress array length. */ diff --git a/src/network/socket.c b/src/network/socket.c index a7666bb8..9907b824 100644 --- a/src/network/socket.c +++ b/src/network/socket.c @@ -72,7 +72,7 @@ struct connect_info { /** For detecting whether a struct socket has been deleted while a * function was using it. */ struct socket_weak_ref { - LIST_HEAD(struct socket_weak_ref); + LIST_HEAD_EL(struct socket_weak_ref); /** done_socket() resets this to NULL. */ struct socket *socket; diff --git a/src/network/state.c b/src/network/state.c index 84385fce..c2ce88fd 100644 --- a/src/network/state.c +++ b/src/network/state.c @@ -140,7 +140,7 @@ static const struct s_msg_dsc msg_dsc[] = { struct strerror_val { - LIST_HEAD(struct strerror_val); + LIST_HEAD_EL(struct strerror_val); char msg[1]; /* must be last */ }; diff --git a/src/osdep/beos/beos.c b/src/osdep/beos/beos.c index 558f700e..6f501ebf 100644 --- a/src/osdep/beos/beos.c +++ b/src/osdep/beos/beos.c @@ -54,7 +54,7 @@ int thr_sem_init = 0; sem_id thr_sem; struct active_thread { - LIST_HEAD(struct active_thread); + LIST_HEAD_EL(struct active_thread); thread_id tid; void (*fn)(void *); diff --git a/src/protocol/bittorrent/bittorrent.c b/src/protocol/bittorrent/bittorrent.c index 1fda4194..68dfbb58 100644 --- a/src/protocol/bittorrent/bittorrent.c +++ b/src/protocol/bittorrent/bittorrent.c @@ -239,7 +239,7 @@ get_bittorrent_peerwire_max_request_length(void) static INIT_LIST_OF(struct bittorrent_selection_info, bittorrent_selections); struct bittorrent_selection_info { - LIST_HEAD(struct bittorrent_selection_info); + LIST_HEAD_EL(struct bittorrent_selection_info); /* Identifier used for saving and getting meta info from the meta info * store. */ diff --git a/src/protocol/bittorrent/common.c b/src/protocol/bittorrent/common.c index 9a2cb039..774ec847 100644 --- a/src/protocol/bittorrent/common.c +++ b/src/protocol/bittorrent/common.c @@ -462,7 +462,7 @@ done_bittorrent_fetch(struct bittorrent_fetcher **fetcher_ref) /* ************************************************************************** */ struct bittorrent_blacklist_item { - LIST_HEAD(struct bittorrent_blacklist_item); + LIST_HEAD_EL(struct bittorrent_blacklist_item); bittorrent_blacklist_flags_T flags; bittorrent_id_T id; diff --git a/src/protocol/bittorrent/common.h b/src/protocol/bittorrent/common.h index e2eb71ea..5c75b6aa 100644 --- a/src/protocol/bittorrent/common.h +++ b/src/protocol/bittorrent/common.h @@ -69,7 +69,7 @@ enum bittorrent_state { /** For showing tracker failure responses to the user. */ struct bittorrent_message { - LIST_HEAD(struct bittorrent_message); + LIST_HEAD_EL(struct bittorrent_message); struct uri *uri; struct connection_state state; @@ -107,7 +107,7 @@ typedef int bittorrent_message_id_TT; * in the peer-wire protocol. See the piece cache header file (cache.h) for more * information about the cloned flag. */ struct bittorrent_peer_request { - LIST_HEAD(struct bittorrent_peer_request); + LIST_HEAD_EL(struct bittorrent_peer_request); uint32_t piece; /**< Zero-based piece index. */ uint32_t offset; /**< Zero-based piece byte offset. */ @@ -150,7 +150,7 @@ struct bittorrent_peer_stats { /** Peer connection information. */ struct bittorrent_peer_connection { - LIST_HEAD(struct bittorrent_peer_connection); + LIST_HEAD_EL(struct bittorrent_peer_connection); /** Unique peer ID string which can be used to look-up the peer hash. */ bittorrent_id_T id; @@ -221,7 +221,7 @@ struct bittorrent_tracker_connection { /** Information about peers returned by the tracker. */ struct bittorrent_peer { - LIST_HEAD(struct bittorrent_peer); + LIST_HEAD_EL(struct bittorrent_peer); bittorrent_id_T id; /**< Unique peer ID string. */ uint16_t port; /**< The port number to connect to. */ @@ -230,7 +230,7 @@ struct bittorrent_peer { /** Information about a file in the torrent. */ struct bittorrent_file { - LIST_HEAD(struct bittorrent_file); + LIST_HEAD_EL(struct bittorrent_file); off_t length; /**< Length of the file in bytes. */ md5_digest_hex_T md5sum; /**< Hexadecimal MD5 sum of the file. */ @@ -296,7 +296,7 @@ enum bittorrent_connection_mode { * is used by the handling of the peer-wire listening socket and should only be * managed by that. */ struct bittorrent_connection { - LIST_HEAD(struct bittorrent_connection); + LIST_HEAD_EL(struct bittorrent_connection); enum bittorrent_connection_mode mode; diff --git a/src/protocol/bittorrent/piececache.h b/src/protocol/bittorrent/piececache.h index 07ed3577..dc4bac2c 100644 --- a/src/protocol/bittorrent/piececache.h +++ b/src/protocol/bittorrent/piececache.h @@ -12,7 +12,7 @@ extern "C" { struct bitfield; struct bittorrent_piece_cache_entry { - LIST_HEAD(struct bittorrent_piece_cache_entry); + LIST_HEAD_EL(struct bittorrent_piece_cache_entry); /** Piece rarity index * To keep track of the client's view of the swarm in regards to pieces a diff --git a/src/protocol/ftpes/ftpes.c b/src/protocol/curl/ftp.c similarity index 78% rename from src/protocol/ftpes/ftpes.c rename to src/protocol/curl/ftp.c index 10d2cd19..2889ff54 100644 --- a/src/protocol/ftpes/ftpes.c +++ b/src/protocol/curl/ftp.c @@ -1,4 +1,4 @@ -/* Internal "ftpes" protocol implementation */ +/* curl ftp protocol implementation */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -45,7 +45,8 @@ #include "osdep/stat.h" #include "protocol/auth/auth.h" #include "protocol/common.h" -#include "protocol/ftpes/ftpes.h" +#include "protocol/curl/ftpes.h" +#include "protocol/curl/sftp.h" #include "protocol/ftp/parse.h" #include "protocol/uri.h" #include "util/conv.h" @@ -63,12 +64,27 @@ struct module ftpes_protocol_module = struct_module( /* done: */ NULL ); +struct module sftp_protocol_module = struct_module( + /* name: */ N_("SFTP"), + /* options: */ NULL, + /* hooks: */ NULL, + /* submodules: */ NULL, + /* data: */ NULL, + /* init: */ NULL, + /* done: */ NULL +); + + #define FTP_BUF_SIZE 16384 /* Types and structs */ struct ftpes_connection_info { + CURL *easy; + char *url; + GlobalInfo *global; + char error[CURL_ERROR_SIZE]; int conn_state; int buf_pos; @@ -335,29 +351,58 @@ ftp_process_dirlist(struct cache_entry *cached, off_t *pos, } } +static void ftpes_got_data(void *stream, void *buffer, size_t len); + static size_t my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) { - return fwrite(buffer, size, nmemb, stdout); + ftpes_got_data(stream, buffer, size * nmemb); + return nmemb; +} + +static size_t +progress_callback(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) +{ + return 0; } static void do_ftpes(struct connection *conn) { + struct ftpes_connection_info *ftp = (struct ftpes_connection_info *)mem_calloc(1, sizeof(*ftp)); struct string u; CURL *curl; - CURLcode res; + + if (!ftp) { + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + conn->info = ftp; + + if (!conn->uri->datalen || conn->uri->data[conn->uri->datalen - 1] == '/') { + ftp->dir = 1; + } + conn->from = 0; + conn->unrestartable = 1; + /// FILE *stream = fopen("/tmp/curl.log", "a"); struct auth_entry *auth = find_auth(conn->uri); char *url = get_uri_string(conn->uri, URI_HOST | URI_PORT | URI_DATA); if (!url) { - exit(0); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; } if (!init_string(&u)) { - exit(0); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); + return; + } + + if (conn->uri->protocol == PROTOCOL_FTP || conn->uri->protocol == PROTOCOL_FTPES) { + add_to_string(&u, "ftp://"); + } else { + add_to_string(&u, "sftp://"); } - add_to_string(&u, "ftp://"); if (auth) { add_to_string(&u, auth->user); @@ -371,54 +416,58 @@ do_ftpes(struct connection *conn) add_char_to_string(&u, '/'); } mem_free(url); - curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { + CURLMcode rc; + + ftp->easy = curl; curl_easy_setopt(curl, CURLOPT_URL, u.source); /* Define our callback to get called when there's data to be written */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); /* Set a pointer to our struct to pass to the callback */ - curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); - /* We activate SSL and we require it for both control and data */ - curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, conn); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, ftp->error); + curl_easy_setopt(curl, CURLOPT_PRIVATE, conn); + /* pass struct to callback */ + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, conn); + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progress_callback); + + /* enable TCP keep-alive for this transfer */ +// curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L); + /* keep-alive idle time to 120 seconds */ +// curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE, 120L); + /* interval time between keep-alive probes: 60 seconds */ +// curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL, 60L); + + /* We activate SSL and we require it for control */ + if (conn->uri->protocol == PROTOCOL_FTPES) { + curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL); + } /// curl_easy_setopt(curl, CURLOPT_STDERR, stream); /* Switch on full protocol/debug output */ curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); - res = curl_easy_perform(curl); - /* always cleanup */ - curl_easy_cleanup(curl); - if (CURLE_OK != res) { - /* we failed */ - //fprintf(stderr, "curl told us %d\n", res); - } + //fprintf(stderr, "Adding easy %p to multi %p (%s)\n", curl, g.multi, u.source); + set_connection_state(conn, connection_state(S_TRANS)); + rc = curl_multi_add_handle(g.multi, curl); + mcode_or_die("new_conn: curl_multi_add_handle", rc); } - curl_global_cleanup(); done_string(&u); - -/// if (stream) { -/// fclose(stream); -/// } - exit(0); } /* 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 -ftpes_got_data(struct socket *socket, struct read_buffer *rb) +ftpes_got_data(void *stream, void *buf, size_t len) { - int len = rb->length; - struct connection *conn = (struct connection *)socket->conn; + 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; - - /* Because this function is called only as a read handler of - * conn->data_socket->fd, the socket must be valid if we get - * here. */ - assert(conn->socket->fd >= 0); - if_assert_failed return; + size_t len2 = len; + size_t copied = 0; /* XXX: This probably belongs rather to connect.c ? */ set_connection_timeout(conn); @@ -434,7 +483,6 @@ out_of_mem: abort_connection(conn, connection_state_for_errno(errno)); return; } - socket->state = SOCKET_END_ONCLOSE; if (ftp->dir) { format.libc_codepage = get_cp_index("System"); @@ -478,27 +526,27 @@ out_of_mem: } if (!ftp->dir && (len > 0)) { - if (add_fragment(conn->cached, conn->from, rb->data, len) == 1) { + if (add_fragment(conn->cached, conn->from, buffer, len) == 1) { conn->tries = 0; } conn->from += len; - kill_buffer_data(rb, len); conn->received += len; - - read_from_socket(socket, rb, connection_state(S_TRANS), ftpes_got_data); return; } +again: + len = len2; + if (FTP_BUF_SIZE - ftp->buf_pos < len) { len = FTP_BUF_SIZE - ftp->buf_pos; } - if (len > 0) { + if (len2 > 0) { int proceeded; - memcpy(ftp->ftp_buffer + ftp->buf_pos, rb->data, len); - kill_buffer_data(rb, len); + 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, @@ -510,8 +558,13 @@ out_of_mem: ftp->buf_pos += len - proceeded; memmove(ftp->ftp_buffer, ftp->ftp_buffer + proceeded, ftp->buf_pos); - read_from_socket(socket, rb, connection_state(S_TRANS), ftpes_got_data); - return; + + len2 -= len; + + if (len2 <= 0) { + return; + } + goto again; } if (ftp_process_dirlist(conn->cached, &conn->from, @@ -524,70 +577,58 @@ out_of_mem: conn->from += (sizeof(str) - 1); } if (ftp->dir) ADD_CONST("\n
\n\n"); - abort_connection(conn, connection_state(S_OK)); } +/* Check for completed transfers, and remove their easy handles */ +void +check_multi_info(GlobalInfo *g) +{ + char *eff_url; + CURLMsg *msg; + int msgs_left; + struct connection *conn; + struct ftpes_connection_info *info; + CURL *easy; + CURLcode res; + + //fprintf(stderr, "REMAINING: %d\n", g->still_running); + + while ((msg = curl_multi_info_read(g->multi, &msgs_left))) { + if (msg->msg == CURLMSG_DONE) { + easy = msg->easy_handle; + res = msg->data.result; + curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn); + info = (struct ftpes_connection_info *)conn->info; + curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url); + //fprintf(stderr, "DONE: %s => (%d) %s\n", eff_url, res, info->error); + curl_multi_remove_handle(g->multi, easy); + curl_easy_cleanup(easy); + abort_connection(conn, connection_state(S_OK)); + } + } +#if 0 + if (g->still_running == 0 && g->stopped) { + event_base_loopbreak(g->evbase); + } +#endif +} + + +static void +done_ftpes(struct connection *conn) +{ + struct ftpes_connection_info *ftp = (struct ftpes_connection_info *)conn->info; +} + void ftpes_protocol_handler(struct connection *conn) { - int ftpes_pipe[2] = { -1, -1 }; - pid_t cpid; - struct ftpes_connection_info *ftp = (struct ftpes_connection_info *)mem_calloc(1, sizeof(*ftp)); - - if (!ftp) { - abort_connection(conn, connection_state(S_OUT_OF_MEM)); - return; - } - conn->info = ftp; - - if (!conn->uri->datalen || conn->uri->data[conn->uri->datalen - 1] == '/') { - ftp->dir = 1; - } - - if (c_pipe(ftpes_pipe)) { - int s_errno = errno; - - if (ftpes_pipe[0] >= 0) close(ftpes_pipe[0]); - if (ftpes_pipe[1] >= 0) close(ftpes_pipe[1]); - abort_connection(conn, connection_state_for_errno(s_errno)); - return; - } - conn->from = 0; - conn->unrestartable = 1; - find_auth(conn->uri); /* remember username and password */ - cpid = fork(); - - if (cpid == -1) { - int s_errno = errno; - - close(ftpes_pipe[0]); - close(ftpes_pipe[1]); - retry_connection(conn, connection_state_for_errno(s_errno)); - return; - } - - if (!cpid) { - dup2(ftpes_pipe[1], 1); - dup2(open("/dev/null", O_RDONLY), 0); - close(ftpes_pipe[0]); - close(2); - close_all_non_term_fd(); - do_ftpes(conn); - } else { - struct read_buffer *buf; - - conn->socket->fd = ftpes_pipe[0]; - set_nonblocking_fd(conn->socket->fd); - close(ftpes_pipe[1]); - buf = alloc_read_buffer(conn->socket); - - if (!buf) { - close_socket(conn->socket); - abort_connection(conn, connection_state(S_OUT_OF_MEM)); - return; - } - read_from_socket(conn->socket, buf, - connection_state(S_CONN), ftpes_got_data); - } + do_ftpes(conn); +} + +void +sftp_protocol_handler(struct connection *conn) +{ + do_ftpes(conn); } diff --git a/src/protocol/ftpes/ftpes.h b/src/protocol/curl/ftpes.h similarity index 82% rename from src/protocol/ftpes/ftpes.h rename to src/protocol/curl/ftpes.h index 6fd3497f..d17436c4 100644 --- a/src/protocol/ftpes/ftpes.h +++ b/src/protocol/curl/ftpes.h @@ -1,5 +1,5 @@ -#ifndef EL__PROTOCOL_FTPES_FTPES_H -#define EL__PROTOCOL_FTPES_FTPES_H +#ifndef EL__PROTOCOL_CURL_FTPES_H +#define EL__PROTOCOL_CURL_FTPES_H #include "main/module.h" #include "protocol/protocol.h" diff --git a/src/protocol/curl/meson.build b/src/protocol/curl/meson.build new file mode 100644 index 00000000..0d47cda7 --- /dev/null +++ b/src/protocol/curl/meson.build @@ -0,0 +1 @@ +srcs += files('ftp.c') diff --git a/src/protocol/sftp/sftp.h b/src/protocol/curl/sftp.h similarity index 81% rename from src/protocol/sftp/sftp.h rename to src/protocol/curl/sftp.h index 1266b7aa..387f1ce2 100644 --- a/src/protocol/sftp/sftp.h +++ b/src/protocol/curl/sftp.h @@ -1,5 +1,5 @@ -#ifndef EL__PROTOCOL_SFTP_SFTP_H -#define EL__PROTOCOL_SFTP_SFTP_H +#ifndef EL__PROTOCOL_CURL_SFTP_H +#define EL__PROTOCOL_CURL_SFTP_H #include "main/module.h" #include "protocol/protocol.h" diff --git a/src/protocol/ftpes/meson.build b/src/protocol/ftpes/meson.build deleted file mode 100644 index 4d2bddbb..00000000 --- a/src/protocol/ftpes/meson.build +++ /dev/null @@ -1 +0,0 @@ -srcs += files('ftpes.c') diff --git a/src/protocol/http/blacklist.c b/src/protocol/http/blacklist.c index 848c659a..51ae7251 100644 --- a/src/protocol/http/blacklist.c +++ b/src/protocol/http/blacklist.c @@ -17,7 +17,7 @@ struct blacklist_entry { - LIST_HEAD(struct blacklist_entry); + LIST_HEAD_EL(struct blacklist_entry); blacklist_flags_T flags; char host[1]; /* Must be last. */ diff --git a/src/protocol/meson.build b/src/protocol/meson.build index f8d6f408..a7958842 100644 --- a/src/protocol/meson.build +++ b/src/protocol/meson.build @@ -1,6 +1,9 @@ if conf_data.get('CONFIG_BITTORRENT') subdir('bittorrent') endif +if conf_data.get('CONFIG_LIBCURL') + subdir('curl') +endif if conf_data.get('CONFIG_FINGER') subdir('finger') endif @@ -9,9 +12,6 @@ if conf_data.get('CONFIG_FSP') endif if conf_data.get('CONFIG_FTP') subdir('ftp') - if conf_data.get('CONFIG_LIBCURL') - subdir('ftpes') - endif endif if conf_data.get('CONFIG_GEMINI') subdir('gemini') @@ -22,9 +22,6 @@ endif if conf_data.get('CONFIG_NNTP') subdir('nntp') endif -if conf_data.get('CONFIG_LIBCURL') - subdir('sftp') -endif if conf_data.get('CONFIG_SMB') subdir('smb') endif diff --git a/src/protocol/protocol.cpp b/src/protocol/protocol.cpp index e5fc5768..37a5b128 100644 --- a/src/protocol/protocol.cpp +++ b/src/protocol/protocol.cpp @@ -29,6 +29,8 @@ #include "protocol/auth/auth.h" #include "protocol/bittorrent/bittorrent.h" #include "protocol/bittorrent/connection.h" +#include "protocol/curl/ftpes.h" +#include "protocol/curl/sftp.h" #include "protocol/data.h" #include "protocol/file/cgi.h" #include "protocol/file/dgi.h" @@ -37,8 +39,6 @@ #include "protocol/finger/finger.h" #include "protocol/fsp/fsp.h" #include "protocol/ftp/ftp.h" -#include "protocol/ftpes/ftpes.h" -#include "protocol/sftp/sftp.h" #include "protocol/gemini/gemini.h" #include "protocol/gopher/gopher.h" #include "protocol/http/http.h" diff --git a/src/protocol/sftp/meson.build b/src/protocol/sftp/meson.build deleted file mode 100644 index 299dc17d..00000000 --- a/src/protocol/sftp/meson.build +++ /dev/null @@ -1 +0,0 @@ -srcs += files('sftp.c') diff --git a/src/protocol/sftp/sftp.c b/src/protocol/sftp/sftp.c deleted file mode 100644 index a8ad80d8..00000000 --- a/src/protocol/sftp/sftp.c +++ /dev/null @@ -1,592 +0,0 @@ -/* SFTP protocol implementation */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include /* For converting permissions to strings */ -#include -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_FCNTL_H -#include /* OS/2 needs this after sys/types.h */ -#endif - -/* We need to have it here. Stupid BSD. */ -#ifdef HAVE_NETINET_IN_H -#include -#endif -#ifdef HAVE_ARPA_INET_H -#include -#endif - -#include - -#include "elinks.h" - -#include "cache/cache.h" -#include "config/options.h" -#include "intl/libintl.h" -#include "main/select.h" -#include "main/module.h" -#include "network/connection.h" -#include "network/progress.h" -#include "network/socket.h" -#include "osdep/osdep.h" -#include "osdep/stat.h" -#include "protocol/auth/auth.h" -#include "protocol/common.h" -#include "protocol/ftp/parse.h" -#include "protocol/sftp/sftp.h" -#include "protocol/uri.h" -#include "util/conv.h" -#include "util/error.h" -#include "util/memory.h" -#include "util/string.h" - -struct module sftp_protocol_module = struct_module( - /* name: */ N_("SFTP"), - /* options: */ NULL, - /* hooks: */ NULL, - /* submodules: */ NULL, - /* data: */ NULL, - /* init: */ NULL, - /* done: */ NULL -); - -#define FTP_BUF_SIZE 16384 - -/* Types and structs */ - -struct sftp_connection_info { - int conn_state; - int buf_pos; - - unsigned int dir:1; /* Directory listing in progress */ - char ftp_buffer[FTP_BUF_SIZE]; -}; - -/** How to format an FTP directory listing in HTML. */ -struct ftp_dir_html_format { - /** Codepage used by C library functions such as strftime(). - * If the FTP server sends non-ASCII bytes in file names or - * such, ELinks normally passes them straight through to the - * generated HTML, which will eventually be parsed using the - * codepage specified in the document.codepage.assume option. - * However, when ELinks itself generates strings with - * strftime(), it turns non-ASCII bytes into entity references - * based on libc_codepage, to make sure they become the right - * characters again. */ - int libc_codepage; - - /** Nonzero if directories should be displayed in a different - * color. From the document.browse.links.color_dirs option. */ - int colorize_dir; - - /** The color of directories, in "#rrggbb" format. This is - * initialized and used only if colorize_dir is nonzero. */ - char dircolor[8]; -}; - -/* Display directory entry formatted in HTML. */ -static int -display_dir_entry(struct cache_entry *cached, off_t *pos, int *tries, - const struct ftp_dir_html_format *format, - struct ftp_file_info *ftp_info) -{ - struct string string; - char permissions[10] = "---------"; - - if (!init_string(&string)) return -1; - - add_char_to_string(&string, ftp_info->type); - - if (ftp_info->permissions) { - mode_t p = ftp_info->permissions; - -#define FTP_PERM(perms, buffer, flag, index, id) \ - if ((perms) & (flag)) (buffer)[(index)] = (id); - - FTP_PERM(p, permissions, S_IRUSR, 0, 'r'); - FTP_PERM(p, permissions, S_IWUSR, 1, 'w'); - FTP_PERM(p, permissions, S_IXUSR, 2, 'x'); - FTP_PERM(p, permissions, S_ISUID, 2, (p & S_IXUSR ? 's' : 'S')); - - FTP_PERM(p, permissions, S_IRGRP, 3, 'r'); - FTP_PERM(p, permissions, S_IWGRP, 4, 'w'); - FTP_PERM(p, permissions, S_IXGRP, 5, 'x'); - FTP_PERM(p, permissions, S_ISGID, 5, (p & S_IXGRP ? 's' : 'S')); - - FTP_PERM(p, permissions, S_IROTH, 6, 'r'); - FTP_PERM(p, permissions, S_IWOTH, 7, 'w'); - FTP_PERM(p, permissions, S_IXOTH, 8, 'x'); - FTP_PERM(p, permissions, S_ISVTX, 8, (p & 0001 ? 't' : 'T')); - -#undef FTP_PERM - - } - - add_to_string(&string, permissions); - add_char_to_string(&string, ' '); - - add_to_string(&string, " 1 ftp ftp "); - - if (ftp_info->size != FTP_SIZE_UNKNOWN) { - add_format_to_string(&string, "%12" OFF_PRINT_FORMAT " ", - (off_print_T) ftp_info->size); - } else { - add_to_string(&string, " - "); - } - -#ifdef HAVE_STRFTIME - if (ftp_info->mtime > 0) { - time_t current_time = time(NULL); - time_t when = ftp_info->mtime; - struct tm *when_tm; - char *fmt; - /* LC_TIME=fi_FI.UTF_8 can generate "elo___ 31 23:59" - * where each _ denotes U+00A0 encoded as 0xC2 0xA0, - * thus needing a 19-byte buffer. */ - char date[MAX_STR_LEN]; - int wr; - - if (ftp_info->local_time_zone) - when_tm = localtime(&when); - else - when_tm = gmtime(&when); - - if (current_time > when + 6L * 30L * 24L * 60L * 60L - || current_time < when - 60L * 60L) - fmt = gettext("%b %e %Y"); - else - fmt = gettext("%b %e %H:%M"); - - wr = strftime(date, sizeof(date), fmt, when_tm); - add_cp_html_to_string(&string, format->libc_codepage, - date, wr); - } else -#endif - add_to_string(&string, gettext(" ")); - /* TODO: Above, the number of spaces might not match the width - * of the string generated by strftime. It depends on the - * locale. So if ELinks knows the timestamps of some FTP - * files but not others, it may misalign the file names. - * Potential solutions: - * - Pad the strings to a compile-time fixed width. - * Con: If we choose a width that suffices for all known - * locales, then it will be stupidly large for most of them. - * - Generate an HTML table. - * Con: Bloats the HTML source. - * Any solution chosen here should also be applied to the - * file: protocol handler. */ - - if (ftp_info->type == FTP_FILE_DIRECTORY && format->colorize_dir) { - add_to_string(&string, "dircolor); - add_to_string(&string, "\">"); - } - - add_to_string(&string, "name.source, ftp_info->name.length, 0); - if (ftp_info->type == FTP_FILE_DIRECTORY) - add_char_to_string(&string, '/'); - add_to_string(&string, "\">"); - add_html_to_string(&string, ftp_info->name.source, ftp_info->name.length); - add_to_string(&string, ""); - - if (ftp_info->type == FTP_FILE_DIRECTORY && format->colorize_dir) { - add_to_string(&string, ""); - } - - if (ftp_info->symlink.length) { - add_to_string(&string, " -> "); - add_html_to_string(&string, ftp_info->symlink.source, - ftp_info->symlink.length); - } - - add_char_to_string(&string, '\n'); - - if (add_fragment(cached, *pos, string.source, string.length)) *tries = 0; - *pos += string.length; - - done_string(&string); - return 0; -} - -/* Get the next line of input and set *@len to the length of the line. - * Return the number of newline characters at the end of the line or -1 - * if we must wait for more input. */ -static int -ftp_get_line(struct cache_entry *cached, char *buf, int bufl, - int last, int *len) -{ - char *newline; - - if (!bufl) return -1; - - newline = (char *)memchr(buf, ASCII_LF, bufl); - - if (newline) { - *len = newline - buf; - if (*len && buf[*len - 1] == ASCII_CR) { - --*len; - return 2; - } else { - return 1; - } - } - - if (last || bufl >= FTP_BUF_SIZE) { - *len = bufl; - return 0; - } - - return -1; -} - -/** Generate HTML for a line that was received from the FTP server but - * could not be parsed. The caller is supposed to have added a \
- * start tag.  (At the time of writing, init_directory_listing() was
- * used for that.)
- *
- * @return -1 if out of memory, or 0 if successful.  */
-static int
-ftp_add_unparsed_line(struct cache_entry *cached, off_t *pos, int *tries, 
-		      const char *line, int line_length)
-{
-	int our_ret;
-	struct string string;
-	int frag_ret;
-
-	our_ret = -1;	 /* assume out of memory if returning early */
-	if (!init_string(&string)) goto out;
-	if (!add_html_to_string(&string, line, line_length)) goto out;
-	if (!add_char_to_string(&string, '\n')) goto out;
-
-	frag_ret = add_fragment(cached, *pos, string.source, string.length);
-	if (frag_ret == -1) goto out;
-	*pos += string.length;
-	if (frag_ret == 1) *tries = 0;
-
-	our_ret = 0;		/* success */
-
-out:
-	done_string(&string);	/* safe even if init_string failed */
-	return our_ret;
-}
-
-/** List a directory in html format.
- *
- * @return the number of bytes used from the beginning of @a buffer,
- * or -1 if out of memory.  */
-static int
-ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
-		    char *buffer, int buflen, int last,
-		    int *tries, const struct ftp_dir_html_format *format)
-{
-	int ret = 0;
-
-	while (1) {
-		struct ftp_file_info ftp_info = INIT_FTP_FILE_INFO;
-		char *buf = buffer + ret;
-		int bufl = buflen - ret;
-		int line_length, eol;
-
-		eol = ftp_get_line(cached, buf, bufl, last, &line_length);
-		if (eol == -1)
-			return ret;
-
-		ret += line_length + eol;
-
-		/* Process line whose end we've already found. */
-
-		if (parse_ftp_file_info(&ftp_info, buf, line_length)) {
-			int retv;
-
-			if (ftp_info.name.source[0] == '.'
-			    && (ftp_info.name.length == 1
-				|| (ftp_info.name.length == 2
-				    && ftp_info.name.source[1] == '.')))
-				continue;
-
-			retv = display_dir_entry(cached, pos, tries,
-						 format, &ftp_info);
-			if (retv < 0) {
-				return ret;
-			}
-
-		} else {
-			int retv = ftp_add_unparsed_line(cached, pos, tries,
-							 buf, line_length);
-
-			if (retv == -1) /* out of memory; propagate to caller */
-				return retv;
-		}
-	}
-}
-
-static size_t
-my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
-{
-	return fwrite(buffer, size, nmemb, stdout);
-}
-
-static void
-do_sftp(struct connection *conn)
-{
-	struct string u;
-	CURL *curl;
-	CURLcode res;
-///	FILE *stream = fopen("/tmp/curl.log", "a");
-	struct auth_entry *auth = find_auth(conn->uri);
-	char *url = get_uri_string(conn->uri, URI_HOST | URI_PORT | URI_DATA);
-
-	if (!url) {
-		exit(0);
-	}
-	if (!init_string(&u)) {
-		exit(0);
-	}
-	add_to_string(&u, "sftp://");
-
-	if (auth) {
-		add_to_string(&u, auth->user);
-		add_char_to_string(&u, ':');
-		add_to_string(&u, auth->password);
-		add_char_to_string(&u, '@');
-	}
-	add_to_string(&u, url);
-
-	if (!conn->uri->datalen) {
-		add_char_to_string(&u, '/');
-	}
-	mem_free(url);
-	curl_global_init(CURL_GLOBAL_DEFAULT);
-	curl = curl_easy_init();
-
-	if (curl) {
-		curl_easy_setopt(curl, CURLOPT_URL, u.source);
-		/* Define our callback to get called when there's data to be written */
-		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
-		/* Set a pointer to our struct to pass to the callback */
-		curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL);
-		/* We activate SSL and we require it for both control and data */
-		curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
-///		curl_easy_setopt(curl, CURLOPT_STDERR, stream);
-		/* Switch on full protocol/debug output */
-		curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
-		res = curl_easy_perform(curl);
-		/* always cleanup */
-		curl_easy_cleanup(curl);
-
-		if (CURLE_OK != res) {
-			/* we failed */
-			//fprintf(stderr, "curl told us %d\n", res);
-		}
-	}
-	curl_global_cleanup();
-	done_string(&u);
-
-///	if (stream) {
-///		fclose(stream);
-///	}
-	exit(0);
-}
-
-/* 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(struct socket *socket, struct read_buffer *rb)
-{
-	int len = rb->length;
-	struct connection *conn = (struct connection *)socket->conn;
-	struct sftp_connection_info *ftp = (struct sftp_connection_info *)conn->info;
-	struct ftp_dir_html_format format;
-
-	/* Because this function is called only as a read handler of
-	 * conn->data_socket->fd, the socket must be valid if we get
-	 * here.  */
-	assert(conn->socket->fd >= 0);
-	if_assert_failed return;
-
-	/* 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;
-	}
-	socket->state = SOCKET_END_ONCLOSE;
-
-	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, rb->data, len) == 1) {
-			conn->tries = 0;
-		}
-		conn->from += len;
-		kill_buffer_data(rb, len);
-		conn->received += len;
-
-		read_from_socket(socket, rb, connection_state(S_TRANS), sftp_got_data);
-		return;
-	}
-
-	if (FTP_BUF_SIZE - ftp->buf_pos < len) {
-		len = FTP_BUF_SIZE - ftp->buf_pos;
-	}
-
-	if (len > 0) {
-		int proceeded;
-
-		memcpy(ftp->ftp_buffer + ftp->buf_pos, rb->data, len);
-		kill_buffer_data(rb, len);
-		conn->received += len;
-		proceeded = ftp_process_dirlist(conn->cached,
-						&conn->from,
-						ftp->ftp_buffer,
-						len + ftp->buf_pos,
-						0, &conn->tries,
-						&format);
-
-		if (proceeded == -1) goto out_of_mem;
-
-		ftp->buf_pos += len - proceeded;
-		memmove(ftp->ftp_buffer, ftp->ftp_buffer + proceeded, ftp->buf_pos);
-		read_from_socket(socket, rb, connection_state(S_TRANS), sftp_got_data);
-		return;
-	}
-
-	if (ftp_process_dirlist(conn->cached, &conn->from,
-				ftp->ftp_buffer, ftp->buf_pos, 1,
-				&conn->tries, &format) == -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) ADD_CONST("
\n
\n\n"); - - abort_connection(conn, connection_state(S_OK)); -} - -void -sftp_protocol_handler(struct connection *conn) -{ - int sftp_pipe[2] = { -1, -1 }; - pid_t cpid; - struct sftp_connection_info *ftp = (struct sftp_connection_info *)mem_calloc(1, sizeof(*ftp)); - - if (!ftp) { - abort_connection(conn, connection_state(S_OUT_OF_MEM)); - return; - } - conn->info = ftp; - - if (!conn->uri->datalen || conn->uri->data[conn->uri->datalen - 1] == '/') { - ftp->dir = 1; - } - - if (c_pipe(sftp_pipe)) { - int s_errno = errno; - - if (sftp_pipe[0] >= 0) close(sftp_pipe[0]); - if (sftp_pipe[1] >= 0) close(sftp_pipe[1]); - abort_connection(conn, connection_state_for_errno(s_errno)); - return; - } - conn->from = 0; - conn->unrestartable = 1; - find_auth(conn->uri); /* remember username and password */ - cpid = fork(); - - if (cpid == -1) { - int s_errno = errno; - - close(sftp_pipe[0]); - close(sftp_pipe[1]); - retry_connection(conn, connection_state_for_errno(s_errno)); - return; - } - - if (!cpid) { - dup2(sftp_pipe[1], 1); - dup2(open("/dev/null", O_RDONLY), 0); - close(sftp_pipe[0]); - close(2); - close_all_non_term_fd(); - do_sftp(conn); - } else { - struct read_buffer *buf; - - conn->socket->fd = sftp_pipe[0]; - set_nonblocking_fd(conn->socket->fd); - close(sftp_pipe[1]); - buf = alloc_read_buffer(conn->socket); - - if (!buf) { - close_socket(conn->socket); - abort_connection(conn, connection_state(S_OUT_OF_MEM)); - return; - } - read_from_socket(conn->socket, buf, - connection_state(S_CONN), sftp_got_data); - } -} diff --git a/src/session/download.h b/src/session/download.h index 451313c4..ba16a70e 100644 --- a/src/session/download.h +++ b/src/session/download.h @@ -52,7 +52,7 @@ typedef unsigned char download_flags_T; struct download { /* XXX: order matters there, there's some hard initialization in * src/session/session.c and src/viewer/text/view.c */ - LIST_HEAD(struct download); + LIST_HEAD_EL(struct download); struct connection *conn; struct cache_entry *cached; @@ -75,7 +75,7 @@ struct download { * These structures are kept in the session.type_queries list, and * destroy_session() calls done_type_query() to destroy them too. */ struct type_query { - LIST_HEAD(struct type_query); + LIST_HEAD_EL(struct type_query); /** After ELinks has downloaded enough of the resource to see * that a type query is needed, it moves the download here and diff --git a/src/session/location.h b/src/session/location.h index 5e90c5e0..6806e594 100644 --- a/src/session/location.h +++ b/src/session/location.h @@ -11,7 +11,7 @@ extern "C" { #endif struct location { - LIST_HEAD(struct location); + LIST_HEAD_EL(struct location); LIST_OF(struct frame) frames; LIST_OF(struct frame) iframes; diff --git a/src/session/session.cpp b/src/session/session.cpp index b47964e5..9b6c418e 100644 --- a/src/session/session.cpp +++ b/src/session/session.cpp @@ -64,7 +64,7 @@ struct file_to_load { - LIST_HEAD(struct file_to_load); + LIST_HEAD_EL(struct file_to_load); struct session *ses; unsigned int req_sent:1; @@ -81,7 +81,7 @@ struct file_to_load { * we can look up this information. In case of failure the session information * has a timeout */ struct session_info { - LIST_HEAD(struct session_info); + LIST_HEAD_EL(struct session_info); int id; timer_id_T timer; @@ -589,7 +589,7 @@ display_timer(struct session *ses) struct questions_entry { - LIST_HEAD(struct questions_entry); + LIST_HEAD_EL(struct questions_entry); void (*callback)(struct session *, void *); void *data; diff --git a/src/session/session.h b/src/session/session.h index 9574f1ce..7897f03a 100644 --- a/src/session/session.h +++ b/src/session/session.h @@ -55,7 +55,7 @@ typedef unsigned int remote_session_flags_T; /** This is generic frame descriptor, meaningful mainly for ses_*_frame*(). */ struct frame { - LIST_HEAD(struct frame); + LIST_HEAD_EL(struct frame); char *name; int redirect_cnt; @@ -64,7 +64,7 @@ struct frame { }; struct iframe { - LIST_HEAD(struct frame); + LIST_HEAD_EL(struct frame); char *name; int redirect_cnt; @@ -158,7 +158,7 @@ enum navigate_mode { * viewed document through the browsing history of this session to the status * bar information. */ struct session { - LIST_HEAD(struct session); + LIST_HEAD_EL(struct session); #ifdef CONFIG_SCRIPTING_SPIDERMONKEY diff --git a/src/terminal/screen.c b/src/terminal/screen.c index 60323515..6c958017 100644 --- a/src/terminal/screen.c +++ b/src/terminal/screen.c @@ -284,7 +284,7 @@ struct screen_driver_opt { * @todo TODO: termcap/terminfo can maybe gradually be introduced via * this structure. We'll see. --jonas */ struct screen_driver { - LIST_HEAD(struct screen_driver); + LIST_HEAD_EL(struct screen_driver); /** The terminal._template_.type. Together with the #name member they * uniquely identify the screen_driver. */ diff --git a/src/terminal/sixel.h b/src/terminal/sixel.h index fd678b3d..a0932c7a 100644 --- a/src/terminal/sixel.h +++ b/src/terminal/sixel.h @@ -15,7 +15,7 @@ struct terminal; struct image { - LIST_HEAD(struct image); + LIST_HEAD_EL(struct image); struct string pixels; int x; int y; diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index 27ee2105..7d445071 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -66,7 +66,7 @@ enum term_redrawing_state { * * @todo TODO: Regroup the following into logical chunks. --pasky */ struct terminal { - LIST_HEAD(struct terminal); /*!< ::terminals is the sentinel. */ + LIST_HEAD_EL(struct terminal); /*!< ::terminals is the sentinel. */ #ifdef CONFIG_SCRIPTING_SPIDERMONKEY struct JSObject *jsobject; /* Instance of terminal_class */ diff --git a/src/terminal/window.h b/src/terminal/window.h index ce6a666c..5296c4c6 100644 --- a/src/terminal/window.h +++ b/src/terminal/window.h @@ -36,7 +36,7 @@ typedef void (window_handler_T)(struct window *, struct term_event *); * systems; they get mouse events in the coordinate system of the * terminal. */ struct window { - LIST_HEAD(struct window); /*!< terminal.windows is the sentinel. */ + LIST_HEAD_EL(struct window); /*!< terminal.windows is the sentinel. */ /** Whether this is a normal window or a tab window. */ enum window_type type; diff --git a/src/util/hash.h b/src/util/hash.h index 62414426..143b9d08 100644 --- a/src/util/hash.h +++ b/src/util/hash.h @@ -14,7 +14,7 @@ typedef unsigned long hash_value_T; typedef hash_value_T (* hash_func_T)(const char *key, unsigned int keylen, hash_value_T magic); struct hash_item { - LIST_HEAD(struct hash_item); + LIST_HEAD_EL(struct hash_item); const char *key; unsigned int keylen; diff --git a/src/util/lists.h b/src/util/lists.h index 0612c509..c5310adf 100644 --- a/src/util/lists.h +++ b/src/util/lists.h @@ -28,7 +28,7 @@ extern "C" { /* Fix namespace clash with system headers (like FreeBSD's, all hail BSD!). */ -#undef LIST_HEAD +#undef LIST_HEAD_EL #undef list_head #define list_head list_head_elinks @@ -55,9 +55,9 @@ struct xlist_head { struct xlist_head *prev; }; -#define NULL_LIST_HEAD NULL, NULL -#define D_LIST_HEAD(x) &x, &x -#define LIST_HEAD(x) x *next; x *prev +#define NULL_LIST_HEAD_EL NULL, NULL +#define D_LIST_HEAD_EL(x) &x, &x +#define LIST_HEAD_EL(x) x *next; x *prev #define LIST_SET_MAGIC(x) list_magic_set(*(x)) #else /* LISTDEBUG */ @@ -112,9 +112,9 @@ struct xlist_head { }; -#define NULL_LIST_HEAD LISTMAGIC1, NULL, NULL, LISTMAGIC2 -#define D_LIST_HEAD(x) LISTMAGIC1, &x, &x, LISTMAGIC2 -#define LIST_HEAD(x) void *magic1; x *next; x *prev; void *magic2 +#define NULL_LIST_HEAD_EL LISTMAGIC1, NULL, NULL, LISTMAGIC2 +#define D_LIST_HEAD_EL(x) LISTMAGIC1, &x, &x, LISTMAGIC2 +#define LIST_HEAD_EL(x) void *magic1; x *next; x *prev; void *magic2 #define LIST_SET_MAGIC(x) list_magic_set(*(x)) #endif /* LISTDEBUG */ @@ -129,7 +129,7 @@ struct xlist_head { /** Define and initialize a list variable. The @a element_T parameter * currently serves as documentation only; the compiler does not check * that it matches. */ -#define INIT_LIST_OF(element_T, x) LIST_OF(element_T) x = { D_LIST_HEAD(x) } +#define INIT_LIST_OF(element_T, x) LIST_OF(element_T) x = { D_LIST_HEAD_EL(x) } #ifdef HAVE_TYPEOF #define list_typeof(x) __typeof__(x) diff --git a/src/util/memdebug.c b/src/util/memdebug.c index 0f89b3b7..e36d9a61 100644 --- a/src/util/memdebug.c +++ b/src/util/memdebug.c @@ -108,7 +108,7 @@ struct alloc_header { - LIST_HEAD(struct alloc_header); + LIST_HEAD_EL(struct alloc_header); #ifdef CHECK_AH_SANITY int magic; diff --git a/src/util/string.h b/src/util/string.h index 4504b6f4..a394a8c0 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -294,7 +294,7 @@ add_bytes_to_string__( struct string_list_item { - LIST_HEAD(struct string_list_item); + LIST_HEAD_EL(struct string_list_item); struct string string; }; @@ -309,7 +309,7 @@ add_to_string_list(LIST_OF(struct string_list_item) *list, void free_string_list(LIST_OF(struct string_list_item) *list); struct ecmascript_string_list_item { - LIST_HEAD(struct ecmascript_string_list_item); + LIST_HEAD_EL(struct ecmascript_string_list_item); struct string string; int element_offset; }; diff --git a/src/viewer/text/form.cpp b/src/viewer/text/form.cpp index c1ed4e11..25840ae4 100644 --- a/src/viewer/text/form.cpp +++ b/src/viewer/text/form.cpp @@ -61,7 +61,7 @@ * in viewer/common/. --pasky */ struct files_offset { - LIST_HEAD(struct files_offset); + LIST_HEAD_EL(struct files_offset); /* offset of the filename in the data generated by encode_multipart. * data[begin] is the FILE_CHAR, data + begin + 1 is the filename. */ int begin; diff --git a/src/viewer/text/form.h b/src/viewer/text/form.h index 716a17bc..790c2ab3 100644 --- a/src/viewer/text/form.h +++ b/src/viewer/text/form.h @@ -7,7 +7,7 @@ #endif #include "document/forms.h" -#include "util/lists.h" /* LIST_HEAD */ +#include "util/lists.h" /* LIST_HEAD_EL */ #include "viewer/action.h" #ifdef __cplusplus @@ -23,7 +23,7 @@ struct terminal; /*! This struct looks a little embarrassing, yeah. */ struct form_view { - LIST_HEAD(struct form_view); + LIST_HEAD_EL(struct form_view); /** The corresponding form.form_num within the document. * We can't just reference to struct form since we can potentially @@ -101,7 +101,7 @@ struct form_state { }; struct submitted_value { - LIST_HEAD(struct submitted_value); + LIST_HEAD_EL(struct submitted_value); char *name; char *value; diff --git a/src/viewer/text/textarea.c b/src/viewer/text/textarea.c index 51729d3d..dfe4ced5 100644 --- a/src/viewer/text/textarea.c +++ b/src/viewer/text/textarea.c @@ -561,7 +561,7 @@ error: } struct textarea_data { - LIST_HEAD(struct textarea_data); + LIST_HEAD_EL(struct textarea_data); size_t fc_maxlength; struct form_state *fs; struct terminal *term;