1
0
Fork 0

[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.
This commit is contained in:
Witold Filipczyk 2023-06-19 18:43:53 +02:00
parent b7bb7fc403
commit a67188413c
70 changed files with 554 additions and 799 deletions

View File

@ -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;
};

View File

@ -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, \

View File

@ -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;

View File

@ -36,7 +36,7 @@
/* Elements' attributes */
struct attributes {
LIST_HEAD(struct attributes);
LIST_HEAD_EL(struct attributes);
char *name;
char *value;

2
src/cache/cache.h vendored
View File

@ -78,7 +78,7 @@ struct cache_entry {
};
struct fragment {
LIST_HEAD(struct fragment);
LIST_HEAD_EL(struct fragment);
off_t offset;
off_t length;

View File

@ -12,7 +12,7 @@ struct session;
struct domain_tree {
LIST_HEAD(struct domain_tree);
LIST_HEAD_EL(struct domain_tree);
struct option *tree;

View File

@ -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;

View File

@ -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. */
};

View File

@ -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;
};

View File

@ -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/-/_/. */

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -109,7 +109,7 @@ enum {
};
struct listener {
LIST_HEAD(struct listener);
LIST_HEAD_EL(struct listener);
char *typ;
JS::RootedValue fun;
};

View File

@ -16,7 +16,7 @@ enum {
};
struct xhr_listener {
LIST_HEAD(struct xhr_listener);
LIST_HEAD_EL(struct xhr_listener);
char *typ;
const char *fun;
};

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -19,7 +19,7 @@ struct object {
};
#define OBJECT_HEAD(type) \
LIST_HEAD(type); \
LIST_HEAD_EL(type); \
struct object object
struct object_head {

View File

@ -57,6 +57,8 @@ do { \
#define EINTRLOOP(ret_, call_) EINTRLOOPX(ret_, call_, -1)
#include <curl/curl.h>
#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

View File

@ -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 <libev/event.h>
#elif defined(HAVE_EVENT_H)
#include <event.h>
#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 <event.h>
#elif defined(HAVE_EV_EVENT_H)
#include <ev-event.h>
#endif
#define USE_LIBEVENT
#endif
#include <curl/curl.h>
#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. */

View File

@ -9,7 +9,7 @@ extern "C" {
#endif
struct timer {
LIST_HEAD(struct timer);
LIST_HEAD_EL(struct timer);
timeval_T interval;
void (*func)(void *);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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. */

View File

@ -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;

View File

@ -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 */
};

View File

@ -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 *);

View File

@ -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. */

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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("</pre>\n<hr/>\n</body>\n</html>");
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);
}

View File

@ -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"

View File

@ -0,0 +1 @@
srcs += files('ftp.c')

View File

@ -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"

View File

@ -1 +0,0 @@
srcs += files('ftpes.c')

View File

@ -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. */

View File

@ -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

View File

@ -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"

View File

@ -1 +0,0 @@
srcs += files('sftp.c')

View File

@ -1,592 +0,0 @@
/* SFTP protocol implementation */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> /* For converting permissions to strings */
#include <sys/types.h>
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h> /* OS/2 needs this after sys/types.h */
#endif
/* We need to have it here. Stupid BSD. */
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <curl/curl.h>
#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, "<font color=\"");
add_to_string(&string, format->dircolor);
add_to_string(&string, "\"><b>");
}
add_to_string(&string, "<a href=\"");
encode_uri_string(&string, ftp_info->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, "</a>");
if (ftp_info->type == FTP_FILE_DIRECTORY && format->colorize_dir) {
add_to_string(&string, "</b></font>");
}
if (ftp_info->symlink.length) {
add_to_string(&string, " -&gt; ");
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 \<pre>
* 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("</pre>\n<hr/>\n</body>\n</html>");
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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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. */

View File

@ -15,7 +15,7 @@ struct terminal;
struct image {
LIST_HEAD(struct image);
LIST_HEAD_EL(struct image);
struct string pixels;
int x;
int y;

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -108,7 +108,7 @@
struct alloc_header {
LIST_HEAD(struct alloc_header);
LIST_HEAD_EL(struct alloc_header);
#ifdef CHECK_AH_SANITY
int magic;

View File

@ -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;
};

View File

@ -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;

View File

@ -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;

View File

@ -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;