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;