1
/* Downloads managment */
2
/* $Id: download.c,v 1.210.2.1 2004/01/17 07:57:11 miciah Exp $ */
12
#ifdef HAVE_SYS_CYGWIN_H
13
#include <sys/cygwin.h>
15
#include <sys/types.h>
17
#include <fcntl.h> /* OS/2 needs this after sys/types.h */
27
#include "bfu/hierbox.h"
28
#include "bfu/msgbox.h"
29
#include "config/options.h"
30
#include "dialogs/download.h"
31
#include "dialogs/menu.h"
32
#include "cache/cache.h"
33
#include "intl/gettext/libintl.h"
34
#include "mime/mime.h"
35
#include "osdep/osdep.h"
36
#include "protocol/http/date.h"
37
#include "protocol/uri.h"
38
#include "protocol/protocol.h"
39
#include "sched/connection.h"
40
#include "sched/download.h"
41
#include "sched/error.h"
42
#include "sched/history.h"
43
#include "sched/location.h"
44
#include "sched/session.h"
45
#include "sched/task.h"
46
#include "terminal/draw.h"
47
#include "terminal/screen.h"
48
#include "terminal/terminal.h"
49
#include "util/conv.h"
50
#include "util/error.h"
51
#include "util/file.h"
52
#include "util/memlist.h"
53
#include "util/memory.h"
54
#include "util/object.h"
55
#include "util/string.h"
56
#include "util/ttime.h"
59
/* TODO: tp_*() should be in separate file, I guess? --pasky */
62
INIT_LIST_HEAD(downloads);
66
are_there_downloads(void)
68
struct file_download *down;
70
foreach (down, downloads)
78
static struct session *
79
get_download_ses(struct file_download *down)
83
foreach (ses, sessions)
87
foreach (ses, sessions)
88
if (ses->tab->term == down->term)
91
if (!list_empty(sessions))
99
abort_download(struct file_download *down, int stop)
102
done_listbox_item(&download_browser, down->box_item);
103
if (down->dlg_data) cancel_dialog(down->dlg_data, NULL);
104
if (down->download.state >= 0)
105
change_connection(&down->download, NULL, PRI_CANCEL, stop);
106
if (down->url) mem_free(down->url);
108
if (down->handle != -1) {
109
prealloc_truncate(down->handle, down->last_pos);
113
if (down->prog) mem_free(down->prog);
115
if (down->delete) unlink(down->file);
116
mem_free(down->file);
124
kill_downloads_to_file(unsigned char *file)
126
struct file_download *file_download;
128
foreach (file_download, downloads) {
129
if (strcmp(file_download->file, file))
132
file_download = file_download->prev;
133
abort_download(file_download->next, 0);
139
abort_all_downloads(void)
141
while (!list_empty(downloads))
142
abort_download(downloads.next, 0 /* does it matter? */);
147
destroy_downloads(struct session *ses)
149
struct file_download *file_download;
152
/* We are supposed to blat all downloads to external handlers belonging
153
* to @ses, but we will refuse to do so if there is another session
154
* bound to this terminal. That looks like the reasonable thing to do,
155
* fulfilling the principle of least astonishment. */
156
foreach (s, sessions) {
157
if (s != ses && s->tab->term == ses->tab->term)
161
foreach (file_download, downloads) {
162
if (file_download->ses != ses || !file_download->prog)
165
file_download = file_download->prev;
166
abort_download(file_download->next, 0);
172
download_error_dialog(struct file_download *file_download, int saved_errno)
174
unsigned char *msg = stracpy(file_download->file);
175
unsigned char *emsg = stracpy((unsigned char *) strerror(saved_errno));
176
struct session *ses = get_download_ses(file_download);
178
if (msg && emsg && ses) {
179
struct terminal *term = ses->tab->term;
181
msg_box(term, getml(msg, emsg, NULL), MSGBOX_FREE_TEXT,
182
N_("Download error"), AL_CENTER,
183
msg_text(term, N_("Could not create file %s: %s"), msg, emsg),
185
N_("OK"), NULL, B_ENTER | B_ESC);
187
if (msg) mem_free(msg);
188
if (emsg) mem_free(emsg);
193
write_cache_entry_to_file(struct cache_entry *ce, struct file_download *file_download)
195
struct fragment *frag;
197
if (file_download->download.prg && file_download->download.prg->seek) {
198
file_download->last_pos = file_download->download.prg->seek;
199
file_download->download.prg->seek = 0;
200
/* This is exclusive with the prealloc, thus we can perform
201
* this in front of that thing safely. */
202
if (lseek(file_download->handle, file_download->last_pos, SEEK_SET) < 0)
206
foreach (frag, ce->frag) {
207
int remain = file_download->last_pos - frag->offset;
208
int *h = &file_download->handle;
211
if (remain < 0 || frag->length <= remain)
214
#ifdef USE_OPEN_PREALLOC
215
if (!file_download->last_pos
216
&& (!file_download->stat.prg
217
|| file_download->stat.prg->size > 0)) {
219
*h = open_prealloc(file_download->file,
220
O_CREAT|O_WRONLY|O_TRUNC,
222
file_download->stat.prg
223
? file_download->stat.prg->size
225
if (*h == -1) goto write_error;
230
w = safe_write(*h, frag->data + remain, frag->length - remain);
231
if (w == -1) goto write_error;
233
file_download->last_pos += w;
239
if (!list_empty(sessions)) download_error_dialog(file_download, errno);
245
download_data_store(struct download *download, struct file_download *file_download)
247
struct session *ses = get_download_ses(file_download);
248
struct terminal *term = NULL;
250
if (!ses) goto abort;
251
term = ses->tab->term;
253
if (download->state >= 0) {
254
if (file_download->dlg_data)
255
redraw_dialog(file_download->dlg_data, 1);
259
if (download->state != S_OK) {
260
unsigned char *errmsg = get_err_msg(download->state, term);
263
if (!errmsg) goto abort;
265
url = get_no_post_url(file_download->url, NULL);
267
if (!url) goto abort;
269
msg_box(term, getml(url, NULL), MSGBOX_FREE_TEXT,
270
N_("Download error"), AL_CENTER,
271
msg_text(term, N_("Error downloading %s:\n\n%s"), url, errmsg),
272
get_download_ses(file_download), 1,
273
N_("OK"), NULL, B_ENTER | B_ESC /*,
274
N_(T_RETRY), NULL, 0 */ /* FIXME: retry */);
279
if (file_download->prog) {
280
prealloc_truncate(file_download->handle,
281
file_download->last_pos);
282
close(file_download->handle);
283
file_download->handle = -1;
284
exec_on_terminal(term, file_download->prog, file_download->file,
285
!!file_download->prog_flags);
286
file_download->delete = 0;
290
if (file_download->notify) {
291
unsigned char *url = get_no_post_url(file_download->url, NULL);
294
msg_box(term, getml(url, NULL), MSGBOX_FREE_TEXT,
295
N_("Download"), AL_CENTER,
296
msg_text(term, N_("Download complete:\n%s"), url),
297
get_download_ses(file_download), 1,
298
N_("OK"), NULL, B_ENTER | B_ESC);
302
if (file_download->remotetime
303
&& get_opt_int("document.download.set_original_time")) {
306
foo.actime = foo.modtime = file_download->remotetime;
307
utime(file_download->file, &foo);
311
if (term && get_opt_int("document.download.notify_bell")
312
+ file_download->notify >= 2) {
316
abort_download(file_download, 0);
320
download_data(struct download *download, struct file_download *file_download)
322
struct cache_entry *ce = download->ce;
323
int broken_302_redirect;
327
if (download->state >= S_WAIT && download->state < S_TRANS)
330
if (ce->last_modified)
331
file_download->remotetime = parse_http_date(ce->last_modified);
333
broken_302_redirect = get_opt_int("protocol.http.bugs.broken_302_redirect");
335
while (ce->redirect && file_download->redirect_cnt++ < MAX_REDIRECTS) {
338
if (download->state >= 0)
339
change_connection(&file_download->download, NULL, PRI_CANCEL, 0);
341
u = join_urls(file_download->url, ce->redirect);
344
if (!broken_302_redirect && !ce->redirect_get) {
345
unsigned char *postdata = post_data_start(file_download->url);
347
if (postdata) add_to_strn(&u, postdata);
350
mem_free(file_download->url);
352
file_download->url = u;
353
file_download->download.state = S_WAIT_REDIR;
355
if (file_download->dlg_data)
356
redraw_dialog(file_download->dlg_data, 1);
358
load_url(file_download->url, get_cache_uri(ce), &file_download->download,
359
PRI_DOWNLOAD, CACHE_MODE_NORMAL,
360
download->prg ? download->prg->start : 0);
365
if (!write_cache_entry_to_file(ce, file_download)) {
366
detach_connection(download, file_download->last_pos);
367
abort_download(file_download, 0);
371
detach_connection(download, file_download->last_pos);
374
download_data_store(download, file_download);
378
/* XXX: We assume that resume is everytime zero in lun's callbacks. */
380
struct terminal *term;
381
unsigned char *ofile, *file;
383
void (*callback)(struct terminal *, unsigned char *, void *, int);
388
lun_alternate(struct lun_hop *lun_hop)
390
lun_hop->callback(lun_hop->term, lun_hop->file, lun_hop->data, 0);
391
if (lun_hop->ofile) mem_free(lun_hop->ofile);
396
lun_overwrite(struct lun_hop *lun_hop)
398
lun_hop->callback(lun_hop->term, lun_hop->ofile, lun_hop->data, 0);
399
if (lun_hop->file) mem_free(lun_hop->file);
404
lun_resume(struct lun_hop *lun_hop)
406
lun_hop->callback(lun_hop->term, lun_hop->ofile, lun_hop->data, 1);
407
if (lun_hop->file) mem_free(lun_hop->file);
412
lun_cancel(struct lun_hop *lun_hop)
414
lun_hop->callback(lun_hop->term, NULL, lun_hop->data, 0);
415
if (lun_hop->ofile) mem_free(lun_hop->ofile);
416
if (lun_hop->file) mem_free(lun_hop->file);
421
lookup_unique_name(struct terminal *term, unsigned char *ofile, int resume,
422
void (*callback)(struct terminal *, unsigned char *, void *, int),
425
struct lun_hop *lun_hop;
429
ofile = expand_tilde(ofile);
431
/* Minor code duplication to prevent useless call to get_opt_int()
432
* if possible. --Zas */
434
callback(term, ofile, data, resume);
438
/* !overwrite means always silently overwrite, which may be admitelly
439
* indeed a little confusing ;-) */
440
overwrite = get_opt_int("document.download.overwrite");
442
/* Nothing special to do... */
443
callback(term, ofile, data, resume);
447
/* Check if the file already exists (file != ofile). */
448
file = get_unique_name(ofile);
450
if (!file || overwrite == 1 || file == ofile) {
451
/* Still nothing special to do... */
452
if (file != ofile) mem_free(ofile);
453
callback(term, file, data, 0);
457
/* overwrite == 2 (ask) and file != ofile (=> original file already
460
lun_hop = mem_calloc(1, sizeof(struct lun_hop));
462
if (file != ofile) mem_free(file);
464
callback(term, NULL, data, 0);
467
lun_hop->term = term;
468
lun_hop->ofile = ofile;
469
lun_hop->file = (file != ofile) ? file : stracpy(ofile);
470
lun_hop->callback = callback;
471
lun_hop->data = data;
473
msg_box(term, NULL, MSGBOX_FREE_TEXT,
474
N_("File exists"), AL_CENTER,
475
msg_text(term, N_("This file already exists:\n"
477
"The alternative filename is:\n"
479
empty_string_or_(lun_hop->ofile),
480
empty_string_or_(file)),
482
N_("Save under the alternative name"), lun_alternate, B_ENTER,
483
N_("Overwrite the original file"), lun_overwrite, 0,
484
N_("Resume download of the original file"), lun_resume, 0,
485
N_("Cancel"), lun_cancel, B_ESC);
489
static void create_download_file_do(struct terminal *, unsigned char *, void *, int);
492
unsigned char **real_file;
495
void (*callback)(struct terminal *, int, void *, int);
500
create_download_file(struct terminal *term, unsigned char *fi,
501
unsigned char **real_file, int safe, int resume,
502
void (*callback)(struct terminal *, int, void *, int),
505
struct cdf_hop *cdf_hop = mem_calloc(1, sizeof(struct cdf_hop));
509
callback(term, -1, data, 0);
513
cdf_hop->real_file = real_file;
514
cdf_hop->safe = safe;
515
cdf_hop->callback = callback;
516
cdf_hop->data = data;
518
/* FIXME: The wd bussiness is probably useless here? --pasky */
522
/* Also the tilde will be expanded here. */
523
lookup_unique_name(term, fi, resume, create_download_file_do, cdf_hop);
532
create_download_file_do(struct terminal *term, unsigned char *file, void *data,
535
struct cdf_hop *cdf_hop = data;
539
#ifdef NO_FILE_SECURITY
542
int sf = cdf_hop->safe;
545
if (!file) goto finish;
550
/* O_APPEND means repositioning at the end of file before each write(),
551
* thus ignoring seek()s and that can hide mysterious bugs. IMHO.
553
h = open(file, O_CREAT | O_WRONLY | (resume ? 0 : O_TRUNC)
554
| (sf && !resume ? O_EXCL : 0),
556
saved_errno = errno; /* Saved in case of ... --Zas */
564
msg_box(term, NULL, MSGBOX_FREE_TEXT,
565
N_("Download error"), AL_CENTER,
566
msg_text(term, N_("Could not create file '%s':\n%s"),
567
file, strerror(saved_errno)),
569
N_("OK"), NULL, B_ENTER | B_ESC);
577
if (!cdf_hop->safe) {
578
unsigned char *download_dir = get_opt_str("document.download.directory");
581
safe_strncpy(download_dir, file, MAX_STR_LEN);
583
/* Find the used directory so it's available in history */
584
for (i = strlen(download_dir); i >= 0; i--)
585
if (dir_sep(download_dir[i]))
587
download_dir[i + 1] = 0;
591
if (cdf_hop->real_file)
592
*cdf_hop->real_file = file;
597
cdf_hop->callback(term, h, cdf_hop->data, resume);
603
static unsigned char *
604
get_temp_name(unsigned char *url)
607
unsigned char *extension;
609
* We use tempnam() here, which is unsafe (race condition), for now.
610
* This should be changed at some time, but it needs an in-depth work
611
* of whole download code. --Zas */
612
unsigned char *nm = tempnam(NULL, ELINKS_TEMPNAME_PREFIX);
614
if (!nm) return NULL;
616
if (!init_string(&name)) {
621
add_to_string(&name, nm);
624
extension = get_extension_from_url(url);
626
add_char_to_string(&name, '.');
627
add_shell_safe_to_string(&name, extension, strlen(extension));
636
subst_file(unsigned char *prog, unsigned char *file)
640
if (!init_string(&name)) return NULL;
645
for (p = 0; prog[p] && prog[p] != '%'; p++);
647
add_bytes_to_string(&name, prog, p);
651
#if defined(HAVE_CYGWIN_CONV_TO_FULL_WIN32_PATH)
653
unsigned char new_path[MAX_PATH];
655
unsigned char new_path[1024];
658
cygwin_conv_to_full_win32_path(file, new_path);
659
add_to_string(&name, new_path);
661
add_to_string(&name, file);
671
static void common_download_do(struct terminal *, int, void *, int);
675
unsigned char *real_file;
679
common_download(struct session *ses, unsigned char *file, int resume)
681
struct cmdw_hop *cmdw_hop;
683
if (!ses->dn_url) return;
685
cmdw_hop = mem_calloc(1, sizeof(struct cmdw_hop));
686
if (!cmdw_hop) return;
689
kill_downloads_to_file(file);
691
create_download_file(ses->tab->term, file, &cmdw_hop->real_file, 0,
692
resume, common_download_do, cmdw_hop);
696
common_download_do(struct terminal *term, int fd, void *data, int resume)
698
struct cmdw_hop *cmdw_hop = data;
699
struct file_download *file_download = NULL;
700
unsigned char *url = cmdw_hop->ses->dn_url;
703
if (!cmdw_hop->real_file) goto download_error;
705
file_download = mem_calloc(1, sizeof(struct file_download));
706
if (!file_download) goto download_error;
708
file_download->url = stracpy(url);
709
if (!file_download->url) goto download_error;
711
file_download->file = cmdw_hop->real_file;
713
if (fstat(fd, &buf)) goto download_error;
714
file_download->last_pos = resume ? (int) buf.st_size : 0;
716
file_download->download.end = (void (*)(struct download *, void *)) download_data;
717
file_download->download.data = file_download;
718
file_download->handle = fd;
719
file_download->ses = cmdw_hop->ses;
720
/* The tab may be closed, but we will still want to ie. open the
721
* handler on that terminal. */
722
file_download->term = cmdw_hop->ses->tab->term;
723
file_download->remotetime = 0;
725
add_to_list(downloads, file_download);
726
load_url(url, cmdw_hop->ses->ref_url, &file_download->download, PRI_DOWNLOAD, CACHE_MODE_NORMAL,
727
(resume ? file_download->last_pos : 0));
729
if (is_in_downloads_list(file_download))
730
file_download->box_item = add_listbox_item(&download_browser,
734
display_download(cmdw_hop->ses->tab->term, file_download, cmdw_hop->ses);
741
if (file_download->url) mem_free(file_download->url);
742
mem_free(file_download);
748
start_download(void *ses, unsigned char *file)
750
enum protocol protocol = known_protocol(((struct session *)ses)->dn_url,
753
if (protocol == PROTOCOL_UNKNOWN) {
754
print_unknown_protocol_dialog(ses);
758
common_download(ses, file, 0);
762
resume_download(void *ses, unsigned char *file)
764
common_download(ses, file, 1);
768
static void tp_cancel(void *);
769
static void tp_free(struct tq *);
772
static void continue_download_do(struct terminal *, int, void *, int);
776
unsigned char *real_file;
781
continue_download(void *data, unsigned char *file)
783
struct tq *tq = data;
784
struct codw_hop *codw_hop;
786
if (!tq->url) return;
788
codw_hop = mem_calloc(1, sizeof(struct codw_hop));
795
/* FIXME: get_temp_name() calls tempnam(). --Zas */
796
file = get_temp_name(tq->url);
805
codw_hop->file = file;
807
kill_downloads_to_file(file);
809
create_download_file(tq->ses->tab->term, file, &codw_hop->real_file,
810
!!tq->prog, 0, continue_download_do, codw_hop);
814
continue_download_do(struct terminal *term, int fd, void *data, int resume)
816
struct codw_hop *codw_hop = data;
817
struct file_download *file_download = NULL;
818
unsigned char *url = codw_hop->tq->url;
820
if (!codw_hop->real_file) goto cancel;
822
file_download = mem_calloc(1, sizeof(struct file_download));
823
if (!file_download) goto cancel;
825
object_nolock(file_download); /* Debugging purpose. */
827
file_download->url = stracpy(url);
828
if (!file_download->url) goto cancel;
830
file_download->file = codw_hop->real_file;
832
file_download->download.end = (void (*)(struct download *, void *)) download_data;
833
file_download->download.data = file_download;
834
file_download->last_pos = 0;
835
file_download->handle = fd;
836
file_download->ses = codw_hop->tq->ses;
838
if (codw_hop->tq->prog) {
839
file_download->prog = subst_file(codw_hop->tq->prog, codw_hop->file);
840
file_download->delete = 1;
841
mem_free(codw_hop->file);
842
mem_free(codw_hop->tq->prog);
843
codw_hop->tq->prog = NULL;
846
file_download->prog_flags = codw_hop->tq->prog_flags;
848
add_to_list(downloads, file_download);
849
change_connection(&codw_hop->tq->download, &file_download->download, PRI_DOWNLOAD, 0);
851
if (is_in_downloads_list(file_download))
852
file_download->box_item = add_listbox_item(&download_browser,
856
tp_free(codw_hop->tq);
857
display_download(codw_hop->tq->ses->tab->term, file_download, codw_hop->tq->ses);
863
tp_cancel(codw_hop->tq);
864
if (codw_hop->tq->prog && codw_hop->file) mem_free(codw_hop->file);
866
if (file_download->url) mem_free(file_download->url);
867
mem_free(file_download);
874
tp_free(struct tq *tq)
876
object_unlock(tq->ce);
878
if (tq->goto_position) mem_free(tq->goto_position);
879
if (tq->prog) mem_free(tq->prog);
880
if (tq->target_frame) mem_free(tq->target_frame);
886
tp_cancel(void *data)
888
struct tq *tq = data;
889
/* XXX: Should we really abort? (1 vs 0 as the last param) --pasky */
890
change_connection(&tq->download, NULL, PRI_CANCEL, 1);
896
tp_save(struct tq *tq)
902
query_file(tq->ses, tq->url, tq, continue_download, tp_cancel, 1);
907
tp_open(struct tq *tq)
909
continue_download(tq, "");
913
/* FIXME: We need to modify this function to take frame data instead, as we
914
* want to use this function for frames as well (now, when frame has content
915
* type text/plain, it is ignored and displayed as HTML). */
917
tp_display(struct tq *tq)
919
struct view_state *vs;
920
struct session *ses = tq->ses;
921
unsigned char *goto_position = ses->goto_position;
922
unsigned char *loading_url = ses->loading_url;
923
unsigned char *target_frame = ses->task.target_frame;
925
ses->goto_position = tq->goto_position;
926
ses->loading_url = tq->url;
927
ses->task.target_frame = tq->target_frame;
928
vs = ses_forward(ses, tq->frame);
929
if (vs) vs->plain = 1;
930
ses->goto_position = goto_position;
931
ses->loading_url = loading_url;
932
ses->task.target_frame = target_frame;
935
tq->goto_position = NULL;
936
cur_loc(ses)->download.end = (void (*)(struct download *, void *))
938
cur_loc(ses)->download.data = ses;
940
if (tq->download.state >= 0)
941
change_connection(&tq->download, &cur_loc(ses)->download, PRI_MAIN, 0);
943
cur_loc(ses)->download.state = tq->download.state;
952
type_query(struct tq *tq, unsigned char *ct, struct mime_handler *handler)
954
struct string filename;
955
unsigned char *content_type;
963
tq->prog = stracpy(handler->program);
964
tq->prog_flags = handler->block;
971
content_type = stracpy(ct);
972
if (!content_type) return;
974
if (init_string(&filename))
975
add_string_uri_filename_to_string(&filename, tq->url);
977
/* @filename.source should be last in the getml()s ! (It terminates the
978
* pointers list in case of allocation failure.) */
981
if (!get_opt_int_tree(cmdline_options, "anonymous")) {
982
msg_box(tq->ses->tab->term, getml(content_type, filename.source, NULL), MSGBOX_FREE_TEXT,
983
N_("Unknown type"), AL_CENTER,
984
msg_text(tq->ses->tab->term, N_("Would you like to "
985
"save the file '%s' (type: %s) "
987
filename.source, content_type),
989
N_("Save"), tp_save, B_ENTER,
990
N_("Display"), tp_display, 0,
991
N_("Cancel"), tp_cancel, B_ESC);
993
msg_box(tq->ses->tab->term, getml(content_type, filename.source, NULL), MSGBOX_FREE_TEXT,
994
N_("Unknown type"), AL_CENTER,
995
msg_text(tq->ses->tab->term, N_("Would you like to "
996
"display the file '%s' (type: %s)?"),
997
filename.source, content_type),
999
N_("Display"), tp_display, B_ENTER,
1000
N_("Cancel"), tp_cancel, B_ESC);
1003
unsigned char *description = handler->description;
1004
unsigned char *desc_sep = (*description) ? "; " : "";
1006
if (!get_opt_int_tree(cmdline_options, "anonymous")) {
1007
/* TODO: Improve the dialog to let the user correct the
1009
msg_box(tq->ses->tab->term, getml(content_type, filename.source, NULL), MSGBOX_FREE_TEXT,
1010
N_("What to do?"), AL_CENTER,
1011
msg_text(tq->ses->tab->term, N_("Would you like to "
1012
"open the file '%s' (type: %s%s%s)\n"
1013
"with '%s', save it or display it?"),
1014
filename.source, content_type, desc_sep,
1015
description, handler->program),
1017
N_("Open"), tp_open, B_ENTER,
1018
N_("Save"), tp_save, 0,
1019
N_("Display"), tp_display, 0,
1020
N_("Cancel"), tp_cancel, B_ESC);
1022
msg_box(tq->ses->tab->term, getml(content_type, filename.source, NULL), MSGBOX_FREE_TEXT,
1023
N_("What to do?"), AL_CENTER,
1024
msg_text(tq->ses->tab->term, N_("Would you like to "
1025
"open the file '%s' (type: %s%s%s)\n"
1026
"with '%s', or display it?"),
1027
filename.source, content_type, desc_sep,
1028
description, handler->program),
1030
N_("Open"), tp_open, B_ENTER,
1031
N_("Display"), tp_display, 0,
1032
N_("Cancel"), tp_cancel, B_ESC);
1038
unsigned char *type;
1039
unsigned int plain:1;
1040
} static known_types[] = {
1042
{ "application/xhtml+xml", 0 }, /* RFC 3236 */
1043
{ "text/plain", 1 },
1048
ses_chktype(struct session *ses, struct download *loading, struct cache_entry *ce, int frame)
1050
struct mime_handler *handler;
1051
struct view_state *vs;
1053
unsigned char *ctype = get_content_type(ce->head, get_cache_uri(ce));
1059
goto plaintext_follow;
1061
for (i = 0; known_types[i].type; i++) {
1062
if (strcasecmp(ctype, known_types[i].type))
1065
plaintext = known_types[i].plain;
1066
goto plaintext_follow;
1069
xwin = ses->tab->term->environment & ENV_XWIN;
1070
handler = get_mime_type_handler(ctype, xwin);
1072
if (!handler && strlen(ctype) >= 4 && !strncasecmp(ctype, "text", 4))
1073
goto plaintext_follow;
1075
foreach (tq, ses->tq)
1076
if (!strcmp(tq->url, ses->loading_url))
1079
tq = mem_calloc(1, sizeof(struct tq));
1080
if (!tq) goto do_not_follow;
1081
add_to_list(ses->tq, tq);
1084
tq->url = stracpy(ses->loading_url);
1085
change_connection(loading, &tq->download, PRI_MAIN, 0);
1086
loading->state = S_OK;
1089
object_lock(tq->ce);
1091
if (ses->goto_position) tq->goto_position = stracpy(ses->goto_position);
1092
if (ses->task.target_frame)
1093
tq->target_frame = stracpy(ses->task.target_frame);
1096
type_query(tq, ctype, handler);
1100
if (handler) mem_free(handler);
1105
if (ctype) mem_free(ctype);
1107
vs = ses_forward(ses, frame);
1108
if (vs) vs->plain = plaintext;