1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

bug 1054: Don't abort downloads when closing a terminal.

Except if they have external handlers.

When ELinks receives an event from a terminal, move that terminal to
the beginning of the global "terminals" list, so that the terminals
are always sorted according to the time of the most recent use.  Note,
this affects the numbering of bookmark folders in session snapshots.

Add get_default_terminal(), which returns the most recently used
terminal that is still open.  Use that in various places that
previously used terminals.prev or terminals.next.  Four functions
fetch the size of the terminal for User-Agent headers, and
get_default_terminal() is not really right, but neither was the
original code; add TODO comments in those functions.

When the user chooses "Background and Notify", associate the download
with the terminal where the dialog box is.  So any later messages will
then appear in that terminal, if it is still open.  However, don't
change the terminal if the download has an external handler.

When a download gets some data, don't immediately check the associated
terminal.  Instead, wait for the download to end.  Then, if the
terminal of the download has been closed, use get_default_terminal()
instead.  If there is no default terminal either, just skip any
message boxes.
This commit is contained in:
Kalle Olavi Niemitalo 2008-10-15 11:05:43 +03:00 committed by Kalle Olavi Niemitalo
parent 9c17d8e805
commit 84e19d0e4e
13 changed files with 97 additions and 27 deletions

6
NEWS
View File

@ -33,6 +33,12 @@ Miscellaneous:
cached response even if you have modified a file between requests,
and that ELinks can send inconsistent data if you modify a file
while it is being uploaded.
* bug 1054: Don't abort downloads when closing the terminal from which
they were started. When such a download ends, display the message
in the most recently used terminal. If the user chooses
``Background and Notify'' via the download manager in some terminal,
reassociate the download with that terminal. These changes do not
apply to downloads to external handlers.
* Really retry forever when connection.retries = 0.
* enhancement: Session-specific options. Any options changed with
toggle-* actions no longer affect other tabs or other terminals.

View File

@ -61,6 +61,15 @@ dlg_set_notify(struct dialog_data *dlg_data, struct widget_data *widget_data)
struct file_download *file_download = dlg_data->dlg->udata;
file_download->notify = 1;
/* The user of this terminal wants to be notified about the
* download. Make this also the terminal where the
* notification appears. However, keep the original terminal
* for external handlers, because the handler may have been
* chosen based on the environment variables (usually TERM or
* DISPLAY) of the ELinks process in that terminal. */
if (!file_download->external_handler)
file_download->term = dlg_data->win->term;
#if CONFIG_BITTORRENT
if (file_download->uri->protocol == PROTOCOL_BITTORRENT)
set_bittorrent_notify_on_completion(&file_download->download,

View File

@ -96,10 +96,12 @@ navigator_get(struct SEE_interpreter *interp, struct SEE_object *o,
if (*optstr && strcmp(optstr, " ")) {
unsigned char *ustr, ts[64] = "";
static unsigned char custr[256];
/* TODO: Somehow get the terminal in which the
* document is actually being displayed. */
struct terminal *term = get_default_terminal();
if (!list_empty(terminals)) {
if (term) {
unsigned int tslen = 0;
struct terminal *term = terminals.prev;
ulongcat(ts, &tslen, term->width, 3, 0);
ts[tslen++] = 'x';

View File

@ -119,10 +119,12 @@ navigator_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
if (*optstr && strcmp(optstr, " ")) {
unsigned char *ustr, ts[64] = "";
static unsigned char custr[256];
/* TODO: Somehow get the terminal in which the
* document is actually being displayed. */
struct terminal *term = get_default_terminal();
if (!list_empty(terminals)) {
if (term) {
unsigned int tslen = 0;
struct terminal *term = terminals.prev;
ulongcat(ts, &tslen, term->width, 3, 0);
ts[tslen++] = 'x';

View File

@ -182,10 +182,12 @@ set_vars(struct connection *conn, unsigned char *script)
str = get_opt_str("protocol.http.user_agent", NULL);
if (*str && strcmp(str, " ")) {
unsigned char *ustr, ts[64] = "";
/* TODO: Somehow get the terminal in which the
* document will actually be displayed. */
struct terminal *term = get_default_terminal();
if (!list_empty(terminals)) {
if (term) {
unsigned int tslen = 0;
struct terminal *term = terminals.prev;
ulongcat(ts, &tslen, term->width, 3, 0);
ts[tslen++] = 'x';

View File

@ -761,12 +761,14 @@ http_send_header(struct socket *socket)
optstr = get_opt_str("protocol.http.user_agent", NULL);
if (*optstr && strcmp(optstr, " ")) {
unsigned char *ustr, ts[64] = "";
/* TODO: Somehow get the terminal in which the
* document will actually be displayed. */
struct terminal *term = get_default_terminal();
add_to_string(&header, "User-Agent: ");
if (!list_empty(terminals)) {
if (term) {
unsigned int tslen = 0;
struct terminal *term = terminals.prev;
ulongcat(ts, &tslen, term->width, 3, 0);
ts[tslen++] = 'x';

View File

@ -113,6 +113,7 @@ static VALUE
erb_module_message(VALUE self, VALUE str)
{
unsigned char *message, *line_end;
struct terminal *term;
str = rb_obj_as_string(str);
message = memacpy(RSTRING(str)->ptr, RSTRING(str)->len);
@ -121,13 +122,14 @@ erb_module_message(VALUE self, VALUE str)
line_end = strchr(message, '\n');
if (line_end) *line_end = '\0';
if (list_empty(terminals)) {
term = get_default_terminal();
if (!term) {
usrerror("[Ruby] %s", message);
mem_free(message);
return Qnil;
}
info_box(terminals.next, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
info_box(term, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
N_("Ruby Message"), ALIGN_LEFT, message);
return Qnil;
@ -144,6 +146,7 @@ erb_stdout_p(int argc, VALUE *argv, VALUE self)
{
int i;
struct string string;
struct terminal *term;
if (!init_string(&string))
return Qnil;
@ -174,13 +177,14 @@ erb_stdout_p(int argc, VALUE *argv, VALUE self)
add_bytes_to_string(&string, ptr, len);
}
if (list_empty(terminals)) {
term = get_default_terminal();
if (!term) {
usrerror("[Ruby] %s", string.source);
done_string(&string);
return Qnil;
}
info_box(terminals.next, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
info_box(term, MSGBOX_NO_TEXT_INTL | MSGBOX_FREE_TEXT,
N_("Ruby Message"), ALIGN_LEFT, string.source);
return Qnil;

View File

@ -40,15 +40,14 @@ report_scripting_error(struct module *module, struct session *ses,
struct string string;
if (!ses) {
if (list_empty(terminals)) {
term = get_default_terminal();
if (term == NULL) {
usrerror(gettext("[%s error] %s"),
gettext(module->name), msg);
sleep(3);
return;
}
term = terminals.next;
} else {
term = ses->tab->term;
}

View File

@ -332,35 +332,46 @@ download_data_store(struct download *download, struct file_download *file_downlo
assert_terminal_ptr_not_dangling(term);
if_assert_failed term = file_download->term = NULL;
if (!term) {
/* No term here, so no beep. --Zas */
abort_download(file_download);
return;
}
if (is_in_progress_state(download->state)) {
if (file_download->dlg_data)
redraw_dialog(file_download->dlg_data, 1);
return;
}
/* If the original terminal of the download has been closed,
* display any messages in the default terminal instead. */
if (term == NULL)
term = get_default_terminal(); /* may be NULL too */
if (!is_in_state(download->state, S_OK)) {
unsigned char *url = get_uri_string(file_download->uri, URI_PUBLIC);
struct connection_state state = download->state;
/* abort_download_and_beep allows term==NULL. */
abort_download_and_beep(file_download, term);
if (!url) return;
info_box(term, MSGBOX_FREE_TEXT,
N_("Download error"), ALIGN_CENTER,
msg_text(term, N_("Error downloading %s:\n\n%s"),
url, get_state_message(state, term)));
if (term) {
info_box(term, MSGBOX_FREE_TEXT,
N_("Download error"), ALIGN_CENTER,
msg_text(term, N_("Error downloading %s:\n\n%s"),
url, get_state_message(state, term)));
}
mem_free(url);
return;
}
if (file_download->external_handler) {
if (term == NULL) {
/* There is no terminal in which to run the handler.
* Abort the download. file_download->delete should
* be 1 here so that the following call also deletes
* the temporary file. */
abort_download(file_download);
return;
}
prealloc_truncate(file_download->handle, file_download->seek);
close(file_download->handle);
file_download->handle = -1;
@ -372,7 +383,7 @@ download_data_store(struct download *download, struct file_download *file_downlo
return;
}
if (file_download->notify) {
if (file_download->notify && term) {
unsigned char *url = get_uri_string(file_download->uri, URI_PUBLIC);
/* This is apparently a little racy. Deleting the box item will
@ -399,6 +410,7 @@ download_data_store(struct download *download, struct file_download *file_downlo
utime(file_download->file, &foo);
}
/* abort_download_and_beep allows term==NULL. */
abort_download_and_beep(file_download, term);
}

View File

@ -66,7 +66,17 @@ struct file_download {
unsigned char *file;
unsigned char *external_handler;
struct session *ses;
/** The terminal in which message boxes about the download
* should be displayed. If this terminal is closed, then
* detach_downloads_from_terminal() changes the pointer to
* NULL, and get_default_terminal() will be used if a
* terminal is needed later. However, if the download has
* an external handler, then detach_downloads_from_terminal()
* aborts it right away; external handlers always run in the
* original terminal, if anywhere. */
struct terminal *term;
time_t remotetime;
off_t seek;
int handle;

View File

@ -468,6 +468,9 @@ in_term(struct terminal *term)
ssize_t r;
unsigned char *iq;
/* Mark this as the most recently used terminal. */
move_to_top_of_list(terminals, term);
if (!interlink
|| !interlink->qfreespace
|| interlink->qfreespace - interlink->qlen > ALLOC_GR) {

View File

@ -68,6 +68,19 @@ cls_redraw_all_terminals(void)
redraw_terminal_cls(term);
}
/** Get the terminal in which message boxes should be displayed, if
* there is no specific reason to use some other terminal. This
* returns NULL if all terminals have been closed. (ELinks keeps
* running anyway if ui.sessions.keep_session_active is true.) */
struct terminal *
get_default_terminal(void)
{
if (list_empty(terminals))
return NULL;
else
return terminals.next;
}
struct terminal *
init_term(int fdin, int fdout)
{
@ -96,6 +109,8 @@ init_term(int fdin, int fdout)
term->spec = get_opt_rec(config_options, name);
object_lock(term->spec);
/* It's a new terminal, so assume the user is using it right now,
* and sort it to the front of the list. */
add_to_list(terminals, term);
set_handlers(fdin, (select_handler_T) in_term, NULL,

View File

@ -164,7 +164,10 @@ struct terminal {
#define do_not_ignore_next_mouse_event(term) \
memset(&(term)->prev_mouse_event, 0, sizeof((term)->prev_mouse_event))
/** We keep track about all the terminals in this list. */
/** We keep track about all the terminals in this list.
* The list is sorted so that terminals.next is the terminal
* from which ELinks most recently got an event. But please
* call get_default_terminal() for that. */
extern LIST_OF(struct terminal) terminals;
@ -175,6 +178,7 @@ void destroy_terminal(struct terminal *);
void redraw_terminal(struct terminal *term);
void redraw_terminal_cls(struct terminal *term);
void cls_redraw_all_terminals(void);
struct terminal *get_default_terminal(void);
void redraw_all_terminals(void);
void destroy_all_terminals(void);